From 52a9c80de5272791a1d6f5ee7abdab7b4b49ce64 Mon Sep 17 00:00:00 2001 From: rafalense Date: Thu, 26 May 2016 11:52:53 +0200 Subject: [PATCH] v3.8.1.2 added missing files --- TMessagesProj/build.gradle | 46 +- .../config/debug/AndroidManifest.xml | 6 +- TMessagesProj/jni/Android.mk | 4 +- TMessagesProj/jni/Application.mk | 2 +- TMessagesProj/jni/NativeLoader.cpp | 22 + TMessagesProj/jni/TgNetWrapper.cpp | 336 + TMessagesProj/jni/audio.c | 150 + TMessagesProj/jni/boringssl/LICENSE | 185 + TMessagesProj/jni/boringssl/README.MD | 10 + TMessagesProj/jni/boringssl/crypto/.gitignore | 1 + .../jni/boringssl/crypto/CMakeLists.txt | 197 + .../jni/boringssl/crypto/aes/CMakeLists.txt | 63 + TMessagesProj/jni/boringssl/crypto/aes/aes.c | 1085 + .../jni/boringssl/crypto/aes/aes_ige.c | 323 + .../jni/boringssl/crypto/aes/asm/aes-586.pl | 2987 +++ .../jni/boringssl/crypto/aes/asm/aes-armv4.pl | 1249 + .../boringssl/crypto/aes/asm/aes-x86_64.pl | 2805 +++ .../jni/boringssl/crypto/aes/asm/aesni-x86.pl | 2525 ++ .../boringssl/crypto/aes/asm/aesni-x86_64.pl | 4048 +++ .../boringssl/crypto/aes/asm/aesv8-armx.pl | 1001 + .../boringssl/crypto/aes/asm/bsaes-armv7.pl | 2515 ++ .../boringssl/crypto/aes/asm/bsaes-x86_64.pl | 3102 +++ .../jni/boringssl/crypto/aes/asm/vpaes-x86.pl | 903 + .../boringssl/crypto/aes/asm/vpaes-x86_64.pl | 1207 + .../jni/boringssl/crypto/aes/internal.h | 87 + .../jni/boringssl/crypto/aes/mode_wrappers.c | 108 + TMessagesProj/jni/boringssl/crypto/arm_arch.h | 136 + .../jni/boringssl/crypto/asn1/CMakeLists.txt | 45 + .../jni/boringssl/crypto/asn1/a_bitstr.c | 255 + .../jni/boringssl/crypto/asn1/a_bool.c | 112 + .../jni/boringssl/crypto/asn1/a_bytes.c | 317 + .../jni/boringssl/crypto/asn1/a_d2i_fp.c | 286 + .../jni/boringssl/crypto/asn1/a_dup.c | 103 + .../jni/boringssl/crypto/asn1/a_enum.c | 183 + .../jni/boringssl/crypto/asn1/a_gentm.c | 255 + .../jni/boringssl/crypto/asn1/a_i2d_fp.c | 154 + .../jni/boringssl/crypto/asn1/a_int.c | 456 + .../jni/boringssl/crypto/asn1/a_mbstr.c | 390 + .../jni/boringssl/crypto/asn1/a_object.c | 412 + .../jni/boringssl/crypto/asn1/a_octet.c | 70 + .../jni/boringssl/crypto/asn1/a_print.c | 119 + .../jni/boringssl/crypto/asn1/a_strnid.c | 286 + .../jni/boringssl/crypto/asn1/a_time.c | 221 + .../jni/boringssl/crypto/asn1/a_type.c | 160 + .../jni/boringssl/crypto/asn1/a_utctm.c | 342 + .../jni/boringssl/crypto/asn1/a_utf8.c | 210 + .../jni/boringssl/crypto/asn1/asn1_lib.c | 510 + .../jni/boringssl/crypto/asn1/asn1_locl.h | 73 + .../jni/boringssl/crypto/asn1/asn1_par.c | 435 + .../jni/boringssl/crypto/asn1/asn_pack.c | 104 + .../jni/boringssl/crypto/asn1/bio_asn1.c | 496 + .../jni/boringssl/crypto/asn1/bio_ndef.c | 254 + .../jni/boringssl/crypto/asn1/charmap.pl | 135 + .../jni/boringssl/crypto/asn1/f_enum.c | 206 + .../jni/boringssl/crypto/asn1/f_int.c | 210 + .../jni/boringssl/crypto/asn1/f_string.c | 204 + .../jni/boringssl/crypto/asn1/t_bitst.c | 102 + .../jni/boringssl/crypto/asn1/t_pkey.c | 112 + .../jni/boringssl/crypto/asn1/tasn_dec.c | 1340 + .../jni/boringssl/crypto/asn1/tasn_enc.c | 695 + .../jni/boringssl/crypto/asn1/tasn_fre.c | 264 + .../jni/boringssl/crypto/asn1/tasn_new.c | 398 + .../jni/boringssl/crypto/asn1/tasn_prn.c | 642 + .../jni/boringssl/crypto/asn1/tasn_typ.c | 137 + .../jni/boringssl/crypto/asn1/tasn_utl.c | 266 + .../jni/boringssl/crypto/asn1/x_bignum.c | 142 + .../jni/boringssl/crypto/asn1/x_long.c | 182 + .../boringssl/crypto/base64/CMakeLists.txt | 9 + .../jni/boringssl/crypto/base64/base64.c | 478 + .../jni/boringssl/crypto/bio/CMakeLists.txt | 19 + TMessagesProj/jni/boringssl/crypto/bio/bio.c | 606 + .../jni/boringssl/crypto/bio/bio_mem.c | 327 + .../jni/boringssl/crypto/bio/buffer.c | 496 + .../jni/boringssl/crypto/bio/connect.c | 538 + TMessagesProj/jni/boringssl/crypto/bio/fd.c | 270 + TMessagesProj/jni/boringssl/crypto/bio/file.c | 350 + .../jni/boringssl/crypto/bio/hexdump.c | 192 + .../jni/boringssl/crypto/bio/internal.h | 108 + TMessagesProj/jni/boringssl/crypto/bio/pair.c | 803 + .../jni/boringssl/crypto/bio/printf.c | 115 + .../jni/boringssl/crypto/bio/socket.c | 195 + .../jni/boringssl/crypto/bio/socket_helper.c | 113 + .../jni/boringssl/crypto/bn/CMakeLists.txt | 68 + TMessagesProj/jni/boringssl/crypto/bn/add.c | 394 + .../jni/boringssl/crypto/bn/asm/armv4-mont.pl | 694 + .../jni/boringssl/crypto/bn/asm/bn-586.pl | 774 + .../jni/boringssl/crypto/bn/asm/co-586.pl | 287 + .../jni/boringssl/crypto/bn/asm/rsaz-avx2.pl | 1898 ++ .../boringssl/crypto/bn/asm/rsaz-x86_64.pl | 2144 ++ .../jni/boringssl/crypto/bn/asm/x86-mont.pl | 592 + .../jni/boringssl/crypto/bn/asm/x86_64-gcc.c | 599 + .../boringssl/crypto/bn/asm/x86_64-mont.pl | 1401 ++ .../boringssl/crypto/bn/asm/x86_64-mont5.pl | 3499 +++ TMessagesProj/jni/boringssl/crypto/bn/bn.c | 338 + .../jni/boringssl/crypto/bn/bn_asn1.c | 74 + TMessagesProj/jni/boringssl/crypto/bn/cmp.c | 200 + .../jni/boringssl/crypto/bn/convert.c | 501 + TMessagesProj/jni/boringssl/crypto/bn/ctx.c | 311 + TMessagesProj/jni/boringssl/crypto/bn/div.c | 625 + .../jni/boringssl/crypto/bn/exponentiation.c | 1559 ++ TMessagesProj/jni/boringssl/crypto/bn/gcd.c | 697 + .../jni/boringssl/crypto/bn/generic.c | 1131 + .../jni/boringssl/crypto/bn/internal.h | 291 + .../jni/boringssl/crypto/bn/kronecker.c | 175 + .../jni/boringssl/crypto/bn/montgomery.c | 565 + TMessagesProj/jni/boringssl/crypto/bn/mul.c | 888 + TMessagesProj/jni/boringssl/crypto/bn/prime.c | 845 + .../jni/boringssl/crypto/bn/random.c | 326 + .../jni/boringssl/crypto/bn/rsaz_exp.c | 326 + .../jni/boringssl/crypto/bn/rsaz_exp.h | 56 + TMessagesProj/jni/boringssl/crypto/bn/shift.c | 299 + TMessagesProj/jni/boringssl/crypto/bn/sqrt.c | 505 + .../jni/boringssl/crypto/buf/CMakeLists.txt | 9 + TMessagesProj/jni/boringssl/crypto/buf/buf.c | 235 + .../crypto/bytestring/CMakeLists.txt | 11 + .../jni/boringssl/crypto/bytestring/ber.c | 221 + .../jni/boringssl/crypto/bytestring/cbb.c | 393 + .../jni/boringssl/crypto/bytestring/cbs.c | 401 + .../boringssl/crypto/bytestring/internal.h | 46 + .../boringssl/crypto/chacha/CMakeLists.txt | 20 + .../boringssl/crypto/chacha/chacha_generic.c | 143 + .../jni/boringssl/crypto/chacha/chacha_vec.c | 327 + .../boringssl/crypto/chacha/chacha_vec_arm.S | 1428 ++ .../crypto/chacha/chacha_vec_arm_generate.go | 150 + .../boringssl/crypto/cipher/CMakeLists.txt | 22 + .../jni/boringssl/crypto/cipher/aead.c | 154 + .../jni/boringssl/crypto/cipher/cipher.c | 652 + .../jni/boringssl/crypto/cipher/derive_key.c | 154 + .../jni/boringssl/crypto/cipher/e_aes.c | 1760 ++ .../crypto/cipher/e_chacha20poly1305.c | 220 + .../jni/boringssl/crypto/cipher/e_des.c | 135 + .../jni/boringssl/crypto/cipher/e_null.c | 85 + .../jni/boringssl/crypto/cipher/e_rc2.c | 443 + .../jni/boringssl/crypto/cipher/e_rc4.c | 397 + .../jni/boringssl/crypto/cipher/e_ssl3.c | 422 + .../jni/boringssl/crypto/cipher/e_tls.c | 613 + .../jni/boringssl/crypto/cipher/internal.h | 161 + .../jni/boringssl/crypto/cipher/tls_cbc.c | 495 + .../jni/boringssl/crypto/cmac/CMakeLists.txt | 9 + .../jni/boringssl/crypto/cmac/cmac.c | 239 + .../jni/boringssl/crypto/conf/CMakeLists.txt | 9 + .../jni/boringssl/crypto/conf/conf.c | 774 + .../jni/boringssl/crypto/conf/conf_def.h | 127 + .../jni/boringssl/crypto/cpu-arm-asm.S | 32 + TMessagesProj/jni/boringssl/crypto/cpu-arm.c | 189 + .../jni/boringssl/crypto/cpu-intel.c | 261 + TMessagesProj/jni/boringssl/crypto/crypto.c | 112 + .../jni/boringssl/crypto/des/CMakeLists.txt | 9 + TMessagesProj/jni/boringssl/crypto/des/des.c | 773 + .../jni/boringssl/crypto/des/internal.h | 229 + .../jni/boringssl/crypto/dh/CMakeLists.txt | 13 + TMessagesProj/jni/boringssl/crypto/dh/check.c | 180 + TMessagesProj/jni/boringssl/crypto/dh/dh.c | 252 + .../jni/boringssl/crypto/dh/dh_asn1.c | 84 + .../jni/boringssl/crypto/dh/dh_impl.c | 326 + .../jni/boringssl/crypto/dh/internal.h | 80 + .../jni/boringssl/crypto/dh/params.c | 316 + .../boringssl/crypto/digest/CMakeLists.txt | 10 + .../jni/boringssl/crypto/digest/digest.c | 247 + .../jni/boringssl/crypto/digest/digests.c | 298 + .../jni/boringssl/crypto/digest/internal.h | 112 + .../jni/boringssl/crypto/digest/md32_common.h | 350 + .../jni/boringssl/crypto/directory.h | 66 + .../jni/boringssl/crypto/directory_posix.c | 108 + .../jni/boringssl/crypto/directory_win.c | 144 + .../jni/boringssl/crypto/dsa/CMakeLists.txt | 11 + TMessagesProj/jni/boringssl/crypto/dsa/dsa.c | 348 + .../jni/boringssl/crypto/dsa/dsa_asn1.c | 150 + .../jni/boringssl/crypto/dsa/dsa_impl.c | 750 + .../jni/boringssl/crypto/dsa/internal.h | 78 + .../jni/boringssl/crypto/ec/CMakeLists.txt | 17 + TMessagesProj/jni/boringssl/crypto/ec/ec.c | 884 + .../jni/boringssl/crypto/ec/ec_asn1.c | 577 + .../jni/boringssl/crypto/ec/ec_key.c | 503 + .../jni/boringssl/crypto/ec/ec_montgomery.c | 283 + .../jni/boringssl/crypto/ec/example_mul.c | 133 + .../jni/boringssl/crypto/ec/internal.h | 372 + TMessagesProj/jni/boringssl/crypto/ec/oct.c | 470 + .../jni/boringssl/crypto/ec/p256-64.c | 1931 ++ .../jni/boringssl/crypto/ec/simple.c | 1357 + .../jni/boringssl/crypto/ec/util-64.c | 183 + TMessagesProj/jni/boringssl/crypto/ec/wnaf.c | 853 + .../jni/boringssl/crypto/ecdh/CMakeLists.txt | 9 + .../jni/boringssl/crypto/ecdh/ecdh.c | 161 + .../jni/boringssl/crypto/ecdsa/CMakeLists.txt | 10 + .../jni/boringssl/crypto/ecdsa/ecdsa.c | 493 + .../jni/boringssl/crypto/ecdsa/ecdsa_asn1.c | 250 + .../boringssl/crypto/engine/CMakeLists.txt | 9 + .../jni/boringssl/crypto/engine/engine.c | 120 + .../jni/boringssl/crypto/err/CMakeLists.txt | 40 + .../jni/boringssl/crypto/err/asn1.errordata | 88 + .../jni/boringssl/crypto/err/bio.errordata | 17 + .../jni/boringssl/crypto/err/bn.errordata | 19 + .../jni/boringssl/crypto/err/cipher.errordata | 25 + .../jni/boringssl/crypto/err/conf.errordata | 6 + .../jni/boringssl/crypto/err/dh.errordata | 4 + .../jni/boringssl/crypto/err/digest.errordata | 1 + .../jni/boringssl/crypto/err/dsa.errordata | 4 + .../jni/boringssl/crypto/err/ec.errordata | 28 + .../jni/boringssl/crypto/err/ecdh.errordata | 3 + .../jni/boringssl/crypto/err/ecdsa.errordata | 6 + .../jni/boringssl/crypto/err/engine.errordata | 1 + TMessagesProj/jni/boringssl/crypto/err/err.c | 775 + .../boringssl/crypto/err/err_data_generate.go | 277 + .../jni/boringssl/crypto/err/evp.errordata | 46 + .../jni/boringssl/crypto/err/hkdf.errordata | 1 + .../jni/boringssl/crypto/err/obj.errordata | 1 + .../jni/boringssl/crypto/err/pem.errordata | 15 + .../jni/boringssl/crypto/err/pkcs8.errordata | 25 + .../jni/boringssl/crypto/err/rsa.errordata | 46 + .../jni/boringssl/crypto/err/ssl.errordata | 216 + .../jni/boringssl/crypto/err/x509.errordata | 37 + .../jni/boringssl/crypto/err/x509v3.errordata | 63 + .../jni/boringssl/crypto/evp/CMakeLists.txt | 20 + .../jni/boringssl/crypto/evp/algorithm.c | 153 + .../jni/boringssl/crypto/evp/digestsign.c | 164 + TMessagesProj/jni/boringssl/crypto/evp/evp.c | 414 + .../jni/boringssl/crypto/evp/evp_asn1.c | 166 + .../jni/boringssl/crypto/evp/evp_ctx.c | 480 + .../jni/boringssl/crypto/evp/internal.h | 271 + .../jni/boringssl/crypto/evp/p_dsa_asn1.c | 585 + TMessagesProj/jni/boringssl/crypto/evp/p_ec.c | 299 + .../jni/boringssl/crypto/evp/p_ec_asn1.c | 573 + .../jni/boringssl/crypto/evp/p_rsa.c | 596 + .../jni/boringssl/crypto/evp/p_rsa_asn1.c | 727 + .../jni/boringssl/crypto/evp/pbkdf.c | 135 + TMessagesProj/jni/boringssl/crypto/evp/sign.c | 151 + TMessagesProj/jni/boringssl/crypto/ex_data.c | 314 + .../jni/boringssl/crypto/header_removed.h | 17 + .../jni/boringssl/crypto/hkdf/CMakeLists.txt | 9 + .../jni/boringssl/crypto/hkdf/hkdf.c | 89 + .../jni/boringssl/crypto/hmac/CMakeLists.txt | 9 + .../jni/boringssl/crypto/hmac/hmac.c | 213 + TMessagesProj/jni/boringssl/crypto/internal.h | 547 + .../jni/boringssl/crypto/lhash/CMakeLists.txt | 9 + .../jni/boringssl/crypto/lhash/lhash.c | 346 + .../jni/boringssl/crypto/lhash/make_macros.sh | 67 + .../jni/boringssl/crypto/md5/CMakeLists.txt | 30 + .../jni/boringssl/crypto/md5/asm/md5-586.pl | 307 + .../boringssl/crypto/md5/asm/md5-x86_64.pl | 370 + TMessagesProj/jni/boringssl/crypto/md5/md5.c | 275 + TMessagesProj/jni/boringssl/crypto/mem.c | 200 + .../jni/boringssl/crypto/modes/CMakeLists.txt | 55 + .../crypto/modes/asm/aesni-gcm-x86_64.pl | 1057 + .../boringssl/crypto/modes/asm/ghash-armv4.pl | 520 + .../boringssl/crypto/modes/asm/ghash-x86.pl | 1393 + .../crypto/modes/asm/ghash-x86_64.pl | 1753 ++ .../crypto/modes/asm/ghashv8-armx.pl | 422 + .../jni/boringssl/crypto/modes/cbc.c | 217 + .../jni/boringssl/crypto/modes/cfb.c | 230 + .../jni/boringssl/crypto/modes/ctr.c | 224 + .../jni/boringssl/crypto/modes/gcm.c | 1250 + .../jni/boringssl/crypto/modes/internal.h | 202 + .../jni/boringssl/crypto/modes/ofb.c | 107 + .../jni/boringssl/crypto/pem/CMakeLists.txt | 16 + .../jni/boringssl/crypto/pem/pem_all.c | 281 + .../jni/boringssl/crypto/pem/pem_info.c | 404 + .../jni/boringssl/crypto/pem/pem_lib.c | 835 + .../jni/boringssl/crypto/pem/pem_oth.c | 89 + .../jni/boringssl/crypto/pem/pem_pk8.c | 244 + .../jni/boringssl/crypto/pem/pem_pkey.c | 312 + .../jni/boringssl/crypto/pem/pem_x509.c | 65 + .../jni/boringssl/crypto/pem/pem_xaux.c | 66 + .../jni/boringssl/crypto/perlasm/arm-xlate.pl | 170 + .../jni/boringssl/crypto/perlasm/cbc.pl | 349 + .../jni/boringssl/crypto/perlasm/readme | 124 + .../boringssl/crypto/perlasm/x86_64-xlate.pl | 1169 + .../jni/boringssl/crypto/perlasm/x86asm.pl | 292 + .../jni/boringssl/crypto/perlasm/x86gas.pl | 263 + .../jni/boringssl/crypto/perlasm/x86masm.pl | 200 + .../jni/boringssl/crypto/perlasm/x86nasm.pl | 187 + .../jni/boringssl/crypto/pkcs8/CMakeLists.txt | 12 + .../jni/boringssl/crypto/pkcs8/internal.h | 74 + .../jni/boringssl/crypto/pkcs8/p5_pbe.c | 150 + .../jni/boringssl/crypto/pkcs8/p5_pbev2.c | 303 + .../jni/boringssl/crypto/pkcs8/p8_pkey.c | 85 + .../jni/boringssl/crypto/pkcs8/pkcs8.c | 1141 + .../boringssl/crypto/poly1305/CMakeLists.txt | 21 + .../jni/boringssl/crypto/poly1305/poly1305.c | 331 + .../boringssl/crypto/poly1305/poly1305_arm.c | 301 + .../crypto/poly1305/poly1305_arm_asm.S | 2015 ++ .../boringssl/crypto/poly1305/poly1305_vec.c | 892 + .../jni/boringssl/crypto/rand/CMakeLists.txt | 24 + .../crypto/rand/asm/rdrand-x86_64.pl | 75 + .../jni/boringssl/crypto/rand/hwrand.c | 65 + .../jni/boringssl/crypto/rand/internal.h | 37 + .../jni/boringssl/crypto/rand/rand.c | 186 + .../jni/boringssl/crypto/rand/urandom.c | 264 + .../jni/boringssl/crypto/rand/windows.c | 56 + .../jni/boringssl/crypto/rc4/CMakeLists.txt | 31 + .../jni/boringssl/crypto/rc4/asm/rc4-586.pl | 414 + .../crypto/rc4/asm/rc4-md5-x86_64.pl | 632 + .../boringssl/crypto/rc4/asm/rc4-x86_64.pl | 653 + TMessagesProj/jni/boringssl/crypto/rc4/rc4.c | 284 + .../jni/boringssl/crypto/refcount_c11.c | 67 + .../jni/boringssl/crypto/refcount_lock.c | 53 + .../jni/boringssl/crypto/rsa/CMakeLists.txt | 13 + .../jni/boringssl/crypto/rsa/blinding.c | 460 + .../jni/boringssl/crypto/rsa/internal.h | 142 + .../jni/boringssl/crypto/rsa/padding.c | 732 + TMessagesProj/jni/boringssl/crypto/rsa/rsa.c | 797 + .../jni/boringssl/crypto/rsa/rsa_asn1.c | 447 + .../jni/boringssl/crypto/rsa/rsa_impl.c | 1155 + .../jni/boringssl/crypto/sha/CMakeLists.txt | 66 + .../jni/boringssl/crypto/sha/asm/sha1-586.pl | 1476 ++ .../crypto/sha/asm/sha1-armv4-large.pl | 701 + .../boringssl/crypto/sha/asm/sha1-armv8.pl | 347 + .../boringssl/crypto/sha/asm/sha1-x86_64.pl | 2067 ++ .../boringssl/crypto/sha/asm/sha256-586.pl | 1281 + .../boringssl/crypto/sha/asm/sha256-armv4.pl | 735 + .../boringssl/crypto/sha/asm/sha512-586.pl | 911 + .../boringssl/crypto/sha/asm/sha512-armv4.pl | 666 + .../boringssl/crypto/sha/asm/sha512-armv8.pl | 436 + .../boringssl/crypto/sha/asm/sha512-x86_64.pl | 2396 ++ TMessagesProj/jni/boringssl/crypto/sha/sha1.c | 381 + .../jni/boringssl/crypto/sha/sha256.c | 370 + .../jni/boringssl/crypto/sha/sha512.c | 605 + .../jni/boringssl/crypto/stack/CMakeLists.txt | 9 + .../jni/boringssl/crypto/stack/make_macros.sh | 115 + .../jni/boringssl/crypto/stack/stack.c | 386 + TMessagesProj/jni/boringssl/crypto/thread.c | 101 + .../jni/boringssl/crypto/thread_none.c | 55 + .../jni/boringssl/crypto/thread_pthread.c | 162 + .../jni/boringssl/crypto/thread_win.c | 282 + .../jni/boringssl/crypto/time_support.c | 212 + .../jni/boringssl/crypto/x509/CMakeLists.txt | 57 + .../jni/boringssl/crypto/x509/a_digest.c | 97 + .../jni/boringssl/crypto/x509/a_sign.c | 136 + .../jni/boringssl/crypto/x509/a_strex.c | 564 + .../jni/boringssl/crypto/x509/a_verify.c | 133 + .../jni/boringssl/crypto/x509/asn1_gen.c | 873 + .../jni/boringssl/crypto/x509/by_dir.c | 491 + .../jni/boringssl/crypto/x509/by_file.c | 295 + .../jni/boringssl/crypto/x509/charmap.h | 15 + .../jni/boringssl/crypto/x509/i2d_pr.c | 84 + .../jni/boringssl/crypto/x509/pkcs7.c | 346 + .../jni/boringssl/crypto/x509/t_crl.c | 129 + .../jni/boringssl/crypto/x509/t_req.c | 246 + .../jni/boringssl/crypto/x509/t_x509.c | 500 + .../jni/boringssl/crypto/x509/t_x509a.c | 109 + .../jni/boringssl/crypto/x509/vpm_int.h | 70 + .../jni/boringssl/crypto/x509/x509.c | 152 + .../jni/boringssl/crypto/x509/x509_att.c | 353 + .../jni/boringssl/crypto/x509/x509_cmp.c | 490 + .../jni/boringssl/crypto/x509/x509_d2.c | 105 + .../jni/boringssl/crypto/x509/x509_def.c | 88 + .../jni/boringssl/crypto/x509/x509_ext.c | 206 + .../jni/boringssl/crypto/x509/x509_lu.c | 732 + .../jni/boringssl/crypto/x509/x509_obj.c | 191 + .../jni/boringssl/crypto/x509/x509_r2x.c | 113 + .../jni/boringssl/crypto/x509/x509_req.c | 315 + .../jni/boringssl/crypto/x509/x509_set.c | 154 + .../jni/boringssl/crypto/x509/x509_trs.c | 304 + .../jni/boringssl/crypto/x509/x509_txt.c | 209 + .../jni/boringssl/crypto/x509/x509_v3.c | 271 + .../jni/boringssl/crypto/x509/x509_vfy.c | 2465 ++ .../jni/boringssl/crypto/x509/x509_vpm.c | 672 + .../jni/boringssl/crypto/x509/x509cset.c | 165 + .../jni/boringssl/crypto/x509/x509name.c | 381 + .../jni/boringssl/crypto/x509/x509rset.c | 80 + .../jni/boringssl/crypto/x509/x509spki.c | 135 + .../jni/boringssl/crypto/x509/x509type.c | 128 + .../jni/boringssl/crypto/x509/x_algor.c | 154 + .../jni/boringssl/crypto/x509/x_all.c | 547 + .../jni/boringssl/crypto/x509/x_attrib.c | 117 + .../jni/boringssl/crypto/x509/x_crl.c | 560 + .../jni/boringssl/crypto/x509/x_exten.c | 75 + .../jni/boringssl/crypto/x509/x_info.c | 95 + .../jni/boringssl/crypto/x509/x_name.c | 538 + .../jni/boringssl/crypto/x509/x_pkey.c | 100 + .../jni/boringssl/crypto/x509/x_pubkey.c | 384 + .../jni/boringssl/crypto/x509/x_req.c | 112 + .../jni/boringssl/crypto/x509/x_sig.c | 69 + .../jni/boringssl/crypto/x509/x_spki.c | 78 + .../jni/boringssl/crypto/x509/x_val.c | 69 + .../jni/boringssl/crypto/x509/x_x509.c | 228 + .../jni/boringssl/crypto/x509/x_x509a.c | 177 + .../boringssl/crypto/x509v3/CMakeLists.txt | 44 + .../jni/boringssl/crypto/x509v3/ext_dat.h | 129 + .../jni/boringssl/crypto/x509v3/pcy_cache.c | 299 + .../jni/boringssl/crypto/x509v3/pcy_data.c | 137 + .../jni/boringssl/crypto/x509v3/pcy_int.h | 212 + .../jni/boringssl/crypto/x509v3/pcy_lib.c | 165 + .../jni/boringssl/crypto/x509v3/pcy_map.c | 133 + .../jni/boringssl/crypto/x509v3/pcy_node.c | 197 + .../jni/boringssl/crypto/x509v3/pcy_tree.c | 876 + .../jni/boringssl/crypto/x509v3/v3_akey.c | 212 + .../jni/boringssl/crypto/x509v3/v3_akeya.c | 71 + .../jni/boringssl/crypto/x509v3/v3_alt.c | 620 + .../jni/boringssl/crypto/x509v3/v3_bcons.c | 126 + .../jni/boringssl/crypto/x509v3/v3_bitst.c | 141 + .../jni/boringssl/crypto/x509v3/v3_conf.c | 459 + .../jni/boringssl/crypto/x509v3/v3_cpols.c | 475 + .../jni/boringssl/crypto/x509v3/v3_crld.c | 616 + .../jni/boringssl/crypto/x509v3/v3_enum.c | 98 + .../jni/boringssl/crypto/x509v3/v3_extku.c | 145 + .../jni/boringssl/crypto/x509v3/v3_genn.c | 252 + .../jni/boringssl/crypto/x509v3/v3_ia5.c | 117 + .../jni/boringssl/crypto/x509v3/v3_info.c | 200 + .../jni/boringssl/crypto/x509v3/v3_int.c | 87 + .../jni/boringssl/crypto/x509v3/v3_lib.c | 335 + .../jni/boringssl/crypto/x509v3/v3_ncons.c | 510 + .../jni/boringssl/crypto/x509v3/v3_pci.c | 335 + .../jni/boringssl/crypto/x509v3/v3_pcia.c | 56 + .../jni/boringssl/crypto/x509v3/v3_pcons.c | 142 + .../jni/boringssl/crypto/x509v3/v3_pku.c | 109 + .../jni/boringssl/crypto/x509v3/v3_pmaps.c | 156 + .../jni/boringssl/crypto/x509v3/v3_prn.c | 207 + .../jni/boringssl/crypto/x509v3/v3_purp.c | 804 + .../jni/boringssl/crypto/x509v3/v3_skey.c | 148 + .../jni/boringssl/crypto/x509v3/v3_sxnet.c | 266 + .../jni/boringssl/crypto/x509v3/v3_utl.c | 1316 + .../jni/boringssl/include/openssl/aead.h | 315 + .../jni/boringssl/include/openssl/aes.h | 167 + .../jni/boringssl/include/openssl/asn1.h | 1169 + .../jni/boringssl/include/openssl/asn1_mac.h | 76 + .../jni/boringssl/include/openssl/asn1t.h | 907 + .../jni/boringssl/include/openssl/base.h | 257 + .../jni/boringssl/include/openssl/base64.h | 179 + .../jni/boringssl/include/openssl/bio.h | 904 + .../jni/boringssl/include/openssl/blowfish.h | 93 + .../jni/boringssl/include/openssl/bn.h | 862 + .../jni/boringssl/include/openssl/buf.h | 118 + .../jni/boringssl/include/openssl/buffer.h | 18 + .../boringssl/include/openssl/bytestring.h | 349 + .../jni/boringssl/include/openssl/cast.h | 96 + .../jni/boringssl/include/openssl/chacha.h | 37 + .../jni/boringssl/include/openssl/cipher.h | 565 + .../jni/boringssl/include/openssl/cmac.h | 76 + .../jni/boringssl/include/openssl/conf.h | 145 + .../jni/boringssl/include/openssl/cpu.h | 126 + .../jni/boringssl/include/openssl/crypto.h | 62 + .../jni/boringssl/include/openssl/des.h | 164 + .../jni/boringssl/include/openssl/dh.h | 270 + .../jni/boringssl/include/openssl/digest.h | 257 + .../jni/boringssl/include/openssl/dsa.h | 374 + .../jni/boringssl/include/openssl/dtls1.h | 16 + .../jni/boringssl/include/openssl/ec.h | 366 + .../jni/boringssl/include/openssl/ec_key.h | 286 + .../jni/boringssl/include/openssl/ecdh.h | 102 + .../jni/boringssl/include/openssl/ecdsa.h | 206 + .../jni/boringssl/include/openssl/engine.h | 107 + .../jni/boringssl/include/openssl/err.h | 503 + .../jni/boringssl/include/openssl/evp.h | 743 + .../jni/boringssl/include/openssl/ex_data.h | 214 + .../jni/boringssl/include/openssl/hkdf.h | 44 + .../jni/boringssl/include/openssl/hmac.h | 160 + .../jni/boringssl/include/openssl/lhash.h | 192 + .../boringssl/include/openssl/lhash_macros.h | 132 + .../jni/boringssl/include/openssl/md5.h | 107 + .../jni/boringssl/include/openssl/mem.h | 140 + .../jni/boringssl/include/openssl/modes.h | 223 + .../jni/boringssl/include/openssl/obj.h | 198 + .../jni/boringssl/include/openssl/obj_mac.h | 4140 +++ .../jni/boringssl/include/openssl/objects.h | 18 + .../include/openssl/opensslfeatures.h | 60 + .../jni/boringssl/include/openssl/opensslv.h | 18 + .../jni/boringssl/include/openssl/ossl_typ.h | 18 + .../jni/boringssl/include/openssl/pem.h | 521 + .../jni/boringssl/include/openssl/pkcs12.h | 18 + .../jni/boringssl/include/openssl/pkcs7.h | 16 + .../jni/boringssl/include/openssl/pkcs8.h | 199 + .../jni/boringssl/include/openssl/poly1305.h | 50 + .../jni/boringssl/include/openssl/pqueue.h | 146 + .../jni/boringssl/include/openssl/rand.h | 97 + .../jni/boringssl/include/openssl/rc4.h | 90 + .../jni/boringssl/include/openssl/rsa.h | 633 + .../jni/boringssl/include/openssl/safestack.h | 16 + .../jni/boringssl/include/openssl/sha.h | 241 + .../jni/boringssl/include/openssl/srtp.h | 178 + .../jni/boringssl/include/openssl/ssl.h | 3067 +++ .../jni/boringssl/include/openssl/ssl3.h | 696 + .../jni/boringssl/include/openssl/stack.h | 298 + .../boringssl/include/openssl/stack_macros.h | 4190 +++ .../jni/boringssl/include/openssl/thread.h | 173 + .../boringssl/include/openssl/time_support.h | 90 + .../jni/boringssl/include/openssl/tls1.h | 672 + .../boringssl/include/openssl/type_check.h | 91 + .../jni/boringssl/include/openssl/x509.h | 1258 + .../jni/boringssl/include/openssl/x509_vfy.h | 612 + .../jni/boringssl/include/openssl/x509v3.h | 798 + .../jni/boringssl/lib/libcrypto_armeabi-v7a.a | Bin 0 -> 7232874 bytes .../jni/boringssl/lib/libcrypto_armeabi.a | Bin 0 -> 7241478 bytes .../jni/boringssl/lib/libcrypto_x86.a | Bin 0 -> 6127532 bytes .../util/android-cmake/AndroidNdkGdb.cmake | 96 + .../android-cmake/AndroidNdkModules.cmake | 58 + .../boringssl/util/android-cmake/README.md | 240 + .../android-cmake/android.toolchain.cmake | 1693 ++ .../boringssl/util/android-cmake/ndk_links.md | 211 + TMessagesProj/jni/breakpad/LICENSE | 50 + .../linux/crash_generation/client_info.h | 53 + .../crash_generation_client.cc | 105 + .../crash_generation_client.h | 65 + .../linux/dump_writer_common/mapping_info.h | 61 + .../dump_writer_common/raw_context_cpu.h | 53 + .../linux/dump_writer_common/thread_info.cc | 299 + .../linux/dump_writer_common/thread_info.h | 91 + .../dump_writer_common/ucontext_reader.cc | 253 + .../dump_writer_common/ucontext_reader.h | 64 + .../client/linux/handler/exception_handler.cc | 754 + .../client/linux/handler/exception_handler.h | 278 + .../linux/handler/minidump_descriptor.cc | 100 + .../linux/handler/minidump_descriptor.h | 161 + .../jni/breakpad/client/linux/log/log.cc | 84 + .../jni/breakpad/client/linux/log/log.h | 55 + .../microdump_writer/microdump_writer.cc | 425 + .../linux/microdump_writer/microdump_writer.h | 64 + .../client/linux/minidump_writer/cpu_set.h | 144 + .../linux/minidump_writer/directory_reader.h | 106 + .../linux/minidump_writer/line_reader.h | 131 + .../linux/minidump_writer/linux_dumper.cc | 612 + .../linux/minidump_writer/linux_dumper.h | 254 + .../minidump_writer/linux_ptrace_dumper.cc | 355 + .../minidump_writer/linux_ptrace_dumper.h | 92 + .../linux/minidump_writer/minidump_writer.cc | 1367 + .../linux/minidump_writer/minidump_writer.h | 124 + .../minidump_writer/proc_cpuinfo_reader.h | 130 + .../client/minidump_file_writer-inl.h | 97 + .../breakpad/client/minidump_file_writer.cc | 284 + .../breakpad/client/minidump_file_writer.h | 272 + .../common/android/breakpad_getcontext.S | 489 + .../jni/breakpad/common/android/include/elf.h | 168 + .../breakpad/common/android/include/link.h | 71 + .../breakpad/common/android/include/sgidefs.h | 41 + .../breakpad/common/android/include/stab.h | 100 + .../common/android/include/sys/procfs.h | 124 + .../common/android/include/sys/signal.h | 35 + .../common/android/include/sys/user.h | 75 + .../common/android/include/ucontext.h | 56 + .../common/android/ucontext_constants.h | 144 + .../jni/breakpad/common/basictypes.h | 58 + .../jni/breakpad/common/byte_cursor.h | 265 + .../jni/breakpad/common/convert_UTF.c | 554 + .../jni/breakpad/common/convert_UTF.h | 164 + .../jni/breakpad/common/linux/eintr_wrapper.h | 58 + .../breakpad/common/linux/elf_gnu_compat.h | 46 + .../jni/breakpad/common/linux/elfutils-inl.h | 74 + .../jni/breakpad/common/linux/elfutils.cc | 194 + .../jni/breakpad/common/linux/elfutils.h | 118 + .../jni/breakpad/common/linux/file_id.cc | 191 + .../jni/breakpad/common/linux/file_id.h | 78 + .../jni/breakpad/common/linux/guid_creator.cc | 104 + .../jni/breakpad/common/linux/guid_creator.h | 48 + .../jni/breakpad/common/linux/ignore_ret.h | 40 + .../common/linux/linux_libc_support.cc | 237 + .../common/linux/linux_libc_support.h | 96 + .../common/linux/memory_mapped_file.cc | 118 + .../common/linux/memory_mapped_file.h | 87 + .../breakpad/common/linux/safe_readlink.cc | 53 + .../jni/breakpad/common/linux/safe_readlink.h | 65 + TMessagesProj/jni/breakpad/common/md5.cc | 251 + TMessagesProj/jni/breakpad/common/md5.h | 27 + TMessagesProj/jni/breakpad/common/memory.h | 212 + .../jni/breakpad/common/memory_range.h | 145 + .../breakpad/common/minidump_type_helper.h | 56 + .../jni/breakpad/common/scoped_ptr.h | 404 + .../jni/breakpad/common/string_conversion.cc | 155 + .../jni/breakpad/common/string_conversion.h | 68 + .../jni/breakpad/common/symbol_data.h | 42 + TMessagesProj/jni/breakpad/common/unordered.h | 62 + .../jni/breakpad/common/using_std_string.h | 65 + .../google_breakpad/common/breakpad_types.h | 86 + .../common/minidump_cpu_amd64.h | 235 + .../google_breakpad/common/minidump_cpu_arm.h | 151 + .../common/minidump_cpu_arm64.h | 140 + .../common/minidump_cpu_mips.h | 160 + .../google_breakpad/common/minidump_cpu_ppc.h | 168 + .../common/minidump_cpu_ppc64.h | 134 + .../common/minidump_cpu_sparc.h | 163 + .../google_breakpad/common/minidump_cpu_x86.h | 174 + .../common/minidump_exception_linux.h | 87 + .../common/minidump_exception_mac.h | 205 + .../common/minidump_exception_ps3.h | 67 + .../common/minidump_exception_solaris.h | 94 + .../common/minidump_exception_win32.h | 2261 ++ .../google_breakpad/common/minidump_format.h | 972 + .../google_breakpad/common/minidump_size.h | 107 + .../processor/basic_source_line_resolver.h | 144 + .../google_breakpad/processor/call_stack.h | 77 + .../google_breakpad/processor/code_module.h | 94 + .../google_breakpad/processor/code_modules.h | 98 + .../google_breakpad/processor/dump_context.h | 116 + .../google_breakpad/processor/dump_object.h | 53 + .../processor/exploitability.h | 82 + .../processor/fast_source_line_resolver.h | 100 + .../google_breakpad/processor/memory_region.h | 79 + .../google_breakpad/processor/microdump.h | 126 + .../processor/microdump_processor.h | 63 + .../google_breakpad/processor/minidump.h | 1130 + .../processor/minidump_processor.h | 147 + .../processor/proc_maps_linux.h | 60 + .../processor/process_result.h | 66 + .../google_breakpad/processor/process_state.h | 189 + .../processor/source_line_resolver_base.h | 128 + .../source_line_resolver_interface.h | 117 + .../google_breakpad/processor/stack_frame.h | 144 + .../processor/stack_frame_cpu.h | 405 + .../processor/stack_frame_symbolizer.h | 108 + .../google_breakpad/processor/stackwalker.h | 235 + .../processor/symbol_supplier.h | 99 + .../google_breakpad/processor/system_info.h | 98 + .../third_party/lss/linux_syscall_support.h | 4029 +++ TMessagesProj/jni/ffmpeg/COPYING.GPLv2 | 339 + TMessagesProj/jni/ffmpeg/COPYING.GPLv3 | 674 + TMessagesProj/jni/ffmpeg/COPYING.LGPLv2.1 | 502 + TMessagesProj/jni/ffmpeg/COPYING.LGPLv3 | 165 + TMessagesProj/jni/ffmpeg/CREDITS | 6 + TMessagesProj/jni/ffmpeg/LICENSE.md | 114 + TMessagesProj/jni/ffmpeg/README.md | 49 + TMessagesProj/jni/ffmpeg/armv5te/libavcodec.a | Bin 0 -> 1673760 bytes .../jni/ffmpeg/armv5te/libavformat.a | Bin 0 -> 352814 bytes TMessagesProj/jni/ffmpeg/armv5te/libavutil.a | Bin 0 -> 527740 bytes TMessagesProj/jni/ffmpeg/armv7-a/libavcodec.a | Bin 0 -> 1469304 bytes .../jni/ffmpeg/armv7-a/libavformat.a | Bin 0 -> 349458 bytes TMessagesProj/jni/ffmpeg/armv7-a/libavutil.a | Bin 0 -> 519280 bytes .../jni/ffmpeg/build_ffmpeg_android.sh | 106 + TMessagesProj/jni/ffmpeg/i686/libavcodec.a | Bin 0 -> 1607390 bytes TMessagesProj/jni/ffmpeg/i686/libavformat.a | Bin 0 -> 413702 bytes TMessagesProj/jni/ffmpeg/i686/libavutil.a | Bin 0 -> 580116 bytes .../jni/ffmpeg/include/libavcodec/avcodec.h | 5418 ++++ .../jni/ffmpeg/include/libavcodec/avdct.h | 84 + .../jni/ffmpeg/include/libavcodec/avfft.h | 118 + .../jni/ffmpeg/include/libavcodec/d3d11va.h | 112 + .../jni/ffmpeg/include/libavcodec/dirac.h | 113 + .../ffmpeg/include/libavcodec/dv_profile.h | 83 + .../jni/ffmpeg/include/libavcodec/dxva2.h | 93 + .../jni/ffmpeg/include/libavcodec/qsv.h | 107 + .../jni/ffmpeg/include/libavcodec/vaapi.h | 189 + .../jni/ffmpeg/include/libavcodec/vda.h | 230 + .../jni/ffmpeg/include/libavcodec/vdpau.h | 253 + .../jni/ffmpeg/include/libavcodec/version.h | 210 + .../ffmpeg/include/libavcodec/videotoolbox.h | 126 + .../ffmpeg/include/libavcodec/vorbis_parser.h | 78 + .../jni/ffmpeg/include/libavcodec/xvmc.h | 170 + .../jni/ffmpeg/include/libavformat/avformat.h | 2806 +++ .../jni/ffmpeg/include/libavformat/avio.h | 727 + .../jni/ffmpeg/include/libavformat/version.h | 78 + .../jni/ffmpeg/include/libavutil/adler32.h | 55 + .../jni/ffmpeg/include/libavutil/aes.h | 65 + .../jni/ffmpeg/include/libavutil/aes_ctr.h | 83 + .../jni/ffmpeg/include/libavutil/attributes.h | 168 + .../jni/ffmpeg/include/libavutil/audio_fifo.h | 170 + .../jni/ffmpeg/include/libavutil/avassert.h | 66 + .../jni/ffmpeg/include/libavutil/avconfig.h | 7 + .../jni/ffmpeg/include/libavutil/avstring.h | 397 + .../jni/ffmpeg/include/libavutil/avutil.h | 343 + .../jni/ffmpeg/include/libavutil/base64.h | 67 + .../jni/ffmpeg/include/libavutil/blowfish.h | 82 + .../jni/ffmpeg/include/libavutil/bprint.h | 219 + .../jni/ffmpeg/include/libavutil/bswap.h | 109 + .../jni/ffmpeg/include/libavutil/buffer.h | 274 + .../jni/ffmpeg/include/libavutil/camellia.h | 70 + .../jni/ffmpeg/include/libavutil/cast5.h | 80 + .../ffmpeg/include/libavutil/channel_layout.h | 223 + .../jni/ffmpeg/include/libavutil/common.h | 519 + .../jni/ffmpeg/include/libavutil/cpu.h | 116 + .../jni/ffmpeg/include/libavutil/crc.h | 91 + .../jni/ffmpeg/include/libavutil/des.h | 77 + .../jni/ffmpeg/include/libavutil/dict.h | 198 + .../jni/ffmpeg/include/libavutil/display.h | 86 + .../ffmpeg/include/libavutil/downmix_info.h | 115 + .../jni/ffmpeg/include/libavutil/error.h | 126 + .../jni/ffmpeg/include/libavutil/eval.h | 113 + .../jni/ffmpeg/include/libavutil/ffversion.h | 5 + .../jni/ffmpeg/include/libavutil/fifo.h | 179 + .../jni/ffmpeg/include/libavutil/file.h | 68 + .../jni/ffmpeg/include/libavutil/frame.h | 713 + .../jni/ffmpeg/include/libavutil/hash.h | 112 + .../jni/ffmpeg/include/libavutil/hmac.h | 100 + .../jni/ffmpeg/include/libavutil/imgutils.h | 213 + .../jni/ffmpeg/include/libavutil/intfloat.h | 77 + .../ffmpeg/include/libavutil/intreadwrite.h | 629 + .../jni/ffmpeg/include/libavutil/lfg.h | 62 + .../jni/ffmpeg/include/libavutil/log.h | 359 + .../jni/ffmpeg/include/libavutil/macros.h | 48 + .../ffmpeg/include/libavutil/mathematics.h | 165 + .../jni/ffmpeg/include/libavutil/md5.h | 81 + .../jni/ffmpeg/include/libavutil/mem.h | 406 + .../ffmpeg/include/libavutil/motion_vector.h | 57 + .../jni/ffmpeg/include/libavutil/murmur3.h | 32 + .../jni/ffmpeg/include/libavutil/opt.h | 865 + .../jni/ffmpeg/include/libavutil/parseutils.h | 193 + .../jni/ffmpeg/include/libavutil/pixdesc.h | 394 + .../jni/ffmpeg/include/libavutil/pixelutils.h | 52 + .../jni/ffmpeg/include/libavutil/pixfmt.h | 469 + .../ffmpeg/include/libavutil/random_seed.h | 43 + .../jni/ffmpeg/include/libavutil/rational.h | 173 + .../jni/ffmpeg/include/libavutil/rc4.h | 66 + .../jni/ffmpeg/include/libavutil/replaygain.h | 51 + .../jni/ffmpeg/include/libavutil/ripemd.h | 75 + .../jni/ffmpeg/include/libavutil/samplefmt.h | 271 + .../jni/ffmpeg/include/libavutil/sha.h | 74 + .../jni/ffmpeg/include/libavutil/sha512.h | 75 + .../jni/ffmpeg/include/libavutil/stereo3d.h | 152 + .../jni/ffmpeg/include/libavutil/tea.h | 71 + .../ffmpeg/include/libavutil/threadmessage.h | 107 + .../jni/ffmpeg/include/libavutil/time.h | 56 + .../jni/ffmpeg/include/libavutil/timecode.h | 140 + .../jni/ffmpeg/include/libavutil/timestamp.h | 78 + .../jni/ffmpeg/include/libavutil/tree.h | 138 + .../jni/ffmpeg/include/libavutil/twofish.h | 70 + .../jni/ffmpeg/include/libavutil/version.h | 129 + .../jni/ffmpeg/include/libavutil/xtea.h | 94 + TMessagesProj/jni/gifvideo.cpp | 266 + TMessagesProj/jni/image.c | 4 +- TMessagesProj/jni/jni.c | 14 + TMessagesProj/jni/libjpeg/NOTICE | 94 + TMessagesProj/jni/libwebp/AUTHORS | 24 + TMessagesProj/jni/libwebp/COPYING | 30 + TMessagesProj/jni/libwebp/PATENTS | 23 + TMessagesProj/jni/libyuv/AUTHORS | 4 + TMessagesProj/jni/libyuv/LICENSE | 29 + TMessagesProj/jni/libyuv/LICENSE_THIRD_PARTY | 8 + TMessagesProj/jni/libyuv/PATENTS | 24 + .../jni/libyuv/include/libyuv/compare_row.h | 77 + .../jni/libyuv/include/libyuv/rotate_row.h | 116 + .../jni/libyuv/source/compare_gcc.cc | 151 + .../jni/libyuv/source/compare_neon64.cc | 64 + TMessagesProj/jni/libyuv/source/rotate_any.cc | 80 + .../jni/libyuv/source/rotate_common.cc | 92 + TMessagesProj/jni/libyuv/source/rotate_gcc.cc | 368 + TMessagesProj/jni/libyuv/source/rotate_win.cc | 247 + TMessagesProj/jni/libyuv/source/row_gcc.cc | 5452 ++++ TMessagesProj/jni/libyuv/source/scale_any.cc | 200 + TMessagesProj/jni/libyuv/source/scale_gcc.cc | 1292 + TMessagesProj/jni/opus/AUTHORS | 6 + TMessagesProj/jni/opus/COPYING | 44 + TMessagesProj/jni/sqlite_statement.c | 33 +- TMessagesProj/jni/tgnet/BuffersStorage.cpp | 123 + TMessagesProj/jni/tgnet/BuffersStorage.h | 38 + TMessagesProj/jni/tgnet/ByteArray.cpp | 71 + TMessagesProj/jni/tgnet/ByteArray.h | 31 + TMessagesProj/jni/tgnet/ByteStream.cpp | 83 + TMessagesProj/jni/tgnet/ByteStream.h | 32 + TMessagesProj/jni/tgnet/Config.cpp | 125 + TMessagesProj/jni/tgnet/Config.h | 28 + TMessagesProj/jni/tgnet/Connection.cpp | 438 + TMessagesProj/jni/tgnet/Connection.h | 85 + TMessagesProj/jni/tgnet/ConnectionSession.cpp | 99 + TMessagesProj/jni/tgnet/ConnectionSession.h | 42 + TMessagesProj/jni/tgnet/ConnectionSocket.cpp | 226 + TMessagesProj/jni/tgnet/ConnectionSocket.h | 59 + .../jni/tgnet/ConnectionsManager.cpp | 2535 ++ TMessagesProj/jni/tgnet/ConnectionsManager.h | 197 + TMessagesProj/jni/tgnet/Datacenter.cpp | 1590 ++ TMessagesProj/jni/tgnet/Datacenter.h | 129 + TMessagesProj/jni/tgnet/Defines.h | 99 + TMessagesProj/jni/tgnet/EventObject.cpp | 43 + TMessagesProj/jni/tgnet/EventObject.h | 26 + TMessagesProj/jni/tgnet/FileLog.cpp | 93 + TMessagesProj/jni/tgnet/FileLog.h | 32 + TMessagesProj/jni/tgnet/MTProtoScheme.cpp | 1421 ++ TMessagesProj/jni/tgnet/MTProtoScheme.h | 989 + TMessagesProj/jni/tgnet/NativeByteBuffer.cpp | 703 + TMessagesProj/jni/tgnet/NativeByteBuffer.h | 107 + TMessagesProj/jni/tgnet/Request.cpp | 69 + TMessagesProj/jni/tgnet/Request.h | 69 + TMessagesProj/jni/tgnet/TLObject.cpp | 38 + TMessagesProj/jni/tgnet/TLObject.h | 27 + TMessagesProj/jni/tgnet/Timer.cpp | 61 + TMessagesProj/jni/tgnet/Timer.h | 40 + TMessagesProj/src/main/AndroidManifest.xml | 31 +- .../main/assets/emoji/v7_emoji2.0x_0_0.jpg | Bin 0 -> 112914 bytes .../main/assets/emoji/v7_emoji2.0x_0_1.jpg | Bin 0 -> 68027 bytes .../main/assets/emoji/v7_emoji2.0x_0_2.jpg | Bin 0 -> 102685 bytes .../main/assets/emoji/v7_emoji2.0x_0_3.jpg | Bin 0 -> 102427 bytes .../main/assets/emoji/v7_emoji2.0x_1_0.jpg | Bin 0 -> 28648 bytes .../main/assets/emoji/v7_emoji2.0x_1_1.jpg | Bin 0 -> 26600 bytes .../main/assets/emoji/v7_emoji2.0x_1_2.jpg | Bin 0 -> 27357 bytes .../main/assets/emoji/v7_emoji2.0x_1_3.jpg | Bin 0 -> 27577 bytes .../main/assets/emoji/v7_emoji2.0x_2_0.jpg | Bin 0 -> 62835 bytes .../main/assets/emoji/v7_emoji2.0x_2_1.jpg | Bin 0 -> 69620 bytes .../main/assets/emoji/v7_emoji2.0x_2_2.jpg | Bin 0 -> 58653 bytes .../main/assets/emoji/v7_emoji2.0x_2_3.jpg | Bin 0 -> 61449 bytes .../main/assets/emoji/v7_emoji2.0x_3_0.jpg | Bin 0 -> 80460 bytes .../main/assets/emoji/v7_emoji2.0x_3_1.jpg | Bin 0 -> 70873 bytes .../main/assets/emoji/v7_emoji2.0x_3_2.jpg | Bin 0 -> 60869 bytes .../main/assets/emoji/v7_emoji2.0x_3_3.jpg | Bin 0 -> 61533 bytes .../main/assets/emoji/v7_emoji2.0x_4_0.jpg | Bin 0 -> 64468 bytes .../main/assets/emoji/v7_emoji2.0x_4_1.jpg | Bin 0 -> 56560 bytes .../main/assets/emoji/v7_emoji2.0x_4_2.jpg | Bin 0 -> 41302 bytes .../main/assets/emoji/v7_emoji2.0x_4_3.jpg | Bin 0 -> 37046 bytes .../main/assets/emoji/v7_emoji2.0x_a_0_0.jpg | Bin 0 -> 83168 bytes .../main/assets/emoji/v7_emoji2.0x_a_0_1.jpg | Bin 0 -> 74534 bytes .../main/assets/emoji/v7_emoji2.0x_a_0_2.jpg | Bin 0 -> 80016 bytes .../main/assets/emoji/v7_emoji2.0x_a_0_3.jpg | Bin 0 -> 75593 bytes .../main/assets/emoji/v7_emoji2.0x_a_1_0.jpg | Bin 0 -> 29173 bytes .../main/assets/emoji/v7_emoji2.0x_a_1_1.jpg | Bin 0 -> 32525 bytes .../main/assets/emoji/v7_emoji2.0x_a_1_2.jpg | Bin 0 -> 30574 bytes .../main/assets/emoji/v7_emoji2.0x_a_1_3.jpg | Bin 0 -> 29000 bytes .../main/assets/emoji/v7_emoji2.0x_a_2_0.jpg | Bin 0 -> 56633 bytes .../main/assets/emoji/v7_emoji2.0x_a_2_1.jpg | Bin 0 -> 65071 bytes .../main/assets/emoji/v7_emoji2.0x_a_2_2.jpg | Bin 0 -> 56586 bytes .../main/assets/emoji/v7_emoji2.0x_a_2_3.jpg | Bin 0 -> 53068 bytes .../main/assets/emoji/v7_emoji2.0x_a_3_0.jpg | Bin 0 -> 52458 bytes .../main/assets/emoji/v7_emoji2.0x_a_3_1.jpg | Bin 0 -> 47128 bytes .../main/assets/emoji/v7_emoji2.0x_a_3_2.jpg | Bin 0 -> 44861 bytes .../main/assets/emoji/v7_emoji2.0x_a_3_3.jpg | Bin 0 -> 43641 bytes .../main/assets/emoji/v7_emoji2.0x_a_4_0.jpg | Bin 0 -> 38542 bytes .../main/assets/emoji/v7_emoji2.0x_a_4_1.jpg | Bin 0 -> 39580 bytes .../main/assets/emoji/v7_emoji2.0x_a_4_2.jpg | Bin 0 -> 39260 bytes .../main/assets/emoji/v7_emoji2.0x_a_4_3.jpg | Bin 0 -> 36532 bytes .../main/assets/emoji/v7_emoji3.0x_0_0.jpg | Bin 0 -> 189637 bytes .../main/assets/emoji/v7_emoji3.0x_0_1.jpg | Bin 0 -> 114815 bytes .../main/assets/emoji/v7_emoji3.0x_0_2.jpg | Bin 0 -> 174128 bytes .../main/assets/emoji/v7_emoji3.0x_0_3.jpg | Bin 0 -> 178441 bytes .../main/assets/emoji/v7_emoji3.0x_1_0.jpg | Bin 0 -> 48231 bytes .../main/assets/emoji/v7_emoji3.0x_1_1.jpg | Bin 0 -> 46975 bytes .../main/assets/emoji/v7_emoji3.0x_1_2.jpg | Bin 0 -> 47358 bytes .../main/assets/emoji/v7_emoji3.0x_1_3.jpg | Bin 0 -> 46852 bytes .../main/assets/emoji/v7_emoji3.0x_2_0.jpg | Bin 0 -> 108916 bytes .../main/assets/emoji/v7_emoji3.0x_2_1.jpg | Bin 0 -> 123185 bytes .../main/assets/emoji/v7_emoji3.0x_2_2.jpg | Bin 0 -> 101227 bytes .../main/assets/emoji/v7_emoji3.0x_2_3.jpg | Bin 0 -> 110050 bytes .../main/assets/emoji/v7_emoji3.0x_3_0.jpg | Bin 0 -> 151582 bytes .../main/assets/emoji/v7_emoji3.0x_3_1.jpg | Bin 0 -> 127847 bytes .../main/assets/emoji/v7_emoji3.0x_3_2.jpg | Bin 0 -> 106519 bytes .../main/assets/emoji/v7_emoji3.0x_3_3.jpg | Bin 0 -> 106513 bytes .../main/assets/emoji/v7_emoji3.0x_4_0.jpg | Bin 0 -> 116990 bytes .../main/assets/emoji/v7_emoji3.0x_4_1.jpg | Bin 0 -> 100560 bytes .../main/assets/emoji/v7_emoji3.0x_4_2.jpg | Bin 0 -> 73844 bytes .../main/assets/emoji/v7_emoji3.0x_4_3.jpg | Bin 0 -> 66231 bytes .../main/assets/emoji/v7_emoji3.0x_a_0_0.jpg | Bin 0 -> 131152 bytes .../main/assets/emoji/v7_emoji3.0x_a_0_1.jpg | Bin 0 -> 117943 bytes .../main/assets/emoji/v7_emoji3.0x_a_0_2.jpg | Bin 0 -> 122130 bytes .../main/assets/emoji/v7_emoji3.0x_a_0_3.jpg | Bin 0 -> 118628 bytes .../main/assets/emoji/v7_emoji3.0x_a_1_0.jpg | Bin 0 -> 44042 bytes .../main/assets/emoji/v7_emoji3.0x_a_1_1.jpg | Bin 0 -> 51143 bytes .../main/assets/emoji/v7_emoji3.0x_a_1_2.jpg | Bin 0 -> 48368 bytes .../main/assets/emoji/v7_emoji3.0x_a_1_3.jpg | Bin 0 -> 44490 bytes .../main/assets/emoji/v7_emoji3.0x_a_2_0.jpg | Bin 0 -> 88915 bytes .../main/assets/emoji/v7_emoji3.0x_a_2_1.jpg | Bin 0 -> 106914 bytes .../main/assets/emoji/v7_emoji3.0x_a_2_2.jpg | Bin 0 -> 88625 bytes .../main/assets/emoji/v7_emoji3.0x_a_2_3.jpg | Bin 0 -> 83013 bytes .../main/assets/emoji/v7_emoji3.0x_a_3_0.jpg | Bin 0 -> 81496 bytes .../main/assets/emoji/v7_emoji3.0x_a_3_1.jpg | Bin 0 -> 72920 bytes .../main/assets/emoji/v7_emoji3.0x_a_3_2.jpg | Bin 0 -> 67638 bytes .../main/assets/emoji/v7_emoji3.0x_a_3_3.jpg | Bin 0 -> 65533 bytes .../main/assets/emoji/v7_emoji3.0x_a_4_0.jpg | Bin 0 -> 64679 bytes .../main/assets/emoji/v7_emoji3.0x_a_4_1.jpg | Bin 0 -> 65329 bytes .../main/assets/emoji/v7_emoji3.0x_a_4_2.jpg | Bin 0 -> 65473 bytes .../main/assets/emoji/v7_emoji3.0x_a_4_3.jpg | Bin 0 -> 58620 bytes .../src/main/assets/fonts/ritalic.ttf | Bin 0 -> 161484 bytes .../org/telegram/SQLite/DatabaseHandler.java | 121 + .../org/telegram/SQLite/SQLiteDatabase.java | 1 - .../telegram/messenger/AndroidUtilities.java | 1550 ++ .../messenger/Animation/Animator10.java | 191 + .../Animation/AnimatorListenerAdapter10.java | 50 + .../messenger/Animation/AnimatorSet10.java | 705 + .../messenger/Animation/FloatEvaluator.java | 24 + .../messenger/Animation/FloatKeyframeSet.java | 114 + .../messenger/Animation/FloatProperty10.java | 30 + .../messenger/Animation/IntEvaluator.java | 24 + .../messenger/Animation/IntKeyframeSet.java | 114 + .../messenger/Animation/IntProperty.java | 30 + .../messenger/Animation/Keyframe.java | 187 + .../messenger/Animation/KeyframeSet.java | 200 + .../Animation/NoSuchPropertyException.java | 24 + .../messenger/Animation/ObjectAnimator10.java | 488 + .../messenger/Animation/Property.java | 49 + .../Animation/PropertyValuesHolder.java | 545 + .../Animation/ReflectiveProperty.java | 182 + .../messenger/Animation/TypeEvaluator.java | 21 + .../messenger/Animation/ValueAnimator.java | 675 + .../telegram/messenger/Animation/View10.java | 349 + .../AnimatorListenerAdapterProxy.java | 112 + .../AnimationCompat/AnimatorSetProxy.java | 137 + .../AnimationCompat/ObjectAnimatorProxy.java | 130 + .../messenger/AnimationCompat/ViewProxy.java | 248 + .../telegram/messenger/AppStartReceiver.java | 24 + .../telegram/messenger/ApplicationLoader.java | 111 +- .../messenger/AuthenticatorService.java | 97 + .../messenger/AutoMessageHeardReceiver.java | 27 + .../messenger/AutoMessageReplyReceiver.java | 38 + .../java/org/telegram/messenger/Bitmaps.java | 257 + .../org/telegram/messenger/CallReceiver.java | 34 + .../org/telegram/messenger/ChatObject.java | 59 + .../telegram/messenger/ClearCacheService.java | 82 + .../messenger/ContactsController.java | 1966 ++ .../messenger/ContactsSyncAdapterService.java | 63 + .../telegram/messenger/DownloadObject.java | 17 + .../java/org/telegram/messenger/Emoji.java | 510 + .../org/telegram/messenger/EmojiData.java | 348 + .../telegram/messenger/FileLoadOperation.java | 112 +- .../org/telegram/messenger/FileLoader.java | 250 +- .../java/org/telegram/messenger/FileLog.java | 12 +- .../GcmInstanceIDListenerService.java | 28 + .../messenger/GcmPushListenerService.java | 54 + .../GcmRegistrationIntentService.java | 75 + .../org/telegram/messenger/ImageLoader.java | 2375 ++ .../org/telegram/messenger/ImageReceiver.java | 1069 + .../telegram/messenger/LocaleController.java | 1844 ++ .../java/org/telegram/messenger/LruCache.java | 253 + .../telegram/messenger/MediaController.java | 3882 +++ .../org/telegram/messenger/MessageObject.java | 1769 ++ .../messenger/MessagesController.java | 7173 ++++++ .../telegram/messenger/MessagesStorage.java | 5866 +++++ .../messenger/ModuleContentProvider.java | 125 + .../messenger/MusicPlayerReceiver.java | 69 + .../messenger/MusicPlayerService.java | 237 + .../messenger/NativeCrashManager.java | 123 + .../org/telegram/messenger/NativeLoader.java | 224 + .../messenger/NotificationCenter.java | 273 + .../messenger/NotificationRepeat.java | 29 + .../messenger/NotificationsController.java | 1835 ++ .../messenger/NotificationsService.java | 43 + .../telegram/messenger/ScreenReceiver.java | 32 + .../telegram/messenger/SecretChatHelper.java | 1904 ++ .../messenger/SendMessagesHelper.java | 3486 +++ .../messenger/ShareBroadcastReceiver.java | 29 + .../org/telegram/messenger/SmsListener.java | 67 + .../messenger/TgChooserTargetService.java | 184 + .../org/telegram/messenger/UserConfig.java | 8 +- .../org/telegram/messenger/UserObject.java | 111 + .../org/telegram/messenger/Utilities.java | 23 +- .../telegram/messenger/VideoEditedInfo.java | 51 + .../messenger/VideoEncodingService.java | 80 + .../telegram/messenger/WearReplyReceiver.java | 38 + .../messenger/audioinfo/AudioInfo.java | 154 + .../messenger/audioinfo/m4a/M4AInfo.java | 325 + .../messenger/audioinfo/m4a/MP4Atom.java | 151 + .../messenger/audioinfo/m4a/MP4Box.java | 87 + .../messenger/audioinfo/m4a/MP4Input.java | 41 + .../messenger/audioinfo/mp3/ID3v1Genre.java | 171 + .../messenger/audioinfo/mp3/ID3v1Info.java | 86 + .../audioinfo/mp3/ID3v2DataInput.java | 74 + .../audioinfo/mp3/ID3v2Encoding.java | 41 + .../audioinfo/mp3/ID3v2Exception.java | 24 + .../audioinfo/mp3/ID3v2FrameBody.java | 155 + .../audioinfo/mp3/ID3v2FrameHeader.java | 165 + .../messenger/audioinfo/mp3/ID3v2Info.java | 376 + .../messenger/audioinfo/mp3/ID3v2TagBody.java | 81 + .../audioinfo/mp3/ID3v2TagHeader.java | 191 + .../messenger/audioinfo/mp3/MP3Exception.java | 24 + .../messenger/audioinfo/mp3/MP3Frame.java | 315 + .../messenger/audioinfo/mp3/MP3Info.java | 270 + .../messenger/audioinfo/mp3/MP3Input.java | 60 + .../audioinfo/util/PositionInputStream.java | 79 + .../audioinfo/util/RangeInputStream.java | 63 + .../telegram/messenger/browser/Browser.java | 199 + .../telegram/messenger/query/BotQuery.java | 205 + .../messenger/query/MessagesQuery.java | 440 + .../messenger/query/MessagesSearchQuery.java | 160 + .../messenger/query/SharedMediaQuery.java | 508 + .../messenger/query/StickersQuery.java | 512 + .../customtabs/CustomTabsCallback.java | 40 + .../support/customtabs/CustomTabsClient.java | 87 + .../support/customtabs/CustomTabsIntent.java | 206 + .../support/customtabs/CustomTabsService.java | 105 + .../CustomTabsServiceConnection.java | 33 + .../support/customtabs/CustomTabsSession.java | 79 + .../customtabs/CustomTabsSessionToken.java | 75 + .../customtabs/ICustomTabsCallback.java | 142 + .../customtabs/ICustomTabsService.java | 291 + .../shared/CustomTabsHelper.java | 142 + .../shared/KeepAliveService.java | 29 + .../shared/ServiceConnection.java | 42 + .../shared/ServiceConnectionCallback.java | 33 + .../messenger/support/util/AsyncListUtil.java | 592 + .../support/util/MessageThreadUtil.java | 281 + .../messenger/support/util/SortedList.java | 891 + .../messenger/support/util/ThreadUtil.java | 45 + .../messenger/support/util/TileList.java | 105 + .../support/widget/AdapterHelper.java | 768 + .../messenger/support/widget/ChildHelper.java | 537 + .../support/widget/DefaultItemAnimator.java | 668 + .../support/widget/GridLayoutManager.java | 1134 + .../messenger/support/widget/LayoutState.java | 116 + .../support/widget/LinearLayoutManager.java | 2242 ++ .../support/widget/LinearSmoothScroller.java | 339 + .../messenger/support/widget/OpReorderer.java | 238 + .../support/widget/OrientationHelper.java | 380 + .../messenger/support/widget/PositionMap.java | 460 + .../support/widget/RecyclerView.java | 11099 ++++++++ .../RecyclerViewAccessibilityDelegate.java | 101 + .../support/widget/ScrollbarHelper.java | 98 + .../support/widget/SimpleItemAnimator.java | 442 + .../widget/StaggeredGridLayoutManager.java | 3040 +++ .../support/widget/ViewInfoStore.java | 330 + .../widget/helper/ItemTouchHelper.java | 2406 ++ .../widget/helper/ItemTouchUIUtil.java | 64 + .../widget/helper/ItemTouchUIUtilImpl.java | 137 + .../util/SortedListAdapterCallback.java | 59 + .../telegram/messenger/time/DateParser.java | 107 + .../telegram/messenger/time/DatePrinter.java | 126 + .../messenger/time/FastDateFormat.java | 613 + .../messenger/time/FastDateParser.java | 873 + .../messenger/time/FastDatePrinter.java | 1278 + .../telegram/messenger/time/FormatCache.java | 265 + .../messenger/video/InputSurface.java | 134 + .../telegram/messenger/video/MP4Builder.java | 445 + .../telegram/messenger/video/Mp4Movie.java | 81 + .../messenger/video/OutputSurface.java | 207 + .../org/telegram/messenger/video/Sample.java | 27 + .../messenger/video/TextureRenderer.java | 213 + .../org/telegram/messenger/video/Track.java | 264 + .../messenger/volley/AuthFailureError.java | 58 + .../org/telegram/messenger/volley/Cache.java | 100 + .../messenger/volley/CacheDispatcher.java | 158 + .../messenger/volley/DefaultRetryPolicy.java | 105 + .../messenger/volley/ExecutorDelivery.java | 118 + .../telegram/messenger/volley/Network.java | 30 + .../messenger/volley/NetworkDispatcher.java | 152 + .../messenger/volley/NetworkError.java | 35 + .../messenger/volley/NetworkResponse.java | 73 + .../messenger/volley/NoConnectionError.java | 31 + .../telegram/messenger/volley/ParseError.java | 33 + .../telegram/messenger/volley/Request.java | 589 + .../messenger/volley/RequestQueue.java | 317 + .../telegram/messenger/volley/Response.java | 85 + .../messenger/volley/ResponseDelivery.java | 35 + .../messenger/volley/RetryPolicy.java | 41 + .../messenger/volley/ServerError.java | 32 + .../messenger/volley/TimeoutError.java | 23 + .../messenger/volley/VolleyError.java | 57 + .../telegram/messenger/volley/VolleyLog.java | 181 + .../volley/toolbox/AndroidAuthenticator.java | 107 + .../volley/toolbox/Authenticator.java | 36 + .../volley/toolbox/BasicNetwork.java | 266 + .../volley/toolbox/ByteArrayPool.java | 135 + .../volley/toolbox/ClearCacheRequest.java | 70 + .../volley/toolbox/DiskBasedCache.java | 571 + .../volley/toolbox/HttpClientStack.java | 194 + .../volley/toolbox/HttpHeaderParser.java | 168 + .../messenger/volley/toolbox/HttpStack.java | 45 + .../messenger/volley/toolbox/HurlStack.java | 262 + .../volley/toolbox/JsonArrayRequest.java | 73 + .../volley/toolbox/JsonObjectRequest.java | 76 + .../messenger/volley/toolbox/JsonRequest.java | 102 + .../messenger/volley/toolbox/NoCache.java | 49 + .../toolbox/PoolingByteArrayOutputStream.java | 93 + .../volley/toolbox/RequestFuture.java | 153 + .../volley/toolbox/StringRequest.java | 73 + .../messenger/volley/toolbox/Volley.java | 80 + .../tgnet/AbstractSerializedData.java | 52 + .../telegram/tgnet/ConnectionsManager.java | 525 + .../org/telegram/tgnet/NativeByteBuffer.java | 506 + .../org/telegram/tgnet/QuickAckDelegate.java | 5 + .../org/telegram/tgnet/RequestDelegate.java | 5 + .../tgnet/RequestDelegateInternal.java | 5 + .../org/telegram/tgnet/SerializedData.java | 477 + .../java/org/telegram/tgnet/TLClassStore.java | 67 + .../java/org/telegram/tgnet/TLObject.java | 47 + .../main/java/org/telegram/tgnet/TLRPC.java | 20993 ++++++++++++++++ .../org/telegram/ui/ActionBar/ActionBar.java | 124 +- .../ui/ActionBar/ActionBarLayout.java | 92 +- .../telegram/ui/ActionBar/ActionBarMenu.java | 23 +- .../ui/ActionBar/ActionBarMenuItem.java | 11 +- .../telegram/ui/ActionBar/BackDrawable.java | 136 + .../telegram/ui/ActionBar/BaseFragment.java | 28 +- .../telegram/ui/ActionBar/BottomSheet.java | 867 + .../ui/ActionBar/DrawerLayoutContainer.java | 55 +- .../telegram/ui/ActionBar/SimpleTextView.java | 281 + .../java/org/telegram/ui/ActionBar/Theme.java | 579 + .../Adapters/BaseSearchAdapterRecycler.java | 218 + .../ui/Adapters/ChatActivityAdapter.java | 2 +- .../telegram/ui/Adapters/ContactsAdapter.java | 2 +- .../telegram/ui/Adapters/DialogsAdapter.java | 43 +- .../ui/Adapters/DialogsSearchAdapter.java | 5 +- .../ui/Adapters/DrawerLayoutAdapter.java | 18 +- .../telegram/ui/Adapters/MentionsAdapter.java | 231 +- .../telegram/ui/Adapters/SearchAdapter.java | 2 +- .../org/telegram/ui/AudioPlayerActivity.java | 484 + .../org/telegram/ui/AudioSelectActivity.java | 346 + .../org/telegram/ui/BlockedUsersActivity.java | 12 +- .../org/telegram/ui/CacheControlActivity.java | 681 + .../org/telegram/ui/Cells/AboutLinkCell.java | 216 + .../java/org/telegram/ui/Cells/AudioCell.java | 169 + .../java/org/telegram/ui/Cells/BaseCell.java | 8 +- .../org/telegram/ui/Cells/BotHelpCell.java | 222 + .../org/telegram/ui/Cells/BotSwitchCell.java | 62 + .../org/telegram/ui/Cells/ChatActionCell.java | 210 +- .../org/telegram/ui/Cells/ChatAudioCell.java | 422 - .../org/telegram/ui/Cells/ChatBaseCell.java | 863 +- .../telegram/ui/Cells/ChatContactCell.java | 335 - .../telegram/ui/Cells/ChatLoadingCell.java | 52 + .../org/telegram/ui/Cells/ChatMediaCell.java | 1429 -- .../telegram/ui/Cells/ChatMessageCell.java | 3943 ++- .../org/telegram/ui/Cells/ChatUnreadCell.java | 68 + .../org/telegram/ui/Cells/CheckBoxCell.java | 103 + .../telegram/ui/Cells/ContextLinkCell.java | 641 + .../org/telegram/ui/Cells/DialogCell.java | 68 +- .../telegram/ui/Cells/DrawerProfileCell.java | 15 +- .../org/telegram/ui/Cells/MentionCell.java | 15 + .../ui/Cells/PhotoAttachCameraCell.java | 34 + .../ui/Cells/PhotoAttachPhotoCell.java | 145 + .../ui/Cells/PhotoPickerPhotoCell.java | 11 +- .../ui/Cells/PhotoPickerSearchCell.java | 14 +- .../telegram/ui/Cells/ProfileSearchCell.java | 5 +- .../telegram/ui/Cells/RadioButtonCell.java | 90 + .../java/org/telegram/ui/Cells/RadioCell.java | 103 + .../telegram/ui/Cells/SendLocationCell.java | 2 +- .../telegram/ui/Cells/ShadowSectionCell.java | 11 +- .../telegram/ui/Cells/ShareDialogCell.java | 118 + .../telegram/ui/Cells/SharedDocumentCell.java | 48 +- .../org/telegram/ui/Cells/SharedLinkCell.java | 494 + .../ui/Cells/SharedPhotoVideoCell.java | 24 +- .../org/telegram/ui/Cells/StickerCell.java | 56 +- .../telegram/ui/Cells/StickerEmojiCell.java | 5 +- .../org/telegram/ui/Cells/StickerSetCell.java | 160 + .../org/telegram/ui/Cells/TextBlockCell.java | 2 +- .../java/org/telegram/ui/Cells/TextCell.java | 62 +- .../org/telegram/ui/Cells/TextCheckCell.java | 62 +- .../ui/Cells/TextDetailSettingsCell.java | 18 + .../telegram/ui/Cells/TextSettingsCell.java | 4 + .../java/org/telegram/ui/Cells/UserCell.java | 32 +- .../org/telegram/ui/Cells/WallpaperCell.java | 85 + .../org/telegram/ui/ChangeAboutActivity.java | 206 + .../org/telegram/ui/ChangeNameActivity.java | 22 +- .../org/telegram/ui/ChangePhoneActivity.java | 608 +- .../telegram/ui/ChannelCreateActivity.java | 1235 + .../org/telegram/ui/ChannelEditActivity.java | 656 + .../telegram/ui/ChannelEditTypeActivity.java | 544 + .../org/telegram/ui/ChannelIntroActivity.java | 150 + .../org/telegram/ui/ChannelUsersActivity.java | 747 + .../java/org/telegram/ui/ChatActivity.java | 4213 ++-- .../telegram/ui/Components/AlertsCreator.java | 224 + .../ui/Components/AnimatedFileDrawable.java | 348 + .../ui/Components/AvatarDrawable.java | 16 +- .../ui/Components/BotKeyboardView.java | 132 + .../ui/Components/ChatActivityEnterView.java | 1031 +- .../ui/Components/ChatAttachView.java | 647 + .../ui/Components/ChatAvatarContainer.java | 386 + .../ui/Components/CheckBoxSquare.java | 183 + .../org/telegram/ui/Components/ChipSpan.java | 41 + .../ui/Components/ClippingImageView.java | 32 +- .../ui/Components/CloseProgressDrawable.java | 91 + .../ui/Components/CloseProgressDrawable2.java | 143 + .../ui/Components/ContextProgressView.java | 69 + .../org/telegram/ui/Components/EmojiView.java | 298 +- .../ui/Components/EmptyTextProgressView.java | 108 + .../org/telegram/ui/Components/Favourite.java | 63 + .../ui/Components/FlowLayoutManager.java | 529 + .../ui/Components/FrameLayoutFixed.java | 2 + .../java/org/telegram/ui/Components/Glow.java | 316 + .../telegram/ui/Components/HintEditText.java | 73 + .../ui/Components/IdenticonDrawable.java | 43 +- .../ui/Components/LetterDrawable.java | 109 + .../org/telegram/ui/Components/LinkPath.java | 51 + .../ui/Components/NumberTextView.java | 167 + .../telegram/ui/Components/PhotoCropView.java | 156 +- .../ui/Components/PhotoFilterBlurControl.java | 2 +- .../Components/PhotoFilterCurvesControl.java | 322 + .../ui/Components/PhotoFilterView.java | 1337 +- .../PhotoViewerCaptionEnterView.java | 146 +- .../ui/Components/PickerBottomLayout.java | 100 + .../telegram/ui/Components/PlayerView.java | 310 + .../ui/Components/PopupAudioView.java | 59 +- .../ui/Components/RadialProgress.java | 66 +- .../telegram/ui/Components/RadioButton.java | 190 + .../ui/Components/RecordStatusDrawable.java | 3 +- .../java/org/telegram/ui/Components/Rect.java | 5 + .../ui/Components/ResourceLoader.java | 257 - .../ui/Components/ScrollSlidingTabStrip.java | 241 + .../org/telegram/ui/Components/SeekBar.java | 77 +- .../ui/Components/SeekBarPreference.java | 3 +- .../ui/Components/SeekBarWaveform.java | 195 + .../ui/Components/SendingFileDrawable.java | 3 +- .../ui/Components/SendingFileEx2Drawable.java | 3 +- .../ui/Components/SendingFileExDrawable.java | 3 +- .../telegram/ui/Components/ShareAlert.java | 928 + .../ui/Components/SimpleTextView.java | 126 - .../Components/SizeNotifierFrameLayout.java | 126 + .../SizeNotifierFrameLayoutPhoto.java | 72 + .../ui/Components/SlidingTabView.java | 4 +- .../ui/Components/SpannableStringLight.java | 88 + .../telegram/ui/Components/StickersAlert.java | 615 + .../org/telegram/ui/Components/Switch.java | 1 + .../ui/Components/TypingDotsDrawable.java | 9 +- .../ui/Components/URLSpanBotCommand.java | 37 + .../ui/Components/URLSpanNoUnderlineBold.java | 26 + .../ui/Components/URLSpanReplacement.java | 18 + .../ui/Components/WebFrameLayout.java | 390 + .../org/telegram/ui/ContactAddActivity.java | 2 + .../org/telegram/ui/ContactsActivity.java | 13 + .../org/telegram/ui/ConvertGroupActivity.java | 216 + .../java/org/telegram/ui/DialogsActivity.java | 2964 +++ .../telegram/ui/DocumentSelectActivity.java | 17 +- .../org/telegram/ui/GroupCreateActivity.java | 39 +- .../telegram/ui/GroupCreateFinalActivity.java | 8 +- .../org/telegram/ui/GroupInviteActivity.java | 13 +- .../org/telegram/ui/IdenticonActivity.java | 100 +- .../org/telegram/ui/ImageListActivity.java | 171 +- .../java/org/telegram/ui/IntroActivity.java | 6 +- .../telegram/ui/LanguageSelectActivity.java | 1 - .../java/org/telegram/ui/LaunchActivity.java | 343 +- .../org/telegram/ui/LocationActivity.java | 44 +- .../java/org/telegram/ui/LoginActivity.java | 538 +- .../org/telegram/ui/ManageSpaceActivity.java | 382 + .../java/org/telegram/ui/MediaActivity.java | 138 +- .../ui/NotificationsSettingsActivity.java | 54 +- .../org/telegram/ui/PasscodeActivity.java | 5 +- .../telegram/ui/PhotoAlbumPickerActivity.java | 7 +- .../org/telegram/ui/PhotoCropActivity.java | 16 +- .../org/telegram/ui/PhotoPickerActivity.java | 7 +- .../java/org/telegram/ui/PhotoViewer.java | 272 +- .../org/telegram/ui/PlusSettingsActivity.java | 1356 + .../ui/PopupNotificationActivity.java | 14 +- ...ivity.java => PrivacyControlActivity.java} | 219 +- .../telegram/ui/PrivacySettingsActivity.java | 112 +- ...ctivity.java => PrivacyUsersActivity.java} | 53 +- .../java/org/telegram/ui/ProfileActivity.java | 1155 +- .../ui/ProfileNotificationsActivity.java | 15 +- .../org/telegram/ui/ReportOtherActivity.java | 151 + .../org/telegram/ui/SecretPhotoViewer.java | 3 + .../org/telegram/ui/SetAdminsActivity.java | 675 + .../org/telegram/ui/SettingsActivity.java | 251 +- .../org/telegram/ui/ShortcutActivity.java | 33 + .../org/telegram/ui/StickerPreviewViewer.java | 430 + .../org/telegram/ui/StickersActivity.java | 410 + .../java/org/telegram/ui/ThemingActivity.java | 13 +- .../org/telegram/ui/ThemingChatActivity.java | 58 +- .../org/telegram/ui/ThemingChatsActivity.java | 155 +- .../telegram/ui/ThemingContactsActivity.java | 9 +- .../telegram/ui/ThemingDrawerActivity.java | 9 +- .../telegram/ui/ThemingProfileActivity.java | 9 +- .../telegram/ui/ThemingSettingsActivity.java | 588 + .../ui/TwoStepVerificationActivity.java | 4 +- .../org/telegram/ui/VideoEditorActivity.java | 13 +- .../org/telegram/ui/WallpapersActivity.java | 50 +- .../src/main/res/anim/no_animation.xml | 3 + .../abc_ic_menu_share_mtrl_alpha.png | Bin 0 -> 406 bytes .../res/drawable-hdpi/addcontact_blue.png | Bin 966 -> 0 bytes .../src/main/res/drawable-hdpi/admin_star.png | Bin 0 -> 1268 bytes .../main/res/drawable-hdpi/admin_star2.png | Bin 0 -> 1288 bytes .../main/res/drawable-hdpi/assign_manager.png | Bin 0 -> 1344 bytes .../main/res/drawable-hdpi/attach_audio.png | Bin 0 -> 3054 bytes .../drawable-hdpi/attach_audio_pressed.png | Bin 0 -> 3041 bytes .../main/res/drawable-hdpi/attach_camera.png | Bin 0 -> 5454 bytes .../drawable-hdpi/attach_camera_pressed.png | Bin 0 -> 5560 bytes .../main/res/drawable-hdpi/attach_contact.png | Bin 0 -> 2861 bytes .../drawable-hdpi/attach_contact_pressed.png | Bin 0 -> 2859 bytes .../main/res/drawable-hdpi/attach_file.png | Bin 0 -> 2685 bytes .../res/drawable-hdpi/attach_file_pressed.png | Bin 0 -> 2687 bytes .../main/res/drawable-hdpi/attach_gallery.png | Bin 0 -> 2726 bytes .../drawable-hdpi/attach_gallery_pressed.png | Bin 0 -> 2718 bytes .../main/res/drawable-hdpi/attach_hide1.png | Bin 0 -> 2270 bytes .../drawable-hdpi/attach_hide1_pressed.png | Bin 0 -> 2275 bytes .../main/res/drawable-hdpi/attach_hide2.png | Bin 0 -> 1124 bytes .../res/drawable-hdpi/attach_location.png | Bin 0 -> 3111 bytes .../drawable-hdpi/attach_location_pressed.png | Bin 0 -> 3117 bytes .../main/res/drawable-hdpi/attach_send1.png | Bin 0 -> 2285 bytes .../drawable-hdpi/attach_send1_pressed.png | Bin 0 -> 2261 bytes .../main/res/drawable-hdpi/attach_send2.png | Bin 0 -> 1545 bytes .../main/res/drawable-hdpi/attach_video.png | Bin 0 -> 2360 bytes .../drawable-hdpi/attach_video_pressed.png | Bin 0 -> 2754 bytes .../res/drawable-hdpi/audiosend_pause.png | Bin 0 -> 2055 bytes .../main/res/drawable-hdpi/audiosend_play.png | Bin 0 -> 2604 bytes .../src/main/res/drawable-hdpi/blockpanel.png | Bin 0 -> 954 bytes .../main/res/drawable-hdpi/bluecounter.9.png | Bin 0 -> 489 bytes .../src/main/res/drawable-hdpi/bot_file.png | Bin 0 -> 1114 bytes .../src/main/res/drawable-hdpi/bot_info.png | Bin 0 -> 1674 bytes .../main/res/drawable-hdpi/bot_keyboard.png | Bin 0 -> 2441 bytes .../main/res/drawable-hdpi/bot_keyboard2.png | Bin 0 -> 1474 bytes .../drawable-hdpi/bot_keyboard_button.9.png | Bin 0 -> 198 bytes .../bot_keyboard_button_pressed.9.png | Bin 0 -> 201 bytes .../src/main/res/drawable-hdpi/bot_lines.png | Bin 0 -> 1110 bytes .../src/main/res/drawable-hdpi/bot_link.png | Bin 0 -> 1034 bytes .../src/main/res/drawable-hdpi/bot_list.png | Bin 0 -> 1300 bytes .../main/res/drawable-hdpi/bot_location.png | Bin 0 -> 1586 bytes .../src/main/res/drawable-hdpi/bot_music.png | Bin 0 -> 1573 bytes .../src/main/res/drawable-hdpi/cancel_b.png | Bin 2095 -> 0 bytes .../res/drawable-hdpi/cancel_b_pressed.png | Bin 2095 -> 0 bytes .../src/main/res/drawable-hdpi/cancel_g.png | Bin 2092 -> 0 bytes .../res/drawable-hdpi/cancel_g_pressed.png | Bin 2134 -> 0 bytes .../main/res/drawable-hdpi/channelintro.png | Bin 0 -> 30414 bytes .../src/main/res/drawable-hdpi/check_list.png | Bin 0 -> 689 bytes .../main/res/drawable-hdpi/check_profile.png | Bin 0 -> 600 bytes .../main/res/drawable-hdpi/contact_blue.png | Bin 0 -> 2296 bytes .../main/res/drawable-hdpi/contact_green.png | Bin 0 -> 2339 bytes .../main/res/drawable-hdpi/corner_in_bl.png | Bin 0 -> 962 bytes .../main/res/drawable-hdpi/corner_in_br.png | Bin 0 -> 959 bytes .../main/res/drawable-hdpi/corner_in_tl.png | Bin 0 -> 971 bytes .../main/res/drawable-hdpi/corner_in_tr.png | Bin 0 -> 962 bytes .../main/res/drawable-hdpi/corner_out_bl.png | Bin 0 -> 987 bytes .../main/res/drawable-hdpi/corner_out_br.png | Bin 0 -> 986 bytes .../main/res/drawable-hdpi/corner_out_tl.png | Bin 0 -> 993 bytes .../main/res/drawable-hdpi/corner_out_tr.png | Bin 0 -> 983 bytes .../res/drawable-hdpi/dialogs_badge2.9.png | Bin 0 -> 1419 bytes .../res/drawable-hdpi/dialogs_check_10.png | Bin 0 -> 444 bytes .../res/drawable-hdpi/dialogs_check_11.png | Bin 0 -> 469 bytes .../res/drawable-hdpi/dialogs_check_12.png | Bin 0 -> 340 bytes .../res/drawable-hdpi/dialogs_check_2.png | Bin 0 -> 618 bytes .../res/drawable-hdpi/dialogs_check_3.png | Bin 0 -> 555 bytes .../res/drawable-hdpi/dialogs_check_4.png | Bin 0 -> 1055 bytes .../res/drawable-hdpi/dialogs_check_5.png | Bin 0 -> 427 bytes .../res/drawable-hdpi/dialogs_check_6.png | Bin 0 -> 340 bytes .../res/drawable-hdpi/dialogs_check_7.png | Bin 0 -> 238 bytes .../res/drawable-hdpi/dialogs_check_8.png | Bin 0 -> 697 bytes .../res/drawable-hdpi/dialogs_check_9.png | Bin 0 -> 531 bytes .../drawable-hdpi/dialogs_halfcheck_10.png | Bin 0 -> 697 bytes .../drawable-hdpi/dialogs_halfcheck_11.png | Bin 0 -> 374 bytes .../drawable-hdpi/dialogs_halfcheck_12.png | Bin 0 -> 332 bytes .../res/drawable-hdpi/dialogs_halfcheck_2.png | Bin 0 -> 618 bytes .../res/drawable-hdpi/dialogs_halfcheck_3.png | Bin 0 -> 555 bytes .../res/drawable-hdpi/dialogs_halfcheck_4.png | Bin 0 -> 862 bytes .../res/drawable-hdpi/dialogs_halfcheck_5.png | Bin 0 -> 401 bytes .../res/drawable-hdpi/dialogs_halfcheck_6.png | Bin 0 -> 340 bytes .../res/drawable-hdpi/dialogs_halfcheck_7.png | Bin 0 -> 238 bytes .../res/drawable-hdpi/dialogs_halfcheck_8.png | Bin 0 -> 697 bytes .../res/drawable-hdpi/dialogs_halfcheck_9.png | Bin 0 -> 572 bytes .../res/drawable-hdpi/doc_actions_b_s.png | Bin 0 -> 1049 bytes .../src/main/res/drawable-hdpi/doc_blue_s.png | Bin 0 -> 1432 bytes .../main/res/drawable-hdpi/doccancel_b_s.png | Bin 0 -> 1644 bytes .../main/res/drawable-hdpi/docload_b_s.png | Bin 0 -> 2766 bytes .../main/res/drawable-hdpi/docpause_b_s.png | Bin 0 -> 1058 bytes .../src/main/res/drawable-hdpi/download_b.png | Bin 2031 -> 0 bytes .../res/drawable-hdpi/download_b_pressed.png | Bin 2041 -> 0 bytes .../src/main/res/drawable-hdpi/download_g.png | Bin 2053 -> 0 bytes .../res/drawable-hdpi/download_g_pressed.png | Bin 2054 -> 0 bytes .../src/main/res/drawable-hdpi/file_b.png | Bin 0 -> 2112 bytes .../main/res/drawable-hdpi/file_b_cancel.png | Bin 0 -> 2253 bytes .../res/drawable-hdpi/file_b_cancel_s.png | Bin 0 -> 2256 bytes .../main/res/drawable-hdpi/file_b_load.png | Bin 0 -> 2117 bytes .../main/res/drawable-hdpi/file_b_load_s.png | Bin 0 -> 2119 bytes .../src/main/res/drawable-hdpi/file_b_s.png | Bin 0 -> 2124 bytes .../src/main/res/drawable-hdpi/file_g.png | Bin 0 -> 2129 bytes .../main/res/drawable-hdpi/file_g_cancel.png | Bin 0 -> 2297 bytes .../res/drawable-hdpi/file_g_cancel_s.png | Bin 0 -> 2244 bytes .../main/res/drawable-hdpi/file_g_load.png | Bin 0 -> 2131 bytes .../main/res/drawable-hdpi/file_g_load_s.png | Bin 0 -> 2137 bytes .../src/main/res/drawable-hdpi/file_g_s.png | Bin 0 -> 2119 bytes .../main/res/drawable-hdpi/ic_action_next.png | Bin 0 -> 291 bytes .../res/drawable-hdpi/ic_action_pause.png | Bin 0 -> 234 bytes .../main/res/drawable-hdpi/ic_action_play.png | Bin 0 -> 348 bytes .../res/drawable-hdpi/ic_action_previous.png | Bin 0 -> 306 bytes .../src/main/res/drawable-hdpi/ic_create.png | Bin 0 -> 1248 bytes .../src/main/res/drawable-hdpi/ic_fp_40px.png | Bin 0 -> 7011 bytes .../res/drawable-hdpi/ic_launcher_beta.png | Bin 0 -> 2712 bytes .../main/res/drawable-hdpi/ic_settings.png | Bin 0 -> 1629 bytes .../main/res/drawable-hdpi/ic_smiles_gif.png | Bin 0 -> 1397 bytes .../src/main/res/drawable-hdpi/igvideo.png | Bin 1955 -> 0 bytes .../main/res/drawable-hdpi/list_circle.png | Bin 0 -> 994 bytes .../res/drawable-hdpi/list_supergroup.png | Bin 0 -> 690 bytes .../src/main/res/drawable-hdpi/location2.png | Bin 0 -> 824 bytes .../main/res/drawable-hdpi/logo_avatar.png | Bin 0 -> 1642 bytes .../src/main/res/drawable-hdpi/managers.png | Bin 0 -> 1562 bytes .../src/main/res/drawable-hdpi/menu_admin.png | Bin 0 -> 670 bytes .../src/main/res/drawable-hdpi/menu_plus.png | Bin 0 -> 1184 bytes .../main/res/drawable-hdpi/menu_themes.png | Bin 0 -> 546 bytes .../res/drawable-hdpi/miniplayer_close.png | Bin 0 -> 1273 bytes .../res/drawable-hdpi/miniplayer_pause.png | Bin 0 -> 984 bytes .../res/drawable-hdpi/miniplayer_play.png | Bin 0 -> 1165 bytes .../main/res/drawable-hdpi/msg_check_10.png | Bin 0 -> 409 bytes .../main/res/drawable-hdpi/msg_check_11.png | Bin 0 -> 451 bytes .../main/res/drawable-hdpi/msg_check_12.png | Bin 0 -> 337 bytes .../main/res/drawable-hdpi/msg_check_2.png | Bin 0 -> 545 bytes .../main/res/drawable-hdpi/msg_check_3.png | Bin 0 -> 532 bytes .../main/res/drawable-hdpi/msg_check_4.png | Bin 0 -> 980 bytes .../main/res/drawable-hdpi/msg_check_5.png | Bin 0 -> 390 bytes .../main/res/drawable-hdpi/msg_check_6.png | Bin 0 -> 310 bytes .../main/res/drawable-hdpi/msg_check_7.png | Bin 0 -> 215 bytes .../main/res/drawable-hdpi/msg_check_8.png | Bin 0 -> 632 bytes .../main/res/drawable-hdpi/msg_check_9.png | Bin 0 -> 537 bytes .../main/res/drawable-hdpi/msg_check_w_10.png | Bin 0 -> 416 bytes .../main/res/drawable-hdpi/msg_check_w_11.png | Bin 0 -> 391 bytes .../main/res/drawable-hdpi/msg_check_w_12.png | Bin 0 -> 319 bytes .../main/res/drawable-hdpi/msg_check_w_2.png | Bin 0 -> 455 bytes .../main/res/drawable-hdpi/msg_check_w_3.png | Bin 0 -> 444 bytes .../main/res/drawable-hdpi/msg_check_w_4.png | Bin 0 -> 1066 bytes .../main/res/drawable-hdpi/msg_check_w_5.png | Bin 0 -> 363 bytes .../main/res/drawable-hdpi/msg_check_w_6.png | Bin 0 -> 274 bytes .../main/res/drawable-hdpi/msg_check_w_7.png | Bin 0 -> 201 bytes .../main/res/drawable-hdpi/msg_check_w_8.png | Bin 0 -> 563 bytes .../main/res/drawable-hdpi/msg_check_w_9.png | Bin 0 -> 443 bytes .../src/main/res/drawable-hdpi/msg_clock2.png | Bin 0 -> 1284 bytes .../main/res/drawable-hdpi/msg_clock2_s.png | Bin 0 -> 1286 bytes .../res/drawable-hdpi/msg_halfcheck_10.png | Bin 0 -> 632 bytes .../res/drawable-hdpi/msg_halfcheck_11.png | Bin 0 -> 377 bytes .../res/drawable-hdpi/msg_halfcheck_12.png | Bin 0 -> 334 bytes .../res/drawable-hdpi/msg_halfcheck_13.png | Bin 0 -> 452 bytes .../res/drawable-hdpi/msg_halfcheck_2.png | Bin 0 -> 545 bytes .../res/drawable-hdpi/msg_halfcheck_3.png | Bin 0 -> 532 bytes .../res/drawable-hdpi/msg_halfcheck_4.png | Bin 0 -> 780 bytes .../res/drawable-hdpi/msg_halfcheck_5.png | Bin 0 -> 383 bytes .../res/drawable-hdpi/msg_halfcheck_6.png | Bin 0 -> 310 bytes .../res/drawable-hdpi/msg_halfcheck_7.png | Bin 0 -> 215 bytes .../res/drawable-hdpi/msg_halfcheck_8.png | Bin 0 -> 632 bytes .../res/drawable-hdpi/msg_halfcheck_9.png | Bin 0 -> 567 bytes .../res/drawable-hdpi/msg_halfcheck_w_10.png | Bin 0 -> 587 bytes .../res/drawable-hdpi/msg_halfcheck_w_11.png | Bin 0 -> 324 bytes .../res/drawable-hdpi/msg_halfcheck_w_12.png | Bin 0 -> 303 bytes .../res/drawable-hdpi/msg_halfcheck_w_13.png | Bin 0 -> 364 bytes .../res/drawable-hdpi/msg_halfcheck_w_2.png | Bin 0 -> 455 bytes .../res/drawable-hdpi/msg_halfcheck_w_3.png | Bin 0 -> 444 bytes .../res/drawable-hdpi/msg_halfcheck_w_4.png | Bin 0 -> 862 bytes .../res/drawable-hdpi/msg_halfcheck_w_5.png | Bin 0 -> 356 bytes .../res/drawable-hdpi/msg_halfcheck_w_6.png | Bin 0 -> 285 bytes .../res/drawable-hdpi/msg_halfcheck_w_7.png | Bin 0 -> 201 bytes .../res/drawable-hdpi/msg_halfcheck_w_8.png | Bin 0 -> 563 bytes .../res/drawable-hdpi/msg_halfcheck_w_9.png | Bin 0 -> 469 bytes .../src/main/res/drawable-hdpi/msg_in_5.9.png | Bin 0 -> 17361 bytes .../res/drawable-hdpi/msg_in_5_photo.9.png | Bin 0 -> 652 bytes .../msg_in_5_photo_selected.9.png | Bin 0 -> 681 bytes .../res/drawable-hdpi/msg_in_5_selected.9.png | Bin 0 -> 17361 bytes .../src/main/res/drawable-hdpi/msg_in_6.9.png | Bin 0 -> 17475 bytes .../res/drawable-hdpi/msg_in_6_photo.9.png | Bin 0 -> 14764 bytes .../msg_in_6_photo_selected.9.png | Bin 0 -> 14828 bytes .../res/drawable-hdpi/msg_in_6_selected.9.png | Bin 0 -> 17485 bytes .../src/main/res/drawable-hdpi/msg_in_7.9.png | Bin 0 -> 17266 bytes .../res/drawable-hdpi/msg_in_7_photo.9.png | Bin 0 -> 652 bytes .../msg_in_7_photo_selected.9.png | Bin 0 -> 681 bytes .../res/drawable-hdpi/msg_in_7_selected.9.png | Bin 0 -> 17764 bytes .../src/main/res/drawable-hdpi/msg_in_8.9.png | Bin 0 -> 957 bytes .../res/drawable-hdpi/msg_in_8_photo.9.png | Bin 0 -> 652 bytes .../msg_in_8_photo_selected.9.png | Bin 0 -> 681 bytes .../res/drawable-hdpi/msg_in_8_selected.9.png | Bin 0 -> 982 bytes .../main/res/drawable-hdpi/msg_out_5.9.png | Bin 0 -> 17741 bytes .../res/drawable-hdpi/msg_out_5_photo.9.png | Bin 0 -> 1625 bytes .../msg_out_5_photo_selected.9.png | Bin 0 -> 1611 bytes .../drawable-hdpi/msg_out_5_selected.9.png | Bin 0 -> 17741 bytes .../main/res/drawable-hdpi/msg_out_6.9.png | Bin 0 -> 17871 bytes .../res/drawable-hdpi/msg_out_6_photo.9.png | Bin 0 -> 15328 bytes .../msg_out_6_photo_selected.9.png | Bin 0 -> 15322 bytes .../drawable-hdpi/msg_out_6_selected.9.png | Bin 0 -> 17871 bytes .../main/res/drawable-hdpi/msg_out_7.9.png | Bin 0 -> 18259 bytes .../res/drawable-hdpi/msg_out_7_photo.9.png | Bin 0 -> 1625 bytes .../msg_out_7_photo_selected.9.png | Bin 0 -> 1611 bytes .../drawable-hdpi/msg_out_7_selected.9.png | Bin 0 -> 18328 bytes .../main/res/drawable-hdpi/msg_out_8.9.png | Bin 0 -> 1871 bytes .../res/drawable-hdpi/msg_out_8_photo.9.png | Bin 0 -> 1625 bytes .../msg_out_8_photo_selected.9.png | Bin 0 -> 1611 bytes .../drawable-hdpi/msg_out_8_selected.9.png | Bin 0 -> 1869 bytes .../src/main/res/drawable-hdpi/nocover.png | Bin 0 -> 2148 bytes .../main/res/drawable-hdpi/nocover_big.9.png | Bin 0 -> 2163 bytes .../res/drawable-hdpi/nocover_small.9.png | Bin 0 -> 1051 bytes .../res/drawable-hdpi/notify_members_off.png | Bin 0 -> 1729 bytes .../res/drawable-hdpi/notify_members_on.png | Bin 0 -> 1409 bytes .../res/drawable-hdpi/pause_b_pressed.png | Bin 1889 -> 0 bytes .../src/main/res/drawable-hdpi/pause_b_s.png | Bin 0 -> 2025 bytes .../res/drawable-hdpi/pause_g_pressed.png | Bin 1902 -> 0 bytes .../src/main/res/drawable-hdpi/pause_g_s.png | Bin 0 -> 2029 bytes .../src/main/res/drawable-hdpi/pause_w.png | Bin 1852 -> 0 bytes .../src/main/res/drawable-hdpi/pause_w2.png | Bin 1886 -> 0 bytes .../res/drawable-hdpi/pause_w2_pressed.png | Bin 1888 -> 0 bytes .../res/drawable-hdpi/pause_w_pressed.png | Bin 1888 -> 0 bytes .../main/res/drawable-hdpi/phone_activate.png | Bin 0 -> 4074 bytes .../main/res/drawable-hdpi/photocancel_b.png | Bin 0 -> 2408 bytes .../res/drawable-hdpi/photocancel_b_s.png | Bin 0 -> 2319 bytes .../main/res/drawable-hdpi/photocancel_g.png | Bin 0 -> 2424 bytes .../res/drawable-hdpi/photocancel_g_s.png | Bin 0 -> 2424 bytes .../res/drawable-hdpi/photocancel_pressed.png | Bin 0 -> 2304 bytes .../res/drawable-hdpi/photogif_pressed.png | Bin 0 -> 2399 bytes .../main/res/drawable-hdpi/photoload_b.png | Bin 0 -> 2266 bytes .../main/res/drawable-hdpi/photoload_b_s.png | Bin 0 -> 2200 bytes .../main/res/drawable-hdpi/photoload_g.png | Bin 0 -> 2271 bytes .../main/res/drawable-hdpi/photoload_g_s.png | Bin 0 -> 2269 bytes .../res/drawable-hdpi/photoload_pressed.png | Bin 0 -> 2120 bytes .../src/main/res/drawable-hdpi/photopause.png | Bin 1088 -> 0 bytes .../main/res/drawable-hdpi/phototime2.9.png | Bin 0 -> 1008 bytes .../main/res/drawable-hdpi/phototime2_b.9.png | Bin 0 -> 1029 bytes .../src/main/res/drawable-hdpi/pl_back.png | Bin 0 -> 1166 bytes .../src/main/res/drawable-hdpi/pl_next.png | Bin 0 -> 1302 bytes .../res/drawable-hdpi/pl_next_pressed.png | Bin 0 -> 1319 bytes .../src/main/res/drawable-hdpi/pl_pause.png | Bin 0 -> 996 bytes .../res/drawable-hdpi/pl_pause_pressed.png | Bin 0 -> 1001 bytes .../src/main/res/drawable-hdpi/pl_play.png | Bin 0 -> 1342 bytes .../res/drawable-hdpi/pl_play_pressed.png | Bin 0 -> 1342 bytes .../main/res/drawable-hdpi/pl_previous.png | Bin 0 -> 1313 bytes .../res/drawable-hdpi/pl_previous_pressed.png | Bin 0 -> 1328 bytes .../src/main/res/drawable-hdpi/pl_repeat.png | Bin 0 -> 1187 bytes .../res/drawable-hdpi/pl_repeat1_active.png | Bin 0 -> 1230 bytes .../res/drawable-hdpi/pl_repeat_active.png | Bin 0 -> 1195 bytes .../src/main/res/drawable-hdpi/pl_shuffle.png | Bin 0 -> 1366 bytes .../res/drawable-hdpi/pl_shuffle_active.png | Bin 0 -> 1369 bytes .../src/main/res/drawable-hdpi/play_b.png | Bin 0 -> 2303 bytes .../src/main/res/drawable-hdpi/play_b_s.png | Bin 0 -> 2326 bytes .../src/main/res/drawable-hdpi/play_g.png | Bin 0 -> 2316 bytes .../src/main/res/drawable-hdpi/play_g_s.png | Bin 0 -> 2308 bytes .../src/main/res/drawable-hdpi/play_w.png | Bin 2200 -> 0 bytes .../src/main/res/drawable-hdpi/play_w2.png | Bin 2240 -> 0 bytes .../res/drawable-hdpi/play_w2_pressed.png | Bin 2238 -> 0 bytes .../main/res/drawable-hdpi/play_w_pressed.png | Bin 2252 -> 0 bytes .../src/main/res/drawable-hdpi/player.png | Bin 0 -> 1415 bytes .../res/drawable-hdpi/playvideo_pressed.png | Bin 0 -> 2388 bytes .../src/main/res/drawable-hdpi/post_views.png | Bin 0 -> 1354 bytes .../main/res/drawable-hdpi/post_views_s.png | Bin 0 -> 1380 bytes .../main/res/drawable-hdpi/post_views_w.png | Bin 0 -> 1317 bytes .../main/res/drawable-hdpi/post_viewsg.png | Bin 0 -> 1377 bytes .../src/main/res/drawable-hdpi/publish.png | Bin 0 -> 1620 bytes .../main/res/drawable-hdpi/publish_active.png | Bin 0 -> 1622 bytes .../src/main/res/drawable-hdpi/recorded.9.png | Bin 0 -> 690 bytes .../src/main/res/drawable-hdpi/redcircle.png | Bin 0 -> 1103 bytes .../s_pause.png} | Bin 982 -> 975 bytes .../res/drawable-hdpi/s_pause_pressed.png | Bin 0 -> 975 bytes .../src/main/res/drawable-hdpi/s_play.png | Bin 0 -> 1178 bytes .../main/res/drawable-hdpi/s_play_pressed.png | Bin 0 -> 1190 bytes .../main/res/drawable-hdpi/search_down.png | Bin 0 -> 1139 bytes .../main/res/drawable-hdpi/search_share.png | Bin 0 -> 1503 bytes .../src/main/res/drawable-hdpi/search_up.png | Bin 0 -> 1123 bytes .../main/res/drawable-hdpi/share_arrow.png | Bin 0 -> 1221 bytes .../main/res/drawable-hdpi/share_round.png | Bin 0 -> 1530 bytes .../main/res/drawable-hdpi/sheet_shadow.9.png | Bin 0 -> 325 bytes .../res/drawable-hdpi/stickercounter.9.png | Bin 0 -> 1425 bytes .../src/main/res/drawable-hdpi/system.9.png | Bin 0 -> 1192 bytes .../main/res/drawable-hdpi/system_black.9.png | Bin 196 -> 0 bytes .../main/res/drawable-hdpi/system_blue.9.png | Bin 1127 -> 0 bytes .../main/res/drawable-hdpi/system_loader.png | Bin 0 -> 1647 bytes .../main/res/drawable-hdpi/system_loader1.png | Bin 839 -> 0 bytes .../main/res/drawable-hdpi/system_loader2.png | Bin 813 -> 0 bytes .../src/main/res/drawable-hdpi/tab_all.png | Bin 0 -> 389 bytes .../src/main/res/drawable-hdpi/tab_bot.png | Bin 0 -> 801 bytes .../main/res/drawable-hdpi/tab_channel.png | Bin 0 -> 1279 bytes .../src/main/res/drawable-hdpi/tab_favs.png | Bin 0 -> 495 bytes .../src/main/res/drawable-hdpi/tab_group.png | Bin 0 -> 797 bytes .../main/res/drawable-hdpi/tab_selected.9.png | Bin 0 -> 165 bytes .../main/res/drawable-hdpi/tab_supergroup.png | Bin 0 -> 901 bytes .../src/main/res/drawable-hdpi/tab_user.png | Bin 0 -> 567 bytes .../src/main/res/drawable-hdpi/tip3.png | Bin 0 -> 19391 bytes .../src/main/res/drawable-hdpi/tip4.png | Bin 0 -> 13067 bytes .../main/res/drawable-hdpi/tool_cropfix.png | Bin 0 -> 1018 bytes .../src/main/res/drawable-hdpi/tool_curve.png | Bin 0 -> 1137 bytes .../src/main/res/drawable-hdpi/tool_fade.png | Bin 0 -> 1372 bytes .../main/res/drawable-hdpi/tool_rotate.png | Bin 0 -> 1399 bytes .../src/main/res/drawable-hdpi/tool_tint.png | Bin 0 -> 1165 bytes .../src/main/res/drawable-hdpi/tooltip.9.png | Bin 0 -> 173 bytes .../main/res/drawable-hdpi/video_actions.png | Bin 0 -> 1106 bytes .../abc_ic_menu_share_mtrl_alpha.png | Bin 0 -> 274 bytes .../src/main/res/drawable-mdpi/admin_star.png | Bin 0 -> 1144 bytes .../main/res/drawable-mdpi/admin_star2.png | Bin 0 -> 1171 bytes .../main/res/drawable-mdpi/assign_manager.png | Bin 0 -> 1200 bytes .../main/res/drawable-mdpi/attach_audio.png | Bin 0 -> 2368 bytes .../drawable-mdpi/attach_audio_pressed.png | Bin 0 -> 2284 bytes .../main/res/drawable-mdpi/attach_camera.png | Bin 0 -> 4069 bytes .../drawable-mdpi/attach_camera_pressed.png | Bin 0 -> 3929 bytes .../main/res/drawable-mdpi/attach_contact.png | Bin 0 -> 2293 bytes .../drawable-mdpi/attach_contact_pressed.png | Bin 0 -> 2189 bytes .../main/res/drawable-mdpi/attach_file.png | Bin 0 -> 2125 bytes .../res/drawable-mdpi/attach_file_pressed.png | Bin 0 -> 2057 bytes .../main/res/drawable-mdpi/attach_gallery.png | Bin 0 -> 2238 bytes .../drawable-mdpi/attach_gallery_pressed.png | Bin 0 -> 2172 bytes .../main/res/drawable-mdpi/attach_hide1.png | Bin 0 -> 1844 bytes .../drawable-mdpi/attach_hide1_pressed.png | Bin 0 -> 1841 bytes .../main/res/drawable-mdpi/attach_hide2.png | Bin 0 -> 1055 bytes .../res/drawable-mdpi/attach_location.png | Bin 0 -> 2447 bytes .../drawable-mdpi/attach_location_pressed.png | Bin 0 -> 2333 bytes .../main/res/drawable-mdpi/attach_send1.png | Bin 0 -> 1844 bytes .../drawable-mdpi/attach_send1_pressed.png | Bin 0 -> 1840 bytes .../main/res/drawable-mdpi/attach_send2.png | Bin 0 -> 1183 bytes .../main/res/drawable-mdpi/attach_video.png | Bin 0 -> 1891 bytes .../drawable-mdpi/attach_video_pressed.png | Bin 0 -> 2108 bytes .../res/drawable-mdpi/audiosend_pause.png | Bin 0 -> 1552 bytes .../main/res/drawable-mdpi/audiosend_play.png | Bin 0 -> 2002 bytes .../src/main/res/drawable-mdpi/blockpanel.png | Bin 0 -> 944 bytes .../main/res/drawable-mdpi/bluecounter.9.png | Bin 0 -> 336 bytes .../src/main/res/drawable-mdpi/bot_file.png | Bin 0 -> 1115 bytes .../src/main/res/drawable-mdpi/bot_info.png | Bin 0 -> 1363 bytes .../main/res/drawable-mdpi/bot_keyboard.png | Bin 0 -> 1836 bytes .../main/res/drawable-mdpi/bot_keyboard2.png | Bin 0 -> 1334 bytes .../drawable-mdpi/bot_keyboard_button.9.png | Bin 0 -> 218 bytes .../bot_keyboard_button_pressed.9.png | Bin 0 -> 214 bytes .../src/main/res/drawable-mdpi/bot_lines.png | Bin 0 -> 1014 bytes .../src/main/res/drawable-mdpi/bot_link.png | Bin 0 -> 1002 bytes .../src/main/res/drawable-mdpi/bot_list.png | Bin 0 -> 1155 bytes .../main/res/drawable-mdpi/bot_location.png | Bin 0 -> 1308 bytes .../src/main/res/drawable-mdpi/bot_music.png | Bin 0 -> 1299 bytes .../src/main/res/drawable-mdpi/cancel_b.png | Bin 1731 -> 0 bytes .../res/drawable-mdpi/cancel_b_pressed.png | Bin 1712 -> 0 bytes .../src/main/res/drawable-mdpi/cancel_g.png | Bin 1724 -> 0 bytes .../res/drawable-mdpi/cancel_g_pressed.png | Bin 1751 -> 0 bytes .../main/res/drawable-mdpi/channelintro.png | Bin 0 -> 18051 bytes .../src/main/res/drawable-mdpi/check_list.png | Bin 0 -> 459 bytes .../main/res/drawable-mdpi/check_profile.png | Bin 0 -> 513 bytes .../main/res/drawable-mdpi/contact_blue.png | Bin 0 -> 1796 bytes .../main/res/drawable-mdpi/contact_green.png | Bin 0 -> 1828 bytes .../corner_in_bl.png} | Bin 966 -> 952 bytes .../main/res/drawable-mdpi/corner_in_br.png | Bin 0 -> 947 bytes ...{addcontact_green.png => corner_in_tl.png} | Bin 956 -> 955 bytes .../main/res/drawable-mdpi/corner_in_tr.png | Bin 0 -> 949 bytes ...{addcontact_blue.png => corner_out_bl.png} | Bin 956 -> 964 bytes .../main/res/drawable-mdpi/corner_out_br.png | Bin 0 -> 962 bytes .../main/res/drawable-mdpi/corner_out_tl.png | Bin 0 -> 967 bytes .../main/res/drawable-mdpi/corner_out_tr.png | Bin 0 -> 963 bytes .../res/drawable-mdpi/dialogs_badge2.9.png | Bin 0 -> 1245 bytes .../res/drawable-mdpi/dialogs_check_10.png | Bin 0 -> 322 bytes .../res/drawable-mdpi/dialogs_check_11.png | Bin 0 -> 339 bytes .../res/drawable-mdpi/dialogs_check_12.png | Bin 0 -> 281 bytes .../res/drawable-mdpi/dialogs_check_2.png | Bin 0 -> 402 bytes .../res/drawable-mdpi/dialogs_check_3.png | Bin 0 -> 390 bytes .../res/drawable-mdpi/dialogs_check_4.png | Bin 0 -> 638 bytes .../res/drawable-mdpi/dialogs_check_5.png | Bin 0 -> 314 bytes .../res/drawable-mdpi/dialogs_check_6.png | Bin 0 -> 262 bytes .../res/drawable-mdpi/dialogs_check_7.png | Bin 0 -> 193 bytes .../res/drawable-mdpi/dialogs_check_8.png | Bin 0 -> 458 bytes .../res/drawable-mdpi/dialogs_check_9.png | Bin 0 -> 372 bytes .../drawable-mdpi/dialogs_halfcheck_10.png | Bin 0 -> 458 bytes .../drawable-mdpi/dialogs_halfcheck_11.png | Bin 0 -> 289 bytes .../drawable-mdpi/dialogs_halfcheck_12.png | Bin 0 -> 271 bytes .../res/drawable-mdpi/dialogs_halfcheck_2.png | Bin 0 -> 402 bytes .../res/drawable-mdpi/dialogs_halfcheck_3.png | Bin 0 -> 390 bytes .../res/drawable-mdpi/dialogs_halfcheck_4.png | Bin 0 -> 550 bytes .../res/drawable-mdpi/dialogs_halfcheck_5.png | Bin 0 -> 312 bytes .../res/drawable-mdpi/dialogs_halfcheck_6.png | Bin 0 -> 261 bytes .../res/drawable-mdpi/dialogs_halfcheck_7.png | Bin 0 -> 193 bytes .../res/drawable-mdpi/dialogs_halfcheck_8.png | Bin 0 -> 458 bytes .../res/drawable-mdpi/dialogs_halfcheck_9.png | Bin 0 -> 389 bytes .../res/drawable-mdpi/doc_actions_b_s.png | Bin 0 -> 1000 bytes .../src/main/res/drawable-mdpi/doc_blue_s.png | Bin 0 -> 1273 bytes .../main/res/drawable-mdpi/doccancel_b_s.png | Bin 0 -> 1219 bytes .../main/res/drawable-mdpi/docload_b_s.png | Bin 0 -> 2044 bytes .../main/res/drawable-mdpi/docpause_b_s.png | Bin 0 -> 1010 bytes .../src/main/res/drawable-mdpi/download_b.png | Bin 1684 -> 0 bytes .../res/drawable-mdpi/download_b_pressed.png | Bin 1676 -> 0 bytes .../src/main/res/drawable-mdpi/download_g.png | Bin 1696 -> 0 bytes .../res/drawable-mdpi/download_g_pressed.png | Bin 1697 -> 0 bytes .../src/main/res/drawable-mdpi/file_b.png | Bin 0 -> 1858 bytes .../main/res/drawable-mdpi/file_b_cancel.png | Bin 0 -> 1859 bytes .../res/drawable-mdpi/file_b_cancel_s.png | Bin 0 -> 1834 bytes .../main/res/drawable-mdpi/file_b_load.png | Bin 0 -> 1710 bytes .../main/res/drawable-mdpi/file_b_load_s.png | Bin 0 -> 1713 bytes .../src/main/res/drawable-mdpi/file_b_s.png | Bin 0 -> 1864 bytes .../src/main/res/drawable-mdpi/file_g.png | Bin 0 -> 1872 bytes .../main/res/drawable-mdpi/file_g_cancel.png | Bin 0 -> 1841 bytes .../res/drawable-mdpi/file_g_cancel_s.png | Bin 0 -> 1847 bytes .../main/res/drawable-mdpi/file_g_load.png | Bin 0 -> 1731 bytes .../main/res/drawable-mdpi/file_g_load_s.png | Bin 0 -> 1723 bytes .../src/main/res/drawable-mdpi/file_g_s.png | Bin 0 -> 1856 bytes .../main/res/drawable-mdpi/ic_action_next.png | Bin 0 -> 229 bytes .../res/drawable-mdpi/ic_action_pause.png | Bin 0 -> 188 bytes .../main/res/drawable-mdpi/ic_action_play.png | Bin 0 -> 282 bytes .../res/drawable-mdpi/ic_action_previous.png | Bin 0 -> 249 bytes .../src/main/res/drawable-mdpi/ic_create.png | Bin 0 -> 1153 bytes .../src/main/res/drawable-mdpi/ic_fp_40px.png | Bin 0 -> 4001 bytes .../res/drawable-mdpi/ic_launcher_beta.png | Bin 0 -> 1784 bytes .../main/res/drawable-mdpi/ic_settings.png | Bin 0 -> 1352 bytes .../main/res/drawable-mdpi/ic_smiles_gif.png | Bin 0 -> 1247 bytes .../src/main/res/drawable-mdpi/igvideo.png | Bin 1553 -> 0 bytes .../main/res/drawable-mdpi/list_circle.png | Bin 0 -> 965 bytes .../res/drawable-mdpi/list_supergroup.png | Bin 0 -> 478 bytes .../src/main/res/drawable-mdpi/location2.png | Bin 0 -> 582 bytes .../main/res/drawable-mdpi/logo_avatar.png | Bin 0 -> 1115 bytes .../src/main/res/drawable-mdpi/managers.png | Bin 0 -> 1358 bytes .../src/main/res/drawable-mdpi/menu_admin.png | Bin 0 -> 477 bytes .../src/main/res/drawable-mdpi/menu_plus.png | Bin 0 -> 633 bytes .../main/res/drawable-mdpi/menu_themes.png | Bin 0 -> 356 bytes .../res/drawable-mdpi/miniplayer_close.png | Bin 0 -> 1124 bytes .../res/drawable-mdpi/miniplayer_pause.png | Bin 0 -> 984 bytes .../res/drawable-mdpi/miniplayer_play.png | Bin 0 -> 1088 bytes .../main/res/drawable-mdpi/msg_check_10.png | Bin 0 -> 312 bytes .../main/res/drawable-mdpi/msg_check_11.png | Bin 0 -> 338 bytes .../main/res/drawable-mdpi/msg_check_12.png | Bin 0 -> 270 bytes .../main/res/drawable-mdpi/msg_check_2.png | Bin 0 -> 385 bytes .../main/res/drawable-mdpi/msg_check_3.png | Bin 0 -> 375 bytes .../main/res/drawable-mdpi/msg_check_4.png | Bin 0 -> 603 bytes .../main/res/drawable-mdpi/msg_check_5.png | Bin 0 -> 303 bytes .../main/res/drawable-mdpi/msg_check_6.png | Bin 0 -> 252 bytes .../main/res/drawable-mdpi/msg_check_7.png | Bin 0 -> 186 bytes .../main/res/drawable-mdpi/msg_check_8.png | Bin 0 -> 418 bytes .../main/res/drawable-mdpi/msg_check_9.png | Bin 0 -> 371 bytes .../main/res/drawable-mdpi/msg_check_w_10.png | Bin 0 -> 307 bytes .../main/res/drawable-mdpi/msg_check_w_11.png | Bin 0 -> 295 bytes .../main/res/drawable-mdpi/msg_check_w_12.png | Bin 0 -> 246 bytes .../main/res/drawable-mdpi/msg_check_w_2.png | Bin 0 -> 319 bytes .../main/res/drawable-mdpi/msg_check_w_3.png | Bin 0 -> 315 bytes .../main/res/drawable-mdpi/msg_check_w_4.png | Bin 0 -> 658 bytes .../main/res/drawable-mdpi/msg_check_w_5.png | Bin 0 -> 280 bytes .../main/res/drawable-mdpi/msg_check_w_6.png | Bin 0 -> 226 bytes .../main/res/drawable-mdpi/msg_check_w_7.png | Bin 0 -> 172 bytes .../main/res/drawable-mdpi/msg_check_w_8.png | Bin 0 -> 417 bytes .../main/res/drawable-mdpi/msg_check_w_9.png | Bin 0 -> 311 bytes .../src/main/res/drawable-mdpi/msg_clock2.png | Bin 0 -> 1141 bytes .../main/res/drawable-mdpi/msg_clock2_s.png | Bin 0 -> 1145 bytes .../res/drawable-mdpi/msg_halfcheck_10.png | Bin 0 -> 418 bytes .../res/drawable-mdpi/msg_halfcheck_11.png | Bin 0 -> 287 bytes .../res/drawable-mdpi/msg_halfcheck_12.png | Bin 0 -> 265 bytes .../res/drawable-mdpi/msg_halfcheck_2.png | Bin 0 -> 385 bytes .../res/drawable-mdpi/msg_halfcheck_3.png | Bin 0 -> 375 bytes .../res/drawable-mdpi/msg_halfcheck_4.png | Bin 0 -> 533 bytes .../res/drawable-mdpi/msg_halfcheck_5.png | Bin 0 -> 286 bytes .../res/drawable-mdpi/msg_halfcheck_6.png | Bin 0 -> 245 bytes .../res/drawable-mdpi/msg_halfcheck_7.png | Bin 0 -> 186 bytes .../res/drawable-mdpi/msg_halfcheck_8.png | Bin 0 -> 418 bytes .../res/drawable-mdpi/msg_halfcheck_9.png | Bin 0 -> 388 bytes .../res/drawable-mdpi/msg_halfcheck_w_10.png | Bin 0 -> 371 bytes .../res/drawable-mdpi/msg_halfcheck_w_11.png | Bin 0 -> 259 bytes .../res/drawable-mdpi/msg_halfcheck_w_12.png | Bin 0 -> 243 bytes .../res/drawable-mdpi/msg_halfcheck_w_2.png | Bin 0 -> 319 bytes .../res/drawable-mdpi/msg_halfcheck_w_3.png | Bin 0 -> 315 bytes .../res/drawable-mdpi/msg_halfcheck_w_4.png | Bin 0 -> 569 bytes .../res/drawable-mdpi/msg_halfcheck_w_5.png | Bin 0 -> 269 bytes .../res/drawable-mdpi/msg_halfcheck_w_6.png | Bin 0 -> 229 bytes .../res/drawable-mdpi/msg_halfcheck_w_7.png | Bin 0 -> 172 bytes .../res/drawable-mdpi/msg_halfcheck_w_8.png | Bin 0 -> 417 bytes .../res/drawable-mdpi/msg_halfcheck_w_9.png | Bin 0 -> 323 bytes .../src/main/res/drawable-mdpi/msg_in_5.9.png | Bin 0 -> 17188 bytes ..._in_photo_2.9.png => msg_in_5_photo.9.png} | Bin .../msg_in_5_photo_selected.9.png | Bin 0 -> 500 bytes .../res/drawable-mdpi/msg_in_5_selected.9.png | Bin 0 -> 17196 bytes .../src/main/res/drawable-mdpi/msg_in_6.9.png | Bin 0 -> 17225 bytes .../res/drawable-mdpi/msg_in_6_photo.9.png | Bin 0 -> 14722 bytes .../msg_in_6_photo_selected.9.png | Bin 0 -> 14775 bytes .../res/drawable-mdpi/msg_in_6_selected.9.png | Bin 0 -> 17254 bytes .../src/main/res/drawable-mdpi/msg_in_7.9.png | Bin 0 -> 16680 bytes .../res/drawable-mdpi/msg_in_7_photo.9.png | Bin 0 -> 470 bytes .../msg_in_7_photo_selected.9.png | Bin 0 -> 500 bytes .../res/drawable-mdpi/msg_in_7_selected.9.png | Bin 0 -> 16868 bytes .../src/main/res/drawable-mdpi/msg_in_8.9.png | Bin 0 -> 669 bytes .../res/drawable-mdpi/msg_in_8_photo.9.png | Bin 0 -> 470 bytes .../msg_in_8_photo_selected.9.png | Bin 0 -> 500 bytes .../res/drawable-mdpi/msg_in_8_selected.9.png | Bin 0 -> 693 bytes .../main/res/drawable-mdpi/msg_out_5.9.png | Bin 0 -> 17604 bytes .../res/drawable-mdpi/msg_out_5_photo.9.png | Bin 0 -> 1465 bytes .../msg_out_5_photo_selected.9.png | Bin 0 -> 1474 bytes .../drawable-mdpi/msg_out_5_selected.9.png | Bin 0 -> 17604 bytes .../main/res/drawable-mdpi/msg_out_6.9.png | Bin 0 -> 17645 bytes .../res/drawable-mdpi/msg_out_6_photo.9.png | Bin 0 -> 15272 bytes .../msg_out_6_photo_selected.9.png | Bin 0 -> 15271 bytes .../drawable-mdpi/msg_out_6_selected.9.png | Bin 0 -> 17645 bytes .../main/res/drawable-mdpi/msg_out_7.9.png | Bin 0 -> 17778 bytes .../res/drawable-mdpi/msg_out_7_photo.9.png | Bin 0 -> 1465 bytes .../msg_out_7_photo_selected.9.png | Bin 0 -> 1474 bytes .../drawable-mdpi/msg_out_7_selected.9.png | Bin 0 -> 18044 bytes .../main/res/drawable-mdpi/msg_out_8_.9.png | Bin 0 -> 1693 bytes .../res/drawable-mdpi/msg_out_8_photo.9.png | Bin 0 -> 1465 bytes .../msg_out_8_photo_selected.9.png | Bin 0 -> 1474 bytes .../drawable-mdpi/msg_out_8_selected.9.png | Bin 0 -> 1694 bytes .../src/main/res/drawable-mdpi/nocover.png | Bin 0 -> 1705 bytes .../main/res/drawable-mdpi/nocover_big.9.png | Bin 0 -> 1550 bytes .../res/drawable-mdpi/nocover_small.9.png | Bin 0 -> 844 bytes .../res/drawable-mdpi/notify_members_off.png | Bin 0 -> 1500 bytes .../res/drawable-mdpi/notify_members_on.png | Bin 0 -> 1294 bytes .../res/drawable-mdpi/pause_b_pressed.png | Bin 1592 -> 0 bytes .../src/main/res/drawable-mdpi/pause_b_s.png | Bin 0 -> 1669 bytes .../res/drawable-mdpi/pause_g_pressed.png | Bin 1616 -> 0 bytes .../src/main/res/drawable-mdpi/pause_g_s.png | Bin 0 -> 1663 bytes .../src/main/res/drawable-mdpi/pause_w.png | Bin 1576 -> 0 bytes .../src/main/res/drawable-mdpi/pause_w2.png | Bin 1606 -> 0 bytes .../res/drawable-mdpi/pause_w2_pressed.png | Bin 1607 -> 0 bytes .../main/res/drawable-mdpi/phone_activate.png | Bin 0 -> 2975 bytes .../main/res/drawable-mdpi/photocancel_b.png | Bin 0 -> 1961 bytes .../res/drawable-mdpi/photocancel_b_s.png | Bin 0 -> 1846 bytes .../main/res/drawable-mdpi/photocancel_g.png | Bin 0 -> 1966 bytes .../res/drawable-mdpi/photocancel_g_s.png | Bin 0 -> 1955 bytes .../res/drawable-mdpi/photocancel_pressed.png | Bin 0 -> 1936 bytes .../res/drawable-mdpi/photogif_pressed.png | Bin 0 -> 2017 bytes .../main/res/drawable-mdpi/photoload_b.png | Bin 0 -> 1824 bytes .../main/res/drawable-mdpi/photoload_b_s.png | Bin 0 -> 1757 bytes .../main/res/drawable-mdpi/photoload_g.png | Bin 0 -> 1824 bytes .../main/res/drawable-mdpi/photoload_g_s.png | Bin 0 -> 1817 bytes .../res/drawable-mdpi/photoload_pressed.png | Bin 0 -> 1797 bytes .../src/main/res/drawable-mdpi/photopause.png | Bin 781 -> 0 bytes .../main/res/drawable-mdpi/phototime2.9.png | Bin 0 -> 998 bytes .../main/res/drawable-mdpi/phototime2_b.9.png | Bin 0 -> 999 bytes .../src/main/res/drawable-mdpi/pl_back.png | Bin 0 -> 1084 bytes .../src/main/res/drawable-mdpi/pl_next.png | Bin 0 -> 1166 bytes .../res/drawable-mdpi/pl_next_pressed.png | Bin 0 -> 1162 bytes .../src/main/res/drawable-mdpi/pl_pause.png | Bin 0 -> 975 bytes .../res/drawable-mdpi/pl_pause_pressed.png | Bin 0 -> 977 bytes .../src/main/res/drawable-mdpi/pl_play.png | Bin 0 -> 1148 bytes .../res/drawable-mdpi/pl_play_pressed.png | Bin 0 -> 1156 bytes .../main/res/drawable-mdpi/pl_previous.png | Bin 0 -> 1182 bytes .../res/drawable-mdpi/pl_previous_pressed.png | Bin 0 -> 1183 bytes .../src/main/res/drawable-mdpi/pl_repeat.png | Bin 0 -> 1058 bytes .../res/drawable-mdpi/pl_repeat1_active.png | Bin 0 -> 1090 bytes .../res/drawable-mdpi/pl_repeat_active.png | Bin 0 -> 1063 bytes .../src/main/res/drawable-mdpi/pl_shuffle.png | Bin 0 -> 1210 bytes .../res/drawable-mdpi/pl_shuffle_active.png | Bin 0 -> 1220 bytes .../src/main/res/drawable-mdpi/play_b.png | Bin 0 -> 1867 bytes .../src/main/res/drawable-mdpi/play_b_s.png | Bin 0 -> 1874 bytes .../src/main/res/drawable-mdpi/play_g.png | Bin 0 -> 1883 bytes .../src/main/res/drawable-mdpi/play_g_s.png | Bin 0 -> 1874 bytes .../src/main/res/drawable-mdpi/play_w.png | Bin 1759 -> 0 bytes .../src/main/res/drawable-mdpi/play_w2.png | Bin 1799 -> 0 bytes .../res/drawable-mdpi/play_w2_pressed.png | Bin 1802 -> 0 bytes .../main/res/drawable-mdpi/play_w_pressed.png | Bin 1795 -> 0 bytes .../src/main/res/drawable-mdpi/player.png | Bin 0 -> 1249 bytes .../res/drawable-mdpi/playvideo_pressed.png | Bin 0 -> 1978 bytes .../src/main/res/drawable-mdpi/post_views.png | Bin 0 -> 1235 bytes .../main/res/drawable-mdpi/post_views_s.png | Bin 0 -> 1234 bytes .../main/res/drawable-mdpi/post_views_w.png | Bin 0 -> 1190 bytes .../main/res/drawable-mdpi/post_viewsg.png | Bin 0 -> 1233 bytes .../src/main/res/drawable-mdpi/publish.png | Bin 0 -> 1327 bytes .../main/res/drawable-mdpi/publish_active.png | Bin 0 -> 1328 bytes .../src/main/res/drawable-mdpi/recorded.9.png | Bin 0 -> 460 bytes .../src/main/res/drawable-mdpi/redcircle.png | Bin 0 -> 1027 bytes .../src/main/res/drawable-mdpi/s_pause.png | Bin 0 -> 965 bytes .../res/drawable-mdpi/s_pause_pressed.png | Bin 0 -> 969 bytes .../src/main/res/drawable-mdpi/s_play.png | Bin 0 -> 1034 bytes .../main/res/drawable-mdpi/s_play_pressed.png | Bin 0 -> 1081 bytes .../main/res/drawable-mdpi/search_down.png | Bin 0 -> 982 bytes .../main/res/drawable-mdpi/search_share.png | Bin 0 -> 1256 bytes .../src/main/res/drawable-mdpi/search_up.png | Bin 0 -> 976 bytes .../main/res/drawable-mdpi/share_arrow.png | Bin 0 -> 1083 bytes .../main/res/drawable-mdpi/share_round.png | Bin 0 -> 1327 bytes .../main/res/drawable-mdpi/sheet_shadow.9.png | Bin 0 -> 207 bytes .../res/drawable-mdpi/stickercounter.9.png | Bin 0 -> 1246 bytes .../src/main/res/drawable-mdpi/system.9.png | Bin 0 -> 1094 bytes .../main/res/drawable-mdpi/system_black.9.png | Bin 156 -> 0 bytes .../main/res/drawable-mdpi/system_blue.9.png | Bin 1052 -> 0 bytes .../main/res/drawable-mdpi/system_loader.png | Bin 0 -> 1310 bytes .../main/res/drawable-mdpi/system_loader1.png | Bin 602 -> 0 bytes .../main/res/drawable-mdpi/system_loader2.png | Bin 575 -> 0 bytes .../src/main/res/drawable-mdpi/tab_all.png | Bin 0 -> 310 bytes .../src/main/res/drawable-mdpi/tab_bot.png | Bin 0 -> 524 bytes .../main/res/drawable-mdpi/tab_channel.png | Bin 0 -> 1136 bytes .../src/main/res/drawable-mdpi/tab_favs.png | Bin 0 -> 360 bytes .../src/main/res/drawable-mdpi/tab_group.png | Bin 0 -> 574 bytes .../main/res/drawable-mdpi/tab_supergroup.png | Bin 0 -> 613 bytes .../src/main/res/drawable-mdpi/tab_user.png | Bin 0 -> 288 bytes .../src/main/res/drawable-mdpi/tip3.png | Bin 0 -> 11288 bytes .../src/main/res/drawable-mdpi/tip4.png | Bin 0 -> 7868 bytes .../main/res/drawable-mdpi/tool_cropfix.png | Bin 0 -> 993 bytes .../src/main/res/drawable-mdpi/tool_curve.png | Bin 0 -> 1080 bytes .../src/main/res/drawable-mdpi/tool_fade.png | Bin 0 -> 1144 bytes .../main/res/drawable-mdpi/tool_rotate.png | Bin 0 -> 1174 bytes .../src/main/res/drawable-mdpi/tool_tint.png | Bin 0 -> 1123 bytes .../src/main/res/drawable-mdpi/tooltip.9.png | Bin 0 -> 146 bytes .../main/res/drawable-mdpi/video_actions.png | Bin 0 -> 1019 bytes .../main/res/drawable-v21/bar_selector.xml | 5 - .../res/drawable-v21/bar_selector_blue.xml | 4 - .../res/drawable-v21/bar_selector_cyan.xml | 4 - .../res/drawable-v21/bar_selector_green.xml | 4 - .../res/drawable-v21/bar_selector_mode.xml | 4 - .../res/drawable-v21/bar_selector_orange.xml | 4 - .../res/drawable-v21/bar_selector_picker.xml | 4 - .../res/drawable-v21/bar_selector_pink.xml | 4 - .../res/drawable-v21/bar_selector_red.xml | 4 - .../res/drawable-v21/bar_selector_violet.xml | 4 - .../res/drawable-v21/bar_selector_yellow.xml | 4 - .../res/drawable-v21/list_selector_white.xml | 14 + .../abc_ic_menu_share_mtrl_alpha.png | Bin 0 -> 498 bytes .../res/drawable-xhdpi/addcontact_blue.png | Bin 982 -> 0 bytes .../main/res/drawable-xhdpi/admin_star.png | Bin 0 -> 1347 bytes .../main/res/drawable-xhdpi/admin_star2.png | Bin 0 -> 1394 bytes .../res/drawable-xhdpi/assign_manager.png | Bin 0 -> 1470 bytes .../main/res/drawable-xhdpi/attach_audio.png | Bin 0 -> 3822 bytes .../drawable-xhdpi/attach_audio_pressed.png | Bin 0 -> 3825 bytes .../main/res/drawable-xhdpi/attach_camera.png | Bin 0 -> 4910 bytes .../drawable-xhdpi/attach_camera_pressed.png | Bin 0 -> 4972 bytes .../res/drawable-xhdpi/attach_contact.png | Bin 0 -> 3537 bytes .../drawable-xhdpi/attach_contact_pressed.png | Bin 0 -> 3519 bytes .../main/res/drawable-xhdpi/attach_file.png | Bin 0 -> 3074 bytes .../drawable-xhdpi/attach_file_pressed.png | Bin 0 -> 3070 bytes .../res/drawable-xhdpi/attach_gallery.png | Bin 0 -> 3406 bytes .../drawable-xhdpi/attach_gallery_pressed.png | Bin 0 -> 3424 bytes .../main/res/drawable-xhdpi/attach_hide1.png | Bin 0 -> 2828 bytes .../drawable-xhdpi/attach_hide1_pressed.png | Bin 0 -> 2806 bytes .../main/res/drawable-xhdpi/attach_hide2.png | Bin 0 -> 1173 bytes .../res/drawable-xhdpi/attach_location.png | Bin 0 -> 3939 bytes .../attach_location_pressed.png | Bin 0 -> 3959 bytes .../main/res/drawable-xhdpi/attach_send1.png | Bin 0 -> 2808 bytes .../drawable-xhdpi/attach_send1_pressed.png | Bin 0 -> 2825 bytes .../main/res/drawable-xhdpi/attach_send2.png | Bin 0 -> 1764 bytes .../main/res/drawable-xhdpi/attach_video.png | Bin 0 -> 2859 bytes .../drawable-xhdpi/attach_video_pressed.png | Bin 0 -> 3440 bytes .../res/drawable-xhdpi/audiosend_pause.png | Bin 0 -> 2442 bytes .../res/drawable-xhdpi/audiosend_play.png | Bin 0 -> 3266 bytes .../main/res/drawable-xhdpi/blockpanel.png | Bin 0 -> 968 bytes .../main/res/drawable-xhdpi/bluecounter.9.png | Bin 0 -> 663 bytes .../src/main/res/drawable-xhdpi/bot_file.png | Bin 0 -> 1319 bytes .../src/main/res/drawable-xhdpi/bot_info.png | Bin 0 -> 1908 bytes .../main/res/drawable-xhdpi/bot_keyboard.png | Bin 0 -> 3012 bytes .../main/res/drawable-xhdpi/bot_keyboard2.png | Bin 0 -> 1758 bytes .../drawable-xhdpi/bot_keyboard_button.9.png | Bin 0 -> 318 bytes .../bot_keyboard_button_pressed.9.png | Bin 0 -> 315 bytes .../src/main/res/drawable-xhdpi/bot_lines.png | Bin 0 -> 1154 bytes .../src/main/res/drawable-xhdpi/bot_link.png | Bin 0 -> 1067 bytes .../src/main/res/drawable-xhdpi/bot_list.png | Bin 0 -> 1428 bytes .../main/res/drawable-xhdpi/bot_location.png | Bin 0 -> 1801 bytes .../src/main/res/drawable-xhdpi/bot_music.png | Bin 0 -> 1710 bytes .../src/main/res/drawable-xhdpi/cancel_b.png | Bin 2334 -> 0 bytes .../res/drawable-xhdpi/cancel_b_pressed.png | Bin 2346 -> 0 bytes .../src/main/res/drawable-xhdpi/cancel_g.png | Bin 2357 -> 0 bytes .../res/drawable-xhdpi/cancel_g_pressed.png | Bin 2401 -> 0 bytes .../main/res/drawable-xhdpi/channelintro.png | Bin 0 -> 46237 bytes .../main/res/drawable-xhdpi/check_list.png | Bin 0 -> 908 bytes .../main/res/drawable-xhdpi/check_profile.png | Bin 0 -> 939 bytes .../main/res/drawable-xhdpi/contact_blue.png | Bin 0 -> 2877 bytes .../main/res/drawable-xhdpi/contact_green.png | Bin 0 -> 2867 bytes .../main/res/drawable-xhdpi/corner_in_bl.png | Bin 0 -> 980 bytes .../main/res/drawable-xhdpi/corner_in_br.png | Bin 0 -> 973 bytes .../main/res/drawable-xhdpi/corner_in_tl.png | Bin 0 -> 992 bytes .../main/res/drawable-xhdpi/corner_in_tr.png | Bin 0 -> 980 bytes .../main/res/drawable-xhdpi/corner_out_bl.png | Bin 0 -> 1022 bytes .../main/res/drawable-xhdpi/corner_out_br.png | Bin 0 -> 1015 bytes .../main/res/drawable-xhdpi/corner_out_tl.png | Bin 0 -> 1029 bytes .../main/res/drawable-xhdpi/corner_out_tr.png | Bin 0 -> 1021 bytes .../res/drawable-xhdpi/dialogs_badge2.9.png | Bin 0 -> 1633 bytes .../res/drawable-xhdpi/dialogs_check_10.png | Bin 0 -> 524 bytes .../res/drawable-xhdpi/dialogs_check_11.png | Bin 0 -> 640 bytes .../res/drawable-xhdpi/dialogs_check_12.png | Bin 0 -> 403 bytes .../res/drawable-xhdpi/dialogs_check_2.png | Bin 0 -> 867 bytes .../res/drawable-xhdpi/dialogs_check_3.png | Bin 0 -> 786 bytes .../res/drawable-xhdpi/dialogs_check_4.png | Bin 0 -> 1493 bytes .../res/drawable-xhdpi/dialogs_check_5.png | Bin 0 -> 537 bytes .../res/drawable-xhdpi/dialogs_check_6.png | Bin 0 -> 448 bytes .../res/drawable-xhdpi/dialogs_check_7.png | Bin 0 -> 233 bytes .../res/drawable-xhdpi/dialogs_check_8.png | Bin 0 -> 903 bytes .../res/drawable-xhdpi/dialogs_check_9.png | Bin 0 -> 772 bytes .../drawable-xhdpi/dialogs_halfcheck_10.png | Bin 0 -> 903 bytes .../drawable-xhdpi/dialogs_halfcheck_11.png | Bin 0 -> 494 bytes .../drawable-xhdpi/dialogs_halfcheck_12.png | Bin 0 -> 398 bytes .../drawable-xhdpi/dialogs_halfcheck_2.png | Bin 0 -> 867 bytes .../drawable-xhdpi/dialogs_halfcheck_3.png | Bin 0 -> 786 bytes .../drawable-xhdpi/dialogs_halfcheck_4.png | Bin 0 -> 1150 bytes .../drawable-xhdpi/dialogs_halfcheck_5.png | Bin 0 -> 504 bytes .../drawable-xhdpi/dialogs_halfcheck_6.png | Bin 0 -> 444 bytes .../drawable-xhdpi/dialogs_halfcheck_7.png | Bin 0 -> 234 bytes .../drawable-xhdpi/dialogs_halfcheck_8.png | Bin 0 -> 903 bytes .../drawable-xhdpi/dialogs_halfcheck_9.png | Bin 0 -> 809 bytes .../res/drawable-xhdpi/doc_actions_b_s.png | Bin 0 -> 1114 bytes .../main/res/drawable-xhdpi/doc_blue_s.png | Bin 0 -> 1551 bytes .../main/res/drawable-xhdpi/doccancel_b_s.png | Bin 0 -> 1484 bytes .../main/res/drawable-xhdpi/docload_b_s.png | Bin 0 -> 3376 bytes .../main/res/drawable-xhdpi/docpause_b_s.png | Bin 0 -> 2087 bytes .../main/res/drawable-xhdpi/download_b.png | Bin 2280 -> 0 bytes .../res/drawable-xhdpi/download_b_pressed.png | Bin 2344 -> 0 bytes .../main/res/drawable-xhdpi/download_g.png | Bin 2272 -> 0 bytes .../res/drawable-xhdpi/download_g_pressed.png | Bin 2282 -> 0 bytes .../src/main/res/drawable-xhdpi/file_b.png | Bin 0 -> 2693 bytes .../main/res/drawable-xhdpi/file_b_cancel.png | Bin 0 -> 2708 bytes .../res/drawable-xhdpi/file_b_cancel_s.png | Bin 0 -> 2706 bytes .../main/res/drawable-xhdpi/file_b_load.png | Bin 0 -> 2479 bytes .../main/res/drawable-xhdpi/file_b_load_s.png | Bin 0 -> 2483 bytes .../src/main/res/drawable-xhdpi/file_b_s.png | Bin 0 -> 2696 bytes .../src/main/res/drawable-xhdpi/file_g.png | Bin 0 -> 2711 bytes .../main/res/drawable-xhdpi/file_g_cancel.png | Bin 0 -> 2724 bytes .../res/drawable-xhdpi/file_g_cancel_s.png | Bin 0 -> 2709 bytes .../main/res/drawable-xhdpi/file_g_load.png | Bin 0 -> 2488 bytes .../main/res/drawable-xhdpi/file_g_load_s.png | Bin 0 -> 2491 bytes .../src/main/res/drawable-xhdpi/file_g_s.png | Bin 0 -> 2696 bytes .../res/drawable-xhdpi/ic_action_next.png | Bin 0 -> 326 bytes .../res/drawable-xhdpi/ic_action_pause.png | Bin 0 -> 215 bytes .../res/drawable-xhdpi/ic_action_play.png | Bin 0 -> 399 bytes .../res/drawable-xhdpi/ic_action_previous.png | Bin 0 -> 354 bytes .../src/main/res/drawable-xhdpi/ic_create.png | Bin 0 -> 1303 bytes .../main/res/drawable-xhdpi/ic_fp_40px.png | Bin 0 -> 10524 bytes .../res/drawable-xhdpi/ic_launcher_beta.png | Bin 0 -> 3653 bytes .../main/res/drawable-xhdpi/ic_settings.png | Bin 0 -> 1768 bytes .../main/res/drawable-xhdpi/ic_smiles_gif.png | Bin 0 -> 1590 bytes .../src/main/res/drawable-xhdpi/igvideo.png | Bin 2441 -> 0 bytes .../main/res/drawable-xhdpi/list_circle.png | Bin 0 -> 1036 bytes .../res/drawable-xhdpi/list_supergroup.png | Bin 0 -> 837 bytes .../src/main/res/drawable-xhdpi/location2.png | Bin 0 -> 1053 bytes .../main/res/drawable-xhdpi/logo_avatar.png | Bin 0 -> 2195 bytes .../src/main/res/drawable-xhdpi/managers.png | Bin 0 -> 1788 bytes .../main/res/drawable-xhdpi/menu_admin.png | Bin 0 -> 830 bytes .../src/main/res/drawable-xhdpi/menu_plus.png | Bin 0 -> 1277 bytes .../main/res/drawable-xhdpi/menu_themes.png | Bin 0 -> 595 bytes .../res/drawable-xhdpi/miniplayer_close.png | Bin 0 -> 1366 bytes .../res/drawable-xhdpi/miniplayer_pause.png | Bin 0 -> 1051 bytes .../res/drawable-xhdpi/miniplayer_play.png | Bin 0 -> 1260 bytes .../main/res/drawable-xhdpi/msg_check_10.png | Bin 0 -> 502 bytes .../main/res/drawable-xhdpi/msg_check_11.png | Bin 0 -> 642 bytes .../main/res/drawable-xhdpi/msg_check_12.png | Bin 0 -> 398 bytes .../main/res/drawable-xhdpi/msg_check_2.png | Bin 0 -> 796 bytes .../main/res/drawable-xhdpi/msg_check_3.png | Bin 0 -> 757 bytes .../main/res/drawable-xhdpi/msg_check_4.png | Bin 0 -> 1377 bytes .../main/res/drawable-xhdpi/msg_check_5.png | Bin 0 -> 503 bytes .../main/res/drawable-xhdpi/msg_check_6.png | Bin 0 -> 412 bytes .../main/res/drawable-xhdpi/msg_check_7.png | Bin 0 -> 233 bytes .../main/res/drawable-xhdpi/msg_check_8.png | Bin 0 -> 849 bytes .../main/res/drawable-xhdpi/msg_check_9.png | Bin 0 -> 769 bytes .../res/drawable-xhdpi/msg_check_w_10.png | Bin 0 -> 551 bytes .../res/drawable-xhdpi/msg_check_w_11.png | Bin 0 -> 526 bytes .../res/drawable-xhdpi/msg_check_w_12.png | Bin 0 -> 366 bytes .../main/res/drawable-xhdpi/msg_check_w_2.png | Bin 0 -> 615 bytes .../main/res/drawable-xhdpi/msg_check_w_3.png | Bin 0 -> 602 bytes .../main/res/drawable-xhdpi/msg_check_w_4.png | Bin 0 -> 1473 bytes .../main/res/drawable-xhdpi/msg_check_w_5.png | Bin 0 -> 433 bytes .../main/res/drawable-xhdpi/msg_check_w_6.png | Bin 0 -> 330 bytes .../main/res/drawable-xhdpi/msg_check_w_7.png | Bin 0 -> 214 bytes .../main/res/drawable-xhdpi/msg_check_w_8.png | Bin 0 -> 764 bytes .../main/res/drawable-xhdpi/msg_check_w_9.png | Bin 0 -> 615 bytes .../main/res/drawable-xhdpi/msg_clock2.png | Bin 0 -> 1481 bytes .../main/res/drawable-xhdpi/msg_clock2_s.png | Bin 0 -> 1484 bytes .../res/drawable-xhdpi/msg_halfcheck_10.png | Bin 0 -> 849 bytes .../res/drawable-xhdpi/msg_halfcheck_11.png | Bin 0 -> 488 bytes .../res/drawable-xhdpi/msg_halfcheck_12.png | Bin 0 -> 390 bytes .../res/drawable-xhdpi/msg_halfcheck_2.png | Bin 0 -> 796 bytes .../res/drawable-xhdpi/msg_halfcheck_3.png | Bin 0 -> 757 bytes .../res/drawable-xhdpi/msg_halfcheck_4.png | Bin 0 -> 1092 bytes .../res/drawable-xhdpi/msg_halfcheck_5.png | Bin 0 -> 479 bytes .../res/drawable-xhdpi/msg_halfcheck_6.png | Bin 0 -> 411 bytes .../res/drawable-xhdpi/msg_halfcheck_7.png | Bin 0 -> 232 bytes .../res/drawable-xhdpi/msg_halfcheck_8.png | Bin 0 -> 849 bytes .../res/drawable-xhdpi/msg_halfcheck_9.png | Bin 0 -> 811 bytes .../res/drawable-xhdpi/msg_halfcheck_w_10.png | Bin 0 -> 806 bytes .../res/drawable-xhdpi/msg_halfcheck_w_11.png | Bin 0 -> 413 bytes .../res/drawable-xhdpi/msg_halfcheck_w_12.png | Bin 0 -> 369 bytes .../res/drawable-xhdpi/msg_halfcheck_w_2.png | Bin 0 -> 615 bytes .../res/drawable-xhdpi/msg_halfcheck_w_3.png | Bin 0 -> 602 bytes .../res/drawable-xhdpi/msg_halfcheck_w_4.png | Bin 0 -> 1179 bytes .../res/drawable-xhdpi/msg_halfcheck_w_5.png | Bin 0 -> 433 bytes .../res/drawable-xhdpi/msg_halfcheck_w_6.png | Bin 0 -> 348 bytes .../res/drawable-xhdpi/msg_halfcheck_w_7.png | Bin 0 -> 211 bytes .../res/drawable-xhdpi/msg_halfcheck_w_8.png | Bin 0 -> 764 bytes .../res/drawable-xhdpi/msg_halfcheck_w_9.png | Bin 0 -> 642 bytes .../main/res/drawable-xhdpi/msg_in_5.9.png | Bin 0 -> 17404 bytes .../res/drawable-xhdpi/msg_in_5_photo.9.png | Bin 0 -> 880 bytes .../msg_in_5_photo_selected.9.png | Bin 0 -> 909 bytes .../drawable-xhdpi/msg_in_5_selected.9.png | Bin 0 -> 17400 bytes .../main/res/drawable-xhdpi/msg_in_6.9.png | Bin 0 -> 17532 bytes .../res/drawable-xhdpi/msg_in_6_photo.9.png | Bin 0 -> 14829 bytes .../msg_in_6_photo_selected.9.png | Bin 0 -> 14860 bytes .../drawable-xhdpi/msg_in_6_selected.9.png | Bin 0 -> 17538 bytes .../main/res/drawable-xhdpi/msg_in_7.9.png | Bin 0 -> 17673 bytes .../res/drawable-xhdpi/msg_in_7_photo.9.png | Bin 0 -> 880 bytes .../msg_in_7_photo_selected.9.png | Bin 0 -> 909 bytes .../drawable-xhdpi/msg_in_7_selected.9.png | Bin 0 -> 17910 bytes .../main/res/drawable-xhdpi/msg_in_8.9.png | Bin 0 -> 1453 bytes .../res/drawable-xhdpi/msg_in_8_photo.9.png | Bin 0 -> 880 bytes .../msg_in_8_photo_selected.9.png | Bin 0 -> 909 bytes .../drawable-xhdpi/msg_in_8_selected.9.png | Bin 0 -> 1520 bytes .../main/res/drawable-xhdpi/msg_out_5.9.png | Bin 0 -> 17795 bytes .../res/drawable-xhdpi/msg_out_5_photo.9.png | Bin 0 -> 1799 bytes .../msg_out_5_photo_selected.9.png | Bin 0 -> 1782 bytes .../drawable-xhdpi/msg_out_5_selected.9.png | Bin 0 -> 17795 bytes .../main/res/drawable-xhdpi/msg_out_6.9.png | Bin 0 -> 17932 bytes .../res/drawable-xhdpi/msg_out_6_photo.9.png | Bin 0 -> 15358 bytes .../msg_out_6_photo_selected.9.png | Bin 0 -> 15353 bytes .../drawable-xhdpi/msg_out_6_selected.9.png | Bin 0 -> 17932 bytes .../main/res/drawable-xhdpi/msg_out_7.9.png | Bin 0 -> 18420 bytes .../res/drawable-xhdpi/msg_out_7_photo.9.png | Bin 0 -> 1799 bytes .../msg_out_7_photo_selected.9.png | Bin 0 -> 1782 bytes .../drawable-xhdpi/msg_out_7_selected.9.png | Bin 0 -> 18538 bytes .../main/res/drawable-xhdpi/msg_out_8.9.png | Bin 0 -> 2258 bytes .../res/drawable-xhdpi/msg_out_8_photo.9.png | Bin 0 -> 1799 bytes .../msg_out_8_photo_selected.9.png | Bin 0 -> 1782 bytes .../drawable-xhdpi/msg_out_8_selected.9.png | Bin 0 -> 2243 bytes .../src/main/res/drawable-xhdpi/nocover.png | Bin 0 -> 2563 bytes .../main/res/drawable-xhdpi/nocover_big.9.png | Bin 0 -> 2822 bytes .../res/drawable-xhdpi/nocover_small.9.png | Bin 0 -> 1307 bytes .../res/drawable-xhdpi/notify_members_off.png | Bin 0 -> 1781 bytes .../res/drawable-xhdpi/notify_members_on.png | Bin 0 -> 1488 bytes .../res/drawable-xhdpi/pause_b_pressed.png | Bin 2164 -> 0 bytes .../src/main/res/drawable-xhdpi/pause_b_s.png | Bin 0 -> 2404 bytes .../res/drawable-xhdpi/pause_g_pressed.png | Bin 2098 -> 0 bytes .../src/main/res/drawable-xhdpi/pause_g_s.png | Bin 0 -> 2407 bytes .../src/main/res/drawable-xhdpi/pause_w.png | Bin 2153 -> 0 bytes .../src/main/res/drawable-xhdpi/pause_w2.png | Bin 2222 -> 0 bytes .../res/drawable-xhdpi/pause_w2_pressed.png | Bin 2219 -> 0 bytes .../res/drawable-xhdpi/pause_w_pressed.png | Bin 2154 -> 0 bytes .../res/drawable-xhdpi/phone_activate.png | Bin 0 -> 5114 bytes .../main/res/drawable-xhdpi/photocancel_b.png | Bin 0 -> 2912 bytes .../res/drawable-xhdpi/photocancel_b_s.png | Bin 0 -> 2791 bytes .../main/res/drawable-xhdpi/photocancel_g.png | Bin 0 -> 2917 bytes .../res/drawable-xhdpi/photocancel_g_s.png | Bin 0 -> 2882 bytes .../drawable-xhdpi/photocancel_pressed.png | Bin 0 -> 2902 bytes .../res/drawable-xhdpi/photogif_pressed.png | Bin 0 -> 2986 bytes .../main/res/drawable-xhdpi/photoload_b.png | Bin 0 -> 2655 bytes .../main/res/drawable-xhdpi/photoload_b_s.png | Bin 0 -> 2609 bytes .../main/res/drawable-xhdpi/photoload_g.png | Bin 0 -> 2672 bytes .../main/res/drawable-xhdpi/photoload_g_s.png | Bin 0 -> 2664 bytes .../res/drawable-xhdpi/photoload_pressed.png | Bin 0 -> 2674 bytes .../main/res/drawable-xhdpi/photopause.png | Bin 1596 -> 0 bytes .../main/res/drawable-xhdpi/phototime2.9.png | Bin 0 -> 1049 bytes .../res/drawable-xhdpi/phototime2_b.9.png | Bin 0 -> 1060 bytes .../src/main/res/drawable-xhdpi/pl_back.png | Bin 0 -> 1199 bytes .../src/main/res/drawable-xhdpi/pl_next.png | Bin 0 -> 1390 bytes .../res/drawable-xhdpi/pl_next_pressed.png | Bin 0 -> 1394 bytes .../src/main/res/drawable-xhdpi/pl_pause.png | Bin 0 -> 1012 bytes .../res/drawable-xhdpi/pl_pause_pressed.png | Bin 0 -> 1004 bytes .../src/main/res/drawable-xhdpi/pl_play.png | Bin 0 -> 1437 bytes .../res/drawable-xhdpi/pl_play_pressed.png | Bin 0 -> 1449 bytes .../main/res/drawable-xhdpi/pl_previous.png | Bin 0 -> 1380 bytes .../drawable-xhdpi/pl_previous_pressed.png | Bin 0 -> 1384 bytes .../src/main/res/drawable-xhdpi/pl_repeat.png | Bin 0 -> 1161 bytes .../res/drawable-xhdpi/pl_repeat1_active.png | Bin 0 -> 1207 bytes .../res/drawable-xhdpi/pl_repeat_active.png | Bin 0 -> 1170 bytes .../main/res/drawable-xhdpi/pl_shuffle.png | Bin 0 -> 1392 bytes .../res/drawable-xhdpi/pl_shuffle_active.png | Bin 0 -> 1395 bytes .../src/main/res/drawable-xhdpi/play_b.png | Bin 0 -> 2913 bytes .../src/main/res/drawable-xhdpi/play_b_s.png | Bin 0 -> 2895 bytes .../src/main/res/drawable-xhdpi/play_g.png | Bin 0 -> 2912 bytes .../src/main/res/drawable-xhdpi/play_g_s.png | Bin 0 -> 2897 bytes .../src/main/res/drawable-xhdpi/play_w.png | Bin 2580 -> 0 bytes .../src/main/res/drawable-xhdpi/play_w2.png | Bin 2663 -> 0 bytes .../res/drawable-xhdpi/play_w2_pressed.png | Bin 2656 -> 0 bytes .../res/drawable-xhdpi/play_w_pressed.png | Bin 2589 -> 0 bytes .../src/main/res/drawable-xhdpi/player.png | Bin 0 -> 1573 bytes .../res/drawable-xhdpi/playvideo_pressed.png | Bin 0 -> 3086 bytes .../main/res/drawable-xhdpi/post_views.png | Bin 0 -> 1497 bytes .../main/res/drawable-xhdpi/post_views_s.png | Bin 0 -> 1497 bytes .../main/res/drawable-xhdpi/post_views_w.png | Bin 0 -> 1452 bytes .../main/res/drawable-xhdpi/post_viewsg.png | Bin 0 -> 1496 bytes .../src/main/res/drawable-xhdpi/publish.png | Bin 0 -> 1791 bytes .../res/drawable-xhdpi/publish_active.png | Bin 0 -> 1777 bytes .../main/res/drawable-xhdpi/recorded.9.png | Bin 0 -> 841 bytes .../src/main/res/drawable-xhdpi/redcircle.png | Bin 0 -> 1173 bytes .../src/main/res/drawable-xhdpi/s_pause.png | Bin 0 -> 976 bytes .../res/drawable-xhdpi/s_pause_pressed.png | Bin 0 -> 985 bytes .../src/main/res/drawable-xhdpi/s_play.png | Bin 0 -> 1230 bytes .../res/drawable-xhdpi/s_play_pressed.png | Bin 0 -> 1245 bytes .../main/res/drawable-xhdpi/search_down.png | Bin 0 -> 1054 bytes .../main/res/drawable-xhdpi/search_share.png | Bin 0 -> 1640 bytes .../src/main/res/drawable-xhdpi/search_up.png | Bin 0 -> 1058 bytes .../main/res/drawable-xhdpi/share_arrow.png | Bin 0 -> 1307 bytes .../main/res/drawable-xhdpi/share_round.png | Bin 0 -> 1800 bytes .../res/drawable-xhdpi/sheet_shadow.9.png | Bin 0 -> 419 bytes .../res/drawable-xhdpi/stickercounter.9.png | Bin 0 -> 1628 bytes .../src/main/res/drawable-xhdpi/system.9.png | Bin 0 -> 1276 bytes .../res/drawable-xhdpi/system_black.9.png | Bin 238 -> 0 bytes .../main/res/drawable-xhdpi/system_blue.9.png | Bin 1204 -> 0 bytes .../main/res/drawable-xhdpi/system_loader.png | Bin 0 -> 1966 bytes .../res/drawable-xhdpi/system_loader1.png | Bin 1118 -> 0 bytes .../res/drawable-xhdpi/system_loader2.png | Bin 1076 -> 0 bytes .../src/main/res/drawable-xhdpi/tab_all.png | Bin 0 -> 651 bytes .../src/main/res/drawable-xhdpi/tab_bot.png | Bin 0 -> 1221 bytes .../main/res/drawable-xhdpi/tab_channel.png | Bin 0 -> 1423 bytes .../src/main/res/drawable-xhdpi/tab_favs.png | Bin 0 -> 600 bytes .../src/main/res/drawable-xhdpi/tab_group.png | Bin 0 -> 983 bytes .../res/drawable-xhdpi/tab_supergroup.png | Bin 0 -> 1178 bytes .../src/main/res/drawable-xhdpi/tab_user.png | Bin 0 -> 431 bytes .../src/main/res/drawable-xhdpi/tip3.png | Bin 0 -> 30328 bytes .../src/main/res/drawable-xhdpi/tip4.png | Bin 0 -> 19278 bytes .../main/res/drawable-xhdpi/tool_cropfix.png | Bin 0 -> 1072 bytes .../main/res/drawable-xhdpi/tool_curve.png | Bin 0 -> 1247 bytes .../src/main/res/drawable-xhdpi/tool_fade.png | Bin 0 -> 1359 bytes .../main/res/drawable-xhdpi/tool_rotate.png | Bin 0 -> 1504 bytes .../src/main/res/drawable-xhdpi/tool_tint.png | Bin 0 -> 1288 bytes .../src/main/res/drawable-xhdpi/tooltip.9.png | Bin 0 -> 200 bytes .../main/res/drawable-xhdpi/video_actions.png | Bin 0 -> 1166 bytes .../src/main/res/drawable-xxhdpi/Thumbs.db | Bin 1097728 -> 0 bytes .../abc_ic_menu_share_mtrl_alpha.png | Bin 0 -> 724 bytes .../res/drawable-xxhdpi/addcontact_blue.png | Bin 1014 -> 0 bytes .../res/drawable-xxhdpi/addcontact_green.png | Bin 1012 -> 0 bytes .../main/res/drawable-xxhdpi/admin_star.png | Bin 0 -> 1565 bytes .../main/res/drawable-xxhdpi/admin_star2.png | Bin 0 -> 1625 bytes .../res/drawable-xxhdpi/assign_manager.png | Bin 0 -> 1791 bytes .../main/res/drawable-xxhdpi/attach_audio.png | Bin 0 -> 5187 bytes .../drawable-xxhdpi/attach_audio_pressed.png | Bin 0 -> 5237 bytes .../res/drawable-xxhdpi/attach_camera.png | Bin 0 -> 6368 bytes .../drawable-xxhdpi/attach_camera_pressed.png | Bin 0 -> 6375 bytes .../res/drawable-xxhdpi/attach_contact.png | Bin 0 -> 4898 bytes .../attach_contact_pressed.png | Bin 0 -> 4959 bytes .../main/res/drawable-xxhdpi/attach_file.png | Bin 0 -> 4297 bytes .../drawable-xxhdpi/attach_file_pressed.png | Bin 0 -> 4269 bytes .../res/drawable-xxhdpi/attach_gallery.png | Bin 0 -> 4425 bytes .../attach_gallery_pressed.png | Bin 0 -> 4444 bytes .../main/res/drawable-xxhdpi/attach_hide1.png | Bin 0 -> 3655 bytes .../drawable-xxhdpi/attach_hide1_pressed.png | Bin 0 -> 3648 bytes .../main/res/drawable-xxhdpi/attach_hide2.png | Bin 0 -> 1301 bytes .../res/drawable-xxhdpi/attach_location.png | Bin 0 -> 5425 bytes .../attach_location_pressed.png | Bin 0 -> 5429 bytes .../main/res/drawable-xxhdpi/attach_send1.png | Bin 0 -> 3664 bytes .../drawable-xxhdpi/attach_send1_pressed.png | Bin 0 -> 3650 bytes .../main/res/drawable-xxhdpi/attach_send2.png | Bin 0 -> 2009 bytes .../main/res/drawable-xxhdpi/attach_video.png | Bin 0 -> 3867 bytes .../drawable-xxhdpi/attach_video_pressed.png | Bin 0 -> 4454 bytes .../res/drawable-xxhdpi/audiosend_pause.png | Bin 0 -> 3224 bytes .../res/drawable-xxhdpi/audiosend_play.png | Bin 0 -> 4247 bytes .../main/res/drawable-xxhdpi/blockpanel.png | Bin 0 -> 994 bytes .../res/drawable-xxhdpi/bluecounter.9.png | Bin 0 -> 961 bytes .../src/main/res/drawable-xxhdpi/bot_file.png | Bin 0 -> 1334 bytes .../src/main/res/drawable-xxhdpi/bot_info.png | Bin 0 -> 2461 bytes .../main/res/drawable-xxhdpi/bot_keyboard.png | Bin 0 -> 2644 bytes .../res/drawable-xxhdpi/bot_keyboard2.png | Bin 0 -> 2074 bytes .../drawable-xxhdpi/bot_keyboard_button.9.png | Bin 0 -> 315 bytes .../bot_keyboard_button_pressed.9.png | Bin 0 -> 321 bytes .../main/res/drawable-xxhdpi/bot_lines.png | Bin 0 -> 1336 bytes .../src/main/res/drawable-xxhdpi/bot_link.png | Bin 0 -> 1095 bytes .../src/main/res/drawable-xxhdpi/bot_list.png | Bin 0 -> 1631 bytes .../main/res/drawable-xxhdpi/bot_location.png | Bin 0 -> 2420 bytes .../main/res/drawable-xxhdpi/bot_music.png | Bin 0 -> 2081 bytes .../src/main/res/drawable-xxhdpi/cancel_b.png | Bin 3190 -> 0 bytes .../res/drawable-xxhdpi/cancel_b_pressed.png | Bin 3161 -> 0 bytes .../src/main/res/drawable-xxhdpi/cancel_g.png | Bin 3187 -> 0 bytes .../res/drawable-xxhdpi/cancel_g_pressed.png | Bin 3197 -> 0 bytes .../main/res/drawable-xxhdpi/channelintro.png | Bin 0 -> 76438 bytes .../main/res/drawable-xxhdpi/check_list.png | Bin 0 -> 1148 bytes .../res/drawable-xxhdpi/check_profile.png | Bin 0 -> 1246 bytes .../main/res/drawable-xxhdpi/contact_blue.png | Bin 0 -> 3861 bytes .../res/drawable-xxhdpi/contact_green.png | Bin 0 -> 3884 bytes .../main/res/drawable-xxhdpi/corner_in_bl.png | Bin 0 -> 1014 bytes .../main/res/drawable-xxhdpi/corner_in_br.png | Bin 0 -> 998 bytes .../main/res/drawable-xxhdpi/corner_in_tl.png | Bin 0 -> 1017 bytes .../main/res/drawable-xxhdpi/corner_in_tr.png | Bin 0 -> 1008 bytes .../res/drawable-xxhdpi/corner_out_bl.png | Bin 0 -> 1072 bytes .../res/drawable-xxhdpi/corner_out_br.png | Bin 0 -> 1058 bytes .../res/drawable-xxhdpi/corner_out_tl.png | Bin 0 -> 1087 bytes .../res/drawable-xxhdpi/corner_out_tr.png | Bin 0 -> 1079 bytes .../res/drawable-xxhdpi/dialogs_badge2.9.png | Bin 0 -> 2069 bytes .../res/drawable-xxhdpi/dialogs_check_10.png | Bin 0 -> 680 bytes .../res/drawable-xxhdpi/dialogs_check_11.png | Bin 0 -> 760 bytes .../res/drawable-xxhdpi/dialogs_check_12.png | Bin 0 -> 542 bytes .../res/drawable-xxhdpi/dialogs_check_2.png | Bin 0 -> 1033 bytes .../res/drawable-xxhdpi/dialogs_check_3.png | Bin 0 -> 954 bytes .../res/drawable-xxhdpi/dialogs_check_4.png | Bin 0 -> 2514 bytes .../res/drawable-xxhdpi/dialogs_check_5.png | Bin 0 -> 746 bytes .../res/drawable-xxhdpi/dialogs_check_6.png | Bin 0 -> 745 bytes .../res/drawable-xxhdpi/dialogs_check_7.png | Bin 0 -> 429 bytes .../res/drawable-xxhdpi/dialogs_check_8.png | Bin 0 -> 1275 bytes .../res/drawable-xxhdpi/dialogs_check_9.png | Bin 0 -> 1154 bytes .../drawable-xxhdpi/dialogs_halfcheck_10.png | Bin 0 -> 1275 bytes .../drawable-xxhdpi/dialogs_halfcheck_11.png | Bin 0 -> 557 bytes .../drawable-xxhdpi/dialogs_halfcheck_12.png | Bin 0 -> 522 bytes .../drawable-xxhdpi/dialogs_halfcheck_2.png | Bin 0 -> 1109 bytes .../drawable-xxhdpi/dialogs_halfcheck_3.png | Bin 0 -> 1005 bytes .../drawable-xxhdpi/dialogs_halfcheck_4.png | Bin 0 -> 1794 bytes .../drawable-xxhdpi/dialogs_halfcheck_5.png | Bin 0 -> 696 bytes .../drawable-xxhdpi/dialogs_halfcheck_6.png | Bin 0 -> 673 bytes .../drawable-xxhdpi/dialogs_halfcheck_7.png | Bin 0 -> 440 bytes .../drawable-xxhdpi/dialogs_halfcheck_8.png | Bin 0 -> 1275 bytes .../drawable-xxhdpi/dialogs_halfcheck_9.png | Bin 0 -> 940 bytes .../res/drawable-xxhdpi/doc_actions_b_s.png | Bin 0 -> 1249 bytes .../main/res/drawable-xxhdpi/doc_blue_s.png | Bin 0 -> 1868 bytes .../res/drawable-xxhdpi/doccancel_b_s.png | Bin 0 -> 1644 bytes .../main/res/drawable-xxhdpi/docload_b_s.png | Bin 0 -> 4642 bytes .../main/res/drawable-xxhdpi/docpause_b_s.png | Bin 0 -> 1220 bytes .../main/res/drawable-xxhdpi/download_b.png | Bin 2878 -> 0 bytes .../drawable-xxhdpi/download_b_pressed.png | Bin 2949 -> 0 bytes .../main/res/drawable-xxhdpi/download_g.png | Bin 2900 -> 0 bytes .../drawable-xxhdpi/download_g_pressed.png | Bin 2904 -> 0 bytes .../src/main/res/drawable-xxhdpi/file_b.png | Bin 0 -> 3509 bytes .../res/drawable-xxhdpi/file_b_cancel.png | Bin 0 -> 3570 bytes .../res/drawable-xxhdpi/file_b_cancel_s.png | Bin 0 -> 3603 bytes .../main/res/drawable-xxhdpi/file_b_load.png | Bin 0 -> 3301 bytes .../res/drawable-xxhdpi/file_b_load_s.png | Bin 0 -> 3303 bytes .../src/main/res/drawable-xxhdpi/file_b_s.png | Bin 0 -> 3493 bytes .../src/main/res/drawable-xxhdpi/file_g.png | Bin 0 -> 3505 bytes .../res/drawable-xxhdpi/file_g_cancel.png | Bin 0 -> 3605 bytes .../res/drawable-xxhdpi/file_g_cancel_s.png | Bin 0 -> 3579 bytes .../main/res/drawable-xxhdpi/file_g_load.png | Bin 0 -> 3288 bytes .../res/drawable-xxhdpi/file_g_load_s.png | Bin 0 -> 3295 bytes .../src/main/res/drawable-xxhdpi/file_g_s.png | Bin 0 -> 3492 bytes .../res/drawable-xxhdpi/ic_action_next.png | Bin 0 -> 408 bytes .../res/drawable-xxhdpi/ic_action_pause.png | Bin 0 -> 293 bytes .../res/drawable-xxhdpi/ic_action_play.png | Bin 0 -> 543 bytes .../drawable-xxhdpi/ic_action_previous.png | Bin 0 -> 447 bytes .../main/res/drawable-xxhdpi/ic_create.png | Bin 0 -> 1455 bytes .../main/res/drawable-xxhdpi/ic_fp_40px.png | Bin 0 -> 18565 bytes .../res/drawable-xxhdpi/ic_launcher_beta.png | Bin 0 -> 6113 bytes .../main/res/drawable-xxhdpi/ic_settings.png | Bin 0 -> 2280 bytes .../res/drawable-xxhdpi/ic_smiles_gif.png | Bin 0 -> 1793 bytes .../src/main/res/drawable-xxhdpi/igvideo.png | Bin 4398 -> 0 bytes .../main/res/drawable-xxhdpi/list_circle.png | Bin 0 -> 1096 bytes .../main/res/drawable-xxhdpi/location2.png | Bin 0 -> 1544 bytes .../main/res/drawable-xxhdpi/logo_avatar.png | Bin 0 -> 3327 bytes .../src/main/res/drawable-xxhdpi/managers.png | Bin 0 -> 2120 bytes .../main/res/drawable-xxhdpi/menu_admin.png | Bin 0 -> 1221 bytes .../main/res/drawable-xxhdpi/menu_plus.png | Bin 0 -> 1827 bytes .../main/res/drawable-xxhdpi/menu_themes.png | Bin 0 -> 833 bytes .../res/drawable-xxhdpi/miniplayer_close.png | Bin 0 -> 1672 bytes .../res/drawable-xxhdpi/miniplayer_pause.png | Bin 0 -> 1068 bytes .../res/drawable-xxhdpi/miniplayer_play.png | Bin 0 -> 1396 bytes .../main/res/drawable-xxhdpi/msg_check_10.png | Bin 0 -> 667 bytes .../main/res/drawable-xxhdpi/msg_check_11.png | Bin 0 -> 746 bytes .../main/res/drawable-xxhdpi/msg_check_12.png | Bin 0 -> 503 bytes .../main/res/drawable-xxhdpi/msg_check_2.png | Bin 0 -> 1235 bytes .../main/res/drawable-xxhdpi/msg_check_3.png | Bin 0 -> 878 bytes .../main/res/drawable-xxhdpi/msg_check_4.png | Bin 0 -> 2320 bytes .../main/res/drawable-xxhdpi/msg_check_5.png | Bin 0 -> 689 bytes .../main/res/drawable-xxhdpi/msg_check_6.png | Bin 0 -> 593 bytes .../main/res/drawable-xxhdpi/msg_check_7.png | Bin 0 -> 297 bytes .../main/res/drawable-xxhdpi/msg_check_8.png | Bin 0 -> 1221 bytes .../main/res/drawable-xxhdpi/msg_check_9.png | Bin 0 -> 1024 bytes .../res/drawable-xxhdpi/msg_check_w_10.png | Bin 0 -> 790 bytes .../res/drawable-xxhdpi/msg_check_w_11.png | Bin 0 -> 684 bytes .../res/drawable-xxhdpi/msg_check_w_12.png | Bin 0 -> 473 bytes .../res/drawable-xxhdpi/msg_check_w_2.png | Bin 0 -> 901 bytes .../res/drawable-xxhdpi/msg_check_w_3.png | Bin 0 -> 850 bytes .../res/drawable-xxhdpi/msg_check_w_4.png | Bin 0 -> 2380 bytes .../res/drawable-xxhdpi/msg_check_w_5.png | Bin 0 -> 642 bytes .../res/drawable-xxhdpi/msg_check_w_6.png | Bin 0 -> 474 bytes .../res/drawable-xxhdpi/msg_check_w_7.png | Bin 0 -> 359 bytes .../res/drawable-xxhdpi/msg_check_w_8.png | Bin 0 -> 1129 bytes .../res/drawable-xxhdpi/msg_check_w_9.png | Bin 0 -> 987 bytes .../main/res/drawable-xxhdpi/msg_clock2.png | Bin 0 -> 1717 bytes .../main/res/drawable-xxhdpi/msg_clock2_s.png | Bin 0 -> 1717 bytes .../res/drawable-xxhdpi/msg_halfcheck_10.png | Bin 0 -> 1221 bytes .../res/drawable-xxhdpi/msg_halfcheck_11.png | Bin 0 -> 549 bytes .../res/drawable-xxhdpi/msg_halfcheck_12.png | Bin 0 -> 492 bytes .../res/drawable-xxhdpi/msg_halfcheck_2.png | Bin 0 -> 1319 bytes .../res/drawable-xxhdpi/msg_halfcheck_3.png | Bin 0 -> 919 bytes .../res/drawable-xxhdpi/msg_halfcheck_4.png | Bin 0 -> 1704 bytes .../res/drawable-xxhdpi/msg_halfcheck_5.png | Bin 0 -> 653 bytes .../res/drawable-xxhdpi/msg_halfcheck_6.png | Bin 0 -> 597 bytes .../res/drawable-xxhdpi/msg_halfcheck_7.png | Bin 0 -> 312 bytes .../res/drawable-xxhdpi/msg_halfcheck_8.png | Bin 0 -> 1226 bytes .../res/drawable-xxhdpi/msg_halfcheck_9.png | Bin 0 -> 927 bytes .../drawable-xxhdpi/msg_halfcheck_w_10.png | Bin 0 -> 1143 bytes .../drawable-xxhdpi/msg_halfcheck_w_11.png | Bin 0 -> 516 bytes .../drawable-xxhdpi/msg_halfcheck_w_12.png | Bin 0 -> 463 bytes .../res/drawable-xxhdpi/msg_halfcheck_w_2.png | Bin 0 -> 901 bytes .../res/drawable-xxhdpi/msg_halfcheck_w_3.png | Bin 0 -> 850 bytes .../res/drawable-xxhdpi/msg_halfcheck_w_4.png | Bin 0 -> 1785 bytes .../res/drawable-xxhdpi/msg_halfcheck_w_5.png | Bin 0 -> 626 bytes .../res/drawable-xxhdpi/msg_halfcheck_w_6.png | Bin 0 -> 478 bytes .../res/drawable-xxhdpi/msg_halfcheck_w_7.png | Bin 0 -> 362 bytes .../res/drawable-xxhdpi/msg_halfcheck_w_8.png | Bin 0 -> 1129 bytes .../res/drawable-xxhdpi/msg_halfcheck_w_9.png | Bin 0 -> 883 bytes .../main/res/drawable-xxhdpi/msg_in_5.9.png | Bin 0 -> 17479 bytes .../res/drawable-xxhdpi/msg_in_5_photo.9.png | Bin 0 -> 1332 bytes .../msg_in_5_photo_selected.9.png | Bin 0 -> 1426 bytes .../drawable-xxhdpi/msg_in_5_selected.9.png | Bin 0 -> 17486 bytes .../main/res/drawable-xxhdpi/msg_in_6.9.png | Bin 0 -> 17618 bytes .../res/drawable-xxhdpi/msg_in_6_photo.9.png | Bin 0 -> 14914 bytes .../msg_in_6_photo_selected.9.png | Bin 0 -> 14943 bytes .../drawable-xxhdpi/msg_in_6_selected.9.png | Bin 0 -> 17632 bytes .../main/res/drawable-xxhdpi/msg_in_7.9.png | Bin 0 -> 17751 bytes .../res/drawable-xxhdpi/msg_in_7_photo.9.png | Bin 0 -> 1332 bytes .../msg_in_7_photo_selected.9.png | Bin 0 -> 1426 bytes .../drawable-xxhdpi/msg_in_7_selected.9.png | Bin 0 -> 17556 bytes .../main/res/drawable-xxhdpi/msg_in_8.9.png | Bin 0 -> 2231 bytes .../res/drawable-xxhdpi/msg_in_8_photo.9.png | Bin 0 -> 1332 bytes .../msg_in_8_photo_selected.9.png | Bin 0 -> 1426 bytes .../drawable-xxhdpi/msg_in_8_selected.9.png | Bin 0 -> 2361 bytes .../main/res/drawable-xxhdpi/msg_out_5.9.png | Bin 0 -> 17782 bytes .../res/drawable-xxhdpi/msg_out_5_photo.9.png | Bin 0 -> 2376 bytes .../msg_out_5_photo_selected.9.png | Bin 0 -> 2375 bytes .../drawable-xxhdpi/msg_out_5_selected.9.png | Bin 0 -> 17782 bytes .../main/res/drawable-xxhdpi/msg_out_6.9.png | Bin 0 -> 17924 bytes .../res/drawable-xxhdpi/msg_out_6_photo.9.png | Bin 0 -> 15435 bytes .../msg_out_6_photo_selected.9.png | Bin 0 -> 15437 bytes .../drawable-xxhdpi/msg_out_6_selected.9.png | Bin 0 -> 17924 bytes .../main/res/drawable-xxhdpi/msg_out_7.9.png | Bin 0 -> 17650 bytes .../res/drawable-xxhdpi/msg_out_7_photo.9.png | Bin 0 -> 2376 bytes .../msg_out_7_photo_selected.9.png | Bin 0 -> 2375 bytes .../drawable-xxhdpi/msg_out_7_selected.9.png | Bin 0 -> 18597 bytes .../main/res/drawable-xxhdpi/msg_out_8.9.png | Bin 0 -> 3076 bytes .../res/drawable-xxhdpi/msg_out_8_photo.9.png | Bin 0 -> 2376 bytes .../msg_out_8_photo_selected.9.png | Bin 0 -> 2375 bytes .../drawable-xxhdpi/msg_out_8_selected.9.png | Bin 0 -> 3062 bytes .../src/main/res/drawable-xxhdpi/nocover.png | Bin 0 -> 3273 bytes .../res/drawable-xxhdpi/nocover_big.9.png | Bin 0 -> 2944 bytes .../res/drawable-xxhdpi/nocover_small.9.png | Bin 0 -> 1772 bytes .../drawable-xxhdpi/notify_members_off.png | Bin 0 -> 2403 bytes .../res/drawable-xxhdpi/notify_members_on.png | Bin 0 -> 1764 bytes .../res/drawable-xxhdpi/pause_b_pressed.png | Bin 2888 -> 0 bytes .../main/res/drawable-xxhdpi/pause_b_s.png | Bin 0 -> 3192 bytes .../res/drawable-xxhdpi/pause_g_pressed.png | Bin 2829 -> 0 bytes .../main/res/drawable-xxhdpi/pause_g_s.png | Bin 0 -> 3189 bytes .../src/main/res/drawable-xxhdpi/pause_w.png | Bin 2785 -> 0 bytes .../src/main/res/drawable-xxhdpi/pause_w2.png | Bin 2895 -> 0 bytes .../res/drawable-xxhdpi/pause_w2_pressed.png | Bin 2896 -> 0 bytes .../res/drawable-xxhdpi/pause_w_pressed.png | Bin 2830 -> 0 bytes .../res/drawable-xxhdpi/phone_activate.png | Bin 0 -> 7188 bytes .../res/drawable-xxhdpi/photocancel_b.png | Bin 0 -> 3783 bytes .../res/drawable-xxhdpi/photocancel_b_s.png | Bin 0 -> 3642 bytes .../res/drawable-xxhdpi/photocancel_g.png | Bin 0 -> 3807 bytes .../res/drawable-xxhdpi/photocancel_g_s.png | Bin 0 -> 3758 bytes .../drawable-xxhdpi/photocancel_pressed.png | Bin 0 -> 4012 bytes .../res/drawable-xxhdpi/photogif_pressed.png | Bin 0 -> 4084 bytes .../main/res/drawable-xxhdpi/photoload_b.png | Bin 0 -> 3421 bytes .../res/drawable-xxhdpi/photoload_b_s.png | Bin 0 -> 3348 bytes .../main/res/drawable-xxhdpi/photoload_g.png | Bin 0 -> 3417 bytes .../res/drawable-xxhdpi/photoload_g_s.png | Bin 0 -> 3424 bytes .../res/drawable-xxhdpi/photoload_pressed.png | Bin 0 -> 3558 bytes .../main/res/drawable-xxhdpi/photopause.png | Bin 2385 -> 0 bytes .../main/res/drawable-xxhdpi/phototime2.9.png | Bin 0 -> 1104 bytes .../res/drawable-xxhdpi/phototime2_b.9.png | Bin 0 -> 1110 bytes .../src/main/res/drawable-xxhdpi/pl_back.png | Bin 0 -> 1317 bytes .../src/main/res/drawable-xxhdpi/pl_next.png | Bin 0 -> 1542 bytes .../res/drawable-xxhdpi/pl_next_pressed.png | Bin 0 -> 1546 bytes .../src/main/res/drawable-xxhdpi/pl_pause.png | Bin 0 -> 1040 bytes .../res/drawable-xxhdpi/pl_pause_pressed.png | Bin 0 -> 1037 bytes .../src/main/res/drawable-xxhdpi/pl_play.png | Bin 0 -> 1759 bytes .../res/drawable-xxhdpi/pl_play_pressed.png | Bin 0 -> 1759 bytes .../main/res/drawable-xxhdpi/pl_previous.png | Bin 0 -> 1505 bytes .../drawable-xxhdpi/pl_previous_pressed.png | Bin 0 -> 1509 bytes .../main/res/drawable-xxhdpi/pl_repeat.png | Bin 0 -> 1263 bytes .../res/drawable-xxhdpi/pl_repeat1_active.png | Bin 0 -> 1320 bytes .../res/drawable-xxhdpi/pl_repeat_active.png | Bin 0 -> 1273 bytes .../main/res/drawable-xxhdpi/pl_shuffle.png | Bin 0 -> 1718 bytes .../res/drawable-xxhdpi/pl_shuffle_active.png | Bin 0 -> 1712 bytes .../src/main/res/drawable-xxhdpi/play_b.png | Bin 0 -> 3742 bytes .../src/main/res/drawable-xxhdpi/play_b_s.png | Bin 0 -> 3696 bytes .../src/main/res/drawable-xxhdpi/play_g.png | Bin 0 -> 3746 bytes .../src/main/res/drawable-xxhdpi/play_g_s.png | Bin 0 -> 3701 bytes .../src/main/res/drawable-xxhdpi/play_w.png | Bin 3433 -> 0 bytes .../src/main/res/drawable-xxhdpi/play_w2.png | Bin 3551 -> 0 bytes .../res/drawable-xxhdpi/play_w2_pressed.png | Bin 3547 -> 0 bytes .../res/drawable-xxhdpi/play_w_pressed.png | Bin 3498 -> 0 bytes .../src/main/res/drawable-xxhdpi/player.png | Bin 0 -> 2047 bytes .../res/drawable-xxhdpi/playvideo_pressed.png | Bin 0 -> 3984 bytes .../main/res/drawable-xxhdpi/post_views.png | Bin 0 -> 1770 bytes .../main/res/drawable-xxhdpi/post_views_s.png | Bin 0 -> 1764 bytes .../main/res/drawable-xxhdpi/post_views_w.png | Bin 0 -> 1725 bytes .../main/res/drawable-xxhdpi/post_viewsg.png | Bin 0 -> 1780 bytes .../src/main/res/drawable-xxhdpi/publish.png | Bin 0 -> 2276 bytes .../res/drawable-xxhdpi/publish_active.png | Bin 0 -> 2252 bytes .../main/res/drawable-xxhdpi/recorded.9.png | Bin 0 -> 1412 bytes .../main/res/drawable-xxhdpi/redcircle.png | Bin 0 -> 1290 bytes .../src/main/res/drawable-xxhdpi/s_pause.png | Bin 0 -> 992 bytes .../res/drawable-xxhdpi/s_pause_pressed.png | Bin 0 -> 1001 bytes .../src/main/res/drawable-xxhdpi/s_play.png | Bin 0 -> 1435 bytes .../res/drawable-xxhdpi/s_play_pressed.png | Bin 0 -> 1444 bytes .../main/res/drawable-xxhdpi/search_down.png | Bin 0 -> 1136 bytes .../main/res/drawable-xxhdpi/search_share.png | Bin 0 -> 2072 bytes .../main/res/drawable-xxhdpi/search_up.png | Bin 0 -> 1125 bytes .../main/res/drawable-xxhdpi/share_arrow.png | Bin 0 -> 1511 bytes .../main/res/drawable-xxhdpi/share_round.png | Bin 0 -> 2389 bytes .../res/drawable-xxhdpi/sheet_shadow.9.png | Bin 0 -> 703 bytes .../res/drawable-xxhdpi/stickercounter.9.png | Bin 0 -> 2068 bytes .../res/drawable-xxhdpi/switch_to_on3.9.png | Bin 0 -> 19985 bytes .../src/main/res/drawable-xxhdpi/system.9.png | Bin 0 -> 1479 bytes .../res/drawable-xxhdpi/system_black.9.png | Bin 330 -> 0 bytes .../res/drawable-xxhdpi/system_blue.9.png | Bin 1309 -> 0 bytes .../res/drawable-xxhdpi/system_loader.png | Bin 0 -> 2517 bytes .../res/drawable-xxhdpi/system_loader1.png | Bin 1665 -> 0 bytes .../res/drawable-xxhdpi/system_loader2.png | Bin 1596 -> 0 bytes .../src/main/res/drawable-xxhdpi/tab_all.png | Bin 0 -> 713 bytes .../src/main/res/drawable-xxhdpi/tab_bot.png | Bin 0 -> 1919 bytes .../main/res/drawable-xxhdpi/tab_channel.png | Bin 0 -> 1610 bytes .../src/main/res/drawable-xxhdpi/tab_favs.png | Bin 0 -> 851 bytes .../main/res/drawable-xxhdpi/tab_group.png | Bin 0 -> 1441 bytes .../res/drawable-xxhdpi/tab_supergroup.png | Bin 0 -> 1869 bytes .../src/main/res/drawable-xxhdpi/tab_user.png | Bin 0 -> 576 bytes .../src/main/res/drawable-xxhdpi/tip3.png | Bin 0 -> 51015 bytes .../src/main/res/drawable-xxhdpi/tip4.png | Bin 0 -> 30829 bytes .../main/res/drawable-xxhdpi/tool_cropfix.png | Bin 0 -> 1183 bytes .../main/res/drawable-xxhdpi/tool_curve.png | Bin 0 -> 1464 bytes .../main/res/drawable-xxhdpi/tool_fade.png | Bin 0 -> 1431 bytes .../main/res/drawable-xxhdpi/tool_rotate.png | Bin 0 -> 1824 bytes .../main/res/drawable-xxhdpi/tool_tint.png | Bin 0 -> 1503 bytes .../main/res/drawable-xxhdpi/tooltip.9.png | Bin 0 -> 267 bytes .../res/drawable-xxhdpi/video_actions.png | Bin 0 -> 1302 bytes .../res/drawable-xxxhdpi/ic_launcher_beta.png | Bin 0 -> 8725 bytes .../res/drawable-xxxhdpi/sheet_shadow.9.png | Bin 0 -> 977 bytes .../main/res/drawable/attach_audio_states.xml | 6 + .../res/drawable/attach_camera_states.xml | 6 + .../res/drawable/attach_contact_states.xml | 6 + .../main/res/drawable/attach_file_states.xml | 6 + .../res/drawable/attach_gallery_states.xml | 6 + .../main/res/drawable/attach_hide_states.xml | 6 + .../res/drawable/attach_location_states.xml | 6 + .../main/res/drawable/attach_send_states.xml | 6 + .../main/res/drawable/attach_video_states.xml | 6 + .../src/main/res/drawable/bar_selector.xml | 22 - .../main/res/drawable/bar_selector_blue.xml | 19 - .../main/res/drawable/bar_selector_cyan.xml | 19 - .../main/res/drawable/bar_selector_green.xml | 19 - .../main/res/drawable/bar_selector_mode.xml | 25 - .../main/res/drawable/bar_selector_picker.xml | 27 - .../main/res/drawable/bar_selector_pink.xml | 19 - .../main/res/drawable/bar_selector_red.xml | 19 - .../main/res/drawable/bar_selector_violet.xml | 19 - .../main/res/drawable/bar_selector_yellow.xml | 19 - .../main/res/drawable/bot_keyboard_states.xml | 15 + .../main/res/drawable/check_profile_fixed.xml | 8 + .../src/main/res/drawable/field_carret.xml | 7 + .../res/drawable/ic_fingerprint_error.xml | 28 + ...tor_orange.xml => list_selector_white.xml} | 12 +- .../main/res/drawable/player_next_states.xml | 6 + .../main/res/drawable/player_pause_states.xml | 6 + .../main/res/drawable/player_play_states.xml | 6 + .../main/res/drawable/player_prev_states.xml | 6 + .../res/drawable/s_player_pause_states.xml | 6 + .../res/drawable/s_player_play_states.xml | 6 + .../src/main/res/layout/identicon_layout.xml | 46 - .../res/layout/player_big_notification.xml | 122 + .../res/layout/player_small_notification.xml | 116 + .../src/main/res/values-eo/strings.xml | 1253 + .../src/main/res/values-eu/strings.xml | 1242 + .../src/main/res/values-fa/strings.xml | 1407 ++ .../src/main/res/values-he/strings.xml | 1293 + .../src/main/res/values-iw/strings.xml | 1295 + .../src/main/res/values-ja/strings.xml | 1058 + .../src/main/res/values-sr/strings.xml | 948 + .../src/main/res/values-uk/strings.xml | 795 + .../src/main/res/xml/automotive_app_desc.xml | 4 + 2452 files changed, 416222 insertions(+), 8051 deletions(-) create mode 100644 TMessagesProj/jni/NativeLoader.cpp create mode 100644 TMessagesProj/jni/TgNetWrapper.cpp create mode 100644 TMessagesProj/jni/boringssl/LICENSE create mode 100644 TMessagesProj/jni/boringssl/README.MD create mode 100644 TMessagesProj/jni/boringssl/crypto/.gitignore create mode 100644 TMessagesProj/jni/boringssl/crypto/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/aes/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/aes/aes.c create mode 100644 TMessagesProj/jni/boringssl/crypto/aes/aes_ige.c create mode 100644 TMessagesProj/jni/boringssl/crypto/aes/asm/aes-586.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/aes/asm/aes-armv4.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/aes/asm/aes-x86_64.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/aes/asm/aesni-x86.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/aes/asm/aesni-x86_64.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/aes/asm/aesv8-armx.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/aes/asm/bsaes-armv7.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/aes/asm/bsaes-x86_64.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/aes/asm/vpaes-x86.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/aes/asm/vpaes-x86_64.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/aes/internal.h create mode 100644 TMessagesProj/jni/boringssl/crypto/aes/mode_wrappers.c create mode 100644 TMessagesProj/jni/boringssl/crypto/arm_arch.h create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/a_bitstr.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/a_bool.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/a_bytes.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/a_d2i_fp.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/a_dup.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/a_enum.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/a_gentm.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/a_i2d_fp.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/a_int.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/a_mbstr.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/a_object.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/a_octet.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/a_print.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/a_strnid.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/a_time.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/a_type.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/a_utctm.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/a_utf8.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/asn1_lib.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/asn1_locl.h create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/asn1_par.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/asn_pack.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/bio_asn1.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/bio_ndef.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/charmap.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/f_enum.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/f_int.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/f_string.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/t_bitst.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/t_pkey.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/tasn_dec.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/tasn_enc.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/tasn_fre.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/tasn_new.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/tasn_prn.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/tasn_typ.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/tasn_utl.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/x_bignum.c create mode 100644 TMessagesProj/jni/boringssl/crypto/asn1/x_long.c create mode 100644 TMessagesProj/jni/boringssl/crypto/base64/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/base64/base64.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bio/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/bio/bio.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bio/bio_mem.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bio/buffer.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bio/connect.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bio/fd.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bio/file.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bio/hexdump.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bio/internal.h create mode 100644 TMessagesProj/jni/boringssl/crypto/bio/pair.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bio/printf.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bio/socket.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bio/socket_helper.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bn/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/bn/add.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bn/asm/armv4-mont.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/bn/asm/bn-586.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/bn/asm/co-586.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/bn/asm/rsaz-avx2.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/bn/asm/rsaz-x86_64.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/bn/asm/x86-mont.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/bn/asm/x86_64-gcc.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bn/asm/x86_64-mont.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/bn/asm/x86_64-mont5.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/bn/bn.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bn/bn_asn1.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bn/cmp.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bn/convert.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bn/ctx.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bn/div.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bn/exponentiation.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bn/gcd.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bn/generic.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bn/internal.h create mode 100644 TMessagesProj/jni/boringssl/crypto/bn/kronecker.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bn/montgomery.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bn/mul.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bn/prime.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bn/random.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bn/rsaz_exp.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bn/rsaz_exp.h create mode 100644 TMessagesProj/jni/boringssl/crypto/bn/shift.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bn/sqrt.c create mode 100644 TMessagesProj/jni/boringssl/crypto/buf/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/buf/buf.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bytestring/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/bytestring/ber.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bytestring/cbb.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bytestring/cbs.c create mode 100644 TMessagesProj/jni/boringssl/crypto/bytestring/internal.h create mode 100644 TMessagesProj/jni/boringssl/crypto/chacha/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/chacha/chacha_generic.c create mode 100644 TMessagesProj/jni/boringssl/crypto/chacha/chacha_vec.c create mode 100644 TMessagesProj/jni/boringssl/crypto/chacha/chacha_vec_arm.S create mode 100644 TMessagesProj/jni/boringssl/crypto/chacha/chacha_vec_arm_generate.go create mode 100644 TMessagesProj/jni/boringssl/crypto/cipher/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/cipher/aead.c create mode 100644 TMessagesProj/jni/boringssl/crypto/cipher/cipher.c create mode 100644 TMessagesProj/jni/boringssl/crypto/cipher/derive_key.c create mode 100644 TMessagesProj/jni/boringssl/crypto/cipher/e_aes.c create mode 100644 TMessagesProj/jni/boringssl/crypto/cipher/e_chacha20poly1305.c create mode 100644 TMessagesProj/jni/boringssl/crypto/cipher/e_des.c create mode 100644 TMessagesProj/jni/boringssl/crypto/cipher/e_null.c create mode 100644 TMessagesProj/jni/boringssl/crypto/cipher/e_rc2.c create mode 100644 TMessagesProj/jni/boringssl/crypto/cipher/e_rc4.c create mode 100644 TMessagesProj/jni/boringssl/crypto/cipher/e_ssl3.c create mode 100644 TMessagesProj/jni/boringssl/crypto/cipher/e_tls.c create mode 100644 TMessagesProj/jni/boringssl/crypto/cipher/internal.h create mode 100644 TMessagesProj/jni/boringssl/crypto/cipher/tls_cbc.c create mode 100644 TMessagesProj/jni/boringssl/crypto/cmac/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/cmac/cmac.c create mode 100644 TMessagesProj/jni/boringssl/crypto/conf/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/conf/conf.c create mode 100644 TMessagesProj/jni/boringssl/crypto/conf/conf_def.h create mode 100644 TMessagesProj/jni/boringssl/crypto/cpu-arm-asm.S create mode 100644 TMessagesProj/jni/boringssl/crypto/cpu-arm.c create mode 100644 TMessagesProj/jni/boringssl/crypto/cpu-intel.c create mode 100644 TMessagesProj/jni/boringssl/crypto/crypto.c create mode 100644 TMessagesProj/jni/boringssl/crypto/des/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/des/des.c create mode 100644 TMessagesProj/jni/boringssl/crypto/des/internal.h create mode 100644 TMessagesProj/jni/boringssl/crypto/dh/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/dh/check.c create mode 100644 TMessagesProj/jni/boringssl/crypto/dh/dh.c create mode 100644 TMessagesProj/jni/boringssl/crypto/dh/dh_asn1.c create mode 100644 TMessagesProj/jni/boringssl/crypto/dh/dh_impl.c create mode 100644 TMessagesProj/jni/boringssl/crypto/dh/internal.h create mode 100644 TMessagesProj/jni/boringssl/crypto/dh/params.c create mode 100644 TMessagesProj/jni/boringssl/crypto/digest/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/digest/digest.c create mode 100644 TMessagesProj/jni/boringssl/crypto/digest/digests.c create mode 100644 TMessagesProj/jni/boringssl/crypto/digest/internal.h create mode 100644 TMessagesProj/jni/boringssl/crypto/digest/md32_common.h create mode 100644 TMessagesProj/jni/boringssl/crypto/directory.h create mode 100644 TMessagesProj/jni/boringssl/crypto/directory_posix.c create mode 100644 TMessagesProj/jni/boringssl/crypto/directory_win.c create mode 100644 TMessagesProj/jni/boringssl/crypto/dsa/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/dsa/dsa.c create mode 100644 TMessagesProj/jni/boringssl/crypto/dsa/dsa_asn1.c create mode 100644 TMessagesProj/jni/boringssl/crypto/dsa/dsa_impl.c create mode 100644 TMessagesProj/jni/boringssl/crypto/dsa/internal.h create mode 100644 TMessagesProj/jni/boringssl/crypto/ec/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/ec/ec.c create mode 100644 TMessagesProj/jni/boringssl/crypto/ec/ec_asn1.c create mode 100644 TMessagesProj/jni/boringssl/crypto/ec/ec_key.c create mode 100644 TMessagesProj/jni/boringssl/crypto/ec/ec_montgomery.c create mode 100644 TMessagesProj/jni/boringssl/crypto/ec/example_mul.c create mode 100644 TMessagesProj/jni/boringssl/crypto/ec/internal.h create mode 100644 TMessagesProj/jni/boringssl/crypto/ec/oct.c create mode 100644 TMessagesProj/jni/boringssl/crypto/ec/p256-64.c create mode 100644 TMessagesProj/jni/boringssl/crypto/ec/simple.c create mode 100644 TMessagesProj/jni/boringssl/crypto/ec/util-64.c create mode 100644 TMessagesProj/jni/boringssl/crypto/ec/wnaf.c create mode 100644 TMessagesProj/jni/boringssl/crypto/ecdh/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/ecdh/ecdh.c create mode 100644 TMessagesProj/jni/boringssl/crypto/ecdsa/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/ecdsa/ecdsa.c create mode 100644 TMessagesProj/jni/boringssl/crypto/ecdsa/ecdsa_asn1.c create mode 100644 TMessagesProj/jni/boringssl/crypto/engine/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/engine/engine.c create mode 100644 TMessagesProj/jni/boringssl/crypto/err/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/err/asn1.errordata create mode 100644 TMessagesProj/jni/boringssl/crypto/err/bio.errordata create mode 100644 TMessagesProj/jni/boringssl/crypto/err/bn.errordata create mode 100644 TMessagesProj/jni/boringssl/crypto/err/cipher.errordata create mode 100644 TMessagesProj/jni/boringssl/crypto/err/conf.errordata create mode 100644 TMessagesProj/jni/boringssl/crypto/err/dh.errordata create mode 100644 TMessagesProj/jni/boringssl/crypto/err/digest.errordata create mode 100644 TMessagesProj/jni/boringssl/crypto/err/dsa.errordata create mode 100644 TMessagesProj/jni/boringssl/crypto/err/ec.errordata create mode 100644 TMessagesProj/jni/boringssl/crypto/err/ecdh.errordata create mode 100644 TMessagesProj/jni/boringssl/crypto/err/ecdsa.errordata create mode 100644 TMessagesProj/jni/boringssl/crypto/err/engine.errordata create mode 100644 TMessagesProj/jni/boringssl/crypto/err/err.c create mode 100644 TMessagesProj/jni/boringssl/crypto/err/err_data_generate.go create mode 100644 TMessagesProj/jni/boringssl/crypto/err/evp.errordata create mode 100644 TMessagesProj/jni/boringssl/crypto/err/hkdf.errordata create mode 100644 TMessagesProj/jni/boringssl/crypto/err/obj.errordata create mode 100644 TMessagesProj/jni/boringssl/crypto/err/pem.errordata create mode 100644 TMessagesProj/jni/boringssl/crypto/err/pkcs8.errordata create mode 100644 TMessagesProj/jni/boringssl/crypto/err/rsa.errordata create mode 100644 TMessagesProj/jni/boringssl/crypto/err/ssl.errordata create mode 100644 TMessagesProj/jni/boringssl/crypto/err/x509.errordata create mode 100644 TMessagesProj/jni/boringssl/crypto/err/x509v3.errordata create mode 100644 TMessagesProj/jni/boringssl/crypto/evp/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/evp/algorithm.c create mode 100644 TMessagesProj/jni/boringssl/crypto/evp/digestsign.c create mode 100644 TMessagesProj/jni/boringssl/crypto/evp/evp.c create mode 100644 TMessagesProj/jni/boringssl/crypto/evp/evp_asn1.c create mode 100644 TMessagesProj/jni/boringssl/crypto/evp/evp_ctx.c create mode 100644 TMessagesProj/jni/boringssl/crypto/evp/internal.h create mode 100644 TMessagesProj/jni/boringssl/crypto/evp/p_dsa_asn1.c create mode 100644 TMessagesProj/jni/boringssl/crypto/evp/p_ec.c create mode 100644 TMessagesProj/jni/boringssl/crypto/evp/p_ec_asn1.c create mode 100644 TMessagesProj/jni/boringssl/crypto/evp/p_rsa.c create mode 100644 TMessagesProj/jni/boringssl/crypto/evp/p_rsa_asn1.c create mode 100644 TMessagesProj/jni/boringssl/crypto/evp/pbkdf.c create mode 100644 TMessagesProj/jni/boringssl/crypto/evp/sign.c create mode 100644 TMessagesProj/jni/boringssl/crypto/ex_data.c create mode 100644 TMessagesProj/jni/boringssl/crypto/header_removed.h create mode 100644 TMessagesProj/jni/boringssl/crypto/hkdf/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/hkdf/hkdf.c create mode 100644 TMessagesProj/jni/boringssl/crypto/hmac/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/hmac/hmac.c create mode 100644 TMessagesProj/jni/boringssl/crypto/internal.h create mode 100644 TMessagesProj/jni/boringssl/crypto/lhash/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/lhash/lhash.c create mode 100644 TMessagesProj/jni/boringssl/crypto/lhash/make_macros.sh create mode 100644 TMessagesProj/jni/boringssl/crypto/md5/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/md5/asm/md5-586.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/md5/asm/md5-x86_64.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/md5/md5.c create mode 100644 TMessagesProj/jni/boringssl/crypto/mem.c create mode 100644 TMessagesProj/jni/boringssl/crypto/modes/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/modes/asm/aesni-gcm-x86_64.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/modes/asm/ghash-armv4.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/modes/asm/ghash-x86.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/modes/asm/ghash-x86_64.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/modes/asm/ghashv8-armx.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/modes/cbc.c create mode 100644 TMessagesProj/jni/boringssl/crypto/modes/cfb.c create mode 100644 TMessagesProj/jni/boringssl/crypto/modes/ctr.c create mode 100644 TMessagesProj/jni/boringssl/crypto/modes/gcm.c create mode 100644 TMessagesProj/jni/boringssl/crypto/modes/internal.h create mode 100644 TMessagesProj/jni/boringssl/crypto/modes/ofb.c create mode 100644 TMessagesProj/jni/boringssl/crypto/pem/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/pem/pem_all.c create mode 100644 TMessagesProj/jni/boringssl/crypto/pem/pem_info.c create mode 100644 TMessagesProj/jni/boringssl/crypto/pem/pem_lib.c create mode 100644 TMessagesProj/jni/boringssl/crypto/pem/pem_oth.c create mode 100644 TMessagesProj/jni/boringssl/crypto/pem/pem_pk8.c create mode 100644 TMessagesProj/jni/boringssl/crypto/pem/pem_pkey.c create mode 100644 TMessagesProj/jni/boringssl/crypto/pem/pem_x509.c create mode 100644 TMessagesProj/jni/boringssl/crypto/pem/pem_xaux.c create mode 100644 TMessagesProj/jni/boringssl/crypto/perlasm/arm-xlate.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/perlasm/cbc.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/perlasm/readme create mode 100644 TMessagesProj/jni/boringssl/crypto/perlasm/x86_64-xlate.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/perlasm/x86asm.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/perlasm/x86gas.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/perlasm/x86masm.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/perlasm/x86nasm.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/pkcs8/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/pkcs8/internal.h create mode 100644 TMessagesProj/jni/boringssl/crypto/pkcs8/p5_pbe.c create mode 100644 TMessagesProj/jni/boringssl/crypto/pkcs8/p5_pbev2.c create mode 100644 TMessagesProj/jni/boringssl/crypto/pkcs8/p8_pkey.c create mode 100644 TMessagesProj/jni/boringssl/crypto/pkcs8/pkcs8.c create mode 100644 TMessagesProj/jni/boringssl/crypto/poly1305/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/poly1305/poly1305.c create mode 100644 TMessagesProj/jni/boringssl/crypto/poly1305/poly1305_arm.c create mode 100644 TMessagesProj/jni/boringssl/crypto/poly1305/poly1305_arm_asm.S create mode 100644 TMessagesProj/jni/boringssl/crypto/poly1305/poly1305_vec.c create mode 100644 TMessagesProj/jni/boringssl/crypto/rand/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/rand/asm/rdrand-x86_64.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/rand/hwrand.c create mode 100644 TMessagesProj/jni/boringssl/crypto/rand/internal.h create mode 100644 TMessagesProj/jni/boringssl/crypto/rand/rand.c create mode 100644 TMessagesProj/jni/boringssl/crypto/rand/urandom.c create mode 100644 TMessagesProj/jni/boringssl/crypto/rand/windows.c create mode 100644 TMessagesProj/jni/boringssl/crypto/rc4/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/rc4/asm/rc4-586.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/rc4/asm/rc4-md5-x86_64.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/rc4/asm/rc4-x86_64.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/rc4/rc4.c create mode 100644 TMessagesProj/jni/boringssl/crypto/refcount_c11.c create mode 100644 TMessagesProj/jni/boringssl/crypto/refcount_lock.c create mode 100644 TMessagesProj/jni/boringssl/crypto/rsa/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/rsa/blinding.c create mode 100644 TMessagesProj/jni/boringssl/crypto/rsa/internal.h create mode 100644 TMessagesProj/jni/boringssl/crypto/rsa/padding.c create mode 100644 TMessagesProj/jni/boringssl/crypto/rsa/rsa.c create mode 100644 TMessagesProj/jni/boringssl/crypto/rsa/rsa_asn1.c create mode 100644 TMessagesProj/jni/boringssl/crypto/rsa/rsa_impl.c create mode 100644 TMessagesProj/jni/boringssl/crypto/sha/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/sha/asm/sha1-586.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/sha/asm/sha1-armv4-large.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/sha/asm/sha1-armv8.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/sha/asm/sha1-x86_64.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/sha/asm/sha256-586.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/sha/asm/sha256-armv4.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/sha/asm/sha512-586.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/sha/asm/sha512-armv4.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/sha/asm/sha512-armv8.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/sha/asm/sha512-x86_64.pl create mode 100644 TMessagesProj/jni/boringssl/crypto/sha/sha1.c create mode 100644 TMessagesProj/jni/boringssl/crypto/sha/sha256.c create mode 100644 TMessagesProj/jni/boringssl/crypto/sha/sha512.c create mode 100644 TMessagesProj/jni/boringssl/crypto/stack/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/stack/make_macros.sh create mode 100644 TMessagesProj/jni/boringssl/crypto/stack/stack.c create mode 100644 TMessagesProj/jni/boringssl/crypto/thread.c create mode 100644 TMessagesProj/jni/boringssl/crypto/thread_none.c create mode 100644 TMessagesProj/jni/boringssl/crypto/thread_pthread.c create mode 100644 TMessagesProj/jni/boringssl/crypto/thread_win.c create mode 100644 TMessagesProj/jni/boringssl/crypto/time_support.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/a_digest.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/a_sign.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/a_strex.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/a_verify.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/asn1_gen.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/by_dir.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/by_file.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/charmap.h create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/i2d_pr.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/pkcs7.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/t_crl.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/t_req.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/t_x509.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/t_x509a.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/vpm_int.h create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x509.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x509_att.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x509_cmp.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x509_d2.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x509_def.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x509_ext.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x509_lu.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x509_obj.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x509_r2x.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x509_req.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x509_set.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x509_trs.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x509_txt.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x509_v3.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x509_vfy.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x509_vpm.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x509cset.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x509name.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x509rset.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x509spki.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x509type.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x_algor.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x_all.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x_attrib.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x_crl.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x_exten.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x_info.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x_name.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x_pkey.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x_pubkey.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x_req.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x_sig.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x_spki.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x_val.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x_x509.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509/x_x509a.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/CMakeLists.txt create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/ext_dat.h create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/pcy_cache.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/pcy_data.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/pcy_int.h create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/pcy_lib.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/pcy_map.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/pcy_node.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/pcy_tree.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/v3_akey.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/v3_akeya.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/v3_alt.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/v3_bcons.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/v3_bitst.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/v3_conf.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/v3_cpols.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/v3_crld.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/v3_enum.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/v3_extku.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/v3_genn.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/v3_ia5.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/v3_info.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/v3_int.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/v3_lib.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/v3_ncons.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/v3_pci.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/v3_pcia.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/v3_pcons.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/v3_pku.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/v3_pmaps.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/v3_prn.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/v3_purp.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/v3_skey.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/v3_sxnet.c create mode 100644 TMessagesProj/jni/boringssl/crypto/x509v3/v3_utl.c create mode 100644 TMessagesProj/jni/boringssl/include/openssl/aead.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/aes.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/asn1.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/asn1_mac.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/asn1t.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/base.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/base64.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/bio.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/blowfish.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/bn.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/buf.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/buffer.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/bytestring.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/cast.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/chacha.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/cipher.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/cmac.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/conf.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/cpu.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/crypto.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/des.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/dh.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/digest.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/dsa.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/dtls1.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/ec.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/ec_key.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/ecdh.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/ecdsa.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/engine.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/err.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/evp.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/ex_data.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/hkdf.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/hmac.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/lhash.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/lhash_macros.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/md5.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/mem.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/modes.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/obj.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/obj_mac.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/objects.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/opensslfeatures.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/opensslv.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/ossl_typ.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/pem.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/pkcs12.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/pkcs7.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/pkcs8.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/poly1305.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/pqueue.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/rand.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/rc4.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/rsa.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/safestack.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/sha.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/srtp.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/ssl.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/ssl3.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/stack.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/stack_macros.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/thread.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/time_support.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/tls1.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/type_check.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/x509.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/x509_vfy.h create mode 100644 TMessagesProj/jni/boringssl/include/openssl/x509v3.h create mode 100644 TMessagesProj/jni/boringssl/lib/libcrypto_armeabi-v7a.a create mode 100644 TMessagesProj/jni/boringssl/lib/libcrypto_armeabi.a create mode 100644 TMessagesProj/jni/boringssl/lib/libcrypto_x86.a create mode 100644 TMessagesProj/jni/boringssl/util/android-cmake/AndroidNdkGdb.cmake create mode 100644 TMessagesProj/jni/boringssl/util/android-cmake/AndroidNdkModules.cmake create mode 100644 TMessagesProj/jni/boringssl/util/android-cmake/README.md create mode 100644 TMessagesProj/jni/boringssl/util/android-cmake/android.toolchain.cmake create mode 100644 TMessagesProj/jni/boringssl/util/android-cmake/ndk_links.md create mode 100644 TMessagesProj/jni/breakpad/LICENSE create mode 100644 TMessagesProj/jni/breakpad/client/linux/crash_generation/client_info.h create mode 100644 TMessagesProj/jni/breakpad/client/linux/crash_generation/crash_generation_client.cc create mode 100644 TMessagesProj/jni/breakpad/client/linux/crash_generation/crash_generation_client.h create mode 100644 TMessagesProj/jni/breakpad/client/linux/dump_writer_common/mapping_info.h create mode 100644 TMessagesProj/jni/breakpad/client/linux/dump_writer_common/raw_context_cpu.h create mode 100644 TMessagesProj/jni/breakpad/client/linux/dump_writer_common/thread_info.cc create mode 100644 TMessagesProj/jni/breakpad/client/linux/dump_writer_common/thread_info.h create mode 100644 TMessagesProj/jni/breakpad/client/linux/dump_writer_common/ucontext_reader.cc create mode 100644 TMessagesProj/jni/breakpad/client/linux/dump_writer_common/ucontext_reader.h create mode 100644 TMessagesProj/jni/breakpad/client/linux/handler/exception_handler.cc create mode 100644 TMessagesProj/jni/breakpad/client/linux/handler/exception_handler.h create mode 100644 TMessagesProj/jni/breakpad/client/linux/handler/minidump_descriptor.cc create mode 100644 TMessagesProj/jni/breakpad/client/linux/handler/minidump_descriptor.h create mode 100644 TMessagesProj/jni/breakpad/client/linux/log/log.cc create mode 100644 TMessagesProj/jni/breakpad/client/linux/log/log.h create mode 100644 TMessagesProj/jni/breakpad/client/linux/microdump_writer/microdump_writer.cc create mode 100644 TMessagesProj/jni/breakpad/client/linux/microdump_writer/microdump_writer.h create mode 100644 TMessagesProj/jni/breakpad/client/linux/minidump_writer/cpu_set.h create mode 100644 TMessagesProj/jni/breakpad/client/linux/minidump_writer/directory_reader.h create mode 100644 TMessagesProj/jni/breakpad/client/linux/minidump_writer/line_reader.h create mode 100644 TMessagesProj/jni/breakpad/client/linux/minidump_writer/linux_dumper.cc create mode 100644 TMessagesProj/jni/breakpad/client/linux/minidump_writer/linux_dumper.h create mode 100644 TMessagesProj/jni/breakpad/client/linux/minidump_writer/linux_ptrace_dumper.cc create mode 100644 TMessagesProj/jni/breakpad/client/linux/minidump_writer/linux_ptrace_dumper.h create mode 100644 TMessagesProj/jni/breakpad/client/linux/minidump_writer/minidump_writer.cc create mode 100644 TMessagesProj/jni/breakpad/client/linux/minidump_writer/minidump_writer.h create mode 100644 TMessagesProj/jni/breakpad/client/linux/minidump_writer/proc_cpuinfo_reader.h create mode 100644 TMessagesProj/jni/breakpad/client/minidump_file_writer-inl.h create mode 100644 TMessagesProj/jni/breakpad/client/minidump_file_writer.cc create mode 100644 TMessagesProj/jni/breakpad/client/minidump_file_writer.h create mode 100644 TMessagesProj/jni/breakpad/common/android/breakpad_getcontext.S create mode 100644 TMessagesProj/jni/breakpad/common/android/include/elf.h create mode 100644 TMessagesProj/jni/breakpad/common/android/include/link.h create mode 100644 TMessagesProj/jni/breakpad/common/android/include/sgidefs.h create mode 100644 TMessagesProj/jni/breakpad/common/android/include/stab.h create mode 100644 TMessagesProj/jni/breakpad/common/android/include/sys/procfs.h create mode 100644 TMessagesProj/jni/breakpad/common/android/include/sys/signal.h create mode 100644 TMessagesProj/jni/breakpad/common/android/include/sys/user.h create mode 100644 TMessagesProj/jni/breakpad/common/android/include/ucontext.h create mode 100644 TMessagesProj/jni/breakpad/common/android/ucontext_constants.h create mode 100644 TMessagesProj/jni/breakpad/common/basictypes.h create mode 100644 TMessagesProj/jni/breakpad/common/byte_cursor.h create mode 100644 TMessagesProj/jni/breakpad/common/convert_UTF.c create mode 100644 TMessagesProj/jni/breakpad/common/convert_UTF.h create mode 100644 TMessagesProj/jni/breakpad/common/linux/eintr_wrapper.h create mode 100644 TMessagesProj/jni/breakpad/common/linux/elf_gnu_compat.h create mode 100644 TMessagesProj/jni/breakpad/common/linux/elfutils-inl.h create mode 100644 TMessagesProj/jni/breakpad/common/linux/elfutils.cc create mode 100644 TMessagesProj/jni/breakpad/common/linux/elfutils.h create mode 100644 TMessagesProj/jni/breakpad/common/linux/file_id.cc create mode 100644 TMessagesProj/jni/breakpad/common/linux/file_id.h create mode 100644 TMessagesProj/jni/breakpad/common/linux/guid_creator.cc create mode 100644 TMessagesProj/jni/breakpad/common/linux/guid_creator.h create mode 100644 TMessagesProj/jni/breakpad/common/linux/ignore_ret.h create mode 100644 TMessagesProj/jni/breakpad/common/linux/linux_libc_support.cc create mode 100644 TMessagesProj/jni/breakpad/common/linux/linux_libc_support.h create mode 100644 TMessagesProj/jni/breakpad/common/linux/memory_mapped_file.cc create mode 100644 TMessagesProj/jni/breakpad/common/linux/memory_mapped_file.h create mode 100644 TMessagesProj/jni/breakpad/common/linux/safe_readlink.cc create mode 100644 TMessagesProj/jni/breakpad/common/linux/safe_readlink.h create mode 100644 TMessagesProj/jni/breakpad/common/md5.cc create mode 100644 TMessagesProj/jni/breakpad/common/md5.h create mode 100644 TMessagesProj/jni/breakpad/common/memory.h create mode 100644 TMessagesProj/jni/breakpad/common/memory_range.h create mode 100644 TMessagesProj/jni/breakpad/common/minidump_type_helper.h create mode 100644 TMessagesProj/jni/breakpad/common/scoped_ptr.h create mode 100644 TMessagesProj/jni/breakpad/common/string_conversion.cc create mode 100644 TMessagesProj/jni/breakpad/common/string_conversion.h create mode 100644 TMessagesProj/jni/breakpad/common/symbol_data.h create mode 100644 TMessagesProj/jni/breakpad/common/unordered.h create mode 100644 TMessagesProj/jni/breakpad/common/using_std_string.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/common/breakpad_types.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_amd64.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_arm.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_arm64.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_mips.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_ppc.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_ppc64.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_sparc.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_x86.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/common/minidump_exception_linux.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/common/minidump_exception_mac.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/common/minidump_exception_ps3.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/common/minidump_exception_solaris.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/common/minidump_exception_win32.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/common/minidump_format.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/common/minidump_size.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/processor/basic_source_line_resolver.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/processor/call_stack.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/processor/code_module.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/processor/code_modules.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/processor/dump_context.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/processor/dump_object.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/processor/exploitability.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/processor/fast_source_line_resolver.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/processor/memory_region.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/processor/microdump.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/processor/microdump_processor.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/processor/minidump.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/processor/minidump_processor.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/processor/proc_maps_linux.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/processor/process_result.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/processor/process_state.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/processor/source_line_resolver_base.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/processor/source_line_resolver_interface.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/processor/stack_frame.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/processor/stack_frame_cpu.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/processor/stack_frame_symbolizer.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/processor/stackwalker.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/processor/symbol_supplier.h create mode 100644 TMessagesProj/jni/breakpad/google_breakpad/processor/system_info.h create mode 100644 TMessagesProj/jni/breakpad/third_party/lss/linux_syscall_support.h create mode 100644 TMessagesProj/jni/ffmpeg/COPYING.GPLv2 create mode 100644 TMessagesProj/jni/ffmpeg/COPYING.GPLv3 create mode 100644 TMessagesProj/jni/ffmpeg/COPYING.LGPLv2.1 create mode 100644 TMessagesProj/jni/ffmpeg/COPYING.LGPLv3 create mode 100644 TMessagesProj/jni/ffmpeg/CREDITS create mode 100644 TMessagesProj/jni/ffmpeg/LICENSE.md create mode 100644 TMessagesProj/jni/ffmpeg/README.md create mode 100644 TMessagesProj/jni/ffmpeg/armv5te/libavcodec.a create mode 100644 TMessagesProj/jni/ffmpeg/armv5te/libavformat.a create mode 100644 TMessagesProj/jni/ffmpeg/armv5te/libavutil.a create mode 100644 TMessagesProj/jni/ffmpeg/armv7-a/libavcodec.a create mode 100644 TMessagesProj/jni/ffmpeg/armv7-a/libavformat.a create mode 100644 TMessagesProj/jni/ffmpeg/armv7-a/libavutil.a create mode 100644 TMessagesProj/jni/ffmpeg/build_ffmpeg_android.sh create mode 100644 TMessagesProj/jni/ffmpeg/i686/libavcodec.a create mode 100644 TMessagesProj/jni/ffmpeg/i686/libavformat.a create mode 100644 TMessagesProj/jni/ffmpeg/i686/libavutil.a create mode 100644 TMessagesProj/jni/ffmpeg/include/libavcodec/avcodec.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavcodec/avdct.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavcodec/avfft.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavcodec/d3d11va.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavcodec/dirac.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavcodec/dv_profile.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavcodec/dxva2.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavcodec/qsv.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavcodec/vaapi.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavcodec/vda.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavcodec/vdpau.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavcodec/version.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavcodec/videotoolbox.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavcodec/vorbis_parser.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavcodec/xvmc.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavformat/avformat.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavformat/avio.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavformat/version.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/adler32.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/aes.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/aes_ctr.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/attributes.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/audio_fifo.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/avassert.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/avconfig.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/avstring.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/avutil.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/base64.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/blowfish.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/bprint.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/bswap.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/buffer.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/camellia.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/cast5.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/channel_layout.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/common.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/cpu.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/crc.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/des.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/dict.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/display.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/downmix_info.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/error.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/eval.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/ffversion.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/fifo.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/file.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/frame.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/hash.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/hmac.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/imgutils.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/intfloat.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/intreadwrite.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/lfg.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/log.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/macros.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/mathematics.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/md5.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/mem.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/motion_vector.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/murmur3.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/opt.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/parseutils.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/pixdesc.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/pixelutils.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/pixfmt.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/random_seed.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/rational.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/rc4.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/replaygain.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/ripemd.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/samplefmt.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/sha.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/sha512.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/stereo3d.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/tea.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/threadmessage.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/time.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/timecode.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/timestamp.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/tree.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/twofish.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/version.h create mode 100644 TMessagesProj/jni/ffmpeg/include/libavutil/xtea.h create mode 100644 TMessagesProj/jni/gifvideo.cpp create mode 100644 TMessagesProj/jni/libjpeg/NOTICE create mode 100644 TMessagesProj/jni/libwebp/AUTHORS create mode 100644 TMessagesProj/jni/libwebp/COPYING create mode 100644 TMessagesProj/jni/libwebp/PATENTS create mode 100644 TMessagesProj/jni/libyuv/AUTHORS create mode 100644 TMessagesProj/jni/libyuv/LICENSE create mode 100644 TMessagesProj/jni/libyuv/LICENSE_THIRD_PARTY create mode 100644 TMessagesProj/jni/libyuv/PATENTS create mode 100644 TMessagesProj/jni/libyuv/include/libyuv/compare_row.h create mode 100644 TMessagesProj/jni/libyuv/include/libyuv/rotate_row.h create mode 100644 TMessagesProj/jni/libyuv/source/compare_gcc.cc create mode 100644 TMessagesProj/jni/libyuv/source/compare_neon64.cc create mode 100644 TMessagesProj/jni/libyuv/source/rotate_any.cc create mode 100644 TMessagesProj/jni/libyuv/source/rotate_common.cc create mode 100644 TMessagesProj/jni/libyuv/source/rotate_gcc.cc create mode 100644 TMessagesProj/jni/libyuv/source/rotate_win.cc create mode 100644 TMessagesProj/jni/libyuv/source/row_gcc.cc create mode 100644 TMessagesProj/jni/libyuv/source/scale_any.cc create mode 100644 TMessagesProj/jni/libyuv/source/scale_gcc.cc create mode 100644 TMessagesProj/jni/opus/AUTHORS create mode 100644 TMessagesProj/jni/opus/COPYING create mode 100644 TMessagesProj/jni/tgnet/BuffersStorage.cpp create mode 100644 TMessagesProj/jni/tgnet/BuffersStorage.h create mode 100644 TMessagesProj/jni/tgnet/ByteArray.cpp create mode 100644 TMessagesProj/jni/tgnet/ByteArray.h create mode 100644 TMessagesProj/jni/tgnet/ByteStream.cpp create mode 100644 TMessagesProj/jni/tgnet/ByteStream.h create mode 100644 TMessagesProj/jni/tgnet/Config.cpp create mode 100644 TMessagesProj/jni/tgnet/Config.h create mode 100644 TMessagesProj/jni/tgnet/Connection.cpp create mode 100644 TMessagesProj/jni/tgnet/Connection.h create mode 100644 TMessagesProj/jni/tgnet/ConnectionSession.cpp create mode 100644 TMessagesProj/jni/tgnet/ConnectionSession.h create mode 100644 TMessagesProj/jni/tgnet/ConnectionSocket.cpp create mode 100644 TMessagesProj/jni/tgnet/ConnectionSocket.h create mode 100644 TMessagesProj/jni/tgnet/ConnectionsManager.cpp create mode 100644 TMessagesProj/jni/tgnet/ConnectionsManager.h create mode 100644 TMessagesProj/jni/tgnet/Datacenter.cpp create mode 100644 TMessagesProj/jni/tgnet/Datacenter.h create mode 100644 TMessagesProj/jni/tgnet/Defines.h create mode 100644 TMessagesProj/jni/tgnet/EventObject.cpp create mode 100644 TMessagesProj/jni/tgnet/EventObject.h create mode 100644 TMessagesProj/jni/tgnet/FileLog.cpp create mode 100644 TMessagesProj/jni/tgnet/FileLog.h create mode 100644 TMessagesProj/jni/tgnet/MTProtoScheme.cpp create mode 100644 TMessagesProj/jni/tgnet/MTProtoScheme.h create mode 100644 TMessagesProj/jni/tgnet/NativeByteBuffer.cpp create mode 100644 TMessagesProj/jni/tgnet/NativeByteBuffer.h create mode 100644 TMessagesProj/jni/tgnet/Request.cpp create mode 100644 TMessagesProj/jni/tgnet/Request.h create mode 100644 TMessagesProj/jni/tgnet/TLObject.cpp create mode 100644 TMessagesProj/jni/tgnet/TLObject.h create mode 100644 TMessagesProj/jni/tgnet/Timer.cpp create mode 100644 TMessagesProj/jni/tgnet/Timer.h create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_0_0.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_0_1.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_0_2.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_0_3.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_1_0.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_1_1.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_1_2.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_1_3.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_2_0.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_2_1.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_2_2.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_2_3.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_3_0.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_3_1.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_3_2.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_3_3.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_4_0.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_4_1.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_4_2.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_4_3.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_0_0.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_0_1.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_0_2.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_0_3.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_1_0.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_1_1.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_1_2.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_1_3.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_2_0.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_2_1.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_2_2.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_2_3.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_3_0.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_3_1.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_3_2.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_3_3.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_4_0.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_4_1.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_4_2.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_4_3.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_0_0.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_0_1.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_0_2.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_0_3.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_1_0.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_1_1.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_1_2.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_1_3.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_2_0.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_2_1.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_2_2.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_2_3.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_3_0.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_3_1.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_3_2.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_3_3.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_4_0.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_4_1.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_4_2.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_4_3.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_0_0.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_0_1.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_0_2.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_0_3.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_1_0.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_1_1.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_1_2.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_1_3.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_2_0.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_2_1.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_2_2.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_2_3.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_3_0.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_3_1.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_3_2.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_3_3.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_4_0.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_4_1.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_4_2.jpg create mode 100644 TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_4_3.jpg create mode 100644 TMessagesProj/src/main/assets/fonts/ritalic.ttf create mode 100644 TMessagesProj/src/main/java/org/telegram/SQLite/DatabaseHandler.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/Animation/Animator10.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/Animation/AnimatorListenerAdapter10.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/Animation/AnimatorSet10.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/Animation/FloatEvaluator.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/Animation/FloatKeyframeSet.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/Animation/FloatProperty10.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/Animation/IntEvaluator.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/Animation/IntKeyframeSet.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/Animation/IntProperty.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/Animation/Keyframe.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/Animation/KeyframeSet.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/Animation/NoSuchPropertyException.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/Animation/ObjectAnimator10.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/Animation/Property.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/Animation/PropertyValuesHolder.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/Animation/ReflectiveProperty.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/Animation/TypeEvaluator.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/Animation/ValueAnimator.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/Animation/View10.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/AnimationCompat/AnimatorListenerAdapterProxy.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/AnimationCompat/AnimatorSetProxy.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/AnimationCompat/ObjectAnimatorProxy.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/AnimationCompat/ViewProxy.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/AppStartReceiver.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/AuthenticatorService.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/AutoMessageHeardReceiver.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/AutoMessageReplyReceiver.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/Bitmaps.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/CallReceiver.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/ClearCacheService.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/ContactsSyncAdapterService.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/DownloadObject.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/Emoji.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/EmojiData.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/GcmInstanceIDListenerService.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/GcmPushListenerService.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/GcmRegistrationIntentService.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/LruCache.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/ModuleContentProvider.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/MusicPlayerReceiver.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/MusicPlayerService.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/NativeCrashManager.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/NativeLoader.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/NotificationRepeat.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/NotificationsService.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/ScreenReceiver.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/SecretChatHelper.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/ShareBroadcastReceiver.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/SmsListener.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/TgChooserTargetService.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/UserObject.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/VideoEncodingService.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/WearReplyReceiver.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/AudioInfo.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/m4a/M4AInfo.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/m4a/MP4Atom.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/m4a/MP4Box.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/m4a/MP4Input.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v1Genre.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v1Info.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2DataInput.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2Encoding.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2Exception.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2FrameBody.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2FrameHeader.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2Info.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2TagBody.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2TagHeader.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/MP3Exception.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/MP3Frame.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/MP3Info.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/MP3Input.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/util/PositionInputStream.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/util/RangeInputStream.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/query/BotQuery.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/query/MessagesQuery.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/query/MessagesSearchQuery.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/query/SharedMediaQuery.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/query/StickersQuery.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/CustomTabsCallback.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/CustomTabsClient.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/CustomTabsIntent.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/CustomTabsService.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/CustomTabsServiceConnection.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/CustomTabsSession.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/CustomTabsSessionToken.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/ICustomTabsCallback.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/ICustomTabsService.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/customtabsclient/shared/CustomTabsHelper.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/customtabsclient/shared/KeepAliveService.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/customtabsclient/shared/ServiceConnection.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/customtabsclient/shared/ServiceConnectionCallback.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/util/AsyncListUtil.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/util/MessageThreadUtil.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/util/SortedList.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/util/ThreadUtil.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/util/TileList.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/widget/AdapterHelper.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/widget/ChildHelper.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/widget/DefaultItemAnimator.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/widget/GridLayoutManager.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/widget/LayoutState.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/widget/LinearLayoutManager.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/widget/LinearSmoothScroller.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/widget/OpReorderer.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/widget/OrientationHelper.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/widget/PositionMap.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/widget/RecyclerView.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/widget/RecyclerViewAccessibilityDelegate.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/widget/ScrollbarHelper.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/widget/SimpleItemAnimator.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/widget/StaggeredGridLayoutManager.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/widget/ViewInfoStore.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/widget/helper/ItemTouchHelper.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/widget/helper/ItemTouchUIUtil.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/widget/helper/ItemTouchUIUtilImpl.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/support/widget/util/SortedListAdapterCallback.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/time/DateParser.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/time/DatePrinter.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/time/FastDateFormat.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/time/FastDateParser.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/time/FastDatePrinter.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/time/FormatCache.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/video/InputSurface.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/video/MP4Builder.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/video/Mp4Movie.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/video/OutputSurface.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/video/Sample.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/video/Track.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/AuthFailureError.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/Cache.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/CacheDispatcher.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/DefaultRetryPolicy.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/ExecutorDelivery.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/Network.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/NetworkDispatcher.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/NetworkError.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/NetworkResponse.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/NoConnectionError.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/ParseError.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/Request.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/RequestQueue.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/Response.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/ResponseDelivery.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/RetryPolicy.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/ServerError.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/TimeoutError.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/VolleyError.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/VolleyLog.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/AndroidAuthenticator.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/Authenticator.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/BasicNetwork.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/ByteArrayPool.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/ClearCacheRequest.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/DiskBasedCache.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/HttpClientStack.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/HttpHeaderParser.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/HttpStack.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/HurlStack.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/JsonArrayRequest.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/JsonObjectRequest.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/JsonRequest.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/NoCache.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/PoolingByteArrayOutputStream.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/RequestFuture.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/StringRequest.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/Volley.java create mode 100644 TMessagesProj/src/main/java/org/telegram/tgnet/AbstractSerializedData.java create mode 100644 TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java create mode 100644 TMessagesProj/src/main/java/org/telegram/tgnet/NativeByteBuffer.java create mode 100644 TMessagesProj/src/main/java/org/telegram/tgnet/QuickAckDelegate.java create mode 100644 TMessagesProj/src/main/java/org/telegram/tgnet/RequestDelegate.java create mode 100644 TMessagesProj/src/main/java/org/telegram/tgnet/RequestDelegateInternal.java create mode 100644 TMessagesProj/src/main/java/org/telegram/tgnet/SerializedData.java create mode 100644 TMessagesProj/src/main/java/org/telegram/tgnet/TLClassStore.java create mode 100644 TMessagesProj/src/main/java/org/telegram/tgnet/TLObject.java create mode 100644 TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BackDrawable.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Adapters/BaseSearchAdapterRecycler.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/AudioPlayerActivity.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/AudioSelectActivity.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Cells/AboutLinkCell.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Cells/AudioCell.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Cells/BotHelpCell.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Cells/BotSwitchCell.java delete mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatAudioCell.java delete mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatContactCell.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatLoadingCell.java delete mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatUnreadCell.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Cells/CheckBoxCell.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Cells/ContextLinkCell.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoAttachCameraCell.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoAttachPhotoCell.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Cells/RadioButtonCell.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Cells/RadioCell.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Cells/ShareDialogCell.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedLinkCell.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerSetCell.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Cells/WallpaperCell.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/ChangeAboutActivity.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/ChannelCreateActivity.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/ChannelEditActivity.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/ChannelEditTypeActivity.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/ChannelIntroActivity.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/ChannelUsersActivity.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/BotKeyboardView.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachView.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBoxSquare.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/ChipSpan.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/CloseProgressDrawable.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/CloseProgressDrawable2.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/ContextProgressView.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/EmptyTextProgressView.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/Favourite.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/FlowLayoutManager.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/Glow.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/HintEditText.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/LetterDrawable.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/LinkPath.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/NumberTextView.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoFilterCurvesControl.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/PickerBottomLayout.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/PlayerView.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/RadioButton.java delete mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/ResourceLoader.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTabStrip.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarWaveform.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java delete mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/SimpleTextView.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/SizeNotifierFrameLayout.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/SizeNotifierFrameLayoutPhoto.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/SpannableStringLight.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/StickersAlert.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanBotCommand.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanNoUnderlineBold.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanReplacement.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/WebFrameLayout.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/ConvertGroupActivity.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/ManageSpaceActivity.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/PlusSettingsActivity.java rename TMessagesProj/src/main/java/org/telegram/ui/{LastSeenActivity.java => PrivacyControlActivity.java} (73%) rename TMessagesProj/src/main/java/org/telegram/ui/{LastSeenUsersActivity.java => PrivacyUsersActivity.java} (85%) create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/ReportOtherActivity.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/SetAdminsActivity.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/ShortcutActivity.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/StickerPreviewViewer.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/StickersActivity.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/ThemingSettingsActivity.java create mode 100644 TMessagesProj/src/main/res/anim/no_animation.xml create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/abc_ic_menu_share_mtrl_alpha.png delete mode 100644 TMessagesProj/src/main/res/drawable-hdpi/addcontact_blue.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/admin_star.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/admin_star2.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/assign_manager.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/attach_audio.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/attach_audio_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/attach_camera.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/attach_camera_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/attach_contact.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/attach_contact_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/attach_file.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/attach_file_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/attach_gallery.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/attach_gallery_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/attach_hide1.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/attach_hide1_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/attach_hide2.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/attach_location.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/attach_location_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/attach_send1.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/attach_send1_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/attach_send2.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/attach_video.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/attach_video_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/audiosend_pause.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/audiosend_play.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/blockpanel.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/bluecounter.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/bot_file.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/bot_info.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/bot_keyboard.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/bot_keyboard2.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/bot_keyboard_button.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/bot_keyboard_button_pressed.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/bot_lines.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/bot_link.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/bot_list.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/bot_location.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/bot_music.png delete mode 100644 TMessagesProj/src/main/res/drawable-hdpi/cancel_b.png delete mode 100644 TMessagesProj/src/main/res/drawable-hdpi/cancel_b_pressed.png delete mode 100644 TMessagesProj/src/main/res/drawable-hdpi/cancel_g.png delete mode 100644 TMessagesProj/src/main/res/drawable-hdpi/cancel_g_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/channelintro.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/check_list.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/check_profile.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/contact_blue.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/contact_green.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/corner_in_bl.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/corner_in_br.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/corner_in_tl.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/corner_in_tr.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/corner_out_bl.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/corner_out_br.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/corner_out_tl.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/corner_out_tr.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/dialogs_badge2.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_10.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_11.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_12.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_2.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_3.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_4.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_5.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_6.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_7.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_8.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_10.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_11.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_12.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_2.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_3.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_4.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_5.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_6.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_7.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_8.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/doc_actions_b_s.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/doc_blue_s.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/doccancel_b_s.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/docload_b_s.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/docpause_b_s.png delete mode 100644 TMessagesProj/src/main/res/drawable-hdpi/download_b.png delete mode 100644 TMessagesProj/src/main/res/drawable-hdpi/download_b_pressed.png delete mode 100644 TMessagesProj/src/main/res/drawable-hdpi/download_g.png delete mode 100644 TMessagesProj/src/main/res/drawable-hdpi/download_g_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/file_b.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/file_b_cancel.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/file_b_cancel_s.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/file_b_load.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/file_b_load_s.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/file_b_s.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/file_g.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/file_g_cancel.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/file_g_cancel_s.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/file_g_load.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/file_g_load_s.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/file_g_s.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/ic_action_next.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/ic_action_pause.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/ic_action_play.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/ic_action_previous.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/ic_create.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/ic_fp_40px.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/ic_launcher_beta.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/ic_settings.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/ic_smiles_gif.png delete mode 100644 TMessagesProj/src/main/res/drawable-hdpi/igvideo.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/list_circle.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/list_supergroup.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/location2.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/logo_avatar.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/managers.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/menu_admin.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/menu_plus.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/menu_themes.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/miniplayer_close.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/miniplayer_pause.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/miniplayer_play.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_check_10.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_check_11.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_check_12.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_check_2.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_check_3.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_check_4.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_check_5.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_check_6.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_check_7.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_check_8.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_check_9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_10.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_11.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_12.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_2.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_3.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_4.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_5.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_6.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_7.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_8.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_clock2.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_clock2_s.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_10.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_11.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_12.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_13.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_2.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_3.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_4.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_5.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_6.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_7.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_8.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_10.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_11.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_12.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_13.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_2.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_3.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_4.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_5.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_6.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_7.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_8.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_in_5.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_in_5_photo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_in_5_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_in_5_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_in_6.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_in_6_photo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_in_6_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_in_6_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_in_7.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_in_7_photo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_in_7_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_in_7_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_in_8.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_in_8_photo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_in_8_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_in_8_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_out_5.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_out_5_photo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_out_5_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_out_5_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_out_6.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_out_6_photo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_out_6_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_out_6_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_out_7.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_out_7_photo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_out_7_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_out_7_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_out_8.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_out_8_photo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_out_8_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_out_8_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/nocover.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/nocover_big.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/nocover_small.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/notify_members_off.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/notify_members_on.png delete mode 100644 TMessagesProj/src/main/res/drawable-hdpi/pause_b_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/pause_b_s.png delete mode 100644 TMessagesProj/src/main/res/drawable-hdpi/pause_g_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/pause_g_s.png delete mode 100644 TMessagesProj/src/main/res/drawable-hdpi/pause_w.png delete mode 100644 TMessagesProj/src/main/res/drawable-hdpi/pause_w2.png delete mode 100644 TMessagesProj/src/main/res/drawable-hdpi/pause_w2_pressed.png delete mode 100644 TMessagesProj/src/main/res/drawable-hdpi/pause_w_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/phone_activate.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/photocancel_b.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/photocancel_b_s.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/photocancel_g.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/photocancel_g_s.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/photocancel_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/photogif_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/photoload_b.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/photoload_b_s.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/photoload_g.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/photoload_g_s.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/photoload_pressed.png delete mode 100644 TMessagesProj/src/main/res/drawable-hdpi/photopause.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/phototime2.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/phototime2_b.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/pl_back.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/pl_next.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/pl_next_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/pl_pause.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/pl_pause_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/pl_play.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/pl_play_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/pl_previous.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/pl_previous_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/pl_repeat.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/pl_repeat1_active.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/pl_repeat_active.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/pl_shuffle.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/pl_shuffle_active.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/play_b.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/play_b_s.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/play_g.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/play_g_s.png delete mode 100644 TMessagesProj/src/main/res/drawable-hdpi/play_w.png delete mode 100644 TMessagesProj/src/main/res/drawable-hdpi/play_w2.png delete mode 100644 TMessagesProj/src/main/res/drawable-hdpi/play_w2_pressed.png delete mode 100644 TMessagesProj/src/main/res/drawable-hdpi/play_w_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/player.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/playvideo_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/post_views.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/post_views_s.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/post_views_w.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/post_viewsg.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/publish.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/publish_active.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/recorded.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/redcircle.png rename TMessagesProj/src/main/res/{drawable-xhdpi/addcontact_green.png => drawable-hdpi/s_pause.png} (52%) create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/s_pause_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/s_play.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/s_play_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/search_down.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/search_share.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/search_up.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/share_arrow.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/share_round.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/sheet_shadow.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/stickercounter.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/system.9.png delete mode 100644 TMessagesProj/src/main/res/drawable-hdpi/system_black.9.png delete mode 100644 TMessagesProj/src/main/res/drawable-hdpi/system_blue.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/system_loader.png delete mode 100644 TMessagesProj/src/main/res/drawable-hdpi/system_loader1.png delete mode 100644 TMessagesProj/src/main/res/drawable-hdpi/system_loader2.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/tab_all.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/tab_bot.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/tab_channel.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/tab_favs.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/tab_group.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/tab_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/tab_supergroup.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/tab_user.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/tip3.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/tip4.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/tool_cropfix.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/tool_curve.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/tool_fade.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/tool_rotate.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/tool_tint.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/tooltip.9.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/video_actions.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/abc_ic_menu_share_mtrl_alpha.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/admin_star.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/admin_star2.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/assign_manager.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/attach_audio.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/attach_audio_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/attach_camera.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/attach_camera_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/attach_contact.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/attach_contact_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/attach_file.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/attach_file_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/attach_gallery.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/attach_gallery_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/attach_hide1.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/attach_hide1_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/attach_hide2.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/attach_location.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/attach_location_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/attach_send1.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/attach_send1_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/attach_send2.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/attach_video.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/attach_video_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/audiosend_pause.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/audiosend_play.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/blockpanel.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/bluecounter.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/bot_file.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/bot_info.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/bot_keyboard.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/bot_keyboard2.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/bot_keyboard_button.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/bot_keyboard_button_pressed.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/bot_lines.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/bot_link.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/bot_list.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/bot_location.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/bot_music.png delete mode 100644 TMessagesProj/src/main/res/drawable-mdpi/cancel_b.png delete mode 100644 TMessagesProj/src/main/res/drawable-mdpi/cancel_b_pressed.png delete mode 100644 TMessagesProj/src/main/res/drawable-mdpi/cancel_g.png delete mode 100644 TMessagesProj/src/main/res/drawable-mdpi/cancel_g_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/channelintro.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/check_list.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/check_profile.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/contact_blue.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/contact_green.png rename TMessagesProj/src/main/res/{drawable-hdpi/addcontact_green.png => drawable-mdpi/corner_in_bl.png} (53%) create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/corner_in_br.png rename TMessagesProj/src/main/res/drawable-mdpi/{addcontact_green.png => corner_in_tl.png} (54%) create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/corner_in_tr.png rename TMessagesProj/src/main/res/drawable-mdpi/{addcontact_blue.png => corner_out_bl.png} (53%) create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/corner_out_br.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/corner_out_tl.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/corner_out_tr.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/dialogs_badge2.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_10.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_11.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_12.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_2.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_3.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_4.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_5.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_6.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_7.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_8.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_10.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_11.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_12.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_2.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_3.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_4.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_5.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_6.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_7.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_8.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/doc_actions_b_s.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/doc_blue_s.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/doccancel_b_s.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/docload_b_s.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/docpause_b_s.png delete mode 100644 TMessagesProj/src/main/res/drawable-mdpi/download_b.png delete mode 100644 TMessagesProj/src/main/res/drawable-mdpi/download_b_pressed.png delete mode 100644 TMessagesProj/src/main/res/drawable-mdpi/download_g.png delete mode 100644 TMessagesProj/src/main/res/drawable-mdpi/download_g_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/file_b.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/file_b_cancel.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/file_b_cancel_s.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/file_b_load.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/file_b_load_s.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/file_b_s.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/file_g.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/file_g_cancel.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/file_g_cancel_s.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/file_g_load.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/file_g_load_s.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/file_g_s.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/ic_action_next.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/ic_action_pause.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/ic_action_play.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/ic_action_previous.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/ic_create.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/ic_fp_40px.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/ic_launcher_beta.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/ic_settings.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/ic_smiles_gif.png delete mode 100644 TMessagesProj/src/main/res/drawable-mdpi/igvideo.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/list_circle.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/list_supergroup.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/location2.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/logo_avatar.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/managers.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/menu_admin.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/menu_plus.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/menu_themes.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/miniplayer_close.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/miniplayer_pause.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/miniplayer_play.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_check_10.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_check_11.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_check_12.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_check_2.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_check_3.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_check_4.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_check_5.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_check_6.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_check_7.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_check_8.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_check_9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_10.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_11.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_12.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_2.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_3.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_4.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_5.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_6.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_7.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_8.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_clock2.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_clock2_s.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_10.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_11.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_12.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_2.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_3.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_4.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_5.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_6.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_7.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_8.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_10.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_11.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_12.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_2.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_3.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_4.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_5.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_6.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_7.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_8.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_in_5.9.png rename TMessagesProj/src/main/res/drawable-mdpi/{msg_in_photo_2.9.png => msg_in_5_photo.9.png} (100%) create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_in_5_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_in_5_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_in_6.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_in_6_photo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_in_6_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_in_6_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_in_7.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_in_7_photo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_in_7_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_in_7_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_in_8.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_in_8_photo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_in_8_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_in_8_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_out_5.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_out_5_photo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_out_5_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_out_5_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_out_6.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_out_6_photo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_out_6_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_out_6_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_out_7.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_out_7_photo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_out_7_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_out_7_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_out_8_.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_out_8_photo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_out_8_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_out_8_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/nocover.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/nocover_big.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/nocover_small.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/notify_members_off.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/notify_members_on.png delete mode 100644 TMessagesProj/src/main/res/drawable-mdpi/pause_b_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/pause_b_s.png delete mode 100644 TMessagesProj/src/main/res/drawable-mdpi/pause_g_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/pause_g_s.png delete mode 100644 TMessagesProj/src/main/res/drawable-mdpi/pause_w.png delete mode 100644 TMessagesProj/src/main/res/drawable-mdpi/pause_w2.png delete mode 100644 TMessagesProj/src/main/res/drawable-mdpi/pause_w2_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/phone_activate.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/photocancel_b.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/photocancel_b_s.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/photocancel_g.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/photocancel_g_s.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/photocancel_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/photogif_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/photoload_b.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/photoload_b_s.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/photoload_g.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/photoload_g_s.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/photoload_pressed.png delete mode 100644 TMessagesProj/src/main/res/drawable-mdpi/photopause.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/phototime2.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/phototime2_b.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/pl_back.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/pl_next.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/pl_next_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/pl_pause.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/pl_pause_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/pl_play.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/pl_play_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/pl_previous.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/pl_previous_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/pl_repeat.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/pl_repeat1_active.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/pl_repeat_active.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/pl_shuffle.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/pl_shuffle_active.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/play_b.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/play_b_s.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/play_g.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/play_g_s.png delete mode 100644 TMessagesProj/src/main/res/drawable-mdpi/play_w.png delete mode 100644 TMessagesProj/src/main/res/drawable-mdpi/play_w2.png delete mode 100644 TMessagesProj/src/main/res/drawable-mdpi/play_w2_pressed.png delete mode 100644 TMessagesProj/src/main/res/drawable-mdpi/play_w_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/player.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/playvideo_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/post_views.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/post_views_s.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/post_views_w.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/post_viewsg.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/publish.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/publish_active.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/recorded.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/redcircle.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/s_pause.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/s_pause_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/s_play.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/s_play_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/search_down.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/search_share.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/search_up.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/share_arrow.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/share_round.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/sheet_shadow.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/stickercounter.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/system.9.png delete mode 100644 TMessagesProj/src/main/res/drawable-mdpi/system_black.9.png delete mode 100644 TMessagesProj/src/main/res/drawable-mdpi/system_blue.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/system_loader.png delete mode 100644 TMessagesProj/src/main/res/drawable-mdpi/system_loader1.png delete mode 100644 TMessagesProj/src/main/res/drawable-mdpi/system_loader2.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/tab_all.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/tab_bot.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/tab_channel.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/tab_favs.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/tab_group.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/tab_supergroup.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/tab_user.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/tip3.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/tip4.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/tool_cropfix.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/tool_curve.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/tool_fade.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/tool_rotate.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/tool_tint.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/tooltip.9.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/video_actions.png delete mode 100644 TMessagesProj/src/main/res/drawable-v21/bar_selector.xml delete mode 100644 TMessagesProj/src/main/res/drawable-v21/bar_selector_blue.xml delete mode 100644 TMessagesProj/src/main/res/drawable-v21/bar_selector_cyan.xml delete mode 100644 TMessagesProj/src/main/res/drawable-v21/bar_selector_green.xml delete mode 100644 TMessagesProj/src/main/res/drawable-v21/bar_selector_mode.xml delete mode 100644 TMessagesProj/src/main/res/drawable-v21/bar_selector_orange.xml delete mode 100644 TMessagesProj/src/main/res/drawable-v21/bar_selector_picker.xml delete mode 100644 TMessagesProj/src/main/res/drawable-v21/bar_selector_pink.xml delete mode 100644 TMessagesProj/src/main/res/drawable-v21/bar_selector_red.xml delete mode 100644 TMessagesProj/src/main/res/drawable-v21/bar_selector_violet.xml delete mode 100644 TMessagesProj/src/main/res/drawable-v21/bar_selector_yellow.xml create mode 100644 TMessagesProj/src/main/res/drawable-v21/list_selector_white.xml create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/abc_ic_menu_share_mtrl_alpha.png delete mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/addcontact_blue.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/admin_star.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/admin_star2.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/assign_manager.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/attach_audio.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/attach_audio_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/attach_camera.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/attach_camera_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/attach_contact.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/attach_contact_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/attach_file.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/attach_file_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/attach_gallery.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/attach_gallery_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/attach_hide1.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/attach_hide1_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/attach_hide2.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/attach_location.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/attach_location_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/attach_send1.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/attach_send1_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/attach_send2.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/attach_video.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/attach_video_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/audiosend_pause.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/audiosend_play.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/blockpanel.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/bluecounter.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/bot_file.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/bot_info.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/bot_keyboard.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/bot_keyboard2.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/bot_keyboard_button.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/bot_keyboard_button_pressed.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/bot_lines.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/bot_link.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/bot_list.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/bot_location.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/bot_music.png delete mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/cancel_b.png delete mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/cancel_b_pressed.png delete mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/cancel_g.png delete mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/cancel_g_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/channelintro.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/check_list.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/check_profile.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/contact_blue.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/contact_green.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/corner_in_bl.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/corner_in_br.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/corner_in_tl.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/corner_in_tr.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/corner_out_bl.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/corner_out_br.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/corner_out_tl.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/corner_out_tr.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/dialogs_badge2.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_10.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_11.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_12.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_2.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_3.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_4.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_5.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_6.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_7.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_8.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_10.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_11.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_12.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_2.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_3.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_4.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_5.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_6.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_7.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_8.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/doc_actions_b_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/doc_blue_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/doccancel_b_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/docload_b_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/docpause_b_s.png delete mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/download_b.png delete mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/download_b_pressed.png delete mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/download_g.png delete mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/download_g_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/file_b.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/file_b_cancel.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/file_b_cancel_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/file_b_load.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/file_b_load_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/file_b_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/file_g.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/file_g_cancel.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/file_g_cancel_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/file_g_load.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/file_g_load_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/file_g_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/ic_action_next.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/ic_action_pause.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/ic_action_play.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/ic_action_previous.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/ic_create.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/ic_fp_40px.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/ic_launcher_beta.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/ic_settings.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/ic_smiles_gif.png delete mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/igvideo.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/list_circle.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/list_supergroup.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/location2.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/logo_avatar.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/managers.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/menu_admin.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/menu_plus.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/menu_themes.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/miniplayer_close.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/miniplayer_pause.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/miniplayer_play.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_check_10.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_check_11.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_check_12.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_check_2.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_check_3.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_check_4.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_check_5.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_check_6.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_check_7.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_check_8.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_check_9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_10.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_11.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_12.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_2.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_3.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_4.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_5.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_6.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_7.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_8.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_clock2.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_clock2_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_10.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_11.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_12.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_2.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_3.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_4.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_5.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_6.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_7.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_8.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_10.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_11.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_12.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_2.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_3.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_4.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_5.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_6.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_7.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_8.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_in_5.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_in_5_photo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_in_5_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_in_5_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_in_6.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_in_6_photo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_in_6_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_in_6_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_in_7.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_in_7_photo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_in_7_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_in_7_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_in_8.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_in_8_photo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_in_8_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_in_8_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_out_5.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_out_5_photo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_out_5_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_out_5_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_out_6.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_out_6_photo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_out_6_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_out_6_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_out_7.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_out_7_photo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_out_7_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_out_7_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_out_8.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_out_8_photo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_out_8_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_out_8_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/nocover.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/nocover_big.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/nocover_small.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/notify_members_off.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/notify_members_on.png delete mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/pause_b_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/pause_b_s.png delete mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/pause_g_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/pause_g_s.png delete mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/pause_w.png delete mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/pause_w2.png delete mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/pause_w2_pressed.png delete mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/pause_w_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/phone_activate.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/photocancel_b.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/photocancel_b_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/photocancel_g.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/photocancel_g_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/photocancel_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/photogif_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/photoload_b.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/photoload_b_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/photoload_g.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/photoload_g_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/photoload_pressed.png delete mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/photopause.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/phototime2.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/phototime2_b.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/pl_back.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/pl_next.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/pl_next_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/pl_pause.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/pl_pause_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/pl_play.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/pl_play_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/pl_previous.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/pl_previous_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/pl_repeat.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/pl_repeat1_active.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/pl_repeat_active.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/pl_shuffle.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/pl_shuffle_active.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/play_b.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/play_b_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/play_g.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/play_g_s.png delete mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/play_w.png delete mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/play_w2.png delete mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/play_w2_pressed.png delete mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/play_w_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/player.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/playvideo_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/post_views.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/post_views_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/post_views_w.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/post_viewsg.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/publish.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/publish_active.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/recorded.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/redcircle.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/s_pause.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/s_pause_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/s_play.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/s_play_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/search_down.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/search_share.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/search_up.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/share_arrow.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/share_round.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/sheet_shadow.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/stickercounter.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/system.9.png delete mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/system_black.9.png delete mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/system_blue.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/system_loader.png delete mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/system_loader1.png delete mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/system_loader2.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/tab_all.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/tab_bot.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/tab_channel.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/tab_favs.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/tab_group.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/tab_supergroup.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/tab_user.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/tip3.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/tip4.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/tool_cropfix.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/tool_curve.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/tool_fade.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/tool_rotate.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/tool_tint.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/tooltip.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/video_actions.png delete mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/Thumbs.db create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/abc_ic_menu_share_mtrl_alpha.png delete mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/addcontact_blue.png delete mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/addcontact_green.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/admin_star.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/admin_star2.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/assign_manager.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/attach_audio.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/attach_audio_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/attach_camera.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/attach_camera_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/attach_contact.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/attach_contact_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/attach_file.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/attach_file_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/attach_gallery.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/attach_gallery_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/attach_hide1.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/attach_hide1_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/attach_hide2.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/attach_location.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/attach_location_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/attach_send1.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/attach_send1_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/attach_send2.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/attach_video.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/attach_video_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/audiosend_pause.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/audiosend_play.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/blockpanel.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/bluecounter.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/bot_file.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/bot_info.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/bot_keyboard.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/bot_keyboard2.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/bot_keyboard_button.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/bot_keyboard_button_pressed.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/bot_lines.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/bot_link.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/bot_list.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/bot_location.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/bot_music.png delete mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/cancel_b.png delete mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/cancel_b_pressed.png delete mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/cancel_g.png delete mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/cancel_g_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/channelintro.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/check_list.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/check_profile.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/contact_blue.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/contact_green.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/corner_in_bl.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/corner_in_br.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/corner_in_tl.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/corner_in_tr.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/corner_out_bl.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/corner_out_br.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/corner_out_tl.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/corner_out_tr.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_badge2.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_10.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_11.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_12.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_2.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_3.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_4.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_5.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_6.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_7.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_8.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_10.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_11.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_12.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_2.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_3.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_4.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_5.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_6.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_7.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_8.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/doc_actions_b_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/doc_blue_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/doccancel_b_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/docload_b_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/docpause_b_s.png delete mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/download_b.png delete mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/download_b_pressed.png delete mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/download_g.png delete mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/download_g_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/file_b.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/file_b_cancel.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/file_b_cancel_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/file_b_load.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/file_b_load_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/file_b_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/file_g.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/file_g_cancel.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/file_g_cancel_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/file_g_load.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/file_g_load_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/file_g_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/ic_action_next.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/ic_action_pause.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/ic_action_play.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/ic_action_previous.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/ic_create.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/ic_fp_40px.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/ic_launcher_beta.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/ic_settings.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/ic_smiles_gif.png delete mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/igvideo.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/list_circle.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/location2.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/logo_avatar.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/managers.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/menu_admin.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/menu_plus.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/menu_themes.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/miniplayer_close.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/miniplayer_pause.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/miniplayer_play.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_10.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_11.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_12.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_2.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_3.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_4.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_5.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_6.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_7.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_8.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_10.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_11.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_12.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_2.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_3.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_4.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_5.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_6.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_7.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_8.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_clock2.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_clock2_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_10.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_11.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_12.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_2.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_3.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_4.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_5.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_6.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_7.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_8.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_10.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_11.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_12.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_2.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_3.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_4.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_5.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_6.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_7.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_8.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_5.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_5_photo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_5_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_5_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_6.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_6_photo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_6_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_6_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_7.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_7_photo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_7_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_7_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_8.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_8_photo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_8_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_8_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_5.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_5_photo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_5_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_5_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_6.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_6_photo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_6_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_6_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_7.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_7_photo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_7_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_7_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_8.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_8_photo.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_8_photo_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_8_selected.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/nocover.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/nocover_big.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/nocover_small.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/notify_members_off.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/notify_members_on.png delete mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/pause_b_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/pause_b_s.png delete mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/pause_g_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/pause_g_s.png delete mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/pause_w.png delete mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/pause_w2.png delete mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/pause_w2_pressed.png delete mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/pause_w_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/phone_activate.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/photocancel_b.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/photocancel_b_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/photocancel_g.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/photocancel_g_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/photocancel_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/photogif_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/photoload_b.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/photoload_b_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/photoload_g.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/photoload_g_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/photoload_pressed.png delete mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/photopause.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/phototime2.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/phototime2_b.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/pl_back.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/pl_next.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/pl_next_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/pl_pause.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/pl_pause_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/pl_play.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/pl_play_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/pl_previous.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/pl_previous_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/pl_repeat.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/pl_repeat1_active.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/pl_repeat_active.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/pl_shuffle.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/pl_shuffle_active.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/play_b.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/play_b_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/play_g.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/play_g_s.png delete mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/play_w.png delete mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/play_w2.png delete mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/play_w2_pressed.png delete mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/play_w_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/player.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/playvideo_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/post_views.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/post_views_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/post_views_w.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/post_viewsg.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/publish.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/publish_active.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/recorded.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/redcircle.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/s_pause.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/s_pause_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/s_play.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/s_play_pressed.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/search_down.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/search_share.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/search_up.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/share_arrow.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/share_round.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/sheet_shadow.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/stickercounter.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/switch_to_on3.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/system.9.png delete mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/system_black.9.png delete mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/system_blue.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/system_loader.png delete mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/system_loader1.png delete mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/system_loader2.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/tab_all.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/tab_bot.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/tab_channel.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/tab_favs.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/tab_group.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/tab_supergroup.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/tab_user.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/tip3.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/tip4.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/tool_cropfix.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/tool_curve.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/tool_fade.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/tool_rotate.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/tool_tint.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/tooltip.9.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/video_actions.png create mode 100644 TMessagesProj/src/main/res/drawable-xxxhdpi/ic_launcher_beta.png create mode 100644 TMessagesProj/src/main/res/drawable-xxxhdpi/sheet_shadow.9.png create mode 100644 TMessagesProj/src/main/res/drawable/attach_audio_states.xml create mode 100644 TMessagesProj/src/main/res/drawable/attach_camera_states.xml create mode 100644 TMessagesProj/src/main/res/drawable/attach_contact_states.xml create mode 100644 TMessagesProj/src/main/res/drawable/attach_file_states.xml create mode 100644 TMessagesProj/src/main/res/drawable/attach_gallery_states.xml create mode 100644 TMessagesProj/src/main/res/drawable/attach_hide_states.xml create mode 100644 TMessagesProj/src/main/res/drawable/attach_location_states.xml create mode 100644 TMessagesProj/src/main/res/drawable/attach_send_states.xml create mode 100644 TMessagesProj/src/main/res/drawable/attach_video_states.xml delete mode 100644 TMessagesProj/src/main/res/drawable/bar_selector.xml delete mode 100644 TMessagesProj/src/main/res/drawable/bar_selector_blue.xml delete mode 100644 TMessagesProj/src/main/res/drawable/bar_selector_cyan.xml delete mode 100644 TMessagesProj/src/main/res/drawable/bar_selector_green.xml delete mode 100644 TMessagesProj/src/main/res/drawable/bar_selector_mode.xml delete mode 100644 TMessagesProj/src/main/res/drawable/bar_selector_picker.xml delete mode 100644 TMessagesProj/src/main/res/drawable/bar_selector_pink.xml delete mode 100644 TMessagesProj/src/main/res/drawable/bar_selector_red.xml delete mode 100644 TMessagesProj/src/main/res/drawable/bar_selector_violet.xml delete mode 100644 TMessagesProj/src/main/res/drawable/bar_selector_yellow.xml create mode 100644 TMessagesProj/src/main/res/drawable/bot_keyboard_states.xml create mode 100644 TMessagesProj/src/main/res/drawable/check_profile_fixed.xml create mode 100644 TMessagesProj/src/main/res/drawable/field_carret.xml create mode 100644 TMessagesProj/src/main/res/drawable/ic_fingerprint_error.xml rename TMessagesProj/src/main/res/drawable/{bar_selector_orange.xml => list_selector_white.xml} (52%) create mode 100644 TMessagesProj/src/main/res/drawable/player_next_states.xml create mode 100644 TMessagesProj/src/main/res/drawable/player_pause_states.xml create mode 100644 TMessagesProj/src/main/res/drawable/player_play_states.xml create mode 100644 TMessagesProj/src/main/res/drawable/player_prev_states.xml create mode 100644 TMessagesProj/src/main/res/drawable/s_player_pause_states.xml create mode 100644 TMessagesProj/src/main/res/drawable/s_player_play_states.xml delete mode 100644 TMessagesProj/src/main/res/layout/identicon_layout.xml create mode 100644 TMessagesProj/src/main/res/layout/player_big_notification.xml create mode 100644 TMessagesProj/src/main/res/layout/player_small_notification.xml create mode 100644 TMessagesProj/src/main/res/values-eo/strings.xml create mode 100644 TMessagesProj/src/main/res/values-eu/strings.xml create mode 100644 TMessagesProj/src/main/res/values-fa/strings.xml create mode 100644 TMessagesProj/src/main/res/values-he/strings.xml create mode 100644 TMessagesProj/src/main/res/values-iw/strings.xml create mode 100644 TMessagesProj/src/main/res/values-ja/strings.xml create mode 100644 TMessagesProj/src/main/res/values-sr/strings.xml create mode 100644 TMessagesProj/src/main/res/values-uk/strings.xml create mode 100644 TMessagesProj/src/main/res/xml/automotive_app_desc.xml diff --git a/TMessagesProj/build.gradle b/TMessagesProj/build.gradle index 4058cf00..7293dfe9 100644 --- a/TMessagesProj/build.gradle +++ b/TMessagesProj/build.gradle @@ -5,16 +5,16 @@ repositories { } dependencies { - compile 'com.android.support:support-v4:23.1.+' + compile 'com.android.support:support-v4:23.3.0' compile "com.google.android.gms:play-services-gcm:8.4.0" compile "com.google.android.gms:play-services-maps:8.4.0" - compile 'net.hockeyapp.android:HockeySDK:3.6.+' + compile 'net.hockeyapp.android:HockeySDK:4.0.0-beta.1' compile 'com.googlecode.mp4parser:isoparser:1.0.+' } android { compileSdkVersion 23 - buildToolsVersion '23.0.2' + buildToolsVersion '23.0.3' useLibrary 'org.apache.http.legacy' //defaultConfig.applicationId = "org.telegram.messenger" @@ -65,6 +65,10 @@ android { } } + defaultConfig.versionCode = 798 + + defaultConfig.manifestPlaceholders = [HOCKEYAPP_APP_ID: ""] + sourceSets.main { jniLibs.srcDir 'libs' jni.srcDirs = [] //disable automatic ndk-build call @@ -87,10 +91,40 @@ android { abortOnError false } + productFlavors { + arm { + ndk { + abiFilter "armeabi" + } + versionCode = 0 + } + armv7 { + ndk { + abiFilter "armeabi-v7a" + } + versionCode = 1 + } + x86 { + ndk { + abiFilter "x86" + } + versionCode = 2 + } + fat { + versionCode = 3 + } + } + + applicationVariants.all { variant -> + def abiVersion = variant.productFlavors.get(0).versionCode + variant.mergedFlavor.versionCode = defaultConfig.versionCode * 10 + abiVersion; + } + defaultConfig { minSdkVersion 9 targetSdkVersion 23 - versionCode 736 - versionName "3.4.2.5" + versionName "3.8.1.2" } -} + } + +apply plugin: 'com.google.gms.google-services' diff --git a/TMessagesProj/config/debug/AndroidManifest.xml b/TMessagesProj/config/debug/AndroidManifest.xml index c524d434..23da651d 100644 --- a/TMessagesProj/config/debug/AndroidManifest.xml +++ b/TMessagesProj/config/debug/AndroidManifest.xml @@ -23,9 +23,9 @@ + + +#include +#include "breakpad/client/linux/handler/exception_handler.h" +#include "breakpad/client/linux/handler/minidump_descriptor.h" + +/*static google_breakpad::ExceptionHandler *exceptionHandler; + +bool callback(const google_breakpad::MinidumpDescriptor &descriptor, void *context, bool succeeded) { + printf("dump path: %s\n", descriptor.path()); + return succeeded; +}*/ + +extern "C" { + void Java_org_telegram_messenger_NativeLoader_init(JNIEnv* env, jobject obj, jstring filepath, bool enable) { + return; + /*if (enable) { + const char *path = env->GetStringUTFChars(filepath, 0); + google_breakpad::MinidumpDescriptor descriptor(path); + exceptionHandler = new google_breakpad::ExceptionHandler(descriptor, NULL, callback, NULL, true, -1); + }*/ + } +} \ No newline at end of file diff --git a/TMessagesProj/jni/TgNetWrapper.cpp b/TMessagesProj/jni/TgNetWrapper.cpp new file mode 100644 index 00000000..decb50bd --- /dev/null +++ b/TMessagesProj/jni/TgNetWrapper.cpp @@ -0,0 +1,336 @@ +#include +#include "tgnet/BuffersStorage.h" +#include "tgnet/NativeByteBuffer.h" +#include "tgnet/ConnectionsManager.h" +#include "tgnet/MTProtoScheme.h" +#include "tgnet/FileLog.h" + +JavaVM *java; +jclass jclass_RequestDelegateInternal; +jmethodID jclass_RequestDelegateInternal_run; + +jclass jclass_QuickAckDelegate; +jmethodID jclass_QuickAckDelegate_run; + +jclass jclass_ConnectionsManager; +jmethodID jclass_ConnectionsManager_onUnparsedMessageReceived; +jmethodID jclass_ConnectionsManager_onUpdate; +jmethodID jclass_ConnectionsManager_onSessionCreated; +jmethodID jclass_ConnectionsManager_onLogout; +jmethodID jclass_ConnectionsManager_onConnectionStateChanged; +jmethodID jclass_ConnectionsManager_onInternalPushReceived; +jmethodID jclass_ConnectionsManager_onUpdateConfig; + +jint getFreeBuffer(JNIEnv *env, jclass c, jint length) { + return (jint) BuffersStorage::getInstance().getFreeBuffer(length); +} + +jint limit(JNIEnv *env, jclass c, jint address) { + NativeByteBuffer *buffer = (NativeByteBuffer *) address; + return buffer->limit(); +} + +jint position(JNIEnv *env, jclass c, jint address) { + NativeByteBuffer *buffer = (NativeByteBuffer *) address; + return buffer->position(); +} + +void reuse(JNIEnv *env, jclass c, jint address) { + NativeByteBuffer *buffer = (NativeByteBuffer *) address; + buffer->reuse(); +} + +jobject getJavaByteBuffer(JNIEnv *env, jclass c, jint address) { + NativeByteBuffer *buffer = (NativeByteBuffer *) address; + return buffer->getJavaByteBuffer(); +} + +static const char *NativeByteBufferClassPathName = "org/telegram/tgnet/NativeByteBuffer"; +static JNINativeMethod NativeByteBufferMethods[] = { + {"native_getFreeBuffer", "(I)I", (void *) getFreeBuffer}, + {"native_limit", "(I)I", (void *) limit}, + {"native_position", "(I)I", (void *) position}, + {"native_reuse", "(I)V", (void *) reuse}, + {"native_getJavaByteBuffer", "(I)Ljava/nio/ByteBuffer;", (void *) getJavaByteBuffer} +}; + +jlong getCurrentTimeMillis(JNIEnv *env, jclass c) { + return ConnectionsManager::getInstance().getCurrentTimeMillis(); +} + +jint getCurrentTime(JNIEnv *env, jclass c) { + return ConnectionsManager::getInstance().getCurrentTime(); +} + +jint getTimeDifference(JNIEnv *env, jclass c) { + return ConnectionsManager::getInstance().getTimeDifference(); +} + +void sendRequest(JNIEnv *env, jclass c, jint object, jobject onComplete, jobject onQuickAck, jint flags, jint datacenterId, jint connetionType, jboolean immediate, jint token) { + TL_api_request *request = new TL_api_request(); + request->request = (NativeByteBuffer *) object; + if (onComplete != nullptr) { + onComplete = env->NewGlobalRef(onComplete); + } + if (onQuickAck != nullptr) { + onQuickAck = env->NewGlobalRef(onQuickAck); + } + ConnectionsManager::getInstance().sendRequest(request, ([onComplete](TLObject *response, TL_error *error) { + TL_api_response *resp = (TL_api_response *) response; + jint ptr = 0; + jint errorCode = 0; + jstring errorText = nullptr; + if (resp != nullptr) { + ptr = (jint) resp->response.get(); + } else if (error != nullptr) { + errorCode = error->code; + errorText = jniEnv->NewStringUTF(error->text.c_str()); + } + if (onComplete != nullptr) { + jniEnv->CallVoidMethod(onComplete, jclass_RequestDelegateInternal_run, ptr, errorCode, errorText); + } + if (errorText != nullptr) { + jniEnv->DeleteLocalRef(errorText); + } + }), ([onQuickAck] { + if (onQuickAck != nullptr) { + jniEnv->CallVoidMethod(onQuickAck, jclass_QuickAckDelegate_run); + } + }), flags, datacenterId, (ConnectionType) connetionType, immediate, token, onComplete, onQuickAck); +} + +void cancelRequest(JNIEnv *env, jclass c, jint token, jboolean notifyServer) { + return ConnectionsManager::getInstance().cancelRequest(token, notifyServer); +} + +void cleanUp(JNIEnv *env, jclass c) { + return ConnectionsManager::getInstance().cleanUp(); +} + +void cancelRequestsForGuid(JNIEnv *env, jclass c, jint guid) { + return ConnectionsManager::getInstance().cancelRequestsForGuid(guid); +} + +void bindRequestToGuid(JNIEnv *env, jclass c, jint requestToken, jint guid) { + return ConnectionsManager::getInstance().bindRequestToGuid(requestToken, guid); +} + +void applyDatacenterAddress(JNIEnv *env, jclass c, jint datacenterId, jstring ipAddress, jint port) { + const char *valueStr = env->GetStringUTFChars(ipAddress, 0); + + ConnectionsManager::getInstance().applyDatacenterAddress(datacenterId, std::string(valueStr), port); + + if (valueStr != 0) { + env->ReleaseStringUTFChars(ipAddress, valueStr); + } +} + +jint getConnectionState(JNIEnv *env, jclass c) { + return ConnectionsManager::getInstance().getConnectionState(); +} + +void setUserId(JNIEnv *env, jclass c, int32_t id) { + ConnectionsManager::getInstance().setUserId(id); +} + +void switchBackend(JNIEnv *env, jclass c) { + ConnectionsManager::getInstance().switchBackend(); +} + +void pauseNetwork(JNIEnv *env, jclass c) { + ConnectionsManager::getInstance().pauseNetwork(); +} + +void resumeNetwork(JNIEnv *env, jclass c, jboolean partial) { + ConnectionsManager::getInstance().resumeNetwork(partial); +} + +void updateDcSettings(JNIEnv *env, jclass c) { + ConnectionsManager::getInstance().updateDcSettings(0); +} + +void setUseIpv6(JNIEnv *env, jclass c, bool value) { + ConnectionsManager::getInstance().setUseIpv6(value); +} + +void setNetworkAvailable(JNIEnv *env, jclass c, jboolean value) { + ConnectionsManager::getInstance().setNetworkAvailable(value); +} + +void setPushConnectionEnabled(JNIEnv *env, jclass c, jboolean value) { + ConnectionsManager::getInstance().setPushConnectionEnabled(value); +} + +class Delegate : public ConnectiosManagerDelegate { + + void onUpdate() { + jniEnv->CallStaticVoidMethod(jclass_ConnectionsManager, jclass_ConnectionsManager_onUpdate); + } + + void onSessionCreated() { + jniEnv->CallStaticVoidMethod(jclass_ConnectionsManager, jclass_ConnectionsManager_onSessionCreated); + } + + void onConnectionStateChanged(ConnectionState state) { + jniEnv->CallStaticVoidMethod(jclass_ConnectionsManager, jclass_ConnectionsManager_onConnectionStateChanged, state); + } + + void onUnparsedMessageReceived(int64_t reqMessageId, NativeByteBuffer *buffer, ConnectionType connectionType) { + if (connectionType == ConnectionTypeGeneric) { + jniEnv->CallStaticVoidMethod(jclass_ConnectionsManager, jclass_ConnectionsManager_onUnparsedMessageReceived, buffer); + } + } + + void onLogout() { + jniEnv->CallStaticVoidMethod(jclass_ConnectionsManager, jclass_ConnectionsManager_onLogout); + } + + void onUpdateConfig(TL_config *config) { + NativeByteBuffer *buffer = BuffersStorage::getInstance().getFreeBuffer(config->getObjectSize()); + config->serializeToStream(buffer); + buffer->position(0); + jniEnv->CallStaticVoidMethod(jclass_ConnectionsManager, jclass_ConnectionsManager_onUpdateConfig, buffer); + buffer->reuse(); + } + + void onInternalPushReceived() { + jniEnv->CallStaticVoidMethod(jclass_ConnectionsManager, jclass_ConnectionsManager_onInternalPushReceived); + } +}; + +void init(JNIEnv *env, jclass c, jint version, jint layer, jint apiId, jstring deviceModel, jstring systemVersion, jstring appVersion, jstring langCode, jstring configPath, jstring logPath, jint userId, jboolean enablePushConnection) { + const char *deviceModelStr = env->GetStringUTFChars(deviceModel, 0); + const char *systemVersionStr = env->GetStringUTFChars(systemVersion, 0); + const char *appVersionStr = env->GetStringUTFChars(appVersion, 0); + const char *langCodeStr = env->GetStringUTFChars(langCode, 0); + const char *configPathStr = env->GetStringUTFChars(configPath, 0); + const char *logPathStr = env->GetStringUTFChars(logPath, 0); + + ConnectionsManager::getInstance().init(version, layer, apiId, std::string(deviceModelStr), std::string(systemVersionStr), std::string(appVersionStr), std::string(langCodeStr), std::string(configPathStr), std::string(logPathStr), userId, true, enablePushConnection); + + if (deviceModelStr != 0) { + env->ReleaseStringUTFChars(deviceModel, deviceModelStr); + } + if (systemVersionStr != 0) { + env->ReleaseStringUTFChars(systemVersion, systemVersionStr); + } + if (appVersionStr != 0) { + env->ReleaseStringUTFChars(appVersion, appVersionStr); + } + if (langCodeStr != 0) { + env->ReleaseStringUTFChars(langCode, langCodeStr); + } + if (configPathStr != 0) { + env->ReleaseStringUTFChars(configPath, configPathStr); + } + if (logPathStr != 0) { + env->ReleaseStringUTFChars(logPath, logPathStr); + } +} + +void setJava(JNIEnv *env, jclass c, jboolean useJavaByteBuffers) { + ConnectionsManager::useJavaVM(java, useJavaByteBuffers); + ConnectionsManager::getInstance().setDelegate(new Delegate()); +} + +static const char *ConnectionsManagerClassPathName = "org/telegram/tgnet/ConnectionsManager"; +static JNINativeMethod ConnectionsManagerMethods[] = { + {"native_getCurrentTimeMillis", "()J", (void *) getCurrentTimeMillis}, + {"native_getCurrentTime", "()I", (void *) getCurrentTime}, + {"native_getTimeDifference", "()I", (void *) getTimeDifference}, + {"native_sendRequest", "(ILorg/telegram/tgnet/RequestDelegateInternal;Lorg/telegram/tgnet/QuickAckDelegate;IIIZI)V", (void *) sendRequest}, + {"native_cancelRequest", "(IZ)V", (void *) cancelRequest}, + {"native_cleanUp", "()V", (void *) cleanUp}, + {"native_cancelRequestsForGuid", "(I)V", (void *) cancelRequestsForGuid}, + {"native_bindRequestToGuid", "(II)V", (void *) bindRequestToGuid}, + {"native_applyDatacenterAddress", "(ILjava/lang/String;I)V", (void *) applyDatacenterAddress}, + {"native_getConnectionState", "()I", (void *) getConnectionState}, + {"native_setUserId", "(I)V", (void *) setUserId}, + {"native_init", "(IIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IZ)V", (void *) init}, + {"native_switchBackend", "()V", (void *) switchBackend}, + {"native_pauseNetwork", "()V", (void *) pauseNetwork}, + {"native_resumeNetwork", "(Z)V", (void *) resumeNetwork}, + {"native_updateDcSettings", "()V", (void *) updateDcSettings}, + {"native_setUseIpv6", "(Z)V", (void *) setUseIpv6}, + {"native_setNetworkAvailable", "(Z)V", (void *) setNetworkAvailable}, + {"native_setPushConnectionEnabled", "(Z)V", (void *) setPushConnectionEnabled}, + {"native_setJava", "(Z)V", (void *) setJava} +}; + +inline int registerNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods, int methodsCount) { + jclass clazz; + clazz = env->FindClass(className); + if (clazz == NULL) { + return JNI_FALSE; + } + if (env->RegisterNatives(clazz, methods, methodsCount) < 0) { + return JNI_FALSE; + } + return JNI_TRUE; +} + +extern "C" int registerNativeTgNetFunctions(JavaVM *vm, JNIEnv *env) { + java = vm; + + if (!registerNativeMethods(env, NativeByteBufferClassPathName, NativeByteBufferMethods, sizeof(NativeByteBufferMethods) / sizeof(NativeByteBufferMethods[0]))) { + return JNI_FALSE; + } + + if (!registerNativeMethods(env, ConnectionsManagerClassPathName, ConnectionsManagerMethods, sizeof(ConnectionsManagerMethods) / sizeof(ConnectionsManagerMethods[0]))) { + return JNI_FALSE; + } + + jclass_RequestDelegateInternal = (jclass) env->NewGlobalRef(env->FindClass("org/telegram/tgnet/RequestDelegateInternal")); + if (jclass_RequestDelegateInternal == 0) { + return JNI_FALSE; + } + jclass_RequestDelegateInternal_run = env->GetMethodID(jclass_RequestDelegateInternal, "run", "(IILjava/lang/String;)V"); + if (jclass_RequestDelegateInternal_run == 0) { + return JNI_FALSE; + } + + jclass_QuickAckDelegate = (jclass) env->NewGlobalRef(env->FindClass("org/telegram/tgnet/QuickAckDelegate")); + if (jclass_RequestDelegateInternal == 0) { + return JNI_FALSE; + } + jclass_QuickAckDelegate_run = env->GetMethodID(jclass_QuickAckDelegate, "run", "()V"); + if (jclass_QuickAckDelegate_run == 0) { + return JNI_FALSE; + } + + jclass_ConnectionsManager = (jclass) env->NewGlobalRef(env->FindClass("org/telegram/tgnet/ConnectionsManager")); + if (jclass_ConnectionsManager == 0) { + return JNI_FALSE; + } + jclass_ConnectionsManager_onUnparsedMessageReceived = env->GetStaticMethodID(jclass_ConnectionsManager, "onUnparsedMessageReceived", "(I)V"); + if (jclass_ConnectionsManager_onUnparsedMessageReceived == 0) { + return JNI_FALSE; + } + jclass_ConnectionsManager_onUpdate = env->GetStaticMethodID(jclass_ConnectionsManager, "onUpdate", "()V"); + if (jclass_ConnectionsManager_onUpdate == 0) { + return JNI_FALSE; + } + jclass_ConnectionsManager_onSessionCreated = env->GetStaticMethodID(jclass_ConnectionsManager, "onSessionCreated", "()V"); + if (jclass_ConnectionsManager_onSessionCreated == 0) { + return JNI_FALSE; + } + jclass_ConnectionsManager_onLogout = env->GetStaticMethodID(jclass_ConnectionsManager, "onLogout", "()V"); + if (jclass_ConnectionsManager_onLogout == 0) { + return JNI_FALSE; + } + jclass_ConnectionsManager_onConnectionStateChanged = env->GetStaticMethodID(jclass_ConnectionsManager, "onConnectionStateChanged", "(I)V"); + if (jclass_ConnectionsManager_onConnectionStateChanged == 0) { + return JNI_FALSE; + } + jclass_ConnectionsManager_onInternalPushReceived = env->GetStaticMethodID(jclass_ConnectionsManager, "onInternalPushReceived", "()V"); + if (jclass_ConnectionsManager_onInternalPushReceived == 0) { + return JNI_FALSE; + } + jclass_ConnectionsManager_onUpdateConfig = env->GetStaticMethodID(jclass_ConnectionsManager, "onUpdateConfig", "(I)V"); + if (jclass_ConnectionsManager_onUpdateConfig == 0) { + return JNI_FALSE; + } + ConnectionsManager::getInstance().setDelegate(new Delegate()); + + return JNI_TRUE; +} diff --git a/TMessagesProj/jni/audio.c b/TMessagesProj/jni/audio.c index 70b6e2fc..c6fd3650 100644 --- a/TMessagesProj/jni/audio.c +++ b/TMessagesProj/jni/audio.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "utils.h" typedef struct { @@ -663,6 +664,155 @@ JNIEXPORT int Java_org_telegram_messenger_MediaController_isOpusFile(JNIEnv *env result = error == OPUS_OK; } + if (pathStr != 0) { + (*env)->ReleaseStringUTFChars(env, path, pathStr); + } + + return result; +} + +static inline void set_bits(uint8_t *bytes, int32_t bitOffset, int32_t value) { + bytes += bitOffset / 8; + bitOffset %= 8; + *((int32_t *) bytes) |= (value << bitOffset); +} + +JNIEXPORT jbyteArray Java_org_telegram_messenger_MediaController_getWaveform2(JNIEnv *env, jclass class, jshortArray array, jint length) { + + jshort *sampleBuffer = (*env)->GetShortArrayElements(env, array, 0); + + jbyteArray result = 0; + int32_t resultSamples = 100; + uint16_t *samples = malloc(100 * 2); + uint64_t sampleIndex = 0; + uint16_t peakSample = 0; + int32_t sampleRate = (int32_t) max(1, length / resultSamples); + int index = 0; + + for (int i = 0; i < length; i++) { + uint16_t sample = (uint16_t) abs(sampleBuffer[i]); + if (sample > peakSample) { + peakSample = sample; + } + if (sampleIndex++ % sampleRate == 0) { + if (index < resultSamples) { + samples[index++] = peakSample; + } + peakSample = 0; + } + } + + int64_t sumSamples = 0; + for (int i = 0; i < resultSamples; i++) { + sumSamples += samples[i]; + } + uint16_t peak = (uint16_t) (sumSamples * 1.8f / resultSamples); + if (peak < 2500) { + peak = 2500; + } + + for (int i = 0; i < resultSamples; i++) { + uint16_t sample = (uint16_t) ((int64_t) samples[i]); + if (sample > peak) { + samples[i] = peak; + } + } + + (*env)->ReleaseShortArrayElements(env, array, sampleBuffer, 0); + + int bitstreamLength = (resultSamples * 5) / 8 + (((resultSamples * 5) % 8) == 0 ? 0 : 1); + result = (*env)->NewByteArray(env, bitstreamLength); + jbyte *bytes = (*env)->GetByteArrayElements(env, result, NULL); + + for (int i = 0; i < resultSamples; i++) { + int32_t value = min(31, abs((int32_t) samples[i]) * 31 / peak); + set_bits(bytes, i * 5, value & 31); + } + + (*env)->ReleaseByteArrayElements(env, result, bytes, JNI_COMMIT); + free(samples); + + return result; +} + +int16_t *sampleBuffer = NULL; + + +JNIEXPORT jbyteArray Java_org_telegram_messenger_MediaController_getWaveform(JNIEnv *env, jclass class, jstring path) { + const char *pathStr = (*env)->GetStringUTFChars(env, path, 0); + jbyteArray result = 0; + + int error = OPUS_OK; + OggOpusFile *opusFile = op_open_file(pathStr, &error); + if (opusFile != NULL && error == OPUS_OK) { + int64_t totalSamples = op_pcm_total(opusFile, -1); + int32_t resultSamples = 100; + int32_t sampleRate = (int32_t) max(1, totalSamples / resultSamples); + + uint16_t *samples = malloc(100 * 2); + + int bufferSize = 1024 * 128; + if (sampleBuffer == NULL) { + sampleBuffer = malloc(bufferSize); + } + uint64_t sampleIndex = 0; + uint16_t peakSample = 0; + + int index = 0; + + while (1) { + int readSamples = op_read(opusFile, sampleBuffer, bufferSize / 2, NULL); + for (int i = 0; i < readSamples; i++) { + uint16_t sample = (uint16_t) abs(sampleBuffer[i]); + if (sample > peakSample) { + peakSample = sample; + } + if (sampleIndex++ % sampleRate == 0) { + if (index < resultSamples) { + samples[index++] = peakSample; + } + peakSample = 0; + } + } + if (readSamples == 0) { + break; + } + } + + int64_t sumSamples = 0; + for (int i = 0; i < resultSamples; i++) { + sumSamples += samples[i]; + } + uint16_t peak = (uint16_t) (sumSamples * 1.8f / resultSamples); + if (peak < 2500) { + peak = 2500; + } + + for (int i = 0; i < resultSamples; i++) { + uint16_t sample = (uint16_t) ((int64_t) samples[i]); + if (sample > peak) { + samples[i] = peak; + } + } + + //free(sampleBuffer); + op_free(opusFile); + + int bitstreamLength = (resultSamples * 5) / 8 + (((resultSamples * 5) % 8) == 0 ? 0 : 1); + result = (*env)->NewByteArray(env, bitstreamLength); + jbyte *bytes = (*env)->GetByteArrayElements(env, result, NULL); + + for (int i = 0; i < resultSamples; i++) { + int32_t value = min(31, abs((int32_t) samples[i]) * 31 / peak); + set_bits(bytes, i * 5, value & 31); + } + + (*env)->ReleaseByteArrayElements(env, result, bytes, JNI_COMMIT); + free(samples); + } + + + if (pathStr != 0) { (*env)->ReleaseStringUTFChars(env, path, pathStr); } diff --git a/TMessagesProj/jni/boringssl/LICENSE b/TMessagesProj/jni/boringssl/LICENSE new file mode 100644 index 00000000..b242dcb1 --- /dev/null +++ b/TMessagesProj/jni/boringssl/LICENSE @@ -0,0 +1,185 @@ +BoringSSL is a fork of OpenSSL. As such, large parts of it fall under OpenSSL +licensing. Files that are completely new have a Google copyright and an ISC +license. This license is reproduced at the bottom of this file. + +Contributors to BoringSSL are required to follow the CLA rules for Chromium: +https://cla.developers.google.com/clas + +Some files from Intel are under yet another license, which is also included +underneath. + +The OpenSSL toolkit stays under a dual license, i.e. both the conditions of the +OpenSSL License and the original SSLeay license apply to the toolkit. See below +for the actual license texts. Actually both licenses are BSD-style Open Source +licenses. In case of any license issues related to OpenSSL please contact +openssl-core@openssl.org. + + OpenSSL License + --------------- + +/* ==================================================================== + * Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + + Original SSLeay License + ----------------------- + +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + + +ISC license used for completely new code in BoringSSL: + +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + + +Some files from Intel carry the following license: + +# Copyright (c) 2012, Intel Corporation +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the +# distribution. +# +# * Neither the name of the Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# +# THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""AS IS"" AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/TMessagesProj/jni/boringssl/README.MD b/TMessagesProj/jni/boringssl/README.MD new file mode 100644 index 00000000..b777c016 --- /dev/null +++ b/TMessagesProj/jni/boringssl/README.MD @@ -0,0 +1,10 @@ +cmake, ninja, go are required + +cmake -DANDROID_NATIVE_API_LEVEL=android-8 \ + -DANDROID_ABI=x86 \ + -DCMAKE_BUILD_TYPE=Release \ + -DANDROID_NDK=/Applications/sdk/ndk-bundle/ \ + -DCMAKE_TOOLCHAIN_FILE=../util/android-cmake/android.toolchain.cmake \ + -DANDROID_NATIVE_API_LEVEL=16 \ + -GNinja .. +cmake --build . \ No newline at end of file diff --git a/TMessagesProj/jni/boringssl/crypto/.gitignore b/TMessagesProj/jni/boringssl/crypto/.gitignore new file mode 100644 index 00000000..08633432 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/.gitignore @@ -0,0 +1 @@ +*.txt~ diff --git a/TMessagesProj/jni/boringssl/crypto/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/CMakeLists.txt new file mode 100644 index 00000000..bfde57a3 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/CMakeLists.txt @@ -0,0 +1,197 @@ +include_directories(. ../include) + +if(APPLE) + if (${ARCH} STREQUAL "x86") + set(PERLASM_FLAGS "-fPIC -DOPENSSL_IA32_SSE2") + endif() + set(PERLASM_STYLE macosx) + set(ASM_EXT S) + enable_language(ASM) +elseif(UNIX) + if (${ARCH} STREQUAL "aarch64") + # The "armx" Perl scripts look for "64" in the style argument + # in order to decide whether to generate 32- or 64-bit asm. + set(PERLASM_STYLE linux64) + elseif (${ARCH} STREQUAL "arm") + set(PERLASM_STYLE linux32) + elseif (${ARCH} STREQUAL "x86") + set(PERLASM_FLAGS "-fPIC -DOPENSSL_IA32_SSE2") + set(PERLASM_STYLE elf) + else() + set(PERLASM_STYLE elf) + endif() + set(ASM_EXT S) + enable_language(ASM) +else() + if (CMAKE_CL_64) + message("Using nasm") + set(PERLASM_STYLE nasm) + else() + message("Using win32n") + set(PERLASM_STYLE win32n) + set(PERLASM_FLAGS "-DOPENSSL_IA32_SSE2") + endif() + + # On Windows, we use the NASM output, specifically built with Yasm. + set(ASM_EXT asm) + enable_language(ASM_NASM) +endif() + +function(perlasm dest src) + add_custom_command( + OUTPUT ${dest} + COMMAND ${PERL_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/${src} ${PERLASM_STYLE} ${PERLASM_FLAGS} ${ARGN} > ${dest} + DEPENDS + ${src} + ${PROJECT_SOURCE_DIR}/crypto/perlasm/arm-xlate.pl + ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86_64-xlate.pl + ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86asm.pl + ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86gas.pl + ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86masm.pl + ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86nasm.pl + WORKING_DIRECTORY . + ) +endfunction() + +if (${ARCH} STREQUAL "x86_64") + set( + CRYPTO_ARCH_SOURCES + + cpu-intel.c + ) +endif() + +if (${ARCH} STREQUAL "x86") + set( + CRYPTO_ARCH_SOURCES + + cpu-intel.c + ) +endif() + +if (${ARCH} STREQUAL "arm") + set( + CRYPTO_ARCH_SOURCES + + cpu-arm.c + cpu-arm-asm.S + ) +endif() + +if (${ARCH} STREQUAL "aarch64") + set( + CRYPTO_ARCH_SOURCES + + cpu-arm.c + ) +endif() + +# Level 0.1 - depends on nothing outside this set. +add_subdirectory(stack) +add_subdirectory(lhash) +add_subdirectory(err) +add_subdirectory(buf) +add_subdirectory(base64) +add_subdirectory(bytestring) + +# Level 0.2 - depends on nothing but itself +add_subdirectory(sha) +add_subdirectory(md5) +add_subdirectory(modes) +add_subdirectory(aes) +add_subdirectory(des) +add_subdirectory(rc4) +add_subdirectory(conf) +add_subdirectory(chacha) +add_subdirectory(poly1305) + +# Level 1, depends only on 0.* +add_subdirectory(digest) +add_subdirectory(cipher) +add_subdirectory(rand) +add_subdirectory(bio) +add_subdirectory(bn) +add_subdirectory(obj) +add_subdirectory(asn1) + +# Level 2 +add_subdirectory(engine) +add_subdirectory(dh) +add_subdirectory(dsa) +add_subdirectory(rsa) +add_subdirectory(ec) +add_subdirectory(ecdh) +add_subdirectory(ecdsa) +add_subdirectory(hmac) + +# Level 3 +add_subdirectory(cmac) +add_subdirectory(evp) +add_subdirectory(hkdf) +add_subdirectory(pem) +add_subdirectory(x509) +add_subdirectory(x509v3) + +# Level 4 +add_subdirectory(pkcs8) + +add_library( + crypto + + crypto.c + directory_posix.c + directory_win.c + ex_data.c + mem.c + refcount_c11.c + refcount_lock.c + thread.c + thread_none.c + thread_pthread.c + thread_win.c + time_support.c + + ${CRYPTO_ARCH_SOURCES} + + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ +) + +if(NOT MSVC AND NOT ANDROID) + target_link_libraries(crypto pthread) +endif() diff --git a/TMessagesProj/jni/boringssl/crypto/aes/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/aes/CMakeLists.txt new file mode 100644 index 00000000..985af113 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/aes/CMakeLists.txt @@ -0,0 +1,63 @@ +include_directories(. .. ../../include) + +if (${ARCH} STREQUAL "x86_64") + set( + AES_ARCH_SOURCES + + aes-x86_64.${ASM_EXT} + aesni-x86_64.${ASM_EXT} + bsaes-x86_64.${ASM_EXT} + vpaes-x86_64.${ASM_EXT} + ) +endif() + +if (${ARCH} STREQUAL "x86") + set( + AES_ARCH_SOURCES + + aes-586.${ASM_EXT} + vpaes-x86.${ASM_EXT} + aesni-x86.${ASM_EXT} + ) +endif() + +if (${ARCH} STREQUAL "arm") + set( + AES_ARCH_SOURCES + + aes-armv4.${ASM_EXT} + bsaes-armv7.${ASM_EXT} + aesv8-armx.${ASM_EXT} + ) +endif() + +if (${ARCH} STREQUAL "aarch64") + set( + AES_ARCH_SOURCES + + aesv8-armx.${ASM_EXT} + ) +endif() + +add_library( + aes + + OBJECT + + aes.c + aes_ige.c + mode_wrappers.c + + ${AES_ARCH_SOURCES} +) + +perlasm(aes-x86_64.${ASM_EXT} asm/aes-x86_64.pl) +perlasm(aesni-x86_64.${ASM_EXT} asm/aesni-x86_64.pl) +perlasm(bsaes-x86_64.${ASM_EXT} asm/bsaes-x86_64.pl) +perlasm(vpaes-x86_64.${ASM_EXT} asm/vpaes-x86_64.pl) +perlasm(aes-586.${ASM_EXT} asm/aes-586.pl) +perlasm(vpaes-x86.${ASM_EXT} asm/vpaes-x86.pl) +perlasm(aesni-x86.${ASM_EXT} asm/aesni-x86.pl) +perlasm(aes-armv4.${ASM_EXT} asm/aes-armv4.pl) +perlasm(bsaes-armv7.${ASM_EXT} asm/bsaes-armv7.pl) +perlasm(aesv8-armx.${ASM_EXT} asm/aesv8-armx.pl) diff --git a/TMessagesProj/jni/boringssl/crypto/aes/aes.c b/TMessagesProj/jni/boringssl/crypto/aes/aes.c new file mode 100644 index 00000000..933aa073 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/aes/aes.c @@ -0,0 +1,1085 @@ +/* ==================================================================== + * Copyright (c) 2002-2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== */ + +#include + +#include + +#include "internal.h" + + +#if defined(OPENSSL_NO_ASM) || \ + (!defined(OPENSSL_X86) && !defined(OPENSSL_X86_64) && !defined(OPENSSL_ARM)) + +/* Te0[x] = S [x].[02, 01, 01, 03]; + * Te1[x] = S [x].[03, 02, 01, 01]; + * Te2[x] = S [x].[01, 03, 02, 01]; + * Te3[x] = S [x].[01, 01, 03, 02]; + * + * Td0[x] = Si[x].[0e, 09, 0d, 0b]; + * Td1[x] = Si[x].[0b, 0e, 09, 0d]; + * Td2[x] = Si[x].[0d, 0b, 0e, 09]; + * Td3[x] = Si[x].[09, 0d, 0b, 0e]; + * Td4[x] = Si[x].[01]; */ + +static const uint32_t Te0[256] = { + 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, 0xfff2f20dU, + 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, 0x60303050U, 0x02010103U, + 0xce6767a9U, 0x562b2b7dU, 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, + 0xec76769aU, 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, + 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, 0x41adadecU, + 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, 0x239c9cbfU, 0x53a4a4f7U, + 0xe4727296U, 0x9bc0c05bU, 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, + 0x4c26266aU, 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, + 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, 0xe2717193U, + 0xabd8d873U, 0x62313153U, 0x2a15153fU, 0x0804040cU, 0x95c7c752U, + 0x46232365U, 0x9dc3c35eU, 0x30181828U, 0x379696a1U, 0x0a05050fU, + 0x2f9a9ab5U, 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, + 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, 0x1209091bU, + 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, 0x361b1b2dU, 0xdc6e6eb2U, + 0xb45a5aeeU, 0x5ba0a0fbU, 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, + 0x7db3b3ceU, 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, + 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, 0x40202060U, + 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, 0xd46a6abeU, 0x8dcbcb46U, + 0x67bebed9U, 0x7239394bU, 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, + 0x85cfcf4aU, 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, + 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, 0x8a4545cfU, + 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, 0xa05050f0U, 0x783c3c44U, + 0x259f9fbaU, 0x4ba8a8e3U, 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, + 0x058f8f8aU, 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, + 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, 0x20101030U, + 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, 0x81cdcd4cU, 0x180c0c14U, + 0x26131335U, 0xc3ecec2fU, 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, + 0x2e171739U, 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, + 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, 0xc06060a0U, + 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, 0x44222266U, 0x542a2a7eU, + 0x3b9090abU, 0x0b888883U, 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, + 0x2814143cU, 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, + 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, 0x924949dbU, + 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, 0x9fc2c25dU, 0xbdd3d36eU, + 0x43acacefU, 0xc46262a6U, 0x399191a8U, 0x319595a4U, 0xd3e4e437U, + 0xf279798bU, 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, + 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, 0xd86c6cb4U, + 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, 0xca6565afU, 0xf47a7a8eU, + 0x47aeaee9U, 0x10080818U, 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, + 0x5c2e2e72U, 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, + 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, 0x964b4bddU, + 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, 0xe0707090U, 0x7c3e3e42U, + 0x71b5b5c4U, 0xcc6666aaU, 0x904848d8U, 0x06030305U, 0xf7f6f601U, + 0x1c0e0e12U, 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, + 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, 0xd9e1e138U, + 0xebf8f813U, 0x2b9898b3U, 0x22111133U, 0xd26969bbU, 0xa9d9d970U, + 0x078e8e89U, 0x339494a7U, 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, + 0xc9e9e920U, 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, + 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, 0x65bfbfdaU, + 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, 0x824141c3U, 0x299999b0U, + 0x5a2d2d77U, 0x1e0f0f11U, 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, + 0x2c16163aU, }; + +static const uint32_t Te1[256] = { + 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, 0x0dfff2f2U, + 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, 0x50603030U, 0x03020101U, + 0xa9ce6767U, 0x7d562b2bU, 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, + 0x9aec7676U, 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU, + 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, 0xec41adadU, + 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU, 0xbf239c9cU, 0xf753a4a4U, + 0x96e47272U, 0x5b9bc0c0U, 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, + 0x6a4c2626U, 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU, + 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U, 0x93e27171U, + 0x73abd8d8U, 0x53623131U, 0x3f2a1515U, 0x0c080404U, 0x5295c7c7U, + 0x65462323U, 0x5e9dc3c3U, 0x28301818U, 0xa1379696U, 0x0f0a0505U, + 0xb52f9a9aU, 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U, + 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U, 0x1b120909U, + 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, 0x2d361b1bU, 0xb2dc6e6eU, + 0xeeb45a5aU, 0xfb5ba0a0U, 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, + 0xce7db3b3U, 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U, + 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU, 0x60402020U, + 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, 0xbed46a6aU, 0x468dcbcbU, + 0xd967bebeU, 0x4b723939U, 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, + 0x4a85cfcfU, 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU, + 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, 0xcf8a4545U, + 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, 0xf0a05050U, 0x44783c3cU, + 0xba259f9fU, 0xe34ba8a8U, 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, + 0x8a058f8fU, 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U, + 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, 0x30201010U, + 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U, 0x4c81cdcdU, 0x14180c0cU, + 0x35261313U, 0x2fc3ececU, 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, + 0x392e1717U, 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU, + 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U, 0xa0c06060U, + 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU, 0x66442222U, 0x7e542a2aU, + 0xab3b9090U, 0x830b8888U, 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, + 0x3c281414U, 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU, + 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU, 0xdb924949U, + 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU, 0x5d9fc2c2U, 0x6ebdd3d3U, + 0xef43acacU, 0xa6c46262U, 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, + 0x8bf27979U, 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU, + 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U, 0xb4d86c6cU, + 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, 0xafca6565U, 0x8ef47a7aU, + 0xe947aeaeU, 0x18100808U, 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, + 0x725c2e2eU, 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U, + 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU, 0xdd964b4bU, + 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU, 0x90e07070U, 0x427c3e3eU, + 0xc471b5b5U, 0xaacc6666U, 0xd8904848U, 0x05060303U, 0x01f7f6f6U, + 0x121c0e0eU, 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U, + 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU, 0x38d9e1e1U, + 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, 0xbbd26969U, 0x70a9d9d9U, + 0x89078e8eU, 0xa7339494U, 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, + 0x20c9e9e9U, 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU, + 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, 0xda65bfbfU, + 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, 0xc3824141U, 0xb0299999U, + 0x775a2d2dU, 0x111e0f0fU, 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, + 0x3a2c1616U, }; + +static const uint32_t Te2[256] = { + 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, 0xf20dfff2U, + 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, 0x30506030U, 0x01030201U, + 0x67a9ce67U, 0x2b7d562bU, 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, + 0x769aec76U, 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU, + 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, 0xadec41adU, + 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU, 0x9cbf239cU, 0xa4f753a4U, + 0x7296e472U, 0xc05b9bc0U, 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, + 0x266a4c26U, 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU, + 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U, 0x7193e271U, + 0xd873abd8U, 0x31536231U, 0x153f2a15U, 0x040c0804U, 0xc75295c7U, + 0x23654623U, 0xc35e9dc3U, 0x18283018U, 0x96a13796U, 0x050f0a05U, + 0x9ab52f9aU, 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U, + 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U, 0x091b1209U, + 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, 0x1b2d361bU, 0x6eb2dc6eU, + 0x5aeeb45aU, 0xa0fb5ba0U, 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, + 0xb3ce7db3U, 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U, + 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU, 0x20604020U, + 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, 0x6abed46aU, 0xcb468dcbU, + 0xbed967beU, 0x394b7239U, 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, + 0xcf4a85cfU, 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU, + 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, 0x45cf8a45U, + 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, 0x50f0a050U, 0x3c44783cU, + 0x9fba259fU, 0xa8e34ba8U, 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, + 0x8f8a058fU, 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U, + 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, 0x10302010U, + 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U, 0xcd4c81cdU, 0x0c14180cU, + 0x13352613U, 0xec2fc3ecU, 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, + 0x17392e17U, 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU, + 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U, 0x60a0c060U, + 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU, 0x22664422U, 0x2a7e542aU, + 0x90ab3b90U, 0x88830b88U, 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, + 0x143c2814U, 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU, + 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU, 0x49db9249U, + 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU, 0xc25d9fc2U, 0xd36ebdd3U, + 0xacef43acU, 0x62a6c462U, 0x91a83991U, 0x95a43195U, 0xe437d3e4U, + 0x798bf279U, 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU, + 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U, 0x6cb4d86cU, + 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, 0x65afca65U, 0x7a8ef47aU, + 0xaee947aeU, 0x08181008U, 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, + 0x2e725c2eU, 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U, + 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU, 0x4bdd964bU, + 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU, 0x7090e070U, 0x3e427c3eU, + 0xb5c471b5U, 0x66aacc66U, 0x48d89048U, 0x03050603U, 0xf601f7f6U, + 0x0e121c0eU, 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U, + 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU, 0xe138d9e1U, + 0xf813ebf8U, 0x98b32b98U, 0x11332211U, 0x69bbd269U, 0xd970a9d9U, + 0x8e89078eU, 0x94a73394U, 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, + 0xe920c9e9U, 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU, + 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, 0xbfda65bfU, + 0xe631d7e6U, 0x42c68442U, 0x68b8d068U, 0x41c38241U, 0x99b02999U, + 0x2d775a2dU, 0x0f111e0fU, 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, + 0x163a2c16U, }; + +static const uint32_t Te3[256] = { + 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, 0xf2f20dffU, + 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, 0x30305060U, 0x01010302U, + 0x6767a9ceU, 0x2b2b7d56U, 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, + 0x76769aecU, 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU, + 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, 0xadadec41U, + 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U, 0x9c9cbf23U, 0xa4a4f753U, + 0x727296e4U, 0xc0c05b9bU, 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, + 0x26266a4cU, 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U, + 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U, 0x717193e2U, + 0xd8d873abU, 0x31315362U, 0x15153f2aU, 0x04040c08U, 0xc7c75295U, + 0x23236546U, 0xc3c35e9dU, 0x18182830U, 0x9696a137U, 0x05050f0aU, + 0x9a9ab52fU, 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU, + 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU, 0x09091b12U, + 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, 0x1b1b2d36U, 0x6e6eb2dcU, + 0x5a5aeeb4U, 0xa0a0fb5bU, 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, + 0xb3b3ce7dU, 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U, + 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U, 0x20206040U, + 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, 0x6a6abed4U, 0xcbcb468dU, + 0xbebed967U, 0x39394b72U, 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, + 0xcfcf4a85U, 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU, + 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, 0x4545cf8aU, + 0xf9f910e9U, 0x02020604U, 0x7f7f81feU, 0x5050f0a0U, 0x3c3c4478U, + 0x9f9fba25U, 0xa8a8e34bU, 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, + 0x8f8f8a05U, 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U, + 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, 0x10103020U, + 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU, 0xcdcd4c81U, 0x0c0c1418U, + 0x13133526U, 0xecec2fc3U, 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, + 0x1717392eU, 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU, + 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U, 0x6060a0c0U, + 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U, 0x22226644U, 0x2a2a7e54U, + 0x9090ab3bU, 0x8888830bU, 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, + 0x14143c28U, 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU, + 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, 0x4949db92U, + 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U, 0xc2c25d9fU, 0xd3d36ebdU, + 0xacacef43U, 0x6262a6c4U, 0x9191a839U, 0x9595a431U, 0xe4e437d3U, + 0x79798bf2U, 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU, + 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U, 0x6c6cb4d8U, + 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, 0x6565afcaU, 0x7a7a8ef4U, + 0xaeaee947U, 0x08081810U, 0xbabad56fU, 0x787888f0U, 0x25256f4aU, + 0x2e2e725cU, 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U, + 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU, 0x4b4bdd96U, + 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU, 0x707090e0U, 0x3e3e427cU, + 0xb5b5c471U, 0x6666aaccU, 0x4848d890U, 0x03030506U, 0xf6f601f7U, + 0x0e0e121cU, 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U, + 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U, 0xe1e138d9U, + 0xf8f813ebU, 0x9898b32bU, 0x11113322U, 0x6969bbd2U, 0xd9d970a9U, + 0x8e8e8907U, 0x9494a733U, 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, + 0xe9e920c9U, 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U, + 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, 0xbfbfda65U, + 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, 0x4141c382U, 0x9999b029U, + 0x2d2d775aU, 0x0f0f111eU, 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, + 0x16163a2cU, }; + +static const uint32_t Td0[256] = { + 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, 0x3bab6bcbU, + 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, 0x2030fa55U, 0xad766df6U, + 0x88cc7691U, 0xf5024c25U, 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, + 0xb562a38fU, 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, + 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, 0x038f5fe7U, + 0x15929c95U, 0xbf6d7aebU, 0x955259daU, 0xd4be832dU, 0x587421d3U, + 0x49e06929U, 0x8ec9c844U, 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, + 0x27b971ddU, 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, + 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, 0xb16477e0U, + 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, 0x70486858U, 0x8f45fd19U, + 0x94de6c87U, 0x527bf8b7U, 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, + 0x6655ab2aU, 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, + 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, 0x8acf1c2bU, + 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, 0x65daf4cdU, 0x0605bed5U, + 0xd134621fU, 0xc4a6fe8aU, 0x342e539dU, 0xa2f355a0U, 0x058ae132U, + 0xa4f6eb75U, 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, + 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, 0x91548db5U, + 0x71c45d05U, 0x0406d46fU, 0x605015ffU, 0x1998fb24U, 0xd6bde997U, + 0x894043ccU, 0x67d99e77U, 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, + 0x79c8eedbU, 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, + 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, 0xfd0efffbU, + 0x0f853856U, 0x3daed51eU, 0x362d3927U, 0x0a0fd964U, 0x685ca621U, + 0x9b5b54d1U, 0x24362e3aU, 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, + 0x1b9b919eU, 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, + 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, 0x0e090d0bU, + 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, 0x57f11985U, 0xaf75074cU, + 0xee99ddbbU, 0xa37f60fdU, 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, + 0x5bfb7e34U, 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, + 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, 0x854a247dU, + 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, 0x1d9e2f4bU, 0xdcb230f3U, + 0x0d8652ecU, 0x77c1e3d0U, 0x2bb3166cU, 0xa970b999U, 0x119448faU, + 0x47e96422U, 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, + 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, 0xa6f581cfU, + 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, 0x2c3a9de4U, 0x5078920dU, + 0x6a5fcc9bU, 0x547e4662U, 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, + 0x82c3aff5U, 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, + 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, 0xcd267809U, + 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, 0xe6956e65U, 0xaaffe67eU, + 0x21bccf08U, 0xef15e8e6U, 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, + 0x29b07cd6U, 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, + 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, 0xf104984aU, + 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, 0x764dd68dU, 0x43efb04dU, + 0xccaa4d54U, 0xe49604dfU, 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, + 0x4665517fU, 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, + 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, 0x9ad7618cU, + 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, 0xcea927eeU, 0xb761c935U, + 0xe11ce5edU, 0x7a47b13cU, 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, + 0x73c737bfU, 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U, + 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, 0x161dc372U, + 0xbce2250cU, 0x283c498bU, 0xff0d9541U, 0x39a80171U, 0x080cb3deU, + 0xd8b4e49cU, 0x6456c190U, 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, + 0xd0b85742U, }; + +static const uint32_t Td1[256] = { + 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU, 0xcb3bab6bU, + 0xf11f9d45U, 0xabacfa58U, 0x934be303U, 0x552030faU, 0xf6ad766dU, + 0x9188cc76U, 0x25f5024cU, 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, + 0x8fb562a3U, 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U, + 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U, 0xe7038f5fU, + 0x9515929cU, 0xebbf6d7aU, 0xda955259U, 0x2dd4be83U, 0xd3587421U, + 0x2949e069U, 0x448ec9c8U, 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, + 0xdd27b971U, 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU, + 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU, 0xe0b16477U, + 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU, 0x58704868U, 0x198f45fdU, + 0x8794de6cU, 0xb7527bf8U, 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, + 0x2a6655abU, 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U, + 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U, 0x2b8acf1cU, + 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U, 0xcd65daf4U, 0xd50605beU, + 0x1fd13462U, 0x8ac4a6feU, 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, + 0x75a4f6ebU, 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U, + 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU, 0xb591548dU, + 0x0571c45dU, 0x6f0406d4U, 0xff605015U, 0x241998fbU, 0x97d6bde9U, + 0xcc894043U, 0x7767d99eU, 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, + 0xdb79c8eeU, 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U, + 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U, 0xfbfd0effU, + 0x560f8538U, 0x1e3daed5U, 0x27362d39U, 0x640a0fd9U, 0x21685ca6U, + 0xd19b5b54U, 0x3a24362eU, 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, + 0x9e1b9b91U, 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU, + 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U, 0x0b0e090dU, + 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U, 0x8557f119U, 0x4caf7507U, + 0xbbee99ddU, 0xfda37f60U, 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, + 0x345bfb7eU, 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U, + 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U, 0x7d854a24U, + 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U, 0x4b1d9e2fU, 0xf3dcb230U, + 0xec0d8652U, 0xd077c1e3U, 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, + 0x2247e964U, 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U, + 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU, 0xcfa6f581U, + 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU, 0xe42c3a9dU, 0x0d507892U, + 0x9b6a5fccU, 0x62547e46U, 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, + 0xf582c3afU, 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U, + 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU, 0x09cd2678U, + 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU, 0x65e6956eU, 0x7eaaffe6U, + 0x0821bccfU, 0xe6ef15e8U, 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, + 0xd629b07cU, 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U, + 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U, 0x4af10498U, + 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U, 0x8d764dd6U, 0x4d43efb0U, + 0x54ccaa4dU, 0xdfe49604U, 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, + 0x7f466551U, 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U, + 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U, 0x8c9ad761U, + 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU, 0xeecea927U, 0x35b761c9U, + 0xede11ce5U, 0x3c7a47b1U, 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, + 0xbf73c737U, 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU, + 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U, 0x72161dc3U, + 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U, 0x7139a801U, 0xde080cb3U, + 0x9cd8b4e4U, 0x906456c1U, 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, + 0x42d0b857U, }; + +static const uint32_t Td2[256] = { + 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U, 0x6bcb3babU, + 0x45f11f9dU, 0x58abacfaU, 0x03934be3U, 0xfa552030U, 0x6df6ad76U, + 0x769188ccU, 0x4c25f502U, 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, + 0xa38fb562U, 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU, + 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U, 0x5fe7038fU, + 0x9c951592U, 0x7aebbf6dU, 0x59da9552U, 0x832dd4beU, 0x21d35874U, + 0x692949e0U, 0xc8448ec9U, 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, + 0x71dd27b9U, 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU, + 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U, 0x77e0b164U, + 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U, 0x68587048U, 0xfd198f45U, + 0x6c8794deU, 0xf8b7527bU, 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, + 0xab2a6655U, 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U, + 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U, 0x1c2b8acfU, + 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U, 0xf4cd65daU, 0xbed50605U, + 0x621fd134U, 0xfe8ac4a6U, 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, + 0xeb75a4f6U, 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU, + 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U, 0x8db59154U, + 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U, 0xfb241998U, 0xe997d6bdU, + 0x43cc8940U, 0x9e7767d9U, 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, + 0xeedb79c8U, 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U, + 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU, 0xfffbfd0eU, + 0x38560f85U, 0xd51e3daeU, 0x3927362dU, 0xd9640a0fU, 0xa621685cU, + 0x54d19b5bU, 0x2e3a2436U, 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, + 0x919e1b9bU, 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U, + 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU, 0x0d0b0e09U, + 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU, 0x198557f1U, 0x074caf75U, + 0xddbbee99U, 0x60fda37fU, 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, + 0x7e345bfbU, 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U, + 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U, 0x247d854aU, + 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U, 0x2f4b1d9eU, 0x30f3dcb2U, + 0x52ec0d86U, 0xe3d077c1U, 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, + 0x642247e9U, 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U, + 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U, 0x81cfa6f5U, + 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU, 0x9de42c3aU, 0x920d5078U, + 0xcc9b6a5fU, 0x4662547eU, 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, + 0xaff582c3U, 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U, + 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU, 0x7809cd26U, + 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU, 0x6e65e695U, 0xe67eaaffU, + 0xcf0821bcU, 0xe8e6ef15U, 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, + 0x7cd629b0U, 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U, + 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U, 0x984af104U, + 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U, 0xd68d764dU, 0xb04d43efU, + 0x4d54ccaaU, 0x04dfe496U, 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, + 0x517f4665U, 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU, + 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U, 0x618c9ad7U, + 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U, 0x27eecea9U, 0xc935b761U, + 0xe5ede11cU, 0xb13c7a47U, 0xdf599cd2U, 0x733f55f2U, 0xce791814U, + 0x37bf73c7U, 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U, + 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U, 0xc372161dU, + 0x250cbce2U, 0x498b283cU, 0x9541ff0dU, 0x017139a8U, 0xb3de080cU, + 0xe49cd8b4U, 0xc1906456U, 0x84617bcbU, 0xb670d532U, 0x5c74486cU, + 0x5742d0b8U, }; + +static const uint32_t Td3[256] = { + 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU, 0xab6bcb3bU, + 0x9d45f11fU, 0xfa58abacU, 0xe303934bU, 0x30fa5520U, 0x766df6adU, + 0xcc769188U, 0x024c25f5U, 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, + 0x62a38fb5U, 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU, + 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU, 0x8f5fe703U, + 0x929c9515U, 0x6d7aebbfU, 0x5259da95U, 0xbe832dd4U, 0x7421d358U, + 0xe0692949U, 0xc9c8448eU, 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, + 0xb971dd27U, 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU, + 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U, 0x6477e0b1U, + 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U, 0x48685870U, 0x45fd198fU, + 0xde6c8794U, 0x7bf8b752U, 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, + 0x55ab2a66U, 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U, + 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU, 0xcf1c2b8aU, + 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU, 0xdaf4cd65U, 0x05bed506U, + 0x34621fd1U, 0xa6fe8ac4U, 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, + 0xf6eb75a4U, 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU, + 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU, 0x548db591U, + 0xc45d0571U, 0x06d46f04U, 0x5015ff60U, 0x98fb2419U, 0xbde997d6U, + 0x4043cc89U, 0xd99e7767U, 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, + 0xc8eedb79U, 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U, + 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU, 0x0efffbfdU, + 0x8538560fU, 0xaed51e3dU, 0x2d392736U, 0x0fd9640aU, 0x5ca62168U, + 0x5b54d19bU, 0x362e3a24U, 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, + 0x9b919e1bU, 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU, + 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U, 0x090d0b0eU, + 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U, 0xf1198557U, 0x75074cafU, + 0x99ddbbeeU, 0x7f60fda3U, 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, + 0xfb7e345bU, 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U, + 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U, 0x4a247d85U, + 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U, 0x9e2f4b1dU, 0xb230f3dcU, + 0x8652ec0dU, 0xc1e3d077U, 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, + 0xe9642247U, 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U, + 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U, 0xf581cfa6U, + 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU, 0x3a9de42cU, 0x78920d50U, + 0x5fcc9b6aU, 0x7e466254U, 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, + 0xc3aff582U, 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU, + 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU, 0x267809cdU, + 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U, 0x956e65e6U, 0xffe67eaaU, + 0xbccf0821U, 0x15e8e6efU, 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, + 0xb07cd629U, 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U, + 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U, 0x04984af1U, + 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U, 0x4dd68d76U, 0xefb04d43U, + 0xaa4d54ccU, 0x9604dfe4U, 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, + 0x65517f46U, 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU, + 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU, 0xd7618c9aU, + 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU, 0xa927eeceU, 0x61c935b7U, + 0x1ce5ede1U, 0x47b13c7aU, 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, + 0xc737bf73U, 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U, + 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U, 0x1dc37216U, + 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU, 0xa8017139U, 0x0cb3de08U, + 0xb4e49cd8U, 0x56c19064U, 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, + 0xb85742d0U, }; + +static const uint8_t Td4[256] = { + 0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U, 0xbfU, 0x40U, 0xa3U, + 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU, 0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, + 0xffU, 0x87U, 0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU, 0x54U, + 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU, 0xeeU, 0x4cU, 0x95U, 0x0bU, + 0x42U, 0xfaU, 0xc3U, 0x4eU, 0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, + 0xb2U, 0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U, 0x72U, 0xf8U, + 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U, 0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, + 0x65U, 0xb6U, 0x92U, 0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU, + 0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U, 0x90U, 0xd8U, 0xabU, + 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU, 0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, + 0x45U, 0x06U, 0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U, 0xc1U, + 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU, 0x3aU, 0x91U, 0x11U, 0x41U, + 0x4fU, 0x67U, 0xdcU, 0xeaU, 0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, + 0x73U, 0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U, 0xe2U, 0xf9U, + 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU, 0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, + 0x29U, 0xc5U, 0x89U, 0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU, + 0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U, 0x9aU, 0xdbU, 0xc0U, + 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U, 0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, + 0xc7U, 0x31U, 0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU, 0x60U, + 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU, 0x2dU, 0xe5U, 0x7aU, 0x9fU, + 0x93U, 0xc9U, 0x9cU, 0xefU, 0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, + 0xb0U, 0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U, 0x17U, 0x2bU, + 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U, 0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, + 0x21U, 0x0cU, 0x7dU, }; + +static const uint32_t rcon[] = { + 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, + 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, + /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ +}; + +int AES_set_encrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey) { + uint32_t *rk; + int i = 0; + uint32_t temp; + + if (!key || !aeskey) { + return -1; + } + + switch (bits) { + case 128: + aeskey->rounds = 10; + break; + case 192: + aeskey->rounds = 12; + break; + case 256: + aeskey->rounds = 14; + break; + default: + return -2; + } + + rk = aeskey->rd_key; + + rk[0] = GETU32(key); + rk[1] = GETU32(key + 4); + rk[2] = GETU32(key + 8); + rk[3] = GETU32(key + 12); + if (bits == 128) { + while (1) { + temp = rk[3]; + rk[4] = rk[0] ^ (Te2[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te3[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te0[(temp) & 0xff] & 0x0000ff00) ^ + (Te1[(temp >> 24)] & 0x000000ff) ^ rcon[i]; + rk[5] = rk[1] ^ rk[4]; + rk[6] = rk[2] ^ rk[5]; + rk[7] = rk[3] ^ rk[6]; + if (++i == 10) { + return 0; + } + rk += 4; + } + } + rk[4] = GETU32(key + 16); + rk[5] = GETU32(key + 20); + if (bits == 192) { + while (1) { + temp = rk[5]; + rk[6] = rk[0] ^ (Te2[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te3[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te0[(temp) & 0xff] & 0x0000ff00) ^ + (Te1[(temp >> 24)] & 0x000000ff) ^ rcon[i]; + rk[7] = rk[1] ^ rk[6]; + rk[8] = rk[2] ^ rk[7]; + rk[9] = rk[3] ^ rk[8]; + if (++i == 8) { + return 0; + } + rk[10] = rk[4] ^ rk[9]; + rk[11] = rk[5] ^ rk[10]; + rk += 6; + } + } + rk[6] = GETU32(key + 24); + rk[7] = GETU32(key + 28); + if (bits == 256) { + while (1) { + temp = rk[7]; + rk[8] = rk[0] ^ (Te2[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te3[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te0[(temp) & 0xff] & 0x0000ff00) ^ + (Te1[(temp >> 24)] & 0x000000ff) ^ rcon[i]; + rk[9] = rk[1] ^ rk[8]; + rk[10] = rk[2] ^ rk[9]; + rk[11] = rk[3] ^ rk[10]; + if (++i == 7) { + return 0; + } + temp = rk[11]; + rk[12] = rk[4] ^ (Te2[(temp >> 24)] & 0xff000000) ^ + (Te3[(temp >> 16) & 0xff] & 0x00ff0000) ^ + (Te0[(temp >> 8) & 0xff] & 0x0000ff00) ^ + (Te1[(temp) & 0xff] & 0x000000ff); + rk[13] = rk[5] ^ rk[12]; + rk[14] = rk[6] ^ rk[13]; + rk[15] = rk[7] ^ rk[14]; + + rk += 8; + } + } + return 0; +} + +int AES_set_decrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey) { + uint32_t *rk; + int i, j, status; + uint32_t temp; + + /* first, start with an encryption schedule */ + status = AES_set_encrypt_key(key, bits, aeskey); + if (status < 0) { + return status; + } + + rk = aeskey->rd_key; + + /* invert the order of the round keys: */ + for (i = 0, j = 4 * aeskey->rounds; i < j; i += 4, j -= 4) { + temp = rk[i]; + rk[i] = rk[j]; + rk[j] = temp; + temp = rk[i + 1]; + rk[i + 1] = rk[j + 1]; + rk[j + 1] = temp; + temp = rk[i + 2]; + rk[i + 2] = rk[j + 2]; + rk[j + 2] = temp; + temp = rk[i + 3]; + rk[i + 3] = rk[j + 3]; + rk[j + 3] = temp; + } + /* apply the inverse MixColumn transform to all round keys but the first and + * the last: */ + for (i = 1; i < (int)aeskey->rounds; i++) { + rk += 4; + rk[0] = + Td0[Te1[(rk[0] >> 24)] & 0xff] ^ Td1[Te1[(rk[0] >> 16) & 0xff] & 0xff] ^ + Td2[Te1[(rk[0] >> 8) & 0xff] & 0xff] ^ Td3[Te1[(rk[0]) & 0xff] & 0xff]; + rk[1] = + Td0[Te1[(rk[1] >> 24)] & 0xff] ^ Td1[Te1[(rk[1] >> 16) & 0xff] & 0xff] ^ + Td2[Te1[(rk[1] >> 8) & 0xff] & 0xff] ^ Td3[Te1[(rk[1]) & 0xff] & 0xff]; + rk[2] = + Td0[Te1[(rk[2] >> 24)] & 0xff] ^ Td1[Te1[(rk[2] >> 16) & 0xff] & 0xff] ^ + Td2[Te1[(rk[2] >> 8) & 0xff] & 0xff] ^ Td3[Te1[(rk[2]) & 0xff] & 0xff]; + rk[3] = + Td0[Te1[(rk[3] >> 24)] & 0xff] ^ Td1[Te1[(rk[3] >> 16) & 0xff] & 0xff] ^ + Td2[Te1[(rk[3] >> 8) & 0xff] & 0xff] ^ Td3[Te1[(rk[3]) & 0xff] & 0xff]; + } + return 0; +} + +void AES_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { + const uint32_t *rk; + uint32_t s0, s1, s2, s3, t0, t1, t2, t3; +#ifndef FULL_UNROLL + int r; +#endif /* ?FULL_UNROLL */ + + assert(in && out && key); + rk = key->rd_key; + + /* map byte array block to cipher state + * and add initial round key: */ + s0 = GETU32(in) ^ rk[0]; + s1 = GETU32(in + 4) ^ rk[1]; + s2 = GETU32(in + 8) ^ rk[2]; + s3 = GETU32(in + 12) ^ rk[3]; +#ifdef FULL_UNROLL + /* round 1: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ + Te3[s3 & 0xff] ^ rk[4]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ + Te3[s0 & 0xff] ^ rk[5]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ + Te3[s1 & 0xff] ^ rk[6]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ + Te3[s2 & 0xff] ^ rk[7]; + /* round 2: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ + Te3[t3 & 0xff] ^ rk[8]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ + Te3[t0 & 0xff] ^ rk[9]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ + Te3[t1 & 0xff] ^ rk[10]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ + Te3[t2 & 0xff] ^ rk[11]; + /* round 3: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ + Te3[s3 & 0xff] ^ rk[12]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ + Te3[s0 & 0xff] ^ rk[13]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ + Te3[s1 & 0xff] ^ rk[14]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ + Te3[s2 & 0xff] ^ rk[15]; + /* round 4: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ + Te3[t3 & 0xff] ^ rk[16]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ + Te3[t0 & 0xff] ^ rk[17]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ + Te3[t1 & 0xff] ^ rk[18]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ + Te3[t2 & 0xff] ^ rk[19]; + /* round 5: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ + Te3[s3 & 0xff] ^ rk[20]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ + Te3[s0 & 0xff] ^ rk[21]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ + Te3[s1 & 0xff] ^ rk[22]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ + Te3[s2 & 0xff] ^ rk[23]; + /* round 6: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ + Te3[t3 & 0xff] ^ rk[24]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ + Te3[t0 & 0xff] ^ rk[25]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ + Te3[t1 & 0xff] ^ rk[26]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ + Te3[t2 & 0xff] ^ rk[27]; + /* round 7: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ + Te3[s3 & 0xff] ^ rk[28]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ + Te3[s0 & 0xff] ^ rk[29]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ + Te3[s1 & 0xff] ^ rk[30]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ + Te3[s2 & 0xff] ^ rk[31]; + /* round 8: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ + Te3[t3 & 0xff] ^ rk[32]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ + Te3[t0 & 0xff] ^ rk[33]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ + Te3[t1 & 0xff] ^ rk[34]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ + Te3[t2 & 0xff] ^ rk[35]; + /* round 9: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ + Te3[s3 & 0xff] ^ rk[36]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ + Te3[s0 & 0xff] ^ rk[37]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ + Te3[s1 & 0xff] ^ rk[38]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ + Te3[s2 & 0xff] ^ rk[39]; + if (key->rounds > 10) { + /* round 10: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ + Te3[t3 & 0xff] ^ rk[40]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ + Te3[t0 & 0xff] ^ rk[41]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ + Te3[t1 & 0xff] ^ rk[42]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ + Te3[t2 & 0xff] ^ rk[43]; + /* round 11: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ + Te3[s3 & 0xff] ^ rk[44]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ + Te3[s0 & 0xff] ^ rk[45]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ + Te3[s1 & 0xff] ^ rk[46]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ + Te3[s2 & 0xff] ^ rk[47]; + if (key->rounds > 12) { + /* round 12: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ + Te3[t3 & 0xff] ^ rk[48]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ + Te3[t0 & 0xff] ^ rk[49]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ + Te3[t1 & 0xff] ^ rk[50]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ + Te3[t2 & 0xff] ^ rk[51]; + /* round 13: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ + Te3[s3 & 0xff] ^ rk[52]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ + Te3[s0 & 0xff] ^ rk[53]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ + Te3[s1 & 0xff] ^ rk[54]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ + Te3[s2 & 0xff] ^ rk[55]; + } + } + rk += key->rounds << 2; +#else /* !FULL_UNROLL */ + /* + * Nr - 1 full rounds: + */ + r = key->rounds >> 1; + for (;;) { + t0 = Te0[(s0 >> 24)] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ + Te3[(s3) & 0xff] ^ rk[4]; + t1 = Te0[(s1 >> 24)] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ + Te3[(s0) & 0xff] ^ rk[5]; + t2 = Te0[(s2 >> 24)] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ + Te3[(s1) & 0xff] ^ rk[6]; + t3 = Te0[(s3 >> 24)] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ + Te3[(s2) & 0xff] ^ rk[7]; + + rk += 8; + if (--r == 0) { + break; + } + + s0 = Te0[(t0 >> 24)] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ + Te3[(t3) & 0xff] ^ rk[0]; + s1 = Te0[(t1 >> 24)] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ + Te3[(t0) & 0xff] ^ rk[1]; + s2 = Te0[(t2 >> 24)] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ + Te3[(t1) & 0xff] ^ rk[2]; + s3 = Te0[(t3 >> 24)] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ + Te3[(t2) & 0xff] ^ rk[3]; + } +#endif /* ?FULL_UNROLL */ + /* apply last round and map cipher state to byte array block: */ + s0 = (Te2[(t0 >> 24)] & 0xff000000) ^ (Te3[(t1 >> 16) & 0xff] & 0x00ff0000) ^ + (Te0[(t2 >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(t3) & 0xff] & 0x000000ff) ^ + rk[0]; + PUTU32(out, s0); + s1 = (Te2[(t1 >> 24)] & 0xff000000) ^ (Te3[(t2 >> 16) & 0xff] & 0x00ff0000) ^ + (Te0[(t3 >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(t0) & 0xff] & 0x000000ff) ^ + rk[1]; + PUTU32(out + 4, s1); + s2 = (Te2[(t2 >> 24)] & 0xff000000) ^ (Te3[(t3 >> 16) & 0xff] & 0x00ff0000) ^ + (Te0[(t0 >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(t1) & 0xff] & 0x000000ff) ^ + rk[2]; + PUTU32(out + 8, s2); + s3 = (Te2[(t3 >> 24)] & 0xff000000) ^ (Te3[(t0 >> 16) & 0xff] & 0x00ff0000) ^ + (Te0[(t1 >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(t2) & 0xff] & 0x000000ff) ^ + rk[3]; + PUTU32(out + 12, s3); +} + +void AES_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { + const uint32_t *rk; + uint32_t s0, s1, s2, s3, t0, t1, t2, t3; +#ifndef FULL_UNROLL + int r; +#endif /* ?FULL_UNROLL */ + + assert(in && out && key); + rk = key->rd_key; + + /* map byte array block to cipher state + * and add initial round key: */ + s0 = GETU32(in) ^ rk[0]; + s1 = GETU32(in + 4) ^ rk[1]; + s2 = GETU32(in + 8) ^ rk[2]; + s3 = GETU32(in + 12) ^ rk[3]; +#ifdef FULL_UNROLL + /* round 1: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ + Td3[s1 & 0xff] ^ rk[4]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ + Td3[s2 & 0xff] ^ rk[5]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ + Td3[s3 & 0xff] ^ rk[6]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ + Td3[s0 & 0xff] ^ rk[7]; + /* round 2: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ + Td3[t1 & 0xff] ^ rk[8]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ + Td3[t2 & 0xff] ^ rk[9]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ + Td3[t3 & 0xff] ^ rk[10]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ + Td3[t0 & 0xff] ^ rk[11]; + /* round 3: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ + Td3[s1 & 0xff] ^ rk[12]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ + Td3[s2 & 0xff] ^ rk[13]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ + Td3[s3 & 0xff] ^ rk[14]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ + Td3[s0 & 0xff] ^ rk[15]; + /* round 4: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ + Td3[t1 & 0xff] ^ rk[16]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ + Td3[t2 & 0xff] ^ rk[17]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ + Td3[t3 & 0xff] ^ rk[18]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ + Td3[t0 & 0xff] ^ rk[19]; + /* round 5: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ + Td3[s1 & 0xff] ^ rk[20]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ + Td3[s2 & 0xff] ^ rk[21]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ + Td3[s3 & 0xff] ^ rk[22]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ + Td3[s0 & 0xff] ^ rk[23]; + /* round 6: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ + Td3[t1 & 0xff] ^ rk[24]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ + Td3[t2 & 0xff] ^ rk[25]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ + Td3[t3 & 0xff] ^ rk[26]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ + Td3[t0 & 0xff] ^ rk[27]; + /* round 7: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ + Td3[s1 & 0xff] ^ rk[28]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ + Td3[s2 & 0xff] ^ rk[29]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ + Td3[s3 & 0xff] ^ rk[30]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ + Td3[s0 & 0xff] ^ rk[31]; + /* round 8: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ + Td3[t1 & 0xff] ^ rk[32]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ + Td3[t2 & 0xff] ^ rk[33]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ + Td3[t3 & 0xff] ^ rk[34]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ + Td3[t0 & 0xff] ^ rk[35]; + /* round 9: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ + Td3[s1 & 0xff] ^ rk[36]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ + Td3[s2 & 0xff] ^ rk[37]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ + Td3[s3 & 0xff] ^ rk[38]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ + Td3[s0 & 0xff] ^ rk[39]; + if (key->rounds > 10) { + /* round 10: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ + Td3[t1 & 0xff] ^ rk[40]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ + Td3[t2 & 0xff] ^ rk[41]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ + Td3[t3 & 0xff] ^ rk[42]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ + Td3[t0 & 0xff] ^ rk[43]; + /* round 11: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ + Td3[s1 & 0xff] ^ rk[44]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ + Td3[s2 & 0xff] ^ rk[45]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ + Td3[s3 & 0xff] ^ rk[46]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ + Td3[s0 & 0xff] ^ rk[47]; + if (key->rounds > 12) { + /* round 12: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ + Td3[t1 & 0xff] ^ rk[48]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ + Td3[t2 & 0xff] ^ rk[49]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ + Td3[t3 & 0xff] ^ rk[50]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ + Td3[t0 & 0xff] ^ rk[51]; + /* round 13: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ + Td3[s1 & 0xff] ^ rk[52]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ + Td3[s2 & 0xff] ^ rk[53]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ + Td3[s3 & 0xff] ^ rk[54]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ + Td3[s0 & 0xff] ^ rk[55]; + } + } + rk += key->rounds << 2; +#else /* !FULL_UNROLL */ + /* + * Nr - 1 full rounds: + */ + r = key->rounds >> 1; + for (;;) { + t0 = Td0[(s0 >> 24)] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ + Td3[(s1) & 0xff] ^ rk[4]; + t1 = Td0[(s1 >> 24)] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ + Td3[(s2) & 0xff] ^ rk[5]; + t2 = Td0[(s2 >> 24)] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ + Td3[(s3) & 0xff] ^ rk[6]; + t3 = Td0[(s3 >> 24)] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ + Td3[(s0) & 0xff] ^ rk[7]; + + rk += 8; + if (--r == 0) { + break; + } + + s0 = Td0[(t0 >> 24)] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ + Td3[(t1) & 0xff] ^ rk[0]; + s1 = Td0[(t1 >> 24)] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ + Td3[(t2) & 0xff] ^ rk[1]; + s2 = Td0[(t2 >> 24)] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ + Td3[(t3) & 0xff] ^ rk[2]; + s3 = Td0[(t3 >> 24)] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ + Td3[(t0) & 0xff] ^ rk[3]; + } +#endif /* ?FULL_UNROLL */ + /* apply last round and + * map cipher state to byte array block: */ + s0 = ((uint32_t)Td4[(t0 >> 24)] << 24) ^ + ((uint32_t)Td4[(t3 >> 16) & 0xff] << 16) ^ + ((uint32_t)Td4[(t2 >> 8) & 0xff] << 8) ^ + ((uint32_t)Td4[(t1) & 0xff]) ^ rk[0]; + PUTU32(out, s0); + s1 = ((uint32_t)Td4[(t1 >> 24)] << 24) ^ + ((uint32_t)Td4[(t0 >> 16) & 0xff] << 16) ^ + ((uint32_t)Td4[(t3 >> 8) & 0xff] << 8) ^ + ((uint32_t)Td4[(t2) & 0xff]) ^ rk[1]; + PUTU32(out + 4, s1); + s2 = ((uint32_t)Td4[(t2 >> 24)] << 24) ^ + ((uint32_t)Td4[(t1 >> 16) & 0xff] << 16) ^ + ((uint32_t)Td4[(t0 >> 8) & 0xff] << 8) ^ + ((uint32_t)Td4[(t3) & 0xff]) ^ rk[2]; + PUTU32(out + 8, s2); + s3 = ((uint32_t)Td4[(t3 >> 24)] << 24) ^ + ((uint32_t)Td4[(t2 >> 16) & 0xff] << 16) ^ + ((uint32_t)Td4[(t1 >> 8) & 0xff] << 8) ^ + ((uint32_t)Td4[(t0) & 0xff]) ^ rk[3]; + PUTU32(out + 12, s3); +} + +#else + +/* In this case several functions are provided by asm code. However, one cannot + * control asm symbol visibility with command line flags and such so they are + * always hidden and wrapped by these C functions, which can be so + * controlled. */ + +void asm_AES_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); +void AES_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { + asm_AES_encrypt(in, out, key); +} + +void asm_AES_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); +void AES_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { + asm_AES_decrypt(in, out, key); +} + +int asm_AES_set_encrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey); +int AES_set_encrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey) { + return asm_AES_set_encrypt_key(key, bits, aeskey); +} + +int asm_AES_set_decrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey); +int AES_set_decrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey) { + return asm_AES_set_decrypt_key(key, bits, aeskey); +} + +#endif /* OPENSSL_NO_ASM || (!OPENSSL_X86 && !OPENSSL_X86_64 && !OPENSSL_ARM) */ diff --git a/TMessagesProj/jni/boringssl/crypto/aes/aes_ige.c b/TMessagesProj/jni/boringssl/crypto/aes/aes_ige.c new file mode 100644 index 00000000..b425c7d6 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/aes/aes_ige.c @@ -0,0 +1,323 @@ +/* crypto/aes/aes_ige.c -*- mode:C; c-file-style: "eay" -*- */ +/* ==================================================================== + * Copyright (c) 2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + */ + +#include +#include +#include +#include + +#define N_WORDS (AES_BLOCK_SIZE / sizeof(unsigned long)) +typedef struct { + unsigned long data[N_WORDS]; +} aes_block_t; + +/* XXX: probably some better way to do this */ +#if defined(__i386__) || defined(__x86_64__) +#define UNALIGNED_MEMOPS_ARE_FAST 1 +#else +#define UNALIGNED_MEMOPS_ARE_FAST 0 +#endif + +#if UNALIGNED_MEMOPS_ARE_FAST +#define load_block(d, s) (d) = *(const aes_block_t *)(s) +#define store_block(d, s) *(aes_block_t *)(d) = (s) +#else +#define load_block(d, s) memcpy((d).data, (s), AES_BLOCK_SIZE) +#define store_block(d, s) memcpy((d), (s).data, AES_BLOCK_SIZE) +#endif + +/* N.B. The IV for this mode is _twice_ the block size */ + +void AES_ige_encrypt(const unsigned char *in, unsigned char *out, + size_t length, const AES_KEY *key, + unsigned char *ivec, const int enc) + { + size_t n; + size_t len = length; + + assert(in && out && key && ivec); + assert((AES_ENCRYPT == enc)||(AES_DECRYPT == enc)); + assert((length%AES_BLOCK_SIZE) == 0); + + len = length / AES_BLOCK_SIZE; + + if (AES_ENCRYPT == enc) + { + if (in != out && + (UNALIGNED_MEMOPS_ARE_FAST || ((size_t)in|(size_t)out|(size_t)ivec)%sizeof(long)==0)) + { + aes_block_t *ivp = (aes_block_t *)ivec; + aes_block_t *iv2p = (aes_block_t *)(ivec + AES_BLOCK_SIZE); + + while (len) + { + aes_block_t *inp = (aes_block_t *)in; + aes_block_t *outp = (aes_block_t *)out; + + for(n=0 ; n < N_WORDS; ++n) + outp->data[n] = inp->data[n] ^ ivp->data[n]; + AES_encrypt((unsigned char *)outp->data, (unsigned char *)outp->data, key); + for(n=0 ; n < N_WORDS; ++n) + outp->data[n] ^= iv2p->data[n]; + ivp = outp; + iv2p = inp; + --len; + in += AES_BLOCK_SIZE; + out += AES_BLOCK_SIZE; + } + memcpy(ivec, ivp->data, AES_BLOCK_SIZE); + memcpy(ivec + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE); + } + else + { + aes_block_t tmp, tmp2; + aes_block_t iv; + aes_block_t iv2; + + load_block(iv, ivec); + load_block(iv2, ivec + AES_BLOCK_SIZE); + + while (len) + { + load_block(tmp, in); + for(n=0 ; n < N_WORDS; ++n) + tmp2.data[n] = tmp.data[n] ^ iv.data[n]; + AES_encrypt((unsigned char *)tmp2.data, (unsigned char *)tmp2.data, key); + for(n=0 ; n < N_WORDS; ++n) + tmp2.data[n] ^= iv2.data[n]; + store_block(out, tmp2); + iv = tmp2; + iv2 = tmp; + --len; + in += AES_BLOCK_SIZE; + out += AES_BLOCK_SIZE; + } + memcpy(ivec, iv.data, AES_BLOCK_SIZE); + memcpy(ivec + AES_BLOCK_SIZE, iv2.data, AES_BLOCK_SIZE); + } + } + else + { + if (in != out && + (UNALIGNED_MEMOPS_ARE_FAST || ((size_t)in|(size_t)out|(size_t)ivec)%sizeof(long)==0)) + { + aes_block_t *ivp = (aes_block_t *)ivec; + aes_block_t *iv2p = (aes_block_t *)(ivec + AES_BLOCK_SIZE); + + while (len) + { + aes_block_t tmp; + aes_block_t *inp = (aes_block_t *)in; + aes_block_t *outp = (aes_block_t *)out; + + for(n=0 ; n < N_WORDS; ++n) + tmp.data[n] = inp->data[n] ^ iv2p->data[n]; + AES_decrypt((unsigned char *)tmp.data, (unsigned char *)outp->data, key); + for(n=0 ; n < N_WORDS; ++n) + outp->data[n] ^= ivp->data[n]; + ivp = inp; + iv2p = outp; + --len; + in += AES_BLOCK_SIZE; + out += AES_BLOCK_SIZE; + } + memcpy(ivec, ivp->data, AES_BLOCK_SIZE); + memcpy(ivec + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE); + } + else + { + aes_block_t tmp, tmp2; + aes_block_t iv; + aes_block_t iv2; + + load_block(iv, ivec); + load_block(iv2, ivec + AES_BLOCK_SIZE); + + while (len) + { + load_block(tmp, in); + tmp2 = tmp; + for(n=0 ; n < N_WORDS; ++n) + tmp.data[n] ^= iv2.data[n]; + AES_decrypt((unsigned char *)tmp.data, (unsigned char *)tmp.data, key); + for(n=0 ; n < N_WORDS; ++n) + tmp.data[n] ^= iv.data[n]; + store_block(out, tmp); + iv = tmp2; + iv2 = tmp; + --len; + in += AES_BLOCK_SIZE; + out += AES_BLOCK_SIZE; + } + memcpy(ivec, iv.data, AES_BLOCK_SIZE); + memcpy(ivec + AES_BLOCK_SIZE, iv2.data, AES_BLOCK_SIZE); + } + } + } + +/* + * Note that its effectively impossible to do biIGE in anything other + * than a single pass, so no provision is made for chaining. + */ + +/* N.B. The IV for this mode is _four times_ the block size */ + +void AES_bi_ige_encrypt(const unsigned char *in, unsigned char *out, + size_t length, const AES_KEY *key, + const AES_KEY *key2, const unsigned char *ivec, + const int enc) + { + size_t n; + size_t len = length; + unsigned char tmp[AES_BLOCK_SIZE]; + unsigned char tmp2[AES_BLOCK_SIZE]; + unsigned char tmp3[AES_BLOCK_SIZE]; + unsigned char prev[AES_BLOCK_SIZE]; + const unsigned char *iv; + const unsigned char *iv2; + + assert(in && out && key && ivec); + assert((AES_ENCRYPT == enc)||(AES_DECRYPT == enc)); + assert((length%AES_BLOCK_SIZE) == 0); + + if (AES_ENCRYPT == enc) + { + /* XXX: Do a separate case for when in != out (strictly should + check for overlap, too) */ + + /* First the forward pass */ + iv = ivec; + iv2 = ivec + AES_BLOCK_SIZE; + while (len >= AES_BLOCK_SIZE) + { + for(n=0 ; n < AES_BLOCK_SIZE ; ++n) + out[n] = in[n] ^ iv[n]; + AES_encrypt(out, out, key); + for(n=0 ; n < AES_BLOCK_SIZE ; ++n) + out[n] ^= iv2[n]; + iv = out; + memcpy(prev, in, AES_BLOCK_SIZE); + iv2 = prev; + len -= AES_BLOCK_SIZE; + in += AES_BLOCK_SIZE; + out += AES_BLOCK_SIZE; + } + + /* And now backwards */ + iv = ivec + AES_BLOCK_SIZE*2; + iv2 = ivec + AES_BLOCK_SIZE*3; + len = length; + while(len >= AES_BLOCK_SIZE) + { + out -= AES_BLOCK_SIZE; + /* XXX: reduce copies by alternating between buffers */ + memcpy(tmp, out, AES_BLOCK_SIZE); + for(n=0 ; n < AES_BLOCK_SIZE ; ++n) + out[n] ^= iv[n]; + /* hexdump(stdout, "out ^ iv", out, AES_BLOCK_SIZE); */ + AES_encrypt(out, out, key); + /* hexdump(stdout,"enc", out, AES_BLOCK_SIZE); */ + /* hexdump(stdout,"iv2", iv2, AES_BLOCK_SIZE); */ + for(n=0 ; n < AES_BLOCK_SIZE ; ++n) + out[n] ^= iv2[n]; + /* hexdump(stdout,"out", out, AES_BLOCK_SIZE); */ + iv = out; + memcpy(prev, tmp, AES_BLOCK_SIZE); + iv2 = prev; + len -= AES_BLOCK_SIZE; + } + } + else + { + /* First backwards */ + iv = ivec + AES_BLOCK_SIZE*2; + iv2 = ivec + AES_BLOCK_SIZE*3; + in += length; + out += length; + while (len >= AES_BLOCK_SIZE) + { + in -= AES_BLOCK_SIZE; + out -= AES_BLOCK_SIZE; + memcpy(tmp, in, AES_BLOCK_SIZE); + memcpy(tmp2, in, AES_BLOCK_SIZE); + for(n=0 ; n < AES_BLOCK_SIZE ; ++n) + tmp[n] ^= iv2[n]; + AES_decrypt(tmp, out, key); + for(n=0 ; n < AES_BLOCK_SIZE ; ++n) + out[n] ^= iv[n]; + memcpy(tmp3, tmp2, AES_BLOCK_SIZE); + iv = tmp3; + iv2 = out; + len -= AES_BLOCK_SIZE; + } + + /* And now forwards */ + iv = ivec; + iv2 = ivec + AES_BLOCK_SIZE; + len = length; + while (len >= AES_BLOCK_SIZE) + { + memcpy(tmp, out, AES_BLOCK_SIZE); + memcpy(tmp2, out, AES_BLOCK_SIZE); + for(n=0 ; n < AES_BLOCK_SIZE ; ++n) + tmp[n] ^= iv2[n]; + AES_decrypt(tmp, out, key); + for(n=0 ; n < AES_BLOCK_SIZE ; ++n) + out[n] ^= iv[n]; + memcpy(tmp3, tmp2, AES_BLOCK_SIZE); + iv = tmp3; + iv2 = out; + len -= AES_BLOCK_SIZE; + in += AES_BLOCK_SIZE; + out += AES_BLOCK_SIZE; + } + } + } diff --git a/TMessagesProj/jni/boringssl/crypto/aes/asm/aes-586.pl b/TMessagesProj/jni/boringssl/crypto/aes/asm/aes-586.pl new file mode 100644 index 00000000..6e8a6a80 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/aes/asm/aes-586.pl @@ -0,0 +1,2987 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# Version 4.3. +# +# You might fail to appreciate this module performance from the first +# try. If compared to "vanilla" linux-ia32-icc target, i.e. considered +# to be *the* best Intel C compiler without -KPIC, performance appears +# to be virtually identical... But try to re-configure with shared +# library support... Aha! Intel compiler "suddenly" lags behind by 30% +# [on P4, more on others]:-) And if compared to position-independent +# code generated by GNU C, this code performs *more* than *twice* as +# fast! Yes, all this buzz about PIC means that unlike other hand- +# coded implementations, this one was explicitly designed to be safe +# to use even in shared library context... This also means that this +# code isn't necessarily absolutely fastest "ever," because in order +# to achieve position independence an extra register has to be +# off-loaded to stack, which affects the benchmark result. +# +# Special note about instruction choice. Do you recall RC4_INT code +# performing poorly on P4? It might be the time to figure out why. +# RC4_INT code implies effective address calculations in base+offset*4 +# form. Trouble is that it seems that offset scaling turned to be +# critical path... At least eliminating scaling resulted in 2.8x RC4 +# performance improvement [as you might recall]. As AES code is hungry +# for scaling too, I [try to] avoid the latter by favoring off-by-2 +# shifts and masking the result with 0xFF<<2 instead of "boring" 0xFF. +# +# As was shown by Dean Gaudet , the above note turned +# void. Performance improvement with off-by-2 shifts was observed on +# intermediate implementation, which was spilling yet another register +# to stack... Final offset*4 code below runs just a tad faster on P4, +# but exhibits up to 10% improvement on other cores. +# +# Second version is "monolithic" replacement for aes_core.c, which in +# addition to AES_[de|en]crypt implements AES_set_[de|en]cryption_key. +# This made it possible to implement little-endian variant of the +# algorithm without modifying the base C code. Motivating factor for +# the undertaken effort was that it appeared that in tight IA-32 +# register window little-endian flavor could achieve slightly higher +# Instruction Level Parallelism, and it indeed resulted in up to 15% +# better performance on most recent µ-archs... +# +# Third version adds AES_cbc_encrypt implementation, which resulted in +# up to 40% performance imrovement of CBC benchmark results. 40% was +# observed on P4 core, where "overall" imrovement coefficient, i.e. if +# compared to PIC generated by GCC and in CBC mode, was observed to be +# as large as 4x:-) CBC performance is virtually identical to ECB now +# and on some platforms even better, e.g. 17.6 "small" cycles/byte on +# Opteron, because certain function prologues and epilogues are +# effectively taken out of the loop... +# +# Version 3.2 implements compressed tables and prefetch of these tables +# in CBC[!] mode. Former means that 3/4 of table references are now +# misaligned, which unfortunately has negative impact on elder IA-32 +# implementations, Pentium suffered 30% penalty, PIII - 10%. +# +# Version 3.3 avoids L1 cache aliasing between stack frame and +# S-boxes, and 3.4 - L1 cache aliasing even between key schedule. The +# latter is achieved by copying the key schedule to controlled place in +# stack. This unfortunately has rather strong impact on small block CBC +# performance, ~2x deterioration on 16-byte block if compared to 3.3. +# +# Version 3.5 checks if there is L1 cache aliasing between user-supplied +# key schedule and S-boxes and abstains from copying the former if +# there is no. This allows end-user to consciously retain small block +# performance by aligning key schedule in specific manner. +# +# Version 3.6 compresses Td4 to 256 bytes and prefetches it in ECB. +# +# Current ECB performance numbers for 128-bit key in CPU cycles per +# processed byte [measure commonly used by AES benchmarkers] are: +# +# small footprint fully unrolled +# P4 24 22 +# AMD K8 20 19 +# PIII 25 23 +# Pentium 81 78 +# +# Version 3.7 reimplements outer rounds as "compact." Meaning that +# first and last rounds reference compact 256 bytes S-box. This means +# that first round consumes a lot more CPU cycles and that encrypt +# and decrypt performance becomes asymmetric. Encrypt performance +# drops by 10-12%, while decrypt - by 20-25%:-( 256 bytes S-box is +# aggressively pre-fetched. +# +# Version 4.0 effectively rolls back to 3.6 and instead implements +# additional set of functions, _[x86|sse]_AES_[en|de]crypt_compact, +# which use exclusively 256 byte S-box. These functions are to be +# called in modes not concealing plain text, such as ECB, or when +# we're asked to process smaller amount of data [or unconditionally +# on hyper-threading CPU]. Currently it's called unconditionally from +# AES_[en|de]crypt, which affects all modes, but CBC. CBC routine +# still needs to be modified to switch between slower and faster +# mode when appropriate... But in either case benchmark landscape +# changes dramatically and below numbers are CPU cycles per processed +# byte for 128-bit key. +# +# ECB encrypt ECB decrypt CBC large chunk +# P4 52[54] 83[95] 23 +# AMD K8 46[41] 66[70] 18 +# PIII 41[50] 60[77] 24 +# Core 2 31[36] 45[64] 18.5 +# Atom 76[100] 96[138] 60 +# Pentium 115 150 77 +# +# Version 4.1 switches to compact S-box even in key schedule setup. +# +# Version 4.2 prefetches compact S-box in every SSE round or in other +# words every cache-line is *guaranteed* to be accessed within ~50 +# cycles window. Why just SSE? Because it's needed on hyper-threading +# CPU! Which is also why it's prefetched with 64 byte stride. Best +# part is that it has no negative effect on performance:-) +# +# Version 4.3 implements switch between compact and non-compact block +# functions in AES_cbc_encrypt depending on how much data was asked +# to be processed in one stroke. +# +###################################################################### +# Timing attacks are classified in two classes: synchronous when +# attacker consciously initiates cryptographic operation and collects +# timing data of various character afterwards, and asynchronous when +# malicious code is executed on same CPU simultaneously with AES, +# instruments itself and performs statistical analysis of this data. +# +# As far as synchronous attacks go the root to the AES timing +# vulnerability is twofold. Firstly, of 256 S-box elements at most 160 +# are referred to in single 128-bit block operation. Well, in C +# implementation with 4 distinct tables it's actually as little as 40 +# references per 256 elements table, but anyway... Secondly, even +# though S-box elements are clustered into smaller amount of cache- +# lines, smaller than 160 and even 40, it turned out that for certain +# plain-text pattern[s] or simply put chosen plain-text and given key +# few cache-lines remain unaccessed during block operation. Now, if +# attacker can figure out this access pattern, he can deduct the key +# [or at least part of it]. The natural way to mitigate this kind of +# attacks is to minimize the amount of cache-lines in S-box and/or +# prefetch them to ensure that every one is accessed for more uniform +# timing. But note that *if* plain-text was concealed in such way that +# input to block function is distributed *uniformly*, then attack +# wouldn't apply. Now note that some encryption modes, most notably +# CBC, do mask the plain-text in this exact way [secure cipher output +# is distributed uniformly]. Yes, one still might find input that +# would reveal the information about given key, but if amount of +# candidate inputs to be tried is larger than amount of possible key +# combinations then attack becomes infeasible. This is why revised +# AES_cbc_encrypt "dares" to switch to larger S-box when larger chunk +# of data is to be processed in one stroke. The current size limit of +# 512 bytes is chosen to provide same [diminishigly low] probability +# for cache-line to remain untouched in large chunk operation with +# large S-box as for single block operation with compact S-box and +# surely needs more careful consideration... +# +# As for asynchronous attacks. There are two flavours: attacker code +# being interleaved with AES on hyper-threading CPU at *instruction* +# level, and two processes time sharing single core. As for latter. +# Two vectors. 1. Given that attacker process has higher priority, +# yield execution to process performing AES just before timer fires +# off the scheduler, immediately regain control of CPU and analyze the +# cache state. For this attack to be efficient attacker would have to +# effectively slow down the operation by several *orders* of magnitute, +# by ratio of time slice to duration of handful of AES rounds, which +# unlikely to remain unnoticed. Not to mention that this also means +# that he would spend correspondigly more time to collect enough +# statistical data to mount the attack. It's probably appropriate to +# say that if adeversary reckons that this attack is beneficial and +# risks to be noticed, you probably have larger problems having him +# mere opportunity. In other words suggested code design expects you +# to preclude/mitigate this attack by overall system security design. +# 2. Attacker manages to make his code interrupt driven. In order for +# this kind of attack to be feasible, interrupt rate has to be high +# enough, again comparable to duration of handful of AES rounds. But +# is there interrupt source of such rate? Hardly, not even 1Gbps NIC +# generates interrupts at such raging rate... +# +# And now back to the former, hyper-threading CPU or more specifically +# Intel P4. Recall that asynchronous attack implies that malicious +# code instruments itself. And naturally instrumentation granularity +# has be noticeably lower than duration of codepath accessing S-box. +# Given that all cache-lines are accessed during that time that is. +# Current implementation accesses *all* cache-lines within ~50 cycles +# window, which is actually *less* than RDTSC latency on Intel P4! + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +push(@INC,"${dir}","${dir}../../perlasm"); +require "x86asm.pl"; + +&asm_init($ARGV[0],"aes-586.pl",$x86only = $ARGV[$#ARGV] eq "386"); +&static_label("AES_Te"); +&static_label("AES_Td"); + +$s0="eax"; +$s1="ebx"; +$s2="ecx"; +$s3="edx"; +$key="edi"; +$acc="esi"; +$tbl="ebp"; + +# stack frame layout in _[x86|sse]_AES_* routines, frame is allocated +# by caller +$__ra=&DWP(0,"esp"); # return address +$__s0=&DWP(4,"esp"); # s0 backing store +$__s1=&DWP(8,"esp"); # s1 backing store +$__s2=&DWP(12,"esp"); # s2 backing store +$__s3=&DWP(16,"esp"); # s3 backing store +$__key=&DWP(20,"esp"); # pointer to key schedule +$__end=&DWP(24,"esp"); # pointer to end of key schedule +$__tbl=&DWP(28,"esp"); # %ebp backing store + +# stack frame layout in AES_[en|crypt] routines, which differs from +# above by 4 and overlaps by %ebp backing store +$_tbl=&DWP(24,"esp"); +$_esp=&DWP(28,"esp"); + +sub _data_word() { my $i; while(defined($i=shift)) { &data_word($i,$i); } } + +$speed_limit=512; # chunks smaller than $speed_limit are + # processed with compact routine in CBC mode +$small_footprint=1; # $small_footprint=1 code is ~5% slower [on + # recent µ-archs], but ~5 times smaller! + # I favor compact code to minimize cache + # contention and in hope to "collect" 5% back + # in real-life applications... + +$vertical_spin=0; # shift "verticaly" defaults to 0, because of + # its proof-of-concept status... +# Note that there is no decvert(), as well as last encryption round is +# performed with "horizontal" shifts. This is because this "vertical" +# implementation [one which groups shifts on a given $s[i] to form a +# "column," unlike "horizontal" one, which groups shifts on different +# $s[i] to form a "row"] is work in progress. It was observed to run +# few percents faster on Intel cores, but not AMD. On AMD K8 core it's +# whole 12% slower:-( So we face a trade-off... Shall it be resolved +# some day? Till then the code is considered experimental and by +# default remains dormant... + +sub encvert() +{ my ($te,@s) = @_; + my ($v0,$v1) = ($acc,$key); + + &mov ($v0,$s[3]); # copy s3 + &mov (&DWP(4,"esp"),$s[2]); # save s2 + &mov ($v1,$s[0]); # copy s0 + &mov (&DWP(8,"esp"),$s[1]); # save s1 + + &movz ($s[2],&HB($s[0])); + &and ($s[0],0xFF); + &mov ($s[0],&DWP(0,$te,$s[0],8)); # s0>>0 + &shr ($v1,16); + &mov ($s[3],&DWP(3,$te,$s[2],8)); # s0>>8 + &movz ($s[1],&HB($v1)); + &and ($v1,0xFF); + &mov ($s[2],&DWP(2,$te,$v1,8)); # s0>>16 + &mov ($v1,$v0); + &mov ($s[1],&DWP(1,$te,$s[1],8)); # s0>>24 + + &and ($v0,0xFF); + &xor ($s[3],&DWP(0,$te,$v0,8)); # s3>>0 + &movz ($v0,&HB($v1)); + &shr ($v1,16); + &xor ($s[2],&DWP(3,$te,$v0,8)); # s3>>8 + &movz ($v0,&HB($v1)); + &and ($v1,0xFF); + &xor ($s[1],&DWP(2,$te,$v1,8)); # s3>>16 + &mov ($v1,&DWP(4,"esp")); # restore s2 + &xor ($s[0],&DWP(1,$te,$v0,8)); # s3>>24 + + &mov ($v0,$v1); + &and ($v1,0xFF); + &xor ($s[2],&DWP(0,$te,$v1,8)); # s2>>0 + &movz ($v1,&HB($v0)); + &shr ($v0,16); + &xor ($s[1],&DWP(3,$te,$v1,8)); # s2>>8 + &movz ($v1,&HB($v0)); + &and ($v0,0xFF); + &xor ($s[0],&DWP(2,$te,$v0,8)); # s2>>16 + &mov ($v0,&DWP(8,"esp")); # restore s1 + &xor ($s[3],&DWP(1,$te,$v1,8)); # s2>>24 + + &mov ($v1,$v0); + &and ($v0,0xFF); + &xor ($s[1],&DWP(0,$te,$v0,8)); # s1>>0 + &movz ($v0,&HB($v1)); + &shr ($v1,16); + &xor ($s[0],&DWP(3,$te,$v0,8)); # s1>>8 + &movz ($v0,&HB($v1)); + &and ($v1,0xFF); + &xor ($s[3],&DWP(2,$te,$v1,8)); # s1>>16 + &mov ($key,$__key); # reincarnate v1 as key + &xor ($s[2],&DWP(1,$te,$v0,8)); # s1>>24 +} + +# Another experimental routine, which features "horizontal spin," but +# eliminates one reference to stack. Strangely enough runs slower... +sub enchoriz() +{ my ($v0,$v1) = ($key,$acc); + + &movz ($v0,&LB($s0)); # 3, 2, 1, 0* + &rotr ($s2,8); # 8,11,10, 9 + &mov ($v1,&DWP(0,$te,$v0,8)); # 0 + &movz ($v0,&HB($s1)); # 7, 6, 5*, 4 + &rotr ($s3,16); # 13,12,15,14 + &xor ($v1,&DWP(3,$te,$v0,8)); # 5 + &movz ($v0,&HB($s2)); # 8,11,10*, 9 + &rotr ($s0,16); # 1, 0, 3, 2 + &xor ($v1,&DWP(2,$te,$v0,8)); # 10 + &movz ($v0,&HB($s3)); # 13,12,15*,14 + &xor ($v1,&DWP(1,$te,$v0,8)); # 15, t[0] collected + &mov ($__s0,$v1); # t[0] saved + + &movz ($v0,&LB($s1)); # 7, 6, 5, 4* + &shr ($s1,16); # -, -, 7, 6 + &mov ($v1,&DWP(0,$te,$v0,8)); # 4 + &movz ($v0,&LB($s3)); # 13,12,15,14* + &xor ($v1,&DWP(2,$te,$v0,8)); # 14 + &movz ($v0,&HB($s0)); # 1, 0, 3*, 2 + &and ($s3,0xffff0000); # 13,12, -, - + &xor ($v1,&DWP(1,$te,$v0,8)); # 3 + &movz ($v0,&LB($s2)); # 8,11,10, 9* + &or ($s3,$s1); # 13,12, 7, 6 + &xor ($v1,&DWP(3,$te,$v0,8)); # 9, t[1] collected + &mov ($s1,$v1); # s[1]=t[1] + + &movz ($v0,&LB($s0)); # 1, 0, 3, 2* + &shr ($s2,16); # -, -, 8,11 + &mov ($v1,&DWP(2,$te,$v0,8)); # 2 + &movz ($v0,&HB($s3)); # 13,12, 7*, 6 + &xor ($v1,&DWP(1,$te,$v0,8)); # 7 + &movz ($v0,&HB($s2)); # -, -, 8*,11 + &xor ($v1,&DWP(0,$te,$v0,8)); # 8 + &mov ($v0,$s3); + &shr ($v0,24); # 13 + &xor ($v1,&DWP(3,$te,$v0,8)); # 13, t[2] collected + + &movz ($v0,&LB($s2)); # -, -, 8,11* + &shr ($s0,24); # 1* + &mov ($s2,&DWP(1,$te,$v0,8)); # 11 + &xor ($s2,&DWP(3,$te,$s0,8)); # 1 + &mov ($s0,$__s0); # s[0]=t[0] + &movz ($v0,&LB($s3)); # 13,12, 7, 6* + &shr ($s3,16); # , ,13,12 + &xor ($s2,&DWP(2,$te,$v0,8)); # 6 + &mov ($key,$__key); # reincarnate v0 as key + &and ($s3,0xff); # , ,13,12* + &mov ($s3,&DWP(0,$te,$s3,8)); # 12 + &xor ($s3,$s2); # s[2]=t[3] collected + &mov ($s2,$v1); # s[2]=t[2] +} + +# More experimental code... SSE one... Even though this one eliminates +# *all* references to stack, it's not faster... +sub sse_encbody() +{ + &movz ($acc,&LB("eax")); # 0 + &mov ("ecx",&DWP(0,$tbl,$acc,8)); # 0 + &pshufw ("mm2","mm0",0x0d); # 7, 6, 3, 2 + &movz ("edx",&HB("eax")); # 1 + &mov ("edx",&DWP(3,$tbl,"edx",8)); # 1 + &shr ("eax",16); # 5, 4 + + &movz ($acc,&LB("ebx")); # 10 + &xor ("ecx",&DWP(2,$tbl,$acc,8)); # 10 + &pshufw ("mm6","mm4",0x08); # 13,12, 9, 8 + &movz ($acc,&HB("ebx")); # 11 + &xor ("edx",&DWP(1,$tbl,$acc,8)); # 11 + &shr ("ebx",16); # 15,14 + + &movz ($acc,&HB("eax")); # 5 + &xor ("ecx",&DWP(3,$tbl,$acc,8)); # 5 + &movq ("mm3",QWP(16,$key)); + &movz ($acc,&HB("ebx")); # 15 + &xor ("ecx",&DWP(1,$tbl,$acc,8)); # 15 + &movd ("mm0","ecx"); # t[0] collected + + &movz ($acc,&LB("eax")); # 4 + &mov ("ecx",&DWP(0,$tbl,$acc,8)); # 4 + &movd ("eax","mm2"); # 7, 6, 3, 2 + &movz ($acc,&LB("ebx")); # 14 + &xor ("ecx",&DWP(2,$tbl,$acc,8)); # 14 + &movd ("ebx","mm6"); # 13,12, 9, 8 + + &movz ($acc,&HB("eax")); # 3 + &xor ("ecx",&DWP(1,$tbl,$acc,8)); # 3 + &movz ($acc,&HB("ebx")); # 9 + &xor ("ecx",&DWP(3,$tbl,$acc,8)); # 9 + &movd ("mm1","ecx"); # t[1] collected + + &movz ($acc,&LB("eax")); # 2 + &mov ("ecx",&DWP(2,$tbl,$acc,8)); # 2 + &shr ("eax",16); # 7, 6 + &punpckldq ("mm0","mm1"); # t[0,1] collected + &movz ($acc,&LB("ebx")); # 8 + &xor ("ecx",&DWP(0,$tbl,$acc,8)); # 8 + &shr ("ebx",16); # 13,12 + + &movz ($acc,&HB("eax")); # 7 + &xor ("ecx",&DWP(1,$tbl,$acc,8)); # 7 + &pxor ("mm0","mm3"); + &movz ("eax",&LB("eax")); # 6 + &xor ("edx",&DWP(2,$tbl,"eax",8)); # 6 + &pshufw ("mm1","mm0",0x08); # 5, 4, 1, 0 + &movz ($acc,&HB("ebx")); # 13 + &xor ("ecx",&DWP(3,$tbl,$acc,8)); # 13 + &xor ("ecx",&DWP(24,$key)); # t[2] + &movd ("mm4","ecx"); # t[2] collected + &movz ("ebx",&LB("ebx")); # 12 + &xor ("edx",&DWP(0,$tbl,"ebx",8)); # 12 + &shr ("ecx",16); + &movd ("eax","mm1"); # 5, 4, 1, 0 + &mov ("ebx",&DWP(28,$key)); # t[3] + &xor ("ebx","edx"); + &movd ("mm5","ebx"); # t[3] collected + &and ("ebx",0xffff0000); + &or ("ebx","ecx"); + + &punpckldq ("mm4","mm5"); # t[2,3] collected +} + +###################################################################### +# "Compact" block function +###################################################################### + +sub enccompact() +{ my $Fn = \&mov; + while ($#_>5) { pop(@_); $Fn=sub{}; } + my ($i,$te,@s)=@_; + my $tmp = $key; + my $out = $i==3?$s[0]:$acc; + + # $Fn is used in first compact round and its purpose is to + # void restoration of some values from stack, so that after + # 4xenccompact with extra argument $key value is left there... + if ($i==3) { &$Fn ($key,$__key); }##%edx + else { &mov ($out,$s[0]); } + &and ($out,0xFF); + if ($i==1) { &shr ($s[0],16); }#%ebx[1] + if ($i==2) { &shr ($s[0],24); }#%ecx[2] + &movz ($out,&BP(-128,$te,$out,1)); + + if ($i==3) { $tmp=$s[1]; }##%eax + &movz ($tmp,&HB($s[1])); + &movz ($tmp,&BP(-128,$te,$tmp,1)); + &shl ($tmp,8); + &xor ($out,$tmp); + + if ($i==3) { $tmp=$s[2]; &mov ($s[1],$__s0); }##%ebx + else { &mov ($tmp,$s[2]); + &shr ($tmp,16); } + if ($i==2) { &and ($s[1],0xFF); }#%edx[2] + &and ($tmp,0xFF); + &movz ($tmp,&BP(-128,$te,$tmp,1)); + &shl ($tmp,16); + &xor ($out,$tmp); + + if ($i==3) { $tmp=$s[3]; &mov ($s[2],$__s1); }##%ecx + elsif($i==2){ &movz ($tmp,&HB($s[3])); }#%ebx[2] + else { &mov ($tmp,$s[3]); + &shr ($tmp,24); } + &movz ($tmp,&BP(-128,$te,$tmp,1)); + &shl ($tmp,24); + &xor ($out,$tmp); + if ($i<2) { &mov (&DWP(4+4*$i,"esp"),$out); } + if ($i==3) { &mov ($s[3],$acc); } + &comment(); +} + +sub enctransform() +{ my @s = ($s0,$s1,$s2,$s3); + my $i = shift; + my $tmp = $tbl; + my $r2 = $key ; + + &and ($tmp,$s[$i]); + &lea ($r2,&DWP(0,$s[$i],$s[$i])); + &mov ($acc,$tmp); + &shr ($tmp,7); + &and ($r2,0xfefefefe); + &sub ($acc,$tmp); + &mov ($tmp,$s[$i]); + &and ($acc,0x1b1b1b1b); + &rotr ($tmp,16); + &xor ($acc,$r2); # r2 + &mov ($r2,$s[$i]); + + &xor ($s[$i],$acc); # r0 ^ r2 + &rotr ($r2,16+8); + &xor ($acc,$tmp); + &rotl ($s[$i],24); + &xor ($acc,$r2); + &mov ($tmp,0x80808080) if ($i!=1); + &xor ($s[$i],$acc); # ROTATE(r2^r0,24) ^ r2 +} + +&function_begin_B("_x86_AES_encrypt_compact"); + # note that caller is expected to allocate stack frame for me! + &mov ($__key,$key); # save key + + &xor ($s0,&DWP(0,$key)); # xor with key + &xor ($s1,&DWP(4,$key)); + &xor ($s2,&DWP(8,$key)); + &xor ($s3,&DWP(12,$key)); + + &mov ($acc,&DWP(240,$key)); # load key->rounds + &lea ($acc,&DWP(-2,$acc,$acc)); + &lea ($acc,&DWP(0,$key,$acc,8)); + &mov ($__end,$acc); # end of key schedule + + # prefetch Te4 + &mov ($key,&DWP(0-128,$tbl)); + &mov ($acc,&DWP(32-128,$tbl)); + &mov ($key,&DWP(64-128,$tbl)); + &mov ($acc,&DWP(96-128,$tbl)); + &mov ($key,&DWP(128-128,$tbl)); + &mov ($acc,&DWP(160-128,$tbl)); + &mov ($key,&DWP(192-128,$tbl)); + &mov ($acc,&DWP(224-128,$tbl)); + + &set_label("loop",16); + + &enccompact(0,$tbl,$s0,$s1,$s2,$s3,1); + &enccompact(1,$tbl,$s1,$s2,$s3,$s0,1); + &enccompact(2,$tbl,$s2,$s3,$s0,$s1,1); + &enccompact(3,$tbl,$s3,$s0,$s1,$s2,1); + &mov ($tbl,0x80808080); + &enctransform(2); + &enctransform(3); + &enctransform(0); + &enctransform(1); + &mov ($key,$__key); + &mov ($tbl,$__tbl); + &add ($key,16); # advance rd_key + &xor ($s0,&DWP(0,$key)); + &xor ($s1,&DWP(4,$key)); + &xor ($s2,&DWP(8,$key)); + &xor ($s3,&DWP(12,$key)); + + &cmp ($key,$__end); + &mov ($__key,$key); + &jb (&label("loop")); + + &enccompact(0,$tbl,$s0,$s1,$s2,$s3); + &enccompact(1,$tbl,$s1,$s2,$s3,$s0); + &enccompact(2,$tbl,$s2,$s3,$s0,$s1); + &enccompact(3,$tbl,$s3,$s0,$s1,$s2); + + &xor ($s0,&DWP(16,$key)); + &xor ($s1,&DWP(20,$key)); + &xor ($s2,&DWP(24,$key)); + &xor ($s3,&DWP(28,$key)); + + &ret (); +&function_end_B("_x86_AES_encrypt_compact"); + +###################################################################### +# "Compact" SSE block function. +###################################################################### +# +# Performance is not actually extraordinary in comparison to pure +# x86 code. In particular encrypt performance is virtually the same. +# Decrypt performance on the other hand is 15-20% better on newer +# µ-archs [but we're thankful for *any* improvement here], and ~50% +# better on PIII:-) And additionally on the pros side this code +# eliminates redundant references to stack and thus relieves/ +# minimizes the pressure on the memory bus. +# +# MMX register layout lsb +# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +# | mm4 | mm0 | +# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +# | s3 | s2 | s1 | s0 | +# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +# |15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| +# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +# +# Indexes translate as s[N/4]>>(8*(N%4)), e.g. 5 means s1>>8. +# In this terms encryption and decryption "compact" permutation +# matrices can be depicted as following: +# +# encryption lsb # decryption lsb +# +----++----+----+----+----+ # +----++----+----+----+----+ +# | t0 || 15 | 10 | 5 | 0 | # | t0 || 7 | 10 | 13 | 0 | +# +----++----+----+----+----+ # +----++----+----+----+----+ +# | t1 || 3 | 14 | 9 | 4 | # | t1 || 11 | 14 | 1 | 4 | +# +----++----+----+----+----+ # +----++----+----+----+----+ +# | t2 || 7 | 2 | 13 | 8 | # | t2 || 15 | 2 | 5 | 8 | +# +----++----+----+----+----+ # +----++----+----+----+----+ +# | t3 || 11 | 6 | 1 | 12 | # | t3 || 3 | 6 | 9 | 12 | +# +----++----+----+----+----+ # +----++----+----+----+----+ +# +###################################################################### +# Why not xmm registers? Short answer. It was actually tested and +# was not any faster, but *contrary*, most notably on Intel CPUs. +# Longer answer. Main advantage of using mm registers is that movd +# latency is lower, especially on Intel P4. While arithmetic +# instructions are twice as many, they can be scheduled every cycle +# and not every second one when they are operating on xmm register, +# so that "arithmetic throughput" remains virtually the same. And +# finally the code can be executed even on elder SSE-only CPUs:-) + +sub sse_enccompact() +{ + &pshufw ("mm1","mm0",0x08); # 5, 4, 1, 0 + &pshufw ("mm5","mm4",0x0d); # 15,14,11,10 + &movd ("eax","mm1"); # 5, 4, 1, 0 + &movd ("ebx","mm5"); # 15,14,11,10 + &mov ($__key,$key); + + &movz ($acc,&LB("eax")); # 0 + &movz ("edx",&HB("eax")); # 1 + &pshufw ("mm2","mm0",0x0d); # 7, 6, 3, 2 + &movz ("ecx",&BP(-128,$tbl,$acc,1)); # 0 + &movz ($key,&LB("ebx")); # 10 + &movz ("edx",&BP(-128,$tbl,"edx",1)); # 1 + &shr ("eax",16); # 5, 4 + &shl ("edx",8); # 1 + + &movz ($acc,&BP(-128,$tbl,$key,1)); # 10 + &movz ($key,&HB("ebx")); # 11 + &shl ($acc,16); # 10 + &pshufw ("mm6","mm4",0x08); # 13,12, 9, 8 + &or ("ecx",$acc); # 10 + &movz ($acc,&BP(-128,$tbl,$key,1)); # 11 + &movz ($key,&HB("eax")); # 5 + &shl ($acc,24); # 11 + &shr ("ebx",16); # 15,14 + &or ("edx",$acc); # 11 + + &movz ($acc,&BP(-128,$tbl,$key,1)); # 5 + &movz ($key,&HB("ebx")); # 15 + &shl ($acc,8); # 5 + &or ("ecx",$acc); # 5 + &movz ($acc,&BP(-128,$tbl,$key,1)); # 15 + &movz ($key,&LB("eax")); # 4 + &shl ($acc,24); # 15 + &or ("ecx",$acc); # 15 + + &movz ($acc,&BP(-128,$tbl,$key,1)); # 4 + &movz ($key,&LB("ebx")); # 14 + &movd ("eax","mm2"); # 7, 6, 3, 2 + &movd ("mm0","ecx"); # t[0] collected + &movz ("ecx",&BP(-128,$tbl,$key,1)); # 14 + &movz ($key,&HB("eax")); # 3 + &shl ("ecx",16); # 14 + &movd ("ebx","mm6"); # 13,12, 9, 8 + &or ("ecx",$acc); # 14 + + &movz ($acc,&BP(-128,$tbl,$key,1)); # 3 + &movz ($key,&HB("ebx")); # 9 + &shl ($acc,24); # 3 + &or ("ecx",$acc); # 3 + &movz ($acc,&BP(-128,$tbl,$key,1)); # 9 + &movz ($key,&LB("ebx")); # 8 + &shl ($acc,8); # 9 + &shr ("ebx",16); # 13,12 + &or ("ecx",$acc); # 9 + + &movz ($acc,&BP(-128,$tbl,$key,1)); # 8 + &movz ($key,&LB("eax")); # 2 + &shr ("eax",16); # 7, 6 + &movd ("mm1","ecx"); # t[1] collected + &movz ("ecx",&BP(-128,$tbl,$key,1)); # 2 + &movz ($key,&HB("eax")); # 7 + &shl ("ecx",16); # 2 + &and ("eax",0xff); # 6 + &or ("ecx",$acc); # 2 + + &punpckldq ("mm0","mm1"); # t[0,1] collected + + &movz ($acc,&BP(-128,$tbl,$key,1)); # 7 + &movz ($key,&HB("ebx")); # 13 + &shl ($acc,24); # 7 + &and ("ebx",0xff); # 12 + &movz ("eax",&BP(-128,$tbl,"eax",1)); # 6 + &or ("ecx",$acc); # 7 + &shl ("eax",16); # 6 + &movz ($acc,&BP(-128,$tbl,$key,1)); # 13 + &or ("edx","eax"); # 6 + &shl ($acc,8); # 13 + &movz ("ebx",&BP(-128,$tbl,"ebx",1)); # 12 + &or ("ecx",$acc); # 13 + &or ("edx","ebx"); # 12 + &mov ($key,$__key); + &movd ("mm4","ecx"); # t[2] collected + &movd ("mm5","edx"); # t[3] collected + + &punpckldq ("mm4","mm5"); # t[2,3] collected +} + + if (!$x86only) { +&function_begin_B("_sse_AES_encrypt_compact"); + &pxor ("mm0",&QWP(0,$key)); # 7, 6, 5, 4, 3, 2, 1, 0 + &pxor ("mm4",&QWP(8,$key)); # 15,14,13,12,11,10, 9, 8 + + # note that caller is expected to allocate stack frame for me! + &mov ($acc,&DWP(240,$key)); # load key->rounds + &lea ($acc,&DWP(-2,$acc,$acc)); + &lea ($acc,&DWP(0,$key,$acc,8)); + &mov ($__end,$acc); # end of key schedule + + &mov ($s0,0x1b1b1b1b); # magic constant + &mov (&DWP(8,"esp"),$s0); + &mov (&DWP(12,"esp"),$s0); + + # prefetch Te4 + &mov ($s0,&DWP(0-128,$tbl)); + &mov ($s1,&DWP(32-128,$tbl)); + &mov ($s2,&DWP(64-128,$tbl)); + &mov ($s3,&DWP(96-128,$tbl)); + &mov ($s0,&DWP(128-128,$tbl)); + &mov ($s1,&DWP(160-128,$tbl)); + &mov ($s2,&DWP(192-128,$tbl)); + &mov ($s3,&DWP(224-128,$tbl)); + + &set_label("loop",16); + &sse_enccompact(); + &add ($key,16); + &cmp ($key,$__end); + &ja (&label("out")); + + &movq ("mm2",&QWP(8,"esp")); + &pxor ("mm3","mm3"); &pxor ("mm7","mm7"); + &movq ("mm1","mm0"); &movq ("mm5","mm4"); # r0 + &pcmpgtb("mm3","mm0"); &pcmpgtb("mm7","mm4"); + &pand ("mm3","mm2"); &pand ("mm7","mm2"); + &pshufw ("mm2","mm0",0xb1); &pshufw ("mm6","mm4",0xb1);# ROTATE(r0,16) + &paddb ("mm0","mm0"); &paddb ("mm4","mm4"); + &pxor ("mm0","mm3"); &pxor ("mm4","mm7"); # = r2 + &pshufw ("mm3","mm2",0xb1); &pshufw ("mm7","mm6",0xb1);# r0 + &pxor ("mm1","mm0"); &pxor ("mm5","mm4"); # r0^r2 + &pxor ("mm0","mm2"); &pxor ("mm4","mm6"); # ^= ROTATE(r0,16) + + &movq ("mm2","mm3"); &movq ("mm6","mm7"); + &pslld ("mm3",8); &pslld ("mm7",8); + &psrld ("mm2",24); &psrld ("mm6",24); + &pxor ("mm0","mm3"); &pxor ("mm4","mm7"); # ^= r0<<8 + &pxor ("mm0","mm2"); &pxor ("mm4","mm6"); # ^= r0>>24 + + &movq ("mm3","mm1"); &movq ("mm7","mm5"); + &movq ("mm2",&QWP(0,$key)); &movq ("mm6",&QWP(8,$key)); + &psrld ("mm1",8); &psrld ("mm5",8); + &mov ($s0,&DWP(0-128,$tbl)); + &pslld ("mm3",24); &pslld ("mm7",24); + &mov ($s1,&DWP(64-128,$tbl)); + &pxor ("mm0","mm1"); &pxor ("mm4","mm5"); # ^= (r2^r0)<<8 + &mov ($s2,&DWP(128-128,$tbl)); + &pxor ("mm0","mm3"); &pxor ("mm4","mm7"); # ^= (r2^r0)>>24 + &mov ($s3,&DWP(192-128,$tbl)); + + &pxor ("mm0","mm2"); &pxor ("mm4","mm6"); + &jmp (&label("loop")); + + &set_label("out",16); + &pxor ("mm0",&QWP(0,$key)); + &pxor ("mm4",&QWP(8,$key)); + + &ret (); +&function_end_B("_sse_AES_encrypt_compact"); + } + +###################################################################### +# Vanilla block function. +###################################################################### + +sub encstep() +{ my ($i,$te,@s) = @_; + my $tmp = $key; + my $out = $i==3?$s[0]:$acc; + + # lines marked with #%e?x[i] denote "reordered" instructions... + if ($i==3) { &mov ($key,$__key); }##%edx + else { &mov ($out,$s[0]); + &and ($out,0xFF); } + if ($i==1) { &shr ($s[0],16); }#%ebx[1] + if ($i==2) { &shr ($s[0],24); }#%ecx[2] + &mov ($out,&DWP(0,$te,$out,8)); + + if ($i==3) { $tmp=$s[1]; }##%eax + &movz ($tmp,&HB($s[1])); + &xor ($out,&DWP(3,$te,$tmp,8)); + + if ($i==3) { $tmp=$s[2]; &mov ($s[1],$__s0); }##%ebx + else { &mov ($tmp,$s[2]); + &shr ($tmp,16); } + if ($i==2) { &and ($s[1],0xFF); }#%edx[2] + &and ($tmp,0xFF); + &xor ($out,&DWP(2,$te,$tmp,8)); + + if ($i==3) { $tmp=$s[3]; &mov ($s[2],$__s1); }##%ecx + elsif($i==2){ &movz ($tmp,&HB($s[3])); }#%ebx[2] + else { &mov ($tmp,$s[3]); + &shr ($tmp,24) } + &xor ($out,&DWP(1,$te,$tmp,8)); + if ($i<2) { &mov (&DWP(4+4*$i,"esp"),$out); } + if ($i==3) { &mov ($s[3],$acc); } + &comment(); +} + +sub enclast() +{ my ($i,$te,@s)=@_; + my $tmp = $key; + my $out = $i==3?$s[0]:$acc; + + if ($i==3) { &mov ($key,$__key); }##%edx + else { &mov ($out,$s[0]); } + &and ($out,0xFF); + if ($i==1) { &shr ($s[0],16); }#%ebx[1] + if ($i==2) { &shr ($s[0],24); }#%ecx[2] + &mov ($out,&DWP(2,$te,$out,8)); + &and ($out,0x000000ff); + + if ($i==3) { $tmp=$s[1]; }##%eax + &movz ($tmp,&HB($s[1])); + &mov ($tmp,&DWP(0,$te,$tmp,8)); + &and ($tmp,0x0000ff00); + &xor ($out,$tmp); + + if ($i==3) { $tmp=$s[2]; &mov ($s[1],$__s0); }##%ebx + else { &mov ($tmp,$s[2]); + &shr ($tmp,16); } + if ($i==2) { &and ($s[1],0xFF); }#%edx[2] + &and ($tmp,0xFF); + &mov ($tmp,&DWP(0,$te,$tmp,8)); + &and ($tmp,0x00ff0000); + &xor ($out,$tmp); + + if ($i==3) { $tmp=$s[3]; &mov ($s[2],$__s1); }##%ecx + elsif($i==2){ &movz ($tmp,&HB($s[3])); }#%ebx[2] + else { &mov ($tmp,$s[3]); + &shr ($tmp,24); } + &mov ($tmp,&DWP(2,$te,$tmp,8)); + &and ($tmp,0xff000000); + &xor ($out,$tmp); + if ($i<2) { &mov (&DWP(4+4*$i,"esp"),$out); } + if ($i==3) { &mov ($s[3],$acc); } +} + +&function_begin_B("_x86_AES_encrypt"); + if ($vertical_spin) { + # I need high parts of volatile registers to be accessible... + &exch ($s1="edi",$key="ebx"); + &mov ($s2="esi",$acc="ecx"); + } + + # note that caller is expected to allocate stack frame for me! + &mov ($__key,$key); # save key + + &xor ($s0,&DWP(0,$key)); # xor with key + &xor ($s1,&DWP(4,$key)); + &xor ($s2,&DWP(8,$key)); + &xor ($s3,&DWP(12,$key)); + + &mov ($acc,&DWP(240,$key)); # load key->rounds + + if ($small_footprint) { + &lea ($acc,&DWP(-2,$acc,$acc)); + &lea ($acc,&DWP(0,$key,$acc,8)); + &mov ($__end,$acc); # end of key schedule + + &set_label("loop",16); + if ($vertical_spin) { + &encvert($tbl,$s0,$s1,$s2,$s3); + } else { + &encstep(0,$tbl,$s0,$s1,$s2,$s3); + &encstep(1,$tbl,$s1,$s2,$s3,$s0); + &encstep(2,$tbl,$s2,$s3,$s0,$s1); + &encstep(3,$tbl,$s3,$s0,$s1,$s2); + } + &add ($key,16); # advance rd_key + &xor ($s0,&DWP(0,$key)); + &xor ($s1,&DWP(4,$key)); + &xor ($s2,&DWP(8,$key)); + &xor ($s3,&DWP(12,$key)); + &cmp ($key,$__end); + &mov ($__key,$key); + &jb (&label("loop")); + } + else { + &cmp ($acc,10); + &jle (&label("10rounds")); + &cmp ($acc,12); + &jle (&label("12rounds")); + + &set_label("14rounds",4); + for ($i=1;$i<3;$i++) { + if ($vertical_spin) { + &encvert($tbl,$s0,$s1,$s2,$s3); + } else { + &encstep(0,$tbl,$s0,$s1,$s2,$s3); + &encstep(1,$tbl,$s1,$s2,$s3,$s0); + &encstep(2,$tbl,$s2,$s3,$s0,$s1); + &encstep(3,$tbl,$s3,$s0,$s1,$s2); + } + &xor ($s0,&DWP(16*$i+0,$key)); + &xor ($s1,&DWP(16*$i+4,$key)); + &xor ($s2,&DWP(16*$i+8,$key)); + &xor ($s3,&DWP(16*$i+12,$key)); + } + &add ($key,32); + &mov ($__key,$key); # advance rd_key + &set_label("12rounds",4); + for ($i=1;$i<3;$i++) { + if ($vertical_spin) { + &encvert($tbl,$s0,$s1,$s2,$s3); + } else { + &encstep(0,$tbl,$s0,$s1,$s2,$s3); + &encstep(1,$tbl,$s1,$s2,$s3,$s0); + &encstep(2,$tbl,$s2,$s3,$s0,$s1); + &encstep(3,$tbl,$s3,$s0,$s1,$s2); + } + &xor ($s0,&DWP(16*$i+0,$key)); + &xor ($s1,&DWP(16*$i+4,$key)); + &xor ($s2,&DWP(16*$i+8,$key)); + &xor ($s3,&DWP(16*$i+12,$key)); + } + &add ($key,32); + &mov ($__key,$key); # advance rd_key + &set_label("10rounds",4); + for ($i=1;$i<10;$i++) { + if ($vertical_spin) { + &encvert($tbl,$s0,$s1,$s2,$s3); + } else { + &encstep(0,$tbl,$s0,$s1,$s2,$s3); + &encstep(1,$tbl,$s1,$s2,$s3,$s0); + &encstep(2,$tbl,$s2,$s3,$s0,$s1); + &encstep(3,$tbl,$s3,$s0,$s1,$s2); + } + &xor ($s0,&DWP(16*$i+0,$key)); + &xor ($s1,&DWP(16*$i+4,$key)); + &xor ($s2,&DWP(16*$i+8,$key)); + &xor ($s3,&DWP(16*$i+12,$key)); + } + } + + if ($vertical_spin) { + # "reincarnate" some registers for "horizontal" spin... + &mov ($s1="ebx",$key="edi"); + &mov ($s2="ecx",$acc="esi"); + } + &enclast(0,$tbl,$s0,$s1,$s2,$s3); + &enclast(1,$tbl,$s1,$s2,$s3,$s0); + &enclast(2,$tbl,$s2,$s3,$s0,$s1); + &enclast(3,$tbl,$s3,$s0,$s1,$s2); + + &add ($key,$small_footprint?16:160); + &xor ($s0,&DWP(0,$key)); + &xor ($s1,&DWP(4,$key)); + &xor ($s2,&DWP(8,$key)); + &xor ($s3,&DWP(12,$key)); + + &ret (); + +&set_label("AES_Te",64); # Yes! I keep it in the code segment! + &_data_word(0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6); + &_data_word(0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591); + &_data_word(0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56); + &_data_word(0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec); + &_data_word(0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa); + &_data_word(0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb); + &_data_word(0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45); + &_data_word(0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b); + &_data_word(0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c); + &_data_word(0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83); + &_data_word(0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9); + &_data_word(0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a); + &_data_word(0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d); + &_data_word(0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f); + &_data_word(0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df); + &_data_word(0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea); + &_data_word(0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34); + &_data_word(0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b); + &_data_word(0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d); + &_data_word(0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413); + &_data_word(0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1); + &_data_word(0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6); + &_data_word(0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972); + &_data_word(0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85); + &_data_word(0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed); + &_data_word(0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511); + &_data_word(0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe); + &_data_word(0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b); + &_data_word(0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05); + &_data_word(0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1); + &_data_word(0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142); + &_data_word(0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf); + &_data_word(0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3); + &_data_word(0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e); + &_data_word(0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a); + &_data_word(0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6); + &_data_word(0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3); + &_data_word(0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b); + &_data_word(0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428); + &_data_word(0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad); + &_data_word(0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14); + &_data_word(0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8); + &_data_word(0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4); + &_data_word(0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2); + &_data_word(0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda); + &_data_word(0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949); + &_data_word(0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf); + &_data_word(0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810); + &_data_word(0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c); + &_data_word(0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697); + &_data_word(0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e); + &_data_word(0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f); + &_data_word(0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc); + &_data_word(0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c); + &_data_word(0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969); + &_data_word(0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27); + &_data_word(0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122); + &_data_word(0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433); + &_data_word(0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9); + &_data_word(0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5); + &_data_word(0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a); + &_data_word(0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0); + &_data_word(0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e); + &_data_word(0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c); + +#Te4 # four copies of Te4 to choose from to avoid L1 aliasing + &data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5); + &data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76); + &data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0); + &data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0); + &data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc); + &data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15); + &data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a); + &data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75); + &data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0); + &data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84); + &data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b); + &data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf); + &data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85); + &data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8); + &data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5); + &data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2); + &data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17); + &data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73); + &data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88); + &data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb); + &data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c); + &data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79); + &data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9); + &data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08); + &data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6); + &data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a); + &data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e); + &data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e); + &data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94); + &data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf); + &data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68); + &data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16); + + &data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5); + &data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76); + &data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0); + &data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0); + &data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc); + &data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15); + &data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a); + &data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75); + &data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0); + &data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84); + &data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b); + &data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf); + &data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85); + &data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8); + &data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5); + &data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2); + &data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17); + &data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73); + &data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88); + &data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb); + &data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c); + &data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79); + &data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9); + &data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08); + &data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6); + &data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a); + &data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e); + &data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e); + &data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94); + &data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf); + &data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68); + &data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16); + + &data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5); + &data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76); + &data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0); + &data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0); + &data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc); + &data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15); + &data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a); + &data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75); + &data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0); + &data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84); + &data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b); + &data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf); + &data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85); + &data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8); + &data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5); + &data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2); + &data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17); + &data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73); + &data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88); + &data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb); + &data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c); + &data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79); + &data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9); + &data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08); + &data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6); + &data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a); + &data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e); + &data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e); + &data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94); + &data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf); + &data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68); + &data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16); + + &data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5); + &data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76); + &data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0); + &data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0); + &data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc); + &data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15); + &data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a); + &data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75); + &data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0); + &data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84); + &data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b); + &data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf); + &data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85); + &data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8); + &data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5); + &data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2); + &data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17); + &data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73); + &data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88); + &data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb); + &data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c); + &data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79); + &data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9); + &data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08); + &data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6); + &data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a); + &data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e); + &data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e); + &data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94); + &data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf); + &data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68); + &data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16); +#rcon: + &data_word(0x00000001, 0x00000002, 0x00000004, 0x00000008); + &data_word(0x00000010, 0x00000020, 0x00000040, 0x00000080); + &data_word(0x0000001b, 0x00000036, 0x00000000, 0x00000000); + &data_word(0x00000000, 0x00000000, 0x00000000, 0x00000000); +&function_end_B("_x86_AES_encrypt"); + +# void asm_AES_encrypt (const void *inp,void *out,const AES_KEY *key); +&function_begin("asm_AES_encrypt"); + &mov ($acc,&wparam(0)); # load inp + &mov ($key,&wparam(2)); # load key + + &mov ($s0,"esp"); + &sub ("esp",36); + &and ("esp",-64); # align to cache-line + + # place stack frame just "above" the key schedule + &lea ($s1,&DWP(-64-63,$key)); + &sub ($s1,"esp"); + &neg ($s1); + &and ($s1,0x3C0); # modulo 1024, but aligned to cache-line + &sub ("esp",$s1); + &add ("esp",4); # 4 is reserved for caller's return address + &mov ($_esp,$s0); # save stack pointer + + &call (&label("pic_point")); # make it PIC! + &set_label("pic_point"); + &blindpop($tbl); + &picmeup($s0,"OPENSSL_ia32cap_P",$tbl,&label("pic_point")) if (!$x86only); + &lea ($tbl,&DWP(&label("AES_Te")."-".&label("pic_point"),$tbl)); + + # pick Te4 copy which can't "overlap" with stack frame or key schedule + &lea ($s1,&DWP(768-4,"esp")); + &sub ($s1,$tbl); + &and ($s1,0x300); + &lea ($tbl,&DWP(2048+128,$tbl,$s1)); + + if (!$x86only) { + &bt (&DWP(0,$s0),25); # check for SSE bit + &jnc (&label("x86")); + + &movq ("mm0",&QWP(0,$acc)); + &movq ("mm4",&QWP(8,$acc)); + &call ("_sse_AES_encrypt_compact"); + &mov ("esp",$_esp); # restore stack pointer + &mov ($acc,&wparam(1)); # load out + &movq (&QWP(0,$acc),"mm0"); # write output data + &movq (&QWP(8,$acc),"mm4"); + &emms (); + &function_end_A(); + } + &set_label("x86",16); + &mov ($_tbl,$tbl); + &mov ($s0,&DWP(0,$acc)); # load input data + &mov ($s1,&DWP(4,$acc)); + &mov ($s2,&DWP(8,$acc)); + &mov ($s3,&DWP(12,$acc)); + &call ("_x86_AES_encrypt_compact"); + &mov ("esp",$_esp); # restore stack pointer + &mov ($acc,&wparam(1)); # load out + &mov (&DWP(0,$acc),$s0); # write output data + &mov (&DWP(4,$acc),$s1); + &mov (&DWP(8,$acc),$s2); + &mov (&DWP(12,$acc),$s3); +&function_end("asm_AES_encrypt"); + +#--------------------------------------------------------------------# + +###################################################################### +# "Compact" block function +###################################################################### + +sub deccompact() +{ my $Fn = \&mov; + while ($#_>5) { pop(@_); $Fn=sub{}; } + my ($i,$td,@s)=@_; + my $tmp = $key; + my $out = $i==3?$s[0]:$acc; + + # $Fn is used in first compact round and its purpose is to + # void restoration of some values from stack, so that after + # 4xdeccompact with extra argument $key, $s0 and $s1 values + # are left there... + if($i==3) { &$Fn ($key,$__key); } + else { &mov ($out,$s[0]); } + &and ($out,0xFF); + &movz ($out,&BP(-128,$td,$out,1)); + + if ($i==3) { $tmp=$s[1]; } + &movz ($tmp,&HB($s[1])); + &movz ($tmp,&BP(-128,$td,$tmp,1)); + &shl ($tmp,8); + &xor ($out,$tmp); + + if ($i==3) { $tmp=$s[2]; &mov ($s[1],$acc); } + else { mov ($tmp,$s[2]); } + &shr ($tmp,16); + &and ($tmp,0xFF); + &movz ($tmp,&BP(-128,$td,$tmp,1)); + &shl ($tmp,16); + &xor ($out,$tmp); + + if ($i==3) { $tmp=$s[3]; &$Fn ($s[2],$__s1); } + else { &mov ($tmp,$s[3]); } + &shr ($tmp,24); + &movz ($tmp,&BP(-128,$td,$tmp,1)); + &shl ($tmp,24); + &xor ($out,$tmp); + if ($i<2) { &mov (&DWP(4+4*$i,"esp"),$out); } + if ($i==3) { &$Fn ($s[3],$__s0); } +} + +# must be called with 2,3,0,1 as argument sequence!!! +sub dectransform() +{ my @s = ($s0,$s1,$s2,$s3); + my $i = shift; + my $tmp = $key; + my $tp2 = @s[($i+2)%4]; $tp2 = @s[2] if ($i==1); + my $tp4 = @s[($i+3)%4]; $tp4 = @s[3] if ($i==1); + my $tp8 = $tbl; + + &mov ($tmp,0x80808080); + &and ($tmp,$s[$i]); + &mov ($acc,$tmp); + &shr ($tmp,7); + &lea ($tp2,&DWP(0,$s[$i],$s[$i])); + &sub ($acc,$tmp); + &and ($tp2,0xfefefefe); + &and ($acc,0x1b1b1b1b); + &xor ($tp2,$acc); + &mov ($tmp,0x80808080); + + &and ($tmp,$tp2); + &mov ($acc,$tmp); + &shr ($tmp,7); + &lea ($tp4,&DWP(0,$tp2,$tp2)); + &sub ($acc,$tmp); + &and ($tp4,0xfefefefe); + &and ($acc,0x1b1b1b1b); + &xor ($tp2,$s[$i]); # tp2^tp1 + &xor ($tp4,$acc); + &mov ($tmp,0x80808080); + + &and ($tmp,$tp4); + &mov ($acc,$tmp); + &shr ($tmp,7); + &lea ($tp8,&DWP(0,$tp4,$tp4)); + &sub ($acc,$tmp); + &and ($tp8,0xfefefefe); + &and ($acc,0x1b1b1b1b); + &xor ($tp4,$s[$i]); # tp4^tp1 + &rotl ($s[$i],8); # = ROTATE(tp1,8) + &xor ($tp8,$acc); + + &xor ($s[$i],$tp2); + &xor ($tp2,$tp8); + &xor ($s[$i],$tp4); + &xor ($tp4,$tp8); + &rotl ($tp2,24); + &xor ($s[$i],$tp8); # ^= tp8^(tp4^tp1)^(tp2^tp1) + &rotl ($tp4,16); + &xor ($s[$i],$tp2); # ^= ROTATE(tp8^tp2^tp1,24) + &rotl ($tp8,8); + &xor ($s[$i],$tp4); # ^= ROTATE(tp8^tp4^tp1,16) + &mov ($s[0],$__s0) if($i==2); #prefetch $s0 + &mov ($s[1],$__s1) if($i==3); #prefetch $s1 + &mov ($s[2],$__s2) if($i==1); + &xor ($s[$i],$tp8); # ^= ROTATE(tp8,8) + + &mov ($s[3],$__s3) if($i==1); + &mov (&DWP(4+4*$i,"esp"),$s[$i]) if($i>=2); +} + +&function_begin_B("_x86_AES_decrypt_compact"); + # note that caller is expected to allocate stack frame for me! + &mov ($__key,$key); # save key + + &xor ($s0,&DWP(0,$key)); # xor with key + &xor ($s1,&DWP(4,$key)); + &xor ($s2,&DWP(8,$key)); + &xor ($s3,&DWP(12,$key)); + + &mov ($acc,&DWP(240,$key)); # load key->rounds + + &lea ($acc,&DWP(-2,$acc,$acc)); + &lea ($acc,&DWP(0,$key,$acc,8)); + &mov ($__end,$acc); # end of key schedule + + # prefetch Td4 + &mov ($key,&DWP(0-128,$tbl)); + &mov ($acc,&DWP(32-128,$tbl)); + &mov ($key,&DWP(64-128,$tbl)); + &mov ($acc,&DWP(96-128,$tbl)); + &mov ($key,&DWP(128-128,$tbl)); + &mov ($acc,&DWP(160-128,$tbl)); + &mov ($key,&DWP(192-128,$tbl)); + &mov ($acc,&DWP(224-128,$tbl)); + + &set_label("loop",16); + + &deccompact(0,$tbl,$s0,$s3,$s2,$s1,1); + &deccompact(1,$tbl,$s1,$s0,$s3,$s2,1); + &deccompact(2,$tbl,$s2,$s1,$s0,$s3,1); + &deccompact(3,$tbl,$s3,$s2,$s1,$s0,1); + &dectransform(2); + &dectransform(3); + &dectransform(0); + &dectransform(1); + &mov ($key,$__key); + &mov ($tbl,$__tbl); + &add ($key,16); # advance rd_key + &xor ($s0,&DWP(0,$key)); + &xor ($s1,&DWP(4,$key)); + &xor ($s2,&DWP(8,$key)); + &xor ($s3,&DWP(12,$key)); + + &cmp ($key,$__end); + &mov ($__key,$key); + &jb (&label("loop")); + + &deccompact(0,$tbl,$s0,$s3,$s2,$s1); + &deccompact(1,$tbl,$s1,$s0,$s3,$s2); + &deccompact(2,$tbl,$s2,$s1,$s0,$s3); + &deccompact(3,$tbl,$s3,$s2,$s1,$s0); + + &xor ($s0,&DWP(16,$key)); + &xor ($s1,&DWP(20,$key)); + &xor ($s2,&DWP(24,$key)); + &xor ($s3,&DWP(28,$key)); + + &ret (); +&function_end_B("_x86_AES_decrypt_compact"); + +###################################################################### +# "Compact" SSE block function. +###################################################################### + +sub sse_deccompact() +{ + &pshufw ("mm1","mm0",0x0c); # 7, 6, 1, 0 + &pshufw ("mm5","mm4",0x09); # 13,12,11,10 + &movd ("eax","mm1"); # 7, 6, 1, 0 + &movd ("ebx","mm5"); # 13,12,11,10 + &mov ($__key,$key); + + &movz ($acc,&LB("eax")); # 0 + &movz ("edx",&HB("eax")); # 1 + &pshufw ("mm2","mm0",0x06); # 3, 2, 5, 4 + &movz ("ecx",&BP(-128,$tbl,$acc,1)); # 0 + &movz ($key,&LB("ebx")); # 10 + &movz ("edx",&BP(-128,$tbl,"edx",1)); # 1 + &shr ("eax",16); # 7, 6 + &shl ("edx",8); # 1 + + &movz ($acc,&BP(-128,$tbl,$key,1)); # 10 + &movz ($key,&HB("ebx")); # 11 + &shl ($acc,16); # 10 + &pshufw ("mm6","mm4",0x03); # 9, 8,15,14 + &or ("ecx",$acc); # 10 + &movz ($acc,&BP(-128,$tbl,$key,1)); # 11 + &movz ($key,&HB("eax")); # 7 + &shl ($acc,24); # 11 + &shr ("ebx",16); # 13,12 + &or ("edx",$acc); # 11 + + &movz ($acc,&BP(-128,$tbl,$key,1)); # 7 + &movz ($key,&HB("ebx")); # 13 + &shl ($acc,24); # 7 + &or ("ecx",$acc); # 7 + &movz ($acc,&BP(-128,$tbl,$key,1)); # 13 + &movz ($key,&LB("eax")); # 6 + &shl ($acc,8); # 13 + &movd ("eax","mm2"); # 3, 2, 5, 4 + &or ("ecx",$acc); # 13 + + &movz ($acc,&BP(-128,$tbl,$key,1)); # 6 + &movz ($key,&LB("ebx")); # 12 + &shl ($acc,16); # 6 + &movd ("ebx","mm6"); # 9, 8,15,14 + &movd ("mm0","ecx"); # t[0] collected + &movz ("ecx",&BP(-128,$tbl,$key,1)); # 12 + &movz ($key,&LB("eax")); # 4 + &or ("ecx",$acc); # 12 + + &movz ($acc,&BP(-128,$tbl,$key,1)); # 4 + &movz ($key,&LB("ebx")); # 14 + &or ("edx",$acc); # 4 + &movz ($acc,&BP(-128,$tbl,$key,1)); # 14 + &movz ($key,&HB("eax")); # 5 + &shl ($acc,16); # 14 + &shr ("eax",16); # 3, 2 + &or ("edx",$acc); # 14 + + &movz ($acc,&BP(-128,$tbl,$key,1)); # 5 + &movz ($key,&HB("ebx")); # 15 + &shr ("ebx",16); # 9, 8 + &shl ($acc,8); # 5 + &movd ("mm1","edx"); # t[1] collected + &movz ("edx",&BP(-128,$tbl,$key,1)); # 15 + &movz ($key,&HB("ebx")); # 9 + &shl ("edx",24); # 15 + &and ("ebx",0xff); # 8 + &or ("edx",$acc); # 15 + + &punpckldq ("mm0","mm1"); # t[0,1] collected + + &movz ($acc,&BP(-128,$tbl,$key,1)); # 9 + &movz ($key,&LB("eax")); # 2 + &shl ($acc,8); # 9 + &movz ("eax",&HB("eax")); # 3 + &movz ("ebx",&BP(-128,$tbl,"ebx",1)); # 8 + &or ("ecx",$acc); # 9 + &movz ($acc,&BP(-128,$tbl,$key,1)); # 2 + &or ("edx","ebx"); # 8 + &shl ($acc,16); # 2 + &movz ("eax",&BP(-128,$tbl,"eax",1)); # 3 + &or ("edx",$acc); # 2 + &shl ("eax",24); # 3 + &or ("ecx","eax"); # 3 + &mov ($key,$__key); + &movd ("mm4","edx"); # t[2] collected + &movd ("mm5","ecx"); # t[3] collected + + &punpckldq ("mm4","mm5"); # t[2,3] collected +} + + if (!$x86only) { +&function_begin_B("_sse_AES_decrypt_compact"); + &pxor ("mm0",&QWP(0,$key)); # 7, 6, 5, 4, 3, 2, 1, 0 + &pxor ("mm4",&QWP(8,$key)); # 15,14,13,12,11,10, 9, 8 + + # note that caller is expected to allocate stack frame for me! + &mov ($acc,&DWP(240,$key)); # load key->rounds + &lea ($acc,&DWP(-2,$acc,$acc)); + &lea ($acc,&DWP(0,$key,$acc,8)); + &mov ($__end,$acc); # end of key schedule + + &mov ($s0,0x1b1b1b1b); # magic constant + &mov (&DWP(8,"esp"),$s0); + &mov (&DWP(12,"esp"),$s0); + + # prefetch Td4 + &mov ($s0,&DWP(0-128,$tbl)); + &mov ($s1,&DWP(32-128,$tbl)); + &mov ($s2,&DWP(64-128,$tbl)); + &mov ($s3,&DWP(96-128,$tbl)); + &mov ($s0,&DWP(128-128,$tbl)); + &mov ($s1,&DWP(160-128,$tbl)); + &mov ($s2,&DWP(192-128,$tbl)); + &mov ($s3,&DWP(224-128,$tbl)); + + &set_label("loop",16); + &sse_deccompact(); + &add ($key,16); + &cmp ($key,$__end); + &ja (&label("out")); + + # ROTATE(x^y,N) == ROTATE(x,N)^ROTATE(y,N) + &movq ("mm3","mm0"); &movq ("mm7","mm4"); + &movq ("mm2","mm0",1); &movq ("mm6","mm4",1); + &movq ("mm1","mm0"); &movq ("mm5","mm4"); + &pshufw ("mm0","mm0",0xb1); &pshufw ("mm4","mm4",0xb1);# = ROTATE(tp0,16) + &pslld ("mm2",8); &pslld ("mm6",8); + &psrld ("mm3",8); &psrld ("mm7",8); + &pxor ("mm0","mm2"); &pxor ("mm4","mm6"); # ^= tp0<<8 + &pxor ("mm0","mm3"); &pxor ("mm4","mm7"); # ^= tp0>>8 + &pslld ("mm2",16); &pslld ("mm6",16); + &psrld ("mm3",16); &psrld ("mm7",16); + &pxor ("mm0","mm2"); &pxor ("mm4","mm6"); # ^= tp0<<24 + &pxor ("mm0","mm3"); &pxor ("mm4","mm7"); # ^= tp0>>24 + + &movq ("mm3",&QWP(8,"esp")); + &pxor ("mm2","mm2"); &pxor ("mm6","mm6"); + &pcmpgtb("mm2","mm1"); &pcmpgtb("mm6","mm5"); + &pand ("mm2","mm3"); &pand ("mm6","mm3"); + &paddb ("mm1","mm1"); &paddb ("mm5","mm5"); + &pxor ("mm1","mm2"); &pxor ("mm5","mm6"); # tp2 + &movq ("mm3","mm1"); &movq ("mm7","mm5"); + &movq ("mm2","mm1"); &movq ("mm6","mm5"); + &pxor ("mm0","mm1"); &pxor ("mm4","mm5"); # ^= tp2 + &pslld ("mm3",24); &pslld ("mm7",24); + &psrld ("mm2",8); &psrld ("mm6",8); + &pxor ("mm0","mm3"); &pxor ("mm4","mm7"); # ^= tp2<<24 + &pxor ("mm0","mm2"); &pxor ("mm4","mm6"); # ^= tp2>>8 + + &movq ("mm2",&QWP(8,"esp")); + &pxor ("mm3","mm3"); &pxor ("mm7","mm7"); + &pcmpgtb("mm3","mm1"); &pcmpgtb("mm7","mm5"); + &pand ("mm3","mm2"); &pand ("mm7","mm2"); + &paddb ("mm1","mm1"); &paddb ("mm5","mm5"); + &pxor ("mm1","mm3"); &pxor ("mm5","mm7"); # tp4 + &pshufw ("mm3","mm1",0xb1); &pshufw ("mm7","mm5",0xb1); + &pxor ("mm0","mm1"); &pxor ("mm4","mm5"); # ^= tp4 + &pxor ("mm0","mm3"); &pxor ("mm4","mm7"); # ^= ROTATE(tp4,16) + + &pxor ("mm3","mm3"); &pxor ("mm7","mm7"); + &pcmpgtb("mm3","mm1"); &pcmpgtb("mm7","mm5"); + &pand ("mm3","mm2"); &pand ("mm7","mm2"); + &paddb ("mm1","mm1"); &paddb ("mm5","mm5"); + &pxor ("mm1","mm3"); &pxor ("mm5","mm7"); # tp8 + &pxor ("mm0","mm1"); &pxor ("mm4","mm5"); # ^= tp8 + &movq ("mm3","mm1"); &movq ("mm7","mm5"); + &pshufw ("mm2","mm1",0xb1); &pshufw ("mm6","mm5",0xb1); + &pxor ("mm0","mm2"); &pxor ("mm4","mm6"); # ^= ROTATE(tp8,16) + &pslld ("mm1",8); &pslld ("mm5",8); + &psrld ("mm3",8); &psrld ("mm7",8); + &movq ("mm2",&QWP(0,$key)); &movq ("mm6",&QWP(8,$key)); + &pxor ("mm0","mm1"); &pxor ("mm4","mm5"); # ^= tp8<<8 + &pxor ("mm0","mm3"); &pxor ("mm4","mm7"); # ^= tp8>>8 + &mov ($s0,&DWP(0-128,$tbl)); + &pslld ("mm1",16); &pslld ("mm5",16); + &mov ($s1,&DWP(64-128,$tbl)); + &psrld ("mm3",16); &psrld ("mm7",16); + &mov ($s2,&DWP(128-128,$tbl)); + &pxor ("mm0","mm1"); &pxor ("mm4","mm5"); # ^= tp8<<24 + &mov ($s3,&DWP(192-128,$tbl)); + &pxor ("mm0","mm3"); &pxor ("mm4","mm7"); # ^= tp8>>24 + + &pxor ("mm0","mm2"); &pxor ("mm4","mm6"); + &jmp (&label("loop")); + + &set_label("out",16); + &pxor ("mm0",&QWP(0,$key)); + &pxor ("mm4",&QWP(8,$key)); + + &ret (); +&function_end_B("_sse_AES_decrypt_compact"); + } + +###################################################################### +# Vanilla block function. +###################################################################### + +sub decstep() +{ my ($i,$td,@s) = @_; + my $tmp = $key; + my $out = $i==3?$s[0]:$acc; + + # no instructions are reordered, as performance appears + # optimal... or rather that all attempts to reorder didn't + # result in better performance [which by the way is not a + # bit lower than ecryption]. + if($i==3) { &mov ($key,$__key); } + else { &mov ($out,$s[0]); } + &and ($out,0xFF); + &mov ($out,&DWP(0,$td,$out,8)); + + if ($i==3) { $tmp=$s[1]; } + &movz ($tmp,&HB($s[1])); + &xor ($out,&DWP(3,$td,$tmp,8)); + + if ($i==3) { $tmp=$s[2]; &mov ($s[1],$acc); } + else { &mov ($tmp,$s[2]); } + &shr ($tmp,16); + &and ($tmp,0xFF); + &xor ($out,&DWP(2,$td,$tmp,8)); + + if ($i==3) { $tmp=$s[3]; &mov ($s[2],$__s1); } + else { &mov ($tmp,$s[3]); } + &shr ($tmp,24); + &xor ($out,&DWP(1,$td,$tmp,8)); + if ($i<2) { &mov (&DWP(4+4*$i,"esp"),$out); } + if ($i==3) { &mov ($s[3],$__s0); } + &comment(); +} + +sub declast() +{ my ($i,$td,@s)=@_; + my $tmp = $key; + my $out = $i==3?$s[0]:$acc; + + if($i==0) { &lea ($td,&DWP(2048+128,$td)); + &mov ($tmp,&DWP(0-128,$td)); + &mov ($acc,&DWP(32-128,$td)); + &mov ($tmp,&DWP(64-128,$td)); + &mov ($acc,&DWP(96-128,$td)); + &mov ($tmp,&DWP(128-128,$td)); + &mov ($acc,&DWP(160-128,$td)); + &mov ($tmp,&DWP(192-128,$td)); + &mov ($acc,&DWP(224-128,$td)); + &lea ($td,&DWP(-128,$td)); } + if($i==3) { &mov ($key,$__key); } + else { &mov ($out,$s[0]); } + &and ($out,0xFF); + &movz ($out,&BP(0,$td,$out,1)); + + if ($i==3) { $tmp=$s[1]; } + &movz ($tmp,&HB($s[1])); + &movz ($tmp,&BP(0,$td,$tmp,1)); + &shl ($tmp,8); + &xor ($out,$tmp); + + if ($i==3) { $tmp=$s[2]; &mov ($s[1],$acc); } + else { mov ($tmp,$s[2]); } + &shr ($tmp,16); + &and ($tmp,0xFF); + &movz ($tmp,&BP(0,$td,$tmp,1)); + &shl ($tmp,16); + &xor ($out,$tmp); + + if ($i==3) { $tmp=$s[3]; &mov ($s[2],$__s1); } + else { &mov ($tmp,$s[3]); } + &shr ($tmp,24); + &movz ($tmp,&BP(0,$td,$tmp,1)); + &shl ($tmp,24); + &xor ($out,$tmp); + if ($i<2) { &mov (&DWP(4+4*$i,"esp"),$out); } + if ($i==3) { &mov ($s[3],$__s0); + &lea ($td,&DWP(-2048,$td)); } +} + +&function_begin_B("_x86_AES_decrypt"); + # note that caller is expected to allocate stack frame for me! + &mov ($__key,$key); # save key + + &xor ($s0,&DWP(0,$key)); # xor with key + &xor ($s1,&DWP(4,$key)); + &xor ($s2,&DWP(8,$key)); + &xor ($s3,&DWP(12,$key)); + + &mov ($acc,&DWP(240,$key)); # load key->rounds + + if ($small_footprint) { + &lea ($acc,&DWP(-2,$acc,$acc)); + &lea ($acc,&DWP(0,$key,$acc,8)); + &mov ($__end,$acc); # end of key schedule + &set_label("loop",16); + &decstep(0,$tbl,$s0,$s3,$s2,$s1); + &decstep(1,$tbl,$s1,$s0,$s3,$s2); + &decstep(2,$tbl,$s2,$s1,$s0,$s3); + &decstep(3,$tbl,$s3,$s2,$s1,$s0); + &add ($key,16); # advance rd_key + &xor ($s0,&DWP(0,$key)); + &xor ($s1,&DWP(4,$key)); + &xor ($s2,&DWP(8,$key)); + &xor ($s3,&DWP(12,$key)); + &cmp ($key,$__end); + &mov ($__key,$key); + &jb (&label("loop")); + } + else { + &cmp ($acc,10); + &jle (&label("10rounds")); + &cmp ($acc,12); + &jle (&label("12rounds")); + + &set_label("14rounds",4); + for ($i=1;$i<3;$i++) { + &decstep(0,$tbl,$s0,$s3,$s2,$s1); + &decstep(1,$tbl,$s1,$s0,$s3,$s2); + &decstep(2,$tbl,$s2,$s1,$s0,$s3); + &decstep(3,$tbl,$s3,$s2,$s1,$s0); + &xor ($s0,&DWP(16*$i+0,$key)); + &xor ($s1,&DWP(16*$i+4,$key)); + &xor ($s2,&DWP(16*$i+8,$key)); + &xor ($s3,&DWP(16*$i+12,$key)); + } + &add ($key,32); + &mov ($__key,$key); # advance rd_key + &set_label("12rounds",4); + for ($i=1;$i<3;$i++) { + &decstep(0,$tbl,$s0,$s3,$s2,$s1); + &decstep(1,$tbl,$s1,$s0,$s3,$s2); + &decstep(2,$tbl,$s2,$s1,$s0,$s3); + &decstep(3,$tbl,$s3,$s2,$s1,$s0); + &xor ($s0,&DWP(16*$i+0,$key)); + &xor ($s1,&DWP(16*$i+4,$key)); + &xor ($s2,&DWP(16*$i+8,$key)); + &xor ($s3,&DWP(16*$i+12,$key)); + } + &add ($key,32); + &mov ($__key,$key); # advance rd_key + &set_label("10rounds",4); + for ($i=1;$i<10;$i++) { + &decstep(0,$tbl,$s0,$s3,$s2,$s1); + &decstep(1,$tbl,$s1,$s0,$s3,$s2); + &decstep(2,$tbl,$s2,$s1,$s0,$s3); + &decstep(3,$tbl,$s3,$s2,$s1,$s0); + &xor ($s0,&DWP(16*$i+0,$key)); + &xor ($s1,&DWP(16*$i+4,$key)); + &xor ($s2,&DWP(16*$i+8,$key)); + &xor ($s3,&DWP(16*$i+12,$key)); + } + } + + &declast(0,$tbl,$s0,$s3,$s2,$s1); + &declast(1,$tbl,$s1,$s0,$s3,$s2); + &declast(2,$tbl,$s2,$s1,$s0,$s3); + &declast(3,$tbl,$s3,$s2,$s1,$s0); + + &add ($key,$small_footprint?16:160); + &xor ($s0,&DWP(0,$key)); + &xor ($s1,&DWP(4,$key)); + &xor ($s2,&DWP(8,$key)); + &xor ($s3,&DWP(12,$key)); + + &ret (); + +&set_label("AES_Td",64); # Yes! I keep it in the code segment! + &_data_word(0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a); + &_data_word(0xcb6bab3b, 0xf1459d1f, 0xab58faac, 0x9303e34b); + &_data_word(0x55fa3020, 0xf66d76ad, 0x9176cc88, 0x254c02f5); + &_data_word(0xfcd7e54f, 0xd7cb2ac5, 0x80443526, 0x8fa362b5); + &_data_word(0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d); + &_data_word(0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b); + &_data_word(0xe75f8f03, 0x959c9215, 0xeb7a6dbf, 0xda595295); + &_data_word(0x2d83bed4, 0xd3217458, 0x2969e049, 0x44c8c98e); + &_data_word(0x6a89c275, 0x78798ef4, 0x6b3e5899, 0xdd71b927); + &_data_word(0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d); + &_data_word(0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362); + &_data_word(0xe07764b1, 0x84ae6bbb, 0x1ca081fe, 0x942b08f9); + &_data_word(0x58684870, 0x19fd458f, 0x876cde94, 0xb7f87b52); + &_data_word(0x23d373ab, 0xe2024b72, 0x578f1fe3, 0x2aab5566); + &_data_word(0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3); + &_data_word(0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed); + &_data_word(0x2b1ccf8a, 0x92b479a7, 0xf0f207f3, 0xa1e2694e); + &_data_word(0xcdf4da65, 0xd5be0506, 0x1f6234d1, 0x8afea6c4); + &_data_word(0x9d532e34, 0xa055f3a2, 0x32e18a05, 0x75ebf6a4); + &_data_word(0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd); + &_data_word(0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d); + &_data_word(0xb58d5491, 0x055dc471, 0x6fd40604, 0xff155060); + &_data_word(0x24fb9819, 0x97e9bdd6, 0xcc434089, 0x779ed967); + &_data_word(0xbd42e8b0, 0x888b8907, 0x385b19e7, 0xdbeec879); + &_data_word(0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000); + &_data_word(0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c); + &_data_word(0xfbff0efd, 0x5638850f, 0x1ed5ae3d, 0x27392d36); + &_data_word(0x64d90f0a, 0x21a65c68, 0xd1545b9b, 0x3a2e3624); + &_data_word(0xb1670a0c, 0x0fe75793, 0xd296eeb4, 0x9e919b1b); + &_data_word(0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c); + &_data_word(0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12); + &_data_word(0x0b0d090e, 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14); + &_data_word(0x8519f157, 0x4c0775af, 0xbbdd99ee, 0xfd607fa3); + &_data_word(0x9f2601f7, 0xbcf5725c, 0xc53b6644, 0x347efb5b); + &_data_word(0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8); + &_data_word(0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684); + &_data_word(0x7d244a85, 0xf83dbbd2, 0x1132f9ae, 0x6da129c7); + &_data_word(0x4b2f9e1d, 0xf330b2dc, 0xec52860d, 0xd0e3c177); + &_data_word(0x6c16b32b, 0x99b970a9, 0xfa489411, 0x2264e947); + &_data_word(0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322); + &_data_word(0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498); + &_data_word(0xcf81f5a6, 0x28de7aa5, 0x268eb7da, 0xa4bfad3f); + &_data_word(0xe49d3a2c, 0x0d927850, 0x9bcc5f6a, 0x62467e54); + &_data_word(0xc2138df6, 0xe8b8d890, 0x5ef7392e, 0xf5afc382); + &_data_word(0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf); + &_data_word(0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb); + &_data_word(0x097826cd, 0xf418596e, 0x01b79aec, 0xa89a4f83); + &_data_word(0x656e95e6, 0x7ee6ffaa, 0x08cfbc21, 0xe6e815ef); + &_data_word(0xd99be7ba, 0xce366f4a, 0xd4099fea, 0xd67cb029); + &_data_word(0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235); + &_data_word(0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733); + &_data_word(0x4a9804f1, 0xf7daec41, 0x0e50cd7f, 0x2ff69117); + &_data_word(0x8dd64d76, 0x4db0ef43, 0x544daacc, 0xdf0496e4); + &_data_word(0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, 0x7f516546); + &_data_word(0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb); + &_data_word(0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d); + &_data_word(0x8c61d79a, 0x7a0ca137, 0x8e14f859, 0x893c13eb); + &_data_word(0xee27a9ce, 0x35c961b7, 0xede51ce1, 0x3cb1477a); + &_data_word(0x59dfd29c, 0x3f73f255, 0x79ce1418, 0xbf37c773); + &_data_word(0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478); + &_data_word(0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2); + &_data_word(0x72c31d16, 0x0c25e2bc, 0x8b493c28, 0x41950dff); + &_data_word(0x7101a839, 0xdeb30c08, 0x9ce4b4d8, 0x90c15664); + &_data_word(0x6184cb7b, 0x70b632d5, 0x745c6c48, 0x4257b8d0); + +#Td4: # four copies of Td4 to choose from to avoid L1 aliasing + &data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38); + &data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb); + &data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87); + &data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb); + &data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d); + &data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e); + &data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2); + &data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25); + &data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16); + &data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92); + &data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda); + &data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84); + &data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a); + &data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06); + &data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02); + &data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b); + &data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea); + &data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73); + &data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85); + &data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e); + &data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89); + &data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b); + &data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20); + &data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4); + &data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31); + &data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f); + &data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d); + &data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef); + &data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0); + &data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61); + &data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26); + &data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d); + + &data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38); + &data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb); + &data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87); + &data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb); + &data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d); + &data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e); + &data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2); + &data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25); + &data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16); + &data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92); + &data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda); + &data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84); + &data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a); + &data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06); + &data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02); + &data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b); + &data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea); + &data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73); + &data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85); + &data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e); + &data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89); + &data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b); + &data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20); + &data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4); + &data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31); + &data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f); + &data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d); + &data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef); + &data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0); + &data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61); + &data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26); + &data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d); + + &data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38); + &data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb); + &data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87); + &data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb); + &data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d); + &data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e); + &data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2); + &data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25); + &data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16); + &data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92); + &data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda); + &data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84); + &data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a); + &data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06); + &data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02); + &data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b); + &data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea); + &data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73); + &data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85); + &data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e); + &data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89); + &data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b); + &data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20); + &data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4); + &data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31); + &data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f); + &data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d); + &data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef); + &data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0); + &data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61); + &data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26); + &data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d); + + &data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38); + &data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb); + &data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87); + &data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb); + &data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d); + &data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e); + &data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2); + &data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25); + &data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16); + &data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92); + &data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda); + &data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84); + &data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a); + &data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06); + &data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02); + &data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b); + &data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea); + &data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73); + &data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85); + &data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e); + &data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89); + &data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b); + &data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20); + &data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4); + &data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31); + &data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f); + &data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d); + &data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef); + &data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0); + &data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61); + &data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26); + &data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d); +&function_end_B("_x86_AES_decrypt"); + +# void asm_AES_decrypt (const void *inp,void *out,const AES_KEY *key); +&function_begin("asm_AES_decrypt"); + &mov ($acc,&wparam(0)); # load inp + &mov ($key,&wparam(2)); # load key + + &mov ($s0,"esp"); + &sub ("esp",36); + &and ("esp",-64); # align to cache-line + + # place stack frame just "above" the key schedule + &lea ($s1,&DWP(-64-63,$key)); + &sub ($s1,"esp"); + &neg ($s1); + &and ($s1,0x3C0); # modulo 1024, but aligned to cache-line + &sub ("esp",$s1); + &add ("esp",4); # 4 is reserved for caller's return address + &mov ($_esp,$s0); # save stack pointer + + &call (&label("pic_point")); # make it PIC! + &set_label("pic_point"); + &blindpop($tbl); + &picmeup($s0,"OPENSSL_ia32cap_P",$tbl,&label("pic_point")) if(!$x86only); + &lea ($tbl,&DWP(&label("AES_Td")."-".&label("pic_point"),$tbl)); + + # pick Td4 copy which can't "overlap" with stack frame or key schedule + &lea ($s1,&DWP(768-4,"esp")); + &sub ($s1,$tbl); + &and ($s1,0x300); + &lea ($tbl,&DWP(2048+128,$tbl,$s1)); + + if (!$x86only) { + &bt (&DWP(0,$s0),25); # check for SSE bit + &jnc (&label("x86")); + + &movq ("mm0",&QWP(0,$acc)); + &movq ("mm4",&QWP(8,$acc)); + &call ("_sse_AES_decrypt_compact"); + &mov ("esp",$_esp); # restore stack pointer + &mov ($acc,&wparam(1)); # load out + &movq (&QWP(0,$acc),"mm0"); # write output data + &movq (&QWP(8,$acc),"mm4"); + &emms (); + &function_end_A(); + } + &set_label("x86",16); + &mov ($_tbl,$tbl); + &mov ($s0,&DWP(0,$acc)); # load input data + &mov ($s1,&DWP(4,$acc)); + &mov ($s2,&DWP(8,$acc)); + &mov ($s3,&DWP(12,$acc)); + &call ("_x86_AES_decrypt_compact"); + &mov ("esp",$_esp); # restore stack pointer + &mov ($acc,&wparam(1)); # load out + &mov (&DWP(0,$acc),$s0); # write output data + &mov (&DWP(4,$acc),$s1); + &mov (&DWP(8,$acc),$s2); + &mov (&DWP(12,$acc),$s3); +&function_end("asm_AES_decrypt"); + +# void asm_AES_cbc_encrypt (const void char *inp, unsigned char *out, +# size_t length, const AES_KEY *key, +# unsigned char *ivp,const int enc); +{ +# stack frame layout +# -4(%esp) # return address 0(%esp) +# 0(%esp) # s0 backing store 4(%esp) +# 4(%esp) # s1 backing store 8(%esp) +# 8(%esp) # s2 backing store 12(%esp) +# 12(%esp) # s3 backing store 16(%esp) +# 16(%esp) # key backup 20(%esp) +# 20(%esp) # end of key schedule 24(%esp) +# 24(%esp) # %ebp backup 28(%esp) +# 28(%esp) # %esp backup +my $_inp=&DWP(32,"esp"); # copy of wparam(0) +my $_out=&DWP(36,"esp"); # copy of wparam(1) +my $_len=&DWP(40,"esp"); # copy of wparam(2) +my $_key=&DWP(44,"esp"); # copy of wparam(3) +my $_ivp=&DWP(48,"esp"); # copy of wparam(4) +my $_tmp=&DWP(52,"esp"); # volatile variable +# +my $ivec=&DWP(60,"esp"); # ivec[16] +my $aes_key=&DWP(76,"esp"); # copy of aes_key +my $mark=&DWP(76+240,"esp"); # copy of aes_key->rounds + +&function_begin("asm_AES_cbc_encrypt"); + &mov ($s2 eq "ecx"? $s2 : "",&wparam(2)); # load len + &cmp ($s2,0); + &je (&label("drop_out")); + + &call (&label("pic_point")); # make it PIC! + &set_label("pic_point"); + &blindpop($tbl); + &picmeup($s0,"OPENSSL_ia32cap_P",$tbl,&label("pic_point")) if(!$x86only); + + &cmp (&wparam(5),0); + &lea ($tbl,&DWP(&label("AES_Te")."-".&label("pic_point"),$tbl)); + &jne (&label("picked_te")); + &lea ($tbl,&DWP(&label("AES_Td")."-".&label("AES_Te"),$tbl)); + &set_label("picked_te"); + + # one can argue if this is required + &pushf (); + &cld (); + + &cmp ($s2,$speed_limit); + &jb (&label("slow_way")); + &test ($s2,15); + &jnz (&label("slow_way")); + if (!$x86only) { + &bt (&DWP(0,$s0),28); # check for hyper-threading bit + &jc (&label("slow_way")); + } + # pre-allocate aligned stack frame... + &lea ($acc,&DWP(-80-244,"esp")); + &and ($acc,-64); + + # ... and make sure it doesn't alias with $tbl modulo 4096 + &mov ($s0,$tbl); + &lea ($s1,&DWP(2048+256,$tbl)); + &mov ($s3,$acc); + &and ($s0,0xfff); # s = %ebp&0xfff + &and ($s1,0xfff); # e = (%ebp+2048+256)&0xfff + &and ($s3,0xfff); # p = %esp&0xfff + + &cmp ($s3,$s1); # if (p>=e) %esp =- (p-e); + &jb (&label("tbl_break_out")); + &sub ($s3,$s1); + &sub ($acc,$s3); + &jmp (&label("tbl_ok")); + &set_label("tbl_break_out",4); # else %esp -= (p-s)&0xfff + framesz; + &sub ($s3,$s0); + &and ($s3,0xfff); + &add ($s3,384); + &sub ($acc,$s3); + &set_label("tbl_ok",4); + + &lea ($s3,&wparam(0)); # obtain pointer to parameter block + &exch ("esp",$acc); # allocate stack frame + &add ("esp",4); # reserve for return address! + &mov ($_tbl,$tbl); # save %ebp + &mov ($_esp,$acc); # save %esp + + &mov ($s0,&DWP(0,$s3)); # load inp + &mov ($s1,&DWP(4,$s3)); # load out + #&mov ($s2,&DWP(8,$s3)); # load len + &mov ($key,&DWP(12,$s3)); # load key + &mov ($acc,&DWP(16,$s3)); # load ivp + &mov ($s3,&DWP(20,$s3)); # load enc flag + + &mov ($_inp,$s0); # save copy of inp + &mov ($_out,$s1); # save copy of out + &mov ($_len,$s2); # save copy of len + &mov ($_key,$key); # save copy of key + &mov ($_ivp,$acc); # save copy of ivp + + &mov ($mark,0); # copy of aes_key->rounds = 0; + # do we copy key schedule to stack? + &mov ($s1 eq "ebx" ? $s1 : "",$key); + &mov ($s2 eq "ecx" ? $s2 : "",244/4); + &sub ($s1,$tbl); + &mov ("esi",$key); + &and ($s1,0xfff); + &lea ("edi",$aes_key); + &cmp ($s1,2048+256); + &jb (&label("do_copy")); + &cmp ($s1,4096-244); + &jb (&label("skip_copy")); + &set_label("do_copy",4); + &mov ($_key,"edi"); + &data_word(0xA5F3F689); # rep movsd + &set_label("skip_copy"); + + &mov ($key,16); + &set_label("prefetch_tbl",4); + &mov ($s0,&DWP(0,$tbl)); + &mov ($s1,&DWP(32,$tbl)); + &mov ($s2,&DWP(64,$tbl)); + &mov ($acc,&DWP(96,$tbl)); + &lea ($tbl,&DWP(128,$tbl)); + &sub ($key,1); + &jnz (&label("prefetch_tbl")); + &sub ($tbl,2048); + + &mov ($acc,$_inp); + &mov ($key,$_ivp); + + &cmp ($s3,0); + &je (&label("fast_decrypt")); + +#----------------------------- ENCRYPT -----------------------------# + &mov ($s0,&DWP(0,$key)); # load iv + &mov ($s1,&DWP(4,$key)); + + &set_label("fast_enc_loop",16); + &mov ($s2,&DWP(8,$key)); + &mov ($s3,&DWP(12,$key)); + + &xor ($s0,&DWP(0,$acc)); # xor input data + &xor ($s1,&DWP(4,$acc)); + &xor ($s2,&DWP(8,$acc)); + &xor ($s3,&DWP(12,$acc)); + + &mov ($key,$_key); # load key + &call ("_x86_AES_encrypt"); + + &mov ($acc,$_inp); # load inp + &mov ($key,$_out); # load out + + &mov (&DWP(0,$key),$s0); # save output data + &mov (&DWP(4,$key),$s1); + &mov (&DWP(8,$key),$s2); + &mov (&DWP(12,$key),$s3); + + &lea ($acc,&DWP(16,$acc)); # advance inp + &mov ($s2,$_len); # load len + &mov ($_inp,$acc); # save inp + &lea ($s3,&DWP(16,$key)); # advance out + &mov ($_out,$s3); # save out + &sub ($s2,16); # decrease len + &mov ($_len,$s2); # save len + &jnz (&label("fast_enc_loop")); + &mov ($acc,$_ivp); # load ivp + &mov ($s2,&DWP(8,$key)); # restore last 2 dwords + &mov ($s3,&DWP(12,$key)); + &mov (&DWP(0,$acc),$s0); # save ivec + &mov (&DWP(4,$acc),$s1); + &mov (&DWP(8,$acc),$s2); + &mov (&DWP(12,$acc),$s3); + + &cmp ($mark,0); # was the key schedule copied? + &mov ("edi",$_key); + &je (&label("skip_ezero")); + # zero copy of key schedule + &mov ("ecx",240/4); + &xor ("eax","eax"); + &align (4); + &data_word(0xABF3F689); # rep stosd + &set_label("skip_ezero"); + &mov ("esp",$_esp); + &popf (); + &set_label("drop_out"); + &function_end_A(); + &pushf (); # kludge, never executed + +#----------------------------- DECRYPT -----------------------------# +&set_label("fast_decrypt",16); + + &cmp ($acc,$_out); + &je (&label("fast_dec_in_place")); # in-place processing... + + &mov ($_tmp,$key); + + &align (4); + &set_label("fast_dec_loop",16); + &mov ($s0,&DWP(0,$acc)); # read input + &mov ($s1,&DWP(4,$acc)); + &mov ($s2,&DWP(8,$acc)); + &mov ($s3,&DWP(12,$acc)); + + &mov ($key,$_key); # load key + &call ("_x86_AES_decrypt"); + + &mov ($key,$_tmp); # load ivp + &mov ($acc,$_len); # load len + &xor ($s0,&DWP(0,$key)); # xor iv + &xor ($s1,&DWP(4,$key)); + &xor ($s2,&DWP(8,$key)); + &xor ($s3,&DWP(12,$key)); + + &mov ($key,$_out); # load out + &mov ($acc,$_inp); # load inp + + &mov (&DWP(0,$key),$s0); # write output + &mov (&DWP(4,$key),$s1); + &mov (&DWP(8,$key),$s2); + &mov (&DWP(12,$key),$s3); + + &mov ($s2,$_len); # load len + &mov ($_tmp,$acc); # save ivp + &lea ($acc,&DWP(16,$acc)); # advance inp + &mov ($_inp,$acc); # save inp + &lea ($key,&DWP(16,$key)); # advance out + &mov ($_out,$key); # save out + &sub ($s2,16); # decrease len + &mov ($_len,$s2); # save len + &jnz (&label("fast_dec_loop")); + &mov ($key,$_tmp); # load temp ivp + &mov ($acc,$_ivp); # load user ivp + &mov ($s0,&DWP(0,$key)); # load iv + &mov ($s1,&DWP(4,$key)); + &mov ($s2,&DWP(8,$key)); + &mov ($s3,&DWP(12,$key)); + &mov (&DWP(0,$acc),$s0); # copy back to user + &mov (&DWP(4,$acc),$s1); + &mov (&DWP(8,$acc),$s2); + &mov (&DWP(12,$acc),$s3); + &jmp (&label("fast_dec_out")); + + &set_label("fast_dec_in_place",16); + &set_label("fast_dec_in_place_loop"); + &mov ($s0,&DWP(0,$acc)); # read input + &mov ($s1,&DWP(4,$acc)); + &mov ($s2,&DWP(8,$acc)); + &mov ($s3,&DWP(12,$acc)); + + &lea ($key,$ivec); + &mov (&DWP(0,$key),$s0); # copy to temp + &mov (&DWP(4,$key),$s1); + &mov (&DWP(8,$key),$s2); + &mov (&DWP(12,$key),$s3); + + &mov ($key,$_key); # load key + &call ("_x86_AES_decrypt"); + + &mov ($key,$_ivp); # load ivp + &mov ($acc,$_out); # load out + &xor ($s0,&DWP(0,$key)); # xor iv + &xor ($s1,&DWP(4,$key)); + &xor ($s2,&DWP(8,$key)); + &xor ($s3,&DWP(12,$key)); + + &mov (&DWP(0,$acc),$s0); # write output + &mov (&DWP(4,$acc),$s1); + &mov (&DWP(8,$acc),$s2); + &mov (&DWP(12,$acc),$s3); + + &lea ($acc,&DWP(16,$acc)); # advance out + &mov ($_out,$acc); # save out + + &lea ($acc,$ivec); + &mov ($s0,&DWP(0,$acc)); # read temp + &mov ($s1,&DWP(4,$acc)); + &mov ($s2,&DWP(8,$acc)); + &mov ($s3,&DWP(12,$acc)); + + &mov (&DWP(0,$key),$s0); # copy iv + &mov (&DWP(4,$key),$s1); + &mov (&DWP(8,$key),$s2); + &mov (&DWP(12,$key),$s3); + + &mov ($acc,$_inp); # load inp + &mov ($s2,$_len); # load len + &lea ($acc,&DWP(16,$acc)); # advance inp + &mov ($_inp,$acc); # save inp + &sub ($s2,16); # decrease len + &mov ($_len,$s2); # save len + &jnz (&label("fast_dec_in_place_loop")); + + &set_label("fast_dec_out",4); + &cmp ($mark,0); # was the key schedule copied? + &mov ("edi",$_key); + &je (&label("skip_dzero")); + # zero copy of key schedule + &mov ("ecx",240/4); + &xor ("eax","eax"); + &align (4); + &data_word(0xABF3F689); # rep stosd + &set_label("skip_dzero"); + &mov ("esp",$_esp); + &popf (); + &function_end_A(); + &pushf (); # kludge, never executed + +#--------------------------- SLOW ROUTINE ---------------------------# +&set_label("slow_way",16); + + &mov ($s0,&DWP(0,$s0)) if (!$x86only);# load OPENSSL_ia32cap + &mov ($key,&wparam(3)); # load key + + # pre-allocate aligned stack frame... + &lea ($acc,&DWP(-80,"esp")); + &and ($acc,-64); + + # ... and make sure it doesn't alias with $key modulo 1024 + &lea ($s1,&DWP(-80-63,$key)); + &sub ($s1,$acc); + &neg ($s1); + &and ($s1,0x3C0); # modulo 1024, but aligned to cache-line + &sub ($acc,$s1); + + # pick S-box copy which can't overlap with stack frame or $key + &lea ($s1,&DWP(768,$acc)); + &sub ($s1,$tbl); + &and ($s1,0x300); + &lea ($tbl,&DWP(2048+128,$tbl,$s1)); + + &lea ($s3,&wparam(0)); # pointer to parameter block + + &exch ("esp",$acc); + &add ("esp",4); # reserve for return address! + &mov ($_tbl,$tbl); # save %ebp + &mov ($_esp,$acc); # save %esp + &mov ($_tmp,$s0); # save OPENSSL_ia32cap + + &mov ($s0,&DWP(0,$s3)); # load inp + &mov ($s1,&DWP(4,$s3)); # load out + #&mov ($s2,&DWP(8,$s3)); # load len + #&mov ($key,&DWP(12,$s3)); # load key + &mov ($acc,&DWP(16,$s3)); # load ivp + &mov ($s3,&DWP(20,$s3)); # load enc flag + + &mov ($_inp,$s0); # save copy of inp + &mov ($_out,$s1); # save copy of out + &mov ($_len,$s2); # save copy of len + &mov ($_key,$key); # save copy of key + &mov ($_ivp,$acc); # save copy of ivp + + &mov ($key,$acc); + &mov ($acc,$s0); + + &cmp ($s3,0); + &je (&label("slow_decrypt")); + +#--------------------------- SLOW ENCRYPT ---------------------------# + &cmp ($s2,16); + &mov ($s3,$s1); + &jb (&label("slow_enc_tail")); + + if (!$x86only) { + &bt ($_tmp,25); # check for SSE bit + &jnc (&label("slow_enc_x86")); + + &movq ("mm0",&QWP(0,$key)); # load iv + &movq ("mm4",&QWP(8,$key)); + + &set_label("slow_enc_loop_sse",16); + &pxor ("mm0",&QWP(0,$acc)); # xor input data + &pxor ("mm4",&QWP(8,$acc)); + + &mov ($key,$_key); + &call ("_sse_AES_encrypt_compact"); + + &mov ($acc,$_inp); # load inp + &mov ($key,$_out); # load out + &mov ($s2,$_len); # load len + + &movq (&QWP(0,$key),"mm0"); # save output data + &movq (&QWP(8,$key),"mm4"); + + &lea ($acc,&DWP(16,$acc)); # advance inp + &mov ($_inp,$acc); # save inp + &lea ($s3,&DWP(16,$key)); # advance out + &mov ($_out,$s3); # save out + &sub ($s2,16); # decrease len + &cmp ($s2,16); + &mov ($_len,$s2); # save len + &jae (&label("slow_enc_loop_sse")); + &test ($s2,15); + &jnz (&label("slow_enc_tail")); + &mov ($acc,$_ivp); # load ivp + &movq (&QWP(0,$acc),"mm0"); # save ivec + &movq (&QWP(8,$acc),"mm4"); + &emms (); + &mov ("esp",$_esp); + &popf (); + &function_end_A(); + &pushf (); # kludge, never executed + } + &set_label("slow_enc_x86",16); + &mov ($s0,&DWP(0,$key)); # load iv + &mov ($s1,&DWP(4,$key)); + + &set_label("slow_enc_loop_x86",4); + &mov ($s2,&DWP(8,$key)); + &mov ($s3,&DWP(12,$key)); + + &xor ($s0,&DWP(0,$acc)); # xor input data + &xor ($s1,&DWP(4,$acc)); + &xor ($s2,&DWP(8,$acc)); + &xor ($s3,&DWP(12,$acc)); + + &mov ($key,$_key); # load key + &call ("_x86_AES_encrypt_compact"); + + &mov ($acc,$_inp); # load inp + &mov ($key,$_out); # load out + + &mov (&DWP(0,$key),$s0); # save output data + &mov (&DWP(4,$key),$s1); + &mov (&DWP(8,$key),$s2); + &mov (&DWP(12,$key),$s3); + + &mov ($s2,$_len); # load len + &lea ($acc,&DWP(16,$acc)); # advance inp + &mov ($_inp,$acc); # save inp + &lea ($s3,&DWP(16,$key)); # advance out + &mov ($_out,$s3); # save out + &sub ($s2,16); # decrease len + &cmp ($s2,16); + &mov ($_len,$s2); # save len + &jae (&label("slow_enc_loop_x86")); + &test ($s2,15); + &jnz (&label("slow_enc_tail")); + &mov ($acc,$_ivp); # load ivp + &mov ($s2,&DWP(8,$key)); # restore last dwords + &mov ($s3,&DWP(12,$key)); + &mov (&DWP(0,$acc),$s0); # save ivec + &mov (&DWP(4,$acc),$s1); + &mov (&DWP(8,$acc),$s2); + &mov (&DWP(12,$acc),$s3); + + &mov ("esp",$_esp); + &popf (); + &function_end_A(); + &pushf (); # kludge, never executed + + &set_label("slow_enc_tail",16); + &emms () if (!$x86only); + &mov ($key eq "edi"? $key:"",$s3); # load out to edi + &mov ($s1,16); + &sub ($s1,$s2); + &cmp ($key,$acc eq "esi"? $acc:""); # compare with inp + &je (&label("enc_in_place")); + &align (4); + &data_word(0xA4F3F689); # rep movsb # copy input + &jmp (&label("enc_skip_in_place")); + &set_label("enc_in_place"); + &lea ($key,&DWP(0,$key,$s2)); + &set_label("enc_skip_in_place"); + &mov ($s2,$s1); + &xor ($s0,$s0); + &align (4); + &data_word(0xAAF3F689); # rep stosb # zero tail + + &mov ($key,$_ivp); # restore ivp + &mov ($acc,$s3); # output as input + &mov ($s0,&DWP(0,$key)); + &mov ($s1,&DWP(4,$key)); + &mov ($_len,16); # len=16 + &jmp (&label("slow_enc_loop_x86")); # one more spin... + +#--------------------------- SLOW DECRYPT ---------------------------# +&set_label("slow_decrypt",16); + if (!$x86only) { + &bt ($_tmp,25); # check for SSE bit + &jnc (&label("slow_dec_loop_x86")); + + &set_label("slow_dec_loop_sse",4); + &movq ("mm0",&QWP(0,$acc)); # read input + &movq ("mm4",&QWP(8,$acc)); + + &mov ($key,$_key); + &call ("_sse_AES_decrypt_compact"); + + &mov ($acc,$_inp); # load inp + &lea ($s0,$ivec); + &mov ($s1,$_out); # load out + &mov ($s2,$_len); # load len + &mov ($key,$_ivp); # load ivp + + &movq ("mm1",&QWP(0,$acc)); # re-read input + &movq ("mm5",&QWP(8,$acc)); + + &pxor ("mm0",&QWP(0,$key)); # xor iv + &pxor ("mm4",&QWP(8,$key)); + + &movq (&QWP(0,$key),"mm1"); # copy input to iv + &movq (&QWP(8,$key),"mm5"); + + &sub ($s2,16); # decrease len + &jc (&label("slow_dec_partial_sse")); + + &movq (&QWP(0,$s1),"mm0"); # write output + &movq (&QWP(8,$s1),"mm4"); + + &lea ($s1,&DWP(16,$s1)); # advance out + &mov ($_out,$s1); # save out + &lea ($acc,&DWP(16,$acc)); # advance inp + &mov ($_inp,$acc); # save inp + &mov ($_len,$s2); # save len + &jnz (&label("slow_dec_loop_sse")); + &emms (); + &mov ("esp",$_esp); + &popf (); + &function_end_A(); + &pushf (); # kludge, never executed + + &set_label("slow_dec_partial_sse",16); + &movq (&QWP(0,$s0),"mm0"); # save output to temp + &movq (&QWP(8,$s0),"mm4"); + &emms (); + + &add ($s2 eq "ecx" ? "ecx":"",16); + &mov ("edi",$s1); # out + &mov ("esi",$s0); # temp + &align (4); + &data_word(0xA4F3F689); # rep movsb # copy partial output + + &mov ("esp",$_esp); + &popf (); + &function_end_A(); + &pushf (); # kludge, never executed + } + &set_label("slow_dec_loop_x86",16); + &mov ($s0,&DWP(0,$acc)); # read input + &mov ($s1,&DWP(4,$acc)); + &mov ($s2,&DWP(8,$acc)); + &mov ($s3,&DWP(12,$acc)); + + &lea ($key,$ivec); + &mov (&DWP(0,$key),$s0); # copy to temp + &mov (&DWP(4,$key),$s1); + &mov (&DWP(8,$key),$s2); + &mov (&DWP(12,$key),$s3); + + &mov ($key,$_key); # load key + &call ("_x86_AES_decrypt_compact"); + + &mov ($key,$_ivp); # load ivp + &mov ($acc,$_len); # load len + &xor ($s0,&DWP(0,$key)); # xor iv + &xor ($s1,&DWP(4,$key)); + &xor ($s2,&DWP(8,$key)); + &xor ($s3,&DWP(12,$key)); + + &sub ($acc,16); + &jc (&label("slow_dec_partial_x86")); + + &mov ($_len,$acc); # save len + &mov ($acc,$_out); # load out + + &mov (&DWP(0,$acc),$s0); # write output + &mov (&DWP(4,$acc),$s1); + &mov (&DWP(8,$acc),$s2); + &mov (&DWP(12,$acc),$s3); + + &lea ($acc,&DWP(16,$acc)); # advance out + &mov ($_out,$acc); # save out + + &lea ($acc,$ivec); + &mov ($s0,&DWP(0,$acc)); # read temp + &mov ($s1,&DWP(4,$acc)); + &mov ($s2,&DWP(8,$acc)); + &mov ($s3,&DWP(12,$acc)); + + &mov (&DWP(0,$key),$s0); # copy it to iv + &mov (&DWP(4,$key),$s1); + &mov (&DWP(8,$key),$s2); + &mov (&DWP(12,$key),$s3); + + &mov ($acc,$_inp); # load inp + &lea ($acc,&DWP(16,$acc)); # advance inp + &mov ($_inp,$acc); # save inp + &jnz (&label("slow_dec_loop_x86")); + &mov ("esp",$_esp); + &popf (); + &function_end_A(); + &pushf (); # kludge, never executed + + &set_label("slow_dec_partial_x86",16); + &lea ($acc,$ivec); + &mov (&DWP(0,$acc),$s0); # save output to temp + &mov (&DWP(4,$acc),$s1); + &mov (&DWP(8,$acc),$s2); + &mov (&DWP(12,$acc),$s3); + + &mov ($acc,$_inp); + &mov ($s0,&DWP(0,$acc)); # re-read input + &mov ($s1,&DWP(4,$acc)); + &mov ($s2,&DWP(8,$acc)); + &mov ($s3,&DWP(12,$acc)); + + &mov (&DWP(0,$key),$s0); # copy it to iv + &mov (&DWP(4,$key),$s1); + &mov (&DWP(8,$key),$s2); + &mov (&DWP(12,$key),$s3); + + &mov ("ecx",$_len); + &mov ("edi",$_out); + &lea ("esi",$ivec); + &align (4); + &data_word(0xA4F3F689); # rep movsb # copy partial output + + &mov ("esp",$_esp); + &popf (); +&function_end("asm_AES_cbc_encrypt"); +} + +#------------------------------------------------------------------# + +sub enckey() +{ + &movz ("esi",&LB("edx")); # rk[i]>>0 + &movz ("ebx",&BP(-128,$tbl,"esi",1)); + &movz ("esi",&HB("edx")); # rk[i]>>8 + &shl ("ebx",24); + &xor ("eax","ebx"); + + &movz ("ebx",&BP(-128,$tbl,"esi",1)); + &shr ("edx",16); + &movz ("esi",&LB("edx")); # rk[i]>>16 + &xor ("eax","ebx"); + + &movz ("ebx",&BP(-128,$tbl,"esi",1)); + &movz ("esi",&HB("edx")); # rk[i]>>24 + &shl ("ebx",8); + &xor ("eax","ebx"); + + &movz ("ebx",&BP(-128,$tbl,"esi",1)); + &shl ("ebx",16); + &xor ("eax","ebx"); + + &xor ("eax",&DWP(1024-128,$tbl,"ecx",4)); # rcon +} + +&function_begin("_x86_AES_set_encrypt_key"); + &mov ("esi",&wparam(1)); # user supplied key + &mov ("edi",&wparam(3)); # private key schedule + + &test ("esi",-1); + &jz (&label("badpointer")); + &test ("edi",-1); + &jz (&label("badpointer")); + + &call (&label("pic_point")); + &set_label("pic_point"); + &blindpop($tbl); + &lea ($tbl,&DWP(&label("AES_Te")."-".&label("pic_point"),$tbl)); + &lea ($tbl,&DWP(2048+128,$tbl)); + + # prefetch Te4 + &mov ("eax",&DWP(0-128,$tbl)); + &mov ("ebx",&DWP(32-128,$tbl)); + &mov ("ecx",&DWP(64-128,$tbl)); + &mov ("edx",&DWP(96-128,$tbl)); + &mov ("eax",&DWP(128-128,$tbl)); + &mov ("ebx",&DWP(160-128,$tbl)); + &mov ("ecx",&DWP(192-128,$tbl)); + &mov ("edx",&DWP(224-128,$tbl)); + + &mov ("ecx",&wparam(2)); # number of bits in key + &cmp ("ecx",128); + &je (&label("10rounds")); + &cmp ("ecx",192); + &je (&label("12rounds")); + &cmp ("ecx",256); + &je (&label("14rounds")); + &mov ("eax",-2); # invalid number of bits + &jmp (&label("exit")); + + &set_label("10rounds"); + &mov ("eax",&DWP(0,"esi")); # copy first 4 dwords + &mov ("ebx",&DWP(4,"esi")); + &mov ("ecx",&DWP(8,"esi")); + &mov ("edx",&DWP(12,"esi")); + &mov (&DWP(0,"edi"),"eax"); + &mov (&DWP(4,"edi"),"ebx"); + &mov (&DWP(8,"edi"),"ecx"); + &mov (&DWP(12,"edi"),"edx"); + + &xor ("ecx","ecx"); + &jmp (&label("10shortcut")); + + &align (4); + &set_label("10loop"); + &mov ("eax",&DWP(0,"edi")); # rk[0] + &mov ("edx",&DWP(12,"edi")); # rk[3] + &set_label("10shortcut"); + &enckey (); + + &mov (&DWP(16,"edi"),"eax"); # rk[4] + &xor ("eax",&DWP(4,"edi")); + &mov (&DWP(20,"edi"),"eax"); # rk[5] + &xor ("eax",&DWP(8,"edi")); + &mov (&DWP(24,"edi"),"eax"); # rk[6] + &xor ("eax",&DWP(12,"edi")); + &mov (&DWP(28,"edi"),"eax"); # rk[7] + &inc ("ecx"); + &add ("edi",16); + &cmp ("ecx",10); + &jl (&label("10loop")); + + &mov (&DWP(80,"edi"),10); # setup number of rounds + &xor ("eax","eax"); + &jmp (&label("exit")); + + &set_label("12rounds"); + &mov ("eax",&DWP(0,"esi")); # copy first 6 dwords + &mov ("ebx",&DWP(4,"esi")); + &mov ("ecx",&DWP(8,"esi")); + &mov ("edx",&DWP(12,"esi")); + &mov (&DWP(0,"edi"),"eax"); + &mov (&DWP(4,"edi"),"ebx"); + &mov (&DWP(8,"edi"),"ecx"); + &mov (&DWP(12,"edi"),"edx"); + &mov ("ecx",&DWP(16,"esi")); + &mov ("edx",&DWP(20,"esi")); + &mov (&DWP(16,"edi"),"ecx"); + &mov (&DWP(20,"edi"),"edx"); + + &xor ("ecx","ecx"); + &jmp (&label("12shortcut")); + + &align (4); + &set_label("12loop"); + &mov ("eax",&DWP(0,"edi")); # rk[0] + &mov ("edx",&DWP(20,"edi")); # rk[5] + &set_label("12shortcut"); + &enckey (); + + &mov (&DWP(24,"edi"),"eax"); # rk[6] + &xor ("eax",&DWP(4,"edi")); + &mov (&DWP(28,"edi"),"eax"); # rk[7] + &xor ("eax",&DWP(8,"edi")); + &mov (&DWP(32,"edi"),"eax"); # rk[8] + &xor ("eax",&DWP(12,"edi")); + &mov (&DWP(36,"edi"),"eax"); # rk[9] + + &cmp ("ecx",7); + &je (&label("12break")); + &inc ("ecx"); + + &xor ("eax",&DWP(16,"edi")); + &mov (&DWP(40,"edi"),"eax"); # rk[10] + &xor ("eax",&DWP(20,"edi")); + &mov (&DWP(44,"edi"),"eax"); # rk[11] + + &add ("edi",24); + &jmp (&label("12loop")); + + &set_label("12break"); + &mov (&DWP(72,"edi"),12); # setup number of rounds + &xor ("eax","eax"); + &jmp (&label("exit")); + + &set_label("14rounds"); + &mov ("eax",&DWP(0,"esi")); # copy first 8 dwords + &mov ("ebx",&DWP(4,"esi")); + &mov ("ecx",&DWP(8,"esi")); + &mov ("edx",&DWP(12,"esi")); + &mov (&DWP(0,"edi"),"eax"); + &mov (&DWP(4,"edi"),"ebx"); + &mov (&DWP(8,"edi"),"ecx"); + &mov (&DWP(12,"edi"),"edx"); + &mov ("eax",&DWP(16,"esi")); + &mov ("ebx",&DWP(20,"esi")); + &mov ("ecx",&DWP(24,"esi")); + &mov ("edx",&DWP(28,"esi")); + &mov (&DWP(16,"edi"),"eax"); + &mov (&DWP(20,"edi"),"ebx"); + &mov (&DWP(24,"edi"),"ecx"); + &mov (&DWP(28,"edi"),"edx"); + + &xor ("ecx","ecx"); + &jmp (&label("14shortcut")); + + &align (4); + &set_label("14loop"); + &mov ("edx",&DWP(28,"edi")); # rk[7] + &set_label("14shortcut"); + &mov ("eax",&DWP(0,"edi")); # rk[0] + + &enckey (); + + &mov (&DWP(32,"edi"),"eax"); # rk[8] + &xor ("eax",&DWP(4,"edi")); + &mov (&DWP(36,"edi"),"eax"); # rk[9] + &xor ("eax",&DWP(8,"edi")); + &mov (&DWP(40,"edi"),"eax"); # rk[10] + &xor ("eax",&DWP(12,"edi")); + &mov (&DWP(44,"edi"),"eax"); # rk[11] + + &cmp ("ecx",6); + &je (&label("14break")); + &inc ("ecx"); + + &mov ("edx","eax"); + &mov ("eax",&DWP(16,"edi")); # rk[4] + &movz ("esi",&LB("edx")); # rk[11]>>0 + &movz ("ebx",&BP(-128,$tbl,"esi",1)); + &movz ("esi",&HB("edx")); # rk[11]>>8 + &xor ("eax","ebx"); + + &movz ("ebx",&BP(-128,$tbl,"esi",1)); + &shr ("edx",16); + &shl ("ebx",8); + &movz ("esi",&LB("edx")); # rk[11]>>16 + &xor ("eax","ebx"); + + &movz ("ebx",&BP(-128,$tbl,"esi",1)); + &movz ("esi",&HB("edx")); # rk[11]>>24 + &shl ("ebx",16); + &xor ("eax","ebx"); + + &movz ("ebx",&BP(-128,$tbl,"esi",1)); + &shl ("ebx",24); + &xor ("eax","ebx"); + + &mov (&DWP(48,"edi"),"eax"); # rk[12] + &xor ("eax",&DWP(20,"edi")); + &mov (&DWP(52,"edi"),"eax"); # rk[13] + &xor ("eax",&DWP(24,"edi")); + &mov (&DWP(56,"edi"),"eax"); # rk[14] + &xor ("eax",&DWP(28,"edi")); + &mov (&DWP(60,"edi"),"eax"); # rk[15] + + &add ("edi",32); + &jmp (&label("14loop")); + + &set_label("14break"); + &mov (&DWP(48,"edi"),14); # setup number of rounds + &xor ("eax","eax"); + &jmp (&label("exit")); + + &set_label("badpointer"); + &mov ("eax",-1); + &set_label("exit"); +&function_end("_x86_AES_set_encrypt_key"); + +# int asm_AES_set_encrypt_key(const unsigned char *userKey, const int bits, +# AES_KEY *key) +&function_begin_B("asm_AES_set_encrypt_key"); + &call ("_x86_AES_set_encrypt_key"); + &ret (); +&function_end_B("asm_AES_set_encrypt_key"); + +sub deckey() +{ my ($i,$key,$tp1,$tp2,$tp4,$tp8) = @_; + my $tmp = $tbl; + + &mov ($tmp,0x80808080); + &and ($tmp,$tp1); + &lea ($tp2,&DWP(0,$tp1,$tp1)); + &mov ($acc,$tmp); + &shr ($tmp,7); + &sub ($acc,$tmp); + &and ($tp2,0xfefefefe); + &and ($acc,0x1b1b1b1b); + &xor ($tp2,$acc); + &mov ($tmp,0x80808080); + + &and ($tmp,$tp2); + &lea ($tp4,&DWP(0,$tp2,$tp2)); + &mov ($acc,$tmp); + &shr ($tmp,7); + &sub ($acc,$tmp); + &and ($tp4,0xfefefefe); + &and ($acc,0x1b1b1b1b); + &xor ($tp2,$tp1); # tp2^tp1 + &xor ($tp4,$acc); + &mov ($tmp,0x80808080); + + &and ($tmp,$tp4); + &lea ($tp8,&DWP(0,$tp4,$tp4)); + &mov ($acc,$tmp); + &shr ($tmp,7); + &xor ($tp4,$tp1); # tp4^tp1 + &sub ($acc,$tmp); + &and ($tp8,0xfefefefe); + &and ($acc,0x1b1b1b1b); + &rotl ($tp1,8); # = ROTATE(tp1,8) + &xor ($tp8,$acc); + + &mov ($tmp,&DWP(4*($i+1),$key)); # modulo-scheduled load + + &xor ($tp1,$tp2); + &xor ($tp2,$tp8); + &xor ($tp1,$tp4); + &rotl ($tp2,24); + &xor ($tp4,$tp8); + &xor ($tp1,$tp8); # ^= tp8^(tp4^tp1)^(tp2^tp1) + &rotl ($tp4,16); + &xor ($tp1,$tp2); # ^= ROTATE(tp8^tp2^tp1,24) + &rotl ($tp8,8); + &xor ($tp1,$tp4); # ^= ROTATE(tp8^tp4^tp1,16) + &mov ($tp2,$tmp); + &xor ($tp1,$tp8); # ^= ROTATE(tp8,8) + + &mov (&DWP(4*$i,$key),$tp1); +} + +# int asm_AES_set_decrypt_key(const unsigned char *userKey, const int bits, +# AES_KEY *key) +&function_begin_B("asm_AES_set_decrypt_key"); + &call ("_x86_AES_set_encrypt_key"); + &cmp ("eax",0); + &je (&label("proceed")); + &ret (); + + &set_label("proceed"); + &push ("ebp"); + &push ("ebx"); + &push ("esi"); + &push ("edi"); + + &mov ("esi",&wparam(2)); + &mov ("ecx",&DWP(240,"esi")); # pull number of rounds + &lea ("ecx",&DWP(0,"","ecx",4)); + &lea ("edi",&DWP(0,"esi","ecx",4)); # pointer to last chunk + + &set_label("invert",4); # invert order of chunks + &mov ("eax",&DWP(0,"esi")); + &mov ("ebx",&DWP(4,"esi")); + &mov ("ecx",&DWP(0,"edi")); + &mov ("edx",&DWP(4,"edi")); + &mov (&DWP(0,"edi"),"eax"); + &mov (&DWP(4,"edi"),"ebx"); + &mov (&DWP(0,"esi"),"ecx"); + &mov (&DWP(4,"esi"),"edx"); + &mov ("eax",&DWP(8,"esi")); + &mov ("ebx",&DWP(12,"esi")); + &mov ("ecx",&DWP(8,"edi")); + &mov ("edx",&DWP(12,"edi")); + &mov (&DWP(8,"edi"),"eax"); + &mov (&DWP(12,"edi"),"ebx"); + &mov (&DWP(8,"esi"),"ecx"); + &mov (&DWP(12,"esi"),"edx"); + &add ("esi",16); + &sub ("edi",16); + &cmp ("esi","edi"); + &jne (&label("invert")); + + &mov ($key,&wparam(2)); + &mov ($acc,&DWP(240,$key)); # pull number of rounds + &lea ($acc,&DWP(-2,$acc,$acc)); + &lea ($acc,&DWP(0,$key,$acc,8)); + &mov (&wparam(2),$acc); + + &mov ($s0,&DWP(16,$key)); # modulo-scheduled load + &set_label("permute",4); # permute the key schedule + &add ($key,16); + &deckey (0,$key,$s0,$s1,$s2,$s3); + &deckey (1,$key,$s1,$s2,$s3,$s0); + &deckey (2,$key,$s2,$s3,$s0,$s1); + &deckey (3,$key,$s3,$s0,$s1,$s2); + &cmp ($key,&wparam(2)); + &jb (&label("permute")); + + &xor ("eax","eax"); # return success +&function_end("asm_AES_set_decrypt_key"); +&asciz("AES for x86, CRYPTOGAMS by "); + +&asm_finish(); diff --git a/TMessagesProj/jni/boringssl/crypto/aes/asm/aes-armv4.pl b/TMessagesProj/jni/boringssl/crypto/aes/asm/aes-armv4.pl new file mode 100644 index 00000000..36cd3b6d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/aes/asm/aes-armv4.pl @@ -0,0 +1,1249 @@ +#!/usr/bin/env perl + +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== + +# AES for ARMv4 + +# January 2007. +# +# Code uses single 1K S-box and is >2 times faster than code generated +# by gcc-3.4.1. This is thanks to unique feature of ARMv4 ISA, which +# allows to merge logical or arithmetic operation with shift or rotate +# in one instruction and emit combined result every cycle. The module +# is endian-neutral. The performance is ~42 cycles/byte for 128-bit +# key [on single-issue Xscale PXA250 core]. + +# May 2007. +# +# AES_set_[en|de]crypt_key is added. + +# July 2010. +# +# Rescheduling for dual-issue pipeline resulted in 12% improvement on +# Cortex A8 core and ~25 cycles per byte processed with 128-bit key. + +# February 2011. +# +# Profiler-assisted and platform-specific optimization resulted in 16% +# improvement on Cortex A8 core and ~21.5 cycles per byte. + +$flavour = shift; +if ($flavour=~/^\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; } +else { while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {} } + +if ($flavour && $flavour ne "void") { + $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; + ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or + ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or + die "can't locate arm-xlate.pl"; + + open STDOUT,"| \"$^X\" $xlate $flavour $output"; +} else { + open STDOUT,">$output"; +} + +$s0="r0"; +$s1="r1"; +$s2="r2"; +$s3="r3"; +$t1="r4"; +$t2="r5"; +$t3="r6"; +$i1="r7"; +$i2="r8"; +$i3="r9"; + +$tbl="r10"; +$key="r11"; +$rounds="r12"; + +$code=<<___; +#if defined(__arm__) +#ifndef __KERNEL__ +# include "arm_arch.h" +#else +# define __ARM_ARCH__ __LINUX_ARM_ARCH__ +#endif + +.text +#if __ARM_ARCH__<7 +.code 32 +#else +.syntax unified +# if defined(__thumb2__) && !defined(__APPLE__) +.thumb +# else +.code 32 +# endif +#endif + +.type AES_Te,%object +.align 5 +AES_Te: +.word 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d +.word 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554 +.word 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d +.word 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a +.word 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87 +.word 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b +.word 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea +.word 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b +.word 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a +.word 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f +.word 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108 +.word 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f +.word 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e +.word 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5 +.word 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d +.word 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f +.word 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e +.word 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb +.word 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce +.word 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497 +.word 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c +.word 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed +.word 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b +.word 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a +.word 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16 +.word 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594 +.word 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81 +.word 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3 +.word 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a +.word 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504 +.word 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163 +.word 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d +.word 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f +.word 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739 +.word 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47 +.word 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395 +.word 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f +.word 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883 +.word 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c +.word 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76 +.word 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e +.word 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4 +.word 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6 +.word 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b +.word 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7 +.word 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0 +.word 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25 +.word 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818 +.word 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72 +.word 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651 +.word 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21 +.word 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85 +.word 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa +.word 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12 +.word 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0 +.word 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9 +.word 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133 +.word 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7 +.word 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920 +.word 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a +.word 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17 +.word 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8 +.word 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11 +.word 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a +@ Te4[256] +.byte 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5 +.byte 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76 +.byte 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0 +.byte 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0 +.byte 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc +.byte 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15 +.byte 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a +.byte 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75 +.byte 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0 +.byte 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84 +.byte 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b +.byte 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf +.byte 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85 +.byte 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8 +.byte 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5 +.byte 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2 +.byte 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17 +.byte 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73 +.byte 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88 +.byte 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb +.byte 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c +.byte 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79 +.byte 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9 +.byte 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08 +.byte 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6 +.byte 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a +.byte 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e +.byte 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e +.byte 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94 +.byte 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf +.byte 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68 +.byte 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 +@ rcon[] +.word 0x01000000, 0x02000000, 0x04000000, 0x08000000 +.word 0x10000000, 0x20000000, 0x40000000, 0x80000000 +.word 0x1B000000, 0x36000000, 0, 0, 0, 0, 0, 0 +.size AES_Te,.-AES_Te + +@ void asm_AES_encrypt(const unsigned char *in, unsigned char *out, +@ const AES_KEY *key) { +.global asm_AES_encrypt +.hidden asm_AES_encrypt +.type asm_AES_encrypt,%function +.align 5 +asm_AES_encrypt: +#if __ARM_ARCH__<7 + sub r3,pc,#8 @ asm_AES_encrypt +#else + adr r3,asm_AES_encrypt +#endif + stmdb sp!,{r1,r4-r12,lr} +#ifdef __APPLE__ + adr $tbl,AES_Te +#else + sub $tbl,r3,#asm_AES_encrypt-AES_Te @ Te +#endif + mov $rounds,r0 @ inp + mov $key,r2 +#if __ARM_ARCH__<7 + ldrb $s0,[$rounds,#3] @ load input data in endian-neutral + ldrb $t1,[$rounds,#2] @ manner... + ldrb $t2,[$rounds,#1] + ldrb $t3,[$rounds,#0] + orr $s0,$s0,$t1,lsl#8 + ldrb $s1,[$rounds,#7] + orr $s0,$s0,$t2,lsl#16 + ldrb $t1,[$rounds,#6] + orr $s0,$s0,$t3,lsl#24 + ldrb $t2,[$rounds,#5] + ldrb $t3,[$rounds,#4] + orr $s1,$s1,$t1,lsl#8 + ldrb $s2,[$rounds,#11] + orr $s1,$s1,$t2,lsl#16 + ldrb $t1,[$rounds,#10] + orr $s1,$s1,$t3,lsl#24 + ldrb $t2,[$rounds,#9] + ldrb $t3,[$rounds,#8] + orr $s2,$s2,$t1,lsl#8 + ldrb $s3,[$rounds,#15] + orr $s2,$s2,$t2,lsl#16 + ldrb $t1,[$rounds,#14] + orr $s2,$s2,$t3,lsl#24 + ldrb $t2,[$rounds,#13] + ldrb $t3,[$rounds,#12] + orr $s3,$s3,$t1,lsl#8 + orr $s3,$s3,$t2,lsl#16 + orr $s3,$s3,$t3,lsl#24 +#else + ldr $s0,[$rounds,#0] + ldr $s1,[$rounds,#4] + ldr $s2,[$rounds,#8] + ldr $s3,[$rounds,#12] +#ifdef __ARMEL__ + rev $s0,$s0 + rev $s1,$s1 + rev $s2,$s2 + rev $s3,$s3 +#endif +#endif + bl _armv4_AES_encrypt + + ldr $rounds,[sp],#4 @ pop out +#if __ARM_ARCH__>=7 +#ifdef __ARMEL__ + rev $s0,$s0 + rev $s1,$s1 + rev $s2,$s2 + rev $s3,$s3 +#endif + str $s0,[$rounds,#0] + str $s1,[$rounds,#4] + str $s2,[$rounds,#8] + str $s3,[$rounds,#12] +#else + mov $t1,$s0,lsr#24 @ write output in endian-neutral + mov $t2,$s0,lsr#16 @ manner... + mov $t3,$s0,lsr#8 + strb $t1,[$rounds,#0] + strb $t2,[$rounds,#1] + mov $t1,$s1,lsr#24 + strb $t3,[$rounds,#2] + mov $t2,$s1,lsr#16 + strb $s0,[$rounds,#3] + mov $t3,$s1,lsr#8 + strb $t1,[$rounds,#4] + strb $t2,[$rounds,#5] + mov $t1,$s2,lsr#24 + strb $t3,[$rounds,#6] + mov $t2,$s2,lsr#16 + strb $s1,[$rounds,#7] + mov $t3,$s2,lsr#8 + strb $t1,[$rounds,#8] + strb $t2,[$rounds,#9] + mov $t1,$s3,lsr#24 + strb $t3,[$rounds,#10] + mov $t2,$s3,lsr#16 + strb $s2,[$rounds,#11] + mov $t3,$s3,lsr#8 + strb $t1,[$rounds,#12] + strb $t2,[$rounds,#13] + strb $t3,[$rounds,#14] + strb $s3,[$rounds,#15] +#endif +#if __ARM_ARCH__>=5 + ldmia sp!,{r4-r12,pc} +#else + ldmia sp!,{r4-r12,lr} + tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet + bx lr @ interoperable with Thumb ISA:-) +#endif +.size asm_AES_encrypt,.-asm_AES_encrypt + +.type _armv4_AES_encrypt,%function +.align 2 +_armv4_AES_encrypt: + str lr,[sp,#-4]! @ push lr + ldmia $key!,{$t1-$i1} + eor $s0,$s0,$t1 + ldr $rounds,[$key,#240-16] + eor $s1,$s1,$t2 + eor $s2,$s2,$t3 + eor $s3,$s3,$i1 + sub $rounds,$rounds,#1 + mov lr,#255 + + and $i1,lr,$s0 + and $i2,lr,$s0,lsr#8 + and $i3,lr,$s0,lsr#16 + mov $s0,$s0,lsr#24 +.Lenc_loop: + ldr $t1,[$tbl,$i1,lsl#2] @ Te3[s0>>0] + and $i1,lr,$s1,lsr#16 @ i0 + ldr $t2,[$tbl,$i2,lsl#2] @ Te2[s0>>8] + and $i2,lr,$s1 + ldr $t3,[$tbl,$i3,lsl#2] @ Te1[s0>>16] + and $i3,lr,$s1,lsr#8 + ldr $s0,[$tbl,$s0,lsl#2] @ Te0[s0>>24] + mov $s1,$s1,lsr#24 + + ldr $i1,[$tbl,$i1,lsl#2] @ Te1[s1>>16] + ldr $i2,[$tbl,$i2,lsl#2] @ Te3[s1>>0] + ldr $i3,[$tbl,$i3,lsl#2] @ Te2[s1>>8] + eor $s0,$s0,$i1,ror#8 + ldr $s1,[$tbl,$s1,lsl#2] @ Te0[s1>>24] + and $i1,lr,$s2,lsr#8 @ i0 + eor $t2,$t2,$i2,ror#8 + and $i2,lr,$s2,lsr#16 @ i1 + eor $t3,$t3,$i3,ror#8 + and $i3,lr,$s2 + ldr $i1,[$tbl,$i1,lsl#2] @ Te2[s2>>8] + eor $s1,$s1,$t1,ror#24 + ldr $i2,[$tbl,$i2,lsl#2] @ Te1[s2>>16] + mov $s2,$s2,lsr#24 + + ldr $i3,[$tbl,$i3,lsl#2] @ Te3[s2>>0] + eor $s0,$s0,$i1,ror#16 + ldr $s2,[$tbl,$s2,lsl#2] @ Te0[s2>>24] + and $i1,lr,$s3 @ i0 + eor $s1,$s1,$i2,ror#8 + and $i2,lr,$s3,lsr#8 @ i1 + eor $t3,$t3,$i3,ror#16 + and $i3,lr,$s3,lsr#16 @ i2 + ldr $i1,[$tbl,$i1,lsl#2] @ Te3[s3>>0] + eor $s2,$s2,$t2,ror#16 + ldr $i2,[$tbl,$i2,lsl#2] @ Te2[s3>>8] + mov $s3,$s3,lsr#24 + + ldr $i3,[$tbl,$i3,lsl#2] @ Te1[s3>>16] + eor $s0,$s0,$i1,ror#24 + ldr $i1,[$key],#16 + eor $s1,$s1,$i2,ror#16 + ldr $s3,[$tbl,$s3,lsl#2] @ Te0[s3>>24] + eor $s2,$s2,$i3,ror#8 + ldr $t1,[$key,#-12] + eor $s3,$s3,$t3,ror#8 + + ldr $t2,[$key,#-8] + eor $s0,$s0,$i1 + ldr $t3,[$key,#-4] + and $i1,lr,$s0 + eor $s1,$s1,$t1 + and $i2,lr,$s0,lsr#8 + eor $s2,$s2,$t2 + and $i3,lr,$s0,lsr#16 + eor $s3,$s3,$t3 + mov $s0,$s0,lsr#24 + + subs $rounds,$rounds,#1 + bne .Lenc_loop + + add $tbl,$tbl,#2 + + ldrb $t1,[$tbl,$i1,lsl#2] @ Te4[s0>>0] + and $i1,lr,$s1,lsr#16 @ i0 + ldrb $t2,[$tbl,$i2,lsl#2] @ Te4[s0>>8] + and $i2,lr,$s1 + ldrb $t3,[$tbl,$i3,lsl#2] @ Te4[s0>>16] + and $i3,lr,$s1,lsr#8 + ldrb $s0,[$tbl,$s0,lsl#2] @ Te4[s0>>24] + mov $s1,$s1,lsr#24 + + ldrb $i1,[$tbl,$i1,lsl#2] @ Te4[s1>>16] + ldrb $i2,[$tbl,$i2,lsl#2] @ Te4[s1>>0] + ldrb $i3,[$tbl,$i3,lsl#2] @ Te4[s1>>8] + eor $s0,$i1,$s0,lsl#8 + ldrb $s1,[$tbl,$s1,lsl#2] @ Te4[s1>>24] + and $i1,lr,$s2,lsr#8 @ i0 + eor $t2,$i2,$t2,lsl#8 + and $i2,lr,$s2,lsr#16 @ i1 + eor $t3,$i3,$t3,lsl#8 + and $i3,lr,$s2 + ldrb $i1,[$tbl,$i1,lsl#2] @ Te4[s2>>8] + eor $s1,$t1,$s1,lsl#24 + ldrb $i2,[$tbl,$i2,lsl#2] @ Te4[s2>>16] + mov $s2,$s2,lsr#24 + + ldrb $i3,[$tbl,$i3,lsl#2] @ Te4[s2>>0] + eor $s0,$i1,$s0,lsl#8 + ldrb $s2,[$tbl,$s2,lsl#2] @ Te4[s2>>24] + and $i1,lr,$s3 @ i0 + eor $s1,$s1,$i2,lsl#16 + and $i2,lr,$s3,lsr#8 @ i1 + eor $t3,$i3,$t3,lsl#8 + and $i3,lr,$s3,lsr#16 @ i2 + ldrb $i1,[$tbl,$i1,lsl#2] @ Te4[s3>>0] + eor $s2,$t2,$s2,lsl#24 + ldrb $i2,[$tbl,$i2,lsl#2] @ Te4[s3>>8] + mov $s3,$s3,lsr#24 + + ldrb $i3,[$tbl,$i3,lsl#2] @ Te4[s3>>16] + eor $s0,$i1,$s0,lsl#8 + ldr $i1,[$key,#0] + ldrb $s3,[$tbl,$s3,lsl#2] @ Te4[s3>>24] + eor $s1,$s1,$i2,lsl#8 + ldr $t1,[$key,#4] + eor $s2,$s2,$i3,lsl#16 + ldr $t2,[$key,#8] + eor $s3,$t3,$s3,lsl#24 + ldr $t3,[$key,#12] + + eor $s0,$s0,$i1 + eor $s1,$s1,$t1 + eor $s2,$s2,$t2 + eor $s3,$s3,$t3 + + sub $tbl,$tbl,#2 + ldr pc,[sp],#4 @ pop and return +.size _armv4_AES_encrypt,.-_armv4_AES_encrypt + +.global asm_AES_set_encrypt_key +.hidden asm_AES_set_encrypt_key +.type asm_AES_set_encrypt_key,%function +.align 5 +asm_AES_set_encrypt_key: +_armv4_AES_set_encrypt_key: +#if __ARM_ARCH__<7 + sub r3,pc,#8 @ asm_AES_set_encrypt_key +#else + adr r3,asm_AES_set_encrypt_key +#endif + teq r0,#0 +#if __ARM_ARCH__>=7 + itt eq @ Thumb2 thing, sanity check in ARM +#endif + moveq r0,#-1 + beq .Labrt + teq r2,#0 +#if __ARM_ARCH__>=7 + itt eq @ Thumb2 thing, sanity check in ARM +#endif + moveq r0,#-1 + beq .Labrt + + teq r1,#128 + beq .Lok + teq r1,#192 + beq .Lok + teq r1,#256 +#if __ARM_ARCH__>=7 + itt ne @ Thumb2 thing, sanity check in ARM +#endif + movne r0,#-1 + bne .Labrt + +.Lok: stmdb sp!,{r4-r12,lr} + mov $rounds,r0 @ inp + mov lr,r1 @ bits + mov $key,r2 @ key + +#ifdef __APPLE__ + adr $tbl,AES_Te+1024 @ Te4 +#else + sub $tbl,r3,#_armv4_AES_set_encrypt_key-AES_Te-1024 @ Te4 +#endif + +#if __ARM_ARCH__<7 + ldrb $s0,[$rounds,#3] @ load input data in endian-neutral + ldrb $t1,[$rounds,#2] @ manner... + ldrb $t2,[$rounds,#1] + ldrb $t3,[$rounds,#0] + orr $s0,$s0,$t1,lsl#8 + ldrb $s1,[$rounds,#7] + orr $s0,$s0,$t2,lsl#16 + ldrb $t1,[$rounds,#6] + orr $s0,$s0,$t3,lsl#24 + ldrb $t2,[$rounds,#5] + ldrb $t3,[$rounds,#4] + orr $s1,$s1,$t1,lsl#8 + ldrb $s2,[$rounds,#11] + orr $s1,$s1,$t2,lsl#16 + ldrb $t1,[$rounds,#10] + orr $s1,$s1,$t3,lsl#24 + ldrb $t2,[$rounds,#9] + ldrb $t3,[$rounds,#8] + orr $s2,$s2,$t1,lsl#8 + ldrb $s3,[$rounds,#15] + orr $s2,$s2,$t2,lsl#16 + ldrb $t1,[$rounds,#14] + orr $s2,$s2,$t3,lsl#24 + ldrb $t2,[$rounds,#13] + ldrb $t3,[$rounds,#12] + orr $s3,$s3,$t1,lsl#8 + str $s0,[$key],#16 + orr $s3,$s3,$t2,lsl#16 + str $s1,[$key,#-12] + orr $s3,$s3,$t3,lsl#24 + str $s2,[$key,#-8] + str $s3,[$key,#-4] +#else + ldr $s0,[$rounds,#0] + ldr $s1,[$rounds,#4] + ldr $s2,[$rounds,#8] + ldr $s3,[$rounds,#12] +#ifdef __ARMEL__ + rev $s0,$s0 + rev $s1,$s1 + rev $s2,$s2 + rev $s3,$s3 +#endif + str $s0,[$key],#16 + str $s1,[$key,#-12] + str $s2,[$key,#-8] + str $s3,[$key,#-4] +#endif + + teq lr,#128 + bne .Lnot128 + mov $rounds,#10 + str $rounds,[$key,#240-16] + add $t3,$tbl,#256 @ rcon + mov lr,#255 + +.L128_loop: + and $t2,lr,$s3,lsr#24 + and $i1,lr,$s3,lsr#16 + ldrb $t2,[$tbl,$t2] + and $i2,lr,$s3,lsr#8 + ldrb $i1,[$tbl,$i1] + and $i3,lr,$s3 + ldrb $i2,[$tbl,$i2] + orr $t2,$t2,$i1,lsl#24 + ldrb $i3,[$tbl,$i3] + orr $t2,$t2,$i2,lsl#16 + ldr $t1,[$t3],#4 @ rcon[i++] + orr $t2,$t2,$i3,lsl#8 + eor $t2,$t2,$t1 + eor $s0,$s0,$t2 @ rk[4]=rk[0]^... + eor $s1,$s1,$s0 @ rk[5]=rk[1]^rk[4] + str $s0,[$key],#16 + eor $s2,$s2,$s1 @ rk[6]=rk[2]^rk[5] + str $s1,[$key,#-12] + eor $s3,$s3,$s2 @ rk[7]=rk[3]^rk[6] + str $s2,[$key,#-8] + subs $rounds,$rounds,#1 + str $s3,[$key,#-4] + bne .L128_loop + sub r2,$key,#176 + b .Ldone + +.Lnot128: +#if __ARM_ARCH__<7 + ldrb $i2,[$rounds,#19] + ldrb $t1,[$rounds,#18] + ldrb $t2,[$rounds,#17] + ldrb $t3,[$rounds,#16] + orr $i2,$i2,$t1,lsl#8 + ldrb $i3,[$rounds,#23] + orr $i2,$i2,$t2,lsl#16 + ldrb $t1,[$rounds,#22] + orr $i2,$i2,$t3,lsl#24 + ldrb $t2,[$rounds,#21] + ldrb $t3,[$rounds,#20] + orr $i3,$i3,$t1,lsl#8 + orr $i3,$i3,$t2,lsl#16 + str $i2,[$key],#8 + orr $i3,$i3,$t3,lsl#24 + str $i3,[$key,#-4] +#else + ldr $i2,[$rounds,#16] + ldr $i3,[$rounds,#20] +#ifdef __ARMEL__ + rev $i2,$i2 + rev $i3,$i3 +#endif + str $i2,[$key],#8 + str $i3,[$key,#-4] +#endif + + teq lr,#192 + bne .Lnot192 + mov $rounds,#12 + str $rounds,[$key,#240-24] + add $t3,$tbl,#256 @ rcon + mov lr,#255 + mov $rounds,#8 + +.L192_loop: + and $t2,lr,$i3,lsr#24 + and $i1,lr,$i3,lsr#16 + ldrb $t2,[$tbl,$t2] + and $i2,lr,$i3,lsr#8 + ldrb $i1,[$tbl,$i1] + and $i3,lr,$i3 + ldrb $i2,[$tbl,$i2] + orr $t2,$t2,$i1,lsl#24 + ldrb $i3,[$tbl,$i3] + orr $t2,$t2,$i2,lsl#16 + ldr $t1,[$t3],#4 @ rcon[i++] + orr $t2,$t2,$i3,lsl#8 + eor $i3,$t2,$t1 + eor $s0,$s0,$i3 @ rk[6]=rk[0]^... + eor $s1,$s1,$s0 @ rk[7]=rk[1]^rk[6] + str $s0,[$key],#24 + eor $s2,$s2,$s1 @ rk[8]=rk[2]^rk[7] + str $s1,[$key,#-20] + eor $s3,$s3,$s2 @ rk[9]=rk[3]^rk[8] + str $s2,[$key,#-16] + subs $rounds,$rounds,#1 + str $s3,[$key,#-12] +#if __ARM_ARCH__>=7 + itt eq @ Thumb2 thing, sanity check in ARM +#endif + subeq r2,$key,#216 + beq .Ldone + + ldr $i1,[$key,#-32] + ldr $i2,[$key,#-28] + eor $i1,$i1,$s3 @ rk[10]=rk[4]^rk[9] + eor $i3,$i2,$i1 @ rk[11]=rk[5]^rk[10] + str $i1,[$key,#-8] + str $i3,[$key,#-4] + b .L192_loop + +.Lnot192: +#if __ARM_ARCH__<7 + ldrb $i2,[$rounds,#27] + ldrb $t1,[$rounds,#26] + ldrb $t2,[$rounds,#25] + ldrb $t3,[$rounds,#24] + orr $i2,$i2,$t1,lsl#8 + ldrb $i3,[$rounds,#31] + orr $i2,$i2,$t2,lsl#16 + ldrb $t1,[$rounds,#30] + orr $i2,$i2,$t3,lsl#24 + ldrb $t2,[$rounds,#29] + ldrb $t3,[$rounds,#28] + orr $i3,$i3,$t1,lsl#8 + orr $i3,$i3,$t2,lsl#16 + str $i2,[$key],#8 + orr $i3,$i3,$t3,lsl#24 + str $i3,[$key,#-4] +#else + ldr $i2,[$rounds,#24] + ldr $i3,[$rounds,#28] +#ifdef __ARMEL__ + rev $i2,$i2 + rev $i3,$i3 +#endif + str $i2,[$key],#8 + str $i3,[$key,#-4] +#endif + + mov $rounds,#14 + str $rounds,[$key,#240-32] + add $t3,$tbl,#256 @ rcon + mov lr,#255 + mov $rounds,#7 + +.L256_loop: + and $t2,lr,$i3,lsr#24 + and $i1,lr,$i3,lsr#16 + ldrb $t2,[$tbl,$t2] + and $i2,lr,$i3,lsr#8 + ldrb $i1,[$tbl,$i1] + and $i3,lr,$i3 + ldrb $i2,[$tbl,$i2] + orr $t2,$t2,$i1,lsl#24 + ldrb $i3,[$tbl,$i3] + orr $t2,$t2,$i2,lsl#16 + ldr $t1,[$t3],#4 @ rcon[i++] + orr $t2,$t2,$i3,lsl#8 + eor $i3,$t2,$t1 + eor $s0,$s0,$i3 @ rk[8]=rk[0]^... + eor $s1,$s1,$s0 @ rk[9]=rk[1]^rk[8] + str $s0,[$key],#32 + eor $s2,$s2,$s1 @ rk[10]=rk[2]^rk[9] + str $s1,[$key,#-28] + eor $s3,$s3,$s2 @ rk[11]=rk[3]^rk[10] + str $s2,[$key,#-24] + subs $rounds,$rounds,#1 + str $s3,[$key,#-20] +#if __ARM_ARCH__>=7 + itt eq @ Thumb2 thing, sanity check in ARM +#endif + subeq r2,$key,#256 + beq .Ldone + + and $t2,lr,$s3 + and $i1,lr,$s3,lsr#8 + ldrb $t2,[$tbl,$t2] + and $i2,lr,$s3,lsr#16 + ldrb $i1,[$tbl,$i1] + and $i3,lr,$s3,lsr#24 + ldrb $i2,[$tbl,$i2] + orr $t2,$t2,$i1,lsl#8 + ldrb $i3,[$tbl,$i3] + orr $t2,$t2,$i2,lsl#16 + ldr $t1,[$key,#-48] + orr $t2,$t2,$i3,lsl#24 + + ldr $i1,[$key,#-44] + ldr $i2,[$key,#-40] + eor $t1,$t1,$t2 @ rk[12]=rk[4]^... + ldr $i3,[$key,#-36] + eor $i1,$i1,$t1 @ rk[13]=rk[5]^rk[12] + str $t1,[$key,#-16] + eor $i2,$i2,$i1 @ rk[14]=rk[6]^rk[13] + str $i1,[$key,#-12] + eor $i3,$i3,$i2 @ rk[15]=rk[7]^rk[14] + str $i2,[$key,#-8] + str $i3,[$key,#-4] + b .L256_loop + +.align 2 +.Ldone: mov r0,#0 + ldmia sp!,{r4-r12,lr} +.Labrt: +#if __ARM_ARCH__>=5 + ret @ bx lr +#else + tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet + bx lr @ interoperable with Thumb ISA:-) +#endif +.size asm_AES_set_encrypt_key,.-asm_AES_set_encrypt_key + +.global asm_AES_set_decrypt_key +.hidden asm_AES_set_decrypt_key +.type asm_AES_set_decrypt_key,%function +.align 5 +asm_AES_set_decrypt_key: + str lr,[sp,#-4]! @ push lr + bl _armv4_AES_set_encrypt_key + teq r0,#0 + ldr lr,[sp],#4 @ pop lr + bne .Labrt + + mov r0,r2 @ asm_AES_set_encrypt_key preserves r2, + mov r1,r2 @ which is AES_KEY *key + b _armv4_AES_set_enc2dec_key +.size asm_AES_set_decrypt_key,.-asm_AES_set_decrypt_key + +@ void AES_set_enc2dec_key(const AES_KEY *inp,AES_KEY *out) +.global AES_set_enc2dec_key +.hidden AES_set_enc2dec_key +.type AES_set_enc2dec_key,%function +.align 5 +AES_set_enc2dec_key: +_armv4_AES_set_enc2dec_key: + stmdb sp!,{r4-r12,lr} + + ldr $rounds,[r0,#240] + mov $i1,r0 @ input + add $i2,r0,$rounds,lsl#4 + mov $key,r1 @ ouput + add $tbl,r1,$rounds,lsl#4 + str $rounds,[r1,#240] + +.Linv: ldr $s0,[$i1],#16 + ldr $s1,[$i1,#-12] + ldr $s2,[$i1,#-8] + ldr $s3,[$i1,#-4] + ldr $t1,[$i2],#-16 + ldr $t2,[$i2,#16+4] + ldr $t3,[$i2,#16+8] + ldr $i3,[$i2,#16+12] + str $s0,[$tbl],#-16 + str $s1,[$tbl,#16+4] + str $s2,[$tbl,#16+8] + str $s3,[$tbl,#16+12] + str $t1,[$key],#16 + str $t2,[$key,#-12] + str $t3,[$key,#-8] + str $i3,[$key,#-4] + teq $i1,$i2 + bne .Linv + + ldr $s0,[$i1] + ldr $s1,[$i1,#4] + ldr $s2,[$i1,#8] + ldr $s3,[$i1,#12] + str $s0,[$key] + str $s1,[$key,#4] + str $s2,[$key,#8] + str $s3,[$key,#12] + sub $key,$key,$rounds,lsl#3 +___ +$mask80=$i1; +$mask1b=$i2; +$mask7f=$i3; +$code.=<<___; + ldr $s0,[$key,#16]! @ prefetch tp1 + mov $mask80,#0x80 + mov $mask1b,#0x1b + orr $mask80,$mask80,#0x8000 + orr $mask1b,$mask1b,#0x1b00 + orr $mask80,$mask80,$mask80,lsl#16 + orr $mask1b,$mask1b,$mask1b,lsl#16 + sub $rounds,$rounds,#1 + mvn $mask7f,$mask80 + mov $rounds,$rounds,lsl#2 @ (rounds-1)*4 + +.Lmix: and $t1,$s0,$mask80 + and $s1,$s0,$mask7f + sub $t1,$t1,$t1,lsr#7 + and $t1,$t1,$mask1b + eor $s1,$t1,$s1,lsl#1 @ tp2 + + and $t1,$s1,$mask80 + and $s2,$s1,$mask7f + sub $t1,$t1,$t1,lsr#7 + and $t1,$t1,$mask1b + eor $s2,$t1,$s2,lsl#1 @ tp4 + + and $t1,$s2,$mask80 + and $s3,$s2,$mask7f + sub $t1,$t1,$t1,lsr#7 + and $t1,$t1,$mask1b + eor $s3,$t1,$s3,lsl#1 @ tp8 + + eor $t1,$s1,$s2 + eor $t2,$s0,$s3 @ tp9 + eor $t1,$t1,$s3 @ tpe + eor $t1,$t1,$s1,ror#24 + eor $t1,$t1,$t2,ror#24 @ ^= ROTATE(tpb=tp9^tp2,8) + eor $t1,$t1,$s2,ror#16 + eor $t1,$t1,$t2,ror#16 @ ^= ROTATE(tpd=tp9^tp4,16) + eor $t1,$t1,$t2,ror#8 @ ^= ROTATE(tp9,24) + + ldr $s0,[$key,#4] @ prefetch tp1 + str $t1,[$key],#4 + subs $rounds,$rounds,#1 + bne .Lmix + + mov r0,#0 +#if __ARM_ARCH__>=5 + ldmia sp!,{r4-r12,pc} +#else + ldmia sp!,{r4-r12,lr} + tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet + bx lr @ interoperable with Thumb ISA:-) +#endif +.size AES_set_enc2dec_key,.-AES_set_enc2dec_key + +.type AES_Td,%object +.align 5 +AES_Td: +.word 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96 +.word 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393 +.word 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25 +.word 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f +.word 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1 +.word 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6 +.word 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da +.word 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844 +.word 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd +.word 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4 +.word 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45 +.word 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94 +.word 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7 +.word 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a +.word 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5 +.word 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c +.word 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1 +.word 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a +.word 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75 +.word 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051 +.word 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46 +.word 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff +.word 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77 +.word 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb +.word 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000 +.word 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e +.word 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927 +.word 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a +.word 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e +.word 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16 +.word 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d +.word 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8 +.word 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd +.word 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34 +.word 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163 +.word 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120 +.word 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d +.word 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0 +.word 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422 +.word 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef +.word 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36 +.word 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4 +.word 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662 +.word 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5 +.word 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3 +.word 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b +.word 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8 +.word 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6 +.word 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6 +.word 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0 +.word 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815 +.word 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f +.word 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df +.word 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f +.word 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e +.word 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713 +.word 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89 +.word 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c +.word 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf +.word 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86 +.word 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f +.word 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541 +.word 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190 +.word 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742 +@ Td4[256] +.byte 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38 +.byte 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb +.byte 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87 +.byte 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb +.byte 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d +.byte 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e +.byte 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2 +.byte 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25 +.byte 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16 +.byte 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92 +.byte 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda +.byte 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84 +.byte 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a +.byte 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06 +.byte 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02 +.byte 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b +.byte 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea +.byte 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73 +.byte 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85 +.byte 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e +.byte 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89 +.byte 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b +.byte 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20 +.byte 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4 +.byte 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31 +.byte 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f +.byte 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d +.byte 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef +.byte 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0 +.byte 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61 +.byte 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26 +.byte 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d +.size AES_Td,.-AES_Td + +@ void asm_AES_decrypt(const unsigned char *in, unsigned char *out, +@ const AES_KEY *key) { +.global asm_AES_decrypt +.hidden asm_AES_decrypt +.type asm_AES_decrypt,%function +.align 5 +asm_AES_decrypt: +#if __ARM_ARCH__<7 + sub r3,pc,#8 @ asm_AES_decrypt +#else + adr r3,asm_AES_decrypt +#endif + stmdb sp!,{r1,r4-r12,lr} +#ifdef __APPLE__ + adr $tbl,AES_Td +#else + sub $tbl,r3,#asm_AES_decrypt-AES_Td @ Td +#endif + mov $rounds,r0 @ inp + mov $key,r2 +#if __ARM_ARCH__<7 + ldrb $s0,[$rounds,#3] @ load input data in endian-neutral + ldrb $t1,[$rounds,#2] @ manner... + ldrb $t2,[$rounds,#1] + ldrb $t3,[$rounds,#0] + orr $s0,$s0,$t1,lsl#8 + ldrb $s1,[$rounds,#7] + orr $s0,$s0,$t2,lsl#16 + ldrb $t1,[$rounds,#6] + orr $s0,$s0,$t3,lsl#24 + ldrb $t2,[$rounds,#5] + ldrb $t3,[$rounds,#4] + orr $s1,$s1,$t1,lsl#8 + ldrb $s2,[$rounds,#11] + orr $s1,$s1,$t2,lsl#16 + ldrb $t1,[$rounds,#10] + orr $s1,$s1,$t3,lsl#24 + ldrb $t2,[$rounds,#9] + ldrb $t3,[$rounds,#8] + orr $s2,$s2,$t1,lsl#8 + ldrb $s3,[$rounds,#15] + orr $s2,$s2,$t2,lsl#16 + ldrb $t1,[$rounds,#14] + orr $s2,$s2,$t3,lsl#24 + ldrb $t2,[$rounds,#13] + ldrb $t3,[$rounds,#12] + orr $s3,$s3,$t1,lsl#8 + orr $s3,$s3,$t2,lsl#16 + orr $s3,$s3,$t3,lsl#24 +#else + ldr $s0,[$rounds,#0] + ldr $s1,[$rounds,#4] + ldr $s2,[$rounds,#8] + ldr $s3,[$rounds,#12] +#ifdef __ARMEL__ + rev $s0,$s0 + rev $s1,$s1 + rev $s2,$s2 + rev $s3,$s3 +#endif +#endif + bl _armv4_AES_decrypt + + ldr $rounds,[sp],#4 @ pop out +#if __ARM_ARCH__>=7 +#ifdef __ARMEL__ + rev $s0,$s0 + rev $s1,$s1 + rev $s2,$s2 + rev $s3,$s3 +#endif + str $s0,[$rounds,#0] + str $s1,[$rounds,#4] + str $s2,[$rounds,#8] + str $s3,[$rounds,#12] +#else + mov $t1,$s0,lsr#24 @ write output in endian-neutral + mov $t2,$s0,lsr#16 @ manner... + mov $t3,$s0,lsr#8 + strb $t1,[$rounds,#0] + strb $t2,[$rounds,#1] + mov $t1,$s1,lsr#24 + strb $t3,[$rounds,#2] + mov $t2,$s1,lsr#16 + strb $s0,[$rounds,#3] + mov $t3,$s1,lsr#8 + strb $t1,[$rounds,#4] + strb $t2,[$rounds,#5] + mov $t1,$s2,lsr#24 + strb $t3,[$rounds,#6] + mov $t2,$s2,lsr#16 + strb $s1,[$rounds,#7] + mov $t3,$s2,lsr#8 + strb $t1,[$rounds,#8] + strb $t2,[$rounds,#9] + mov $t1,$s3,lsr#24 + strb $t3,[$rounds,#10] + mov $t2,$s3,lsr#16 + strb $s2,[$rounds,#11] + mov $t3,$s3,lsr#8 + strb $t1,[$rounds,#12] + strb $t2,[$rounds,#13] + strb $t3,[$rounds,#14] + strb $s3,[$rounds,#15] +#endif +#if __ARM_ARCH__>=5 + ldmia sp!,{r4-r12,pc} +#else + ldmia sp!,{r4-r12,lr} + tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet + bx lr @ interoperable with Thumb ISA:-) +#endif +.size asm_AES_decrypt,.-asm_AES_decrypt + +.type _armv4_AES_decrypt,%function +.align 2 +_armv4_AES_decrypt: + str lr,[sp,#-4]! @ push lr + ldmia $key!,{$t1-$i1} + eor $s0,$s0,$t1 + ldr $rounds,[$key,#240-16] + eor $s1,$s1,$t2 + eor $s2,$s2,$t3 + eor $s3,$s3,$i1 + sub $rounds,$rounds,#1 + mov lr,#255 + + and $i1,lr,$s0,lsr#16 + and $i2,lr,$s0,lsr#8 + and $i3,lr,$s0 + mov $s0,$s0,lsr#24 +.Ldec_loop: + ldr $t1,[$tbl,$i1,lsl#2] @ Td1[s0>>16] + and $i1,lr,$s1 @ i0 + ldr $t2,[$tbl,$i2,lsl#2] @ Td2[s0>>8] + and $i2,lr,$s1,lsr#16 + ldr $t3,[$tbl,$i3,lsl#2] @ Td3[s0>>0] + and $i3,lr,$s1,lsr#8 + ldr $s0,[$tbl,$s0,lsl#2] @ Td0[s0>>24] + mov $s1,$s1,lsr#24 + + ldr $i1,[$tbl,$i1,lsl#2] @ Td3[s1>>0] + ldr $i2,[$tbl,$i2,lsl#2] @ Td1[s1>>16] + ldr $i3,[$tbl,$i3,lsl#2] @ Td2[s1>>8] + eor $s0,$s0,$i1,ror#24 + ldr $s1,[$tbl,$s1,lsl#2] @ Td0[s1>>24] + and $i1,lr,$s2,lsr#8 @ i0 + eor $t2,$i2,$t2,ror#8 + and $i2,lr,$s2 @ i1 + eor $t3,$i3,$t3,ror#8 + and $i3,lr,$s2,lsr#16 + ldr $i1,[$tbl,$i1,lsl#2] @ Td2[s2>>8] + eor $s1,$s1,$t1,ror#8 + ldr $i2,[$tbl,$i2,lsl#2] @ Td3[s2>>0] + mov $s2,$s2,lsr#24 + + ldr $i3,[$tbl,$i3,lsl#2] @ Td1[s2>>16] + eor $s0,$s0,$i1,ror#16 + ldr $s2,[$tbl,$s2,lsl#2] @ Td0[s2>>24] + and $i1,lr,$s3,lsr#16 @ i0 + eor $s1,$s1,$i2,ror#24 + and $i2,lr,$s3,lsr#8 @ i1 + eor $t3,$i3,$t3,ror#8 + and $i3,lr,$s3 @ i2 + ldr $i1,[$tbl,$i1,lsl#2] @ Td1[s3>>16] + eor $s2,$s2,$t2,ror#8 + ldr $i2,[$tbl,$i2,lsl#2] @ Td2[s3>>8] + mov $s3,$s3,lsr#24 + + ldr $i3,[$tbl,$i3,lsl#2] @ Td3[s3>>0] + eor $s0,$s0,$i1,ror#8 + ldr $i1,[$key],#16 + eor $s1,$s1,$i2,ror#16 + ldr $s3,[$tbl,$s3,lsl#2] @ Td0[s3>>24] + eor $s2,$s2,$i3,ror#24 + + ldr $t1,[$key,#-12] + eor $s0,$s0,$i1 + ldr $t2,[$key,#-8] + eor $s3,$s3,$t3,ror#8 + ldr $t3,[$key,#-4] + and $i1,lr,$s0,lsr#16 + eor $s1,$s1,$t1 + and $i2,lr,$s0,lsr#8 + eor $s2,$s2,$t2 + and $i3,lr,$s0 + eor $s3,$s3,$t3 + mov $s0,$s0,lsr#24 + + subs $rounds,$rounds,#1 + bne .Ldec_loop + + add $tbl,$tbl,#1024 + + ldr $t2,[$tbl,#0] @ prefetch Td4 + ldr $t3,[$tbl,#32] + ldr $t1,[$tbl,#64] + ldr $t2,[$tbl,#96] + ldr $t3,[$tbl,#128] + ldr $t1,[$tbl,#160] + ldr $t2,[$tbl,#192] + ldr $t3,[$tbl,#224] + + ldrb $s0,[$tbl,$s0] @ Td4[s0>>24] + ldrb $t1,[$tbl,$i1] @ Td4[s0>>16] + and $i1,lr,$s1 @ i0 + ldrb $t2,[$tbl,$i2] @ Td4[s0>>8] + and $i2,lr,$s1,lsr#16 + ldrb $t3,[$tbl,$i3] @ Td4[s0>>0] + and $i3,lr,$s1,lsr#8 + + add $s1,$tbl,$s1,lsr#24 + ldrb $i1,[$tbl,$i1] @ Td4[s1>>0] + ldrb $s1,[$s1] @ Td4[s1>>24] + ldrb $i2,[$tbl,$i2] @ Td4[s1>>16] + eor $s0,$i1,$s0,lsl#24 + ldrb $i3,[$tbl,$i3] @ Td4[s1>>8] + eor $s1,$t1,$s1,lsl#8 + and $i1,lr,$s2,lsr#8 @ i0 + eor $t2,$t2,$i2,lsl#8 + and $i2,lr,$s2 @ i1 + ldrb $i1,[$tbl,$i1] @ Td4[s2>>8] + eor $t3,$t3,$i3,lsl#8 + ldrb $i2,[$tbl,$i2] @ Td4[s2>>0] + and $i3,lr,$s2,lsr#16 + + add $s2,$tbl,$s2,lsr#24 + ldrb $s2,[$s2] @ Td4[s2>>24] + eor $s0,$s0,$i1,lsl#8 + ldrb $i3,[$tbl,$i3] @ Td4[s2>>16] + eor $s1,$i2,$s1,lsl#16 + and $i1,lr,$s3,lsr#16 @ i0 + eor $s2,$t2,$s2,lsl#16 + and $i2,lr,$s3,lsr#8 @ i1 + ldrb $i1,[$tbl,$i1] @ Td4[s3>>16] + eor $t3,$t3,$i3,lsl#16 + ldrb $i2,[$tbl,$i2] @ Td4[s3>>8] + and $i3,lr,$s3 @ i2 + + add $s3,$tbl,$s3,lsr#24 + ldrb $i3,[$tbl,$i3] @ Td4[s3>>0] + ldrb $s3,[$s3] @ Td4[s3>>24] + eor $s0,$s0,$i1,lsl#16 + ldr $i1,[$key,#0] + eor $s1,$s1,$i2,lsl#8 + ldr $t1,[$key,#4] + eor $s2,$i3,$s2,lsl#8 + ldr $t2,[$key,#8] + eor $s3,$t3,$s3,lsl#24 + ldr $t3,[$key,#12] + + eor $s0,$s0,$i1 + eor $s1,$s1,$t1 + eor $s2,$s2,$t2 + eor $s3,$s3,$t3 + + sub $tbl,$tbl,#1024 + ldr pc,[sp],#4 @ pop and return +.size _armv4_AES_decrypt,.-_armv4_AES_decrypt +.asciz "AES for ARMv4, CRYPTOGAMS by " +.align 2 + +#endif +___ + +$code =~ s/\bbx\s+lr\b/.word\t0xe12fff1e/gm; # make it possible to compile with -march=armv4 +$code =~ s/\bret\b/bx\tlr/gm; + +open SELF,$0; +while() { + next if (/^#!/); + last if (!s/^#/@/ and !/^$/); + print; +} +close SELF; + +print $code; +close STDOUT; # enforce flush diff --git a/TMessagesProj/jni/boringssl/crypto/aes/asm/aes-x86_64.pl b/TMessagesProj/jni/boringssl/crypto/aes/asm/aes-x86_64.pl new file mode 100644 index 00000000..4b6e1b44 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/aes/asm/aes-x86_64.pl @@ -0,0 +1,2805 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# Version 2.1. +# +# aes-*-cbc benchmarks are improved by >70% [compared to gcc 3.3.2 on +# Opteron 240 CPU] plus all the bells-n-whistles from 32-bit version +# [you'll notice a lot of resemblance], such as compressed S-boxes +# in little-endian byte order, prefetch of these tables in CBC mode, +# as well as avoiding L1 cache aliasing between stack frame and key +# schedule and already mentioned tables, compressed Td4... +# +# Performance in number of cycles per processed byte for 128-bit key: +# +# ECB encrypt ECB decrypt CBC large chunk +# AMD64 33 43 13.0 +# EM64T 38 56 18.6(*) +# Core 2 30 42 14.5(*) +# Atom 65 86 32.1(*) +# +# (*) with hyper-threading off + +$flavour = shift; +$output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or +die "can't locate x86_64-xlate.pl"; + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +$verticalspin=1; # unlike 32-bit version $verticalspin performs + # ~15% better on both AMD and Intel cores +$speed_limit=512; # see aes-586.pl for details + +$code=".text\n"; + +$s0="%eax"; +$s1="%ebx"; +$s2="%ecx"; +$s3="%edx"; +$acc0="%esi"; $mask80="%rsi"; +$acc1="%edi"; $maskfe="%rdi"; +$acc2="%ebp"; $mask1b="%rbp"; +$inp="%r8"; +$out="%r9"; +$t0="%r10d"; +$t1="%r11d"; +$t2="%r12d"; +$rnds="%r13d"; +$sbox="%r14"; +$key="%r15"; + +sub hi() { my $r=shift; $r =~ s/%[er]([a-d])x/%\1h/; $r; } +sub lo() { my $r=shift; $r =~ s/%[er]([a-d])x/%\1l/; + $r =~ s/%[er]([sd]i)/%\1l/; + $r =~ s/%(r[0-9]+)[d]?/%\1b/; $r; } +sub LO() { my $r=shift; $r =~ s/%r([a-z]+)/%e\1/; + $r =~ s/%r([0-9]+)/%r\1d/; $r; } +sub _data_word() +{ my $i; + while(defined($i=shift)) { $code.=sprintf".long\t0x%08x,0x%08x\n",$i,$i; } +} +sub data_word() +{ my $i; + my $last=pop(@_); + $code.=".long\t"; + while(defined($i=shift)) { $code.=sprintf"0x%08x,",$i; } + $code.=sprintf"0x%08x\n",$last; +} + +sub data_byte() +{ my $i; + my $last=pop(@_); + $code.=".byte\t"; + while(defined($i=shift)) { $code.=sprintf"0x%02x,",$i&0xff; } + $code.=sprintf"0x%02x\n",$last&0xff; +} + +sub encvert() +{ my $t3="%r8d"; # zaps $inp! + +$code.=<<___; + # favor 3-way issue Opteron pipeline... + movzb `&lo("$s0")`,$acc0 + movzb `&lo("$s1")`,$acc1 + movzb `&lo("$s2")`,$acc2 + mov 0($sbox,$acc0,8),$t0 + mov 0($sbox,$acc1,8),$t1 + mov 0($sbox,$acc2,8),$t2 + + movzb `&hi("$s1")`,$acc0 + movzb `&hi("$s2")`,$acc1 + movzb `&lo("$s3")`,$acc2 + xor 3($sbox,$acc0,8),$t0 + xor 3($sbox,$acc1,8),$t1 + mov 0($sbox,$acc2,8),$t3 + + movzb `&hi("$s3")`,$acc0 + shr \$16,$s2 + movzb `&hi("$s0")`,$acc2 + xor 3($sbox,$acc0,8),$t2 + shr \$16,$s3 + xor 3($sbox,$acc2,8),$t3 + + shr \$16,$s1 + lea 16($key),$key + shr \$16,$s0 + + movzb `&lo("$s2")`,$acc0 + movzb `&lo("$s3")`,$acc1 + movzb `&lo("$s0")`,$acc2 + xor 2($sbox,$acc0,8),$t0 + xor 2($sbox,$acc1,8),$t1 + xor 2($sbox,$acc2,8),$t2 + + movzb `&hi("$s3")`,$acc0 + movzb `&hi("$s0")`,$acc1 + movzb `&lo("$s1")`,$acc2 + xor 1($sbox,$acc0,8),$t0 + xor 1($sbox,$acc1,8),$t1 + xor 2($sbox,$acc2,8),$t3 + + mov 12($key),$s3 + movzb `&hi("$s1")`,$acc1 + movzb `&hi("$s2")`,$acc2 + mov 0($key),$s0 + xor 1($sbox,$acc1,8),$t2 + xor 1($sbox,$acc2,8),$t3 + + mov 4($key),$s1 + mov 8($key),$s2 + xor $t0,$s0 + xor $t1,$s1 + xor $t2,$s2 + xor $t3,$s3 +___ +} + +sub enclastvert() +{ my $t3="%r8d"; # zaps $inp! + +$code.=<<___; + movzb `&lo("$s0")`,$acc0 + movzb `&lo("$s1")`,$acc1 + movzb `&lo("$s2")`,$acc2 + movzb 2($sbox,$acc0,8),$t0 + movzb 2($sbox,$acc1,8),$t1 + movzb 2($sbox,$acc2,8),$t2 + + movzb `&lo("$s3")`,$acc0 + movzb `&hi("$s1")`,$acc1 + movzb `&hi("$s2")`,$acc2 + movzb 2($sbox,$acc0,8),$t3 + mov 0($sbox,$acc1,8),$acc1 #$t0 + mov 0($sbox,$acc2,8),$acc2 #$t1 + + and \$0x0000ff00,$acc1 + and \$0x0000ff00,$acc2 + + xor $acc1,$t0 + xor $acc2,$t1 + shr \$16,$s2 + + movzb `&hi("$s3")`,$acc0 + movzb `&hi("$s0")`,$acc1 + shr \$16,$s3 + mov 0($sbox,$acc0,8),$acc0 #$t2 + mov 0($sbox,$acc1,8),$acc1 #$t3 + + and \$0x0000ff00,$acc0 + and \$0x0000ff00,$acc1 + shr \$16,$s1 + xor $acc0,$t2 + xor $acc1,$t3 + shr \$16,$s0 + + movzb `&lo("$s2")`,$acc0 + movzb `&lo("$s3")`,$acc1 + movzb `&lo("$s0")`,$acc2 + mov 0($sbox,$acc0,8),$acc0 #$t0 + mov 0($sbox,$acc1,8),$acc1 #$t1 + mov 0($sbox,$acc2,8),$acc2 #$t2 + + and \$0x00ff0000,$acc0 + and \$0x00ff0000,$acc1 + and \$0x00ff0000,$acc2 + + xor $acc0,$t0 + xor $acc1,$t1 + xor $acc2,$t2 + + movzb `&lo("$s1")`,$acc0 + movzb `&hi("$s3")`,$acc1 + movzb `&hi("$s0")`,$acc2 + mov 0($sbox,$acc0,8),$acc0 #$t3 + mov 2($sbox,$acc1,8),$acc1 #$t0 + mov 2($sbox,$acc2,8),$acc2 #$t1 + + and \$0x00ff0000,$acc0 + and \$0xff000000,$acc1 + and \$0xff000000,$acc2 + + xor $acc0,$t3 + xor $acc1,$t0 + xor $acc2,$t1 + + movzb `&hi("$s1")`,$acc0 + movzb `&hi("$s2")`,$acc1 + mov 16+12($key),$s3 + mov 2($sbox,$acc0,8),$acc0 #$t2 + mov 2($sbox,$acc1,8),$acc1 #$t3 + mov 16+0($key),$s0 + + and \$0xff000000,$acc0 + and \$0xff000000,$acc1 + + xor $acc0,$t2 + xor $acc1,$t3 + + mov 16+4($key),$s1 + mov 16+8($key),$s2 + xor $t0,$s0 + xor $t1,$s1 + xor $t2,$s2 + xor $t3,$s3 +___ +} + +sub encstep() +{ my ($i,@s) = @_; + my $tmp0=$acc0; + my $tmp1=$acc1; + my $tmp2=$acc2; + my $out=($t0,$t1,$t2,$s[0])[$i]; + + if ($i==3) { + $tmp0=$s[1]; + $tmp1=$s[2]; + $tmp2=$s[3]; + } + $code.=" movzb ".&lo($s[0]).",$out\n"; + $code.=" mov $s[2],$tmp1\n" if ($i!=3); + $code.=" lea 16($key),$key\n" if ($i==0); + + $code.=" movzb ".&hi($s[1]).",$tmp0\n"; + $code.=" mov 0($sbox,$out,8),$out\n"; + + $code.=" shr \$16,$tmp1\n"; + $code.=" mov $s[3],$tmp2\n" if ($i!=3); + $code.=" xor 3($sbox,$tmp0,8),$out\n"; + + $code.=" movzb ".&lo($tmp1).",$tmp1\n"; + $code.=" shr \$24,$tmp2\n"; + $code.=" xor 4*$i($key),$out\n"; + + $code.=" xor 2($sbox,$tmp1,8),$out\n"; + $code.=" xor 1($sbox,$tmp2,8),$out\n"; + + $code.=" mov $t0,$s[1]\n" if ($i==3); + $code.=" mov $t1,$s[2]\n" if ($i==3); + $code.=" mov $t2,$s[3]\n" if ($i==3); + $code.="\n"; +} + +sub enclast() +{ my ($i,@s)=@_; + my $tmp0=$acc0; + my $tmp1=$acc1; + my $tmp2=$acc2; + my $out=($t0,$t1,$t2,$s[0])[$i]; + + if ($i==3) { + $tmp0=$s[1]; + $tmp1=$s[2]; + $tmp2=$s[3]; + } + $code.=" movzb ".&lo($s[0]).",$out\n"; + $code.=" mov $s[2],$tmp1\n" if ($i!=3); + + $code.=" mov 2($sbox,$out,8),$out\n"; + $code.=" shr \$16,$tmp1\n"; + $code.=" mov $s[3],$tmp2\n" if ($i!=3); + + $code.=" and \$0x000000ff,$out\n"; + $code.=" movzb ".&hi($s[1]).",$tmp0\n"; + $code.=" movzb ".&lo($tmp1).",$tmp1\n"; + $code.=" shr \$24,$tmp2\n"; + + $code.=" mov 0($sbox,$tmp0,8),$tmp0\n"; + $code.=" mov 0($sbox,$tmp1,8),$tmp1\n"; + $code.=" mov 2($sbox,$tmp2,8),$tmp2\n"; + + $code.=" and \$0x0000ff00,$tmp0\n"; + $code.=" and \$0x00ff0000,$tmp1\n"; + $code.=" and \$0xff000000,$tmp2\n"; + + $code.=" xor $tmp0,$out\n"; + $code.=" mov $t0,$s[1]\n" if ($i==3); + $code.=" xor $tmp1,$out\n"; + $code.=" mov $t1,$s[2]\n" if ($i==3); + $code.=" xor $tmp2,$out\n"; + $code.=" mov $t2,$s[3]\n" if ($i==3); + $code.="\n"; +} + +$code.=<<___; +.type _x86_64_AES_encrypt,\@abi-omnipotent +.align 16 +_x86_64_AES_encrypt: + xor 0($key),$s0 # xor with key + xor 4($key),$s1 + xor 8($key),$s2 + xor 12($key),$s3 + + mov 240($key),$rnds # load key->rounds + sub \$1,$rnds + jmp .Lenc_loop +.align 16 +.Lenc_loop: +___ + if ($verticalspin) { &encvert(); } + else { &encstep(0,$s0,$s1,$s2,$s3); + &encstep(1,$s1,$s2,$s3,$s0); + &encstep(2,$s2,$s3,$s0,$s1); + &encstep(3,$s3,$s0,$s1,$s2); + } +$code.=<<___; + sub \$1,$rnds + jnz .Lenc_loop +___ + if ($verticalspin) { &enclastvert(); } + else { &enclast(0,$s0,$s1,$s2,$s3); + &enclast(1,$s1,$s2,$s3,$s0); + &enclast(2,$s2,$s3,$s0,$s1); + &enclast(3,$s3,$s0,$s1,$s2); + $code.=<<___; + xor 16+0($key),$s0 # xor with key + xor 16+4($key),$s1 + xor 16+8($key),$s2 + xor 16+12($key),$s3 +___ + } +$code.=<<___; + .byte 0xf3,0xc3 # rep ret +.size _x86_64_AES_encrypt,.-_x86_64_AES_encrypt +___ + +# it's possible to implement this by shifting tN by 8, filling least +# significant byte with byte load and finally bswap-ing at the end, +# but such partial register load kills Core 2... +sub enccompactvert() +{ my ($t3,$t4,$t5)=("%r8d","%r9d","%r13d"); + +$code.=<<___; + movzb `&lo("$s0")`,$t0 + movzb `&lo("$s1")`,$t1 + movzb `&lo("$s2")`,$t2 + movzb `&lo("$s3")`,$t3 + movzb `&hi("$s1")`,$acc0 + movzb `&hi("$s2")`,$acc1 + shr \$16,$s2 + movzb `&hi("$s3")`,$acc2 + movzb ($sbox,$t0,1),$t0 + movzb ($sbox,$t1,1),$t1 + movzb ($sbox,$t2,1),$t2 + movzb ($sbox,$t3,1),$t3 + + movzb ($sbox,$acc0,1),$t4 #$t0 + movzb `&hi("$s0")`,$acc0 + movzb ($sbox,$acc1,1),$t5 #$t1 + movzb `&lo("$s2")`,$acc1 + movzb ($sbox,$acc2,1),$acc2 #$t2 + movzb ($sbox,$acc0,1),$acc0 #$t3 + + shl \$8,$t4 + shr \$16,$s3 + shl \$8,$t5 + xor $t4,$t0 + shr \$16,$s0 + movzb `&lo("$s3")`,$t4 + shr \$16,$s1 + xor $t5,$t1 + shl \$8,$acc2 + movzb `&lo("$s0")`,$t5 + movzb ($sbox,$acc1,1),$acc1 #$t0 + xor $acc2,$t2 + + shl \$8,$acc0 + movzb `&lo("$s1")`,$acc2 + shl \$16,$acc1 + xor $acc0,$t3 + movzb ($sbox,$t4,1),$t4 #$t1 + movzb `&hi("$s3")`,$acc0 + movzb ($sbox,$t5,1),$t5 #$t2 + xor $acc1,$t0 + + shr \$8,$s2 + movzb `&hi("$s0")`,$acc1 + shl \$16,$t4 + shr \$8,$s1 + shl \$16,$t5 + xor $t4,$t1 + movzb ($sbox,$acc2,1),$acc2 #$t3 + movzb ($sbox,$acc0,1),$acc0 #$t0 + movzb ($sbox,$acc1,1),$acc1 #$t1 + movzb ($sbox,$s2,1),$s3 #$t3 + movzb ($sbox,$s1,1),$s2 #$t2 + + shl \$16,$acc2 + xor $t5,$t2 + shl \$24,$acc0 + xor $acc2,$t3 + shl \$24,$acc1 + xor $acc0,$t0 + shl \$24,$s3 + xor $acc1,$t1 + shl \$24,$s2 + mov $t0,$s0 + mov $t1,$s1 + xor $t2,$s2 + xor $t3,$s3 +___ +} + +sub enctransform_ref() +{ my $sn = shift; + my ($acc,$r2,$tmp)=("%r8d","%r9d","%r13d"); + +$code.=<<___; + mov $sn,$acc + and \$0x80808080,$acc + mov $acc,$tmp + shr \$7,$tmp + lea ($sn,$sn),$r2 + sub $tmp,$acc + and \$0xfefefefe,$r2 + and \$0x1b1b1b1b,$acc + mov $sn,$tmp + xor $acc,$r2 + + xor $r2,$sn + rol \$24,$sn + xor $r2,$sn + ror \$16,$tmp + xor $tmp,$sn + ror \$8,$tmp + xor $tmp,$sn +___ +} + +# unlike decrypt case it does not pay off to parallelize enctransform +sub enctransform() +{ my ($t3,$r20,$r21)=($acc2,"%r8d","%r9d"); + +$code.=<<___; + mov \$0x80808080,$t0 + mov \$0x80808080,$t1 + and $s0,$t0 + and $s1,$t1 + mov $t0,$acc0 + mov $t1,$acc1 + shr \$7,$t0 + lea ($s0,$s0),$r20 + shr \$7,$t1 + lea ($s1,$s1),$r21 + sub $t0,$acc0 + sub $t1,$acc1 + and \$0xfefefefe,$r20 + and \$0xfefefefe,$r21 + and \$0x1b1b1b1b,$acc0 + and \$0x1b1b1b1b,$acc1 + mov $s0,$t0 + mov $s1,$t1 + xor $acc0,$r20 + xor $acc1,$r21 + + xor $r20,$s0 + xor $r21,$s1 + mov \$0x80808080,$t2 + rol \$24,$s0 + mov \$0x80808080,$t3 + rol \$24,$s1 + and $s2,$t2 + and $s3,$t3 + xor $r20,$s0 + xor $r21,$s1 + mov $t2,$acc0 + ror \$16,$t0 + mov $t3,$acc1 + ror \$16,$t1 + lea ($s2,$s2),$r20 + shr \$7,$t2 + xor $t0,$s0 + shr \$7,$t3 + xor $t1,$s1 + ror \$8,$t0 + lea ($s3,$s3),$r21 + ror \$8,$t1 + sub $t2,$acc0 + sub $t3,$acc1 + xor $t0,$s0 + xor $t1,$s1 + + and \$0xfefefefe,$r20 + and \$0xfefefefe,$r21 + and \$0x1b1b1b1b,$acc0 + and \$0x1b1b1b1b,$acc1 + mov $s2,$t2 + mov $s3,$t3 + xor $acc0,$r20 + xor $acc1,$r21 + + ror \$16,$t2 + xor $r20,$s2 + ror \$16,$t3 + xor $r21,$s3 + rol \$24,$s2 + mov 0($sbox),$acc0 # prefetch Te4 + rol \$24,$s3 + xor $r20,$s2 + mov 64($sbox),$acc1 + xor $r21,$s3 + mov 128($sbox),$r20 + xor $t2,$s2 + ror \$8,$t2 + xor $t3,$s3 + ror \$8,$t3 + xor $t2,$s2 + mov 192($sbox),$r21 + xor $t3,$s3 +___ +} + +$code.=<<___; +.type _x86_64_AES_encrypt_compact,\@abi-omnipotent +.align 16 +_x86_64_AES_encrypt_compact: + lea 128($sbox),$inp # size optimization + mov 0-128($inp),$acc1 # prefetch Te4 + mov 32-128($inp),$acc2 + mov 64-128($inp),$t0 + mov 96-128($inp),$t1 + mov 128-128($inp),$acc1 + mov 160-128($inp),$acc2 + mov 192-128($inp),$t0 + mov 224-128($inp),$t1 + jmp .Lenc_loop_compact +.align 16 +.Lenc_loop_compact: + xor 0($key),$s0 # xor with key + xor 4($key),$s1 + xor 8($key),$s2 + xor 12($key),$s3 + lea 16($key),$key +___ + &enccompactvert(); +$code.=<<___; + cmp 16(%rsp),$key + je .Lenc_compact_done +___ + &enctransform(); +$code.=<<___; + jmp .Lenc_loop_compact +.align 16 +.Lenc_compact_done: + xor 0($key),$s0 + xor 4($key),$s1 + xor 8($key),$s2 + xor 12($key),$s3 + .byte 0xf3,0xc3 # rep ret +.size _x86_64_AES_encrypt_compact,.-_x86_64_AES_encrypt_compact +___ + +# void asm_AES_encrypt (const void *inp,void *out,const AES_KEY *key); +$code.=<<___; +.align 16 +.globl asm_AES_encrypt +.type asm_AES_encrypt,\@function,3 +.hidden asm_AES_encrypt +asm_AES_encrypt: + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + + # allocate frame "above" key schedule + mov %rsp,%r10 + lea -63(%rdx),%rcx # %rdx is key argument + and \$-64,%rsp + sub %rsp,%rcx + neg %rcx + and \$0x3c0,%rcx + sub %rcx,%rsp + sub \$32,%rsp + + mov %rsi,16(%rsp) # save out + mov %r10,24(%rsp) # save real stack pointer +.Lenc_prologue: + + mov %rdx,$key + mov 240($key),$rnds # load rounds + + mov 0(%rdi),$s0 # load input vector + mov 4(%rdi),$s1 + mov 8(%rdi),$s2 + mov 12(%rdi),$s3 + + shl \$4,$rnds + lea ($key,$rnds),%rbp + mov $key,(%rsp) # key schedule + mov %rbp,8(%rsp) # end of key schedule + + # pick Te4 copy which can't "overlap" with stack frame or key schedule + lea .LAES_Te+2048(%rip),$sbox + lea 768(%rsp),%rbp + sub $sbox,%rbp + and \$0x300,%rbp + lea ($sbox,%rbp),$sbox + + call _x86_64_AES_encrypt_compact + + mov 16(%rsp),$out # restore out + mov 24(%rsp),%rsi # restore saved stack pointer + mov $s0,0($out) # write output vector + mov $s1,4($out) + mov $s2,8($out) + mov $s3,12($out) + + mov (%rsi),%r15 + mov 8(%rsi),%r14 + mov 16(%rsi),%r13 + mov 24(%rsi),%r12 + mov 32(%rsi),%rbp + mov 40(%rsi),%rbx + lea 48(%rsi),%rsp +.Lenc_epilogue: + ret +.size asm_AES_encrypt,.-asm_AES_encrypt +___ + +#------------------------------------------------------------------# + +sub decvert() +{ my $t3="%r8d"; # zaps $inp! + +$code.=<<___; + # favor 3-way issue Opteron pipeline... + movzb `&lo("$s0")`,$acc0 + movzb `&lo("$s1")`,$acc1 + movzb `&lo("$s2")`,$acc2 + mov 0($sbox,$acc0,8),$t0 + mov 0($sbox,$acc1,8),$t1 + mov 0($sbox,$acc2,8),$t2 + + movzb `&hi("$s3")`,$acc0 + movzb `&hi("$s0")`,$acc1 + movzb `&lo("$s3")`,$acc2 + xor 3($sbox,$acc0,8),$t0 + xor 3($sbox,$acc1,8),$t1 + mov 0($sbox,$acc2,8),$t3 + + movzb `&hi("$s1")`,$acc0 + shr \$16,$s0 + movzb `&hi("$s2")`,$acc2 + xor 3($sbox,$acc0,8),$t2 + shr \$16,$s3 + xor 3($sbox,$acc2,8),$t3 + + shr \$16,$s1 + lea 16($key),$key + shr \$16,$s2 + + movzb `&lo("$s2")`,$acc0 + movzb `&lo("$s3")`,$acc1 + movzb `&lo("$s0")`,$acc2 + xor 2($sbox,$acc0,8),$t0 + xor 2($sbox,$acc1,8),$t1 + xor 2($sbox,$acc2,8),$t2 + + movzb `&hi("$s1")`,$acc0 + movzb `&hi("$s2")`,$acc1 + movzb `&lo("$s1")`,$acc2 + xor 1($sbox,$acc0,8),$t0 + xor 1($sbox,$acc1,8),$t1 + xor 2($sbox,$acc2,8),$t3 + + movzb `&hi("$s3")`,$acc0 + mov 12($key),$s3 + movzb `&hi("$s0")`,$acc2 + xor 1($sbox,$acc0,8),$t2 + mov 0($key),$s0 + xor 1($sbox,$acc2,8),$t3 + + xor $t0,$s0 + mov 4($key),$s1 + mov 8($key),$s2 + xor $t2,$s2 + xor $t1,$s1 + xor $t3,$s3 +___ +} + +sub declastvert() +{ my $t3="%r8d"; # zaps $inp! + +$code.=<<___; + lea 2048($sbox),$sbox # size optimization + movzb `&lo("$s0")`,$acc0 + movzb `&lo("$s1")`,$acc1 + movzb `&lo("$s2")`,$acc2 + movzb ($sbox,$acc0,1),$t0 + movzb ($sbox,$acc1,1),$t1 + movzb ($sbox,$acc2,1),$t2 + + movzb `&lo("$s3")`,$acc0 + movzb `&hi("$s3")`,$acc1 + movzb `&hi("$s0")`,$acc2 + movzb ($sbox,$acc0,1),$t3 + movzb ($sbox,$acc1,1),$acc1 #$t0 + movzb ($sbox,$acc2,1),$acc2 #$t1 + + shl \$8,$acc1 + shl \$8,$acc2 + + xor $acc1,$t0 + xor $acc2,$t1 + shr \$16,$s3 + + movzb `&hi("$s1")`,$acc0 + movzb `&hi("$s2")`,$acc1 + shr \$16,$s0 + movzb ($sbox,$acc0,1),$acc0 #$t2 + movzb ($sbox,$acc1,1),$acc1 #$t3 + + shl \$8,$acc0 + shl \$8,$acc1 + shr \$16,$s1 + xor $acc0,$t2 + xor $acc1,$t3 + shr \$16,$s2 + + movzb `&lo("$s2")`,$acc0 + movzb `&lo("$s3")`,$acc1 + movzb `&lo("$s0")`,$acc2 + movzb ($sbox,$acc0,1),$acc0 #$t0 + movzb ($sbox,$acc1,1),$acc1 #$t1 + movzb ($sbox,$acc2,1),$acc2 #$t2 + + shl \$16,$acc0 + shl \$16,$acc1 + shl \$16,$acc2 + + xor $acc0,$t0 + xor $acc1,$t1 + xor $acc2,$t2 + + movzb `&lo("$s1")`,$acc0 + movzb `&hi("$s1")`,$acc1 + movzb `&hi("$s2")`,$acc2 + movzb ($sbox,$acc0,1),$acc0 #$t3 + movzb ($sbox,$acc1,1),$acc1 #$t0 + movzb ($sbox,$acc2,1),$acc2 #$t1 + + shl \$16,$acc0 + shl \$24,$acc1 + shl \$24,$acc2 + + xor $acc0,$t3 + xor $acc1,$t0 + xor $acc2,$t1 + + movzb `&hi("$s3")`,$acc0 + movzb `&hi("$s0")`,$acc1 + mov 16+12($key),$s3 + movzb ($sbox,$acc0,1),$acc0 #$t2 + movzb ($sbox,$acc1,1),$acc1 #$t3 + mov 16+0($key),$s0 + + shl \$24,$acc0 + shl \$24,$acc1 + + xor $acc0,$t2 + xor $acc1,$t3 + + mov 16+4($key),$s1 + mov 16+8($key),$s2 + lea -2048($sbox),$sbox + xor $t0,$s0 + xor $t1,$s1 + xor $t2,$s2 + xor $t3,$s3 +___ +} + +sub decstep() +{ my ($i,@s) = @_; + my $tmp0=$acc0; + my $tmp1=$acc1; + my $tmp2=$acc2; + my $out=($t0,$t1,$t2,$s[0])[$i]; + + $code.=" mov $s[0],$out\n" if ($i!=3); + $tmp1=$s[2] if ($i==3); + $code.=" mov $s[2],$tmp1\n" if ($i!=3); + $code.=" and \$0xFF,$out\n"; + + $code.=" mov 0($sbox,$out,8),$out\n"; + $code.=" shr \$16,$tmp1\n"; + $tmp2=$s[3] if ($i==3); + $code.=" mov $s[3],$tmp2\n" if ($i!=3); + + $tmp0=$s[1] if ($i==3); + $code.=" movzb ".&hi($s[1]).",$tmp0\n"; + $code.=" and \$0xFF,$tmp1\n"; + $code.=" shr \$24,$tmp2\n"; + + $code.=" xor 3($sbox,$tmp0,8),$out\n"; + $code.=" xor 2($sbox,$tmp1,8),$out\n"; + $code.=" xor 1($sbox,$tmp2,8),$out\n"; + + $code.=" mov $t2,$s[1]\n" if ($i==3); + $code.=" mov $t1,$s[2]\n" if ($i==3); + $code.=" mov $t0,$s[3]\n" if ($i==3); + $code.="\n"; +} + +sub declast() +{ my ($i,@s)=@_; + my $tmp0=$acc0; + my $tmp1=$acc1; + my $tmp2=$acc2; + my $out=($t0,$t1,$t2,$s[0])[$i]; + + $code.=" mov $s[0],$out\n" if ($i!=3); + $tmp1=$s[2] if ($i==3); + $code.=" mov $s[2],$tmp1\n" if ($i!=3); + $code.=" and \$0xFF,$out\n"; + + $code.=" movzb 2048($sbox,$out,1),$out\n"; + $code.=" shr \$16,$tmp1\n"; + $tmp2=$s[3] if ($i==3); + $code.=" mov $s[3],$tmp2\n" if ($i!=3); + + $tmp0=$s[1] if ($i==3); + $code.=" movzb ".&hi($s[1]).",$tmp0\n"; + $code.=" and \$0xFF,$tmp1\n"; + $code.=" shr \$24,$tmp2\n"; + + $code.=" movzb 2048($sbox,$tmp0,1),$tmp0\n"; + $code.=" movzb 2048($sbox,$tmp1,1),$tmp1\n"; + $code.=" movzb 2048($sbox,$tmp2,1),$tmp2\n"; + + $code.=" shl \$8,$tmp0\n"; + $code.=" shl \$16,$tmp1\n"; + $code.=" shl \$24,$tmp2\n"; + + $code.=" xor $tmp0,$out\n"; + $code.=" mov $t2,$s[1]\n" if ($i==3); + $code.=" xor $tmp1,$out\n"; + $code.=" mov $t1,$s[2]\n" if ($i==3); + $code.=" xor $tmp2,$out\n"; + $code.=" mov $t0,$s[3]\n" if ($i==3); + $code.="\n"; +} + +$code.=<<___; +.type _x86_64_AES_decrypt,\@abi-omnipotent +.align 16 +_x86_64_AES_decrypt: + xor 0($key),$s0 # xor with key + xor 4($key),$s1 + xor 8($key),$s2 + xor 12($key),$s3 + + mov 240($key),$rnds # load key->rounds + sub \$1,$rnds + jmp .Ldec_loop +.align 16 +.Ldec_loop: +___ + if ($verticalspin) { &decvert(); } + else { &decstep(0,$s0,$s3,$s2,$s1); + &decstep(1,$s1,$s0,$s3,$s2); + &decstep(2,$s2,$s1,$s0,$s3); + &decstep(3,$s3,$s2,$s1,$s0); + $code.=<<___; + lea 16($key),$key + xor 0($key),$s0 # xor with key + xor 4($key),$s1 + xor 8($key),$s2 + xor 12($key),$s3 +___ + } +$code.=<<___; + sub \$1,$rnds + jnz .Ldec_loop +___ + if ($verticalspin) { &declastvert(); } + else { &declast(0,$s0,$s3,$s2,$s1); + &declast(1,$s1,$s0,$s3,$s2); + &declast(2,$s2,$s1,$s0,$s3); + &declast(3,$s3,$s2,$s1,$s0); + $code.=<<___; + xor 16+0($key),$s0 # xor with key + xor 16+4($key),$s1 + xor 16+8($key),$s2 + xor 16+12($key),$s3 +___ + } +$code.=<<___; + .byte 0xf3,0xc3 # rep ret +.size _x86_64_AES_decrypt,.-_x86_64_AES_decrypt +___ + +sub deccompactvert() +{ my ($t3,$t4,$t5)=("%r8d","%r9d","%r13d"); + +$code.=<<___; + movzb `&lo("$s0")`,$t0 + movzb `&lo("$s1")`,$t1 + movzb `&lo("$s2")`,$t2 + movzb `&lo("$s3")`,$t3 + movzb `&hi("$s3")`,$acc0 + movzb `&hi("$s0")`,$acc1 + shr \$16,$s3 + movzb `&hi("$s1")`,$acc2 + movzb ($sbox,$t0,1),$t0 + movzb ($sbox,$t1,1),$t1 + movzb ($sbox,$t2,1),$t2 + movzb ($sbox,$t3,1),$t3 + + movzb ($sbox,$acc0,1),$t4 #$t0 + movzb `&hi("$s2")`,$acc0 + movzb ($sbox,$acc1,1),$t5 #$t1 + movzb ($sbox,$acc2,1),$acc2 #$t2 + movzb ($sbox,$acc0,1),$acc0 #$t3 + + shr \$16,$s2 + shl \$8,$t5 + shl \$8,$t4 + movzb `&lo("$s2")`,$acc1 + shr \$16,$s0 + xor $t4,$t0 + shr \$16,$s1 + movzb `&lo("$s3")`,$t4 + + shl \$8,$acc2 + xor $t5,$t1 + shl \$8,$acc0 + movzb `&lo("$s0")`,$t5 + movzb ($sbox,$acc1,1),$acc1 #$t0 + xor $acc2,$t2 + movzb `&lo("$s1")`,$acc2 + + shl \$16,$acc1 + xor $acc0,$t3 + movzb ($sbox,$t4,1),$t4 #$t1 + movzb `&hi("$s1")`,$acc0 + movzb ($sbox,$acc2,1),$acc2 #$t3 + xor $acc1,$t0 + movzb ($sbox,$t5,1),$t5 #$t2 + movzb `&hi("$s2")`,$acc1 + + shl \$16,$acc2 + shl \$16,$t4 + shl \$16,$t5 + xor $acc2,$t3 + movzb `&hi("$s3")`,$acc2 + xor $t4,$t1 + shr \$8,$s0 + xor $t5,$t2 + + movzb ($sbox,$acc0,1),$acc0 #$t0 + movzb ($sbox,$acc1,1),$s1 #$t1 + movzb ($sbox,$acc2,1),$s2 #$t2 + movzb ($sbox,$s0,1),$s3 #$t3 + + mov $t0,$s0 + shl \$24,$acc0 + shl \$24,$s1 + shl \$24,$s2 + xor $acc0,$s0 + shl \$24,$s3 + xor $t1,$s1 + xor $t2,$s2 + xor $t3,$s3 +___ +} + +# parallelized version! input is pair of 64-bit values: %rax=s1.s0 +# and %rcx=s3.s2, output is four 32-bit values in %eax=s0, %ebx=s1, +# %ecx=s2 and %edx=s3. +sub dectransform() +{ my ($tp10,$tp20,$tp40,$tp80,$acc0)=("%rax","%r8", "%r9", "%r10","%rbx"); + my ($tp18,$tp28,$tp48,$tp88,$acc8)=("%rcx","%r11","%r12","%r13","%rdx"); + my $prefetch = shift; + +$code.=<<___; + mov $mask80,$tp40 + mov $mask80,$tp48 + and $tp10,$tp40 + and $tp18,$tp48 + mov $tp40,$acc0 + mov $tp48,$acc8 + shr \$7,$tp40 + lea ($tp10,$tp10),$tp20 + shr \$7,$tp48 + lea ($tp18,$tp18),$tp28 + sub $tp40,$acc0 + sub $tp48,$acc8 + and $maskfe,$tp20 + and $maskfe,$tp28 + and $mask1b,$acc0 + and $mask1b,$acc8 + xor $acc0,$tp20 + xor $acc8,$tp28 + mov $mask80,$tp80 + mov $mask80,$tp88 + + and $tp20,$tp80 + and $tp28,$tp88 + mov $tp80,$acc0 + mov $tp88,$acc8 + shr \$7,$tp80 + lea ($tp20,$tp20),$tp40 + shr \$7,$tp88 + lea ($tp28,$tp28),$tp48 + sub $tp80,$acc0 + sub $tp88,$acc8 + and $maskfe,$tp40 + and $maskfe,$tp48 + and $mask1b,$acc0 + and $mask1b,$acc8 + xor $acc0,$tp40 + xor $acc8,$tp48 + mov $mask80,$tp80 + mov $mask80,$tp88 + + and $tp40,$tp80 + and $tp48,$tp88 + mov $tp80,$acc0 + mov $tp88,$acc8 + shr \$7,$tp80 + xor $tp10,$tp20 # tp2^=tp1 + shr \$7,$tp88 + xor $tp18,$tp28 # tp2^=tp1 + sub $tp80,$acc0 + sub $tp88,$acc8 + lea ($tp40,$tp40),$tp80 + lea ($tp48,$tp48),$tp88 + xor $tp10,$tp40 # tp4^=tp1 + xor $tp18,$tp48 # tp4^=tp1 + and $maskfe,$tp80 + and $maskfe,$tp88 + and $mask1b,$acc0 + and $mask1b,$acc8 + xor $acc0,$tp80 + xor $acc8,$tp88 + + xor $tp80,$tp10 # tp1^=tp8 + xor $tp88,$tp18 # tp1^=tp8 + xor $tp80,$tp20 # tp2^tp1^=tp8 + xor $tp88,$tp28 # tp2^tp1^=tp8 + mov $tp10,$acc0 + mov $tp18,$acc8 + xor $tp80,$tp40 # tp4^tp1^=tp8 + shr \$32,$acc0 + xor $tp88,$tp48 # tp4^tp1^=tp8 + shr \$32,$acc8 + xor $tp20,$tp80 # tp8^=tp8^tp2^tp1=tp2^tp1 + rol \$8,`&LO("$tp10")` # ROTATE(tp1^tp8,8) + xor $tp28,$tp88 # tp8^=tp8^tp2^tp1=tp2^tp1 + rol \$8,`&LO("$tp18")` # ROTATE(tp1^tp8,8) + xor $tp40,$tp80 # tp2^tp1^=tp8^tp4^tp1=tp8^tp4^tp2 + rol \$8,`&LO("$acc0")` # ROTATE(tp1^tp8,8) + xor $tp48,$tp88 # tp2^tp1^=tp8^tp4^tp1=tp8^tp4^tp2 + + rol \$8,`&LO("$acc8")` # ROTATE(tp1^tp8,8) + xor `&LO("$tp80")`,`&LO("$tp10")` + shr \$32,$tp80 + xor `&LO("$tp88")`,`&LO("$tp18")` + shr \$32,$tp88 + xor `&LO("$tp80")`,`&LO("$acc0")` + xor `&LO("$tp88")`,`&LO("$acc8")` + + mov $tp20,$tp80 + rol \$24,`&LO("$tp20")` # ROTATE(tp2^tp1^tp8,24) + mov $tp28,$tp88 + rol \$24,`&LO("$tp28")` # ROTATE(tp2^tp1^tp8,24) + shr \$32,$tp80 + xor `&LO("$tp20")`,`&LO("$tp10")` + shr \$32,$tp88 + xor `&LO("$tp28")`,`&LO("$tp18")` + rol \$24,`&LO("$tp80")` # ROTATE(tp2^tp1^tp8,24) + mov $tp40,$tp20 + rol \$24,`&LO("$tp88")` # ROTATE(tp2^tp1^tp8,24) + mov $tp48,$tp28 + shr \$32,$tp20 + xor `&LO("$tp80")`,`&LO("$acc0")` + shr \$32,$tp28 + xor `&LO("$tp88")`,`&LO("$acc8")` + + `"mov 0($sbox),$mask80" if ($prefetch)` + rol \$16,`&LO("$tp40")` # ROTATE(tp4^tp1^tp8,16) + `"mov 64($sbox),$maskfe" if ($prefetch)` + rol \$16,`&LO("$tp48")` # ROTATE(tp4^tp1^tp8,16) + `"mov 128($sbox),$mask1b" if ($prefetch)` + rol \$16,`&LO("$tp20")` # ROTATE(tp4^tp1^tp8,16) + `"mov 192($sbox),$tp80" if ($prefetch)` + xor `&LO("$tp40")`,`&LO("$tp10")` + rol \$16,`&LO("$tp28")` # ROTATE(tp4^tp1^tp8,16) + xor `&LO("$tp48")`,`&LO("$tp18")` + `"mov 256($sbox),$tp88" if ($prefetch)` + xor `&LO("$tp20")`,`&LO("$acc0")` + xor `&LO("$tp28")`,`&LO("$acc8")` +___ +} + +$code.=<<___; +.type _x86_64_AES_decrypt_compact,\@abi-omnipotent +.align 16 +_x86_64_AES_decrypt_compact: + lea 128($sbox),$inp # size optimization + mov 0-128($inp),$acc1 # prefetch Td4 + mov 32-128($inp),$acc2 + mov 64-128($inp),$t0 + mov 96-128($inp),$t1 + mov 128-128($inp),$acc1 + mov 160-128($inp),$acc2 + mov 192-128($inp),$t0 + mov 224-128($inp),$t1 + jmp .Ldec_loop_compact + +.align 16 +.Ldec_loop_compact: + xor 0($key),$s0 # xor with key + xor 4($key),$s1 + xor 8($key),$s2 + xor 12($key),$s3 + lea 16($key),$key +___ + &deccompactvert(); +$code.=<<___; + cmp 16(%rsp),$key + je .Ldec_compact_done + + mov 256+0($sbox),$mask80 + shl \$32,%rbx + shl \$32,%rdx + mov 256+8($sbox),$maskfe + or %rbx,%rax + or %rdx,%rcx + mov 256+16($sbox),$mask1b +___ + &dectransform(1); +$code.=<<___; + jmp .Ldec_loop_compact +.align 16 +.Ldec_compact_done: + xor 0($key),$s0 + xor 4($key),$s1 + xor 8($key),$s2 + xor 12($key),$s3 + .byte 0xf3,0xc3 # rep ret +.size _x86_64_AES_decrypt_compact,.-_x86_64_AES_decrypt_compact +___ + +# void asm_AES_decrypt (const void *inp,void *out,const AES_KEY *key); +$code.=<<___; +.align 16 +.globl asm_AES_decrypt +.type asm_AES_decrypt,\@function,3 +.hidden asm_AES_decrypt +asm_AES_decrypt: + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + + # allocate frame "above" key schedule + mov %rsp,%r10 + lea -63(%rdx),%rcx # %rdx is key argument + and \$-64,%rsp + sub %rsp,%rcx + neg %rcx + and \$0x3c0,%rcx + sub %rcx,%rsp + sub \$32,%rsp + + mov %rsi,16(%rsp) # save out + mov %r10,24(%rsp) # save real stack pointer +.Ldec_prologue: + + mov %rdx,$key + mov 240($key),$rnds # load rounds + + mov 0(%rdi),$s0 # load input vector + mov 4(%rdi),$s1 + mov 8(%rdi),$s2 + mov 12(%rdi),$s3 + + shl \$4,$rnds + lea ($key,$rnds),%rbp + mov $key,(%rsp) # key schedule + mov %rbp,8(%rsp) # end of key schedule + + # pick Td4 copy which can't "overlap" with stack frame or key schedule + lea .LAES_Td+2048(%rip),$sbox + lea 768(%rsp),%rbp + sub $sbox,%rbp + and \$0x300,%rbp + lea ($sbox,%rbp),$sbox + shr \$3,%rbp # recall "magic" constants! + add %rbp,$sbox + + call _x86_64_AES_decrypt_compact + + mov 16(%rsp),$out # restore out + mov 24(%rsp),%rsi # restore saved stack pointer + mov $s0,0($out) # write output vector + mov $s1,4($out) + mov $s2,8($out) + mov $s3,12($out) + + mov (%rsi),%r15 + mov 8(%rsi),%r14 + mov 16(%rsi),%r13 + mov 24(%rsi),%r12 + mov 32(%rsi),%rbp + mov 40(%rsi),%rbx + lea 48(%rsi),%rsp +.Ldec_epilogue: + ret +.size asm_AES_decrypt,.-asm_AES_decrypt +___ +#------------------------------------------------------------------# + +sub enckey() +{ +$code.=<<___; + movz %dl,%esi # rk[i]>>0 + movzb -128(%rbp,%rsi),%ebx + movz %dh,%esi # rk[i]>>8 + shl \$24,%ebx + xor %ebx,%eax + + movzb -128(%rbp,%rsi),%ebx + shr \$16,%edx + movz %dl,%esi # rk[i]>>16 + xor %ebx,%eax + + movzb -128(%rbp,%rsi),%ebx + movz %dh,%esi # rk[i]>>24 + shl \$8,%ebx + xor %ebx,%eax + + movzb -128(%rbp,%rsi),%ebx + shl \$16,%ebx + xor %ebx,%eax + + xor 1024-128(%rbp,%rcx,4),%eax # rcon +___ +} + +# int asm_AES_set_encrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key) +$code.=<<___; +.align 16 +.globl asm_AES_set_encrypt_key +.type asm_AES_set_encrypt_key,\@function,3 +asm_AES_set_encrypt_key: + push %rbx + push %rbp + push %r12 # redundant, but allows to share + push %r13 # exception handler... + push %r14 + push %r15 + sub \$8,%rsp +.Lenc_key_prologue: + + call _x86_64_AES_set_encrypt_key + + mov 40(%rsp),%rbp + mov 48(%rsp),%rbx + add \$56,%rsp +.Lenc_key_epilogue: + ret +.size asm_AES_set_encrypt_key,.-asm_AES_set_encrypt_key + +.type _x86_64_AES_set_encrypt_key,\@abi-omnipotent +.align 16 +_x86_64_AES_set_encrypt_key: + mov %esi,%ecx # %ecx=bits + mov %rdi,%rsi # %rsi=userKey + mov %rdx,%rdi # %rdi=key + + test \$-1,%rsi + jz .Lbadpointer + test \$-1,%rdi + jz .Lbadpointer + + lea .LAES_Te(%rip),%rbp + lea 2048+128(%rbp),%rbp + + # prefetch Te4 + mov 0-128(%rbp),%eax + mov 32-128(%rbp),%ebx + mov 64-128(%rbp),%r8d + mov 96-128(%rbp),%edx + mov 128-128(%rbp),%eax + mov 160-128(%rbp),%ebx + mov 192-128(%rbp),%r8d + mov 224-128(%rbp),%edx + + cmp \$128,%ecx + je .L10rounds + cmp \$192,%ecx + je .L12rounds + cmp \$256,%ecx + je .L14rounds + mov \$-2,%rax # invalid number of bits + jmp .Lexit + +.L10rounds: + mov 0(%rsi),%rax # copy first 4 dwords + mov 8(%rsi),%rdx + mov %rax,0(%rdi) + mov %rdx,8(%rdi) + + shr \$32,%rdx + xor %ecx,%ecx + jmp .L10shortcut +.align 4 +.L10loop: + mov 0(%rdi),%eax # rk[0] + mov 12(%rdi),%edx # rk[3] +.L10shortcut: +___ + &enckey (); +$code.=<<___; + mov %eax,16(%rdi) # rk[4] + xor 4(%rdi),%eax + mov %eax,20(%rdi) # rk[5] + xor 8(%rdi),%eax + mov %eax,24(%rdi) # rk[6] + xor 12(%rdi),%eax + mov %eax,28(%rdi) # rk[7] + add \$1,%ecx + lea 16(%rdi),%rdi + cmp \$10,%ecx + jl .L10loop + + movl \$10,80(%rdi) # setup number of rounds + xor %rax,%rax + jmp .Lexit + +.L12rounds: + mov 0(%rsi),%rax # copy first 6 dwords + mov 8(%rsi),%rbx + mov 16(%rsi),%rdx + mov %rax,0(%rdi) + mov %rbx,8(%rdi) + mov %rdx,16(%rdi) + + shr \$32,%rdx + xor %ecx,%ecx + jmp .L12shortcut +.align 4 +.L12loop: + mov 0(%rdi),%eax # rk[0] + mov 20(%rdi),%edx # rk[5] +.L12shortcut: +___ + &enckey (); +$code.=<<___; + mov %eax,24(%rdi) # rk[6] + xor 4(%rdi),%eax + mov %eax,28(%rdi) # rk[7] + xor 8(%rdi),%eax + mov %eax,32(%rdi) # rk[8] + xor 12(%rdi),%eax + mov %eax,36(%rdi) # rk[9] + + cmp \$7,%ecx + je .L12break + add \$1,%ecx + + xor 16(%rdi),%eax + mov %eax,40(%rdi) # rk[10] + xor 20(%rdi),%eax + mov %eax,44(%rdi) # rk[11] + + lea 24(%rdi),%rdi + jmp .L12loop +.L12break: + movl \$12,72(%rdi) # setup number of rounds + xor %rax,%rax + jmp .Lexit + +.L14rounds: + mov 0(%rsi),%rax # copy first 8 dwords + mov 8(%rsi),%rbx + mov 16(%rsi),%rcx + mov 24(%rsi),%rdx + mov %rax,0(%rdi) + mov %rbx,8(%rdi) + mov %rcx,16(%rdi) + mov %rdx,24(%rdi) + + shr \$32,%rdx + xor %ecx,%ecx + jmp .L14shortcut +.align 4 +.L14loop: + mov 0(%rdi),%eax # rk[0] + mov 28(%rdi),%edx # rk[4] +.L14shortcut: +___ + &enckey (); +$code.=<<___; + mov %eax,32(%rdi) # rk[8] + xor 4(%rdi),%eax + mov %eax,36(%rdi) # rk[9] + xor 8(%rdi),%eax + mov %eax,40(%rdi) # rk[10] + xor 12(%rdi),%eax + mov %eax,44(%rdi) # rk[11] + + cmp \$6,%ecx + je .L14break + add \$1,%ecx + + mov %eax,%edx + mov 16(%rdi),%eax # rk[4] + movz %dl,%esi # rk[11]>>0 + movzb -128(%rbp,%rsi),%ebx + movz %dh,%esi # rk[11]>>8 + xor %ebx,%eax + + movzb -128(%rbp,%rsi),%ebx + shr \$16,%edx + shl \$8,%ebx + movz %dl,%esi # rk[11]>>16 + xor %ebx,%eax + + movzb -128(%rbp,%rsi),%ebx + movz %dh,%esi # rk[11]>>24 + shl \$16,%ebx + xor %ebx,%eax + + movzb -128(%rbp,%rsi),%ebx + shl \$24,%ebx + xor %ebx,%eax + + mov %eax,48(%rdi) # rk[12] + xor 20(%rdi),%eax + mov %eax,52(%rdi) # rk[13] + xor 24(%rdi),%eax + mov %eax,56(%rdi) # rk[14] + xor 28(%rdi),%eax + mov %eax,60(%rdi) # rk[15] + + lea 32(%rdi),%rdi + jmp .L14loop +.L14break: + movl \$14,48(%rdi) # setup number of rounds + xor %rax,%rax + jmp .Lexit + +.Lbadpointer: + mov \$-1,%rax +.Lexit: + .byte 0xf3,0xc3 # rep ret +.size _x86_64_AES_set_encrypt_key,.-_x86_64_AES_set_encrypt_key +___ + +sub deckey_ref() +{ my ($i,$ptr,$te,$td) = @_; + my ($tp1,$tp2,$tp4,$tp8,$acc)=("%eax","%ebx","%edi","%edx","%r8d"); +$code.=<<___; + mov $i($ptr),$tp1 + mov $tp1,$acc + and \$0x80808080,$acc + mov $acc,$tp4 + shr \$7,$tp4 + lea 0($tp1,$tp1),$tp2 + sub $tp4,$acc + and \$0xfefefefe,$tp2 + and \$0x1b1b1b1b,$acc + xor $tp2,$acc + mov $acc,$tp2 + + and \$0x80808080,$acc + mov $acc,$tp8 + shr \$7,$tp8 + lea 0($tp2,$tp2),$tp4 + sub $tp8,$acc + and \$0xfefefefe,$tp4 + and \$0x1b1b1b1b,$acc + xor $tp1,$tp2 # tp2^tp1 + xor $tp4,$acc + mov $acc,$tp4 + + and \$0x80808080,$acc + mov $acc,$tp8 + shr \$7,$tp8 + sub $tp8,$acc + lea 0($tp4,$tp4),$tp8 + xor $tp1,$tp4 # tp4^tp1 + and \$0xfefefefe,$tp8 + and \$0x1b1b1b1b,$acc + xor $acc,$tp8 + + xor $tp8,$tp1 # tp1^tp8 + rol \$8,$tp1 # ROTATE(tp1^tp8,8) + xor $tp8,$tp2 # tp2^tp1^tp8 + xor $tp8,$tp4 # tp4^tp1^tp8 + xor $tp2,$tp8 + xor $tp4,$tp8 # tp8^(tp8^tp4^tp1)^(tp8^tp2^tp1)=tp8^tp4^tp2 + + xor $tp8,$tp1 + rol \$24,$tp2 # ROTATE(tp2^tp1^tp8,24) + xor $tp2,$tp1 + rol \$16,$tp4 # ROTATE(tp4^tp1^tp8,16) + xor $tp4,$tp1 + + mov $tp1,$i($ptr) +___ +} + +# int asm_AES_set_decrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key) +$code.=<<___; +.align 16 +.globl asm_AES_set_decrypt_key +.type asm_AES_set_decrypt_key,\@function,3 +asm_AES_set_decrypt_key: + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + push %rdx # save key schedule +.Ldec_key_prologue: + + call _x86_64_AES_set_encrypt_key + mov (%rsp),%r8 # restore key schedule + cmp \$0,%eax + jne .Labort + + mov 240(%r8),%r14d # pull number of rounds + xor %rdi,%rdi + lea (%rdi,%r14d,4),%rcx + mov %r8,%rsi + lea (%r8,%rcx,4),%rdi # pointer to last chunk +.align 4 +.Linvert: + mov 0(%rsi),%rax + mov 8(%rsi),%rbx + mov 0(%rdi),%rcx + mov 8(%rdi),%rdx + mov %rax,0(%rdi) + mov %rbx,8(%rdi) + mov %rcx,0(%rsi) + mov %rdx,8(%rsi) + lea 16(%rsi),%rsi + lea -16(%rdi),%rdi + cmp %rsi,%rdi + jne .Linvert + + lea .LAES_Te+2048+1024(%rip),%rax # rcon + + mov 40(%rax),$mask80 + mov 48(%rax),$maskfe + mov 56(%rax),$mask1b + + mov %r8,$key + sub \$1,%r14d +.align 4 +.Lpermute: + lea 16($key),$key + mov 0($key),%rax + mov 8($key),%rcx +___ + &dectransform (); +$code.=<<___; + mov %eax,0($key) + mov %ebx,4($key) + mov %ecx,8($key) + mov %edx,12($key) + sub \$1,%r14d + jnz .Lpermute + + xor %rax,%rax +.Labort: + mov 8(%rsp),%r15 + mov 16(%rsp),%r14 + mov 24(%rsp),%r13 + mov 32(%rsp),%r12 + mov 40(%rsp),%rbp + mov 48(%rsp),%rbx + add \$56,%rsp +.Ldec_key_epilogue: + ret +.size asm_AES_set_decrypt_key,.-asm_AES_set_decrypt_key +___ + +# void asm_AES_cbc_encrypt (const void char *inp, unsigned char *out, +# size_t length, const AES_KEY *key, +# unsigned char *ivp,const int enc); +{ +# stack frame layout +# -8(%rsp) return address +my $keyp="0(%rsp)"; # one to pass as $key +my $keyend="8(%rsp)"; # &(keyp->rd_key[4*keyp->rounds]) +my $_rsp="16(%rsp)"; # saved %rsp +my $_inp="24(%rsp)"; # copy of 1st parameter, inp +my $_out="32(%rsp)"; # copy of 2nd parameter, out +my $_len="40(%rsp)"; # copy of 3rd parameter, length +my $_key="48(%rsp)"; # copy of 4th parameter, key +my $_ivp="56(%rsp)"; # copy of 5th parameter, ivp +my $ivec="64(%rsp)"; # ivec[16] +my $aes_key="80(%rsp)"; # copy of aes_key +my $mark="80+240(%rsp)"; # copy of aes_key->rounds + +$code.=<<___; +.align 16 +.globl asm_AES_cbc_encrypt +.type asm_AES_cbc_encrypt,\@function,6 +.extern OPENSSL_ia32cap_P +.hidden asm_AES_cbc_encrypt +asm_AES_cbc_encrypt: + cmp \$0,%rdx # check length + je .Lcbc_epilogue + pushfq + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 +.Lcbc_prologue: + + cld + mov %r9d,%r9d # clear upper half of enc + + lea .LAES_Te(%rip),$sbox + cmp \$0,%r9 + jne .Lcbc_picked_te + lea .LAES_Td(%rip),$sbox +.Lcbc_picked_te: + + mov OPENSSL_ia32cap_P(%rip),%r10d + cmp \$$speed_limit,%rdx + jb .Lcbc_slow_prologue + test \$15,%rdx + jnz .Lcbc_slow_prologue + bt \$28,%r10d + jc .Lcbc_slow_prologue + + # allocate aligned stack frame... + lea -88-248(%rsp),$key + and \$-64,$key + + # ... and make sure it doesn't alias with AES_T[ed] modulo 4096 + mov $sbox,%r10 + lea 2304($sbox),%r11 + mov $key,%r12 + and \$0xFFF,%r10 # s = $sbox&0xfff + and \$0xFFF,%r11 # e = ($sbox+2048)&0xfff + and \$0xFFF,%r12 # p = %rsp&0xfff + + cmp %r11,%r12 # if (p=>e) %rsp =- (p-e); + jb .Lcbc_te_break_out + sub %r11,%r12 + sub %r12,$key + jmp .Lcbc_te_ok +.Lcbc_te_break_out: # else %rsp -= (p-s)&0xfff + framesz + sub %r10,%r12 + and \$0xFFF,%r12 + add \$320,%r12 + sub %r12,$key +.align 4 +.Lcbc_te_ok: + + xchg %rsp,$key + #add \$8,%rsp # reserve for return address! + mov $key,$_rsp # save %rsp +.Lcbc_fast_body: + mov %rdi,$_inp # save copy of inp + mov %rsi,$_out # save copy of out + mov %rdx,$_len # save copy of len + mov %rcx,$_key # save copy of key + mov %r8,$_ivp # save copy of ivp + movl \$0,$mark # copy of aes_key->rounds = 0; + mov %r8,%rbp # rearrange input arguments + mov %r9,%rbx + mov %rsi,$out + mov %rdi,$inp + mov %rcx,$key + + mov 240($key),%eax # key->rounds + # do we copy key schedule to stack? + mov $key,%r10 + sub $sbox,%r10 + and \$0xfff,%r10 + cmp \$2304,%r10 + jb .Lcbc_do_ecopy + cmp \$4096-248,%r10 + jb .Lcbc_skip_ecopy +.align 4 +.Lcbc_do_ecopy: + mov $key,%rsi + lea $aes_key,%rdi + lea $aes_key,$key + mov \$240/8,%ecx + .long 0x90A548F3 # rep movsq + mov %eax,(%rdi) # copy aes_key->rounds +.Lcbc_skip_ecopy: + mov $key,$keyp # save key pointer + + mov \$18,%ecx +.align 4 +.Lcbc_prefetch_te: + mov 0($sbox),%r10 + mov 32($sbox),%r11 + mov 64($sbox),%r12 + mov 96($sbox),%r13 + lea 128($sbox),$sbox + sub \$1,%ecx + jnz .Lcbc_prefetch_te + lea -2304($sbox),$sbox + + cmp \$0,%rbx + je .LFAST_DECRYPT + +#----------------------------- ENCRYPT -----------------------------# + mov 0(%rbp),$s0 # load iv + mov 4(%rbp),$s1 + mov 8(%rbp),$s2 + mov 12(%rbp),$s3 + +.align 4 +.Lcbc_fast_enc_loop: + xor 0($inp),$s0 + xor 4($inp),$s1 + xor 8($inp),$s2 + xor 12($inp),$s3 + mov $keyp,$key # restore key + mov $inp,$_inp # if ($verticalspin) save inp + + call _x86_64_AES_encrypt + + mov $_inp,$inp # if ($verticalspin) restore inp + mov $_len,%r10 + mov $s0,0($out) + mov $s1,4($out) + mov $s2,8($out) + mov $s3,12($out) + + lea 16($inp),$inp + lea 16($out),$out + sub \$16,%r10 + test \$-16,%r10 + mov %r10,$_len + jnz .Lcbc_fast_enc_loop + mov $_ivp,%rbp # restore ivp + mov $s0,0(%rbp) # save ivec + mov $s1,4(%rbp) + mov $s2,8(%rbp) + mov $s3,12(%rbp) + + jmp .Lcbc_fast_cleanup + +#----------------------------- DECRYPT -----------------------------# +.align 16 +.LFAST_DECRYPT: + cmp $inp,$out + je .Lcbc_fast_dec_in_place + + mov %rbp,$ivec +.align 4 +.Lcbc_fast_dec_loop: + mov 0($inp),$s0 # read input + mov 4($inp),$s1 + mov 8($inp),$s2 + mov 12($inp),$s3 + mov $keyp,$key # restore key + mov $inp,$_inp # if ($verticalspin) save inp + + call _x86_64_AES_decrypt + + mov $ivec,%rbp # load ivp + mov $_inp,$inp # if ($verticalspin) restore inp + mov $_len,%r10 # load len + xor 0(%rbp),$s0 # xor iv + xor 4(%rbp),$s1 + xor 8(%rbp),$s2 + xor 12(%rbp),$s3 + mov $inp,%rbp # current input, next iv + + sub \$16,%r10 + mov %r10,$_len # update len + mov %rbp,$ivec # update ivp + + mov $s0,0($out) # write output + mov $s1,4($out) + mov $s2,8($out) + mov $s3,12($out) + + lea 16($inp),$inp + lea 16($out),$out + jnz .Lcbc_fast_dec_loop + mov $_ivp,%r12 # load user ivp + mov 0(%rbp),%r10 # load iv + mov 8(%rbp),%r11 + mov %r10,0(%r12) # copy back to user + mov %r11,8(%r12) + jmp .Lcbc_fast_cleanup + +.align 16 +.Lcbc_fast_dec_in_place: + mov 0(%rbp),%r10 # copy iv to stack + mov 8(%rbp),%r11 + mov %r10,0+$ivec + mov %r11,8+$ivec +.align 4 +.Lcbc_fast_dec_in_place_loop: + mov 0($inp),$s0 # load input + mov 4($inp),$s1 + mov 8($inp),$s2 + mov 12($inp),$s3 + mov $keyp,$key # restore key + mov $inp,$_inp # if ($verticalspin) save inp + + call _x86_64_AES_decrypt + + mov $_inp,$inp # if ($verticalspin) restore inp + mov $_len,%r10 + xor 0+$ivec,$s0 + xor 4+$ivec,$s1 + xor 8+$ivec,$s2 + xor 12+$ivec,$s3 + + mov 0($inp),%r11 # load input + mov 8($inp),%r12 + sub \$16,%r10 + jz .Lcbc_fast_dec_in_place_done + + mov %r11,0+$ivec # copy input to iv + mov %r12,8+$ivec + + mov $s0,0($out) # save output [zaps input] + mov $s1,4($out) + mov $s2,8($out) + mov $s3,12($out) + + lea 16($inp),$inp + lea 16($out),$out + mov %r10,$_len + jmp .Lcbc_fast_dec_in_place_loop +.Lcbc_fast_dec_in_place_done: + mov $_ivp,%rdi + mov %r11,0(%rdi) # copy iv back to user + mov %r12,8(%rdi) + + mov $s0,0($out) # save output [zaps input] + mov $s1,4($out) + mov $s2,8($out) + mov $s3,12($out) + +.align 4 +.Lcbc_fast_cleanup: + cmpl \$0,$mark # was the key schedule copied? + lea $aes_key,%rdi + je .Lcbc_exit + mov \$240/8,%ecx + xor %rax,%rax + .long 0x90AB48F3 # rep stosq + + jmp .Lcbc_exit + +#--------------------------- SLOW ROUTINE ---------------------------# +.align 16 +.Lcbc_slow_prologue: + # allocate aligned stack frame... + lea -88(%rsp),%rbp + and \$-64,%rbp + # ... just "above" key schedule + lea -88-63(%rcx),%r10 + sub %rbp,%r10 + neg %r10 + and \$0x3c0,%r10 + sub %r10,%rbp + + xchg %rsp,%rbp + #add \$8,%rsp # reserve for return address! + mov %rbp,$_rsp # save %rsp +.Lcbc_slow_body: + #mov %rdi,$_inp # save copy of inp + #mov %rsi,$_out # save copy of out + #mov %rdx,$_len # save copy of len + #mov %rcx,$_key # save copy of key + mov %r8,$_ivp # save copy of ivp + mov %r8,%rbp # rearrange input arguments + mov %r9,%rbx + mov %rsi,$out + mov %rdi,$inp + mov %rcx,$key + mov %rdx,%r10 + + mov 240($key),%eax + mov $key,$keyp # save key pointer + shl \$4,%eax + lea ($key,%rax),%rax + mov %rax,$keyend + + # pick Te4 copy which can't "overlap" with stack frame or key scdedule + lea 2048($sbox),$sbox + lea 768-8(%rsp),%rax + sub $sbox,%rax + and \$0x300,%rax + lea ($sbox,%rax),$sbox + + cmp \$0,%rbx + je .LSLOW_DECRYPT + +#--------------------------- SLOW ENCRYPT ---------------------------# + test \$-16,%r10 # check upon length + mov 0(%rbp),$s0 # load iv + mov 4(%rbp),$s1 + mov 8(%rbp),$s2 + mov 12(%rbp),$s3 + jz .Lcbc_slow_enc_tail # short input... + +.align 4 +.Lcbc_slow_enc_loop: + xor 0($inp),$s0 + xor 4($inp),$s1 + xor 8($inp),$s2 + xor 12($inp),$s3 + mov $keyp,$key # restore key + mov $inp,$_inp # save inp + mov $out,$_out # save out + mov %r10,$_len # save len + + call _x86_64_AES_encrypt_compact + + mov $_inp,$inp # restore inp + mov $_out,$out # restore out + mov $_len,%r10 # restore len + mov $s0,0($out) + mov $s1,4($out) + mov $s2,8($out) + mov $s3,12($out) + + lea 16($inp),$inp + lea 16($out),$out + sub \$16,%r10 + test \$-16,%r10 + jnz .Lcbc_slow_enc_loop + test \$15,%r10 + jnz .Lcbc_slow_enc_tail + mov $_ivp,%rbp # restore ivp + mov $s0,0(%rbp) # save ivec + mov $s1,4(%rbp) + mov $s2,8(%rbp) + mov $s3,12(%rbp) + + jmp .Lcbc_exit + +.align 4 +.Lcbc_slow_enc_tail: + mov %rax,%r11 + mov %rcx,%r12 + mov %r10,%rcx + mov $inp,%rsi + mov $out,%rdi + .long 0x9066A4F3 # rep movsb + mov \$16,%rcx # zero tail + sub %r10,%rcx + xor %rax,%rax + .long 0x9066AAF3 # rep stosb + mov $out,$inp # this is not a mistake! + mov \$16,%r10 # len=16 + mov %r11,%rax + mov %r12,%rcx + jmp .Lcbc_slow_enc_loop # one more spin... +#--------------------------- SLOW DECRYPT ---------------------------# +.align 16 +.LSLOW_DECRYPT: + shr \$3,%rax + add %rax,$sbox # recall "magic" constants! + + mov 0(%rbp),%r11 # copy iv to stack + mov 8(%rbp),%r12 + mov %r11,0+$ivec + mov %r12,8+$ivec + +.align 4 +.Lcbc_slow_dec_loop: + mov 0($inp),$s0 # load input + mov 4($inp),$s1 + mov 8($inp),$s2 + mov 12($inp),$s3 + mov $keyp,$key # restore key + mov $inp,$_inp # save inp + mov $out,$_out # save out + mov %r10,$_len # save len + + call _x86_64_AES_decrypt_compact + + mov $_inp,$inp # restore inp + mov $_out,$out # restore out + mov $_len,%r10 + xor 0+$ivec,$s0 + xor 4+$ivec,$s1 + xor 8+$ivec,$s2 + xor 12+$ivec,$s3 + + mov 0($inp),%r11 # load input + mov 8($inp),%r12 + sub \$16,%r10 + jc .Lcbc_slow_dec_partial + jz .Lcbc_slow_dec_done + + mov %r11,0+$ivec # copy input to iv + mov %r12,8+$ivec + + mov $s0,0($out) # save output [can zap input] + mov $s1,4($out) + mov $s2,8($out) + mov $s3,12($out) + + lea 16($inp),$inp + lea 16($out),$out + jmp .Lcbc_slow_dec_loop +.Lcbc_slow_dec_done: + mov $_ivp,%rdi + mov %r11,0(%rdi) # copy iv back to user + mov %r12,8(%rdi) + + mov $s0,0($out) # save output [can zap input] + mov $s1,4($out) + mov $s2,8($out) + mov $s3,12($out) + + jmp .Lcbc_exit + +.align 4 +.Lcbc_slow_dec_partial: + mov $_ivp,%rdi + mov %r11,0(%rdi) # copy iv back to user + mov %r12,8(%rdi) + + mov $s0,0+$ivec # save output to stack + mov $s1,4+$ivec + mov $s2,8+$ivec + mov $s3,12+$ivec + + mov $out,%rdi + lea $ivec,%rsi + lea 16(%r10),%rcx + .long 0x9066A4F3 # rep movsb + jmp .Lcbc_exit + +.align 16 +.Lcbc_exit: + mov $_rsp,%rsi + mov (%rsi),%r15 + mov 8(%rsi),%r14 + mov 16(%rsi),%r13 + mov 24(%rsi),%r12 + mov 32(%rsi),%rbp + mov 40(%rsi),%rbx + lea 48(%rsi),%rsp +.Lcbc_popfq: + popfq +.Lcbc_epilogue: + ret +.size asm_AES_cbc_encrypt,.-asm_AES_cbc_encrypt +___ +} + +$code.=<<___; +.align 64 +.LAES_Te: +___ + &_data_word(0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6); + &_data_word(0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591); + &_data_word(0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56); + &_data_word(0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec); + &_data_word(0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa); + &_data_word(0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb); + &_data_word(0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45); + &_data_word(0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b); + &_data_word(0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c); + &_data_word(0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83); + &_data_word(0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9); + &_data_word(0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a); + &_data_word(0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d); + &_data_word(0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f); + &_data_word(0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df); + &_data_word(0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea); + &_data_word(0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34); + &_data_word(0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b); + &_data_word(0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d); + &_data_word(0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413); + &_data_word(0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1); + &_data_word(0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6); + &_data_word(0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972); + &_data_word(0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85); + &_data_word(0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed); + &_data_word(0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511); + &_data_word(0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe); + &_data_word(0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b); + &_data_word(0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05); + &_data_word(0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1); + &_data_word(0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142); + &_data_word(0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf); + &_data_word(0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3); + &_data_word(0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e); + &_data_word(0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a); + &_data_word(0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6); + &_data_word(0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3); + &_data_word(0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b); + &_data_word(0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428); + &_data_word(0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad); + &_data_word(0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14); + &_data_word(0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8); + &_data_word(0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4); + &_data_word(0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2); + &_data_word(0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda); + &_data_word(0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949); + &_data_word(0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf); + &_data_word(0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810); + &_data_word(0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c); + &_data_word(0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697); + &_data_word(0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e); + &_data_word(0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f); + &_data_word(0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc); + &_data_word(0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c); + &_data_word(0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969); + &_data_word(0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27); + &_data_word(0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122); + &_data_word(0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433); + &_data_word(0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9); + &_data_word(0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5); + &_data_word(0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a); + &_data_word(0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0); + &_data_word(0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e); + &_data_word(0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c); + +#Te4 # four copies of Te4 to choose from to avoid L1 aliasing + &data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5); + &data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76); + &data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0); + &data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0); + &data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc); + &data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15); + &data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a); + &data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75); + &data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0); + &data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84); + &data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b); + &data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf); + &data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85); + &data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8); + &data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5); + &data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2); + &data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17); + &data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73); + &data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88); + &data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb); + &data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c); + &data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79); + &data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9); + &data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08); + &data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6); + &data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a); + &data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e); + &data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e); + &data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94); + &data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf); + &data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68); + &data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16); + + &data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5); + &data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76); + &data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0); + &data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0); + &data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc); + &data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15); + &data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a); + &data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75); + &data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0); + &data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84); + &data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b); + &data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf); + &data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85); + &data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8); + &data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5); + &data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2); + &data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17); + &data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73); + &data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88); + &data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb); + &data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c); + &data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79); + &data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9); + &data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08); + &data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6); + &data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a); + &data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e); + &data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e); + &data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94); + &data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf); + &data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68); + &data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16); + + &data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5); + &data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76); + &data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0); + &data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0); + &data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc); + &data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15); + &data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a); + &data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75); + &data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0); + &data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84); + &data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b); + &data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf); + &data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85); + &data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8); + &data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5); + &data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2); + &data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17); + &data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73); + &data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88); + &data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb); + &data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c); + &data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79); + &data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9); + &data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08); + &data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6); + &data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a); + &data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e); + &data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e); + &data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94); + &data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf); + &data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68); + &data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16); + + &data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5); + &data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76); + &data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0); + &data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0); + &data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc); + &data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15); + &data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a); + &data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75); + &data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0); + &data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84); + &data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b); + &data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf); + &data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85); + &data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8); + &data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5); + &data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2); + &data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17); + &data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73); + &data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88); + &data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb); + &data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c); + &data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79); + &data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9); + &data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08); + &data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6); + &data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a); + &data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e); + &data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e); + &data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94); + &data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf); + &data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68); + &data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16); +#rcon: +$code.=<<___; + .long 0x00000001, 0x00000002, 0x00000004, 0x00000008 + .long 0x00000010, 0x00000020, 0x00000040, 0x00000080 + .long 0x0000001b, 0x00000036, 0x80808080, 0x80808080 + .long 0xfefefefe, 0xfefefefe, 0x1b1b1b1b, 0x1b1b1b1b +___ +$code.=<<___; +.align 64 +.LAES_Td: +___ + &_data_word(0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a); + &_data_word(0xcb6bab3b, 0xf1459d1f, 0xab58faac, 0x9303e34b); + &_data_word(0x55fa3020, 0xf66d76ad, 0x9176cc88, 0x254c02f5); + &_data_word(0xfcd7e54f, 0xd7cb2ac5, 0x80443526, 0x8fa362b5); + &_data_word(0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d); + &_data_word(0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b); + &_data_word(0xe75f8f03, 0x959c9215, 0xeb7a6dbf, 0xda595295); + &_data_word(0x2d83bed4, 0xd3217458, 0x2969e049, 0x44c8c98e); + &_data_word(0x6a89c275, 0x78798ef4, 0x6b3e5899, 0xdd71b927); + &_data_word(0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d); + &_data_word(0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362); + &_data_word(0xe07764b1, 0x84ae6bbb, 0x1ca081fe, 0x942b08f9); + &_data_word(0x58684870, 0x19fd458f, 0x876cde94, 0xb7f87b52); + &_data_word(0x23d373ab, 0xe2024b72, 0x578f1fe3, 0x2aab5566); + &_data_word(0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3); + &_data_word(0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed); + &_data_word(0x2b1ccf8a, 0x92b479a7, 0xf0f207f3, 0xa1e2694e); + &_data_word(0xcdf4da65, 0xd5be0506, 0x1f6234d1, 0x8afea6c4); + &_data_word(0x9d532e34, 0xa055f3a2, 0x32e18a05, 0x75ebf6a4); + &_data_word(0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd); + &_data_word(0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d); + &_data_word(0xb58d5491, 0x055dc471, 0x6fd40604, 0xff155060); + &_data_word(0x24fb9819, 0x97e9bdd6, 0xcc434089, 0x779ed967); + &_data_word(0xbd42e8b0, 0x888b8907, 0x385b19e7, 0xdbeec879); + &_data_word(0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000); + &_data_word(0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c); + &_data_word(0xfbff0efd, 0x5638850f, 0x1ed5ae3d, 0x27392d36); + &_data_word(0x64d90f0a, 0x21a65c68, 0xd1545b9b, 0x3a2e3624); + &_data_word(0xb1670a0c, 0x0fe75793, 0xd296eeb4, 0x9e919b1b); + &_data_word(0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c); + &_data_word(0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12); + &_data_word(0x0b0d090e, 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14); + &_data_word(0x8519f157, 0x4c0775af, 0xbbdd99ee, 0xfd607fa3); + &_data_word(0x9f2601f7, 0xbcf5725c, 0xc53b6644, 0x347efb5b); + &_data_word(0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8); + &_data_word(0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684); + &_data_word(0x7d244a85, 0xf83dbbd2, 0x1132f9ae, 0x6da129c7); + &_data_word(0x4b2f9e1d, 0xf330b2dc, 0xec52860d, 0xd0e3c177); + &_data_word(0x6c16b32b, 0x99b970a9, 0xfa489411, 0x2264e947); + &_data_word(0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322); + &_data_word(0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498); + &_data_word(0xcf81f5a6, 0x28de7aa5, 0x268eb7da, 0xa4bfad3f); + &_data_word(0xe49d3a2c, 0x0d927850, 0x9bcc5f6a, 0x62467e54); + &_data_word(0xc2138df6, 0xe8b8d890, 0x5ef7392e, 0xf5afc382); + &_data_word(0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf); + &_data_word(0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb); + &_data_word(0x097826cd, 0xf418596e, 0x01b79aec, 0xa89a4f83); + &_data_word(0x656e95e6, 0x7ee6ffaa, 0x08cfbc21, 0xe6e815ef); + &_data_word(0xd99be7ba, 0xce366f4a, 0xd4099fea, 0xd67cb029); + &_data_word(0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235); + &_data_word(0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733); + &_data_word(0x4a9804f1, 0xf7daec41, 0x0e50cd7f, 0x2ff69117); + &_data_word(0x8dd64d76, 0x4db0ef43, 0x544daacc, 0xdf0496e4); + &_data_word(0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, 0x7f516546); + &_data_word(0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb); + &_data_word(0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d); + &_data_word(0x8c61d79a, 0x7a0ca137, 0x8e14f859, 0x893c13eb); + &_data_word(0xee27a9ce, 0x35c961b7, 0xede51ce1, 0x3cb1477a); + &_data_word(0x59dfd29c, 0x3f73f255, 0x79ce1418, 0xbf37c773); + &_data_word(0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478); + &_data_word(0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2); + &_data_word(0x72c31d16, 0x0c25e2bc, 0x8b493c28, 0x41950dff); + &_data_word(0x7101a839, 0xdeb30c08, 0x9ce4b4d8, 0x90c15664); + &_data_word(0x6184cb7b, 0x70b632d5, 0x745c6c48, 0x4257b8d0); + +#Td4: # four copies of Td4 to choose from to avoid L1 aliasing + &data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38); + &data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb); + &data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87); + &data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb); + &data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d); + &data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e); + &data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2); + &data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25); + &data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16); + &data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92); + &data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda); + &data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84); + &data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a); + &data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06); + &data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02); + &data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b); + &data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea); + &data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73); + &data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85); + &data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e); + &data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89); + &data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b); + &data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20); + &data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4); + &data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31); + &data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f); + &data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d); + &data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef); + &data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0); + &data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61); + &data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26); + &data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d); +$code.=<<___; + .long 0x80808080, 0x80808080, 0xfefefefe, 0xfefefefe + .long 0x1b1b1b1b, 0x1b1b1b1b, 0, 0 +___ + &data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38); + &data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb); + &data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87); + &data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb); + &data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d); + &data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e); + &data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2); + &data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25); + &data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16); + &data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92); + &data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda); + &data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84); + &data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a); + &data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06); + &data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02); + &data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b); + &data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea); + &data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73); + &data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85); + &data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e); + &data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89); + &data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b); + &data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20); + &data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4); + &data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31); + &data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f); + &data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d); + &data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef); + &data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0); + &data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61); + &data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26); + &data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d); +$code.=<<___; + .long 0x80808080, 0x80808080, 0xfefefefe, 0xfefefefe + .long 0x1b1b1b1b, 0x1b1b1b1b, 0, 0 +___ + &data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38); + &data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb); + &data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87); + &data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb); + &data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d); + &data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e); + &data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2); + &data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25); + &data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16); + &data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92); + &data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda); + &data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84); + &data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a); + &data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06); + &data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02); + &data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b); + &data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea); + &data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73); + &data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85); + &data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e); + &data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89); + &data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b); + &data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20); + &data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4); + &data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31); + &data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f); + &data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d); + &data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef); + &data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0); + &data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61); + &data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26); + &data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d); +$code.=<<___; + .long 0x80808080, 0x80808080, 0xfefefefe, 0xfefefefe + .long 0x1b1b1b1b, 0x1b1b1b1b, 0, 0 +___ + &data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38); + &data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb); + &data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87); + &data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb); + &data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d); + &data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e); + &data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2); + &data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25); + &data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16); + &data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92); + &data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda); + &data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84); + &data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a); + &data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06); + &data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02); + &data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b); + &data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea); + &data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73); + &data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85); + &data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e); + &data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89); + &data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b); + &data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20); + &data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4); + &data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31); + &data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f); + &data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d); + &data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef); + &data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0); + &data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61); + &data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26); + &data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d); +$code.=<<___; + .long 0x80808080, 0x80808080, 0xfefefefe, 0xfefefefe + .long 0x1b1b1b1b, 0x1b1b1b1b, 0, 0 +.asciz "AES for x86_64, CRYPTOGAMS by " +.align 64 +___ + +# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame, +# CONTEXT *context,DISPATCHER_CONTEXT *disp) +if ($win64) { +$rec="%rcx"; +$frame="%rdx"; +$context="%r8"; +$disp="%r9"; + +$code.=<<___; +.extern __imp_RtlVirtualUnwind +.type block_se_handler,\@abi-omnipotent +.align 16 +block_se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + mov 8($disp),%rsi # disp->ImageBase + mov 56($disp),%r11 # disp->HandlerData + + mov 0(%r11),%r10d # HandlerData[0] + lea (%rsi,%r10),%r10 # prologue label + cmp %r10,%rbx # context->RipRsp + + mov 4(%r11),%r10d # HandlerData[1] + lea (%rsi,%r10),%r10 # epilogue label + cmp %r10,%rbx # context->Rip>=epilogue label + jae .Lin_block_prologue + + mov 24(%rax),%rax # pull saved real stack pointer + lea 48(%rax),%rax # adjust... + + mov -8(%rax),%rbx + mov -16(%rax),%rbp + mov -24(%rax),%r12 + mov -32(%rax),%r13 + mov -40(%rax),%r14 + mov -48(%rax),%r15 + mov %rbx,144($context) # restore context->Rbx + mov %rbp,160($context) # restore context->Rbp + mov %r12,216($context) # restore context->R12 + mov %r13,224($context) # restore context->R13 + mov %r14,232($context) # restore context->R14 + mov %r15,240($context) # restore context->R15 + +.Lin_block_prologue: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + + jmp .Lcommon_seh_exit +.size block_se_handler,.-block_se_handler + +.type key_se_handler,\@abi-omnipotent +.align 16 +key_se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + mov 8($disp),%rsi # disp->ImageBase + mov 56($disp),%r11 # disp->HandlerData + + mov 0(%r11),%r10d # HandlerData[0] + lea (%rsi,%r10),%r10 # prologue label + cmp %r10,%rbx # context->RipRsp + + mov 4(%r11),%r10d # HandlerData[1] + lea (%rsi,%r10),%r10 # epilogue label + cmp %r10,%rbx # context->Rip>=epilogue label + jae .Lin_key_prologue + + lea 56(%rax),%rax + + mov -8(%rax),%rbx + mov -16(%rax),%rbp + mov -24(%rax),%r12 + mov -32(%rax),%r13 + mov -40(%rax),%r14 + mov -48(%rax),%r15 + mov %rbx,144($context) # restore context->Rbx + mov %rbp,160($context) # restore context->Rbp + mov %r12,216($context) # restore context->R12 + mov %r13,224($context) # restore context->R13 + mov %r14,232($context) # restore context->R14 + mov %r15,240($context) # restore context->R15 + +.Lin_key_prologue: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + + jmp .Lcommon_seh_exit +.size key_se_handler,.-key_se_handler + +.type cbc_se_handler,\@abi-omnipotent +.align 16 +cbc_se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + lea .Lcbc_prologue(%rip),%r10 + cmp %r10,%rbx # context->Rip<.Lcbc_prologue + jb .Lin_cbc_prologue + + lea .Lcbc_fast_body(%rip),%r10 + cmp %r10,%rbx # context->Rip<.Lcbc_fast_body + jb .Lin_cbc_frame_setup + + lea .Lcbc_slow_prologue(%rip),%r10 + cmp %r10,%rbx # context->Rip<.Lcbc_slow_prologue + jb .Lin_cbc_body + + lea .Lcbc_slow_body(%rip),%r10 + cmp %r10,%rbx # context->Rip<.Lcbc_slow_body + jb .Lin_cbc_frame_setup + +.Lin_cbc_body: + mov 152($context),%rax # pull context->Rsp + + lea .Lcbc_epilogue(%rip),%r10 + cmp %r10,%rbx # context->Rip>=.Lcbc_epilogue + jae .Lin_cbc_prologue + + lea 8(%rax),%rax + + lea .Lcbc_popfq(%rip),%r10 + cmp %r10,%rbx # context->Rip>=.Lcbc_popfq + jae .Lin_cbc_prologue + + mov `16-8`(%rax),%rax # biased $_rsp + lea 56(%rax),%rax + +.Lin_cbc_frame_setup: + mov -16(%rax),%rbx + mov -24(%rax),%rbp + mov -32(%rax),%r12 + mov -40(%rax),%r13 + mov -48(%rax),%r14 + mov -56(%rax),%r15 + mov %rbx,144($context) # restore context->Rbx + mov %rbp,160($context) # restore context->Rbp + mov %r12,216($context) # restore context->R12 + mov %r13,224($context) # restore context->R13 + mov %r14,232($context) # restore context->R14 + mov %r15,240($context) # restore context->R15 + +.Lin_cbc_prologue: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + +.Lcommon_seh_exit: + + mov 40($disp),%rdi # disp->ContextRecord + mov $context,%rsi # context + mov \$`1232/8`,%ecx # sizeof(CONTEXT) + .long 0xa548f3fc # cld; rep movsq + + mov $disp,%rsi + xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER + mov 8(%rsi),%rdx # arg2, disp->ImageBase + mov 0(%rsi),%r8 # arg3, disp->ControlPc + mov 16(%rsi),%r9 # arg4, disp->FunctionEntry + mov 40(%rsi),%r10 # disp->ContextRecord + lea 56(%rsi),%r11 # &disp->HandlerData + lea 24(%rsi),%r12 # &disp->EstablisherFrame + mov %r10,32(%rsp) # arg5 + mov %r11,40(%rsp) # arg6 + mov %r12,48(%rsp) # arg7 + mov %rcx,56(%rsp) # arg8, (NULL) + call *__imp_RtlVirtualUnwind(%rip) + + mov \$1,%eax # ExceptionContinueSearch + add \$64,%rsp + popfq + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + pop %rdi + pop %rsi + ret +.size cbc_se_handler,.-cbc_se_handler + +.section .pdata +.align 4 + .rva .LSEH_begin_asm_AES_encrypt + .rva .LSEH_end_asm_AES_encrypt + .rva .LSEH_info_asm_AES_encrypt + + .rva .LSEH_begin_asm_AES_decrypt + .rva .LSEH_end_asm_AES_decrypt + .rva .LSEH_info_asm_AES_decrypt + + .rva .LSEH_begin_asm_AES_set_encrypt_key + .rva .LSEH_end_asm_AES_set_encrypt_key + .rva .LSEH_info_asm_AES_set_encrypt_key + + .rva .LSEH_begin_asm_AES_set_decrypt_key + .rva .LSEH_end_asm_AES_set_decrypt_key + .rva .LSEH_info_asm_AES_set_decrypt_key + + .rva .LSEH_begin_asm_AES_cbc_encrypt + .rva .LSEH_end_asm_AES_cbc_encrypt + .rva .LSEH_info_asm_AES_cbc_encrypt + +.section .xdata +.align 8 +.LSEH_info_asm_AES_encrypt: + .byte 9,0,0,0 + .rva block_se_handler + .rva .Lenc_prologue,.Lenc_epilogue # HandlerData[] +.LSEH_info_asm_AES_decrypt: + .byte 9,0,0,0 + .rva block_se_handler + .rva .Ldec_prologue,.Ldec_epilogue # HandlerData[] +.LSEH_info_asm_AES_set_encrypt_key: + .byte 9,0,0,0 + .rva key_se_handler + .rva .Lenc_key_prologue,.Lenc_key_epilogue # HandlerData[] +.LSEH_info_asm_AES_set_decrypt_key: + .byte 9,0,0,0 + .rva key_se_handler + .rva .Ldec_key_prologue,.Ldec_key_epilogue # HandlerData[] +.LSEH_info_asm_AES_cbc_encrypt: + .byte 9,0,0,0 + .rva cbc_se_handler +___ +} + +$code =~ s/\`([^\`]*)\`/eval($1)/gem; + +print $code; + +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/aes/asm/aesni-x86.pl b/TMessagesProj/jni/boringssl/crypto/aes/asm/aesni-x86.pl new file mode 100644 index 00000000..f67df8cf --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/aes/asm/aesni-x86.pl @@ -0,0 +1,2525 @@ +#!/usr/bin/env perl + +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# This module implements support for Intel AES-NI extension. In +# OpenSSL context it's used with Intel engine, but can also be used as +# drop-in replacement for crypto/aes/asm/aes-586.pl [see below for +# details]. +# +# Performance. +# +# To start with see corresponding paragraph in aesni-x86_64.pl... +# Instead of filling table similar to one found there I've chosen to +# summarize *comparison* results for raw ECB, CTR and CBC benchmarks. +# The simplified table below represents 32-bit performance relative +# to 64-bit one in every given point. Ratios vary for different +# encryption modes, therefore interval values. +# +# 16-byte 64-byte 256-byte 1-KB 8-KB +# 53-67% 67-84% 91-94% 95-98% 97-99.5% +# +# Lower ratios for smaller block sizes are perfectly understandable, +# because function call overhead is higher in 32-bit mode. Largest +# 8-KB block performance is virtually same: 32-bit code is less than +# 1% slower for ECB, CBC and CCM, and ~3% slower otherwise. + +# January 2011 +# +# See aesni-x86_64.pl for details. Unlike x86_64 version this module +# interleaves at most 6 aes[enc|dec] instructions, because there are +# not enough registers for 8x interleave [which should be optimal for +# Sandy Bridge]. Actually, performance results for 6x interleave +# factor presented in aesni-x86_64.pl (except for CTR) are for this +# module. + +# April 2011 +# +# Add aesni_xts_[en|de]crypt. Westmere spends 1.50 cycles processing +# one byte out of 8KB with 128-bit key, Sandy Bridge - 1.09. + +###################################################################### +# Current large-block performance in cycles per byte processed with +# 128-bit key (less is better). +# +# CBC en-/decrypt CTR XTS ECB +# Westmere 3.77/1.37 1.37 1.52 1.27 +# * Bridge 5.07/0.98 0.99 1.09 0.91 +# Haswell 4.44/0.80 0.97 1.03 0.72 +# Silvermont 5.77/3.56 3.67 4.03 3.46 +# Bulldozer 5.80/0.98 1.05 1.24 0.93 + +$PREFIX="aesni"; # if $PREFIX is set to "AES", the script + # generates drop-in replacement for + # crypto/aes/asm/aes-586.pl:-) +$inline=1; # inline _aesni_[en|de]crypt + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +push(@INC,"${dir}","${dir}../../perlasm"); +require "x86asm.pl"; + +&asm_init($ARGV[0],$0); + +&external_label("OPENSSL_ia32cap_P"); +&static_label("key_const"); + +if ($PREFIX eq "aesni") { $movekey=\&movups; } +else { $movekey=\&movups; } + +$len="eax"; +$rounds="ecx"; +$key="edx"; +$inp="esi"; +$out="edi"; +$rounds_="ebx"; # backup copy for $rounds +$key_="ebp"; # backup copy for $key + +$rndkey0="xmm0"; +$rndkey1="xmm1"; +$inout0="xmm2"; +$inout1="xmm3"; +$inout2="xmm4"; +$inout3="xmm5"; $in1="xmm5"; +$inout4="xmm6"; $in0="xmm6"; +$inout5="xmm7"; $ivec="xmm7"; + +# AESNI extenstion +sub aeskeygenassist +{ my($dst,$src,$imm)=@_; + if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/) + { &data_byte(0x66,0x0f,0x3a,0xdf,0xc0|($1<<3)|$2,$imm); } +} +sub aescommon +{ my($opcodelet,$dst,$src)=@_; + if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/) + { &data_byte(0x66,0x0f,0x38,$opcodelet,0xc0|($1<<3)|$2);} +} +sub aesimc { aescommon(0xdb,@_); } +sub aesenc { aescommon(0xdc,@_); } +sub aesenclast { aescommon(0xdd,@_); } +sub aesdec { aescommon(0xde,@_); } +sub aesdeclast { aescommon(0xdf,@_); } + +# Inline version of internal aesni_[en|de]crypt1 +{ my $sn; +sub aesni_inline_generate1 +{ my ($p,$inout,$ivec)=@_; $inout=$inout0 if (!defined($inout)); + $sn++; + + &$movekey ($rndkey0,&QWP(0,$key)); + &$movekey ($rndkey1,&QWP(16,$key)); + &xorps ($ivec,$rndkey0) if (defined($ivec)); + &lea ($key,&DWP(32,$key)); + &xorps ($inout,$ivec) if (defined($ivec)); + &xorps ($inout,$rndkey0) if (!defined($ivec)); + &set_label("${p}1_loop_$sn"); + eval"&aes${p} ($inout,$rndkey1)"; + &dec ($rounds); + &$movekey ($rndkey1,&QWP(0,$key)); + &lea ($key,&DWP(16,$key)); + &jnz (&label("${p}1_loop_$sn")); + eval"&aes${p}last ($inout,$rndkey1)"; +}} + +sub aesni_generate1 # fully unrolled loop +{ my ($p,$inout)=@_; $inout=$inout0 if (!defined($inout)); + + &function_begin_B("_aesni_${p}rypt1"); + &movups ($rndkey0,&QWP(0,$key)); + &$movekey ($rndkey1,&QWP(0x10,$key)); + &xorps ($inout,$rndkey0); + &$movekey ($rndkey0,&QWP(0x20,$key)); + &lea ($key,&DWP(0x30,$key)); + &cmp ($rounds,11); + &jb (&label("${p}128")); + &lea ($key,&DWP(0x20,$key)); + &je (&label("${p}192")); + &lea ($key,&DWP(0x20,$key)); + eval"&aes${p} ($inout,$rndkey1)"; + &$movekey ($rndkey1,&QWP(-0x40,$key)); + eval"&aes${p} ($inout,$rndkey0)"; + &$movekey ($rndkey0,&QWP(-0x30,$key)); + &set_label("${p}192"); + eval"&aes${p} ($inout,$rndkey1)"; + &$movekey ($rndkey1,&QWP(-0x20,$key)); + eval"&aes${p} ($inout,$rndkey0)"; + &$movekey ($rndkey0,&QWP(-0x10,$key)); + &set_label("${p}128"); + eval"&aes${p} ($inout,$rndkey1)"; + &$movekey ($rndkey1,&QWP(0,$key)); + eval"&aes${p} ($inout,$rndkey0)"; + &$movekey ($rndkey0,&QWP(0x10,$key)); + eval"&aes${p} ($inout,$rndkey1)"; + &$movekey ($rndkey1,&QWP(0x20,$key)); + eval"&aes${p} ($inout,$rndkey0)"; + &$movekey ($rndkey0,&QWP(0x30,$key)); + eval"&aes${p} ($inout,$rndkey1)"; + &$movekey ($rndkey1,&QWP(0x40,$key)); + eval"&aes${p} ($inout,$rndkey0)"; + &$movekey ($rndkey0,&QWP(0x50,$key)); + eval"&aes${p} ($inout,$rndkey1)"; + &$movekey ($rndkey1,&QWP(0x60,$key)); + eval"&aes${p} ($inout,$rndkey0)"; + &$movekey ($rndkey0,&QWP(0x70,$key)); + eval"&aes${p} ($inout,$rndkey1)"; + eval"&aes${p}last ($inout,$rndkey0)"; + &ret(); + &function_end_B("_aesni_${p}rypt1"); +} + +# void $PREFIX_encrypt (const void *inp,void *out,const AES_KEY *key); +&aesni_generate1("enc") if (!$inline); +&function_begin_B("${PREFIX}_encrypt"); + &mov ("eax",&wparam(0)); + &mov ($key,&wparam(2)); + &movups ($inout0,&QWP(0,"eax")); + &mov ($rounds,&DWP(240,$key)); + &mov ("eax",&wparam(1)); + if ($inline) + { &aesni_inline_generate1("enc"); } + else + { &call ("_aesni_encrypt1"); } + &pxor ($rndkey0,$rndkey0); # clear register bank + &pxor ($rndkey1,$rndkey1); + &movups (&QWP(0,"eax"),$inout0); + &pxor ($inout0,$inout0); + &ret (); +&function_end_B("${PREFIX}_encrypt"); + +# void $PREFIX_decrypt (const void *inp,void *out,const AES_KEY *key); +&aesni_generate1("dec") if(!$inline); +&function_begin_B("${PREFIX}_decrypt"); + &mov ("eax",&wparam(0)); + &mov ($key,&wparam(2)); + &movups ($inout0,&QWP(0,"eax")); + &mov ($rounds,&DWP(240,$key)); + &mov ("eax",&wparam(1)); + if ($inline) + { &aesni_inline_generate1("dec"); } + else + { &call ("_aesni_decrypt1"); } + &pxor ($rndkey0,$rndkey0); # clear register bank + &pxor ($rndkey1,$rndkey1); + &movups (&QWP(0,"eax"),$inout0); + &pxor ($inout0,$inout0); + &ret (); +&function_end_B("${PREFIX}_decrypt"); + +# _aesni_[en|de]cryptN are private interfaces, N denotes interleave +# factor. Why 3x subroutine were originally used in loops? Even though +# aes[enc|dec] latency was originally 6, it could be scheduled only +# every *2nd* cycle. Thus 3x interleave was the one providing optimal +# utilization, i.e. when subroutine's throughput is virtually same as +# of non-interleaved subroutine [for number of input blocks up to 3]. +# This is why it originally made no sense to implement 2x subroutine. +# But times change and it became appropriate to spend extra 192 bytes +# on 2x subroutine on Atom Silvermont account. For processors that +# can schedule aes[enc|dec] every cycle optimal interleave factor +# equals to corresponding instructions latency. 8x is optimal for +# * Bridge, but it's unfeasible to accommodate such implementation +# in XMM registers addreassable in 32-bit mode and therefore maximum +# of 6x is used instead... + +sub aesni_generate2 +{ my $p=shift; + + &function_begin_B("_aesni_${p}rypt2"); + &$movekey ($rndkey0,&QWP(0,$key)); + &shl ($rounds,4); + &$movekey ($rndkey1,&QWP(16,$key)); + &xorps ($inout0,$rndkey0); + &pxor ($inout1,$rndkey0); + &$movekey ($rndkey0,&QWP(32,$key)); + &lea ($key,&DWP(32,$key,$rounds)); + &neg ($rounds); + &add ($rounds,16); + + &set_label("${p}2_loop"); + eval"&aes${p} ($inout0,$rndkey1)"; + eval"&aes${p} ($inout1,$rndkey1)"; + &$movekey ($rndkey1,&QWP(0,$key,$rounds)); + &add ($rounds,32); + eval"&aes${p} ($inout0,$rndkey0)"; + eval"&aes${p} ($inout1,$rndkey0)"; + &$movekey ($rndkey0,&QWP(-16,$key,$rounds)); + &jnz (&label("${p}2_loop")); + eval"&aes${p} ($inout0,$rndkey1)"; + eval"&aes${p} ($inout1,$rndkey1)"; + eval"&aes${p}last ($inout0,$rndkey0)"; + eval"&aes${p}last ($inout1,$rndkey0)"; + &ret(); + &function_end_B("_aesni_${p}rypt2"); +} + +sub aesni_generate3 +{ my $p=shift; + + &function_begin_B("_aesni_${p}rypt3"); + &$movekey ($rndkey0,&QWP(0,$key)); + &shl ($rounds,4); + &$movekey ($rndkey1,&QWP(16,$key)); + &xorps ($inout0,$rndkey0); + &pxor ($inout1,$rndkey0); + &pxor ($inout2,$rndkey0); + &$movekey ($rndkey0,&QWP(32,$key)); + &lea ($key,&DWP(32,$key,$rounds)); + &neg ($rounds); + &add ($rounds,16); + + &set_label("${p}3_loop"); + eval"&aes${p} ($inout0,$rndkey1)"; + eval"&aes${p} ($inout1,$rndkey1)"; + eval"&aes${p} ($inout2,$rndkey1)"; + &$movekey ($rndkey1,&QWP(0,$key,$rounds)); + &add ($rounds,32); + eval"&aes${p} ($inout0,$rndkey0)"; + eval"&aes${p} ($inout1,$rndkey0)"; + eval"&aes${p} ($inout2,$rndkey0)"; + &$movekey ($rndkey0,&QWP(-16,$key,$rounds)); + &jnz (&label("${p}3_loop")); + eval"&aes${p} ($inout0,$rndkey1)"; + eval"&aes${p} ($inout1,$rndkey1)"; + eval"&aes${p} ($inout2,$rndkey1)"; + eval"&aes${p}last ($inout0,$rndkey0)"; + eval"&aes${p}last ($inout1,$rndkey0)"; + eval"&aes${p}last ($inout2,$rndkey0)"; + &ret(); + &function_end_B("_aesni_${p}rypt3"); +} + +# 4x interleave is implemented to improve small block performance, +# most notably [and naturally] 4 block by ~30%. One can argue that one +# should have implemented 5x as well, but improvement would be <20%, +# so it's not worth it... +sub aesni_generate4 +{ my $p=shift; + + &function_begin_B("_aesni_${p}rypt4"); + &$movekey ($rndkey0,&QWP(0,$key)); + &$movekey ($rndkey1,&QWP(16,$key)); + &shl ($rounds,4); + &xorps ($inout0,$rndkey0); + &pxor ($inout1,$rndkey0); + &pxor ($inout2,$rndkey0); + &pxor ($inout3,$rndkey0); + &$movekey ($rndkey0,&QWP(32,$key)); + &lea ($key,&DWP(32,$key,$rounds)); + &neg ($rounds); + &data_byte (0x0f,0x1f,0x40,0x00); + &add ($rounds,16); + + &set_label("${p}4_loop"); + eval"&aes${p} ($inout0,$rndkey1)"; + eval"&aes${p} ($inout1,$rndkey1)"; + eval"&aes${p} ($inout2,$rndkey1)"; + eval"&aes${p} ($inout3,$rndkey1)"; + &$movekey ($rndkey1,&QWP(0,$key,$rounds)); + &add ($rounds,32); + eval"&aes${p} ($inout0,$rndkey0)"; + eval"&aes${p} ($inout1,$rndkey0)"; + eval"&aes${p} ($inout2,$rndkey0)"; + eval"&aes${p} ($inout3,$rndkey0)"; + &$movekey ($rndkey0,&QWP(-16,$key,$rounds)); + &jnz (&label("${p}4_loop")); + + eval"&aes${p} ($inout0,$rndkey1)"; + eval"&aes${p} ($inout1,$rndkey1)"; + eval"&aes${p} ($inout2,$rndkey1)"; + eval"&aes${p} ($inout3,$rndkey1)"; + eval"&aes${p}last ($inout0,$rndkey0)"; + eval"&aes${p}last ($inout1,$rndkey0)"; + eval"&aes${p}last ($inout2,$rndkey0)"; + eval"&aes${p}last ($inout3,$rndkey0)"; + &ret(); + &function_end_B("_aesni_${p}rypt4"); +} + +sub aesni_generate6 +{ my $p=shift; + + &function_begin_B("_aesni_${p}rypt6"); + &static_label("_aesni_${p}rypt6_enter"); + &$movekey ($rndkey0,&QWP(0,$key)); + &shl ($rounds,4); + &$movekey ($rndkey1,&QWP(16,$key)); + &xorps ($inout0,$rndkey0); + &pxor ($inout1,$rndkey0); # pxor does better here + &pxor ($inout2,$rndkey0); + eval"&aes${p} ($inout0,$rndkey1)"; + &pxor ($inout3,$rndkey0); + &pxor ($inout4,$rndkey0); + eval"&aes${p} ($inout1,$rndkey1)"; + &lea ($key,&DWP(32,$key,$rounds)); + &neg ($rounds); + eval"&aes${p} ($inout2,$rndkey1)"; + &pxor ($inout5,$rndkey0); + &$movekey ($rndkey0,&QWP(0,$key,$rounds)); + &add ($rounds,16); + &jmp (&label("_aesni_${p}rypt6_inner")); + + &set_label("${p}6_loop",16); + eval"&aes${p} ($inout0,$rndkey1)"; + eval"&aes${p} ($inout1,$rndkey1)"; + eval"&aes${p} ($inout2,$rndkey1)"; + &set_label("_aesni_${p}rypt6_inner"); + eval"&aes${p} ($inout3,$rndkey1)"; + eval"&aes${p} ($inout4,$rndkey1)"; + eval"&aes${p} ($inout5,$rndkey1)"; + &set_label("_aesni_${p}rypt6_enter"); + &$movekey ($rndkey1,&QWP(0,$key,$rounds)); + &add ($rounds,32); + eval"&aes${p} ($inout0,$rndkey0)"; + eval"&aes${p} ($inout1,$rndkey0)"; + eval"&aes${p} ($inout2,$rndkey0)"; + eval"&aes${p} ($inout3,$rndkey0)"; + eval"&aes${p} ($inout4,$rndkey0)"; + eval"&aes${p} ($inout5,$rndkey0)"; + &$movekey ($rndkey0,&QWP(-16,$key,$rounds)); + &jnz (&label("${p}6_loop")); + + eval"&aes${p} ($inout0,$rndkey1)"; + eval"&aes${p} ($inout1,$rndkey1)"; + eval"&aes${p} ($inout2,$rndkey1)"; + eval"&aes${p} ($inout3,$rndkey1)"; + eval"&aes${p} ($inout4,$rndkey1)"; + eval"&aes${p} ($inout5,$rndkey1)"; + eval"&aes${p}last ($inout0,$rndkey0)"; + eval"&aes${p}last ($inout1,$rndkey0)"; + eval"&aes${p}last ($inout2,$rndkey0)"; + eval"&aes${p}last ($inout3,$rndkey0)"; + eval"&aes${p}last ($inout4,$rndkey0)"; + eval"&aes${p}last ($inout5,$rndkey0)"; + &ret(); + &function_end_B("_aesni_${p}rypt6"); +} +&aesni_generate2("enc") if ($PREFIX eq "aesni"); +&aesni_generate2("dec"); +&aesni_generate3("enc") if ($PREFIX eq "aesni"); +&aesni_generate3("dec"); +&aesni_generate4("enc") if ($PREFIX eq "aesni"); +&aesni_generate4("dec"); +&aesni_generate6("enc") if ($PREFIX eq "aesni"); +&aesni_generate6("dec"); + +if ($PREFIX eq "aesni") { +###################################################################### +# void aesni_ecb_encrypt (const void *in, void *out, +# size_t length, const AES_KEY *key, +# int enc); +&function_begin("aesni_ecb_encrypt"); + &mov ($inp,&wparam(0)); + &mov ($out,&wparam(1)); + &mov ($len,&wparam(2)); + &mov ($key,&wparam(3)); + &mov ($rounds_,&wparam(4)); + &and ($len,-16); + &jz (&label("ecb_ret")); + &mov ($rounds,&DWP(240,$key)); + &test ($rounds_,$rounds_); + &jz (&label("ecb_decrypt")); + + &mov ($key_,$key); # backup $key + &mov ($rounds_,$rounds); # backup $rounds + &cmp ($len,0x60); + &jb (&label("ecb_enc_tail")); + + &movdqu ($inout0,&QWP(0,$inp)); + &movdqu ($inout1,&QWP(0x10,$inp)); + &movdqu ($inout2,&QWP(0x20,$inp)); + &movdqu ($inout3,&QWP(0x30,$inp)); + &movdqu ($inout4,&QWP(0x40,$inp)); + &movdqu ($inout5,&QWP(0x50,$inp)); + &lea ($inp,&DWP(0x60,$inp)); + &sub ($len,0x60); + &jmp (&label("ecb_enc_loop6_enter")); + +&set_label("ecb_enc_loop6",16); + &movups (&QWP(0,$out),$inout0); + &movdqu ($inout0,&QWP(0,$inp)); + &movups (&QWP(0x10,$out),$inout1); + &movdqu ($inout1,&QWP(0x10,$inp)); + &movups (&QWP(0x20,$out),$inout2); + &movdqu ($inout2,&QWP(0x20,$inp)); + &movups (&QWP(0x30,$out),$inout3); + &movdqu ($inout3,&QWP(0x30,$inp)); + &movups (&QWP(0x40,$out),$inout4); + &movdqu ($inout4,&QWP(0x40,$inp)); + &movups (&QWP(0x50,$out),$inout5); + &lea ($out,&DWP(0x60,$out)); + &movdqu ($inout5,&QWP(0x50,$inp)); + &lea ($inp,&DWP(0x60,$inp)); +&set_label("ecb_enc_loop6_enter"); + + &call ("_aesni_encrypt6"); + + &mov ($key,$key_); # restore $key + &mov ($rounds,$rounds_); # restore $rounds + &sub ($len,0x60); + &jnc (&label("ecb_enc_loop6")); + + &movups (&QWP(0,$out),$inout0); + &movups (&QWP(0x10,$out),$inout1); + &movups (&QWP(0x20,$out),$inout2); + &movups (&QWP(0x30,$out),$inout3); + &movups (&QWP(0x40,$out),$inout4); + &movups (&QWP(0x50,$out),$inout5); + &lea ($out,&DWP(0x60,$out)); + &add ($len,0x60); + &jz (&label("ecb_ret")); + +&set_label("ecb_enc_tail"); + &movups ($inout0,&QWP(0,$inp)); + &cmp ($len,0x20); + &jb (&label("ecb_enc_one")); + &movups ($inout1,&QWP(0x10,$inp)); + &je (&label("ecb_enc_two")); + &movups ($inout2,&QWP(0x20,$inp)); + &cmp ($len,0x40); + &jb (&label("ecb_enc_three")); + &movups ($inout3,&QWP(0x30,$inp)); + &je (&label("ecb_enc_four")); + &movups ($inout4,&QWP(0x40,$inp)); + &xorps ($inout5,$inout5); + &call ("_aesni_encrypt6"); + &movups (&QWP(0,$out),$inout0); + &movups (&QWP(0x10,$out),$inout1); + &movups (&QWP(0x20,$out),$inout2); + &movups (&QWP(0x30,$out),$inout3); + &movups (&QWP(0x40,$out),$inout4); + jmp (&label("ecb_ret")); + +&set_label("ecb_enc_one",16); + if ($inline) + { &aesni_inline_generate1("enc"); } + else + { &call ("_aesni_encrypt1"); } + &movups (&QWP(0,$out),$inout0); + &jmp (&label("ecb_ret")); + +&set_label("ecb_enc_two",16); + &call ("_aesni_encrypt2"); + &movups (&QWP(0,$out),$inout0); + &movups (&QWP(0x10,$out),$inout1); + &jmp (&label("ecb_ret")); + +&set_label("ecb_enc_three",16); + &call ("_aesni_encrypt3"); + &movups (&QWP(0,$out),$inout0); + &movups (&QWP(0x10,$out),$inout1); + &movups (&QWP(0x20,$out),$inout2); + &jmp (&label("ecb_ret")); + +&set_label("ecb_enc_four",16); + &call ("_aesni_encrypt4"); + &movups (&QWP(0,$out),$inout0); + &movups (&QWP(0x10,$out),$inout1); + &movups (&QWP(0x20,$out),$inout2); + &movups (&QWP(0x30,$out),$inout3); + &jmp (&label("ecb_ret")); +###################################################################### +&set_label("ecb_decrypt",16); + &mov ($key_,$key); # backup $key + &mov ($rounds_,$rounds); # backup $rounds + &cmp ($len,0x60); + &jb (&label("ecb_dec_tail")); + + &movdqu ($inout0,&QWP(0,$inp)); + &movdqu ($inout1,&QWP(0x10,$inp)); + &movdqu ($inout2,&QWP(0x20,$inp)); + &movdqu ($inout3,&QWP(0x30,$inp)); + &movdqu ($inout4,&QWP(0x40,$inp)); + &movdqu ($inout5,&QWP(0x50,$inp)); + &lea ($inp,&DWP(0x60,$inp)); + &sub ($len,0x60); + &jmp (&label("ecb_dec_loop6_enter")); + +&set_label("ecb_dec_loop6",16); + &movups (&QWP(0,$out),$inout0); + &movdqu ($inout0,&QWP(0,$inp)); + &movups (&QWP(0x10,$out),$inout1); + &movdqu ($inout1,&QWP(0x10,$inp)); + &movups (&QWP(0x20,$out),$inout2); + &movdqu ($inout2,&QWP(0x20,$inp)); + &movups (&QWP(0x30,$out),$inout3); + &movdqu ($inout3,&QWP(0x30,$inp)); + &movups (&QWP(0x40,$out),$inout4); + &movdqu ($inout4,&QWP(0x40,$inp)); + &movups (&QWP(0x50,$out),$inout5); + &lea ($out,&DWP(0x60,$out)); + &movdqu ($inout5,&QWP(0x50,$inp)); + &lea ($inp,&DWP(0x60,$inp)); +&set_label("ecb_dec_loop6_enter"); + + &call ("_aesni_decrypt6"); + + &mov ($key,$key_); # restore $key + &mov ($rounds,$rounds_); # restore $rounds + &sub ($len,0x60); + &jnc (&label("ecb_dec_loop6")); + + &movups (&QWP(0,$out),$inout0); + &movups (&QWP(0x10,$out),$inout1); + &movups (&QWP(0x20,$out),$inout2); + &movups (&QWP(0x30,$out),$inout3); + &movups (&QWP(0x40,$out),$inout4); + &movups (&QWP(0x50,$out),$inout5); + &lea ($out,&DWP(0x60,$out)); + &add ($len,0x60); + &jz (&label("ecb_ret")); + +&set_label("ecb_dec_tail"); + &movups ($inout0,&QWP(0,$inp)); + &cmp ($len,0x20); + &jb (&label("ecb_dec_one")); + &movups ($inout1,&QWP(0x10,$inp)); + &je (&label("ecb_dec_two")); + &movups ($inout2,&QWP(0x20,$inp)); + &cmp ($len,0x40); + &jb (&label("ecb_dec_three")); + &movups ($inout3,&QWP(0x30,$inp)); + &je (&label("ecb_dec_four")); + &movups ($inout4,&QWP(0x40,$inp)); + &xorps ($inout5,$inout5); + &call ("_aesni_decrypt6"); + &movups (&QWP(0,$out),$inout0); + &movups (&QWP(0x10,$out),$inout1); + &movups (&QWP(0x20,$out),$inout2); + &movups (&QWP(0x30,$out),$inout3); + &movups (&QWP(0x40,$out),$inout4); + &jmp (&label("ecb_ret")); + +&set_label("ecb_dec_one",16); + if ($inline) + { &aesni_inline_generate1("dec"); } + else + { &call ("_aesni_decrypt1"); } + &movups (&QWP(0,$out),$inout0); + &jmp (&label("ecb_ret")); + +&set_label("ecb_dec_two",16); + &call ("_aesni_decrypt2"); + &movups (&QWP(0,$out),$inout0); + &movups (&QWP(0x10,$out),$inout1); + &jmp (&label("ecb_ret")); + +&set_label("ecb_dec_three",16); + &call ("_aesni_decrypt3"); + &movups (&QWP(0,$out),$inout0); + &movups (&QWP(0x10,$out),$inout1); + &movups (&QWP(0x20,$out),$inout2); + &jmp (&label("ecb_ret")); + +&set_label("ecb_dec_four",16); + &call ("_aesni_decrypt4"); + &movups (&QWP(0,$out),$inout0); + &movups (&QWP(0x10,$out),$inout1); + &movups (&QWP(0x20,$out),$inout2); + &movups (&QWP(0x30,$out),$inout3); + +&set_label("ecb_ret"); + &pxor ("xmm0","xmm0"); # clear register bank + &pxor ("xmm1","xmm1"); + &pxor ("xmm2","xmm2"); + &pxor ("xmm3","xmm3"); + &pxor ("xmm4","xmm4"); + &pxor ("xmm5","xmm5"); + &pxor ("xmm6","xmm6"); + &pxor ("xmm7","xmm7"); +&function_end("aesni_ecb_encrypt"); + +###################################################################### +# void aesni_ccm64_[en|de]crypt_blocks (const void *in, void *out, +# size_t blocks, const AES_KEY *key, +# const char *ivec,char *cmac); +# +# Handles only complete blocks, operates on 64-bit counter and +# does not update *ivec! Nor does it finalize CMAC value +# (see engine/eng_aesni.c for details) +# +{ my $cmac=$inout1; +&function_begin("aesni_ccm64_encrypt_blocks"); + &mov ($inp,&wparam(0)); + &mov ($out,&wparam(1)); + &mov ($len,&wparam(2)); + &mov ($key,&wparam(3)); + &mov ($rounds_,&wparam(4)); + &mov ($rounds,&wparam(5)); + &mov ($key_,"esp"); + &sub ("esp",60); + &and ("esp",-16); # align stack + &mov (&DWP(48,"esp"),$key_); + + &movdqu ($ivec,&QWP(0,$rounds_)); # load ivec + &movdqu ($cmac,&QWP(0,$rounds)); # load cmac + &mov ($rounds,&DWP(240,$key)); + + # compose byte-swap control mask for pshufb on stack + &mov (&DWP(0,"esp"),0x0c0d0e0f); + &mov (&DWP(4,"esp"),0x08090a0b); + &mov (&DWP(8,"esp"),0x04050607); + &mov (&DWP(12,"esp"),0x00010203); + + # compose counter increment vector on stack + &mov ($rounds_,1); + &xor ($key_,$key_); + &mov (&DWP(16,"esp"),$rounds_); + &mov (&DWP(20,"esp"),$key_); + &mov (&DWP(24,"esp"),$key_); + &mov (&DWP(28,"esp"),$key_); + + &shl ($rounds,4); + &mov ($rounds_,16); + &lea ($key_,&DWP(0,$key)); + &movdqa ($inout3,&QWP(0,"esp")); + &movdqa ($inout0,$ivec); + &lea ($key,&DWP(32,$key,$rounds)); + &sub ($rounds_,$rounds); + &pshufb ($ivec,$inout3); + +&set_label("ccm64_enc_outer"); + &$movekey ($rndkey0,&QWP(0,$key_)); + &mov ($rounds,$rounds_); + &movups ($in0,&QWP(0,$inp)); + + &xorps ($inout0,$rndkey0); + &$movekey ($rndkey1,&QWP(16,$key_)); + &xorps ($rndkey0,$in0); + &xorps ($cmac,$rndkey0); # cmac^=inp + &$movekey ($rndkey0,&QWP(32,$key_)); + +&set_label("ccm64_enc2_loop"); + &aesenc ($inout0,$rndkey1); + &aesenc ($cmac,$rndkey1); + &$movekey ($rndkey1,&QWP(0,$key,$rounds)); + &add ($rounds,32); + &aesenc ($inout0,$rndkey0); + &aesenc ($cmac,$rndkey0); + &$movekey ($rndkey0,&QWP(-16,$key,$rounds)); + &jnz (&label("ccm64_enc2_loop")); + &aesenc ($inout0,$rndkey1); + &aesenc ($cmac,$rndkey1); + &paddq ($ivec,&QWP(16,"esp")); + &dec ($len); + &aesenclast ($inout0,$rndkey0); + &aesenclast ($cmac,$rndkey0); + + &lea ($inp,&DWP(16,$inp)); + &xorps ($in0,$inout0); # inp^=E(ivec) + &movdqa ($inout0,$ivec); + &movups (&QWP(0,$out),$in0); # save output + &pshufb ($inout0,$inout3); + &lea ($out,&DWP(16,$out)); + &jnz (&label("ccm64_enc_outer")); + + &mov ("esp",&DWP(48,"esp")); + &mov ($out,&wparam(5)); + &movups (&QWP(0,$out),$cmac); + + &pxor ("xmm0","xmm0"); # clear register bank + &pxor ("xmm1","xmm1"); + &pxor ("xmm2","xmm2"); + &pxor ("xmm3","xmm3"); + &pxor ("xmm4","xmm4"); + &pxor ("xmm5","xmm5"); + &pxor ("xmm6","xmm6"); + &pxor ("xmm7","xmm7"); +&function_end("aesni_ccm64_encrypt_blocks"); + +&function_begin("aesni_ccm64_decrypt_blocks"); + &mov ($inp,&wparam(0)); + &mov ($out,&wparam(1)); + &mov ($len,&wparam(2)); + &mov ($key,&wparam(3)); + &mov ($rounds_,&wparam(4)); + &mov ($rounds,&wparam(5)); + &mov ($key_,"esp"); + &sub ("esp",60); + &and ("esp",-16); # align stack + &mov (&DWP(48,"esp"),$key_); + + &movdqu ($ivec,&QWP(0,$rounds_)); # load ivec + &movdqu ($cmac,&QWP(0,$rounds)); # load cmac + &mov ($rounds,&DWP(240,$key)); + + # compose byte-swap control mask for pshufb on stack + &mov (&DWP(0,"esp"),0x0c0d0e0f); + &mov (&DWP(4,"esp"),0x08090a0b); + &mov (&DWP(8,"esp"),0x04050607); + &mov (&DWP(12,"esp"),0x00010203); + + # compose counter increment vector on stack + &mov ($rounds_,1); + &xor ($key_,$key_); + &mov (&DWP(16,"esp"),$rounds_); + &mov (&DWP(20,"esp"),$key_); + &mov (&DWP(24,"esp"),$key_); + &mov (&DWP(28,"esp"),$key_); + + &movdqa ($inout3,&QWP(0,"esp")); # bswap mask + &movdqa ($inout0,$ivec); + + &mov ($key_,$key); + &mov ($rounds_,$rounds); + + &pshufb ($ivec,$inout3); + if ($inline) + { &aesni_inline_generate1("enc"); } + else + { &call ("_aesni_encrypt1"); } + &shl ($rounds_,4); + &mov ($rounds,16); + &movups ($in0,&QWP(0,$inp)); # load inp + &paddq ($ivec,&QWP(16,"esp")); + &lea ($inp,&QWP(16,$inp)); + &sub ($rounds,$rounds_); + &lea ($key,&DWP(32,$key_,$rounds_)); + &mov ($rounds_,$rounds); + &jmp (&label("ccm64_dec_outer")); + +&set_label("ccm64_dec_outer",16); + &xorps ($in0,$inout0); # inp ^= E(ivec) + &movdqa ($inout0,$ivec); + &movups (&QWP(0,$out),$in0); # save output + &lea ($out,&DWP(16,$out)); + &pshufb ($inout0,$inout3); + + &sub ($len,1); + &jz (&label("ccm64_dec_break")); + + &$movekey ($rndkey0,&QWP(0,$key_)); + &mov ($rounds,$rounds_); + &$movekey ($rndkey1,&QWP(16,$key_)); + &xorps ($in0,$rndkey0); + &xorps ($inout0,$rndkey0); + &xorps ($cmac,$in0); # cmac^=out + &$movekey ($rndkey0,&QWP(32,$key_)); + +&set_label("ccm64_dec2_loop"); + &aesenc ($inout0,$rndkey1); + &aesenc ($cmac,$rndkey1); + &$movekey ($rndkey1,&QWP(0,$key,$rounds)); + &add ($rounds,32); + &aesenc ($inout0,$rndkey0); + &aesenc ($cmac,$rndkey0); + &$movekey ($rndkey0,&QWP(-16,$key,$rounds)); + &jnz (&label("ccm64_dec2_loop")); + &movups ($in0,&QWP(0,$inp)); # load inp + &paddq ($ivec,&QWP(16,"esp")); + &aesenc ($inout0,$rndkey1); + &aesenc ($cmac,$rndkey1); + &aesenclast ($inout0,$rndkey0); + &aesenclast ($cmac,$rndkey0); + &lea ($inp,&QWP(16,$inp)); + &jmp (&label("ccm64_dec_outer")); + +&set_label("ccm64_dec_break",16); + &mov ($rounds,&DWP(240,$key_)); + &mov ($key,$key_); + if ($inline) + { &aesni_inline_generate1("enc",$cmac,$in0); } + else + { &call ("_aesni_encrypt1",$cmac); } + + &mov ("esp",&DWP(48,"esp")); + &mov ($out,&wparam(5)); + &movups (&QWP(0,$out),$cmac); + + &pxor ("xmm0","xmm0"); # clear register bank + &pxor ("xmm1","xmm1"); + &pxor ("xmm2","xmm2"); + &pxor ("xmm3","xmm3"); + &pxor ("xmm4","xmm4"); + &pxor ("xmm5","xmm5"); + &pxor ("xmm6","xmm6"); + &pxor ("xmm7","xmm7"); +&function_end("aesni_ccm64_decrypt_blocks"); +} + +###################################################################### +# void aesni_ctr32_encrypt_blocks (const void *in, void *out, +# size_t blocks, const AES_KEY *key, +# const char *ivec); +# +# Handles only complete blocks, operates on 32-bit counter and +# does not update *ivec! (see crypto/modes/ctr128.c for details) +# +# stack layout: +# 0 pshufb mask +# 16 vector addend: 0,6,6,6 +# 32 counter-less ivec +# 48 1st triplet of counter vector +# 64 2nd triplet of counter vector +# 80 saved %esp + +&function_begin("aesni_ctr32_encrypt_blocks"); + &mov ($inp,&wparam(0)); + &mov ($out,&wparam(1)); + &mov ($len,&wparam(2)); + &mov ($key,&wparam(3)); + &mov ($rounds_,&wparam(4)); + &mov ($key_,"esp"); + &sub ("esp",88); + &and ("esp",-16); # align stack + &mov (&DWP(80,"esp"),$key_); + + &cmp ($len,1); + &je (&label("ctr32_one_shortcut")); + + &movdqu ($inout5,&QWP(0,$rounds_)); # load ivec + + # compose byte-swap control mask for pshufb on stack + &mov (&DWP(0,"esp"),0x0c0d0e0f); + &mov (&DWP(4,"esp"),0x08090a0b); + &mov (&DWP(8,"esp"),0x04050607); + &mov (&DWP(12,"esp"),0x00010203); + + # compose counter increment vector on stack + &mov ($rounds,6); + &xor ($key_,$key_); + &mov (&DWP(16,"esp"),$rounds); + &mov (&DWP(20,"esp"),$rounds); + &mov (&DWP(24,"esp"),$rounds); + &mov (&DWP(28,"esp"),$key_); + + &pextrd ($rounds_,$inout5,3); # pull 32-bit counter + &pinsrd ($inout5,$key_,3); # wipe 32-bit counter + + &mov ($rounds,&DWP(240,$key)); # key->rounds + + # compose 2 vectors of 3x32-bit counters + &bswap ($rounds_); + &pxor ($rndkey0,$rndkey0); + &pxor ($rndkey1,$rndkey1); + &movdqa ($inout0,&QWP(0,"esp")); # load byte-swap mask + &pinsrd ($rndkey0,$rounds_,0); + &lea ($key_,&DWP(3,$rounds_)); + &pinsrd ($rndkey1,$key_,0); + &inc ($rounds_); + &pinsrd ($rndkey0,$rounds_,1); + &inc ($key_); + &pinsrd ($rndkey1,$key_,1); + &inc ($rounds_); + &pinsrd ($rndkey0,$rounds_,2); + &inc ($key_); + &pinsrd ($rndkey1,$key_,2); + &movdqa (&QWP(48,"esp"),$rndkey0); # save 1st triplet + &pshufb ($rndkey0,$inout0); # byte swap + &movdqu ($inout4,&QWP(0,$key)); # key[0] + &movdqa (&QWP(64,"esp"),$rndkey1); # save 2nd triplet + &pshufb ($rndkey1,$inout0); # byte swap + + &pshufd ($inout0,$rndkey0,3<<6); # place counter to upper dword + &pshufd ($inout1,$rndkey0,2<<6); + &cmp ($len,6); + &jb (&label("ctr32_tail")); + &pxor ($inout5,$inout4); # counter-less ivec^key[0] + &shl ($rounds,4); + &mov ($rounds_,16); + &movdqa (&QWP(32,"esp"),$inout5); # save counter-less ivec^key[0] + &mov ($key_,$key); # backup $key + &sub ($rounds_,$rounds); # backup twisted $rounds + &lea ($key,&DWP(32,$key,$rounds)); + &sub ($len,6); + &jmp (&label("ctr32_loop6")); + +&set_label("ctr32_loop6",16); + # inlining _aesni_encrypt6's prologue gives ~6% improvement... + &pshufd ($inout2,$rndkey0,1<<6); + &movdqa ($rndkey0,&QWP(32,"esp")); # pull counter-less ivec + &pshufd ($inout3,$rndkey1,3<<6); + &pxor ($inout0,$rndkey0); # merge counter-less ivec + &pshufd ($inout4,$rndkey1,2<<6); + &pxor ($inout1,$rndkey0); + &pshufd ($inout5,$rndkey1,1<<6); + &$movekey ($rndkey1,&QWP(16,$key_)); + &pxor ($inout2,$rndkey0); + &pxor ($inout3,$rndkey0); + &aesenc ($inout0,$rndkey1); + &pxor ($inout4,$rndkey0); + &pxor ($inout5,$rndkey0); + &aesenc ($inout1,$rndkey1); + &$movekey ($rndkey0,&QWP(32,$key_)); + &mov ($rounds,$rounds_); + &aesenc ($inout2,$rndkey1); + &aesenc ($inout3,$rndkey1); + &aesenc ($inout4,$rndkey1); + &aesenc ($inout5,$rndkey1); + + &call (&label("_aesni_encrypt6_enter")); + + &movups ($rndkey1,&QWP(0,$inp)); + &movups ($rndkey0,&QWP(0x10,$inp)); + &xorps ($inout0,$rndkey1); + &movups ($rndkey1,&QWP(0x20,$inp)); + &xorps ($inout1,$rndkey0); + &movups (&QWP(0,$out),$inout0); + &movdqa ($rndkey0,&QWP(16,"esp")); # load increment + &xorps ($inout2,$rndkey1); + &movdqa ($rndkey1,&QWP(64,"esp")); # load 2nd triplet + &movups (&QWP(0x10,$out),$inout1); + &movups (&QWP(0x20,$out),$inout2); + + &paddd ($rndkey1,$rndkey0); # 2nd triplet increment + &paddd ($rndkey0,&QWP(48,"esp")); # 1st triplet increment + &movdqa ($inout0,&QWP(0,"esp")); # load byte swap mask + + &movups ($inout1,&QWP(0x30,$inp)); + &movups ($inout2,&QWP(0x40,$inp)); + &xorps ($inout3,$inout1); + &movups ($inout1,&QWP(0x50,$inp)); + &lea ($inp,&DWP(0x60,$inp)); + &movdqa (&QWP(48,"esp"),$rndkey0); # save 1st triplet + &pshufb ($rndkey0,$inout0); # byte swap + &xorps ($inout4,$inout2); + &movups (&QWP(0x30,$out),$inout3); + &xorps ($inout5,$inout1); + &movdqa (&QWP(64,"esp"),$rndkey1); # save 2nd triplet + &pshufb ($rndkey1,$inout0); # byte swap + &movups (&QWP(0x40,$out),$inout4); + &pshufd ($inout0,$rndkey0,3<<6); + &movups (&QWP(0x50,$out),$inout5); + &lea ($out,&DWP(0x60,$out)); + + &pshufd ($inout1,$rndkey0,2<<6); + &sub ($len,6); + &jnc (&label("ctr32_loop6")); + + &add ($len,6); + &jz (&label("ctr32_ret")); + &movdqu ($inout5,&QWP(0,$key_)); + &mov ($key,$key_); + &pxor ($inout5,&QWP(32,"esp")); # restore count-less ivec + &mov ($rounds,&DWP(240,$key_)); # restore $rounds + +&set_label("ctr32_tail"); + &por ($inout0,$inout5); + &cmp ($len,2); + &jb (&label("ctr32_one")); + + &pshufd ($inout2,$rndkey0,1<<6); + &por ($inout1,$inout5); + &je (&label("ctr32_two")); + + &pshufd ($inout3,$rndkey1,3<<6); + &por ($inout2,$inout5); + &cmp ($len,4); + &jb (&label("ctr32_three")); + + &pshufd ($inout4,$rndkey1,2<<6); + &por ($inout3,$inout5); + &je (&label("ctr32_four")); + + &por ($inout4,$inout5); + &call ("_aesni_encrypt6"); + &movups ($rndkey1,&QWP(0,$inp)); + &movups ($rndkey0,&QWP(0x10,$inp)); + &xorps ($inout0,$rndkey1); + &movups ($rndkey1,&QWP(0x20,$inp)); + &xorps ($inout1,$rndkey0); + &movups ($rndkey0,&QWP(0x30,$inp)); + &xorps ($inout2,$rndkey1); + &movups ($rndkey1,&QWP(0x40,$inp)); + &xorps ($inout3,$rndkey0); + &movups (&QWP(0,$out),$inout0); + &xorps ($inout4,$rndkey1); + &movups (&QWP(0x10,$out),$inout1); + &movups (&QWP(0x20,$out),$inout2); + &movups (&QWP(0x30,$out),$inout3); + &movups (&QWP(0x40,$out),$inout4); + &jmp (&label("ctr32_ret")); + +&set_label("ctr32_one_shortcut",16); + &movups ($inout0,&QWP(0,$rounds_)); # load ivec + &mov ($rounds,&DWP(240,$key)); + +&set_label("ctr32_one"); + if ($inline) + { &aesni_inline_generate1("enc"); } + else + { &call ("_aesni_encrypt1"); } + &movups ($in0,&QWP(0,$inp)); + &xorps ($in0,$inout0); + &movups (&QWP(0,$out),$in0); + &jmp (&label("ctr32_ret")); + +&set_label("ctr32_two",16); + &call ("_aesni_encrypt2"); + &movups ($inout3,&QWP(0,$inp)); + &movups ($inout4,&QWP(0x10,$inp)); + &xorps ($inout0,$inout3); + &xorps ($inout1,$inout4); + &movups (&QWP(0,$out),$inout0); + &movups (&QWP(0x10,$out),$inout1); + &jmp (&label("ctr32_ret")); + +&set_label("ctr32_three",16); + &call ("_aesni_encrypt3"); + &movups ($inout3,&QWP(0,$inp)); + &movups ($inout4,&QWP(0x10,$inp)); + &xorps ($inout0,$inout3); + &movups ($inout5,&QWP(0x20,$inp)); + &xorps ($inout1,$inout4); + &movups (&QWP(0,$out),$inout0); + &xorps ($inout2,$inout5); + &movups (&QWP(0x10,$out),$inout1); + &movups (&QWP(0x20,$out),$inout2); + &jmp (&label("ctr32_ret")); + +&set_label("ctr32_four",16); + &call ("_aesni_encrypt4"); + &movups ($inout4,&QWP(0,$inp)); + &movups ($inout5,&QWP(0x10,$inp)); + &movups ($rndkey1,&QWP(0x20,$inp)); + &xorps ($inout0,$inout4); + &movups ($rndkey0,&QWP(0x30,$inp)); + &xorps ($inout1,$inout5); + &movups (&QWP(0,$out),$inout0); + &xorps ($inout2,$rndkey1); + &movups (&QWP(0x10,$out),$inout1); + &xorps ($inout3,$rndkey0); + &movups (&QWP(0x20,$out),$inout2); + &movups (&QWP(0x30,$out),$inout3); + +&set_label("ctr32_ret"); + &pxor ("xmm0","xmm0"); # clear register bank + &pxor ("xmm1","xmm1"); + &pxor ("xmm2","xmm2"); + &pxor ("xmm3","xmm3"); + &pxor ("xmm4","xmm4"); + &movdqa (&QWP(32,"esp"),"xmm0"); # clear stack + &pxor ("xmm5","xmm5"); + &movdqa (&QWP(48,"esp"),"xmm0"); + &pxor ("xmm6","xmm6"); + &movdqa (&QWP(64,"esp"),"xmm0"); + &pxor ("xmm7","xmm7"); + &mov ("esp",&DWP(80,"esp")); +&function_end("aesni_ctr32_encrypt_blocks"); + +###################################################################### +# void aesni_xts_[en|de]crypt(const char *inp,char *out,size_t len, +# const AES_KEY *key1, const AES_KEY *key2 +# const unsigned char iv[16]); +# +{ my ($tweak,$twtmp,$twres,$twmask)=($rndkey1,$rndkey0,$inout0,$inout1); + +&function_begin("aesni_xts_encrypt"); + &mov ($key,&wparam(4)); # key2 + &mov ($inp,&wparam(5)); # clear-text tweak + + &mov ($rounds,&DWP(240,$key)); # key2->rounds + &movups ($inout0,&QWP(0,$inp)); + if ($inline) + { &aesni_inline_generate1("enc"); } + else + { &call ("_aesni_encrypt1"); } + + &mov ($inp,&wparam(0)); + &mov ($out,&wparam(1)); + &mov ($len,&wparam(2)); + &mov ($key,&wparam(3)); # key1 + + &mov ($key_,"esp"); + &sub ("esp",16*7+8); + &mov ($rounds,&DWP(240,$key)); # key1->rounds + &and ("esp",-16); # align stack + + &mov (&DWP(16*6+0,"esp"),0x87); # compose the magic constant + &mov (&DWP(16*6+4,"esp"),0); + &mov (&DWP(16*6+8,"esp"),1); + &mov (&DWP(16*6+12,"esp"),0); + &mov (&DWP(16*7+0,"esp"),$len); # save original $len + &mov (&DWP(16*7+4,"esp"),$key_); # save original %esp + + &movdqa ($tweak,$inout0); + &pxor ($twtmp,$twtmp); + &movdqa ($twmask,&QWP(6*16,"esp")); # 0x0...010...87 + &pcmpgtd($twtmp,$tweak); # broadcast upper bits + + &and ($len,-16); + &mov ($key_,$key); # backup $key + &mov ($rounds_,$rounds); # backup $rounds + &sub ($len,16*6); + &jc (&label("xts_enc_short")); + + &shl ($rounds,4); + &mov ($rounds_,16); + &sub ($rounds_,$rounds); + &lea ($key,&DWP(32,$key,$rounds)); + &jmp (&label("xts_enc_loop6")); + +&set_label("xts_enc_loop6",16); + for ($i=0;$i<4;$i++) { + &pshufd ($twres,$twtmp,0x13); + &pxor ($twtmp,$twtmp); + &movdqa (&QWP(16*$i,"esp"),$tweak); + &paddq ($tweak,$tweak); # &psllq($tweak,1); + &pand ($twres,$twmask); # isolate carry and residue + &pcmpgtd ($twtmp,$tweak); # broadcast upper bits + &pxor ($tweak,$twres); + } + &pshufd ($inout5,$twtmp,0x13); + &movdqa (&QWP(16*$i++,"esp"),$tweak); + &paddq ($tweak,$tweak); # &psllq($tweak,1); + &$movekey ($rndkey0,&QWP(0,$key_)); + &pand ($inout5,$twmask); # isolate carry and residue + &movups ($inout0,&QWP(0,$inp)); # load input + &pxor ($inout5,$tweak); + + # inline _aesni_encrypt6 prologue and flip xor with tweak and key[0] + &mov ($rounds,$rounds_); # restore $rounds + &movdqu ($inout1,&QWP(16*1,$inp)); + &xorps ($inout0,$rndkey0); # input^=rndkey[0] + &movdqu ($inout2,&QWP(16*2,$inp)); + &pxor ($inout1,$rndkey0); + &movdqu ($inout3,&QWP(16*3,$inp)); + &pxor ($inout2,$rndkey0); + &movdqu ($inout4,&QWP(16*4,$inp)); + &pxor ($inout3,$rndkey0); + &movdqu ($rndkey1,&QWP(16*5,$inp)); + &pxor ($inout4,$rndkey0); + &lea ($inp,&DWP(16*6,$inp)); + &pxor ($inout0,&QWP(16*0,"esp")); # input^=tweak + &movdqa (&QWP(16*$i,"esp"),$inout5); # save last tweak + &pxor ($inout5,$rndkey1); + + &$movekey ($rndkey1,&QWP(16,$key_)); + &pxor ($inout1,&QWP(16*1,"esp")); + &pxor ($inout2,&QWP(16*2,"esp")); + &aesenc ($inout0,$rndkey1); + &pxor ($inout3,&QWP(16*3,"esp")); + &pxor ($inout4,&QWP(16*4,"esp")); + &aesenc ($inout1,$rndkey1); + &pxor ($inout5,$rndkey0); + &$movekey ($rndkey0,&QWP(32,$key_)); + &aesenc ($inout2,$rndkey1); + &aesenc ($inout3,$rndkey1); + &aesenc ($inout4,$rndkey1); + &aesenc ($inout5,$rndkey1); + &call (&label("_aesni_encrypt6_enter")); + + &movdqa ($tweak,&QWP(16*5,"esp")); # last tweak + &pxor ($twtmp,$twtmp); + &xorps ($inout0,&QWP(16*0,"esp")); # output^=tweak + &pcmpgtd ($twtmp,$tweak); # broadcast upper bits + &xorps ($inout1,&QWP(16*1,"esp")); + &movups (&QWP(16*0,$out),$inout0); # write output + &xorps ($inout2,&QWP(16*2,"esp")); + &movups (&QWP(16*1,$out),$inout1); + &xorps ($inout3,&QWP(16*3,"esp")); + &movups (&QWP(16*2,$out),$inout2); + &xorps ($inout4,&QWP(16*4,"esp")); + &movups (&QWP(16*3,$out),$inout3); + &xorps ($inout5,$tweak); + &movups (&QWP(16*4,$out),$inout4); + &pshufd ($twres,$twtmp,0x13); + &movups (&QWP(16*5,$out),$inout5); + &lea ($out,&DWP(16*6,$out)); + &movdqa ($twmask,&QWP(16*6,"esp")); # 0x0...010...87 + + &pxor ($twtmp,$twtmp); + &paddq ($tweak,$tweak); # &psllq($tweak,1); + &pand ($twres,$twmask); # isolate carry and residue + &pcmpgtd($twtmp,$tweak); # broadcast upper bits + &pxor ($tweak,$twres); + + &sub ($len,16*6); + &jnc (&label("xts_enc_loop6")); + + &mov ($rounds,&DWP(240,$key_)); # restore $rounds + &mov ($key,$key_); # restore $key + &mov ($rounds_,$rounds); + +&set_label("xts_enc_short"); + &add ($len,16*6); + &jz (&label("xts_enc_done6x")); + + &movdqa ($inout3,$tweak); # put aside previous tweak + &cmp ($len,0x20); + &jb (&label("xts_enc_one")); + + &pshufd ($twres,$twtmp,0x13); + &pxor ($twtmp,$twtmp); + &paddq ($tweak,$tweak); # &psllq($tweak,1); + &pand ($twres,$twmask); # isolate carry and residue + &pcmpgtd($twtmp,$tweak); # broadcast upper bits + &pxor ($tweak,$twres); + &je (&label("xts_enc_two")); + + &pshufd ($twres,$twtmp,0x13); + &pxor ($twtmp,$twtmp); + &movdqa ($inout4,$tweak); # put aside previous tweak + &paddq ($tweak,$tweak); # &psllq($tweak,1); + &pand ($twres,$twmask); # isolate carry and residue + &pcmpgtd($twtmp,$tweak); # broadcast upper bits + &pxor ($tweak,$twres); + &cmp ($len,0x40); + &jb (&label("xts_enc_three")); + + &pshufd ($twres,$twtmp,0x13); + &pxor ($twtmp,$twtmp); + &movdqa ($inout5,$tweak); # put aside previous tweak + &paddq ($tweak,$tweak); # &psllq($tweak,1); + &pand ($twres,$twmask); # isolate carry and residue + &pcmpgtd($twtmp,$tweak); # broadcast upper bits + &pxor ($tweak,$twres); + &movdqa (&QWP(16*0,"esp"),$inout3); + &movdqa (&QWP(16*1,"esp"),$inout4); + &je (&label("xts_enc_four")); + + &movdqa (&QWP(16*2,"esp"),$inout5); + &pshufd ($inout5,$twtmp,0x13); + &movdqa (&QWP(16*3,"esp"),$tweak); + &paddq ($tweak,$tweak); # &psllq($inout0,1); + &pand ($inout5,$twmask); # isolate carry and residue + &pxor ($inout5,$tweak); + + &movdqu ($inout0,&QWP(16*0,$inp)); # load input + &movdqu ($inout1,&QWP(16*1,$inp)); + &movdqu ($inout2,&QWP(16*2,$inp)); + &pxor ($inout0,&QWP(16*0,"esp")); # input^=tweak + &movdqu ($inout3,&QWP(16*3,$inp)); + &pxor ($inout1,&QWP(16*1,"esp")); + &movdqu ($inout4,&QWP(16*4,$inp)); + &pxor ($inout2,&QWP(16*2,"esp")); + &lea ($inp,&DWP(16*5,$inp)); + &pxor ($inout3,&QWP(16*3,"esp")); + &movdqa (&QWP(16*4,"esp"),$inout5); # save last tweak + &pxor ($inout4,$inout5); + + &call ("_aesni_encrypt6"); + + &movaps ($tweak,&QWP(16*4,"esp")); # last tweak + &xorps ($inout0,&QWP(16*0,"esp")); # output^=tweak + &xorps ($inout1,&QWP(16*1,"esp")); + &xorps ($inout2,&QWP(16*2,"esp")); + &movups (&QWP(16*0,$out),$inout0); # write output + &xorps ($inout3,&QWP(16*3,"esp")); + &movups (&QWP(16*1,$out),$inout1); + &xorps ($inout4,$tweak); + &movups (&QWP(16*2,$out),$inout2); + &movups (&QWP(16*3,$out),$inout3); + &movups (&QWP(16*4,$out),$inout4); + &lea ($out,&DWP(16*5,$out)); + &jmp (&label("xts_enc_done")); + +&set_label("xts_enc_one",16); + &movups ($inout0,&QWP(16*0,$inp)); # load input + &lea ($inp,&DWP(16*1,$inp)); + &xorps ($inout0,$inout3); # input^=tweak + if ($inline) + { &aesni_inline_generate1("enc"); } + else + { &call ("_aesni_encrypt1"); } + &xorps ($inout0,$inout3); # output^=tweak + &movups (&QWP(16*0,$out),$inout0); # write output + &lea ($out,&DWP(16*1,$out)); + + &movdqa ($tweak,$inout3); # last tweak + &jmp (&label("xts_enc_done")); + +&set_label("xts_enc_two",16); + &movaps ($inout4,$tweak); # put aside last tweak + + &movups ($inout0,&QWP(16*0,$inp)); # load input + &movups ($inout1,&QWP(16*1,$inp)); + &lea ($inp,&DWP(16*2,$inp)); + &xorps ($inout0,$inout3); # input^=tweak + &xorps ($inout1,$inout4); + + &call ("_aesni_encrypt2"); + + &xorps ($inout0,$inout3); # output^=tweak + &xorps ($inout1,$inout4); + &movups (&QWP(16*0,$out),$inout0); # write output + &movups (&QWP(16*1,$out),$inout1); + &lea ($out,&DWP(16*2,$out)); + + &movdqa ($tweak,$inout4); # last tweak + &jmp (&label("xts_enc_done")); + +&set_label("xts_enc_three",16); + &movaps ($inout5,$tweak); # put aside last tweak + &movups ($inout0,&QWP(16*0,$inp)); # load input + &movups ($inout1,&QWP(16*1,$inp)); + &movups ($inout2,&QWP(16*2,$inp)); + &lea ($inp,&DWP(16*3,$inp)); + &xorps ($inout0,$inout3); # input^=tweak + &xorps ($inout1,$inout4); + &xorps ($inout2,$inout5); + + &call ("_aesni_encrypt3"); + + &xorps ($inout0,$inout3); # output^=tweak + &xorps ($inout1,$inout4); + &xorps ($inout2,$inout5); + &movups (&QWP(16*0,$out),$inout0); # write output + &movups (&QWP(16*1,$out),$inout1); + &movups (&QWP(16*2,$out),$inout2); + &lea ($out,&DWP(16*3,$out)); + + &movdqa ($tweak,$inout5); # last tweak + &jmp (&label("xts_enc_done")); + +&set_label("xts_enc_four",16); + &movaps ($inout4,$tweak); # put aside last tweak + + &movups ($inout0,&QWP(16*0,$inp)); # load input + &movups ($inout1,&QWP(16*1,$inp)); + &movups ($inout2,&QWP(16*2,$inp)); + &xorps ($inout0,&QWP(16*0,"esp")); # input^=tweak + &movups ($inout3,&QWP(16*3,$inp)); + &lea ($inp,&DWP(16*4,$inp)); + &xorps ($inout1,&QWP(16*1,"esp")); + &xorps ($inout2,$inout5); + &xorps ($inout3,$inout4); + + &call ("_aesni_encrypt4"); + + &xorps ($inout0,&QWP(16*0,"esp")); # output^=tweak + &xorps ($inout1,&QWP(16*1,"esp")); + &xorps ($inout2,$inout5); + &movups (&QWP(16*0,$out),$inout0); # write output + &xorps ($inout3,$inout4); + &movups (&QWP(16*1,$out),$inout1); + &movups (&QWP(16*2,$out),$inout2); + &movups (&QWP(16*3,$out),$inout3); + &lea ($out,&DWP(16*4,$out)); + + &movdqa ($tweak,$inout4); # last tweak + &jmp (&label("xts_enc_done")); + +&set_label("xts_enc_done6x",16); # $tweak is pre-calculated + &mov ($len,&DWP(16*7+0,"esp")); # restore original $len + &and ($len,15); + &jz (&label("xts_enc_ret")); + &movdqa ($inout3,$tweak); + &mov (&DWP(16*7+0,"esp"),$len); # save $len%16 + &jmp (&label("xts_enc_steal")); + +&set_label("xts_enc_done",16); + &mov ($len,&DWP(16*7+0,"esp")); # restore original $len + &pxor ($twtmp,$twtmp); + &and ($len,15); + &jz (&label("xts_enc_ret")); + + &pcmpgtd($twtmp,$tweak); # broadcast upper bits + &mov (&DWP(16*7+0,"esp"),$len); # save $len%16 + &pshufd ($inout3,$twtmp,0x13); + &paddq ($tweak,$tweak); # &psllq($tweak,1); + &pand ($inout3,&QWP(16*6,"esp")); # isolate carry and residue + &pxor ($inout3,$tweak); + +&set_label("xts_enc_steal"); + &movz ($rounds,&BP(0,$inp)); + &movz ($key,&BP(-16,$out)); + &lea ($inp,&DWP(1,$inp)); + &mov (&BP(-16,$out),&LB($rounds)); + &mov (&BP(0,$out),&LB($key)); + &lea ($out,&DWP(1,$out)); + &sub ($len,1); + &jnz (&label("xts_enc_steal")); + + &sub ($out,&DWP(16*7+0,"esp")); # rewind $out + &mov ($key,$key_); # restore $key + &mov ($rounds,$rounds_); # restore $rounds + + &movups ($inout0,&QWP(-16,$out)); # load input + &xorps ($inout0,$inout3); # input^=tweak + if ($inline) + { &aesni_inline_generate1("enc"); } + else + { &call ("_aesni_encrypt1"); } + &xorps ($inout0,$inout3); # output^=tweak + &movups (&QWP(-16,$out),$inout0); # write output + +&set_label("xts_enc_ret"); + &pxor ("xmm0","xmm0"); # clear register bank + &pxor ("xmm1","xmm1"); + &pxor ("xmm2","xmm2"); + &movdqa (&QWP(16*0,"esp"),"xmm0"); # clear stack + &pxor ("xmm3","xmm3"); + &movdqa (&QWP(16*1,"esp"),"xmm0"); + &pxor ("xmm4","xmm4"); + &movdqa (&QWP(16*2,"esp"),"xmm0"); + &pxor ("xmm5","xmm5"); + &movdqa (&QWP(16*3,"esp"),"xmm0"); + &pxor ("xmm6","xmm6"); + &movdqa (&QWP(16*4,"esp"),"xmm0"); + &pxor ("xmm7","xmm7"); + &movdqa (&QWP(16*5,"esp"),"xmm0"); + &mov ("esp",&DWP(16*7+4,"esp")); # restore %esp +&function_end("aesni_xts_encrypt"); + +&function_begin("aesni_xts_decrypt"); + &mov ($key,&wparam(4)); # key2 + &mov ($inp,&wparam(5)); # clear-text tweak + + &mov ($rounds,&DWP(240,$key)); # key2->rounds + &movups ($inout0,&QWP(0,$inp)); + if ($inline) + { &aesni_inline_generate1("enc"); } + else + { &call ("_aesni_encrypt1"); } + + &mov ($inp,&wparam(0)); + &mov ($out,&wparam(1)); + &mov ($len,&wparam(2)); + &mov ($key,&wparam(3)); # key1 + + &mov ($key_,"esp"); + &sub ("esp",16*7+8); + &and ("esp",-16); # align stack + + &xor ($rounds_,$rounds_); # if(len%16) len-=16; + &test ($len,15); + &setnz (&LB($rounds_)); + &shl ($rounds_,4); + &sub ($len,$rounds_); + + &mov (&DWP(16*6+0,"esp"),0x87); # compose the magic constant + &mov (&DWP(16*6+4,"esp"),0); + &mov (&DWP(16*6+8,"esp"),1); + &mov (&DWP(16*6+12,"esp"),0); + &mov (&DWP(16*7+0,"esp"),$len); # save original $len + &mov (&DWP(16*7+4,"esp"),$key_); # save original %esp + + &mov ($rounds,&DWP(240,$key)); # key1->rounds + &mov ($key_,$key); # backup $key + &mov ($rounds_,$rounds); # backup $rounds + + &movdqa ($tweak,$inout0); + &pxor ($twtmp,$twtmp); + &movdqa ($twmask,&QWP(6*16,"esp")); # 0x0...010...87 + &pcmpgtd($twtmp,$tweak); # broadcast upper bits + + &and ($len,-16); + &sub ($len,16*6); + &jc (&label("xts_dec_short")); + + &shl ($rounds,4); + &mov ($rounds_,16); + &sub ($rounds_,$rounds); + &lea ($key,&DWP(32,$key,$rounds)); + &jmp (&label("xts_dec_loop6")); + +&set_label("xts_dec_loop6",16); + for ($i=0;$i<4;$i++) { + &pshufd ($twres,$twtmp,0x13); + &pxor ($twtmp,$twtmp); + &movdqa (&QWP(16*$i,"esp"),$tweak); + &paddq ($tweak,$tweak); # &psllq($tweak,1); + &pand ($twres,$twmask); # isolate carry and residue + &pcmpgtd ($twtmp,$tweak); # broadcast upper bits + &pxor ($tweak,$twres); + } + &pshufd ($inout5,$twtmp,0x13); + &movdqa (&QWP(16*$i++,"esp"),$tweak); + &paddq ($tweak,$tweak); # &psllq($tweak,1); + &$movekey ($rndkey0,&QWP(0,$key_)); + &pand ($inout5,$twmask); # isolate carry and residue + &movups ($inout0,&QWP(0,$inp)); # load input + &pxor ($inout5,$tweak); + + # inline _aesni_encrypt6 prologue and flip xor with tweak and key[0] + &mov ($rounds,$rounds_); + &movdqu ($inout1,&QWP(16*1,$inp)); + &xorps ($inout0,$rndkey0); # input^=rndkey[0] + &movdqu ($inout2,&QWP(16*2,$inp)); + &pxor ($inout1,$rndkey0); + &movdqu ($inout3,&QWP(16*3,$inp)); + &pxor ($inout2,$rndkey0); + &movdqu ($inout4,&QWP(16*4,$inp)); + &pxor ($inout3,$rndkey0); + &movdqu ($rndkey1,&QWP(16*5,$inp)); + &pxor ($inout4,$rndkey0); + &lea ($inp,&DWP(16*6,$inp)); + &pxor ($inout0,&QWP(16*0,"esp")); # input^=tweak + &movdqa (&QWP(16*$i,"esp"),$inout5); # save last tweak + &pxor ($inout5,$rndkey1); + + &$movekey ($rndkey1,&QWP(16,$key_)); + &pxor ($inout1,&QWP(16*1,"esp")); + &pxor ($inout2,&QWP(16*2,"esp")); + &aesdec ($inout0,$rndkey1); + &pxor ($inout3,&QWP(16*3,"esp")); + &pxor ($inout4,&QWP(16*4,"esp")); + &aesdec ($inout1,$rndkey1); + &pxor ($inout5,$rndkey0); + &$movekey ($rndkey0,&QWP(32,$key_)); + &aesdec ($inout2,$rndkey1); + &aesdec ($inout3,$rndkey1); + &aesdec ($inout4,$rndkey1); + &aesdec ($inout5,$rndkey1); + &call (&label("_aesni_decrypt6_enter")); + + &movdqa ($tweak,&QWP(16*5,"esp")); # last tweak + &pxor ($twtmp,$twtmp); + &xorps ($inout0,&QWP(16*0,"esp")); # output^=tweak + &pcmpgtd ($twtmp,$tweak); # broadcast upper bits + &xorps ($inout1,&QWP(16*1,"esp")); + &movups (&QWP(16*0,$out),$inout0); # write output + &xorps ($inout2,&QWP(16*2,"esp")); + &movups (&QWP(16*1,$out),$inout1); + &xorps ($inout3,&QWP(16*3,"esp")); + &movups (&QWP(16*2,$out),$inout2); + &xorps ($inout4,&QWP(16*4,"esp")); + &movups (&QWP(16*3,$out),$inout3); + &xorps ($inout5,$tweak); + &movups (&QWP(16*4,$out),$inout4); + &pshufd ($twres,$twtmp,0x13); + &movups (&QWP(16*5,$out),$inout5); + &lea ($out,&DWP(16*6,$out)); + &movdqa ($twmask,&QWP(16*6,"esp")); # 0x0...010...87 + + &pxor ($twtmp,$twtmp); + &paddq ($tweak,$tweak); # &psllq($tweak,1); + &pand ($twres,$twmask); # isolate carry and residue + &pcmpgtd($twtmp,$tweak); # broadcast upper bits + &pxor ($tweak,$twres); + + &sub ($len,16*6); + &jnc (&label("xts_dec_loop6")); + + &mov ($rounds,&DWP(240,$key_)); # restore $rounds + &mov ($key,$key_); # restore $key + &mov ($rounds_,$rounds); + +&set_label("xts_dec_short"); + &add ($len,16*6); + &jz (&label("xts_dec_done6x")); + + &movdqa ($inout3,$tweak); # put aside previous tweak + &cmp ($len,0x20); + &jb (&label("xts_dec_one")); + + &pshufd ($twres,$twtmp,0x13); + &pxor ($twtmp,$twtmp); + &paddq ($tweak,$tweak); # &psllq($tweak,1); + &pand ($twres,$twmask); # isolate carry and residue + &pcmpgtd($twtmp,$tweak); # broadcast upper bits + &pxor ($tweak,$twres); + &je (&label("xts_dec_two")); + + &pshufd ($twres,$twtmp,0x13); + &pxor ($twtmp,$twtmp); + &movdqa ($inout4,$tweak); # put aside previous tweak + &paddq ($tweak,$tweak); # &psllq($tweak,1); + &pand ($twres,$twmask); # isolate carry and residue + &pcmpgtd($twtmp,$tweak); # broadcast upper bits + &pxor ($tweak,$twres); + &cmp ($len,0x40); + &jb (&label("xts_dec_three")); + + &pshufd ($twres,$twtmp,0x13); + &pxor ($twtmp,$twtmp); + &movdqa ($inout5,$tweak); # put aside previous tweak + &paddq ($tweak,$tweak); # &psllq($tweak,1); + &pand ($twres,$twmask); # isolate carry and residue + &pcmpgtd($twtmp,$tweak); # broadcast upper bits + &pxor ($tweak,$twres); + &movdqa (&QWP(16*0,"esp"),$inout3); + &movdqa (&QWP(16*1,"esp"),$inout4); + &je (&label("xts_dec_four")); + + &movdqa (&QWP(16*2,"esp"),$inout5); + &pshufd ($inout5,$twtmp,0x13); + &movdqa (&QWP(16*3,"esp"),$tweak); + &paddq ($tweak,$tweak); # &psllq($inout0,1); + &pand ($inout5,$twmask); # isolate carry and residue + &pxor ($inout5,$tweak); + + &movdqu ($inout0,&QWP(16*0,$inp)); # load input + &movdqu ($inout1,&QWP(16*1,$inp)); + &movdqu ($inout2,&QWP(16*2,$inp)); + &pxor ($inout0,&QWP(16*0,"esp")); # input^=tweak + &movdqu ($inout3,&QWP(16*3,$inp)); + &pxor ($inout1,&QWP(16*1,"esp")); + &movdqu ($inout4,&QWP(16*4,$inp)); + &pxor ($inout2,&QWP(16*2,"esp")); + &lea ($inp,&DWP(16*5,$inp)); + &pxor ($inout3,&QWP(16*3,"esp")); + &movdqa (&QWP(16*4,"esp"),$inout5); # save last tweak + &pxor ($inout4,$inout5); + + &call ("_aesni_decrypt6"); + + &movaps ($tweak,&QWP(16*4,"esp")); # last tweak + &xorps ($inout0,&QWP(16*0,"esp")); # output^=tweak + &xorps ($inout1,&QWP(16*1,"esp")); + &xorps ($inout2,&QWP(16*2,"esp")); + &movups (&QWP(16*0,$out),$inout0); # write output + &xorps ($inout3,&QWP(16*3,"esp")); + &movups (&QWP(16*1,$out),$inout1); + &xorps ($inout4,$tweak); + &movups (&QWP(16*2,$out),$inout2); + &movups (&QWP(16*3,$out),$inout3); + &movups (&QWP(16*4,$out),$inout4); + &lea ($out,&DWP(16*5,$out)); + &jmp (&label("xts_dec_done")); + +&set_label("xts_dec_one",16); + &movups ($inout0,&QWP(16*0,$inp)); # load input + &lea ($inp,&DWP(16*1,$inp)); + &xorps ($inout0,$inout3); # input^=tweak + if ($inline) + { &aesni_inline_generate1("dec"); } + else + { &call ("_aesni_decrypt1"); } + &xorps ($inout0,$inout3); # output^=tweak + &movups (&QWP(16*0,$out),$inout0); # write output + &lea ($out,&DWP(16*1,$out)); + + &movdqa ($tweak,$inout3); # last tweak + &jmp (&label("xts_dec_done")); + +&set_label("xts_dec_two",16); + &movaps ($inout4,$tweak); # put aside last tweak + + &movups ($inout0,&QWP(16*0,$inp)); # load input + &movups ($inout1,&QWP(16*1,$inp)); + &lea ($inp,&DWP(16*2,$inp)); + &xorps ($inout0,$inout3); # input^=tweak + &xorps ($inout1,$inout4); + + &call ("_aesni_decrypt2"); + + &xorps ($inout0,$inout3); # output^=tweak + &xorps ($inout1,$inout4); + &movups (&QWP(16*0,$out),$inout0); # write output + &movups (&QWP(16*1,$out),$inout1); + &lea ($out,&DWP(16*2,$out)); + + &movdqa ($tweak,$inout4); # last tweak + &jmp (&label("xts_dec_done")); + +&set_label("xts_dec_three",16); + &movaps ($inout5,$tweak); # put aside last tweak + &movups ($inout0,&QWP(16*0,$inp)); # load input + &movups ($inout1,&QWP(16*1,$inp)); + &movups ($inout2,&QWP(16*2,$inp)); + &lea ($inp,&DWP(16*3,$inp)); + &xorps ($inout0,$inout3); # input^=tweak + &xorps ($inout1,$inout4); + &xorps ($inout2,$inout5); + + &call ("_aesni_decrypt3"); + + &xorps ($inout0,$inout3); # output^=tweak + &xorps ($inout1,$inout4); + &xorps ($inout2,$inout5); + &movups (&QWP(16*0,$out),$inout0); # write output + &movups (&QWP(16*1,$out),$inout1); + &movups (&QWP(16*2,$out),$inout2); + &lea ($out,&DWP(16*3,$out)); + + &movdqa ($tweak,$inout5); # last tweak + &jmp (&label("xts_dec_done")); + +&set_label("xts_dec_four",16); + &movaps ($inout4,$tweak); # put aside last tweak + + &movups ($inout0,&QWP(16*0,$inp)); # load input + &movups ($inout1,&QWP(16*1,$inp)); + &movups ($inout2,&QWP(16*2,$inp)); + &xorps ($inout0,&QWP(16*0,"esp")); # input^=tweak + &movups ($inout3,&QWP(16*3,$inp)); + &lea ($inp,&DWP(16*4,$inp)); + &xorps ($inout1,&QWP(16*1,"esp")); + &xorps ($inout2,$inout5); + &xorps ($inout3,$inout4); + + &call ("_aesni_decrypt4"); + + &xorps ($inout0,&QWP(16*0,"esp")); # output^=tweak + &xorps ($inout1,&QWP(16*1,"esp")); + &xorps ($inout2,$inout5); + &movups (&QWP(16*0,$out),$inout0); # write output + &xorps ($inout3,$inout4); + &movups (&QWP(16*1,$out),$inout1); + &movups (&QWP(16*2,$out),$inout2); + &movups (&QWP(16*3,$out),$inout3); + &lea ($out,&DWP(16*4,$out)); + + &movdqa ($tweak,$inout4); # last tweak + &jmp (&label("xts_dec_done")); + +&set_label("xts_dec_done6x",16); # $tweak is pre-calculated + &mov ($len,&DWP(16*7+0,"esp")); # restore original $len + &and ($len,15); + &jz (&label("xts_dec_ret")); + &mov (&DWP(16*7+0,"esp"),$len); # save $len%16 + &jmp (&label("xts_dec_only_one_more")); + +&set_label("xts_dec_done",16); + &mov ($len,&DWP(16*7+0,"esp")); # restore original $len + &pxor ($twtmp,$twtmp); + &and ($len,15); + &jz (&label("xts_dec_ret")); + + &pcmpgtd($twtmp,$tweak); # broadcast upper bits + &mov (&DWP(16*7+0,"esp"),$len); # save $len%16 + &pshufd ($twres,$twtmp,0x13); + &pxor ($twtmp,$twtmp); + &movdqa ($twmask,&QWP(16*6,"esp")); + &paddq ($tweak,$tweak); # &psllq($tweak,1); + &pand ($twres,$twmask); # isolate carry and residue + &pcmpgtd($twtmp,$tweak); # broadcast upper bits + &pxor ($tweak,$twres); + +&set_label("xts_dec_only_one_more"); + &pshufd ($inout3,$twtmp,0x13); + &movdqa ($inout4,$tweak); # put aside previous tweak + &paddq ($tweak,$tweak); # &psllq($tweak,1); + &pand ($inout3,$twmask); # isolate carry and residue + &pxor ($inout3,$tweak); + + &mov ($key,$key_); # restore $key + &mov ($rounds,$rounds_); # restore $rounds + + &movups ($inout0,&QWP(0,$inp)); # load input + &xorps ($inout0,$inout3); # input^=tweak + if ($inline) + { &aesni_inline_generate1("dec"); } + else + { &call ("_aesni_decrypt1"); } + &xorps ($inout0,$inout3); # output^=tweak + &movups (&QWP(0,$out),$inout0); # write output + +&set_label("xts_dec_steal"); + &movz ($rounds,&BP(16,$inp)); + &movz ($key,&BP(0,$out)); + &lea ($inp,&DWP(1,$inp)); + &mov (&BP(0,$out),&LB($rounds)); + &mov (&BP(16,$out),&LB($key)); + &lea ($out,&DWP(1,$out)); + &sub ($len,1); + &jnz (&label("xts_dec_steal")); + + &sub ($out,&DWP(16*7+0,"esp")); # rewind $out + &mov ($key,$key_); # restore $key + &mov ($rounds,$rounds_); # restore $rounds + + &movups ($inout0,&QWP(0,$out)); # load input + &xorps ($inout0,$inout4); # input^=tweak + if ($inline) + { &aesni_inline_generate1("dec"); } + else + { &call ("_aesni_decrypt1"); } + &xorps ($inout0,$inout4); # output^=tweak + &movups (&QWP(0,$out),$inout0); # write output + +&set_label("xts_dec_ret"); + &pxor ("xmm0","xmm0"); # clear register bank + &pxor ("xmm1","xmm1"); + &pxor ("xmm2","xmm2"); + &movdqa (&QWP(16*0,"esp"),"xmm0"); # clear stack + &pxor ("xmm3","xmm3"); + &movdqa (&QWP(16*1,"esp"),"xmm0"); + &pxor ("xmm4","xmm4"); + &movdqa (&QWP(16*2,"esp"),"xmm0"); + &pxor ("xmm5","xmm5"); + &movdqa (&QWP(16*3,"esp"),"xmm0"); + &pxor ("xmm6","xmm6"); + &movdqa (&QWP(16*4,"esp"),"xmm0"); + &pxor ("xmm7","xmm7"); + &movdqa (&QWP(16*5,"esp"),"xmm0"); + &mov ("esp",&DWP(16*7+4,"esp")); # restore %esp +&function_end("aesni_xts_decrypt"); +} +} + +###################################################################### +# void $PREFIX_cbc_encrypt (const void *inp, void *out, +# size_t length, const AES_KEY *key, +# unsigned char *ivp,const int enc); +&function_begin("${PREFIX}_cbc_encrypt"); + &mov ($inp,&wparam(0)); + &mov ($rounds_,"esp"); + &mov ($out,&wparam(1)); + &sub ($rounds_,24); + &mov ($len,&wparam(2)); + &and ($rounds_,-16); + &mov ($key,&wparam(3)); + &mov ($key_,&wparam(4)); + &test ($len,$len); + &jz (&label("cbc_abort")); + + &cmp (&wparam(5),0); + &xchg ($rounds_,"esp"); # alloca + &movups ($ivec,&QWP(0,$key_)); # load IV + &mov ($rounds,&DWP(240,$key)); + &mov ($key_,$key); # backup $key + &mov (&DWP(16,"esp"),$rounds_); # save original %esp + &mov ($rounds_,$rounds); # backup $rounds + &je (&label("cbc_decrypt")); + + &movaps ($inout0,$ivec); + &cmp ($len,16); + &jb (&label("cbc_enc_tail")); + &sub ($len,16); + &jmp (&label("cbc_enc_loop")); + +&set_label("cbc_enc_loop",16); + &movups ($ivec,&QWP(0,$inp)); # input actually + &lea ($inp,&DWP(16,$inp)); + if ($inline) + { &aesni_inline_generate1("enc",$inout0,$ivec); } + else + { &xorps($inout0,$ivec); &call("_aesni_encrypt1"); } + &mov ($rounds,$rounds_); # restore $rounds + &mov ($key,$key_); # restore $key + &movups (&QWP(0,$out),$inout0); # store output + &lea ($out,&DWP(16,$out)); + &sub ($len,16); + &jnc (&label("cbc_enc_loop")); + &add ($len,16); + &jnz (&label("cbc_enc_tail")); + &movaps ($ivec,$inout0); + &pxor ($inout0,$inout0); + &jmp (&label("cbc_ret")); + +&set_label("cbc_enc_tail"); + &mov ("ecx",$len); # zaps $rounds + &data_word(0xA4F3F689); # rep movsb + &mov ("ecx",16); # zero tail + &sub ("ecx",$len); + &xor ("eax","eax"); # zaps $len + &data_word(0xAAF3F689); # rep stosb + &lea ($out,&DWP(-16,$out)); # rewind $out by 1 block + &mov ($rounds,$rounds_); # restore $rounds + &mov ($inp,$out); # $inp and $out are the same + &mov ($key,$key_); # restore $key + &jmp (&label("cbc_enc_loop")); +###################################################################### +&set_label("cbc_decrypt",16); + &cmp ($len,0x50); + &jbe (&label("cbc_dec_tail")); + &movaps (&QWP(0,"esp"),$ivec); # save IV + &sub ($len,0x50); + &jmp (&label("cbc_dec_loop6_enter")); + +&set_label("cbc_dec_loop6",16); + &movaps (&QWP(0,"esp"),$rndkey0); # save IV + &movups (&QWP(0,$out),$inout5); + &lea ($out,&DWP(0x10,$out)); +&set_label("cbc_dec_loop6_enter"); + &movdqu ($inout0,&QWP(0,$inp)); + &movdqu ($inout1,&QWP(0x10,$inp)); + &movdqu ($inout2,&QWP(0x20,$inp)); + &movdqu ($inout3,&QWP(0x30,$inp)); + &movdqu ($inout4,&QWP(0x40,$inp)); + &movdqu ($inout5,&QWP(0x50,$inp)); + + &call ("_aesni_decrypt6"); + + &movups ($rndkey1,&QWP(0,$inp)); + &movups ($rndkey0,&QWP(0x10,$inp)); + &xorps ($inout0,&QWP(0,"esp")); # ^=IV + &xorps ($inout1,$rndkey1); + &movups ($rndkey1,&QWP(0x20,$inp)); + &xorps ($inout2,$rndkey0); + &movups ($rndkey0,&QWP(0x30,$inp)); + &xorps ($inout3,$rndkey1); + &movups ($rndkey1,&QWP(0x40,$inp)); + &xorps ($inout4,$rndkey0); + &movups ($rndkey0,&QWP(0x50,$inp)); # IV + &xorps ($inout5,$rndkey1); + &movups (&QWP(0,$out),$inout0); + &movups (&QWP(0x10,$out),$inout1); + &lea ($inp,&DWP(0x60,$inp)); + &movups (&QWP(0x20,$out),$inout2); + &mov ($rounds,$rounds_); # restore $rounds + &movups (&QWP(0x30,$out),$inout3); + &mov ($key,$key_); # restore $key + &movups (&QWP(0x40,$out),$inout4); + &lea ($out,&DWP(0x50,$out)); + &sub ($len,0x60); + &ja (&label("cbc_dec_loop6")); + + &movaps ($inout0,$inout5); + &movaps ($ivec,$rndkey0); + &add ($len,0x50); + &jle (&label("cbc_dec_clear_tail_collected")); + &movups (&QWP(0,$out),$inout0); + &lea ($out,&DWP(0x10,$out)); +&set_label("cbc_dec_tail"); + &movups ($inout0,&QWP(0,$inp)); + &movaps ($in0,$inout0); + &cmp ($len,0x10); + &jbe (&label("cbc_dec_one")); + + &movups ($inout1,&QWP(0x10,$inp)); + &movaps ($in1,$inout1); + &cmp ($len,0x20); + &jbe (&label("cbc_dec_two")); + + &movups ($inout2,&QWP(0x20,$inp)); + &cmp ($len,0x30); + &jbe (&label("cbc_dec_three")); + + &movups ($inout3,&QWP(0x30,$inp)); + &cmp ($len,0x40); + &jbe (&label("cbc_dec_four")); + + &movups ($inout4,&QWP(0x40,$inp)); + &movaps (&QWP(0,"esp"),$ivec); # save IV + &movups ($inout0,&QWP(0,$inp)); + &xorps ($inout5,$inout5); + &call ("_aesni_decrypt6"); + &movups ($rndkey1,&QWP(0,$inp)); + &movups ($rndkey0,&QWP(0x10,$inp)); + &xorps ($inout0,&QWP(0,"esp")); # ^= IV + &xorps ($inout1,$rndkey1); + &movups ($rndkey1,&QWP(0x20,$inp)); + &xorps ($inout2,$rndkey0); + &movups ($rndkey0,&QWP(0x30,$inp)); + &xorps ($inout3,$rndkey1); + &movups ($ivec,&QWP(0x40,$inp)); # IV + &xorps ($inout4,$rndkey0); + &movups (&QWP(0,$out),$inout0); + &movups (&QWP(0x10,$out),$inout1); + &pxor ($inout1,$inout1); + &movups (&QWP(0x20,$out),$inout2); + &pxor ($inout2,$inout2); + &movups (&QWP(0x30,$out),$inout3); + &pxor ($inout3,$inout3); + &lea ($out,&DWP(0x40,$out)); + &movaps ($inout0,$inout4); + &pxor ($inout4,$inout4); + &sub ($len,0x50); + &jmp (&label("cbc_dec_tail_collected")); + +&set_label("cbc_dec_one",16); + if ($inline) + { &aesni_inline_generate1("dec"); } + else + { &call ("_aesni_decrypt1"); } + &xorps ($inout0,$ivec); + &movaps ($ivec,$in0); + &sub ($len,0x10); + &jmp (&label("cbc_dec_tail_collected")); + +&set_label("cbc_dec_two",16); + &call ("_aesni_decrypt2"); + &xorps ($inout0,$ivec); + &xorps ($inout1,$in0); + &movups (&QWP(0,$out),$inout0); + &movaps ($inout0,$inout1); + &pxor ($inout1,$inout1); + &lea ($out,&DWP(0x10,$out)); + &movaps ($ivec,$in1); + &sub ($len,0x20); + &jmp (&label("cbc_dec_tail_collected")); + +&set_label("cbc_dec_three",16); + &call ("_aesni_decrypt3"); + &xorps ($inout0,$ivec); + &xorps ($inout1,$in0); + &xorps ($inout2,$in1); + &movups (&QWP(0,$out),$inout0); + &movaps ($inout0,$inout2); + &pxor ($inout2,$inout2); + &movups (&QWP(0x10,$out),$inout1); + &pxor ($inout1,$inout1); + &lea ($out,&DWP(0x20,$out)); + &movups ($ivec,&QWP(0x20,$inp)); + &sub ($len,0x30); + &jmp (&label("cbc_dec_tail_collected")); + +&set_label("cbc_dec_four",16); + &call ("_aesni_decrypt4"); + &movups ($rndkey1,&QWP(0x10,$inp)); + &movups ($rndkey0,&QWP(0x20,$inp)); + &xorps ($inout0,$ivec); + &movups ($ivec,&QWP(0x30,$inp)); + &xorps ($inout1,$in0); + &movups (&QWP(0,$out),$inout0); + &xorps ($inout2,$rndkey1); + &movups (&QWP(0x10,$out),$inout1); + &pxor ($inout1,$inout1); + &xorps ($inout3,$rndkey0); + &movups (&QWP(0x20,$out),$inout2); + &pxor ($inout2,$inout2); + &lea ($out,&DWP(0x30,$out)); + &movaps ($inout0,$inout3); + &pxor ($inout3,$inout3); + &sub ($len,0x40); + &jmp (&label("cbc_dec_tail_collected")); + +&set_label("cbc_dec_clear_tail_collected",16); + &pxor ($inout1,$inout1); + &pxor ($inout2,$inout2); + &pxor ($inout3,$inout3); + &pxor ($inout4,$inout4); +&set_label("cbc_dec_tail_collected"); + &and ($len,15); + &jnz (&label("cbc_dec_tail_partial")); + &movups (&QWP(0,$out),$inout0); + &pxor ($rndkey0,$rndkey0); + &jmp (&label("cbc_ret")); + +&set_label("cbc_dec_tail_partial",16); + &movaps (&QWP(0,"esp"),$inout0); + &pxor ($rndkey0,$rndkey0); + &mov ("ecx",16); + &mov ($inp,"esp"); + &sub ("ecx",$len); + &data_word(0xA4F3F689); # rep movsb + &movdqa (&QWP(0,"esp"),$inout0); + +&set_label("cbc_ret"); + &mov ("esp",&DWP(16,"esp")); # pull original %esp + &mov ($key_,&wparam(4)); + &pxor ($inout0,$inout0); + &pxor ($rndkey1,$rndkey1); + &movups (&QWP(0,$key_),$ivec); # output IV + &pxor ($ivec,$ivec); +&set_label("cbc_abort"); +&function_end("${PREFIX}_cbc_encrypt"); + +###################################################################### +# Mechanical port from aesni-x86_64.pl. +# +# _aesni_set_encrypt_key is private interface, +# input: +# "eax" const unsigned char *userKey +# $rounds int bits +# $key AES_KEY *key +# output: +# "eax" return code +# $round rounds + +&function_begin_B("_aesni_set_encrypt_key"); + &push ("ebp"); + &push ("ebx"); + &test ("eax","eax"); + &jz (&label("bad_pointer")); + &test ($key,$key); + &jz (&label("bad_pointer")); + + &call (&label("pic")); +&set_label("pic"); + &blindpop("ebx"); + &lea ("ebx",&DWP(&label("key_const")."-".&label("pic"),"ebx")); + + &picmeup("ebp","OPENSSL_ia32cap_P","ebx",&label("key_const")); + &movups ("xmm0",&QWP(0,"eax")); # pull first 128 bits of *userKey + &xorps ("xmm4","xmm4"); # low dword of xmm4 is assumed 0 + &mov ("ebp",&DWP(4,"ebp")); + &lea ($key,&DWP(16,$key)); + &and ("ebp",1<<28|1<<11); # AVX and XOP bits + &cmp ($rounds,256); + &je (&label("14rounds")); + &cmp ($rounds,192); + &je (&label("12rounds")); + &cmp ($rounds,128); + &jne (&label("bad_keybits")); + +&set_label("10rounds",16); + &cmp ("ebp",1<<28); + &je (&label("10rounds_alt")); + + &mov ($rounds,9); + &$movekey (&QWP(-16,$key),"xmm0"); # round 0 + &aeskeygenassist("xmm1","xmm0",0x01); # round 1 + &call (&label("key_128_cold")); + &aeskeygenassist("xmm1","xmm0",0x2); # round 2 + &call (&label("key_128")); + &aeskeygenassist("xmm1","xmm0",0x04); # round 3 + &call (&label("key_128")); + &aeskeygenassist("xmm1","xmm0",0x08); # round 4 + &call (&label("key_128")); + &aeskeygenassist("xmm1","xmm0",0x10); # round 5 + &call (&label("key_128")); + &aeskeygenassist("xmm1","xmm0",0x20); # round 6 + &call (&label("key_128")); + &aeskeygenassist("xmm1","xmm0",0x40); # round 7 + &call (&label("key_128")); + &aeskeygenassist("xmm1","xmm0",0x80); # round 8 + &call (&label("key_128")); + &aeskeygenassist("xmm1","xmm0",0x1b); # round 9 + &call (&label("key_128")); + &aeskeygenassist("xmm1","xmm0",0x36); # round 10 + &call (&label("key_128")); + &$movekey (&QWP(0,$key),"xmm0"); + &mov (&DWP(80,$key),$rounds); + + &jmp (&label("good_key")); + +&set_label("key_128",16); + &$movekey (&QWP(0,$key),"xmm0"); + &lea ($key,&DWP(16,$key)); +&set_label("key_128_cold"); + &shufps ("xmm4","xmm0",0b00010000); + &xorps ("xmm0","xmm4"); + &shufps ("xmm4","xmm0",0b10001100); + &xorps ("xmm0","xmm4"); + &shufps ("xmm1","xmm1",0b11111111); # critical path + &xorps ("xmm0","xmm1"); + &ret(); + +&set_label("10rounds_alt",16); + &movdqa ("xmm5",&QWP(0x00,"ebx")); + &mov ($rounds,8); + &movdqa ("xmm4",&QWP(0x20,"ebx")); + &movdqa ("xmm2","xmm0"); + &movdqu (&QWP(-16,$key),"xmm0"); + +&set_label("loop_key128"); + &pshufb ("xmm0","xmm5"); + &aesenclast ("xmm0","xmm4"); + &pslld ("xmm4",1); + &lea ($key,&DWP(16,$key)); + + &movdqa ("xmm3","xmm2"); + &pslldq ("xmm2",4); + &pxor ("xmm3","xmm2"); + &pslldq ("xmm2",4); + &pxor ("xmm3","xmm2"); + &pslldq ("xmm2",4); + &pxor ("xmm2","xmm3"); + + &pxor ("xmm0","xmm2"); + &movdqu (&QWP(-16,$key),"xmm0"); + &movdqa ("xmm2","xmm0"); + + &dec ($rounds); + &jnz (&label("loop_key128")); + + &movdqa ("xmm4",&QWP(0x30,"ebx")); + + &pshufb ("xmm0","xmm5"); + &aesenclast ("xmm0","xmm4"); + &pslld ("xmm4",1); + + &movdqa ("xmm3","xmm2"); + &pslldq ("xmm2",4); + &pxor ("xmm3","xmm2"); + &pslldq ("xmm2",4); + &pxor ("xmm3","xmm2"); + &pslldq ("xmm2",4); + &pxor ("xmm2","xmm3"); + + &pxor ("xmm0","xmm2"); + &movdqu (&QWP(0,$key),"xmm0"); + + &movdqa ("xmm2","xmm0"); + &pshufb ("xmm0","xmm5"); + &aesenclast ("xmm0","xmm4"); + + &movdqa ("xmm3","xmm2"); + &pslldq ("xmm2",4); + &pxor ("xmm3","xmm2"); + &pslldq ("xmm2",4); + &pxor ("xmm3","xmm2"); + &pslldq ("xmm2",4); + &pxor ("xmm2","xmm3"); + + &pxor ("xmm0","xmm2"); + &movdqu (&QWP(16,$key),"xmm0"); + + &mov ($rounds,9); + &mov (&DWP(96,$key),$rounds); + + &jmp (&label("good_key")); + +&set_label("12rounds",16); + &movq ("xmm2",&QWP(16,"eax")); # remaining 1/3 of *userKey + &cmp ("ebp",1<<28); + &je (&label("12rounds_alt")); + + &mov ($rounds,11); + &$movekey (&QWP(-16,$key),"xmm0"); # round 0 + &aeskeygenassist("xmm1","xmm2",0x01); # round 1,2 + &call (&label("key_192a_cold")); + &aeskeygenassist("xmm1","xmm2",0x02); # round 2,3 + &call (&label("key_192b")); + &aeskeygenassist("xmm1","xmm2",0x04); # round 4,5 + &call (&label("key_192a")); + &aeskeygenassist("xmm1","xmm2",0x08); # round 5,6 + &call (&label("key_192b")); + &aeskeygenassist("xmm1","xmm2",0x10); # round 7,8 + &call (&label("key_192a")); + &aeskeygenassist("xmm1","xmm2",0x20); # round 8,9 + &call (&label("key_192b")); + &aeskeygenassist("xmm1","xmm2",0x40); # round 10,11 + &call (&label("key_192a")); + &aeskeygenassist("xmm1","xmm2",0x80); # round 11,12 + &call (&label("key_192b")); + &$movekey (&QWP(0,$key),"xmm0"); + &mov (&DWP(48,$key),$rounds); + + &jmp (&label("good_key")); + +&set_label("key_192a",16); + &$movekey (&QWP(0,$key),"xmm0"); + &lea ($key,&DWP(16,$key)); +&set_label("key_192a_cold",16); + &movaps ("xmm5","xmm2"); +&set_label("key_192b_warm"); + &shufps ("xmm4","xmm0",0b00010000); + &movdqa ("xmm3","xmm2"); + &xorps ("xmm0","xmm4"); + &shufps ("xmm4","xmm0",0b10001100); + &pslldq ("xmm3",4); + &xorps ("xmm0","xmm4"); + &pshufd ("xmm1","xmm1",0b01010101); # critical path + &pxor ("xmm2","xmm3"); + &pxor ("xmm0","xmm1"); + &pshufd ("xmm3","xmm0",0b11111111); + &pxor ("xmm2","xmm3"); + &ret(); + +&set_label("key_192b",16); + &movaps ("xmm3","xmm0"); + &shufps ("xmm5","xmm0",0b01000100); + &$movekey (&QWP(0,$key),"xmm5"); + &shufps ("xmm3","xmm2",0b01001110); + &$movekey (&QWP(16,$key),"xmm3"); + &lea ($key,&DWP(32,$key)); + &jmp (&label("key_192b_warm")); + +&set_label("12rounds_alt",16); + &movdqa ("xmm5",&QWP(0x10,"ebx")); + &movdqa ("xmm4",&QWP(0x20,"ebx")); + &mov ($rounds,8); + &movdqu (&QWP(-16,$key),"xmm0"); + +&set_label("loop_key192"); + &movq (&QWP(0,$key),"xmm2"); + &movdqa ("xmm1","xmm2"); + &pshufb ("xmm2","xmm5"); + &aesenclast ("xmm2","xmm4"); + &pslld ("xmm4",1); + &lea ($key,&DWP(24,$key)); + + &movdqa ("xmm3","xmm0"); + &pslldq ("xmm0",4); + &pxor ("xmm3","xmm0"); + &pslldq ("xmm0",4); + &pxor ("xmm3","xmm0"); + &pslldq ("xmm0",4); + &pxor ("xmm0","xmm3"); + + &pshufd ("xmm3","xmm0",0xff); + &pxor ("xmm3","xmm1"); + &pslldq ("xmm1",4); + &pxor ("xmm3","xmm1"); + + &pxor ("xmm0","xmm2"); + &pxor ("xmm2","xmm3"); + &movdqu (&QWP(-16,$key),"xmm0"); + + &dec ($rounds); + &jnz (&label("loop_key192")); + + &mov ($rounds,11); + &mov (&DWP(32,$key),$rounds); + + &jmp (&label("good_key")); + +&set_label("14rounds",16); + &movups ("xmm2",&QWP(16,"eax")); # remaining half of *userKey + &lea ($key,&DWP(16,$key)); + &cmp ("ebp",1<<28); + &je (&label("14rounds_alt")); + + &mov ($rounds,13); + &$movekey (&QWP(-32,$key),"xmm0"); # round 0 + &$movekey (&QWP(-16,$key),"xmm2"); # round 1 + &aeskeygenassist("xmm1","xmm2",0x01); # round 2 + &call (&label("key_256a_cold")); + &aeskeygenassist("xmm1","xmm0",0x01); # round 3 + &call (&label("key_256b")); + &aeskeygenassist("xmm1","xmm2",0x02); # round 4 + &call (&label("key_256a")); + &aeskeygenassist("xmm1","xmm0",0x02); # round 5 + &call (&label("key_256b")); + &aeskeygenassist("xmm1","xmm2",0x04); # round 6 + &call (&label("key_256a")); + &aeskeygenassist("xmm1","xmm0",0x04); # round 7 + &call (&label("key_256b")); + &aeskeygenassist("xmm1","xmm2",0x08); # round 8 + &call (&label("key_256a")); + &aeskeygenassist("xmm1","xmm0",0x08); # round 9 + &call (&label("key_256b")); + &aeskeygenassist("xmm1","xmm2",0x10); # round 10 + &call (&label("key_256a")); + &aeskeygenassist("xmm1","xmm0",0x10); # round 11 + &call (&label("key_256b")); + &aeskeygenassist("xmm1","xmm2",0x20); # round 12 + &call (&label("key_256a")); + &aeskeygenassist("xmm1","xmm0",0x20); # round 13 + &call (&label("key_256b")); + &aeskeygenassist("xmm1","xmm2",0x40); # round 14 + &call (&label("key_256a")); + &$movekey (&QWP(0,$key),"xmm0"); + &mov (&DWP(16,$key),$rounds); + &xor ("eax","eax"); + + &jmp (&label("good_key")); + +&set_label("key_256a",16); + &$movekey (&QWP(0,$key),"xmm2"); + &lea ($key,&DWP(16,$key)); +&set_label("key_256a_cold"); + &shufps ("xmm4","xmm0",0b00010000); + &xorps ("xmm0","xmm4"); + &shufps ("xmm4","xmm0",0b10001100); + &xorps ("xmm0","xmm4"); + &shufps ("xmm1","xmm1",0b11111111); # critical path + &xorps ("xmm0","xmm1"); + &ret(); + +&set_label("key_256b",16); + &$movekey (&QWP(0,$key),"xmm0"); + &lea ($key,&DWP(16,$key)); + + &shufps ("xmm4","xmm2",0b00010000); + &xorps ("xmm2","xmm4"); + &shufps ("xmm4","xmm2",0b10001100); + &xorps ("xmm2","xmm4"); + &shufps ("xmm1","xmm1",0b10101010); # critical path + &xorps ("xmm2","xmm1"); + &ret(); + +&set_label("14rounds_alt",16); + &movdqa ("xmm5",&QWP(0x00,"ebx")); + &movdqa ("xmm4",&QWP(0x20,"ebx")); + &mov ($rounds,7); + &movdqu (&QWP(-32,$key),"xmm0"); + &movdqa ("xmm1","xmm2"); + &movdqu (&QWP(-16,$key),"xmm2"); + +&set_label("loop_key256"); + &pshufb ("xmm2","xmm5"); + &aesenclast ("xmm2","xmm4"); + + &movdqa ("xmm3","xmm0"); + &pslldq ("xmm0",4); + &pxor ("xmm3","xmm0"); + &pslldq ("xmm0",4); + &pxor ("xmm3","xmm0"); + &pslldq ("xmm0",4); + &pxor ("xmm0","xmm3"); + &pslld ("xmm4",1); + + &pxor ("xmm0","xmm2"); + &movdqu (&QWP(0,$key),"xmm0"); + + &dec ($rounds); + &jz (&label("done_key256")); + + &pshufd ("xmm2","xmm0",0xff); + &pxor ("xmm3","xmm3"); + &aesenclast ("xmm2","xmm3"); + + &movdqa ("xmm3","xmm1") + &pslldq ("xmm1",4); + &pxor ("xmm3","xmm1"); + &pslldq ("xmm1",4); + &pxor ("xmm3","xmm1"); + &pslldq ("xmm1",4); + &pxor ("xmm1","xmm3"); + + &pxor ("xmm2","xmm1"); + &movdqu (&QWP(16,$key),"xmm2"); + &lea ($key,&DWP(32,$key)); + &movdqa ("xmm1","xmm2"); + &jmp (&label("loop_key256")); + +&set_label("done_key256"); + &mov ($rounds,13); + &mov (&DWP(16,$key),$rounds); + +&set_label("good_key"); + &pxor ("xmm0","xmm0"); + &pxor ("xmm1","xmm1"); + &pxor ("xmm2","xmm2"); + &pxor ("xmm3","xmm3"); + &pxor ("xmm4","xmm4"); + &pxor ("xmm5","xmm5"); + &xor ("eax","eax"); + &pop ("ebx"); + &pop ("ebp"); + &ret (); + +&set_label("bad_pointer",4); + &mov ("eax",-1); + &pop ("ebx"); + &pop ("ebp"); + &ret (); +&set_label("bad_keybits",4); + &pxor ("xmm0","xmm0"); + &mov ("eax",-2); + &pop ("ebx"); + &pop ("ebp"); + &ret (); +&function_end_B("_aesni_set_encrypt_key"); + +# int $PREFIX_set_encrypt_key (const unsigned char *userKey, int bits, +# AES_KEY *key) +&function_begin_B("${PREFIX}_set_encrypt_key"); + &mov ("eax",&wparam(0)); + &mov ($rounds,&wparam(1)); + &mov ($key,&wparam(2)); + &call ("_aesni_set_encrypt_key"); + &ret (); +&function_end_B("${PREFIX}_set_encrypt_key"); + +# int $PREFIX_set_decrypt_key (const unsigned char *userKey, int bits, +# AES_KEY *key) +&function_begin_B("${PREFIX}_set_decrypt_key"); + &mov ("eax",&wparam(0)); + &mov ($rounds,&wparam(1)); + &mov ($key,&wparam(2)); + &call ("_aesni_set_encrypt_key"); + &mov ($key,&wparam(2)); + &shl ($rounds,4); # rounds-1 after _aesni_set_encrypt_key + &test ("eax","eax"); + &jnz (&label("dec_key_ret")); + &lea ("eax",&DWP(16,$key,$rounds)); # end of key schedule + + &$movekey ("xmm0",&QWP(0,$key)); # just swap + &$movekey ("xmm1",&QWP(0,"eax")); + &$movekey (&QWP(0,"eax"),"xmm0"); + &$movekey (&QWP(0,$key),"xmm1"); + &lea ($key,&DWP(16,$key)); + &lea ("eax",&DWP(-16,"eax")); + +&set_label("dec_key_inverse"); + &$movekey ("xmm0",&QWP(0,$key)); # swap and inverse + &$movekey ("xmm1",&QWP(0,"eax")); + &aesimc ("xmm0","xmm0"); + &aesimc ("xmm1","xmm1"); + &lea ($key,&DWP(16,$key)); + &lea ("eax",&DWP(-16,"eax")); + &$movekey (&QWP(16,"eax"),"xmm0"); + &$movekey (&QWP(-16,$key),"xmm1"); + &cmp ("eax",$key); + &ja (&label("dec_key_inverse")); + + &$movekey ("xmm0",&QWP(0,$key)); # inverse middle + &aesimc ("xmm0","xmm0"); + &$movekey (&QWP(0,$key),"xmm0"); + + &pxor ("xmm0","xmm0"); + &pxor ("xmm1","xmm1"); + &xor ("eax","eax"); # return success +&set_label("dec_key_ret"); + &ret (); +&function_end_B("${PREFIX}_set_decrypt_key"); + +&set_label("key_const",64); +&data_word(0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d); +&data_word(0x04070605,0x04070605,0x04070605,0x04070605); +&data_word(1,1,1,1); +&data_word(0x1b,0x1b,0x1b,0x1b); +&asciz("AES for Intel AES-NI, CRYPTOGAMS by "); + +&asm_finish(); diff --git a/TMessagesProj/jni/boringssl/crypto/aes/asm/aesni-x86_64.pl b/TMessagesProj/jni/boringssl/crypto/aes/asm/aesni-x86_64.pl new file mode 100644 index 00000000..25ca574f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/aes/asm/aesni-x86_64.pl @@ -0,0 +1,4048 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# This module implements support for Intel AES-NI extension. In +# OpenSSL context it's used with Intel engine, but can also be used as +# drop-in replacement for crypto/aes/asm/aes-x86_64.pl [see below for +# details]. +# +# Performance. +# +# Given aes(enc|dec) instructions' latency asymptotic performance for +# non-parallelizable modes such as CBC encrypt is 3.75 cycles per byte +# processed with 128-bit key. And given their throughput asymptotic +# performance for parallelizable modes is 1.25 cycles per byte. Being +# asymptotic limit it's not something you commonly achieve in reality, +# but how close does one get? Below are results collected for +# different modes and block sized. Pairs of numbers are for en-/ +# decryption. +# +# 16-byte 64-byte 256-byte 1-KB 8-KB +# ECB 4.25/4.25 1.38/1.38 1.28/1.28 1.26/1.26 1.26/1.26 +# CTR 5.42/5.42 1.92/1.92 1.44/1.44 1.28/1.28 1.26/1.26 +# CBC 4.38/4.43 4.15/1.43 4.07/1.32 4.07/1.29 4.06/1.28 +# CCM 5.66/9.42 4.42/5.41 4.16/4.40 4.09/4.15 4.06/4.07 +# OFB 5.42/5.42 4.64/4.64 4.44/4.44 4.39/4.39 4.38/4.38 +# CFB 5.73/5.85 5.56/5.62 5.48/5.56 5.47/5.55 5.47/5.55 +# +# ECB, CTR, CBC and CCM results are free from EVP overhead. This means +# that otherwise used 'openssl speed -evp aes-128-??? -engine aesni +# [-decrypt]' will exhibit 10-15% worse results for smaller blocks. +# The results were collected with specially crafted speed.c benchmark +# in order to compare them with results reported in "Intel Advanced +# Encryption Standard (AES) New Instruction Set" White Paper Revision +# 3.0 dated May 2010. All above results are consistently better. This +# module also provides better performance for block sizes smaller than +# 128 bytes in points *not* represented in the above table. +# +# Looking at the results for 8-KB buffer. +# +# CFB and OFB results are far from the limit, because implementation +# uses "generic" CRYPTO_[c|o]fb128_encrypt interfaces relying on +# single-block aesni_encrypt, which is not the most optimal way to go. +# CBC encrypt result is unexpectedly high and there is no documented +# explanation for it. Seemingly there is a small penalty for feeding +# the result back to AES unit the way it's done in CBC mode. There is +# nothing one can do and the result appears optimal. CCM result is +# identical to CBC, because CBC-MAC is essentially CBC encrypt without +# saving output. CCM CTR "stays invisible," because it's neatly +# interleaved wih CBC-MAC. This provides ~30% improvement over +# "straghtforward" CCM implementation with CTR and CBC-MAC performed +# disjointly. Parallelizable modes practically achieve the theoretical +# limit. +# +# Looking at how results vary with buffer size. +# +# Curves are practically saturated at 1-KB buffer size. In most cases +# "256-byte" performance is >95%, and "64-byte" is ~90% of "8-KB" one. +# CTR curve doesn't follow this pattern and is "slowest" changing one +# with "256-byte" result being 87% of "8-KB." This is because overhead +# in CTR mode is most computationally intensive. Small-block CCM +# decrypt is slower than encrypt, because first CTR and last CBC-MAC +# iterations can't be interleaved. +# +# Results for 192- and 256-bit keys. +# +# EVP-free results were observed to scale perfectly with number of +# rounds for larger block sizes, i.e. 192-bit result being 10/12 times +# lower and 256-bit one - 10/14. Well, in CBC encrypt case differences +# are a tad smaller, because the above mentioned penalty biases all +# results by same constant value. In similar way function call +# overhead affects small-block performance, as well as OFB and CFB +# results. Differences are not large, most common coefficients are +# 10/11.7 and 10/13.4 (as opposite to 10/12.0 and 10/14.0), but one +# observe even 10/11.2 and 10/12.4 (CTR, OFB, CFB)... + +# January 2011 +# +# While Westmere processor features 6 cycles latency for aes[enc|dec] +# instructions, which can be scheduled every second cycle, Sandy +# Bridge spends 8 cycles per instruction, but it can schedule them +# every cycle. This means that code targeting Westmere would perform +# suboptimally on Sandy Bridge. Therefore this update. +# +# In addition, non-parallelizable CBC encrypt (as well as CCM) is +# optimized. Relative improvement might appear modest, 8% on Westmere, +# but in absolute terms it's 3.77 cycles per byte encrypted with +# 128-bit key on Westmere, and 5.07 - on Sandy Bridge. These numbers +# should be compared to asymptotic limits of 3.75 for Westmere and +# 5.00 for Sandy Bridge. Actually, the fact that they get this close +# to asymptotic limits is quite amazing. Indeed, the limit is +# calculated as latency times number of rounds, 10 for 128-bit key, +# and divided by 16, the number of bytes in block, or in other words +# it accounts *solely* for aesenc instructions. But there are extra +# instructions, and numbers so close to the asymptotic limits mean +# that it's as if it takes as little as *one* additional cycle to +# execute all of them. How is it possible? It is possible thanks to +# out-of-order execution logic, which manages to overlap post- +# processing of previous block, things like saving the output, with +# actual encryption of current block, as well as pre-processing of +# current block, things like fetching input and xor-ing it with +# 0-round element of the key schedule, with actual encryption of +# previous block. Keep this in mind... +# +# For parallelizable modes, such as ECB, CBC decrypt, CTR, higher +# performance is achieved by interleaving instructions working on +# independent blocks. In which case asymptotic limit for such modes +# can be obtained by dividing above mentioned numbers by AES +# instructions' interleave factor. Westmere can execute at most 3 +# instructions at a time, meaning that optimal interleave factor is 3, +# and that's where the "magic" number of 1.25 come from. "Optimal +# interleave factor" means that increase of interleave factor does +# not improve performance. The formula has proven to reflect reality +# pretty well on Westmere... Sandy Bridge on the other hand can +# execute up to 8 AES instructions at a time, so how does varying +# interleave factor affect the performance? Here is table for ECB +# (numbers are cycles per byte processed with 128-bit key): +# +# instruction interleave factor 3x 6x 8x +# theoretical asymptotic limit 1.67 0.83 0.625 +# measured performance for 8KB block 1.05 0.86 0.84 +# +# "as if" interleave factor 4.7x 5.8x 6.0x +# +# Further data for other parallelizable modes: +# +# CBC decrypt 1.16 0.93 0.74 +# CTR 1.14 0.91 0.74 +# +# Well, given 3x column it's probably inappropriate to call the limit +# asymptotic, if it can be surpassed, isn't it? What happens there? +# Rewind to CBC paragraph for the answer. Yes, out-of-order execution +# magic is responsible for this. Processor overlaps not only the +# additional instructions with AES ones, but even AES instuctions +# processing adjacent triplets of independent blocks. In the 6x case +# additional instructions still claim disproportionally small amount +# of additional cycles, but in 8x case number of instructions must be +# a tad too high for out-of-order logic to cope with, and AES unit +# remains underutilized... As you can see 8x interleave is hardly +# justifiable, so there no need to feel bad that 32-bit aesni-x86.pl +# utilizies 6x interleave because of limited register bank capacity. +# +# Higher interleave factors do have negative impact on Westmere +# performance. While for ECB mode it's negligible ~1.5%, other +# parallelizables perform ~5% worse, which is outweighed by ~25% +# improvement on Sandy Bridge. To balance regression on Westmere +# CTR mode was implemented with 6x aesenc interleave factor. + +# April 2011 +# +# Add aesni_xts_[en|de]crypt. Westmere spends 1.25 cycles processing +# one byte out of 8KB with 128-bit key, Sandy Bridge - 0.90. Just like +# in CTR mode AES instruction interleave factor was chosen to be 6x. + +###################################################################### +# Current large-block performance in cycles per byte processed with +# 128-bit key (less is better). +# +# CBC en-/decrypt CTR XTS ECB +# Westmere 3.77/1.25 1.25 1.25 1.26 +# * Bridge 5.07/0.74 0.75 0.90 0.85 +# Haswell 4.44/0.63 0.63 0.73 0.63 +# Silvermont 5.75/3.54 3.56 4.12 3.87(*) +# Bulldozer 5.77/0.70 0.72 0.90 0.70 +# +# (*) Atom Silvermont ECB result is suboptimal because of penalties +# incurred by operations on %xmm8-15. As ECB is not considered +# critical, nothing was done to mitigate the problem. + +$PREFIX="aesni"; # if $PREFIX is set to "AES", the script + # generates drop-in replacement for + # crypto/aes/asm/aes-x86_64.pl:-) + +$flavour = shift; +$output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or +die "can't locate x86_64-xlate.pl"; + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +$movkey = $PREFIX eq "aesni" ? "movups" : "movups"; +@_4args=$win64? ("%rcx","%rdx","%r8", "%r9") : # Win64 order + ("%rdi","%rsi","%rdx","%rcx"); # Unix order + +$code=".text\n"; +$code.=".extern OPENSSL_ia32cap_P\n"; + +$rounds="%eax"; # input to and changed by aesni_[en|de]cryptN !!! +# this is natural Unix argument order for public $PREFIX_[ecb|cbc]_encrypt ... +$inp="%rdi"; +$out="%rsi"; +$len="%rdx"; +$key="%rcx"; # input to and changed by aesni_[en|de]cryptN !!! +$ivp="%r8"; # cbc, ctr, ... + +$rnds_="%r10d"; # backup copy for $rounds +$key_="%r11"; # backup copy for $key + +# %xmm register layout +$rndkey0="%xmm0"; $rndkey1="%xmm1"; +$inout0="%xmm2"; $inout1="%xmm3"; +$inout2="%xmm4"; $inout3="%xmm5"; +$inout4="%xmm6"; $inout5="%xmm7"; +$inout6="%xmm8"; $inout7="%xmm9"; + +$in2="%xmm6"; $in1="%xmm7"; # used in CBC decrypt, CTR, ... +$in0="%xmm8"; $iv="%xmm9"; + +# Inline version of internal aesni_[en|de]crypt1. +# +# Why folded loop? Because aes[enc|dec] is slow enough to accommodate +# cycles which take care of loop variables... +{ my $sn; +sub aesni_generate1 { +my ($p,$key,$rounds,$inout,$ivec)=@_; $inout=$inout0 if (!defined($inout)); +++$sn; +$code.=<<___; + $movkey ($key),$rndkey0 + $movkey 16($key),$rndkey1 +___ +$code.=<<___ if (defined($ivec)); + xorps $rndkey0,$ivec + lea 32($key),$key + xorps $ivec,$inout +___ +$code.=<<___ if (!defined($ivec)); + lea 32($key),$key + xorps $rndkey0,$inout +___ +$code.=<<___; +.Loop_${p}1_$sn: + aes${p} $rndkey1,$inout + dec $rounds + $movkey ($key),$rndkey1 + lea 16($key),$key + jnz .Loop_${p}1_$sn # loop body is 16 bytes + aes${p}last $rndkey1,$inout +___ +}} +# void $PREFIX_[en|de]crypt (const void *inp,void *out,const AES_KEY *key); +# +{ my ($inp,$out,$key) = @_4args; + +$code.=<<___; +.globl ${PREFIX}_encrypt +.type ${PREFIX}_encrypt,\@abi-omnipotent +.align 16 +${PREFIX}_encrypt: + movups ($inp),$inout0 # load input + mov 240($key),$rounds # key->rounds +___ + &aesni_generate1("enc",$key,$rounds); +$code.=<<___; + pxor $rndkey0,$rndkey0 # clear register bank + pxor $rndkey1,$rndkey1 + movups $inout0,($out) # output + pxor $inout0,$inout0 + ret +.size ${PREFIX}_encrypt,.-${PREFIX}_encrypt + +.globl ${PREFIX}_decrypt +.type ${PREFIX}_decrypt,\@abi-omnipotent +.align 16 +${PREFIX}_decrypt: + movups ($inp),$inout0 # load input + mov 240($key),$rounds # key->rounds +___ + &aesni_generate1("dec",$key,$rounds); +$code.=<<___; + pxor $rndkey0,$rndkey0 # clear register bank + pxor $rndkey1,$rndkey1 + movups $inout0,($out) # output + pxor $inout0,$inout0 + ret +.size ${PREFIX}_decrypt, .-${PREFIX}_decrypt +___ +} + +# _aesni_[en|de]cryptN are private interfaces, N denotes interleave +# factor. Why 3x subroutine were originally used in loops? Even though +# aes[enc|dec] latency was originally 6, it could be scheduled only +# every *2nd* cycle. Thus 3x interleave was the one providing optimal +# utilization, i.e. when subroutine's throughput is virtually same as +# of non-interleaved subroutine [for number of input blocks up to 3]. +# This is why it originally made no sense to implement 2x subroutine. +# But times change and it became appropriate to spend extra 192 bytes +# on 2x subroutine on Atom Silvermont account. For processors that +# can schedule aes[enc|dec] every cycle optimal interleave factor +# equals to corresponding instructions latency. 8x is optimal for +# * Bridge and "super-optimal" for other Intel CPUs... + +sub aesni_generate2 { +my $dir=shift; +# As already mentioned it takes in $key and $rounds, which are *not* +# preserved. $inout[0-1] is cipher/clear text... +$code.=<<___; +.type _aesni_${dir}rypt2,\@abi-omnipotent +.align 16 +_aesni_${dir}rypt2: + $movkey ($key),$rndkey0 + shl \$4,$rounds + $movkey 16($key),$rndkey1 + xorps $rndkey0,$inout0 + xorps $rndkey0,$inout1 + $movkey 32($key),$rndkey0 + lea 32($key,$rounds),$key + neg %rax # $rounds + add \$16,%rax + +.L${dir}_loop2: + aes${dir} $rndkey1,$inout0 + aes${dir} $rndkey1,$inout1 + $movkey ($key,%rax),$rndkey1 + add \$32,%rax + aes${dir} $rndkey0,$inout0 + aes${dir} $rndkey0,$inout1 + $movkey -16($key,%rax),$rndkey0 + jnz .L${dir}_loop2 + + aes${dir} $rndkey1,$inout0 + aes${dir} $rndkey1,$inout1 + aes${dir}last $rndkey0,$inout0 + aes${dir}last $rndkey0,$inout1 + ret +.size _aesni_${dir}rypt2,.-_aesni_${dir}rypt2 +___ +} +sub aesni_generate3 { +my $dir=shift; +# As already mentioned it takes in $key and $rounds, which are *not* +# preserved. $inout[0-2] is cipher/clear text... +$code.=<<___; +.type _aesni_${dir}rypt3,\@abi-omnipotent +.align 16 +_aesni_${dir}rypt3: + $movkey ($key),$rndkey0 + shl \$4,$rounds + $movkey 16($key),$rndkey1 + xorps $rndkey0,$inout0 + xorps $rndkey0,$inout1 + xorps $rndkey0,$inout2 + $movkey 32($key),$rndkey0 + lea 32($key,$rounds),$key + neg %rax # $rounds + add \$16,%rax + +.L${dir}_loop3: + aes${dir} $rndkey1,$inout0 + aes${dir} $rndkey1,$inout1 + aes${dir} $rndkey1,$inout2 + $movkey ($key,%rax),$rndkey1 + add \$32,%rax + aes${dir} $rndkey0,$inout0 + aes${dir} $rndkey0,$inout1 + aes${dir} $rndkey0,$inout2 + $movkey -16($key,%rax),$rndkey0 + jnz .L${dir}_loop3 + + aes${dir} $rndkey1,$inout0 + aes${dir} $rndkey1,$inout1 + aes${dir} $rndkey1,$inout2 + aes${dir}last $rndkey0,$inout0 + aes${dir}last $rndkey0,$inout1 + aes${dir}last $rndkey0,$inout2 + ret +.size _aesni_${dir}rypt3,.-_aesni_${dir}rypt3 +___ +} +# 4x interleave is implemented to improve small block performance, +# most notably [and naturally] 4 block by ~30%. One can argue that one +# should have implemented 5x as well, but improvement would be <20%, +# so it's not worth it... +sub aesni_generate4 { +my $dir=shift; +# As already mentioned it takes in $key and $rounds, which are *not* +# preserved. $inout[0-3] is cipher/clear text... +$code.=<<___; +.type _aesni_${dir}rypt4,\@abi-omnipotent +.align 16 +_aesni_${dir}rypt4: + $movkey ($key),$rndkey0 + shl \$4,$rounds + $movkey 16($key),$rndkey1 + xorps $rndkey0,$inout0 + xorps $rndkey0,$inout1 + xorps $rndkey0,$inout2 + xorps $rndkey0,$inout3 + $movkey 32($key),$rndkey0 + lea 32($key,$rounds),$key + neg %rax # $rounds + .byte 0x0f,0x1f,0x00 + add \$16,%rax + +.L${dir}_loop4: + aes${dir} $rndkey1,$inout0 + aes${dir} $rndkey1,$inout1 + aes${dir} $rndkey1,$inout2 + aes${dir} $rndkey1,$inout3 + $movkey ($key,%rax),$rndkey1 + add \$32,%rax + aes${dir} $rndkey0,$inout0 + aes${dir} $rndkey0,$inout1 + aes${dir} $rndkey0,$inout2 + aes${dir} $rndkey0,$inout3 + $movkey -16($key,%rax),$rndkey0 + jnz .L${dir}_loop4 + + aes${dir} $rndkey1,$inout0 + aes${dir} $rndkey1,$inout1 + aes${dir} $rndkey1,$inout2 + aes${dir} $rndkey1,$inout3 + aes${dir}last $rndkey0,$inout0 + aes${dir}last $rndkey0,$inout1 + aes${dir}last $rndkey0,$inout2 + aes${dir}last $rndkey0,$inout3 + ret +.size _aesni_${dir}rypt4,.-_aesni_${dir}rypt4 +___ +} +sub aesni_generate6 { +my $dir=shift; +# As already mentioned it takes in $key and $rounds, which are *not* +# preserved. $inout[0-5] is cipher/clear text... +$code.=<<___; +.type _aesni_${dir}rypt6,\@abi-omnipotent +.align 16 +_aesni_${dir}rypt6: + $movkey ($key),$rndkey0 + shl \$4,$rounds + $movkey 16($key),$rndkey1 + xorps $rndkey0,$inout0 + pxor $rndkey0,$inout1 + pxor $rndkey0,$inout2 + aes${dir} $rndkey1,$inout0 + lea 32($key,$rounds),$key + neg %rax # $rounds + aes${dir} $rndkey1,$inout1 + pxor $rndkey0,$inout3 + pxor $rndkey0,$inout4 + aes${dir} $rndkey1,$inout2 + pxor $rndkey0,$inout5 + $movkey ($key,%rax),$rndkey0 + add \$16,%rax + jmp .L${dir}_loop6_enter +.align 16 +.L${dir}_loop6: + aes${dir} $rndkey1,$inout0 + aes${dir} $rndkey1,$inout1 + aes${dir} $rndkey1,$inout2 +.L${dir}_loop6_enter: + aes${dir} $rndkey1,$inout3 + aes${dir} $rndkey1,$inout4 + aes${dir} $rndkey1,$inout5 + $movkey ($key,%rax),$rndkey1 + add \$32,%rax + aes${dir} $rndkey0,$inout0 + aes${dir} $rndkey0,$inout1 + aes${dir} $rndkey0,$inout2 + aes${dir} $rndkey0,$inout3 + aes${dir} $rndkey0,$inout4 + aes${dir} $rndkey0,$inout5 + $movkey -16($key,%rax),$rndkey0 + jnz .L${dir}_loop6 + + aes${dir} $rndkey1,$inout0 + aes${dir} $rndkey1,$inout1 + aes${dir} $rndkey1,$inout2 + aes${dir} $rndkey1,$inout3 + aes${dir} $rndkey1,$inout4 + aes${dir} $rndkey1,$inout5 + aes${dir}last $rndkey0,$inout0 + aes${dir}last $rndkey0,$inout1 + aes${dir}last $rndkey0,$inout2 + aes${dir}last $rndkey0,$inout3 + aes${dir}last $rndkey0,$inout4 + aes${dir}last $rndkey0,$inout5 + ret +.size _aesni_${dir}rypt6,.-_aesni_${dir}rypt6 +___ +} +sub aesni_generate8 { +my $dir=shift; +# As already mentioned it takes in $key and $rounds, which are *not* +# preserved. $inout[0-7] is cipher/clear text... +$code.=<<___; +.type _aesni_${dir}rypt8,\@abi-omnipotent +.align 16 +_aesni_${dir}rypt8: + $movkey ($key),$rndkey0 + shl \$4,$rounds + $movkey 16($key),$rndkey1 + xorps $rndkey0,$inout0 + xorps $rndkey0,$inout1 + pxor $rndkey0,$inout2 + pxor $rndkey0,$inout3 + pxor $rndkey0,$inout4 + lea 32($key,$rounds),$key + neg %rax # $rounds + aes${dir} $rndkey1,$inout0 + pxor $rndkey0,$inout5 + pxor $rndkey0,$inout6 + aes${dir} $rndkey1,$inout1 + pxor $rndkey0,$inout7 + $movkey ($key,%rax),$rndkey0 + add \$16,%rax + jmp .L${dir}_loop8_inner +.align 16 +.L${dir}_loop8: + aes${dir} $rndkey1,$inout0 + aes${dir} $rndkey1,$inout1 +.L${dir}_loop8_inner: + aes${dir} $rndkey1,$inout2 + aes${dir} $rndkey1,$inout3 + aes${dir} $rndkey1,$inout4 + aes${dir} $rndkey1,$inout5 + aes${dir} $rndkey1,$inout6 + aes${dir} $rndkey1,$inout7 +.L${dir}_loop8_enter: + $movkey ($key,%rax),$rndkey1 + add \$32,%rax + aes${dir} $rndkey0,$inout0 + aes${dir} $rndkey0,$inout1 + aes${dir} $rndkey0,$inout2 + aes${dir} $rndkey0,$inout3 + aes${dir} $rndkey0,$inout4 + aes${dir} $rndkey0,$inout5 + aes${dir} $rndkey0,$inout6 + aes${dir} $rndkey0,$inout7 + $movkey -16($key,%rax),$rndkey0 + jnz .L${dir}_loop8 + + aes${dir} $rndkey1,$inout0 + aes${dir} $rndkey1,$inout1 + aes${dir} $rndkey1,$inout2 + aes${dir} $rndkey1,$inout3 + aes${dir} $rndkey1,$inout4 + aes${dir} $rndkey1,$inout5 + aes${dir} $rndkey1,$inout6 + aes${dir} $rndkey1,$inout7 + aes${dir}last $rndkey0,$inout0 + aes${dir}last $rndkey0,$inout1 + aes${dir}last $rndkey0,$inout2 + aes${dir}last $rndkey0,$inout3 + aes${dir}last $rndkey0,$inout4 + aes${dir}last $rndkey0,$inout5 + aes${dir}last $rndkey0,$inout6 + aes${dir}last $rndkey0,$inout7 + ret +.size _aesni_${dir}rypt8,.-_aesni_${dir}rypt8 +___ +} +&aesni_generate2("enc") if ($PREFIX eq "aesni"); +&aesni_generate2("dec"); +&aesni_generate3("enc") if ($PREFIX eq "aesni"); +&aesni_generate3("dec"); +&aesni_generate4("enc") if ($PREFIX eq "aesni"); +&aesni_generate4("dec"); +&aesni_generate6("enc") if ($PREFIX eq "aesni"); +&aesni_generate6("dec"); +&aesni_generate8("enc") if ($PREFIX eq "aesni"); +&aesni_generate8("dec"); + +if ($PREFIX eq "aesni") { +######################################################################## +# void aesni_ecb_encrypt (const void *in, void *out, +# size_t length, const AES_KEY *key, +# int enc); +$code.=<<___; +.globl aesni_ecb_encrypt +.type aesni_ecb_encrypt,\@function,5 +.align 16 +aesni_ecb_encrypt: +___ +$code.=<<___ if ($win64); + lea -0x58(%rsp),%rsp + movaps %xmm6,(%rsp) # offload $inout4..7 + movaps %xmm7,0x10(%rsp) + movaps %xmm8,0x20(%rsp) + movaps %xmm9,0x30(%rsp) +.Lecb_enc_body: +___ +$code.=<<___; + and \$-16,$len # if ($len<16) + jz .Lecb_ret # return + + mov 240($key),$rounds # key->rounds + $movkey ($key),$rndkey0 + mov $key,$key_ # backup $key + mov $rounds,$rnds_ # backup $rounds + test %r8d,%r8d # 5th argument + jz .Lecb_decrypt +#--------------------------- ECB ENCRYPT ------------------------------# + cmp \$0x80,$len # if ($len<8*16) + jb .Lecb_enc_tail # short input + + movdqu ($inp),$inout0 # load 8 input blocks + movdqu 0x10($inp),$inout1 + movdqu 0x20($inp),$inout2 + movdqu 0x30($inp),$inout3 + movdqu 0x40($inp),$inout4 + movdqu 0x50($inp),$inout5 + movdqu 0x60($inp),$inout6 + movdqu 0x70($inp),$inout7 + lea 0x80($inp),$inp # $inp+=8*16 + sub \$0x80,$len # $len-=8*16 (can be zero) + jmp .Lecb_enc_loop8_enter +.align 16 +.Lecb_enc_loop8: + movups $inout0,($out) # store 8 output blocks + mov $key_,$key # restore $key + movdqu ($inp),$inout0 # load 8 input blocks + mov $rnds_,$rounds # restore $rounds + movups $inout1,0x10($out) + movdqu 0x10($inp),$inout1 + movups $inout2,0x20($out) + movdqu 0x20($inp),$inout2 + movups $inout3,0x30($out) + movdqu 0x30($inp),$inout3 + movups $inout4,0x40($out) + movdqu 0x40($inp),$inout4 + movups $inout5,0x50($out) + movdqu 0x50($inp),$inout5 + movups $inout6,0x60($out) + movdqu 0x60($inp),$inout6 + movups $inout7,0x70($out) + lea 0x80($out),$out # $out+=8*16 + movdqu 0x70($inp),$inout7 + lea 0x80($inp),$inp # $inp+=8*16 +.Lecb_enc_loop8_enter: + + call _aesni_encrypt8 + + sub \$0x80,$len + jnc .Lecb_enc_loop8 # loop if $len-=8*16 didn't borrow + + movups $inout0,($out) # store 8 output blocks + mov $key_,$key # restore $key + movups $inout1,0x10($out) + mov $rnds_,$rounds # restore $rounds + movups $inout2,0x20($out) + movups $inout3,0x30($out) + movups $inout4,0x40($out) + movups $inout5,0x50($out) + movups $inout6,0x60($out) + movups $inout7,0x70($out) + lea 0x80($out),$out # $out+=8*16 + add \$0x80,$len # restore real remaining $len + jz .Lecb_ret # done if ($len==0) + +.Lecb_enc_tail: # $len is less than 8*16 + movups ($inp),$inout0 + cmp \$0x20,$len + jb .Lecb_enc_one + movups 0x10($inp),$inout1 + je .Lecb_enc_two + movups 0x20($inp),$inout2 + cmp \$0x40,$len + jb .Lecb_enc_three + movups 0x30($inp),$inout3 + je .Lecb_enc_four + movups 0x40($inp),$inout4 + cmp \$0x60,$len + jb .Lecb_enc_five + movups 0x50($inp),$inout5 + je .Lecb_enc_six + movdqu 0x60($inp),$inout6 + xorps $inout7,$inout7 + call _aesni_encrypt8 + movups $inout0,($out) # store 7 output blocks + movups $inout1,0x10($out) + movups $inout2,0x20($out) + movups $inout3,0x30($out) + movups $inout4,0x40($out) + movups $inout5,0x50($out) + movups $inout6,0x60($out) + jmp .Lecb_ret +.align 16 +.Lecb_enc_one: +___ + &aesni_generate1("enc",$key,$rounds); +$code.=<<___; + movups $inout0,($out) # store one output block + jmp .Lecb_ret +.align 16 +.Lecb_enc_two: + call _aesni_encrypt2 + movups $inout0,($out) # store 2 output blocks + movups $inout1,0x10($out) + jmp .Lecb_ret +.align 16 +.Lecb_enc_three: + call _aesni_encrypt3 + movups $inout0,($out) # store 3 output blocks + movups $inout1,0x10($out) + movups $inout2,0x20($out) + jmp .Lecb_ret +.align 16 +.Lecb_enc_four: + call _aesni_encrypt4 + movups $inout0,($out) # store 4 output blocks + movups $inout1,0x10($out) + movups $inout2,0x20($out) + movups $inout3,0x30($out) + jmp .Lecb_ret +.align 16 +.Lecb_enc_five: + xorps $inout5,$inout5 + call _aesni_encrypt6 + movups $inout0,($out) # store 5 output blocks + movups $inout1,0x10($out) + movups $inout2,0x20($out) + movups $inout3,0x30($out) + movups $inout4,0x40($out) + jmp .Lecb_ret +.align 16 +.Lecb_enc_six: + call _aesni_encrypt6 + movups $inout0,($out) # store 6 output blocks + movups $inout1,0x10($out) + movups $inout2,0x20($out) + movups $inout3,0x30($out) + movups $inout4,0x40($out) + movups $inout5,0x50($out) + jmp .Lecb_ret + #--------------------------- ECB DECRYPT ------------------------------# +.align 16 +.Lecb_decrypt: + cmp \$0x80,$len # if ($len<8*16) + jb .Lecb_dec_tail # short input + + movdqu ($inp),$inout0 # load 8 input blocks + movdqu 0x10($inp),$inout1 + movdqu 0x20($inp),$inout2 + movdqu 0x30($inp),$inout3 + movdqu 0x40($inp),$inout4 + movdqu 0x50($inp),$inout5 + movdqu 0x60($inp),$inout6 + movdqu 0x70($inp),$inout7 + lea 0x80($inp),$inp # $inp+=8*16 + sub \$0x80,$len # $len-=8*16 (can be zero) + jmp .Lecb_dec_loop8_enter +.align 16 +.Lecb_dec_loop8: + movups $inout0,($out) # store 8 output blocks + mov $key_,$key # restore $key + movdqu ($inp),$inout0 # load 8 input blocks + mov $rnds_,$rounds # restore $rounds + movups $inout1,0x10($out) + movdqu 0x10($inp),$inout1 + movups $inout2,0x20($out) + movdqu 0x20($inp),$inout2 + movups $inout3,0x30($out) + movdqu 0x30($inp),$inout3 + movups $inout4,0x40($out) + movdqu 0x40($inp),$inout4 + movups $inout5,0x50($out) + movdqu 0x50($inp),$inout5 + movups $inout6,0x60($out) + movdqu 0x60($inp),$inout6 + movups $inout7,0x70($out) + lea 0x80($out),$out # $out+=8*16 + movdqu 0x70($inp),$inout7 + lea 0x80($inp),$inp # $inp+=8*16 +.Lecb_dec_loop8_enter: + + call _aesni_decrypt8 + + $movkey ($key_),$rndkey0 + sub \$0x80,$len + jnc .Lecb_dec_loop8 # loop if $len-=8*16 didn't borrow + + movups $inout0,($out) # store 8 output blocks + pxor $inout0,$inout0 # clear register bank + mov $key_,$key # restore $key + movups $inout1,0x10($out) + pxor $inout1,$inout1 + mov $rnds_,$rounds # restore $rounds + movups $inout2,0x20($out) + pxor $inout2,$inout2 + movups $inout3,0x30($out) + pxor $inout3,$inout3 + movups $inout4,0x40($out) + pxor $inout4,$inout4 + movups $inout5,0x50($out) + pxor $inout5,$inout5 + movups $inout6,0x60($out) + pxor $inout6,$inout6 + movups $inout7,0x70($out) + pxor $inout7,$inout7 + lea 0x80($out),$out # $out+=8*16 + add \$0x80,$len # restore real remaining $len + jz .Lecb_ret # done if ($len==0) + +.Lecb_dec_tail: + movups ($inp),$inout0 + cmp \$0x20,$len + jb .Lecb_dec_one + movups 0x10($inp),$inout1 + je .Lecb_dec_two + movups 0x20($inp),$inout2 + cmp \$0x40,$len + jb .Lecb_dec_three + movups 0x30($inp),$inout3 + je .Lecb_dec_four + movups 0x40($inp),$inout4 + cmp \$0x60,$len + jb .Lecb_dec_five + movups 0x50($inp),$inout5 + je .Lecb_dec_six + movups 0x60($inp),$inout6 + $movkey ($key),$rndkey0 + xorps $inout7,$inout7 + call _aesni_decrypt8 + movups $inout0,($out) # store 7 output blocks + pxor $inout0,$inout0 # clear register bank + movups $inout1,0x10($out) + pxor $inout1,$inout1 + movups $inout2,0x20($out) + pxor $inout2,$inout2 + movups $inout3,0x30($out) + pxor $inout3,$inout3 + movups $inout4,0x40($out) + pxor $inout4,$inout4 + movups $inout5,0x50($out) + pxor $inout5,$inout5 + movups $inout6,0x60($out) + pxor $inout6,$inout6 + pxor $inout7,$inout7 + jmp .Lecb_ret +.align 16 +.Lecb_dec_one: +___ + &aesni_generate1("dec",$key,$rounds); +$code.=<<___; + movups $inout0,($out) # store one output block + pxor $inout0,$inout0 # clear register bank + jmp .Lecb_ret +.align 16 +.Lecb_dec_two: + call _aesni_decrypt2 + movups $inout0,($out) # store 2 output blocks + pxor $inout0,$inout0 # clear register bank + movups $inout1,0x10($out) + pxor $inout1,$inout1 + jmp .Lecb_ret +.align 16 +.Lecb_dec_three: + call _aesni_decrypt3 + movups $inout0,($out) # store 3 output blocks + pxor $inout0,$inout0 # clear register bank + movups $inout1,0x10($out) + pxor $inout1,$inout1 + movups $inout2,0x20($out) + pxor $inout2,$inout2 + jmp .Lecb_ret +.align 16 +.Lecb_dec_four: + call _aesni_decrypt4 + movups $inout0,($out) # store 4 output blocks + pxor $inout0,$inout0 # clear register bank + movups $inout1,0x10($out) + pxor $inout1,$inout1 + movups $inout2,0x20($out) + pxor $inout2,$inout2 + movups $inout3,0x30($out) + pxor $inout3,$inout3 + jmp .Lecb_ret +.align 16 +.Lecb_dec_five: + xorps $inout5,$inout5 + call _aesni_decrypt6 + movups $inout0,($out) # store 5 output blocks + pxor $inout0,$inout0 # clear register bank + movups $inout1,0x10($out) + pxor $inout1,$inout1 + movups $inout2,0x20($out) + pxor $inout2,$inout2 + movups $inout3,0x30($out) + pxor $inout3,$inout3 + movups $inout4,0x40($out) + pxor $inout4,$inout4 + pxor $inout5,$inout5 + jmp .Lecb_ret +.align 16 +.Lecb_dec_six: + call _aesni_decrypt6 + movups $inout0,($out) # store 6 output blocks + pxor $inout0,$inout0 # clear register bank + movups $inout1,0x10($out) + pxor $inout1,$inout1 + movups $inout2,0x20($out) + pxor $inout2,$inout2 + movups $inout3,0x30($out) + pxor $inout3,$inout3 + movups $inout4,0x40($out) + pxor $inout4,$inout4 + movups $inout5,0x50($out) + pxor $inout5,$inout5 + +.Lecb_ret: + xorps $rndkey0,$rndkey0 # %xmm0 + pxor $rndkey1,$rndkey1 +___ +$code.=<<___ if ($win64); + movaps (%rsp),%xmm6 + movaps %xmm0,(%rsp) # clear stack + movaps 0x10(%rsp),%xmm7 + movaps %xmm0,0x10(%rsp) + movaps 0x20(%rsp),%xmm8 + movaps %xmm0,0x20(%rsp) + movaps 0x30(%rsp),%xmm9 + movaps %xmm0,0x30(%rsp) + lea 0x58(%rsp),%rsp +.Lecb_enc_ret: +___ +$code.=<<___; + ret +.size aesni_ecb_encrypt,.-aesni_ecb_encrypt +___ + +{ +###################################################################### +# void aesni_ccm64_[en|de]crypt_blocks (const void *in, void *out, +# size_t blocks, const AES_KEY *key, +# const char *ivec,char *cmac); +# +# Handles only complete blocks, operates on 64-bit counter and +# does not update *ivec! Nor does it finalize CMAC value +# (see engine/eng_aesni.c for details) +# +{ +my $cmac="%r9"; # 6th argument + +my $increment="%xmm9"; +my $iv="%xmm6"; +my $bswap_mask="%xmm7"; + +$code.=<<___; +.globl aesni_ccm64_encrypt_blocks +.type aesni_ccm64_encrypt_blocks,\@function,6 +.align 16 +aesni_ccm64_encrypt_blocks: +___ +$code.=<<___ if ($win64); + lea -0x58(%rsp),%rsp + movaps %xmm6,(%rsp) # $iv + movaps %xmm7,0x10(%rsp) # $bswap_mask + movaps %xmm8,0x20(%rsp) # $in0 + movaps %xmm9,0x30(%rsp) # $increment +.Lccm64_enc_body: +___ +$code.=<<___; + mov 240($key),$rounds # key->rounds + movdqu ($ivp),$iv + movdqa .Lincrement64(%rip),$increment + movdqa .Lbswap_mask(%rip),$bswap_mask + + shl \$4,$rounds + mov \$16,$rnds_ + lea 0($key),$key_ + movdqu ($cmac),$inout1 + movdqa $iv,$inout0 + lea 32($key,$rounds),$key # end of key schedule + pshufb $bswap_mask,$iv + sub %rax,%r10 # twisted $rounds + jmp .Lccm64_enc_outer +.align 16 +.Lccm64_enc_outer: + $movkey ($key_),$rndkey0 + mov %r10,%rax + movups ($inp),$in0 # load inp + + xorps $rndkey0,$inout0 # counter + $movkey 16($key_),$rndkey1 + xorps $in0,$rndkey0 + xorps $rndkey0,$inout1 # cmac^=inp + $movkey 32($key_),$rndkey0 + +.Lccm64_enc2_loop: + aesenc $rndkey1,$inout0 + aesenc $rndkey1,$inout1 + $movkey ($key,%rax),$rndkey1 + add \$32,%rax + aesenc $rndkey0,$inout0 + aesenc $rndkey0,$inout1 + $movkey -16($key,%rax),$rndkey0 + jnz .Lccm64_enc2_loop + aesenc $rndkey1,$inout0 + aesenc $rndkey1,$inout1 + paddq $increment,$iv + dec $len # $len-- ($len is in blocks) + aesenclast $rndkey0,$inout0 + aesenclast $rndkey0,$inout1 + + lea 16($inp),$inp + xorps $inout0,$in0 # inp ^= E(iv) + movdqa $iv,$inout0 + movups $in0,($out) # save output + pshufb $bswap_mask,$inout0 + lea 16($out),$out # $out+=16 + jnz .Lccm64_enc_outer # loop if ($len!=0) + + pxor $rndkey0,$rndkey0 # clear register bank + pxor $rndkey1,$rndkey1 + pxor $inout0,$inout0 + movups $inout1,($cmac) # store resulting mac + pxor $inout1,$inout1 + pxor $in0,$in0 + pxor $iv,$iv +___ +$code.=<<___ if ($win64); + movaps (%rsp),%xmm6 + movaps %xmm0,(%rsp) # clear stack + movaps 0x10(%rsp),%xmm7 + movaps %xmm0,0x10(%rsp) + movaps 0x20(%rsp),%xmm8 + movaps %xmm0,0x20(%rsp) + movaps 0x30(%rsp),%xmm9 + movaps %xmm0,0x30(%rsp) + lea 0x58(%rsp),%rsp +.Lccm64_enc_ret: +___ +$code.=<<___; + ret +.size aesni_ccm64_encrypt_blocks,.-aesni_ccm64_encrypt_blocks +___ +###################################################################### +$code.=<<___; +.globl aesni_ccm64_decrypt_blocks +.type aesni_ccm64_decrypt_blocks,\@function,6 +.align 16 +aesni_ccm64_decrypt_blocks: +___ +$code.=<<___ if ($win64); + lea -0x58(%rsp),%rsp + movaps %xmm6,(%rsp) # $iv + movaps %xmm7,0x10(%rsp) # $bswap_mask + movaps %xmm8,0x20(%rsp) # $in8 + movaps %xmm9,0x30(%rsp) # $increment +.Lccm64_dec_body: +___ +$code.=<<___; + mov 240($key),$rounds # key->rounds + movups ($ivp),$iv + movdqu ($cmac),$inout1 + movdqa .Lincrement64(%rip),$increment + movdqa .Lbswap_mask(%rip),$bswap_mask + + movaps $iv,$inout0 + mov $rounds,$rnds_ + mov $key,$key_ + pshufb $bswap_mask,$iv +___ + &aesni_generate1("enc",$key,$rounds); +$code.=<<___; + shl \$4,$rnds_ + mov \$16,$rounds + movups ($inp),$in0 # load inp + paddq $increment,$iv + lea 16($inp),$inp # $inp+=16 + sub %r10,%rax # twisted $rounds + lea 32($key_,$rnds_),$key # end of key schedule + mov %rax,%r10 + jmp .Lccm64_dec_outer +.align 16 +.Lccm64_dec_outer: + xorps $inout0,$in0 # inp ^= E(iv) + movdqa $iv,$inout0 + movups $in0,($out) # save output + lea 16($out),$out # $out+=16 + pshufb $bswap_mask,$inout0 + + sub \$1,$len # $len-- ($len is in blocks) + jz .Lccm64_dec_break # if ($len==0) break + + $movkey ($key_),$rndkey0 + mov %r10,%rax + $movkey 16($key_),$rndkey1 + xorps $rndkey0,$in0 + xorps $rndkey0,$inout0 + xorps $in0,$inout1 # cmac^=out + $movkey 32($key_),$rndkey0 + jmp .Lccm64_dec2_loop +.align 16 +.Lccm64_dec2_loop: + aesenc $rndkey1,$inout0 + aesenc $rndkey1,$inout1 + $movkey ($key,%rax),$rndkey1 + add \$32,%rax + aesenc $rndkey0,$inout0 + aesenc $rndkey0,$inout1 + $movkey -16($key,%rax),$rndkey0 + jnz .Lccm64_dec2_loop + movups ($inp),$in0 # load input + paddq $increment,$iv + aesenc $rndkey1,$inout0 + aesenc $rndkey1,$inout1 + aesenclast $rndkey0,$inout0 + aesenclast $rndkey0,$inout1 + lea 16($inp),$inp # $inp+=16 + jmp .Lccm64_dec_outer + +.align 16 +.Lccm64_dec_break: + #xorps $in0,$inout1 # cmac^=out + mov 240($key_),$rounds +___ + &aesni_generate1("enc",$key_,$rounds,$inout1,$in0); +$code.=<<___; + pxor $rndkey0,$rndkey0 # clear register bank + pxor $rndkey1,$rndkey1 + pxor $inout0,$inout0 + movups $inout1,($cmac) # store resulting mac + pxor $inout1,$inout1 + pxor $in0,$in0 + pxor $iv,$iv +___ +$code.=<<___ if ($win64); + movaps (%rsp),%xmm6 + movaps %xmm0,(%rsp) # clear stack + movaps 0x10(%rsp),%xmm7 + movaps %xmm0,0x10(%rsp) + movaps 0x20(%rsp),%xmm8 + movaps %xmm0,0x20(%rsp) + movaps 0x30(%rsp),%xmm9 + movaps %xmm0,0x30(%rsp) + lea 0x58(%rsp),%rsp +.Lccm64_dec_ret: +___ +$code.=<<___; + ret +.size aesni_ccm64_decrypt_blocks,.-aesni_ccm64_decrypt_blocks +___ +} +###################################################################### +# void aesni_ctr32_encrypt_blocks (const void *in, void *out, +# size_t blocks, const AES_KEY *key, +# const char *ivec); +# +# Handles only complete blocks, operates on 32-bit counter and +# does not update *ivec! (see crypto/modes/ctr128.c for details) +# +# Overhaul based on suggestions from Shay Gueron and Vlad Krasnov, +# http://rt.openssl.org/Ticket/Display.html?id=3021&user=guest&pass=guest. +# Keywords are full unroll and modulo-schedule counter calculations +# with zero-round key xor. +{ +my ($in0,$in1,$in2,$in3,$in4,$in5)=map("%xmm$_",(10..15)); +my ($key0,$ctr)=("${key_}d","${ivp}d"); +my $frame_size = 0x80 + ($win64?160:0); + +$code.=<<___; +.globl aesni_ctr32_encrypt_blocks +.type aesni_ctr32_encrypt_blocks,\@function,5 +.align 16 +aesni_ctr32_encrypt_blocks: + cmp \$1,$len + jne .Lctr32_bulk + + # handle single block without allocating stack frame, + # useful when handling edges + movups ($ivp),$inout0 + movups ($inp),$inout1 + mov 240($key),%edx # key->rounds +___ + &aesni_generate1("enc",$key,"%edx"); +$code.=<<___; + pxor $rndkey0,$rndkey0 # clear register bank + pxor $rndkey1,$rndkey1 + xorps $inout1,$inout0 + pxor $inout1,$inout1 + movups $inout0,($out) + xorps $inout0,$inout0 + jmp .Lctr32_epilogue + +.align 16 +.Lctr32_bulk: + lea (%rsp),%rax + push %rbp + sub \$$frame_size,%rsp + and \$-16,%rsp # Linux kernel stack can be incorrectly seeded +___ +$code.=<<___ if ($win64); + movaps %xmm6,-0xa8(%rax) # offload everything + movaps %xmm7,-0x98(%rax) + movaps %xmm8,-0x88(%rax) + movaps %xmm9,-0x78(%rax) + movaps %xmm10,-0x68(%rax) + movaps %xmm11,-0x58(%rax) + movaps %xmm12,-0x48(%rax) + movaps %xmm13,-0x38(%rax) + movaps %xmm14,-0x28(%rax) + movaps %xmm15,-0x18(%rax) +.Lctr32_body: +___ +$code.=<<___; + lea -8(%rax),%rbp + + # 8 16-byte words on top of stack are counter values + # xor-ed with zero-round key + + movdqu ($ivp),$inout0 + movdqu ($key),$rndkey0 + mov 12($ivp),$ctr # counter LSB + pxor $rndkey0,$inout0 + mov 12($key),$key0 # 0-round key LSB + movdqa $inout0,0x00(%rsp) # populate counter block + bswap $ctr + movdqa $inout0,$inout1 + movdqa $inout0,$inout2 + movdqa $inout0,$inout3 + movdqa $inout0,0x40(%rsp) + movdqa $inout0,0x50(%rsp) + movdqa $inout0,0x60(%rsp) + mov %rdx,%r10 # about to borrow %rdx + movdqa $inout0,0x70(%rsp) + + lea 1($ctr),%rax + lea 2($ctr),%rdx + bswap %eax + bswap %edx + xor $key0,%eax + xor $key0,%edx + pinsrd \$3,%eax,$inout1 + lea 3($ctr),%rax + movdqa $inout1,0x10(%rsp) + pinsrd \$3,%edx,$inout2 + bswap %eax + mov %r10,%rdx # restore %rdx + lea 4($ctr),%r10 + movdqa $inout2,0x20(%rsp) + xor $key0,%eax + bswap %r10d + pinsrd \$3,%eax,$inout3 + xor $key0,%r10d + movdqa $inout3,0x30(%rsp) + lea 5($ctr),%r9 + mov %r10d,0x40+12(%rsp) + bswap %r9d + lea 6($ctr),%r10 + mov 240($key),$rounds # key->rounds + xor $key0,%r9d + bswap %r10d + mov %r9d,0x50+12(%rsp) + xor $key0,%r10d + lea 7($ctr),%r9 + mov %r10d,0x60+12(%rsp) + bswap %r9d + mov OPENSSL_ia32cap_P+4(%rip),%r10d + xor $key0,%r9d + and \$`1<<26|1<<22`,%r10d # isolate XSAVE+MOVBE + mov %r9d,0x70+12(%rsp) + + $movkey 0x10($key),$rndkey1 + + movdqa 0x40(%rsp),$inout4 + movdqa 0x50(%rsp),$inout5 + + cmp \$8,$len # $len is in blocks + jb .Lctr32_tail # short input if ($len<8) + + sub \$6,$len # $len is biased by -6 + cmp \$`1<<22`,%r10d # check for MOVBE without XSAVE + je .Lctr32_6x # [which denotes Atom Silvermont] + + lea 0x80($key),$key # size optimization + sub \$2,$len # $len is biased by -8 + jmp .Lctr32_loop8 + +.align 16 +.Lctr32_6x: + shl \$4,$rounds + mov \$48,$rnds_ + bswap $key0 + lea 32($key,$rounds),$key # end of key schedule + sub %rax,%r10 # twisted $rounds + jmp .Lctr32_loop6 + +.align 16 +.Lctr32_loop6: + add \$6,$ctr # next counter value + $movkey -48($key,$rnds_),$rndkey0 + aesenc $rndkey1,$inout0 + mov $ctr,%eax + xor $key0,%eax + aesenc $rndkey1,$inout1 + movbe %eax,`0x00+12`(%rsp) # store next counter value + lea 1($ctr),%eax + aesenc $rndkey1,$inout2 + xor $key0,%eax + movbe %eax,`0x10+12`(%rsp) + aesenc $rndkey1,$inout3 + lea 2($ctr),%eax + xor $key0,%eax + aesenc $rndkey1,$inout4 + movbe %eax,`0x20+12`(%rsp) + lea 3($ctr),%eax + aesenc $rndkey1,$inout5 + $movkey -32($key,$rnds_),$rndkey1 + xor $key0,%eax + + aesenc $rndkey0,$inout0 + movbe %eax,`0x30+12`(%rsp) + lea 4($ctr),%eax + aesenc $rndkey0,$inout1 + xor $key0,%eax + movbe %eax,`0x40+12`(%rsp) + aesenc $rndkey0,$inout2 + lea 5($ctr),%eax + xor $key0,%eax + aesenc $rndkey0,$inout3 + movbe %eax,`0x50+12`(%rsp) + mov %r10,%rax # mov $rnds_,$rounds + aesenc $rndkey0,$inout4 + aesenc $rndkey0,$inout5 + $movkey -16($key,$rnds_),$rndkey0 + + call .Lenc_loop6 + + movdqu ($inp),$inout6 # load 6 input blocks + movdqu 0x10($inp),$inout7 + movdqu 0x20($inp),$in0 + movdqu 0x30($inp),$in1 + movdqu 0x40($inp),$in2 + movdqu 0x50($inp),$in3 + lea 0x60($inp),$inp # $inp+=6*16 + $movkey -64($key,$rnds_),$rndkey1 + pxor $inout0,$inout6 # inp^=E(ctr) + movaps 0x00(%rsp),$inout0 # load next counter [xor-ed with 0 round] + pxor $inout1,$inout7 + movaps 0x10(%rsp),$inout1 + pxor $inout2,$in0 + movaps 0x20(%rsp),$inout2 + pxor $inout3,$in1 + movaps 0x30(%rsp),$inout3 + pxor $inout4,$in2 + movaps 0x40(%rsp),$inout4 + pxor $inout5,$in3 + movaps 0x50(%rsp),$inout5 + movdqu $inout6,($out) # store 6 output blocks + movdqu $inout7,0x10($out) + movdqu $in0,0x20($out) + movdqu $in1,0x30($out) + movdqu $in2,0x40($out) + movdqu $in3,0x50($out) + lea 0x60($out),$out # $out+=6*16 + + sub \$6,$len + jnc .Lctr32_loop6 # loop if $len-=6 didn't borrow + + add \$6,$len # restore real remaining $len + jz .Lctr32_done # done if ($len==0) + + lea -48($rnds_),$rounds + lea -80($key,$rnds_),$key # restore $key + neg $rounds + shr \$4,$rounds # restore $rounds + jmp .Lctr32_tail + +.align 32 +.Lctr32_loop8: + add \$8,$ctr # next counter value + movdqa 0x60(%rsp),$inout6 + aesenc $rndkey1,$inout0 + mov $ctr,%r9d + movdqa 0x70(%rsp),$inout7 + aesenc $rndkey1,$inout1 + bswap %r9d + $movkey 0x20-0x80($key),$rndkey0 + aesenc $rndkey1,$inout2 + xor $key0,%r9d + nop + aesenc $rndkey1,$inout3 + mov %r9d,0x00+12(%rsp) # store next counter value + lea 1($ctr),%r9 + aesenc $rndkey1,$inout4 + aesenc $rndkey1,$inout5 + aesenc $rndkey1,$inout6 + aesenc $rndkey1,$inout7 + $movkey 0x30-0x80($key),$rndkey1 +___ +for($i=2;$i<8;$i++) { +my $rndkeyx = ($i&1)?$rndkey1:$rndkey0; +$code.=<<___; + bswap %r9d + aesenc $rndkeyx,$inout0 + aesenc $rndkeyx,$inout1 + xor $key0,%r9d + .byte 0x66,0x90 + aesenc $rndkeyx,$inout2 + aesenc $rndkeyx,$inout3 + mov %r9d,`0x10*($i-1)`+12(%rsp) + lea $i($ctr),%r9 + aesenc $rndkeyx,$inout4 + aesenc $rndkeyx,$inout5 + aesenc $rndkeyx,$inout6 + aesenc $rndkeyx,$inout7 + $movkey `0x20+0x10*$i`-0x80($key),$rndkeyx +___ +} +$code.=<<___; + bswap %r9d + aesenc $rndkey0,$inout0 + aesenc $rndkey0,$inout1 + aesenc $rndkey0,$inout2 + xor $key0,%r9d + movdqu 0x00($inp),$in0 # start loading input + aesenc $rndkey0,$inout3 + mov %r9d,0x70+12(%rsp) + cmp \$11,$rounds + aesenc $rndkey0,$inout4 + aesenc $rndkey0,$inout5 + aesenc $rndkey0,$inout6 + aesenc $rndkey0,$inout7 + $movkey 0xa0-0x80($key),$rndkey0 + + jb .Lctr32_enc_done + + aesenc $rndkey1,$inout0 + aesenc $rndkey1,$inout1 + aesenc $rndkey1,$inout2 + aesenc $rndkey1,$inout3 + aesenc $rndkey1,$inout4 + aesenc $rndkey1,$inout5 + aesenc $rndkey1,$inout6 + aesenc $rndkey1,$inout7 + $movkey 0xb0-0x80($key),$rndkey1 + + aesenc $rndkey0,$inout0 + aesenc $rndkey0,$inout1 + aesenc $rndkey0,$inout2 + aesenc $rndkey0,$inout3 + aesenc $rndkey0,$inout4 + aesenc $rndkey0,$inout5 + aesenc $rndkey0,$inout6 + aesenc $rndkey0,$inout7 + $movkey 0xc0-0x80($key),$rndkey0 + je .Lctr32_enc_done + + aesenc $rndkey1,$inout0 + aesenc $rndkey1,$inout1 + aesenc $rndkey1,$inout2 + aesenc $rndkey1,$inout3 + aesenc $rndkey1,$inout4 + aesenc $rndkey1,$inout5 + aesenc $rndkey1,$inout6 + aesenc $rndkey1,$inout7 + $movkey 0xd0-0x80($key),$rndkey1 + + aesenc $rndkey0,$inout0 + aesenc $rndkey0,$inout1 + aesenc $rndkey0,$inout2 + aesenc $rndkey0,$inout3 + aesenc $rndkey0,$inout4 + aesenc $rndkey0,$inout5 + aesenc $rndkey0,$inout6 + aesenc $rndkey0,$inout7 + $movkey 0xe0-0x80($key),$rndkey0 + jmp .Lctr32_enc_done + +.align 16 +.Lctr32_enc_done: + movdqu 0x10($inp),$in1 + pxor $rndkey0,$in0 # input^=round[last] + movdqu 0x20($inp),$in2 + pxor $rndkey0,$in1 + movdqu 0x30($inp),$in3 + pxor $rndkey0,$in2 + movdqu 0x40($inp),$in4 + pxor $rndkey0,$in3 + movdqu 0x50($inp),$in5 + pxor $rndkey0,$in4 + pxor $rndkey0,$in5 + aesenc $rndkey1,$inout0 + aesenc $rndkey1,$inout1 + aesenc $rndkey1,$inout2 + aesenc $rndkey1,$inout3 + aesenc $rndkey1,$inout4 + aesenc $rndkey1,$inout5 + aesenc $rndkey1,$inout6 + aesenc $rndkey1,$inout7 + movdqu 0x60($inp),$rndkey1 # borrow $rndkey1 for inp[6] + lea 0x80($inp),$inp # $inp+=8*16 + + aesenclast $in0,$inout0 # $inN is inp[N]^round[last] + pxor $rndkey0,$rndkey1 # borrowed $rndkey + movdqu 0x70-0x80($inp),$in0 + aesenclast $in1,$inout1 + pxor $rndkey0,$in0 + movdqa 0x00(%rsp),$in1 # load next counter block + aesenclast $in2,$inout2 + aesenclast $in3,$inout3 + movdqa 0x10(%rsp),$in2 + movdqa 0x20(%rsp),$in3 + aesenclast $in4,$inout4 + aesenclast $in5,$inout5 + movdqa 0x30(%rsp),$in4 + movdqa 0x40(%rsp),$in5 + aesenclast $rndkey1,$inout6 + movdqa 0x50(%rsp),$rndkey0 + $movkey 0x10-0x80($key),$rndkey1#real 1st-round key + aesenclast $in0,$inout7 + + movups $inout0,($out) # store 8 output blocks + movdqa $in1,$inout0 + movups $inout1,0x10($out) + movdqa $in2,$inout1 + movups $inout2,0x20($out) + movdqa $in3,$inout2 + movups $inout3,0x30($out) + movdqa $in4,$inout3 + movups $inout4,0x40($out) + movdqa $in5,$inout4 + movups $inout5,0x50($out) + movdqa $rndkey0,$inout5 + movups $inout6,0x60($out) + movups $inout7,0x70($out) + lea 0x80($out),$out # $out+=8*16 + + sub \$8,$len + jnc .Lctr32_loop8 # loop if $len-=8 didn't borrow + + add \$8,$len # restore real remainig $len + jz .Lctr32_done # done if ($len==0) + lea -0x80($key),$key + +.Lctr32_tail: + # note that at this point $inout0..5 are populated with + # counter values xor-ed with 0-round key + lea 16($key),$key + cmp \$4,$len + jb .Lctr32_loop3 + je .Lctr32_loop4 + + # if ($len>4) compute 7 E(counter) + shl \$4,$rounds + movdqa 0x60(%rsp),$inout6 + pxor $inout7,$inout7 + + $movkey 16($key),$rndkey0 + aesenc $rndkey1,$inout0 + aesenc $rndkey1,$inout1 + lea 32-16($key,$rounds),$key# prepare for .Lenc_loop8_enter + neg %rax + aesenc $rndkey1,$inout2 + add \$16,%rax # prepare for .Lenc_loop8_enter + movups ($inp),$in0 + aesenc $rndkey1,$inout3 + aesenc $rndkey1,$inout4 + movups 0x10($inp),$in1 # pre-load input + movups 0x20($inp),$in2 + aesenc $rndkey1,$inout5 + aesenc $rndkey1,$inout6 + + call .Lenc_loop8_enter + + movdqu 0x30($inp),$in3 + pxor $in0,$inout0 + movdqu 0x40($inp),$in0 + pxor $in1,$inout1 + movdqu $inout0,($out) # store output + pxor $in2,$inout2 + movdqu $inout1,0x10($out) + pxor $in3,$inout3 + movdqu $inout2,0x20($out) + pxor $in0,$inout4 + movdqu $inout3,0x30($out) + movdqu $inout4,0x40($out) + cmp \$6,$len + jb .Lctr32_done # $len was 5, stop store + + movups 0x50($inp),$in1 + xorps $in1,$inout5 + movups $inout5,0x50($out) + je .Lctr32_done # $len was 6, stop store + + movups 0x60($inp),$in2 + xorps $in2,$inout6 + movups $inout6,0x60($out) + jmp .Lctr32_done # $len was 7, stop store + +.align 32 +.Lctr32_loop4: + aesenc $rndkey1,$inout0 + lea 16($key),$key + dec $rounds + aesenc $rndkey1,$inout1 + aesenc $rndkey1,$inout2 + aesenc $rndkey1,$inout3 + $movkey ($key),$rndkey1 + jnz .Lctr32_loop4 + aesenclast $rndkey1,$inout0 + aesenclast $rndkey1,$inout1 + movups ($inp),$in0 # load input + movups 0x10($inp),$in1 + aesenclast $rndkey1,$inout2 + aesenclast $rndkey1,$inout3 + movups 0x20($inp),$in2 + movups 0x30($inp),$in3 + + xorps $in0,$inout0 + movups $inout0,($out) # store output + xorps $in1,$inout1 + movups $inout1,0x10($out) + pxor $in2,$inout2 + movdqu $inout2,0x20($out) + pxor $in3,$inout3 + movdqu $inout3,0x30($out) + jmp .Lctr32_done # $len was 4, stop store + +.align 32 +.Lctr32_loop3: + aesenc $rndkey1,$inout0 + lea 16($key),$key + dec $rounds + aesenc $rndkey1,$inout1 + aesenc $rndkey1,$inout2 + $movkey ($key),$rndkey1 + jnz .Lctr32_loop3 + aesenclast $rndkey1,$inout0 + aesenclast $rndkey1,$inout1 + aesenclast $rndkey1,$inout2 + + movups ($inp),$in0 # load input + xorps $in0,$inout0 + movups $inout0,($out) # store output + cmp \$2,$len + jb .Lctr32_done # $len was 1, stop store + + movups 0x10($inp),$in1 + xorps $in1,$inout1 + movups $inout1,0x10($out) + je .Lctr32_done # $len was 2, stop store + + movups 0x20($inp),$in2 + xorps $in2,$inout2 + movups $inout2,0x20($out) # $len was 3, stop store + +.Lctr32_done: + xorps %xmm0,%xmm0 # clear regiser bank + xor $key0,$key0 + pxor %xmm1,%xmm1 + pxor %xmm2,%xmm2 + pxor %xmm3,%xmm3 + pxor %xmm4,%xmm4 + pxor %xmm5,%xmm5 +___ +$code.=<<___ if (!$win64); + pxor %xmm6,%xmm6 + pxor %xmm7,%xmm7 + movaps %xmm0,0x00(%rsp) # clear stack + pxor %xmm8,%xmm8 + movaps %xmm0,0x10(%rsp) + pxor %xmm9,%xmm9 + movaps %xmm0,0x20(%rsp) + pxor %xmm10,%xmm10 + movaps %xmm0,0x30(%rsp) + pxor %xmm11,%xmm11 + movaps %xmm0,0x40(%rsp) + pxor %xmm12,%xmm12 + movaps %xmm0,0x50(%rsp) + pxor %xmm13,%xmm13 + movaps %xmm0,0x60(%rsp) + pxor %xmm14,%xmm14 + movaps %xmm0,0x70(%rsp) + pxor %xmm15,%xmm15 +___ +$code.=<<___ if ($win64); + movaps -0xa0(%rbp),%xmm6 + movaps %xmm0,-0xa0(%rbp) # clear stack + movaps -0x90(%rbp),%xmm7 + movaps %xmm0,-0x90(%rbp) + movaps -0x80(%rbp),%xmm8 + movaps %xmm0,-0x80(%rbp) + movaps -0x70(%rbp),%xmm9 + movaps %xmm0,-0x70(%rbp) + movaps -0x60(%rbp),%xmm10 + movaps %xmm0,-0x60(%rbp) + movaps -0x50(%rbp),%xmm11 + movaps %xmm0,-0x50(%rbp) + movaps -0x40(%rbp),%xmm12 + movaps %xmm0,-0x40(%rbp) + movaps -0x30(%rbp),%xmm13 + movaps %xmm0,-0x30(%rbp) + movaps -0x20(%rbp),%xmm14 + movaps %xmm0,-0x20(%rbp) + movaps -0x10(%rbp),%xmm15 + movaps %xmm0,-0x10(%rbp) + movaps %xmm0,0x00(%rsp) + movaps %xmm0,0x10(%rsp) + movaps %xmm0,0x20(%rsp) + movaps %xmm0,0x30(%rsp) + movaps %xmm0,0x40(%rsp) + movaps %xmm0,0x50(%rsp) + movaps %xmm0,0x60(%rsp) + movaps %xmm0,0x70(%rsp) +___ +$code.=<<___; + lea (%rbp),%rsp + pop %rbp +.Lctr32_epilogue: + ret +.size aesni_ctr32_encrypt_blocks,.-aesni_ctr32_encrypt_blocks +___ +} + +###################################################################### +# void aesni_xts_[en|de]crypt(const char *inp,char *out,size_t len, +# const AES_KEY *key1, const AES_KEY *key2 +# const unsigned char iv[16]); +# +{ +my @tweak=map("%xmm$_",(10..15)); +my ($twmask,$twres,$twtmp)=("%xmm8","%xmm9",@tweak[4]); +my ($key2,$ivp,$len_)=("%r8","%r9","%r9"); +my $frame_size = 0x70 + ($win64?160:0); + +$code.=<<___; +.globl aesni_xts_encrypt +.type aesni_xts_encrypt,\@function,6 +.align 16 +aesni_xts_encrypt: + lea (%rsp),%rax + push %rbp + sub \$$frame_size,%rsp + and \$-16,%rsp # Linux kernel stack can be incorrectly seeded +___ +$code.=<<___ if ($win64); + movaps %xmm6,-0xa8(%rax) # offload everything + movaps %xmm7,-0x98(%rax) + movaps %xmm8,-0x88(%rax) + movaps %xmm9,-0x78(%rax) + movaps %xmm10,-0x68(%rax) + movaps %xmm11,-0x58(%rax) + movaps %xmm12,-0x48(%rax) + movaps %xmm13,-0x38(%rax) + movaps %xmm14,-0x28(%rax) + movaps %xmm15,-0x18(%rax) +.Lxts_enc_body: +___ +$code.=<<___; + lea -8(%rax),%rbp + movups ($ivp),$inout0 # load clear-text tweak + mov 240(%r8),$rounds # key2->rounds + mov 240($key),$rnds_ # key1->rounds +___ + # generate the tweak + &aesni_generate1("enc",$key2,$rounds,$inout0); +$code.=<<___; + $movkey ($key),$rndkey0 # zero round key + mov $key,$key_ # backup $key + mov $rnds_,$rounds # backup $rounds + shl \$4,$rnds_ + mov $len,$len_ # backup $len + and \$-16,$len + + $movkey 16($key,$rnds_),$rndkey1 # last round key + + movdqa .Lxts_magic(%rip),$twmask + movdqa $inout0,@tweak[5] + pshufd \$0x5f,$inout0,$twres + pxor $rndkey0,$rndkey1 +___ + # alternative tweak calculation algorithm is based on suggestions + # by Shay Gueron. psrad doesn't conflict with AES-NI instructions + # and should help in the future... + for ($i=0;$i<4;$i++) { + $code.=<<___; + movdqa $twres,$twtmp + paddd $twres,$twres + movdqa @tweak[5],@tweak[$i] + psrad \$31,$twtmp # broadcast upper bits + paddq @tweak[5],@tweak[5] + pand $twmask,$twtmp + pxor $rndkey0,@tweak[$i] + pxor $twtmp,@tweak[5] +___ + } +$code.=<<___; + movdqa @tweak[5],@tweak[4] + psrad \$31,$twres + paddq @tweak[5],@tweak[5] + pand $twmask,$twres + pxor $rndkey0,@tweak[4] + pxor $twres,@tweak[5] + movaps $rndkey1,0x60(%rsp) # save round[0]^round[last] + + sub \$16*6,$len + jc .Lxts_enc_short # if $len-=6*16 borrowed + + mov \$16+96,$rounds + lea 32($key_,$rnds_),$key # end of key schedule + sub %r10,%rax # twisted $rounds + $movkey 16($key_),$rndkey1 + mov %rax,%r10 # backup twisted $rounds + lea .Lxts_magic(%rip),%r8 + jmp .Lxts_enc_grandloop + +.align 32 +.Lxts_enc_grandloop: + movdqu `16*0`($inp),$inout0 # load input + movdqa $rndkey0,$twmask + movdqu `16*1`($inp),$inout1 + pxor @tweak[0],$inout0 # input^=tweak^round[0] + movdqu `16*2`($inp),$inout2 + pxor @tweak[1],$inout1 + aesenc $rndkey1,$inout0 + movdqu `16*3`($inp),$inout3 + pxor @tweak[2],$inout2 + aesenc $rndkey1,$inout1 + movdqu `16*4`($inp),$inout4 + pxor @tweak[3],$inout3 + aesenc $rndkey1,$inout2 + movdqu `16*5`($inp),$inout5 + pxor @tweak[5],$twmask # round[0]^=tweak[5] + movdqa 0x60(%rsp),$twres # load round[0]^round[last] + pxor @tweak[4],$inout4 + aesenc $rndkey1,$inout3 + $movkey 32($key_),$rndkey0 + lea `16*6`($inp),$inp + pxor $twmask,$inout5 + + pxor $twres,@tweak[0] # calclulate tweaks^round[last] + aesenc $rndkey1,$inout4 + pxor $twres,@tweak[1] + movdqa @tweak[0],`16*0`(%rsp) # put aside tweaks^round[last] + aesenc $rndkey1,$inout5 + $movkey 48($key_),$rndkey1 + pxor $twres,@tweak[2] + + aesenc $rndkey0,$inout0 + pxor $twres,@tweak[3] + movdqa @tweak[1],`16*1`(%rsp) + aesenc $rndkey0,$inout1 + pxor $twres,@tweak[4] + movdqa @tweak[2],`16*2`(%rsp) + aesenc $rndkey0,$inout2 + aesenc $rndkey0,$inout3 + pxor $twres,$twmask + movdqa @tweak[4],`16*4`(%rsp) + aesenc $rndkey0,$inout4 + aesenc $rndkey0,$inout5 + $movkey 64($key_),$rndkey0 + movdqa $twmask,`16*5`(%rsp) + pshufd \$0x5f,@tweak[5],$twres + jmp .Lxts_enc_loop6 +.align 32 +.Lxts_enc_loop6: + aesenc $rndkey1,$inout0 + aesenc $rndkey1,$inout1 + aesenc $rndkey1,$inout2 + aesenc $rndkey1,$inout3 + aesenc $rndkey1,$inout4 + aesenc $rndkey1,$inout5 + $movkey -64($key,%rax),$rndkey1 + add \$32,%rax + + aesenc $rndkey0,$inout0 + aesenc $rndkey0,$inout1 + aesenc $rndkey0,$inout2 + aesenc $rndkey0,$inout3 + aesenc $rndkey0,$inout4 + aesenc $rndkey0,$inout5 + $movkey -80($key,%rax),$rndkey0 + jnz .Lxts_enc_loop6 + + movdqa (%r8),$twmask # start calculating next tweak + movdqa $twres,$twtmp + paddd $twres,$twres + aesenc $rndkey1,$inout0 + paddq @tweak[5],@tweak[5] + psrad \$31,$twtmp + aesenc $rndkey1,$inout1 + pand $twmask,$twtmp + $movkey ($key_),@tweak[0] # load round[0] + aesenc $rndkey1,$inout2 + aesenc $rndkey1,$inout3 + aesenc $rndkey1,$inout4 + pxor $twtmp,@tweak[5] + movaps @tweak[0],@tweak[1] # copy round[0] + aesenc $rndkey1,$inout5 + $movkey -64($key),$rndkey1 + + movdqa $twres,$twtmp + aesenc $rndkey0,$inout0 + paddd $twres,$twres + pxor @tweak[5],@tweak[0] + aesenc $rndkey0,$inout1 + psrad \$31,$twtmp + paddq @tweak[5],@tweak[5] + aesenc $rndkey0,$inout2 + aesenc $rndkey0,$inout3 + pand $twmask,$twtmp + movaps @tweak[1],@tweak[2] + aesenc $rndkey0,$inout4 + pxor $twtmp,@tweak[5] + movdqa $twres,$twtmp + aesenc $rndkey0,$inout5 + $movkey -48($key),$rndkey0 + + paddd $twres,$twres + aesenc $rndkey1,$inout0 + pxor @tweak[5],@tweak[1] + psrad \$31,$twtmp + aesenc $rndkey1,$inout1 + paddq @tweak[5],@tweak[5] + pand $twmask,$twtmp + aesenc $rndkey1,$inout2 + aesenc $rndkey1,$inout3 + movdqa @tweak[3],`16*3`(%rsp) + pxor $twtmp,@tweak[5] + aesenc $rndkey1,$inout4 + movaps @tweak[2],@tweak[3] + movdqa $twres,$twtmp + aesenc $rndkey1,$inout5 + $movkey -32($key),$rndkey1 + + paddd $twres,$twres + aesenc $rndkey0,$inout0 + pxor @tweak[5],@tweak[2] + psrad \$31,$twtmp + aesenc $rndkey0,$inout1 + paddq @tweak[5],@tweak[5] + pand $twmask,$twtmp + aesenc $rndkey0,$inout2 + aesenc $rndkey0,$inout3 + aesenc $rndkey0,$inout4 + pxor $twtmp,@tweak[5] + movaps @tweak[3],@tweak[4] + aesenc $rndkey0,$inout5 + + movdqa $twres,$rndkey0 + paddd $twres,$twres + aesenc $rndkey1,$inout0 + pxor @tweak[5],@tweak[3] + psrad \$31,$rndkey0 + aesenc $rndkey1,$inout1 + paddq @tweak[5],@tweak[5] + pand $twmask,$rndkey0 + aesenc $rndkey1,$inout2 + aesenc $rndkey1,$inout3 + pxor $rndkey0,@tweak[5] + $movkey ($key_),$rndkey0 + aesenc $rndkey1,$inout4 + aesenc $rndkey1,$inout5 + $movkey 16($key_),$rndkey1 + + pxor @tweak[5],@tweak[4] + aesenclast `16*0`(%rsp),$inout0 + psrad \$31,$twres + paddq @tweak[5],@tweak[5] + aesenclast `16*1`(%rsp),$inout1 + aesenclast `16*2`(%rsp),$inout2 + pand $twmask,$twres + mov %r10,%rax # restore $rounds + aesenclast `16*3`(%rsp),$inout3 + aesenclast `16*4`(%rsp),$inout4 + aesenclast `16*5`(%rsp),$inout5 + pxor $twres,@tweak[5] + + lea `16*6`($out),$out # $out+=6*16 + movups $inout0,`-16*6`($out) # store 6 output blocks + movups $inout1,`-16*5`($out) + movups $inout2,`-16*4`($out) + movups $inout3,`-16*3`($out) + movups $inout4,`-16*2`($out) + movups $inout5,`-16*1`($out) + sub \$16*6,$len + jnc .Lxts_enc_grandloop # loop if $len-=6*16 didn't borrow + + mov \$16+96,$rounds + sub $rnds_,$rounds + mov $key_,$key # restore $key + shr \$4,$rounds # restore original value + +.Lxts_enc_short: + # at the point @tweak[0..5] are populated with tweak values + mov $rounds,$rnds_ # backup $rounds + pxor $rndkey0,@tweak[0] + add \$16*6,$len # restore real remaining $len + jz .Lxts_enc_done # done if ($len==0) + + pxor $rndkey0,@tweak[1] + cmp \$0x20,$len + jb .Lxts_enc_one # $len is 1*16 + pxor $rndkey0,@tweak[2] + je .Lxts_enc_two # $len is 2*16 + + pxor $rndkey0,@tweak[3] + cmp \$0x40,$len + jb .Lxts_enc_three # $len is 3*16 + pxor $rndkey0,@tweak[4] + je .Lxts_enc_four # $len is 4*16 + + movdqu ($inp),$inout0 # $len is 5*16 + movdqu 16*1($inp),$inout1 + movdqu 16*2($inp),$inout2 + pxor @tweak[0],$inout0 + movdqu 16*3($inp),$inout3 + pxor @tweak[1],$inout1 + movdqu 16*4($inp),$inout4 + lea 16*5($inp),$inp # $inp+=5*16 + pxor @tweak[2],$inout2 + pxor @tweak[3],$inout3 + pxor @tweak[4],$inout4 + pxor $inout5,$inout5 + + call _aesni_encrypt6 + + xorps @tweak[0],$inout0 + movdqa @tweak[5],@tweak[0] + xorps @tweak[1],$inout1 + xorps @tweak[2],$inout2 + movdqu $inout0,($out) # store 5 output blocks + xorps @tweak[3],$inout3 + movdqu $inout1,16*1($out) + xorps @tweak[4],$inout4 + movdqu $inout2,16*2($out) + movdqu $inout3,16*3($out) + movdqu $inout4,16*4($out) + lea 16*5($out),$out # $out+=5*16 + jmp .Lxts_enc_done + +.align 16 +.Lxts_enc_one: + movups ($inp),$inout0 + lea 16*1($inp),$inp # inp+=1*16 + xorps @tweak[0],$inout0 +___ + &aesni_generate1("enc",$key,$rounds); +$code.=<<___; + xorps @tweak[0],$inout0 + movdqa @tweak[1],@tweak[0] + movups $inout0,($out) # store one output block + lea 16*1($out),$out # $out+=1*16 + jmp .Lxts_enc_done + +.align 16 +.Lxts_enc_two: + movups ($inp),$inout0 + movups 16($inp),$inout1 + lea 32($inp),$inp # $inp+=2*16 + xorps @tweak[0],$inout0 + xorps @tweak[1],$inout1 + + call _aesni_encrypt2 + + xorps @tweak[0],$inout0 + movdqa @tweak[2],@tweak[0] + xorps @tweak[1],$inout1 + movups $inout0,($out) # store 2 output blocks + movups $inout1,16*1($out) + lea 16*2($out),$out # $out+=2*16 + jmp .Lxts_enc_done + +.align 16 +.Lxts_enc_three: + movups ($inp),$inout0 + movups 16*1($inp),$inout1 + movups 16*2($inp),$inout2 + lea 16*3($inp),$inp # $inp+=3*16 + xorps @tweak[0],$inout0 + xorps @tweak[1],$inout1 + xorps @tweak[2],$inout2 + + call _aesni_encrypt3 + + xorps @tweak[0],$inout0 + movdqa @tweak[3],@tweak[0] + xorps @tweak[1],$inout1 + xorps @tweak[2],$inout2 + movups $inout0,($out) # store 3 output blocks + movups $inout1,16*1($out) + movups $inout2,16*2($out) + lea 16*3($out),$out # $out+=3*16 + jmp .Lxts_enc_done + +.align 16 +.Lxts_enc_four: + movups ($inp),$inout0 + movups 16*1($inp),$inout1 + movups 16*2($inp),$inout2 + xorps @tweak[0],$inout0 + movups 16*3($inp),$inout3 + lea 16*4($inp),$inp # $inp+=4*16 + xorps @tweak[1],$inout1 + xorps @tweak[2],$inout2 + xorps @tweak[3],$inout3 + + call _aesni_encrypt4 + + pxor @tweak[0],$inout0 + movdqa @tweak[4],@tweak[0] + pxor @tweak[1],$inout1 + pxor @tweak[2],$inout2 + movdqu $inout0,($out) # store 4 output blocks + pxor @tweak[3],$inout3 + movdqu $inout1,16*1($out) + movdqu $inout2,16*2($out) + movdqu $inout3,16*3($out) + lea 16*4($out),$out # $out+=4*16 + jmp .Lxts_enc_done + +.align 16 +.Lxts_enc_done: + and \$15,$len_ # see if $len%16 is 0 + jz .Lxts_enc_ret + mov $len_,$len + +.Lxts_enc_steal: + movzb ($inp),%eax # borrow $rounds ... + movzb -16($out),%ecx # ... and $key + lea 1($inp),$inp + mov %al,-16($out) + mov %cl,0($out) + lea 1($out),$out + sub \$1,$len + jnz .Lxts_enc_steal + + sub $len_,$out # rewind $out + mov $key_,$key # restore $key + mov $rnds_,$rounds # restore $rounds + + movups -16($out),$inout0 + xorps @tweak[0],$inout0 +___ + &aesni_generate1("enc",$key,$rounds); +$code.=<<___; + xorps @tweak[0],$inout0 + movups $inout0,-16($out) + +.Lxts_enc_ret: + xorps %xmm0,%xmm0 # clear register bank + pxor %xmm1,%xmm1 + pxor %xmm2,%xmm2 + pxor %xmm3,%xmm3 + pxor %xmm4,%xmm4 + pxor %xmm5,%xmm5 +___ +$code.=<<___ if (!$win64); + pxor %xmm6,%xmm6 + pxor %xmm7,%xmm7 + movaps %xmm0,0x00(%rsp) # clear stack + pxor %xmm8,%xmm8 + movaps %xmm0,0x10(%rsp) + pxor %xmm9,%xmm9 + movaps %xmm0,0x20(%rsp) + pxor %xmm10,%xmm10 + movaps %xmm0,0x30(%rsp) + pxor %xmm11,%xmm11 + movaps %xmm0,0x40(%rsp) + pxor %xmm12,%xmm12 + movaps %xmm0,0x50(%rsp) + pxor %xmm13,%xmm13 + movaps %xmm0,0x60(%rsp) + pxor %xmm14,%xmm14 + pxor %xmm15,%xmm15 +___ +$code.=<<___ if ($win64); + movaps -0xa0(%rbp),%xmm6 + movaps %xmm0,-0xa0(%rbp) # clear stack + movaps -0x90(%rbp),%xmm7 + movaps %xmm0,-0x90(%rbp) + movaps -0x80(%rbp),%xmm8 + movaps %xmm0,-0x80(%rbp) + movaps -0x70(%rbp),%xmm9 + movaps %xmm0,-0x70(%rbp) + movaps -0x60(%rbp),%xmm10 + movaps %xmm0,-0x60(%rbp) + movaps -0x50(%rbp),%xmm11 + movaps %xmm0,-0x50(%rbp) + movaps -0x40(%rbp),%xmm12 + movaps %xmm0,-0x40(%rbp) + movaps -0x30(%rbp),%xmm13 + movaps %xmm0,-0x30(%rbp) + movaps -0x20(%rbp),%xmm14 + movaps %xmm0,-0x20(%rbp) + movaps -0x10(%rbp),%xmm15 + movaps %xmm0,-0x10(%rbp) + movaps %xmm0,0x00(%rsp) + movaps %xmm0,0x10(%rsp) + movaps %xmm0,0x20(%rsp) + movaps %xmm0,0x30(%rsp) + movaps %xmm0,0x40(%rsp) + movaps %xmm0,0x50(%rsp) + movaps %xmm0,0x60(%rsp) +___ +$code.=<<___; + lea (%rbp),%rsp + pop %rbp +.Lxts_enc_epilogue: + ret +.size aesni_xts_encrypt,.-aesni_xts_encrypt +___ + +$code.=<<___; +.globl aesni_xts_decrypt +.type aesni_xts_decrypt,\@function,6 +.align 16 +aesni_xts_decrypt: + lea (%rsp),%rax + push %rbp + sub \$$frame_size,%rsp + and \$-16,%rsp # Linux kernel stack can be incorrectly seeded +___ +$code.=<<___ if ($win64); + movaps %xmm6,-0xa8(%rax) # offload everything + movaps %xmm7,-0x98(%rax) + movaps %xmm8,-0x88(%rax) + movaps %xmm9,-0x78(%rax) + movaps %xmm10,-0x68(%rax) + movaps %xmm11,-0x58(%rax) + movaps %xmm12,-0x48(%rax) + movaps %xmm13,-0x38(%rax) + movaps %xmm14,-0x28(%rax) + movaps %xmm15,-0x18(%rax) +.Lxts_dec_body: +___ +$code.=<<___; + lea -8(%rax),%rbp + movups ($ivp),$inout0 # load clear-text tweak + mov 240($key2),$rounds # key2->rounds + mov 240($key),$rnds_ # key1->rounds +___ + # generate the tweak + &aesni_generate1("enc",$key2,$rounds,$inout0); +$code.=<<___; + xor %eax,%eax # if ($len%16) len-=16; + test \$15,$len + setnz %al + shl \$4,%rax + sub %rax,$len + + $movkey ($key),$rndkey0 # zero round key + mov $key,$key_ # backup $key + mov $rnds_,$rounds # backup $rounds + shl \$4,$rnds_ + mov $len,$len_ # backup $len + and \$-16,$len + + $movkey 16($key,$rnds_),$rndkey1 # last round key + + movdqa .Lxts_magic(%rip),$twmask + movdqa $inout0,@tweak[5] + pshufd \$0x5f,$inout0,$twres + pxor $rndkey0,$rndkey1 +___ + for ($i=0;$i<4;$i++) { + $code.=<<___; + movdqa $twres,$twtmp + paddd $twres,$twres + movdqa @tweak[5],@tweak[$i] + psrad \$31,$twtmp # broadcast upper bits + paddq @tweak[5],@tweak[5] + pand $twmask,$twtmp + pxor $rndkey0,@tweak[$i] + pxor $twtmp,@tweak[5] +___ + } +$code.=<<___; + movdqa @tweak[5],@tweak[4] + psrad \$31,$twres + paddq @tweak[5],@tweak[5] + pand $twmask,$twres + pxor $rndkey0,@tweak[4] + pxor $twres,@tweak[5] + movaps $rndkey1,0x60(%rsp) # save round[0]^round[last] + + sub \$16*6,$len + jc .Lxts_dec_short # if $len-=6*16 borrowed + + mov \$16+96,$rounds + lea 32($key_,$rnds_),$key # end of key schedule + sub %r10,%rax # twisted $rounds + $movkey 16($key_),$rndkey1 + mov %rax,%r10 # backup twisted $rounds + lea .Lxts_magic(%rip),%r8 + jmp .Lxts_dec_grandloop + +.align 32 +.Lxts_dec_grandloop: + movdqu `16*0`($inp),$inout0 # load input + movdqa $rndkey0,$twmask + movdqu `16*1`($inp),$inout1 + pxor @tweak[0],$inout0 # intput^=tweak^round[0] + movdqu `16*2`($inp),$inout2 + pxor @tweak[1],$inout1 + aesdec $rndkey1,$inout0 + movdqu `16*3`($inp),$inout3 + pxor @tweak[2],$inout2 + aesdec $rndkey1,$inout1 + movdqu `16*4`($inp),$inout4 + pxor @tweak[3],$inout3 + aesdec $rndkey1,$inout2 + movdqu `16*5`($inp),$inout5 + pxor @tweak[5],$twmask # round[0]^=tweak[5] + movdqa 0x60(%rsp),$twres # load round[0]^round[last] + pxor @tweak[4],$inout4 + aesdec $rndkey1,$inout3 + $movkey 32($key_),$rndkey0 + lea `16*6`($inp),$inp + pxor $twmask,$inout5 + + pxor $twres,@tweak[0] # calclulate tweaks^round[last] + aesdec $rndkey1,$inout4 + pxor $twres,@tweak[1] + movdqa @tweak[0],`16*0`(%rsp) # put aside tweaks^last round key + aesdec $rndkey1,$inout5 + $movkey 48($key_),$rndkey1 + pxor $twres,@tweak[2] + + aesdec $rndkey0,$inout0 + pxor $twres,@tweak[3] + movdqa @tweak[1],`16*1`(%rsp) + aesdec $rndkey0,$inout1 + pxor $twres,@tweak[4] + movdqa @tweak[2],`16*2`(%rsp) + aesdec $rndkey0,$inout2 + aesdec $rndkey0,$inout3 + pxor $twres,$twmask + movdqa @tweak[4],`16*4`(%rsp) + aesdec $rndkey0,$inout4 + aesdec $rndkey0,$inout5 + $movkey 64($key_),$rndkey0 + movdqa $twmask,`16*5`(%rsp) + pshufd \$0x5f,@tweak[5],$twres + jmp .Lxts_dec_loop6 +.align 32 +.Lxts_dec_loop6: + aesdec $rndkey1,$inout0 + aesdec $rndkey1,$inout1 + aesdec $rndkey1,$inout2 + aesdec $rndkey1,$inout3 + aesdec $rndkey1,$inout4 + aesdec $rndkey1,$inout5 + $movkey -64($key,%rax),$rndkey1 + add \$32,%rax + + aesdec $rndkey0,$inout0 + aesdec $rndkey0,$inout1 + aesdec $rndkey0,$inout2 + aesdec $rndkey0,$inout3 + aesdec $rndkey0,$inout4 + aesdec $rndkey0,$inout5 + $movkey -80($key,%rax),$rndkey0 + jnz .Lxts_dec_loop6 + + movdqa (%r8),$twmask # start calculating next tweak + movdqa $twres,$twtmp + paddd $twres,$twres + aesdec $rndkey1,$inout0 + paddq @tweak[5],@tweak[5] + psrad \$31,$twtmp + aesdec $rndkey1,$inout1 + pand $twmask,$twtmp + $movkey ($key_),@tweak[0] # load round[0] + aesdec $rndkey1,$inout2 + aesdec $rndkey1,$inout3 + aesdec $rndkey1,$inout4 + pxor $twtmp,@tweak[5] + movaps @tweak[0],@tweak[1] # copy round[0] + aesdec $rndkey1,$inout5 + $movkey -64($key),$rndkey1 + + movdqa $twres,$twtmp + aesdec $rndkey0,$inout0 + paddd $twres,$twres + pxor @tweak[5],@tweak[0] + aesdec $rndkey0,$inout1 + psrad \$31,$twtmp + paddq @tweak[5],@tweak[5] + aesdec $rndkey0,$inout2 + aesdec $rndkey0,$inout3 + pand $twmask,$twtmp + movaps @tweak[1],@tweak[2] + aesdec $rndkey0,$inout4 + pxor $twtmp,@tweak[5] + movdqa $twres,$twtmp + aesdec $rndkey0,$inout5 + $movkey -48($key),$rndkey0 + + paddd $twres,$twres + aesdec $rndkey1,$inout0 + pxor @tweak[5],@tweak[1] + psrad \$31,$twtmp + aesdec $rndkey1,$inout1 + paddq @tweak[5],@tweak[5] + pand $twmask,$twtmp + aesdec $rndkey1,$inout2 + aesdec $rndkey1,$inout3 + movdqa @tweak[3],`16*3`(%rsp) + pxor $twtmp,@tweak[5] + aesdec $rndkey1,$inout4 + movaps @tweak[2],@tweak[3] + movdqa $twres,$twtmp + aesdec $rndkey1,$inout5 + $movkey -32($key),$rndkey1 + + paddd $twres,$twres + aesdec $rndkey0,$inout0 + pxor @tweak[5],@tweak[2] + psrad \$31,$twtmp + aesdec $rndkey0,$inout1 + paddq @tweak[5],@tweak[5] + pand $twmask,$twtmp + aesdec $rndkey0,$inout2 + aesdec $rndkey0,$inout3 + aesdec $rndkey0,$inout4 + pxor $twtmp,@tweak[5] + movaps @tweak[3],@tweak[4] + aesdec $rndkey0,$inout5 + + movdqa $twres,$rndkey0 + paddd $twres,$twres + aesdec $rndkey1,$inout0 + pxor @tweak[5],@tweak[3] + psrad \$31,$rndkey0 + aesdec $rndkey1,$inout1 + paddq @tweak[5],@tweak[5] + pand $twmask,$rndkey0 + aesdec $rndkey1,$inout2 + aesdec $rndkey1,$inout3 + pxor $rndkey0,@tweak[5] + $movkey ($key_),$rndkey0 + aesdec $rndkey1,$inout4 + aesdec $rndkey1,$inout5 + $movkey 16($key_),$rndkey1 + + pxor @tweak[5],@tweak[4] + aesdeclast `16*0`(%rsp),$inout0 + psrad \$31,$twres + paddq @tweak[5],@tweak[5] + aesdeclast `16*1`(%rsp),$inout1 + aesdeclast `16*2`(%rsp),$inout2 + pand $twmask,$twres + mov %r10,%rax # restore $rounds + aesdeclast `16*3`(%rsp),$inout3 + aesdeclast `16*4`(%rsp),$inout4 + aesdeclast `16*5`(%rsp),$inout5 + pxor $twres,@tweak[5] + + lea `16*6`($out),$out # $out+=6*16 + movups $inout0,`-16*6`($out) # store 6 output blocks + movups $inout1,`-16*5`($out) + movups $inout2,`-16*4`($out) + movups $inout3,`-16*3`($out) + movups $inout4,`-16*2`($out) + movups $inout5,`-16*1`($out) + sub \$16*6,$len + jnc .Lxts_dec_grandloop # loop if $len-=6*16 didn't borrow + + mov \$16+96,$rounds + sub $rnds_,$rounds + mov $key_,$key # restore $key + shr \$4,$rounds # restore original value + +.Lxts_dec_short: + # at the point @tweak[0..5] are populated with tweak values + mov $rounds,$rnds_ # backup $rounds + pxor $rndkey0,@tweak[0] + pxor $rndkey0,@tweak[1] + add \$16*6,$len # restore real remaining $len + jz .Lxts_dec_done # done if ($len==0) + + pxor $rndkey0,@tweak[2] + cmp \$0x20,$len + jb .Lxts_dec_one # $len is 1*16 + pxor $rndkey0,@tweak[3] + je .Lxts_dec_two # $len is 2*16 + + pxor $rndkey0,@tweak[4] + cmp \$0x40,$len + jb .Lxts_dec_three # $len is 3*16 + je .Lxts_dec_four # $len is 4*16 + + movdqu ($inp),$inout0 # $len is 5*16 + movdqu 16*1($inp),$inout1 + movdqu 16*2($inp),$inout2 + pxor @tweak[0],$inout0 + movdqu 16*3($inp),$inout3 + pxor @tweak[1],$inout1 + movdqu 16*4($inp),$inout4 + lea 16*5($inp),$inp # $inp+=5*16 + pxor @tweak[2],$inout2 + pxor @tweak[3],$inout3 + pxor @tweak[4],$inout4 + + call _aesni_decrypt6 + + xorps @tweak[0],$inout0 + xorps @tweak[1],$inout1 + xorps @tweak[2],$inout2 + movdqu $inout0,($out) # store 5 output blocks + xorps @tweak[3],$inout3 + movdqu $inout1,16*1($out) + xorps @tweak[4],$inout4 + movdqu $inout2,16*2($out) + pxor $twtmp,$twtmp + movdqu $inout3,16*3($out) + pcmpgtd @tweak[5],$twtmp + movdqu $inout4,16*4($out) + lea 16*5($out),$out # $out+=5*16 + pshufd \$0x13,$twtmp,@tweak[1] # $twres + and \$15,$len_ + jz .Lxts_dec_ret + + movdqa @tweak[5],@tweak[0] + paddq @tweak[5],@tweak[5] # psllq 1,$tweak + pand $twmask,@tweak[1] # isolate carry and residue + pxor @tweak[5],@tweak[1] + jmp .Lxts_dec_done2 + +.align 16 +.Lxts_dec_one: + movups ($inp),$inout0 + lea 16*1($inp),$inp # $inp+=1*16 + xorps @tweak[0],$inout0 +___ + &aesni_generate1("dec",$key,$rounds); +$code.=<<___; + xorps @tweak[0],$inout0 + movdqa @tweak[1],@tweak[0] + movups $inout0,($out) # store one output block + movdqa @tweak[2],@tweak[1] + lea 16*1($out),$out # $out+=1*16 + jmp .Lxts_dec_done + +.align 16 +.Lxts_dec_two: + movups ($inp),$inout0 + movups 16($inp),$inout1 + lea 32($inp),$inp # $inp+=2*16 + xorps @tweak[0],$inout0 + xorps @tweak[1],$inout1 + + call _aesni_decrypt2 + + xorps @tweak[0],$inout0 + movdqa @tweak[2],@tweak[0] + xorps @tweak[1],$inout1 + movdqa @tweak[3],@tweak[1] + movups $inout0,($out) # store 2 output blocks + movups $inout1,16*1($out) + lea 16*2($out),$out # $out+=2*16 + jmp .Lxts_dec_done + +.align 16 +.Lxts_dec_three: + movups ($inp),$inout0 + movups 16*1($inp),$inout1 + movups 16*2($inp),$inout2 + lea 16*3($inp),$inp # $inp+=3*16 + xorps @tweak[0],$inout0 + xorps @tweak[1],$inout1 + xorps @tweak[2],$inout2 + + call _aesni_decrypt3 + + xorps @tweak[0],$inout0 + movdqa @tweak[3],@tweak[0] + xorps @tweak[1],$inout1 + movdqa @tweak[4],@tweak[1] + xorps @tweak[2],$inout2 + movups $inout0,($out) # store 3 output blocks + movups $inout1,16*1($out) + movups $inout2,16*2($out) + lea 16*3($out),$out # $out+=3*16 + jmp .Lxts_dec_done + +.align 16 +.Lxts_dec_four: + movups ($inp),$inout0 + movups 16*1($inp),$inout1 + movups 16*2($inp),$inout2 + xorps @tweak[0],$inout0 + movups 16*3($inp),$inout3 + lea 16*4($inp),$inp # $inp+=4*16 + xorps @tweak[1],$inout1 + xorps @tweak[2],$inout2 + xorps @tweak[3],$inout3 + + call _aesni_decrypt4 + + pxor @tweak[0],$inout0 + movdqa @tweak[4],@tweak[0] + pxor @tweak[1],$inout1 + movdqa @tweak[5],@tweak[1] + pxor @tweak[2],$inout2 + movdqu $inout0,($out) # store 4 output blocks + pxor @tweak[3],$inout3 + movdqu $inout1,16*1($out) + movdqu $inout2,16*2($out) + movdqu $inout3,16*3($out) + lea 16*4($out),$out # $out+=4*16 + jmp .Lxts_dec_done + +.align 16 +.Lxts_dec_done: + and \$15,$len_ # see if $len%16 is 0 + jz .Lxts_dec_ret +.Lxts_dec_done2: + mov $len_,$len + mov $key_,$key # restore $key + mov $rnds_,$rounds # restore $rounds + + movups ($inp),$inout0 + xorps @tweak[1],$inout0 +___ + &aesni_generate1("dec",$key,$rounds); +$code.=<<___; + xorps @tweak[1],$inout0 + movups $inout0,($out) + +.Lxts_dec_steal: + movzb 16($inp),%eax # borrow $rounds ... + movzb ($out),%ecx # ... and $key + lea 1($inp),$inp + mov %al,($out) + mov %cl,16($out) + lea 1($out),$out + sub \$1,$len + jnz .Lxts_dec_steal + + sub $len_,$out # rewind $out + mov $key_,$key # restore $key + mov $rnds_,$rounds # restore $rounds + + movups ($out),$inout0 + xorps @tweak[0],$inout0 +___ + &aesni_generate1("dec",$key,$rounds); +$code.=<<___; + xorps @tweak[0],$inout0 + movups $inout0,($out) + +.Lxts_dec_ret: + xorps %xmm0,%xmm0 # clear register bank + pxor %xmm1,%xmm1 + pxor %xmm2,%xmm2 + pxor %xmm3,%xmm3 + pxor %xmm4,%xmm4 + pxor %xmm5,%xmm5 +___ +$code.=<<___ if (!$win64); + pxor %xmm6,%xmm6 + pxor %xmm7,%xmm7 + movaps %xmm0,0x00(%rsp) # clear stack + pxor %xmm8,%xmm8 + movaps %xmm0,0x10(%rsp) + pxor %xmm9,%xmm9 + movaps %xmm0,0x20(%rsp) + pxor %xmm10,%xmm10 + movaps %xmm0,0x30(%rsp) + pxor %xmm11,%xmm11 + movaps %xmm0,0x40(%rsp) + pxor %xmm12,%xmm12 + movaps %xmm0,0x50(%rsp) + pxor %xmm13,%xmm13 + movaps %xmm0,0x60(%rsp) + pxor %xmm14,%xmm14 + pxor %xmm15,%xmm15 +___ +$code.=<<___ if ($win64); + movaps -0xa0(%rbp),%xmm6 + movaps %xmm0,-0xa0(%rbp) # clear stack + movaps -0x90(%rbp),%xmm7 + movaps %xmm0,-0x90(%rbp) + movaps -0x80(%rbp),%xmm8 + movaps %xmm0,-0x80(%rbp) + movaps -0x70(%rbp),%xmm9 + movaps %xmm0,-0x70(%rbp) + movaps -0x60(%rbp),%xmm10 + movaps %xmm0,-0x60(%rbp) + movaps -0x50(%rbp),%xmm11 + movaps %xmm0,-0x50(%rbp) + movaps -0x40(%rbp),%xmm12 + movaps %xmm0,-0x40(%rbp) + movaps -0x30(%rbp),%xmm13 + movaps %xmm0,-0x30(%rbp) + movaps -0x20(%rbp),%xmm14 + movaps %xmm0,-0x20(%rbp) + movaps -0x10(%rbp),%xmm15 + movaps %xmm0,-0x10(%rbp) + movaps %xmm0,0x00(%rsp) + movaps %xmm0,0x10(%rsp) + movaps %xmm0,0x20(%rsp) + movaps %xmm0,0x30(%rsp) + movaps %xmm0,0x40(%rsp) + movaps %xmm0,0x50(%rsp) + movaps %xmm0,0x60(%rsp) +___ +$code.=<<___; + lea (%rbp),%rsp + pop %rbp +.Lxts_dec_epilogue: + ret +.size aesni_xts_decrypt,.-aesni_xts_decrypt +___ +} }} + +######################################################################## +# void $PREFIX_cbc_encrypt (const void *inp, void *out, +# size_t length, const AES_KEY *key, +# unsigned char *ivp,const int enc); +{ +my $frame_size = 0x10 + ($win64?0xa0:0); # used in decrypt +my ($iv,$in0,$in1,$in2,$in3,$in4)=map("%xmm$_",(10..15)); +my $inp_=$key_; + +$code.=<<___; +.globl ${PREFIX}_cbc_encrypt +.type ${PREFIX}_cbc_encrypt,\@function,6 +.align 16 +${PREFIX}_cbc_encrypt: + test $len,$len # check length + jz .Lcbc_ret + + mov 240($key),$rnds_ # key->rounds + mov $key,$key_ # backup $key + test %r9d,%r9d # 6th argument + jz .Lcbc_decrypt +#--------------------------- CBC ENCRYPT ------------------------------# + movups ($ivp),$inout0 # load iv as initial state + mov $rnds_,$rounds + cmp \$16,$len + jb .Lcbc_enc_tail + sub \$16,$len + jmp .Lcbc_enc_loop +.align 16 +.Lcbc_enc_loop: + movups ($inp),$inout1 # load input + lea 16($inp),$inp + #xorps $inout1,$inout0 +___ + &aesni_generate1("enc",$key,$rounds,$inout0,$inout1); +$code.=<<___; + mov $rnds_,$rounds # restore $rounds + mov $key_,$key # restore $key + movups $inout0,0($out) # store output + lea 16($out),$out + sub \$16,$len + jnc .Lcbc_enc_loop + add \$16,$len + jnz .Lcbc_enc_tail + pxor $rndkey0,$rndkey0 # clear register bank + pxor $rndkey1,$rndkey1 + movups $inout0,($ivp) + pxor $inout0,$inout0 + pxor $inout1,$inout1 + jmp .Lcbc_ret + +.Lcbc_enc_tail: + mov $len,%rcx # zaps $key + xchg $inp,$out # $inp is %rsi and $out is %rdi now + .long 0x9066A4F3 # rep movsb + mov \$16,%ecx # zero tail + sub $len,%rcx + xor %eax,%eax + .long 0x9066AAF3 # rep stosb + lea -16(%rdi),%rdi # rewind $out by 1 block + mov $rnds_,$rounds # restore $rounds + mov %rdi,%rsi # $inp and $out are the same + mov $key_,$key # restore $key + xor $len,$len # len=16 + jmp .Lcbc_enc_loop # one more spin + #--------------------------- CBC DECRYPT ------------------------------# +.align 16 +.Lcbc_decrypt: + cmp \$16,$len + jne .Lcbc_decrypt_bulk + + # handle single block without allocating stack frame, + # useful in ciphertext stealing mode + movdqu ($inp),$inout0 # load input + movdqu ($ivp),$inout1 # load iv + movdqa $inout0,$inout2 # future iv +___ + &aesni_generate1("dec",$key,$rnds_); +$code.=<<___; + pxor $rndkey0,$rndkey0 # clear register bank + pxor $rndkey1,$rndkey1 + movdqu $inout2,($ivp) # store iv + xorps $inout1,$inout0 # ^=iv + pxor $inout1,$inout1 + movups $inout0,($out) # store output + pxor $inout0,$inout0 + jmp .Lcbc_ret +.align 16 +.Lcbc_decrypt_bulk: + lea (%rsp),%rax + push %rbp + sub \$$frame_size,%rsp + and \$-16,%rsp # Linux kernel stack can be incorrectly seeded +___ +$code.=<<___ if ($win64); + movaps %xmm6,0x10(%rsp) + movaps %xmm7,0x20(%rsp) + movaps %xmm8,0x30(%rsp) + movaps %xmm9,0x40(%rsp) + movaps %xmm10,0x50(%rsp) + movaps %xmm11,0x60(%rsp) + movaps %xmm12,0x70(%rsp) + movaps %xmm13,0x80(%rsp) + movaps %xmm14,0x90(%rsp) + movaps %xmm15,0xa0(%rsp) +.Lcbc_decrypt_body: +___ +$code.=<<___; + lea -8(%rax),%rbp + movups ($ivp),$iv + mov $rnds_,$rounds + cmp \$0x50,$len + jbe .Lcbc_dec_tail + + $movkey ($key),$rndkey0 + movdqu 0x00($inp),$inout0 # load input + movdqu 0x10($inp),$inout1 + movdqa $inout0,$in0 + movdqu 0x20($inp),$inout2 + movdqa $inout1,$in1 + movdqu 0x30($inp),$inout3 + movdqa $inout2,$in2 + movdqu 0x40($inp),$inout4 + movdqa $inout3,$in3 + movdqu 0x50($inp),$inout5 + movdqa $inout4,$in4 + mov OPENSSL_ia32cap_P+4(%rip),%r9d + cmp \$0x70,$len + jbe .Lcbc_dec_six_or_seven + + and \$`1<<26|1<<22`,%r9d # isolate XSAVE+MOVBE + sub \$0x50,$len # $len is biased by -5*16 + cmp \$`1<<22`,%r9d # check for MOVBE without XSAVE + je .Lcbc_dec_loop6_enter # [which denotes Atom Silvermont] + sub \$0x20,$len # $len is biased by -7*16 + lea 0x70($key),$key # size optimization + jmp .Lcbc_dec_loop8_enter +.align 16 +.Lcbc_dec_loop8: + movups $inout7,($out) + lea 0x10($out),$out +.Lcbc_dec_loop8_enter: + movdqu 0x60($inp),$inout6 + pxor $rndkey0,$inout0 + movdqu 0x70($inp),$inout7 + pxor $rndkey0,$inout1 + $movkey 0x10-0x70($key),$rndkey1 + pxor $rndkey0,$inout2 + xor $inp_,$inp_ + cmp \$0x70,$len # is there at least 0x60 bytes ahead? + pxor $rndkey0,$inout3 + pxor $rndkey0,$inout4 + pxor $rndkey0,$inout5 + pxor $rndkey0,$inout6 + + aesdec $rndkey1,$inout0 + pxor $rndkey0,$inout7 + $movkey 0x20-0x70($key),$rndkey0 + aesdec $rndkey1,$inout1 + aesdec $rndkey1,$inout2 + aesdec $rndkey1,$inout3 + aesdec $rndkey1,$inout4 + aesdec $rndkey1,$inout5 + aesdec $rndkey1,$inout6 + setnc ${inp_}b + shl \$7,$inp_ + aesdec $rndkey1,$inout7 + add $inp,$inp_ + $movkey 0x30-0x70($key),$rndkey1 +___ +for($i=1;$i<12;$i++) { +my $rndkeyx = ($i&1)?$rndkey0:$rndkey1; +$code.=<<___ if ($i==7); + cmp \$11,$rounds +___ +$code.=<<___; + aesdec $rndkeyx,$inout0 + aesdec $rndkeyx,$inout1 + aesdec $rndkeyx,$inout2 + aesdec $rndkeyx,$inout3 + aesdec $rndkeyx,$inout4 + aesdec $rndkeyx,$inout5 + aesdec $rndkeyx,$inout6 + aesdec $rndkeyx,$inout7 + $movkey `0x30+0x10*$i`-0x70($key),$rndkeyx +___ +$code.=<<___ if ($i<6 || (!($i&1) && $i>7)); + nop +___ +$code.=<<___ if ($i==7); + jb .Lcbc_dec_done +___ +$code.=<<___ if ($i==9); + je .Lcbc_dec_done +___ +$code.=<<___ if ($i==11); + jmp .Lcbc_dec_done +___ +} +$code.=<<___; +.align 16 +.Lcbc_dec_done: + aesdec $rndkey1,$inout0 + aesdec $rndkey1,$inout1 + pxor $rndkey0,$iv + pxor $rndkey0,$in0 + aesdec $rndkey1,$inout2 + aesdec $rndkey1,$inout3 + pxor $rndkey0,$in1 + pxor $rndkey0,$in2 + aesdec $rndkey1,$inout4 + aesdec $rndkey1,$inout5 + pxor $rndkey0,$in3 + pxor $rndkey0,$in4 + aesdec $rndkey1,$inout6 + aesdec $rndkey1,$inout7 + movdqu 0x50($inp),$rndkey1 + + aesdeclast $iv,$inout0 + movdqu 0x60($inp),$iv # borrow $iv + pxor $rndkey0,$rndkey1 + aesdeclast $in0,$inout1 + pxor $rndkey0,$iv + movdqu 0x70($inp),$rndkey0 # next IV + aesdeclast $in1,$inout2 + lea 0x80($inp),$inp + movdqu 0x00($inp_),$in0 + aesdeclast $in2,$inout3 + aesdeclast $in3,$inout4 + movdqu 0x10($inp_),$in1 + movdqu 0x20($inp_),$in2 + aesdeclast $in4,$inout5 + aesdeclast $rndkey1,$inout6 + movdqu 0x30($inp_),$in3 + movdqu 0x40($inp_),$in4 + aesdeclast $iv,$inout7 + movdqa $rndkey0,$iv # return $iv + movdqu 0x50($inp_),$rndkey1 + $movkey -0x70($key),$rndkey0 + + movups $inout0,($out) # store output + movdqa $in0,$inout0 + movups $inout1,0x10($out) + movdqa $in1,$inout1 + movups $inout2,0x20($out) + movdqa $in2,$inout2 + movups $inout3,0x30($out) + movdqa $in3,$inout3 + movups $inout4,0x40($out) + movdqa $in4,$inout4 + movups $inout5,0x50($out) + movdqa $rndkey1,$inout5 + movups $inout6,0x60($out) + lea 0x70($out),$out + + sub \$0x80,$len + ja .Lcbc_dec_loop8 + + movaps $inout7,$inout0 + lea -0x70($key),$key + add \$0x70,$len + jle .Lcbc_dec_clear_tail_collected + movups $inout7,($out) + lea 0x10($out),$out + cmp \$0x50,$len + jbe .Lcbc_dec_tail + + movaps $in0,$inout0 +.Lcbc_dec_six_or_seven: + cmp \$0x60,$len + ja .Lcbc_dec_seven + + movaps $inout5,$inout6 + call _aesni_decrypt6 + pxor $iv,$inout0 # ^= IV + movaps $inout6,$iv + pxor $in0,$inout1 + movdqu $inout0,($out) + pxor $in1,$inout2 + movdqu $inout1,0x10($out) + pxor $inout1,$inout1 # clear register bank + pxor $in2,$inout3 + movdqu $inout2,0x20($out) + pxor $inout2,$inout2 + pxor $in3,$inout4 + movdqu $inout3,0x30($out) + pxor $inout3,$inout3 + pxor $in4,$inout5 + movdqu $inout4,0x40($out) + pxor $inout4,$inout4 + lea 0x50($out),$out + movdqa $inout5,$inout0 + pxor $inout5,$inout5 + jmp .Lcbc_dec_tail_collected + +.align 16 +.Lcbc_dec_seven: + movups 0x60($inp),$inout6 + xorps $inout7,$inout7 + call _aesni_decrypt8 + movups 0x50($inp),$inout7 + pxor $iv,$inout0 # ^= IV + movups 0x60($inp),$iv + pxor $in0,$inout1 + movdqu $inout0,($out) + pxor $in1,$inout2 + movdqu $inout1,0x10($out) + pxor $inout1,$inout1 # clear register bank + pxor $in2,$inout3 + movdqu $inout2,0x20($out) + pxor $inout2,$inout2 + pxor $in3,$inout4 + movdqu $inout3,0x30($out) + pxor $inout3,$inout3 + pxor $in4,$inout5 + movdqu $inout4,0x40($out) + pxor $inout4,$inout4 + pxor $inout7,$inout6 + movdqu $inout5,0x50($out) + pxor $inout5,$inout5 + lea 0x60($out),$out + movdqa $inout6,$inout0 + pxor $inout6,$inout6 + pxor $inout7,$inout7 + jmp .Lcbc_dec_tail_collected + +.align 16 +.Lcbc_dec_loop6: + movups $inout5,($out) + lea 0x10($out),$out + movdqu 0x00($inp),$inout0 # load input + movdqu 0x10($inp),$inout1 + movdqa $inout0,$in0 + movdqu 0x20($inp),$inout2 + movdqa $inout1,$in1 + movdqu 0x30($inp),$inout3 + movdqa $inout2,$in2 + movdqu 0x40($inp),$inout4 + movdqa $inout3,$in3 + movdqu 0x50($inp),$inout5 + movdqa $inout4,$in4 +.Lcbc_dec_loop6_enter: + lea 0x60($inp),$inp + movdqa $inout5,$inout6 + + call _aesni_decrypt6 + + pxor $iv,$inout0 # ^= IV + movdqa $inout6,$iv + pxor $in0,$inout1 + movdqu $inout0,($out) + pxor $in1,$inout2 + movdqu $inout1,0x10($out) + pxor $in2,$inout3 + movdqu $inout2,0x20($out) + pxor $in3,$inout4 + mov $key_,$key + movdqu $inout3,0x30($out) + pxor $in4,$inout5 + mov $rnds_,$rounds + movdqu $inout4,0x40($out) + lea 0x50($out),$out + sub \$0x60,$len + ja .Lcbc_dec_loop6 + + movdqa $inout5,$inout0 + add \$0x50,$len + jle .Lcbc_dec_clear_tail_collected + movups $inout5,($out) + lea 0x10($out),$out + +.Lcbc_dec_tail: + movups ($inp),$inout0 + sub \$0x10,$len + jbe .Lcbc_dec_one # $len is 1*16 or less + + movups 0x10($inp),$inout1 + movaps $inout0,$in0 + sub \$0x10,$len + jbe .Lcbc_dec_two # $len is 2*16 or less + + movups 0x20($inp),$inout2 + movaps $inout1,$in1 + sub \$0x10,$len + jbe .Lcbc_dec_three # $len is 3*16 or less + + movups 0x30($inp),$inout3 + movaps $inout2,$in2 + sub \$0x10,$len + jbe .Lcbc_dec_four # $len is 4*16 or less + + movups 0x40($inp),$inout4 # $len is 5*16 or less + movaps $inout3,$in3 + movaps $inout4,$in4 + xorps $inout5,$inout5 + call _aesni_decrypt6 + pxor $iv,$inout0 + movaps $in4,$iv + pxor $in0,$inout1 + movdqu $inout0,($out) + pxor $in1,$inout2 + movdqu $inout1,0x10($out) + pxor $inout1,$inout1 # clear register bank + pxor $in2,$inout3 + movdqu $inout2,0x20($out) + pxor $inout2,$inout2 + pxor $in3,$inout4 + movdqu $inout3,0x30($out) + pxor $inout3,$inout3 + lea 0x40($out),$out + movdqa $inout4,$inout0 + pxor $inout4,$inout4 + pxor $inout5,$inout5 + sub \$0x10,$len + jmp .Lcbc_dec_tail_collected + +.align 16 +.Lcbc_dec_one: + movaps $inout0,$in0 +___ + &aesni_generate1("dec",$key,$rounds); +$code.=<<___; + xorps $iv,$inout0 + movaps $in0,$iv + jmp .Lcbc_dec_tail_collected +.align 16 +.Lcbc_dec_two: + movaps $inout1,$in1 + call _aesni_decrypt2 + pxor $iv,$inout0 + movaps $in1,$iv + pxor $in0,$inout1 + movdqu $inout0,($out) + movdqa $inout1,$inout0 + pxor $inout1,$inout1 # clear register bank + lea 0x10($out),$out + jmp .Lcbc_dec_tail_collected +.align 16 +.Lcbc_dec_three: + movaps $inout2,$in2 + call _aesni_decrypt3 + pxor $iv,$inout0 + movaps $in2,$iv + pxor $in0,$inout1 + movdqu $inout0,($out) + pxor $in1,$inout2 + movdqu $inout1,0x10($out) + pxor $inout1,$inout1 # clear register bank + movdqa $inout2,$inout0 + pxor $inout2,$inout2 + lea 0x20($out),$out + jmp .Lcbc_dec_tail_collected +.align 16 +.Lcbc_dec_four: + movaps $inout3,$in3 + call _aesni_decrypt4 + pxor $iv,$inout0 + movaps $in3,$iv + pxor $in0,$inout1 + movdqu $inout0,($out) + pxor $in1,$inout2 + movdqu $inout1,0x10($out) + pxor $inout1,$inout1 # clear register bank + pxor $in2,$inout3 + movdqu $inout2,0x20($out) + pxor $inout2,$inout2 + movdqa $inout3,$inout0 + pxor $inout3,$inout3 + lea 0x30($out),$out + jmp .Lcbc_dec_tail_collected + +.align 16 +.Lcbc_dec_clear_tail_collected: + pxor $inout1,$inout1 # clear register bank + pxor $inout2,$inout2 + pxor $inout3,$inout3 +___ +$code.=<<___ if (!$win64); + pxor $inout4,$inout4 # %xmm6..9 + pxor $inout5,$inout5 + pxor $inout6,$inout6 + pxor $inout7,$inout7 +___ +$code.=<<___; +.Lcbc_dec_tail_collected: + movups $iv,($ivp) + and \$15,$len + jnz .Lcbc_dec_tail_partial + movups $inout0,($out) + pxor $inout0,$inout0 + jmp .Lcbc_dec_ret +.align 16 +.Lcbc_dec_tail_partial: + movaps $inout0,(%rsp) + pxor $inout0,$inout0 + mov \$16,%rcx + mov $out,%rdi + sub $len,%rcx + lea (%rsp),%rsi + .long 0x9066A4F3 # rep movsb + movdqa $inout0,(%rsp) + +.Lcbc_dec_ret: + xorps $rndkey0,$rndkey0 # %xmm0 + pxor $rndkey1,$rndkey1 +___ +$code.=<<___ if ($win64); + movaps 0x10(%rsp),%xmm6 + movaps %xmm0,0x10(%rsp) # clear stack + movaps 0x20(%rsp),%xmm7 + movaps %xmm0,0x20(%rsp) + movaps 0x30(%rsp),%xmm8 + movaps %xmm0,0x30(%rsp) + movaps 0x40(%rsp),%xmm9 + movaps %xmm0,0x40(%rsp) + movaps 0x50(%rsp),%xmm10 + movaps %xmm0,0x50(%rsp) + movaps 0x60(%rsp),%xmm11 + movaps %xmm0,0x60(%rsp) + movaps 0x70(%rsp),%xmm12 + movaps %xmm0,0x70(%rsp) + movaps 0x80(%rsp),%xmm13 + movaps %xmm0,0x80(%rsp) + movaps 0x90(%rsp),%xmm14 + movaps %xmm0,0x90(%rsp) + movaps 0xa0(%rsp),%xmm15 + movaps %xmm0,0xa0(%rsp) +___ +$code.=<<___; + lea (%rbp),%rsp + pop %rbp +.Lcbc_ret: + ret +.size ${PREFIX}_cbc_encrypt,.-${PREFIX}_cbc_encrypt +___ +} +# int ${PREFIX}_set_decrypt_key(const unsigned char *inp, +# int bits, AES_KEY *key) +# +# input: $inp user-supplied key +# $bits $inp length in bits +# $key pointer to key schedule +# output: %eax 0 denoting success, -1 or -2 - failure (see C) +# *$key key schedule +# +{ my ($inp,$bits,$key) = @_4args; + $bits =~ s/%r/%e/; + +$code.=<<___; +.globl ${PREFIX}_set_decrypt_key +.type ${PREFIX}_set_decrypt_key,\@abi-omnipotent +.align 16 +${PREFIX}_set_decrypt_key: + .byte 0x48,0x83,0xEC,0x08 # sub rsp,8 + call __aesni_set_encrypt_key + shl \$4,$bits # rounds-1 after _aesni_set_encrypt_key + test %eax,%eax + jnz .Ldec_key_ret + lea 16($key,$bits),$inp # points at the end of key schedule + + $movkey ($key),%xmm0 # just swap + $movkey ($inp),%xmm1 + $movkey %xmm0,($inp) + $movkey %xmm1,($key) + lea 16($key),$key + lea -16($inp),$inp + +.Ldec_key_inverse: + $movkey ($key),%xmm0 # swap and inverse + $movkey ($inp),%xmm1 + aesimc %xmm0,%xmm0 + aesimc %xmm1,%xmm1 + lea 16($key),$key + lea -16($inp),$inp + $movkey %xmm0,16($inp) + $movkey %xmm1,-16($key) + cmp $key,$inp + ja .Ldec_key_inverse + + $movkey ($key),%xmm0 # inverse middle + aesimc %xmm0,%xmm0 + pxor %xmm1,%xmm1 + $movkey %xmm0,($inp) + pxor %xmm0,%xmm0 +.Ldec_key_ret: + add \$8,%rsp + ret +.LSEH_end_set_decrypt_key: +.size ${PREFIX}_set_decrypt_key,.-${PREFIX}_set_decrypt_key +___ + +# This is based on submission by +# +# Huang Ying +# Vinodh Gopal +# Kahraman Akdemir +# +# Agressively optimized in respect to aeskeygenassist's critical path +# and is contained in %xmm0-5 to meet Win64 ABI requirement. +# +# int ${PREFIX}_set_encrypt_key(const unsigned char *inp, +# int bits, AES_KEY * const key); +# +# input: $inp user-supplied key +# $bits $inp length in bits +# $key pointer to key schedule +# output: %eax 0 denoting success, -1 or -2 - failure (see C) +# $bits rounds-1 (used in aesni_set_decrypt_key) +# *$key key schedule +# $key pointer to key schedule (used in +# aesni_set_decrypt_key) +# +# Subroutine is frame-less, which means that only volatile registers +# are used. Note that it's declared "abi-omnipotent", which means that +# amount of volatile registers is smaller on Windows. +# +$code.=<<___; +.globl ${PREFIX}_set_encrypt_key +.type ${PREFIX}_set_encrypt_key,\@abi-omnipotent +.align 16 +${PREFIX}_set_encrypt_key: +__aesni_set_encrypt_key: + .byte 0x48,0x83,0xEC,0x08 # sub rsp,8 + mov \$-1,%rax + test $inp,$inp + jz .Lenc_key_ret + test $key,$key + jz .Lenc_key_ret + + mov \$`1<<28|1<<11`,%r10d # AVX and XOP bits + movups ($inp),%xmm0 # pull first 128 bits of *userKey + xorps %xmm4,%xmm4 # low dword of xmm4 is assumed 0 + and OPENSSL_ia32cap_P+4(%rip),%r10d + lea 16($key),%rax # %rax is used as modifiable copy of $key + cmp \$256,$bits + je .L14rounds + cmp \$192,$bits + je .L12rounds + cmp \$128,$bits + jne .Lbad_keybits + +.L10rounds: + mov \$9,$bits # 10 rounds for 128-bit key + cmp \$`1<<28`,%r10d # AVX, bit no XOP + je .L10rounds_alt + + $movkey %xmm0,($key) # round 0 + aeskeygenassist \$0x1,%xmm0,%xmm1 # round 1 + call .Lkey_expansion_128_cold + aeskeygenassist \$0x2,%xmm0,%xmm1 # round 2 + call .Lkey_expansion_128 + aeskeygenassist \$0x4,%xmm0,%xmm1 # round 3 + call .Lkey_expansion_128 + aeskeygenassist \$0x8,%xmm0,%xmm1 # round 4 + call .Lkey_expansion_128 + aeskeygenassist \$0x10,%xmm0,%xmm1 # round 5 + call .Lkey_expansion_128 + aeskeygenassist \$0x20,%xmm0,%xmm1 # round 6 + call .Lkey_expansion_128 + aeskeygenassist \$0x40,%xmm0,%xmm1 # round 7 + call .Lkey_expansion_128 + aeskeygenassist \$0x80,%xmm0,%xmm1 # round 8 + call .Lkey_expansion_128 + aeskeygenassist \$0x1b,%xmm0,%xmm1 # round 9 + call .Lkey_expansion_128 + aeskeygenassist \$0x36,%xmm0,%xmm1 # round 10 + call .Lkey_expansion_128 + $movkey %xmm0,(%rax) + mov $bits,80(%rax) # 240(%rdx) + xor %eax,%eax + jmp .Lenc_key_ret + +.align 16 +.L10rounds_alt: + movdqa .Lkey_rotate(%rip),%xmm5 + mov \$8,%r10d + movdqa .Lkey_rcon1(%rip),%xmm4 + movdqa %xmm0,%xmm2 + movdqu %xmm0,($key) + jmp .Loop_key128 + +.align 16 +.Loop_key128: + pshufb %xmm5,%xmm0 + aesenclast %xmm4,%xmm0 + pslld \$1,%xmm4 + lea 16(%rax),%rax + + movdqa %xmm2,%xmm3 + pslldq \$4,%xmm2 + pxor %xmm2,%xmm3 + pslldq \$4,%xmm2 + pxor %xmm2,%xmm3 + pslldq \$4,%xmm2 + pxor %xmm3,%xmm2 + + pxor %xmm2,%xmm0 + movdqu %xmm0,-16(%rax) + movdqa %xmm0,%xmm2 + + dec %r10d + jnz .Loop_key128 + + movdqa .Lkey_rcon1b(%rip),%xmm4 + + pshufb %xmm5,%xmm0 + aesenclast %xmm4,%xmm0 + pslld \$1,%xmm4 + + movdqa %xmm2,%xmm3 + pslldq \$4,%xmm2 + pxor %xmm2,%xmm3 + pslldq \$4,%xmm2 + pxor %xmm2,%xmm3 + pslldq \$4,%xmm2 + pxor %xmm3,%xmm2 + + pxor %xmm2,%xmm0 + movdqu %xmm0,(%rax) + + movdqa %xmm0,%xmm2 + pshufb %xmm5,%xmm0 + aesenclast %xmm4,%xmm0 + + movdqa %xmm2,%xmm3 + pslldq \$4,%xmm2 + pxor %xmm2,%xmm3 + pslldq \$4,%xmm2 + pxor %xmm2,%xmm3 + pslldq \$4,%xmm2 + pxor %xmm3,%xmm2 + + pxor %xmm2,%xmm0 + movdqu %xmm0,16(%rax) + + mov $bits,96(%rax) # 240($key) + xor %eax,%eax + jmp .Lenc_key_ret + +.align 16 +.L12rounds: + movq 16($inp),%xmm2 # remaining 1/3 of *userKey + mov \$11,$bits # 12 rounds for 192 + cmp \$`1<<28`,%r10d # AVX, but no XOP + je .L12rounds_alt + + $movkey %xmm0,($key) # round 0 + aeskeygenassist \$0x1,%xmm2,%xmm1 # round 1,2 + call .Lkey_expansion_192a_cold + aeskeygenassist \$0x2,%xmm2,%xmm1 # round 2,3 + call .Lkey_expansion_192b + aeskeygenassist \$0x4,%xmm2,%xmm1 # round 4,5 + call .Lkey_expansion_192a + aeskeygenassist \$0x8,%xmm2,%xmm1 # round 5,6 + call .Lkey_expansion_192b + aeskeygenassist \$0x10,%xmm2,%xmm1 # round 7,8 + call .Lkey_expansion_192a + aeskeygenassist \$0x20,%xmm2,%xmm1 # round 8,9 + call .Lkey_expansion_192b + aeskeygenassist \$0x40,%xmm2,%xmm1 # round 10,11 + call .Lkey_expansion_192a + aeskeygenassist \$0x80,%xmm2,%xmm1 # round 11,12 + call .Lkey_expansion_192b + $movkey %xmm0,(%rax) + mov $bits,48(%rax) # 240(%rdx) + xor %rax, %rax + jmp .Lenc_key_ret + +.align 16 +.L12rounds_alt: + movdqa .Lkey_rotate192(%rip),%xmm5 + movdqa .Lkey_rcon1(%rip),%xmm4 + mov \$8,%r10d + movdqu %xmm0,($key) + jmp .Loop_key192 + +.align 16 +.Loop_key192: + movq %xmm2,0(%rax) + movdqa %xmm2,%xmm1 + pshufb %xmm5,%xmm2 + aesenclast %xmm4,%xmm2 + pslld \$1, %xmm4 + lea 24(%rax),%rax + + movdqa %xmm0,%xmm3 + pslldq \$4,%xmm0 + pxor %xmm0,%xmm3 + pslldq \$4,%xmm0 + pxor %xmm0,%xmm3 + pslldq \$4,%xmm0 + pxor %xmm3,%xmm0 + + pshufd \$0xff,%xmm0,%xmm3 + pxor %xmm1,%xmm3 + pslldq \$4,%xmm1 + pxor %xmm1,%xmm3 + + pxor %xmm2,%xmm0 + pxor %xmm3,%xmm2 + movdqu %xmm0,-16(%rax) + + dec %r10d + jnz .Loop_key192 + + mov $bits,32(%rax) # 240($key) + xor %eax,%eax + jmp .Lenc_key_ret + +.align 16 +.L14rounds: + movups 16($inp),%xmm2 # remaning half of *userKey + mov \$13,$bits # 14 rounds for 256 + lea 16(%rax),%rax + cmp \$`1<<28`,%r10d # AVX, but no XOP + je .L14rounds_alt + + $movkey %xmm0,($key) # round 0 + $movkey %xmm2,16($key) # round 1 + aeskeygenassist \$0x1,%xmm2,%xmm1 # round 2 + call .Lkey_expansion_256a_cold + aeskeygenassist \$0x1,%xmm0,%xmm1 # round 3 + call .Lkey_expansion_256b + aeskeygenassist \$0x2,%xmm2,%xmm1 # round 4 + call .Lkey_expansion_256a + aeskeygenassist \$0x2,%xmm0,%xmm1 # round 5 + call .Lkey_expansion_256b + aeskeygenassist \$0x4,%xmm2,%xmm1 # round 6 + call .Lkey_expansion_256a + aeskeygenassist \$0x4,%xmm0,%xmm1 # round 7 + call .Lkey_expansion_256b + aeskeygenassist \$0x8,%xmm2,%xmm1 # round 8 + call .Lkey_expansion_256a + aeskeygenassist \$0x8,%xmm0,%xmm1 # round 9 + call .Lkey_expansion_256b + aeskeygenassist \$0x10,%xmm2,%xmm1 # round 10 + call .Lkey_expansion_256a + aeskeygenassist \$0x10,%xmm0,%xmm1 # round 11 + call .Lkey_expansion_256b + aeskeygenassist \$0x20,%xmm2,%xmm1 # round 12 + call .Lkey_expansion_256a + aeskeygenassist \$0x20,%xmm0,%xmm1 # round 13 + call .Lkey_expansion_256b + aeskeygenassist \$0x40,%xmm2,%xmm1 # round 14 + call .Lkey_expansion_256a + $movkey %xmm0,(%rax) + mov $bits,16(%rax) # 240(%rdx) + xor %rax,%rax + jmp .Lenc_key_ret + +.align 16 +.L14rounds_alt: + movdqa .Lkey_rotate(%rip),%xmm5 + movdqa .Lkey_rcon1(%rip),%xmm4 + mov \$7,%r10d + movdqu %xmm0,0($key) + movdqa %xmm2,%xmm1 + movdqu %xmm2,16($key) + jmp .Loop_key256 + +.align 16 +.Loop_key256: + pshufb %xmm5,%xmm2 + aesenclast %xmm4,%xmm2 + + movdqa %xmm0,%xmm3 + pslldq \$4,%xmm0 + pxor %xmm0,%xmm3 + pslldq \$4,%xmm0 + pxor %xmm0,%xmm3 + pslldq \$4,%xmm0 + pxor %xmm3,%xmm0 + pslld \$1,%xmm4 + + pxor %xmm2,%xmm0 + movdqu %xmm0,(%rax) + + dec %r10d + jz .Ldone_key256 + + pshufd \$0xff,%xmm0,%xmm2 + pxor %xmm3,%xmm3 + aesenclast %xmm3,%xmm2 + + movdqa %xmm1,%xmm3 + pslldq \$4,%xmm1 + pxor %xmm1,%xmm3 + pslldq \$4,%xmm1 + pxor %xmm1,%xmm3 + pslldq \$4,%xmm1 + pxor %xmm3,%xmm1 + + pxor %xmm1,%xmm2 + movdqu %xmm2,16(%rax) + lea 32(%rax),%rax + movdqa %xmm2,%xmm1 + + jmp .Loop_key256 + +.Ldone_key256: + mov $bits,16(%rax) # 240($key) + xor %eax,%eax + jmp .Lenc_key_ret + +.align 16 +.Lbad_keybits: + mov \$-2,%rax +.Lenc_key_ret: + pxor %xmm0,%xmm0 + pxor %xmm1,%xmm1 + pxor %xmm2,%xmm2 + pxor %xmm3,%xmm3 + pxor %xmm4,%xmm4 + pxor %xmm5,%xmm5 + add \$8,%rsp + ret +.LSEH_end_set_encrypt_key: + +.align 16 +.Lkey_expansion_128: + $movkey %xmm0,(%rax) + lea 16(%rax),%rax +.Lkey_expansion_128_cold: + shufps \$0b00010000,%xmm0,%xmm4 + xorps %xmm4, %xmm0 + shufps \$0b10001100,%xmm0,%xmm4 + xorps %xmm4, %xmm0 + shufps \$0b11111111,%xmm1,%xmm1 # critical path + xorps %xmm1,%xmm0 + ret + +.align 16 +.Lkey_expansion_192a: + $movkey %xmm0,(%rax) + lea 16(%rax),%rax +.Lkey_expansion_192a_cold: + movaps %xmm2, %xmm5 +.Lkey_expansion_192b_warm: + shufps \$0b00010000,%xmm0,%xmm4 + movdqa %xmm2,%xmm3 + xorps %xmm4,%xmm0 + shufps \$0b10001100,%xmm0,%xmm4 + pslldq \$4,%xmm3 + xorps %xmm4,%xmm0 + pshufd \$0b01010101,%xmm1,%xmm1 # critical path + pxor %xmm3,%xmm2 + pxor %xmm1,%xmm0 + pshufd \$0b11111111,%xmm0,%xmm3 + pxor %xmm3,%xmm2 + ret + +.align 16 +.Lkey_expansion_192b: + movaps %xmm0,%xmm3 + shufps \$0b01000100,%xmm0,%xmm5 + $movkey %xmm5,(%rax) + shufps \$0b01001110,%xmm2,%xmm3 + $movkey %xmm3,16(%rax) + lea 32(%rax),%rax + jmp .Lkey_expansion_192b_warm + +.align 16 +.Lkey_expansion_256a: + $movkey %xmm2,(%rax) + lea 16(%rax),%rax +.Lkey_expansion_256a_cold: + shufps \$0b00010000,%xmm0,%xmm4 + xorps %xmm4,%xmm0 + shufps \$0b10001100,%xmm0,%xmm4 + xorps %xmm4,%xmm0 + shufps \$0b11111111,%xmm1,%xmm1 # critical path + xorps %xmm1,%xmm0 + ret + +.align 16 +.Lkey_expansion_256b: + $movkey %xmm0,(%rax) + lea 16(%rax),%rax + + shufps \$0b00010000,%xmm2,%xmm4 + xorps %xmm4,%xmm2 + shufps \$0b10001100,%xmm2,%xmm4 + xorps %xmm4,%xmm2 + shufps \$0b10101010,%xmm1,%xmm1 # critical path + xorps %xmm1,%xmm2 + ret +.size ${PREFIX}_set_encrypt_key,.-${PREFIX}_set_encrypt_key +.size __aesni_set_encrypt_key,.-__aesni_set_encrypt_key +___ +} + +$code.=<<___; +.align 64 +.Lbswap_mask: + .byte 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 +.Lincrement32: + .long 6,6,6,0 +.Lincrement64: + .long 1,0,0,0 +.Lxts_magic: + .long 0x87,0,1,0 +.Lincrement1: + .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 +.Lkey_rotate: + .long 0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d +.Lkey_rotate192: + .long 0x04070605,0x04070605,0x04070605,0x04070605 +.Lkey_rcon1: + .long 1,1,1,1 +.Lkey_rcon1b: + .long 0x1b,0x1b,0x1b,0x1b + +.asciz "AES for Intel AES-NI, CRYPTOGAMS by " +.align 64 +___ + +# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame, +# CONTEXT *context,DISPATCHER_CONTEXT *disp) +if ($win64) { +$rec="%rcx"; +$frame="%rdx"; +$context="%r8"; +$disp="%r9"; + +$code.=<<___; +.extern __imp_RtlVirtualUnwind +___ +$code.=<<___ if ($PREFIX eq "aesni"); +.type ecb_ccm64_se_handler,\@abi-omnipotent +.align 16 +ecb_ccm64_se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + mov 8($disp),%rsi # disp->ImageBase + mov 56($disp),%r11 # disp->HandlerData + + mov 0(%r11),%r10d # HandlerData[0] + lea (%rsi,%r10),%r10 # prologue label + cmp %r10,%rbx # context->RipRsp + + mov 4(%r11),%r10d # HandlerData[1] + lea (%rsi,%r10),%r10 # epilogue label + cmp %r10,%rbx # context->Rip>=epilogue label + jae .Lcommon_seh_tail + + lea 0(%rax),%rsi # %xmm save area + lea 512($context),%rdi # &context.Xmm6 + mov \$8,%ecx # 4*sizeof(%xmm0)/sizeof(%rax) + .long 0xa548f3fc # cld; rep movsq + lea 0x58(%rax),%rax # adjust stack pointer + + jmp .Lcommon_seh_tail +.size ecb_ccm64_se_handler,.-ecb_ccm64_se_handler + +.type ctr_xts_se_handler,\@abi-omnipotent +.align 16 +ctr_xts_se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + mov 8($disp),%rsi # disp->ImageBase + mov 56($disp),%r11 # disp->HandlerData + + mov 0(%r11),%r10d # HandlerData[0] + lea (%rsi,%r10),%r10 # prologue lable + cmp %r10,%rbx # context->RipRsp + + mov 4(%r11),%r10d # HandlerData[1] + lea (%rsi,%r10),%r10 # epilogue label + cmp %r10,%rbx # context->Rip>=epilogue label + jae .Lcommon_seh_tail + + mov 160($context),%rax # pull context->Rbp + lea -0xa0(%rax),%rsi # %xmm save area + lea 512($context),%rdi # & context.Xmm6 + mov \$20,%ecx # 10*sizeof(%xmm0)/sizeof(%rax) + .long 0xa548f3fc # cld; rep movsq + + jmp .Lcommon_rbp_tail +.size ctr_xts_se_handler,.-ctr_xts_se_handler +___ +$code.=<<___; +.type cbc_se_handler,\@abi-omnipotent +.align 16 +cbc_se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 152($context),%rax # pull context->Rsp + mov 248($context),%rbx # pull context->Rip + + lea .Lcbc_decrypt_bulk(%rip),%r10 + cmp %r10,%rbx # context->Rip<"prologue" label + jb .Lcommon_seh_tail + + lea .Lcbc_decrypt_body(%rip),%r10 + cmp %r10,%rbx # context->RipRip>="epilogue" label + jae .Lcommon_seh_tail + + lea 16(%rax),%rsi # %xmm save area + lea 512($context),%rdi # &context.Xmm6 + mov \$20,%ecx # 10*sizeof(%xmm0)/sizeof(%rax) + .long 0xa548f3fc # cld; rep movsq + +.Lcommon_rbp_tail: + mov 160($context),%rax # pull context->Rbp + mov (%rax),%rbp # restore saved %rbp + lea 8(%rax),%rax # adjust stack pointer + mov %rbp,160($context) # restore context->Rbp + jmp .Lcommon_seh_tail + +.Lrestore_cbc_rax: + mov 120($context),%rax + +.Lcommon_seh_tail: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + + mov 40($disp),%rdi # disp->ContextRecord + mov $context,%rsi # context + mov \$154,%ecx # sizeof(CONTEXT) + .long 0xa548f3fc # cld; rep movsq + + mov $disp,%rsi + xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER + mov 8(%rsi),%rdx # arg2, disp->ImageBase + mov 0(%rsi),%r8 # arg3, disp->ControlPc + mov 16(%rsi),%r9 # arg4, disp->FunctionEntry + mov 40(%rsi),%r10 # disp->ContextRecord + lea 56(%rsi),%r11 # &disp->HandlerData + lea 24(%rsi),%r12 # &disp->EstablisherFrame + mov %r10,32(%rsp) # arg5 + mov %r11,40(%rsp) # arg6 + mov %r12,48(%rsp) # arg7 + mov %rcx,56(%rsp) # arg8, (NULL) + call *__imp_RtlVirtualUnwind(%rip) + + mov \$1,%eax # ExceptionContinueSearch + add \$64,%rsp + popfq + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + pop %rdi + pop %rsi + ret +.size cbc_se_handler,.-cbc_se_handler + +.section .pdata +.align 4 +___ +$code.=<<___ if ($PREFIX eq "aesni"); + .rva .LSEH_begin_aesni_ecb_encrypt + .rva .LSEH_end_aesni_ecb_encrypt + .rva .LSEH_info_ecb + + .rva .LSEH_begin_aesni_ccm64_encrypt_blocks + .rva .LSEH_end_aesni_ccm64_encrypt_blocks + .rva .LSEH_info_ccm64_enc + + .rva .LSEH_begin_aesni_ccm64_decrypt_blocks + .rva .LSEH_end_aesni_ccm64_decrypt_blocks + .rva .LSEH_info_ccm64_dec + + .rva .LSEH_begin_aesni_ctr32_encrypt_blocks + .rva .LSEH_end_aesni_ctr32_encrypt_blocks + .rva .LSEH_info_ctr32 + + .rva .LSEH_begin_aesni_xts_encrypt + .rva .LSEH_end_aesni_xts_encrypt + .rva .LSEH_info_xts_enc + + .rva .LSEH_begin_aesni_xts_decrypt + .rva .LSEH_end_aesni_xts_decrypt + .rva .LSEH_info_xts_dec +___ +$code.=<<___; + .rva .LSEH_begin_${PREFIX}_cbc_encrypt + .rva .LSEH_end_${PREFIX}_cbc_encrypt + .rva .LSEH_info_cbc + + .rva ${PREFIX}_set_decrypt_key + .rva .LSEH_end_set_decrypt_key + .rva .LSEH_info_key + + .rva ${PREFIX}_set_encrypt_key + .rva .LSEH_end_set_encrypt_key + .rva .LSEH_info_key +.section .xdata +.align 8 +___ +$code.=<<___ if ($PREFIX eq "aesni"); +.LSEH_info_ecb: + .byte 9,0,0,0 + .rva ecb_ccm64_se_handler + .rva .Lecb_enc_body,.Lecb_enc_ret # HandlerData[] +.LSEH_info_ccm64_enc: + .byte 9,0,0,0 + .rva ecb_ccm64_se_handler + .rva .Lccm64_enc_body,.Lccm64_enc_ret # HandlerData[] +.LSEH_info_ccm64_dec: + .byte 9,0,0,0 + .rva ecb_ccm64_se_handler + .rva .Lccm64_dec_body,.Lccm64_dec_ret # HandlerData[] +.LSEH_info_ctr32: + .byte 9,0,0,0 + .rva ctr_xts_se_handler + .rva .Lctr32_body,.Lctr32_epilogue # HandlerData[] +.LSEH_info_xts_enc: + .byte 9,0,0,0 + .rva ctr_xts_se_handler + .rva .Lxts_enc_body,.Lxts_enc_epilogue # HandlerData[] +.LSEH_info_xts_dec: + .byte 9,0,0,0 + .rva ctr_xts_se_handler + .rva .Lxts_dec_body,.Lxts_dec_epilogue # HandlerData[] +___ +$code.=<<___; +.LSEH_info_cbc: + .byte 9,0,0,0 + .rva cbc_se_handler +.LSEH_info_key: + .byte 0x01,0x04,0x01,0x00 + .byte 0x04,0x02,0x00,0x00 # sub rsp,8 +___ +} + +sub rex { + local *opcode=shift; + my ($dst,$src)=@_; + my $rex=0; + + $rex|=0x04 if($dst>=8); + $rex|=0x01 if($src>=8); + push @opcode,$rex|0x40 if($rex); +} + +sub aesni { + my $line=shift; + my @opcode=(0x66); + + if ($line=~/(aeskeygenassist)\s+\$([x0-9a-f]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) { + rex(\@opcode,$4,$3); + push @opcode,0x0f,0x3a,0xdf; + push @opcode,0xc0|($3&7)|(($4&7)<<3); # ModR/M + my $c=$2; + push @opcode,$c=~/^0/?oct($c):$c; + return ".byte\t".join(',',@opcode); + } + elsif ($line=~/(aes[a-z]+)\s+%xmm([0-9]+),\s*%xmm([0-9]+)/) { + my %opcodelet = ( + "aesimc" => 0xdb, + "aesenc" => 0xdc, "aesenclast" => 0xdd, + "aesdec" => 0xde, "aesdeclast" => 0xdf + ); + return undef if (!defined($opcodelet{$1})); + rex(\@opcode,$3,$2); + push @opcode,0x0f,0x38,$opcodelet{$1}; + push @opcode,0xc0|($2&7)|(($3&7)<<3); # ModR/M + return ".byte\t".join(',',@opcode); + } + elsif ($line=~/(aes[a-z]+)\s+([0x1-9a-fA-F]*)\(%rsp\),\s*%xmm([0-9]+)/) { + my %opcodelet = ( + "aesenc" => 0xdc, "aesenclast" => 0xdd, + "aesdec" => 0xde, "aesdeclast" => 0xdf + ); + return undef if (!defined($opcodelet{$1})); + my $off = $2; + push @opcode,0x44 if ($3>=8); + push @opcode,0x0f,0x38,$opcodelet{$1}; + push @opcode,0x44|(($3&7)<<3),0x24; # ModR/M + push @opcode,($off=~/^0/?oct($off):$off)&0xff; + return ".byte\t".join(',',@opcode); + } + return $line; +} + +sub movbe { + ".byte 0x0f,0x38,0xf1,0x44,0x24,".shift; +} + +$code =~ s/\`([^\`]*)\`/eval($1)/gem; +$code =~ s/\b(aes.*%xmm[0-9]+).*$/aesni($1)/gem; +#$code =~ s/\bmovbe\s+%eax/bswap %eax; mov %eax/gm; # debugging artefact +$code =~ s/\bmovbe\s+%eax,\s*([0-9]+)\(%rsp\)/movbe($1)/gem; + +print $code; + +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/aes/asm/aesv8-armx.pl b/TMessagesProj/jni/boringssl/crypto/aes/asm/aesv8-armx.pl new file mode 100644 index 00000000..b0916f66 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/aes/asm/aesv8-armx.pl @@ -0,0 +1,1001 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# This module implements support for ARMv8 AES instructions. The +# module is endian-agnostic in sense that it supports both big- and +# little-endian cases. As does it support both 32- and 64-bit modes +# of operation. Latter is achieved by limiting amount of utilized +# registers to 16, which implies additional NEON load and integer +# instructions. This has no effect on mighty Apple A7, where results +# are literally equal to the theoretical estimates based on AES +# instruction latencies and issue rates. On Cortex-A53, an in-order +# execution core, this costs up to 10-15%, which is partially +# compensated by implementing dedicated code path for 128-bit +# CBC encrypt case. On Cortex-A57 parallelizable mode performance +# seems to be limited by sheer amount of NEON instructions... +# +# Performance in cycles per byte processed with 128-bit key: +# +# CBC enc CBC dec CTR +# Apple A7 2.39 1.20 1.20 +# Cortex-A53 1.32 1.29 1.46 +# Cortex-A57(*) 1.95 0.85 0.93 +# Denver 1.96 0.86 0.80 +# +# (*) original 3.64/1.34/1.32 results were for r0p0 revision +# and are still same even for updated module; + +$flavour = shift; +$output = shift; + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or +die "can't locate arm-xlate.pl"; + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +$prefix="aes_v8"; + +$code=<<___; +#include "arm_arch.h" + +#if __ARM_MAX_ARCH__>=7 +.text +___ +$code.=<<___ if ($flavour =~ /64/); +#if !defined(__clang__) +.arch armv8-a+crypto +#endif +___ +$code.=".arch armv7-a\n.fpu neon\n.code 32\n" if ($flavour !~ /64/); + #^^^^^^ this is done to simplify adoption by not depending + # on latest binutils. + +# Assembler mnemonics are an eclectic mix of 32- and 64-bit syntax, +# NEON is mostly 32-bit mnemonics, integer - mostly 64. Goal is to +# maintain both 32- and 64-bit codes within single module and +# transliterate common code to either flavour with regex vodoo. +# +{{{ +my ($inp,$bits,$out,$ptr,$rounds)=("x0","w1","x2","x3","w12"); +my ($zero,$rcon,$mask,$in0,$in1,$tmp,$key)= + $flavour=~/64/? map("q$_",(0..6)) : map("q$_",(0..3,8..10)); + + +$code.=<<___; +.align 5 +.Lrcon: +.long 0x01,0x01,0x01,0x01 +.long 0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d // rotate-n-splat +.long 0x1b,0x1b,0x1b,0x1b + +.globl ${prefix}_set_encrypt_key +.type ${prefix}_set_encrypt_key,%function +.align 5 +${prefix}_set_encrypt_key: +.Lenc_key: +___ +$code.=<<___ if ($flavour =~ /64/); + stp x29,x30,[sp,#-16]! + add x29,sp,#0 +___ +$code.=<<___; + mov $ptr,#-1 + cmp $inp,#0 + b.eq .Lenc_key_abort + cmp $out,#0 + b.eq .Lenc_key_abort + mov $ptr,#-2 + cmp $bits,#128 + b.lt .Lenc_key_abort + cmp $bits,#256 + b.gt .Lenc_key_abort + tst $bits,#0x3f + b.ne .Lenc_key_abort + + adr $ptr,.Lrcon + cmp $bits,#192 + + veor $zero,$zero,$zero + vld1.8 {$in0},[$inp],#16 + mov $bits,#8 // reuse $bits + vld1.32 {$rcon,$mask},[$ptr],#32 + + b.lt .Loop128 + b.eq .L192 + b .L256 + +.align 4 +.Loop128: + vtbl.8 $key,{$in0},$mask + vext.8 $tmp,$zero,$in0,#12 + vst1.32 {$in0},[$out],#16 + aese $key,$zero + subs $bits,$bits,#1 + + veor $in0,$in0,$tmp + vext.8 $tmp,$zero,$tmp,#12 + veor $in0,$in0,$tmp + vext.8 $tmp,$zero,$tmp,#12 + veor $key,$key,$rcon + veor $in0,$in0,$tmp + vshl.u8 $rcon,$rcon,#1 + veor $in0,$in0,$key + b.ne .Loop128 + + vld1.32 {$rcon},[$ptr] + + vtbl.8 $key,{$in0},$mask + vext.8 $tmp,$zero,$in0,#12 + vst1.32 {$in0},[$out],#16 + aese $key,$zero + + veor $in0,$in0,$tmp + vext.8 $tmp,$zero,$tmp,#12 + veor $in0,$in0,$tmp + vext.8 $tmp,$zero,$tmp,#12 + veor $key,$key,$rcon + veor $in0,$in0,$tmp + vshl.u8 $rcon,$rcon,#1 + veor $in0,$in0,$key + + vtbl.8 $key,{$in0},$mask + vext.8 $tmp,$zero,$in0,#12 + vst1.32 {$in0},[$out],#16 + aese $key,$zero + + veor $in0,$in0,$tmp + vext.8 $tmp,$zero,$tmp,#12 + veor $in0,$in0,$tmp + vext.8 $tmp,$zero,$tmp,#12 + veor $key,$key,$rcon + veor $in0,$in0,$tmp + veor $in0,$in0,$key + vst1.32 {$in0},[$out] + add $out,$out,#0x50 + + mov $rounds,#10 + b .Ldone + +.align 4 +.L192: + vld1.8 {$in1},[$inp],#8 + vmov.i8 $key,#8 // borrow $key + vst1.32 {$in0},[$out],#16 + vsub.i8 $mask,$mask,$key // adjust the mask + +.Loop192: + vtbl.8 $key,{$in1},$mask + vext.8 $tmp,$zero,$in0,#12 + vst1.32 {$in1},[$out],#8 + aese $key,$zero + subs $bits,$bits,#1 + + veor $in0,$in0,$tmp + vext.8 $tmp,$zero,$tmp,#12 + veor $in0,$in0,$tmp + vext.8 $tmp,$zero,$tmp,#12 + veor $in0,$in0,$tmp + + vdup.32 $tmp,${in0}[3] + veor $tmp,$tmp,$in1 + veor $key,$key,$rcon + vext.8 $in1,$zero,$in1,#12 + vshl.u8 $rcon,$rcon,#1 + veor $in1,$in1,$tmp + veor $in0,$in0,$key + veor $in1,$in1,$key + vst1.32 {$in0},[$out],#16 + b.ne .Loop192 + + mov $rounds,#12 + add $out,$out,#0x20 + b .Ldone + +.align 4 +.L256: + vld1.8 {$in1},[$inp] + mov $bits,#7 + mov $rounds,#14 + vst1.32 {$in0},[$out],#16 + +.Loop256: + vtbl.8 $key,{$in1},$mask + vext.8 $tmp,$zero,$in0,#12 + vst1.32 {$in1},[$out],#16 + aese $key,$zero + subs $bits,$bits,#1 + + veor $in0,$in0,$tmp + vext.8 $tmp,$zero,$tmp,#12 + veor $in0,$in0,$tmp + vext.8 $tmp,$zero,$tmp,#12 + veor $key,$key,$rcon + veor $in0,$in0,$tmp + vshl.u8 $rcon,$rcon,#1 + veor $in0,$in0,$key + vst1.32 {$in0},[$out],#16 + b.eq .Ldone + + vdup.32 $key,${in0}[3] // just splat + vext.8 $tmp,$zero,$in1,#12 + aese $key,$zero + + veor $in1,$in1,$tmp + vext.8 $tmp,$zero,$tmp,#12 + veor $in1,$in1,$tmp + vext.8 $tmp,$zero,$tmp,#12 + veor $in1,$in1,$tmp + + veor $in1,$in1,$key + b .Loop256 + +.Ldone: + str $rounds,[$out] + mov $ptr,#0 + +.Lenc_key_abort: + mov x0,$ptr // return value + `"ldr x29,[sp],#16" if ($flavour =~ /64/)` + ret +.size ${prefix}_set_encrypt_key,.-${prefix}_set_encrypt_key + +.globl ${prefix}_set_decrypt_key +.type ${prefix}_set_decrypt_key,%function +.align 5 +${prefix}_set_decrypt_key: +___ +$code.=<<___ if ($flavour =~ /64/); + stp x29,x30,[sp,#-16]! + add x29,sp,#0 +___ +$code.=<<___ if ($flavour !~ /64/); + stmdb sp!,{r4,lr} +___ +$code.=<<___; + bl .Lenc_key + + cmp x0,#0 + b.ne .Ldec_key_abort + + sub $out,$out,#240 // restore original $out + mov x4,#-16 + add $inp,$out,x12,lsl#4 // end of key schedule + + vld1.32 {v0.16b},[$out] + vld1.32 {v1.16b},[$inp] + vst1.32 {v0.16b},[$inp],x4 + vst1.32 {v1.16b},[$out],#16 + +.Loop_imc: + vld1.32 {v0.16b},[$out] + vld1.32 {v1.16b},[$inp] + aesimc v0.16b,v0.16b + aesimc v1.16b,v1.16b + vst1.32 {v0.16b},[$inp],x4 + vst1.32 {v1.16b},[$out],#16 + cmp $inp,$out + b.hi .Loop_imc + + vld1.32 {v0.16b},[$out] + aesimc v0.16b,v0.16b + vst1.32 {v0.16b},[$inp] + + eor x0,x0,x0 // return value +.Ldec_key_abort: +___ +$code.=<<___ if ($flavour !~ /64/); + ldmia sp!,{r4,pc} +___ +$code.=<<___ if ($flavour =~ /64/); + ldp x29,x30,[sp],#16 + ret +___ +$code.=<<___; +.size ${prefix}_set_decrypt_key,.-${prefix}_set_decrypt_key +___ +}}} +{{{ +sub gen_block () { +my $dir = shift; +my ($e,$mc) = $dir eq "en" ? ("e","mc") : ("d","imc"); +my ($inp,$out,$key)=map("x$_",(0..2)); +my $rounds="w3"; +my ($rndkey0,$rndkey1,$inout)=map("q$_",(0..3)); + +$code.=<<___; +.globl ${prefix}_${dir}crypt +.type ${prefix}_${dir}crypt,%function +.align 5 +${prefix}_${dir}crypt: + ldr $rounds,[$key,#240] + vld1.32 {$rndkey0},[$key],#16 + vld1.8 {$inout},[$inp] + sub $rounds,$rounds,#2 + vld1.32 {$rndkey1},[$key],#16 + +.Loop_${dir}c: + aes$e $inout,$rndkey0 + aes$mc $inout,$inout + vld1.32 {$rndkey0},[$key],#16 + subs $rounds,$rounds,#2 + aes$e $inout,$rndkey1 + aes$mc $inout,$inout + vld1.32 {$rndkey1},[$key],#16 + b.gt .Loop_${dir}c + + aes$e $inout,$rndkey0 + aes$mc $inout,$inout + vld1.32 {$rndkey0},[$key] + aes$e $inout,$rndkey1 + veor $inout,$inout,$rndkey0 + + vst1.8 {$inout},[$out] + ret +.size ${prefix}_${dir}crypt,.-${prefix}_${dir}crypt +___ +} +&gen_block("en"); +&gen_block("de"); +}}} +{{{ +my ($inp,$out,$len,$key,$ivp)=map("x$_",(0..4)); my $enc="w5"; +my ($rounds,$cnt,$key_,$step,$step1)=($enc,"w6","x7","x8","x12"); +my ($dat0,$dat1,$in0,$in1,$tmp0,$tmp1,$ivec,$rndlast)=map("q$_",(0..7)); + +my ($dat,$tmp,$rndzero_n_last)=($dat0,$tmp0,$tmp1); +my ($key4,$key5,$key6,$key7)=("x6","x12","x14",$key); + +### q8-q15 preloaded key schedule + +$code.=<<___; +.globl ${prefix}_cbc_encrypt +.type ${prefix}_cbc_encrypt,%function +.align 5 +${prefix}_cbc_encrypt: +___ +$code.=<<___ if ($flavour =~ /64/); + stp x29,x30,[sp,#-16]! + add x29,sp,#0 +___ +$code.=<<___ if ($flavour !~ /64/); + mov ip,sp + stmdb sp!,{r4-r8,lr} + vstmdb sp!,{d8-d15} @ ABI specification says so + ldmia ip,{r4-r5} @ load remaining args +___ +$code.=<<___; + subs $len,$len,#16 + mov $step,#16 + b.lo .Lcbc_abort + cclr $step,eq + + cmp $enc,#0 // en- or decrypting? + ldr $rounds,[$key,#240] + and $len,$len,#-16 + vld1.8 {$ivec},[$ivp] + vld1.8 {$dat},[$inp],$step + + vld1.32 {q8-q9},[$key] // load key schedule... + sub $rounds,$rounds,#6 + add $key_,$key,x5,lsl#4 // pointer to last 7 round keys + sub $rounds,$rounds,#2 + vld1.32 {q10-q11},[$key_],#32 + vld1.32 {q12-q13},[$key_],#32 + vld1.32 {q14-q15},[$key_],#32 + vld1.32 {$rndlast},[$key_] + + add $key_,$key,#32 + mov $cnt,$rounds + b.eq .Lcbc_dec + + cmp $rounds,#2 + veor $dat,$dat,$ivec + veor $rndzero_n_last,q8,$rndlast + b.eq .Lcbc_enc128 + + vld1.32 {$in0-$in1},[$key_] + add $key_,$key,#16 + add $key4,$key,#16*4 + add $key5,$key,#16*5 + aese $dat,q8 + aesmc $dat,$dat + add $key6,$key,#16*6 + add $key7,$key,#16*7 + b .Lenter_cbc_enc + +.align 4 +.Loop_cbc_enc: + aese $dat,q8 + aesmc $dat,$dat + vst1.8 {$ivec},[$out],#16 +.Lenter_cbc_enc: + aese $dat,q9 + aesmc $dat,$dat + aese $dat,$in0 + aesmc $dat,$dat + vld1.32 {q8},[$key4] + cmp $rounds,#4 + aese $dat,$in1 + aesmc $dat,$dat + vld1.32 {q9},[$key5] + b.eq .Lcbc_enc192 + + aese $dat,q8 + aesmc $dat,$dat + vld1.32 {q8},[$key6] + aese $dat,q9 + aesmc $dat,$dat + vld1.32 {q9},[$key7] + nop + +.Lcbc_enc192: + aese $dat,q8 + aesmc $dat,$dat + subs $len,$len,#16 + aese $dat,q9 + aesmc $dat,$dat + cclr $step,eq + aese $dat,q10 + aesmc $dat,$dat + aese $dat,q11 + aesmc $dat,$dat + vld1.8 {q8},[$inp],$step + aese $dat,q12 + aesmc $dat,$dat + veor q8,q8,$rndzero_n_last + aese $dat,q13 + aesmc $dat,$dat + vld1.32 {q9},[$key_] // re-pre-load rndkey[1] + aese $dat,q14 + aesmc $dat,$dat + aese $dat,q15 + veor $ivec,$dat,$rndlast + b.hs .Loop_cbc_enc + + vst1.8 {$ivec},[$out],#16 + b .Lcbc_done + +.align 5 +.Lcbc_enc128: + vld1.32 {$in0-$in1},[$key_] + aese $dat,q8 + aesmc $dat,$dat + b .Lenter_cbc_enc128 +.Loop_cbc_enc128: + aese $dat,q8 + aesmc $dat,$dat + vst1.8 {$ivec},[$out],#16 +.Lenter_cbc_enc128: + aese $dat,q9 + aesmc $dat,$dat + subs $len,$len,#16 + aese $dat,$in0 + aesmc $dat,$dat + cclr $step,eq + aese $dat,$in1 + aesmc $dat,$dat + aese $dat,q10 + aesmc $dat,$dat + aese $dat,q11 + aesmc $dat,$dat + vld1.8 {q8},[$inp],$step + aese $dat,q12 + aesmc $dat,$dat + aese $dat,q13 + aesmc $dat,$dat + aese $dat,q14 + aesmc $dat,$dat + veor q8,q8,$rndzero_n_last + aese $dat,q15 + veor $ivec,$dat,$rndlast + b.hs .Loop_cbc_enc128 + + vst1.8 {$ivec},[$out],#16 + b .Lcbc_done +___ +{ +my ($dat2,$in2,$tmp2)=map("q$_",(10,11,9)); +$code.=<<___; +.align 5 +.Lcbc_dec: + vld1.8 {$dat2},[$inp],#16 + subs $len,$len,#32 // bias + add $cnt,$rounds,#2 + vorr $in1,$dat,$dat + vorr $dat1,$dat,$dat + vorr $in2,$dat2,$dat2 + b.lo .Lcbc_dec_tail + + vorr $dat1,$dat2,$dat2 + vld1.8 {$dat2},[$inp],#16 + vorr $in0,$dat,$dat + vorr $in1,$dat1,$dat1 + vorr $in2,$dat2,$dat2 + +.Loop3x_cbc_dec: + aesd $dat0,q8 + aesimc $dat0,$dat0 + aesd $dat1,q8 + aesimc $dat1,$dat1 + aesd $dat2,q8 + aesimc $dat2,$dat2 + vld1.32 {q8},[$key_],#16 + subs $cnt,$cnt,#2 + aesd $dat0,q9 + aesimc $dat0,$dat0 + aesd $dat1,q9 + aesimc $dat1,$dat1 + aesd $dat2,q9 + aesimc $dat2,$dat2 + vld1.32 {q9},[$key_],#16 + b.gt .Loop3x_cbc_dec + + aesd $dat0,q8 + aesimc $dat0,$dat0 + aesd $dat1,q8 + aesimc $dat1,$dat1 + aesd $dat2,q8 + aesimc $dat2,$dat2 + veor $tmp0,$ivec,$rndlast + subs $len,$len,#0x30 + veor $tmp1,$in0,$rndlast + mov.lo x6,$len // x6, $cnt, is zero at this point + aesd $dat0,q9 + aesimc $dat0,$dat0 + aesd $dat1,q9 + aesimc $dat1,$dat1 + aesd $dat2,q9 + aesimc $dat2,$dat2 + veor $tmp2,$in1,$rndlast + add $inp,$inp,x6 // $inp is adjusted in such way that + // at exit from the loop $dat1-$dat2 + // are loaded with last "words" + vorr $ivec,$in2,$in2 + mov $key_,$key + aesd $dat0,q12 + aesimc $dat0,$dat0 + aesd $dat1,q12 + aesimc $dat1,$dat1 + aesd $dat2,q12 + aesimc $dat2,$dat2 + vld1.8 {$in0},[$inp],#16 + aesd $dat0,q13 + aesimc $dat0,$dat0 + aesd $dat1,q13 + aesimc $dat1,$dat1 + aesd $dat2,q13 + aesimc $dat2,$dat2 + vld1.8 {$in1},[$inp],#16 + aesd $dat0,q14 + aesimc $dat0,$dat0 + aesd $dat1,q14 + aesimc $dat1,$dat1 + aesd $dat2,q14 + aesimc $dat2,$dat2 + vld1.8 {$in2},[$inp],#16 + aesd $dat0,q15 + aesd $dat1,q15 + aesd $dat2,q15 + vld1.32 {q8},[$key_],#16 // re-pre-load rndkey[0] + add $cnt,$rounds,#2 + veor $tmp0,$tmp0,$dat0 + veor $tmp1,$tmp1,$dat1 + veor $dat2,$dat2,$tmp2 + vld1.32 {q9},[$key_],#16 // re-pre-load rndkey[1] + vst1.8 {$tmp0},[$out],#16 + vorr $dat0,$in0,$in0 + vst1.8 {$tmp1},[$out],#16 + vorr $dat1,$in1,$in1 + vst1.8 {$dat2},[$out],#16 + vorr $dat2,$in2,$in2 + b.hs .Loop3x_cbc_dec + + cmn $len,#0x30 + b.eq .Lcbc_done + nop + +.Lcbc_dec_tail: + aesd $dat1,q8 + aesimc $dat1,$dat1 + aesd $dat2,q8 + aesimc $dat2,$dat2 + vld1.32 {q8},[$key_],#16 + subs $cnt,$cnt,#2 + aesd $dat1,q9 + aesimc $dat1,$dat1 + aesd $dat2,q9 + aesimc $dat2,$dat2 + vld1.32 {q9},[$key_],#16 + b.gt .Lcbc_dec_tail + + aesd $dat1,q8 + aesimc $dat1,$dat1 + aesd $dat2,q8 + aesimc $dat2,$dat2 + aesd $dat1,q9 + aesimc $dat1,$dat1 + aesd $dat2,q9 + aesimc $dat2,$dat2 + aesd $dat1,q12 + aesimc $dat1,$dat1 + aesd $dat2,q12 + aesimc $dat2,$dat2 + cmn $len,#0x20 + aesd $dat1,q13 + aesimc $dat1,$dat1 + aesd $dat2,q13 + aesimc $dat2,$dat2 + veor $tmp1,$ivec,$rndlast + aesd $dat1,q14 + aesimc $dat1,$dat1 + aesd $dat2,q14 + aesimc $dat2,$dat2 + veor $tmp2,$in1,$rndlast + aesd $dat1,q15 + aesd $dat2,q15 + b.eq .Lcbc_dec_one + veor $tmp1,$tmp1,$dat1 + veor $tmp2,$tmp2,$dat2 + vorr $ivec,$in2,$in2 + vst1.8 {$tmp1},[$out],#16 + vst1.8 {$tmp2},[$out],#16 + b .Lcbc_done + +.Lcbc_dec_one: + veor $tmp1,$tmp1,$dat2 + vorr $ivec,$in2,$in2 + vst1.8 {$tmp1},[$out],#16 + +.Lcbc_done: + vst1.8 {$ivec},[$ivp] +.Lcbc_abort: +___ +} +$code.=<<___ if ($flavour !~ /64/); + vldmia sp!,{d8-d15} + ldmia sp!,{r4-r8,pc} +___ +$code.=<<___ if ($flavour =~ /64/); + ldr x29,[sp],#16 + ret +___ +$code.=<<___; +.size ${prefix}_cbc_encrypt,.-${prefix}_cbc_encrypt +___ +}}} +{{{ +my ($inp,$out,$len,$key,$ivp)=map("x$_",(0..4)); +my ($rounds,$cnt,$key_)=("w5","w6","x7"); +my ($ctr,$tctr0,$tctr1,$tctr2)=map("w$_",(8..10,12)); +my $step="x12"; # aliases with $tctr2 + +my ($dat0,$dat1,$in0,$in1,$tmp0,$tmp1,$ivec,$rndlast)=map("q$_",(0..7)); +my ($dat2,$in2,$tmp2)=map("q$_",(10,11,9)); + +my ($dat,$tmp)=($dat0,$tmp0); + +### q8-q15 preloaded key schedule + +$code.=<<___; +.globl ${prefix}_ctr32_encrypt_blocks +.type ${prefix}_ctr32_encrypt_blocks,%function +.align 5 +${prefix}_ctr32_encrypt_blocks: +___ +$code.=<<___ if ($flavour =~ /64/); + stp x29,x30,[sp,#-16]! + add x29,sp,#0 +___ +$code.=<<___ if ($flavour !~ /64/); + mov ip,sp + stmdb sp!,{r4-r10,lr} + vstmdb sp!,{d8-d15} @ ABI specification says so + ldr r4, [ip] @ load remaining arg +___ +$code.=<<___; + ldr $rounds,[$key,#240] + + ldr $ctr, [$ivp, #12] + vld1.32 {$dat0},[$ivp] + + vld1.32 {q8-q9},[$key] // load key schedule... + sub $rounds,$rounds,#4 + mov $step,#16 + cmp $len,#2 + add $key_,$key,x5,lsl#4 // pointer to last 5 round keys + sub $rounds,$rounds,#2 + vld1.32 {q12-q13},[$key_],#32 + vld1.32 {q14-q15},[$key_],#32 + vld1.32 {$rndlast},[$key_] + add $key_,$key,#32 + mov $cnt,$rounds + cclr $step,lo +#ifndef __ARMEB__ + rev $ctr, $ctr +#endif + vorr $dat1,$dat0,$dat0 + add $tctr1, $ctr, #1 + vorr $dat2,$dat0,$dat0 + add $ctr, $ctr, #2 + vorr $ivec,$dat0,$dat0 + rev $tctr1, $tctr1 + vmov.32 ${dat1}[3],$tctr1 + b.ls .Lctr32_tail + rev $tctr2, $ctr + sub $len,$len,#3 // bias + vmov.32 ${dat2}[3],$tctr2 + b .Loop3x_ctr32 + +.align 4 +.Loop3x_ctr32: + aese $dat0,q8 + aesmc $dat0,$dat0 + aese $dat1,q8 + aesmc $dat1,$dat1 + aese $dat2,q8 + aesmc $dat2,$dat2 + vld1.32 {q8},[$key_],#16 + subs $cnt,$cnt,#2 + aese $dat0,q9 + aesmc $dat0,$dat0 + aese $dat1,q9 + aesmc $dat1,$dat1 + aese $dat2,q9 + aesmc $dat2,$dat2 + vld1.32 {q9},[$key_],#16 + b.gt .Loop3x_ctr32 + + aese $dat0,q8 + aesmc $tmp0,$dat0 + aese $dat1,q8 + aesmc $tmp1,$dat1 + vld1.8 {$in0},[$inp],#16 + vorr $dat0,$ivec,$ivec + aese $dat2,q8 + aesmc $dat2,$dat2 + vld1.8 {$in1},[$inp],#16 + vorr $dat1,$ivec,$ivec + aese $tmp0,q9 + aesmc $tmp0,$tmp0 + aese $tmp1,q9 + aesmc $tmp1,$tmp1 + vld1.8 {$in2},[$inp],#16 + mov $key_,$key + aese $dat2,q9 + aesmc $tmp2,$dat2 + vorr $dat2,$ivec,$ivec + add $tctr0,$ctr,#1 + aese $tmp0,q12 + aesmc $tmp0,$tmp0 + aese $tmp1,q12 + aesmc $tmp1,$tmp1 + veor $in0,$in0,$rndlast + add $tctr1,$ctr,#2 + aese $tmp2,q12 + aesmc $tmp2,$tmp2 + veor $in1,$in1,$rndlast + add $ctr,$ctr,#3 + aese $tmp0,q13 + aesmc $tmp0,$tmp0 + aese $tmp1,q13 + aesmc $tmp1,$tmp1 + veor $in2,$in2,$rndlast + rev $tctr0,$tctr0 + aese $tmp2,q13 + aesmc $tmp2,$tmp2 + vmov.32 ${dat0}[3], $tctr0 + rev $tctr1,$tctr1 + aese $tmp0,q14 + aesmc $tmp0,$tmp0 + aese $tmp1,q14 + aesmc $tmp1,$tmp1 + vmov.32 ${dat1}[3], $tctr1 + rev $tctr2,$ctr + aese $tmp2,q14 + aesmc $tmp2,$tmp2 + vmov.32 ${dat2}[3], $tctr2 + subs $len,$len,#3 + aese $tmp0,q15 + aese $tmp1,q15 + aese $tmp2,q15 + + veor $in0,$in0,$tmp0 + vld1.32 {q8},[$key_],#16 // re-pre-load rndkey[0] + vst1.8 {$in0},[$out],#16 + veor $in1,$in1,$tmp1 + mov $cnt,$rounds + vst1.8 {$in1},[$out],#16 + veor $in2,$in2,$tmp2 + vld1.32 {q9},[$key_],#16 // re-pre-load rndkey[1] + vst1.8 {$in2},[$out],#16 + b.hs .Loop3x_ctr32 + + adds $len,$len,#3 + b.eq .Lctr32_done + cmp $len,#1 + mov $step,#16 + cclr $step,eq + +.Lctr32_tail: + aese $dat0,q8 + aesmc $dat0,$dat0 + aese $dat1,q8 + aesmc $dat1,$dat1 + vld1.32 {q8},[$key_],#16 + subs $cnt,$cnt,#2 + aese $dat0,q9 + aesmc $dat0,$dat0 + aese $dat1,q9 + aesmc $dat1,$dat1 + vld1.32 {q9},[$key_],#16 + b.gt .Lctr32_tail + + aese $dat0,q8 + aesmc $dat0,$dat0 + aese $dat1,q8 + aesmc $dat1,$dat1 + aese $dat0,q9 + aesmc $dat0,$dat0 + aese $dat1,q9 + aesmc $dat1,$dat1 + vld1.8 {$in0},[$inp],$step + aese $dat0,q12 + aesmc $dat0,$dat0 + aese $dat1,q12 + aesmc $dat1,$dat1 + vld1.8 {$in1},[$inp] + aese $dat0,q13 + aesmc $dat0,$dat0 + aese $dat1,q13 + aesmc $dat1,$dat1 + veor $in0,$in0,$rndlast + aese $dat0,q14 + aesmc $dat0,$dat0 + aese $dat1,q14 + aesmc $dat1,$dat1 + veor $in1,$in1,$rndlast + aese $dat0,q15 + aese $dat1,q15 + + cmp $len,#1 + veor $in0,$in0,$dat0 + veor $in1,$in1,$dat1 + vst1.8 {$in0},[$out],#16 + b.eq .Lctr32_done + vst1.8 {$in1},[$out] + +.Lctr32_done: +___ +$code.=<<___ if ($flavour !~ /64/); + vldmia sp!,{d8-d15} + ldmia sp!,{r4-r10,pc} +___ +$code.=<<___ if ($flavour =~ /64/); + ldr x29,[sp],#16 + ret +___ +$code.=<<___; +.size ${prefix}_ctr32_encrypt_blocks,.-${prefix}_ctr32_encrypt_blocks +___ +}}} +$code.=<<___; +#endif +___ +######################################## +if ($flavour =~ /64/) { ######## 64-bit code + my %opcode = ( + "aesd" => 0x4e285800, "aese" => 0x4e284800, + "aesimc"=> 0x4e287800, "aesmc" => 0x4e286800 ); + + local *unaes = sub { + my ($mnemonic,$arg)=@_; + + $arg =~ m/[qv]([0-9]+)[^,]*,\s*[qv]([0-9]+)/o && + sprintf ".inst\t0x%08x\t//%s %s", + $opcode{$mnemonic}|$1|($2<<5), + $mnemonic,$arg; + }; + + foreach(split("\n",$code)) { + s/\`([^\`]*)\`/eval($1)/geo; + + s/\bq([0-9]+)\b/"v".($1<8?$1:$1+8).".16b"/geo; # old->new registers + s/@\s/\/\//o; # old->new style commentary + + #s/[v]?(aes\w+)\s+([qv].*)/unaes($1,$2)/geo or + s/cclr\s+([wx])([^,]+),\s*([a-z]+)/csel $1$2,$1zr,$1$2,$3/o or + s/mov\.([a-z]+)\s+([wx][0-9]+),\s*([wx][0-9]+)/csel $2,$3,$2,$1/o or + s/vmov\.i8/movi/o or # fix up legacy mnemonics + s/vext\.8/ext/o or + s/vrev32\.8/rev32/o or + s/vtst\.8/cmtst/o or + s/vshr/ushr/o or + s/^(\s+)v/$1/o or # strip off v prefix + s/\bbx\s+lr\b/ret/o; + + # fix up remainig legacy suffixes + s/\.[ui]?8//o; + m/\],#8/o and s/\.16b/\.8b/go; + s/\.[ui]?32//o and s/\.16b/\.4s/go; + s/\.[ui]?64//o and s/\.16b/\.2d/go; + s/\.[42]([sd])\[([0-3])\]/\.$1\[$2\]/o; + + print $_,"\n"; + } +} else { ######## 32-bit code + my %opcode = ( + "aesd" => 0xf3b00340, "aese" => 0xf3b00300, + "aesimc"=> 0xf3b003c0, "aesmc" => 0xf3b00380 ); + + local *unaes = sub { + my ($mnemonic,$arg)=@_; + + if ($arg =~ m/[qv]([0-9]+)[^,]*,\s*[qv]([0-9]+)/o) { + my $word = $opcode{$mnemonic}|(($1&7)<<13)|(($1&8)<<19) + |(($2&7)<<1) |(($2&8)<<2); + # since ARMv7 instructions are always encoded little-endian. + # correct solution is to use .inst directive, but older + # assemblers don't implement it:-( + sprintf ".byte\t0x%02x,0x%02x,0x%02x,0x%02x\t@ %s %s", + $word&0xff,($word>>8)&0xff, + ($word>>16)&0xff,($word>>24)&0xff, + $mnemonic,$arg; + } + }; + + sub unvtbl { + my $arg=shift; + + $arg =~ m/q([0-9]+),\s*\{q([0-9]+)\},\s*q([0-9]+)/o && + sprintf "vtbl.8 d%d,{q%d},d%d\n\t". + "vtbl.8 d%d,{q%d},d%d", 2*$1,$2,2*$3, 2*$1+1,$2,2*$3+1; + } + + sub unvdup32 { + my $arg=shift; + + $arg =~ m/q([0-9]+),\s*q([0-9]+)\[([0-3])\]/o && + sprintf "vdup.32 q%d,d%d[%d]",$1,2*$2+($3>>1),$3&1; + } + + sub unvmov32 { + my $arg=shift; + + $arg =~ m/q([0-9]+)\[([0-3])\],(.*)/o && + sprintf "vmov.32 d%d[%d],%s",2*$1+($2>>1),$2&1,$3; + } + + foreach(split("\n",$code)) { + s/\`([^\`]*)\`/eval($1)/geo; + + s/\b[wx]([0-9]+)\b/r$1/go; # new->old registers + s/\bv([0-9])\.[12468]+[bsd]\b/q$1/go; # new->old registers + s/\/\/\s?/@ /o; # new->old style commentary + + # fix up remainig new-style suffixes + s/\{q([0-9]+)\},\s*\[(.+)\],#8/sprintf "{d%d},[$2]!",2*$1/eo or + s/\],#[0-9]+/]!/o; + + s/[v]?(aes\w+)\s+([qv].*)/unaes($1,$2)/geo or + s/cclr\s+([^,]+),\s*([a-z]+)/mov$2 $1,#0/o or + s/vtbl\.8\s+(.*)/unvtbl($1)/geo or + s/vdup\.32\s+(.*)/unvdup32($1)/geo or + s/vmov\.32\s+(.*)/unvmov32($1)/geo or + s/^(\s+)b\./$1b/o or + s/^(\s+)mov\./$1mov/o or + s/^(\s+)ret/$1bx\tlr/o; + + print $_,"\n"; + } +} + +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/aes/asm/bsaes-armv7.pl b/TMessagesProj/jni/boringssl/crypto/aes/asm/bsaes-armv7.pl new file mode 100644 index 00000000..273f0b9e --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/aes/asm/bsaes-armv7.pl @@ -0,0 +1,2515 @@ +#!/usr/bin/env perl + +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# +# Specific modes and adaptation for Linux kernel by Ard Biesheuvel +# . Permission to use under GPL terms is +# granted. +# ==================================================================== + +# Bit-sliced AES for ARM NEON +# +# February 2012. +# +# This implementation is direct adaptation of bsaes-x86_64 module for +# ARM NEON. Except that this module is endian-neutral [in sense that +# it can be compiled for either endianness] by courtesy of vld1.8's +# neutrality. Initial version doesn't implement interface to OpenSSL, +# only low-level primitives and unsupported entry points, just enough +# to collect performance results, which for Cortex-A8 core are: +# +# encrypt 19.5 cycles per byte processed with 128-bit key +# decrypt 22.1 cycles per byte processed with 128-bit key +# key conv. 440 cycles per 128-bit key/0.18 of 8x block +# +# Snapdragon S4 encrypts byte in 17.6 cycles and decrypts in 19.7, +# which is [much] worse than anticipated (for further details see +# http://www.openssl.org/~appro/Snapdragon-S4.html). +# +# Cortex-A15 manages in 14.2/16.1 cycles [when integer-only code +# manages in 20.0 cycles]. +# +# When comparing to x86_64 results keep in mind that NEON unit is +# [mostly] single-issue and thus can't [fully] benefit from +# instruction-level parallelism. And when comparing to aes-armv4 +# results keep in mind key schedule conversion overhead (see +# bsaes-x86_64.pl for further details)... +# +# + +# April-August 2013 +# +# Add CBC, CTR and XTS subroutines, adapt for kernel use. +# +# + +$flavour = shift; +if ($flavour=~/^\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; } +else { while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {} } + +if ($flavour && $flavour ne "void") { + $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; + ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or + ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or + die "can't locate arm-xlate.pl"; + + open STDOUT,"| \"$^X\" $xlate $flavour $output"; +} else { + open STDOUT,">$output"; +} + +my ($inp,$out,$len,$key)=("r0","r1","r2","r3"); +my @XMM=map("q$_",(0..15)); + +{ +my ($key,$rounds,$const)=("r4","r5","r6"); + +sub Dlo() { shift=~m|q([1]?[0-9])|?"d".($1*2):""; } +sub Dhi() { shift=~m|q([1]?[0-9])|?"d".($1*2+1):""; } + +sub Sbox { +# input in lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb +# output in lsb > [b0, b1, b4, b6, b3, b7, b2, b5] < msb +my @b=@_[0..7]; +my @t=@_[8..11]; +my @s=@_[12..15]; + &InBasisChange (@b); + &Inv_GF256 (@b[6,5,0,3,7,1,4,2],@t,@s); + &OutBasisChange (@b[7,1,4,2,6,5,0,3]); +} + +sub InBasisChange { +# input in lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb +# output in lsb > [b6, b5, b0, b3, b7, b1, b4, b2] < msb +my @b=@_[0..7]; +$code.=<<___; + veor @b[2], @b[2], @b[1] + veor @b[5], @b[5], @b[6] + veor @b[3], @b[3], @b[0] + veor @b[6], @b[6], @b[2] + veor @b[5], @b[5], @b[0] + + veor @b[6], @b[6], @b[3] + veor @b[3], @b[3], @b[7] + veor @b[7], @b[7], @b[5] + veor @b[3], @b[3], @b[4] + veor @b[4], @b[4], @b[5] + + veor @b[2], @b[2], @b[7] + veor @b[3], @b[3], @b[1] + veor @b[1], @b[1], @b[5] +___ +} + +sub OutBasisChange { +# input in lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb +# output in lsb > [b6, b1, b2, b4, b7, b0, b3, b5] < msb +my @b=@_[0..7]; +$code.=<<___; + veor @b[0], @b[0], @b[6] + veor @b[1], @b[1], @b[4] + veor @b[4], @b[4], @b[6] + veor @b[2], @b[2], @b[0] + veor @b[6], @b[6], @b[1] + + veor @b[1], @b[1], @b[5] + veor @b[5], @b[5], @b[3] + veor @b[3], @b[3], @b[7] + veor @b[7], @b[7], @b[5] + veor @b[2], @b[2], @b[5] + + veor @b[4], @b[4], @b[7] +___ +} + +sub InvSbox { +# input in lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb +# output in lsb > [b0, b1, b6, b4, b2, b7, b3, b5] < msb +my @b=@_[0..7]; +my @t=@_[8..11]; +my @s=@_[12..15]; + &InvInBasisChange (@b); + &Inv_GF256 (@b[5,1,2,6,3,7,0,4],@t,@s); + &InvOutBasisChange (@b[3,7,0,4,5,1,2,6]); +} + +sub InvInBasisChange { # OutBasisChange in reverse (with twist) +my @b=@_[5,1,2,6,3,7,0,4]; +$code.=<<___ + veor @b[1], @b[1], @b[7] + veor @b[4], @b[4], @b[7] + + veor @b[7], @b[7], @b[5] + veor @b[1], @b[1], @b[3] + veor @b[2], @b[2], @b[5] + veor @b[3], @b[3], @b[7] + + veor @b[6], @b[6], @b[1] + veor @b[2], @b[2], @b[0] + veor @b[5], @b[5], @b[3] + veor @b[4], @b[4], @b[6] + veor @b[0], @b[0], @b[6] + veor @b[1], @b[1], @b[4] +___ +} + +sub InvOutBasisChange { # InBasisChange in reverse +my @b=@_[2,5,7,3,6,1,0,4]; +$code.=<<___; + veor @b[1], @b[1], @b[5] + veor @b[2], @b[2], @b[7] + + veor @b[3], @b[3], @b[1] + veor @b[4], @b[4], @b[5] + veor @b[7], @b[7], @b[5] + veor @b[3], @b[3], @b[4] + veor @b[5], @b[5], @b[0] + veor @b[3], @b[3], @b[7] + veor @b[6], @b[6], @b[2] + veor @b[2], @b[2], @b[1] + veor @b[6], @b[6], @b[3] + + veor @b[3], @b[3], @b[0] + veor @b[5], @b[5], @b[6] +___ +} + +sub Mul_GF4 { +#;************************************************************* +#;* Mul_GF4: Input x0-x1,y0-y1 Output x0-x1 Temp t0 (8) * +#;************************************************************* +my ($x0,$x1,$y0,$y1,$t0,$t1)=@_; +$code.=<<___; + veor $t0, $y0, $y1 + vand $t0, $t0, $x0 + veor $x0, $x0, $x1 + vand $t1, $x1, $y0 + vand $x0, $x0, $y1 + veor $x1, $t1, $t0 + veor $x0, $x0, $t1 +___ +} + +sub Mul_GF4_N { # not used, see next subroutine +# multiply and scale by N +my ($x0,$x1,$y0,$y1,$t0)=@_; +$code.=<<___; + veor $t0, $y0, $y1 + vand $t0, $t0, $x0 + veor $x0, $x0, $x1 + vand $x1, $x1, $y0 + vand $x0, $x0, $y1 + veor $x1, $x1, $x0 + veor $x0, $x0, $t0 +___ +} + +sub Mul_GF4_N_GF4 { +# interleaved Mul_GF4_N and Mul_GF4 +my ($x0,$x1,$y0,$y1,$t0, + $x2,$x3,$y2,$y3,$t1)=@_; +$code.=<<___; + veor $t0, $y0, $y1 + veor $t1, $y2, $y3 + vand $t0, $t0, $x0 + vand $t1, $t1, $x2 + veor $x0, $x0, $x1 + veor $x2, $x2, $x3 + vand $x1, $x1, $y0 + vand $x3, $x3, $y2 + vand $x0, $x0, $y1 + vand $x2, $x2, $y3 + veor $x1, $x1, $x0 + veor $x2, $x2, $x3 + veor $x0, $x0, $t0 + veor $x3, $x3, $t1 +___ +} +sub Mul_GF16_2 { +my @x=@_[0..7]; +my @y=@_[8..11]; +my @t=@_[12..15]; +$code.=<<___; + veor @t[0], @x[0], @x[2] + veor @t[1], @x[1], @x[3] +___ + &Mul_GF4 (@x[0], @x[1], @y[0], @y[1], @t[2..3]); +$code.=<<___; + veor @y[0], @y[0], @y[2] + veor @y[1], @y[1], @y[3] +___ + Mul_GF4_N_GF4 (@t[0], @t[1], @y[0], @y[1], @t[3], + @x[2], @x[3], @y[2], @y[3], @t[2]); +$code.=<<___; + veor @x[0], @x[0], @t[0] + veor @x[2], @x[2], @t[0] + veor @x[1], @x[1], @t[1] + veor @x[3], @x[3], @t[1] + + veor @t[0], @x[4], @x[6] + veor @t[1], @x[5], @x[7] +___ + &Mul_GF4_N_GF4 (@t[0], @t[1], @y[0], @y[1], @t[3], + @x[6], @x[7], @y[2], @y[3], @t[2]); +$code.=<<___; + veor @y[0], @y[0], @y[2] + veor @y[1], @y[1], @y[3] +___ + &Mul_GF4 (@x[4], @x[5], @y[0], @y[1], @t[2..3]); +$code.=<<___; + veor @x[4], @x[4], @t[0] + veor @x[6], @x[6], @t[0] + veor @x[5], @x[5], @t[1] + veor @x[7], @x[7], @t[1] +___ +} +sub Inv_GF256 { +#;******************************************************************** +#;* Inv_GF256: Input x0-x7 Output x0-x7 Temp t0-t3,s0-s3 (144) * +#;******************************************************************** +my @x=@_[0..7]; +my @t=@_[8..11]; +my @s=@_[12..15]; +# direct optimizations from hardware +$code.=<<___; + veor @t[3], @x[4], @x[6] + veor @t[2], @x[5], @x[7] + veor @t[1], @x[1], @x[3] + veor @s[1], @x[7], @x[6] + vmov @t[0], @t[2] + veor @s[0], @x[0], @x[2] + + vorr @t[2], @t[2], @t[1] + veor @s[3], @t[3], @t[0] + vand @s[2], @t[3], @s[0] + vorr @t[3], @t[3], @s[0] + veor @s[0], @s[0], @t[1] + vand @t[0], @t[0], @t[1] + veor @t[1], @x[3], @x[2] + vand @s[3], @s[3], @s[0] + vand @s[1], @s[1], @t[1] + veor @t[1], @x[4], @x[5] + veor @s[0], @x[1], @x[0] + veor @t[3], @t[3], @s[1] + veor @t[2], @t[2], @s[1] + vand @s[1], @t[1], @s[0] + vorr @t[1], @t[1], @s[0] + veor @t[3], @t[3], @s[3] + veor @t[0], @t[0], @s[1] + veor @t[2], @t[2], @s[2] + veor @t[1], @t[1], @s[3] + veor @t[0], @t[0], @s[2] + vand @s[0], @x[7], @x[3] + veor @t[1], @t[1], @s[2] + vand @s[1], @x[6], @x[2] + vand @s[2], @x[5], @x[1] + vorr @s[3], @x[4], @x[0] + veor @t[3], @t[3], @s[0] + veor @t[1], @t[1], @s[2] + veor @t[0], @t[0], @s[3] + veor @t[2], @t[2], @s[1] + + @ Inv_GF16 \t0, \t1, \t2, \t3, \s0, \s1, \s2, \s3 + + @ new smaller inversion + + vand @s[2], @t[3], @t[1] + vmov @s[0], @t[0] + + veor @s[1], @t[2], @s[2] + veor @s[3], @t[0], @s[2] + veor @s[2], @t[0], @s[2] @ @s[2]=@s[3] + + vbsl @s[1], @t[1], @t[0] + vbsl @s[3], @t[3], @t[2] + veor @t[3], @t[3], @t[2] + + vbsl @s[0], @s[1], @s[2] + vbsl @t[0], @s[2], @s[1] + + vand @s[2], @s[0], @s[3] + veor @t[1], @t[1], @t[0] + + veor @s[2], @s[2], @t[3] +___ +# output in s3, s2, s1, t1 + +# Mul_GF16_2 \x0, \x1, \x2, \x3, \x4, \x5, \x6, \x7, \t2, \t3, \t0, \t1, \s0, \s1, \s2, \s3 + +# Mul_GF16_2 \x0, \x1, \x2, \x3, \x4, \x5, \x6, \x7, \s3, \s2, \s1, \t1, \s0, \t0, \t2, \t3 + &Mul_GF16_2(@x,@s[3,2,1],@t[1],@s[0],@t[0,2,3]); + +### output msb > [x3,x2,x1,x0,x7,x6,x5,x4] < lsb +} + +# AES linear components + +sub ShiftRows { +my @x=@_[0..7]; +my @t=@_[8..11]; +my $mask=pop; +$code.=<<___; + vldmia $key!, {@t[0]-@t[3]} + veor @t[0], @t[0], @x[0] + veor @t[1], @t[1], @x[1] + vtbl.8 `&Dlo(@x[0])`, {@t[0]}, `&Dlo($mask)` + vtbl.8 `&Dhi(@x[0])`, {@t[0]}, `&Dhi($mask)` + vldmia $key!, {@t[0]} + veor @t[2], @t[2], @x[2] + vtbl.8 `&Dlo(@x[1])`, {@t[1]}, `&Dlo($mask)` + vtbl.8 `&Dhi(@x[1])`, {@t[1]}, `&Dhi($mask)` + vldmia $key!, {@t[1]} + veor @t[3], @t[3], @x[3] + vtbl.8 `&Dlo(@x[2])`, {@t[2]}, `&Dlo($mask)` + vtbl.8 `&Dhi(@x[2])`, {@t[2]}, `&Dhi($mask)` + vldmia $key!, {@t[2]} + vtbl.8 `&Dlo(@x[3])`, {@t[3]}, `&Dlo($mask)` + vtbl.8 `&Dhi(@x[3])`, {@t[3]}, `&Dhi($mask)` + vldmia $key!, {@t[3]} + veor @t[0], @t[0], @x[4] + veor @t[1], @t[1], @x[5] + vtbl.8 `&Dlo(@x[4])`, {@t[0]}, `&Dlo($mask)` + vtbl.8 `&Dhi(@x[4])`, {@t[0]}, `&Dhi($mask)` + veor @t[2], @t[2], @x[6] + vtbl.8 `&Dlo(@x[5])`, {@t[1]}, `&Dlo($mask)` + vtbl.8 `&Dhi(@x[5])`, {@t[1]}, `&Dhi($mask)` + veor @t[3], @t[3], @x[7] + vtbl.8 `&Dlo(@x[6])`, {@t[2]}, `&Dlo($mask)` + vtbl.8 `&Dhi(@x[6])`, {@t[2]}, `&Dhi($mask)` + vtbl.8 `&Dlo(@x[7])`, {@t[3]}, `&Dlo($mask)` + vtbl.8 `&Dhi(@x[7])`, {@t[3]}, `&Dhi($mask)` +___ +} + +sub MixColumns { +# modified to emit output in order suitable for feeding back to aesenc[last] +my @x=@_[0..7]; +my @t=@_[8..15]; +my $inv=@_[16]; # optional +$code.=<<___; + vext.8 @t[0], @x[0], @x[0], #12 @ x0 <<< 32 + vext.8 @t[1], @x[1], @x[1], #12 + veor @x[0], @x[0], @t[0] @ x0 ^ (x0 <<< 32) + vext.8 @t[2], @x[2], @x[2], #12 + veor @x[1], @x[1], @t[1] + vext.8 @t[3], @x[3], @x[3], #12 + veor @x[2], @x[2], @t[2] + vext.8 @t[4], @x[4], @x[4], #12 + veor @x[3], @x[3], @t[3] + vext.8 @t[5], @x[5], @x[5], #12 + veor @x[4], @x[4], @t[4] + vext.8 @t[6], @x[6], @x[6], #12 + veor @x[5], @x[5], @t[5] + vext.8 @t[7], @x[7], @x[7], #12 + veor @x[6], @x[6], @t[6] + + veor @t[1], @t[1], @x[0] + veor @x[7], @x[7], @t[7] + vext.8 @x[0], @x[0], @x[0], #8 @ (x0 ^ (x0 <<< 32)) <<< 64) + veor @t[2], @t[2], @x[1] + veor @t[0], @t[0], @x[7] + veor @t[1], @t[1], @x[7] + vext.8 @x[1], @x[1], @x[1], #8 + veor @t[5], @t[5], @x[4] + veor @x[0], @x[0], @t[0] + veor @t[6], @t[6], @x[5] + veor @x[1], @x[1], @t[1] + vext.8 @t[0], @x[4], @x[4], #8 + veor @t[4], @t[4], @x[3] + vext.8 @t[1], @x[5], @x[5], #8 + veor @t[7], @t[7], @x[6] + vext.8 @x[4], @x[3], @x[3], #8 + veor @t[3], @t[3], @x[2] + vext.8 @x[5], @x[7], @x[7], #8 + veor @t[4], @t[4], @x[7] + vext.8 @x[3], @x[6], @x[6], #8 + veor @t[3], @t[3], @x[7] + vext.8 @x[6], @x[2], @x[2], #8 + veor @x[7], @t[1], @t[5] +___ +$code.=<<___ if (!$inv); + veor @x[2], @t[0], @t[4] + veor @x[4], @x[4], @t[3] + veor @x[5], @x[5], @t[7] + veor @x[3], @x[3], @t[6] + @ vmov @x[2], @t[0] + veor @x[6], @x[6], @t[2] + @ vmov @x[7], @t[1] +___ +$code.=<<___ if ($inv); + veor @t[3], @t[3], @x[4] + veor @x[5], @x[5], @t[7] + veor @x[2], @x[3], @t[6] + veor @x[3], @t[0], @t[4] + veor @x[4], @x[6], @t[2] + vmov @x[6], @t[3] + @ vmov @x[7], @t[1] +___ +} + +sub InvMixColumns_orig { +my @x=@_[0..7]; +my @t=@_[8..15]; + +$code.=<<___; + @ multiplication by 0x0e + vext.8 @t[7], @x[7], @x[7], #12 + vmov @t[2], @x[2] + veor @x[2], @x[2], @x[5] @ 2 5 + veor @x[7], @x[7], @x[5] @ 7 5 + vext.8 @t[0], @x[0], @x[0], #12 + vmov @t[5], @x[5] + veor @x[5], @x[5], @x[0] @ 5 0 [1] + veor @x[0], @x[0], @x[1] @ 0 1 + vext.8 @t[1], @x[1], @x[1], #12 + veor @x[1], @x[1], @x[2] @ 1 25 + veor @x[0], @x[0], @x[6] @ 01 6 [2] + vext.8 @t[3], @x[3], @x[3], #12 + veor @x[1], @x[1], @x[3] @ 125 3 [4] + veor @x[2], @x[2], @x[0] @ 25 016 [3] + veor @x[3], @x[3], @x[7] @ 3 75 + veor @x[7], @x[7], @x[6] @ 75 6 [0] + vext.8 @t[6], @x[6], @x[6], #12 + vmov @t[4], @x[4] + veor @x[6], @x[6], @x[4] @ 6 4 + veor @x[4], @x[4], @x[3] @ 4 375 [6] + veor @x[3], @x[3], @x[7] @ 375 756=36 + veor @x[6], @x[6], @t[5] @ 64 5 [7] + veor @x[3], @x[3], @t[2] @ 36 2 + vext.8 @t[5], @t[5], @t[5], #12 + veor @x[3], @x[3], @t[4] @ 362 4 [5] +___ + my @y = @x[7,5,0,2,1,3,4,6]; +$code.=<<___; + @ multiplication by 0x0b + veor @y[1], @y[1], @y[0] + veor @y[0], @y[0], @t[0] + vext.8 @t[2], @t[2], @t[2], #12 + veor @y[1], @y[1], @t[1] + veor @y[0], @y[0], @t[5] + vext.8 @t[4], @t[4], @t[4], #12 + veor @y[1], @y[1], @t[6] + veor @y[0], @y[0], @t[7] + veor @t[7], @t[7], @t[6] @ clobber t[7] + + veor @y[3], @y[3], @t[0] + veor @y[1], @y[1], @y[0] + vext.8 @t[0], @t[0], @t[0], #12 + veor @y[2], @y[2], @t[1] + veor @y[4], @y[4], @t[1] + vext.8 @t[1], @t[1], @t[1], #12 + veor @y[2], @y[2], @t[2] + veor @y[3], @y[3], @t[2] + veor @y[5], @y[5], @t[2] + veor @y[2], @y[2], @t[7] + vext.8 @t[2], @t[2], @t[2], #12 + veor @y[3], @y[3], @t[3] + veor @y[6], @y[6], @t[3] + veor @y[4], @y[4], @t[3] + veor @y[7], @y[7], @t[4] + vext.8 @t[3], @t[3], @t[3], #12 + veor @y[5], @y[5], @t[4] + veor @y[7], @y[7], @t[7] + veor @t[7], @t[7], @t[5] @ clobber t[7] even more + veor @y[3], @y[3], @t[5] + veor @y[4], @y[4], @t[4] + + veor @y[5], @y[5], @t[7] + vext.8 @t[4], @t[4], @t[4], #12 + veor @y[6], @y[6], @t[7] + veor @y[4], @y[4], @t[7] + + veor @t[7], @t[7], @t[5] + vext.8 @t[5], @t[5], @t[5], #12 + + @ multiplication by 0x0d + veor @y[4], @y[4], @y[7] + veor @t[7], @t[7], @t[6] @ restore t[7] + veor @y[7], @y[7], @t[4] + vext.8 @t[6], @t[6], @t[6], #12 + veor @y[2], @y[2], @t[0] + veor @y[7], @y[7], @t[5] + vext.8 @t[7], @t[7], @t[7], #12 + veor @y[2], @y[2], @t[2] + + veor @y[3], @y[3], @y[1] + veor @y[1], @y[1], @t[1] + veor @y[0], @y[0], @t[0] + veor @y[3], @y[3], @t[0] + veor @y[1], @y[1], @t[5] + veor @y[0], @y[0], @t[5] + vext.8 @t[0], @t[0], @t[0], #12 + veor @y[1], @y[1], @t[7] + veor @y[0], @y[0], @t[6] + veor @y[3], @y[3], @y[1] + veor @y[4], @y[4], @t[1] + vext.8 @t[1], @t[1], @t[1], #12 + + veor @y[7], @y[7], @t[7] + veor @y[4], @y[4], @t[2] + veor @y[5], @y[5], @t[2] + veor @y[2], @y[2], @t[6] + veor @t[6], @t[6], @t[3] @ clobber t[6] + vext.8 @t[2], @t[2], @t[2], #12 + veor @y[4], @y[4], @y[7] + veor @y[3], @y[3], @t[6] + + veor @y[6], @y[6], @t[6] + veor @y[5], @y[5], @t[5] + vext.8 @t[5], @t[5], @t[5], #12 + veor @y[6], @y[6], @t[4] + vext.8 @t[4], @t[4], @t[4], #12 + veor @y[5], @y[5], @t[6] + veor @y[6], @y[6], @t[7] + vext.8 @t[7], @t[7], @t[7], #12 + veor @t[6], @t[6], @t[3] @ restore t[6] + vext.8 @t[3], @t[3], @t[3], #12 + + @ multiplication by 0x09 + veor @y[4], @y[4], @y[1] + veor @t[1], @t[1], @y[1] @ t[1]=y[1] + veor @t[0], @t[0], @t[5] @ clobber t[0] + vext.8 @t[6], @t[6], @t[6], #12 + veor @t[1], @t[1], @t[5] + veor @y[3], @y[3], @t[0] + veor @t[0], @t[0], @y[0] @ t[0]=y[0] + veor @t[1], @t[1], @t[6] + veor @t[6], @t[6], @t[7] @ clobber t[6] + veor @y[4], @y[4], @t[1] + veor @y[7], @y[7], @t[4] + veor @y[6], @y[6], @t[3] + veor @y[5], @y[5], @t[2] + veor @t[4], @t[4], @y[4] @ t[4]=y[4] + veor @t[3], @t[3], @y[3] @ t[3]=y[3] + veor @t[5], @t[5], @y[5] @ t[5]=y[5] + veor @t[2], @t[2], @y[2] @ t[2]=y[2] + veor @t[3], @t[3], @t[7] + veor @XMM[5], @t[5], @t[6] + veor @XMM[6], @t[6], @y[6] @ t[6]=y[6] + veor @XMM[2], @t[2], @t[6] + veor @XMM[7], @t[7], @y[7] @ t[7]=y[7] + + vmov @XMM[0], @t[0] + vmov @XMM[1], @t[1] + @ vmov @XMM[2], @t[2] + vmov @XMM[3], @t[3] + vmov @XMM[4], @t[4] + @ vmov @XMM[5], @t[5] + @ vmov @XMM[6], @t[6] + @ vmov @XMM[7], @t[7] +___ +} + +sub InvMixColumns { +my @x=@_[0..7]; +my @t=@_[8..15]; + +# Thanks to Jussi Kivilinna for providing pointer to +# +# | 0e 0b 0d 09 | | 02 03 01 01 | | 05 00 04 00 | +# | 09 0e 0b 0d | = | 01 02 03 01 | x | 00 05 00 04 | +# | 0d 09 0e 0b | | 01 01 02 03 | | 04 00 05 00 | +# | 0b 0d 09 0e | | 03 01 01 02 | | 00 04 00 05 | + +$code.=<<___; + @ multiplication by 0x05-0x00-0x04-0x00 + vext.8 @t[0], @x[0], @x[0], #8 + vext.8 @t[6], @x[6], @x[6], #8 + vext.8 @t[7], @x[7], @x[7], #8 + veor @t[0], @t[0], @x[0] + vext.8 @t[1], @x[1], @x[1], #8 + veor @t[6], @t[6], @x[6] + vext.8 @t[2], @x[2], @x[2], #8 + veor @t[7], @t[7], @x[7] + vext.8 @t[3], @x[3], @x[3], #8 + veor @t[1], @t[1], @x[1] + vext.8 @t[4], @x[4], @x[4], #8 + veor @t[2], @t[2], @x[2] + vext.8 @t[5], @x[5], @x[5], #8 + veor @t[3], @t[3], @x[3] + veor @t[4], @t[4], @x[4] + veor @t[5], @t[5], @x[5] + + veor @x[0], @x[0], @t[6] + veor @x[1], @x[1], @t[6] + veor @x[2], @x[2], @t[0] + veor @x[4], @x[4], @t[2] + veor @x[3], @x[3], @t[1] + veor @x[1], @x[1], @t[7] + veor @x[2], @x[2], @t[7] + veor @x[4], @x[4], @t[6] + veor @x[5], @x[5], @t[3] + veor @x[3], @x[3], @t[6] + veor @x[6], @x[6], @t[4] + veor @x[4], @x[4], @t[7] + veor @x[5], @x[5], @t[7] + veor @x[7], @x[7], @t[5] +___ + &MixColumns (@x,@t,1); # flipped 2<->3 and 4<->6 +} + +sub swapmove { +my ($a,$b,$n,$mask,$t)=@_; +$code.=<<___; + vshr.u64 $t, $b, #$n + veor $t, $t, $a + vand $t, $t, $mask + veor $a, $a, $t + vshl.u64 $t, $t, #$n + veor $b, $b, $t +___ +} +sub swapmove2x { +my ($a0,$b0,$a1,$b1,$n,$mask,$t0,$t1)=@_; +$code.=<<___; + vshr.u64 $t0, $b0, #$n + vshr.u64 $t1, $b1, #$n + veor $t0, $t0, $a0 + veor $t1, $t1, $a1 + vand $t0, $t0, $mask + vand $t1, $t1, $mask + veor $a0, $a0, $t0 + vshl.u64 $t0, $t0, #$n + veor $a1, $a1, $t1 + vshl.u64 $t1, $t1, #$n + veor $b0, $b0, $t0 + veor $b1, $b1, $t1 +___ +} + +sub bitslice { +my @x=reverse(@_[0..7]); +my ($t0,$t1,$t2,$t3)=@_[8..11]; +$code.=<<___; + vmov.i8 $t0,#0x55 @ compose .LBS0 + vmov.i8 $t1,#0x33 @ compose .LBS1 +___ + &swapmove2x(@x[0,1,2,3],1,$t0,$t2,$t3); + &swapmove2x(@x[4,5,6,7],1,$t0,$t2,$t3); +$code.=<<___; + vmov.i8 $t0,#0x0f @ compose .LBS2 +___ + &swapmove2x(@x[0,2,1,3],2,$t1,$t2,$t3); + &swapmove2x(@x[4,6,5,7],2,$t1,$t2,$t3); + + &swapmove2x(@x[0,4,1,5],4,$t0,$t2,$t3); + &swapmove2x(@x[2,6,3,7],4,$t0,$t2,$t3); +} + +$code.=<<___; +#if defined(__arm__) +#ifndef __KERNEL__ +# include "arm_arch.h" + +# define VFP_ABI_PUSH vstmdb sp!,{d8-d15} +# define VFP_ABI_POP vldmia sp!,{d8-d15} +# define VFP_ABI_FRAME 0x40 +#else +# define VFP_ABI_PUSH +# define VFP_ABI_POP +# define VFP_ABI_FRAME 0 +# define BSAES_ASM_EXTENDED_KEY +# define XTS_CHAIN_TWEAK +# define __ARM_ARCH__ __LINUX_ARM_ARCH__ +# define __ARM_MAX_ARCH__ 7 +#endif + +#ifdef __thumb__ +# define adrl adr +#endif + +#if __ARM_MAX_ARCH__>=7 +.arch armv7-a +.fpu neon + +.text +.syntax unified @ ARMv7-capable assembler is expected to handle this +#if defined(__thumb2__) && !defined(__APPLE__) +.thumb +#else +.code 32 +#endif + +.type _bsaes_decrypt8,%function +.align 4 +_bsaes_decrypt8: + adr $const,_bsaes_decrypt8 + vldmia $key!, {@XMM[9]} @ round 0 key +#ifdef __APPLE__ + adr $const,.LM0ISR +#else + add $const,$const,#.LM0ISR-_bsaes_decrypt8 +#endif + + vldmia $const!, {@XMM[8]} @ .LM0ISR + veor @XMM[10], @XMM[0], @XMM[9] @ xor with round0 key + veor @XMM[11], @XMM[1], @XMM[9] + vtbl.8 `&Dlo(@XMM[0])`, {@XMM[10]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[0])`, {@XMM[10]}, `&Dhi(@XMM[8])` + veor @XMM[12], @XMM[2], @XMM[9] + vtbl.8 `&Dlo(@XMM[1])`, {@XMM[11]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[1])`, {@XMM[11]}, `&Dhi(@XMM[8])` + veor @XMM[13], @XMM[3], @XMM[9] + vtbl.8 `&Dlo(@XMM[2])`, {@XMM[12]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[2])`, {@XMM[12]}, `&Dhi(@XMM[8])` + veor @XMM[14], @XMM[4], @XMM[9] + vtbl.8 `&Dlo(@XMM[3])`, {@XMM[13]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[3])`, {@XMM[13]}, `&Dhi(@XMM[8])` + veor @XMM[15], @XMM[5], @XMM[9] + vtbl.8 `&Dlo(@XMM[4])`, {@XMM[14]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[4])`, {@XMM[14]}, `&Dhi(@XMM[8])` + veor @XMM[10], @XMM[6], @XMM[9] + vtbl.8 `&Dlo(@XMM[5])`, {@XMM[15]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[5])`, {@XMM[15]}, `&Dhi(@XMM[8])` + veor @XMM[11], @XMM[7], @XMM[9] + vtbl.8 `&Dlo(@XMM[6])`, {@XMM[10]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[6])`, {@XMM[10]}, `&Dhi(@XMM[8])` + vtbl.8 `&Dlo(@XMM[7])`, {@XMM[11]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[7])`, {@XMM[11]}, `&Dhi(@XMM[8])` +___ + &bitslice (@XMM[0..7, 8..11]); +$code.=<<___; + sub $rounds,$rounds,#1 + b .Ldec_sbox +.align 4 +.Ldec_loop: +___ + &ShiftRows (@XMM[0..7, 8..12]); +$code.=".Ldec_sbox:\n"; + &InvSbox (@XMM[0..7, 8..15]); +$code.=<<___; + subs $rounds,$rounds,#1 + bcc .Ldec_done +___ + &InvMixColumns (@XMM[0,1,6,4,2,7,3,5, 8..15]); +$code.=<<___; + vldmia $const, {@XMM[12]} @ .LISR + ite eq @ Thumb2 thing, sanity check in ARM + addeq $const,$const,#0x10 + bne .Ldec_loop + vldmia $const, {@XMM[12]} @ .LISRM0 + b .Ldec_loop +.align 4 +.Ldec_done: +___ + &bitslice (@XMM[0,1,6,4,2,7,3,5, 8..11]); +$code.=<<___; + vldmia $key, {@XMM[8]} @ last round key + veor @XMM[6], @XMM[6], @XMM[8] + veor @XMM[4], @XMM[4], @XMM[8] + veor @XMM[2], @XMM[2], @XMM[8] + veor @XMM[7], @XMM[7], @XMM[8] + veor @XMM[3], @XMM[3], @XMM[8] + veor @XMM[5], @XMM[5], @XMM[8] + veor @XMM[0], @XMM[0], @XMM[8] + veor @XMM[1], @XMM[1], @XMM[8] + bx lr +.size _bsaes_decrypt8,.-_bsaes_decrypt8 + +.type _bsaes_const,%object +.align 6 +_bsaes_const: +.LM0ISR: @ InvShiftRows constants + .quad 0x0a0e0206070b0f03, 0x0004080c0d010509 +.LISR: + .quad 0x0504070602010003, 0x0f0e0d0c080b0a09 +.LISRM0: + .quad 0x01040b0e0205080f, 0x0306090c00070a0d +.LM0SR: @ ShiftRows constants + .quad 0x0a0e02060f03070b, 0x0004080c05090d01 +.LSR: + .quad 0x0504070600030201, 0x0f0e0d0c0a09080b +.LSRM0: + .quad 0x0304090e00050a0f, 0x01060b0c0207080d +.LM0: + .quad 0x02060a0e03070b0f, 0x0004080c0105090d +.LREVM0SR: + .quad 0x090d01050c000408, 0x03070b0f060a0e02 +.asciz "Bit-sliced AES for NEON, CRYPTOGAMS by " +.align 6 +.size _bsaes_const,.-_bsaes_const + +.type _bsaes_encrypt8,%function +.align 4 +_bsaes_encrypt8: + adr $const,_bsaes_encrypt8 + vldmia $key!, {@XMM[9]} @ round 0 key +#ifdef __APPLE__ + adr $const,.LM0SR +#else + sub $const,$const,#_bsaes_encrypt8-.LM0SR +#endif + + vldmia $const!, {@XMM[8]} @ .LM0SR +_bsaes_encrypt8_alt: + veor @XMM[10], @XMM[0], @XMM[9] @ xor with round0 key + veor @XMM[11], @XMM[1], @XMM[9] + vtbl.8 `&Dlo(@XMM[0])`, {@XMM[10]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[0])`, {@XMM[10]}, `&Dhi(@XMM[8])` + veor @XMM[12], @XMM[2], @XMM[9] + vtbl.8 `&Dlo(@XMM[1])`, {@XMM[11]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[1])`, {@XMM[11]}, `&Dhi(@XMM[8])` + veor @XMM[13], @XMM[3], @XMM[9] + vtbl.8 `&Dlo(@XMM[2])`, {@XMM[12]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[2])`, {@XMM[12]}, `&Dhi(@XMM[8])` + veor @XMM[14], @XMM[4], @XMM[9] + vtbl.8 `&Dlo(@XMM[3])`, {@XMM[13]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[3])`, {@XMM[13]}, `&Dhi(@XMM[8])` + veor @XMM[15], @XMM[5], @XMM[9] + vtbl.8 `&Dlo(@XMM[4])`, {@XMM[14]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[4])`, {@XMM[14]}, `&Dhi(@XMM[8])` + veor @XMM[10], @XMM[6], @XMM[9] + vtbl.8 `&Dlo(@XMM[5])`, {@XMM[15]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[5])`, {@XMM[15]}, `&Dhi(@XMM[8])` + veor @XMM[11], @XMM[7], @XMM[9] + vtbl.8 `&Dlo(@XMM[6])`, {@XMM[10]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[6])`, {@XMM[10]}, `&Dhi(@XMM[8])` + vtbl.8 `&Dlo(@XMM[7])`, {@XMM[11]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[7])`, {@XMM[11]}, `&Dhi(@XMM[8])` +_bsaes_encrypt8_bitslice: +___ + &bitslice (@XMM[0..7, 8..11]); +$code.=<<___; + sub $rounds,$rounds,#1 + b .Lenc_sbox +.align 4 +.Lenc_loop: +___ + &ShiftRows (@XMM[0..7, 8..12]); +$code.=".Lenc_sbox:\n"; + &Sbox (@XMM[0..7, 8..15]); +$code.=<<___; + subs $rounds,$rounds,#1 + bcc .Lenc_done +___ + &MixColumns (@XMM[0,1,4,6,3,7,2,5, 8..15]); +$code.=<<___; + vldmia $const, {@XMM[12]} @ .LSR + ite eq @ Thumb2 thing, samity check in ARM + addeq $const,$const,#0x10 + bne .Lenc_loop + vldmia $const, {@XMM[12]} @ .LSRM0 + b .Lenc_loop +.align 4 +.Lenc_done: +___ + # output in lsb > [t0, t1, t4, t6, t3, t7, t2, t5] < msb + &bitslice (@XMM[0,1,4,6,3,7,2,5, 8..11]); +$code.=<<___; + vldmia $key, {@XMM[8]} @ last round key + veor @XMM[4], @XMM[4], @XMM[8] + veor @XMM[6], @XMM[6], @XMM[8] + veor @XMM[3], @XMM[3], @XMM[8] + veor @XMM[7], @XMM[7], @XMM[8] + veor @XMM[2], @XMM[2], @XMM[8] + veor @XMM[5], @XMM[5], @XMM[8] + veor @XMM[0], @XMM[0], @XMM[8] + veor @XMM[1], @XMM[1], @XMM[8] + bx lr +.size _bsaes_encrypt8,.-_bsaes_encrypt8 +___ +} +{ +my ($out,$inp,$rounds,$const)=("r12","r4","r5","r6"); + +sub bitslice_key { +my @x=reverse(@_[0..7]); +my ($bs0,$bs1,$bs2,$t2,$t3)=@_[8..12]; + + &swapmove (@x[0,1],1,$bs0,$t2,$t3); +$code.=<<___; + @ &swapmove(@x[2,3],1,$t0,$t2,$t3); + vmov @x[2], @x[0] + vmov @x[3], @x[1] +___ + #&swapmove2x(@x[4,5,6,7],1,$t0,$t2,$t3); + + &swapmove2x (@x[0,2,1,3],2,$bs1,$t2,$t3); +$code.=<<___; + @ &swapmove2x(@x[4,6,5,7],2,$t1,$t2,$t3); + vmov @x[4], @x[0] + vmov @x[6], @x[2] + vmov @x[5], @x[1] + vmov @x[7], @x[3] +___ + &swapmove2x (@x[0,4,1,5],4,$bs2,$t2,$t3); + &swapmove2x (@x[2,6,3,7],4,$bs2,$t2,$t3); +} + +$code.=<<___; +.type _bsaes_key_convert,%function +.align 4 +_bsaes_key_convert: + adr $const,_bsaes_key_convert + vld1.8 {@XMM[7]}, [$inp]! @ load round 0 key +#ifdef __APPLE__ + adr $const,.LM0 +#else + sub $const,$const,#_bsaes_key_convert-.LM0 +#endif + vld1.8 {@XMM[15]}, [$inp]! @ load round 1 key + + vmov.i8 @XMM[8], #0x01 @ bit masks + vmov.i8 @XMM[9], #0x02 + vmov.i8 @XMM[10], #0x04 + vmov.i8 @XMM[11], #0x08 + vmov.i8 @XMM[12], #0x10 + vmov.i8 @XMM[13], #0x20 + vldmia $const, {@XMM[14]} @ .LM0 + +#ifdef __ARMEL__ + vrev32.8 @XMM[7], @XMM[7] + vrev32.8 @XMM[15], @XMM[15] +#endif + sub $rounds,$rounds,#1 + vstmia $out!, {@XMM[7]} @ save round 0 key + b .Lkey_loop + +.align 4 +.Lkey_loop: + vtbl.8 `&Dlo(@XMM[7])`,{@XMM[15]},`&Dlo(@XMM[14])` + vtbl.8 `&Dhi(@XMM[7])`,{@XMM[15]},`&Dhi(@XMM[14])` + vmov.i8 @XMM[6], #0x40 + vmov.i8 @XMM[15], #0x80 + + vtst.8 @XMM[0], @XMM[7], @XMM[8] + vtst.8 @XMM[1], @XMM[7], @XMM[9] + vtst.8 @XMM[2], @XMM[7], @XMM[10] + vtst.8 @XMM[3], @XMM[7], @XMM[11] + vtst.8 @XMM[4], @XMM[7], @XMM[12] + vtst.8 @XMM[5], @XMM[7], @XMM[13] + vtst.8 @XMM[6], @XMM[7], @XMM[6] + vtst.8 @XMM[7], @XMM[7], @XMM[15] + vld1.8 {@XMM[15]}, [$inp]! @ load next round key + vmvn @XMM[0], @XMM[0] @ "pnot" + vmvn @XMM[1], @XMM[1] + vmvn @XMM[5], @XMM[5] + vmvn @XMM[6], @XMM[6] +#ifdef __ARMEL__ + vrev32.8 @XMM[15], @XMM[15] +#endif + subs $rounds,$rounds,#1 + vstmia $out!,{@XMM[0]-@XMM[7]} @ write bit-sliced round key + bne .Lkey_loop + + vmov.i8 @XMM[7],#0x63 @ compose .L63 + @ don't save last round key + bx lr +.size _bsaes_key_convert,.-_bsaes_key_convert +___ +} + +if (0) { # following four functions are unsupported interface + # used for benchmarking... +$code.=<<___; +.globl bsaes_enc_key_convert +.hidden bsaes_enc_key_convert +.type bsaes_enc_key_convert,%function +.align 4 +bsaes_enc_key_convert: + stmdb sp!,{r4-r6,lr} + vstmdb sp!,{d8-d15} @ ABI specification says so + + ldr r5,[$inp,#240] @ pass rounds + mov r4,$inp @ pass key + mov r12,$out @ pass key schedule + bl _bsaes_key_convert + veor @XMM[7],@XMM[7],@XMM[15] @ fix up last round key + vstmia r12, {@XMM[7]} @ save last round key + + vldmia sp!,{d8-d15} + ldmia sp!,{r4-r6,pc} +.size bsaes_enc_key_convert,.-bsaes_enc_key_convert + +.globl bsaes_encrypt_128 +.hidden bsaes_encrypt_128 +.type bsaes_encrypt_128,%function +.align 4 +bsaes_encrypt_128: + stmdb sp!,{r4-r6,lr} + vstmdb sp!,{d8-d15} @ ABI specification says so +.Lenc128_loop: + vld1.8 {@XMM[0]-@XMM[1]}, [$inp]! @ load input + vld1.8 {@XMM[2]-@XMM[3]}, [$inp]! + mov r4,$key @ pass the key + vld1.8 {@XMM[4]-@XMM[5]}, [$inp]! + mov r5,#10 @ pass rounds + vld1.8 {@XMM[6]-@XMM[7]}, [$inp]! + + bl _bsaes_encrypt8 + + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output + vst1.8 {@XMM[4]}, [$out]! + vst1.8 {@XMM[6]}, [$out]! + vst1.8 {@XMM[3]}, [$out]! + vst1.8 {@XMM[7]}, [$out]! + vst1.8 {@XMM[2]}, [$out]! + subs $len,$len,#0x80 + vst1.8 {@XMM[5]}, [$out]! + bhi .Lenc128_loop + + vldmia sp!,{d8-d15} + ldmia sp!,{r4-r6,pc} +.size bsaes_encrypt_128,.-bsaes_encrypt_128 + +.globl bsaes_dec_key_convert +.hidden bsaes_dec_key_convert +.type bsaes_dec_key_convert,%function +.align 4 +bsaes_dec_key_convert: + stmdb sp!,{r4-r6,lr} + vstmdb sp!,{d8-d15} @ ABI specification says so + + ldr r5,[$inp,#240] @ pass rounds + mov r4,$inp @ pass key + mov r12,$out @ pass key schedule + bl _bsaes_key_convert + vldmia $out, {@XMM[6]} + vstmia r12, {@XMM[15]} @ save last round key + veor @XMM[7], @XMM[7], @XMM[6] @ fix up round 0 key + vstmia $out, {@XMM[7]} + + vldmia sp!,{d8-d15} + ldmia sp!,{r4-r6,pc} +.size bsaes_dec_key_convert,.-bsaes_dec_key_convert + +.globl bsaes_decrypt_128 +.hidden bsaes_decrypt_128 +.type bsaes_decrypt_128,%function +.align 4 +bsaes_decrypt_128: + stmdb sp!,{r4-r6,lr} + vstmdb sp!,{d8-d15} @ ABI specification says so +.Ldec128_loop: + vld1.8 {@XMM[0]-@XMM[1]}, [$inp]! @ load input + vld1.8 {@XMM[2]-@XMM[3]}, [$inp]! + mov r4,$key @ pass the key + vld1.8 {@XMM[4]-@XMM[5]}, [$inp]! + mov r5,#10 @ pass rounds + vld1.8 {@XMM[6]-@XMM[7]}, [$inp]! + + bl _bsaes_decrypt8 + + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output + vst1.8 {@XMM[6]}, [$out]! + vst1.8 {@XMM[4]}, [$out]! + vst1.8 {@XMM[2]}, [$out]! + vst1.8 {@XMM[7]}, [$out]! + vst1.8 {@XMM[3]}, [$out]! + subs $len,$len,#0x80 + vst1.8 {@XMM[5]}, [$out]! + bhi .Ldec128_loop + + vldmia sp!,{d8-d15} + ldmia sp!,{r4-r6,pc} +.size bsaes_decrypt_128,.-bsaes_decrypt_128 +___ +} +{ +my ($inp,$out,$len,$key, $ivp,$fp,$rounds)=map("r$_",(0..3,8..10)); +my ($keysched)=("sp"); + +$code.=<<___; +.extern AES_cbc_encrypt +.extern AES_decrypt + +.global bsaes_cbc_encrypt +.hidden bsaes_cbc_encrypt +.type bsaes_cbc_encrypt,%function +.align 5 +bsaes_cbc_encrypt: +#ifndef __KERNEL__ + cmp $len, #128 +#ifndef __thumb__ + blo AES_cbc_encrypt +#else + bhs 1f + b AES_cbc_encrypt +1: +#endif +#endif + + @ it is up to the caller to make sure we are called with enc == 0 + + mov ip, sp + stmdb sp!, {r4-r10, lr} + VFP_ABI_PUSH + ldr $ivp, [ip] @ IV is 1st arg on the stack + mov $len, $len, lsr#4 @ len in 16 byte blocks + sub sp, #0x10 @ scratch space to carry over the IV + mov $fp, sp @ save sp + + ldr $rounds, [$key, #240] @ get # of rounds +#ifndef BSAES_ASM_EXTENDED_KEY + @ allocate the key schedule on the stack + sub r12, sp, $rounds, lsl#7 @ 128 bytes per inner round key + add r12, #`128-32` @ sifze of bit-slices key schedule + + @ populate the key schedule + mov r4, $key @ pass key + mov r5, $rounds @ pass # of rounds + mov sp, r12 @ sp is $keysched + bl _bsaes_key_convert + vldmia $keysched, {@XMM[6]} + vstmia r12, {@XMM[15]} @ save last round key + veor @XMM[7], @XMM[7], @XMM[6] @ fix up round 0 key + vstmia $keysched, {@XMM[7]} +#else + ldr r12, [$key, #244] + eors r12, #1 + beq 0f + + @ populate the key schedule + str r12, [$key, #244] + mov r4, $key @ pass key + mov r5, $rounds @ pass # of rounds + add r12, $key, #248 @ pass key schedule + bl _bsaes_key_convert + add r4, $key, #248 + vldmia r4, {@XMM[6]} + vstmia r12, {@XMM[15]} @ save last round key + veor @XMM[7], @XMM[7], @XMM[6] @ fix up round 0 key + vstmia r4, {@XMM[7]} + +.align 2 +0: +#endif + + vld1.8 {@XMM[15]}, [$ivp] @ load IV + b .Lcbc_dec_loop + +.align 4 +.Lcbc_dec_loop: + subs $len, $len, #0x8 + bmi .Lcbc_dec_loop_finish + + vld1.8 {@XMM[0]-@XMM[1]}, [$inp]! @ load input + vld1.8 {@XMM[2]-@XMM[3]}, [$inp]! +#ifndef BSAES_ASM_EXTENDED_KEY + mov r4, $keysched @ pass the key +#else + add r4, $key, #248 +#endif + vld1.8 {@XMM[4]-@XMM[5]}, [$inp]! + mov r5, $rounds + vld1.8 {@XMM[6]-@XMM[7]}, [$inp] + sub $inp, $inp, #0x60 + vstmia $fp, {@XMM[15]} @ put aside IV + + bl _bsaes_decrypt8 + + vldmia $fp, {@XMM[14]} @ reload IV + vld1.8 {@XMM[8]-@XMM[9]}, [$inp]! @ reload input + veor @XMM[0], @XMM[0], @XMM[14] @ ^= IV + vld1.8 {@XMM[10]-@XMM[11]}, [$inp]! + veor @XMM[1], @XMM[1], @XMM[8] + veor @XMM[6], @XMM[6], @XMM[9] + vld1.8 {@XMM[12]-@XMM[13]}, [$inp]! + veor @XMM[4], @XMM[4], @XMM[10] + veor @XMM[2], @XMM[2], @XMM[11] + vld1.8 {@XMM[14]-@XMM[15]}, [$inp]! + veor @XMM[7], @XMM[7], @XMM[12] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output + veor @XMM[3], @XMM[3], @XMM[13] + vst1.8 {@XMM[6]}, [$out]! + veor @XMM[5], @XMM[5], @XMM[14] + vst1.8 {@XMM[4]}, [$out]! + vst1.8 {@XMM[2]}, [$out]! + vst1.8 {@XMM[7]}, [$out]! + vst1.8 {@XMM[3]}, [$out]! + vst1.8 {@XMM[5]}, [$out]! + + b .Lcbc_dec_loop + +.Lcbc_dec_loop_finish: + adds $len, $len, #8 + beq .Lcbc_dec_done + + vld1.8 {@XMM[0]}, [$inp]! @ load input + cmp $len, #2 + blo .Lcbc_dec_one + vld1.8 {@XMM[1]}, [$inp]! +#ifndef BSAES_ASM_EXTENDED_KEY + mov r4, $keysched @ pass the key +#else + add r4, $key, #248 +#endif + mov r5, $rounds + vstmia $fp, {@XMM[15]} @ put aside IV + beq .Lcbc_dec_two + vld1.8 {@XMM[2]}, [$inp]! + cmp $len, #4 + blo .Lcbc_dec_three + vld1.8 {@XMM[3]}, [$inp]! + beq .Lcbc_dec_four + vld1.8 {@XMM[4]}, [$inp]! + cmp $len, #6 + blo .Lcbc_dec_five + vld1.8 {@XMM[5]}, [$inp]! + beq .Lcbc_dec_six + vld1.8 {@XMM[6]}, [$inp]! + sub $inp, $inp, #0x70 + + bl _bsaes_decrypt8 + + vldmia $fp, {@XMM[14]} @ reload IV + vld1.8 {@XMM[8]-@XMM[9]}, [$inp]! @ reload input + veor @XMM[0], @XMM[0], @XMM[14] @ ^= IV + vld1.8 {@XMM[10]-@XMM[11]}, [$inp]! + veor @XMM[1], @XMM[1], @XMM[8] + veor @XMM[6], @XMM[6], @XMM[9] + vld1.8 {@XMM[12]-@XMM[13]}, [$inp]! + veor @XMM[4], @XMM[4], @XMM[10] + veor @XMM[2], @XMM[2], @XMM[11] + vld1.8 {@XMM[15]}, [$inp]! + veor @XMM[7], @XMM[7], @XMM[12] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output + veor @XMM[3], @XMM[3], @XMM[13] + vst1.8 {@XMM[6]}, [$out]! + vst1.8 {@XMM[4]}, [$out]! + vst1.8 {@XMM[2]}, [$out]! + vst1.8 {@XMM[7]}, [$out]! + vst1.8 {@XMM[3]}, [$out]! + b .Lcbc_dec_done +.align 4 +.Lcbc_dec_six: + sub $inp, $inp, #0x60 + bl _bsaes_decrypt8 + vldmia $fp,{@XMM[14]} @ reload IV + vld1.8 {@XMM[8]-@XMM[9]}, [$inp]! @ reload input + veor @XMM[0], @XMM[0], @XMM[14] @ ^= IV + vld1.8 {@XMM[10]-@XMM[11]}, [$inp]! + veor @XMM[1], @XMM[1], @XMM[8] + veor @XMM[6], @XMM[6], @XMM[9] + vld1.8 {@XMM[12]}, [$inp]! + veor @XMM[4], @XMM[4], @XMM[10] + veor @XMM[2], @XMM[2], @XMM[11] + vld1.8 {@XMM[15]}, [$inp]! + veor @XMM[7], @XMM[7], @XMM[12] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output + vst1.8 {@XMM[6]}, [$out]! + vst1.8 {@XMM[4]}, [$out]! + vst1.8 {@XMM[2]}, [$out]! + vst1.8 {@XMM[7]}, [$out]! + b .Lcbc_dec_done +.align 4 +.Lcbc_dec_five: + sub $inp, $inp, #0x50 + bl _bsaes_decrypt8 + vldmia $fp, {@XMM[14]} @ reload IV + vld1.8 {@XMM[8]-@XMM[9]}, [$inp]! @ reload input + veor @XMM[0], @XMM[0], @XMM[14] @ ^= IV + vld1.8 {@XMM[10]-@XMM[11]}, [$inp]! + veor @XMM[1], @XMM[1], @XMM[8] + veor @XMM[6], @XMM[6], @XMM[9] + vld1.8 {@XMM[15]}, [$inp]! + veor @XMM[4], @XMM[4], @XMM[10] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output + veor @XMM[2], @XMM[2], @XMM[11] + vst1.8 {@XMM[6]}, [$out]! + vst1.8 {@XMM[4]}, [$out]! + vst1.8 {@XMM[2]}, [$out]! + b .Lcbc_dec_done +.align 4 +.Lcbc_dec_four: + sub $inp, $inp, #0x40 + bl _bsaes_decrypt8 + vldmia $fp, {@XMM[14]} @ reload IV + vld1.8 {@XMM[8]-@XMM[9]}, [$inp]! @ reload input + veor @XMM[0], @XMM[0], @XMM[14] @ ^= IV + vld1.8 {@XMM[10]}, [$inp]! + veor @XMM[1], @XMM[1], @XMM[8] + veor @XMM[6], @XMM[6], @XMM[9] + vld1.8 {@XMM[15]}, [$inp]! + veor @XMM[4], @XMM[4], @XMM[10] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output + vst1.8 {@XMM[6]}, [$out]! + vst1.8 {@XMM[4]}, [$out]! + b .Lcbc_dec_done +.align 4 +.Lcbc_dec_three: + sub $inp, $inp, #0x30 + bl _bsaes_decrypt8 + vldmia $fp, {@XMM[14]} @ reload IV + vld1.8 {@XMM[8]-@XMM[9]}, [$inp]! @ reload input + veor @XMM[0], @XMM[0], @XMM[14] @ ^= IV + vld1.8 {@XMM[15]}, [$inp]! + veor @XMM[1], @XMM[1], @XMM[8] + veor @XMM[6], @XMM[6], @XMM[9] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output + vst1.8 {@XMM[6]}, [$out]! + b .Lcbc_dec_done +.align 4 +.Lcbc_dec_two: + sub $inp, $inp, #0x20 + bl _bsaes_decrypt8 + vldmia $fp, {@XMM[14]} @ reload IV + vld1.8 {@XMM[8]}, [$inp]! @ reload input + veor @XMM[0], @XMM[0], @XMM[14] @ ^= IV + vld1.8 {@XMM[15]}, [$inp]! @ reload input + veor @XMM[1], @XMM[1], @XMM[8] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output + b .Lcbc_dec_done +.align 4 +.Lcbc_dec_one: + sub $inp, $inp, #0x10 + mov $rounds, $out @ save original out pointer + mov $out, $fp @ use the iv scratch space as out buffer + mov r2, $key + vmov @XMM[4],@XMM[15] @ just in case ensure that IV + vmov @XMM[5],@XMM[0] @ and input are preserved + bl AES_decrypt + vld1.8 {@XMM[0]}, [$fp,:64] @ load result + veor @XMM[0], @XMM[0], @XMM[4] @ ^= IV + vmov @XMM[15], @XMM[5] @ @XMM[5] holds input + vst1.8 {@XMM[0]}, [$rounds] @ write output + +.Lcbc_dec_done: +#ifndef BSAES_ASM_EXTENDED_KEY + vmov.i32 q0, #0 + vmov.i32 q1, #0 +.Lcbc_dec_bzero: @ wipe key schedule [if any] + vstmia $keysched!, {q0-q1} + cmp $keysched, $fp + bne .Lcbc_dec_bzero +#endif + + mov sp, $fp + add sp, #0x10 @ add sp,$fp,#0x10 is no good for thumb + vst1.8 {@XMM[15]}, [$ivp] @ return IV + VFP_ABI_POP + ldmia sp!, {r4-r10, pc} +.size bsaes_cbc_encrypt,.-bsaes_cbc_encrypt +___ +} +{ +my ($inp,$out,$len,$key, $ctr,$fp,$rounds)=(map("r$_",(0..3,8..10))); +my $const = "r6"; # shared with _bsaes_encrypt8_alt +my $keysched = "sp"; + +$code.=<<___; +.extern AES_encrypt +.global bsaes_ctr32_encrypt_blocks +.hidden bsaes_ctr32_encrypt_blocks +.type bsaes_ctr32_encrypt_blocks,%function +.align 5 +bsaes_ctr32_encrypt_blocks: + cmp $len, #8 @ use plain AES for + blo .Lctr_enc_short @ small sizes + + mov ip, sp + stmdb sp!, {r4-r10, lr} + VFP_ABI_PUSH + ldr $ctr, [ip] @ ctr is 1st arg on the stack + sub sp, sp, #0x10 @ scratch space to carry over the ctr + mov $fp, sp @ save sp + + ldr $rounds, [$key, #240] @ get # of rounds +#ifndef BSAES_ASM_EXTENDED_KEY + @ allocate the key schedule on the stack + sub r12, sp, $rounds, lsl#7 @ 128 bytes per inner round key + add r12, #`128-32` @ size of bit-sliced key schedule + + @ populate the key schedule + mov r4, $key @ pass key + mov r5, $rounds @ pass # of rounds + mov sp, r12 @ sp is $keysched + bl _bsaes_key_convert + veor @XMM[7],@XMM[7],@XMM[15] @ fix up last round key + vstmia r12, {@XMM[7]} @ save last round key + + vld1.8 {@XMM[0]}, [$ctr] @ load counter +#ifdef __APPLE__ + mov $ctr, #:lower16:(.LREVM0SR-.LM0) + add $ctr, $const, $ctr +#else + add $ctr, $const, #.LREVM0SR-.LM0 @ borrow $ctr +#endif + vldmia $keysched, {@XMM[4]} @ load round0 key +#else + ldr r12, [$key, #244] + eors r12, #1 + beq 0f + + @ populate the key schedule + str r12, [$key, #244] + mov r4, $key @ pass key + mov r5, $rounds @ pass # of rounds + add r12, $key, #248 @ pass key schedule + bl _bsaes_key_convert + veor @XMM[7],@XMM[7],@XMM[15] @ fix up last round key + vstmia r12, {@XMM[7]} @ save last round key + +.align 2 +0: add r12, $key, #248 + vld1.8 {@XMM[0]}, [$ctr] @ load counter + adrl $ctr, .LREVM0SR @ borrow $ctr + vldmia r12, {@XMM[4]} @ load round0 key + sub sp, #0x10 @ place for adjusted round0 key +#endif + + vmov.i32 @XMM[8],#1 @ compose 1<<96 + veor @XMM[9],@XMM[9],@XMM[9] + vrev32.8 @XMM[0],@XMM[0] + vext.8 @XMM[8],@XMM[9],@XMM[8],#4 + vrev32.8 @XMM[4],@XMM[4] + vadd.u32 @XMM[9],@XMM[8],@XMM[8] @ compose 2<<96 + vstmia $keysched, {@XMM[4]} @ save adjusted round0 key + b .Lctr_enc_loop + +.align 4 +.Lctr_enc_loop: + vadd.u32 @XMM[10], @XMM[8], @XMM[9] @ compose 3<<96 + vadd.u32 @XMM[1], @XMM[0], @XMM[8] @ +1 + vadd.u32 @XMM[2], @XMM[0], @XMM[9] @ +2 + vadd.u32 @XMM[3], @XMM[0], @XMM[10] @ +3 + vadd.u32 @XMM[4], @XMM[1], @XMM[10] + vadd.u32 @XMM[5], @XMM[2], @XMM[10] + vadd.u32 @XMM[6], @XMM[3], @XMM[10] + vadd.u32 @XMM[7], @XMM[4], @XMM[10] + vadd.u32 @XMM[10], @XMM[5], @XMM[10] @ next counter + + @ Borrow prologue from _bsaes_encrypt8 to use the opportunity + @ to flip byte order in 32-bit counter + + vldmia $keysched, {@XMM[9]} @ load round0 key +#ifndef BSAES_ASM_EXTENDED_KEY + add r4, $keysched, #0x10 @ pass next round key +#else + add r4, $key, #`248+16` +#endif + vldmia $ctr, {@XMM[8]} @ .LREVM0SR + mov r5, $rounds @ pass rounds + vstmia $fp, {@XMM[10]} @ save next counter +#ifdef __APPLE__ + mov $const, #:lower16:(.LREVM0SR-.LSR) + sub $const, $ctr, $const +#else + sub $const, $ctr, #.LREVM0SR-.LSR @ pass constants +#endif + + bl _bsaes_encrypt8_alt + + subs $len, $len, #8 + blo .Lctr_enc_loop_done + + vld1.8 {@XMM[8]-@XMM[9]}, [$inp]! @ load input + vld1.8 {@XMM[10]-@XMM[11]}, [$inp]! + veor @XMM[0], @XMM[8] + veor @XMM[1], @XMM[9] + vld1.8 {@XMM[12]-@XMM[13]}, [$inp]! + veor @XMM[4], @XMM[10] + veor @XMM[6], @XMM[11] + vld1.8 {@XMM[14]-@XMM[15]}, [$inp]! + veor @XMM[3], @XMM[12] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output + veor @XMM[7], @XMM[13] + veor @XMM[2], @XMM[14] + vst1.8 {@XMM[4]}, [$out]! + veor @XMM[5], @XMM[15] + vst1.8 {@XMM[6]}, [$out]! + vmov.i32 @XMM[8], #1 @ compose 1<<96 + vst1.8 {@XMM[3]}, [$out]! + veor @XMM[9], @XMM[9], @XMM[9] + vst1.8 {@XMM[7]}, [$out]! + vext.8 @XMM[8], @XMM[9], @XMM[8], #4 + vst1.8 {@XMM[2]}, [$out]! + vadd.u32 @XMM[9],@XMM[8],@XMM[8] @ compose 2<<96 + vst1.8 {@XMM[5]}, [$out]! + vldmia $fp, {@XMM[0]} @ load counter + + bne .Lctr_enc_loop + b .Lctr_enc_done + +.align 4 +.Lctr_enc_loop_done: + add $len, $len, #8 + vld1.8 {@XMM[8]}, [$inp]! @ load input + veor @XMM[0], @XMM[8] + vst1.8 {@XMM[0]}, [$out]! @ write output + cmp $len, #2 + blo .Lctr_enc_done + vld1.8 {@XMM[9]}, [$inp]! + veor @XMM[1], @XMM[9] + vst1.8 {@XMM[1]}, [$out]! + beq .Lctr_enc_done + vld1.8 {@XMM[10]}, [$inp]! + veor @XMM[4], @XMM[10] + vst1.8 {@XMM[4]}, [$out]! + cmp $len, #4 + blo .Lctr_enc_done + vld1.8 {@XMM[11]}, [$inp]! + veor @XMM[6], @XMM[11] + vst1.8 {@XMM[6]}, [$out]! + beq .Lctr_enc_done + vld1.8 {@XMM[12]}, [$inp]! + veor @XMM[3], @XMM[12] + vst1.8 {@XMM[3]}, [$out]! + cmp $len, #6 + blo .Lctr_enc_done + vld1.8 {@XMM[13]}, [$inp]! + veor @XMM[7], @XMM[13] + vst1.8 {@XMM[7]}, [$out]! + beq .Lctr_enc_done + vld1.8 {@XMM[14]}, [$inp] + veor @XMM[2], @XMM[14] + vst1.8 {@XMM[2]}, [$out]! + +.Lctr_enc_done: + vmov.i32 q0, #0 + vmov.i32 q1, #0 +#ifndef BSAES_ASM_EXTENDED_KEY +.Lctr_enc_bzero: @ wipe key schedule [if any] + vstmia $keysched!, {q0-q1} + cmp $keysched, $fp + bne .Lctr_enc_bzero +#else + vstmia $keysched, {q0-q1} +#endif + + mov sp, $fp + add sp, #0x10 @ add sp,$fp,#0x10 is no good for thumb + VFP_ABI_POP + ldmia sp!, {r4-r10, pc} @ return + +.align 4 +.Lctr_enc_short: + ldr ip, [sp] @ ctr pointer is passed on stack + stmdb sp!, {r4-r8, lr} + + mov r4, $inp @ copy arguments + mov r5, $out + mov r6, $len + mov r7, $key + ldr r8, [ip, #12] @ load counter LSW + vld1.8 {@XMM[1]}, [ip] @ load whole counter value +#ifdef __ARMEL__ + rev r8, r8 +#endif + sub sp, sp, #0x10 + vst1.8 {@XMM[1]}, [sp] @ copy counter value + sub sp, sp, #0x10 + +.Lctr_enc_short_loop: + add r0, sp, #0x10 @ input counter value + mov r1, sp @ output on the stack + mov r2, r7 @ key + + bl AES_encrypt + + vld1.8 {@XMM[0]}, [r4]! @ load input + vld1.8 {@XMM[1]}, [sp] @ load encrypted counter + add r8, r8, #1 +#ifdef __ARMEL__ + rev r0, r8 + str r0, [sp, #0x1c] @ next counter value +#else + str r8, [sp, #0x1c] @ next counter value +#endif + veor @XMM[0],@XMM[0],@XMM[1] + vst1.8 {@XMM[0]}, [r5]! @ store output + subs r6, r6, #1 + bne .Lctr_enc_short_loop + + vmov.i32 q0, #0 + vmov.i32 q1, #0 + vstmia sp!, {q0-q1} + + ldmia sp!, {r4-r8, pc} +.size bsaes_ctr32_encrypt_blocks,.-bsaes_ctr32_encrypt_blocks +___ +} +{ +###################################################################### +# void bsaes_xts_[en|de]crypt(const char *inp,char *out,size_t len, +# const AES_KEY *key1, const AES_KEY *key2, +# const unsigned char iv[16]); +# +my ($inp,$out,$len,$key,$rounds,$magic,$fp)=(map("r$_",(7..10,1..3))); +my $const="r6"; # returned by _bsaes_key_convert +my $twmask=@XMM[5]; +my @T=@XMM[6..7]; + +$code.=<<___; +.globl bsaes_xts_encrypt +.hidden bsaes_xts_encrypt +.type bsaes_xts_encrypt,%function +.align 4 +bsaes_xts_encrypt: + mov ip, sp + stmdb sp!, {r4-r10, lr} @ 0x20 + VFP_ABI_PUSH + mov r6, sp @ future $fp + + mov $inp, r0 + mov $out, r1 + mov $len, r2 + mov $key, r3 + + sub r0, sp, #0x10 @ 0x10 + bic r0, #0xf @ align at 16 bytes + mov sp, r0 + +#ifdef XTS_CHAIN_TWEAK + ldr r0, [ip] @ pointer to input tweak +#else + @ generate initial tweak + ldr r0, [ip, #4] @ iv[] + mov r1, sp + ldr r2, [ip, #0] @ key2 + bl AES_encrypt + mov r0,sp @ pointer to initial tweak +#endif + + ldr $rounds, [$key, #240] @ get # of rounds + mov $fp, r6 +#ifndef BSAES_ASM_EXTENDED_KEY + @ allocate the key schedule on the stack + sub r12, sp, $rounds, lsl#7 @ 128 bytes per inner round key + @ add r12, #`128-32` @ size of bit-sliced key schedule + sub r12, #`32+16` @ place for tweak[9] + + @ populate the key schedule + mov r4, $key @ pass key + mov r5, $rounds @ pass # of rounds + mov sp, r12 + add r12, #0x90 @ pass key schedule + bl _bsaes_key_convert + veor @XMM[7], @XMM[7], @XMM[15] @ fix up last round key + vstmia r12, {@XMM[7]} @ save last round key +#else + ldr r12, [$key, #244] + eors r12, #1 + beq 0f + + str r12, [$key, #244] + mov r4, $key @ pass key + mov r5, $rounds @ pass # of rounds + add r12, $key, #248 @ pass key schedule + bl _bsaes_key_convert + veor @XMM[7], @XMM[7], @XMM[15] @ fix up last round key + vstmia r12, {@XMM[7]} + +.align 2 +0: sub sp, #0x90 @ place for tweak[9] +#endif + + vld1.8 {@XMM[8]}, [r0] @ initial tweak + adr $magic, .Lxts_magic + + subs $len, #0x80 + blo .Lxts_enc_short + b .Lxts_enc_loop + +.align 4 +.Lxts_enc_loop: + vldmia $magic, {$twmask} @ load XTS magic + vshr.s64 @T[0], @XMM[8], #63 + mov r0, sp + vand @T[0], @T[0], $twmask +___ +for($i=9;$i<16;$i++) { +$code.=<<___; + vadd.u64 @XMM[$i], @XMM[$i-1], @XMM[$i-1] + vst1.64 {@XMM[$i-1]}, [r0,:128]! + vswp `&Dhi("@T[0]")`,`&Dlo("@T[0]")` + vshr.s64 @T[1], @XMM[$i], #63 + veor @XMM[$i], @XMM[$i], @T[0] + vand @T[1], @T[1], $twmask +___ + @T=reverse(@T); + +$code.=<<___ if ($i>=10); + vld1.8 {@XMM[$i-10]}, [$inp]! +___ +$code.=<<___ if ($i>=11); + veor @XMM[$i-11], @XMM[$i-11], @XMM[$i-3] +___ +} +$code.=<<___; + vadd.u64 @XMM[8], @XMM[15], @XMM[15] + vst1.64 {@XMM[15]}, [r0,:128]! + vswp `&Dhi("@T[0]")`,`&Dlo("@T[0]")` + veor @XMM[8], @XMM[8], @T[0] + vst1.64 {@XMM[8]}, [r0,:128] @ next round tweak + + vld1.8 {@XMM[6]-@XMM[7]}, [$inp]! + veor @XMM[5], @XMM[5], @XMM[13] +#ifndef BSAES_ASM_EXTENDED_KEY + add r4, sp, #0x90 @ pass key schedule +#else + add r4, $key, #248 @ pass key schedule +#endif + veor @XMM[6], @XMM[6], @XMM[14] + mov r5, $rounds @ pass rounds + veor @XMM[7], @XMM[7], @XMM[15] + mov r0, sp + + bl _bsaes_encrypt8 + + vld1.64 {@XMM[ 8]-@XMM[ 9]}, [r0,:128]! + vld1.64 {@XMM[10]-@XMM[11]}, [r0,:128]! + veor @XMM[0], @XMM[0], @XMM[ 8] + vld1.64 {@XMM[12]-@XMM[13]}, [r0,:128]! + veor @XMM[1], @XMM[1], @XMM[ 9] + veor @XMM[8], @XMM[4], @XMM[10] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! + veor @XMM[9], @XMM[6], @XMM[11] + vld1.64 {@XMM[14]-@XMM[15]}, [r0,:128]! + veor @XMM[10], @XMM[3], @XMM[12] + vst1.8 {@XMM[8]-@XMM[9]}, [$out]! + veor @XMM[11], @XMM[7], @XMM[13] + veor @XMM[12], @XMM[2], @XMM[14] + vst1.8 {@XMM[10]-@XMM[11]}, [$out]! + veor @XMM[13], @XMM[5], @XMM[15] + vst1.8 {@XMM[12]-@XMM[13]}, [$out]! + + vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak + + subs $len, #0x80 + bpl .Lxts_enc_loop + +.Lxts_enc_short: + adds $len, #0x70 + bmi .Lxts_enc_done + + vldmia $magic, {$twmask} @ load XTS magic + vshr.s64 @T[0], @XMM[8], #63 + mov r0, sp + vand @T[0], @T[0], $twmask +___ +for($i=9;$i<16;$i++) { +$code.=<<___; + vadd.u64 @XMM[$i], @XMM[$i-1], @XMM[$i-1] + vst1.64 {@XMM[$i-1]}, [r0,:128]! + vswp `&Dhi("@T[0]")`,`&Dlo("@T[0]")` + vshr.s64 @T[1], @XMM[$i], #63 + veor @XMM[$i], @XMM[$i], @T[0] + vand @T[1], @T[1], $twmask +___ + @T=reverse(@T); + +$code.=<<___ if ($i>=10); + vld1.8 {@XMM[$i-10]}, [$inp]! + subs $len, #0x10 + bmi .Lxts_enc_`$i-9` +___ +$code.=<<___ if ($i>=11); + veor @XMM[$i-11], @XMM[$i-11], @XMM[$i-3] +___ +} +$code.=<<___; + sub $len, #0x10 + vst1.64 {@XMM[15]}, [r0,:128] @ next round tweak + + vld1.8 {@XMM[6]}, [$inp]! + veor @XMM[5], @XMM[5], @XMM[13] +#ifndef BSAES_ASM_EXTENDED_KEY + add r4, sp, #0x90 @ pass key schedule +#else + add r4, $key, #248 @ pass key schedule +#endif + veor @XMM[6], @XMM[6], @XMM[14] + mov r5, $rounds @ pass rounds + mov r0, sp + + bl _bsaes_encrypt8 + + vld1.64 {@XMM[ 8]-@XMM[ 9]}, [r0,:128]! + vld1.64 {@XMM[10]-@XMM[11]}, [r0,:128]! + veor @XMM[0], @XMM[0], @XMM[ 8] + vld1.64 {@XMM[12]-@XMM[13]}, [r0,:128]! + veor @XMM[1], @XMM[1], @XMM[ 9] + veor @XMM[8], @XMM[4], @XMM[10] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! + veor @XMM[9], @XMM[6], @XMM[11] + vld1.64 {@XMM[14]}, [r0,:128]! + veor @XMM[10], @XMM[3], @XMM[12] + vst1.8 {@XMM[8]-@XMM[9]}, [$out]! + veor @XMM[11], @XMM[7], @XMM[13] + veor @XMM[12], @XMM[2], @XMM[14] + vst1.8 {@XMM[10]-@XMM[11]}, [$out]! + vst1.8 {@XMM[12]}, [$out]! + + vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak + b .Lxts_enc_done +.align 4 +.Lxts_enc_6: + vst1.64 {@XMM[14]}, [r0,:128] @ next round tweak + + veor @XMM[4], @XMM[4], @XMM[12] +#ifndef BSAES_ASM_EXTENDED_KEY + add r4, sp, #0x90 @ pass key schedule +#else + add r4, $key, #248 @ pass key schedule +#endif + veor @XMM[5], @XMM[5], @XMM[13] + mov r5, $rounds @ pass rounds + mov r0, sp + + bl _bsaes_encrypt8 + + vld1.64 {@XMM[ 8]-@XMM[ 9]}, [r0,:128]! + vld1.64 {@XMM[10]-@XMM[11]}, [r0,:128]! + veor @XMM[0], @XMM[0], @XMM[ 8] + vld1.64 {@XMM[12]-@XMM[13]}, [r0,:128]! + veor @XMM[1], @XMM[1], @XMM[ 9] + veor @XMM[8], @XMM[4], @XMM[10] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! + veor @XMM[9], @XMM[6], @XMM[11] + veor @XMM[10], @XMM[3], @XMM[12] + vst1.8 {@XMM[8]-@XMM[9]}, [$out]! + veor @XMM[11], @XMM[7], @XMM[13] + vst1.8 {@XMM[10]-@XMM[11]}, [$out]! + + vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak + b .Lxts_enc_done + +@ put this in range for both ARM and Thumb mode adr instructions +.align 5 +.Lxts_magic: + .quad 1, 0x87 + +.align 5 +.Lxts_enc_5: + vst1.64 {@XMM[13]}, [r0,:128] @ next round tweak + + veor @XMM[3], @XMM[3], @XMM[11] +#ifndef BSAES_ASM_EXTENDED_KEY + add r4, sp, #0x90 @ pass key schedule +#else + add r4, $key, #248 @ pass key schedule +#endif + veor @XMM[4], @XMM[4], @XMM[12] + mov r5, $rounds @ pass rounds + mov r0, sp + + bl _bsaes_encrypt8 + + vld1.64 {@XMM[ 8]-@XMM[ 9]}, [r0,:128]! + vld1.64 {@XMM[10]-@XMM[11]}, [r0,:128]! + veor @XMM[0], @XMM[0], @XMM[ 8] + vld1.64 {@XMM[12]}, [r0,:128]! + veor @XMM[1], @XMM[1], @XMM[ 9] + veor @XMM[8], @XMM[4], @XMM[10] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! + veor @XMM[9], @XMM[6], @XMM[11] + veor @XMM[10], @XMM[3], @XMM[12] + vst1.8 {@XMM[8]-@XMM[9]}, [$out]! + vst1.8 {@XMM[10]}, [$out]! + + vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak + b .Lxts_enc_done +.align 4 +.Lxts_enc_4: + vst1.64 {@XMM[12]}, [r0,:128] @ next round tweak + + veor @XMM[2], @XMM[2], @XMM[10] +#ifndef BSAES_ASM_EXTENDED_KEY + add r4, sp, #0x90 @ pass key schedule +#else + add r4, $key, #248 @ pass key schedule +#endif + veor @XMM[3], @XMM[3], @XMM[11] + mov r5, $rounds @ pass rounds + mov r0, sp + + bl _bsaes_encrypt8 + + vld1.64 {@XMM[ 8]-@XMM[ 9]}, [r0,:128]! + vld1.64 {@XMM[10]-@XMM[11]}, [r0,:128]! + veor @XMM[0], @XMM[0], @XMM[ 8] + veor @XMM[1], @XMM[1], @XMM[ 9] + veor @XMM[8], @XMM[4], @XMM[10] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! + veor @XMM[9], @XMM[6], @XMM[11] + vst1.8 {@XMM[8]-@XMM[9]}, [$out]! + + vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak + b .Lxts_enc_done +.align 4 +.Lxts_enc_3: + vst1.64 {@XMM[11]}, [r0,:128] @ next round tweak + + veor @XMM[1], @XMM[1], @XMM[9] +#ifndef BSAES_ASM_EXTENDED_KEY + add r4, sp, #0x90 @ pass key schedule +#else + add r4, $key, #248 @ pass key schedule +#endif + veor @XMM[2], @XMM[2], @XMM[10] + mov r5, $rounds @ pass rounds + mov r0, sp + + bl _bsaes_encrypt8 + + vld1.64 {@XMM[8]-@XMM[9]}, [r0,:128]! + vld1.64 {@XMM[10]}, [r0,:128]! + veor @XMM[0], @XMM[0], @XMM[ 8] + veor @XMM[1], @XMM[1], @XMM[ 9] + veor @XMM[8], @XMM[4], @XMM[10] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! + vst1.8 {@XMM[8]}, [$out]! + + vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak + b .Lxts_enc_done +.align 4 +.Lxts_enc_2: + vst1.64 {@XMM[10]}, [r0,:128] @ next round tweak + + veor @XMM[0], @XMM[0], @XMM[8] +#ifndef BSAES_ASM_EXTENDED_KEY + add r4, sp, #0x90 @ pass key schedule +#else + add r4, $key, #248 @ pass key schedule +#endif + veor @XMM[1], @XMM[1], @XMM[9] + mov r5, $rounds @ pass rounds + mov r0, sp + + bl _bsaes_encrypt8 + + vld1.64 {@XMM[8]-@XMM[9]}, [r0,:128]! + veor @XMM[0], @XMM[0], @XMM[ 8] + veor @XMM[1], @XMM[1], @XMM[ 9] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! + + vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak + b .Lxts_enc_done +.align 4 +.Lxts_enc_1: + mov r0, sp + veor @XMM[0], @XMM[8] + mov r1, sp + vst1.8 {@XMM[0]}, [sp,:128] + mov r2, $key + mov r4, $fp @ preserve fp + + bl AES_encrypt + + vld1.8 {@XMM[0]}, [sp,:128] + veor @XMM[0], @XMM[0], @XMM[8] + vst1.8 {@XMM[0]}, [$out]! + mov $fp, r4 + + vmov @XMM[8], @XMM[9] @ next round tweak + +.Lxts_enc_done: +#ifndef XTS_CHAIN_TWEAK + adds $len, #0x10 + beq .Lxts_enc_ret + sub r6, $out, #0x10 + +.Lxts_enc_steal: + ldrb r0, [$inp], #1 + ldrb r1, [$out, #-0x10] + strb r0, [$out, #-0x10] + strb r1, [$out], #1 + + subs $len, #1 + bhi .Lxts_enc_steal + + vld1.8 {@XMM[0]}, [r6] + mov r0, sp + veor @XMM[0], @XMM[0], @XMM[8] + mov r1, sp + vst1.8 {@XMM[0]}, [sp,:128] + mov r2, $key + mov r4, $fp @ preserve fp + + bl AES_encrypt + + vld1.8 {@XMM[0]}, [sp,:128] + veor @XMM[0], @XMM[0], @XMM[8] + vst1.8 {@XMM[0]}, [r6] + mov $fp, r4 +#endif + +.Lxts_enc_ret: + bic r0, $fp, #0xf + vmov.i32 q0, #0 + vmov.i32 q1, #0 +#ifdef XTS_CHAIN_TWEAK + ldr r1, [$fp, #0x20+VFP_ABI_FRAME] @ chain tweak +#endif +.Lxts_enc_bzero: @ wipe key schedule [if any] + vstmia sp!, {q0-q1} + cmp sp, r0 + bne .Lxts_enc_bzero + + mov sp, $fp +#ifdef XTS_CHAIN_TWEAK + vst1.8 {@XMM[8]}, [r1] +#endif + VFP_ABI_POP + ldmia sp!, {r4-r10, pc} @ return + +.size bsaes_xts_encrypt,.-bsaes_xts_encrypt + +.globl bsaes_xts_decrypt +.hidden bsaes_xts_decrypt +.type bsaes_xts_decrypt,%function +.align 4 +bsaes_xts_decrypt: + mov ip, sp + stmdb sp!, {r4-r10, lr} @ 0x20 + VFP_ABI_PUSH + mov r6, sp @ future $fp + + mov $inp, r0 + mov $out, r1 + mov $len, r2 + mov $key, r3 + + sub r0, sp, #0x10 @ 0x10 + bic r0, #0xf @ align at 16 bytes + mov sp, r0 + +#ifdef XTS_CHAIN_TWEAK + ldr r0, [ip] @ pointer to input tweak +#else + @ generate initial tweak + ldr r0, [ip, #4] @ iv[] + mov r1, sp + ldr r2, [ip, #0] @ key2 + bl AES_encrypt + mov r0, sp @ pointer to initial tweak +#endif + + ldr $rounds, [$key, #240] @ get # of rounds + mov $fp, r6 +#ifndef BSAES_ASM_EXTENDED_KEY + @ allocate the key schedule on the stack + sub r12, sp, $rounds, lsl#7 @ 128 bytes per inner round key + @ add r12, #`128-32` @ size of bit-sliced key schedule + sub r12, #`32+16` @ place for tweak[9] + + @ populate the key schedule + mov r4, $key @ pass key + mov r5, $rounds @ pass # of rounds + mov sp, r12 + add r12, #0x90 @ pass key schedule + bl _bsaes_key_convert + add r4, sp, #0x90 + vldmia r4, {@XMM[6]} + vstmia r12, {@XMM[15]} @ save last round key + veor @XMM[7], @XMM[7], @XMM[6] @ fix up round 0 key + vstmia r4, {@XMM[7]} +#else + ldr r12, [$key, #244] + eors r12, #1 + beq 0f + + str r12, [$key, #244] + mov r4, $key @ pass key + mov r5, $rounds @ pass # of rounds + add r12, $key, #248 @ pass key schedule + bl _bsaes_key_convert + add r4, $key, #248 + vldmia r4, {@XMM[6]} + vstmia r12, {@XMM[15]} @ save last round key + veor @XMM[7], @XMM[7], @XMM[6] @ fix up round 0 key + vstmia r4, {@XMM[7]} + +.align 2 +0: sub sp, #0x90 @ place for tweak[9] +#endif + vld1.8 {@XMM[8]}, [r0] @ initial tweak + adr $magic, .Lxts_magic + +#ifndef XTS_CHAIN_TWEAK + tst $len, #0xf @ if not multiple of 16 + it ne @ Thumb2 thing, sanity check in ARM + subne $len, #0x10 @ subtract another 16 bytes +#endif + subs $len, #0x80 + + blo .Lxts_dec_short + b .Lxts_dec_loop + +.align 4 +.Lxts_dec_loop: + vldmia $magic, {$twmask} @ load XTS magic + vshr.s64 @T[0], @XMM[8], #63 + mov r0, sp + vand @T[0], @T[0], $twmask +___ +for($i=9;$i<16;$i++) { +$code.=<<___; + vadd.u64 @XMM[$i], @XMM[$i-1], @XMM[$i-1] + vst1.64 {@XMM[$i-1]}, [r0,:128]! + vswp `&Dhi("@T[0]")`,`&Dlo("@T[0]")` + vshr.s64 @T[1], @XMM[$i], #63 + veor @XMM[$i], @XMM[$i], @T[0] + vand @T[1], @T[1], $twmask +___ + @T=reverse(@T); + +$code.=<<___ if ($i>=10); + vld1.8 {@XMM[$i-10]}, [$inp]! +___ +$code.=<<___ if ($i>=11); + veor @XMM[$i-11], @XMM[$i-11], @XMM[$i-3] +___ +} +$code.=<<___; + vadd.u64 @XMM[8], @XMM[15], @XMM[15] + vst1.64 {@XMM[15]}, [r0,:128]! + vswp `&Dhi("@T[0]")`,`&Dlo("@T[0]")` + veor @XMM[8], @XMM[8], @T[0] + vst1.64 {@XMM[8]}, [r0,:128] @ next round tweak + + vld1.8 {@XMM[6]-@XMM[7]}, [$inp]! + veor @XMM[5], @XMM[5], @XMM[13] +#ifndef BSAES_ASM_EXTENDED_KEY + add r4, sp, #0x90 @ pass key schedule +#else + add r4, $key, #248 @ pass key schedule +#endif + veor @XMM[6], @XMM[6], @XMM[14] + mov r5, $rounds @ pass rounds + veor @XMM[7], @XMM[7], @XMM[15] + mov r0, sp + + bl _bsaes_decrypt8 + + vld1.64 {@XMM[ 8]-@XMM[ 9]}, [r0,:128]! + vld1.64 {@XMM[10]-@XMM[11]}, [r0,:128]! + veor @XMM[0], @XMM[0], @XMM[ 8] + vld1.64 {@XMM[12]-@XMM[13]}, [r0,:128]! + veor @XMM[1], @XMM[1], @XMM[ 9] + veor @XMM[8], @XMM[6], @XMM[10] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! + veor @XMM[9], @XMM[4], @XMM[11] + vld1.64 {@XMM[14]-@XMM[15]}, [r0,:128]! + veor @XMM[10], @XMM[2], @XMM[12] + vst1.8 {@XMM[8]-@XMM[9]}, [$out]! + veor @XMM[11], @XMM[7], @XMM[13] + veor @XMM[12], @XMM[3], @XMM[14] + vst1.8 {@XMM[10]-@XMM[11]}, [$out]! + veor @XMM[13], @XMM[5], @XMM[15] + vst1.8 {@XMM[12]-@XMM[13]}, [$out]! + + vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak + + subs $len, #0x80 + bpl .Lxts_dec_loop + +.Lxts_dec_short: + adds $len, #0x70 + bmi .Lxts_dec_done + + vldmia $magic, {$twmask} @ load XTS magic + vshr.s64 @T[0], @XMM[8], #63 + mov r0, sp + vand @T[0], @T[0], $twmask +___ +for($i=9;$i<16;$i++) { +$code.=<<___; + vadd.u64 @XMM[$i], @XMM[$i-1], @XMM[$i-1] + vst1.64 {@XMM[$i-1]}, [r0,:128]! + vswp `&Dhi("@T[0]")`,`&Dlo("@T[0]")` + vshr.s64 @T[1], @XMM[$i], #63 + veor @XMM[$i], @XMM[$i], @T[0] + vand @T[1], @T[1], $twmask +___ + @T=reverse(@T); + +$code.=<<___ if ($i>=10); + vld1.8 {@XMM[$i-10]}, [$inp]! + subs $len, #0x10 + bmi .Lxts_dec_`$i-9` +___ +$code.=<<___ if ($i>=11); + veor @XMM[$i-11], @XMM[$i-11], @XMM[$i-3] +___ +} +$code.=<<___; + sub $len, #0x10 + vst1.64 {@XMM[15]}, [r0,:128] @ next round tweak + + vld1.8 {@XMM[6]}, [$inp]! + veor @XMM[5], @XMM[5], @XMM[13] +#ifndef BSAES_ASM_EXTENDED_KEY + add r4, sp, #0x90 @ pass key schedule +#else + add r4, $key, #248 @ pass key schedule +#endif + veor @XMM[6], @XMM[6], @XMM[14] + mov r5, $rounds @ pass rounds + mov r0, sp + + bl _bsaes_decrypt8 + + vld1.64 {@XMM[ 8]-@XMM[ 9]}, [r0,:128]! + vld1.64 {@XMM[10]-@XMM[11]}, [r0,:128]! + veor @XMM[0], @XMM[0], @XMM[ 8] + vld1.64 {@XMM[12]-@XMM[13]}, [r0,:128]! + veor @XMM[1], @XMM[1], @XMM[ 9] + veor @XMM[8], @XMM[6], @XMM[10] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! + veor @XMM[9], @XMM[4], @XMM[11] + vld1.64 {@XMM[14]}, [r0,:128]! + veor @XMM[10], @XMM[2], @XMM[12] + vst1.8 {@XMM[8]-@XMM[9]}, [$out]! + veor @XMM[11], @XMM[7], @XMM[13] + veor @XMM[12], @XMM[3], @XMM[14] + vst1.8 {@XMM[10]-@XMM[11]}, [$out]! + vst1.8 {@XMM[12]}, [$out]! + + vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak + b .Lxts_dec_done +.align 4 +.Lxts_dec_6: + vst1.64 {@XMM[14]}, [r0,:128] @ next round tweak + + veor @XMM[4], @XMM[4], @XMM[12] +#ifndef BSAES_ASM_EXTENDED_KEY + add r4, sp, #0x90 @ pass key schedule +#else + add r4, $key, #248 @ pass key schedule +#endif + veor @XMM[5], @XMM[5], @XMM[13] + mov r5, $rounds @ pass rounds + mov r0, sp + + bl _bsaes_decrypt8 + + vld1.64 {@XMM[ 8]-@XMM[ 9]}, [r0,:128]! + vld1.64 {@XMM[10]-@XMM[11]}, [r0,:128]! + veor @XMM[0], @XMM[0], @XMM[ 8] + vld1.64 {@XMM[12]-@XMM[13]}, [r0,:128]! + veor @XMM[1], @XMM[1], @XMM[ 9] + veor @XMM[8], @XMM[6], @XMM[10] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! + veor @XMM[9], @XMM[4], @XMM[11] + veor @XMM[10], @XMM[2], @XMM[12] + vst1.8 {@XMM[8]-@XMM[9]}, [$out]! + veor @XMM[11], @XMM[7], @XMM[13] + vst1.8 {@XMM[10]-@XMM[11]}, [$out]! + + vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak + b .Lxts_dec_done +.align 4 +.Lxts_dec_5: + vst1.64 {@XMM[13]}, [r0,:128] @ next round tweak + + veor @XMM[3], @XMM[3], @XMM[11] +#ifndef BSAES_ASM_EXTENDED_KEY + add r4, sp, #0x90 @ pass key schedule +#else + add r4, $key, #248 @ pass key schedule +#endif + veor @XMM[4], @XMM[4], @XMM[12] + mov r5, $rounds @ pass rounds + mov r0, sp + + bl _bsaes_decrypt8 + + vld1.64 {@XMM[ 8]-@XMM[ 9]}, [r0,:128]! + vld1.64 {@XMM[10]-@XMM[11]}, [r0,:128]! + veor @XMM[0], @XMM[0], @XMM[ 8] + vld1.64 {@XMM[12]}, [r0,:128]! + veor @XMM[1], @XMM[1], @XMM[ 9] + veor @XMM[8], @XMM[6], @XMM[10] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! + veor @XMM[9], @XMM[4], @XMM[11] + veor @XMM[10], @XMM[2], @XMM[12] + vst1.8 {@XMM[8]-@XMM[9]}, [$out]! + vst1.8 {@XMM[10]}, [$out]! + + vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak + b .Lxts_dec_done +.align 4 +.Lxts_dec_4: + vst1.64 {@XMM[12]}, [r0,:128] @ next round tweak + + veor @XMM[2], @XMM[2], @XMM[10] +#ifndef BSAES_ASM_EXTENDED_KEY + add r4, sp, #0x90 @ pass key schedule +#else + add r4, $key, #248 @ pass key schedule +#endif + veor @XMM[3], @XMM[3], @XMM[11] + mov r5, $rounds @ pass rounds + mov r0, sp + + bl _bsaes_decrypt8 + + vld1.64 {@XMM[ 8]-@XMM[ 9]}, [r0,:128]! + vld1.64 {@XMM[10]-@XMM[11]}, [r0,:128]! + veor @XMM[0], @XMM[0], @XMM[ 8] + veor @XMM[1], @XMM[1], @XMM[ 9] + veor @XMM[8], @XMM[6], @XMM[10] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! + veor @XMM[9], @XMM[4], @XMM[11] + vst1.8 {@XMM[8]-@XMM[9]}, [$out]! + + vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak + b .Lxts_dec_done +.align 4 +.Lxts_dec_3: + vst1.64 {@XMM[11]}, [r0,:128] @ next round tweak + + veor @XMM[1], @XMM[1], @XMM[9] +#ifndef BSAES_ASM_EXTENDED_KEY + add r4, sp, #0x90 @ pass key schedule +#else + add r4, $key, #248 @ pass key schedule +#endif + veor @XMM[2], @XMM[2], @XMM[10] + mov r5, $rounds @ pass rounds + mov r0, sp + + bl _bsaes_decrypt8 + + vld1.64 {@XMM[8]-@XMM[9]}, [r0,:128]! + vld1.64 {@XMM[10]}, [r0,:128]! + veor @XMM[0], @XMM[0], @XMM[ 8] + veor @XMM[1], @XMM[1], @XMM[ 9] + veor @XMM[8], @XMM[6], @XMM[10] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! + vst1.8 {@XMM[8]}, [$out]! + + vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak + b .Lxts_dec_done +.align 4 +.Lxts_dec_2: + vst1.64 {@XMM[10]}, [r0,:128] @ next round tweak + + veor @XMM[0], @XMM[0], @XMM[8] +#ifndef BSAES_ASM_EXTENDED_KEY + add r4, sp, #0x90 @ pass key schedule +#else + add r4, $key, #248 @ pass key schedule +#endif + veor @XMM[1], @XMM[1], @XMM[9] + mov r5, $rounds @ pass rounds + mov r0, sp + + bl _bsaes_decrypt8 + + vld1.64 {@XMM[8]-@XMM[9]}, [r0,:128]! + veor @XMM[0], @XMM[0], @XMM[ 8] + veor @XMM[1], @XMM[1], @XMM[ 9] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! + + vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak + b .Lxts_dec_done +.align 4 +.Lxts_dec_1: + mov r0, sp + veor @XMM[0], @XMM[8] + mov r1, sp + vst1.8 {@XMM[0]}, [sp,:128] + mov r2, $key + mov r4, $fp @ preserve fp + mov r5, $magic @ preserve magic + + bl AES_decrypt + + vld1.8 {@XMM[0]}, [sp,:128] + veor @XMM[0], @XMM[0], @XMM[8] + vst1.8 {@XMM[0]}, [$out]! + mov $fp, r4 + mov $magic, r5 + + vmov @XMM[8], @XMM[9] @ next round tweak + +.Lxts_dec_done: +#ifndef XTS_CHAIN_TWEAK + adds $len, #0x10 + beq .Lxts_dec_ret + + @ calculate one round of extra tweak for the stolen ciphertext + vldmia $magic, {$twmask} + vshr.s64 @XMM[6], @XMM[8], #63 + vand @XMM[6], @XMM[6], $twmask + vadd.u64 @XMM[9], @XMM[8], @XMM[8] + vswp `&Dhi("@XMM[6]")`,`&Dlo("@XMM[6]")` + veor @XMM[9], @XMM[9], @XMM[6] + + @ perform the final decryption with the last tweak value + vld1.8 {@XMM[0]}, [$inp]! + mov r0, sp + veor @XMM[0], @XMM[0], @XMM[9] + mov r1, sp + vst1.8 {@XMM[0]}, [sp,:128] + mov r2, $key + mov r4, $fp @ preserve fp + + bl AES_decrypt + + vld1.8 {@XMM[0]}, [sp,:128] + veor @XMM[0], @XMM[0], @XMM[9] + vst1.8 {@XMM[0]}, [$out] + + mov r6, $out +.Lxts_dec_steal: + ldrb r1, [$out] + ldrb r0, [$inp], #1 + strb r1, [$out, #0x10] + strb r0, [$out], #1 + + subs $len, #1 + bhi .Lxts_dec_steal + + vld1.8 {@XMM[0]}, [r6] + mov r0, sp + veor @XMM[0], @XMM[8] + mov r1, sp + vst1.8 {@XMM[0]}, [sp,:128] + mov r2, $key + + bl AES_decrypt + + vld1.8 {@XMM[0]}, [sp,:128] + veor @XMM[0], @XMM[0], @XMM[8] + vst1.8 {@XMM[0]}, [r6] + mov $fp, r4 +#endif + +.Lxts_dec_ret: + bic r0, $fp, #0xf + vmov.i32 q0, #0 + vmov.i32 q1, #0 +#ifdef XTS_CHAIN_TWEAK + ldr r1, [$fp, #0x20+VFP_ABI_FRAME] @ chain tweak +#endif +.Lxts_dec_bzero: @ wipe key schedule [if any] + vstmia sp!, {q0-q1} + cmp sp, r0 + bne .Lxts_dec_bzero + + mov sp, $fp +#ifdef XTS_CHAIN_TWEAK + vst1.8 {@XMM[8]}, [r1] +#endif + VFP_ABI_POP + ldmia sp!, {r4-r10, pc} @ return + +.size bsaes_xts_decrypt,.-bsaes_xts_decrypt +___ +} +$code.=<<___; +#endif +#endif +___ + +$code =~ s/\`([^\`]*)\`/eval($1)/gem; + +open SELF,$0; +while() { + next if (/^#!/); + last if (!s/^#/@/ and !/^$/); + print; +} +close SELF; + +print $code; + +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/aes/asm/bsaes-x86_64.pl b/TMessagesProj/jni/boringssl/crypto/aes/asm/bsaes-x86_64.pl new file mode 100644 index 00000000..3f7d33c4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/aes/asm/bsaes-x86_64.pl @@ -0,0 +1,3102 @@ +#!/usr/bin/env perl + +################################################################### +### AES-128 [originally in CTR mode] ### +### bitsliced implementation for Intel Core 2 processors ### +### requires support of SSE extensions up to SSSE3 ### +### Author: Emilia Käsper and Peter Schwabe ### +### Date: 2009-03-19 ### +### Public domain ### +### ### +### See http://homes.esat.kuleuven.be/~ekasper/#software for ### +### further information. ### +################################################################### +# +# September 2011. +# +# Started as transliteration to "perlasm" the original code has +# undergone following changes: +# +# - code was made position-independent; +# - rounds were folded into a loop resulting in >5x size reduction +# from 12.5KB to 2.2KB; +# - above was possibile thanks to mixcolumns() modification that +# allowed to feed its output back to aesenc[last], this was +# achieved at cost of two additional inter-registers moves; +# - some instruction reordering and interleaving; +# - this module doesn't implement key setup subroutine, instead it +# relies on conversion of "conventional" key schedule as returned +# by AES_set_encrypt_key (see discussion below); +# - first and last round keys are treated differently, which allowed +# to skip one shiftrows(), reduce bit-sliced key schedule and +# speed-up conversion by 22%; +# - support for 192- and 256-bit keys was added; +# +# Resulting performance in CPU cycles spent to encrypt one byte out +# of 4096-byte buffer with 128-bit key is: +# +# Emilia's this(*) difference +# +# Core 2 9.30 8.69 +7% +# Nehalem(**) 7.63 6.88 +11% +# Atom 17.1 16.4 +4% +# Silvermont - 12.9 +# +# (*) Comparison is not completely fair, because "this" is ECB, +# i.e. no extra processing such as counter values calculation +# and xor-ing input as in Emilia's CTR implementation is +# performed. However, the CTR calculations stand for not more +# than 1% of total time, so comparison is *rather* fair. +# +# (**) Results were collected on Westmere, which is considered to +# be equivalent to Nehalem for this code. +# +# As for key schedule conversion subroutine. Interface to OpenSSL +# relies on per-invocation on-the-fly conversion. This naturally +# has impact on performance, especially for short inputs. Conversion +# time in CPU cycles and its ratio to CPU cycles spent in 8x block +# function is: +# +# conversion conversion/8x block +# Core 2 240 0.22 +# Nehalem 180 0.20 +# Atom 430 0.20 +# +# The ratio values mean that 128-byte blocks will be processed +# 16-18% slower, 256-byte blocks - 9-10%, 384-byte blocks - 6-7%, +# etc. Then keep in mind that input sizes not divisible by 128 are +# *effectively* slower, especially shortest ones, e.g. consecutive +# 144-byte blocks are processed 44% slower than one would expect, +# 272 - 29%, 400 - 22%, etc. Yet, despite all these "shortcomings" +# it's still faster than ["hyper-threading-safe" code path in] +# aes-x86_64.pl on all lengths above 64 bytes... +# +# October 2011. +# +# Add decryption procedure. Performance in CPU cycles spent to decrypt +# one byte out of 4096-byte buffer with 128-bit key is: +# +# Core 2 9.98 +# Nehalem 7.80 +# Atom 17.9 +# Silvermont 14.0 +# +# November 2011. +# +# Add bsaes_xts_[en|de]crypt. Less-than-80-bytes-block performance is +# suboptimal, but XTS is meant to be used with larger blocks... +# +# + +$flavour = shift; +$output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or +die "can't locate x86_64-xlate.pl"; + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +my ($inp,$out,$len,$key,$ivp)=("%rdi","%rsi","%rdx","%rcx"); +my @XMM=map("%xmm$_",(15,0..14)); # best on Atom, +10% over (0..15) +my $ecb=0; # suppress unreferenced ECB subroutines, spare some space... + +{ +my ($key,$rounds,$const)=("%rax","%r10d","%r11"); + +sub Sbox { +# input in lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb +# output in lsb > [b0, b1, b4, b6, b3, b7, b2, b5] < msb +my @b=@_[0..7]; +my @t=@_[8..11]; +my @s=@_[12..15]; + &InBasisChange (@b); + &Inv_GF256 (@b[6,5,0,3,7,1,4,2],@t,@s); + &OutBasisChange (@b[7,1,4,2,6,5,0,3]); +} + +sub InBasisChange { +# input in lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb +# output in lsb > [b6, b5, b0, b3, b7, b1, b4, b2] < msb +my @b=@_[0..7]; +$code.=<<___; + pxor @b[6], @b[5] + pxor @b[1], @b[2] + pxor @b[0], @b[3] + pxor @b[2], @b[6] + pxor @b[0], @b[5] + + pxor @b[3], @b[6] + pxor @b[7], @b[3] + pxor @b[5], @b[7] + pxor @b[4], @b[3] + pxor @b[5], @b[4] + pxor @b[1], @b[3] + + pxor @b[7], @b[2] + pxor @b[5], @b[1] +___ +} + +sub OutBasisChange { +# input in lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb +# output in lsb > [b6, b1, b2, b4, b7, b0, b3, b5] < msb +my @b=@_[0..7]; +$code.=<<___; + pxor @b[6], @b[0] + pxor @b[4], @b[1] + pxor @b[0], @b[2] + pxor @b[6], @b[4] + pxor @b[1], @b[6] + + pxor @b[5], @b[1] + pxor @b[3], @b[5] + pxor @b[7], @b[3] + pxor @b[5], @b[7] + pxor @b[5], @b[2] + + pxor @b[7], @b[4] +___ +} + +sub InvSbox { +# input in lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb +# output in lsb > [b0, b1, b6, b4, b2, b7, b3, b5] < msb +my @b=@_[0..7]; +my @t=@_[8..11]; +my @s=@_[12..15]; + &InvInBasisChange (@b); + &Inv_GF256 (@b[5,1,2,6,3,7,0,4],@t,@s); + &InvOutBasisChange (@b[3,7,0,4,5,1,2,6]); +} + +sub InvInBasisChange { # OutBasisChange in reverse +my @b=@_[5,1,2,6,3,7,0,4]; +$code.=<<___ + pxor @b[7], @b[4] + + pxor @b[5], @b[7] + pxor @b[5], @b[2] + pxor @b[7], @b[3] + pxor @b[3], @b[5] + pxor @b[5], @b[1] + + pxor @b[1], @b[6] + pxor @b[0], @b[2] + pxor @b[6], @b[4] + pxor @b[6], @b[0] + pxor @b[4], @b[1] +___ +} + +sub InvOutBasisChange { # InBasisChange in reverse +my @b=@_[2,5,7,3,6,1,0,4]; +$code.=<<___; + pxor @b[5], @b[1] + pxor @b[7], @b[2] + + pxor @b[1], @b[3] + pxor @b[5], @b[4] + pxor @b[5], @b[7] + pxor @b[4], @b[3] + pxor @b[0], @b[5] + pxor @b[7], @b[3] + pxor @b[2], @b[6] + pxor @b[1], @b[2] + pxor @b[3], @b[6] + + pxor @b[0], @b[3] + pxor @b[6], @b[5] +___ +} + +sub Mul_GF4 { +#;************************************************************* +#;* Mul_GF4: Input x0-x1,y0-y1 Output x0-x1 Temp t0 (8) * +#;************************************************************* +my ($x0,$x1,$y0,$y1,$t0)=@_; +$code.=<<___; + movdqa $y0, $t0 + pxor $y1, $t0 + pand $x0, $t0 + pxor $x1, $x0 + pand $y0, $x1 + pand $y1, $x0 + pxor $x1, $x0 + pxor $t0, $x1 +___ +} + +sub Mul_GF4_N { # not used, see next subroutine +# multiply and scale by N +my ($x0,$x1,$y0,$y1,$t0)=@_; +$code.=<<___; + movdqa $y0, $t0 + pxor $y1, $t0 + pand $x0, $t0 + pxor $x1, $x0 + pand $y0, $x1 + pand $y1, $x0 + pxor $x0, $x1 + pxor $t0, $x0 +___ +} + +sub Mul_GF4_N_GF4 { +# interleaved Mul_GF4_N and Mul_GF4 +my ($x0,$x1,$y0,$y1,$t0, + $x2,$x3,$y2,$y3,$t1)=@_; +$code.=<<___; + movdqa $y0, $t0 + movdqa $y2, $t1 + pxor $y1, $t0 + pxor $y3, $t1 + pand $x0, $t0 + pand $x2, $t1 + pxor $x1, $x0 + pxor $x3, $x2 + pand $y0, $x1 + pand $y2, $x3 + pand $y1, $x0 + pand $y3, $x2 + pxor $x0, $x1 + pxor $x3, $x2 + pxor $t0, $x0 + pxor $t1, $x3 +___ +} +sub Mul_GF16_2 { +my @x=@_[0..7]; +my @y=@_[8..11]; +my @t=@_[12..15]; +$code.=<<___; + movdqa @x[0], @t[0] + movdqa @x[1], @t[1] +___ + &Mul_GF4 (@x[0], @x[1], @y[0], @y[1], @t[2]); +$code.=<<___; + pxor @x[2], @t[0] + pxor @x[3], @t[1] + pxor @y[2], @y[0] + pxor @y[3], @y[1] +___ + Mul_GF4_N_GF4 (@t[0], @t[1], @y[0], @y[1], @t[3], + @x[2], @x[3], @y[2], @y[3], @t[2]); +$code.=<<___; + pxor @t[0], @x[0] + pxor @t[0], @x[2] + pxor @t[1], @x[1] + pxor @t[1], @x[3] + + movdqa @x[4], @t[0] + movdqa @x[5], @t[1] + pxor @x[6], @t[0] + pxor @x[7], @t[1] +___ + &Mul_GF4_N_GF4 (@t[0], @t[1], @y[0], @y[1], @t[3], + @x[6], @x[7], @y[2], @y[3], @t[2]); +$code.=<<___; + pxor @y[2], @y[0] + pxor @y[3], @y[1] +___ + &Mul_GF4 (@x[4], @x[5], @y[0], @y[1], @t[3]); +$code.=<<___; + pxor @t[0], @x[4] + pxor @t[0], @x[6] + pxor @t[1], @x[5] + pxor @t[1], @x[7] +___ +} +sub Inv_GF256 { +#;******************************************************************** +#;* Inv_GF256: Input x0-x7 Output x0-x7 Temp t0-t3,s0-s3 (144) * +#;******************************************************************** +my @x=@_[0..7]; +my @t=@_[8..11]; +my @s=@_[12..15]; +# direct optimizations from hardware +$code.=<<___; + movdqa @x[4], @t[3] + movdqa @x[5], @t[2] + movdqa @x[1], @t[1] + movdqa @x[7], @s[1] + movdqa @x[0], @s[0] + + pxor @x[6], @t[3] + pxor @x[7], @t[2] + pxor @x[3], @t[1] + movdqa @t[3], @s[2] + pxor @x[6], @s[1] + movdqa @t[2], @t[0] + pxor @x[2], @s[0] + movdqa @t[3], @s[3] + + por @t[1], @t[2] + por @s[0], @t[3] + pxor @t[0], @s[3] + pand @s[0], @s[2] + pxor @t[1], @s[0] + pand @t[1], @t[0] + pand @s[0], @s[3] + movdqa @x[3], @s[0] + pxor @x[2], @s[0] + pand @s[0], @s[1] + pxor @s[1], @t[3] + pxor @s[1], @t[2] + movdqa @x[4], @s[1] + movdqa @x[1], @s[0] + pxor @x[5], @s[1] + pxor @x[0], @s[0] + movdqa @s[1], @t[1] + pand @s[0], @s[1] + por @s[0], @t[1] + pxor @s[1], @t[0] + pxor @s[3], @t[3] + pxor @s[2], @t[2] + pxor @s[3], @t[1] + movdqa @x[7], @s[0] + pxor @s[2], @t[0] + movdqa @x[6], @s[1] + pxor @s[2], @t[1] + movdqa @x[5], @s[2] + pand @x[3], @s[0] + movdqa @x[4], @s[3] + pand @x[2], @s[1] + pand @x[1], @s[2] + por @x[0], @s[3] + pxor @s[0], @t[3] + pxor @s[1], @t[2] + pxor @s[2], @t[1] + pxor @s[3], @t[0] + + #Inv_GF16 \t0, \t1, \t2, \t3, \s0, \s1, \s2, \s3 + + # new smaller inversion + + movdqa @t[3], @s[0] + pand @t[1], @t[3] + pxor @t[2], @s[0] + + movdqa @t[0], @s[2] + movdqa @s[0], @s[3] + pxor @t[3], @s[2] + pand @s[2], @s[3] + + movdqa @t[1], @s[1] + pxor @t[2], @s[3] + pxor @t[0], @s[1] + + pxor @t[2], @t[3] + + pand @t[3], @s[1] + + movdqa @s[2], @t[2] + pxor @t[0], @s[1] + + pxor @s[1], @t[2] + pxor @s[1], @t[1] + + pand @t[0], @t[2] + + pxor @t[2], @s[2] + pxor @t[2], @t[1] + + pand @s[3], @s[2] + + pxor @s[0], @s[2] +___ +# output in s3, s2, s1, t1 + +# Mul_GF16_2 \x0, \x1, \x2, \x3, \x4, \x5, \x6, \x7, \t2, \t3, \t0, \t1, \s0, \s1, \s2, \s3 + +# Mul_GF16_2 \x0, \x1, \x2, \x3, \x4, \x5, \x6, \x7, \s3, \s2, \s1, \t1, \s0, \t0, \t2, \t3 + &Mul_GF16_2(@x,@s[3,2,1],@t[1],@s[0],@t[0,2,3]); + +### output msb > [x3,x2,x1,x0,x7,x6,x5,x4] < lsb +} + +# AES linear components + +sub ShiftRows { +my @x=@_[0..7]; +my $mask=pop; +$code.=<<___; + pxor 0x00($key),@x[0] + pxor 0x10($key),@x[1] + pxor 0x20($key),@x[2] + pxor 0x30($key),@x[3] + pshufb $mask,@x[0] + pshufb $mask,@x[1] + pxor 0x40($key),@x[4] + pxor 0x50($key),@x[5] + pshufb $mask,@x[2] + pshufb $mask,@x[3] + pxor 0x60($key),@x[6] + pxor 0x70($key),@x[7] + pshufb $mask,@x[4] + pshufb $mask,@x[5] + pshufb $mask,@x[6] + pshufb $mask,@x[7] + lea 0x80($key),$key +___ +} + +sub MixColumns { +# modified to emit output in order suitable for feeding back to aesenc[last] +my @x=@_[0..7]; +my @t=@_[8..15]; +my $inv=@_[16]; # optional +$code.=<<___; + pshufd \$0x93, @x[0], @t[0] # x0 <<< 32 + pshufd \$0x93, @x[1], @t[1] + pxor @t[0], @x[0] # x0 ^ (x0 <<< 32) + pshufd \$0x93, @x[2], @t[2] + pxor @t[1], @x[1] + pshufd \$0x93, @x[3], @t[3] + pxor @t[2], @x[2] + pshufd \$0x93, @x[4], @t[4] + pxor @t[3], @x[3] + pshufd \$0x93, @x[5], @t[5] + pxor @t[4], @x[4] + pshufd \$0x93, @x[6], @t[6] + pxor @t[5], @x[5] + pshufd \$0x93, @x[7], @t[7] + pxor @t[6], @x[6] + pxor @t[7], @x[7] + + pxor @x[0], @t[1] + pxor @x[7], @t[0] + pxor @x[7], @t[1] + pshufd \$0x4E, @x[0], @x[0] # (x0 ^ (x0 <<< 32)) <<< 64) + pxor @x[1], @t[2] + pshufd \$0x4E, @x[1], @x[1] + pxor @x[4], @t[5] + pxor @t[0], @x[0] + pxor @x[5], @t[6] + pxor @t[1], @x[1] + pxor @x[3], @t[4] + pshufd \$0x4E, @x[4], @t[0] + pxor @x[6], @t[7] + pshufd \$0x4E, @x[5], @t[1] + pxor @x[2], @t[3] + pshufd \$0x4E, @x[3], @x[4] + pxor @x[7], @t[3] + pshufd \$0x4E, @x[7], @x[5] + pxor @x[7], @t[4] + pshufd \$0x4E, @x[6], @x[3] + pxor @t[4], @t[0] + pshufd \$0x4E, @x[2], @x[6] + pxor @t[5], @t[1] +___ +$code.=<<___ if (!$inv); + pxor @t[3], @x[4] + pxor @t[7], @x[5] + pxor @t[6], @x[3] + movdqa @t[0], @x[2] + pxor @t[2], @x[6] + movdqa @t[1], @x[7] +___ +$code.=<<___ if ($inv); + pxor @x[4], @t[3] + pxor @t[7], @x[5] + pxor @x[3], @t[6] + movdqa @t[0], @x[3] + pxor @t[2], @x[6] + movdqa @t[6], @x[2] + movdqa @t[1], @x[7] + movdqa @x[6], @x[4] + movdqa @t[3], @x[6] +___ +} + +sub InvMixColumns_orig { +my @x=@_[0..7]; +my @t=@_[8..15]; + +$code.=<<___; + # multiplication by 0x0e + pshufd \$0x93, @x[7], @t[7] + movdqa @x[2], @t[2] + pxor @x[5], @x[7] # 7 5 + pxor @x[5], @x[2] # 2 5 + pshufd \$0x93, @x[0], @t[0] + movdqa @x[5], @t[5] + pxor @x[0], @x[5] # 5 0 [1] + pxor @x[1], @x[0] # 0 1 + pshufd \$0x93, @x[1], @t[1] + pxor @x[2], @x[1] # 1 25 + pxor @x[6], @x[0] # 01 6 [2] + pxor @x[3], @x[1] # 125 3 [4] + pshufd \$0x93, @x[3], @t[3] + pxor @x[0], @x[2] # 25 016 [3] + pxor @x[7], @x[3] # 3 75 + pxor @x[6], @x[7] # 75 6 [0] + pshufd \$0x93, @x[6], @t[6] + movdqa @x[4], @t[4] + pxor @x[4], @x[6] # 6 4 + pxor @x[3], @x[4] # 4 375 [6] + pxor @x[7], @x[3] # 375 756=36 + pxor @t[5], @x[6] # 64 5 [7] + pxor @t[2], @x[3] # 36 2 + pxor @t[4], @x[3] # 362 4 [5] + pshufd \$0x93, @t[5], @t[5] +___ + my @y = @x[7,5,0,2,1,3,4,6]; +$code.=<<___; + # multiplication by 0x0b + pxor @y[0], @y[1] + pxor @t[0], @y[0] + pxor @t[1], @y[1] + pshufd \$0x93, @t[2], @t[2] + pxor @t[5], @y[0] + pxor @t[6], @y[1] + pxor @t[7], @y[0] + pshufd \$0x93, @t[4], @t[4] + pxor @t[6], @t[7] # clobber t[7] + pxor @y[0], @y[1] + + pxor @t[0], @y[3] + pshufd \$0x93, @t[0], @t[0] + pxor @t[1], @y[2] + pxor @t[1], @y[4] + pxor @t[2], @y[2] + pshufd \$0x93, @t[1], @t[1] + pxor @t[2], @y[3] + pxor @t[2], @y[5] + pxor @t[7], @y[2] + pshufd \$0x93, @t[2], @t[2] + pxor @t[3], @y[3] + pxor @t[3], @y[6] + pxor @t[3], @y[4] + pshufd \$0x93, @t[3], @t[3] + pxor @t[4], @y[7] + pxor @t[4], @y[5] + pxor @t[7], @y[7] + pxor @t[5], @y[3] + pxor @t[4], @y[4] + pxor @t[5], @t[7] # clobber t[7] even more + + pxor @t[7], @y[5] + pshufd \$0x93, @t[4], @t[4] + pxor @t[7], @y[6] + pxor @t[7], @y[4] + + pxor @t[5], @t[7] + pshufd \$0x93, @t[5], @t[5] + pxor @t[6], @t[7] # restore t[7] + + # multiplication by 0x0d + pxor @y[7], @y[4] + pxor @t[4], @y[7] + pshufd \$0x93, @t[6], @t[6] + pxor @t[0], @y[2] + pxor @t[5], @y[7] + pxor @t[2], @y[2] + pshufd \$0x93, @t[7], @t[7] + + pxor @y[1], @y[3] + pxor @t[1], @y[1] + pxor @t[0], @y[0] + pxor @t[0], @y[3] + pxor @t[5], @y[1] + pxor @t[5], @y[0] + pxor @t[7], @y[1] + pshufd \$0x93, @t[0], @t[0] + pxor @t[6], @y[0] + pxor @y[1], @y[3] + pxor @t[1], @y[4] + pshufd \$0x93, @t[1], @t[1] + + pxor @t[7], @y[7] + pxor @t[2], @y[4] + pxor @t[2], @y[5] + pshufd \$0x93, @t[2], @t[2] + pxor @t[6], @y[2] + pxor @t[3], @t[6] # clobber t[6] + pxor @y[7], @y[4] + pxor @t[6], @y[3] + + pxor @t[6], @y[6] + pxor @t[5], @y[5] + pxor @t[4], @y[6] + pshufd \$0x93, @t[4], @t[4] + pxor @t[6], @y[5] + pxor @t[7], @y[6] + pxor @t[3], @t[6] # restore t[6] + + pshufd \$0x93, @t[5], @t[5] + pshufd \$0x93, @t[6], @t[6] + pshufd \$0x93, @t[7], @t[7] + pshufd \$0x93, @t[3], @t[3] + + # multiplication by 0x09 + pxor @y[1], @y[4] + pxor @y[1], @t[1] # t[1]=y[1] + pxor @t[5], @t[0] # clobber t[0] + pxor @t[5], @t[1] + pxor @t[0], @y[3] + pxor @y[0], @t[0] # t[0]=y[0] + pxor @t[6], @t[1] + pxor @t[7], @t[6] # clobber t[6] + pxor @t[1], @y[4] + pxor @t[4], @y[7] + pxor @y[4], @t[4] # t[4]=y[4] + pxor @t[3], @y[6] + pxor @y[3], @t[3] # t[3]=y[3] + pxor @t[2], @y[5] + pxor @y[2], @t[2] # t[2]=y[2] + pxor @t[7], @t[3] + pxor @y[5], @t[5] # t[5]=y[5] + pxor @t[6], @t[2] + pxor @t[6], @t[5] + pxor @y[6], @t[6] # t[6]=y[6] + pxor @y[7], @t[7] # t[7]=y[7] + + movdqa @t[0],@XMM[0] + movdqa @t[1],@XMM[1] + movdqa @t[2],@XMM[2] + movdqa @t[3],@XMM[3] + movdqa @t[4],@XMM[4] + movdqa @t[5],@XMM[5] + movdqa @t[6],@XMM[6] + movdqa @t[7],@XMM[7] +___ +} + +sub InvMixColumns { +my @x=@_[0..7]; +my @t=@_[8..15]; + +# Thanks to Jussi Kivilinna for providing pointer to +# +# | 0e 0b 0d 09 | | 02 03 01 01 | | 05 00 04 00 | +# | 09 0e 0b 0d | = | 01 02 03 01 | x | 00 05 00 04 | +# | 0d 09 0e 0b | | 01 01 02 03 | | 04 00 05 00 | +# | 0b 0d 09 0e | | 03 01 01 02 | | 00 04 00 05 | + +$code.=<<___; + # multiplication by 0x05-0x00-0x04-0x00 + pshufd \$0x4E, @x[0], @t[0] + pshufd \$0x4E, @x[6], @t[6] + pxor @x[0], @t[0] + pshufd \$0x4E, @x[7], @t[7] + pxor @x[6], @t[6] + pshufd \$0x4E, @x[1], @t[1] + pxor @x[7], @t[7] + pshufd \$0x4E, @x[2], @t[2] + pxor @x[1], @t[1] + pshufd \$0x4E, @x[3], @t[3] + pxor @x[2], @t[2] + pxor @t[6], @x[0] + pxor @t[6], @x[1] + pshufd \$0x4E, @x[4], @t[4] + pxor @x[3], @t[3] + pxor @t[0], @x[2] + pxor @t[1], @x[3] + pshufd \$0x4E, @x[5], @t[5] + pxor @x[4], @t[4] + pxor @t[7], @x[1] + pxor @t[2], @x[4] + pxor @x[5], @t[5] + + pxor @t[7], @x[2] + pxor @t[6], @x[3] + pxor @t[6], @x[4] + pxor @t[3], @x[5] + pxor @t[4], @x[6] + pxor @t[7], @x[4] + pxor @t[7], @x[5] + pxor @t[5], @x[7] +___ + &MixColumns (@x,@t,1); # flipped 2<->3 and 4<->6 +} + +sub aesenc { # not used +my @b=@_[0..7]; +my @t=@_[8..15]; +$code.=<<___; + movdqa 0x30($const),@t[0] # .LSR +___ + &ShiftRows (@b,@t[0]); + &Sbox (@b,@t); + &MixColumns (@b[0,1,4,6,3,7,2,5],@t); +} + +sub aesenclast { # not used +my @b=@_[0..7]; +my @t=@_[8..15]; +$code.=<<___; + movdqa 0x40($const),@t[0] # .LSRM0 +___ + &ShiftRows (@b,@t[0]); + &Sbox (@b,@t); +$code.=<<___ + pxor 0x00($key),@b[0] + pxor 0x10($key),@b[1] + pxor 0x20($key),@b[4] + pxor 0x30($key),@b[6] + pxor 0x40($key),@b[3] + pxor 0x50($key),@b[7] + pxor 0x60($key),@b[2] + pxor 0x70($key),@b[5] +___ +} + +sub swapmove { +my ($a,$b,$n,$mask,$t)=@_; +$code.=<<___; + movdqa $b,$t + psrlq \$$n,$b + pxor $a,$b + pand $mask,$b + pxor $b,$a + psllq \$$n,$b + pxor $t,$b +___ +} +sub swapmove2x { +my ($a0,$b0,$a1,$b1,$n,$mask,$t0,$t1)=@_; +$code.=<<___; + movdqa $b0,$t0 + psrlq \$$n,$b0 + movdqa $b1,$t1 + psrlq \$$n,$b1 + pxor $a0,$b0 + pxor $a1,$b1 + pand $mask,$b0 + pand $mask,$b1 + pxor $b0,$a0 + psllq \$$n,$b0 + pxor $b1,$a1 + psllq \$$n,$b1 + pxor $t0,$b0 + pxor $t1,$b1 +___ +} + +sub bitslice { +my @x=reverse(@_[0..7]); +my ($t0,$t1,$t2,$t3)=@_[8..11]; +$code.=<<___; + movdqa 0x00($const),$t0 # .LBS0 + movdqa 0x10($const),$t1 # .LBS1 +___ + &swapmove2x(@x[0,1,2,3],1,$t0,$t2,$t3); + &swapmove2x(@x[4,5,6,7],1,$t0,$t2,$t3); +$code.=<<___; + movdqa 0x20($const),$t0 # .LBS2 +___ + &swapmove2x(@x[0,2,1,3],2,$t1,$t2,$t3); + &swapmove2x(@x[4,6,5,7],2,$t1,$t2,$t3); + + &swapmove2x(@x[0,4,1,5],4,$t0,$t2,$t3); + &swapmove2x(@x[2,6,3,7],4,$t0,$t2,$t3); +} + +$code.=<<___; +.text + +.extern asm_AES_encrypt +.extern asm_AES_decrypt + +.type _bsaes_encrypt8,\@abi-omnipotent +.align 64 +_bsaes_encrypt8: + lea .LBS0(%rip), $const # constants table + + movdqa ($key), @XMM[9] # round 0 key + lea 0x10($key), $key + movdqa 0x50($const), @XMM[8] # .LM0SR + pxor @XMM[9], @XMM[0] # xor with round0 key + pxor @XMM[9], @XMM[1] + pxor @XMM[9], @XMM[2] + pxor @XMM[9], @XMM[3] + pshufb @XMM[8], @XMM[0] + pshufb @XMM[8], @XMM[1] + pxor @XMM[9], @XMM[4] + pxor @XMM[9], @XMM[5] + pshufb @XMM[8], @XMM[2] + pshufb @XMM[8], @XMM[3] + pxor @XMM[9], @XMM[6] + pxor @XMM[9], @XMM[7] + pshufb @XMM[8], @XMM[4] + pshufb @XMM[8], @XMM[5] + pshufb @XMM[8], @XMM[6] + pshufb @XMM[8], @XMM[7] +_bsaes_encrypt8_bitslice: +___ + &bitslice (@XMM[0..7, 8..11]); +$code.=<<___; + dec $rounds + jmp .Lenc_sbox +.align 16 +.Lenc_loop: +___ + &ShiftRows (@XMM[0..7, 8]); +$code.=".Lenc_sbox:\n"; + &Sbox (@XMM[0..7, 8..15]); +$code.=<<___; + dec $rounds + jl .Lenc_done +___ + &MixColumns (@XMM[0,1,4,6,3,7,2,5, 8..15]); +$code.=<<___; + movdqa 0x30($const), @XMM[8] # .LSR + jnz .Lenc_loop + movdqa 0x40($const), @XMM[8] # .LSRM0 + jmp .Lenc_loop +.align 16 +.Lenc_done: +___ + # output in lsb > [t0, t1, t4, t6, t3, t7, t2, t5] < msb + &bitslice (@XMM[0,1,4,6,3,7,2,5, 8..11]); +$code.=<<___; + movdqa ($key), @XMM[8] # last round key + pxor @XMM[8], @XMM[4] + pxor @XMM[8], @XMM[6] + pxor @XMM[8], @XMM[3] + pxor @XMM[8], @XMM[7] + pxor @XMM[8], @XMM[2] + pxor @XMM[8], @XMM[5] + pxor @XMM[8], @XMM[0] + pxor @XMM[8], @XMM[1] + ret +.size _bsaes_encrypt8,.-_bsaes_encrypt8 + +.type _bsaes_decrypt8,\@abi-omnipotent +.align 64 +_bsaes_decrypt8: + lea .LBS0(%rip), $const # constants table + + movdqa ($key), @XMM[9] # round 0 key + lea 0x10($key), $key + movdqa -0x30($const), @XMM[8] # .LM0ISR + pxor @XMM[9], @XMM[0] # xor with round0 key + pxor @XMM[9], @XMM[1] + pxor @XMM[9], @XMM[2] + pxor @XMM[9], @XMM[3] + pshufb @XMM[8], @XMM[0] + pshufb @XMM[8], @XMM[1] + pxor @XMM[9], @XMM[4] + pxor @XMM[9], @XMM[5] + pshufb @XMM[8], @XMM[2] + pshufb @XMM[8], @XMM[3] + pxor @XMM[9], @XMM[6] + pxor @XMM[9], @XMM[7] + pshufb @XMM[8], @XMM[4] + pshufb @XMM[8], @XMM[5] + pshufb @XMM[8], @XMM[6] + pshufb @XMM[8], @XMM[7] +___ + &bitslice (@XMM[0..7, 8..11]); +$code.=<<___; + dec $rounds + jmp .Ldec_sbox +.align 16 +.Ldec_loop: +___ + &ShiftRows (@XMM[0..7, 8]); +$code.=".Ldec_sbox:\n"; + &InvSbox (@XMM[0..7, 8..15]); +$code.=<<___; + dec $rounds + jl .Ldec_done +___ + &InvMixColumns (@XMM[0,1,6,4,2,7,3,5, 8..15]); +$code.=<<___; + movdqa -0x10($const), @XMM[8] # .LISR + jnz .Ldec_loop + movdqa -0x20($const), @XMM[8] # .LISRM0 + jmp .Ldec_loop +.align 16 +.Ldec_done: +___ + &bitslice (@XMM[0,1,6,4,2,7,3,5, 8..11]); +$code.=<<___; + movdqa ($key), @XMM[8] # last round key + pxor @XMM[8], @XMM[6] + pxor @XMM[8], @XMM[4] + pxor @XMM[8], @XMM[2] + pxor @XMM[8], @XMM[7] + pxor @XMM[8], @XMM[3] + pxor @XMM[8], @XMM[5] + pxor @XMM[8], @XMM[0] + pxor @XMM[8], @XMM[1] + ret +.size _bsaes_decrypt8,.-_bsaes_decrypt8 +___ +} +{ +my ($out,$inp,$rounds,$const)=("%rax","%rcx","%r10d","%r11"); + +sub bitslice_key { +my @x=reverse(@_[0..7]); +my ($bs0,$bs1,$bs2,$t2,$t3)=@_[8..12]; + + &swapmove (@x[0,1],1,$bs0,$t2,$t3); +$code.=<<___; + #&swapmove(@x[2,3],1,$t0,$t2,$t3); + movdqa @x[0], @x[2] + movdqa @x[1], @x[3] +___ + #&swapmove2x(@x[4,5,6,7],1,$t0,$t2,$t3); + + &swapmove2x (@x[0,2,1,3],2,$bs1,$t2,$t3); +$code.=<<___; + #&swapmove2x(@x[4,6,5,7],2,$t1,$t2,$t3); + movdqa @x[0], @x[4] + movdqa @x[2], @x[6] + movdqa @x[1], @x[5] + movdqa @x[3], @x[7] +___ + &swapmove2x (@x[0,4,1,5],4,$bs2,$t2,$t3); + &swapmove2x (@x[2,6,3,7],4,$bs2,$t2,$t3); +} + +$code.=<<___; +.type _bsaes_key_convert,\@abi-omnipotent +.align 16 +_bsaes_key_convert: + lea .Lmasks(%rip), $const + movdqu ($inp), %xmm7 # load round 0 key + lea 0x10($inp), $inp + movdqa 0x00($const), %xmm0 # 0x01... + movdqa 0x10($const), %xmm1 # 0x02... + movdqa 0x20($const), %xmm2 # 0x04... + movdqa 0x30($const), %xmm3 # 0x08... + movdqa 0x40($const), %xmm4 # .LM0 + pcmpeqd %xmm5, %xmm5 # .LNOT + + movdqu ($inp), %xmm6 # load round 1 key + movdqa %xmm7, ($out) # save round 0 key + lea 0x10($out), $out + dec $rounds + jmp .Lkey_loop +.align 16 +.Lkey_loop: + pshufb %xmm4, %xmm6 # .LM0 + + movdqa %xmm0, %xmm8 + movdqa %xmm1, %xmm9 + + pand %xmm6, %xmm8 + pand %xmm6, %xmm9 + movdqa %xmm2, %xmm10 + pcmpeqb %xmm0, %xmm8 + psllq \$4, %xmm0 # 0x10... + movdqa %xmm3, %xmm11 + pcmpeqb %xmm1, %xmm9 + psllq \$4, %xmm1 # 0x20... + + pand %xmm6, %xmm10 + pand %xmm6, %xmm11 + movdqa %xmm0, %xmm12 + pcmpeqb %xmm2, %xmm10 + psllq \$4, %xmm2 # 0x40... + movdqa %xmm1, %xmm13 + pcmpeqb %xmm3, %xmm11 + psllq \$4, %xmm3 # 0x80... + + movdqa %xmm2, %xmm14 + movdqa %xmm3, %xmm15 + pxor %xmm5, %xmm8 # "pnot" + pxor %xmm5, %xmm9 + + pand %xmm6, %xmm12 + pand %xmm6, %xmm13 + movdqa %xmm8, 0x00($out) # write bit-sliced round key + pcmpeqb %xmm0, %xmm12 + psrlq \$4, %xmm0 # 0x01... + movdqa %xmm9, 0x10($out) + pcmpeqb %xmm1, %xmm13 + psrlq \$4, %xmm1 # 0x02... + lea 0x10($inp), $inp + + pand %xmm6, %xmm14 + pand %xmm6, %xmm15 + movdqa %xmm10, 0x20($out) + pcmpeqb %xmm2, %xmm14 + psrlq \$4, %xmm2 # 0x04... + movdqa %xmm11, 0x30($out) + pcmpeqb %xmm3, %xmm15 + psrlq \$4, %xmm3 # 0x08... + movdqu ($inp), %xmm6 # load next round key + + pxor %xmm5, %xmm13 # "pnot" + pxor %xmm5, %xmm14 + movdqa %xmm12, 0x40($out) + movdqa %xmm13, 0x50($out) + movdqa %xmm14, 0x60($out) + movdqa %xmm15, 0x70($out) + lea 0x80($out),$out + dec $rounds + jnz .Lkey_loop + + movdqa 0x50($const), %xmm7 # .L63 + #movdqa %xmm6, ($out) # don't save last round key + ret +.size _bsaes_key_convert,.-_bsaes_key_convert +___ +} + +if (0 && !$win64) { # following four functions are unsupported interface + # used for benchmarking... +$code.=<<___; +.globl bsaes_enc_key_convert +.type bsaes_enc_key_convert,\@function,2 +.align 16 +bsaes_enc_key_convert: + mov 240($inp),%r10d # pass rounds + mov $inp,%rcx # pass key + mov $out,%rax # pass key schedule + call _bsaes_key_convert + pxor %xmm6,%xmm7 # fix up last round key + movdqa %xmm7,(%rax) # save last round key + ret +.size bsaes_enc_key_convert,.-bsaes_enc_key_convert + +.globl bsaes_encrypt_128 +.type bsaes_encrypt_128,\@function,4 +.align 16 +bsaes_encrypt_128: +.Lenc128_loop: + movdqu 0x00($inp), @XMM[0] # load input + movdqu 0x10($inp), @XMM[1] + movdqu 0x20($inp), @XMM[2] + movdqu 0x30($inp), @XMM[3] + movdqu 0x40($inp), @XMM[4] + movdqu 0x50($inp), @XMM[5] + movdqu 0x60($inp), @XMM[6] + movdqu 0x70($inp), @XMM[7] + mov $key, %rax # pass the $key + lea 0x80($inp), $inp + mov \$10,%r10d + + call _bsaes_encrypt8 + + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[4], 0x20($out) + movdqu @XMM[6], 0x30($out) + movdqu @XMM[3], 0x40($out) + movdqu @XMM[7], 0x50($out) + movdqu @XMM[2], 0x60($out) + movdqu @XMM[5], 0x70($out) + lea 0x80($out), $out + sub \$0x80,$len + ja .Lenc128_loop + ret +.size bsaes_encrypt_128,.-bsaes_encrypt_128 + +.globl bsaes_dec_key_convert +.type bsaes_dec_key_convert,\@function,2 +.align 16 +bsaes_dec_key_convert: + mov 240($inp),%r10d # pass rounds + mov $inp,%rcx # pass key + mov $out,%rax # pass key schedule + call _bsaes_key_convert + pxor ($out),%xmm7 # fix up round 0 key + movdqa %xmm6,(%rax) # save last round key + movdqa %xmm7,($out) + ret +.size bsaes_dec_key_convert,.-bsaes_dec_key_convert + +.globl bsaes_decrypt_128 +.type bsaes_decrypt_128,\@function,4 +.align 16 +bsaes_decrypt_128: +.Ldec128_loop: + movdqu 0x00($inp), @XMM[0] # load input + movdqu 0x10($inp), @XMM[1] + movdqu 0x20($inp), @XMM[2] + movdqu 0x30($inp), @XMM[3] + movdqu 0x40($inp), @XMM[4] + movdqu 0x50($inp), @XMM[5] + movdqu 0x60($inp), @XMM[6] + movdqu 0x70($inp), @XMM[7] + mov $key, %rax # pass the $key + lea 0x80($inp), $inp + mov \$10,%r10d + + call _bsaes_decrypt8 + + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[6], 0x20($out) + movdqu @XMM[4], 0x30($out) + movdqu @XMM[2], 0x40($out) + movdqu @XMM[7], 0x50($out) + movdqu @XMM[3], 0x60($out) + movdqu @XMM[5], 0x70($out) + lea 0x80($out), $out + sub \$0x80,$len + ja .Ldec128_loop + ret +.size bsaes_decrypt_128,.-bsaes_decrypt_128 +___ +} +{ +###################################################################### +# +# OpenSSL interface +# +my ($arg1,$arg2,$arg3,$arg4,$arg5,$arg6)=$win64 ? ("%rcx","%rdx","%r8","%r9","%r10","%r11d") + : ("%rdi","%rsi","%rdx","%rcx","%r8","%r9d"); +my ($inp,$out,$len,$key)=("%r12","%r13","%r14","%r15"); + +if ($ecb) { +$code.=<<___; +.globl bsaes_ecb_encrypt_blocks +.type bsaes_ecb_encrypt_blocks,\@abi-omnipotent +.align 16 +bsaes_ecb_encrypt_blocks: + mov %rsp, %rax +.Lecb_enc_prologue: + push %rbp + push %rbx + push %r12 + push %r13 + push %r14 + push %r15 + lea -0x48(%rsp),%rsp +___ +$code.=<<___ if ($win64); + lea -0xa0(%rsp), %rsp + movaps %xmm6, 0x40(%rsp) + movaps %xmm7, 0x50(%rsp) + movaps %xmm8, 0x60(%rsp) + movaps %xmm9, 0x70(%rsp) + movaps %xmm10, 0x80(%rsp) + movaps %xmm11, 0x90(%rsp) + movaps %xmm12, 0xa0(%rsp) + movaps %xmm13, 0xb0(%rsp) + movaps %xmm14, 0xc0(%rsp) + movaps %xmm15, 0xd0(%rsp) +.Lecb_enc_body: +___ +$code.=<<___; + mov %rsp,%rbp # backup %rsp + mov 240($arg4),%eax # rounds + mov $arg1,$inp # backup arguments + mov $arg2,$out + mov $arg3,$len + mov $arg4,$key + cmp \$8,$arg3 + jb .Lecb_enc_short + + mov %eax,%ebx # backup rounds + shl \$7,%rax # 128 bytes per inner round key + sub \$`128-32`,%rax # size of bit-sliced key schedule + sub %rax,%rsp + mov %rsp,%rax # pass key schedule + mov $key,%rcx # pass key + mov %ebx,%r10d # pass rounds + call _bsaes_key_convert + pxor %xmm6,%xmm7 # fix up last round key + movdqa %xmm7,(%rax) # save last round key + + sub \$8,$len +.Lecb_enc_loop: + movdqu 0x00($inp), @XMM[0] # load input + movdqu 0x10($inp), @XMM[1] + movdqu 0x20($inp), @XMM[2] + movdqu 0x30($inp), @XMM[3] + movdqu 0x40($inp), @XMM[4] + movdqu 0x50($inp), @XMM[5] + mov %rsp, %rax # pass key schedule + movdqu 0x60($inp), @XMM[6] + mov %ebx,%r10d # pass rounds + movdqu 0x70($inp), @XMM[7] + lea 0x80($inp), $inp + + call _bsaes_encrypt8 + + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[4], 0x20($out) + movdqu @XMM[6], 0x30($out) + movdqu @XMM[3], 0x40($out) + movdqu @XMM[7], 0x50($out) + movdqu @XMM[2], 0x60($out) + movdqu @XMM[5], 0x70($out) + lea 0x80($out), $out + sub \$8,$len + jnc .Lecb_enc_loop + + add \$8,$len + jz .Lecb_enc_done + + movdqu 0x00($inp), @XMM[0] # load input + mov %rsp, %rax # pass key schedule + mov %ebx,%r10d # pass rounds + cmp \$2,$len + jb .Lecb_enc_one + movdqu 0x10($inp), @XMM[1] + je .Lecb_enc_two + movdqu 0x20($inp), @XMM[2] + cmp \$4,$len + jb .Lecb_enc_three + movdqu 0x30($inp), @XMM[3] + je .Lecb_enc_four + movdqu 0x40($inp), @XMM[4] + cmp \$6,$len + jb .Lecb_enc_five + movdqu 0x50($inp), @XMM[5] + je .Lecb_enc_six + movdqu 0x60($inp), @XMM[6] + call _bsaes_encrypt8 + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[4], 0x20($out) + movdqu @XMM[6], 0x30($out) + movdqu @XMM[3], 0x40($out) + movdqu @XMM[7], 0x50($out) + movdqu @XMM[2], 0x60($out) + jmp .Lecb_enc_done +.align 16 +.Lecb_enc_six: + call _bsaes_encrypt8 + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[4], 0x20($out) + movdqu @XMM[6], 0x30($out) + movdqu @XMM[3], 0x40($out) + movdqu @XMM[7], 0x50($out) + jmp .Lecb_enc_done +.align 16 +.Lecb_enc_five: + call _bsaes_encrypt8 + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[4], 0x20($out) + movdqu @XMM[6], 0x30($out) + movdqu @XMM[3], 0x40($out) + jmp .Lecb_enc_done +.align 16 +.Lecb_enc_four: + call _bsaes_encrypt8 + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[4], 0x20($out) + movdqu @XMM[6], 0x30($out) + jmp .Lecb_enc_done +.align 16 +.Lecb_enc_three: + call _bsaes_encrypt8 + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[4], 0x20($out) + jmp .Lecb_enc_done +.align 16 +.Lecb_enc_two: + call _bsaes_encrypt8 + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + jmp .Lecb_enc_done +.align 16 +.Lecb_enc_one: + call _bsaes_encrypt8 + movdqu @XMM[0], 0x00($out) # write output + jmp .Lecb_enc_done +.align 16 +.Lecb_enc_short: + lea ($inp), $arg1 + lea ($out), $arg2 + lea ($key), $arg3 + call asm_AES_encrypt + lea 16($inp), $inp + lea 16($out), $out + dec $len + jnz .Lecb_enc_short + +.Lecb_enc_done: + lea (%rsp),%rax + pxor %xmm0, %xmm0 +.Lecb_enc_bzero: # wipe key schedule [if any] + movdqa %xmm0, 0x00(%rax) + movdqa %xmm0, 0x10(%rax) + lea 0x20(%rax), %rax + cmp %rax, %rbp + jb .Lecb_enc_bzero + + lea (%rbp),%rsp # restore %rsp +___ +$code.=<<___ if ($win64); + movaps 0x40(%rbp), %xmm6 + movaps 0x50(%rbp), %xmm7 + movaps 0x60(%rbp), %xmm8 + movaps 0x70(%rbp), %xmm9 + movaps 0x80(%rbp), %xmm10 + movaps 0x90(%rbp), %xmm11 + movaps 0xa0(%rbp), %xmm12 + movaps 0xb0(%rbp), %xmm13 + movaps 0xc0(%rbp), %xmm14 + movaps 0xd0(%rbp), %xmm15 + lea 0xa0(%rbp), %rsp +___ +$code.=<<___; + mov 0x48(%rsp), %r15 + mov 0x50(%rsp), %r14 + mov 0x58(%rsp), %r13 + mov 0x60(%rsp), %r12 + mov 0x68(%rsp), %rbx + mov 0x70(%rsp), %rax + lea 0x78(%rsp), %rsp + mov %rax, %rbp +.Lecb_enc_epilogue: + ret +.size bsaes_ecb_encrypt_blocks,.-bsaes_ecb_encrypt_blocks + +.globl bsaes_ecb_decrypt_blocks +.type bsaes_ecb_decrypt_blocks,\@abi-omnipotent +.align 16 +bsaes_ecb_decrypt_blocks: + mov %rsp, %rax +.Lecb_dec_prologue: + push %rbp + push %rbx + push %r12 + push %r13 + push %r14 + push %r15 + lea -0x48(%rsp),%rsp +___ +$code.=<<___ if ($win64); + lea -0xa0(%rsp), %rsp + movaps %xmm6, 0x40(%rsp) + movaps %xmm7, 0x50(%rsp) + movaps %xmm8, 0x60(%rsp) + movaps %xmm9, 0x70(%rsp) + movaps %xmm10, 0x80(%rsp) + movaps %xmm11, 0x90(%rsp) + movaps %xmm12, 0xa0(%rsp) + movaps %xmm13, 0xb0(%rsp) + movaps %xmm14, 0xc0(%rsp) + movaps %xmm15, 0xd0(%rsp) +.Lecb_dec_body: +___ +$code.=<<___; + mov %rsp,%rbp # backup %rsp + mov 240($arg4),%eax # rounds + mov $arg1,$inp # backup arguments + mov $arg2,$out + mov $arg3,$len + mov $arg4,$key + cmp \$8,$arg3 + jb .Lecb_dec_short + + mov %eax,%ebx # backup rounds + shl \$7,%rax # 128 bytes per inner round key + sub \$`128-32`,%rax # size of bit-sliced key schedule + sub %rax,%rsp + mov %rsp,%rax # pass key schedule + mov $key,%rcx # pass key + mov %ebx,%r10d # pass rounds + call _bsaes_key_convert + pxor (%rsp),%xmm7 # fix up 0 round key + movdqa %xmm6,(%rax) # save last round key + movdqa %xmm7,(%rsp) + + sub \$8,$len +.Lecb_dec_loop: + movdqu 0x00($inp), @XMM[0] # load input + movdqu 0x10($inp), @XMM[1] + movdqu 0x20($inp), @XMM[2] + movdqu 0x30($inp), @XMM[3] + movdqu 0x40($inp), @XMM[4] + movdqu 0x50($inp), @XMM[5] + mov %rsp, %rax # pass key schedule + movdqu 0x60($inp), @XMM[6] + mov %ebx,%r10d # pass rounds + movdqu 0x70($inp), @XMM[7] + lea 0x80($inp), $inp + + call _bsaes_decrypt8 + + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[6], 0x20($out) + movdqu @XMM[4], 0x30($out) + movdqu @XMM[2], 0x40($out) + movdqu @XMM[7], 0x50($out) + movdqu @XMM[3], 0x60($out) + movdqu @XMM[5], 0x70($out) + lea 0x80($out), $out + sub \$8,$len + jnc .Lecb_dec_loop + + add \$8,$len + jz .Lecb_dec_done + + movdqu 0x00($inp), @XMM[0] # load input + mov %rsp, %rax # pass key schedule + mov %ebx,%r10d # pass rounds + cmp \$2,$len + jb .Lecb_dec_one + movdqu 0x10($inp), @XMM[1] + je .Lecb_dec_two + movdqu 0x20($inp), @XMM[2] + cmp \$4,$len + jb .Lecb_dec_three + movdqu 0x30($inp), @XMM[3] + je .Lecb_dec_four + movdqu 0x40($inp), @XMM[4] + cmp \$6,$len + jb .Lecb_dec_five + movdqu 0x50($inp), @XMM[5] + je .Lecb_dec_six + movdqu 0x60($inp), @XMM[6] + call _bsaes_decrypt8 + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[6], 0x20($out) + movdqu @XMM[4], 0x30($out) + movdqu @XMM[2], 0x40($out) + movdqu @XMM[7], 0x50($out) + movdqu @XMM[3], 0x60($out) + jmp .Lecb_dec_done +.align 16 +.Lecb_dec_six: + call _bsaes_decrypt8 + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[6], 0x20($out) + movdqu @XMM[4], 0x30($out) + movdqu @XMM[2], 0x40($out) + movdqu @XMM[7], 0x50($out) + jmp .Lecb_dec_done +.align 16 +.Lecb_dec_five: + call _bsaes_decrypt8 + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[6], 0x20($out) + movdqu @XMM[4], 0x30($out) + movdqu @XMM[2], 0x40($out) + jmp .Lecb_dec_done +.align 16 +.Lecb_dec_four: + call _bsaes_decrypt8 + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[6], 0x20($out) + movdqu @XMM[4], 0x30($out) + jmp .Lecb_dec_done +.align 16 +.Lecb_dec_three: + call _bsaes_decrypt8 + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[6], 0x20($out) + jmp .Lecb_dec_done +.align 16 +.Lecb_dec_two: + call _bsaes_decrypt8 + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + jmp .Lecb_dec_done +.align 16 +.Lecb_dec_one: + call _bsaes_decrypt8 + movdqu @XMM[0], 0x00($out) # write output + jmp .Lecb_dec_done +.align 16 +.Lecb_dec_short: + lea ($inp), $arg1 + lea ($out), $arg2 + lea ($key), $arg3 + call asm_AES_decrypt + lea 16($inp), $inp + lea 16($out), $out + dec $len + jnz .Lecb_dec_short + +.Lecb_dec_done: + lea (%rsp),%rax + pxor %xmm0, %xmm0 +.Lecb_dec_bzero: # wipe key schedule [if any] + movdqa %xmm0, 0x00(%rax) + movdqa %xmm0, 0x10(%rax) + lea 0x20(%rax), %rax + cmp %rax, %rbp + jb .Lecb_dec_bzero + + lea (%rbp),%rsp # restore %rsp +___ +$code.=<<___ if ($win64); + movaps 0x40(%rbp), %xmm6 + movaps 0x50(%rbp), %xmm7 + movaps 0x60(%rbp), %xmm8 + movaps 0x70(%rbp), %xmm9 + movaps 0x80(%rbp), %xmm10 + movaps 0x90(%rbp), %xmm11 + movaps 0xa0(%rbp), %xmm12 + movaps 0xb0(%rbp), %xmm13 + movaps 0xc0(%rbp), %xmm14 + movaps 0xd0(%rbp), %xmm15 + lea 0xa0(%rbp), %rsp +___ +$code.=<<___; + mov 0x48(%rsp), %r15 + mov 0x50(%rsp), %r14 + mov 0x58(%rsp), %r13 + mov 0x60(%rsp), %r12 + mov 0x68(%rsp), %rbx + mov 0x70(%rsp), %rax + lea 0x78(%rsp), %rsp + mov %rax, %rbp +.Lecb_dec_epilogue: + ret +.size bsaes_ecb_decrypt_blocks,.-bsaes_ecb_decrypt_blocks +___ +} +$code.=<<___; +.extern asm_AES_cbc_encrypt +.globl bsaes_cbc_encrypt +.type bsaes_cbc_encrypt,\@abi-omnipotent +.align 16 +bsaes_cbc_encrypt: +___ +$code.=<<___ if ($win64); + mov 48(%rsp),$arg6 # pull direction flag +___ +$code.=<<___; + cmp \$0,$arg6 + jne asm_AES_cbc_encrypt + cmp \$128,$arg3 + jb asm_AES_cbc_encrypt + + mov %rsp, %rax +.Lcbc_dec_prologue: + push %rbp + push %rbx + push %r12 + push %r13 + push %r14 + push %r15 + lea -0x48(%rsp), %rsp +___ +$code.=<<___ if ($win64); + mov 0xa0(%rsp),$arg5 # pull ivp + lea -0xa0(%rsp), %rsp + movaps %xmm6, 0x40(%rsp) + movaps %xmm7, 0x50(%rsp) + movaps %xmm8, 0x60(%rsp) + movaps %xmm9, 0x70(%rsp) + movaps %xmm10, 0x80(%rsp) + movaps %xmm11, 0x90(%rsp) + movaps %xmm12, 0xa0(%rsp) + movaps %xmm13, 0xb0(%rsp) + movaps %xmm14, 0xc0(%rsp) + movaps %xmm15, 0xd0(%rsp) +.Lcbc_dec_body: +___ +$code.=<<___; + mov %rsp, %rbp # backup %rsp + mov 240($arg4), %eax # rounds + mov $arg1, $inp # backup arguments + mov $arg2, $out + mov $arg3, $len + mov $arg4, $key + mov $arg5, %rbx + shr \$4, $len # bytes to blocks + + mov %eax, %edx # rounds + shl \$7, %rax # 128 bytes per inner round key + sub \$`128-32`, %rax # size of bit-sliced key schedule + sub %rax, %rsp + + mov %rsp, %rax # pass key schedule + mov $key, %rcx # pass key + mov %edx, %r10d # pass rounds + call _bsaes_key_convert + pxor (%rsp),%xmm7 # fix up 0 round key + movdqa %xmm6,(%rax) # save last round key + movdqa %xmm7,(%rsp) + + movdqu (%rbx), @XMM[15] # load IV + sub \$8,$len +.Lcbc_dec_loop: + movdqu 0x00($inp), @XMM[0] # load input + movdqu 0x10($inp), @XMM[1] + movdqu 0x20($inp), @XMM[2] + movdqu 0x30($inp), @XMM[3] + movdqu 0x40($inp), @XMM[4] + movdqu 0x50($inp), @XMM[5] + mov %rsp, %rax # pass key schedule + movdqu 0x60($inp), @XMM[6] + mov %edx,%r10d # pass rounds + movdqu 0x70($inp), @XMM[7] + movdqa @XMM[15], 0x20(%rbp) # put aside IV + + call _bsaes_decrypt8 + + pxor 0x20(%rbp), @XMM[0] # ^= IV + movdqu 0x00($inp), @XMM[8] # re-load input + movdqu 0x10($inp), @XMM[9] + pxor @XMM[8], @XMM[1] + movdqu 0x20($inp), @XMM[10] + pxor @XMM[9], @XMM[6] + movdqu 0x30($inp), @XMM[11] + pxor @XMM[10], @XMM[4] + movdqu 0x40($inp), @XMM[12] + pxor @XMM[11], @XMM[2] + movdqu 0x50($inp), @XMM[13] + pxor @XMM[12], @XMM[7] + movdqu 0x60($inp), @XMM[14] + pxor @XMM[13], @XMM[3] + movdqu 0x70($inp), @XMM[15] # IV + pxor @XMM[14], @XMM[5] + movdqu @XMM[0], 0x00($out) # write output + lea 0x80($inp), $inp + movdqu @XMM[1], 0x10($out) + movdqu @XMM[6], 0x20($out) + movdqu @XMM[4], 0x30($out) + movdqu @XMM[2], 0x40($out) + movdqu @XMM[7], 0x50($out) + movdqu @XMM[3], 0x60($out) + movdqu @XMM[5], 0x70($out) + lea 0x80($out), $out + sub \$8,$len + jnc .Lcbc_dec_loop + + add \$8,$len + jz .Lcbc_dec_done + + movdqu 0x00($inp), @XMM[0] # load input + mov %rsp, %rax # pass key schedule + mov %edx, %r10d # pass rounds + cmp \$2,$len + jb .Lcbc_dec_one + movdqu 0x10($inp), @XMM[1] + je .Lcbc_dec_two + movdqu 0x20($inp), @XMM[2] + cmp \$4,$len + jb .Lcbc_dec_three + movdqu 0x30($inp), @XMM[3] + je .Lcbc_dec_four + movdqu 0x40($inp), @XMM[4] + cmp \$6,$len + jb .Lcbc_dec_five + movdqu 0x50($inp), @XMM[5] + je .Lcbc_dec_six + movdqu 0x60($inp), @XMM[6] + movdqa @XMM[15], 0x20(%rbp) # put aside IV + call _bsaes_decrypt8 + pxor 0x20(%rbp), @XMM[0] # ^= IV + movdqu 0x00($inp), @XMM[8] # re-load input + movdqu 0x10($inp), @XMM[9] + pxor @XMM[8], @XMM[1] + movdqu 0x20($inp), @XMM[10] + pxor @XMM[9], @XMM[6] + movdqu 0x30($inp), @XMM[11] + pxor @XMM[10], @XMM[4] + movdqu 0x40($inp), @XMM[12] + pxor @XMM[11], @XMM[2] + movdqu 0x50($inp), @XMM[13] + pxor @XMM[12], @XMM[7] + movdqu 0x60($inp), @XMM[15] # IV + pxor @XMM[13], @XMM[3] + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[6], 0x20($out) + movdqu @XMM[4], 0x30($out) + movdqu @XMM[2], 0x40($out) + movdqu @XMM[7], 0x50($out) + movdqu @XMM[3], 0x60($out) + jmp .Lcbc_dec_done +.align 16 +.Lcbc_dec_six: + movdqa @XMM[15], 0x20(%rbp) # put aside IV + call _bsaes_decrypt8 + pxor 0x20(%rbp), @XMM[0] # ^= IV + movdqu 0x00($inp), @XMM[8] # re-load input + movdqu 0x10($inp), @XMM[9] + pxor @XMM[8], @XMM[1] + movdqu 0x20($inp), @XMM[10] + pxor @XMM[9], @XMM[6] + movdqu 0x30($inp), @XMM[11] + pxor @XMM[10], @XMM[4] + movdqu 0x40($inp), @XMM[12] + pxor @XMM[11], @XMM[2] + movdqu 0x50($inp), @XMM[15] # IV + pxor @XMM[12], @XMM[7] + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[6], 0x20($out) + movdqu @XMM[4], 0x30($out) + movdqu @XMM[2], 0x40($out) + movdqu @XMM[7], 0x50($out) + jmp .Lcbc_dec_done +.align 16 +.Lcbc_dec_five: + movdqa @XMM[15], 0x20(%rbp) # put aside IV + call _bsaes_decrypt8 + pxor 0x20(%rbp), @XMM[0] # ^= IV + movdqu 0x00($inp), @XMM[8] # re-load input + movdqu 0x10($inp), @XMM[9] + pxor @XMM[8], @XMM[1] + movdqu 0x20($inp), @XMM[10] + pxor @XMM[9], @XMM[6] + movdqu 0x30($inp), @XMM[11] + pxor @XMM[10], @XMM[4] + movdqu 0x40($inp), @XMM[15] # IV + pxor @XMM[11], @XMM[2] + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[6], 0x20($out) + movdqu @XMM[4], 0x30($out) + movdqu @XMM[2], 0x40($out) + jmp .Lcbc_dec_done +.align 16 +.Lcbc_dec_four: + movdqa @XMM[15], 0x20(%rbp) # put aside IV + call _bsaes_decrypt8 + pxor 0x20(%rbp), @XMM[0] # ^= IV + movdqu 0x00($inp), @XMM[8] # re-load input + movdqu 0x10($inp), @XMM[9] + pxor @XMM[8], @XMM[1] + movdqu 0x20($inp), @XMM[10] + pxor @XMM[9], @XMM[6] + movdqu 0x30($inp), @XMM[15] # IV + pxor @XMM[10], @XMM[4] + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[6], 0x20($out) + movdqu @XMM[4], 0x30($out) + jmp .Lcbc_dec_done +.align 16 +.Lcbc_dec_three: + movdqa @XMM[15], 0x20(%rbp) # put aside IV + call _bsaes_decrypt8 + pxor 0x20(%rbp), @XMM[0] # ^= IV + movdqu 0x00($inp), @XMM[8] # re-load input + movdqu 0x10($inp), @XMM[9] + pxor @XMM[8], @XMM[1] + movdqu 0x20($inp), @XMM[15] # IV + pxor @XMM[9], @XMM[6] + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[6], 0x20($out) + jmp .Lcbc_dec_done +.align 16 +.Lcbc_dec_two: + movdqa @XMM[15], 0x20(%rbp) # put aside IV + call _bsaes_decrypt8 + pxor 0x20(%rbp), @XMM[0] # ^= IV + movdqu 0x00($inp), @XMM[8] # re-load input + movdqu 0x10($inp), @XMM[15] # IV + pxor @XMM[8], @XMM[1] + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + jmp .Lcbc_dec_done +.align 16 +.Lcbc_dec_one: + lea ($inp), $arg1 + lea 0x20(%rbp), $arg2 # buffer output + lea ($key), $arg3 + call asm_AES_decrypt # doesn't touch %xmm + pxor 0x20(%rbp), @XMM[15] # ^= IV + movdqu @XMM[15], ($out) # write output + movdqa @XMM[0], @XMM[15] # IV + +.Lcbc_dec_done: + movdqu @XMM[15], (%rbx) # return IV + lea (%rsp), %rax + pxor %xmm0, %xmm0 +.Lcbc_dec_bzero: # wipe key schedule [if any] + movdqa %xmm0, 0x00(%rax) + movdqa %xmm0, 0x10(%rax) + lea 0x20(%rax), %rax + cmp %rax, %rbp + ja .Lcbc_dec_bzero + + lea (%rbp),%rsp # restore %rsp +___ +$code.=<<___ if ($win64); + movaps 0x40(%rbp), %xmm6 + movaps 0x50(%rbp), %xmm7 + movaps 0x60(%rbp), %xmm8 + movaps 0x70(%rbp), %xmm9 + movaps 0x80(%rbp), %xmm10 + movaps 0x90(%rbp), %xmm11 + movaps 0xa0(%rbp), %xmm12 + movaps 0xb0(%rbp), %xmm13 + movaps 0xc0(%rbp), %xmm14 + movaps 0xd0(%rbp), %xmm15 + lea 0xa0(%rbp), %rsp +___ +$code.=<<___; + mov 0x48(%rsp), %r15 + mov 0x50(%rsp), %r14 + mov 0x58(%rsp), %r13 + mov 0x60(%rsp), %r12 + mov 0x68(%rsp), %rbx + mov 0x70(%rsp), %rax + lea 0x78(%rsp), %rsp + mov %rax, %rbp +.Lcbc_dec_epilogue: + ret +.size bsaes_cbc_encrypt,.-bsaes_cbc_encrypt + +.globl bsaes_ctr32_encrypt_blocks +.type bsaes_ctr32_encrypt_blocks,\@abi-omnipotent +.align 16 +bsaes_ctr32_encrypt_blocks: + mov %rsp, %rax +.Lctr_enc_prologue: + push %rbp + push %rbx + push %r12 + push %r13 + push %r14 + push %r15 + lea -0x48(%rsp), %rsp +___ +$code.=<<___ if ($win64); + mov 0xa0(%rsp),$arg5 # pull ivp + lea -0xa0(%rsp), %rsp + movaps %xmm6, 0x40(%rsp) + movaps %xmm7, 0x50(%rsp) + movaps %xmm8, 0x60(%rsp) + movaps %xmm9, 0x70(%rsp) + movaps %xmm10, 0x80(%rsp) + movaps %xmm11, 0x90(%rsp) + movaps %xmm12, 0xa0(%rsp) + movaps %xmm13, 0xb0(%rsp) + movaps %xmm14, 0xc0(%rsp) + movaps %xmm15, 0xd0(%rsp) +.Lctr_enc_body: +___ +$code.=<<___; + mov %rsp, %rbp # backup %rsp + movdqu ($arg5), %xmm0 # load counter + mov 240($arg4), %eax # rounds + mov $arg1, $inp # backup arguments + mov $arg2, $out + mov $arg3, $len + mov $arg4, $key + movdqa %xmm0, 0x20(%rbp) # copy counter + cmp \$8, $arg3 + jb .Lctr_enc_short + + mov %eax, %ebx # rounds + shl \$7, %rax # 128 bytes per inner round key + sub \$`128-32`, %rax # size of bit-sliced key schedule + sub %rax, %rsp + + mov %rsp, %rax # pass key schedule + mov $key, %rcx # pass key + mov %ebx, %r10d # pass rounds + call _bsaes_key_convert + pxor %xmm6,%xmm7 # fix up last round key + movdqa %xmm7,(%rax) # save last round key + + movdqa (%rsp), @XMM[9] # load round0 key + lea .LADD1(%rip), %r11 + movdqa 0x20(%rbp), @XMM[0] # counter copy + movdqa -0x20(%r11), @XMM[8] # .LSWPUP + pshufb @XMM[8], @XMM[9] # byte swap upper part + pshufb @XMM[8], @XMM[0] + movdqa @XMM[9], (%rsp) # save adjusted round0 key + jmp .Lctr_enc_loop +.align 16 +.Lctr_enc_loop: + movdqa @XMM[0], 0x20(%rbp) # save counter + movdqa @XMM[0], @XMM[1] # prepare 8 counter values + movdqa @XMM[0], @XMM[2] + paddd 0x00(%r11), @XMM[1] # .LADD1 + movdqa @XMM[0], @XMM[3] + paddd 0x10(%r11), @XMM[2] # .LADD2 + movdqa @XMM[0], @XMM[4] + paddd 0x20(%r11), @XMM[3] # .LADD3 + movdqa @XMM[0], @XMM[5] + paddd 0x30(%r11), @XMM[4] # .LADD4 + movdqa @XMM[0], @XMM[6] + paddd 0x40(%r11), @XMM[5] # .LADD5 + movdqa @XMM[0], @XMM[7] + paddd 0x50(%r11), @XMM[6] # .LADD6 + paddd 0x60(%r11), @XMM[7] # .LADD7 + + # Borrow prologue from _bsaes_encrypt8 to use the opportunity + # to flip byte order in 32-bit counter + movdqa (%rsp), @XMM[9] # round 0 key + lea 0x10(%rsp), %rax # pass key schedule + movdqa -0x10(%r11), @XMM[8] # .LSWPUPM0SR + pxor @XMM[9], @XMM[0] # xor with round0 key + pxor @XMM[9], @XMM[1] + pxor @XMM[9], @XMM[2] + pxor @XMM[9], @XMM[3] + pshufb @XMM[8], @XMM[0] + pshufb @XMM[8], @XMM[1] + pxor @XMM[9], @XMM[4] + pxor @XMM[9], @XMM[5] + pshufb @XMM[8], @XMM[2] + pshufb @XMM[8], @XMM[3] + pxor @XMM[9], @XMM[6] + pxor @XMM[9], @XMM[7] + pshufb @XMM[8], @XMM[4] + pshufb @XMM[8], @XMM[5] + pshufb @XMM[8], @XMM[6] + pshufb @XMM[8], @XMM[7] + lea .LBS0(%rip), %r11 # constants table + mov %ebx,%r10d # pass rounds + + call _bsaes_encrypt8_bitslice + + sub \$8,$len + jc .Lctr_enc_loop_done + + movdqu 0x00($inp), @XMM[8] # load input + movdqu 0x10($inp), @XMM[9] + movdqu 0x20($inp), @XMM[10] + movdqu 0x30($inp), @XMM[11] + movdqu 0x40($inp), @XMM[12] + movdqu 0x50($inp), @XMM[13] + movdqu 0x60($inp), @XMM[14] + movdqu 0x70($inp), @XMM[15] + lea 0x80($inp),$inp + pxor @XMM[0], @XMM[8] + movdqa 0x20(%rbp), @XMM[0] # load counter + pxor @XMM[9], @XMM[1] + movdqu @XMM[8], 0x00($out) # write output + pxor @XMM[10], @XMM[4] + movdqu @XMM[1], 0x10($out) + pxor @XMM[11], @XMM[6] + movdqu @XMM[4], 0x20($out) + pxor @XMM[12], @XMM[3] + movdqu @XMM[6], 0x30($out) + pxor @XMM[13], @XMM[7] + movdqu @XMM[3], 0x40($out) + pxor @XMM[14], @XMM[2] + movdqu @XMM[7], 0x50($out) + pxor @XMM[15], @XMM[5] + movdqu @XMM[2], 0x60($out) + lea .LADD1(%rip), %r11 + movdqu @XMM[5], 0x70($out) + lea 0x80($out), $out + paddd 0x70(%r11), @XMM[0] # .LADD8 + jnz .Lctr_enc_loop + + jmp .Lctr_enc_done +.align 16 +.Lctr_enc_loop_done: + add \$8, $len + movdqu 0x00($inp), @XMM[8] # load input + pxor @XMM[8], @XMM[0] + movdqu @XMM[0], 0x00($out) # write output + cmp \$2,$len + jb .Lctr_enc_done + movdqu 0x10($inp), @XMM[9] + pxor @XMM[9], @XMM[1] + movdqu @XMM[1], 0x10($out) + je .Lctr_enc_done + movdqu 0x20($inp), @XMM[10] + pxor @XMM[10], @XMM[4] + movdqu @XMM[4], 0x20($out) + cmp \$4,$len + jb .Lctr_enc_done + movdqu 0x30($inp), @XMM[11] + pxor @XMM[11], @XMM[6] + movdqu @XMM[6], 0x30($out) + je .Lctr_enc_done + movdqu 0x40($inp), @XMM[12] + pxor @XMM[12], @XMM[3] + movdqu @XMM[3], 0x40($out) + cmp \$6,$len + jb .Lctr_enc_done + movdqu 0x50($inp), @XMM[13] + pxor @XMM[13], @XMM[7] + movdqu @XMM[7], 0x50($out) + je .Lctr_enc_done + movdqu 0x60($inp), @XMM[14] + pxor @XMM[14], @XMM[2] + movdqu @XMM[2], 0x60($out) + jmp .Lctr_enc_done + +.align 16 +.Lctr_enc_short: + lea 0x20(%rbp), $arg1 + lea 0x30(%rbp), $arg2 + lea ($key), $arg3 + call asm_AES_encrypt + movdqu ($inp), @XMM[1] + lea 16($inp), $inp + mov 0x2c(%rbp), %eax # load 32-bit counter + bswap %eax + pxor 0x30(%rbp), @XMM[1] + inc %eax # increment + movdqu @XMM[1], ($out) + bswap %eax + lea 16($out), $out + mov %eax, 0x2c(%rsp) # save 32-bit counter + dec $len + jnz .Lctr_enc_short + +.Lctr_enc_done: + lea (%rsp), %rax + pxor %xmm0, %xmm0 +.Lctr_enc_bzero: # wipe key schedule [if any] + movdqa %xmm0, 0x00(%rax) + movdqa %xmm0, 0x10(%rax) + lea 0x20(%rax), %rax + cmp %rax, %rbp + ja .Lctr_enc_bzero + + lea (%rbp),%rsp # restore %rsp +___ +$code.=<<___ if ($win64); + movaps 0x40(%rbp), %xmm6 + movaps 0x50(%rbp), %xmm7 + movaps 0x60(%rbp), %xmm8 + movaps 0x70(%rbp), %xmm9 + movaps 0x80(%rbp), %xmm10 + movaps 0x90(%rbp), %xmm11 + movaps 0xa0(%rbp), %xmm12 + movaps 0xb0(%rbp), %xmm13 + movaps 0xc0(%rbp), %xmm14 + movaps 0xd0(%rbp), %xmm15 + lea 0xa0(%rbp), %rsp +___ +$code.=<<___; + mov 0x48(%rsp), %r15 + mov 0x50(%rsp), %r14 + mov 0x58(%rsp), %r13 + mov 0x60(%rsp), %r12 + mov 0x68(%rsp), %rbx + mov 0x70(%rsp), %rax + lea 0x78(%rsp), %rsp + mov %rax, %rbp +.Lctr_enc_epilogue: + ret +.size bsaes_ctr32_encrypt_blocks,.-bsaes_ctr32_encrypt_blocks +___ +###################################################################### +# void bsaes_xts_[en|de]crypt(const char *inp,char *out,size_t len, +# const AES_KEY *key1, const AES_KEY *key2, +# const unsigned char iv[16]); +# +my ($twmask,$twres,$twtmp)=@XMM[13..15]; +$arg6=~s/d$//; + +$code.=<<___; +.globl bsaes_xts_encrypt +.type bsaes_xts_encrypt,\@abi-omnipotent +.align 16 +bsaes_xts_encrypt: + mov %rsp, %rax +.Lxts_enc_prologue: + push %rbp + push %rbx + push %r12 + push %r13 + push %r14 + push %r15 + lea -0x48(%rsp), %rsp +___ +$code.=<<___ if ($win64); + mov 0xa0(%rsp),$arg5 # pull key2 + mov 0xa8(%rsp),$arg6 # pull ivp + lea -0xa0(%rsp), %rsp + movaps %xmm6, 0x40(%rsp) + movaps %xmm7, 0x50(%rsp) + movaps %xmm8, 0x60(%rsp) + movaps %xmm9, 0x70(%rsp) + movaps %xmm10, 0x80(%rsp) + movaps %xmm11, 0x90(%rsp) + movaps %xmm12, 0xa0(%rsp) + movaps %xmm13, 0xb0(%rsp) + movaps %xmm14, 0xc0(%rsp) + movaps %xmm15, 0xd0(%rsp) +.Lxts_enc_body: +___ +$code.=<<___; + mov %rsp, %rbp # backup %rsp + mov $arg1, $inp # backup arguments + mov $arg2, $out + mov $arg3, $len + mov $arg4, $key + + lea ($arg6), $arg1 + lea 0x20(%rbp), $arg2 + lea ($arg5), $arg3 + call asm_AES_encrypt # generate initial tweak + + mov 240($key), %eax # rounds + mov $len, %rbx # backup $len + + mov %eax, %edx # rounds + shl \$7, %rax # 128 bytes per inner round key + sub \$`128-32`, %rax # size of bit-sliced key schedule + sub %rax, %rsp + + mov %rsp, %rax # pass key schedule + mov $key, %rcx # pass key + mov %edx, %r10d # pass rounds + call _bsaes_key_convert + pxor %xmm6, %xmm7 # fix up last round key + movdqa %xmm7, (%rax) # save last round key + + and \$-16, $len + sub \$0x80, %rsp # place for tweak[8] + movdqa 0x20(%rbp), @XMM[7] # initial tweak + + pxor $twtmp, $twtmp + movdqa .Lxts_magic(%rip), $twmask + pcmpgtd @XMM[7], $twtmp # broadcast upper bits + + sub \$0x80, $len + jc .Lxts_enc_short + jmp .Lxts_enc_loop + +.align 16 +.Lxts_enc_loop: +___ + for ($i=0;$i<7;$i++) { + $code.=<<___; + pshufd \$0x13, $twtmp, $twres + pxor $twtmp, $twtmp + movdqa @XMM[7], @XMM[$i] + movdqa @XMM[7], `0x10*$i`(%rsp)# save tweak[$i] + paddq @XMM[7], @XMM[7] # psllq 1,$tweak + pand $twmask, $twres # isolate carry and residue + pcmpgtd @XMM[7], $twtmp # broadcast upper bits + pxor $twres, @XMM[7] +___ + $code.=<<___ if ($i>=1); + movdqu `0x10*($i-1)`($inp), @XMM[8+$i-1] +___ + $code.=<<___ if ($i>=2); + pxor @XMM[8+$i-2], @XMM[$i-2]# input[] ^ tweak[] +___ + } +$code.=<<___; + movdqu 0x60($inp), @XMM[8+6] + pxor @XMM[8+5], @XMM[5] + movdqu 0x70($inp), @XMM[8+7] + lea 0x80($inp), $inp + movdqa @XMM[7], 0x70(%rsp) + pxor @XMM[8+6], @XMM[6] + lea 0x80(%rsp), %rax # pass key schedule + pxor @XMM[8+7], @XMM[7] + mov %edx, %r10d # pass rounds + + call _bsaes_encrypt8 + + pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + pxor 0x10(%rsp), @XMM[1] + movdqu @XMM[0], 0x00($out) # write output + pxor 0x20(%rsp), @XMM[4] + movdqu @XMM[1], 0x10($out) + pxor 0x30(%rsp), @XMM[6] + movdqu @XMM[4], 0x20($out) + pxor 0x40(%rsp), @XMM[3] + movdqu @XMM[6], 0x30($out) + pxor 0x50(%rsp), @XMM[7] + movdqu @XMM[3], 0x40($out) + pxor 0x60(%rsp), @XMM[2] + movdqu @XMM[7], 0x50($out) + pxor 0x70(%rsp), @XMM[5] + movdqu @XMM[2], 0x60($out) + movdqu @XMM[5], 0x70($out) + lea 0x80($out), $out + + movdqa 0x70(%rsp), @XMM[7] # prepare next iteration tweak + pxor $twtmp, $twtmp + movdqa .Lxts_magic(%rip), $twmask + pcmpgtd @XMM[7], $twtmp + pshufd \$0x13, $twtmp, $twres + pxor $twtmp, $twtmp + paddq @XMM[7], @XMM[7] # psllq 1,$tweak + pand $twmask, $twres # isolate carry and residue + pcmpgtd @XMM[7], $twtmp # broadcast upper bits + pxor $twres, @XMM[7] + + sub \$0x80,$len + jnc .Lxts_enc_loop + +.Lxts_enc_short: + add \$0x80, $len + jz .Lxts_enc_done +___ + for ($i=0;$i<7;$i++) { + $code.=<<___; + pshufd \$0x13, $twtmp, $twres + pxor $twtmp, $twtmp + movdqa @XMM[7], @XMM[$i] + movdqa @XMM[7], `0x10*$i`(%rsp)# save tweak[$i] + paddq @XMM[7], @XMM[7] # psllq 1,$tweak + pand $twmask, $twres # isolate carry and residue + pcmpgtd @XMM[7], $twtmp # broadcast upper bits + pxor $twres, @XMM[7] +___ + $code.=<<___ if ($i>=1); + movdqu `0x10*($i-1)`($inp), @XMM[8+$i-1] + cmp \$`0x10*$i`,$len + je .Lxts_enc_$i +___ + $code.=<<___ if ($i>=2); + pxor @XMM[8+$i-2], @XMM[$i-2]# input[] ^ tweak[] +___ + } +$code.=<<___; + movdqu 0x60($inp), @XMM[8+6] + pxor @XMM[8+5], @XMM[5] + movdqa @XMM[7], 0x70(%rsp) + lea 0x70($inp), $inp + pxor @XMM[8+6], @XMM[6] + lea 0x80(%rsp), %rax # pass key schedule + mov %edx, %r10d # pass rounds + + call _bsaes_encrypt8 + + pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + pxor 0x10(%rsp), @XMM[1] + movdqu @XMM[0], 0x00($out) # write output + pxor 0x20(%rsp), @XMM[4] + movdqu @XMM[1], 0x10($out) + pxor 0x30(%rsp), @XMM[6] + movdqu @XMM[4], 0x20($out) + pxor 0x40(%rsp), @XMM[3] + movdqu @XMM[6], 0x30($out) + pxor 0x50(%rsp), @XMM[7] + movdqu @XMM[3], 0x40($out) + pxor 0x60(%rsp), @XMM[2] + movdqu @XMM[7], 0x50($out) + movdqu @XMM[2], 0x60($out) + lea 0x70($out), $out + + movdqa 0x70(%rsp), @XMM[7] # next iteration tweak + jmp .Lxts_enc_done +.align 16 +.Lxts_enc_6: + pxor @XMM[8+4], @XMM[4] + lea 0x60($inp), $inp + pxor @XMM[8+5], @XMM[5] + lea 0x80(%rsp), %rax # pass key schedule + mov %edx, %r10d # pass rounds + + call _bsaes_encrypt8 + + pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + pxor 0x10(%rsp), @XMM[1] + movdqu @XMM[0], 0x00($out) # write output + pxor 0x20(%rsp), @XMM[4] + movdqu @XMM[1], 0x10($out) + pxor 0x30(%rsp), @XMM[6] + movdqu @XMM[4], 0x20($out) + pxor 0x40(%rsp), @XMM[3] + movdqu @XMM[6], 0x30($out) + pxor 0x50(%rsp), @XMM[7] + movdqu @XMM[3], 0x40($out) + movdqu @XMM[7], 0x50($out) + lea 0x60($out), $out + + movdqa 0x60(%rsp), @XMM[7] # next iteration tweak + jmp .Lxts_enc_done +.align 16 +.Lxts_enc_5: + pxor @XMM[8+3], @XMM[3] + lea 0x50($inp), $inp + pxor @XMM[8+4], @XMM[4] + lea 0x80(%rsp), %rax # pass key schedule + mov %edx, %r10d # pass rounds + + call _bsaes_encrypt8 + + pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + pxor 0x10(%rsp), @XMM[1] + movdqu @XMM[0], 0x00($out) # write output + pxor 0x20(%rsp), @XMM[4] + movdqu @XMM[1], 0x10($out) + pxor 0x30(%rsp), @XMM[6] + movdqu @XMM[4], 0x20($out) + pxor 0x40(%rsp), @XMM[3] + movdqu @XMM[6], 0x30($out) + movdqu @XMM[3], 0x40($out) + lea 0x50($out), $out + + movdqa 0x50(%rsp), @XMM[7] # next iteration tweak + jmp .Lxts_enc_done +.align 16 +.Lxts_enc_4: + pxor @XMM[8+2], @XMM[2] + lea 0x40($inp), $inp + pxor @XMM[8+3], @XMM[3] + lea 0x80(%rsp), %rax # pass key schedule + mov %edx, %r10d # pass rounds + + call _bsaes_encrypt8 + + pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + pxor 0x10(%rsp), @XMM[1] + movdqu @XMM[0], 0x00($out) # write output + pxor 0x20(%rsp), @XMM[4] + movdqu @XMM[1], 0x10($out) + pxor 0x30(%rsp), @XMM[6] + movdqu @XMM[4], 0x20($out) + movdqu @XMM[6], 0x30($out) + lea 0x40($out), $out + + movdqa 0x40(%rsp), @XMM[7] # next iteration tweak + jmp .Lxts_enc_done +.align 16 +.Lxts_enc_3: + pxor @XMM[8+1], @XMM[1] + lea 0x30($inp), $inp + pxor @XMM[8+2], @XMM[2] + lea 0x80(%rsp), %rax # pass key schedule + mov %edx, %r10d # pass rounds + + call _bsaes_encrypt8 + + pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + pxor 0x10(%rsp), @XMM[1] + movdqu @XMM[0], 0x00($out) # write output + pxor 0x20(%rsp), @XMM[4] + movdqu @XMM[1], 0x10($out) + movdqu @XMM[4], 0x20($out) + lea 0x30($out), $out + + movdqa 0x30(%rsp), @XMM[7] # next iteration tweak + jmp .Lxts_enc_done +.align 16 +.Lxts_enc_2: + pxor @XMM[8+0], @XMM[0] + lea 0x20($inp), $inp + pxor @XMM[8+1], @XMM[1] + lea 0x80(%rsp), %rax # pass key schedule + mov %edx, %r10d # pass rounds + + call _bsaes_encrypt8 + + pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + pxor 0x10(%rsp), @XMM[1] + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + lea 0x20($out), $out + + movdqa 0x20(%rsp), @XMM[7] # next iteration tweak + jmp .Lxts_enc_done +.align 16 +.Lxts_enc_1: + pxor @XMM[0], @XMM[8] + lea 0x10($inp), $inp + movdqa @XMM[8], 0x20(%rbp) + lea 0x20(%rbp), $arg1 + lea 0x20(%rbp), $arg2 + lea ($key), $arg3 + call asm_AES_encrypt # doesn't touch %xmm + pxor 0x20(%rbp), @XMM[0] # ^= tweak[] + #pxor @XMM[8], @XMM[0] + #lea 0x80(%rsp), %rax # pass key schedule + #mov %edx, %r10d # pass rounds + #call _bsaes_encrypt8 + #pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + movdqu @XMM[0], 0x00($out) # write output + lea 0x10($out), $out + + movdqa 0x10(%rsp), @XMM[7] # next iteration tweak + +.Lxts_enc_done: + and \$15, %ebx + jz .Lxts_enc_ret + mov $out, %rdx + +.Lxts_enc_steal: + movzb ($inp), %eax + movzb -16(%rdx), %ecx + lea 1($inp), $inp + mov %al, -16(%rdx) + mov %cl, 0(%rdx) + lea 1(%rdx), %rdx + sub \$1,%ebx + jnz .Lxts_enc_steal + + movdqu -16($out), @XMM[0] + lea 0x20(%rbp), $arg1 + pxor @XMM[7], @XMM[0] + lea 0x20(%rbp), $arg2 + movdqa @XMM[0], 0x20(%rbp) + lea ($key), $arg3 + call asm_AES_encrypt # doesn't touch %xmm + pxor 0x20(%rbp), @XMM[7] + movdqu @XMM[7], -16($out) + +.Lxts_enc_ret: + lea (%rsp), %rax + pxor %xmm0, %xmm0 +.Lxts_enc_bzero: # wipe key schedule [if any] + movdqa %xmm0, 0x00(%rax) + movdqa %xmm0, 0x10(%rax) + lea 0x20(%rax), %rax + cmp %rax, %rbp + ja .Lxts_enc_bzero + + lea (%rbp),%rsp # restore %rsp +___ +$code.=<<___ if ($win64); + movaps 0x40(%rbp), %xmm6 + movaps 0x50(%rbp), %xmm7 + movaps 0x60(%rbp), %xmm8 + movaps 0x70(%rbp), %xmm9 + movaps 0x80(%rbp), %xmm10 + movaps 0x90(%rbp), %xmm11 + movaps 0xa0(%rbp), %xmm12 + movaps 0xb0(%rbp), %xmm13 + movaps 0xc0(%rbp), %xmm14 + movaps 0xd0(%rbp), %xmm15 + lea 0xa0(%rbp), %rsp +___ +$code.=<<___; + mov 0x48(%rsp), %r15 + mov 0x50(%rsp), %r14 + mov 0x58(%rsp), %r13 + mov 0x60(%rsp), %r12 + mov 0x68(%rsp), %rbx + mov 0x70(%rsp), %rax + lea 0x78(%rsp), %rsp + mov %rax, %rbp +.Lxts_enc_epilogue: + ret +.size bsaes_xts_encrypt,.-bsaes_xts_encrypt + +.globl bsaes_xts_decrypt +.type bsaes_xts_decrypt,\@abi-omnipotent +.align 16 +bsaes_xts_decrypt: + mov %rsp, %rax +.Lxts_dec_prologue: + push %rbp + push %rbx + push %r12 + push %r13 + push %r14 + push %r15 + lea -0x48(%rsp), %rsp +___ +$code.=<<___ if ($win64); + mov 0xa0(%rsp),$arg5 # pull key2 + mov 0xa8(%rsp),$arg6 # pull ivp + lea -0xa0(%rsp), %rsp + movaps %xmm6, 0x40(%rsp) + movaps %xmm7, 0x50(%rsp) + movaps %xmm8, 0x60(%rsp) + movaps %xmm9, 0x70(%rsp) + movaps %xmm10, 0x80(%rsp) + movaps %xmm11, 0x90(%rsp) + movaps %xmm12, 0xa0(%rsp) + movaps %xmm13, 0xb0(%rsp) + movaps %xmm14, 0xc0(%rsp) + movaps %xmm15, 0xd0(%rsp) +.Lxts_dec_body: +___ +$code.=<<___; + mov %rsp, %rbp # backup %rsp + mov $arg1, $inp # backup arguments + mov $arg2, $out + mov $arg3, $len + mov $arg4, $key + + lea ($arg6), $arg1 + lea 0x20(%rbp), $arg2 + lea ($arg5), $arg3 + call asm_AES_encrypt # generate initial tweak + + mov 240($key), %eax # rounds + mov $len, %rbx # backup $len + + mov %eax, %edx # rounds + shl \$7, %rax # 128 bytes per inner round key + sub \$`128-32`, %rax # size of bit-sliced key schedule + sub %rax, %rsp + + mov %rsp, %rax # pass key schedule + mov $key, %rcx # pass key + mov %edx, %r10d # pass rounds + call _bsaes_key_convert + pxor (%rsp), %xmm7 # fix up round 0 key + movdqa %xmm6, (%rax) # save last round key + movdqa %xmm7, (%rsp) + + xor %eax, %eax # if ($len%16) len-=16; + and \$-16, $len + test \$15, %ebx + setnz %al + shl \$4, %rax + sub %rax, $len + + sub \$0x80, %rsp # place for tweak[8] + movdqa 0x20(%rbp), @XMM[7] # initial tweak + + pxor $twtmp, $twtmp + movdqa .Lxts_magic(%rip), $twmask + pcmpgtd @XMM[7], $twtmp # broadcast upper bits + + sub \$0x80, $len + jc .Lxts_dec_short + jmp .Lxts_dec_loop + +.align 16 +.Lxts_dec_loop: +___ + for ($i=0;$i<7;$i++) { + $code.=<<___; + pshufd \$0x13, $twtmp, $twres + pxor $twtmp, $twtmp + movdqa @XMM[7], @XMM[$i] + movdqa @XMM[7], `0x10*$i`(%rsp)# save tweak[$i] + paddq @XMM[7], @XMM[7] # psllq 1,$tweak + pand $twmask, $twres # isolate carry and residue + pcmpgtd @XMM[7], $twtmp # broadcast upper bits + pxor $twres, @XMM[7] +___ + $code.=<<___ if ($i>=1); + movdqu `0x10*($i-1)`($inp), @XMM[8+$i-1] +___ + $code.=<<___ if ($i>=2); + pxor @XMM[8+$i-2], @XMM[$i-2]# input[] ^ tweak[] +___ + } +$code.=<<___; + movdqu 0x60($inp), @XMM[8+6] + pxor @XMM[8+5], @XMM[5] + movdqu 0x70($inp), @XMM[8+7] + lea 0x80($inp), $inp + movdqa @XMM[7], 0x70(%rsp) + pxor @XMM[8+6], @XMM[6] + lea 0x80(%rsp), %rax # pass key schedule + pxor @XMM[8+7], @XMM[7] + mov %edx, %r10d # pass rounds + + call _bsaes_decrypt8 + + pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + pxor 0x10(%rsp), @XMM[1] + movdqu @XMM[0], 0x00($out) # write output + pxor 0x20(%rsp), @XMM[6] + movdqu @XMM[1], 0x10($out) + pxor 0x30(%rsp), @XMM[4] + movdqu @XMM[6], 0x20($out) + pxor 0x40(%rsp), @XMM[2] + movdqu @XMM[4], 0x30($out) + pxor 0x50(%rsp), @XMM[7] + movdqu @XMM[2], 0x40($out) + pxor 0x60(%rsp), @XMM[3] + movdqu @XMM[7], 0x50($out) + pxor 0x70(%rsp), @XMM[5] + movdqu @XMM[3], 0x60($out) + movdqu @XMM[5], 0x70($out) + lea 0x80($out), $out + + movdqa 0x70(%rsp), @XMM[7] # prepare next iteration tweak + pxor $twtmp, $twtmp + movdqa .Lxts_magic(%rip), $twmask + pcmpgtd @XMM[7], $twtmp + pshufd \$0x13, $twtmp, $twres + pxor $twtmp, $twtmp + paddq @XMM[7], @XMM[7] # psllq 1,$tweak + pand $twmask, $twres # isolate carry and residue + pcmpgtd @XMM[7], $twtmp # broadcast upper bits + pxor $twres, @XMM[7] + + sub \$0x80,$len + jnc .Lxts_dec_loop + +.Lxts_dec_short: + add \$0x80, $len + jz .Lxts_dec_done +___ + for ($i=0;$i<7;$i++) { + $code.=<<___; + pshufd \$0x13, $twtmp, $twres + pxor $twtmp, $twtmp + movdqa @XMM[7], @XMM[$i] + movdqa @XMM[7], `0x10*$i`(%rsp)# save tweak[$i] + paddq @XMM[7], @XMM[7] # psllq 1,$tweak + pand $twmask, $twres # isolate carry and residue + pcmpgtd @XMM[7], $twtmp # broadcast upper bits + pxor $twres, @XMM[7] +___ + $code.=<<___ if ($i>=1); + movdqu `0x10*($i-1)`($inp), @XMM[8+$i-1] + cmp \$`0x10*$i`,$len + je .Lxts_dec_$i +___ + $code.=<<___ if ($i>=2); + pxor @XMM[8+$i-2], @XMM[$i-2]# input[] ^ tweak[] +___ + } +$code.=<<___; + movdqu 0x60($inp), @XMM[8+6] + pxor @XMM[8+5], @XMM[5] + movdqa @XMM[7], 0x70(%rsp) + lea 0x70($inp), $inp + pxor @XMM[8+6], @XMM[6] + lea 0x80(%rsp), %rax # pass key schedule + mov %edx, %r10d # pass rounds + + call _bsaes_decrypt8 + + pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + pxor 0x10(%rsp), @XMM[1] + movdqu @XMM[0], 0x00($out) # write output + pxor 0x20(%rsp), @XMM[6] + movdqu @XMM[1], 0x10($out) + pxor 0x30(%rsp), @XMM[4] + movdqu @XMM[6], 0x20($out) + pxor 0x40(%rsp), @XMM[2] + movdqu @XMM[4], 0x30($out) + pxor 0x50(%rsp), @XMM[7] + movdqu @XMM[2], 0x40($out) + pxor 0x60(%rsp), @XMM[3] + movdqu @XMM[7], 0x50($out) + movdqu @XMM[3], 0x60($out) + lea 0x70($out), $out + + movdqa 0x70(%rsp), @XMM[7] # next iteration tweak + jmp .Lxts_dec_done +.align 16 +.Lxts_dec_6: + pxor @XMM[8+4], @XMM[4] + lea 0x60($inp), $inp + pxor @XMM[8+5], @XMM[5] + lea 0x80(%rsp), %rax # pass key schedule + mov %edx, %r10d # pass rounds + + call _bsaes_decrypt8 + + pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + pxor 0x10(%rsp), @XMM[1] + movdqu @XMM[0], 0x00($out) # write output + pxor 0x20(%rsp), @XMM[6] + movdqu @XMM[1], 0x10($out) + pxor 0x30(%rsp), @XMM[4] + movdqu @XMM[6], 0x20($out) + pxor 0x40(%rsp), @XMM[2] + movdqu @XMM[4], 0x30($out) + pxor 0x50(%rsp), @XMM[7] + movdqu @XMM[2], 0x40($out) + movdqu @XMM[7], 0x50($out) + lea 0x60($out), $out + + movdqa 0x60(%rsp), @XMM[7] # next iteration tweak + jmp .Lxts_dec_done +.align 16 +.Lxts_dec_5: + pxor @XMM[8+3], @XMM[3] + lea 0x50($inp), $inp + pxor @XMM[8+4], @XMM[4] + lea 0x80(%rsp), %rax # pass key schedule + mov %edx, %r10d # pass rounds + + call _bsaes_decrypt8 + + pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + pxor 0x10(%rsp), @XMM[1] + movdqu @XMM[0], 0x00($out) # write output + pxor 0x20(%rsp), @XMM[6] + movdqu @XMM[1], 0x10($out) + pxor 0x30(%rsp), @XMM[4] + movdqu @XMM[6], 0x20($out) + pxor 0x40(%rsp), @XMM[2] + movdqu @XMM[4], 0x30($out) + movdqu @XMM[2], 0x40($out) + lea 0x50($out), $out + + movdqa 0x50(%rsp), @XMM[7] # next iteration tweak + jmp .Lxts_dec_done +.align 16 +.Lxts_dec_4: + pxor @XMM[8+2], @XMM[2] + lea 0x40($inp), $inp + pxor @XMM[8+3], @XMM[3] + lea 0x80(%rsp), %rax # pass key schedule + mov %edx, %r10d # pass rounds + + call _bsaes_decrypt8 + + pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + pxor 0x10(%rsp), @XMM[1] + movdqu @XMM[0], 0x00($out) # write output + pxor 0x20(%rsp), @XMM[6] + movdqu @XMM[1], 0x10($out) + pxor 0x30(%rsp), @XMM[4] + movdqu @XMM[6], 0x20($out) + movdqu @XMM[4], 0x30($out) + lea 0x40($out), $out + + movdqa 0x40(%rsp), @XMM[7] # next iteration tweak + jmp .Lxts_dec_done +.align 16 +.Lxts_dec_3: + pxor @XMM[8+1], @XMM[1] + lea 0x30($inp), $inp + pxor @XMM[8+2], @XMM[2] + lea 0x80(%rsp), %rax # pass key schedule + mov %edx, %r10d # pass rounds + + call _bsaes_decrypt8 + + pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + pxor 0x10(%rsp), @XMM[1] + movdqu @XMM[0], 0x00($out) # write output + pxor 0x20(%rsp), @XMM[6] + movdqu @XMM[1], 0x10($out) + movdqu @XMM[6], 0x20($out) + lea 0x30($out), $out + + movdqa 0x30(%rsp), @XMM[7] # next iteration tweak + jmp .Lxts_dec_done +.align 16 +.Lxts_dec_2: + pxor @XMM[8+0], @XMM[0] + lea 0x20($inp), $inp + pxor @XMM[8+1], @XMM[1] + lea 0x80(%rsp), %rax # pass key schedule + mov %edx, %r10d # pass rounds + + call _bsaes_decrypt8 + + pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + pxor 0x10(%rsp), @XMM[1] + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + lea 0x20($out), $out + + movdqa 0x20(%rsp), @XMM[7] # next iteration tweak + jmp .Lxts_dec_done +.align 16 +.Lxts_dec_1: + pxor @XMM[0], @XMM[8] + lea 0x10($inp), $inp + movdqa @XMM[8], 0x20(%rbp) + lea 0x20(%rbp), $arg1 + lea 0x20(%rbp), $arg2 + lea ($key), $arg3 + call asm_AES_decrypt # doesn't touch %xmm + pxor 0x20(%rbp), @XMM[0] # ^= tweak[] + #pxor @XMM[8], @XMM[0] + #lea 0x80(%rsp), %rax # pass key schedule + #mov %edx, %r10d # pass rounds + #call _bsaes_decrypt8 + #pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + movdqu @XMM[0], 0x00($out) # write output + lea 0x10($out), $out + + movdqa 0x10(%rsp), @XMM[7] # next iteration tweak + +.Lxts_dec_done: + and \$15, %ebx + jz .Lxts_dec_ret + + pxor $twtmp, $twtmp + movdqa .Lxts_magic(%rip), $twmask + pcmpgtd @XMM[7], $twtmp + pshufd \$0x13, $twtmp, $twres + movdqa @XMM[7], @XMM[6] + paddq @XMM[7], @XMM[7] # psllq 1,$tweak + pand $twmask, $twres # isolate carry and residue + movdqu ($inp), @XMM[0] + pxor $twres, @XMM[7] + + lea 0x20(%rbp), $arg1 + pxor @XMM[7], @XMM[0] + lea 0x20(%rbp), $arg2 + movdqa @XMM[0], 0x20(%rbp) + lea ($key), $arg3 + call asm_AES_decrypt # doesn't touch %xmm + pxor 0x20(%rbp), @XMM[7] + mov $out, %rdx + movdqu @XMM[7], ($out) + +.Lxts_dec_steal: + movzb 16($inp), %eax + movzb (%rdx), %ecx + lea 1($inp), $inp + mov %al, (%rdx) + mov %cl, 16(%rdx) + lea 1(%rdx), %rdx + sub \$1,%ebx + jnz .Lxts_dec_steal + + movdqu ($out), @XMM[0] + lea 0x20(%rbp), $arg1 + pxor @XMM[6], @XMM[0] + lea 0x20(%rbp), $arg2 + movdqa @XMM[0], 0x20(%rbp) + lea ($key), $arg3 + call asm_AES_decrypt # doesn't touch %xmm + pxor 0x20(%rbp), @XMM[6] + movdqu @XMM[6], ($out) + +.Lxts_dec_ret: + lea (%rsp), %rax + pxor %xmm0, %xmm0 +.Lxts_dec_bzero: # wipe key schedule [if any] + movdqa %xmm0, 0x00(%rax) + movdqa %xmm0, 0x10(%rax) + lea 0x20(%rax), %rax + cmp %rax, %rbp + ja .Lxts_dec_bzero + + lea (%rbp),%rsp # restore %rsp +___ +$code.=<<___ if ($win64); + movaps 0x40(%rbp), %xmm6 + movaps 0x50(%rbp), %xmm7 + movaps 0x60(%rbp), %xmm8 + movaps 0x70(%rbp), %xmm9 + movaps 0x80(%rbp), %xmm10 + movaps 0x90(%rbp), %xmm11 + movaps 0xa0(%rbp), %xmm12 + movaps 0xb0(%rbp), %xmm13 + movaps 0xc0(%rbp), %xmm14 + movaps 0xd0(%rbp), %xmm15 + lea 0xa0(%rbp), %rsp +___ +$code.=<<___; + mov 0x48(%rsp), %r15 + mov 0x50(%rsp), %r14 + mov 0x58(%rsp), %r13 + mov 0x60(%rsp), %r12 + mov 0x68(%rsp), %rbx + mov 0x70(%rsp), %rax + lea 0x78(%rsp), %rsp + mov %rax, %rbp +.Lxts_dec_epilogue: + ret +.size bsaes_xts_decrypt,.-bsaes_xts_decrypt +___ +} +$code.=<<___; +.type _bsaes_const,\@object +.align 64 +_bsaes_const: +.LM0ISR: # InvShiftRows constants + .quad 0x0a0e0206070b0f03, 0x0004080c0d010509 +.LISRM0: + .quad 0x01040b0e0205080f, 0x0306090c00070a0d +.LISR: + .quad 0x0504070602010003, 0x0f0e0d0c080b0a09 +.LBS0: # bit-slice constants + .quad 0x5555555555555555, 0x5555555555555555 +.LBS1: + .quad 0x3333333333333333, 0x3333333333333333 +.LBS2: + .quad 0x0f0f0f0f0f0f0f0f, 0x0f0f0f0f0f0f0f0f +.LSR: # shiftrows constants + .quad 0x0504070600030201, 0x0f0e0d0c0a09080b +.LSRM0: + .quad 0x0304090e00050a0f, 0x01060b0c0207080d +.LM0SR: + .quad 0x0a0e02060f03070b, 0x0004080c05090d01 +.LSWPUP: # byte-swap upper dword + .quad 0x0706050403020100, 0x0c0d0e0f0b0a0908 +.LSWPUPM0SR: + .quad 0x0a0d02060c03070b, 0x0004080f05090e01 +.LADD1: # counter increment constants + .quad 0x0000000000000000, 0x0000000100000000 +.LADD2: + .quad 0x0000000000000000, 0x0000000200000000 +.LADD3: + .quad 0x0000000000000000, 0x0000000300000000 +.LADD4: + .quad 0x0000000000000000, 0x0000000400000000 +.LADD5: + .quad 0x0000000000000000, 0x0000000500000000 +.LADD6: + .quad 0x0000000000000000, 0x0000000600000000 +.LADD7: + .quad 0x0000000000000000, 0x0000000700000000 +.LADD8: + .quad 0x0000000000000000, 0x0000000800000000 +.Lxts_magic: + .long 0x87,0,1,0 +.Lmasks: + .quad 0x0101010101010101, 0x0101010101010101 + .quad 0x0202020202020202, 0x0202020202020202 + .quad 0x0404040404040404, 0x0404040404040404 + .quad 0x0808080808080808, 0x0808080808080808 +.LM0: + .quad 0x02060a0e03070b0f, 0x0004080c0105090d +.L63: + .quad 0x6363636363636363, 0x6363636363636363 +.asciz "Bit-sliced AES for x86_64/SSSE3, Emilia Käsper, Peter Schwabe, Andy Polyakov" +.align 64 +.size _bsaes_const,.-_bsaes_const +___ + +# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame, +# CONTEXT *context,DISPATCHER_CONTEXT *disp) +if ($win64) { +$rec="%rcx"; +$frame="%rdx"; +$context="%r8"; +$disp="%r9"; + +$code.=<<___; +.extern __imp_RtlVirtualUnwind +.type se_handler,\@abi-omnipotent +.align 16 +se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + mov 8($disp),%rsi # disp->ImageBase + mov 56($disp),%r11 # disp->HandlerData + + mov 0(%r11),%r10d # HandlerData[0] + lea (%rsi,%r10),%r10 # prologue label + cmp %r10,%rbx # context->RipRsp + + mov 4(%r11),%r10d # HandlerData[1] + lea (%rsi,%r10),%r10 # epilogue label + cmp %r10,%rbx # context->Rip>=epilogue label + jae .Lin_prologue + + mov 160($context),%rax # pull context->Rbp + + lea 0x40(%rax),%rsi # %xmm save area + lea 512($context),%rdi # &context.Xmm6 + mov \$20,%ecx # 10*sizeof(%xmm0)/sizeof(%rax) + .long 0xa548f3fc # cld; rep movsq + lea 0xa0(%rax),%rax # adjust stack pointer + + mov 0x70(%rax),%rbp + mov 0x68(%rax),%rbx + mov 0x60(%rax),%r12 + mov 0x58(%rax),%r13 + mov 0x50(%rax),%r14 + mov 0x48(%rax),%r15 + lea 0x78(%rax),%rax # adjust stack pointer + mov %rbx,144($context) # restore context->Rbx + mov %rbp,160($context) # restore context->Rbp + mov %r12,216($context) # restore context->R12 + mov %r13,224($context) # restore context->R13 + mov %r14,232($context) # restore context->R14 + mov %r15,240($context) # restore context->R15 + +.Lin_prologue: + mov %rax,152($context) # restore context->Rsp + + mov 40($disp),%rdi # disp->ContextRecord + mov $context,%rsi # context + mov \$`1232/8`,%ecx # sizeof(CONTEXT) + .long 0xa548f3fc # cld; rep movsq + + mov $disp,%rsi + xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER + mov 8(%rsi),%rdx # arg2, disp->ImageBase + mov 0(%rsi),%r8 # arg3, disp->ControlPc + mov 16(%rsi),%r9 # arg4, disp->FunctionEntry + mov 40(%rsi),%r10 # disp->ContextRecord + lea 56(%rsi),%r11 # &disp->HandlerData + lea 24(%rsi),%r12 # &disp->EstablisherFrame + mov %r10,32(%rsp) # arg5 + mov %r11,40(%rsp) # arg6 + mov %r12,48(%rsp) # arg7 + mov %rcx,56(%rsp) # arg8, (NULL) + call *__imp_RtlVirtualUnwind(%rip) + + mov \$1,%eax # ExceptionContinueSearch + add \$64,%rsp + popfq + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + pop %rdi + pop %rsi + ret +.size se_handler,.-se_handler + +.section .pdata +.align 4 +___ +$code.=<<___ if ($ecb); + .rva .Lecb_enc_prologue + .rva .Lecb_enc_epilogue + .rva .Lecb_enc_info + + .rva .Lecb_dec_prologue + .rva .Lecb_dec_epilogue + .rva .Lecb_dec_info +___ +$code.=<<___; + .rva .Lcbc_dec_prologue + .rva .Lcbc_dec_epilogue + .rva .Lcbc_dec_info + + .rva .Lctr_enc_prologue + .rva .Lctr_enc_epilogue + .rva .Lctr_enc_info + + .rva .Lxts_enc_prologue + .rva .Lxts_enc_epilogue + .rva .Lxts_enc_info + + .rva .Lxts_dec_prologue + .rva .Lxts_dec_epilogue + .rva .Lxts_dec_info + +.section .xdata +.align 8 +___ +$code.=<<___ if ($ecb); +.Lecb_enc_info: + .byte 9,0,0,0 + .rva se_handler + .rva .Lecb_enc_body,.Lecb_enc_epilogue # HandlerData[] +.Lecb_dec_info: + .byte 9,0,0,0 + .rva se_handler + .rva .Lecb_dec_body,.Lecb_dec_epilogue # HandlerData[] +___ +$code.=<<___; +.Lcbc_dec_info: + .byte 9,0,0,0 + .rva se_handler + .rva .Lcbc_dec_body,.Lcbc_dec_epilogue # HandlerData[] +.Lctr_enc_info: + .byte 9,0,0,0 + .rva se_handler + .rva .Lctr_enc_body,.Lctr_enc_epilogue # HandlerData[] +.Lxts_enc_info: + .byte 9,0,0,0 + .rva se_handler + .rva .Lxts_enc_body,.Lxts_enc_epilogue # HandlerData[] +.Lxts_dec_info: + .byte 9,0,0,0 + .rva se_handler + .rva .Lxts_dec_body,.Lxts_dec_epilogue # HandlerData[] +___ +} + +$code =~ s/\`([^\`]*)\`/eval($1)/gem; + +print $code; + +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/aes/asm/vpaes-x86.pl b/TMessagesProj/jni/boringssl/crypto/aes/asm/vpaes-x86.pl new file mode 100644 index 00000000..2ba149c3 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/aes/asm/vpaes-x86.pl @@ -0,0 +1,903 @@ +#!/usr/bin/env perl + +###################################################################### +## Constant-time SSSE3 AES core implementation. +## version 0.1 +## +## By Mike Hamburg (Stanford University), 2009 +## Public domain. +## +## For details see http://shiftleft.org/papers/vector_aes/ and +## http://crypto.stanford.edu/vpaes/. + +###################################################################### +# September 2011. +# +# Port vpaes-x86_64.pl as 32-bit "almost" drop-in replacement for +# aes-586.pl. "Almost" refers to the fact that AES_cbc_encrypt +# doesn't handle partial vectors (doesn't have to if called from +# EVP only). "Drop-in" implies that this module doesn't share key +# schedule structure with the original nor does it make assumption +# about its alignment... +# +# Performance summary. aes-586.pl column lists large-block CBC +# encrypt/decrypt/with-hyper-threading-off(*) results in cycles per +# byte processed with 128-bit key, and vpaes-x86.pl column - [also +# large-block CBC] encrypt/decrypt. +# +# aes-586.pl vpaes-x86.pl +# +# Core 2(**) 28.1/41.4/18.3 21.9/25.2(***) +# Nehalem 27.9/40.4/18.1 10.2/11.9 +# Atom 70.7/92.1/60.1 61.1/75.4(***) +# Silvermont 45.4/62.9/24.1 49.2/61.1(***) +# +# (*) "Hyper-threading" in the context refers rather to cache shared +# among multiple cores, than to specifically Intel HTT. As vast +# majority of contemporary cores share cache, slower code path +# is common place. In other words "with-hyper-threading-off" +# results are presented mostly for reference purposes. +# +# (**) "Core 2" refers to initial 65nm design, a.k.a. Conroe. +# +# (***) Less impressive improvement on Core 2 and Atom is due to slow +# pshufb, yet it's respectable +28%/64% improvement on Core 2 +# and +15% on Atom (as implied, over "hyper-threading-safe" +# code path). +# +# + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +push(@INC,"${dir}","${dir}../../perlasm"); +require "x86asm.pl"; + +&asm_init($ARGV[0],"vpaes-x86.pl",$x86only = $ARGV[$#ARGV] eq "386"); + +$PREFIX="vpaes"; + +my ($round, $base, $magic, $key, $const, $inp, $out)= + ("eax", "ebx", "ecx", "edx","ebp", "esi","edi"); + +&static_label("_vpaes_consts"); +&static_label("_vpaes_schedule_low_round"); + +&set_label("_vpaes_consts",64); +$k_inv=-0x30; # inv, inva + &data_word(0x0D080180,0x0E05060F,0x0A0B0C02,0x04070309); + &data_word(0x0F0B0780,0x01040A06,0x02050809,0x030D0E0C); + +$k_s0F=-0x10; # s0F + &data_word(0x0F0F0F0F,0x0F0F0F0F,0x0F0F0F0F,0x0F0F0F0F); + +$k_ipt=0x00; # input transform (lo, hi) + &data_word(0x5A2A7000,0xC2B2E898,0x52227808,0xCABAE090); + &data_word(0x317C4D00,0x4C01307D,0xB0FDCC81,0xCD80B1FC); + +$k_sb1=0x20; # sb1u, sb1t + &data_word(0xCB503E00,0xB19BE18F,0x142AF544,0xA5DF7A6E); + &data_word(0xFAE22300,0x3618D415,0x0D2ED9EF,0x3BF7CCC1); +$k_sb2=0x40; # sb2u, sb2t + &data_word(0x0B712400,0xE27A93C6,0xBC982FCD,0x5EB7E955); + &data_word(0x0AE12900,0x69EB8840,0xAB82234A,0xC2A163C8); +$k_sbo=0x60; # sbou, sbot + &data_word(0x6FBDC700,0xD0D26D17,0xC502A878,0x15AABF7A); + &data_word(0x5FBB6A00,0xCFE474A5,0x412B35FA,0x8E1E90D1); + +$k_mc_forward=0x80; # mc_forward + &data_word(0x00030201,0x04070605,0x080B0A09,0x0C0F0E0D); + &data_word(0x04070605,0x080B0A09,0x0C0F0E0D,0x00030201); + &data_word(0x080B0A09,0x0C0F0E0D,0x00030201,0x04070605); + &data_word(0x0C0F0E0D,0x00030201,0x04070605,0x080B0A09); + +$k_mc_backward=0xc0; # mc_backward + &data_word(0x02010003,0x06050407,0x0A09080B,0x0E0D0C0F); + &data_word(0x0E0D0C0F,0x02010003,0x06050407,0x0A09080B); + &data_word(0x0A09080B,0x0E0D0C0F,0x02010003,0x06050407); + &data_word(0x06050407,0x0A09080B,0x0E0D0C0F,0x02010003); + +$k_sr=0x100; # sr + &data_word(0x03020100,0x07060504,0x0B0A0908,0x0F0E0D0C); + &data_word(0x0F0A0500,0x030E0904,0x07020D08,0x0B06010C); + &data_word(0x0B020900,0x0F060D04,0x030A0108,0x070E050C); + &data_word(0x070A0D00,0x0B0E0104,0x0F020508,0x0306090C); + +$k_rcon=0x140; # rcon + &data_word(0xAF9DEEB6,0x1F8391B9,0x4D7C7D81,0x702A9808); + +$k_s63=0x150; # s63: all equal to 0x63 transformed + &data_word(0x5B5B5B5B,0x5B5B5B5B,0x5B5B5B5B,0x5B5B5B5B); + +$k_opt=0x160; # output transform + &data_word(0xD6B66000,0xFF9F4929,0xDEBE6808,0xF7974121); + &data_word(0x50BCEC00,0x01EDBD51,0xB05C0CE0,0xE10D5DB1); + +$k_deskew=0x180; # deskew tables: inverts the sbox's "skew" + &data_word(0x47A4E300,0x07E4A340,0x5DBEF91A,0x1DFEB95A); + &data_word(0x83EA6900,0x5F36B5DC,0xF49D1E77,0x2841C2AB); +## +## Decryption stuff +## Key schedule constants +## +$k_dksd=0x1a0; # decryption key schedule: invskew x*D + &data_word(0xA3E44700,0xFEB91A5D,0x5A1DBEF9,0x0740E3A4); + &data_word(0xB5368300,0x41C277F4,0xAB289D1E,0x5FDC69EA); +$k_dksb=0x1c0; # decryption key schedule: invskew x*B + &data_word(0x8550D500,0x9A4FCA1F,0x1CC94C99,0x03D65386); + &data_word(0xB6FC4A00,0x115BEDA7,0x7E3482C8,0xD993256F); +$k_dkse=0x1e0; # decryption key schedule: invskew x*E + 0x63 + &data_word(0x1FC9D600,0xD5031CCA,0x994F5086,0x53859A4C); + &data_word(0x4FDC7BE8,0xA2319605,0x20B31487,0xCD5EF96A); +$k_dks9=0x200; # decryption key schedule: invskew x*9 + &data_word(0x7ED9A700,0xB6116FC8,0x82255BFC,0x4AED9334); + &data_word(0x27143300,0x45765162,0xE9DAFDCE,0x8BB89FAC); + +## +## Decryption stuff +## Round function constants +## +$k_dipt=0x220; # decryption input transform + &data_word(0x0B545F00,0x0F505B04,0x114E451A,0x154A411E); + &data_word(0x60056500,0x86E383E6,0xF491F194,0x12771772); + +$k_dsb9=0x240; # decryption sbox output *9*u, *9*t + &data_word(0x9A86D600,0x851C0353,0x4F994CC9,0xCAD51F50); + &data_word(0xECD74900,0xC03B1789,0xB2FBA565,0x725E2C9E); +$k_dsbd=0x260; # decryption sbox output *D*u, *D*t + &data_word(0xE6B1A200,0x7D57CCDF,0x882A4439,0xF56E9B13); + &data_word(0x24C6CB00,0x3CE2FAF7,0x15DEEFD3,0x2931180D); +$k_dsbb=0x280; # decryption sbox output *B*u, *B*t + &data_word(0x96B44200,0xD0226492,0xB0F2D404,0x602646F6); + &data_word(0xCD596700,0xC19498A6,0x3255AA6B,0xF3FF0C3E); +$k_dsbe=0x2a0; # decryption sbox output *E*u, *E*t + &data_word(0x26D4D000,0x46F29296,0x64B4F6B0,0x22426004); + &data_word(0xFFAAC100,0x0C55A6CD,0x98593E32,0x9467F36B); +$k_dsbo=0x2c0; # decryption sbox final output + &data_word(0x7EF94000,0x1387EA53,0xD4943E2D,0xC7AA6DB9); + &data_word(0x93441D00,0x12D7560F,0xD8C58E9C,0xCA4B8159); +&asciz ("Vector Permutation AES for x86/SSSE3, Mike Hamburg (Stanford University)"); +&align (64); + +&function_begin_B("_vpaes_preheat"); + &add ($const,&DWP(0,"esp")); + &movdqa ("xmm7",&QWP($k_inv,$const)); + &movdqa ("xmm6",&QWP($k_s0F,$const)); + &ret (); +&function_end_B("_vpaes_preheat"); + +## +## _aes_encrypt_core +## +## AES-encrypt %xmm0. +## +## Inputs: +## %xmm0 = input +## %xmm6-%xmm7 as in _vpaes_preheat +## (%edx) = scheduled keys +## +## Output in %xmm0 +## Clobbers %xmm1-%xmm5, %eax, %ebx, %ecx, %edx +## +## +&function_begin_B("_vpaes_encrypt_core"); + &mov ($magic,16); + &mov ($round,&DWP(240,$key)); + &movdqa ("xmm1","xmm6") + &movdqa ("xmm2",&QWP($k_ipt,$const)); + &pandn ("xmm1","xmm0"); + &pand ("xmm0","xmm6"); + &movdqu ("xmm5",&QWP(0,$key)); + &pshufb ("xmm2","xmm0"); + &movdqa ("xmm0",&QWP($k_ipt+16,$const)); + &pxor ("xmm2","xmm5"); + &psrld ("xmm1",4); + &add ($key,16); + &pshufb ("xmm0","xmm1"); + &lea ($base,&DWP($k_mc_backward,$const)); + &pxor ("xmm0","xmm2"); + &jmp (&label("enc_entry")); + + +&set_label("enc_loop",16); + # middle of middle round + &movdqa ("xmm4",&QWP($k_sb1,$const)); # 4 : sb1u + &movdqa ("xmm0",&QWP($k_sb1+16,$const));# 0 : sb1t + &pshufb ("xmm4","xmm2"); # 4 = sb1u + &pshufb ("xmm0","xmm3"); # 0 = sb1t + &pxor ("xmm4","xmm5"); # 4 = sb1u + k + &movdqa ("xmm5",&QWP($k_sb2,$const)); # 4 : sb2u + &pxor ("xmm0","xmm4"); # 0 = A + &movdqa ("xmm1",&QWP(-0x40,$base,$magic));# .Lk_mc_forward[] + &pshufb ("xmm5","xmm2"); # 4 = sb2u + &movdqa ("xmm2",&QWP($k_sb2+16,$const));# 2 : sb2t + &movdqa ("xmm4",&QWP(0,$base,$magic)); # .Lk_mc_backward[] + &pshufb ("xmm2","xmm3"); # 2 = sb2t + &movdqa ("xmm3","xmm0"); # 3 = A + &pxor ("xmm2","xmm5"); # 2 = 2A + &pshufb ("xmm0","xmm1"); # 0 = B + &add ($key,16); # next key + &pxor ("xmm0","xmm2"); # 0 = 2A+B + &pshufb ("xmm3","xmm4"); # 3 = D + &add ($magic,16); # next mc + &pxor ("xmm3","xmm0"); # 3 = 2A+B+D + &pshufb ("xmm0","xmm1"); # 0 = 2B+C + &and ($magic,0x30); # ... mod 4 + &sub ($round,1); # nr-- + &pxor ("xmm0","xmm3"); # 0 = 2A+3B+C+D + +&set_label("enc_entry"); + # top of round + &movdqa ("xmm1","xmm6"); # 1 : i + &movdqa ("xmm5",&QWP($k_inv+16,$const));# 2 : a/k + &pandn ("xmm1","xmm0"); # 1 = i<<4 + &psrld ("xmm1",4); # 1 = i + &pand ("xmm0","xmm6"); # 0 = k + &pshufb ("xmm5","xmm0"); # 2 = a/k + &movdqa ("xmm3","xmm7"); # 3 : 1/i + &pxor ("xmm0","xmm1"); # 0 = j + &pshufb ("xmm3","xmm1"); # 3 = 1/i + &movdqa ("xmm4","xmm7"); # 4 : 1/j + &pxor ("xmm3","xmm5"); # 3 = iak = 1/i + a/k + &pshufb ("xmm4","xmm0"); # 4 = 1/j + &movdqa ("xmm2","xmm7"); # 2 : 1/iak + &pxor ("xmm4","xmm5"); # 4 = jak = 1/j + a/k + &pshufb ("xmm2","xmm3"); # 2 = 1/iak + &movdqa ("xmm3","xmm7"); # 3 : 1/jak + &pxor ("xmm2","xmm0"); # 2 = io + &pshufb ("xmm3","xmm4"); # 3 = 1/jak + &movdqu ("xmm5",&QWP(0,$key)); + &pxor ("xmm3","xmm1"); # 3 = jo + &jnz (&label("enc_loop")); + + # middle of last round + &movdqa ("xmm4",&QWP($k_sbo,$const)); # 3 : sbou .Lk_sbo + &movdqa ("xmm0",&QWP($k_sbo+16,$const));# 3 : sbot .Lk_sbo+16 + &pshufb ("xmm4","xmm2"); # 4 = sbou + &pxor ("xmm4","xmm5"); # 4 = sb1u + k + &pshufb ("xmm0","xmm3"); # 0 = sb1t + &movdqa ("xmm1",&QWP(0x40,$base,$magic));# .Lk_sr[] + &pxor ("xmm0","xmm4"); # 0 = A + &pshufb ("xmm0","xmm1"); + &ret (); +&function_end_B("_vpaes_encrypt_core"); + +## +## Decryption core +## +## Same API as encryption core. +## +&function_begin_B("_vpaes_decrypt_core"); + &lea ($base,&DWP($k_dsbd,$const)); + &mov ($round,&DWP(240,$key)); + &movdqa ("xmm1","xmm6"); + &movdqa ("xmm2",&QWP($k_dipt-$k_dsbd,$base)); + &pandn ("xmm1","xmm0"); + &mov ($magic,$round); + &psrld ("xmm1",4) + &movdqu ("xmm5",&QWP(0,$key)); + &shl ($magic,4); + &pand ("xmm0","xmm6"); + &pshufb ("xmm2","xmm0"); + &movdqa ("xmm0",&QWP($k_dipt-$k_dsbd+16,$base)); + &xor ($magic,0x30); + &pshufb ("xmm0","xmm1"); + &and ($magic,0x30); + &pxor ("xmm2","xmm5"); + &movdqa ("xmm5",&QWP($k_mc_forward+48,$const)); + &pxor ("xmm0","xmm2"); + &add ($key,16); + &lea ($magic,&DWP($k_sr-$k_dsbd,$base,$magic)); + &jmp (&label("dec_entry")); + +&set_label("dec_loop",16); +## +## Inverse mix columns +## + &movdqa ("xmm4",&QWP(-0x20,$base)); # 4 : sb9u + &movdqa ("xmm1",&QWP(-0x10,$base)); # 0 : sb9t + &pshufb ("xmm4","xmm2"); # 4 = sb9u + &pshufb ("xmm1","xmm3"); # 0 = sb9t + &pxor ("xmm0","xmm4"); + &movdqa ("xmm4",&QWP(0,$base)); # 4 : sbdu + &pxor ("xmm0","xmm1"); # 0 = ch + &movdqa ("xmm1",&QWP(0x10,$base)); # 0 : sbdt + + &pshufb ("xmm4","xmm2"); # 4 = sbdu + &pshufb ("xmm0","xmm5"); # MC ch + &pshufb ("xmm1","xmm3"); # 0 = sbdt + &pxor ("xmm0","xmm4"); # 4 = ch + &movdqa ("xmm4",&QWP(0x20,$base)); # 4 : sbbu + &pxor ("xmm0","xmm1"); # 0 = ch + &movdqa ("xmm1",&QWP(0x30,$base)); # 0 : sbbt + + &pshufb ("xmm4","xmm2"); # 4 = sbbu + &pshufb ("xmm0","xmm5"); # MC ch + &pshufb ("xmm1","xmm3"); # 0 = sbbt + &pxor ("xmm0","xmm4"); # 4 = ch + &movdqa ("xmm4",&QWP(0x40,$base)); # 4 : sbeu + &pxor ("xmm0","xmm1"); # 0 = ch + &movdqa ("xmm1",&QWP(0x50,$base)); # 0 : sbet + + &pshufb ("xmm4","xmm2"); # 4 = sbeu + &pshufb ("xmm0","xmm5"); # MC ch + &pshufb ("xmm1","xmm3"); # 0 = sbet + &pxor ("xmm0","xmm4"); # 4 = ch + &add ($key,16); # next round key + &palignr("xmm5","xmm5",12); + &pxor ("xmm0","xmm1"); # 0 = ch + &sub ($round,1); # nr-- + +&set_label("dec_entry"); + # top of round + &movdqa ("xmm1","xmm6"); # 1 : i + &movdqa ("xmm2",&QWP($k_inv+16,$const));# 2 : a/k + &pandn ("xmm1","xmm0"); # 1 = i<<4 + &pand ("xmm0","xmm6"); # 0 = k + &psrld ("xmm1",4); # 1 = i + &pshufb ("xmm2","xmm0"); # 2 = a/k + &movdqa ("xmm3","xmm7"); # 3 : 1/i + &pxor ("xmm0","xmm1"); # 0 = j + &pshufb ("xmm3","xmm1"); # 3 = 1/i + &movdqa ("xmm4","xmm7"); # 4 : 1/j + &pxor ("xmm3","xmm2"); # 3 = iak = 1/i + a/k + &pshufb ("xmm4","xmm0"); # 4 = 1/j + &pxor ("xmm4","xmm2"); # 4 = jak = 1/j + a/k + &movdqa ("xmm2","xmm7"); # 2 : 1/iak + &pshufb ("xmm2","xmm3"); # 2 = 1/iak + &movdqa ("xmm3","xmm7"); # 3 : 1/jak + &pxor ("xmm2","xmm0"); # 2 = io + &pshufb ("xmm3","xmm4"); # 3 = 1/jak + &movdqu ("xmm0",&QWP(0,$key)); + &pxor ("xmm3","xmm1"); # 3 = jo + &jnz (&label("dec_loop")); + + # middle of last round + &movdqa ("xmm4",&QWP(0x60,$base)); # 3 : sbou + &pshufb ("xmm4","xmm2"); # 4 = sbou + &pxor ("xmm4","xmm0"); # 4 = sb1u + k + &movdqa ("xmm0",&QWP(0x70,$base)); # 0 : sbot + &movdqa ("xmm2",&QWP(0,$magic)); + &pshufb ("xmm0","xmm3"); # 0 = sb1t + &pxor ("xmm0","xmm4"); # 0 = A + &pshufb ("xmm0","xmm2"); + &ret (); +&function_end_B("_vpaes_decrypt_core"); + +######################################################## +## ## +## AES key schedule ## +## ## +######################################################## +&function_begin_B("_vpaes_schedule_core"); + &add ($const,&DWP(0,"esp")); + &movdqu ("xmm0",&QWP(0,$inp)); # load key (unaligned) + &movdqa ("xmm2",&QWP($k_rcon,$const)); # load rcon + + # input transform + &movdqa ("xmm3","xmm0"); + &lea ($base,&DWP($k_ipt,$const)); + &movdqa (&QWP(4,"esp"),"xmm2"); # xmm8 + &call ("_vpaes_schedule_transform"); + &movdqa ("xmm7","xmm0"); + + &test ($out,$out); + &jnz (&label("schedule_am_decrypting")); + + # encrypting, output zeroth round key after transform + &movdqu (&QWP(0,$key),"xmm0"); + &jmp (&label("schedule_go")); + +&set_label("schedule_am_decrypting"); + # decrypting, output zeroth round key after shiftrows + &movdqa ("xmm1",&QWP($k_sr,$const,$magic)); + &pshufb ("xmm3","xmm1"); + &movdqu (&QWP(0,$key),"xmm3"); + &xor ($magic,0x30); + +&set_label("schedule_go"); + &cmp ($round,192); + &ja (&label("schedule_256")); + &je (&label("schedule_192")); + # 128: fall though + +## +## .schedule_128 +## +## 128-bit specific part of key schedule. +## +## This schedule is really simple, because all its parts +## are accomplished by the subroutines. +## +&set_label("schedule_128"); + &mov ($round,10); + +&set_label("loop_schedule_128"); + &call ("_vpaes_schedule_round"); + &dec ($round); + &jz (&label("schedule_mangle_last")); + &call ("_vpaes_schedule_mangle"); # write output + &jmp (&label("loop_schedule_128")); + +## +## .aes_schedule_192 +## +## 192-bit specific part of key schedule. +## +## The main body of this schedule is the same as the 128-bit +## schedule, but with more smearing. The long, high side is +## stored in %xmm7 as before, and the short, low side is in +## the high bits of %xmm6. +## +## This schedule is somewhat nastier, however, because each +## round produces 192 bits of key material, or 1.5 round keys. +## Therefore, on each cycle we do 2 rounds and produce 3 round +## keys. +## +&set_label("schedule_192",16); + &movdqu ("xmm0",&QWP(8,$inp)); # load key part 2 (very unaligned) + &call ("_vpaes_schedule_transform"); # input transform + &movdqa ("xmm6","xmm0"); # save short part + &pxor ("xmm4","xmm4"); # clear 4 + &movhlps("xmm6","xmm4"); # clobber low side with zeros + &mov ($round,4); + +&set_label("loop_schedule_192"); + &call ("_vpaes_schedule_round"); + &palignr("xmm0","xmm6",8); + &call ("_vpaes_schedule_mangle"); # save key n + &call ("_vpaes_schedule_192_smear"); + &call ("_vpaes_schedule_mangle"); # save key n+1 + &call ("_vpaes_schedule_round"); + &dec ($round); + &jz (&label("schedule_mangle_last")); + &call ("_vpaes_schedule_mangle"); # save key n+2 + &call ("_vpaes_schedule_192_smear"); + &jmp (&label("loop_schedule_192")); + +## +## .aes_schedule_256 +## +## 256-bit specific part of key schedule. +## +## The structure here is very similar to the 128-bit +## schedule, but with an additional "low side" in +## %xmm6. The low side's rounds are the same as the +## high side's, except no rcon and no rotation. +## +&set_label("schedule_256",16); + &movdqu ("xmm0",&QWP(16,$inp)); # load key part 2 (unaligned) + &call ("_vpaes_schedule_transform"); # input transform + &mov ($round,7); + +&set_label("loop_schedule_256"); + &call ("_vpaes_schedule_mangle"); # output low result + &movdqa ("xmm6","xmm0"); # save cur_lo in xmm6 + + # high round + &call ("_vpaes_schedule_round"); + &dec ($round); + &jz (&label("schedule_mangle_last")); + &call ("_vpaes_schedule_mangle"); + + # low round. swap xmm7 and xmm6 + &pshufd ("xmm0","xmm0",0xFF); + &movdqa (&QWP(20,"esp"),"xmm7"); + &movdqa ("xmm7","xmm6"); + &call ("_vpaes_schedule_low_round"); + &movdqa ("xmm7",&QWP(20,"esp")); + + &jmp (&label("loop_schedule_256")); + +## +## .aes_schedule_mangle_last +## +## Mangler for last round of key schedule +## Mangles %xmm0 +## when encrypting, outputs out(%xmm0) ^ 63 +## when decrypting, outputs unskew(%xmm0) +## +## Always called right before return... jumps to cleanup and exits +## +&set_label("schedule_mangle_last",16); + # schedule last round key from xmm0 + &lea ($base,&DWP($k_deskew,$const)); + &test ($out,$out); + &jnz (&label("schedule_mangle_last_dec")); + + # encrypting + &movdqa ("xmm1",&QWP($k_sr,$const,$magic)); + &pshufb ("xmm0","xmm1"); # output permute + &lea ($base,&DWP($k_opt,$const)); # prepare to output transform + &add ($key,32); + +&set_label("schedule_mangle_last_dec"); + &add ($key,-16); + &pxor ("xmm0",&QWP($k_s63,$const)); + &call ("_vpaes_schedule_transform"); # output transform + &movdqu (&QWP(0,$key),"xmm0"); # save last key + + # cleanup + &pxor ("xmm0","xmm0"); + &pxor ("xmm1","xmm1"); + &pxor ("xmm2","xmm2"); + &pxor ("xmm3","xmm3"); + &pxor ("xmm4","xmm4"); + &pxor ("xmm5","xmm5"); + &pxor ("xmm6","xmm6"); + &pxor ("xmm7","xmm7"); + &ret (); +&function_end_B("_vpaes_schedule_core"); + +## +## .aes_schedule_192_smear +## +## Smear the short, low side in the 192-bit key schedule. +## +## Inputs: +## %xmm7: high side, b a x y +## %xmm6: low side, d c 0 0 +## %xmm13: 0 +## +## Outputs: +## %xmm6: b+c+d b+c 0 0 +## %xmm0: b+c+d b+c b a +## +&function_begin_B("_vpaes_schedule_192_smear"); + &pshufd ("xmm1","xmm6",0x80); # d c 0 0 -> c 0 0 0 + &pshufd ("xmm0","xmm7",0xFE); # b a _ _ -> b b b a + &pxor ("xmm6","xmm1"); # -> c+d c 0 0 + &pxor ("xmm1","xmm1"); + &pxor ("xmm6","xmm0"); # -> b+c+d b+c b a + &movdqa ("xmm0","xmm6"); + &movhlps("xmm6","xmm1"); # clobber low side with zeros + &ret (); +&function_end_B("_vpaes_schedule_192_smear"); + +## +## .aes_schedule_round +## +## Runs one main round of the key schedule on %xmm0, %xmm7 +## +## Specifically, runs subbytes on the high dword of %xmm0 +## then rotates it by one byte and xors into the low dword of +## %xmm7. +## +## Adds rcon from low byte of %xmm8, then rotates %xmm8 for +## next rcon. +## +## Smears the dwords of %xmm7 by xoring the low into the +## second low, result into third, result into highest. +## +## Returns results in %xmm7 = %xmm0. +## Clobbers %xmm1-%xmm5. +## +&function_begin_B("_vpaes_schedule_round"); + # extract rcon from xmm8 + &movdqa ("xmm2",&QWP(8,"esp")); # xmm8 + &pxor ("xmm1","xmm1"); + &palignr("xmm1","xmm2",15); + &palignr("xmm2","xmm2",15); + &pxor ("xmm7","xmm1"); + + # rotate + &pshufd ("xmm0","xmm0",0xFF); + &palignr("xmm0","xmm0",1); + + # fall through... + &movdqa (&QWP(8,"esp"),"xmm2"); # xmm8 + + # low round: same as high round, but no rotation and no rcon. +&set_label("_vpaes_schedule_low_round"); + # smear xmm7 + &movdqa ("xmm1","xmm7"); + &pslldq ("xmm7",4); + &pxor ("xmm7","xmm1"); + &movdqa ("xmm1","xmm7"); + &pslldq ("xmm7",8); + &pxor ("xmm7","xmm1"); + &pxor ("xmm7",&QWP($k_s63,$const)); + + # subbyte + &movdqa ("xmm4",&QWP($k_s0F,$const)); + &movdqa ("xmm5",&QWP($k_inv,$const)); # 4 : 1/j + &movdqa ("xmm1","xmm4"); + &pandn ("xmm1","xmm0"); + &psrld ("xmm1",4); # 1 = i + &pand ("xmm0","xmm4"); # 0 = k + &movdqa ("xmm2",&QWP($k_inv+16,$const));# 2 : a/k + &pshufb ("xmm2","xmm0"); # 2 = a/k + &pxor ("xmm0","xmm1"); # 0 = j + &movdqa ("xmm3","xmm5"); # 3 : 1/i + &pshufb ("xmm3","xmm1"); # 3 = 1/i + &pxor ("xmm3","xmm2"); # 3 = iak = 1/i + a/k + &movdqa ("xmm4","xmm5"); # 4 : 1/j + &pshufb ("xmm4","xmm0"); # 4 = 1/j + &pxor ("xmm4","xmm2"); # 4 = jak = 1/j + a/k + &movdqa ("xmm2","xmm5"); # 2 : 1/iak + &pshufb ("xmm2","xmm3"); # 2 = 1/iak + &pxor ("xmm2","xmm0"); # 2 = io + &movdqa ("xmm3","xmm5"); # 3 : 1/jak + &pshufb ("xmm3","xmm4"); # 3 = 1/jak + &pxor ("xmm3","xmm1"); # 3 = jo + &movdqa ("xmm4",&QWP($k_sb1,$const)); # 4 : sbou + &pshufb ("xmm4","xmm2"); # 4 = sbou + &movdqa ("xmm0",&QWP($k_sb1+16,$const));# 0 : sbot + &pshufb ("xmm0","xmm3"); # 0 = sb1t + &pxor ("xmm0","xmm4"); # 0 = sbox output + + # add in smeared stuff + &pxor ("xmm0","xmm7"); + &movdqa ("xmm7","xmm0"); + &ret (); +&function_end_B("_vpaes_schedule_round"); + +## +## .aes_schedule_transform +## +## Linear-transform %xmm0 according to tables at (%ebx) +## +## Output in %xmm0 +## Clobbers %xmm1, %xmm2 +## +&function_begin_B("_vpaes_schedule_transform"); + &movdqa ("xmm2",&QWP($k_s0F,$const)); + &movdqa ("xmm1","xmm2"); + &pandn ("xmm1","xmm0"); + &psrld ("xmm1",4); + &pand ("xmm0","xmm2"); + &movdqa ("xmm2",&QWP(0,$base)); + &pshufb ("xmm2","xmm0"); + &movdqa ("xmm0",&QWP(16,$base)); + &pshufb ("xmm0","xmm1"); + &pxor ("xmm0","xmm2"); + &ret (); +&function_end_B("_vpaes_schedule_transform"); + +## +## .aes_schedule_mangle +## +## Mangle xmm0 from (basis-transformed) standard version +## to our version. +## +## On encrypt, +## xor with 0x63 +## multiply by circulant 0,1,1,1 +## apply shiftrows transform +## +## On decrypt, +## xor with 0x63 +## multiply by "inverse mixcolumns" circulant E,B,D,9 +## deskew +## apply shiftrows transform +## +## +## Writes out to (%edx), and increments or decrements it +## Keeps track of round number mod 4 in %ecx +## Preserves xmm0 +## Clobbers xmm1-xmm5 +## +&function_begin_B("_vpaes_schedule_mangle"); + &movdqa ("xmm4","xmm0"); # save xmm0 for later + &movdqa ("xmm5",&QWP($k_mc_forward,$const)); + &test ($out,$out); + &jnz (&label("schedule_mangle_dec")); + + # encrypting + &add ($key,16); + &pxor ("xmm4",&QWP($k_s63,$const)); + &pshufb ("xmm4","xmm5"); + &movdqa ("xmm3","xmm4"); + &pshufb ("xmm4","xmm5"); + &pxor ("xmm3","xmm4"); + &pshufb ("xmm4","xmm5"); + &pxor ("xmm3","xmm4"); + + &jmp (&label("schedule_mangle_both")); + +&set_label("schedule_mangle_dec",16); + # inverse mix columns + &movdqa ("xmm2",&QWP($k_s0F,$const)); + &lea ($inp,&DWP($k_dksd,$const)); + &movdqa ("xmm1","xmm2"); + &pandn ("xmm1","xmm4"); + &psrld ("xmm1",4); # 1 = hi + &pand ("xmm4","xmm2"); # 4 = lo + + &movdqa ("xmm2",&QWP(0,$inp)); + &pshufb ("xmm2","xmm4"); + &movdqa ("xmm3",&QWP(0x10,$inp)); + &pshufb ("xmm3","xmm1"); + &pxor ("xmm3","xmm2"); + &pshufb ("xmm3","xmm5"); + + &movdqa ("xmm2",&QWP(0x20,$inp)); + &pshufb ("xmm2","xmm4"); + &pxor ("xmm2","xmm3"); + &movdqa ("xmm3",&QWP(0x30,$inp)); + &pshufb ("xmm3","xmm1"); + &pxor ("xmm3","xmm2"); + &pshufb ("xmm3","xmm5"); + + &movdqa ("xmm2",&QWP(0x40,$inp)); + &pshufb ("xmm2","xmm4"); + &pxor ("xmm2","xmm3"); + &movdqa ("xmm3",&QWP(0x50,$inp)); + &pshufb ("xmm3","xmm1"); + &pxor ("xmm3","xmm2"); + &pshufb ("xmm3","xmm5"); + + &movdqa ("xmm2",&QWP(0x60,$inp)); + &pshufb ("xmm2","xmm4"); + &pxor ("xmm2","xmm3"); + &movdqa ("xmm3",&QWP(0x70,$inp)); + &pshufb ("xmm3","xmm1"); + &pxor ("xmm3","xmm2"); + + &add ($key,-16); + +&set_label("schedule_mangle_both"); + &movdqa ("xmm1",&QWP($k_sr,$const,$magic)); + &pshufb ("xmm3","xmm1"); + &add ($magic,-16); + &and ($magic,0x30); + &movdqu (&QWP(0,$key),"xmm3"); + &ret (); +&function_end_B("_vpaes_schedule_mangle"); + +# +# Interface to OpenSSL +# +&function_begin("${PREFIX}_set_encrypt_key"); + &mov ($inp,&wparam(0)); # inp + &lea ($base,&DWP(-56,"esp")); + &mov ($round,&wparam(1)); # bits + &and ($base,-16); + &mov ($key,&wparam(2)); # key + &xchg ($base,"esp"); # alloca + &mov (&DWP(48,"esp"),$base); + + &mov ($base,$round); + &shr ($base,5); + &add ($base,5); + &mov (&DWP(240,$key),$base); # AES_KEY->rounds = nbits/32+5; + &mov ($magic,0x30); + &mov ($out,0); + + &lea ($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point"))); + &call ("_vpaes_schedule_core"); +&set_label("pic_point"); + + &mov ("esp",&DWP(48,"esp")); + &xor ("eax","eax"); +&function_end("${PREFIX}_set_encrypt_key"); + +&function_begin("${PREFIX}_set_decrypt_key"); + &mov ($inp,&wparam(0)); # inp + &lea ($base,&DWP(-56,"esp")); + &mov ($round,&wparam(1)); # bits + &and ($base,-16); + &mov ($key,&wparam(2)); # key + &xchg ($base,"esp"); # alloca + &mov (&DWP(48,"esp"),$base); + + &mov ($base,$round); + &shr ($base,5); + &add ($base,5); + &mov (&DWP(240,$key),$base); # AES_KEY->rounds = nbits/32+5; + &shl ($base,4); + &lea ($key,&DWP(16,$key,$base)); + + &mov ($out,1); + &mov ($magic,$round); + &shr ($magic,1); + &and ($magic,32); + &xor ($magic,32); # nbist==192?0:32; + + &lea ($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point"))); + &call ("_vpaes_schedule_core"); +&set_label("pic_point"); + + &mov ("esp",&DWP(48,"esp")); + &xor ("eax","eax"); +&function_end("${PREFIX}_set_decrypt_key"); + +&function_begin("${PREFIX}_encrypt"); + &lea ($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point"))); + &call ("_vpaes_preheat"); +&set_label("pic_point"); + &mov ($inp,&wparam(0)); # inp + &lea ($base,&DWP(-56,"esp")); + &mov ($out,&wparam(1)); # out + &and ($base,-16); + &mov ($key,&wparam(2)); # key + &xchg ($base,"esp"); # alloca + &mov (&DWP(48,"esp"),$base); + + &movdqu ("xmm0",&QWP(0,$inp)); + &call ("_vpaes_encrypt_core"); + &movdqu (&QWP(0,$out),"xmm0"); + + &mov ("esp",&DWP(48,"esp")); +&function_end("${PREFIX}_encrypt"); + +&function_begin("${PREFIX}_decrypt"); + &lea ($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point"))); + &call ("_vpaes_preheat"); +&set_label("pic_point"); + &mov ($inp,&wparam(0)); # inp + &lea ($base,&DWP(-56,"esp")); + &mov ($out,&wparam(1)); # out + &and ($base,-16); + &mov ($key,&wparam(2)); # key + &xchg ($base,"esp"); # alloca + &mov (&DWP(48,"esp"),$base); + + &movdqu ("xmm0",&QWP(0,$inp)); + &call ("_vpaes_decrypt_core"); + &movdqu (&QWP(0,$out),"xmm0"); + + &mov ("esp",&DWP(48,"esp")); +&function_end("${PREFIX}_decrypt"); + +&function_begin("${PREFIX}_cbc_encrypt"); + &mov ($inp,&wparam(0)); # inp + &mov ($out,&wparam(1)); # out + &mov ($round,&wparam(2)); # len + &mov ($key,&wparam(3)); # key + &sub ($round,16); + &jc (&label("cbc_abort")); + &lea ($base,&DWP(-56,"esp")); + &mov ($const,&wparam(4)); # ivp + &and ($base,-16); + &mov ($magic,&wparam(5)); # enc + &xchg ($base,"esp"); # alloca + &movdqu ("xmm1",&QWP(0,$const)); # load IV + &sub ($out,$inp); + &mov (&DWP(48,"esp"),$base); + + &mov (&DWP(0,"esp"),$out); # save out + &mov (&DWP(4,"esp"),$key) # save key + &mov (&DWP(8,"esp"),$const); # save ivp + &mov ($out,$round); # $out works as $len + + &lea ($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point"))); + &call ("_vpaes_preheat"); +&set_label("pic_point"); + &cmp ($magic,0); + &je (&label("cbc_dec_loop")); + &jmp (&label("cbc_enc_loop")); + +&set_label("cbc_enc_loop",16); + &movdqu ("xmm0",&QWP(0,$inp)); # load input + &pxor ("xmm0","xmm1"); # inp^=iv + &call ("_vpaes_encrypt_core"); + &mov ($base,&DWP(0,"esp")); # restore out + &mov ($key,&DWP(4,"esp")); # restore key + &movdqa ("xmm1","xmm0"); + &movdqu (&QWP(0,$base,$inp),"xmm0"); # write output + &lea ($inp,&DWP(16,$inp)); + &sub ($out,16); + &jnc (&label("cbc_enc_loop")); + &jmp (&label("cbc_done")); + +&set_label("cbc_dec_loop",16); + &movdqu ("xmm0",&QWP(0,$inp)); # load input + &movdqa (&QWP(16,"esp"),"xmm1"); # save IV + &movdqa (&QWP(32,"esp"),"xmm0"); # save future IV + &call ("_vpaes_decrypt_core"); + &mov ($base,&DWP(0,"esp")); # restore out + &mov ($key,&DWP(4,"esp")); # restore key + &pxor ("xmm0",&QWP(16,"esp")); # out^=iv + &movdqa ("xmm1",&QWP(32,"esp")); # load next IV + &movdqu (&QWP(0,$base,$inp),"xmm0"); # write output + &lea ($inp,&DWP(16,$inp)); + &sub ($out,16); + &jnc (&label("cbc_dec_loop")); + +&set_label("cbc_done"); + &mov ($base,&DWP(8,"esp")); # restore ivp + &mov ("esp",&DWP(48,"esp")); + &movdqu (&QWP(0,$base),"xmm1"); # write IV +&set_label("cbc_abort"); +&function_end("${PREFIX}_cbc_encrypt"); + +&asm_finish(); diff --git a/TMessagesProj/jni/boringssl/crypto/aes/asm/vpaes-x86_64.pl b/TMessagesProj/jni/boringssl/crypto/aes/asm/vpaes-x86_64.pl new file mode 100644 index 00000000..f2ef318f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/aes/asm/vpaes-x86_64.pl @@ -0,0 +1,1207 @@ +#!/usr/bin/env perl + +###################################################################### +## Constant-time SSSE3 AES core implementation. +## version 0.1 +## +## By Mike Hamburg (Stanford University), 2009 +## Public domain. +## +## For details see http://shiftleft.org/papers/vector_aes/ and +## http://crypto.stanford.edu/vpaes/. + +###################################################################### +# September 2011. +# +# Interface to OpenSSL as "almost" drop-in replacement for +# aes-x86_64.pl. "Almost" refers to the fact that AES_cbc_encrypt +# doesn't handle partial vectors (doesn't have to if called from +# EVP only). "Drop-in" implies that this module doesn't share key +# schedule structure with the original nor does it make assumption +# about its alignment... +# +# Performance summary. aes-x86_64.pl column lists large-block CBC +# encrypt/decrypt/with-hyper-threading-off(*) results in cycles per +# byte processed with 128-bit key, and vpaes-x86_64.pl column - +# [also large-block CBC] encrypt/decrypt. +# +# aes-x86_64.pl vpaes-x86_64.pl +# +# Core 2(**) 29.6/41.1/14.3 21.9/25.2(***) +# Nehalem 29.6/40.3/14.6 10.0/11.8 +# Atom 57.3/74.2/32.1 60.9/77.2(***) +# Silvermont 52.7/64.0/19.5 48.8/60.8(***) +# +# (*) "Hyper-threading" in the context refers rather to cache shared +# among multiple cores, than to specifically Intel HTT. As vast +# majority of contemporary cores share cache, slower code path +# is common place. In other words "with-hyper-threading-off" +# results are presented mostly for reference purposes. +# +# (**) "Core 2" refers to initial 65nm design, a.k.a. Conroe. +# +# (***) Less impressive improvement on Core 2 and Atom is due to slow +# pshufb, yet it's respectable +36%/62% improvement on Core 2 +# (as implied, over "hyper-threading-safe" code path). +# +# + +$flavour = shift; +$output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or +die "can't locate x86_64-xlate.pl"; + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +$PREFIX="vpaes"; + +$code.=<<___; +.text + +## +## _aes_encrypt_core +## +## AES-encrypt %xmm0. +## +## Inputs: +## %xmm0 = input +## %xmm9-%xmm15 as in _vpaes_preheat +## (%rdx) = scheduled keys +## +## Output in %xmm0 +## Clobbers %xmm1-%xmm5, %r9, %r10, %r11, %rax +## Preserves %xmm6 - %xmm8 so you get some local vectors +## +## +.type _vpaes_encrypt_core,\@abi-omnipotent +.align 16 +_vpaes_encrypt_core: + mov %rdx, %r9 + mov \$16, %r11 + mov 240(%rdx),%eax + movdqa %xmm9, %xmm1 + movdqa .Lk_ipt(%rip), %xmm2 # iptlo + pandn %xmm0, %xmm1 + movdqu (%r9), %xmm5 # round0 key + psrld \$4, %xmm1 + pand %xmm9, %xmm0 + pshufb %xmm0, %xmm2 + movdqa .Lk_ipt+16(%rip), %xmm0 # ipthi + pshufb %xmm1, %xmm0 + pxor %xmm5, %xmm2 + add \$16, %r9 + pxor %xmm2, %xmm0 + lea .Lk_mc_backward(%rip),%r10 + jmp .Lenc_entry + +.align 16 +.Lenc_loop: + # middle of middle round + movdqa %xmm13, %xmm4 # 4 : sb1u + movdqa %xmm12, %xmm0 # 0 : sb1t + pshufb %xmm2, %xmm4 # 4 = sb1u + pshufb %xmm3, %xmm0 # 0 = sb1t + pxor %xmm5, %xmm4 # 4 = sb1u + k + movdqa %xmm15, %xmm5 # 4 : sb2u + pxor %xmm4, %xmm0 # 0 = A + movdqa -0x40(%r11,%r10), %xmm1 # .Lk_mc_forward[] + pshufb %xmm2, %xmm5 # 4 = sb2u + movdqa (%r11,%r10), %xmm4 # .Lk_mc_backward[] + movdqa %xmm14, %xmm2 # 2 : sb2t + pshufb %xmm3, %xmm2 # 2 = sb2t + movdqa %xmm0, %xmm3 # 3 = A + pxor %xmm5, %xmm2 # 2 = 2A + pshufb %xmm1, %xmm0 # 0 = B + add \$16, %r9 # next key + pxor %xmm2, %xmm0 # 0 = 2A+B + pshufb %xmm4, %xmm3 # 3 = D + add \$16, %r11 # next mc + pxor %xmm0, %xmm3 # 3 = 2A+B+D + pshufb %xmm1, %xmm0 # 0 = 2B+C + and \$0x30, %r11 # ... mod 4 + sub \$1,%rax # nr-- + pxor %xmm3, %xmm0 # 0 = 2A+3B+C+D + +.Lenc_entry: + # top of round + movdqa %xmm9, %xmm1 # 1 : i + movdqa %xmm11, %xmm5 # 2 : a/k + pandn %xmm0, %xmm1 # 1 = i<<4 + psrld \$4, %xmm1 # 1 = i + pand %xmm9, %xmm0 # 0 = k + pshufb %xmm0, %xmm5 # 2 = a/k + movdqa %xmm10, %xmm3 # 3 : 1/i + pxor %xmm1, %xmm0 # 0 = j + pshufb %xmm1, %xmm3 # 3 = 1/i + movdqa %xmm10, %xmm4 # 4 : 1/j + pxor %xmm5, %xmm3 # 3 = iak = 1/i + a/k + pshufb %xmm0, %xmm4 # 4 = 1/j + movdqa %xmm10, %xmm2 # 2 : 1/iak + pxor %xmm5, %xmm4 # 4 = jak = 1/j + a/k + pshufb %xmm3, %xmm2 # 2 = 1/iak + movdqa %xmm10, %xmm3 # 3 : 1/jak + pxor %xmm0, %xmm2 # 2 = io + pshufb %xmm4, %xmm3 # 3 = 1/jak + movdqu (%r9), %xmm5 + pxor %xmm1, %xmm3 # 3 = jo + jnz .Lenc_loop + + # middle of last round + movdqa -0x60(%r10), %xmm4 # 3 : sbou .Lk_sbo + movdqa -0x50(%r10), %xmm0 # 0 : sbot .Lk_sbo+16 + pshufb %xmm2, %xmm4 # 4 = sbou + pxor %xmm5, %xmm4 # 4 = sb1u + k + pshufb %xmm3, %xmm0 # 0 = sb1t + movdqa 0x40(%r11,%r10), %xmm1 # .Lk_sr[] + pxor %xmm4, %xmm0 # 0 = A + pshufb %xmm1, %xmm0 + ret +.size _vpaes_encrypt_core,.-_vpaes_encrypt_core + +## +## Decryption core +## +## Same API as encryption core. +## +.type _vpaes_decrypt_core,\@abi-omnipotent +.align 16 +_vpaes_decrypt_core: + mov %rdx, %r9 # load key + mov 240(%rdx),%eax + movdqa %xmm9, %xmm1 + movdqa .Lk_dipt(%rip), %xmm2 # iptlo + pandn %xmm0, %xmm1 + mov %rax, %r11 + psrld \$4, %xmm1 + movdqu (%r9), %xmm5 # round0 key + shl \$4, %r11 + pand %xmm9, %xmm0 + pshufb %xmm0, %xmm2 + movdqa .Lk_dipt+16(%rip), %xmm0 # ipthi + xor \$0x30, %r11 + lea .Lk_dsbd(%rip),%r10 + pshufb %xmm1, %xmm0 + and \$0x30, %r11 + pxor %xmm5, %xmm2 + movdqa .Lk_mc_forward+48(%rip), %xmm5 + pxor %xmm2, %xmm0 + add \$16, %r9 + add %r10, %r11 + jmp .Ldec_entry + +.align 16 +.Ldec_loop: +## +## Inverse mix columns +## + movdqa -0x20(%r10),%xmm4 # 4 : sb9u + movdqa -0x10(%r10),%xmm1 # 0 : sb9t + pshufb %xmm2, %xmm4 # 4 = sb9u + pshufb %xmm3, %xmm1 # 0 = sb9t + pxor %xmm4, %xmm0 + movdqa 0x00(%r10),%xmm4 # 4 : sbdu + pxor %xmm1, %xmm0 # 0 = ch + movdqa 0x10(%r10),%xmm1 # 0 : sbdt + + pshufb %xmm2, %xmm4 # 4 = sbdu + pshufb %xmm5, %xmm0 # MC ch + pshufb %xmm3, %xmm1 # 0 = sbdt + pxor %xmm4, %xmm0 # 4 = ch + movdqa 0x20(%r10),%xmm4 # 4 : sbbu + pxor %xmm1, %xmm0 # 0 = ch + movdqa 0x30(%r10),%xmm1 # 0 : sbbt + + pshufb %xmm2, %xmm4 # 4 = sbbu + pshufb %xmm5, %xmm0 # MC ch + pshufb %xmm3, %xmm1 # 0 = sbbt + pxor %xmm4, %xmm0 # 4 = ch + movdqa 0x40(%r10),%xmm4 # 4 : sbeu + pxor %xmm1, %xmm0 # 0 = ch + movdqa 0x50(%r10),%xmm1 # 0 : sbet + + pshufb %xmm2, %xmm4 # 4 = sbeu + pshufb %xmm5, %xmm0 # MC ch + pshufb %xmm3, %xmm1 # 0 = sbet + pxor %xmm4, %xmm0 # 4 = ch + add \$16, %r9 # next round key + palignr \$12, %xmm5, %xmm5 + pxor %xmm1, %xmm0 # 0 = ch + sub \$1,%rax # nr-- + +.Ldec_entry: + # top of round + movdqa %xmm9, %xmm1 # 1 : i + pandn %xmm0, %xmm1 # 1 = i<<4 + movdqa %xmm11, %xmm2 # 2 : a/k + psrld \$4, %xmm1 # 1 = i + pand %xmm9, %xmm0 # 0 = k + pshufb %xmm0, %xmm2 # 2 = a/k + movdqa %xmm10, %xmm3 # 3 : 1/i + pxor %xmm1, %xmm0 # 0 = j + pshufb %xmm1, %xmm3 # 3 = 1/i + movdqa %xmm10, %xmm4 # 4 : 1/j + pxor %xmm2, %xmm3 # 3 = iak = 1/i + a/k + pshufb %xmm0, %xmm4 # 4 = 1/j + pxor %xmm2, %xmm4 # 4 = jak = 1/j + a/k + movdqa %xmm10, %xmm2 # 2 : 1/iak + pshufb %xmm3, %xmm2 # 2 = 1/iak + movdqa %xmm10, %xmm3 # 3 : 1/jak + pxor %xmm0, %xmm2 # 2 = io + pshufb %xmm4, %xmm3 # 3 = 1/jak + movdqu (%r9), %xmm0 + pxor %xmm1, %xmm3 # 3 = jo + jnz .Ldec_loop + + # middle of last round + movdqa 0x60(%r10), %xmm4 # 3 : sbou + pshufb %xmm2, %xmm4 # 4 = sbou + pxor %xmm0, %xmm4 # 4 = sb1u + k + movdqa 0x70(%r10), %xmm0 # 0 : sbot + movdqa -0x160(%r11), %xmm2 # .Lk_sr-.Lk_dsbd=-0x160 + pshufb %xmm3, %xmm0 # 0 = sb1t + pxor %xmm4, %xmm0 # 0 = A + pshufb %xmm2, %xmm0 + ret +.size _vpaes_decrypt_core,.-_vpaes_decrypt_core + +######################################################## +## ## +## AES key schedule ## +## ## +######################################################## +.type _vpaes_schedule_core,\@abi-omnipotent +.align 16 +_vpaes_schedule_core: + # rdi = key + # rsi = size in bits + # rdx = buffer + # rcx = direction. 0=encrypt, 1=decrypt + + call _vpaes_preheat # load the tables + movdqa .Lk_rcon(%rip), %xmm8 # load rcon + movdqu (%rdi), %xmm0 # load key (unaligned) + + # input transform + movdqa %xmm0, %xmm3 + lea .Lk_ipt(%rip), %r11 + call _vpaes_schedule_transform + movdqa %xmm0, %xmm7 + + lea .Lk_sr(%rip),%r10 + test %rcx, %rcx + jnz .Lschedule_am_decrypting + + # encrypting, output zeroth round key after transform + movdqu %xmm0, (%rdx) + jmp .Lschedule_go + +.Lschedule_am_decrypting: + # decrypting, output zeroth round key after shiftrows + movdqa (%r8,%r10),%xmm1 + pshufb %xmm1, %xmm3 + movdqu %xmm3, (%rdx) + xor \$0x30, %r8 + +.Lschedule_go: + cmp \$192, %esi + ja .Lschedule_256 + je .Lschedule_192 + # 128: fall though + +## +## .schedule_128 +## +## 128-bit specific part of key schedule. +## +## This schedule is really simple, because all its parts +## are accomplished by the subroutines. +## +.Lschedule_128: + mov \$10, %esi + +.Loop_schedule_128: + call _vpaes_schedule_round + dec %rsi + jz .Lschedule_mangle_last + call _vpaes_schedule_mangle # write output + jmp .Loop_schedule_128 + +## +## .aes_schedule_192 +## +## 192-bit specific part of key schedule. +## +## The main body of this schedule is the same as the 128-bit +## schedule, but with more smearing. The long, high side is +## stored in %xmm7 as before, and the short, low side is in +## the high bits of %xmm6. +## +## This schedule is somewhat nastier, however, because each +## round produces 192 bits of key material, or 1.5 round keys. +## Therefore, on each cycle we do 2 rounds and produce 3 round +## keys. +## +.align 16 +.Lschedule_192: + movdqu 8(%rdi),%xmm0 # load key part 2 (very unaligned) + call _vpaes_schedule_transform # input transform + movdqa %xmm0, %xmm6 # save short part + pxor %xmm4, %xmm4 # clear 4 + movhlps %xmm4, %xmm6 # clobber low side with zeros + mov \$4, %esi + +.Loop_schedule_192: + call _vpaes_schedule_round + palignr \$8,%xmm6,%xmm0 + call _vpaes_schedule_mangle # save key n + call _vpaes_schedule_192_smear + call _vpaes_schedule_mangle # save key n+1 + call _vpaes_schedule_round + dec %rsi + jz .Lschedule_mangle_last + call _vpaes_schedule_mangle # save key n+2 + call _vpaes_schedule_192_smear + jmp .Loop_schedule_192 + +## +## .aes_schedule_256 +## +## 256-bit specific part of key schedule. +## +## The structure here is very similar to the 128-bit +## schedule, but with an additional "low side" in +## %xmm6. The low side's rounds are the same as the +## high side's, except no rcon and no rotation. +## +.align 16 +.Lschedule_256: + movdqu 16(%rdi),%xmm0 # load key part 2 (unaligned) + call _vpaes_schedule_transform # input transform + mov \$7, %esi + +.Loop_schedule_256: + call _vpaes_schedule_mangle # output low result + movdqa %xmm0, %xmm6 # save cur_lo in xmm6 + + # high round + call _vpaes_schedule_round + dec %rsi + jz .Lschedule_mangle_last + call _vpaes_schedule_mangle + + # low round. swap xmm7 and xmm6 + pshufd \$0xFF, %xmm0, %xmm0 + movdqa %xmm7, %xmm5 + movdqa %xmm6, %xmm7 + call _vpaes_schedule_low_round + movdqa %xmm5, %xmm7 + + jmp .Loop_schedule_256 + + +## +## .aes_schedule_mangle_last +## +## Mangler for last round of key schedule +## Mangles %xmm0 +## when encrypting, outputs out(%xmm0) ^ 63 +## when decrypting, outputs unskew(%xmm0) +## +## Always called right before return... jumps to cleanup and exits +## +.align 16 +.Lschedule_mangle_last: + # schedule last round key from xmm0 + lea .Lk_deskew(%rip),%r11 # prepare to deskew + test %rcx, %rcx + jnz .Lschedule_mangle_last_dec + + # encrypting + movdqa (%r8,%r10),%xmm1 + pshufb %xmm1, %xmm0 # output permute + lea .Lk_opt(%rip), %r11 # prepare to output transform + add \$32, %rdx + +.Lschedule_mangle_last_dec: + add \$-16, %rdx + pxor .Lk_s63(%rip), %xmm0 + call _vpaes_schedule_transform # output transform + movdqu %xmm0, (%rdx) # save last key + + # cleanup + pxor %xmm0, %xmm0 + pxor %xmm1, %xmm1 + pxor %xmm2, %xmm2 + pxor %xmm3, %xmm3 + pxor %xmm4, %xmm4 + pxor %xmm5, %xmm5 + pxor %xmm6, %xmm6 + pxor %xmm7, %xmm7 + ret +.size _vpaes_schedule_core,.-_vpaes_schedule_core + +## +## .aes_schedule_192_smear +## +## Smear the short, low side in the 192-bit key schedule. +## +## Inputs: +## %xmm7: high side, b a x y +## %xmm6: low side, d c 0 0 +## %xmm13: 0 +## +## Outputs: +## %xmm6: b+c+d b+c 0 0 +## %xmm0: b+c+d b+c b a +## +.type _vpaes_schedule_192_smear,\@abi-omnipotent +.align 16 +_vpaes_schedule_192_smear: + pshufd \$0x80, %xmm6, %xmm1 # d c 0 0 -> c 0 0 0 + pshufd \$0xFE, %xmm7, %xmm0 # b a _ _ -> b b b a + pxor %xmm1, %xmm6 # -> c+d c 0 0 + pxor %xmm1, %xmm1 + pxor %xmm0, %xmm6 # -> b+c+d b+c b a + movdqa %xmm6, %xmm0 + movhlps %xmm1, %xmm6 # clobber low side with zeros + ret +.size _vpaes_schedule_192_smear,.-_vpaes_schedule_192_smear + +## +## .aes_schedule_round +## +## Runs one main round of the key schedule on %xmm0, %xmm7 +## +## Specifically, runs subbytes on the high dword of %xmm0 +## then rotates it by one byte and xors into the low dword of +## %xmm7. +## +## Adds rcon from low byte of %xmm8, then rotates %xmm8 for +## next rcon. +## +## Smears the dwords of %xmm7 by xoring the low into the +## second low, result into third, result into highest. +## +## Returns results in %xmm7 = %xmm0. +## Clobbers %xmm1-%xmm4, %r11. +## +.type _vpaes_schedule_round,\@abi-omnipotent +.align 16 +_vpaes_schedule_round: + # extract rcon from xmm8 + pxor %xmm1, %xmm1 + palignr \$15, %xmm8, %xmm1 + palignr \$15, %xmm8, %xmm8 + pxor %xmm1, %xmm7 + + # rotate + pshufd \$0xFF, %xmm0, %xmm0 + palignr \$1, %xmm0, %xmm0 + + # fall through... + + # low round: same as high round, but no rotation and no rcon. +_vpaes_schedule_low_round: + # smear xmm7 + movdqa %xmm7, %xmm1 + pslldq \$4, %xmm7 + pxor %xmm1, %xmm7 + movdqa %xmm7, %xmm1 + pslldq \$8, %xmm7 + pxor %xmm1, %xmm7 + pxor .Lk_s63(%rip), %xmm7 + + # subbytes + movdqa %xmm9, %xmm1 + pandn %xmm0, %xmm1 + psrld \$4, %xmm1 # 1 = i + pand %xmm9, %xmm0 # 0 = k + movdqa %xmm11, %xmm2 # 2 : a/k + pshufb %xmm0, %xmm2 # 2 = a/k + pxor %xmm1, %xmm0 # 0 = j + movdqa %xmm10, %xmm3 # 3 : 1/i + pshufb %xmm1, %xmm3 # 3 = 1/i + pxor %xmm2, %xmm3 # 3 = iak = 1/i + a/k + movdqa %xmm10, %xmm4 # 4 : 1/j + pshufb %xmm0, %xmm4 # 4 = 1/j + pxor %xmm2, %xmm4 # 4 = jak = 1/j + a/k + movdqa %xmm10, %xmm2 # 2 : 1/iak + pshufb %xmm3, %xmm2 # 2 = 1/iak + pxor %xmm0, %xmm2 # 2 = io + movdqa %xmm10, %xmm3 # 3 : 1/jak + pshufb %xmm4, %xmm3 # 3 = 1/jak + pxor %xmm1, %xmm3 # 3 = jo + movdqa %xmm13, %xmm4 # 4 : sbou + pshufb %xmm2, %xmm4 # 4 = sbou + movdqa %xmm12, %xmm0 # 0 : sbot + pshufb %xmm3, %xmm0 # 0 = sb1t + pxor %xmm4, %xmm0 # 0 = sbox output + + # add in smeared stuff + pxor %xmm7, %xmm0 + movdqa %xmm0, %xmm7 + ret +.size _vpaes_schedule_round,.-_vpaes_schedule_round + +## +## .aes_schedule_transform +## +## Linear-transform %xmm0 according to tables at (%r11) +## +## Requires that %xmm9 = 0x0F0F... as in preheat +## Output in %xmm0 +## Clobbers %xmm1, %xmm2 +## +.type _vpaes_schedule_transform,\@abi-omnipotent +.align 16 +_vpaes_schedule_transform: + movdqa %xmm9, %xmm1 + pandn %xmm0, %xmm1 + psrld \$4, %xmm1 + pand %xmm9, %xmm0 + movdqa (%r11), %xmm2 # lo + pshufb %xmm0, %xmm2 + movdqa 16(%r11), %xmm0 # hi + pshufb %xmm1, %xmm0 + pxor %xmm2, %xmm0 + ret +.size _vpaes_schedule_transform,.-_vpaes_schedule_transform + +## +## .aes_schedule_mangle +## +## Mangle xmm0 from (basis-transformed) standard version +## to our version. +## +## On encrypt, +## xor with 0x63 +## multiply by circulant 0,1,1,1 +## apply shiftrows transform +## +## On decrypt, +## xor with 0x63 +## multiply by "inverse mixcolumns" circulant E,B,D,9 +## deskew +## apply shiftrows transform +## +## +## Writes out to (%rdx), and increments or decrements it +## Keeps track of round number mod 4 in %r8 +## Preserves xmm0 +## Clobbers xmm1-xmm5 +## +.type _vpaes_schedule_mangle,\@abi-omnipotent +.align 16 +_vpaes_schedule_mangle: + movdqa %xmm0, %xmm4 # save xmm0 for later + movdqa .Lk_mc_forward(%rip),%xmm5 + test %rcx, %rcx + jnz .Lschedule_mangle_dec + + # encrypting + add \$16, %rdx + pxor .Lk_s63(%rip),%xmm4 + pshufb %xmm5, %xmm4 + movdqa %xmm4, %xmm3 + pshufb %xmm5, %xmm4 + pxor %xmm4, %xmm3 + pshufb %xmm5, %xmm4 + pxor %xmm4, %xmm3 + + jmp .Lschedule_mangle_both +.align 16 +.Lschedule_mangle_dec: + # inverse mix columns + lea .Lk_dksd(%rip),%r11 + movdqa %xmm9, %xmm1 + pandn %xmm4, %xmm1 + psrld \$4, %xmm1 # 1 = hi + pand %xmm9, %xmm4 # 4 = lo + + movdqa 0x00(%r11), %xmm2 + pshufb %xmm4, %xmm2 + movdqa 0x10(%r11), %xmm3 + pshufb %xmm1, %xmm3 + pxor %xmm2, %xmm3 + pshufb %xmm5, %xmm3 + + movdqa 0x20(%r11), %xmm2 + pshufb %xmm4, %xmm2 + pxor %xmm3, %xmm2 + movdqa 0x30(%r11), %xmm3 + pshufb %xmm1, %xmm3 + pxor %xmm2, %xmm3 + pshufb %xmm5, %xmm3 + + movdqa 0x40(%r11), %xmm2 + pshufb %xmm4, %xmm2 + pxor %xmm3, %xmm2 + movdqa 0x50(%r11), %xmm3 + pshufb %xmm1, %xmm3 + pxor %xmm2, %xmm3 + pshufb %xmm5, %xmm3 + + movdqa 0x60(%r11), %xmm2 + pshufb %xmm4, %xmm2 + pxor %xmm3, %xmm2 + movdqa 0x70(%r11), %xmm3 + pshufb %xmm1, %xmm3 + pxor %xmm2, %xmm3 + + add \$-16, %rdx + +.Lschedule_mangle_both: + movdqa (%r8,%r10),%xmm1 + pshufb %xmm1,%xmm3 + add \$-16, %r8 + and \$0x30, %r8 + movdqu %xmm3, (%rdx) + ret +.size _vpaes_schedule_mangle,.-_vpaes_schedule_mangle + +# +# Interface to OpenSSL +# +.globl ${PREFIX}_set_encrypt_key +.type ${PREFIX}_set_encrypt_key,\@function,3 +.align 16 +${PREFIX}_set_encrypt_key: +___ +$code.=<<___ if ($win64); + lea -0xb8(%rsp),%rsp + movaps %xmm6,0x10(%rsp) + movaps %xmm7,0x20(%rsp) + movaps %xmm8,0x30(%rsp) + movaps %xmm9,0x40(%rsp) + movaps %xmm10,0x50(%rsp) + movaps %xmm11,0x60(%rsp) + movaps %xmm12,0x70(%rsp) + movaps %xmm13,0x80(%rsp) + movaps %xmm14,0x90(%rsp) + movaps %xmm15,0xa0(%rsp) +.Lenc_key_body: +___ +$code.=<<___; + mov %esi,%eax + shr \$5,%eax + add \$5,%eax + mov %eax,240(%rdx) # AES_KEY->rounds = nbits/32+5; + + mov \$0,%ecx + mov \$0x30,%r8d + call _vpaes_schedule_core +___ +$code.=<<___ if ($win64); + movaps 0x10(%rsp),%xmm6 + movaps 0x20(%rsp),%xmm7 + movaps 0x30(%rsp),%xmm8 + movaps 0x40(%rsp),%xmm9 + movaps 0x50(%rsp),%xmm10 + movaps 0x60(%rsp),%xmm11 + movaps 0x70(%rsp),%xmm12 + movaps 0x80(%rsp),%xmm13 + movaps 0x90(%rsp),%xmm14 + movaps 0xa0(%rsp),%xmm15 + lea 0xb8(%rsp),%rsp +.Lenc_key_epilogue: +___ +$code.=<<___; + xor %eax,%eax + ret +.size ${PREFIX}_set_encrypt_key,.-${PREFIX}_set_encrypt_key + +.globl ${PREFIX}_set_decrypt_key +.type ${PREFIX}_set_decrypt_key,\@function,3 +.align 16 +${PREFIX}_set_decrypt_key: +___ +$code.=<<___ if ($win64); + lea -0xb8(%rsp),%rsp + movaps %xmm6,0x10(%rsp) + movaps %xmm7,0x20(%rsp) + movaps %xmm8,0x30(%rsp) + movaps %xmm9,0x40(%rsp) + movaps %xmm10,0x50(%rsp) + movaps %xmm11,0x60(%rsp) + movaps %xmm12,0x70(%rsp) + movaps %xmm13,0x80(%rsp) + movaps %xmm14,0x90(%rsp) + movaps %xmm15,0xa0(%rsp) +.Ldec_key_body: +___ +$code.=<<___; + mov %esi,%eax + shr \$5,%eax + add \$5,%eax + mov %eax,240(%rdx) # AES_KEY->rounds = nbits/32+5; + shl \$4,%eax + lea 16(%rdx,%rax),%rdx + + mov \$1,%ecx + mov %esi,%r8d + shr \$1,%r8d + and \$32,%r8d + xor \$32,%r8d # nbits==192?0:32 + call _vpaes_schedule_core +___ +$code.=<<___ if ($win64); + movaps 0x10(%rsp),%xmm6 + movaps 0x20(%rsp),%xmm7 + movaps 0x30(%rsp),%xmm8 + movaps 0x40(%rsp),%xmm9 + movaps 0x50(%rsp),%xmm10 + movaps 0x60(%rsp),%xmm11 + movaps 0x70(%rsp),%xmm12 + movaps 0x80(%rsp),%xmm13 + movaps 0x90(%rsp),%xmm14 + movaps 0xa0(%rsp),%xmm15 + lea 0xb8(%rsp),%rsp +.Ldec_key_epilogue: +___ +$code.=<<___; + xor %eax,%eax + ret +.size ${PREFIX}_set_decrypt_key,.-${PREFIX}_set_decrypt_key + +.globl ${PREFIX}_encrypt +.type ${PREFIX}_encrypt,\@function,3 +.align 16 +${PREFIX}_encrypt: +___ +$code.=<<___ if ($win64); + lea -0xb8(%rsp),%rsp + movaps %xmm6,0x10(%rsp) + movaps %xmm7,0x20(%rsp) + movaps %xmm8,0x30(%rsp) + movaps %xmm9,0x40(%rsp) + movaps %xmm10,0x50(%rsp) + movaps %xmm11,0x60(%rsp) + movaps %xmm12,0x70(%rsp) + movaps %xmm13,0x80(%rsp) + movaps %xmm14,0x90(%rsp) + movaps %xmm15,0xa0(%rsp) +.Lenc_body: +___ +$code.=<<___; + movdqu (%rdi),%xmm0 + call _vpaes_preheat + call _vpaes_encrypt_core + movdqu %xmm0,(%rsi) +___ +$code.=<<___ if ($win64); + movaps 0x10(%rsp),%xmm6 + movaps 0x20(%rsp),%xmm7 + movaps 0x30(%rsp),%xmm8 + movaps 0x40(%rsp),%xmm9 + movaps 0x50(%rsp),%xmm10 + movaps 0x60(%rsp),%xmm11 + movaps 0x70(%rsp),%xmm12 + movaps 0x80(%rsp),%xmm13 + movaps 0x90(%rsp),%xmm14 + movaps 0xa0(%rsp),%xmm15 + lea 0xb8(%rsp),%rsp +.Lenc_epilogue: +___ +$code.=<<___; + ret +.size ${PREFIX}_encrypt,.-${PREFIX}_encrypt + +.globl ${PREFIX}_decrypt +.type ${PREFIX}_decrypt,\@function,3 +.align 16 +${PREFIX}_decrypt: +___ +$code.=<<___ if ($win64); + lea -0xb8(%rsp),%rsp + movaps %xmm6,0x10(%rsp) + movaps %xmm7,0x20(%rsp) + movaps %xmm8,0x30(%rsp) + movaps %xmm9,0x40(%rsp) + movaps %xmm10,0x50(%rsp) + movaps %xmm11,0x60(%rsp) + movaps %xmm12,0x70(%rsp) + movaps %xmm13,0x80(%rsp) + movaps %xmm14,0x90(%rsp) + movaps %xmm15,0xa0(%rsp) +.Ldec_body: +___ +$code.=<<___; + movdqu (%rdi),%xmm0 + call _vpaes_preheat + call _vpaes_decrypt_core + movdqu %xmm0,(%rsi) +___ +$code.=<<___ if ($win64); + movaps 0x10(%rsp),%xmm6 + movaps 0x20(%rsp),%xmm7 + movaps 0x30(%rsp),%xmm8 + movaps 0x40(%rsp),%xmm9 + movaps 0x50(%rsp),%xmm10 + movaps 0x60(%rsp),%xmm11 + movaps 0x70(%rsp),%xmm12 + movaps 0x80(%rsp),%xmm13 + movaps 0x90(%rsp),%xmm14 + movaps 0xa0(%rsp),%xmm15 + lea 0xb8(%rsp),%rsp +.Ldec_epilogue: +___ +$code.=<<___; + ret +.size ${PREFIX}_decrypt,.-${PREFIX}_decrypt +___ +{ +my ($inp,$out,$len,$key,$ivp,$enc)=("%rdi","%rsi","%rdx","%rcx","%r8","%r9"); +# void AES_cbc_encrypt (const void char *inp, unsigned char *out, +# size_t length, const AES_KEY *key, +# unsigned char *ivp,const int enc); +$code.=<<___; +.globl ${PREFIX}_cbc_encrypt +.type ${PREFIX}_cbc_encrypt,\@function,6 +.align 16 +${PREFIX}_cbc_encrypt: + xchg $key,$len +___ +($len,$key)=($key,$len); +$code.=<<___; + sub \$16,$len + jc .Lcbc_abort +___ +$code.=<<___ if ($win64); + lea -0xb8(%rsp),%rsp + movaps %xmm6,0x10(%rsp) + movaps %xmm7,0x20(%rsp) + movaps %xmm8,0x30(%rsp) + movaps %xmm9,0x40(%rsp) + movaps %xmm10,0x50(%rsp) + movaps %xmm11,0x60(%rsp) + movaps %xmm12,0x70(%rsp) + movaps %xmm13,0x80(%rsp) + movaps %xmm14,0x90(%rsp) + movaps %xmm15,0xa0(%rsp) +.Lcbc_body: +___ +$code.=<<___; + movdqu ($ivp),%xmm6 # load IV + sub $inp,$out + call _vpaes_preheat + cmp \$0,${enc}d + je .Lcbc_dec_loop + jmp .Lcbc_enc_loop +.align 16 +.Lcbc_enc_loop: + movdqu ($inp),%xmm0 + pxor %xmm6,%xmm0 + call _vpaes_encrypt_core + movdqa %xmm0,%xmm6 + movdqu %xmm0,($out,$inp) + lea 16($inp),$inp + sub \$16,$len + jnc .Lcbc_enc_loop + jmp .Lcbc_done +.align 16 +.Lcbc_dec_loop: + movdqu ($inp),%xmm0 + movdqa %xmm0,%xmm7 + call _vpaes_decrypt_core + pxor %xmm6,%xmm0 + movdqa %xmm7,%xmm6 + movdqu %xmm0,($out,$inp) + lea 16($inp),$inp + sub \$16,$len + jnc .Lcbc_dec_loop +.Lcbc_done: + movdqu %xmm6,($ivp) # save IV +___ +$code.=<<___ if ($win64); + movaps 0x10(%rsp),%xmm6 + movaps 0x20(%rsp),%xmm7 + movaps 0x30(%rsp),%xmm8 + movaps 0x40(%rsp),%xmm9 + movaps 0x50(%rsp),%xmm10 + movaps 0x60(%rsp),%xmm11 + movaps 0x70(%rsp),%xmm12 + movaps 0x80(%rsp),%xmm13 + movaps 0x90(%rsp),%xmm14 + movaps 0xa0(%rsp),%xmm15 + lea 0xb8(%rsp),%rsp +.Lcbc_epilogue: +___ +$code.=<<___; +.Lcbc_abort: + ret +.size ${PREFIX}_cbc_encrypt,.-${PREFIX}_cbc_encrypt +___ +} +$code.=<<___; +## +## _aes_preheat +## +## Fills register %r10 -> .aes_consts (so you can -fPIC) +## and %xmm9-%xmm15 as specified below. +## +.type _vpaes_preheat,\@abi-omnipotent +.align 16 +_vpaes_preheat: + lea .Lk_s0F(%rip), %r10 + movdqa -0x20(%r10), %xmm10 # .Lk_inv + movdqa -0x10(%r10), %xmm11 # .Lk_inv+16 + movdqa 0x00(%r10), %xmm9 # .Lk_s0F + movdqa 0x30(%r10), %xmm13 # .Lk_sb1 + movdqa 0x40(%r10), %xmm12 # .Lk_sb1+16 + movdqa 0x50(%r10), %xmm15 # .Lk_sb2 + movdqa 0x60(%r10), %xmm14 # .Lk_sb2+16 + ret +.size _vpaes_preheat,.-_vpaes_preheat +######################################################## +## ## +## Constants ## +## ## +######################################################## +.type _vpaes_consts,\@object +.align 64 +_vpaes_consts: +.Lk_inv: # inv, inva + .quad 0x0E05060F0D080180, 0x040703090A0B0C02 + .quad 0x01040A060F0B0780, 0x030D0E0C02050809 + +.Lk_s0F: # s0F + .quad 0x0F0F0F0F0F0F0F0F, 0x0F0F0F0F0F0F0F0F + +.Lk_ipt: # input transform (lo, hi) + .quad 0xC2B2E8985A2A7000, 0xCABAE09052227808 + .quad 0x4C01307D317C4D00, 0xCD80B1FCB0FDCC81 + +.Lk_sb1: # sb1u, sb1t + .quad 0xB19BE18FCB503E00, 0xA5DF7A6E142AF544 + .quad 0x3618D415FAE22300, 0x3BF7CCC10D2ED9EF +.Lk_sb2: # sb2u, sb2t + .quad 0xE27A93C60B712400, 0x5EB7E955BC982FCD + .quad 0x69EB88400AE12900, 0xC2A163C8AB82234A +.Lk_sbo: # sbou, sbot + .quad 0xD0D26D176FBDC700, 0x15AABF7AC502A878 + .quad 0xCFE474A55FBB6A00, 0x8E1E90D1412B35FA + +.Lk_mc_forward: # mc_forward + .quad 0x0407060500030201, 0x0C0F0E0D080B0A09 + .quad 0x080B0A0904070605, 0x000302010C0F0E0D + .quad 0x0C0F0E0D080B0A09, 0x0407060500030201 + .quad 0x000302010C0F0E0D, 0x080B0A0904070605 + +.Lk_mc_backward:# mc_backward + .quad 0x0605040702010003, 0x0E0D0C0F0A09080B + .quad 0x020100030E0D0C0F, 0x0A09080B06050407 + .quad 0x0E0D0C0F0A09080B, 0x0605040702010003 + .quad 0x0A09080B06050407, 0x020100030E0D0C0F + +.Lk_sr: # sr + .quad 0x0706050403020100, 0x0F0E0D0C0B0A0908 + .quad 0x030E09040F0A0500, 0x0B06010C07020D08 + .quad 0x0F060D040B020900, 0x070E050C030A0108 + .quad 0x0B0E0104070A0D00, 0x0306090C0F020508 + +.Lk_rcon: # rcon + .quad 0x1F8391B9AF9DEEB6, 0x702A98084D7C7D81 + +.Lk_s63: # s63: all equal to 0x63 transformed + .quad 0x5B5B5B5B5B5B5B5B, 0x5B5B5B5B5B5B5B5B + +.Lk_opt: # output transform + .quad 0xFF9F4929D6B66000, 0xF7974121DEBE6808 + .quad 0x01EDBD5150BCEC00, 0xE10D5DB1B05C0CE0 + +.Lk_deskew: # deskew tables: inverts the sbox's "skew" + .quad 0x07E4A34047A4E300, 0x1DFEB95A5DBEF91A + .quad 0x5F36B5DC83EA6900, 0x2841C2ABF49D1E77 + +## +## Decryption stuff +## Key schedule constants +## +.Lk_dksd: # decryption key schedule: invskew x*D + .quad 0xFEB91A5DA3E44700, 0x0740E3A45A1DBEF9 + .quad 0x41C277F4B5368300, 0x5FDC69EAAB289D1E +.Lk_dksb: # decryption key schedule: invskew x*B + .quad 0x9A4FCA1F8550D500, 0x03D653861CC94C99 + .quad 0x115BEDA7B6FC4A00, 0xD993256F7E3482C8 +.Lk_dkse: # decryption key schedule: invskew x*E + 0x63 + .quad 0xD5031CCA1FC9D600, 0x53859A4C994F5086 + .quad 0xA23196054FDC7BE8, 0xCD5EF96A20B31487 +.Lk_dks9: # decryption key schedule: invskew x*9 + .quad 0xB6116FC87ED9A700, 0x4AED933482255BFC + .quad 0x4576516227143300, 0x8BB89FACE9DAFDCE + +## +## Decryption stuff +## Round function constants +## +.Lk_dipt: # decryption input transform + .quad 0x0F505B040B545F00, 0x154A411E114E451A + .quad 0x86E383E660056500, 0x12771772F491F194 + +.Lk_dsb9: # decryption sbox output *9*u, *9*t + .quad 0x851C03539A86D600, 0xCAD51F504F994CC9 + .quad 0xC03B1789ECD74900, 0x725E2C9EB2FBA565 +.Lk_dsbd: # decryption sbox output *D*u, *D*t + .quad 0x7D57CCDFE6B1A200, 0xF56E9B13882A4439 + .quad 0x3CE2FAF724C6CB00, 0x2931180D15DEEFD3 +.Lk_dsbb: # decryption sbox output *B*u, *B*t + .quad 0xD022649296B44200, 0x602646F6B0F2D404 + .quad 0xC19498A6CD596700, 0xF3FF0C3E3255AA6B +.Lk_dsbe: # decryption sbox output *E*u, *E*t + .quad 0x46F2929626D4D000, 0x2242600464B4F6B0 + .quad 0x0C55A6CDFFAAC100, 0x9467F36B98593E32 +.Lk_dsbo: # decryption sbox final output + .quad 0x1387EA537EF94000, 0xC7AA6DB9D4943E2D + .quad 0x12D7560F93441D00, 0xCA4B8159D8C58E9C +.asciz "Vector Permutation AES for x86_64/SSSE3, Mike Hamburg (Stanford University)" +.align 64 +.size _vpaes_consts,.-_vpaes_consts +___ + +if ($win64) { +# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame, +# CONTEXT *context,DISPATCHER_CONTEXT *disp) +$rec="%rcx"; +$frame="%rdx"; +$context="%r8"; +$disp="%r9"; + +$code.=<<___; +.extern __imp_RtlVirtualUnwind +.type se_handler,\@abi-omnipotent +.align 16 +se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + mov 8($disp),%rsi # disp->ImageBase + mov 56($disp),%r11 # disp->HandlerData + + mov 0(%r11),%r10d # HandlerData[0] + lea (%rsi,%r10),%r10 # prologue label + cmp %r10,%rbx # context->RipRsp + + mov 4(%r11),%r10d # HandlerData[1] + lea (%rsi,%r10),%r10 # epilogue label + cmp %r10,%rbx # context->Rip>=epilogue label + jae .Lin_prologue + + lea 16(%rax),%rsi # %xmm save area + lea 512($context),%rdi # &context.Xmm6 + mov \$20,%ecx # 10*sizeof(%xmm0)/sizeof(%rax) + .long 0xa548f3fc # cld; rep movsq + lea 0xb8(%rax),%rax # adjust stack pointer + +.Lin_prologue: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + + mov 40($disp),%rdi # disp->ContextRecord + mov $context,%rsi # context + mov \$`1232/8`,%ecx # sizeof(CONTEXT) + .long 0xa548f3fc # cld; rep movsq + + mov $disp,%rsi + xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER + mov 8(%rsi),%rdx # arg2, disp->ImageBase + mov 0(%rsi),%r8 # arg3, disp->ControlPc + mov 16(%rsi),%r9 # arg4, disp->FunctionEntry + mov 40(%rsi),%r10 # disp->ContextRecord + lea 56(%rsi),%r11 # &disp->HandlerData + lea 24(%rsi),%r12 # &disp->EstablisherFrame + mov %r10,32(%rsp) # arg5 + mov %r11,40(%rsp) # arg6 + mov %r12,48(%rsp) # arg7 + mov %rcx,56(%rsp) # arg8, (NULL) + call *__imp_RtlVirtualUnwind(%rip) + + mov \$1,%eax # ExceptionContinueSearch + add \$64,%rsp + popfq + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + pop %rdi + pop %rsi + ret +.size se_handler,.-se_handler + +.section .pdata +.align 4 + .rva .LSEH_begin_${PREFIX}_set_encrypt_key + .rva .LSEH_end_${PREFIX}_set_encrypt_key + .rva .LSEH_info_${PREFIX}_set_encrypt_key + + .rva .LSEH_begin_${PREFIX}_set_decrypt_key + .rva .LSEH_end_${PREFIX}_set_decrypt_key + .rva .LSEH_info_${PREFIX}_set_decrypt_key + + .rva .LSEH_begin_${PREFIX}_encrypt + .rva .LSEH_end_${PREFIX}_encrypt + .rva .LSEH_info_${PREFIX}_encrypt + + .rva .LSEH_begin_${PREFIX}_decrypt + .rva .LSEH_end_${PREFIX}_decrypt + .rva .LSEH_info_${PREFIX}_decrypt + + .rva .LSEH_begin_${PREFIX}_cbc_encrypt + .rva .LSEH_end_${PREFIX}_cbc_encrypt + .rva .LSEH_info_${PREFIX}_cbc_encrypt + +.section .xdata +.align 8 +.LSEH_info_${PREFIX}_set_encrypt_key: + .byte 9,0,0,0 + .rva se_handler + .rva .Lenc_key_body,.Lenc_key_epilogue # HandlerData[] +.LSEH_info_${PREFIX}_set_decrypt_key: + .byte 9,0,0,0 + .rva se_handler + .rva .Ldec_key_body,.Ldec_key_epilogue # HandlerData[] +.LSEH_info_${PREFIX}_encrypt: + .byte 9,0,0,0 + .rva se_handler + .rva .Lenc_body,.Lenc_epilogue # HandlerData[] +.LSEH_info_${PREFIX}_decrypt: + .byte 9,0,0,0 + .rva se_handler + .rva .Ldec_body,.Ldec_epilogue # HandlerData[] +.LSEH_info_${PREFIX}_cbc_encrypt: + .byte 9,0,0,0 + .rva se_handler + .rva .Lcbc_body,.Lcbc_epilogue # HandlerData[] +___ +} + +$code =~ s/\`([^\`]*)\`/eval($1)/gem; + +print $code; + +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/aes/internal.h b/TMessagesProj/jni/boringssl/crypto/aes/internal.h new file mode 100644 index 00000000..3dc5c637 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/aes/internal.h @@ -0,0 +1,87 @@ +/* ==================================================================== + * Copyright (c) 2002-2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== */ + +#ifndef OPENSSL_HEADER_AES_INTERNAL_H +#define OPENSSL_HEADER_AES_INTERNAL_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +#if defined(_MSC_VER) && \ + (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64)) +#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00) +#define GETU32(p) SWAP(*((uint32_t *)(p))) +#define PUTU32(ct, st) \ + { *((uint32_t *)(ct)) = SWAP((st)); } +#else +#define GETU32(pt) \ + (((uint32_t)(pt)[0] << 24) ^ ((uint32_t)(pt)[1] << 16) ^ \ + ((uint32_t)(pt)[2] << 8) ^ ((uint32_t)(pt)[3])) +#define PUTU32(ct, st) \ + { \ + (ct)[0] = (uint8_t)((st) >> 24); \ + (ct)[1] = (uint8_t)((st) >> 16); \ + (ct)[2] = (uint8_t)((st) >> 8); \ + (ct)[3] = (uint8_t)(st); \ + } +#endif + +#define MAXKC (256 / 32) +#define MAXKB (256 / 8) +#define MAXNR 14 + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_AES_INTERNAL_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/aes/mode_wrappers.c b/TMessagesProj/jni/boringssl/crypto/aes/mode_wrappers.c new file mode 100644 index 00000000..c706896d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/aes/mode_wrappers.c @@ -0,0 +1,108 @@ +/* ==================================================================== + * Copyright (c) 2002-2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== */ + +#include + +#include "assert.h" + +#include + + +void AES_ctr128_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const AES_KEY *key, uint8_t ivec[AES_BLOCK_SIZE], + uint8_t ecount_buf[AES_BLOCK_SIZE], unsigned int *num) { + CRYPTO_ctr128_encrypt(in, out, len, key, ivec, ecount_buf, num, + (block128_f)AES_encrypt); +} + +void AES_ecb_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key, + const int enc) { + assert(in && out && key); + assert((AES_ENCRYPT == enc) || (AES_DECRYPT == enc)); + + if (AES_ENCRYPT == enc) { + AES_encrypt(in, out, key); + } else { + AES_decrypt(in, out, key); + } +} + +#if defined(OPENSSL_NO_ASM) || \ + (!defined(OPENSSL_X86_64) && !defined(OPENSSL_X86)) +void AES_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const AES_KEY *key, uint8_t *ivec, const int enc) { + + if (enc) { + CRYPTO_cbc128_encrypt(in, out, len, key, ivec, (block128_f)AES_encrypt); + } else { + CRYPTO_cbc128_decrypt(in, out, len, key, ivec, (block128_f)AES_decrypt); + } +} +#else + +void asm_AES_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const AES_KEY *key, uint8_t *ivec, const int enc); +void AES_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const AES_KEY *key, uint8_t *ivec, const int enc) { + asm_AES_cbc_encrypt(in, out, len, key, ivec, enc); +} + +#endif /* OPENSSL_NO_ASM || (!OPENSSL_X86_64 && !OPENSSL_X86) */ + +void AES_ofb128_encrypt(const uint8_t *in, uint8_t *out, size_t length, + const AES_KEY *key, uint8_t *ivec, int *num) { + CRYPTO_ofb128_encrypt(in, out, length, key, ivec, num, + (block128_f)AES_encrypt); +} + +void AES_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t length, + const AES_KEY *key, uint8_t *ivec, int *num, + int enc) { + CRYPTO_cfb128_encrypt(in, out, length, key, ivec, num, enc, + (block128_f)AES_encrypt); +} diff --git a/TMessagesProj/jni/boringssl/crypto/arm_arch.h b/TMessagesProj/jni/boringssl/crypto/arm_arch.h new file mode 100644 index 00000000..0600fbb1 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/arm_arch.h @@ -0,0 +1,136 @@ +/* ==================================================================== + * Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef OPENSSL_HEADER_ARM_ARCH_H +#define OPENSSL_HEADER_ARM_ARCH_H + +#if !defined(__ARM_ARCH__) +# if defined(__CC_ARM) +# define __ARM_ARCH__ __TARGET_ARCH_ARM +# if defined(__BIG_ENDIAN) +# define __ARMEB__ +# else +# define __ARMEL__ +# endif +# elif defined(__GNUC__) +# if defined(__aarch64__) +# define __ARM_ARCH__ 8 +# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define __ARMEB__ +# else +# define __ARMEL__ +# endif + /* Why doesn't gcc define __ARM_ARCH__? Instead it defines + * bunch of below macros. See all_architectires[] table in + * gcc/config/arm/arm.c. On a side note it defines + * __ARMEL__/__ARMEB__ for little-/big-endian. */ +# elif defined(__ARM_ARCH) +# define __ARM_ARCH__ __ARM_ARCH +# elif defined(__ARM_ARCH_8A__) +# define __ARM_ARCH__ 8 +# elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || \ + defined(__ARM_ARCH_7R__)|| defined(__ARM_ARCH_7M__) || \ + defined(__ARM_ARCH_7EM__) +# define __ARM_ARCH__ 7 +# elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \ + defined(__ARM_ARCH_6K__)|| defined(__ARM_ARCH_6M__) || \ + defined(__ARM_ARCH_6Z__)|| defined(__ARM_ARCH_6ZK__) || \ + defined(__ARM_ARCH_6T2__) +# define __ARM_ARCH__ 6 +# elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) || \ + defined(__ARM_ARCH_5E__)|| defined(__ARM_ARCH_5TE__) || \ + defined(__ARM_ARCH_5TEJ__) +# define __ARM_ARCH__ 5 +# elif defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) +# define __ARM_ARCH__ 4 +# else +# error "unsupported ARM architecture" +# endif +# endif +#endif + +/* Even when building for 32-bit ARM, support for aarch64 crypto instructions + * will be included. */ +#define __ARM_MAX_ARCH__ 8 + +#if !__ASSEMBLER__ + +/* OPENSSL_armcap_P contains flags describing the capabilities of the CPU and + * is easy for assembly code to acesss. For C code, see the functions in + * |cpu.h|. */ +extern uint32_t OPENSSL_armcap_P; + +#endif /* !__ASSEMBLER__ */ + +/* ARMV7_NEON is true when a NEON unit is present in the current CPU. */ +#define ARMV7_NEON (1 << 0) + +/* ARMV7_NEON_FUNCTIONAL is true when the NEON unit doesn't contain subtle bugs. + * The Poly1305 NEON code is known to trigger bugs in the NEON units of some + * phones. If this bit isn't set then the Poly1305 NEON code won't be used. + * See https://code.google.com/p/chromium/issues/detail?id=341598. */ +#define ARMV7_NEON_FUNCTIONAL (1 << 10) + +/* ARMV8_AES indicates support for hardware AES instructions. */ +#define ARMV8_AES (1 << 2) + +/* ARMV8_SHA1 indicates support for hardware SHA-1 instructions. */ +#define ARMV8_SHA1 (1 << 3) + +/* ARMV8_SHA256 indicates support for hardware SHA-256 instructions. */ +#define ARMV8_SHA256 (1 << 4) + +/* ARMV8_PMULL indicates support for carryless multiplication. */ +#define ARMV8_PMULL (1 << 5) + + +#endif /* OPENSSL_HEADER_THREAD_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/asn1/CMakeLists.txt new file mode 100644 index 00000000..283636e2 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/CMakeLists.txt @@ -0,0 +1,45 @@ +include_directories(. .. ../../include) + +add_library( + asn1 + + OBJECT + + a_bitstr.c + a_bool.c + a_bytes.c + a_d2i_fp.c + a_dup.c + a_enum.c + a_gentm.c + a_i2d_fp.c + a_int.c + a_mbstr.c + a_object.c + a_octet.c + a_print.c + a_strnid.c + a_time.c + a_type.c + a_utctm.c + a_utf8.c + asn1_lib.c + asn1_par.c + asn_pack.c + bio_asn1.c + bio_ndef.c + f_enum.c + f_int.c + f_string.c + t_bitst.c + t_pkey.c + tasn_dec.c + tasn_enc.c + tasn_fre.c + tasn_new.c + tasn_prn.c + tasn_typ.c + tasn_utl.c + x_bignum.c + x_long.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_bitstr.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_bitstr.c new file mode 100644 index 00000000..8bad3394 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_bitstr.c @@ -0,0 +1,255 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include + + +int ASN1_BIT_STRING_set(ASN1_BIT_STRING *x, unsigned char *d, int len) +{ return M_ASN1_BIT_STRING_set(x, d, len); } + +int i2c_ASN1_BIT_STRING(ASN1_BIT_STRING *a, unsigned char **pp) + { + int ret,j,bits,len; + unsigned char *p,*d; + + if (a == NULL) return(0); + + len=a->length; + + if (len > 0) + { + if (a->flags & ASN1_STRING_FLAG_BITS_LEFT) + { + bits=(int)a->flags&0x07; + } + else + { + for ( ; len > 0; len--) + { + if (a->data[len-1]) break; + } + j=a->data[len-1]; + if (j & 0x01) bits=0; + else if (j & 0x02) bits=1; + else if (j & 0x04) bits=2; + else if (j & 0x08) bits=3; + else if (j & 0x10) bits=4; + else if (j & 0x20) bits=5; + else if (j & 0x40) bits=6; + else if (j & 0x80) bits=7; + else bits=0; /* should not happen */ + } + } + else + bits=0; + + ret=1+len; + if (pp == NULL) return(ret); + + p= *pp; + + *(p++)=(unsigned char)bits; + d=a->data; + memcpy(p,d,len); + p+=len; + if (len > 0) p[-1]&=(0xff< 7) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_BIT_STRING_BITS_LEFT); + goto err; + } + + /* We do this to preserve the settings. If we modify + * the settings, via the _set_bit function, we will recalculate + * on output */ + ret->flags&= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07); /* clear */ + ret->flags|=(ASN1_STRING_FLAG_BITS_LEFT|padding); /* set */ + + if (len-- > 1) /* using one because of the bits left byte */ + { + s=(unsigned char *)OPENSSL_malloc((int)len); + if (s == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto err; + } + memcpy(s,p,(int)len); + s[len-1]&=(0xff<length=(int)len; + if (ret->data != NULL) OPENSSL_free(ret->data); + ret->data=s; + ret->type=V_ASN1_BIT_STRING; + if (a != NULL) (*a)=ret; + *pp=p; + return(ret); +err: + if ((ret != NULL) && ((a == NULL) || (*a != ret))) + M_ASN1_BIT_STRING_free(ret); + return(NULL); + } + +/* These next 2 functions from Goetz Babin-Ebell + */ +int ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *a, int n, int value) + { + int w,v,iv; + unsigned char *c; + + w=n/8; + v=1<<(7-(n&0x07)); + iv= ~v; + if (!value) v=0; + + if (a == NULL) + return 0; + + a->flags&= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07); /* clear, set on write */ + + if ((a->length < (w+1)) || (a->data == NULL)) + { + if (!value) return(1); /* Don't need to set */ + if (a->data == NULL) + c=(unsigned char *)OPENSSL_malloc(w+1); + else + c=(unsigned char *)OPENSSL_realloc_clean(a->data, + a->length, + w+1); + if (c == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return 0; + } + if (w+1-a->length > 0) memset(c+a->length, 0, w+1-a->length); + a->data=c; + a->length=w+1; + } + a->data[w]=((a->data[w])&iv)|v; + while ((a->length > 0) && (a->data[a->length-1] == 0)) + a->length--; + return(1); + } + +int ASN1_BIT_STRING_get_bit(ASN1_BIT_STRING *a, int n) + { + int w,v; + + w=n/8; + v=1<<(7-(n&0x07)); + if ((a == NULL) || (a->length < (w+1)) || (a->data == NULL)) + return(0); + return((a->data[w]&v) != 0); + } + +/* + * Checks if the given bit string contains only bits specified by + * the flags vector. Returns 0 if there is at least one bit set in 'a' + * which is not specified in 'flags', 1 otherwise. + * 'len' is the length of 'flags'. + */ +int ASN1_BIT_STRING_check(ASN1_BIT_STRING *a, + unsigned char *flags, int flags_len) + { + int i, ok; + /* Check if there is one bit set at all. */ + if (!a || !a->data) return 1; + + /* Check each byte of the internal representation of the bit string. */ + ok = 1; + for (i = 0; i < a->length && ok; ++i) + { + unsigned char mask = i < flags_len ? ~flags[i] : 0xff; + /* We are done if there is an unneeded bit set. */ + ok = (a->data[i] & mask) == 0; + } + return ok; + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_bool.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_bool.c new file mode 100644 index 00000000..826bcf43 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_bool.c @@ -0,0 +1,112 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + +int i2d_ASN1_BOOLEAN(int a, unsigned char **pp) + { + int r; + unsigned char *p; + + r=ASN1_object_size(0,1,V_ASN1_BOOLEAN); + if (pp == NULL) return(r); + p= *pp; + + ASN1_put_object(&p,0,1,V_ASN1_BOOLEAN,V_ASN1_UNIVERSAL); + *(p++)= (unsigned char)a; + *pp=p; + return(r); + } + +int d2i_ASN1_BOOLEAN(int *a, const unsigned char **pp, long length) + { + int ret= -1; + const unsigned char *p; + long len; + int inf,tag,xclass; + int i=0; + + p= *pp; + inf=ASN1_get_object(&p,&len,&tag,&xclass,length); + if (inf & 0x80) + { + i=ASN1_R_BAD_OBJECT_HEADER; + goto err; + } + + if (tag != V_ASN1_BOOLEAN) + { + i=ASN1_R_EXPECTING_A_BOOLEAN; + goto err; + } + + if (len != 1) + { + i=ASN1_R_BOOLEAN_IS_WRONG_LENGTH; + goto err; + } + ret= (int)*(p++); + if (a != NULL) (*a)=ret; + *pp=p; + return(ret); +err: + OPENSSL_PUT_ERROR(ASN1, i); + return(ret); + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_bytes.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_bytes.c new file mode 100644 index 00000000..19043755 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_bytes.c @@ -0,0 +1,317 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include + + +static int asn1_collate_primitive(ASN1_STRING *a, ASN1_const_CTX *c); +/* type is a 'bitmap' of acceptable string types. + */ +ASN1_STRING *d2i_ASN1_type_bytes(ASN1_STRING **a, const unsigned char **pp, + long length, int type) + { + ASN1_STRING *ret=NULL; + const unsigned char *p; + unsigned char *s; + long len; + int inf,tag,xclass; + int i=0; + + p= *pp; + inf=ASN1_get_object(&p,&len,&tag,&xclass,length); + if (inf & 0x80) goto err; + + if (tag >= 32) + { + i=ASN1_R_TAG_VALUE_TOO_HIGH; + goto err; + } + if (!(ASN1_tag2bit(tag) & type)) + { + i=ASN1_R_WRONG_TYPE; + goto err; + } + + /* If a bit-string, exit early */ + if (tag == V_ASN1_BIT_STRING) + return(d2i_ASN1_BIT_STRING(a,pp,length)); + + if ((a == NULL) || ((*a) == NULL)) + { + if ((ret=ASN1_STRING_new()) == NULL) return(NULL); + } + else + ret=(*a); + + if (len != 0) + { + s=(unsigned char *)OPENSSL_malloc((int)len+1); + if (s == NULL) + { + i=ERR_R_MALLOC_FAILURE; + goto err; + } + memcpy(s,p,(int)len); + s[len]='\0'; + p+=len; + } + else + s=NULL; + + if (ret->data != NULL) OPENSSL_free(ret->data); + ret->length=(int)len; + ret->data=s; + ret->type=tag; + if (a != NULL) (*a)=ret; + *pp=p; + return(ret); +err: + OPENSSL_PUT_ERROR(ASN1, i); + if ((ret != NULL) && ((a == NULL) || (*a != ret))) + ASN1_STRING_free(ret); + return(NULL); + } + +int i2d_ASN1_bytes(ASN1_STRING *a, unsigned char **pp, int tag, int xclass) + { + int ret,r,constructed; + unsigned char *p; + + if (a == NULL) return(0); + + if (tag == V_ASN1_BIT_STRING) + return(i2d_ASN1_BIT_STRING(a,pp)); + + ret=a->length; + r=ASN1_object_size(0,ret,tag); + if (pp == NULL) return(r); + p= *pp; + + if ((tag == V_ASN1_SEQUENCE) || (tag == V_ASN1_SET)) + constructed=1; + else + constructed=0; + ASN1_put_object(&p,constructed,ret,tag,xclass); + memcpy(p,a->data,a->length); + p+=a->length; + *pp= p; + return(r); + } + +ASN1_STRING *d2i_ASN1_bytes(ASN1_STRING **a, const unsigned char **pp, + long length, int Ptag, int Pclass) + { + ASN1_STRING *ret=NULL; + const unsigned char *p; + unsigned char *s; + long len; + int inf,tag,xclass; + int i=0; + + if ((a == NULL) || ((*a) == NULL)) + { + if ((ret=ASN1_STRING_new()) == NULL) return(NULL); + } + else + ret=(*a); + + p= *pp; + inf=ASN1_get_object(&p,&len,&tag,&xclass,length); + if (inf & 0x80) + { + i=ASN1_R_BAD_OBJECT_HEADER; + goto err; + } + + if (tag != Ptag) + { + i=ASN1_R_WRONG_TAG; + goto err; + } + + if (inf & V_ASN1_CONSTRUCTED) + { + ASN1_const_CTX c; + + c.pp=pp; + c.p=p; + c.inf=inf; + c.slen=len; + c.tag=Ptag; + c.xclass=Pclass; + c.max=(length == 0)?0:(p+length); + if (!asn1_collate_primitive(ret,&c)) + goto err; + else + { + p=c.p; + } + } + else + { + if (len != 0) + { + if ((ret->length < len) || (ret->data == NULL)) + { + if (ret->data != NULL) OPENSSL_free(ret->data); + s=(unsigned char *)OPENSSL_malloc((int)len + 1); + if (s == NULL) + { + i=ERR_R_MALLOC_FAILURE; + goto err; + } + } + else + s=ret->data; + memcpy(s,p,(int)len); + s[len] = '\0'; + p+=len; + } + else + { + s=NULL; + if (ret->data != NULL) OPENSSL_free(ret->data); + } + + ret->length=(int)len; + ret->data=s; + ret->type=Ptag; + } + + if (a != NULL) (*a)=ret; + *pp=p; + return(ret); +err: + if ((ret != NULL) && ((a == NULL) || (*a != ret))) + ASN1_STRING_free(ret); + OPENSSL_PUT_ERROR(ASN1, i); + return(NULL); + } + + +/* We are about to parse 0..n d2i_ASN1_bytes objects, we are to collapse + * them into the one structure that is then returned */ +/* There have been a few bug fixes for this function from + * Paul Keogh , many thanks to him */ +static int asn1_collate_primitive(ASN1_STRING *a, ASN1_const_CTX *c) + { + ASN1_STRING *os=NULL; + BUF_MEM b; + int num; + + b.length=0; + b.max=0; + b.data=NULL; + + if (a == NULL) + { + c->error=ERR_R_PASSED_NULL_PARAMETER; + goto err; + } + + num=0; + for (;;) + { + if (c->inf & 1) + { + c->eos=ASN1_const_check_infinite_end(&c->p, + (long)(c->max-c->p)); + if (c->eos) break; + } + else + { + if (c->slen <= 0) break; + } + + c->q=c->p; + if (d2i_ASN1_bytes(&os,&c->p,c->max-c->p,c->tag,c->xclass) + == NULL) + { + c->error=ERR_R_ASN1_LIB; + goto err; + } + + if (!BUF_MEM_grow_clean(&b,num+os->length)) + { + c->error=ERR_R_BUF_LIB; + goto err; + } + memcpy(&(b.data[num]),os->data,os->length); + if (!(c->inf & 1)) + c->slen-=(c->p-c->q); + num+=os->length; + } + + if (!asn1_const_Finish(c)) goto err; + + a->length=num; + if (a->data != NULL) OPENSSL_free(a->data); + a->data=(unsigned char *)b.data; + if (os != NULL) ASN1_STRING_free(os); + return(1); +err: + OPENSSL_PUT_ERROR(ASN1, c->error); + if (os != NULL) ASN1_STRING_free(os); + if (b.data != NULL) OPENSSL_free(b.data); + return(0); + } + diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_d2i_fp.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_d2i_fp.c new file mode 100644 index 00000000..97ec75b5 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_d2i_fp.c @@ -0,0 +1,286 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include + + +static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb); + +#ifndef NO_OLD_ASN1 +#ifndef OPENSSL_NO_FP_API + +void *ASN1_d2i_fp(void *(*xnew)(void), d2i_of_void *d2i, FILE *in, void **x) + { + BIO *b; + void *ret; + + if ((b=BIO_new(BIO_s_file())) == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_BUF_LIB); + return(NULL); + } + BIO_set_fp(b,in,BIO_NOCLOSE); + ret=ASN1_d2i_bio(xnew,d2i,b,x); + BIO_free(b); + return(ret); + } +#endif + +void *ASN1_d2i_bio(void *(*xnew)(void), d2i_of_void *d2i, BIO *in, void **x) + { + BUF_MEM *b = NULL; + const unsigned char *p; + void *ret=NULL; + int len; + + len = asn1_d2i_read_bio(in, &b); + if(len < 0) goto err; + + p=(unsigned char *)b->data; + ret=d2i(x,&p,len); +err: + if (b != NULL) BUF_MEM_free(b); + return(ret); + } + +#endif + +void *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *x) + { + BUF_MEM *b = NULL; + const unsigned char *p; + void *ret=NULL; + int len; + + len = asn1_d2i_read_bio(in, &b); + if(len < 0) goto err; + + p=(const unsigned char *)b->data; + ret=ASN1_item_d2i(x,&p,len, it); +err: + if (b != NULL) BUF_MEM_free(b); + return(ret); + } + +#ifndef OPENSSL_NO_FP_API +void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x) + { + BIO *b; + char *ret; + + if ((b=BIO_new(BIO_s_file())) == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_BUF_LIB); + return(NULL); + } + BIO_set_fp(b,in,BIO_NOCLOSE); + ret=ASN1_item_d2i_bio(it,b,x); + BIO_free(b); + return(ret); + } +#endif + +#define HEADER_SIZE 8 +static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb) + { + BUF_MEM *b; + unsigned char *p; + int i; + ASN1_const_CTX c; + size_t want=HEADER_SIZE; + int eos=0; + size_t off=0; + size_t len=0; + + b=BUF_MEM_new(); + if (b == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return -1; + } + + ERR_clear_error(); + for (;;) + { + if (want >= (len-off)) + { + want-=(len-off); + + if (len + want < len || !BUF_MEM_grow_clean(b,len+want)) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto err; + } + i=BIO_read(in,&(b->data[len]),want); + if ((i < 0) && ((len-off) == 0)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NOT_ENOUGH_DATA); + goto err; + } + if (i > 0) + { + if (len+i < len) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG); + goto err; + } + len+=i; + } + } + /* else data already loaded */ + + p=(unsigned char *)&(b->data[off]); + c.p=p; + c.inf=ASN1_get_object(&(c.p),&(c.slen),&(c.tag),&(c.xclass), + len-off); + if (c.inf & 0x80) + { + uint32_t e; + + e=ERR_GET_REASON(ERR_peek_error()); + if (e != ASN1_R_TOO_LONG) + goto err; + else + ERR_clear_error(); /* clear error */ + } + i=c.p-p;/* header length */ + off+=i; /* end of data */ + + if (c.inf & 1) + { + /* no data body so go round again */ + eos++; + if (eos < 0) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_HEADER_TOO_LONG); + goto err; + } + want=HEADER_SIZE; + } + else if (eos && (c.slen == 0) && (c.tag == V_ASN1_EOC)) + { + /* eos value, so go back and read another header */ + eos--; + if (eos <= 0) + break; + else + want=HEADER_SIZE; + } + else + { + /* suck in c.slen bytes of data */ + want=c.slen; + if (want > (len-off)) + { + want-=(len-off); + if (want > INT_MAX /* BIO_read takes an int length */ || + len+want < len) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG); + goto err; + } + if (!BUF_MEM_grow_clean(b,len+want)) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto err; + } + while (want > 0) + { + i=BIO_read(in,&(b->data[len]),want); + if (i <= 0) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NOT_ENOUGH_DATA); + goto err; + } + /* This can't overflow because + * |len+want| didn't overflow. */ + len+=i; + want-=i; + } + } + if (off + c.slen < off) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG); + goto err; + } + off+=c.slen; + if (eos <= 0) + { + break; + } + else + want=HEADER_SIZE; + } + } + + if (off > INT_MAX) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG); + goto err; + } + + *pb = b; + return off; +err: + if (b != NULL) BUF_MEM_free(b); + return -1; + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_dup.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_dup.c new file mode 100644 index 00000000..5e87457c --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_dup.c @@ -0,0 +1,103 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + +void *ASN1_dup(i2d_of_void *i2d, d2i_of_void *d2i, void *x) + { + unsigned char *b,*p; + const unsigned char *p2; + int i; + char *ret; + + if (x == NULL) return(NULL); + + i=i2d(x,NULL); + b=OPENSSL_malloc(i+10); + if (b == NULL) + { OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); return(NULL); } + p= b; + i=i2d(x,&p); + p2= b; + ret=d2i(NULL,&p2,i); + OPENSSL_free(b); + return(ret); + } + +/* ASN1_ITEM version of dup: this follows the model above except we don't need + * to allocate the buffer. At some point this could be rewritten to directly dup + * the underlying structure instead of doing and encode and decode. */ +void *ASN1_item_dup(const ASN1_ITEM *it, void *x) + { + unsigned char *b = NULL; + const unsigned char *p; + long i; + void *ret; + + if (x == NULL) return(NULL); + + i=ASN1_item_i2d(x,&b,it); + if (b == NULL) + { OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); return(NULL); } + p= b; + ret=ASN1_item_d2i(NULL,&p,i, it); + OPENSSL_free(b); + return(ret); + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_enum.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_enum.c new file mode 100644 index 00000000..579dafd3 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_enum.c @@ -0,0 +1,183 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include + + +/* + * Code for ENUMERATED type: identical to INTEGER apart from a different tag. + * for comments on encoding see a_int.c + */ + +int ASN1_ENUMERATED_set(ASN1_ENUMERATED *a, long v) + { + int j,k; + unsigned int i; + unsigned char buf[sizeof(long)+1]; + long d; + + a->type=V_ASN1_ENUMERATED; + if (a->length < (int)(sizeof(long)+1)) + { + if (a->data != NULL) + OPENSSL_free(a->data); + if ((a->data=(unsigned char *)OPENSSL_malloc(sizeof(long)+1)) != NULL) + memset((char *)a->data,0,sizeof(long)+1); + } + if (a->data == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return(0); + } + d=v; + if (d < 0) + { + d= -d; + a->type=V_ASN1_NEG_ENUMERATED; + } + + for (i=0; i>=8; + } + j=0; + for (k=i-1; k >=0; k--) + a->data[j++]=buf[k]; + a->length=j; + return(1); + } + +long ASN1_ENUMERATED_get(ASN1_ENUMERATED *a) + { + int neg=0,i; + long r=0; + + if (a == NULL) return(0L); + i=a->type; + if (i == V_ASN1_NEG_ENUMERATED) + neg=1; + else if (i != V_ASN1_ENUMERATED) + return -1; + + if (a->length > (int)sizeof(long)) + { + /* hmm... a bit ugly */ + return(0xffffffffL); + } + if (a->data == NULL) + return 0; + + for (i=0; ilength; i++) + { + r<<=8; + r|=(unsigned char)a->data[i]; + } + if (neg) r= -r; + return(r); + } + +ASN1_ENUMERATED *BN_to_ASN1_ENUMERATED(BIGNUM *bn, ASN1_ENUMERATED *ai) + { + ASN1_ENUMERATED *ret; + int len,j; + + if (ai == NULL) + ret=M_ASN1_ENUMERATED_new(); + else + ret=ai; + if (ret == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + goto err; + } + if(BN_is_negative(bn)) ret->type = V_ASN1_NEG_ENUMERATED; + else ret->type=V_ASN1_ENUMERATED; + j=BN_num_bits(bn); + len=((j == 0)?0:((j/8)+1)); + if (ret->length < len+4) + { + unsigned char *new_data=OPENSSL_realloc(ret->data, len+4); + if (!new_data) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto err; + } + ret->data=new_data; + } + + ret->length=BN_bn2bin(bn,ret->data); + return(ret); +err: + if (ret != ai) M_ASN1_ENUMERATED_free(ret); + return(NULL); + } + +BIGNUM *ASN1_ENUMERATED_to_BN(ASN1_ENUMERATED *ai, BIGNUM *bn) + { + BIGNUM *ret; + + if ((ret=BN_bin2bn(ai->data,ai->length,bn)) == NULL) + OPENSSL_PUT_ERROR(ASN1, ASN1_R_BN_LIB); + else if(ai->type == V_ASN1_NEG_ENUMERATED) BN_set_negative(ret,1); + return(ret); + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_gentm.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_gentm.c new file mode 100644 index 00000000..7cb18a95 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_gentm.c @@ -0,0 +1,255 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include +#include + + +int asn1_generalizedtime_to_tm(struct tm *tm, const ASN1_GENERALIZEDTIME *d) + { + static const int min[9]={ 0, 0, 1, 1, 0, 0, 0, 0, 0}; + static const int max[9]={99, 99,12,31,23,59,59,12,59}; + char *a; + int n,i,l,o; + + if (d->type != V_ASN1_GENERALIZEDTIME) return(0); + l=d->length; + a=(char *)d->data; + o=0; + /* GENERALIZEDTIME is similar to UTCTIME except the year is + * represented as YYYY. This stuff treats everything as a two digit + * field so make first two fields 00 to 99 + */ + if (l < 13) goto err; + for (i=0; i<7; i++) + { + if ((i == 6) && ((a[o] == 'Z') || + (a[o] == '+') || (a[o] == '-'))) + { + i++; + if (tm) + tm->tm_sec = 0; + break; + } + if ((a[o] < '0') || (a[o] > '9')) goto err; + n= a[o]-'0'; + if (++o > l) goto err; + + if ((a[o] < '0') || (a[o] > '9')) goto err; + n=(n*10)+ a[o]-'0'; + if (++o > l) goto err; + + if ((n < min[i]) || (n > max[i])) goto err; + if (tm) + { + switch(i) + { + case 0: + tm->tm_year = n * 100 - 1900; + break; + case 1: + tm->tm_year += n; + break; + case 2: + tm->tm_mon = n - 1; + break; + case 3: + tm->tm_mday = n; + break; + case 4: + tm->tm_hour = n; + break; + case 5: + tm->tm_min = n; + break; + case 6: + tm->tm_sec = n; + break; + } + } + } + /* Optional fractional seconds: decimal point followed by one + * or more digits. + */ + if (a[o] == '.') + { + if (++o > l) goto err; + i = o; + while ((a[o] >= '0') && (a[o] <= '9') && (o <= l)) + o++; + /* Must have at least one digit after decimal point */ + if (i == o) goto err; + } + + if (a[o] == 'Z') + o++; + else if ((a[o] == '+') || (a[o] == '-')) + { + int offsign = a[o] == '-' ? -1 : 1, offset = 0; + o++; + if (o+4 > l) goto err; + for (i=7; i<9; i++) + { + if ((a[o] < '0') || (a[o] > '9')) goto err; + n= a[o]-'0'; + o++; + if ((a[o] < '0') || (a[o] > '9')) goto err; + n=(n*10)+ a[o]-'0'; + if ((n < min[i]) || (n > max[i])) goto err; + if (tm) + { + if (i == 7) + offset = n * 3600; + else if (i == 8) + offset += n * 60; + } + o++; + } + if (offset && !OPENSSL_gmtime_adj(tm, 0, offset * offsign)) + return 0; + } + else if (a[o]) + { + /* Missing time zone information. */ + goto err; + } + return(o == l); +err: + return(0); + } + +int ASN1_GENERALIZEDTIME_check(const ASN1_GENERALIZEDTIME *d) + { + return asn1_generalizedtime_to_tm(NULL, d); + } + +int ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *s, const char *str) + { + ASN1_GENERALIZEDTIME t; + + t.type=V_ASN1_GENERALIZEDTIME; + t.length=strlen(str); + t.data=(unsigned char *)str; + if (ASN1_GENERALIZEDTIME_check(&t)) + { + if (s != NULL) + { + if (!ASN1_STRING_set((ASN1_STRING *)s, + (unsigned char *)str,t.length)) + return 0; + s->type=V_ASN1_GENERALIZEDTIME; + } + return(1); + } + else + return(0); + } + +ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_set(ASN1_GENERALIZEDTIME *s, + time_t t) + { + return ASN1_GENERALIZEDTIME_adj(s, t, 0, 0); + } + +ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_adj(ASN1_GENERALIZEDTIME *s, + time_t t, int offset_day, long offset_sec) + { + char *p; + struct tm *ts; + struct tm data; + size_t len = 20; + + if (s == NULL) + s=M_ASN1_GENERALIZEDTIME_new(); + if (s == NULL) + return(NULL); + + ts=OPENSSL_gmtime(&t, &data); + if (ts == NULL) + return(NULL); + + if (offset_day || offset_sec) + { + if (!OPENSSL_gmtime_adj(ts, offset_day, offset_sec)) + return NULL; + } + + p=(char *)s->data; + if ((p == NULL) || ((size_t)s->length < len)) + { + p=OPENSSL_malloc(len); + if (p == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return(NULL); + } + if (s->data != NULL) + OPENSSL_free(s->data); + s->data=(unsigned char *)p; + } + + BIO_snprintf(p,len,"%04d%02d%02d%02d%02d%02dZ",ts->tm_year + 1900, + ts->tm_mon+1,ts->tm_mday,ts->tm_hour,ts->tm_min,ts->tm_sec); + s->length=strlen(p); + s->type=V_ASN1_GENERALIZEDTIME; + return(s); + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_i2d_fp.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_i2d_fp.c new file mode 100644 index 00000000..8a6ce256 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_i2d_fp.c @@ -0,0 +1,154 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + +int ASN1_i2d_fp(i2d_of_void *i2d, FILE *out, void *x) + { + BIO *b; + int ret; + + if ((b=BIO_new(BIO_s_file())) == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_BUF_LIB); + return(0); + } + BIO_set_fp(b,out,BIO_NOCLOSE); + ret=ASN1_i2d_bio(i2d,b,x); + BIO_free(b); + return(ret); + } + +int ASN1_i2d_bio(i2d_of_void *i2d, BIO *out, unsigned char *x) + { + char *b; + unsigned char *p; + int i,j=0,n,ret=1; + + n=i2d(x,NULL); + b=(char *)OPENSSL_malloc(n); + if (b == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return(0); + } + + p=(unsigned char *)b; + i2d(x,&p); + + for (;;) + { + i=BIO_write(out,&(b[j]),n); + if (i == n) break; + if (i <= 0) + { + ret=0; + break; + } + j+=i; + n-=i; + } + OPENSSL_free(b); + return(ret); + } + +int ASN1_item_i2d_fp(const ASN1_ITEM *it, FILE *out, void *x) + { + BIO *b; + int ret; + + if ((b=BIO_new(BIO_s_file())) == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_BUF_LIB); + return(0); + } + BIO_set_fp(b,out,BIO_NOCLOSE); + ret=ASN1_item_i2d_bio(it,b,x); + BIO_free(b); + return(ret); + } + +int ASN1_item_i2d_bio(const ASN1_ITEM *it, BIO *out, void *x) + { + unsigned char *b = NULL; + int i,j=0,n,ret=1; + + n = ASN1_item_i2d(x, &b, it); + if (b == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return(0); + } + + for (;;) + { + i=BIO_write(out,&(b[j]),n); + if (i == n) break; + if (i <= 0) + { + ret=0; + break; + } + j+=i; + n-=i; + } + OPENSSL_free(b); + return(ret); + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_int.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_int.c new file mode 100644 index 00000000..9a565343 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_int.c @@ -0,0 +1,456 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include + + +ASN1_INTEGER *ASN1_INTEGER_dup(const ASN1_INTEGER *x) +{ return M_ASN1_INTEGER_dup(x);} + +int ASN1_INTEGER_cmp(const ASN1_INTEGER *x, const ASN1_INTEGER *y) + { + int neg, ret; + /* Compare signs */ + neg = x->type & V_ASN1_NEG; + if (neg != (y->type & V_ASN1_NEG)) + { + if (neg) + return -1; + else + return 1; + } + + ret = ASN1_STRING_cmp(x, y); + + if (neg) + return -ret; + else + return ret; + } + + +/* + * This converts an ASN1 INTEGER into its content encoding. + * The internal representation is an ASN1_STRING whose data is a big endian + * representation of the value, ignoring the sign. The sign is determined by + * the type: V_ASN1_INTEGER for positive and V_ASN1_NEG_INTEGER for negative. + * + * Positive integers are no problem: they are almost the same as the DER + * encoding, except if the first byte is >= 0x80 we need to add a zero pad. + * + * Negative integers are a bit trickier... + * The DER representation of negative integers is in 2s complement form. + * The internal form is converted by complementing each octet and finally + * adding one to the result. This can be done less messily with a little trick. + * If the internal form has trailing zeroes then they will become FF by the + * complement and 0 by the add one (due to carry) so just copy as many trailing + * zeros to the destination as there are in the source. The carry will add one + * to the last none zero octet: so complement this octet and add one and finally + * complement any left over until you get to the start of the string. + * + * Padding is a little trickier too. If the first bytes is > 0x80 then we pad + * with 0xff. However if the first byte is 0x80 and one of the following bytes + * is non-zero we pad with 0xff. The reason for this distinction is that 0x80 + * followed by optional zeros isn't padded. + */ + +int i2c_ASN1_INTEGER(ASN1_INTEGER *a, unsigned char **pp) + { + int pad=0,ret,i,neg; + unsigned char *p,*n,pb=0; + + if (a == NULL) return(0); + neg=a->type & V_ASN1_NEG; + if (a->length == 0) + ret=1; + else + { + ret=a->length; + i=a->data[0]; + if (!neg && (i > 127)) { + pad=1; + pb=0; + } else if(neg) { + if(i>128) { + pad=1; + pb=0xFF; + } else if(i == 128) { + /* + * Special case: if any other bytes non zero we pad: + * otherwise we don't. + */ + for(i = 1; i < a->length; i++) if(a->data[i]) { + pad=1; + pb=0xFF; + break; + } + } + } + ret+=pad; + } + if (pp == NULL) return(ret); + p= *pp; + + if (pad) *(p++)=pb; + if (a->length == 0) *(p++)=0; + else if (!neg) memcpy(p,a->data,(unsigned int)a->length); + else { + /* Begin at the end of the encoding */ + n=a->data + a->length - 1; + p += a->length - 1; + i = a->length; + /* Copy zeros to destination as long as source is zero */ + while(!*n) { + *(p--) = 0; + n--; + i--; + } + /* Complement and increment next octet */ + *(p--) = ((*(n--)) ^ 0xff) + 1; + i--; + /* Complement any octets left */ + for(;i > 0; i--) *(p--) = *(n--) ^ 0xff; + } + + *pp+=ret; + return(ret); + } + +/* Convert just ASN1 INTEGER content octets to ASN1_INTEGER structure */ + +ASN1_INTEGER *c2i_ASN1_INTEGER(ASN1_INTEGER **a, const unsigned char **pp, + long len) + { + ASN1_INTEGER *ret=NULL; + const unsigned char *p, *pend; + unsigned char *to,*s; + int i; + + if ((a == NULL) || ((*a) == NULL)) + { + if ((ret=M_ASN1_INTEGER_new()) == NULL) return(NULL); + ret->type=V_ASN1_INTEGER; + } + else + ret=(*a); + + p= *pp; + pend = p + len; + + /* We must OPENSSL_malloc stuff, even for 0 bytes otherwise it + * signifies a missing NULL parameter. */ + s=(unsigned char *)OPENSSL_malloc((int)len+1); + if (s == NULL) + { + i=ERR_R_MALLOC_FAILURE; + goto err; + } + to=s; + if(!len) { + /* Strictly speaking this is an illegal INTEGER but we + * tolerate it. + */ + ret->type=V_ASN1_INTEGER; + } else if (*p & 0x80) /* a negative number */ + { + ret->type=V_ASN1_NEG_INTEGER; + if ((*p == 0xff) && (len != 1)) { + p++; + len--; + } + i = len; + p += i - 1; + to += i - 1; + while((!*p) && i) { + *(to--) = 0; + i--; + p--; + } + /* Special case: if all zeros then the number will be of + * the form FF followed by n zero bytes: this corresponds to + * 1 followed by n zero bytes. We've already written n zeros + * so we just append an extra one and set the first byte to + * a 1. This is treated separately because it is the only case + * where the number of bytes is larger than len. + */ + if(!i) { + *s = 1; + s[len] = 0; + len++; + } else { + *(to--) = (*(p--) ^ 0xff) + 1; + i--; + for(;i > 0; i--) *(to--) = *(p--) ^ 0xff; + } + } else { + ret->type=V_ASN1_INTEGER; + if ((*p == 0) && (len != 1)) + { + p++; + len--; + } + memcpy(s,p,(int)len); + } + + if (ret->data != NULL) OPENSSL_free(ret->data); + ret->data=s; + ret->length=(int)len; + if (a != NULL) (*a)=ret; + *pp=pend; + return(ret); +err: + OPENSSL_PUT_ERROR(ASN1, i); + if ((ret != NULL) && ((a == NULL) || (*a != ret))) + M_ASN1_INTEGER_free(ret); + return(NULL); + } + + +/* This is a version of d2i_ASN1_INTEGER that ignores the sign bit of + * ASN1 integers: some broken software can encode a positive INTEGER + * with its MSB set as negative (it doesn't add a padding zero). + */ + +ASN1_INTEGER *d2i_ASN1_UINTEGER(ASN1_INTEGER **a, const unsigned char **pp, + long length) + { + ASN1_INTEGER *ret=NULL; + const unsigned char *p; + unsigned char *s; + long len; + int inf,tag,xclass; + int i; + + if ((a == NULL) || ((*a) == NULL)) + { + if ((ret=M_ASN1_INTEGER_new()) == NULL) return(NULL); + ret->type=V_ASN1_INTEGER; + } + else + ret=(*a); + + p= *pp; + inf=ASN1_get_object(&p,&len,&tag,&xclass,length); + if (inf & 0x80) + { + i=ASN1_R_BAD_OBJECT_HEADER; + goto err; + } + + if (tag != V_ASN1_INTEGER) + { + i=ASN1_R_EXPECTING_AN_INTEGER; + goto err; + } + + /* We must OPENSSL_malloc stuff, even for 0 bytes otherwise it + * signifies a missing NULL parameter. */ + s=(unsigned char *)OPENSSL_malloc((int)len+1); + if (s == NULL) + { + i=ERR_R_MALLOC_FAILURE; + goto err; + } + ret->type=V_ASN1_INTEGER; + if(len) { + if ((*p == 0) && (len != 1)) + { + p++; + len--; + } + memcpy(s,p,(int)len); + p+=len; + } + + if (ret->data != NULL) OPENSSL_free(ret->data); + ret->data=s; + ret->length=(int)len; + if (a != NULL) (*a)=ret; + *pp=p; + return(ret); +err: + OPENSSL_PUT_ERROR(ASN1, i); + if ((ret != NULL) && ((a == NULL) || (*a != ret))) + M_ASN1_INTEGER_free(ret); + return(NULL); + } + +int ASN1_INTEGER_set(ASN1_INTEGER *a, long v) + { + int j,k; + unsigned int i; + unsigned char buf[sizeof(long)+1]; + long d; + + a->type=V_ASN1_INTEGER; + if (a->length < (int)(sizeof(long)+1)) + { + if (a->data != NULL) + OPENSSL_free(a->data); + if ((a->data=(unsigned char *)OPENSSL_malloc(sizeof(long)+1)) != NULL) + memset((char *)a->data,0,sizeof(long)+1); + } + if (a->data == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return(0); + } + d=v; + if (d < 0) + { + d= -d; + a->type=V_ASN1_NEG_INTEGER; + } + + for (i=0; i>=8; + } + j=0; + for (k=i-1; k >=0; k--) + a->data[j++]=buf[k]; + a->length=j; + return(1); + } + +long ASN1_INTEGER_get(const ASN1_INTEGER *a) + { + int neg=0,i; + long r=0; + + if (a == NULL) return(0L); + i=a->type; + if (i == V_ASN1_NEG_INTEGER) + neg=1; + else if (i != V_ASN1_INTEGER) + return -1; + + if (a->length > (int)sizeof(long)) + { + /* hmm... a bit ugly, return all ones */ + return -1; + } + if (a->data == NULL) + return 0; + + for (i=0; ilength; i++) + { + r<<=8; + r|=(unsigned char)a->data[i]; + } + if (neg) r= -r; + return(r); + } + +ASN1_INTEGER *BN_to_ASN1_INTEGER(const BIGNUM *bn, ASN1_INTEGER *ai) + { + ASN1_INTEGER *ret; + int len,j; + + if (ai == NULL) + ret=M_ASN1_INTEGER_new(); + else + ret=ai; + if (ret == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + goto err; + } + if (BN_is_negative(bn) && !BN_is_zero(bn)) + ret->type = V_ASN1_NEG_INTEGER; + else ret->type=V_ASN1_INTEGER; + j=BN_num_bits(bn); + len=((j == 0)?0:((j/8)+1)); + if (ret->length < len+4) + { + unsigned char *new_data=OPENSSL_realloc(ret->data, len+4); + if (!new_data) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto err; + } + ret->data=new_data; + } + ret->length=BN_bn2bin(bn,ret->data); + /* Correct zero case */ + if(!ret->length) + { + ret->data[0] = 0; + ret->length = 1; + } + return(ret); +err: + if (ret != ai) M_ASN1_INTEGER_free(ret); + return(NULL); + } + +BIGNUM *ASN1_INTEGER_to_BN(const ASN1_INTEGER *ai, BIGNUM *bn) + { + BIGNUM *ret; + + if ((ret=BN_bin2bn(ai->data,ai->length,bn)) == NULL) + OPENSSL_PUT_ERROR(ASN1, ASN1_R_BN_LIB); + else if(ai->type == V_ASN1_NEG_INTEGER) + BN_set_negative(ret, 1); + return(ret); + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_mbstr.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_mbstr.c new file mode 100644 index 00000000..42806d1a --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_mbstr.c @@ -0,0 +1,390 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include + + +static int traverse_string(const unsigned char *p, int len, int inform, + int (*rfunc)(unsigned long value, void *in), void *arg); +static int in_utf8(unsigned long value, void *arg); +static int out_utf8(unsigned long value, void *arg); +static int type_str(unsigned long value, void *arg); +static int cpy_asc(unsigned long value, void *arg); +static int cpy_bmp(unsigned long value, void *arg); +static int cpy_univ(unsigned long value, void *arg); +static int cpy_utf8(unsigned long value, void *arg); +static int is_printable(unsigned long value); + +/* These functions take a string in UTF8, ASCII or multibyte form and + * a mask of permissible ASN1 string types. It then works out the minimal + * type (using the order Printable < IA5 < T61 < BMP < Universal < UTF8) + * and creates a string of the correct type with the supplied data. + * Yes this is horrible: it has to be :-( + * The 'ncopy' form checks minimum and maximum size limits too. + */ + +int ASN1_mbstring_copy(ASN1_STRING **out, const unsigned char *in, int len, + int inform, unsigned long mask) +{ + return ASN1_mbstring_ncopy(out, in, len, inform, mask, 0, 0); +} + +int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len, + int inform, unsigned long mask, + long minsize, long maxsize) +{ + int str_type; + int ret; + char free_out; + int outform, outlen = 0; + ASN1_STRING *dest; + unsigned char *p; + int nchar; + char strbuf[32]; + int (*cpyfunc)(unsigned long,void *) = NULL; + if(len == -1) len = strlen((const char *)in); + if(!mask) mask = DIRSTRING_TYPE; + + /* First do a string check and work out the number of characters */ + switch(inform) { + + case MBSTRING_BMP: + if(len & 1) { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_BMPSTRING_LENGTH); + return -1; + } + nchar = len >> 1; + break; + + case MBSTRING_UNIV: + if(len & 3) { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_UNIVERSALSTRING_LENGTH); + return -1; + } + nchar = len >> 2; + break; + + case MBSTRING_UTF8: + nchar = 0; + /* This counts the characters and does utf8 syntax checking */ + ret = traverse_string(in, len, MBSTRING_UTF8, in_utf8, &nchar); + if(ret < 0) { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_UTF8STRING); + return -1; + } + break; + + case MBSTRING_ASC: + nchar = len; + break; + + default: + OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNKNOWN_FORMAT); + return -1; + } + + if((minsize > 0) && (nchar < minsize)) { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_STRING_TOO_SHORT); + BIO_snprintf(strbuf, sizeof strbuf, "%ld", minsize); + ERR_add_error_data(2, "minsize=", strbuf); + return -1; + } + + if((maxsize > 0) && (nchar > maxsize)) { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_STRING_TOO_LONG); + BIO_snprintf(strbuf, sizeof strbuf, "%ld", maxsize); + ERR_add_error_data(2, "maxsize=", strbuf); + return -1; + } + + /* Now work out minimal type (if any) */ + if(traverse_string(in, len, inform, type_str, &mask) < 0) { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_CHARACTERS); + return -1; + } + + + /* Now work out output format and string type */ + outform = MBSTRING_ASC; + if(mask & B_ASN1_PRINTABLESTRING) str_type = V_ASN1_PRINTABLESTRING; + else if(mask & B_ASN1_IA5STRING) str_type = V_ASN1_IA5STRING; + else if(mask & B_ASN1_T61STRING) str_type = V_ASN1_T61STRING; + else if(mask & B_ASN1_BMPSTRING) { + str_type = V_ASN1_BMPSTRING; + outform = MBSTRING_BMP; + } else if(mask & B_ASN1_UNIVERSALSTRING) { + str_type = V_ASN1_UNIVERSALSTRING; + outform = MBSTRING_UNIV; + } else { + str_type = V_ASN1_UTF8STRING; + outform = MBSTRING_UTF8; + } + if(!out) return str_type; + if(*out) { + free_out = 0; + dest = *out; + if(dest->data) { + dest->length = 0; + OPENSSL_free(dest->data); + dest->data = NULL; + } + dest->type = str_type; + } else { + free_out = 1; + dest = ASN1_STRING_type_new(str_type); + if(!dest) { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return -1; + } + *out = dest; + } + /* If both the same type just copy across */ + if(inform == outform) { + if(!ASN1_STRING_set(dest, in, len)) { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return -1; + } + return str_type; + } + + /* Work out how much space the destination will need */ + switch(outform) { + case MBSTRING_ASC: + outlen = nchar; + cpyfunc = cpy_asc; + break; + + case MBSTRING_BMP: + outlen = nchar << 1; + cpyfunc = cpy_bmp; + break; + + case MBSTRING_UNIV: + outlen = nchar << 2; + cpyfunc = cpy_univ; + break; + + case MBSTRING_UTF8: + outlen = 0; + traverse_string(in, len, inform, out_utf8, &outlen); + cpyfunc = cpy_utf8; + break; + } + if(!(p = OPENSSL_malloc(outlen + 1))) { + if(free_out) ASN1_STRING_free(dest); + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return -1; + } + dest->length = outlen; + dest->data = p; + p[outlen] = 0; + traverse_string(in, len, inform, cpyfunc, &p); + return str_type; +} + +/* This function traverses a string and passes the value of each character + * to an optional function along with a void * argument. + */ + +static int traverse_string(const unsigned char *p, int len, int inform, + int (*rfunc)(unsigned long value, void *in), void *arg) +{ + unsigned long value; + int ret; + while(len) { + if(inform == MBSTRING_ASC) { + value = *p++; + len--; + } else if(inform == MBSTRING_BMP) { + value = *p++ << 8; + value |= *p++; + len -= 2; + } else if(inform == MBSTRING_UNIV) { + value = ((unsigned long)*p++) << 24; + value |= ((unsigned long)*p++) << 16; + value |= *p++ << 8; + value |= *p++; + len -= 4; + } else { + ret = UTF8_getc(p, len, &value); + if(ret < 0) return -1; + len -= ret; + p += ret; + } + if(rfunc) { + ret = rfunc(value, arg); + if(ret <= 0) return ret; + } + } + return 1; +} + +/* Various utility functions for traverse_string */ + +/* Just count number of characters */ + +static int in_utf8(unsigned long value, void *arg) +{ + int *nchar; + nchar = arg; + (*nchar)++; + return 1; +} + +/* Determine size of output as a UTF8 String */ + +static int out_utf8(unsigned long value, void *arg) +{ + int *outlen; + outlen = arg; + *outlen += UTF8_putc(NULL, -1, value); + return 1; +} + +/* Determine the "type" of a string: check each character against a + * supplied "mask". + */ + +static int type_str(unsigned long value, void *arg) +{ + unsigned long types; + types = *((unsigned long *)arg); + if((types & B_ASN1_PRINTABLESTRING) && !is_printable(value)) + types &= ~B_ASN1_PRINTABLESTRING; + if((types & B_ASN1_IA5STRING) && (value > 127)) + types &= ~B_ASN1_IA5STRING; + if((types & B_ASN1_T61STRING) && (value > 0xff)) + types &= ~B_ASN1_T61STRING; + if((types & B_ASN1_BMPSTRING) && (value > 0xffff)) + types &= ~B_ASN1_BMPSTRING; + if(!types) return -1; + *((unsigned long *)arg) = types; + return 1; +} + +/* Copy one byte per character ASCII like strings */ + +static int cpy_asc(unsigned long value, void *arg) +{ + unsigned char **p, *q; + p = arg; + q = *p; + *q = (unsigned char) value; + (*p)++; + return 1; +} + +/* Copy two byte per character BMPStrings */ + +static int cpy_bmp(unsigned long value, void *arg) +{ + unsigned char **p, *q; + p = arg; + q = *p; + *q++ = (unsigned char) ((value >> 8) & 0xff); + *q = (unsigned char) (value & 0xff); + *p += 2; + return 1; +} + +/* Copy four byte per character UniversalStrings */ + +static int cpy_univ(unsigned long value, void *arg) +{ + unsigned char **p, *q; + p = arg; + q = *p; + *q++ = (unsigned char) ((value >> 24) & 0xff); + *q++ = (unsigned char) ((value >> 16) & 0xff); + *q++ = (unsigned char) ((value >> 8) & 0xff); + *q = (unsigned char) (value & 0xff); + *p += 4; + return 1; +} + +/* Copy to a UTF8String */ + +static int cpy_utf8(unsigned long value, void *arg) +{ + unsigned char **p; + int ret; + p = arg; + /* We already know there is enough room so pass 0xff as the length */ + ret = UTF8_putc(*p, 0xff, value); + *p += ret; + return 1; +} + +/* Return 1 if the character is permitted in a PrintableString */ +static int is_printable(unsigned long value) +{ + int ch; + if(value > 0x7f) return 0; + ch = (int) value; + /* Note: we can't use 'isalnum' because certain accented + * characters may count as alphanumeric in some environments. + */ + if((ch >= 'a') && (ch <= 'z')) return 1; + if((ch >= 'A') && (ch <= 'Z')) return 1; + if((ch >= '0') && (ch <= '9')) return 1; + if ((ch == ' ') || strchr("'()+,-./:=?", ch)) return 1; + return 0; +} diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_object.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_object.c new file mode 100644 index 00000000..6ddfca92 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_object.c @@ -0,0 +1,412 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include +#include + + +int i2d_ASN1_OBJECT(ASN1_OBJECT *a, unsigned char **pp) + { + unsigned char *p; + int objsize; + + if ((a == NULL) || (a->data == NULL)) return(0); + + objsize = ASN1_object_size(0,a->length,V_ASN1_OBJECT); + if (pp == NULL) return objsize; + + p= *pp; + ASN1_put_object(&p,0,a->length,V_ASN1_OBJECT,V_ASN1_UNIVERSAL); + memcpy(p,a->data,a->length); + p+=a->length; + + *pp=p; + return(objsize); + } + +int a2d_ASN1_OBJECT(unsigned char *out, int olen, const char *buf, int num) + { + int i,first,len=0,c, use_bn; + char ftmp[24], *tmp = ftmp; + int tmpsize = sizeof ftmp; + const char *p; + unsigned long l; + BIGNUM *bl = NULL; + + if (num == 0) + return(0); + else if (num == -1) + num=strlen(buf); + + p=buf; + c= *(p++); + num--; + if ((c >= '0') && (c <= '2')) + { + first= c-'0'; + } + else + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_FIRST_NUM_TOO_LARGE); + goto err; + } + + if (num <= 0) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_SECOND_NUMBER); + goto err; + } + c= *(p++); + num--; + for (;;) + { + if (num <= 0) break; + if ((c != '.') && (c != ' ')) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_SEPARATOR); + goto err; + } + l=0; + use_bn = 0; + for (;;) + { + if (num <= 0) break; + num--; + c= *(p++); + if ((c == ' ') || (c == '.')) + break; + if ((c < '0') || (c > '9')) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_DIGIT); + goto err; + } + if (!use_bn && l >= ((ULONG_MAX - 80) / 10L)) + { + use_bn = 1; + if (!bl) + bl = BN_new(); + if (!bl || !BN_set_word(bl, l)) + goto err; + } + if (use_bn) + { + if (!BN_mul_word(bl, 10L) + || !BN_add_word(bl, c-'0')) + goto err; + } + else + l=l*10L+(long)(c-'0'); + } + if (len == 0) + { + if ((first < 2) && (l >= 40)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_SECOND_NUMBER_TOO_LARGE); + goto err; + } + if (use_bn) + { + if (!BN_add_word(bl, first * 40)) + goto err; + } + else + l+=(long)first*40; + } + i=0; + if (use_bn) + { + int blsize; + blsize = BN_num_bits(bl); + blsize = (blsize + 6)/7; + if (blsize > tmpsize) + { + if (tmp != ftmp) + OPENSSL_free(tmp); + tmpsize = blsize + 32; + tmp = OPENSSL_malloc(tmpsize); + if (!tmp) + goto err; + } + while(blsize--) + tmp[i++] = (unsigned char)BN_div_word(bl, 0x80L); + } + else + { + + for (;;) + { + tmp[i++]=(unsigned char)l&0x7f; + l>>=7L; + if (l == 0L) break; + } + + } + if (out != NULL) + { + if (len+i > olen) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_BUFFER_TOO_SMALL); + goto err; + } + while (--i > 0) + out[len++]=tmp[i]|0x80; + out[len++]=tmp[0]; + } + else + len+=i; + } + if (tmp != ftmp) + OPENSSL_free(tmp); + if (bl) + BN_free(bl); + return(len); +err: + if (tmp != ftmp) + OPENSSL_free(tmp); + if (bl) + BN_free(bl); + return(0); + } + +int i2t_ASN1_OBJECT(char *buf, int buf_len, ASN1_OBJECT *a) +{ + return OBJ_obj2txt(buf, buf_len, a, 0); +} + +int i2a_ASN1_OBJECT(BIO *bp, ASN1_OBJECT *a) + { + char buf[80], *p = buf; + int i; + + if ((a == NULL) || (a->data == NULL)) + return(BIO_write(bp,"NULL",4)); + i=i2t_ASN1_OBJECT(buf,sizeof buf,a); + if (i > (int)(sizeof(buf) - 1)) + { + p = OPENSSL_malloc(i + 1); + if (!p) + return -1; + i2t_ASN1_OBJECT(p,i + 1,a); + } + if (i <= 0) + return BIO_write(bp, "", 9); + BIO_write(bp,p,i); + if (p != buf) + OPENSSL_free(p); + return(i); + } + +ASN1_OBJECT *d2i_ASN1_OBJECT(ASN1_OBJECT **a, const unsigned char **pp, + long length) +{ + const unsigned char *p; + long len; + int tag,xclass; + int inf,i; + ASN1_OBJECT *ret = NULL; + p= *pp; + inf=ASN1_get_object(&p,&len,&tag,&xclass,length); + if (inf & 0x80) + { + i=ASN1_R_BAD_OBJECT_HEADER; + goto err; + } + + if (tag != V_ASN1_OBJECT) + { + i=ASN1_R_EXPECTING_AN_OBJECT; + goto err; + } + ret = c2i_ASN1_OBJECT(a, &p, len); + if(ret) *pp = p; + return ret; +err: + OPENSSL_PUT_ERROR(ASN1, i); + return(NULL); +} + +ASN1_OBJECT *c2i_ASN1_OBJECT(ASN1_OBJECT **a, const unsigned char **pp, + long len) + { + ASN1_OBJECT *ret=NULL; + const unsigned char *p; + unsigned char *data; + int i, length; + + /* Sanity check OID encoding. + * Need at least one content octet. + * MSB must be clear in the last octet. + * can't have leading 0x80 in subidentifiers, see: X.690 8.19.2 + */ + if (len <= 0 || len > INT_MAX || pp == NULL || (p = *pp) == NULL || + p[len - 1] & 0x80) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_OBJECT_ENCODING); + return NULL; + } + /* Now 0 < len <= INT_MAX, so the cast is safe. */ + length = (int)len; + for (i = 0; i < length; i++, p++) + { + if (*p == 0x80 && (!i || !(p[-1] & 0x80))) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_OBJECT_ENCODING); + return NULL; + } + } + + /* only the ASN1_OBJECTs from the 'table' will have values + * for ->sn or ->ln */ + if ((a == NULL) || ((*a) == NULL) || + !((*a)->flags & ASN1_OBJECT_FLAG_DYNAMIC)) + { + if ((ret=ASN1_OBJECT_new()) == NULL) return(NULL); + } + else ret=(*a); + + p= *pp; + /* detach data from object */ + data = (unsigned char *)ret->data; + ret->data = NULL; + /* once detached we can change it */ + if ((data == NULL) || (ret->length < length)) + { + ret->length=0; + if (data != NULL) OPENSSL_free(data); + data=(unsigned char *)OPENSSL_malloc(length); + if (data == NULL) + { i=ERR_R_MALLOC_FAILURE; goto err; } + ret->flags|=ASN1_OBJECT_FLAG_DYNAMIC_DATA; + } + memcpy(data,p,length); + /* reattach data to object, after which it remains const */ + ret->data =data; + ret->length=length; + ret->sn=NULL; + ret->ln=NULL; + /* ret->flags=ASN1_OBJECT_FLAG_DYNAMIC; we know it is dynamic */ + p+=length; + + if (a != NULL) (*a)=ret; + *pp=p; + return(ret); +err: + OPENSSL_PUT_ERROR(ASN1, i); + if ((ret != NULL) && ((a == NULL) || (*a != ret))) + ASN1_OBJECT_free(ret); + return(NULL); + } + +ASN1_OBJECT *ASN1_OBJECT_new(void) + { + ASN1_OBJECT *ret; + + ret=(ASN1_OBJECT *)OPENSSL_malloc(sizeof(ASN1_OBJECT)); + if (ret == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return(NULL); + } + ret->length=0; + ret->data=NULL; + ret->nid=0; + ret->sn=NULL; + ret->ln=NULL; + ret->flags=ASN1_OBJECT_FLAG_DYNAMIC; + return(ret); + } + +void ASN1_OBJECT_free(ASN1_OBJECT *a) + { + if (a == NULL) return; + if (a->flags & ASN1_OBJECT_FLAG_DYNAMIC_STRINGS) + { +#ifndef CONST_STRICT /* disable purely for compile-time strict const checking. Doing this on a "real" compile will cause memory leaks */ + if (a->sn != NULL) OPENSSL_free((void *)a->sn); + if (a->ln != NULL) OPENSSL_free((void *)a->ln); +#endif + a->sn=a->ln=NULL; + } + if (a->flags & ASN1_OBJECT_FLAG_DYNAMIC_DATA) + { + if (a->data != NULL) OPENSSL_free((void *)a->data); + a->data=NULL; + a->length=0; + } + if (a->flags & ASN1_OBJECT_FLAG_DYNAMIC) + OPENSSL_free(a); + } + +ASN1_OBJECT *ASN1_OBJECT_create(int nid, unsigned char *data, int len, + const char *sn, const char *ln) + { + ASN1_OBJECT o; + + o.sn=sn; + o.ln=ln; + o.data=data; + o.nid=nid; + o.length=len; + o.flags=ASN1_OBJECT_FLAG_DYNAMIC|ASN1_OBJECT_FLAG_DYNAMIC_STRINGS| + ASN1_OBJECT_FLAG_DYNAMIC_DATA; + return(OBJ_dup(&o)); + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_octet.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_octet.c new file mode 100644 index 00000000..583c9e9d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_octet.c @@ -0,0 +1,70 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + +ASN1_OCTET_STRING *ASN1_OCTET_STRING_dup(const ASN1_OCTET_STRING *x) +{ return M_ASN1_OCTET_STRING_dup(x); } + +int ASN1_OCTET_STRING_cmp(const ASN1_OCTET_STRING *a, const ASN1_OCTET_STRING *b) +{ return M_ASN1_OCTET_STRING_cmp(a, b); } + +int ASN1_OCTET_STRING_set(ASN1_OCTET_STRING *x, const unsigned char *d, int len) +{ return M_ASN1_OCTET_STRING_set(x, d, len); } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_print.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_print.c new file mode 100644 index 00000000..3b6be10b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_print.c @@ -0,0 +1,119 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + +int ASN1_PRINTABLE_type(const unsigned char *s, int len) + { + int c; + int ia5=0; + int t61=0; + + if (len <= 0) len= -1; + if (s == NULL) return(V_ASN1_PRINTABLESTRING); + + while ((*s) && (len-- != 0)) + { + c= *(s++); + if (!( ((c >= 'a') && (c <= 'z')) || + ((c >= 'A') && (c <= 'Z')) || + (c == ' ') || + ((c >= '0') && (c <= '9')) || + (c == ' ') || (c == '\'') || + (c == '(') || (c == ')') || + (c == '+') || (c == ',') || + (c == '-') || (c == '.') || + (c == '/') || (c == ':') || + (c == '=') || (c == '?'))) + ia5=1; + if (c&0x80) + t61=1; + } + if (t61) return(V_ASN1_T61STRING); + if (ia5) return(V_ASN1_IA5STRING); + return(V_ASN1_PRINTABLESTRING); + } + +int ASN1_UNIVERSALSTRING_to_string(ASN1_UNIVERSALSTRING *s) + { + int i; + unsigned char *p; + + if (s->type != V_ASN1_UNIVERSALSTRING) return(0); + if ((s->length%4) != 0) return(0); + p=s->data; + for (i=0; ilength; i+=4) + { + if ((p[0] != '\0') || (p[1] != '\0') || (p[2] != '\0')) + break; + else + p+=4; + } + if (i < s->length) return(0); + p=s->data; + for (i=3; ilength; i+=4) + { + *(p++)=s->data[i]; + } + *(p)='\0'; + s->length/=4; + s->type=ASN1_PRINTABLE_type(s->data,s->length); + return(1); + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_strnid.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_strnid.c new file mode 100644 index 00000000..d4316f72 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_strnid.c @@ -0,0 +1,286 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include /* For bsearch */ +#include + +#include +#include +#include + + +static STACK_OF(ASN1_STRING_TABLE) *stable = NULL; +static void st_free(ASN1_STRING_TABLE *tbl); + +/* This is the global mask for the mbstring functions: this is use to + * mask out certain types (such as BMPString and UTF8String) because + * certain software (e.g. Netscape) has problems with them. + */ + +static unsigned long global_mask = B_ASN1_UTF8STRING; + +void ASN1_STRING_set_default_mask(unsigned long mask) +{ + global_mask = mask; +} + +unsigned long ASN1_STRING_get_default_mask(void) +{ + return global_mask; +} + +/* This function sets the default to various "flavours" of configuration. + * based on an ASCII string. Currently this is: + * MASK:XXXX : a numerical mask value. + * nobmp : Don't use BMPStrings (just Printable, T61). + * pkix : PKIX recommendation in RFC2459. + * utf8only : only use UTF8Strings (RFC2459 recommendation for 2004). + * default: the default value, Printable, T61, BMP. + */ + +int ASN1_STRING_set_default_mask_asc(const char *p) +{ + unsigned long mask; + char *end; + if(!strncmp(p, "MASK:", 5)) { + if(!p[5]) return 0; + mask = strtoul(p + 5, &end, 0); + if(*end) return 0; + } else if(!strcmp(p, "nombstr")) + mask = ~((unsigned long)(B_ASN1_BMPSTRING|B_ASN1_UTF8STRING)); + else if(!strcmp(p, "pkix")) + mask = ~((unsigned long)B_ASN1_T61STRING); + else if(!strcmp(p, "utf8only")) mask = B_ASN1_UTF8STRING; + else if(!strcmp(p, "default")) + mask = 0xFFFFFFFFL; + else return 0; + ASN1_STRING_set_default_mask(mask); + return 1; +} + +/* The following function generates an ASN1_STRING based on limits in a table. + * Frequently the types and length of an ASN1_STRING are restricted by a + * corresponding OID. For example certificates and certificate requests. + */ + +ASN1_STRING *ASN1_STRING_set_by_NID(ASN1_STRING **out, const unsigned char *in, + int inlen, int inform, int nid) +{ + ASN1_STRING_TABLE *tbl; + ASN1_STRING *str = NULL; + unsigned long mask; + int ret; + if(!out) out = &str; + tbl = ASN1_STRING_TABLE_get(nid); + if(tbl) { + mask = tbl->mask; + if(!(tbl->flags & STABLE_NO_MASK)) mask &= global_mask; + ret = ASN1_mbstring_ncopy(out, in, inlen, inform, mask, + tbl->minsize, tbl->maxsize); + } else ret = ASN1_mbstring_copy(out, in, inlen, inform, DIRSTRING_TYPE & global_mask); + if(ret <= 0) return NULL; + return *out; +} + +/* Now the tables and helper functions for the string table: + */ + +/* size limits: this stuff is taken straight from RFC3280 */ + +#define ub_name 32768 +#define ub_common_name 64 +#define ub_locality_name 128 +#define ub_state_name 128 +#define ub_organization_name 64 +#define ub_organization_unit_name 64 +#define ub_title 64 +#define ub_email_address 128 +#define ub_serial_number 64 + + +/* This table must be kept in NID order */ + +static const ASN1_STRING_TABLE tbl_standard[] = { +{NID_commonName, 1, ub_common_name, DIRSTRING_TYPE, 0}, +{NID_countryName, 2, 2, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK}, +{NID_localityName, 1, ub_locality_name, DIRSTRING_TYPE, 0}, +{NID_stateOrProvinceName, 1, ub_state_name, DIRSTRING_TYPE, 0}, +{NID_organizationName, 1, ub_organization_name, DIRSTRING_TYPE, 0}, +{NID_organizationalUnitName, 1, ub_organization_unit_name, DIRSTRING_TYPE, 0}, +{NID_pkcs9_emailAddress, 1, ub_email_address, B_ASN1_IA5STRING, STABLE_NO_MASK}, +{NID_pkcs9_unstructuredName, 1, -1, PKCS9STRING_TYPE, 0}, +{NID_pkcs9_challengePassword, 1, -1, PKCS9STRING_TYPE, 0}, +{NID_pkcs9_unstructuredAddress, 1, -1, DIRSTRING_TYPE, 0}, +{NID_givenName, 1, ub_name, DIRSTRING_TYPE, 0}, +{NID_surname, 1, ub_name, DIRSTRING_TYPE, 0}, +{NID_initials, 1, ub_name, DIRSTRING_TYPE, 0}, +{NID_serialNumber, 1, ub_serial_number, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK}, +{NID_friendlyName, -1, -1, B_ASN1_BMPSTRING, STABLE_NO_MASK}, +{NID_name, 1, ub_name, DIRSTRING_TYPE, 0}, +{NID_dnQualifier, -1, -1, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK}, +{NID_domainComponent, 1, -1, B_ASN1_IA5STRING, STABLE_NO_MASK}, +{NID_ms_csp_name, -1, -1, B_ASN1_BMPSTRING, STABLE_NO_MASK} +}; + +static int sk_table_cmp(const ASN1_STRING_TABLE **a, + const ASN1_STRING_TABLE **b) +{ + return (*a)->nid - (*b)->nid; +} + +static int table_cmp(const void *in_a, const void *in_b) +{ + const ASN1_STRING_TABLE *a = in_a; + const ASN1_STRING_TABLE *b = in_b; + return a->nid - b->nid; +} + +ASN1_STRING_TABLE *ASN1_STRING_TABLE_get(int nid) +{ + int found; + size_t idx; + ASN1_STRING_TABLE *ttmp; + ASN1_STRING_TABLE fnd; + fnd.nid = nid; + + ttmp = bsearch(&fnd, tbl_standard, sizeof(tbl_standard)/sizeof(ASN1_STRING_TABLE), sizeof(ASN1_STRING_TABLE), table_cmp); + if(ttmp) return ttmp; + if(!stable) return NULL; + found = sk_ASN1_STRING_TABLE_find(stable, &idx, &fnd); + if (!found) return NULL; + return sk_ASN1_STRING_TABLE_value(stable, idx); +} + +int ASN1_STRING_TABLE_add(int nid, + long minsize, long maxsize, unsigned long mask, + unsigned long flags) +{ + ASN1_STRING_TABLE *tmp; + char new_nid = 0; + flags &= ~STABLE_FLAGS_MALLOC; + if(!stable) stable = sk_ASN1_STRING_TABLE_new(sk_table_cmp); + if(!stable) { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return 0; + } + if(!(tmp = ASN1_STRING_TABLE_get(nid))) { + tmp = OPENSSL_malloc(sizeof(ASN1_STRING_TABLE)); + if(!tmp) { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return 0; + } + tmp->flags = flags | STABLE_FLAGS_MALLOC; + tmp->nid = nid; + new_nid = 1; + } else tmp->flags = (tmp->flags & STABLE_FLAGS_MALLOC) | flags; + if(minsize != -1) tmp->minsize = minsize; + if(maxsize != -1) tmp->maxsize = maxsize; + tmp->mask = mask; + if(new_nid) sk_ASN1_STRING_TABLE_push(stable, tmp); + return 1; +} + +void ASN1_STRING_TABLE_cleanup(void) +{ + STACK_OF(ASN1_STRING_TABLE) *tmp; + tmp = stable; + if(!tmp) return; + stable = NULL; + sk_ASN1_STRING_TABLE_pop_free(tmp, st_free); +} + +static void st_free(ASN1_STRING_TABLE *tbl) +{ + if(tbl->flags & STABLE_FLAGS_MALLOC) OPENSSL_free(tbl); +} + + +#ifdef STRING_TABLE_TEST + +int +main(void) +{ + ASN1_STRING_TABLE *tmp; + int i, last_nid = -1; + + for (tmp = tbl_standard, i = 0; + i < sizeof(tbl_standard)/sizeof(ASN1_STRING_TABLE); i++, tmp++) + { + if (tmp->nid < last_nid) + { + last_nid = 0; + break; + } + last_nid = tmp->nid; + } + + if (last_nid != 0) + { + printf("Table order OK\n"); + exit(0); + } + + for (tmp = tbl_standard, i = 0; + i < sizeof(tbl_standard)/sizeof(ASN1_STRING_TABLE); i++, tmp++) + printf("Index %d, NID %d, Name=%s\n", i, tmp->nid, + OBJ_nid2ln(tmp->nid)); + + return 0; +} + +#endif diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_time.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_time.c new file mode 100644 index 00000000..ac2cb485 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_time.c @@ -0,0 +1,221 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include "asn1_locl.h" + + +/* This is an implementation of the ASN1 Time structure which is: + * Time ::= CHOICE { + * utcTime UTCTime, + * generalTime GeneralizedTime } + * written by Steve Henson. + */ + +IMPLEMENT_ASN1_MSTRING(ASN1_TIME, B_ASN1_TIME) + +IMPLEMENT_ASN1_FUNCTIONS(ASN1_TIME) + +#if 0 +int i2d_ASN1_TIME(ASN1_TIME *a, unsigned char **pp) + { + if(a->type == V_ASN1_UTCTIME || a->type == V_ASN1_GENERALIZEDTIME) + return(i2d_ASN1_bytes((ASN1_STRING *)a,pp, + a->type ,V_ASN1_UNIVERSAL)); + OPENSSL_PUT_ERROR(ASN1, ASN1_R_EXPECTING_A_TIME); + return -1; + } +#endif + + +ASN1_TIME *ASN1_TIME_set(ASN1_TIME *s, time_t t) + { + return ASN1_TIME_adj(s, t, 0, 0); + } + +ASN1_TIME *ASN1_TIME_adj(ASN1_TIME *s, time_t t, + int offset_day, long offset_sec) + { + struct tm *ts; + struct tm data; + + ts=OPENSSL_gmtime(&t,&data); + if (ts == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ERROR_GETTING_TIME); + return NULL; + } + if (offset_day || offset_sec) + { + if (!OPENSSL_gmtime_adj(ts, offset_day, offset_sec)) + return NULL; + } + if((ts->tm_year >= 50) && (ts->tm_year < 150)) + return ASN1_UTCTIME_adj(s, t, offset_day, offset_sec); + return ASN1_GENERALIZEDTIME_adj(s, t, offset_day, offset_sec); + } + +int ASN1_TIME_check(ASN1_TIME *t) + { + if (t->type == V_ASN1_GENERALIZEDTIME) + return ASN1_GENERALIZEDTIME_check(t); + else if (t->type == V_ASN1_UTCTIME) + return ASN1_UTCTIME_check(t); + return 0; + } + +/* Convert an ASN1_TIME structure to GeneralizedTime */ +ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(ASN1_TIME *t, ASN1_GENERALIZEDTIME **out) + { + ASN1_GENERALIZEDTIME *ret; + char *str; + int newlen; + + if (!ASN1_TIME_check(t)) return NULL; + + if (!out || !*out) + { + if (!(ret = ASN1_GENERALIZEDTIME_new ())) + return NULL; + if (out) *out = ret; + } + else ret = *out; + + /* If already GeneralizedTime just copy across */ + if (t->type == V_ASN1_GENERALIZEDTIME) + { + if(!ASN1_STRING_set(ret, t->data, t->length)) + return NULL; + return ret; + } + + /* grow the string */ + if (!ASN1_STRING_set(ret, NULL, t->length + 2)) + return NULL; + /* ASN1_STRING_set() allocated 'len + 1' bytes. */ + newlen = t->length + 2 + 1; + str = (char *)ret->data; + /* Work out the century and prepend */ + if (t->data[0] >= '5') BUF_strlcpy(str, "19", newlen); + else BUF_strlcpy(str, "20", newlen); + + BUF_strlcat(str, (char *)t->data, newlen); + + return ret; + } + +int ASN1_TIME_set_string(ASN1_TIME *s, const char *str) + { + ASN1_TIME t; + + t.length = strlen(str); + t.data = (unsigned char *)str; + t.flags = 0; + + t.type = V_ASN1_UTCTIME; + + if (!ASN1_TIME_check(&t)) + { + t.type = V_ASN1_GENERALIZEDTIME; + if (!ASN1_TIME_check(&t)) + return 0; + } + + if (s && !ASN1_STRING_copy((ASN1_STRING *)s, (ASN1_STRING *)&t)) + return 0; + + return 1; + } + +static int asn1_time_to_tm(struct tm *tm, const ASN1_TIME *t) + { + if (t == NULL) + { + time_t now_t; + time(&now_t); + if (OPENSSL_gmtime(&now_t, tm)) + return 1; + return 0; + } + + if (t->type == V_ASN1_UTCTIME) + return asn1_utctime_to_tm(tm, t); + else if (t->type == V_ASN1_GENERALIZEDTIME) + return asn1_generalizedtime_to_tm(tm, t); + + return 0; + } + +int ASN1_TIME_diff(int *pday, int *psec, + const ASN1_TIME *from, const ASN1_TIME *to) + { + struct tm tm_from, tm_to; + if (!asn1_time_to_tm(&tm_from, from)) + return 0; + if (!asn1_time_to_tm(&tm_to, to)) + return 0; + return OPENSSL_gmtime_diff(pday, psec, &tm_from, &tm_to); + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_type.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_type.c new file mode 100644 index 00000000..fd3d5b11 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_type.c @@ -0,0 +1,160 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include +#include + + +int ASN1_TYPE_get(ASN1_TYPE *a) + { + if ((a->value.ptr != NULL) || (a->type == V_ASN1_NULL)) + return(a->type); + else + return(0); + } + +void ASN1_TYPE_set(ASN1_TYPE *a, int type, void *value) + { + if (a->value.ptr != NULL) + { + ASN1_TYPE **tmp_a = &a; + ASN1_primitive_free((ASN1_VALUE **)tmp_a, NULL); + } + a->type=type; + if (type == V_ASN1_BOOLEAN) + a->value.boolean = value ? 0xff : 0; + else + a->value.ptr=value; + } + +int ASN1_TYPE_set1(ASN1_TYPE *a, int type, const void *value) + { + if (!value || (type == V_ASN1_BOOLEAN)) + { + void *p = (void *)value; + ASN1_TYPE_set(a, type, p); + } + else if (type == V_ASN1_OBJECT) + { + ASN1_OBJECT *odup; + odup = OBJ_dup(value); + if (!odup) + return 0; + ASN1_TYPE_set(a, type, odup); + } + else + { + ASN1_STRING *sdup; + sdup = ASN1_STRING_dup(value); + if (!sdup) + return 0; + ASN1_TYPE_set(a, type, sdup); + } + return 1; + } + +/* Returns 0 if they are equal, != 0 otherwise. */ +int ASN1_TYPE_cmp(const ASN1_TYPE *a, const ASN1_TYPE *b) + { + int result = -1; + + if (!a || !b || a->type != b->type) return -1; + + switch (a->type) + { + case V_ASN1_OBJECT: + result = OBJ_cmp(a->value.object, b->value.object); + break; + case V_ASN1_NULL: + result = 0; /* They do not have content. */ + break; + case V_ASN1_BOOLEAN: + result = a->value.boolean - b->value.boolean; + break; + case V_ASN1_INTEGER: + case V_ASN1_NEG_INTEGER: + case V_ASN1_ENUMERATED: + case V_ASN1_NEG_ENUMERATED: + case V_ASN1_BIT_STRING: + case V_ASN1_OCTET_STRING: + case V_ASN1_SEQUENCE: + case V_ASN1_SET: + case V_ASN1_NUMERICSTRING: + case V_ASN1_PRINTABLESTRING: + case V_ASN1_T61STRING: + case V_ASN1_VIDEOTEXSTRING: + case V_ASN1_IA5STRING: + case V_ASN1_UTCTIME: + case V_ASN1_GENERALIZEDTIME: + case V_ASN1_GRAPHICSTRING: + case V_ASN1_VISIBLESTRING: + case V_ASN1_GENERALSTRING: + case V_ASN1_UNIVERSALSTRING: + case V_ASN1_BMPSTRING: + case V_ASN1_UTF8STRING: + case V_ASN1_OTHER: + default: + result = ASN1_STRING_cmp((ASN1_STRING *) a->value.ptr, + (ASN1_STRING *) b->value.ptr); + break; + } + + return result; + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_utctm.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_utctm.c new file mode 100644 index 00000000..dbbbecb4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_utctm.c @@ -0,0 +1,342 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include +#include + + +#if 0 +int i2d_ASN1_UTCTIME(ASN1_UTCTIME *a, unsigned char **pp) + { + return(i2d_ASN1_bytes((ASN1_STRING *)a,pp, + V_ASN1_UTCTIME,V_ASN1_UNIVERSAL)); + } + + +ASN1_UTCTIME *d2i_ASN1_UTCTIME(ASN1_UTCTIME **a, unsigned char **pp, + long length) + { + ASN1_UTCTIME *ret=NULL; + + ret=(ASN1_UTCTIME *)d2i_ASN1_bytes((ASN1_STRING **)a,pp,length, + V_ASN1_UTCTIME,V_ASN1_UNIVERSAL); + if (ret == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_NESTED_ASN1_ERROR); + return(NULL); + } + if (!ASN1_UTCTIME_check(ret)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_TIME_FORMAT); + goto err; + } + + return(ret); +err: + if ((ret != NULL) && ((a == NULL) || (*a != ret))) + M_ASN1_UTCTIME_free(ret); + return(NULL); + } + +#endif + +int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d) + { + static const int min[8]={ 0, 1, 1, 0, 0, 0, 0, 0}; + static const int max[8]={99,12,31,23,59,59,12,59}; + char *a; + int n,i,l,o; + + if (d->type != V_ASN1_UTCTIME) return(0); + l=d->length; + a=(char *)d->data; + o=0; + + if (l < 11) goto err; + for (i=0; i<6; i++) + { + if ((i == 5) && ((a[o] == 'Z') || + (a[o] == '+') || (a[o] == '-'))) + { + i++; + if (tm) + tm->tm_sec = 0; + break; + } + if ((a[o] < '0') || (a[o] > '9')) goto err; + n= a[o]-'0'; + if (++o > l) goto err; + + if ((a[o] < '0') || (a[o] > '9')) goto err; + n=(n*10)+ a[o]-'0'; + if (++o > l) goto err; + + if ((n < min[i]) || (n > max[i])) goto err; + if (tm) + { + switch(i) + { + case 0: + tm->tm_year = n < 50 ? n + 100 : n; + break; + case 1: + tm->tm_mon = n - 1; + break; + case 2: + tm->tm_mday = n; + break; + case 3: + tm->tm_hour = n; + break; + case 4: + tm->tm_min = n; + break; + case 5: + tm->tm_sec = n; + break; + } + } + } + if (a[o] == 'Z') + o++; + else if ((a[o] == '+') || (a[o] == '-')) + { + int offsign = a[o] == '-' ? -1 : 1, offset = 0; + o++; + if (o+4 > l) goto err; + for (i=6; i<8; i++) + { + if ((a[o] < '0') || (a[o] > '9')) goto err; + n= a[o]-'0'; + o++; + if ((a[o] < '0') || (a[o] > '9')) goto err; + n=(n*10)+ a[o]-'0'; + if ((n < min[i]) || (n > max[i])) goto err; + if (tm) + { + if (i == 6) + offset = n * 3600; + else if (i == 7) + offset += n * 60; + } + o++; + } + if (offset && !OPENSSL_gmtime_adj(tm, 0, offset * offsign)) + return 0; + } + return o == l; +err: + return 0; + } + +int ASN1_UTCTIME_check(const ASN1_UTCTIME *d) + { + return asn1_utctime_to_tm(NULL, d); + } + +int ASN1_UTCTIME_set_string(ASN1_UTCTIME *s, const char *str) + { + ASN1_UTCTIME t; + + t.type=V_ASN1_UTCTIME; + t.length=strlen(str); + t.data=(unsigned char *)str; + if (ASN1_UTCTIME_check(&t)) + { + if (s != NULL) + { + if (!ASN1_STRING_set((ASN1_STRING *)s, + (unsigned char *)str,t.length)) + return 0; + s->type = V_ASN1_UTCTIME; + } + return(1); + } + else + return(0); + } + +ASN1_UTCTIME *ASN1_UTCTIME_set(ASN1_UTCTIME *s, time_t t) + { + return ASN1_UTCTIME_adj(s, t, 0, 0); + } + +ASN1_UTCTIME *ASN1_UTCTIME_adj(ASN1_UTCTIME *s, time_t t, + int offset_day, long offset_sec) + { + char *p; + struct tm *ts; + struct tm data; + size_t len = 20; + int free_s = 0; + + if (s == NULL) + { + free_s = 1; + s=M_ASN1_UTCTIME_new(); + } + if (s == NULL) + goto err; + + + ts=OPENSSL_gmtime(&t, &data); + if (ts == NULL) + goto err; + + if (offset_day || offset_sec) + { + if (!OPENSSL_gmtime_adj(ts, offset_day, offset_sec)) + goto err; + } + + if((ts->tm_year < 50) || (ts->tm_year >= 150)) + goto err; + + p=(char *)s->data; + if ((p == NULL) || ((size_t)s->length < len)) + { + p=OPENSSL_malloc(len); + if (p == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto err; + } + if (s->data != NULL) + OPENSSL_free(s->data); + s->data=(unsigned char *)p; + } + + BIO_snprintf(p,len,"%02d%02d%02d%02d%02d%02dZ",ts->tm_year%100, + ts->tm_mon+1,ts->tm_mday,ts->tm_hour,ts->tm_min,ts->tm_sec); + s->length=strlen(p); + s->type=V_ASN1_UTCTIME; + return(s); + err: + if (free_s && s) + M_ASN1_UTCTIME_free(s); + return NULL; + } + + +int ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *s, time_t t) + { + struct tm stm, ttm; + int day, sec; + + if (!asn1_utctime_to_tm(&stm, s)) + return -2; + + if (!OPENSSL_gmtime(&t, &ttm)) + return -2; + + if (!OPENSSL_gmtime_diff(&day, &sec, &ttm, &stm)) + return -2; + + if (day > 0) + return 1; + if (day < 0) + return -1; + if (sec > 0) + return 1; + if (sec < 0) + return -1; + return 0; + } + + +#if 0 +time_t ASN1_UTCTIME_get(const ASN1_UTCTIME *s) + { + struct tm tm; + int offset; + + memset(&tm,'\0',sizeof tm); + +#define g2(p) (((p)[0]-'0')*10+(p)[1]-'0') + tm.tm_year=g2(s->data); + if(tm.tm_year < 50) + tm.tm_year+=100; + tm.tm_mon=g2(s->data+2)-1; + tm.tm_mday=g2(s->data+4); + tm.tm_hour=g2(s->data+6); + tm.tm_min=g2(s->data+8); + tm.tm_sec=g2(s->data+10); + if(s->data[12] == 'Z') + offset=0; + else + { + offset=g2(s->data+13)*60+g2(s->data+15); + if(s->data[12] == '-') + offset= -offset; + } +#undef g2 + + return mktime(&tm)-offset*60; /* FIXME: mktime assumes the current timezone + * instead of UTC, and unless we rewrite OpenSSL + * in Lisp we cannot locally change the timezone + * without possibly interfering with other parts + * of the program. timegm, which uses UTC, is + * non-standard. + * Also time_t is inappropriate for general + * UTC times because it may a 32 bit type. */ + } +#endif diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_utf8.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_utf8.c new file mode 100644 index 00000000..ed6e98d3 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_utf8.c @@ -0,0 +1,210 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + +/* UTF8 utilities */ + +/* This parses a UTF8 string one character at a time. It is passed a pointer + * to the string and the length of the string. It sets 'value' to the value of + * the current character. It returns the number of characters read or a + * negative error code: + * -1 = string too short + * -2 = illegal character + * -3 = subsequent characters not of the form 10xxxxxx + * -4 = character encoded incorrectly (not minimal length). + */ + +int UTF8_getc(const unsigned char *str, int len, unsigned long *val) +{ + const unsigned char *p; + unsigned long value; + int ret; + if(len <= 0) return 0; + p = str; + + /* Check syntax and work out the encoded value (if correct) */ + if((*p & 0x80) == 0) { + value = *p++ & 0x7f; + ret = 1; + } else if((*p & 0xe0) == 0xc0) { + if(len < 2) return -1; + if((p[1] & 0xc0) != 0x80) return -3; + value = (*p++ & 0x1f) << 6; + value |= *p++ & 0x3f; + if(value < 0x80) return -4; + ret = 2; + } else if((*p & 0xf0) == 0xe0) { + if(len < 3) return -1; + if( ((p[1] & 0xc0) != 0x80) + || ((p[2] & 0xc0) != 0x80) ) return -3; + value = (*p++ & 0xf) << 12; + value |= (*p++ & 0x3f) << 6; + value |= *p++ & 0x3f; + if(value < 0x800) return -4; + ret = 3; + } else if((*p & 0xf8) == 0xf0) { + if(len < 4) return -1; + if( ((p[1] & 0xc0) != 0x80) + || ((p[2] & 0xc0) != 0x80) + || ((p[3] & 0xc0) != 0x80) ) return -3; + value = ((unsigned long)(*p++ & 0x7)) << 18; + value |= (*p++ & 0x3f) << 12; + value |= (*p++ & 0x3f) << 6; + value |= *p++ & 0x3f; + if(value < 0x10000) return -4; + ret = 4; + } else if((*p & 0xfc) == 0xf8) { + if(len < 5) return -1; + if( ((p[1] & 0xc0) != 0x80) + || ((p[2] & 0xc0) != 0x80) + || ((p[3] & 0xc0) != 0x80) + || ((p[4] & 0xc0) != 0x80) ) return -3; + value = ((unsigned long)(*p++ & 0x3)) << 24; + value |= ((unsigned long)(*p++ & 0x3f)) << 18; + value |= ((unsigned long)(*p++ & 0x3f)) << 12; + value |= (*p++ & 0x3f) << 6; + value |= *p++ & 0x3f; + if(value < 0x200000) return -4; + ret = 5; + } else if((*p & 0xfe) == 0xfc) { + if(len < 6) return -1; + if( ((p[1] & 0xc0) != 0x80) + || ((p[2] & 0xc0) != 0x80) + || ((p[3] & 0xc0) != 0x80) + || ((p[4] & 0xc0) != 0x80) + || ((p[5] & 0xc0) != 0x80) ) return -3; + value = ((unsigned long)(*p++ & 0x1)) << 30; + value |= ((unsigned long)(*p++ & 0x3f)) << 24; + value |= ((unsigned long)(*p++ & 0x3f)) << 18; + value |= ((unsigned long)(*p++ & 0x3f)) << 12; + value |= (*p++ & 0x3f) << 6; + value |= *p++ & 0x3f; + if(value < 0x4000000) return -4; + ret = 6; + } else return -2; + *val = value; + return ret; +} + +/* This takes a character 'value' and writes the UTF8 encoded value in + * 'str' where 'str' is a buffer containing 'len' characters. Returns + * the number of characters written or -1 if 'len' is too small. 'str' can + * be set to NULL in which case it just returns the number of characters. + * It will need at most 6 characters. + */ + +int UTF8_putc(unsigned char *str, int len, unsigned long value) +{ + if(!str) len = 6; /* Maximum we will need */ + else if(len <= 0) return -1; + if(value < 0x80) { + if(str) *str = (unsigned char)value; + return 1; + } + if(value < 0x800) { + if(len < 2) return -1; + if(str) { + *str++ = (unsigned char)(((value >> 6) & 0x1f) | 0xc0); + *str = (unsigned char)((value & 0x3f) | 0x80); + } + return 2; + } + if(value < 0x10000) { + if(len < 3) return -1; + if(str) { + *str++ = (unsigned char)(((value >> 12) & 0xf) | 0xe0); + *str++ = (unsigned char)(((value >> 6) & 0x3f) | 0x80); + *str = (unsigned char)((value & 0x3f) | 0x80); + } + return 3; + } + if(value < 0x200000) { + if(len < 4) return -1; + if(str) { + *str++ = (unsigned char)(((value >> 18) & 0x7) | 0xf0); + *str++ = (unsigned char)(((value >> 12) & 0x3f) | 0x80); + *str++ = (unsigned char)(((value >> 6) & 0x3f) | 0x80); + *str = (unsigned char)((value & 0x3f) | 0x80); + } + return 4; + } + if(value < 0x4000000) { + if(len < 5) return -1; + if(str) { + *str++ = (unsigned char)(((value >> 24) & 0x3) | 0xf8); + *str++ = (unsigned char)(((value >> 18) & 0x3f) | 0x80); + *str++ = (unsigned char)(((value >> 12) & 0x3f) | 0x80); + *str++ = (unsigned char)(((value >> 6) & 0x3f) | 0x80); + *str = (unsigned char)((value & 0x3f) | 0x80); + } + return 5; + } + if(len < 6) return -1; + if(str) { + *str++ = (unsigned char)(((value >> 30) & 0x1) | 0xfc); + *str++ = (unsigned char)(((value >> 24) & 0x3f) | 0x80); + *str++ = (unsigned char)(((value >> 18) & 0x3f) | 0x80); + *str++ = (unsigned char)(((value >> 12) & 0x3f) | 0x80); + *str++ = (unsigned char)(((value >> 6) & 0x3f) | 0x80); + *str = (unsigned char)((value & 0x3f) | 0x80); + } + return 6; +} diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/asn1_lib.c b/TMessagesProj/jni/boringssl/crypto/asn1/asn1_lib.c new file mode 100644 index 00000000..a109749f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/asn1_lib.c @@ -0,0 +1,510 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include +#include + + +/* Used in asn1_mac.h. + * TODO(davidben): Remove this once asn1_mac.h is gone or trimmed. */ +OPENSSL_DECLARE_ERROR_REASON(ASN1, MALLOC_FAILURE); + +/* Cross-module errors from crypto/x509/i2d_pr.c */ +OPENSSL_DECLARE_ERROR_REASON(ASN1, UNSUPPORTED_PUBLIC_KEY_TYPE); + +/* Cross-module errors from crypto/x509/asn1_gen.c. + * TODO(davidben): Remove these once asn1_gen.c is gone. */ +OPENSSL_DECLARE_ERROR_REASON(ASN1, DEPTH_EXCEEDED); +OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_BITSTRING_FORMAT); +OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_BOOLEAN); +OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_FORMAT); +OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_HEX); +OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_IMPLICIT_TAG); +OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_INTEGER); +OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_NESTED_TAGGING); +OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_NULL_VALUE); +OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_OBJECT); +OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_TIME_VALUE); +OPENSSL_DECLARE_ERROR_REASON(ASN1, INTEGER_NOT_ASCII_FORMAT); +OPENSSL_DECLARE_ERROR_REASON(ASN1, INVALID_MODIFIER); +OPENSSL_DECLARE_ERROR_REASON(ASN1, INVALID_NUMBER); +OPENSSL_DECLARE_ERROR_REASON(ASN1, LIST_ERROR); +OPENSSL_DECLARE_ERROR_REASON(ASN1, MISSING_VALUE); +OPENSSL_DECLARE_ERROR_REASON(ASN1, NOT_ASCII_FORMAT); +OPENSSL_DECLARE_ERROR_REASON(ASN1, OBJECT_NOT_ASCII_FORMAT); +OPENSSL_DECLARE_ERROR_REASON(ASN1, SEQUENCE_OR_SET_NEEDS_CONFIG); +OPENSSL_DECLARE_ERROR_REASON(ASN1, TIME_NOT_ASCII_FORMAT); +OPENSSL_DECLARE_ERROR_REASON(ASN1, UNKNOWN_FORMAT); +OPENSSL_DECLARE_ERROR_REASON(ASN1, UNKNOWN_TAG); +OPENSSL_DECLARE_ERROR_REASON(ASN1, UNSUPPORTED_TYPE); + +static int asn1_get_length(const unsigned char **pp,int *inf,long *rl,int max); +static void asn1_put_length(unsigned char **pp, int length); + +static int _asn1_check_infinite_end(const unsigned char **p, long len) + { + /* If there is 0 or 1 byte left, the length check should pick + * things up */ + if (len <= 0) + return(1); + else if ((len >= 2) && ((*p)[0] == 0) && ((*p)[1] == 0)) + { + (*p)+=2; + return(1); + } + return(0); + } + +int ASN1_check_infinite_end(unsigned char **p, long len) + { + return _asn1_check_infinite_end((const unsigned char **)p, len); + } + +int ASN1_const_check_infinite_end(const unsigned char **p, long len) + { + return _asn1_check_infinite_end(p, len); + } + + +int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag, + int *pclass, long omax) + { + int i,ret; + long l; + const unsigned char *p= *pp; + int tag,xclass,inf; + long max=omax; + + if (!max) goto err; + ret=(*p&V_ASN1_CONSTRUCTED); + xclass=(*p&V_ASN1_PRIVATE); + i= *p&V_ASN1_PRIMITIVE_TAG; + if (i == V_ASN1_PRIMITIVE_TAG) + { /* high-tag */ + p++; + if (--max == 0) goto err; + l=0; + while (*p&0x80) + { + l<<=7L; + l|= *(p++)&0x7f; + if (--max == 0) goto err; + if (l > (INT_MAX >> 7L)) goto err; + } + l<<=7L; + l|= *(p++)&0x7f; + tag=(int)l; + if (--max == 0) goto err; + } + else + { + tag=i; + p++; + if (--max == 0) goto err; + } + *ptag=tag; + *pclass=xclass; + if (!asn1_get_length(&p,&inf,plength,(int)max)) goto err; + + if (inf && !(ret & V_ASN1_CONSTRUCTED)) + goto err; + +#if 0 + fprintf(stderr,"p=%d + *plength=%ld > omax=%ld + *pp=%d (%d > %d)\n", + (int)p,*plength,omax,(int)*pp,(int)(p+ *plength), + (int)(omax+ *pp)); + +#endif + if (*plength > (omax - (p - *pp))) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG); + /* Set this so that even if things are not long enough + * the values are set correctly */ + ret|=0x80; + } + *pp=p; + return(ret|inf); +err: + OPENSSL_PUT_ERROR(ASN1, ASN1_R_HEADER_TOO_LONG); + return(0x80); + } + +static int asn1_get_length(const unsigned char **pp, int *inf, long *rl, int max) + { + const unsigned char *p= *pp; + unsigned long ret=0; + unsigned int i; + + if (max-- < 1) return(0); + if (*p == 0x80) + { + *inf=1; + ret=0; + p++; + } + else + { + *inf=0; + i= *p&0x7f; + if (*(p++) & 0x80) + { + if (i > sizeof(long)) + return 0; + if (max-- == 0) return(0); + while (i-- > 0) + { + ret<<=8L; + ret|= *(p++); + if (max-- == 0) return(0); + } + } + else + ret=i; + } + if (ret > LONG_MAX) + return 0; + *pp=p; + *rl=(long)ret; + return(1); + } + +/* class 0 is constructed + * constructed == 2 for indefinite length constructed */ +void ASN1_put_object(unsigned char **pp, int constructed, int length, int tag, + int xclass) + { + unsigned char *p= *pp; + int i, ttag; + + i=(constructed)?V_ASN1_CONSTRUCTED:0; + i|=(xclass&V_ASN1_PRIVATE); + if (tag < 31) + *(p++)=i|(tag&V_ASN1_PRIMITIVE_TAG); + else + { + *(p++)=i|V_ASN1_PRIMITIVE_TAG; + for(i = 0, ttag = tag; ttag > 0; i++) ttag >>=7; + ttag = i; + while(i-- > 0) + { + p[i] = tag & 0x7f; + if(i != (ttag - 1)) p[i] |= 0x80; + tag >>= 7; + } + p += ttag; + } + if (constructed == 2) + *(p++)=0x80; + else + asn1_put_length(&p,length); + *pp=p; + } + +int ASN1_put_eoc(unsigned char **pp) + { + unsigned char *p = *pp; + *p++ = 0; + *p++ = 0; + *pp = p; + return 2; + } + +static void asn1_put_length(unsigned char **pp, int length) + { + unsigned char *p= *pp; + int i,l; + if (length <= 127) + *(p++)=(unsigned char)length; + else + { + l=length; + for (i=0; l > 0; i++) + l>>=8; + *(p++)=i|0x80; + l=i; + while (i-- > 0) + { + p[i]=length&0xff; + length>>=8; + } + p+=l; + } + *pp=p; + } + +int ASN1_object_size(int constructed, int length, int tag) + { + int ret; + + ret=length; + ret++; + if (tag >= 31) + { + while (tag > 0) + { + tag>>=7; + ret++; + } + } + if (constructed == 2) + return ret + 3; + ret++; + if (length > 127) + { + while (length > 0) + { + length>>=8; + ret++; + } + } + return(ret); + } + +static int _asn1_Finish(ASN1_const_CTX *c) + { + if ((c->inf == (1|V_ASN1_CONSTRUCTED)) && (!c->eos)) + { + if (!ASN1_const_check_infinite_end(&c->p,c->slen)) + { + c->error=ASN1_R_MISSING_ASN1_EOS; + return(0); + } + } + if ( ((c->slen != 0) && !(c->inf & 1)) || + ((c->slen < 0) && (c->inf & 1))) + { + c->error=ASN1_R_ASN1_LENGTH_MISMATCH; + return(0); + } + return(1); + } + +int asn1_Finish(ASN1_CTX *c) + { + return _asn1_Finish((ASN1_const_CTX *)c); + } + +int asn1_const_Finish(ASN1_const_CTX *c) + { + return _asn1_Finish(c); + } + +int asn1_GetSequence(ASN1_const_CTX *c, long *length) + { + const unsigned char *q; + + q=c->p; + c->inf=ASN1_get_object(&(c->p),&(c->slen),&(c->tag),&(c->xclass), + *length); + if (c->inf & 0x80) + { + c->error=ASN1_R_BAD_GET_ASN1_OBJECT_CALL; + return(0); + } + if (c->tag != V_ASN1_SEQUENCE) + { + c->error=ASN1_R_EXPECTING_AN_ASN1_SEQUENCE; + return(0); + } + (*length)-=(c->p-q); + if (c->max && (*length < 0)) + { + c->error=ASN1_R_ASN1_LENGTH_MISMATCH; + return(0); + } + if (c->inf == (1|V_ASN1_CONSTRUCTED)) + c->slen= *length+ *(c->pp)-c->p; + c->eos=0; + return(1); + } + +int ASN1_STRING_copy(ASN1_STRING *dst, const ASN1_STRING *str) + { + if (str == NULL) + return 0; + dst->type = str->type; + if (!ASN1_STRING_set(dst,str->data,str->length)) + return 0; + dst->flags = str->flags; + return 1; + } + +ASN1_STRING *ASN1_STRING_dup(const ASN1_STRING *str) + { + ASN1_STRING *ret; + if (!str) + return NULL; + ret=ASN1_STRING_new(); + if (!ret) + return NULL; + if (!ASN1_STRING_copy(ret,str)) + { + ASN1_STRING_free(ret); + return NULL; + } + return ret; + } + +int ASN1_STRING_set(ASN1_STRING *str, const void *_data, int len) + { + unsigned char *c; + const char *data=_data; + + if (len < 0) + { + if (data == NULL) + return(0); + else + len=strlen(data); + } + if ((str->length < len) || (str->data == NULL)) + { + c=str->data; + if (c == NULL) + str->data=OPENSSL_malloc(len+1); + else + str->data=OPENSSL_realloc(c,len+1); + + if (str->data == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + str->data=c; + return(0); + } + } + str->length=len; + if (data != NULL) + { + memcpy(str->data,data,len); + /* an allowance for strings :-) */ + str->data[len]='\0'; + } + return(1); + } + +void ASN1_STRING_set0(ASN1_STRING *str, void *data, int len) + { + if (str->data) + OPENSSL_free(str->data); + str->data = data; + str->length = len; + } + +ASN1_STRING *ASN1_STRING_new(void) + { + return(ASN1_STRING_type_new(V_ASN1_OCTET_STRING)); + } + + +ASN1_STRING *ASN1_STRING_type_new(int type) + { + ASN1_STRING *ret; + + ret=(ASN1_STRING *)OPENSSL_malloc(sizeof(ASN1_STRING)); + if (ret == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return(NULL); + } + ret->length=0; + ret->type=type; + ret->data=NULL; + ret->flags=0; + return(ret); + } + +void ASN1_STRING_free(ASN1_STRING *a) + { + if (a == NULL) return; + if (a->data && !(a->flags & ASN1_STRING_FLAG_NDEF)) + OPENSSL_free(a->data); + OPENSSL_free(a); + } + +int ASN1_STRING_cmp(const ASN1_STRING *a, const ASN1_STRING *b) + { + int i; + + i=(a->length-b->length); + if (i == 0) + { + i=memcmp(a->data,b->data,a->length); + if (i == 0) + return(a->type-b->type); + else + return(i); + } + else + return(i); + } + +int ASN1_STRING_length(const ASN1_STRING *x) +{ return M_ASN1_STRING_length(x); } + +void ASN1_STRING_length_set(ASN1_STRING *x, int len) +{ M_ASN1_STRING_length_set(x, len); return; } + +int ASN1_STRING_type(ASN1_STRING *x) +{ return M_ASN1_STRING_type(x); } + +unsigned char * ASN1_STRING_data(ASN1_STRING *x) +{ return M_ASN1_STRING_data(x); } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/asn1_locl.h b/TMessagesProj/jni/boringssl/crypto/asn1/asn1_locl.h new file mode 100644 index 00000000..ca5f6120 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/asn1_locl.h @@ -0,0 +1,73 @@ +/* asn1t.h */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2006. + */ +/* ==================================================================== + * Copyright (c) 2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +/* Internal ASN1 structures and functions: not for application use */ + +int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d); +int asn1_generalizedtime_to_tm(struct tm *tm, const ASN1_GENERALIZEDTIME *d); + +/* ASN1 print context structure */ + +struct asn1_pctx_st + { + unsigned long flags; + unsigned long nm_flags; + unsigned long cert_flags; + unsigned long oid_flags; + unsigned long str_flags; + } /* ASN1_PCTX */; diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/asn1_par.c b/TMessagesProj/jni/boringssl/crypto/asn1/asn1_par.c new file mode 100644 index 00000000..aff3e2b7 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/asn1_par.c @@ -0,0 +1,435 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include + + +static int asn1_print_info(BIO *bp, int tag, int xclass,int constructed, + int indent); +static int asn1_parse2(BIO *bp, const unsigned char **pp, long length, + int offset, int depth, int indent, int dump); +static int asn1_print_info(BIO *bp, int tag, int xclass, int constructed, + int indent) + { + static const char fmt[]="%-18s"; + char str[128]; + const char *p; + + if (constructed & V_ASN1_CONSTRUCTED) + p="cons: "; + else + p="prim: "; + if (BIO_write(bp,p,6) < 6) goto err; + BIO_indent(bp,indent,128); + + p=str; + if ((xclass & V_ASN1_PRIVATE) == V_ASN1_PRIVATE) + BIO_snprintf(str,sizeof str,"priv [ %d ] ",tag); + else if ((xclass & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC) + BIO_snprintf(str,sizeof str,"cont [ %d ]",tag); + else if ((xclass & V_ASN1_APPLICATION) == V_ASN1_APPLICATION) + BIO_snprintf(str,sizeof str,"appl [ %d ]",tag); + else if (tag > 30) + BIO_snprintf(str,sizeof str,"",tag); + else + p = ASN1_tag2str(tag); + + if (BIO_printf(bp,fmt,p) <= 0) + goto err; + return(1); +err: + return(0); + } + +int ASN1_parse(BIO *bp, const unsigned char *pp, long len, int indent) + { + return(asn1_parse2(bp,&pp,len,0,0,indent,0)); + } + +int ASN1_parse_dump(BIO *bp, const unsigned char *pp, long len, int indent, int dump) + { + return(asn1_parse2(bp,&pp,len,0,0,indent,dump)); + } + +static int asn1_parse2(BIO *bp, const unsigned char **pp, long length, int offset, + int depth, int indent, int dump) + { + const unsigned char *p,*ep,*tot,*op,*opp; + long len; + int tag,xclass,ret=0; + int nl,hl,j,r; + ASN1_OBJECT *o=NULL; + ASN1_OCTET_STRING *os=NULL; + /* ASN1_BMPSTRING *bmp=NULL;*/ + int dump_indent; + +#if 0 + dump_indent = indent; +#else + dump_indent = 6; /* Because we know BIO_dump_indent() */ +#endif + p= *pp; + tot=p+length; + op=p-1; + while ((p < tot) && (op < p)) + { + op=p; + j=ASN1_get_object(&p,&len,&tag,&xclass,length); +#ifdef LINT + j=j; +#endif + if (j & 0x80) + { + if (BIO_puts(bp, "Error in encoding\n") <= 0) + goto end; + ret=0; + goto end; + } + hl=(p-op); + length-=hl; + /* if j == 0x21 it is a constructed indefinite length object */ + if (BIO_printf(bp,"%5ld:",(long)offset+(long)(op- *pp)) + <= 0) goto end; + + if (j != (V_ASN1_CONSTRUCTED | 1)) + { + if (BIO_printf(bp,"d=%-2d hl=%ld l=%4ld ", + depth,(long)hl,len) <= 0) + goto end; + } + else + { + if (BIO_printf(bp,"d=%-2d hl=%ld l=inf ", + depth,(long)hl) <= 0) + goto end; + } + if (!asn1_print_info(bp,tag,xclass,j,(indent)?depth:0)) + goto end; + if (j & V_ASN1_CONSTRUCTED) + { + ep=p+len; + if (BIO_puts(bp, "\n") <= 0) goto end; + if (len > length) + { + BIO_printf(bp, + "length is greater than %ld\n",length); + ret=0; + goto end; + } + if ((j == 0x21) && (len == 0)) + { + for (;;) + { + r=asn1_parse2(bp,&p,(long)(tot-p), + offset+(p - *pp),depth+1, + indent,dump); + if (r == 0) { ret=0; goto end; } + if ((r == 2) || (p >= tot)) break; + } + } + else + while (p < ep) + { + r=asn1_parse2(bp,&p,(long)len, + offset+(p - *pp),depth+1, + indent,dump); + if (r == 0) { ret=0; goto end; } + } + } + else if (xclass != 0) + { + p+=len; + if (BIO_puts(bp, "\n") <= 0) goto end; + } + else + { + nl=0; + if ( (tag == V_ASN1_PRINTABLESTRING) || + (tag == V_ASN1_T61STRING) || + (tag == V_ASN1_IA5STRING) || + (tag == V_ASN1_VISIBLESTRING) || + (tag == V_ASN1_NUMERICSTRING) || + (tag == V_ASN1_UTF8STRING) || + (tag == V_ASN1_UTCTIME) || + (tag == V_ASN1_GENERALIZEDTIME)) + { + if (BIO_puts(bp, ":") <= 0) goto end; + if ((len > 0) && + BIO_write(bp,(const char *)p,(int)len) + != (int)len) + goto end; + } + else if (tag == V_ASN1_OBJECT) + { + opp=op; + if (d2i_ASN1_OBJECT(&o,&opp,len+hl) != NULL) + { + if (BIO_puts(bp, ":") <= 0) goto end; + i2a_ASN1_OBJECT(bp,o); + } + else + { + if (BIO_puts(bp, ":BAD OBJECT") <= 0) + goto end; + } + } + else if (tag == V_ASN1_BOOLEAN) + { + int ii; + + opp=op; + ii=d2i_ASN1_BOOLEAN(NULL,&opp,len+hl); + if (ii < 0) + { + if (BIO_puts(bp, "Bad boolean\n") <= 0) + goto end; + } + BIO_printf(bp,":%d",ii); + } + else if (tag == V_ASN1_BMPSTRING) + { + /* do the BMP thang */ + } + else if (tag == V_ASN1_OCTET_STRING) + { + int i,printable=1; + + opp=op; + os=d2i_ASN1_OCTET_STRING(NULL,&opp,len+hl); + if (os != NULL && os->length > 0) + { + opp = os->data; + /* testing whether the octet string is + * printable */ + for (i=0; ilength; i++) + { + if (( (opp[i] < ' ') && + (opp[i] != '\n') && + (opp[i] != '\r') && + (opp[i] != '\t')) || + (opp[i] > '~')) + { + printable=0; + break; + } + } + if (printable) + /* printable string */ + { + if (BIO_puts(bp, ":") <= 0) + goto end; + if (BIO_write(bp,(const char *)opp, + os->length) <= 0) + goto end; + } + else if (!dump) + /* not printable => print octet string + * as hex dump */ + { + if (BIO_puts(bp, "[HEX DUMP]:") <= 0) + goto end; + for (i=0; ilength; i++) + { + if (BIO_printf(bp,"%02X" + , opp[i]) <= 0) + goto end; + } + } + else + /* print the normal dump */ + { + if (!nl) + { + if (BIO_puts(bp, "\n") <= 0) + goto end; + } + if (!BIO_hexdump(bp, opp, + ((dump == -1 || dump > + os->length)?os->length:dump), + dump_indent)) + goto end; + nl=1; + } + } + if (os != NULL) + { + M_ASN1_OCTET_STRING_free(os); + os=NULL; + } + } + else if (tag == V_ASN1_INTEGER) + { + ASN1_INTEGER *bs; + int i; + + opp=op; + bs=d2i_ASN1_INTEGER(NULL,&opp,len+hl); + if (bs != NULL) + { + if (BIO_puts(bp, ":") <= 0) goto end; + if (bs->type == V_ASN1_NEG_INTEGER) + if (BIO_puts(bp, "-") <= 0) + goto end; + for (i=0; ilength; i++) + { + if (BIO_printf(bp,"%02X", + bs->data[i]) <= 0) + goto end; + } + if (bs->length == 0) + { + if (BIO_puts(bp, "00") <= 0) + goto end; + } + } + else + { + if (BIO_puts(bp, "BAD INTEGER") <= 0) + goto end; + } + M_ASN1_INTEGER_free(bs); + } + else if (tag == V_ASN1_ENUMERATED) + { + ASN1_ENUMERATED *bs; + int i; + + opp=op; + bs=d2i_ASN1_ENUMERATED(NULL,&opp,len+hl); + if (bs != NULL) + { + if (BIO_puts(bp, ":") <= 0) goto end; + if (bs->type == V_ASN1_NEG_ENUMERATED) + if (BIO_puts(bp, "-") <= 0) + goto end; + for (i=0; ilength; i++) + { + if (BIO_printf(bp,"%02X", + bs->data[i]) <= 0) + goto end; + } + if (bs->length == 0) + { + if (BIO_puts(bp, "00") <= 0) + goto end; + } + } + else + { + if (BIO_puts(bp, "BAD ENUMERATED") <= 0) + goto end; + } + M_ASN1_ENUMERATED_free(bs); + } + else if (len > 0 && dump) + { + if (!nl) + { + if (BIO_puts(bp, "\n") <= 0) + goto end; + } + if (!BIO_hexdump(bp,p, + ((dump == -1 || dump > len)?len:dump), + dump_indent)) + goto end; + nl=1; + } + + if (!nl) + { + if (BIO_puts(bp, "\n") <= 0) goto end; + } + p+=len; + if ((tag == V_ASN1_EOC) && (xclass == 0)) + { + ret=2; /* End of sequence */ + goto end; + } + } + length-=len; + } + ret=1; +end: + if (o != NULL) ASN1_OBJECT_free(o); + if (os != NULL) M_ASN1_OCTET_STRING_free(os); + *pp=p; + return(ret); + } + +const char *ASN1_tag2str(int tag) +{ + static const char * const tag2str[] = { + "EOC", "BOOLEAN", "INTEGER", "BIT STRING", "OCTET STRING", /* 0-4 */ + "NULL", "OBJECT", "OBJECT DESCRIPTOR", "EXTERNAL", "REAL", /* 5-9 */ + "ENUMERATED", "", "UTF8STRING", "", /* 10-13 */ + "", "", "SEQUENCE", "SET", /* 15-17 */ + "NUMERICSTRING", "PRINTABLESTRING", "T61STRING", /* 18-20 */ + "VIDEOTEXSTRING", "IA5STRING", "UTCTIME","GENERALIZEDTIME", /* 21-24 */ + "GRAPHICSTRING", "VISIBLESTRING", "GENERALSTRING", /* 25-27 */ + "UNIVERSALSTRING", "", "BMPSTRING" /* 28-30 */ + }; + + if((tag == V_ASN1_NEG_INTEGER) || (tag == V_ASN1_NEG_ENUMERATED)) + tag &= ~0x100; + + if(tag < 0 || tag > 30) return "(unknown)"; + return tag2str[tag]; +} + diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/asn_pack.c b/TMessagesProj/jni/boringssl/crypto/asn1/asn_pack.c new file mode 100644 index 00000000..e842a10d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/asn_pack.c @@ -0,0 +1,104 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + +/* ASN1_ITEM versions of the above */ + +ASN1_STRING *ASN1_item_pack(void *obj, const ASN1_ITEM *it, ASN1_STRING **oct) +{ + ASN1_STRING *octmp; + + if (!oct || !*oct) { + if (!(octmp = ASN1_STRING_new ())) { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return NULL; + } + if (oct) *oct = octmp; + } else octmp = *oct; + + if(octmp->data) { + OPENSSL_free(octmp->data); + octmp->data = NULL; + } + + if (!(octmp->length = ASN1_item_i2d(obj, &octmp->data, it))) { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ENCODE_ERROR); + return NULL; + } + if (!octmp->data) { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return NULL; + } + return octmp; +} + +/* Extract an ASN1 object from an ASN1_STRING */ + +void *ASN1_item_unpack(ASN1_STRING *oct, const ASN1_ITEM *it) +{ + const unsigned char *p; + void *ret; + + p = oct->data; + if(!(ret = ASN1_item_d2i(NULL, &p, oct->length, it))) + OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR); + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/bio_asn1.c b/TMessagesProj/jni/boringssl/crypto/asn1/bio_asn1.c new file mode 100644 index 00000000..15f233be --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/bio_asn1.c @@ -0,0 +1,496 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include + + +/* Must be large enough for biggest tag+length */ +#define DEFAULT_ASN1_BUF_SIZE 20 + +typedef enum + { + ASN1_STATE_START, + ASN1_STATE_PRE_COPY, + ASN1_STATE_HEADER, + ASN1_STATE_HEADER_COPY, + ASN1_STATE_DATA_COPY, + ASN1_STATE_POST_COPY, + ASN1_STATE_DONE + } asn1_bio_state_t; + +typedef struct BIO_ASN1_EX_FUNCS_st + { + asn1_ps_func *ex_func; + asn1_ps_func *ex_free_func; + } BIO_ASN1_EX_FUNCS; + +typedef struct BIO_ASN1_BUF_CTX_t + { + /* Internal state */ + asn1_bio_state_t state; + /* Internal buffer */ + unsigned char *buf; + /* Size of buffer */ + int bufsize; + /* Current position in buffer */ + int bufpos; + /* Current buffer length */ + int buflen; + /* Amount of data to copy */ + int copylen; + /* Class and tag to use */ + int asn1_class, asn1_tag; + asn1_ps_func *prefix, *prefix_free, *suffix, *suffix_free; + /* Extra buffer for prefix and suffix data */ + unsigned char *ex_buf; + int ex_len; + int ex_pos; + void *ex_arg; + } BIO_ASN1_BUF_CTX; + + +static int asn1_bio_write(BIO *h, const char *buf,int num); +static int asn1_bio_read(BIO *h, char *buf, int size); +static int asn1_bio_puts(BIO *h, const char *str); +static int asn1_bio_gets(BIO *h, char *str, int size); +static long asn1_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static int asn1_bio_new(BIO *h); +static int asn1_bio_free(BIO *data); +static long asn1_bio_callback_ctrl(BIO *h, int cmd, bio_info_cb fp); + +static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size); +static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, + asn1_ps_func *cleanup, asn1_bio_state_t next); +static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, + asn1_ps_func *setup, + asn1_bio_state_t ex_state, + asn1_bio_state_t other_state); + +static const BIO_METHOD methods_asn1= + { + BIO_TYPE_ASN1, + "asn1", + asn1_bio_write, + asn1_bio_read, + asn1_bio_puts, + asn1_bio_gets, + asn1_bio_ctrl, + asn1_bio_new, + asn1_bio_free, + asn1_bio_callback_ctrl, + }; + +const BIO_METHOD *BIO_f_asn1(void) + { + return(&methods_asn1); + } + + +static int asn1_bio_new(BIO *b) + { + BIO_ASN1_BUF_CTX *ctx; + ctx = OPENSSL_malloc(sizeof(BIO_ASN1_BUF_CTX)); + if (!ctx) + return 0; + if (!asn1_bio_init(ctx, DEFAULT_ASN1_BUF_SIZE)) + { + OPENSSL_free(ctx); + return 0; + } + b->init = 1; + b->ptr = (char *)ctx; + b->flags = 0; + return 1; + } + +static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size) + { + ctx->buf = OPENSSL_malloc(size); + if (!ctx->buf) + return 0; + ctx->bufsize = size; + ctx->bufpos = 0; + ctx->buflen = 0; + ctx->copylen = 0; + ctx->asn1_class = V_ASN1_UNIVERSAL; + ctx->asn1_tag = V_ASN1_OCTET_STRING; + ctx->ex_buf = 0; + ctx->ex_pos = 0; + ctx->ex_len = 0; + ctx->state = ASN1_STATE_START; + return 1; + } + +static int asn1_bio_free(BIO *b) + { + BIO_ASN1_BUF_CTX *ctx; + ctx = (BIO_ASN1_BUF_CTX *) b->ptr; + if (ctx == NULL) + return 0; + if (ctx->buf) + OPENSSL_free(ctx->buf); + OPENSSL_free(ctx); + b->init = 0; + b->ptr = NULL; + b->flags = 0; + return 1; + } + +static int asn1_bio_write(BIO *b, const char *in , int inl) + { + BIO_ASN1_BUF_CTX *ctx; + int wrmax, wrlen, ret; + unsigned char *p; + if (!in || (inl < 0) || (b->next_bio == NULL)) + return 0; + ctx = (BIO_ASN1_BUF_CTX *) b->ptr; + if (ctx == NULL) + return 0; + + wrlen = 0; + ret = -1; + + for(;;) + { + switch (ctx->state) + { + + /* Setup prefix data, call it */ + case ASN1_STATE_START: + if (!asn1_bio_setup_ex(b, ctx, ctx->prefix, + ASN1_STATE_PRE_COPY, ASN1_STATE_HEADER)) + return 0; + break; + + /* Copy any pre data first */ + case ASN1_STATE_PRE_COPY: + + ret = asn1_bio_flush_ex(b, ctx, ctx->prefix_free, + ASN1_STATE_HEADER); + + if (ret <= 0) + goto done; + + break; + + case ASN1_STATE_HEADER: + ctx->buflen = + ASN1_object_size(0, inl, ctx->asn1_tag) - inl; + assert(ctx->buflen <= ctx->bufsize); + p = ctx->buf; + ASN1_put_object(&p, 0, inl, + ctx->asn1_tag, ctx->asn1_class); + ctx->copylen = inl; + ctx->state = ASN1_STATE_HEADER_COPY; + + break; + + case ASN1_STATE_HEADER_COPY: + ret = BIO_write(b->next_bio, + ctx->buf + ctx->bufpos, ctx->buflen); + if (ret <= 0) + goto done; + + ctx->buflen -= ret; + if (ctx->buflen) + ctx->bufpos += ret; + else + { + ctx->bufpos = 0; + ctx->state = ASN1_STATE_DATA_COPY; + } + + break; + + case ASN1_STATE_DATA_COPY: + + if (inl > ctx->copylen) + wrmax = ctx->copylen; + else + wrmax = inl; + ret = BIO_write(b->next_bio, in, wrmax); + if (ret <= 0) + break; + wrlen += ret; + ctx->copylen -= ret; + in += ret; + inl -= ret; + + if (ctx->copylen == 0) + ctx->state = ASN1_STATE_HEADER; + + if (inl == 0) + goto done; + + break; + + default: + BIO_clear_retry_flags(b); + return 0; + + } + + } + + done: + BIO_clear_retry_flags(b); + BIO_copy_next_retry(b); + + return (wrlen > 0) ? wrlen : ret; + + } + +static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, + asn1_ps_func *cleanup, asn1_bio_state_t next) + { + int ret; + if (ctx->ex_len <= 0) + return 1; + for(;;) + { + ret = BIO_write(b->next_bio, ctx->ex_buf + ctx->ex_pos, + ctx->ex_len); + if (ret <= 0) + break; + ctx->ex_len -= ret; + if (ctx->ex_len > 0) + ctx->ex_pos += ret; + else + { + if(cleanup) + cleanup(b, &ctx->ex_buf, &ctx->ex_len, + &ctx->ex_arg); + ctx->state = next; + ctx->ex_pos = 0; + break; + } + } + return ret; + } + +static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, + asn1_ps_func *setup, + asn1_bio_state_t ex_state, + asn1_bio_state_t other_state) + { + if (setup && !setup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg)) + { + BIO_clear_retry_flags(b); + return 0; + } + if (ctx->ex_len > 0) + ctx->state = ex_state; + else + ctx->state = other_state; + return 1; + } + +static int asn1_bio_read(BIO *b, char *in , int inl) + { + if (!b->next_bio) + return 0; + return BIO_read(b->next_bio, in , inl); + } + +static int asn1_bio_puts(BIO *b, const char *str) + { + return asn1_bio_write(b, str, strlen(str)); + } + +static int asn1_bio_gets(BIO *b, char *str, int size) + { + if (!b->next_bio) + return 0; + return BIO_gets(b->next_bio, str , size); + } + +static long asn1_bio_callback_ctrl(BIO *b, int cmd, bio_info_cb fp) + { + if (b->next_bio == NULL) return(0); + return BIO_callback_ctrl(b->next_bio,cmd,fp); + } + +static long asn1_bio_ctrl(BIO *b, int cmd, long arg1, void *arg2) + { + BIO_ASN1_BUF_CTX *ctx; + BIO_ASN1_EX_FUNCS *ex_func; + long ret = 1; + ctx = (BIO_ASN1_BUF_CTX *) b->ptr; + if (ctx == NULL) + return 0; + switch(cmd) + { + + case BIO_C_SET_PREFIX: + ex_func = arg2; + ctx->prefix = ex_func->ex_func; + ctx->prefix_free = ex_func->ex_free_func; + break; + + case BIO_C_GET_PREFIX: + ex_func = arg2; + ex_func->ex_func = ctx->prefix; + ex_func->ex_free_func = ctx->prefix_free; + break; + + case BIO_C_SET_SUFFIX: + ex_func = arg2; + ctx->suffix = ex_func->ex_func; + ctx->suffix_free = ex_func->ex_free_func; + break; + + case BIO_C_GET_SUFFIX: + ex_func = arg2; + ex_func->ex_func = ctx->suffix; + ex_func->ex_free_func = ctx->suffix_free; + break; + + case BIO_C_SET_EX_ARG: + ctx->ex_arg = arg2; + break; + + case BIO_C_GET_EX_ARG: + *(void **)arg2 = ctx->ex_arg; + break; + + case BIO_CTRL_FLUSH: + if (!b->next_bio) + return 0; + + /* Call post function if possible */ + if (ctx->state == ASN1_STATE_HEADER) + { + if (!asn1_bio_setup_ex(b, ctx, ctx->suffix, + ASN1_STATE_POST_COPY, ASN1_STATE_DONE)) + return 0; + } + + if (ctx->state == ASN1_STATE_POST_COPY) + { + ret = asn1_bio_flush_ex(b, ctx, ctx->suffix_free, + ASN1_STATE_DONE); + if (ret <= 0) + return ret; + } + + if (ctx->state == ASN1_STATE_DONE) + return BIO_ctrl(b->next_bio, cmd, arg1, arg2); + else + { + BIO_clear_retry_flags(b); + return 0; + } + break; + + + default: + if (!b->next_bio) + return 0; + return BIO_ctrl(b->next_bio, cmd, arg1, arg2); + + } + + return ret; + } + +static int asn1_bio_set_ex(BIO *b, int cmd, + asn1_ps_func *ex_func, asn1_ps_func *ex_free_func) + { + BIO_ASN1_EX_FUNCS extmp; + extmp.ex_func = ex_func; + extmp.ex_free_func = ex_free_func; + return BIO_ctrl(b, cmd, 0, &extmp); + } + +static int asn1_bio_get_ex(BIO *b, int cmd, + asn1_ps_func **ex_func, asn1_ps_func **ex_free_func) + { + BIO_ASN1_EX_FUNCS extmp; + int ret; + ret = BIO_ctrl(b, cmd, 0, &extmp); + if (ret > 0) + { + *ex_func = extmp.ex_func; + *ex_free_func = extmp.ex_free_func; + } + return ret; + } + +int BIO_asn1_set_prefix(BIO *b, asn1_ps_func *prefix, asn1_ps_func *prefix_free) + { + return asn1_bio_set_ex(b, BIO_C_SET_PREFIX, prefix, prefix_free); + } + +int BIO_asn1_get_prefix(BIO *b, asn1_ps_func **pprefix, asn1_ps_func **pprefix_free) + { + return asn1_bio_get_ex(b, BIO_C_GET_PREFIX, pprefix, pprefix_free); + } + +int BIO_asn1_set_suffix(BIO *b, asn1_ps_func *suffix, asn1_ps_func *suffix_free) + { + return asn1_bio_set_ex(b, BIO_C_SET_SUFFIX, suffix, suffix_free); + } + +int BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix, asn1_ps_func **psuffix_free) + { + return asn1_bio_get_ex(b, BIO_C_GET_SUFFIX, psuffix, psuffix_free); + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/bio_ndef.c b/TMessagesProj/jni/boringssl/crypto/asn1/bio_ndef.c new file mode 100644 index 00000000..f07d3de7 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/bio_ndef.c @@ -0,0 +1,254 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include +#include + + +/* Experimental NDEF ASN1 BIO support routines */ + +/* The usage is quite simple, initialize an ASN1 structure, + * get a BIO from it then any data written through the BIO + * will end up translated to approptiate format on the fly. + * The data is streamed out and does *not* need to be + * all held in memory at once. + * + * When the BIO is flushed the output is finalized and any + * signatures etc written out. + * + * The BIO is a 'proper' BIO and can handle non blocking I/O + * correctly. + * + * The usage is simple. The implementation is *not*... + */ + +/* BIO support data stored in the ASN1 BIO ex_arg */ + +typedef struct ndef_aux_st + { + /* ASN1 structure this BIO refers to */ + ASN1_VALUE *val; + const ASN1_ITEM *it; + /* Top of the BIO chain */ + BIO *ndef_bio; + /* Output BIO */ + BIO *out; + /* Boundary where content is inserted */ + unsigned char **boundary; + /* DER buffer start */ + unsigned char *derbuf; + } NDEF_SUPPORT; + +static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg); +static int ndef_prefix_free(BIO *b, unsigned char **pbuf, int *plen, void *parg); +static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg); +static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen, void *parg); + +BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it) + { + NDEF_SUPPORT *ndef_aux = NULL; + BIO *asn_bio = NULL; + const ASN1_AUX *aux = it->funcs; + ASN1_STREAM_ARG sarg; + + if (!aux || !aux->asn1_cb) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_STREAMING_NOT_SUPPORTED); + return NULL; + } + ndef_aux = OPENSSL_malloc(sizeof(NDEF_SUPPORT)); + asn_bio = BIO_new(BIO_f_asn1()); + + /* ASN1 bio needs to be next to output BIO */ + + out = BIO_push(asn_bio, out); + + if (!ndef_aux || !asn_bio || !out) + goto err; + + BIO_asn1_set_prefix(asn_bio, ndef_prefix, ndef_prefix_free); + BIO_asn1_set_suffix(asn_bio, ndef_suffix, ndef_suffix_free); + + /* Now let callback prepend any digest, cipher etc BIOs + * ASN1 structure needs. + */ + + sarg.out = out; + sarg.ndef_bio = NULL; + sarg.boundary = NULL; + + if (aux->asn1_cb(ASN1_OP_STREAM_PRE, &val, it, &sarg) <= 0) + goto err; + + ndef_aux->val = val; + ndef_aux->it = it; + ndef_aux->ndef_bio = sarg.ndef_bio; + ndef_aux->boundary = sarg.boundary; + ndef_aux->out = out; + + BIO_ctrl(asn_bio, BIO_C_SET_EX_ARG, 0, ndef_aux); + + return sarg.ndef_bio; + + err: + if (asn_bio) + BIO_free(asn_bio); + if (ndef_aux) + OPENSSL_free(ndef_aux); + return NULL; + } + +static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg) + { + NDEF_SUPPORT *ndef_aux; + unsigned char *p; + int derlen; + + if (!parg) + return 0; + + ndef_aux = *(NDEF_SUPPORT **)parg; + + derlen = ASN1_item_ndef_i2d(ndef_aux->val, NULL, ndef_aux->it); + p = OPENSSL_malloc(derlen); + if (p == NULL) + return 0; + + ndef_aux->derbuf = p; + *pbuf = p; + derlen = ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it); + + if (!*ndef_aux->boundary) + return 0; + + *plen = *ndef_aux->boundary - *pbuf; + + return 1; + } + +static int ndef_prefix_free(BIO *b, unsigned char **pbuf, int *plen, void *parg) + { + NDEF_SUPPORT *ndef_aux; + + if (!parg) + return 0; + + ndef_aux = *(NDEF_SUPPORT **)parg; + + if (ndef_aux->derbuf) + OPENSSL_free(ndef_aux->derbuf); + + ndef_aux->derbuf = NULL; + *pbuf = NULL; + *plen = 0; + return 1; + } + +static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen, void *parg) + { + NDEF_SUPPORT **pndef_aux = (NDEF_SUPPORT **)parg; + if (!ndef_prefix_free(b, pbuf, plen, parg)) + return 0; + OPENSSL_free(*pndef_aux); + *pndef_aux = NULL; + return 1; + } + +static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg) + { + NDEF_SUPPORT *ndef_aux; + unsigned char *p; + int derlen; + const ASN1_AUX *aux; + ASN1_STREAM_ARG sarg; + + if (!parg) + return 0; + + ndef_aux = *(NDEF_SUPPORT **)parg; + + aux = ndef_aux->it->funcs; + + /* Finalize structures */ + sarg.ndef_bio = ndef_aux->ndef_bio; + sarg.out = ndef_aux->out; + sarg.boundary = ndef_aux->boundary; + if (aux->asn1_cb(ASN1_OP_STREAM_POST, + &ndef_aux->val, ndef_aux->it, &sarg) <= 0) + return 0; + + derlen = ASN1_item_ndef_i2d(ndef_aux->val, NULL, ndef_aux->it); + p = OPENSSL_malloc(derlen); + if (p == NULL) + return 0; + + ndef_aux->derbuf = p; + *pbuf = p; + derlen = ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it); + + if (!*ndef_aux->boundary) + return 0; + *pbuf = *ndef_aux->boundary; + *plen = derlen - (*ndef_aux->boundary - ndef_aux->derbuf); + + return 1; + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/charmap.pl b/TMessagesProj/jni/boringssl/crypto/asn1/charmap.pl new file mode 100644 index 00000000..71bc7b8b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/charmap.pl @@ -0,0 +1,135 @@ +#!/usr/local/bin/perl -w + +# Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project +# 2000. +# +# ==================================================================== +# Copyright (c) 2000 The OpenSSL Project. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# 3. All advertising materials mentioning features or use of this +# software must display the following acknowledgment: +# "This product includes software developed by the OpenSSL Project +# for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" +# +# 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to +# endorse or promote products derived from this software without +# prior written permission. For written permission, please contact +# licensing@OpenSSL.org. +# +# 5. Products derived from this software may not be called "OpenSSL" +# nor may "OpenSSL" appear in their names without prior written +# permission of the OpenSSL Project. +# +# 6. Redistributions of any form whatsoever must retain the following +# acknowledgment: +# "This product includes software developed by the OpenSSL Project +# for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" +# +# THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY +# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR +# ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +# OF THE POSSIBILITY OF SUCH DAMAGE. +# ==================================================================== +# +# This product includes cryptographic software written by Eric Young +# (eay@cryptsoft.com). This product includes software written by Tim +# Hudson (tjh@cryptsoft.com). + +use strict; + +my ($i, @arr); + +# Set up an array with the type of ASCII characters +# Each set bit represents a character property. + +# RFC2253 character properties +my $RFC2253_ESC = 1; # Character escaped with \ +my $ESC_CTRL = 2; # Escaped control character +# These are used with RFC1779 quoting using " +my $NOESC_QUOTE = 8; # Not escaped if quoted +my $PSTRING_CHAR = 0x10; # Valid PrintableString character +my $RFC2253_FIRST_ESC = 0x20; # Escaped with \ if first character +my $RFC2253_LAST_ESC = 0x40; # Escaped with \ if last character + +for($i = 0; $i < 128; $i++) { + # Set the RFC2253 escape characters (control) + $arr[$i] = 0; + if(($i < 32) || ($i > 126)) { + $arr[$i] |= $ESC_CTRL; + } + + # Some PrintableString characters + if( ( ( $i >= ord("a")) && ( $i <= ord("z")) ) + || ( ( $i >= ord("A")) && ( $i <= ord("Z")) ) + || ( ( $i >= ord("0")) && ( $i <= ord("9")) ) ) { + $arr[$i] |= $PSTRING_CHAR; + } +} + +# Now setup the rest + +# Remaining RFC2253 escaped characters + +$arr[ord(" ")] |= $NOESC_QUOTE | $RFC2253_FIRST_ESC | $RFC2253_LAST_ESC; +$arr[ord("#")] |= $NOESC_QUOTE | $RFC2253_FIRST_ESC; + +$arr[ord(",")] |= $NOESC_QUOTE | $RFC2253_ESC; +$arr[ord("+")] |= $NOESC_QUOTE | $RFC2253_ESC; +$arr[ord("\"")] |= $RFC2253_ESC; +$arr[ord("\\")] |= $RFC2253_ESC; +$arr[ord("<")] |= $NOESC_QUOTE | $RFC2253_ESC; +$arr[ord(">")] |= $NOESC_QUOTE | $RFC2253_ESC; +$arr[ord(";")] |= $NOESC_QUOTE | $RFC2253_ESC; + +# Remaining PrintableString characters + +$arr[ord(" ")] |= $PSTRING_CHAR; +$arr[ord("'")] |= $PSTRING_CHAR; +$arr[ord("(")] |= $PSTRING_CHAR; +$arr[ord(")")] |= $PSTRING_CHAR; +$arr[ord("+")] |= $PSTRING_CHAR; +$arr[ord(",")] |= $PSTRING_CHAR; +$arr[ord("-")] |= $PSTRING_CHAR; +$arr[ord(".")] |= $PSTRING_CHAR; +$arr[ord("/")] |= $PSTRING_CHAR; +$arr[ord(":")] |= $PSTRING_CHAR; +$arr[ord("=")] |= $PSTRING_CHAR; +$arr[ord("?")] |= $PSTRING_CHAR; + +# Now generate the C code + +print < + +#include +#include + +/* Based on a_int.c: equivalent ENUMERATED functions */ + +int i2a_ASN1_ENUMERATED(BIO *bp, ASN1_ENUMERATED *a) + { + int i,n=0; + static const char *h="0123456789ABCDEF"; + char buf[2]; + + if (a == NULL) return(0); + + if (a->length == 0) + { + if (BIO_write(bp,"00",2) != 2) goto err; + n=2; + } + else + { + for (i=0; ilength; i++) + { + if ((i != 0) && (i%35 == 0)) + { + if (BIO_write(bp,"\\\n",2) != 2) goto err; + n+=2; + } + buf[0]=h[((unsigned char)a->data[i]>>4)&0x0f]; + buf[1]=h[((unsigned char)a->data[i] )&0x0f]; + if (BIO_write(bp,buf,2) != 2) goto err; + n+=2; + } + } + return(n); +err: + return(-1); + } + +int a2i_ASN1_ENUMERATED(BIO *bp, ASN1_ENUMERATED *bs, char *buf, int size) + { + int ret=0; + int i,j,k,m,n,again,bufsize; + unsigned char *s=NULL,*sp; + unsigned char *bufp; + int num=0,slen=0,first=1; + + bs->type=V_ASN1_ENUMERATED; + + bufsize=BIO_gets(bp,buf,size); + for (;;) + { + if (bufsize < 1) goto err_sl; + i=bufsize; + if (buf[i-1] == '\n') buf[--i]='\0'; + if (i == 0) goto err_sl; + if (buf[i-1] == '\r') buf[--i]='\0'; + if (i == 0) goto err_sl; + again=(buf[i-1] == '\\'); + + for (j=0; j= '0') && (buf[j] <= '9')) || + ((buf[j] >= 'a') && (buf[j] <= 'f')) || + ((buf[j] >= 'A') && (buf[j] <= 'F')))) + { + i=j; + break; + } + } + buf[i]='\0'; + /* We have now cleared all the crap off the end of the + * line */ + if (i < 2) goto err_sl; + + bufp=(unsigned char *)buf; + if (first) + { + first=0; + if ((bufp[0] == '0') && (buf[1] == '0')) + { + bufp+=2; + i-=2; + } + } + k=0; + i-=again; + if (i%2 != 0) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ODD_NUMBER_OF_CHARS); + goto err; + } + i/=2; + if (num+i > slen) + { + if (s == NULL) + sp=(unsigned char *)OPENSSL_malloc( + (unsigned int)num+i*2); + else + sp=(unsigned char *)OPENSSL_realloc(s, + (unsigned int)num+i*2); + if (sp == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto err; + } + s=sp; + slen=num+i*2; + } + for (j=0; j= '0') && (m <= '9')) + m-='0'; + else if ((m >= 'a') && (m <= 'f')) + m=m-'a'+10; + else if ((m >= 'A') && (m <= 'F')) + m=m-'A'+10; + else + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NON_HEX_CHARACTERS); + goto err; + } + s[num+j]<<=4; + s[num+j]|=m; + } + } + num+=i; + if (again) + bufsize=BIO_gets(bp,buf,size); + else + break; + } + bs->length=num; + bs->data=s; + ret=1; +err: + if (0) + { +err_sl: + OPENSSL_PUT_ERROR(ASN1, ASN1_R_SHORT_LINE); + } + if (s != NULL) + OPENSSL_free(s); + return(ret); + } + diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/f_int.c b/TMessagesProj/jni/boringssl/crypto/asn1/f_int.c new file mode 100644 index 00000000..5186304b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/f_int.c @@ -0,0 +1,210 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + +int i2a_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *a) + { + int i,n=0; + static const char *h="0123456789ABCDEF"; + char buf[2]; + + if (a == NULL) return(0); + + if (a->type & V_ASN1_NEG) + { + if (BIO_write(bp, "-", 1) != 1) goto err; + n = 1; + } + + if (a->length == 0) + { + if (BIO_write(bp,"00",2) != 2) goto err; + n += 2; + } + else + { + for (i=0; ilength; i++) + { + if ((i != 0) && (i%35 == 0)) + { + if (BIO_write(bp,"\\\n",2) != 2) goto err; + n+=2; + } + buf[0]=h[((unsigned char)a->data[i]>>4)&0x0f]; + buf[1]=h[((unsigned char)a->data[i] )&0x0f]; + if (BIO_write(bp,buf,2) != 2) goto err; + n+=2; + } + } + return(n); +err: + return(-1); + } + +int a2i_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *bs, char *buf, int size) + { + int ret=0; + int i,j,k,m,n,again,bufsize; + unsigned char *s=NULL,*sp; + unsigned char *bufp; + int num=0,slen=0,first=1; + + bs->type=V_ASN1_INTEGER; + + bufsize=BIO_gets(bp,buf,size); + for (;;) + { + if (bufsize < 1) goto err_sl; + i=bufsize; + if (buf[i-1] == '\n') buf[--i]='\0'; + if (i == 0) goto err_sl; + if (buf[i-1] == '\r') buf[--i]='\0'; + if (i == 0) goto err_sl; + again=(buf[i-1] == '\\'); + + for (j=0; j= '0') && (buf[j] <= '9')) || + ((buf[j] >= 'a') && (buf[j] <= 'f')) || + ((buf[j] >= 'A') && (buf[j] <= 'F')))) + { + i=j; + break; + } + } + buf[i]='\0'; + /* We have now cleared all the crap off the end of the + * line */ + if (i < 2) goto err_sl; + + bufp=(unsigned char *)buf; + if (first) + { + first=0; + if ((bufp[0] == '0') && (buf[1] == '0')) + { + bufp+=2; + i-=2; + } + } + k=0; + i-=again; + if (i%2 != 0) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ODD_NUMBER_OF_CHARS); + goto err; + } + i/=2; + if (num+i > slen) + { + if (s == NULL) + sp=(unsigned char *)OPENSSL_malloc( + (unsigned int)num+i*2); + else + sp=OPENSSL_realloc_clean(s,slen,num+i*2); + if (sp == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto err; + } + s=sp; + slen=num+i*2; + } + for (j=0; j= '0') && (m <= '9')) + m-='0'; + else if ((m >= 'a') && (m <= 'f')) + m=m-'a'+10; + else if ((m >= 'A') && (m <= 'F')) + m=m-'A'+10; + else + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NON_HEX_CHARACTERS); + goto err; + } + s[num+j]<<=4; + s[num+j]|=m; + } + } + num+=i; + if (again) + bufsize=BIO_gets(bp,buf,size); + else + break; + } + bs->length=num; + bs->data=s; + ret=1; +err: + if (0) + { +err_sl: + OPENSSL_PUT_ERROR(ASN1, ASN1_R_SHORT_LINE); + } + if (s != NULL) + OPENSSL_free(s); + return(ret); + } + diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/f_string.c b/TMessagesProj/jni/boringssl/crypto/asn1/f_string.c new file mode 100644 index 00000000..5a7fe36a --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/f_string.c @@ -0,0 +1,204 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + + +int i2a_ASN1_STRING(BIO *bp, ASN1_STRING *a, int type) + { + int i,n=0; + static const char *h="0123456789ABCDEF"; + char buf[2]; + + if (a == NULL) return(0); + + if (a->length == 0) + { + if (BIO_write(bp,"0",1) != 1) goto err; + n=1; + } + else + { + for (i=0; ilength; i++) + { + if ((i != 0) && (i%35 == 0)) + { + if (BIO_write(bp,"\\\n",2) != 2) goto err; + n+=2; + } + buf[0]=h[((unsigned char)a->data[i]>>4)&0x0f]; + buf[1]=h[((unsigned char)a->data[i] )&0x0f]; + if (BIO_write(bp,buf,2) != 2) goto err; + n+=2; + } + } + return(n); +err: + return(-1); + } + +int a2i_ASN1_STRING(BIO *bp, ASN1_STRING *bs, char *buf, int size) + { + int ret=0; + int i,j,k,m,n,again,bufsize; + unsigned char *s=NULL,*sp; + unsigned char *bufp; + int num=0,slen=0,first=1; + + bufsize=BIO_gets(bp,buf,size); + for (;;) + { + if (bufsize < 1) + { + if (first) + break; + else + goto err_sl; + } + first=0; + + i=bufsize; + if (buf[i-1] == '\n') buf[--i]='\0'; + if (i == 0) goto err_sl; + if (buf[i-1] == '\r') buf[--i]='\0'; + if (i == 0) goto err_sl; + again=(buf[i-1] == '\\'); + + for (j=i-1; j>0; j--) + { + if (!( ((buf[j] >= '0') && (buf[j] <= '9')) || + ((buf[j] >= 'a') && (buf[j] <= 'f')) || + ((buf[j] >= 'A') && (buf[j] <= 'F')))) + { + i=j; + break; + } + } + buf[i]='\0'; + /* We have now cleared all the crap off the end of the + * line */ + if (i < 2) goto err_sl; + + bufp=(unsigned char *)buf; + + k=0; + i-=again; + if (i%2 != 0) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ODD_NUMBER_OF_CHARS); + goto err; + } + i/=2; + if (num+i > slen) + { + if (s == NULL) + sp=(unsigned char *)OPENSSL_malloc( + (unsigned int)num+i*2); + else + sp=(unsigned char *)OPENSSL_realloc(s, + (unsigned int)num+i*2); + if (sp == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto err; + } + s=sp; + slen=num+i*2; + } + for (j=0; j= '0') && (m <= '9')) + m-='0'; + else if ((m >= 'a') && (m <= 'f')) + m=m-'a'+10; + else if ((m >= 'A') && (m <= 'F')) + m=m-'A'+10; + else + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NON_HEX_CHARACTERS); + goto err; + } + s[num+j]<<=4; + s[num+j]|=m; + } + } + num+=i; + if (again) + bufsize=BIO_gets(bp,buf,size); + else + break; + } + bs->length=num; + bs->data=s; + ret=1; +err: + if (0) + { +err_sl: + OPENSSL_PUT_ERROR(ASN1, ASN1_R_SHORT_LINE); + } + if (s != NULL) + OPENSSL_free(s); + return(ret); + } + diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/t_bitst.c b/TMessagesProj/jni/boringssl/crypto/asn1/t_bitst.c new file mode 100644 index 00000000..1ca6e089 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/t_bitst.c @@ -0,0 +1,102 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include + + +int ASN1_BIT_STRING_name_print(BIO *out, ASN1_BIT_STRING *bs, + BIT_STRING_BITNAME *tbl, int indent) +{ + BIT_STRING_BITNAME *bnam; + char first = 1; + BIO_printf(out, "%*s", indent, ""); + for(bnam = tbl; bnam->lname; bnam++) { + if(ASN1_BIT_STRING_get_bit(bs, bnam->bitnum)) { + if(!first) BIO_puts(out, ", "); + BIO_puts(out, bnam->lname); + first = 0; + } + } + BIO_puts(out, "\n"); + return 1; +} + +int ASN1_BIT_STRING_set_asc(ASN1_BIT_STRING *bs, char *name, int value, + BIT_STRING_BITNAME *tbl) +{ + int bitnum; + bitnum = ASN1_BIT_STRING_num_asc(name, tbl); + if(bitnum < 0) return 0; + if(bs) { + if(!ASN1_BIT_STRING_set_bit(bs, bitnum, value)) + return 0; + } + return 1; +} + +int ASN1_BIT_STRING_num_asc(char *name, BIT_STRING_BITNAME *tbl) +{ + BIT_STRING_BITNAME *bnam; + for(bnam = tbl; bnam->lname; bnam++) { + if(!strcmp(bnam->sname, name) || + !strcmp(bnam->lname, name) ) return bnam->bitnum; + } + return -1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/t_pkey.c b/TMessagesProj/jni/boringssl/crypto/asn1/t_pkey.c new file mode 100644 index 00000000..6ac9b3d6 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/t_pkey.c @@ -0,0 +1,112 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + +int ASN1_bn_print(BIO *bp, const char *number, const BIGNUM *num, + unsigned char *buf, int off) + { + int n,i; + const char *neg; + + if (num == NULL) return(1); + neg = (BN_is_negative(num))?"-":""; + if(!BIO_indent(bp,off,128)) + return 0; + if (BN_is_zero(num)) + { + if (BIO_printf(bp, "%s 0\n", number) <= 0) + return 0; + return 1; + } + + if (BN_num_bytes(num) <= sizeof(long)) + { + if (BIO_printf(bp,"%s %s%lu (%s0x%lx)\n",number,neg, + (unsigned long)num->d[0],neg,(unsigned long)num->d[0]) + <= 0) return(0); + } + else + { + buf[0]=0; + if (BIO_printf(bp,"%s%s",number, + (neg[0] == '-')?" (Negative)":"") <= 0) + return(0); + n=BN_bn2bin(num,&buf[1]); + + if (buf[1] & 0x80) + n++; + else buf++; + + for (i=0; i + +#include + +#include +#include +#include +#include + +#include "../internal.h" + + +static int asn1_check_eoc(const unsigned char **in, long len); +static int asn1_find_end(const unsigned char **in, long len, char inf); + +static int asn1_collect(BUF_MEM *buf, const unsigned char **in, long len, + char inf, int tag, int aclass, int depth); + +static int collect_data(BUF_MEM *buf, const unsigned char **p, long plen); + +static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass, + char *inf, char *cst, + const unsigned char **in, long len, + int exptag, int expclass, char opt, + ASN1_TLC *ctx); + +static int asn1_template_ex_d2i(ASN1_VALUE **pval, + const unsigned char **in, long len, + const ASN1_TEMPLATE *tt, char opt, + ASN1_TLC *ctx); +static int asn1_template_noexp_d2i(ASN1_VALUE **val, + const unsigned char **in, long len, + const ASN1_TEMPLATE *tt, char opt, + ASN1_TLC *ctx); +static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, + const unsigned char **in, long len, + const ASN1_ITEM *it, + int tag, int aclass, char opt, ASN1_TLC *ctx); + +/* Table to convert tags to bit values, used for MSTRING type */ +static const unsigned long tag2bit[32] = { +0, 0, 0, B_ASN1_BIT_STRING, /* tags 0 - 3 */ +B_ASN1_OCTET_STRING, 0, 0, B_ASN1_UNKNOWN,/* tags 4- 7 */ +B_ASN1_UNKNOWN, B_ASN1_UNKNOWN, B_ASN1_UNKNOWN, B_ASN1_UNKNOWN,/* tags 8-11 */ +B_ASN1_UTF8STRING,B_ASN1_UNKNOWN,B_ASN1_UNKNOWN,B_ASN1_UNKNOWN,/* tags 12-15 */ +B_ASN1_SEQUENCE,0,B_ASN1_NUMERICSTRING,B_ASN1_PRINTABLESTRING, /* tags 16-19 */ +B_ASN1_T61STRING,B_ASN1_VIDEOTEXSTRING,B_ASN1_IA5STRING, /* tags 20-22 */ +B_ASN1_UTCTIME, B_ASN1_GENERALIZEDTIME, /* tags 23-24 */ +B_ASN1_GRAPHICSTRING,B_ASN1_ISO64STRING,B_ASN1_GENERALSTRING, /* tags 25-27 */ +B_ASN1_UNIVERSALSTRING,B_ASN1_UNKNOWN,B_ASN1_BMPSTRING,B_ASN1_UNKNOWN, /* tags 28-31 */ + }; + +unsigned long ASN1_tag2bit(int tag) + { + if ((tag < 0) || (tag > 30)) return 0; + return tag2bit[tag]; + } + +/* Macro to initialize and invalidate the cache */ + +#define asn1_tlc_clear(c) if (c) (c)->valid = 0 +/* Version to avoid compiler warning about 'c' always non-NULL */ +#define asn1_tlc_clear_nc(c) (c)->valid = 0 + +/* Decode an ASN1 item, this currently behaves just + * like a standard 'd2i' function. 'in' points to + * a buffer to read the data from, in future we will + * have more advanced versions that can input data + * a piece at a time and this will simply be a special + * case. + */ + +ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **pval, + const unsigned char **in, long len, const ASN1_ITEM *it) + { + ASN1_TLC c; + ASN1_VALUE *ptmpval = NULL; + if (!pval) + pval = &ptmpval; + asn1_tlc_clear_nc(&c); + if (ASN1_item_ex_d2i(pval, in, len, it, -1, 0, 0, &c) > 0) + return *pval; + return NULL; + } + +int ASN1_template_d2i(ASN1_VALUE **pval, + const unsigned char **in, long len, const ASN1_TEMPLATE *tt) + { + ASN1_TLC c; + asn1_tlc_clear_nc(&c); + return asn1_template_ex_d2i(pval, in, len, tt, 0, &c); + } + + +/* Decode an item, taking care of IMPLICIT tagging, if any. + * If 'opt' set and tag mismatch return -1 to handle OPTIONAL + */ + +int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, + const ASN1_ITEM *it, + int tag, int aclass, char opt, ASN1_TLC *ctx) + { + const ASN1_TEMPLATE *tt, *errtt = NULL; + const ASN1_COMPAT_FUNCS *cf; + const ASN1_EXTERN_FUNCS *ef; + const ASN1_AUX *aux = it->funcs; + ASN1_aux_cb *asn1_cb; + const unsigned char *p = NULL, *q; + unsigned char *wp=NULL; /* BIG FAT WARNING! BREAKS CONST WHERE USED */ + unsigned char imphack = 0, oclass; + char seq_eoc, seq_nolen, cst, isopt; + long tmplen; + int i; + int otag; + int ret = 0; + ASN1_VALUE **pchptr, *ptmpval; + if (!pval) + return 0; + if (aux && aux->asn1_cb) + asn1_cb = aux->asn1_cb; + else asn1_cb = 0; + + switch(it->itype) + { + case ASN1_ITYPE_PRIMITIVE: + if (it->templates) + { + /* tagging or OPTIONAL is currently illegal on an item + * template because the flags can't get passed down. + * In practice this isn't a problem: we include the + * relevant flags from the item template in the + * template itself. + */ + if ((tag != -1) || opt) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE); + goto err; + } + return asn1_template_ex_d2i(pval, in, len, + it->templates, opt, ctx); + } + return asn1_d2i_ex_primitive(pval, in, len, it, + tag, aclass, opt, ctx); + break; + + case ASN1_ITYPE_MSTRING: + p = *in; + /* Just read in tag and class */ + ret = asn1_check_tlen(NULL, &otag, &oclass, NULL, NULL, + &p, len, -1, 0, 1, ctx); + if (!ret) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + goto err; + } + + /* Must be UNIVERSAL class */ + if (oclass != V_ASN1_UNIVERSAL) + { + /* If OPTIONAL, assume this is OK */ + if (opt) return -1; + OPENSSL_PUT_ERROR(ASN1, ASN1_R_MSTRING_NOT_UNIVERSAL); + goto err; + } + /* Check tag matches bit map */ + if (!(ASN1_tag2bit(otag) & it->utype)) + { + /* If OPTIONAL, assume this is OK */ + if (opt) + return -1; + OPENSSL_PUT_ERROR(ASN1, ASN1_R_MSTRING_WRONG_TAG); + goto err; + } + return asn1_d2i_ex_primitive(pval, in, len, + it, otag, 0, 0, ctx); + + case ASN1_ITYPE_EXTERN: + /* Use new style d2i */ + ef = it->funcs; + return ef->asn1_ex_d2i(pval, in, len, + it, tag, aclass, opt, ctx); + + case ASN1_ITYPE_COMPAT: + /* we must resort to old style evil hackery */ + cf = it->funcs; + + /* If OPTIONAL see if it is there */ + if (opt) + { + int exptag; + p = *in; + if (tag == -1) + exptag = it->utype; + else exptag = tag; + /* Don't care about anything other than presence + * of expected tag */ + + ret = asn1_check_tlen(NULL, NULL, NULL, NULL, NULL, + &p, len, exptag, aclass, 1, ctx); + if (!ret) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + goto err; + } + if (ret == -1) + return -1; + } + + /* This is the old style evil hack IMPLICIT handling: + * since the underlying code is expecting a tag and + * class other than the one present we change the + * buffer temporarily then change it back afterwards. + * This doesn't and never did work for tags > 30. + * + * Yes this is *horrible* but it is only needed for + * old style d2i which will hopefully not be around + * for much longer. + * FIXME: should copy the buffer then modify it so + * the input buffer can be const: we should *always* + * copy because the old style d2i might modify the + * buffer. + */ + + if (tag != -1) + { + wp = *(unsigned char **)in; + imphack = *wp; + if (p == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + goto err; + } + *wp = (unsigned char)((*p & V_ASN1_CONSTRUCTED) + | it->utype); + } + + ptmpval = cf->asn1_d2i(pval, in, len); + + if (tag != -1) + *wp = imphack; + + if (ptmpval) + return 1; + + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + goto err; + + + case ASN1_ITYPE_CHOICE: + if (asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it, NULL)) + goto auxerr; + + if (*pval) + { + /* Free up and zero CHOICE value if initialised */ + i = asn1_get_choice_selector(pval, it); + if ((i >= 0) && (i < it->tcount)) + { + tt = it->templates + i; + pchptr = asn1_get_field_ptr(pval, tt); + ASN1_template_free(pchptr, tt); + asn1_set_choice_selector(pval, -1, it); + } + } + else if (!ASN1_item_ex_new(pval, it)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + goto err; + } + /* CHOICE type, try each possibility in turn */ + p = *in; + for (i = 0, tt=it->templates; i < it->tcount; i++, tt++) + { + pchptr = asn1_get_field_ptr(pval, tt); + /* We mark field as OPTIONAL so its absence + * can be recognised. + */ + ret = asn1_template_ex_d2i(pchptr, &p, len, tt, 1, ctx); + /* If field not present, try the next one */ + if (ret == -1) + continue; + /* If positive return, read OK, break loop */ + if (ret > 0) + break; + /* Otherwise must be an ASN1 parsing error */ + errtt = tt; + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + goto err; + } + + /* Did we fall off the end without reading anything? */ + if (i == it->tcount) + { + /* If OPTIONAL, this is OK */ + if (opt) + { + /* Free and zero it */ + ASN1_item_ex_free(pval, it); + return -1; + } + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NO_MATCHING_CHOICE_TYPE); + goto err; + } + + asn1_set_choice_selector(pval, i, it); + *in = p; + if (asn1_cb && !asn1_cb(ASN1_OP_D2I_POST, pval, it, NULL)) + goto auxerr; + return 1; + + case ASN1_ITYPE_NDEF_SEQUENCE: + case ASN1_ITYPE_SEQUENCE: + p = *in; + tmplen = len; + + /* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */ + if (tag == -1) + { + tag = V_ASN1_SEQUENCE; + aclass = V_ASN1_UNIVERSAL; + } + /* Get SEQUENCE length and update len, p */ + ret = asn1_check_tlen(&len, NULL, NULL, &seq_eoc, &cst, + &p, len, tag, aclass, opt, ctx); + if (!ret) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + goto err; + } + else if (ret == -1) + return -1; + if (aux && (aux->flags & ASN1_AFLG_BROKEN)) + { + len = tmplen - (p - *in); + seq_nolen = 1; + } + /* If indefinite we don't do a length check */ + else seq_nolen = seq_eoc; + if (!cst) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_SEQUENCE_NOT_CONSTRUCTED); + goto err; + } + + if (!*pval && !ASN1_item_ex_new(pval, it)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + goto err; + } + + if (asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it, NULL)) + goto auxerr; + + /* Free up and zero any ADB found */ + for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) + { + if (tt->flags & ASN1_TFLG_ADB_MASK) + { + const ASN1_TEMPLATE *seqtt; + ASN1_VALUE **pseqval; + seqtt = asn1_do_adb(pval, tt, 1); + pseqval = asn1_get_field_ptr(pval, seqtt); + ASN1_template_free(pseqval, seqtt); + } + } + + /* Get each field entry */ + for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) + { + const ASN1_TEMPLATE *seqtt; + ASN1_VALUE **pseqval; + seqtt = asn1_do_adb(pval, tt, 1); + if (!seqtt) + goto err; + pseqval = asn1_get_field_ptr(pval, seqtt); + /* Have we ran out of data? */ + if (!len) + break; + q = p; + if (asn1_check_eoc(&p, len)) + { + if (!seq_eoc) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNEXPECTED_EOC); + goto err; + } + len -= p - q; + seq_eoc = 0; + q = p; + break; + } + /* This determines the OPTIONAL flag value. The field + * cannot be omitted if it is the last of a SEQUENCE + * and there is still data to be read. This isn't + * strictly necessary but it increases efficiency in + * some cases. + */ + if (i == (it->tcount - 1)) + isopt = 0; + else isopt = (char)(seqtt->flags & ASN1_TFLG_OPTIONAL); + /* attempt to read in field, allowing each to be + * OPTIONAL */ + + ret = asn1_template_ex_d2i(pseqval, &p, len, + seqtt, isopt, ctx); + if (!ret) + { + errtt = seqtt; + goto err; + } + else if (ret == -1) + { + /* OPTIONAL component absent. + * Free and zero the field. + */ + ASN1_template_free(pseqval, seqtt); + continue; + } + /* Update length */ + len -= p - q; + } + + /* Check for EOC if expecting one */ + if (seq_eoc && !asn1_check_eoc(&p, len)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_EOC); + goto err; + } + /* Check all data read */ + if (!seq_nolen && len) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_SEQUENCE_LENGTH_MISMATCH); + goto err; + } + + /* If we get here we've got no more data in the SEQUENCE, + * however we may not have read all fields so check all + * remaining are OPTIONAL and clear any that are. + */ + for (; i < it->tcount; tt++, i++) + { + const ASN1_TEMPLATE *seqtt; + seqtt = asn1_do_adb(pval, tt, 1); + if (!seqtt) + goto err; + if (seqtt->flags & ASN1_TFLG_OPTIONAL) + { + ASN1_VALUE **pseqval; + pseqval = asn1_get_field_ptr(pval, seqtt); + ASN1_template_free(pseqval, seqtt); + } + else + { + errtt = seqtt; + OPENSSL_PUT_ERROR(ASN1, ASN1_R_FIELD_MISSING); + goto err; + } + } + /* Save encoding */ + if (!asn1_enc_save(pval, *in, p - *in, it)) + goto auxerr; + *in = p; + if (asn1_cb && !asn1_cb(ASN1_OP_D2I_POST, pval, it, NULL)) + goto auxerr; + return 1; + + default: + return 0; + } + auxerr: + OPENSSL_PUT_ERROR(ASN1, ASN1_R_AUX_ERROR); + err: + ASN1_item_ex_free(pval, it); + if (errtt) + ERR_add_error_data(4, "Field=", errtt->field_name, + ", Type=", it->sname); + else + ERR_add_error_data(2, "Type=", it->sname); + return 0; + } + +/* Templates are handled with two separate functions. + * One handles any EXPLICIT tag and the other handles the rest. + */ + +static int asn1_template_ex_d2i(ASN1_VALUE **val, + const unsigned char **in, long inlen, + const ASN1_TEMPLATE *tt, char opt, + ASN1_TLC *ctx) + { + int flags, aclass; + int ret; + long len; + const unsigned char *p, *q; + char exp_eoc; + if (!val) + return 0; + flags = tt->flags; + aclass = flags & ASN1_TFLG_TAG_CLASS; + + p = *in; + + /* Check if EXPLICIT tag expected */ + if (flags & ASN1_TFLG_EXPTAG) + { + char cst; + /* Need to work out amount of data available to the inner + * content and where it starts: so read in EXPLICIT header to + * get the info. + */ + ret = asn1_check_tlen(&len, NULL, NULL, &exp_eoc, &cst, + &p, inlen, tt->tag, aclass, opt, ctx); + q = p; + if (!ret) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + return 0; + } + else if (ret == -1) + return -1; + if (!cst) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED); + return 0; + } + /* We've found the field so it can't be OPTIONAL now */ + ret = asn1_template_noexp_d2i(val, &p, len, tt, 0, ctx); + if (!ret) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + return 0; + } + /* We read the field in OK so update length */ + len -= p - q; + if (exp_eoc) + { + /* If NDEF we must have an EOC here */ + if (!asn1_check_eoc(&p, len)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_EOC); + goto err; + } + } + else + { + /* Otherwise we must hit the EXPLICIT tag end or its + * an error */ + if (len) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_EXPLICIT_LENGTH_MISMATCH); + goto err; + } + } + } + else + return asn1_template_noexp_d2i(val, in, inlen, + tt, opt, ctx); + + *in = p; + return 1; + + err: + ASN1_template_free(val, tt); + return 0; + } + +static int asn1_template_noexp_d2i(ASN1_VALUE **val, + const unsigned char **in, long len, + const ASN1_TEMPLATE *tt, char opt, + ASN1_TLC *ctx) + { + int flags, aclass; + int ret; + const unsigned char *p; + if (!val) + return 0; + flags = tt->flags; + aclass = flags & ASN1_TFLG_TAG_CLASS; + + p = *in; + + if (flags & ASN1_TFLG_SK_MASK) + { + /* SET OF, SEQUENCE OF */ + int sktag, skaclass; + char sk_eoc; + /* First work out expected inner tag value */ + if (flags & ASN1_TFLG_IMPTAG) + { + sktag = tt->tag; + skaclass = aclass; + } + else + { + skaclass = V_ASN1_UNIVERSAL; + if (flags & ASN1_TFLG_SET_OF) + sktag = V_ASN1_SET; + else + sktag = V_ASN1_SEQUENCE; + } + /* Get the tag */ + ret = asn1_check_tlen(&len, NULL, NULL, &sk_eoc, NULL, + &p, len, sktag, skaclass, opt, ctx); + if (!ret) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + return 0; + } + else if (ret == -1) + return -1; + if (!*val) + *val = (ASN1_VALUE *)sk_new_null(); + else + { + /* We've got a valid STACK: free up any items present */ + STACK_OF(ASN1_VALUE) *sktmp + = (STACK_OF(ASN1_VALUE) *)*val; + ASN1_VALUE *vtmp; + while(sk_ASN1_VALUE_num(sktmp) > 0) + { + vtmp = sk_ASN1_VALUE_pop(sktmp); + ASN1_item_ex_free(&vtmp, + ASN1_ITEM_ptr(tt->item)); + } + } + + if (!*val) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* Read as many items as we can */ + while(len > 0) + { + ASN1_VALUE *skfield; + const unsigned char *q = p; + /* See if EOC found */ + if (asn1_check_eoc(&p, len)) + { + if (!sk_eoc) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNEXPECTED_EOC); + goto err; + } + len -= p - q; + sk_eoc = 0; + break; + } + skfield = NULL; + if (!ASN1_item_ex_d2i(&skfield, &p, len, + ASN1_ITEM_ptr(tt->item), + -1, 0, 0, ctx)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + goto err; + } + len -= p - q; + if (!sk_ASN1_VALUE_push((STACK_OF(ASN1_VALUE) *)*val, + skfield)) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto err; + } + } + if (sk_eoc) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_EOC); + goto err; + } + } + else if (flags & ASN1_TFLG_IMPTAG) + { + /* IMPLICIT tagging */ + ret = ASN1_item_ex_d2i(val, &p, len, + ASN1_ITEM_ptr(tt->item), tt->tag, aclass, opt, ctx); + if (!ret) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + goto err; + } + else if (ret == -1) + return -1; + } + else + { + /* Nothing special */ + ret = ASN1_item_ex_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item), + -1, 0, opt, ctx); + if (!ret) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + goto err; + } + else if (ret == -1) + return -1; + } + + *in = p; + return 1; + + err: + ASN1_template_free(val, tt); + return 0; + } + +static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, + const unsigned char **in, long inlen, + const ASN1_ITEM *it, + int tag, int aclass, char opt, ASN1_TLC *ctx) + OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS + { + int ret = 0, utype; + long plen; + char cst, inf, free_cont = 0; + const unsigned char *p; + BUF_MEM buf; + const unsigned char *cont = NULL; + long len; + if (!pval) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_NULL); + return 0; /* Should never happen */ + } + + if (it->itype == ASN1_ITYPE_MSTRING) + { + utype = tag; + tag = -1; + } + else + utype = it->utype; + + if (utype == V_ASN1_ANY) + { + /* If type is ANY need to figure out type from tag */ + unsigned char oclass; + if (tag >= 0) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_TAGGED_ANY); + return 0; + } + if (opt) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_OPTIONAL_ANY); + return 0; + } + p = *in; + ret = asn1_check_tlen(NULL, &utype, &oclass, NULL, NULL, + &p, inlen, -1, 0, 0, ctx); + if (!ret) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + return 0; + } + if (oclass != V_ASN1_UNIVERSAL) + utype = V_ASN1_OTHER; + } + if (tag == -1) + { + tag = utype; + aclass = V_ASN1_UNIVERSAL; + } + p = *in; + /* Check header */ + ret = asn1_check_tlen(&plen, NULL, NULL, &inf, &cst, + &p, inlen, tag, aclass, opt, ctx); + if (!ret) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + return 0; + } + else if (ret == -1) + return -1; + ret = 0; + /* SEQUENCE, SET and "OTHER" are left in encoded form */ + if ((utype == V_ASN1_SEQUENCE) + || (utype == V_ASN1_SET) || (utype == V_ASN1_OTHER)) + { + /* Clear context cache for type OTHER because the auto clear + * when we have a exact match wont work + */ + if (utype == V_ASN1_OTHER) + { + asn1_tlc_clear(ctx); + } + /* SEQUENCE and SET must be constructed */ + else if (!cst) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_TYPE_NOT_CONSTRUCTED); + return 0; + } + + cont = *in; + /* If indefinite length constructed find the real end */ + if (inf) + { + if (!asn1_find_end(&p, plen, inf)) + goto err; + len = p - cont; + } + else + { + len = p - cont + plen; + p += plen; + buf.data = NULL; + } + } + else if (cst) + { + if (utype == V_ASN1_NULL || utype == V_ASN1_BOOLEAN + || utype == V_ASN1_OBJECT || utype == V_ASN1_INTEGER + || utype == V_ASN1_ENUMERATED) + { + /* These types only have primitive encodings. */ + OPENSSL_PUT_ERROR(ASN1, ASN1_R_TYPE_NOT_PRIMITIVE); + return 0; + } + + buf.length = 0; + buf.max = 0; + buf.data = NULL; + /* Should really check the internal tags are correct but + * some things may get this wrong. The relevant specs + * say that constructed string types should be OCTET STRINGs + * internally irrespective of the type. So instead just check + * for UNIVERSAL class and ignore the tag. + */ + if (!asn1_collect(&buf, &p, plen, inf, -1, V_ASN1_UNIVERSAL, 0)) + { + free_cont = 1; + goto err; + } + len = buf.length; + /* Append a final null to string */ + if (!BUF_MEM_grow_clean(&buf, len + 1)) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return 0; + } + buf.data[len] = 0; + cont = (const unsigned char *)buf.data; + free_cont = 1; + } + else + { + cont = p; + len = plen; + p += plen; + } + + /* We now have content length and type: translate into a structure */ + if (!asn1_ex_c2i(pval, cont, len, utype, &free_cont, it)) + goto err; + + *in = p; + ret = 1; + err: + if (free_cont && buf.data) OPENSSL_free(buf.data); + return ret; + } + +/* Translate ASN1 content octets into a structure */ + +int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, + int utype, char *free_cont, const ASN1_ITEM *it) + { + ASN1_VALUE **opval = NULL; + ASN1_STRING *stmp; + ASN1_TYPE *typ = NULL; + int ret = 0; + const ASN1_PRIMITIVE_FUNCS *pf; + ASN1_INTEGER **tint; + pf = it->funcs; + + if (pf && pf->prim_c2i) + return pf->prim_c2i(pval, cont, len, utype, free_cont, it); + /* If ANY type clear type and set pointer to internal value */ + if (it->utype == V_ASN1_ANY) + { + if (!*pval) + { + typ = ASN1_TYPE_new(); + if (typ == NULL) + goto err; + *pval = (ASN1_VALUE *)typ; + } + else + typ = (ASN1_TYPE *)*pval; + + if (utype != typ->type) + ASN1_TYPE_set(typ, utype, NULL); + opval = pval; + pval = &typ->value.asn1_value; + } + switch(utype) + { + case V_ASN1_OBJECT: + if (!c2i_ASN1_OBJECT((ASN1_OBJECT **)pval, &cont, len)) + goto err; + break; + + case V_ASN1_NULL: + if (len) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NULL_IS_WRONG_LENGTH); + goto err; + } + *pval = (ASN1_VALUE *)1; + break; + + case V_ASN1_BOOLEAN: + if (len != 1) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_BOOLEAN_IS_WRONG_LENGTH); + goto err; + } + else + { + ASN1_BOOLEAN *tbool; + tbool = (ASN1_BOOLEAN *)pval; + *tbool = *cont; + } + break; + + case V_ASN1_BIT_STRING: + if (!c2i_ASN1_BIT_STRING((ASN1_BIT_STRING **)pval, &cont, len)) + goto err; + break; + + case V_ASN1_INTEGER: + case V_ASN1_NEG_INTEGER: + case V_ASN1_ENUMERATED: + case V_ASN1_NEG_ENUMERATED: + tint = (ASN1_INTEGER **)pval; + if (!c2i_ASN1_INTEGER(tint, &cont, len)) + goto err; + /* Fixup type to match the expected form */ + (*tint)->type = utype | ((*tint)->type & V_ASN1_NEG); + break; + + case V_ASN1_OCTET_STRING: + case V_ASN1_NUMERICSTRING: + case V_ASN1_PRINTABLESTRING: + case V_ASN1_T61STRING: + case V_ASN1_VIDEOTEXSTRING: + case V_ASN1_IA5STRING: + case V_ASN1_UTCTIME: + case V_ASN1_GENERALIZEDTIME: + case V_ASN1_GRAPHICSTRING: + case V_ASN1_VISIBLESTRING: + case V_ASN1_GENERALSTRING: + case V_ASN1_UNIVERSALSTRING: + case V_ASN1_BMPSTRING: + case V_ASN1_UTF8STRING: + case V_ASN1_OTHER: + case V_ASN1_SET: + case V_ASN1_SEQUENCE: + default: + if (utype == V_ASN1_BMPSTRING && (len & 1)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_BMPSTRING_IS_WRONG_LENGTH); + goto err; + } + if (utype == V_ASN1_UNIVERSALSTRING && (len & 3)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH); + goto err; + } + /* All based on ASN1_STRING and handled the same */ + if (!*pval) + { + stmp = ASN1_STRING_type_new(utype); + if (!stmp) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto err; + } + *pval = (ASN1_VALUE *)stmp; + } + else + { + stmp = (ASN1_STRING *)*pval; + stmp->type = utype; + } + /* If we've already allocated a buffer use it */ + if (*free_cont) + { + if (stmp->data) + OPENSSL_free(stmp->data); + stmp->data = (unsigned char *)cont; /* UGLY CAST! RL */ + stmp->length = len; + *free_cont = 0; + } + else + { + if (!ASN1_STRING_set(stmp, cont, len)) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + ASN1_STRING_free(stmp); + *pval = NULL; + goto err; + } + } + break; + } + /* If ASN1_ANY and NULL type fix up value */ + if (typ && (utype == V_ASN1_NULL)) + typ->value.ptr = NULL; + + ret = 1; + err: + if (!ret) + { + ASN1_TYPE_free(typ); + if (opval) + *opval = NULL; + } + return ret; + } + + +/* This function finds the end of an ASN1 structure when passed its maximum + * length, whether it is indefinite length and a pointer to the content. + * This is more efficient than calling asn1_collect because it does not + * recurse on each indefinite length header. + */ + +static int asn1_find_end(const unsigned char **in, long len, char inf) + { + int expected_eoc; + long plen; + const unsigned char *p = *in, *q; + /* If not indefinite length constructed just add length */ + if (inf == 0) + { + *in += len; + return 1; + } + expected_eoc = 1; + /* Indefinite length constructed form. Find the end when enough EOCs + * are found. If more indefinite length constructed headers + * are encountered increment the expected eoc count otherwise just + * skip to the end of the data. + */ + while (len > 0) + { + if(asn1_check_eoc(&p, len)) + { + expected_eoc--; + if (expected_eoc == 0) + break; + len -= 2; + continue; + } + q = p; + /* Just read in a header: only care about the length */ + if(!asn1_check_tlen(&plen, NULL, NULL, &inf, NULL, &p, len, + -1, 0, 0, NULL)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + return 0; + } + if (inf) + expected_eoc++; + else + p += plen; + len -= p - q; + } + if (expected_eoc) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_EOC); + return 0; + } + *in = p; + return 1; + } +/* This function collects the asn1 data from a constructred string + * type into a buffer. The values of 'in' and 'len' should refer + * to the contents of the constructed type and 'inf' should be set + * if it is indefinite length. + */ + +#ifndef ASN1_MAX_STRING_NEST +/* This determines how many levels of recursion are permitted in ASN1 + * string types. If it is not limited stack overflows can occur. If set + * to zero no recursion is allowed at all. Although zero should be adequate + * examples exist that require a value of 1. So 5 should be more than enough. + */ +#define ASN1_MAX_STRING_NEST 5 +#endif + + +static int asn1_collect(BUF_MEM *buf, const unsigned char **in, long len, + char inf, int tag, int aclass, int depth) + { + const unsigned char *p, *q; + long plen; + char cst, ininf; + p = *in; + inf &= 1; + /* If no buffer and not indefinite length constructed just pass over + * the encoded data */ + if (!buf && !inf) + { + *in += len; + return 1; + } + while(len > 0) + { + q = p; + /* Check for EOC */ + if (asn1_check_eoc(&p, len)) + { + /* EOC is illegal outside indefinite length + * constructed form */ + if (!inf) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNEXPECTED_EOC); + return 0; + } + inf = 0; + break; + } + + if (!asn1_check_tlen(&plen, NULL, NULL, &ininf, &cst, &p, + len, tag, aclass, 0, NULL)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + return 0; + } + + /* If indefinite length constructed update max length */ + if (cst) + { + if (depth >= ASN1_MAX_STRING_NEST) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_STRING); + return 0; + } + if (!asn1_collect(buf, &p, plen, ininf, tag, aclass, + depth + 1)) + return 0; + } + else if (plen && !collect_data(buf, &p, plen)) + return 0; + len -= p - q; + } + if (inf) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_EOC); + return 0; + } + *in = p; + return 1; + } + +static int collect_data(BUF_MEM *buf, const unsigned char **p, long plen) + { + int len; + if (buf) + { + len = buf->length; + if (!BUF_MEM_grow_clean(buf, len + plen)) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return 0; + } + memcpy(buf->data + len, *p, plen); + } + *p += plen; + return 1; + } + +/* Check for ASN1 EOC and swallow it if found */ + +static int asn1_check_eoc(const unsigned char **in, long len) + { + const unsigned char *p; + if (len < 2) return 0; + p = *in; + if (!p[0] && !p[1]) + { + *in += 2; + return 1; + } + return 0; + } + +/* Check an ASN1 tag and length: a bit like ASN1_get_object + * but it sets the length for indefinite length constructed + * form, we don't know the exact length but we can set an + * upper bound to the amount of data available minus the + * header length just read. + */ + +static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass, + char *inf, char *cst, + const unsigned char **in, long len, + int exptag, int expclass, char opt, + ASN1_TLC *ctx) + { + int i; + int ptag, pclass; + long plen; + const unsigned char *p, *q; + p = *in; + q = p; + + if (ctx && ctx->valid) + { + i = ctx->ret; + plen = ctx->plen; + pclass = ctx->pclass; + ptag = ctx->ptag; + p += ctx->hdrlen; + } + else + { + i = ASN1_get_object(&p, &plen, &ptag, &pclass, len); + if (ctx) + { + ctx->ret = i; + ctx->plen = plen; + ctx->pclass = pclass; + ctx->ptag = ptag; + ctx->hdrlen = p - q; + ctx->valid = 1; + /* If definite length, and no error, length + + * header can't exceed total amount of data available. + */ + if (!(i & 0x81) && ((plen + ctx->hdrlen) > len)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG); + asn1_tlc_clear(ctx); + return 0; + } + } + } + + if (i & 0x80) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_BAD_OBJECT_HEADER); + asn1_tlc_clear(ctx); + return 0; + } + if (exptag >= 0) + { + if ((exptag != ptag) || (expclass != pclass)) + { + /* If type is OPTIONAL, not an error: + * indicate missing type. + */ + if (opt) return -1; + asn1_tlc_clear(ctx); + OPENSSL_PUT_ERROR(ASN1, ASN1_R_WRONG_TAG); + return 0; + } + /* We have a tag and class match: + * assume we are going to do something with it */ + asn1_tlc_clear(ctx); + } + + if (i & 1) + plen = len - (p - q); + + if (inf) + *inf = i & 1; + + if (cst) + *cst = i & V_ASN1_CONSTRUCTED; + + if (olen) + *olen = plen; + + if (oclass) + *oclass = pclass; + + if (otag) + *otag = ptag; + + *in = p; + return 1; + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/tasn_enc.c b/TMessagesProj/jni/boringssl/crypto/asn1/tasn_enc.c new file mode 100644 index 00000000..38e14d2a --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/tasn_enc.c @@ -0,0 +1,695 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include + + +static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out, + const ASN1_ITEM *it, + int tag, int aclass); +static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out, + int skcontlen, const ASN1_ITEM *item, + int do_sort, int iclass); +static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out, + const ASN1_TEMPLATE *tt, + int tag, int aclass); +static int asn1_item_flags_i2d(ASN1_VALUE *val, unsigned char **out, + const ASN1_ITEM *it, int flags); + +/* Top level i2d equivalents: the 'ndef' variant instructs the encoder + * to use indefinite length constructed encoding, where appropriate + */ + +int ASN1_item_ndef_i2d(ASN1_VALUE *val, unsigned char **out, + const ASN1_ITEM *it) + { + return asn1_item_flags_i2d(val, out, it, ASN1_TFLG_NDEF); + } + +int ASN1_item_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it) + { + return asn1_item_flags_i2d(val, out, it, 0); + } + +/* Encode an ASN1 item, this is use by the + * standard 'i2d' function. 'out' points to + * a buffer to output the data to. + * + * The new i2d has one additional feature. If the output + * buffer is NULL (i.e. *out == NULL) then a buffer is + * allocated and populated with the encoding. + */ + +static int asn1_item_flags_i2d(ASN1_VALUE *val, unsigned char **out, + const ASN1_ITEM *it, int flags) + { + if (out && !*out) + { + unsigned char *p, *buf; + int len; + len = ASN1_item_ex_i2d(&val, NULL, it, -1, flags); + if (len <= 0) + return len; + buf = OPENSSL_malloc(len); + if (!buf) + return -1; + p = buf; + ASN1_item_ex_i2d(&val, &p, it, -1, flags); + *out = buf; + return len; + } + + return ASN1_item_ex_i2d(&val, out, it, -1, flags); + } + +/* Encode an item, taking care of IMPLICIT tagging (if any). + * This function performs the normal item handling: it can be + * used in external types. + */ + +int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, + const ASN1_ITEM *it, int tag, int aclass) + { + const ASN1_TEMPLATE *tt = NULL; + unsigned char *p = NULL; + int i, seqcontlen, seqlen, ndef = 1; + const ASN1_COMPAT_FUNCS *cf; + const ASN1_EXTERN_FUNCS *ef; + const ASN1_AUX *aux = it->funcs; + ASN1_aux_cb *asn1_cb = 0; + + if ((it->itype != ASN1_ITYPE_PRIMITIVE) && !*pval) + return 0; + + if (aux && aux->asn1_cb) + asn1_cb = aux->asn1_cb; + + switch(it->itype) + { + + case ASN1_ITYPE_PRIMITIVE: + if (it->templates) + return asn1_template_ex_i2d(pval, out, it->templates, + tag, aclass); + return asn1_i2d_ex_primitive(pval, out, it, tag, aclass); + break; + + case ASN1_ITYPE_MSTRING: + return asn1_i2d_ex_primitive(pval, out, it, -1, aclass); + + case ASN1_ITYPE_CHOICE: + if (asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it, NULL)) + return 0; + i = asn1_get_choice_selector(pval, it); + if ((i >= 0) && (i < it->tcount)) + { + ASN1_VALUE **pchval; + const ASN1_TEMPLATE *chtt; + chtt = it->templates + i; + pchval = asn1_get_field_ptr(pval, chtt); + return asn1_template_ex_i2d(pchval, out, chtt, + -1, aclass); + } + /* Fixme: error condition if selector out of range */ + if (asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it, NULL)) + return 0; + break; + + case ASN1_ITYPE_EXTERN: + /* If new style i2d it does all the work */ + ef = it->funcs; + return ef->asn1_ex_i2d(pval, out, it, tag, aclass); + + case ASN1_ITYPE_COMPAT: + /* old style hackery... */ + cf = it->funcs; + if (out) + p = *out; + i = cf->asn1_i2d(*pval, out); + /* Fixup for IMPLICIT tag: note this messes up for tags > 30, + * but so did the old code. Tags > 30 are very rare anyway. + */ + if (out && (tag != -1)) + *p = aclass | tag | (*p & V_ASN1_CONSTRUCTED); + return i; + + case ASN1_ITYPE_NDEF_SEQUENCE: + /* Use indefinite length constructed if requested */ + if (aclass & ASN1_TFLG_NDEF) ndef = 2; + /* fall through */ + + case ASN1_ITYPE_SEQUENCE: + i = asn1_enc_restore(&seqcontlen, out, pval, it); + /* An error occurred */ + if (i < 0) + return 0; + /* We have a valid cached encoding... */ + if (i > 0) + return seqcontlen; + /* Otherwise carry on */ + seqcontlen = 0; + /* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */ + if (tag == -1) + { + tag = V_ASN1_SEQUENCE; + /* Retain any other flags in aclass */ + aclass = (aclass & ~ASN1_TFLG_TAG_CLASS) + | V_ASN1_UNIVERSAL; + } + if (asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it, NULL)) + return 0; + /* First work out sequence content length */ + for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) + { + const ASN1_TEMPLATE *seqtt; + ASN1_VALUE **pseqval; + seqtt = asn1_do_adb(pval, tt, 1); + if (!seqtt) + return 0; + pseqval = asn1_get_field_ptr(pval, seqtt); + /* FIXME: check for errors in enhanced version */ + seqcontlen += asn1_template_ex_i2d(pseqval, NULL, seqtt, + -1, aclass); + } + + seqlen = ASN1_object_size(ndef, seqcontlen, tag); + if (!out) + return seqlen; + /* Output SEQUENCE header */ + ASN1_put_object(out, ndef, seqcontlen, tag, aclass); + for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) + { + const ASN1_TEMPLATE *seqtt; + ASN1_VALUE **pseqval; + seqtt = asn1_do_adb(pval, tt, 1); + if (!seqtt) + return 0; + pseqval = asn1_get_field_ptr(pval, seqtt); + /* FIXME: check for errors in enhanced version */ + asn1_template_ex_i2d(pseqval, out, seqtt, -1, aclass); + } + if (ndef == 2) + ASN1_put_eoc(out); + if (asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it, NULL)) + return 0; + return seqlen; + + default: + return 0; + + } + return 0; + } + +int ASN1_template_i2d(ASN1_VALUE **pval, unsigned char **out, + const ASN1_TEMPLATE *tt) + { + return asn1_template_ex_i2d(pval, out, tt, -1, 0); + } + +static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out, + const ASN1_TEMPLATE *tt, int tag, int iclass) + { + int i, ret, flags, ttag, tclass, ndef; + size_t j; + flags = tt->flags; + /* Work out tag and class to use: tagging may come + * either from the template or the arguments, not both + * because this would create ambiguity. Additionally + * the iclass argument may contain some additional flags + * which should be noted and passed down to other levels. + */ + if (flags & ASN1_TFLG_TAG_MASK) + { + /* Error if argument and template tagging */ + if (tag != -1) + /* FIXME: error code here */ + return -1; + /* Get tagging from template */ + ttag = tt->tag; + tclass = flags & ASN1_TFLG_TAG_CLASS; + } + else if (tag != -1) + { + /* No template tagging, get from arguments */ + ttag = tag; + tclass = iclass & ASN1_TFLG_TAG_CLASS; + } + else + { + ttag = -1; + tclass = 0; + } + /* + * Remove any class mask from iflag. + */ + iclass &= ~ASN1_TFLG_TAG_CLASS; + + /* At this point 'ttag' contains the outer tag to use, + * 'tclass' is the class and iclass is any flags passed + * to this function. + */ + + /* if template and arguments require ndef, use it */ + if ((flags & ASN1_TFLG_NDEF) && (iclass & ASN1_TFLG_NDEF)) + ndef = 2; + else ndef = 1; + + if (flags & ASN1_TFLG_SK_MASK) + { + /* SET OF, SEQUENCE OF */ + STACK_OF(ASN1_VALUE) *sk = (STACK_OF(ASN1_VALUE) *)*pval; + int isset, sktag, skaclass; + int skcontlen, sklen; + ASN1_VALUE *skitem; + + if (!*pval) + return 0; + + if (flags & ASN1_TFLG_SET_OF) + { + isset = 1; + /* 2 means we reorder */ + if (flags & ASN1_TFLG_SEQUENCE_OF) + isset = 2; + } + else isset = 0; + + /* Work out inner tag value: if EXPLICIT + * or no tagging use underlying type. + */ + if ((ttag != -1) && !(flags & ASN1_TFLG_EXPTAG)) + { + sktag = ttag; + skaclass = tclass; + } + else + { + skaclass = V_ASN1_UNIVERSAL; + if (isset) + sktag = V_ASN1_SET; + else sktag = V_ASN1_SEQUENCE; + } + + /* Determine total length of items */ + skcontlen = 0; + for (j = 0; j < sk_ASN1_VALUE_num(sk); j++) + { + skitem = sk_ASN1_VALUE_value(sk, j); + skcontlen += ASN1_item_ex_i2d(&skitem, NULL, + ASN1_ITEM_ptr(tt->item), + -1, iclass); + } + sklen = ASN1_object_size(ndef, skcontlen, sktag); + /* If EXPLICIT need length of surrounding tag */ + if (flags & ASN1_TFLG_EXPTAG) + ret = ASN1_object_size(ndef, sklen, ttag); + else ret = sklen; + + if (!out) + return ret; + + /* Now encode this lot... */ + /* EXPLICIT tag */ + if (flags & ASN1_TFLG_EXPTAG) + ASN1_put_object(out, ndef, sklen, ttag, tclass); + /* SET or SEQUENCE and IMPLICIT tag */ + ASN1_put_object(out, ndef, skcontlen, sktag, skaclass); + /* And the stuff itself */ + asn1_set_seq_out(sk, out, skcontlen, ASN1_ITEM_ptr(tt->item), + isset, iclass); + if (ndef == 2) + { + ASN1_put_eoc(out); + if (flags & ASN1_TFLG_EXPTAG) + ASN1_put_eoc(out); + } + + return ret; + } + + if (flags & ASN1_TFLG_EXPTAG) + { + /* EXPLICIT tagging */ + /* Find length of tagged item */ + i = ASN1_item_ex_i2d(pval, NULL, ASN1_ITEM_ptr(tt->item), + -1, iclass); + if (!i) + return 0; + /* Find length of EXPLICIT tag */ + ret = ASN1_object_size(ndef, i, ttag); + if (out) + { + /* Output tag and item */ + ASN1_put_object(out, ndef, i, ttag, tclass); + ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item), + -1, iclass); + if (ndef == 2) + ASN1_put_eoc(out); + } + return ret; + } + + /* Either normal or IMPLICIT tagging: combine class and flags */ + return ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item), + ttag, tclass | iclass); + +} + +/* Temporary structure used to hold DER encoding of items for SET OF */ + +typedef struct { + unsigned char *data; + int length; + ASN1_VALUE *field; +} DER_ENC; + +static int der_cmp(const void *a, const void *b) + { + const DER_ENC *d1 = a, *d2 = b; + int cmplen, i; + cmplen = (d1->length < d2->length) ? d1->length : d2->length; + i = memcmp(d1->data, d2->data, cmplen); + if (i) + return i; + return d1->length - d2->length; + } + +/* Output the content octets of SET OF or SEQUENCE OF */ + +static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out, + int skcontlen, const ASN1_ITEM *item, + int do_sort, int iclass) + { + size_t i; + ASN1_VALUE *skitem; + unsigned char *tmpdat = NULL, *p = NULL; + DER_ENC *derlst = NULL, *tder; + if (do_sort) + { + /* Don't need to sort less than 2 items */ + if (sk_ASN1_VALUE_num(sk) < 2) + do_sort = 0; + else + { + derlst = OPENSSL_malloc(sk_ASN1_VALUE_num(sk) + * sizeof(*derlst)); + if (!derlst) + return 0; + tmpdat = OPENSSL_malloc(skcontlen); + if (!tmpdat) + { + OPENSSL_free(derlst); + return 0; + } + } + } + /* If not sorting just output each item */ + if (!do_sort) + { + for (i = 0; i < sk_ASN1_VALUE_num(sk); i++) + { + skitem = sk_ASN1_VALUE_value(sk, i); + ASN1_item_ex_i2d(&skitem, out, item, -1, iclass); + } + return 1; + } + p = tmpdat; + + /* Doing sort: build up a list of each member's DER encoding */ + for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) + { + skitem = sk_ASN1_VALUE_value(sk, i); + tder->data = p; + tder->length = ASN1_item_ex_i2d(&skitem, &p, item, -1, iclass); + tder->field = skitem; + } + + /* Now sort them */ + qsort(derlst, sk_ASN1_VALUE_num(sk), sizeof(*derlst), der_cmp); + /* Output sorted DER encoding */ + p = *out; + for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) + { + memcpy(p, tder->data, tder->length); + p += tder->length; + } + *out = p; + /* If do_sort is 2 then reorder the STACK */ + if (do_sort == 2) + { + for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); + i++, tder++) + (void)sk_ASN1_VALUE_set(sk, i, tder->field); + } + OPENSSL_free(derlst); + OPENSSL_free(tmpdat); + return 1; + } + +static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out, + const ASN1_ITEM *it, int tag, int aclass) + { + int len; + int utype; + int usetag; + int ndef = 0; + + utype = it->utype; + + /* Get length of content octets and maybe find + * out the underlying type. + */ + + len = asn1_ex_i2c(pval, NULL, &utype, it); + + /* If SEQUENCE, SET or OTHER then header is + * included in pseudo content octets so don't + * include tag+length. We need to check here + * because the call to asn1_ex_i2c() could change + * utype. + */ + if ((utype == V_ASN1_SEQUENCE) || (utype == V_ASN1_SET) || + (utype == V_ASN1_OTHER)) + usetag = 0; + else usetag = 1; + + /* -1 means omit type */ + + if (len == -1) + return 0; + + /* -2 return is special meaning use ndef */ + if (len == -2) + { + ndef = 2; + len = 0; + } + + /* If not implicitly tagged get tag from underlying type */ + if (tag == -1) tag = utype; + + /* Output tag+length followed by content octets */ + if (out) + { + if (usetag) + ASN1_put_object(out, ndef, len, tag, aclass); + asn1_ex_i2c(pval, *out, &utype, it); + if (ndef) + ASN1_put_eoc(out); + else + *out += len; + } + + if (usetag) + return ASN1_object_size(ndef, len, tag); + return len; + } + +/* Produce content octets from a structure */ + +int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype, + const ASN1_ITEM *it) + { + ASN1_BOOLEAN *tbool = NULL; + ASN1_STRING *strtmp; + ASN1_OBJECT *otmp; + int utype; + const unsigned char *cont; + unsigned char c; + int len; + const ASN1_PRIMITIVE_FUNCS *pf; + pf = it->funcs; + if (pf && pf->prim_i2c) + return pf->prim_i2c(pval, cout, putype, it); + + /* Should type be omitted? */ + if ((it->itype != ASN1_ITYPE_PRIMITIVE) + || (it->utype != V_ASN1_BOOLEAN)) + { + if (!*pval) return -1; + } + + if (it->itype == ASN1_ITYPE_MSTRING) + { + /* If MSTRING type set the underlying type */ + strtmp = (ASN1_STRING *)*pval; + utype = strtmp->type; + *putype = utype; + } + else if (it->utype == V_ASN1_ANY) + { + /* If ANY set type and pointer to value */ + ASN1_TYPE *typ; + typ = (ASN1_TYPE *)*pval; + utype = typ->type; + *putype = utype; + pval = &typ->value.asn1_value; + } + else utype = *putype; + + switch(utype) + { + case V_ASN1_OBJECT: + otmp = (ASN1_OBJECT *)*pval; + cont = otmp->data; + len = otmp->length; + break; + + case V_ASN1_NULL: + cont = NULL; + len = 0; + break; + + case V_ASN1_BOOLEAN: + tbool = (ASN1_BOOLEAN *)pval; + if (*tbool == -1) + return -1; + if (it->utype != V_ASN1_ANY) + { + /* Default handling if value == size field then omit */ + if (*tbool && (it->size > 0)) + return -1; + if (!*tbool && !it->size) + return -1; + } + c = (unsigned char)*tbool; + cont = &c; + len = 1; + break; + + case V_ASN1_BIT_STRING: + return i2c_ASN1_BIT_STRING((ASN1_BIT_STRING *)*pval, + cout ? &cout : NULL); + break; + + case V_ASN1_INTEGER: + case V_ASN1_NEG_INTEGER: + case V_ASN1_ENUMERATED: + case V_ASN1_NEG_ENUMERATED: + /* These are all have the same content format + * as ASN1_INTEGER + */ + return i2c_ASN1_INTEGER((ASN1_INTEGER *)*pval, + cout ? &cout : NULL); + break; + + case V_ASN1_OCTET_STRING: + case V_ASN1_NUMERICSTRING: + case V_ASN1_PRINTABLESTRING: + case V_ASN1_T61STRING: + case V_ASN1_VIDEOTEXSTRING: + case V_ASN1_IA5STRING: + case V_ASN1_UTCTIME: + case V_ASN1_GENERALIZEDTIME: + case V_ASN1_GRAPHICSTRING: + case V_ASN1_VISIBLESTRING: + case V_ASN1_GENERALSTRING: + case V_ASN1_UNIVERSALSTRING: + case V_ASN1_BMPSTRING: + case V_ASN1_UTF8STRING: + case V_ASN1_SEQUENCE: + case V_ASN1_SET: + default: + /* All based on ASN1_STRING and handled the same */ + strtmp = (ASN1_STRING *)*pval; + /* Special handling for NDEF */ + if ((it->size == ASN1_TFLG_NDEF) + && (strtmp->flags & ASN1_STRING_FLAG_NDEF)) + { + if (cout) + { + strtmp->data = cout; + strtmp->length = 0; + } + /* Special return code */ + return -2; + } + cont = strtmp->data; + len = strtmp->length; + + break; + + } + if (cout && len) + memcpy(cout, cont, len); + return len; + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/tasn_fre.c b/TMessagesProj/jni/boringssl/crypto/asn1/tasn_fre.c new file mode 100644 index 00000000..d1317ae4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/tasn_fre.c @@ -0,0 +1,264 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + +static void asn1_item_combine_free(ASN1_VALUE **pval, const ASN1_ITEM *it, int combine); + +/* Free up an ASN1 structure */ + +void ASN1_item_free(ASN1_VALUE *val, const ASN1_ITEM *it) + { + asn1_item_combine_free(&val, it, 0); + } + +void ASN1_item_ex_free(ASN1_VALUE **pval, const ASN1_ITEM *it) + { + asn1_item_combine_free(pval, it, 0); + } + +static void asn1_item_combine_free(ASN1_VALUE **pval, const ASN1_ITEM *it, int combine) + { + const ASN1_TEMPLATE *tt = NULL, *seqtt; + const ASN1_EXTERN_FUNCS *ef; + const ASN1_COMPAT_FUNCS *cf; + const ASN1_AUX *aux = it->funcs; + ASN1_aux_cb *asn1_cb; + int i; + if (!pval) + return; + if ((it->itype != ASN1_ITYPE_PRIMITIVE) && !*pval) + return; + if (aux && aux->asn1_cb) + asn1_cb = aux->asn1_cb; + else + asn1_cb = 0; + + switch(it->itype) + { + + case ASN1_ITYPE_PRIMITIVE: + if (it->templates) + ASN1_template_free(pval, it->templates); + else + ASN1_primitive_free(pval, it); + break; + + case ASN1_ITYPE_MSTRING: + ASN1_primitive_free(pval, it); + break; + + case ASN1_ITYPE_CHOICE: + if (asn1_cb) + { + i = asn1_cb(ASN1_OP_FREE_PRE, pval, it, NULL); + if (i == 2) + return; + } + i = asn1_get_choice_selector(pval, it); + if ((i >= 0) && (i < it->tcount)) + { + ASN1_VALUE **pchval; + tt = it->templates + i; + pchval = asn1_get_field_ptr(pval, tt); + ASN1_template_free(pchval, tt); + } + if (asn1_cb) + asn1_cb(ASN1_OP_FREE_POST, pval, it, NULL); + if (!combine) + { + OPENSSL_free(*pval); + *pval = NULL; + } + break; + + case ASN1_ITYPE_COMPAT: + cf = it->funcs; + if (cf && cf->asn1_free) + cf->asn1_free(*pval); + break; + + case ASN1_ITYPE_EXTERN: + ef = it->funcs; + if (ef && ef->asn1_ex_free) + ef->asn1_ex_free(pval, it); + break; + + case ASN1_ITYPE_NDEF_SEQUENCE: + case ASN1_ITYPE_SEQUENCE: + if (!asn1_refcount_dec_and_test_zero(pval, it)) + return; + if (asn1_cb) + { + i = asn1_cb(ASN1_OP_FREE_PRE, pval, it, NULL); + if (i == 2) + return; + } + asn1_enc_free(pval, it); + /* If we free up as normal we will invalidate any + * ANY DEFINED BY field and we wont be able to + * determine the type of the field it defines. So + * free up in reverse order. + */ + tt = it->templates + it->tcount - 1; + for (i = 0; i < it->tcount; tt--, i++) + { + ASN1_VALUE **pseqval; + seqtt = asn1_do_adb(pval, tt, 0); + if (!seqtt) + continue; + pseqval = asn1_get_field_ptr(pval, seqtt); + ASN1_template_free(pseqval, seqtt); + } + if (asn1_cb) + asn1_cb(ASN1_OP_FREE_POST, pval, it, NULL); + if (!combine) + { + OPENSSL_free(*pval); + *pval = NULL; + } + break; + } + } + +void ASN1_template_free(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt) + { + size_t i; + if (tt->flags & ASN1_TFLG_SK_MASK) + { + STACK_OF(ASN1_VALUE) *sk = (STACK_OF(ASN1_VALUE) *)*pval; + for (i = 0; i < sk_ASN1_VALUE_num(sk); i++) + { + ASN1_VALUE *vtmp; + vtmp = sk_ASN1_VALUE_value(sk, i); + asn1_item_combine_free(&vtmp, ASN1_ITEM_ptr(tt->item), + 0); + } + sk_ASN1_VALUE_free(sk); + *pval = NULL; + } + else + asn1_item_combine_free(pval, ASN1_ITEM_ptr(tt->item), + tt->flags & ASN1_TFLG_COMBINE); + } + +void ASN1_primitive_free(ASN1_VALUE **pval, const ASN1_ITEM *it) + { + int utype; + if (it) + { + const ASN1_PRIMITIVE_FUNCS *pf; + pf = it->funcs; + if (pf && pf->prim_free) + { + pf->prim_free(pval, it); + return; + } + } + /* Special case: if 'it' is NULL free contents of ASN1_TYPE */ + if (!it) + { + ASN1_TYPE *typ = (ASN1_TYPE *)*pval; + utype = typ->type; + pval = &typ->value.asn1_value; + if (!*pval) + return; + } + else if (it->itype == ASN1_ITYPE_MSTRING) + { + utype = -1; + if (!*pval) + return; + } + else + { + utype = it->utype; + if ((utype != V_ASN1_BOOLEAN) && !*pval) + return; + } + + switch(utype) + { + case V_ASN1_OBJECT: + ASN1_OBJECT_free((ASN1_OBJECT *)*pval); + break; + + case V_ASN1_BOOLEAN: + if (it) + *(ASN1_BOOLEAN *)pval = it->size; + else + *(ASN1_BOOLEAN *)pval = -1; + return; + + case V_ASN1_NULL: + break; + + case V_ASN1_ANY: + ASN1_primitive_free(pval, NULL); + OPENSSL_free(*pval); + break; + + default: + ASN1_STRING_free((ASN1_STRING *)*pval); + *pval = NULL; + break; + } + *pval = NULL; + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/tasn_new.c b/TMessagesProj/jni/boringssl/crypto/asn1/tasn_new.c new file mode 100644 index 00000000..c68fe066 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/tasn_new.c @@ -0,0 +1,398 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include +#include + + +static int asn1_item_ex_combine_new(ASN1_VALUE **pval, const ASN1_ITEM *it, + int combine); +static void asn1_item_clear(ASN1_VALUE **pval, const ASN1_ITEM *it); +static void asn1_template_clear(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt); +static void asn1_primitive_clear(ASN1_VALUE **pval, const ASN1_ITEM *it); + +ASN1_VALUE *ASN1_item_new(const ASN1_ITEM *it) + { + ASN1_VALUE *ret = NULL; + if (ASN1_item_ex_new(&ret, it) > 0) + return ret; + return NULL; + } + +/* Allocate an ASN1 structure */ + +int ASN1_item_ex_new(ASN1_VALUE **pval, const ASN1_ITEM *it) + { + return asn1_item_ex_combine_new(pval, it, 0); + } + +static int asn1_item_ex_combine_new(ASN1_VALUE **pval, const ASN1_ITEM *it, + int combine) + { + const ASN1_TEMPLATE *tt = NULL; + const ASN1_COMPAT_FUNCS *cf; + const ASN1_EXTERN_FUNCS *ef; + const ASN1_AUX *aux = it->funcs; + ASN1_aux_cb *asn1_cb; + ASN1_VALUE **pseqval; + int i; + if (aux && aux->asn1_cb) + asn1_cb = aux->asn1_cb; + else + asn1_cb = 0; + +#ifdef CRYPTO_MDEBUG + if (it->sname) + CRYPTO_push_info(it->sname); +#endif + + switch(it->itype) + { + + case ASN1_ITYPE_EXTERN: + ef = it->funcs; + if (ef && ef->asn1_ex_new) + { + if (!ef->asn1_ex_new(pval, it)) + goto memerr; + } + break; + + case ASN1_ITYPE_COMPAT: + cf = it->funcs; + if (cf && cf->asn1_new) { + *pval = cf->asn1_new(); + if (!*pval) + goto memerr; + } + break; + + case ASN1_ITYPE_PRIMITIVE: + if (it->templates) + { + if (!ASN1_template_new(pval, it->templates)) + goto memerr; + } + else if (!ASN1_primitive_new(pval, it)) + goto memerr; + break; + + case ASN1_ITYPE_MSTRING: + if (!ASN1_primitive_new(pval, it)) + goto memerr; + break; + + case ASN1_ITYPE_CHOICE: + if (asn1_cb) + { + i = asn1_cb(ASN1_OP_NEW_PRE, pval, it, NULL); + if (!i) + goto auxerr; + if (i==2) + { +#ifdef CRYPTO_MDEBUG + if (it->sname) + CRYPTO_pop_info(); +#endif + return 1; + } + } + if (!combine) + { + *pval = OPENSSL_malloc(it->size); + if (!*pval) + goto memerr; + memset(*pval, 0, it->size); + } + asn1_set_choice_selector(pval, -1, it); + if (asn1_cb && !asn1_cb(ASN1_OP_NEW_POST, pval, it, NULL)) + goto auxerr; + break; + + case ASN1_ITYPE_NDEF_SEQUENCE: + case ASN1_ITYPE_SEQUENCE: + if (asn1_cb) + { + i = asn1_cb(ASN1_OP_NEW_PRE, pval, it, NULL); + if (!i) + goto auxerr; + if (i==2) + { +#ifdef CRYPTO_MDEBUG + if (it->sname) + CRYPTO_pop_info(); +#endif + return 1; + } + } + if (!combine) + { + *pval = OPENSSL_malloc(it->size); + if (!*pval) + goto memerr; + memset(*pval, 0, it->size); + asn1_refcount_set_one(pval, it); + asn1_enc_init(pval, it); + } + for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) + { + pseqval = asn1_get_field_ptr(pval, tt); + if (!ASN1_template_new(pseqval, tt)) + goto memerr; + } + if (asn1_cb && !asn1_cb(ASN1_OP_NEW_POST, pval, it, NULL)) + goto auxerr; + break; + } +#ifdef CRYPTO_MDEBUG + if (it->sname) CRYPTO_pop_info(); +#endif + return 1; + + memerr: + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + ASN1_item_ex_free(pval, it); +#ifdef CRYPTO_MDEBUG + if (it->sname) CRYPTO_pop_info(); +#endif + return 0; + + auxerr: + OPENSSL_PUT_ERROR(ASN1, ASN1_R_AUX_ERROR); + ASN1_item_ex_free(pval, it); +#ifdef CRYPTO_MDEBUG + if (it->sname) CRYPTO_pop_info(); +#endif + return 0; + + } + +static void asn1_item_clear(ASN1_VALUE **pval, const ASN1_ITEM *it) + { + const ASN1_EXTERN_FUNCS *ef; + + switch(it->itype) + { + + case ASN1_ITYPE_EXTERN: + ef = it->funcs; + if (ef && ef->asn1_ex_clear) + ef->asn1_ex_clear(pval, it); + else *pval = NULL; + break; + + + case ASN1_ITYPE_PRIMITIVE: + if (it->templates) + asn1_template_clear(pval, it->templates); + else + asn1_primitive_clear(pval, it); + break; + + case ASN1_ITYPE_MSTRING: + asn1_primitive_clear(pval, it); + break; + + case ASN1_ITYPE_COMPAT: + case ASN1_ITYPE_CHOICE: + case ASN1_ITYPE_SEQUENCE: + case ASN1_ITYPE_NDEF_SEQUENCE: + *pval = NULL; + break; + } + } + + +int ASN1_template_new(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt) + { + const ASN1_ITEM *it = ASN1_ITEM_ptr(tt->item); + int ret; + if (tt->flags & ASN1_TFLG_OPTIONAL) + { + asn1_template_clear(pval, tt); + return 1; + } + /* If ANY DEFINED BY nothing to do */ + + if (tt->flags & ASN1_TFLG_ADB_MASK) + { + *pval = NULL; + return 1; + } +#ifdef CRYPTO_MDEBUG + if (tt->field_name) + CRYPTO_push_info(tt->field_name); +#endif + /* If SET OF or SEQUENCE OF, its a STACK */ + if (tt->flags & ASN1_TFLG_SK_MASK) + { + STACK_OF(ASN1_VALUE) *skval; + skval = sk_ASN1_VALUE_new_null(); + if (!skval) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + ret = 0; + goto done; + } + *pval = (ASN1_VALUE *)skval; + ret = 1; + goto done; + } + /* Otherwise pass it back to the item routine */ + ret = asn1_item_ex_combine_new(pval, it, tt->flags & ASN1_TFLG_COMBINE); + done: +#ifdef CRYPTO_MDEBUG + if (it->sname) + CRYPTO_pop_info(); +#endif + return ret; + } + +static void asn1_template_clear(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt) + { + /* If ADB or STACK just NULL the field */ + if (tt->flags & (ASN1_TFLG_ADB_MASK|ASN1_TFLG_SK_MASK)) + *pval = NULL; + else + asn1_item_clear(pval, ASN1_ITEM_ptr(tt->item)); + } + + +/* NB: could probably combine most of the real XXX_new() behaviour and junk + * all the old functions. + */ + +int ASN1_primitive_new(ASN1_VALUE **pval, const ASN1_ITEM *it) + { + ASN1_TYPE *typ; + ASN1_STRING *str; + int utype; + + if (!it) + return 0; + + if (it->funcs) + { + const ASN1_PRIMITIVE_FUNCS *pf = it->funcs; + if (pf->prim_new) + return pf->prim_new(pval, it); + } + + if (it->itype == ASN1_ITYPE_MSTRING) + utype = -1; + else + utype = it->utype; + switch(utype) + { + case V_ASN1_OBJECT: + *pval = (ASN1_VALUE *)OBJ_nid2obj(NID_undef); + return 1; + + case V_ASN1_BOOLEAN: + *(ASN1_BOOLEAN *)pval = it->size; + return 1; + + case V_ASN1_NULL: + *pval = (ASN1_VALUE *)1; + return 1; + + case V_ASN1_ANY: + typ = OPENSSL_malloc(sizeof(ASN1_TYPE)); + if (!typ) + return 0; + typ->value.ptr = NULL; + typ->type = -1; + *pval = (ASN1_VALUE *)typ; + break; + + default: + str = ASN1_STRING_type_new(utype); + if (it->itype == ASN1_ITYPE_MSTRING && str) + str->flags |= ASN1_STRING_FLAG_MSTRING; + *pval = (ASN1_VALUE *)str; + break; + } + if (*pval) + return 1; + return 0; + } + +static void asn1_primitive_clear(ASN1_VALUE **pval, const ASN1_ITEM *it) + { + int utype; + if (it && it->funcs) + { + const ASN1_PRIMITIVE_FUNCS *pf = it->funcs; + if (pf->prim_clear) + pf->prim_clear(pval, it); + else + *pval = NULL; + return; + } + if (!it || (it->itype == ASN1_ITYPE_MSTRING)) + utype = -1; + else + utype = it->utype; + if (utype == V_ASN1_BOOLEAN) + *(ASN1_BOOLEAN *)pval = it->size; + else *pval = NULL; + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/tasn_prn.c b/TMessagesProj/jni/boringssl/crypto/asn1/tasn_prn.c new file mode 100644 index 00000000..6a097a18 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/tasn_prn.c @@ -0,0 +1,642 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include +#include + +#include "asn1_locl.h" + + + +/* Print routines. + */ + +/* ASN1_PCTX routines */ + +ASN1_PCTX default_pctx = + { + ASN1_PCTX_FLAGS_SHOW_ABSENT, /* flags */ + 0, /* nm_flags */ + 0, /* cert_flags */ + 0, /* oid_flags */ + 0 /* str_flags */ + }; + + +ASN1_PCTX *ASN1_PCTX_new(void) + { + ASN1_PCTX *ret; + ret = OPENSSL_malloc(sizeof(ASN1_PCTX)); + if (ret == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return NULL; + } + ret->flags = 0; + ret->nm_flags = 0; + ret->cert_flags = 0; + ret->oid_flags = 0; + ret->str_flags = 0; + return ret; + } + +void ASN1_PCTX_free(ASN1_PCTX *p) + { + OPENSSL_free(p); + } + +unsigned long ASN1_PCTX_get_flags(ASN1_PCTX *p) + { + return p->flags; + } + +void ASN1_PCTX_set_flags(ASN1_PCTX *p, unsigned long flags) + { + p->flags = flags; + } + +unsigned long ASN1_PCTX_get_nm_flags(ASN1_PCTX *p) + { + return p->nm_flags; + } + +void ASN1_PCTX_set_nm_flags(ASN1_PCTX *p, unsigned long flags) + { + p->nm_flags = flags; + } + +unsigned long ASN1_PCTX_get_cert_flags(ASN1_PCTX *p) + { + return p->cert_flags; + } + +void ASN1_PCTX_set_cert_flags(ASN1_PCTX *p, unsigned long flags) + { + p->cert_flags = flags; + } + +unsigned long ASN1_PCTX_get_oid_flags(ASN1_PCTX *p) + { + return p->oid_flags; + } + +void ASN1_PCTX_set_oid_flags(ASN1_PCTX *p, unsigned long flags) + { + p->oid_flags = flags; + } + +unsigned long ASN1_PCTX_get_str_flags(ASN1_PCTX *p) + { + return p->str_flags; + } + +void ASN1_PCTX_set_str_flags(ASN1_PCTX *p, unsigned long flags) + { + p->str_flags = flags; + } + +/* Main print routines */ + +static int asn1_item_print_ctx(BIO *out, ASN1_VALUE **fld, int indent, + const ASN1_ITEM *it, + const char *fname, const char *sname, + int nohdr, const ASN1_PCTX *pctx); + +int asn1_template_print_ctx(BIO *out, ASN1_VALUE **fld, int indent, + const ASN1_TEMPLATE *tt, const ASN1_PCTX *pctx); + +static int asn1_primitive_print(BIO *out, ASN1_VALUE **fld, + const ASN1_ITEM *it, int indent, + const char *fname, const char *sname, + const ASN1_PCTX *pctx); + +static int asn1_print_fsname(BIO *out, int indent, + const char *fname, const char *sname, + const ASN1_PCTX *pctx); + +int ASN1_item_print(BIO *out, ASN1_VALUE *ifld, int indent, + const ASN1_ITEM *it, const ASN1_PCTX *pctx) + { + const char *sname; + if (pctx == NULL) + pctx = &default_pctx; + if (pctx->flags & ASN1_PCTX_FLAGS_NO_STRUCT_NAME) + sname = NULL; + else + sname = it->sname; + return asn1_item_print_ctx(out, &ifld, indent, it, + NULL, sname, 0, pctx); + } + +static int asn1_item_print_ctx(BIO *out, ASN1_VALUE **fld, int indent, + const ASN1_ITEM *it, + const char *fname, const char *sname, + int nohdr, const ASN1_PCTX *pctx) + { + const ASN1_TEMPLATE *tt; + const ASN1_EXTERN_FUNCS *ef; + ASN1_VALUE **tmpfld; + const ASN1_AUX *aux = it->funcs; + ASN1_aux_cb *asn1_cb; + ASN1_PRINT_ARG parg; + int i; + if (aux && aux->asn1_cb) + { + parg.out = out; + parg.indent = indent; + parg.pctx = pctx; + asn1_cb = aux->asn1_cb; + } + else asn1_cb = 0; + + if(*fld == NULL) + { + if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_ABSENT) + { + if (!nohdr && !asn1_print_fsname(out, indent, + fname, sname, pctx)) + return 0; + if (BIO_puts(out, "\n") <= 0) + return 0; + } + return 1; + } + + switch(it->itype) + { + case ASN1_ITYPE_PRIMITIVE: + if(it->templates) + { + if (!asn1_template_print_ctx(out, fld, indent, + it->templates, pctx)) + return 0; + break; + } + /* fall thru */ + case ASN1_ITYPE_MSTRING: + if (!asn1_primitive_print(out, fld, it, + indent, fname, sname,pctx)) + return 0; + break; + + case ASN1_ITYPE_EXTERN: + if (!nohdr && !asn1_print_fsname(out, indent, fname, sname, pctx)) + return 0; + /* Use new style print routine if possible */ + ef = it->funcs; + if (ef && ef->asn1_ex_print) + { + i = ef->asn1_ex_print(out, fld, indent, "", pctx); + if (!i) + return 0; + if ((i == 2) && (BIO_puts(out, "\n") <= 0)) + return 0; + return 1; + } + else if (sname && + BIO_printf(out, ":EXTERNAL TYPE %s\n", sname) <= 0) + return 0; + break; + + case ASN1_ITYPE_CHOICE: +#if 0 + if (!nohdr && !asn1_print_fsname(out, indent, fname, sname, pctx)) + return 0; +#endif + /* CHOICE type, get selector */ + i = asn1_get_choice_selector(fld, it); + /* This should never happen... */ + if((i < 0) || (i >= it->tcount)) + { + if (BIO_printf(out, + "ERROR: selector [%d] invalid\n", i) <= 0) + return 0; + return 1; + } + tt = it->templates + i; + tmpfld = asn1_get_field_ptr(fld, tt); + if (!asn1_template_print_ctx(out, tmpfld, indent, tt, pctx)) + return 0; + break; + + case ASN1_ITYPE_SEQUENCE: + case ASN1_ITYPE_NDEF_SEQUENCE: + if (!nohdr && !asn1_print_fsname(out, indent, fname, sname, pctx)) + return 0; + if (fname || sname) + { + if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_SEQUENCE) + { + if (BIO_puts(out, " {\n") <= 0) + return 0; + } + else + { + if (BIO_puts(out, "\n") <= 0) + return 0; + } + } + + if (asn1_cb) + { + i = asn1_cb(ASN1_OP_PRINT_PRE, fld, it, &parg); + if (i == 0) + return 0; + if (i == 2) + return 1; + } + + /* Print each field entry */ + for(i = 0, tt = it->templates; i < it->tcount; i++, tt++) + { + const ASN1_TEMPLATE *seqtt; + seqtt = asn1_do_adb(fld, tt, 1); + if (!seqtt) + return 0; + tmpfld = asn1_get_field_ptr(fld, seqtt); + if (!asn1_template_print_ctx(out, tmpfld, + indent + 2, seqtt, pctx)) + return 0; + } + if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_SEQUENCE) + { + if (BIO_printf(out, "%*s}\n", indent, "") < 0) + return 0; + } + + if (asn1_cb) + { + i = asn1_cb(ASN1_OP_PRINT_POST, fld, it, &parg); + if (i == 0) + return 0; + } + break; + + default: + BIO_printf(out, "Unprocessed type %d\n", it->itype); + return 0; + } + + return 1; + } + +int asn1_template_print_ctx(BIO *out, ASN1_VALUE **fld, int indent, + const ASN1_TEMPLATE *tt, const ASN1_PCTX *pctx) + { + int flags; + size_t i; + const char *sname, *fname; + flags = tt->flags; + if(pctx->flags & ASN1_PCTX_FLAGS_SHOW_FIELD_STRUCT_NAME) + sname = ASN1_ITEM_ptr(tt->item)->sname; + else + sname = NULL; + if(pctx->flags & ASN1_PCTX_FLAGS_NO_FIELD_NAME) + fname = NULL; + else + fname = tt->field_name; + if(flags & ASN1_TFLG_SK_MASK) + { + const char *tname; + ASN1_VALUE *skitem; + STACK_OF(ASN1_VALUE) *stack; + + /* SET OF, SEQUENCE OF */ + if (fname) + { + if(pctx->flags & ASN1_PCTX_FLAGS_SHOW_SSOF) + { + if(flags & ASN1_TFLG_SET_OF) + tname = "SET"; + else + tname = "SEQUENCE"; + if (BIO_printf(out, "%*s%s OF %s {\n", + indent, "", tname, tt->field_name) <= 0) + return 0; + } + else if (BIO_printf(out, "%*s%s:\n", indent, "", + fname) <= 0) + return 0; + } + stack = (STACK_OF(ASN1_VALUE) *)*fld; + for(i = 0; i < sk_ASN1_VALUE_num(stack); i++) + { + if ((i > 0) && (BIO_puts(out, "\n") <= 0)) + return 0; + + skitem = sk_ASN1_VALUE_value(stack, i); + if (!asn1_item_print_ctx(out, &skitem, indent + 2, + ASN1_ITEM_ptr(tt->item), NULL, NULL, 1, pctx)) + return 0; + } + if (!i && BIO_printf(out, "%*s\n", indent + 2, "") <= 0) + return 0; + if(pctx->flags & ASN1_PCTX_FLAGS_SHOW_SEQUENCE) + { + if (BIO_printf(out, "%*s}\n", indent, "") <= 0) + return 0; + } + return 1; + } + return asn1_item_print_ctx(out, fld, indent, ASN1_ITEM_ptr(tt->item), + fname, sname, 0, pctx); + } + +static int asn1_print_fsname(BIO *out, int indent, + const char *fname, const char *sname, + const ASN1_PCTX *pctx) + { + static char spaces[] = " "; + const int nspaces = sizeof(spaces) - 1; + +#if 0 + if (!sname && !fname) + return 1; +#endif + + while (indent > nspaces) + { + if (BIO_write(out, spaces, nspaces) != nspaces) + return 0; + indent -= nspaces; + } + if (BIO_write(out, spaces, indent) != indent) + return 0; + if (pctx->flags & ASN1_PCTX_FLAGS_NO_STRUCT_NAME) + sname = NULL; + if (pctx->flags & ASN1_PCTX_FLAGS_NO_FIELD_NAME) + fname = NULL; + if (!sname && !fname) + return 1; + if (fname) + { + if (BIO_puts(out, fname) <= 0) + return 0; + } + if (sname) + { + if (fname) + { + if (BIO_printf(out, " (%s)", sname) <= 0) + return 0; + } + else + { + if (BIO_puts(out, sname) <= 0) + return 0; + } + } + if (BIO_write(out, ": ", 2) != 2) + return 0; + return 1; + } + +static int asn1_print_boolean_ctx(BIO *out, int boolval, + const ASN1_PCTX *pctx) + { + const char *str; + switch (boolval) + { + case -1: + str = "BOOL ABSENT"; + break; + + case 0: + str = "FALSE"; + break; + + default: + str = "TRUE"; + break; + + } + + if (BIO_puts(out, str) <= 0) + return 0; + return 1; + + } + +static int asn1_print_integer_ctx(BIO *out, ASN1_INTEGER *str, + const ASN1_PCTX *pctx) + { + BIGNUM *bn = NULL; + char *s = NULL; + int ret = 1; + + bn = ASN1_INTEGER_to_BN(str, NULL); + if (bn == NULL) { + return 0; + } + s = BN_bn2dec(bn); + BN_free(bn); + if (s == NULL) { + return 0; + } + + if (BIO_puts(out, s) <= 0) { + ret = 0; + } + OPENSSL_free(s); + return ret; + } + +static int asn1_print_oid_ctx(BIO *out, const ASN1_OBJECT *oid, + const ASN1_PCTX *pctx) + { + char objbuf[80]; + const char *ln; + ln = OBJ_nid2ln(OBJ_obj2nid(oid)); + if(!ln) + ln = ""; + OBJ_obj2txt(objbuf, sizeof objbuf, oid, 1); + if (BIO_printf(out, "%s (%s)", ln, objbuf) <= 0) + return 0; + return 1; + } + +static int asn1_print_obstring_ctx(BIO *out, ASN1_STRING *str, int indent, + const ASN1_PCTX *pctx) + { + if (str->type == V_ASN1_BIT_STRING) + { + if (BIO_printf(out, " (%ld unused bits)\n", + str->flags & 0x7) <= 0) + return 0; + } + else if (BIO_puts(out, "\n") <= 0) + return 0; + if (str->length > 0 && !BIO_hexdump(out, str->data, str->length, indent + 2)) { + return 0; + } + return 1; + } + +static int asn1_primitive_print(BIO *out, ASN1_VALUE **fld, + const ASN1_ITEM *it, int indent, + const char *fname, const char *sname, + const ASN1_PCTX *pctx) + { + long utype; + ASN1_STRING *str; + int ret = 1, needlf = 1; + const char *pname; + const ASN1_PRIMITIVE_FUNCS *pf; + pf = it->funcs; + if (!asn1_print_fsname(out, indent, fname, sname, pctx)) + return 0; + if (pf && pf->prim_print) + return pf->prim_print(out, fld, it, indent, pctx); + str = (ASN1_STRING *)*fld; + if (it->itype == ASN1_ITYPE_MSTRING) + utype = str->type & ~V_ASN1_NEG; + else + utype = it->utype; + if (utype == V_ASN1_ANY) + { + ASN1_TYPE *atype = (ASN1_TYPE *)*fld; + utype = atype->type; + fld = &atype->value.asn1_value; + str = (ASN1_STRING *)*fld; + if (pctx->flags & ASN1_PCTX_FLAGS_NO_ANY_TYPE) + pname = NULL; + else + pname = ASN1_tag2str(utype); + } + else + { + if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_TYPE) + pname = ASN1_tag2str(utype); + else + pname = NULL; + } + + if (utype == V_ASN1_NULL) + { + if (BIO_puts(out, "NULL\n") <= 0) + return 0; + return 1; + } + + if (pname) + { + if (BIO_puts(out, pname) <= 0) + return 0; + if (BIO_puts(out, ":") <= 0) + return 0; + } + + switch (utype) + { + case V_ASN1_BOOLEAN: + { + int boolval = *(int *)fld; + if (boolval == -1) + boolval = it->size; + ret = asn1_print_boolean_ctx(out, boolval, pctx); + } + break; + + case V_ASN1_INTEGER: + case V_ASN1_ENUMERATED: + ret = asn1_print_integer_ctx(out, str, pctx); + break; + + case V_ASN1_UTCTIME: + ret = ASN1_UTCTIME_print(out, str); + break; + + case V_ASN1_GENERALIZEDTIME: + ret = ASN1_GENERALIZEDTIME_print(out, str); + break; + + case V_ASN1_OBJECT: + ret = asn1_print_oid_ctx(out, (const ASN1_OBJECT *)*fld, pctx); + break; + + case V_ASN1_OCTET_STRING: + case V_ASN1_BIT_STRING: + ret = asn1_print_obstring_ctx(out, str, indent, pctx); + needlf = 0; + break; + + case V_ASN1_SEQUENCE: + case V_ASN1_SET: + case V_ASN1_OTHER: + if (BIO_puts(out, "\n") <= 0) + return 0; + if (ASN1_parse_dump(out, str->data, str->length, + indent, 0) <= 0) + ret = 0; + needlf = 0; + break; + + default: + ret = ASN1_STRING_print_ex(out, str, pctx->str_flags); + + } + if (!ret) + return 0; + if (needlf && BIO_puts(out, "\n") <= 0) + return 0; + return 1; + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/tasn_typ.c b/TMessagesProj/jni/boringssl/crypto/asn1/tasn_typ.c new file mode 100644 index 00000000..f004b0dc --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/tasn_typ.c @@ -0,0 +1,137 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + + +/* Declarations for string types */ + +#define IMPLEMENT_ASN1_STRING_FUNCTIONS(sname) \ + IMPLEMENT_ASN1_TYPE(sname) \ + IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(sname, sname, sname) \ + sname *sname##_new(void) \ + { \ + return ASN1_STRING_type_new(V_##sname); \ + } \ + void sname##_free(sname *x) \ + { \ + ASN1_STRING_free(x); \ + } + +IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_OCTET_STRING) +IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_INTEGER) +IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_ENUMERATED) +IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_BIT_STRING) +IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_UTF8STRING) +IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_PRINTABLESTRING) +IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_T61STRING) +IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_IA5STRING) +IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_GENERALSTRING) +IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_UTCTIME) +IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_GENERALIZEDTIME) +IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_VISIBLESTRING) +IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_UNIVERSALSTRING) +IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_BMPSTRING) + +IMPLEMENT_ASN1_TYPE(ASN1_NULL); +IMPLEMENT_ASN1_FUNCTIONS(ASN1_NULL); + +IMPLEMENT_ASN1_TYPE(ASN1_OBJECT); + +IMPLEMENT_ASN1_TYPE(ASN1_ANY); + +/* Just swallow an ASN1_SEQUENCE in an ASN1_STRING */; +IMPLEMENT_ASN1_TYPE(ASN1_SEQUENCE); + +IMPLEMENT_ASN1_FUNCTIONS_fname(ASN1_TYPE, ASN1_ANY, ASN1_TYPE); + +/* Multistring types */; + +IMPLEMENT_ASN1_MSTRING(ASN1_PRINTABLE, B_ASN1_PRINTABLE); +IMPLEMENT_ASN1_FUNCTIONS_name(ASN1_STRING, ASN1_PRINTABLE); + +IMPLEMENT_ASN1_MSTRING(DISPLAYTEXT, B_ASN1_DISPLAYTEXT); +IMPLEMENT_ASN1_FUNCTIONS_name(ASN1_STRING, DISPLAYTEXT); + +IMPLEMENT_ASN1_MSTRING(DIRECTORYSTRING, B_ASN1_DIRECTORYSTRING); +IMPLEMENT_ASN1_FUNCTIONS_name(ASN1_STRING, DIRECTORYSTRING); + +/* Three separate BOOLEAN type: normal, DEFAULT TRUE and DEFAULT FALSE */; +IMPLEMENT_ASN1_TYPE_ex(ASN1_BOOLEAN, ASN1_BOOLEAN, -1); +IMPLEMENT_ASN1_TYPE_ex(ASN1_TBOOLEAN, ASN1_BOOLEAN, 1); +IMPLEMENT_ASN1_TYPE_ex(ASN1_FBOOLEAN, ASN1_BOOLEAN, 0); + +/* Special, OCTET STRING with indefinite length constructed support */; + +IMPLEMENT_ASN1_TYPE_ex(ASN1_OCTET_STRING_NDEF, ASN1_OCTET_STRING, + ASN1_TFLG_NDEF); + +ASN1_ITEM_TEMPLATE(ASN1_SEQUENCE_ANY) = ASN1_EX_TEMPLATE_TYPE( + ASN1_TFLG_SEQUENCE_OF, 0, ASN1_SEQUENCE_ANY, ASN1_ANY); +ASN1_ITEM_TEMPLATE_END(ASN1_SEQUENCE_ANY); + +ASN1_ITEM_TEMPLATE(ASN1_SET_ANY) = ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SET_OF, 0, + ASN1_SET_ANY, + ASN1_ANY); +ASN1_ITEM_TEMPLATE_END(ASN1_SET_ANY); + +IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(ASN1_SEQUENCE_ANY, + ASN1_SEQUENCE_ANY, + ASN1_SEQUENCE_ANY); +IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(ASN1_SEQUENCE_ANY, ASN1_SET_ANY, + ASN1_SET_ANY); diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/tasn_utl.c b/TMessagesProj/jni/boringssl/crypto/asn1/tasn_utl.c new file mode 100644 index 00000000..960cdbb7 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/tasn_utl.c @@ -0,0 +1,266 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include +#include +#include + +#include "../internal.h" + + +/* Utility functions for manipulating fields and offsets */ + +/* Add 'offset' to 'addr' */ +#define offset2ptr(addr, offset) (void *)(((char *) addr) + offset) + +/* Given an ASN1_ITEM CHOICE type return the selector value */ +int asn1_get_choice_selector(ASN1_VALUE **pval, const ASN1_ITEM *it) { + int *sel = offset2ptr(*pval, it->utype); + return *sel; +} + +/* Given an ASN1_ITEM CHOICE type set the selector value, return old value. */ +int asn1_set_choice_selector(ASN1_VALUE **pval, int value, + const ASN1_ITEM *it) { + int *sel, ret; + sel = offset2ptr(*pval, it->utype); + ret = *sel; + *sel = value; + return ret; +} + +static CRYPTO_refcount_t *asn1_get_references(ASN1_VALUE **pval, + const ASN1_ITEM *it) { + if (it->itype != ASN1_ITYPE_SEQUENCE && + it->itype != ASN1_ITYPE_NDEF_SEQUENCE) { + return NULL; + } + const ASN1_AUX *aux = it->funcs; + if (!aux || !(aux->flags & ASN1_AFLG_REFCOUNT)) { + return NULL; + } + return offset2ptr(*pval, aux->ref_offset); +} + +void asn1_refcount_set_one(ASN1_VALUE **pval, const ASN1_ITEM *it) { + CRYPTO_refcount_t *references = asn1_get_references(pval, it); + if (references != NULL) { + *references = 1; + } +} + +int asn1_refcount_dec_and_test_zero(ASN1_VALUE **pval, const ASN1_ITEM *it) { + CRYPTO_refcount_t *references = asn1_get_references(pval, it); + if (references != NULL) { + return CRYPTO_refcount_dec_and_test_zero(references); + } + return 1; +} + +static ASN1_ENCODING *asn1_get_enc_ptr(ASN1_VALUE **pval, const ASN1_ITEM *it) { + const ASN1_AUX *aux; + if (!pval || !*pval) { + return NULL; + } + aux = it->funcs; + if (!aux || !(aux->flags & ASN1_AFLG_ENCODING)) { + return NULL; + } + return offset2ptr(*pval, aux->enc_offset); +} + +void asn1_enc_init(ASN1_VALUE **pval, const ASN1_ITEM *it) { + ASN1_ENCODING *enc; + enc = asn1_get_enc_ptr(pval, it); + if (enc) { + enc->enc = NULL; + enc->len = 0; + enc->modified = 1; + } +} + +void asn1_enc_free(ASN1_VALUE **pval, const ASN1_ITEM *it) { + ASN1_ENCODING *enc; + enc = asn1_get_enc_ptr(pval, it); + if (enc) { + if (enc->enc) { + OPENSSL_free(enc->enc); + } + enc->enc = NULL; + enc->len = 0; + enc->modified = 1; + } +} + +int asn1_enc_save(ASN1_VALUE **pval, const unsigned char *in, int inlen, + const ASN1_ITEM *it) { + ASN1_ENCODING *enc; + enc = asn1_get_enc_ptr(pval, it); + if (!enc) { + return 1; + } + + if (enc->enc) { + OPENSSL_free(enc->enc); + } + enc->enc = OPENSSL_malloc(inlen); + if (!enc->enc) { + return 0; + } + memcpy(enc->enc, in, inlen); + enc->len = inlen; + enc->modified = 0; + + return 1; +} + +int asn1_enc_restore(int *len, unsigned char **out, ASN1_VALUE **pval, + const ASN1_ITEM *it) { + ASN1_ENCODING *enc; + enc = asn1_get_enc_ptr(pval, it); + if (!enc || enc->modified) { + return 0; + } + if (out) { + memcpy(*out, enc->enc, enc->len); + *out += enc->len; + } + if (len) { + *len = enc->len; + } + return 1; +} + +/* Given an ASN1_TEMPLATE get a pointer to a field */ +ASN1_VALUE **asn1_get_field_ptr(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt) { + ASN1_VALUE **pvaltmp; + if (tt->flags & ASN1_TFLG_COMBINE) { + return pval; + } + pvaltmp = offset2ptr(*pval, tt->offset); + /* NOTE for BOOLEAN types the field is just a plain int so we can't return + * int **, so settle for (int *). */ + return pvaltmp; +} + +/* Handle ANY DEFINED BY template, find the selector, look up the relevant + * ASN1_TEMPLATE in the table and return it. */ +const ASN1_TEMPLATE *asn1_do_adb(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt, + int nullerr) { + const ASN1_ADB *adb; + const ASN1_ADB_TABLE *atbl; + long selector; + ASN1_VALUE **sfld; + int i; + if (!(tt->flags & ASN1_TFLG_ADB_MASK)) { + return tt; + } + + /* Else ANY DEFINED BY ... get the table */ + adb = ASN1_ADB_ptr(tt->item); + + /* Get the selector field */ + sfld = offset2ptr(*pval, adb->offset); + + /* Check if NULL */ + if (!sfld) { + if (!adb->null_tt) { + goto err; + } + return adb->null_tt; + } + + /* Convert type to a long: + * NB: don't check for NID_undef here because it + * might be a legitimate value in the table */ + if (tt->flags & ASN1_TFLG_ADB_OID) { + selector = OBJ_obj2nid((ASN1_OBJECT *)*sfld); + } else { + selector = ASN1_INTEGER_get((ASN1_INTEGER *)*sfld); + } + + /* Try to find matching entry in table Maybe should check application types + * first to allow application override? Might also be useful to have a flag + * which indicates table is sorted and we can do a binary search. For now + * stick to a linear search. */ + + for (atbl = adb->tbl, i = 0; i < adb->tblcount; i++, atbl++) { + if (atbl->value == selector) { + return &atbl->tt; + } + } + + /* FIXME: need to search application table too */ + + /* No match, return default type */ + if (!adb->default_tt) { + goto err; + } + return adb->default_tt; + +err: + /* FIXME: should log the value or OID of unsupported type */ + if (nullerr) { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE); + } + return NULL; +} diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/x_bignum.c b/TMessagesProj/jni/boringssl/crypto/asn1/x_bignum.c new file mode 100644 index 00000000..f8c62fd8 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/x_bignum.c @@ -0,0 +1,142 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + +/* Custom primitive type for BIGNUM handling. This reads in an ASN1_INTEGER as a + * BIGNUM directly. Currently it ignores the sign which isn't a problem since all + * BIGNUMs used are non negative and anything that looks negative is normally due + * to an encoding error. + */ + +#define BN_SENSITIVE 1 + +static int bn_new(ASN1_VALUE **pval, const ASN1_ITEM *it); +static void bn_free(ASN1_VALUE **pval, const ASN1_ITEM *it); + +static int bn_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, const ASN1_ITEM *it); +static int bn_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, int utype, char *free_cont, const ASN1_ITEM *it); + +static const ASN1_PRIMITIVE_FUNCS bignum_pf = { + NULL, 0, + bn_new, + bn_free, + 0, + bn_c2i, + bn_i2c +}; + +ASN1_ITEM_start(BIGNUM) + ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &bignum_pf, 0, "BIGNUM" +ASN1_ITEM_end(BIGNUM) + +ASN1_ITEM_start(CBIGNUM) + ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &bignum_pf, BN_SENSITIVE, "BIGNUM" +ASN1_ITEM_end(CBIGNUM) + +static int bn_new(ASN1_VALUE **pval, const ASN1_ITEM *it) +{ + *pval = (ASN1_VALUE *)BN_new(); + if(*pval) return 1; + else return 0; +} + +static void bn_free(ASN1_VALUE **pval, const ASN1_ITEM *it) +{ + if(!*pval) return; + if(it->size & BN_SENSITIVE) BN_clear_free((BIGNUM *)*pval); + else BN_free((BIGNUM *)*pval); + *pval = NULL; +} + +static int bn_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, const ASN1_ITEM *it) +{ + BIGNUM *bn; + int pad; + if(!*pval) return -1; + bn = (BIGNUM *)*pval; + /* If MSB set in an octet we need a padding byte */ + if(BN_num_bits(bn) & 0x7) pad = 0; + else pad = 1; + if(cont) { + if(pad) *cont++ = 0; + BN_bn2bin(bn, cont); + } + return pad + BN_num_bytes(bn); +} + +static int bn_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, + int utype, char *free_cont, const ASN1_ITEM *it) +{ + BIGNUM *bn; + if(!*pval) + { + if (!bn_new(pval, it)) + { + return 0; + } + } + bn = (BIGNUM *)*pval; + if(!BN_bin2bn(cont, len, bn)) { + bn_free(pval, it); + return 0; + } + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/x_long.c b/TMessagesProj/jni/boringssl/crypto/asn1/x_long.c new file mode 100644 index 00000000..7b1a6fe8 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/x_long.c @@ -0,0 +1,182 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include +#include + + +/* Custom primitive type for long handling. This converts between an ASN1_INTEGER + * and a long directly. + */ + + +static int long_new(ASN1_VALUE **pval, const ASN1_ITEM *it); +static void long_free(ASN1_VALUE **pval, const ASN1_ITEM *it); + +static int long_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, const ASN1_ITEM *it); +static int long_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, int utype, char *free_cont, const ASN1_ITEM *it); +static int long_print(BIO *out, ASN1_VALUE **pval, const ASN1_ITEM *it, int indent, const ASN1_PCTX *pctx); + +static const ASN1_PRIMITIVE_FUNCS long_pf = { + NULL, 0, + long_new, + long_free, + long_free, /* Clear should set to initial value */ + long_c2i, + long_i2c, + long_print +}; + +ASN1_ITEM_start(LONG) + ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &long_pf, ASN1_LONG_UNDEF, "LONG" +ASN1_ITEM_end(LONG) + +ASN1_ITEM_start(ZLONG) + ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &long_pf, 0, "ZLONG" +ASN1_ITEM_end(ZLONG) + +static int long_new(ASN1_VALUE **pval, const ASN1_ITEM *it) +{ + *(long *)pval = it->size; + return 1; +} + +static void long_free(ASN1_VALUE **pval, const ASN1_ITEM *it) +{ + *(long *)pval = it->size; +} + +static int long_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, const ASN1_ITEM *it) +{ + long ltmp; + unsigned long utmp; + int clen, pad, i; + /* this exists to bypass broken gcc optimization */ + char *cp = (char *)pval; + + /* use memcpy, because we may not be long aligned */ + memcpy(<mp, cp, sizeof(long)); + + if(ltmp == it->size) return -1; + /* Convert the long to positive: we subtract one if negative so + * we can cleanly handle the padding if only the MSB of the leading + * octet is set. + */ + if(ltmp < 0) utmp = -ltmp - 1; + else utmp = ltmp; + clen = BN_num_bits_word(utmp); + /* If MSB of leading octet set we need to pad */ + if(!(clen & 0x7)) pad = 1; + else pad = 0; + + /* Convert number of bits to number of octets */ + clen = (clen + 7) >> 3; + + if(cont) { + if(pad) *cont++ = (ltmp < 0) ? 0xff : 0; + for(i = clen - 1; i >= 0; i--) { + cont[i] = (unsigned char)(utmp & 0xff); + if(ltmp < 0) cont[i] ^= 0xff; + utmp >>= 8; + } + } + return clen + pad; +} + +static int long_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, + int utype, char *free_cont, const ASN1_ITEM *it) +{ + int neg, i; + long ltmp; + unsigned long utmp = 0; + char *cp = (char *)pval; + if(len > (int)sizeof(long)) { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG); + return 0; + } + /* Is it negative? */ + if(len && (cont[0] & 0x80)) neg = 1; + else neg = 0; + utmp = 0; + for(i = 0; i < len; i++) { + utmp <<= 8; + if(neg) utmp |= cont[i] ^ 0xff; + else utmp |= cont[i]; + } + ltmp = (long)utmp; + if(neg) { + ltmp++; + ltmp = -ltmp; + } + if(ltmp == it->size) { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG); + return 0; + } + memcpy(cp, <mp, sizeof(long)); + return 1; +} + +static int long_print(BIO *out, ASN1_VALUE **pval, const ASN1_ITEM *it, + int indent, const ASN1_PCTX *pctx) + { + return BIO_printf(out, "%ld\n", *(long *)pval); + } diff --git a/TMessagesProj/jni/boringssl/crypto/base64/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/base64/CMakeLists.txt new file mode 100644 index 00000000..9c38cc55 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/base64/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories(. .. ../../include) + +add_library( + base64 + + OBJECT + + base64.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/base64/base64.c b/TMessagesProj/jni/boringssl/crypto/base64/base64.c new file mode 100644 index 00000000..4822fb89 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/base64/base64.c @@ -0,0 +1,478 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include + + +static const unsigned char data_bin2ascii[65] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +#define conv_bin2ascii(a) (data_bin2ascii[(a) & 0x3f]) + +/* 64 char lines + * pad input with 0 + * left over chars are set to = + * 1 byte => xx== + * 2 bytes => xxx= + * 3 bytes => xxxx + */ +#define BIN_PER_LINE (64/4*3) +#define CHUNKS_PER_LINE (64/4) +#define CHAR_PER_LINE (64+1) + +/* 0xF0 is a EOLN + * 0xF1 is ignore but next needs to be 0xF0 (for \r\n processing). + * 0xF2 is EOF + * 0xE0 is ignore at start of line. + * 0xFF is error */ + +#define B64_EOLN 0xF0 +#define B64_CR 0xF1 +#define B64_EOF 0xF2 +#define B64_WS 0xE0 +#define B64_ERROR 0xFF +#define B64_NOT_BASE64(a) (((a) | 0x13) == 0xF3) + +static const uint8_t data_ascii2bin[128] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xF0, 0xFF, + 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xF2, 0xFF, 0x3F, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, + 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, + 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +static uint8_t conv_ascii2bin(uint8_t a) { + if (a >= 128) { + return 0xFF; + } + return data_ascii2bin[a]; +} + +void EVP_EncodeInit(EVP_ENCODE_CTX *ctx) { + ctx->length = 48; + ctx->num = 0; + ctx->line_num = 0; +} + +void EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len, + const uint8_t *in, size_t in_len) { + unsigned i, j; + unsigned total = 0; + + *out_len = 0; + if (in_len == 0) { + return; + } + + assert(ctx->length <= sizeof(ctx->enc_data)); + + if (ctx->num + in_len < ctx->length) { + memcpy(&ctx->enc_data[ctx->num], in, in_len); + ctx->num += in_len; + return; + } + if (ctx->num != 0) { + i = ctx->length - ctx->num; + memcpy(&ctx->enc_data[ctx->num], in, i); + in += i; + in_len -= i; + j = EVP_EncodeBlock(out, ctx->enc_data, ctx->length); + ctx->num = 0; + out += j; + *(out++) = '\n'; + *out = '\0'; + total = j + 1; + } + while (in_len >= ctx->length) { + j = EVP_EncodeBlock(out, in, ctx->length); + in += ctx->length; + in_len -= ctx->length; + out += j; + *(out++) = '\n'; + *out = '\0'; + total += j + 1; + } + if (in_len != 0) { + memcpy(&ctx->enc_data[0], in, in_len); + } + ctx->num = in_len; + *out_len = total; +} + +void EVP_EncodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len) { + unsigned ret = 0; + + if (ctx->num != 0) { + ret = EVP_EncodeBlock(out, ctx->enc_data, ctx->num); + out[ret++] = '\n'; + out[ret] = '\0'; + ctx->num = 0; + } + *out_len = ret; +} + +size_t EVP_EncodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len) { + uint32_t l; + size_t remaining = src_len, ret = 0; + + while (remaining) { + if (remaining >= 3) { + l = (((uint32_t)src[0]) << 16L) | (((uint32_t)src[1]) << 8L) | src[2]; + *(dst++) = conv_bin2ascii(l >> 18L); + *(dst++) = conv_bin2ascii(l >> 12L); + *(dst++) = conv_bin2ascii(l >> 6L); + *(dst++) = conv_bin2ascii(l); + remaining -= 3; + } else { + l = ((uint32_t)src[0]) << 16L; + if (remaining == 2) { + l |= ((uint32_t)src[1] << 8L); + } + + *(dst++) = conv_bin2ascii(l >> 18L); + *(dst++) = conv_bin2ascii(l >> 12L); + *(dst++) = (remaining == 1) ? '=' : conv_bin2ascii(l >> 6L); + *(dst++) = '='; + remaining = 0; + } + ret += 4; + src += 3; + } + + *dst = '\0'; + return ret; +} + +int EVP_DecodedLength(size_t *out_len, size_t len) { + if (len % 4 != 0) { + return 0; + } + *out_len = (len / 4) * 3; + return 1; +} + +int EVP_DecodeBase64(uint8_t *out, size_t *out_len, size_t max_out, + const uint8_t *in, size_t in_len) { + uint8_t a, b, c, d; + size_t pad_len = 0, len = 0, max_len, i; + uint32_t l; + + if (!EVP_DecodedLength(&max_len, in_len) || max_out < max_len) { + return 0; + } + + for (i = 0; i < in_len; i += 4) { + a = conv_ascii2bin(*(in++)); + b = conv_ascii2bin(*(in++)); + if (i + 4 == in_len && in[1] == '=') { + if (in[0] == '=') { + pad_len = 2; + } else { + pad_len = 1; + } + } + if (pad_len < 2) { + c = conv_ascii2bin(*(in++)); + } else { + c = 0; + } + if (pad_len < 1) { + d = conv_ascii2bin(*(in++)); + } else { + d = 0; + } + if ((a & 0x80) || (b & 0x80) || (c & 0x80) || (d & 0x80)) { + return 0; + } + l = ((((uint32_t)a) << 18L) | (((uint32_t)b) << 12L) | + (((uint32_t)c) << 6L) | (((uint32_t)d))); + *(out++) = (uint8_t)(l >> 16L) & 0xff; + if (pad_len < 2) { + *(out++) = (uint8_t)(l >> 8L) & 0xff; + } + if (pad_len < 1) { + *(out++) = (uint8_t)(l) & 0xff; + } + len += 3 - pad_len; + } + *out_len = len; + return 1; +} + +void EVP_DecodeInit(EVP_ENCODE_CTX *ctx) { + ctx->length = 30; + ctx->num = 0; + ctx->line_num = 0; + ctx->expect_nl = 0; +} + +int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len, + const uint8_t *in, size_t in_len) { + int seof = -1, eof = 0, rv = -1, v, tmp, exp_nl; + uint8_t *d; + unsigned i, n, ln, ret = 0; + + n = ctx->num; + d = ctx->enc_data; + ln = ctx->line_num; + exp_nl = ctx->expect_nl; + + /* last line of input. */ + if (in_len == 0 || (n == 0 && conv_ascii2bin(in[0]) == B64_EOF)) { + rv = 0; + goto end; + } + + /* We parse the input data */ + for (i = 0; i < in_len; i++) { + /* If the current line is > 80 characters, scream alot */ + if (ln >= 80) { + rv = -1; + goto end; + } + + /* Get char and put it into the buffer */ + tmp = *(in++); + v = conv_ascii2bin(tmp); + /* only save the good data :-) */ + if (!B64_NOT_BASE64(v)) { + assert(n < sizeof(ctx->enc_data)); + d[n++] = tmp; + ln++; + } else if (v == B64_ERROR) { + rv = -1; + goto end; + } + + /* have we seen a '=' which is 'definitly' the last + * input line. seof will point to the character that + * holds it. and eof will hold how many characters to + * chop off. */ + if (tmp == '=') { + if (seof == -1) { + seof = n; + } + eof++; + if (eof > 2) { + /* There are, at most, two equals signs at the end of base64 data. */ + rv = -1; + goto end; + } + } + + if (v == B64_CR) { + ln = 0; + if (exp_nl) { + continue; + } + } + + /* eoln */ + if (v == B64_EOLN) { + ln = 0; + if (exp_nl) { + exp_nl = 0; + continue; + } + } + exp_nl = 0; + + /* If we are at the end of input and it looks like a + * line, process it. */ + if ((i + 1) == in_len && (((n & 3) == 0) || eof)) { + v = B64_EOF; + /* In case things were given us in really small + records (so two '=' were given in separate + updates), eof may contain the incorrect number + of ending bytes to skip, so let's redo the count */ + eof = 0; + if (d[n - 1] == '=') { + eof++; + } + if (d[n - 2] == '=') { + eof++; + } + /* There will never be more than two '=' */ + } + + if ((v == B64_EOF && (n & 3) == 0) || n >= 64) { + /* This is needed to work correctly on 64 byte input + * lines. We process the line and then need to + * accept the '\n' */ + if (v != B64_EOF && n >= 64) { + exp_nl = 1; + } + if (n > 0) { + /* TODO(davidben): Switch this to EVP_DecodeBase64. */ + v = EVP_DecodeBlock(out, d, n); + n = 0; + if (v < 0) { + rv = 0; + goto end; + } + if (eof > v) { + rv = -1; + goto end; + } + ret += (v - eof); + } else { + eof = 1; + v = 0; + } + + /* This is the case where we have had a short + * but valid input line */ + if (v < (int)ctx->length && eof) { + rv = 0; + goto end; + } else { + ctx->length = v; + } + + if (seof >= 0) { + rv = 0; + goto end; + } + out += v; + } + } + rv = 1; + +end: + *out_len = ret; + ctx->num = n; + ctx->line_num = ln; + ctx->expect_nl = exp_nl; + return rv; +} + +int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out, int *outl) { + int i; + + *outl = 0; + if (ctx->num != 0) { + /* TODO(davidben): Switch this to EVP_DecodeBase64. */ + i = EVP_DecodeBlock(out, ctx->enc_data, ctx->num); + if (i < 0) { + return -1; + } + ctx->num = 0; + *outl = i; + return 1; + } else { + return 1; + } +} + +int EVP_DecodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len) { + size_t dst_len; + + /* trim white space from the start of the line. */ + while (conv_ascii2bin(*src) == B64_WS && src_len > 0) { + src++; + src_len--; + } + + /* strip off stuff at the end of the line + * ascii2bin values B64_WS, B64_EOLN, B64_EOLN and B64_EOF */ + while (src_len > 3 && B64_NOT_BASE64(conv_ascii2bin(src[src_len - 1]))) { + src_len--; + } + + if (!EVP_DecodedLength(&dst_len, src_len) || dst_len > INT_MAX) { + return -1; + } + if (!EVP_DecodeBase64(dst, &dst_len, dst_len, src, src_len)) { + return -1; + } + + /* EVP_DecodeBlock does not take padding into account, so put the + * NULs back in... so the caller can strip them back out. */ + while (dst_len % 3 != 0) { + dst[dst_len++] = '\0'; + } + assert(dst_len <= INT_MAX); + + return dst_len; +} + +int EVP_EncodedLength(size_t *out_len, size_t len) { + if (len + 2 < len) { + return 0; + } + len += 2; + len /= 3; + if (((len << 2) >> 2) != len) { + return 0; + } + len <<= 2; + if (len + 1 < len) { + return 0; + } + len++; + *out_len = len; + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bio/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/bio/CMakeLists.txt new file mode 100644 index 00000000..dbf8fe5b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bio/CMakeLists.txt @@ -0,0 +1,19 @@ +include_directories(. .. ../../include) + +add_library( + bio + + OBJECT + + bio.c + bio_mem.c + buffer.c + connect.c + fd.c + file.c + hexdump.c + pair.c + printf.c + socket.c + socket_helper.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/bio/bio.c b/TMessagesProj/jni/boringssl/crypto/bio/bio.c new file mode 100644 index 00000000..4bc98ba3 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bio/bio.c @@ -0,0 +1,606 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "../internal.h" + + +/* BIO_set initialises a BIO structure to have the given type and sets the + * reference count to one. It returns one on success or zero on error. */ +static int bio_set(BIO *bio, const BIO_METHOD *method) { + /* This function can be called with a stack allocated |BIO| so we have to + * assume that the contents of |BIO| are arbitary. This also means that it'll + * leak memory if you call |BIO_set| twice on the same BIO. */ + memset(bio, 0, sizeof(BIO)); + + bio->method = method; + bio->shutdown = 1; + bio->references = 1; + + if (method->create != NULL && !method->create(bio)) { + return 0; + } + + return 1; +} + +BIO *BIO_new(const BIO_METHOD *method) { + BIO *ret = OPENSSL_malloc(sizeof(BIO)); + if (ret == NULL) { + OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE); + return NULL; + } + + if (!bio_set(ret, method)) { + OPENSSL_free(ret); + ret = NULL; + } + + return ret; +} + +int BIO_free(BIO *bio) { + BIO *next_bio; + + for (; bio != NULL; bio = next_bio) { + if (!CRYPTO_refcount_dec_and_test_zero(&bio->references)) { + return 0; + } + + if (bio->callback != NULL) { + int i = (int)bio->callback(bio, BIO_CB_FREE, NULL, 0, 0, 1); + if (i <= 0) { + return i; + } + } + + next_bio = BIO_pop(bio); + + if (bio->method != NULL && bio->method->destroy != NULL) { + bio->method->destroy(bio); + } + + OPENSSL_free(bio); + } + return 1; +} + +BIO *BIO_up_ref(BIO *bio) { + CRYPTO_refcount_inc(&bio->references); + return bio; +} + +void BIO_vfree(BIO *bio) { + BIO_free(bio); +} + +void BIO_free_all(BIO *bio) { + BIO_free(bio); +} + +static int bio_io(BIO *bio, void *buf, int len, size_t method_offset, + int callback_flags, size_t *num) { + int i; + typedef int (*io_func_t)(BIO *, char *, int); + io_func_t io_func = NULL; + + if (bio != NULL && bio->method != NULL) { + io_func = + *((const io_func_t *)(((const uint8_t *)bio->method) + method_offset)); + } + + if (io_func == NULL) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); + return -2; + } + + if (bio->callback != NULL) { + i = (int) bio->callback(bio, callback_flags, buf, len, 0L, 1L); + if (i <= 0) { + return i; + } + } + + if (!bio->init) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED); + return -2; + } + + i = 0; + if (buf != NULL && len > 0) { + i = io_func(bio, buf, len); + } + + if (i > 0) { + *num += i; + } + + if (bio->callback != NULL) { + i = (int)(bio->callback(bio, callback_flags | BIO_CB_RETURN, buf, len, 0L, + (long)i)); + } + + return i; +} + +int BIO_read(BIO *bio, void *buf, int len) { + return bio_io(bio, buf, len, offsetof(BIO_METHOD, bread), BIO_CB_READ, + &bio->num_read); +} + +int BIO_gets(BIO *bio, char *buf, int len) { + return bio_io(bio, buf, len, offsetof(BIO_METHOD, bgets), BIO_CB_GETS, + &bio->num_read); +} + +int BIO_write(BIO *bio, const void *in, int inl) { + return bio_io(bio, (char *)in, inl, offsetof(BIO_METHOD, bwrite), + BIO_CB_WRITE, &bio->num_write); +} + +int BIO_puts(BIO *bio, const char *in) { + return BIO_write(bio, in, strlen(in)); +} + +int BIO_flush(BIO *bio) { + return BIO_ctrl(bio, BIO_CTRL_FLUSH, 0, NULL); +} + +long BIO_ctrl(BIO *bio, int cmd, long larg, void *parg) { + long ret; + + if (bio == NULL) { + return 0; + } + + if (bio->method == NULL || bio->method->ctrl == NULL) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); + return -2; + } + + if (bio->callback != NULL) { + ret = bio->callback(bio, BIO_CB_CTRL, parg, cmd, larg, 1); + if (ret <= 0) { + return ret; + } + } + + ret = bio->method->ctrl(bio, cmd, larg, parg); + + if (bio->callback != NULL) { + ret = bio->callback(bio, BIO_CB_CTRL | BIO_CB_RETURN, parg, cmd, larg, ret); + } + + return ret; +} + +char *BIO_ptr_ctrl(BIO *b, int cmd, long larg) { + char *p = NULL; + + if (BIO_ctrl(b, cmd, larg, (void *)&p) <= 0) { + return NULL; + } + + return p; +} + +long BIO_int_ctrl(BIO *b, int cmd, long larg, int iarg) { + int i = iarg; + + return BIO_ctrl(b, cmd, larg, (void *)&i); +} + +int BIO_reset(BIO *bio) { + return BIO_ctrl(bio, BIO_CTRL_RESET, 0, NULL); +} + +void BIO_set_flags(BIO *bio, int flags) { + bio->flags |= flags; +} + +int BIO_test_flags(const BIO *bio, int flags) { + return bio->flags & flags; +} + +int BIO_should_read(const BIO *bio) { + return BIO_test_flags(bio, BIO_FLAGS_READ); +} + +int BIO_should_write(const BIO *bio) { + return BIO_test_flags(bio, BIO_FLAGS_WRITE); +} + +int BIO_should_retry(const BIO *bio) { + return BIO_test_flags(bio, BIO_FLAGS_SHOULD_RETRY); +} + +int BIO_should_io_special(const BIO *bio) { + return BIO_test_flags(bio, BIO_FLAGS_IO_SPECIAL); +} + +int BIO_get_retry_reason(const BIO *bio) { return bio->retry_reason; } + +void BIO_clear_flags(BIO *bio, int flags) { + bio->flags &= ~flags; +} + +void BIO_set_retry_read(BIO *bio) { + bio->flags |= BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY; +} + +void BIO_set_retry_write(BIO *bio) { + bio->flags |= BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY; +} + +static const int kRetryFlags = BIO_FLAGS_RWS | BIO_FLAGS_SHOULD_RETRY; + +int BIO_get_retry_flags(BIO *bio) { + return bio->flags & kRetryFlags; +} + +void BIO_clear_retry_flags(BIO *bio) { + bio->flags &= ~kRetryFlags; + bio->retry_reason = 0; +} + +int BIO_method_type(const BIO *bio) { return bio->method->type; } + +void BIO_copy_next_retry(BIO *bio) { + BIO_clear_retry_flags(bio); + BIO_set_flags(bio, BIO_get_retry_flags(bio->next_bio)); + bio->retry_reason = bio->next_bio->retry_reason; +} + +long BIO_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) { + long ret; + bio_info_cb cb; + + if (bio == NULL) { + return 0; + } + + if (bio->method == NULL || bio->method->callback_ctrl == NULL) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); + return 0; + } + + cb = bio->callback; + + if (cb != NULL) { + ret = cb(bio, BIO_CB_CTRL, (void *)&fp, cmd, 0, 1L); + if (ret <= 0) { + return ret; + } + } + + ret = bio->method->callback_ctrl(bio, cmd, fp); + + if (cb != NULL) { + ret = cb(bio, BIO_CB_CTRL | BIO_CB_RETURN, (void *)&fp, cmd, 0, ret); + } + + return ret; +} + +size_t BIO_pending(const BIO *bio) { + return BIO_ctrl((BIO *) bio, BIO_CTRL_PENDING, 0, NULL); +} + +size_t BIO_ctrl_pending(const BIO *bio) { + return BIO_pending(bio); +} + +size_t BIO_wpending(const BIO *bio) { + return BIO_ctrl((BIO *) bio, BIO_CTRL_WPENDING, 0, NULL); +} + +int BIO_set_close(BIO *bio, int close_flag) { + return BIO_ctrl(bio, BIO_CTRL_SET_CLOSE, close_flag, NULL); +} + +void BIO_set_callback(BIO *bio, bio_info_cb callback_func) { + bio->callback = callback_func; +} + +void BIO_set_callback_arg(BIO *bio, char *arg) { + bio->cb_arg = arg; +} + +char *BIO_get_callback_arg(const BIO *bio) { + return bio->cb_arg; +} + +OPENSSL_EXPORT size_t BIO_number_read(const BIO *bio) { + return bio->num_read; +} + +OPENSSL_EXPORT size_t BIO_number_written(const BIO *bio) { + return bio->num_write; +} + +BIO *BIO_push(BIO *bio, BIO *appended_bio) { + BIO *last_bio; + + if (bio == NULL) { + return bio; + } + + last_bio = bio; + while (last_bio->next_bio != NULL) { + last_bio = last_bio->next_bio; + } + + last_bio->next_bio = appended_bio; + return bio; +} + +BIO *BIO_pop(BIO *bio) { + BIO *ret; + + if (bio == NULL) { + return NULL; + } + ret = bio->next_bio; + bio->next_bio = NULL; + return ret; +} + +BIO *BIO_next(BIO *bio) { + if (!bio) { + return NULL; + } + return bio->next_bio; +} + +BIO *BIO_find_type(BIO *bio, int type) { + int method_type, mask; + + if (!bio) { + return NULL; + } + mask = type & 0xff; + + do { + if (bio->method != NULL) { + method_type = bio->method->type; + + if (!mask) { + if (method_type & type) { + return bio; + } + } else if (method_type == type) { + return bio; + } + } + bio = bio->next_bio; + } while (bio != NULL); + + return NULL; +} + +int BIO_indent(BIO *bio, unsigned indent, unsigned max_indent) { + if (indent > max_indent) { + indent = max_indent; + } + + while (indent--) { + if (BIO_puts(bio, " ") != 1) { + return 0; + } + } + return 1; +} + +static int print_bio(const char *str, size_t len, void *bio) { + return BIO_write((BIO *)bio, str, len); +} + +void BIO_print_errors(BIO *bio) { + ERR_print_errors_cb(print_bio, bio); +} + +void ERR_print_errors(BIO *bio) { + BIO_print_errors(bio); +} + +/* bio_read_all reads everything from |bio| and prepends |prefix| to it. On + * success, |*out| is set to an allocated buffer (which should be freed with + * |OPENSSL_free|), |*out_len| is set to its length and one is returned. The + * buffer will contain |prefix| followed by the contents of |bio|. On failure, + * zero is returned. + * + * The function will fail if the size of the output would equal or exceed + * |max_len|. */ +static int bio_read_all(BIO *bio, uint8_t **out, size_t *out_len, + const uint8_t *prefix, size_t prefix_len, + size_t max_len) { + static const size_t kChunkSize = 4096; + + size_t len = prefix_len + kChunkSize; + if (len > max_len) { + len = max_len; + } + if (len < prefix_len) { + return 0; + } + *out = OPENSSL_malloc(len); + if (*out == NULL) { + return 0; + } + memcpy(*out, prefix, prefix_len); + size_t done = prefix_len; + + for (;;) { + if (done == len) { + OPENSSL_free(*out); + return 0; + } + const size_t todo = len - done; + assert(todo < INT_MAX); + const int n = BIO_read(bio, *out + done, todo); + if (n == 0) { + *out_len = done; + return 1; + } else if (n == -1) { + OPENSSL_free(*out); + return 0; + } + + done += n; + if (len < max_len && len - done < kChunkSize / 2) { + len += kChunkSize; + if (len < kChunkSize || len > max_len) { + len = max_len; + } + uint8_t *new_buf = OPENSSL_realloc(*out, len); + if (new_buf == NULL) { + OPENSSL_free(*out); + return 0; + } + *out = new_buf; + } + } +} + +int BIO_read_asn1(BIO *bio, uint8_t **out, size_t *out_len, size_t max_len) { + uint8_t header[6]; + + static const size_t kInitialHeaderLen = 2; + if (BIO_read(bio, header, kInitialHeaderLen) != kInitialHeaderLen) { + return 0; + } + + const uint8_t tag = header[0]; + const uint8_t length_byte = header[1]; + + if ((tag & 0x1f) == 0x1f) { + /* Long form tags are not supported. */ + return 0; + } + + size_t len, header_len; + if ((length_byte & 0x80) == 0) { + /* Short form length. */ + len = length_byte; + header_len = kInitialHeaderLen; + } else { + const size_t num_bytes = length_byte & 0x7f; + + if ((tag & 0x20 /* constructed */) != 0 && num_bytes == 0) { + /* indefinite length. */ + return bio_read_all(bio, out, out_len, header, kInitialHeaderLen, + max_len); + } + + if (num_bytes == 0 || num_bytes > 4) { + return 0; + } + + if (BIO_read(bio, header + kInitialHeaderLen, num_bytes) != num_bytes) { + return 0; + } + header_len = kInitialHeaderLen + num_bytes; + + uint32_t len32 = 0; + unsigned i; + for (i = 0; i < num_bytes; i++) { + len32 <<= 8; + len32 |= header[kInitialHeaderLen + i]; + } + + if (len32 < 128) { + /* Length should have used short-form encoding. */ + return 0; + } + + if ((len32 >> ((num_bytes-1)*8)) == 0) { + /* Length should have been at least one byte shorter. */ + return 0; + } + + len = len32; + } + + if (len + header_len < len || + len + header_len > max_len) { + return 0; + } + len += header_len; + *out_len = len; + + *out = OPENSSL_malloc(len); + if (*out == NULL) { + return 0; + } + memcpy(*out, header, header_len); + if (BIO_read(bio, (*out) + header_len, len - header_len) != + len - header_len) { + OPENSSL_free(*out); + return 0; + } + + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bio/bio_mem.c b/TMessagesProj/jni/boringssl/crypto/bio/bio_mem.c new file mode 100644 index 00000000..ef56111b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bio/bio_mem.c @@ -0,0 +1,327 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include +#include + + +BIO *BIO_new_mem_buf(void *buf, int len) { + BIO *ret; + BUF_MEM *b; + const size_t size = len < 0 ? strlen((char *)buf) : (size_t)len; + + if (!buf && len != 0) { + OPENSSL_PUT_ERROR(BIO, BIO_R_NULL_PARAMETER); + return NULL; + } + + ret = BIO_new(BIO_s_mem()); + if (ret == NULL) { + return NULL; + } + + b = (BUF_MEM *)ret->ptr; + b->data = buf; + b->length = size; + b->max = size; + + ret->flags |= BIO_FLAGS_MEM_RDONLY; + + /* |num| is used to store the value that this BIO will return when it runs + * out of data. If it's negative then the retry flags will also be set. Since + * this is static data, retrying wont help */ + ret->num = 0; + + return ret; +} + +static int mem_new(BIO *bio) { + BUF_MEM *b; + + b = BUF_MEM_new(); + if (b == NULL) { + return 0; + } + + /* |shutdown| is used to store the close flag: whether the BIO has ownership + * of the BUF_MEM. */ + bio->shutdown = 1; + bio->init = 1; + bio->num = -1; + bio->ptr = (char *)b; + + return 1; +} + +static int mem_free(BIO *bio) { + BUF_MEM *b; + + if (bio == NULL) { + return 0; + } + + if (!bio->shutdown || !bio->init || bio->ptr == NULL) { + return 1; + } + + b = (BUF_MEM *)bio->ptr; + if (bio->flags & BIO_FLAGS_MEM_RDONLY) { + b->data = NULL; + } + BUF_MEM_free(b); + bio->ptr = NULL; + return 1; +} + +static int mem_read(BIO *bio, char *out, int outl) { + int ret; + BUF_MEM *b = (BUF_MEM*) bio->ptr; + + BIO_clear_retry_flags(bio); + ret = outl; + if (b->length < INT_MAX && ret > (int)b->length) { + ret = b->length; + } + + if (ret > 0) { + memcpy(out, b->data, ret); + b->length -= ret; + if (bio->flags & BIO_FLAGS_MEM_RDONLY) { + b->data += ret; + } else { + memmove(b->data, &b->data[ret], b->length); + } + } else if (b->length == 0) { + ret = bio->num; + if (ret != 0) { + BIO_set_retry_read(bio); + } + } + return ret; +} + +static int mem_write(BIO *bio, const char *in, int inl) { + int ret = -1; + int blen; + BUF_MEM *b; + + b = (BUF_MEM *)bio->ptr; + + if (bio->flags & BIO_FLAGS_MEM_RDONLY) { + OPENSSL_PUT_ERROR(BIO, BIO_R_WRITE_TO_READ_ONLY_BIO); + goto err; + } + + BIO_clear_retry_flags(bio); + blen = b->length; + if (INT_MAX - blen < inl) { + goto err; + } + if (BUF_MEM_grow_clean(b, blen + inl) != (blen + inl)) { + goto err; + } + memcpy(&b->data[blen], in, inl); + ret = inl; + +err: + return ret; +} + +static int mem_puts(BIO *bp, const char *str) { + return mem_write(bp, str, strlen(str)); +} + +static int mem_gets(BIO *bio, char *buf, int size) { + int i, j; + char *p; + BUF_MEM *b = (BUF_MEM *)bio->ptr; + + BIO_clear_retry_flags(bio); + j = b->length; + if (size - 1 < j) { + j = size - 1; + } + if (j <= 0) { + if (size > 0) { + *buf = 0; + } + return 0; + } + + p = b->data; + for (i = 0; i < j; i++) { + if (p[i] == '\n') { + i++; + break; + } + } + + /* i is now the max num of bytes to copy, either j or up to and including the + * first newline */ + + i = mem_read(bio, buf, i); + if (i > 0) { + buf[i] = '\0'; + } + return i; +} + +static long mem_ctrl(BIO *bio, int cmd, long num, void *ptr) { + long ret = 1; + char **pptr; + + BUF_MEM *b = (BUF_MEM *)bio->ptr; + + switch (cmd) { + case BIO_CTRL_RESET: + if (b->data != NULL) { + /* For read only case reset to the start again */ + if (bio->flags & BIO_FLAGS_MEM_RDONLY) { + b->data -= b->max - b->length; + b->length = b->max; + } else { + memset(b->data, 0, b->max); + b->length = 0; + } + } + break; + case BIO_CTRL_EOF: + ret = (long)(b->length == 0); + break; + case BIO_C_SET_BUF_MEM_EOF_RETURN: + bio->num = (int)num; + break; + case BIO_CTRL_INFO: + ret = (long)b->length; + if (ptr != NULL) { + pptr = (char **)ptr; + *pptr = (char *)&b->data[0]; + } + break; + case BIO_C_SET_BUF_MEM: + mem_free(bio); + bio->shutdown = (int)num; + bio->ptr = ptr; + break; + case BIO_C_GET_BUF_MEM_PTR: + if (ptr != NULL) { + pptr = (char **)ptr; + *pptr = (char *)b; + } + break; + case BIO_CTRL_GET_CLOSE: + ret = (long)bio->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + bio->shutdown = (int)num; + break; + + case BIO_CTRL_WPENDING: + ret = 0L; + break; + case BIO_CTRL_PENDING: + ret = (long)b->length; + break; + case BIO_CTRL_FLUSH: + ret = 1; + break; + default: + ret = 0; + break; + } + return ret; +} + +static const BIO_METHOD mem_method = { + BIO_TYPE_MEM, "memory buffer", mem_write, mem_read, mem_puts, + mem_gets, mem_ctrl, mem_new, mem_free, NULL, }; + +const BIO_METHOD *BIO_s_mem(void) { return &mem_method; } + +int BIO_mem_contents(const BIO *bio, const uint8_t **out_contents, + size_t *out_len) { + const BUF_MEM *b; + if (bio->method != &mem_method) { + return 0; + } + + b = (BUF_MEM *)bio->ptr; + *out_contents = (uint8_t *)b->data; + *out_len = b->length; + return 1; +} + +long BIO_get_mem_data(BIO *bio, char **contents) { + return BIO_ctrl(bio, BIO_CTRL_INFO, 0, (char *) contents); +} + +int BIO_get_mem_ptr(BIO *bio, BUF_MEM **out) { + return BIO_ctrl(bio, BIO_C_GET_BUF_MEM_PTR, 0, (char *) out); +} + +int BIO_set_mem_buf(BIO *bio, BUF_MEM *b, int take_ownership) { + return BIO_ctrl(bio, BIO_C_SET_BUF_MEM, take_ownership, (char *) b); +} + +int BIO_set_mem_eof_return(BIO *bio, int eof_value) { + return BIO_ctrl(bio, BIO_C_SET_BUF_MEM_EOF_RETURN, eof_value, NULL); +} diff --git a/TMessagesProj/jni/boringssl/crypto/bio/buffer.c b/TMessagesProj/jni/boringssl/crypto/bio/buffer.c new file mode 100644 index 00000000..9d0cb3c0 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bio/buffer.c @@ -0,0 +1,496 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include + + +#define DEFAULT_BUFFER_SIZE 4096 + +typedef struct bio_f_buffer_ctx_struct { + /* Buffers are setup like this: + * + * <---------------------- size -----------------------> + * +---------------------------------------------------+ + * | consumed | remaining | free space | + * +---------------------------------------------------+ + * <-- off --><------- len -------> + */ + + int ibuf_size; /* how big is the input buffer */ + int obuf_size; /* how big is the output buffer */ + + char *ibuf; /* the char array */ + int ibuf_len; /* how many bytes are in it */ + int ibuf_off; /* write/read offset */ + + char *obuf; /* the char array */ + int obuf_len; /* how many bytes are in it */ + int obuf_off; /* write/read offset */ +} BIO_F_BUFFER_CTX; + +static int buffer_new(BIO *bio) { + BIO_F_BUFFER_CTX *ctx; + + ctx = OPENSSL_malloc(sizeof(BIO_F_BUFFER_CTX)); + if (ctx == NULL) { + return 0; + } + memset(ctx, 0, sizeof(BIO_F_BUFFER_CTX)); + + ctx->ibuf = OPENSSL_malloc(DEFAULT_BUFFER_SIZE); + if (ctx->ibuf == NULL) { + goto err1; + } + ctx->obuf = (char *)OPENSSL_malloc(DEFAULT_BUFFER_SIZE); + if (ctx->obuf == NULL) { + goto err2; + } + ctx->ibuf_size = DEFAULT_BUFFER_SIZE; + ctx->obuf_size = DEFAULT_BUFFER_SIZE; + + bio->init = 1; + bio->ptr = (char *)ctx; + return 1; + +err2: + OPENSSL_free(ctx->ibuf); + +err1: + OPENSSL_free(ctx); + return 0; +} + +static int buffer_free(BIO *bio) { + BIO_F_BUFFER_CTX *ctx; + + if (bio == NULL || bio->ptr == NULL) { + return 0; + } + + ctx = (BIO_F_BUFFER_CTX *)bio->ptr; + OPENSSL_free(ctx->ibuf); + OPENSSL_free(ctx->obuf); + OPENSSL_free(bio->ptr); + + bio->ptr = NULL; + bio->init = 0; + bio->flags = 0; + + return 1; +} + +static int buffer_read(BIO *bio, char *out, int outl) { + int i, num = 0; + BIO_F_BUFFER_CTX *ctx; + + ctx = (BIO_F_BUFFER_CTX *)bio->ptr; + + if (ctx == NULL || bio->next_bio == NULL) { + return 0; + } + + num = 0; + BIO_clear_retry_flags(bio); + + for (;;) { + i = ctx->ibuf_len; + /* If there is stuff left over, grab it */ + if (i != 0) { + if (i > outl) { + i = outl; + } + memcpy(out, &ctx->ibuf[ctx->ibuf_off], i); + ctx->ibuf_off += i; + ctx->ibuf_len -= i; + num += i; + if (outl == i) { + return num; + } + outl -= i; + out += i; + } + + /* We may have done a partial read. Try to do more. We have nothing in the + * buffer. If we get an error and have read some data, just return it and + * let them retry to get the error again. Copy direct to parent address + * space */ + if (outl > ctx->ibuf_size) { + for (;;) { + i = BIO_read(bio->next_bio, out, outl); + if (i <= 0) { + BIO_copy_next_retry(bio); + if (i < 0) { + return (num > 0) ? num : i; + } + return num; + } + num += i; + if (outl == i) { + return num; + } + out += i; + outl -= i; + } + } + /* else */ + + /* we are going to be doing some buffering */ + i = BIO_read(bio->next_bio, ctx->ibuf, ctx->ibuf_size); + if (i <= 0) { + BIO_copy_next_retry(bio); + if (i < 0) { + return (num > 0) ? num : i; + } + return num; + } + ctx->ibuf_off = 0; + ctx->ibuf_len = i; + } +} + +static int buffer_write(BIO *b, const char *in, int inl) { + int i, num = 0; + BIO_F_BUFFER_CTX *ctx; + + ctx = (BIO_F_BUFFER_CTX *)b->ptr; + if (ctx == NULL || b->next_bio == NULL) { + return 0; + } + + BIO_clear_retry_flags(b); + + for (;;) { + i = ctx->obuf_size - (ctx->obuf_off + ctx->obuf_len); + /* add to buffer and return */ + if (i >= inl) { + memcpy(&ctx->obuf[ctx->obuf_off + ctx->obuf_len], in, inl); + ctx->obuf_len += inl; + return num + inl; + } + /* else */ + /* stuff already in buffer, so add to it first, then flush */ + if (ctx->obuf_len != 0) { + if (i > 0) { + memcpy(&ctx->obuf[ctx->obuf_off + ctx->obuf_len], in, i); + in += i; + inl -= i; + num += i; + ctx->obuf_len += i; + } + + /* we now have a full buffer needing flushing */ + for (;;) { + i = BIO_write(b->next_bio, &ctx->obuf[ctx->obuf_off], ctx->obuf_len); + if (i <= 0) { + BIO_copy_next_retry(b); + + if (i < 0) { + return (num > 0) ? num : i; + } + return num; + } + ctx->obuf_off += i; + ctx->obuf_len -= i; + if (ctx->obuf_len == 0) { + break; + } + } + } + + /* we only get here if the buffer has been flushed and we + * still have stuff to write */ + ctx->obuf_off = 0; + + /* we now have inl bytes to write */ + while (inl >= ctx->obuf_size) { + i = BIO_write(b->next_bio, in, inl); + if (i <= 0) { + BIO_copy_next_retry(b); + if (i < 0) { + return (num > 0) ? num : i; + } + return num; + } + num += i; + in += i; + inl -= i; + if (inl == 0) { + return num; + } + } + + /* copy the rest into the buffer since we have only a small + * amount left */ + } +} + +static long buffer_ctrl(BIO *b, int cmd, long num, void *ptr) { + BIO_F_BUFFER_CTX *ctx; + long ret = 1; + char *p1, *p2; + int r, *ip; + int ibs, obs; + + ctx = (BIO_F_BUFFER_CTX *)b->ptr; + + switch (cmd) { + case BIO_CTRL_RESET: + ctx->ibuf_off = 0; + ctx->ibuf_len = 0; + ctx->obuf_off = 0; + ctx->obuf_len = 0; + if (b->next_bio == NULL) { + return 0; + } + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + break; + + case BIO_CTRL_INFO: + ret = ctx->obuf_len; + break; + + case BIO_CTRL_WPENDING: + ret = (long)ctx->obuf_len; + if (ret == 0) { + if (b->next_bio == NULL) { + return 0; + } + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + } + break; + + case BIO_CTRL_PENDING: + ret = (long)ctx->ibuf_len; + if (ret == 0) { + if (b->next_bio == NULL) { + return 0; + } + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + } + break; + + case BIO_C_SET_BUFF_SIZE: + ip = (int *)ptr; + if (*ip == 0) { + ibs = (int)num; + obs = ctx->obuf_size; + } else /* if (*ip == 1) */ { + ibs = ctx->ibuf_size; + obs = (int)num; + } + p1 = ctx->ibuf; + p2 = ctx->obuf; + if (ibs > DEFAULT_BUFFER_SIZE && ibs != ctx->ibuf_size) { + p1 = (char *)OPENSSL_malloc(ibs); + if (p1 == NULL) { + goto malloc_error; + } + } + if (obs > DEFAULT_BUFFER_SIZE && obs != ctx->obuf_size) { + p2 = (char *)OPENSSL_malloc(obs); + if (p2 == NULL) { + if (p1 != ctx->ibuf) { + OPENSSL_free(p1); + } + goto malloc_error; + } + } + + if (ctx->ibuf != p1) { + OPENSSL_free(ctx->ibuf); + ctx->ibuf = p1; + ctx->ibuf_size = ibs; + } + ctx->ibuf_off = 0; + ctx->ibuf_len = 0; + + if (ctx->obuf != p2) { + OPENSSL_free(ctx->obuf); + ctx->obuf = p2; + ctx->obuf_size = obs; + } + ctx->obuf_off = 0; + ctx->obuf_len = 0; + break; + + case BIO_CTRL_FLUSH: + if (b->next_bio == NULL) { + return 0; + } + + while (ctx->obuf_len > 0) { + BIO_clear_retry_flags(b); + r = BIO_write(b->next_bio, &(ctx->obuf[ctx->obuf_off]), + ctx->obuf_len); + BIO_copy_next_retry(b); + if (r <= 0) { + return r; + } + ctx->obuf_off += r; + ctx->obuf_len -= r; + } + + ctx->obuf_len = 0; + ctx->obuf_off = 0; + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + break; + + default: + if (b->next_bio == NULL) { + return 0; + } + BIO_clear_retry_flags(b); + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + BIO_copy_next_retry(b); + break; + } + return ret; + +malloc_error: + OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE); + return 0; +} + +static long buffer_callback_ctrl(BIO *b, int cmd, bio_info_cb fp) { + long ret = 1; + + if (b->next_bio == NULL) { + return 0; + } + + switch (cmd) { + default: + ret = BIO_callback_ctrl(b->next_bio, cmd, fp); + break; + } + return ret; +} + +static int buffer_gets(BIO *b, char *buf, int size) { + BIO_F_BUFFER_CTX *ctx; + int num = 0, i, flag; + char *p; + + ctx = (BIO_F_BUFFER_CTX *)b->ptr; + if (buf == NULL || size <= 0) { + return 0; + } + + size--; /* reserve space for a '\0' */ + BIO_clear_retry_flags(b); + + for (;;) { + if (ctx->ibuf_len > 0) { + p = &ctx->ibuf[ctx->ibuf_off]; + flag = 0; + for (i = 0; (i < ctx->ibuf_len) && (i < size); i++) { + *(buf++) = p[i]; + if (p[i] == '\n') { + flag = 1; + i++; + break; + } + } + num += i; + size -= i; + ctx->ibuf_len -= i; + ctx->ibuf_off += i; + if (flag || size == 0) { + *buf = '\0'; + return num; + } + } else /* read another chunk */ + { + i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size); + if (i <= 0) { + BIO_copy_next_retry(b); + *buf = '\0'; + if (i < 0) { + return (num > 0) ? num : i; + } + return num; + } + ctx->ibuf_len = i; + ctx->ibuf_off = 0; + } + } +} + +static int buffer_puts(BIO *b, const char *str) { + return buffer_write(b, str, strlen(str)); +} + +static const BIO_METHOD methods_buffer = { + BIO_TYPE_BUFFER, "buffer", buffer_write, buffer_read, + buffer_puts, buffer_gets, buffer_ctrl, buffer_new, + buffer_free, buffer_callback_ctrl, +}; + +const BIO_METHOD *BIO_f_buffer(void) { return &methods_buffer; } + +int BIO_set_read_buffer_size(BIO *bio, int buffer_size) { + return BIO_int_ctrl(bio, BIO_C_SET_BUFF_SIZE, buffer_size, 0); +} + +int BIO_set_write_buffer_size(BIO *bio, int buffer_size) { + return BIO_int_ctrl(bio, BIO_C_SET_BUFF_SIZE, buffer_size, 1); +} diff --git a/TMessagesProj/jni/boringssl/crypto/bio/connect.c b/TMessagesProj/jni/boringssl/crypto/bio/connect.c new file mode 100644 index 00000000..2ed2def1 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bio/connect.c @@ -0,0 +1,538 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include +#include + +#if !defined(OPENSSL_WINDOWS) +#include +#include +#include +#include +#else +#pragma warning(push, 3) +#include +#include +#pragma warning(pop) +#endif + +#include +#include +#include + +#include "internal.h" + + +enum { + BIO_CONN_S_BEFORE, + BIO_CONN_S_BLOCKED_CONNECT, + BIO_CONN_S_OK, +}; + +typedef struct bio_connect_st { + int state; + + char *param_hostname; + char *param_port; + int nbio; + + uint8_t ip[4]; + unsigned short port; + + struct sockaddr_storage them; + socklen_t them_length; + + /* the file descriptor is kept in bio->num in order to match the socket + * BIO. */ + + /* info_callback is called when the connection is initially made + * callback(BIO,state,ret); The callback should return 'ret', state is for + * compatibility with the SSL info_callback. */ + int (*info_callback)(const BIO *bio, int state, int ret); +} BIO_CONNECT; + +#if !defined(OPENSSL_WINDOWS) +static int closesocket(int sock) { + return close(sock); +} +#endif + +/* maybe_copy_ipv4_address sets |*ipv4| to the IPv4 address from |ss| (in + * big-endian order), if |ss| contains an IPv4 socket address. */ +static void maybe_copy_ipv4_address(uint8_t *ipv4, + const struct sockaddr_storage *ss) { + const struct sockaddr_in *sin; + + if (ss->ss_family != AF_INET) { + return; + } + + sin = (const struct sockaddr_in*) ss; + memcpy(ipv4, &sin->sin_addr, 4); +} + +static int conn_state(BIO *bio, BIO_CONNECT *c) { + int ret = -1, i; + char *p, *q; + int (*cb)(const BIO *, int, int) = NULL; + + if (c->info_callback != NULL) { + cb = c->info_callback; + } + + for (;;) { + switch (c->state) { + case BIO_CONN_S_BEFORE: + p = c->param_hostname; + if (p == NULL) { + OPENSSL_PUT_ERROR(BIO, BIO_R_NO_HOSTNAME_SPECIFIED); + goto exit_loop; + } + for (; *p != 0; p++) { + if (*p == ':' || *p == '/') { + break; + } + } + + i = *p; + if (i == ':' || i == '/') { + *(p++) = 0; + if (i == ':') { + for (q = p; *q; q++) { + if (*q == '/') { + *q = 0; + break; + } + } + OPENSSL_free(c->param_port); + c->param_port = BUF_strdup(p); + } + } + + if (c->param_port == NULL) { + OPENSSL_PUT_ERROR(BIO, BIO_R_NO_PORT_SPECIFIED); + ERR_add_error_data(2, "host=", c->param_hostname); + goto exit_loop; + } + + if (!bio_ip_and_port_to_socket_and_addr( + &bio->num, &c->them, &c->them_length, c->param_hostname, + c->param_port)) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNABLE_TO_CREATE_SOCKET); + ERR_add_error_data(4, "host=", c->param_hostname, ":", c->param_port); + goto exit_loop; + } + + memset(c->ip, 0, 4); + maybe_copy_ipv4_address(c->ip, &c->them); + + if (c->nbio) { + if (!bio_socket_nbio(bio->num, 1)) { + OPENSSL_PUT_ERROR(BIO, BIO_R_ERROR_SETTING_NBIO); + ERR_add_error_data(4, "host=", c->param_hostname, ":", + c->param_port); + goto exit_loop; + } + } + + i = 1; + ret = setsockopt(bio->num, SOL_SOCKET, SO_KEEPALIVE, (char *)&i, + sizeof(i)); + if (ret < 0) { + OPENSSL_PUT_SYSTEM_ERROR(setsockopt); + OPENSSL_PUT_ERROR(BIO, BIO_R_KEEPALIVE); + ERR_add_error_data(4, "host=", c->param_hostname, ":", c->param_port); + goto exit_loop; + } + + BIO_clear_retry_flags(bio); + ret = connect(bio->num, (struct sockaddr*) &c->them, c->them_length); + if (ret < 0) { + if (bio_fd_should_retry(ret)) { + BIO_set_flags(bio, (BIO_FLAGS_IO_SPECIAL | BIO_FLAGS_SHOULD_RETRY)); + c->state = BIO_CONN_S_BLOCKED_CONNECT; + bio->retry_reason = BIO_RR_CONNECT; + } else { + OPENSSL_PUT_SYSTEM_ERROR(connect); + OPENSSL_PUT_ERROR(BIO, BIO_R_CONNECT_ERROR); + ERR_add_error_data(4, "host=", c->param_hostname, ":", + c->param_port); + } + goto exit_loop; + } else { + c->state = BIO_CONN_S_OK; + } + break; + + case BIO_CONN_S_BLOCKED_CONNECT: + i = bio_sock_error(bio->num); + if (i) { + if (bio_fd_should_retry(ret)) { + BIO_set_flags(bio, (BIO_FLAGS_IO_SPECIAL | BIO_FLAGS_SHOULD_RETRY)); + c->state = BIO_CONN_S_BLOCKED_CONNECT; + bio->retry_reason = BIO_RR_CONNECT; + ret = -1; + } else { + BIO_clear_retry_flags(bio); + OPENSSL_PUT_SYSTEM_ERROR(connect); + OPENSSL_PUT_ERROR(BIO, BIO_R_NBIO_CONNECT_ERROR); + ERR_add_error_data(4, "host=", c->param_hostname, ":", c->param_port); + ret = 0; + } + goto exit_loop; + } else { + c->state = BIO_CONN_S_OK; + } + break; + + case BIO_CONN_S_OK: + ret = 1; + goto exit_loop; + default: + assert(0); + goto exit_loop; + } + + if (cb != NULL) { + ret = cb((BIO *)bio, c->state, ret); + if (ret == 0) { + goto end; + } + } + } + +exit_loop: + if (cb != NULL) { + ret = cb((BIO *)bio, c->state, ret); + } + +end: + return ret; +} + +static BIO_CONNECT *BIO_CONNECT_new(void) { + BIO_CONNECT *ret = OPENSSL_malloc(sizeof(BIO_CONNECT)); + + if (ret == NULL) { + return NULL; + } + memset(ret, 0, sizeof(BIO_CONNECT)); + + ret->state = BIO_CONN_S_BEFORE; + return ret; +} + +static void BIO_CONNECT_free(BIO_CONNECT *c) { + if (c == NULL) { + return; + } + + OPENSSL_free(c->param_hostname); + OPENSSL_free(c->param_port); + OPENSSL_free(c); +} + +static int conn_new(BIO *bio) { + bio->init = 0; + bio->num = -1; + bio->flags = 0; + bio->ptr = (char *)BIO_CONNECT_new(); + return bio->ptr != NULL; +} + +static void conn_close_socket(BIO *bio) { + BIO_CONNECT *c = (BIO_CONNECT *) bio->ptr; + + if (bio->num == -1) { + return; + } + + /* Only do a shutdown if things were established */ + if (c->state == BIO_CONN_S_OK) { + shutdown(bio->num, 2); + } + closesocket(bio->num); + bio->num = -1; +} + +static int conn_free(BIO *bio) { + if (bio == NULL) { + return 0; + } + + if (bio->shutdown) { + conn_close_socket(bio); + } + + BIO_CONNECT_free((BIO_CONNECT*) bio->ptr); + + return 1; +} + +static int conn_read(BIO *bio, char *out, int out_len) { + int ret = 0; + BIO_CONNECT *data; + + data = (BIO_CONNECT *)bio->ptr; + if (data->state != BIO_CONN_S_OK) { + ret = conn_state(bio, data); + if (ret <= 0) { + return ret; + } + } + + bio_clear_socket_error(); + ret = recv(bio->num, out, out_len, 0); + BIO_clear_retry_flags(bio); + if (ret <= 0) { + if (bio_fd_should_retry(ret)) { + BIO_set_retry_read(bio); + } + } + + return ret; +} + +static int conn_write(BIO *bio, const char *in, int in_len) { + int ret; + BIO_CONNECT *data; + + data = (BIO_CONNECT *)bio->ptr; + if (data->state != BIO_CONN_S_OK) { + ret = conn_state(bio, data); + if (ret <= 0) { + return ret; + } + } + + bio_clear_socket_error(); + ret = send(bio->num, in, in_len, 0); + BIO_clear_retry_flags(bio); + if (ret <= 0) { + if (bio_fd_should_retry(ret)) { + BIO_set_retry_write(bio); + } + } + + return ret; +} + +static long conn_ctrl(BIO *bio, int cmd, long num, void *ptr) { + int *ip; + const char **pptr; + long ret = 1; + BIO_CONNECT *data; + + data = (BIO_CONNECT *)bio->ptr; + + switch (cmd) { + case BIO_CTRL_RESET: + ret = 0; + data->state = BIO_CONN_S_BEFORE; + conn_close_socket(bio); + bio->flags = 0; + break; + case BIO_C_DO_STATE_MACHINE: + /* use this one to start the connection */ + if (data->state != BIO_CONN_S_OK) { + ret = (long)conn_state(bio, data); + } else { + ret = 1; + } + break; + case BIO_C_GET_CONNECT: + /* TODO(fork): can this be removed? (Or maybe this whole file). */ + if (ptr != NULL) { + pptr = (const char **)ptr; + if (num == 0) { + *pptr = data->param_hostname; + } else if (num == 1) { + *pptr = data->param_port; + } else if (num == 2) { + *pptr = (char *) &data->ip[0]; + } else if (num == 3) { + *((int *)ptr) = data->port; + } + if (!bio->init) { + *pptr = "not initialized"; + } + ret = 1; + } + break; + case BIO_C_SET_CONNECT: + if (ptr != NULL) { + bio->init = 1; + if (num == 0) { + OPENSSL_free(data->param_hostname); + data->param_hostname = BUF_strdup(ptr); + if (data->param_hostname == NULL) { + ret = 0; + } + } else if (num == 1) { + OPENSSL_free(data->param_port); + data->param_port = BUF_strdup(ptr); + if (data->param_port == NULL) { + ret = 0; + } + } else { + ret = 0; + } + } + break; + case BIO_C_SET_NBIO: + data->nbio = (int)num; + break; + case BIO_C_GET_FD: + if (bio->init) { + ip = (int *)ptr; + if (ip != NULL) { + *ip = bio->num; + } + ret = 1; + } else { + ret = 0; + } + break; + case BIO_CTRL_GET_CLOSE: + ret = bio->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + bio->shutdown = (int)num; + break; + case BIO_CTRL_PENDING: + case BIO_CTRL_WPENDING: + ret = 0; + break; + case BIO_CTRL_FLUSH: + break; + case BIO_CTRL_SET_CALLBACK: { +#if 0 /* FIXME: Should this be used? -- Richard Levitte */ + OPENSSL_PUT_ERROR(BIO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + ret = -1; +#else + ret = 0; +#endif + } break; + case BIO_CTRL_GET_CALLBACK: { + int (**fptr)(const BIO *bio, int state, int xret); + fptr = (int (**)(const BIO *bio, int state, int xret))ptr; + *fptr = data->info_callback; + } break; + default: + ret = 0; + break; + } + return (ret); +} + +static long conn_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) { + long ret = 1; + BIO_CONNECT *data; + + data = (BIO_CONNECT *)bio->ptr; + + switch (cmd) { + case BIO_CTRL_SET_CALLBACK: { + data->info_callback = (int (*)(const struct bio_st *, int, int))fp; + } break; + default: + ret = 0; + break; + } + return ret; +} + +static int conn_puts(BIO *bp, const char *str) { + return conn_write(bp, str, strlen(str)); +} + +BIO *BIO_new_connect(const char *hostname) { + BIO *ret; + + ret = BIO_new(BIO_s_connect()); + if (ret == NULL) { + return NULL; + } + if (!BIO_set_conn_hostname(ret, hostname)) { + BIO_free(ret); + return NULL; + } + return ret; +} + +static const BIO_METHOD methods_connectp = { + BIO_TYPE_CONNECT, "socket connect", conn_write, conn_read, + conn_puts, NULL /* connect_gets, */, conn_ctrl, conn_new, + conn_free, conn_callback_ctrl, +}; + +const BIO_METHOD *BIO_s_connect(void) { return &methods_connectp; } + +int BIO_set_conn_hostname(BIO *bio, const char *name) { + return BIO_ctrl(bio, BIO_C_SET_CONNECT, 0, (void*) name); +} + +int BIO_set_conn_port(BIO *bio, const char *port_str) { + return BIO_ctrl(bio, BIO_C_SET_CONNECT, 1, (void*) port_str); +} + +int BIO_set_nbio(BIO *bio, int on) { + return BIO_ctrl(bio, BIO_C_SET_NBIO, on, NULL); +} diff --git a/TMessagesProj/jni/boringssl/crypto/bio/fd.c b/TMessagesProj/jni/boringssl/crypto/bio/fd.c new file mode 100644 index 00000000..0b5baca9 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bio/fd.c @@ -0,0 +1,270 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#if !defined(OPENSSL_WINDOWS) +#include +#else +#include +#pragma warning(push, 3) +#include +#pragma warning(pop) +#endif + +#include +#include +#include + + +static int bio_fd_non_fatal_error(int err) { + if ( +#ifdef EWOULDBLOCK + err == EWOULDBLOCK || +#endif +#ifdef WSAEWOULDBLOCK + err == WSAEWOULDBLOCK || +#endif +#ifdef ENOTCONN + err == ENOTCONN || +#endif +#ifdef EINTR + err == EINTR || +#endif +#ifdef EAGAIN + err == EAGAIN || +#endif +#ifdef EPROTO + err == EPROTO || +#endif +#ifdef EINPROGRESS + err == EINPROGRESS || +#endif +#ifdef EALREADY + err == EALREADY || +#endif + 0) { + return 1; + } + return 0; +} + +#if defined(OPENSSL_WINDOWS) +int bio_fd_should_retry(int i) { + if (i == -1) { + return bio_fd_non_fatal_error((int)GetLastError()); + } + return 0; +} +#else +int bio_fd_should_retry(int i) { + if (i == -1) { + return bio_fd_non_fatal_error(errno); + } + return 0; +} +#endif + +BIO *BIO_new_fd(int fd, int close_flag) { + BIO *ret = BIO_new(BIO_s_fd()); + if (ret == NULL) { + return NULL; + } + BIO_set_fd(ret, fd, close_flag); + return ret; +} + +static int fd_new(BIO *bio) { + /* num is used to store the file descriptor. */ + bio->num = -1; + return 1; +} + +static int fd_free(BIO *bio) { + if (bio == NULL) { + return 0; + } + + if (bio->shutdown) { + if (bio->init) { + close(bio->num); + } + bio->init = 0; + } + return 1; +} + +static int fd_read(BIO *b, char *out, int outl) { + int ret = 0; + + ret = read(b->num, out, outl); + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (bio_fd_should_retry(ret)) { + BIO_set_retry_read(b); + } + } + + return ret; +} + +static int fd_write(BIO *b, const char *in, int inl) { + int ret = write(b->num, in, inl); + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (bio_fd_should_retry(ret)) { + BIO_set_retry_write(b); + } + } + + return ret; +} + +static long fd_ctrl(BIO *b, int cmd, long num, void *ptr) { + long ret = 1; + int *ip; + + switch (cmd) { + case BIO_CTRL_RESET: + num = 0; + case BIO_C_FILE_SEEK: + ret = 0; + if (b->init) { + ret = (long)lseek(b->num, num, SEEK_SET); + } + break; + case BIO_C_FILE_TELL: + case BIO_CTRL_INFO: + ret = 0; + if (b->init) { + ret = (long)lseek(b->num, 0, SEEK_CUR); + } + break; + case BIO_C_SET_FD: + fd_free(b); + b->num = *((int *)ptr); + b->shutdown = (int)num; + b->init = 1; + break; + case BIO_C_GET_FD: + if (b->init) { + ip = (int *)ptr; + if (ip != NULL) { + *ip = b->num; + } + return 1; + } else { + ret = 0; + } + break; + case BIO_CTRL_GET_CLOSE: + ret = b->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + b->shutdown = (int)num; + break; + case BIO_CTRL_PENDING: + case BIO_CTRL_WPENDING: + ret = 0; + break; + case BIO_CTRL_FLUSH: + ret = 1; + break; + default: + ret = 0; + break; + } + + return ret; +} + +static int fd_puts(BIO *bp, const char *str) { + return fd_write(bp, str, strlen(str)); +} + +static int fd_gets(BIO *bp, char *buf, int size) { + char *ptr = buf; + char *end = buf + size - 1; + + if (size <= 0) { + return 0; + } + + while (ptr < end && fd_read(bp, ptr, 1) > 0 && ptr[0] != '\n') { + ptr++; + } + + ptr[0] = '\0'; + + return ptr - buf; +} + +static const BIO_METHOD methods_fdp = { + BIO_TYPE_FD, "file descriptor", fd_write, fd_read, fd_puts, + fd_gets, fd_ctrl, fd_new, fd_free, NULL, }; + +const BIO_METHOD *BIO_s_fd(void) { return &methods_fdp; } + +int BIO_set_fd(BIO *bio, int fd, int close_flag) { + return BIO_int_ctrl(bio, BIO_C_SET_FD, close_flag, fd); +} + +int BIO_get_fd(BIO *bio, int *out_fd) { + return BIO_ctrl(bio, BIO_C_GET_FD, 0, (char *) out_fd); +} diff --git a/TMessagesProj/jni/boringssl/crypto/bio/file.c b/TMessagesProj/jni/boringssl/crypto/bio/file.c new file mode 100644 index 00000000..cef33b66 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bio/file.c @@ -0,0 +1,350 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#if defined(__linux) || defined(__sun) || defined(__hpux) +/* Following definition aliases fopen to fopen64 on above mentioned + * platforms. This makes it possible to open and sequentially access + * files larger than 2GB from 32-bit application. It does not allow to + * traverse them beyond 2GB with fseek/ftell, but on the other hand *no* + * 32-bit platform permits that, not with fseek/ftell. Not to mention + * that breaking 2GB limit for seeking would require surgery to *our* + * API. But sequential access suffices for practical cases when you + * can run into large files, such as fingerprinting, so we can let API + * alone. For reference, the list of 32-bit platforms which allow for + * sequential access of large files without extra "magic" comprise *BSD, + * Darwin, IRIX... + */ +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif +#endif + +#include + +#include +#include +#include + +#include +#include +#include + + +#define BIO_FP_READ 0x02 +#define BIO_FP_WRITE 0x04 +#define BIO_FP_APPEND 0x08 + +static FILE *open_file(const char *filename, const char *mode) { +#if defined(OPENSSL_WINDOWS) && defined(CP_UTF8) + int sz, len_0 = (int)strlen(filename) + 1; + DWORD flags; + + /* Basically there are three cases to cover: a) filename is pure ASCII + * string; b) actual UTF-8 encoded string and c) locale-ized string, i.e. one + * containing 8-bit characters that are meaningful in current system locale. + * If filename is pure ASCII or real UTF-8 encoded string, + * MultiByteToWideChar succeeds and _wfopen works. If filename is locale-ized + * string, chances are that MultiByteToWideChar fails reporting + * ERROR_NO_UNICODE_TRANSLATION, in which case we fall back to fopen... */ + if ((sz = MultiByteToWideChar(CP_UTF8, (flags = MB_ERR_INVALID_CHARS), + filename, len_0, NULL, 0)) > 0 || + (GetLastError() == ERROR_INVALID_FLAGS && + (sz = MultiByteToWideChar(CP_UTF8, (flags = 0), filename, len_0, NULL, + 0)) > 0)) { + WCHAR wmode[8]; + WCHAR *wfilename = _alloca(sz * sizeof(WCHAR)); + + if (MultiByteToWideChar(CP_UTF8, flags, filename, len_0, wfilename, sz) && + MultiByteToWideChar(CP_UTF8, 0, mode, strlen(mode) + 1, wmode, + sizeof(wmode) / sizeof(wmode[0])) && + (file = _wfopen(wfilename, wmode)) == NULL && + (errno == ENOENT || + errno == EBADF)) /* UTF-8 decode succeeded, but no file, filename + * could still have been locale-ized... */ + return fopen(filename, mode); + } else if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION) { + return fopen(filename, mode); + } +#else + return fopen(filename, mode); +#endif +} + +BIO *BIO_new_file(const char *filename, const char *mode) { + BIO *ret; + FILE *file; + + file = open_file(filename, mode); + if (file == NULL) { + OPENSSL_PUT_SYSTEM_ERROR(fopen); + + ERR_add_error_data(5, "fopen('", filename, "','", mode, "')"); + if (errno == ENOENT) { + OPENSSL_PUT_ERROR(BIO, BIO_R_NO_SUCH_FILE); + } else { + OPENSSL_PUT_ERROR(BIO, BIO_R_SYS_LIB); + } + return NULL; + } + + ret = BIO_new(BIO_s_file()); + if (ret == NULL) { + fclose(file); + return NULL; + } + + BIO_set_fp(ret, file, BIO_CLOSE); + return ret; +} + +BIO *BIO_new_fp(FILE *stream, int close_flag) { + BIO *ret = BIO_new(BIO_s_file()); + + if (ret == NULL) { + return NULL; + } + + BIO_set_fp(ret, stream, close_flag); + return ret; +} + +static int file_new(BIO *bio) { return 1; } + +static int file_free(BIO *bio) { + if (bio == NULL) { + return 0; + } + + if (!bio->shutdown) { + return 1; + } + + if (bio->init && bio->ptr != NULL) { + fclose(bio->ptr); + bio->ptr = NULL; + } + bio->init = 0; + + return 1; +} + +static int file_read(BIO *b, char *out, int outl) { + int ret = 0; + + if (!b->init) { + return 0; + } + + ret = fread(out, 1, outl, (FILE *)b->ptr); + if (ret == 0 && ferror((FILE *)b->ptr)) { + OPENSSL_PUT_SYSTEM_ERROR(fread); + OPENSSL_PUT_ERROR(BIO, ERR_R_SYS_LIB); + ret = -1; + } + + return ret; +} + +static int file_write(BIO *b, const char *in, int inl) { + int ret = 0; + + if (!b->init) { + return 0; + } + + ret = fwrite(in, inl, 1, (FILE *)b->ptr); + if (ret > 0) { + ret = inl; + } + return ret; +} + +static long file_ctrl(BIO *b, int cmd, long num, void *ptr) { + long ret = 1; + FILE *fp = (FILE *)b->ptr; + FILE **fpp; + char p[4]; + + switch (cmd) { + case BIO_CTRL_RESET: + num = 0; + case BIO_C_FILE_SEEK: + ret = (long)fseek(fp, num, 0); + break; + case BIO_CTRL_EOF: + ret = (long)feof(fp); + break; + case BIO_C_FILE_TELL: + case BIO_CTRL_INFO: + ret = ftell(fp); + break; + case BIO_C_SET_FILE_PTR: + file_free(b); + b->shutdown = (int)num & BIO_CLOSE; + b->ptr = ptr; + b->init = 1; + break; + case BIO_C_SET_FILENAME: + file_free(b); + b->shutdown = (int)num & BIO_CLOSE; + if (num & BIO_FP_APPEND) { + if (num & BIO_FP_READ) { + BUF_strlcpy(p, "a+", sizeof(p)); + } else { + BUF_strlcpy(p, "a", sizeof(p)); + } + } else if ((num & BIO_FP_READ) && (num & BIO_FP_WRITE)) { + BUF_strlcpy(p, "r+", sizeof(p)); + } else if (num & BIO_FP_WRITE) { + BUF_strlcpy(p, "w", sizeof(p)); + } else if (num & BIO_FP_READ) { + BUF_strlcpy(p, "r", sizeof(p)); + } else { + OPENSSL_PUT_ERROR(BIO, BIO_R_BAD_FOPEN_MODE); + ret = 0; + break; + } + fp = open_file(ptr, p); + if (fp == NULL) { + OPENSSL_PUT_SYSTEM_ERROR(fopen); + ERR_add_error_data(5, "fopen('", ptr, "','", p, "')"); + OPENSSL_PUT_ERROR(BIO, ERR_R_SYS_LIB); + ret = 0; + break; + } + b->ptr = fp; + b->init = 1; + break; + case BIO_C_GET_FILE_PTR: + /* the ptr parameter is actually a FILE ** in this case. */ + if (ptr != NULL) { + fpp = (FILE **)ptr; + *fpp = (FILE *)b->ptr; + } + break; + case BIO_CTRL_GET_CLOSE: + ret = (long)b->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + b->shutdown = (int)num; + break; + case BIO_CTRL_FLUSH: + ret = 0 == fflush((FILE *)b->ptr); + break; + case BIO_CTRL_WPENDING: + case BIO_CTRL_PENDING: + default: + ret = 0; + break; + } + return ret; +} + +static int file_gets(BIO *bp, char *buf, int size) { + int ret = 0; + + if (size == 0) { + return 0; + } + + if (!fgets(buf, size, (FILE *)bp->ptr)) { + buf[0] = 0; + goto err; + } + ret = strlen(buf); + +err: + return ret; +} + +static int file_puts(BIO *bp, const char *str) { + return file_write(bp, str, strlen(str)); +} + +static const BIO_METHOD methods_filep = { + BIO_TYPE_FILE, "FILE pointer", file_write, file_read, file_puts, + file_gets, file_ctrl, file_new, file_free, NULL, }; + +const BIO_METHOD *BIO_s_file(void) { return &methods_filep; } + + +int BIO_get_fp(BIO *bio, FILE **out_file) { + return BIO_ctrl(bio, BIO_C_GET_FILE_PTR, 0, (char*) out_file); +} + +int BIO_set_fp(BIO *bio, FILE *file, int close_flag) { + return BIO_ctrl(bio, BIO_C_SET_FILE_PTR, close_flag, (char *) file); +} + +int BIO_read_filename(BIO *bio, const char *filename) { + return BIO_ctrl(bio, BIO_C_SET_FILENAME, BIO_CLOSE | BIO_FP_READ, + (char *)filename); +} + +int BIO_write_filename(BIO *bio, const char *filename) { + return BIO_ctrl(bio, BIO_C_SET_FILENAME, BIO_CLOSE | BIO_FP_WRITE, + (char *)filename); +} + +int BIO_append_filename(BIO *bio, const char *filename) { + return BIO_ctrl(bio, BIO_C_SET_FILENAME, BIO_CLOSE | BIO_FP_APPEND, + (char *)filename); +} + +int BIO_rw_filename(BIO *bio, const char *filename) { + return BIO_ctrl(bio, BIO_C_SET_FILENAME, + BIO_CLOSE | BIO_FP_READ | BIO_FP_WRITE, (char *)filename); +} diff --git a/TMessagesProj/jni/boringssl/crypto/bio/hexdump.c b/TMessagesProj/jni/boringssl/crypto/bio/hexdump.c new file mode 100644 index 00000000..17f55183 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bio/hexdump.c @@ -0,0 +1,192 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + +/* hexdump_ctx contains the state of a hexdump. */ +struct hexdump_ctx { + BIO *bio; + char right_chars[18]; /* the contents of the right-hand side, ASCII dump. */ + unsigned used; /* number of bytes in the current line. */ + size_t n; /* number of bytes total. */ + unsigned indent; +}; + +static void hexbyte(char *out, uint8_t b) { + static const char hextable[] = "0123456789abcdef"; + out[0] = hextable[b>>4]; + out[1] = hextable[b&0x0f]; +} + +static char to_char(uint8_t b) { + if (b < 32 || b > 126) { + return '.'; + } + return b; +} + +/* hexdump_write adds |len| bytes of |data| to the current hex dump described by + * |ctx|. */ +static int hexdump_write(struct hexdump_ctx *ctx, const uint8_t *data, + size_t len) { + size_t i; + char buf[10]; + unsigned l; + + /* Output lines look like: + * 00000010 2e 2f 30 31 32 33 34 35 36 37 38 ... 3c 3d // |./0123456789:;<=| + * ^ offset ^ extra space ^ ASCII of line + */ + + for (i = 0; i < len; i++) { + if (ctx->used == 0) { + /* The beginning of a line. */ + BIO_indent(ctx->bio, ctx->indent, UINT_MAX); + + hexbyte(&buf[0], ctx->n >> 24); + hexbyte(&buf[2], ctx->n >> 16); + hexbyte(&buf[4], ctx->n >> 8); + hexbyte(&buf[6], ctx->n); + buf[8] = buf[9] = ' '; + if (BIO_write(ctx->bio, buf, 10) < 0) { + return 0; + } + } + + hexbyte(buf, data[i]); + buf[2] = ' '; + l = 3; + if (ctx->used == 7) { + /* There's an additional space after the 8th byte. */ + buf[3] = ' '; + l = 4; + } else if (ctx->used == 15) { + /* At the end of the line there's an extra space and the bar for the + * right column. */ + buf[3] = ' '; + buf[4] = '|'; + l = 5; + } + + if (BIO_write(ctx->bio, buf, l) < 0) { + return 0; + } + ctx->right_chars[ctx->used] = to_char(data[i]); + ctx->used++; + ctx->n++; + if (ctx->used == 16) { + ctx->right_chars[16] = '|'; + ctx->right_chars[17] = '\n'; + if (BIO_write(ctx->bio, ctx->right_chars, sizeof(ctx->right_chars)) < 0) { + return 0; + } + ctx->used = 0; + } + } + + return 1; +} + +/* finish flushes any buffered data in |ctx|. */ +static int finish(struct hexdump_ctx *ctx) { + /* See the comments in |hexdump| for the details of this format. */ + const unsigned n_bytes = ctx->used; + unsigned l; + char buf[5]; + + if (n_bytes == 0) { + return 1; + } + + memset(buf, ' ', 4); + buf[4] = '|'; + + for (; ctx->used < 16; ctx->used++) { + l = 3; + if (ctx->used == 7) { + l = 4; + } else if (ctx->used == 15) { + l = 5; + } + if (BIO_write(ctx->bio, buf, l) < 0) { + return 0; + } + } + + ctx->right_chars[n_bytes] = '|'; + ctx->right_chars[n_bytes + 1] = '\n'; + if (BIO_write(ctx->bio, ctx->right_chars, n_bytes + 2) < 0) { + return 0; + } + return 1; +} + +int BIO_hexdump(BIO *bio, const uint8_t *data, size_t len, unsigned indent) { + struct hexdump_ctx ctx; + memset(&ctx, 0, sizeof(ctx)); + ctx.bio = bio; + ctx.indent = indent; + + if (!hexdump_write(&ctx, data, len) || !finish(&ctx)) { + return 0; + } + + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bio/internal.h b/TMessagesProj/jni/boringssl/crypto/bio/internal.h new file mode 100644 index 00000000..d9a34f18 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bio/internal.h @@ -0,0 +1,108 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_BIO_INTERNAL_H +#define OPENSSL_HEADER_BIO_INTERNAL_H + +#include + +#if !defined(OPENSSL_WINDOWS) +#if defined(OPENSSL_PNACL) +/* newlib uses u_short in socket.h without defining it. */ +typedef unsigned short u_short; +#endif +#include +#include +#else +typedef int socklen_t; +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* BIO_ip_and_port_to_socket_and_addr creates a socket and fills in |*out_addr| + * and |*out_addr_length| with the correct values for connecting to |hostname| + * on |port_str|. It returns one on success or zero on error. */ +int bio_ip_and_port_to_socket_and_addr(int *out_sock, + struct sockaddr_storage *out_addr, + socklen_t *out_addr_length, + const char *hostname, + const char *port_str); + +/* BIO_socket_nbio sets whether |sock| is non-blocking. It returns one on + * success and zero otherwise. */ +int bio_socket_nbio(int sock, int on); + +/* BIO_clear_socket_error clears the last system socket error. + * + * TODO(fork): remove all callers of this. */ +void bio_clear_socket_error(void); + +/* BIO_sock_error returns the last socket error on |sock|. */ +int bio_sock_error(int sock); + +/* BIO_fd_should_retry returns non-zero if |return_value| indicates an error + * and |errno| indicates that it's non-fatal. */ +int bio_fd_should_retry(int return_value); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_BIO_INTERNAL_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/bio/pair.c b/TMessagesProj/jni/boringssl/crypto/bio/pair.c new file mode 100644 index 00000000..6f788903 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bio/pair.c @@ -0,0 +1,803 @@ +/* ==================================================================== + * Copyright (c) 1998-2003 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include + +#include +#include +#include + + +struct bio_bio_st { + BIO *peer; /* NULL if buf == NULL. + * If peer != NULL, then peer->ptr is also a bio_bio_st, + * and its "peer" member points back to us. + * peer != NULL iff init != 0 in the BIO. */ + + /* This is for what we write (i.e. reading uses peer's struct): */ + int closed; /* valid iff peer != NULL */ + size_t len; /* valid iff buf != NULL; 0 if peer == NULL */ + size_t offset; /* valid iff buf != NULL; 0 if len == 0 */ + size_t size; + uint8_t *buf; /* "size" elements (if != NULL) */ + char buf_externally_allocated; /* true iff buf was externally allocated. */ + + char zero_copy_read_lock; /* true iff a zero copy read operation + * is in progress. */ + char zero_copy_write_lock; /* true iff a zero copy write operation + * is in progress. */ + + size_t request; /* valid iff peer != NULL; 0 if len != 0, + * otherwise set by peer to number of bytes + * it (unsuccessfully) tried to read, + * never more than buffer space (size-len) warrants. */ +}; + +static int bio_new(BIO *bio) { + struct bio_bio_st *b; + + b = OPENSSL_malloc(sizeof *b); + if (b == NULL) { + return 0; + } + memset(b, 0, sizeof(struct bio_bio_st)); + + b->size = 17 * 1024; /* enough for one TLS record (just a default) */ + bio->ptr = b; + return 1; +} + +static void bio_destroy_pair(BIO *bio) { + struct bio_bio_st *b = bio->ptr; + BIO *peer_bio; + struct bio_bio_st *peer_b; + + if (b == NULL) { + return; + } + + peer_bio = b->peer; + if (peer_bio == NULL) { + return; + } + + peer_b = peer_bio->ptr; + + assert(peer_b != NULL); + assert(peer_b->peer == bio); + + peer_b->peer = NULL; + peer_bio->init = 0; + assert(peer_b->buf != NULL); + peer_b->len = 0; + peer_b->offset = 0; + + b->peer = NULL; + bio->init = 0; + assert(b->buf != NULL); + b->len = 0; + b->offset = 0; +} + +static int bio_free(BIO *bio) { + struct bio_bio_st *b; + + if (bio == NULL) { + return 0; + } + b = bio->ptr; + + assert(b != NULL); + + if (b->peer) { + bio_destroy_pair(bio); + } + + if (!b->buf_externally_allocated) { + OPENSSL_free(b->buf); + } + + OPENSSL_free(b); + + return 1; +} + +static size_t bio_zero_copy_get_read_buf(struct bio_bio_st* peer_b, + uint8_t** out_read_buf, + size_t* out_buf_offset) { + size_t max_available; + if (peer_b->len > peer_b->size - peer_b->offset) { + /* Only the first half of the ring buffer can be read. */ + max_available = peer_b->size - peer_b->offset; + } else { + max_available = peer_b->len; + } + + *out_read_buf = peer_b->buf; + *out_buf_offset = peer_b->offset; + return max_available; +} + +int BIO_zero_copy_get_read_buf(BIO* bio, uint8_t** out_read_buf, + size_t* out_buf_offset, + size_t* out_available_bytes) { + struct bio_bio_st* b; + struct bio_bio_st* peer_b; + size_t max_available; + *out_available_bytes = 0; + + BIO_clear_retry_flags(bio); + + if (!bio->init) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED); + return 0; + } + + b = bio->ptr; + + if (!b || !b->peer) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); + return 0; + } + + peer_b = b->peer->ptr; + if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); + return 0; + } + + if (peer_b->zero_copy_read_lock) { + OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT); + return 0; + } + + peer_b->request = 0; /* Is not used by zero-copy API. */ + + max_available = + bio_zero_copy_get_read_buf(peer_b, out_read_buf, out_buf_offset); + + assert(peer_b->buf != NULL); + if (max_available > 0) { + peer_b->zero_copy_read_lock = 1; + } + + *out_available_bytes = max_available; + return 1; +} + +int BIO_zero_copy_get_read_buf_done(BIO* bio, size_t bytes_read) { + struct bio_bio_st* b; + struct bio_bio_st* peer_b; + size_t max_available; + size_t dummy_read_offset; + uint8_t* dummy_read_buf; + + assert(BIO_get_retry_flags(bio) == 0); + + if (!bio->init) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED); + return 0; + } + + b = bio->ptr; + + if (!b || !b->peer) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); + return 0; + } + + peer_b = b->peer->ptr; + if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); + return 0; + } + + if (!peer_b->zero_copy_read_lock) { + OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT); + return 0; + } + + max_available = + bio_zero_copy_get_read_buf(peer_b, &dummy_read_buf, &dummy_read_offset); + if (bytes_read > max_available) { + OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT); + return 0; + } + + peer_b->len -= bytes_read; + assert(peer_b->len >= 0); + assert(peer_b->offset + bytes_read <= peer_b->size); + + /* Move read offset. If zero_copy_write_lock == 1 we must advance the + * offset even if buffer becomes empty, to make sure + * write_offset = (offset + len) mod size does not change. */ + if (peer_b->offset + bytes_read == peer_b->size || + (!peer_b->zero_copy_write_lock && peer_b->len == 0)) { + peer_b->offset = 0; + } else { + peer_b->offset += bytes_read; + } + + bio->num_read += bytes_read; + peer_b->zero_copy_read_lock = 0; + return 1; +} + +static size_t bio_zero_copy_get_write_buf(struct bio_bio_st* b, + uint8_t** out_write_buf, + size_t* out_buf_offset) { + size_t write_offset; + size_t max_available; + + assert(b->len <= b->size); + + write_offset = b->offset + b->len; + + if (write_offset >= b->size) { + /* Only the first half of the ring buffer can be written to. */ + write_offset -= b->size; + /* write up to the start of the ring buffer. */ + max_available = b->offset - write_offset; + } else { + /* write up to the end the buffer. */ + max_available = b->size - write_offset; + } + + *out_write_buf = b->buf; + *out_buf_offset = write_offset; + return max_available; +} + +int BIO_zero_copy_get_write_buf(BIO* bio, uint8_t** out_write_buf, + size_t* out_buf_offset, + size_t* out_available_bytes) { + struct bio_bio_st* b; + struct bio_bio_st* peer_b; + size_t max_available; + + *out_available_bytes = 0; + BIO_clear_retry_flags(bio); + + if (!bio->init) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED); + return 0; + } + + b = bio->ptr; + + if (!b || !b->buf || !b->peer) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); + return 0; + } + peer_b = b->peer->ptr; + if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); + return 0; + } + + assert(b->buf != NULL); + + if (b->zero_copy_write_lock) { + OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT); + return 0; + } + + b->request = 0; + if (b->closed) { + /* Bio is already closed. */ + OPENSSL_PUT_ERROR(BIO, BIO_R_BROKEN_PIPE); + return 0; + } + + max_available = bio_zero_copy_get_write_buf(b, out_write_buf, out_buf_offset); + + if (max_available > 0) { + b->zero_copy_write_lock = 1; + } + + *out_available_bytes = max_available; + return 1; +} + +int BIO_zero_copy_get_write_buf_done(BIO* bio, size_t bytes_written) { + struct bio_bio_st* b; + struct bio_bio_st* peer_b; + + size_t rest; + size_t dummy_write_offset; + uint8_t* dummy_write_buf; + + if (!bio->init) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED); + return 0; + } + + b = bio->ptr; + + if (!b || !b->buf || !b->peer) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); + return 0; + } + peer_b = b->peer->ptr; + if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); + return 0; + } + + b->request = 0; + if (b->closed) { + /* BIO is already closed. */ + OPENSSL_PUT_ERROR(BIO, BIO_R_BROKEN_PIPE); + return 0; + } + + if (!b->zero_copy_write_lock) { + OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT); + return 0; + } + + rest = bio_zero_copy_get_write_buf(b, &dummy_write_buf, &dummy_write_offset); + + if (bytes_written > rest) { + OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT); + return 0; + } + + bio->num_write += bytes_written; + /* Move write offset. */ + b->len += bytes_written; + b->zero_copy_write_lock = 0; + return 1; +} + +static int bio_read(BIO *bio, char *buf, int size_) { + size_t size = size_; + size_t rest; + struct bio_bio_st *b, *peer_b; + + BIO_clear_retry_flags(bio); + + if (!bio->init) { + return 0; + } + + b = bio->ptr; + assert(b != NULL); + assert(b->peer != NULL); + peer_b = b->peer->ptr; + assert(peer_b != NULL); + assert(peer_b->buf != NULL); + + peer_b->request = 0; /* will be set in "retry_read" situation */ + + if (buf == NULL || size == 0 || peer_b->zero_copy_read_lock) { + return 0; + } + + if (peer_b->len == 0) { + if (peer_b->closed) { + return 0; /* writer has closed, and no data is left */ + } else { + BIO_set_retry_read(bio); /* buffer is empty */ + if (size <= peer_b->size) { + peer_b->request = size; + } else { + /* don't ask for more than the peer can + * deliver in one write */ + peer_b->request = peer_b->size; + } + return -1; + } + } + + /* we can read */ + if (peer_b->len < size) { + size = peer_b->len; + } + + /* now read "size" bytes */ + rest = size; + + assert(rest > 0); + /* one or two iterations */ + do { + size_t chunk; + + assert(rest <= peer_b->len); + if (peer_b->offset + rest <= peer_b->size) { + chunk = rest; + } else { + /* wrap around ring buffer */ + chunk = peer_b->size - peer_b->offset; + } + assert(peer_b->offset + chunk <= peer_b->size); + + memcpy(buf, peer_b->buf + peer_b->offset, chunk); + + peer_b->len -= chunk; + /* If zero_copy_write_lock == 1 we must advance the offset even if buffer + * becomes empty, to make sure write_offset = (offset + len) % size + * does not change. */ + if (peer_b->len || peer_b->zero_copy_write_lock) { + peer_b->offset += chunk; + assert(peer_b->offset <= peer_b->size); + if (peer_b->offset == peer_b->size) { + peer_b->offset = 0; + } + buf += chunk; + } else { + /* buffer now empty, no need to advance "buf" */ + assert(chunk == rest); + peer_b->offset = 0; + } + rest -= chunk; + } while (rest); + + return size; +} + +static int bio_write(BIO *bio, const char *buf, int num_) { + size_t num = num_; + size_t rest; + struct bio_bio_st *b; + + BIO_clear_retry_flags(bio); + + if (!bio->init || buf == NULL || num == 0) { + return 0; + } + + b = bio->ptr; + assert(b != NULL); + assert(b->peer != NULL); + assert(b->buf != NULL); + + if (b->zero_copy_write_lock) { + return 0; + } + + b->request = 0; + if (b->closed) { + /* we already closed */ + OPENSSL_PUT_ERROR(BIO, BIO_R_BROKEN_PIPE); + return -1; + } + + assert(b->len <= b->size); + + if (b->len == b->size) { + BIO_set_retry_write(bio); /* buffer is full */ + return -1; + } + + /* we can write */ + if (num > b->size - b->len) { + num = b->size - b->len; + } + + /* now write "num" bytes */ + rest = num; + + assert(rest > 0); + /* one or two iterations */ + do { + size_t write_offset; + size_t chunk; + + assert(b->len + rest <= b->size); + + write_offset = b->offset + b->len; + if (write_offset >= b->size) { + write_offset -= b->size; + } + /* b->buf[write_offset] is the first byte we can write to. */ + + if (write_offset + rest <= b->size) { + chunk = rest; + } else { + /* wrap around ring buffer */ + chunk = b->size - write_offset; + } + + memcpy(b->buf + write_offset, buf, chunk); + + b->len += chunk; + + assert(b->len <= b->size); + + rest -= chunk; + buf += chunk; + } while (rest); + + return num; +} + +static int bio_make_pair(BIO* bio1, BIO* bio2, + size_t writebuf1_len, uint8_t* ext_writebuf1, + size_t writebuf2_len, uint8_t* ext_writebuf2) { + struct bio_bio_st *b1, *b2; + + assert(bio1 != NULL); + assert(bio2 != NULL); + + b1 = bio1->ptr; + b2 = bio2->ptr; + + if (b1->peer != NULL || b2->peer != NULL) { + OPENSSL_PUT_ERROR(BIO, BIO_R_IN_USE); + return 0; + } + + assert(b1->buf_externally_allocated == 0); + assert(b2->buf_externally_allocated == 0); + + if (b1->buf == NULL) { + if (writebuf1_len) { + b1->size = writebuf1_len; + } + if (!ext_writebuf1) { + b1->buf_externally_allocated = 0; + b1->buf = OPENSSL_malloc(b1->size); + if (b1->buf == NULL) { + OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE); + return 0; + } + } else { + b1->buf = ext_writebuf1; + b1->buf_externally_allocated = 1; + } + b1->len = 0; + b1->offset = 0; + } + + if (b2->buf == NULL) { + if (writebuf2_len) { + b2->size = writebuf2_len; + } + if (!ext_writebuf2) { + b2->buf_externally_allocated = 0; + b2->buf = OPENSSL_malloc(b2->size); + if (b2->buf == NULL) { + OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE); + return 0; + } + } else { + b2->buf = ext_writebuf2; + b2->buf_externally_allocated = 1; + } + b2->len = 0; + b2->offset = 0; + } + + b1->peer = bio2; + b1->closed = 0; + b1->request = 0; + b1->zero_copy_read_lock = 0; + b1->zero_copy_write_lock = 0; + b2->peer = bio1; + b2->closed = 0; + b2->request = 0; + b2->zero_copy_read_lock = 0; + b2->zero_copy_write_lock = 0; + + bio1->init = 1; + bio2->init = 1; + + return 1; +} + +static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr) { + long ret; + struct bio_bio_st *b = bio->ptr; + + assert(b != NULL); + + switch (cmd) { + /* specific CTRL codes */ + + case BIO_C_GET_WRITE_BUF_SIZE: + ret = (long)b->size; + break; + + case BIO_C_GET_WRITE_GUARANTEE: + /* How many bytes can the caller feed to the next write + * without having to keep any? */ + if (b->peer == NULL || b->closed) { + ret = 0; + } else { + ret = (long)b->size - b->len; + } + break; + + case BIO_C_GET_READ_REQUEST: + /* If the peer unsuccessfully tried to read, how many bytes + * were requested? (As with BIO_CTRL_PENDING, that number + * can usually be treated as boolean.) */ + ret = (long)b->request; + break; + + case BIO_C_RESET_READ_REQUEST: + /* Reset request. (Can be useful after read attempts + * at the other side that are meant to be non-blocking, + * e.g. when probing SSL_read to see if any data is + * available.) */ + b->request = 0; + ret = 1; + break; + + case BIO_C_SHUTDOWN_WR: + /* similar to shutdown(..., SHUT_WR) */ + b->closed = 1; + ret = 1; + break; + + /* standard CTRL codes follow */ + + case BIO_CTRL_GET_CLOSE: + ret = bio->shutdown; + break; + + case BIO_CTRL_SET_CLOSE: + bio->shutdown = (int)num; + ret = 1; + break; + + case BIO_CTRL_PENDING: + if (b->peer != NULL) { + struct bio_bio_st *peer_b = b->peer->ptr; + ret = (long)peer_b->len; + } else { + ret = 0; + } + break; + + case BIO_CTRL_WPENDING: + ret = 0; + if (b->buf != NULL) { + ret = (long)b->len; + } + break; + + case BIO_CTRL_FLUSH: + ret = 1; + break; + + case BIO_CTRL_EOF: { + BIO *other_bio = ptr; + + if (other_bio) { + struct bio_bio_st *other_b = other_bio->ptr; + assert(other_b != NULL); + ret = other_b->len == 0 && other_b->closed; + } else { + ret = 1; + } + } break; + + default: + ret = 0; + } + return ret; +} + +static int bio_puts(BIO *bio, const char *str) { + return bio_write(bio, str, strlen(str)); +} + +static const BIO_METHOD methods_biop = { + BIO_TYPE_BIO, "BIO pair", bio_write, bio_read, + bio_puts, NULL /* no bio_gets */, bio_ctrl, bio_new, + bio_free, NULL /* no bio_callback_ctrl */ +}; + +const BIO_METHOD *bio_s_bio(void) { return &methods_biop; } + +int BIO_new_bio_pair(BIO** bio1_p, size_t writebuf1, + BIO** bio2_p, size_t writebuf2) { + return BIO_new_bio_pair_external_buf(bio1_p, writebuf1, NULL, bio2_p, + writebuf2, NULL); +} + +int BIO_new_bio_pair_external_buf(BIO** bio1_p, size_t writebuf1_len, + uint8_t* ext_writebuf1, + BIO** bio2_p, size_t writebuf2_len, + uint8_t* ext_writebuf2) { + BIO *bio1 = NULL, *bio2 = NULL; + int ret = 0; + + /* External buffers must have sizes greater than 0. */ + if ((ext_writebuf1 && !writebuf1_len) || (ext_writebuf2 && !writebuf2_len)) { + goto err; + } + + bio1 = BIO_new(bio_s_bio()); + if (bio1 == NULL) { + goto err; + } + bio2 = BIO_new(bio_s_bio()); + if (bio2 == NULL) { + goto err; + } + + if (!bio_make_pair(bio1, bio2, writebuf1_len, ext_writebuf1, writebuf2_len, + ext_writebuf2)) { + goto err; + } + ret = 1; + +err: + if (ret == 0) { + BIO_free(bio1); + bio1 = NULL; + BIO_free(bio2); + bio2 = NULL; + } + + *bio1_p = bio1; + *bio2_p = bio2; + return ret; +} + +size_t BIO_ctrl_get_read_request(BIO *bio) { + return BIO_ctrl(bio, BIO_C_GET_READ_REQUEST, 0, NULL); +} + +size_t BIO_ctrl_get_write_guarantee(BIO *bio) { + return BIO_ctrl(bio, BIO_C_GET_WRITE_GUARANTEE, 0, NULL); +} + +int BIO_shutdown_wr(BIO *bio) { + return BIO_ctrl(bio, BIO_C_SHUTDOWN_WR, 0, NULL); +} diff --git a/TMessagesProj/jni/boringssl/crypto/bio/printf.c b/TMessagesProj/jni/boringssl/crypto/bio/printf.c new file mode 100644 index 00000000..2f5ae4a3 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bio/printf.c @@ -0,0 +1,115 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#if !defined(_POSIX_C_SOURCE) +#define _POSIX_C_SOURCE 201410L /* for snprintf, vprintf etc */ +#endif + +#include + +#include +#include +#include + +#include +#include + +int BIO_printf(BIO *bio, const char *format, ...) { + va_list args; + char buf[256], *out, out_malloced = 0; + int out_len, ret; + + va_start(args, format); + out_len = vsnprintf(buf, sizeof(buf), format, args); + va_end(args); + +#if defined(OPENSSL_WINDOWS) + /* On Windows, vsnprintf returns -1 rather than the requested length on + * truncation */ + if (out_len < 0) { + va_start(args, format); + out_len = _vscprintf(format, args); + va_end(args); + assert(out_len >= sizeof(buf)); + } +#endif + + if (out_len >= sizeof(buf)) { + const int requested_len = out_len; + /* The output was truncated. Note that vsnprintf's return value + * does not include a trailing NUL, but the buffer must be sized + * for it. */ + out = OPENSSL_malloc(requested_len + 1); + out_malloced = 1; + if (out == NULL) { + OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE); + return -1; + } + va_start(args, format); + out_len = vsnprintf(out, requested_len + 1, format, args); + va_end(args); + assert(out_len == requested_len); + } else { + out = buf; + } + + ret = BIO_write(bio, out, out_len); + if (out_malloced) { + OPENSSL_free(out); + } + + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bio/socket.c b/TMessagesProj/jni/boringssl/crypto/bio/socket.c new file mode 100644 index 00000000..98f32a62 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bio/socket.c @@ -0,0 +1,195 @@ +/* crypto/bio/bss_sock.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#if !defined(OPENSSL_WINDOWS) +#include +#else +#pragma warning(push, 3) +#include +#pragma warning(pop) + +#pragma comment(lib, "Ws2_32.lib") +#endif + +#include "internal.h" + + +#if !defined(OPENSSL_WINDOWS) +static int closesocket(int sock) { + return close(sock); +} +#endif + +static int sock_new(BIO *bio) { + bio->init = 0; + bio->num = 0; + bio->ptr = NULL; + bio->flags = 0; + return 1; +} + +static int sock_free(BIO *bio) { + if (bio == NULL) { + return 0; + } + + if (bio->shutdown) { + if (bio->init) { + closesocket(bio->num); + } + bio->init = 0; + bio->flags = 0; + } + return 1; +} + +static int sock_read(BIO *b, char *out, int outl) { + int ret = 0; + + if (out == NULL) { + return 0; + } + + bio_clear_socket_error(); + ret = recv(b->num, out, outl, 0); + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (bio_fd_should_retry(ret)) { + BIO_set_retry_read(b); + } + } + return ret; +} + +static int sock_write(BIO *b, const char *in, int inl) { + int ret; + + bio_clear_socket_error(); + ret = send(b->num, in, inl, 0); + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (bio_fd_should_retry(ret)) { + BIO_set_retry_write(b); + } + } + return ret; +} + +static int sock_puts(BIO *bp, const char *str) { + return sock_write(bp, str, strlen(str)); +} + +static long sock_ctrl(BIO *b, int cmd, long num, void *ptr) { + long ret = 1; + int *ip; + + switch (cmd) { + case BIO_C_SET_FD: + sock_free(b); + b->num = *((int *)ptr); + b->shutdown = (int)num; + b->init = 1; + break; + case BIO_C_GET_FD: + if (b->init) { + ip = (int *)ptr; + if (ip != NULL) { + *ip = b->num; + } + ret = b->num; + } else { + ret = -1; + } + break; + case BIO_CTRL_GET_CLOSE: + ret = b->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + b->shutdown = (int)num; + break; + case BIO_CTRL_FLUSH: + ret = 1; + break; + default: + ret = 0; + break; + } + return ret; +} + +static const BIO_METHOD methods_sockp = { + BIO_TYPE_SOCKET, "socket", sock_write, sock_read, sock_puts, + NULL /* gets, */, sock_ctrl, sock_new, sock_free, NULL, +}; + +const BIO_METHOD *BIO_s_socket(void) { return &methods_sockp; } + +BIO *BIO_new_socket(int fd, int close_flag) { + BIO *ret; + + ret = BIO_new(BIO_s_socket()); + if (ret == NULL) { + return NULL; + } + BIO_set_fd(ret, fd, close_flag); + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bio/socket_helper.c b/TMessagesProj/jni/boringssl/crypto/bio/socket_helper.c new file mode 100644 index 00000000..01f635eb --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bio/socket_helper.c @@ -0,0 +1,113 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200112L + +#include +#include + +#include +#include +#include + +#if !defined(OPENSSL_WINDOWS) +#include +#include +#else +#pragma warning(push, 3) +#include +#include +#pragma warning(pop) +#endif + +#include "internal.h" + + +int bio_ip_and_port_to_socket_and_addr(int *out_sock, + struct sockaddr_storage *out_addr, + socklen_t *out_addr_length, + const char *hostname, + const char *port_str) { + struct addrinfo hint, *result, *cur; + int ret; + + *out_sock = -1; + + memset(&hint, 0, sizeof(hint)); + hint.ai_family = AF_UNSPEC; + hint.ai_socktype = SOCK_STREAM; + + ret = getaddrinfo(hostname, port_str, &hint, &result); + if (ret != 0) { + OPENSSL_PUT_ERROR(SYS, 0); + ERR_add_error_data(1, gai_strerror(ret)); + return 0; + } + + ret = 0; + + for (cur = result; cur; cur = cur->ai_next) { + if (cur->ai_addrlen > sizeof(struct sockaddr_storage)) { + continue; + } + memset(out_addr, 0, sizeof(struct sockaddr_storage)); + memcpy(out_addr, cur->ai_addr, cur->ai_addrlen); + *out_addr_length = cur->ai_addrlen; + + *out_sock = socket(cur->ai_family, cur->ai_socktype, cur->ai_protocol); + if (*out_sock < 0) { + OPENSSL_PUT_SYSTEM_ERROR(socket); + goto out; + } + + ret = 1; + break; + } + +out: + freeaddrinfo(result); + return ret; +} + +int bio_socket_nbio(int sock, int on) { +#if defined(OPENSSL_WINDOWS) + u_long arg = on; + + return 0 == ioctlsocket(sock, FIONBIO, &arg); +#else + int flags = fcntl(sock, F_GETFL, 0); + if (flags < 0) { + return 0; + } + if (!on) { + flags &= ~O_NONBLOCK; + } else { + flags |= O_NONBLOCK; + } + return fcntl(sock, F_SETFL, flags) == 0; +#endif +} + +void bio_clear_socket_error(void) {} + +int bio_sock_error(int sock) { + int error; + socklen_t error_size = sizeof(error); + + if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&error, &error_size) < 0) { + return 1; + } + return error; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/bn/CMakeLists.txt new file mode 100644 index 00000000..af3bcb35 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/CMakeLists.txt @@ -0,0 +1,68 @@ +include_directories(. .. ../../include) + +if (${ARCH} STREQUAL "x86_64") + set( + BN_ARCH_SOURCES + + x86_64-mont.${ASM_EXT} + x86_64-mont5.${ASM_EXT} + rsaz-x86_64.${ASM_EXT} + rsaz-avx2.${ASM_EXT} + + rsaz_exp.c + ) +endif() + +if (${ARCH} STREQUAL "x86") + set( + BN_ARCH_SOURCES + + bn-586.${ASM_EXT} + co-586.${ASM_EXT} + x86-mont.${ASM_EXT} + ) +endif() + +if (${ARCH} STREQUAL "arm") + set( + BN_ARCH_SOURCES + + armv4-mont.${ASM_EXT} + ) +endif() + +add_library( + bn + + OBJECT + + add.c + asm/x86_64-gcc.c + bn.c + bn_asn1.c + cmp.c + convert.c + ctx.c + div.c + exponentiation.c + generic.c + gcd.c + kronecker.c + montgomery.c + mul.c + prime.c + random.c + shift.c + sqrt.c + + ${BN_ARCH_SOURCES} +) + +perlasm(x86_64-mont.${ASM_EXT} asm/x86_64-mont.pl) +perlasm(x86_64-mont5.${ASM_EXT} asm/x86_64-mont5.pl) +perlasm(rsaz-x86_64.${ASM_EXT} asm/rsaz-x86_64.pl) +perlasm(rsaz-avx2.${ASM_EXT} asm/rsaz-avx2.pl) +perlasm(bn-586.${ASM_EXT} asm/bn-586.pl) +perlasm(co-586.${ASM_EXT} asm/co-586.pl) +perlasm(x86-mont.${ASM_EXT} asm/x86-mont.pl) +perlasm(armv4-mont.${ASM_EXT} asm/armv4-mont.pl) diff --git a/TMessagesProj/jni/boringssl/crypto/bn/add.c b/TMessagesProj/jni/boringssl/crypto/bn/add.c new file mode 100644 index 00000000..a043d838 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/add.c @@ -0,0 +1,394 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include "internal.h" + + +int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { + const BIGNUM *tmp; + int a_neg = a->neg, ret; + + /* a + b a+b + * a + -b a-b + * -a + b b-a + * -a + -b -(a+b) + */ + if (a_neg ^ b->neg) { + /* only one is negative */ + if (a_neg) { + tmp = a; + a = b; + b = tmp; + } + + /* we are now a - b */ + if (BN_ucmp(a, b) < 0) { + if (!BN_usub(r, b, a)) { + return 0; + } + r->neg = 1; + } else { + if (!BN_usub(r, a, b)) { + return 0; + } + r->neg = 0; + } + return 1; + } + + ret = BN_uadd(r, a, b); + r->neg = a_neg; + return ret; +} + +int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { + int max, min, dif; + BN_ULONG *ap, *bp, *rp, carry, t1, t2; + const BIGNUM *tmp; + + if (a->top < b->top) { + tmp = a; + a = b; + b = tmp; + } + max = a->top; + min = b->top; + dif = max - min; + + if (bn_wexpand(r, max + 1) == NULL) { + return 0; + } + + r->top = max; + + ap = a->d; + bp = b->d; + rp = r->d; + + carry = bn_add_words(rp, ap, bp, min); + rp += min; + ap += min; + bp += min; + + if (carry) { + while (dif) { + dif--; + t1 = *(ap++); + t2 = (t1 + 1) & BN_MASK2; + *(rp++) = t2; + if (t2) { + carry = 0; + break; + } + } + if (carry) { + /* carry != 0 => dif == 0 */ + *rp = 1; + r->top++; + } + } + + if (dif && rp != ap) { + while (dif--) { + /* copy remaining words if ap != rp */ + *(rp++) = *(ap++); + } + } + + r->neg = 0; + return 1; +} + +int BN_add_word(BIGNUM *a, BN_ULONG w) { + BN_ULONG l; + int i; + + w &= BN_MASK2; + + /* degenerate case: w is zero */ + if (!w) { + return 1; + } + + /* degenerate case: a is zero */ + if (BN_is_zero(a)) { + return BN_set_word(a, w); + } + + /* handle 'a' when negative */ + if (a->neg) { + a->neg = 0; + i = BN_sub_word(a, w); + if (!BN_is_zero(a)) { + a->neg = !(a->neg); + } + return i; + } + + for (i = 0; w != 0 && i < a->top; i++) { + a->d[i] = l = (a->d[i] + w) & BN_MASK2; + w = (w > l) ? 1 : 0; + } + + if (w && i == a->top) { + if (bn_wexpand(a, a->top + 1) == NULL) { + return 0; + } + a->top++; + a->d[i] = w; + } + + return 1; +} + +int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { + int max; + int add = 0, neg = 0; + const BIGNUM *tmp; + + /* a - b a-b + * a - -b a+b + * -a - b -(a+b) + * -a - -b b-a + */ + if (a->neg) { + if (b->neg) { + tmp = a; + a = b; + b = tmp; + } else { + add = 1; + neg = 1; + } + } else { + if (b->neg) { + add = 1; + neg = 0; + } + } + + if (add) { + if (!BN_uadd(r, a, b)) { + return 0; + } + + r->neg = neg; + return 1; + } + + /* We are actually doing a - b :-) */ + + max = (a->top > b->top) ? a->top : b->top; + if (bn_wexpand(r, max) == NULL) { + return 0; + } + + if (BN_ucmp(a, b) < 0) { + if (!BN_usub(r, b, a)) { + return 0; + } + r->neg = 1; + } else { + if (!BN_usub(r, a, b)) { + return 0; + } + r->neg = 0; + } + + return 1; +} + +int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { + int max, min, dif; + register BN_ULONG t1, t2, *ap, *bp, *rp; + int i, carry; + + max = a->top; + min = b->top; + dif = max - min; + + if (dif < 0) /* hmm... should not be happening */ + { + OPENSSL_PUT_ERROR(BN, BN_R_ARG2_LT_ARG3); + return 0; + } + + if (bn_wexpand(r, max) == NULL) { + return 0; + } + + ap = a->d; + bp = b->d; + rp = r->d; + + carry = 0; + for (i = min; i != 0; i--) { + t1 = *(ap++); + t2 = *(bp++); + if (carry) { + carry = (t1 <= t2); + t1 = (t1 - t2 - 1) & BN_MASK2; + } else { + carry = (t1 < t2); + t1 = (t1 - t2) & BN_MASK2; + } + *(rp++) = t1 & BN_MASK2; + } + + if (carry) /* subtracted */ + { + if (!dif) { + /* error: a < b */ + return 0; + } + + while (dif) { + dif--; + t1 = *(ap++); + t2 = (t1 - 1) & BN_MASK2; + *(rp++) = t2; + if (t1) { + break; + } + } + } + + if (rp != ap) { + for (;;) { + if (!dif--) { + break; + } + rp[0] = ap[0]; + if (!dif--) { + break; + } + rp[1] = ap[1]; + if (!dif--) { + break; + } + rp[2] = ap[2]; + if (!dif--) { + break; + } + rp[3] = ap[3]; + rp += 4; + ap += 4; + } + } + + r->top = max; + r->neg = 0; + bn_correct_top(r); + + return 1; +} + +int BN_sub_word(BIGNUM *a, BN_ULONG w) { + int i; + + w &= BN_MASK2; + + /* degenerate case: w is zero */ + if (!w) { + return 1; + } + + /* degenerate case: a is zero */ + if (BN_is_zero(a)) { + i = BN_set_word(a, w); + if (i != 0) { + BN_set_negative(a, 1); + } + return i; + } + + /* handle 'a' when negative */ + if (a->neg) { + a->neg = 0; + i = BN_add_word(a, w); + a->neg = 1; + return i; + } + + if ((a->top == 1) && (a->d[0] < w)) { + a->d[0] = w - a->d[0]; + a->neg = 1; + return 1; + } + + i = 0; + for (;;) { + if (a->d[i] >= w) { + a->d[i] -= w; + break; + } else { + a->d[i] = (a->d[i] - w) & BN_MASK2; + i++; + w = 1; + } + } + + if ((a->d[i] == 0) && (i == (a->top - 1))) { + a->top--; + } + + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/asm/armv4-mont.pl b/TMessagesProj/jni/boringssl/crypto/bn/asm/armv4-mont.pl new file mode 100644 index 00000000..0f1b6a90 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/asm/armv4-mont.pl @@ -0,0 +1,694 @@ +#!/usr/bin/env perl + +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== + +# January 2007. + +# Montgomery multiplication for ARMv4. +# +# Performance improvement naturally varies among CPU implementations +# and compilers. The code was observed to provide +65-35% improvement +# [depending on key length, less for longer keys] on ARM920T, and +# +115-80% on Intel IXP425. This is compared to pre-bn_mul_mont code +# base and compiler generated code with in-lined umull and even umlal +# instructions. The latter means that this code didn't really have an +# "advantage" of utilizing some "secret" instruction. +# +# The code is interoperable with Thumb ISA and is rather compact, less +# than 1/2KB. Windows CE port would be trivial, as it's exclusively +# about decorations, ABI and instruction syntax are identical. + +# November 2013 +# +# Add NEON code path, which handles lengths divisible by 8. RSA/DSA +# performance improvement on Cortex-A8 is ~45-100% depending on key +# length, more for longer keys. On Cortex-A15 the span is ~10-105%. +# On Snapdragon S4 improvement was measured to vary from ~70% to +# incredible ~380%, yes, 4.8x faster, for RSA4096 sign. But this is +# rather because original integer-only code seems to perform +# suboptimally on S4. Situation on Cortex-A9 is unfortunately +# different. It's being looked into, but the trouble is that +# performance for vectors longer than 256 bits is actually couple +# of percent worse than for integer-only code. The code is chosen +# for execution on all NEON-capable processors, because gain on +# others outweighs the marginal loss on Cortex-A9. + +$flavour = shift; +if ($flavour=~/^\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; } +else { while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {} } + +if ($flavour && $flavour ne "void") { + $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; + ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or + ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or + die "can't locate arm-xlate.pl"; + + open STDOUT,"| \"$^X\" $xlate $flavour $output"; +} else { + open STDOUT,">$output"; +} + +$num="r0"; # starts as num argument, but holds &tp[num-1] +$ap="r1"; +$bp="r2"; $bi="r2"; $rp="r2"; +$np="r3"; +$tp="r4"; +$aj="r5"; +$nj="r6"; +$tj="r7"; +$n0="r8"; +########### # r9 is reserved by ELF as platform specific, e.g. TLS pointer +$alo="r10"; # sl, gcc uses it to keep @GOT +$ahi="r11"; # fp +$nlo="r12"; # ip +########### # r13 is stack pointer +$nhi="r14"; # lr +########### # r15 is program counter + +#### argument block layout relative to &tp[num-1], a.k.a. $num +$_rp="$num,#12*4"; +# ap permanently resides in r1 +$_bp="$num,#13*4"; +# np permanently resides in r3 +$_n0="$num,#14*4"; +$_num="$num,#15*4"; $_bpend=$_num; + +$code=<<___; +#include "arm_arch.h" + +.text +.code 32 + +#if __ARM_MAX_ARCH__>=7 +.align 5 +.LOPENSSL_armcap: +.word OPENSSL_armcap_P-.Lbn_mul_mont +#endif + +.global bn_mul_mont +.hidden bn_mul_mont +.type bn_mul_mont,%function + +.align 5 +bn_mul_mont: +.Lbn_mul_mont: + ldr ip,[sp,#4] @ load num + stmdb sp!,{r0,r2} @ sp points at argument block +#if __ARM_MAX_ARCH__>=7 + tst ip,#7 + bne .Lialu + adr r0,bn_mul_mont + ldr r2,.LOPENSSL_armcap + ldr r0,[r0,r2] +#ifdef __APPLE__ + ldr r0,[r0] +#endif + tst r0,#1 @ NEON available? + ldmia sp, {r0,r2} + beq .Lialu + add sp,sp,#8 + b bn_mul8x_mont_neon +.align 4 +.Lialu: +#endif + cmp ip,#2 + mov $num,ip @ load num + movlt r0,#0 + addlt sp,sp,#2*4 + blt .Labrt + + stmdb sp!,{r4-r12,lr} @ save 10 registers + + mov $num,$num,lsl#2 @ rescale $num for byte count + sub sp,sp,$num @ alloca(4*num) + sub sp,sp,#4 @ +extra dword + sub $num,$num,#4 @ "num=num-1" + add $tp,$bp,$num @ &bp[num-1] + + add $num,sp,$num @ $num to point at &tp[num-1] + ldr $n0,[$_n0] @ &n0 + ldr $bi,[$bp] @ bp[0] + ldr $aj,[$ap],#4 @ ap[0],ap++ + ldr $nj,[$np],#4 @ np[0],np++ + ldr $n0,[$n0] @ *n0 + str $tp,[$_bpend] @ save &bp[num] + + umull $alo,$ahi,$aj,$bi @ ap[0]*bp[0] + str $n0,[$_n0] @ save n0 value + mul $n0,$alo,$n0 @ "tp[0]"*n0 + mov $nlo,#0 + umlal $alo,$nlo,$nj,$n0 @ np[0]*n0+"t[0]" + mov $tp,sp + +.L1st: + ldr $aj,[$ap],#4 @ ap[j],ap++ + mov $alo,$ahi + ldr $nj,[$np],#4 @ np[j],np++ + mov $ahi,#0 + umlal $alo,$ahi,$aj,$bi @ ap[j]*bp[0] + mov $nhi,#0 + umlal $nlo,$nhi,$nj,$n0 @ np[j]*n0 + adds $nlo,$nlo,$alo + str $nlo,[$tp],#4 @ tp[j-1]=,tp++ + adc $nlo,$nhi,#0 + cmp $tp,$num + bne .L1st + + adds $nlo,$nlo,$ahi + ldr $tp,[$_bp] @ restore bp + mov $nhi,#0 + ldr $n0,[$_n0] @ restore n0 + adc $nhi,$nhi,#0 + str $nlo,[$num] @ tp[num-1]= + str $nhi,[$num,#4] @ tp[num]= + +.Louter: + sub $tj,$num,sp @ "original" $num-1 value + sub $ap,$ap,$tj @ "rewind" ap to &ap[1] + ldr $bi,[$tp,#4]! @ *(++bp) + sub $np,$np,$tj @ "rewind" np to &np[1] + ldr $aj,[$ap,#-4] @ ap[0] + ldr $alo,[sp] @ tp[0] + ldr $nj,[$np,#-4] @ np[0] + ldr $tj,[sp,#4] @ tp[1] + + mov $ahi,#0 + umlal $alo,$ahi,$aj,$bi @ ap[0]*bp[i]+tp[0] + str $tp,[$_bp] @ save bp + mul $n0,$alo,$n0 + mov $nlo,#0 + umlal $alo,$nlo,$nj,$n0 @ np[0]*n0+"tp[0]" + mov $tp,sp + +.Linner: + ldr $aj,[$ap],#4 @ ap[j],ap++ + adds $alo,$ahi,$tj @ +=tp[j] + ldr $nj,[$np],#4 @ np[j],np++ + mov $ahi,#0 + umlal $alo,$ahi,$aj,$bi @ ap[j]*bp[i] + mov $nhi,#0 + umlal $nlo,$nhi,$nj,$n0 @ np[j]*n0 + adc $ahi,$ahi,#0 + ldr $tj,[$tp,#8] @ tp[j+1] + adds $nlo,$nlo,$alo + str $nlo,[$tp],#4 @ tp[j-1]=,tp++ + adc $nlo,$nhi,#0 + cmp $tp,$num + bne .Linner + + adds $nlo,$nlo,$ahi + mov $nhi,#0 + ldr $tp,[$_bp] @ restore bp + adc $nhi,$nhi,#0 + ldr $n0,[$_n0] @ restore n0 + adds $nlo,$nlo,$tj + ldr $tj,[$_bpend] @ restore &bp[num] + adc $nhi,$nhi,#0 + str $nlo,[$num] @ tp[num-1]= + str $nhi,[$num,#4] @ tp[num]= + + cmp $tp,$tj + bne .Louter + + ldr $rp,[$_rp] @ pull rp + add $num,$num,#4 @ $num to point at &tp[num] + sub $aj,$num,sp @ "original" num value + mov $tp,sp @ "rewind" $tp + mov $ap,$tp @ "borrow" $ap + sub $np,$np,$aj @ "rewind" $np to &np[0] + + subs $tj,$tj,$tj @ "clear" carry flag +.Lsub: ldr $tj,[$tp],#4 + ldr $nj,[$np],#4 + sbcs $tj,$tj,$nj @ tp[j]-np[j] + str $tj,[$rp],#4 @ rp[j]= + teq $tp,$num @ preserve carry + bne .Lsub + sbcs $nhi,$nhi,#0 @ upmost carry + mov $tp,sp @ "rewind" $tp + sub $rp,$rp,$aj @ "rewind" $rp + + and $ap,$tp,$nhi + bic $np,$rp,$nhi + orr $ap,$ap,$np @ ap=borrow?tp:rp + +.Lcopy: ldr $tj,[$ap],#4 @ copy or in-place refresh + str sp,[$tp],#4 @ zap tp + str $tj,[$rp],#4 + cmp $tp,$num + bne .Lcopy + + add sp,$num,#4 @ skip over tp[num+1] + ldmia sp!,{r4-r12,lr} @ restore registers + add sp,sp,#2*4 @ skip over {r0,r2} + mov r0,#1 +.Labrt: +#if __ARM_ARCH__>=5 + ret @ bx lr +#else + tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet + bx lr @ interoperable with Thumb ISA:-) +#endif +.size bn_mul_mont,.-bn_mul_mont +___ +{ +sub Dlo() { shift=~m|q([1]?[0-9])|?"d".($1*2):""; } +sub Dhi() { shift=~m|q([1]?[0-9])|?"d".($1*2+1):""; } + +my ($A0,$A1,$A2,$A3)=map("d$_",(0..3)); +my ($N0,$N1,$N2,$N3)=map("d$_",(4..7)); +my ($Z,$Temp)=("q4","q5"); +my ($A0xB,$A1xB,$A2xB,$A3xB,$A4xB,$A5xB,$A6xB,$A7xB)=map("q$_",(6..13)); +my ($Bi,$Ni,$M0)=map("d$_",(28..31)); +my $zero=&Dlo($Z); +my $temp=&Dlo($Temp); + +my ($rptr,$aptr,$bptr,$nptr,$n0,$num)=map("r$_",(0..5)); +my ($tinptr,$toutptr,$inner,$outer)=map("r$_",(6..9)); + +$code.=<<___; +#if __ARM_MAX_ARCH__>=7 +.arch armv7-a +.fpu neon + +.type bn_mul8x_mont_neon,%function +.align 5 +bn_mul8x_mont_neon: + mov ip,sp + stmdb sp!,{r4-r11} + vstmdb sp!,{d8-d15} @ ABI specification says so + ldmia ip,{r4-r5} @ load rest of parameter block + + sub $toutptr,sp,#16 + vld1.32 {${Bi}[0]}, [$bptr,:32]! + sub $toutptr,$toutptr,$num,lsl#4 + vld1.32 {$A0-$A3}, [$aptr]! @ can't specify :32 :-( + and $toutptr,$toutptr,#-64 + vld1.32 {${M0}[0]}, [$n0,:32] + mov sp,$toutptr @ alloca + veor $zero,$zero,$zero + subs $inner,$num,#8 + vzip.16 $Bi,$zero + + vmull.u32 $A0xB,$Bi,${A0}[0] + vmull.u32 $A1xB,$Bi,${A0}[1] + vmull.u32 $A2xB,$Bi,${A1}[0] + vshl.i64 $temp,`&Dhi("$A0xB")`,#16 + vmull.u32 $A3xB,$Bi,${A1}[1] + + vadd.u64 $temp,$temp,`&Dlo("$A0xB")` + veor $zero,$zero,$zero + vmul.u32 $Ni,$temp,$M0 + + vmull.u32 $A4xB,$Bi,${A2}[0] + vld1.32 {$N0-$N3}, [$nptr]! + vmull.u32 $A5xB,$Bi,${A2}[1] + vmull.u32 $A6xB,$Bi,${A3}[0] + vzip.16 $Ni,$zero + vmull.u32 $A7xB,$Bi,${A3}[1] + + bne .LNEON_1st + + @ special case for num=8, everything is in register bank... + + vmlal.u32 $A0xB,$Ni,${N0}[0] + sub $outer,$num,#1 + vmlal.u32 $A1xB,$Ni,${N0}[1] + vmlal.u32 $A2xB,$Ni,${N1}[0] + vmlal.u32 $A3xB,$Ni,${N1}[1] + + vmlal.u32 $A4xB,$Ni,${N2}[0] + vmov $Temp,$A0xB + vmlal.u32 $A5xB,$Ni,${N2}[1] + vmov $A0xB,$A1xB + vmlal.u32 $A6xB,$Ni,${N3}[0] + vmov $A1xB,$A2xB + vmlal.u32 $A7xB,$Ni,${N3}[1] + vmov $A2xB,$A3xB + vmov $A3xB,$A4xB + vshr.u64 $temp,$temp,#16 + vmov $A4xB,$A5xB + vmov $A5xB,$A6xB + vadd.u64 $temp,$temp,`&Dhi("$Temp")` + vmov $A6xB,$A7xB + veor $A7xB,$A7xB + vshr.u64 $temp,$temp,#16 + + b .LNEON_outer8 + +.align 4 +.LNEON_outer8: + vld1.32 {${Bi}[0]}, [$bptr,:32]! + veor $zero,$zero,$zero + vzip.16 $Bi,$zero + vadd.u64 `&Dlo("$A0xB")`,`&Dlo("$A0xB")`,$temp + + vmlal.u32 $A0xB,$Bi,${A0}[0] + vmlal.u32 $A1xB,$Bi,${A0}[1] + vmlal.u32 $A2xB,$Bi,${A1}[0] + vshl.i64 $temp,`&Dhi("$A0xB")`,#16 + vmlal.u32 $A3xB,$Bi,${A1}[1] + + vadd.u64 $temp,$temp,`&Dlo("$A0xB")` + veor $zero,$zero,$zero + subs $outer,$outer,#1 + vmul.u32 $Ni,$temp,$M0 + + vmlal.u32 $A4xB,$Bi,${A2}[0] + vmlal.u32 $A5xB,$Bi,${A2}[1] + vmlal.u32 $A6xB,$Bi,${A3}[0] + vzip.16 $Ni,$zero + vmlal.u32 $A7xB,$Bi,${A3}[1] + + vmlal.u32 $A0xB,$Ni,${N0}[0] + vmlal.u32 $A1xB,$Ni,${N0}[1] + vmlal.u32 $A2xB,$Ni,${N1}[0] + vmlal.u32 $A3xB,$Ni,${N1}[1] + + vmlal.u32 $A4xB,$Ni,${N2}[0] + vmov $Temp,$A0xB + vmlal.u32 $A5xB,$Ni,${N2}[1] + vmov $A0xB,$A1xB + vmlal.u32 $A6xB,$Ni,${N3}[0] + vmov $A1xB,$A2xB + vmlal.u32 $A7xB,$Ni,${N3}[1] + vmov $A2xB,$A3xB + vmov $A3xB,$A4xB + vshr.u64 $temp,$temp,#16 + vmov $A4xB,$A5xB + vmov $A5xB,$A6xB + vadd.u64 $temp,$temp,`&Dhi("$Temp")` + vmov $A6xB,$A7xB + veor $A7xB,$A7xB + vshr.u64 $temp,$temp,#16 + + bne .LNEON_outer8 + + vadd.u64 `&Dlo("$A0xB")`,`&Dlo("$A0xB")`,$temp + mov $toutptr,sp + vshr.u64 $temp,`&Dlo("$A0xB")`,#16 + mov $inner,$num + vadd.u64 `&Dhi("$A0xB")`,`&Dhi("$A0xB")`,$temp + add $tinptr,sp,#16 + vshr.u64 $temp,`&Dhi("$A0xB")`,#16 + vzip.16 `&Dlo("$A0xB")`,`&Dhi("$A0xB")` + + b .LNEON_tail2 + +.align 4 +.LNEON_1st: + vmlal.u32 $A0xB,$Ni,${N0}[0] + vld1.32 {$A0-$A3}, [$aptr]! + vmlal.u32 $A1xB,$Ni,${N0}[1] + subs $inner,$inner,#8 + vmlal.u32 $A2xB,$Ni,${N1}[0] + vmlal.u32 $A3xB,$Ni,${N1}[1] + + vmlal.u32 $A4xB,$Ni,${N2}[0] + vld1.32 {$N0-$N1}, [$nptr]! + vmlal.u32 $A5xB,$Ni,${N2}[1] + vst1.64 {$A0xB-$A1xB}, [$toutptr,:256]! + vmlal.u32 $A6xB,$Ni,${N3}[0] + vmlal.u32 $A7xB,$Ni,${N3}[1] + vst1.64 {$A2xB-$A3xB}, [$toutptr,:256]! + + vmull.u32 $A0xB,$Bi,${A0}[0] + vld1.32 {$N2-$N3}, [$nptr]! + vmull.u32 $A1xB,$Bi,${A0}[1] + vst1.64 {$A4xB-$A5xB}, [$toutptr,:256]! + vmull.u32 $A2xB,$Bi,${A1}[0] + vmull.u32 $A3xB,$Bi,${A1}[1] + vst1.64 {$A6xB-$A7xB}, [$toutptr,:256]! + + vmull.u32 $A4xB,$Bi,${A2}[0] + vmull.u32 $A5xB,$Bi,${A2}[1] + vmull.u32 $A6xB,$Bi,${A3}[0] + vmull.u32 $A7xB,$Bi,${A3}[1] + + bne .LNEON_1st + + vmlal.u32 $A0xB,$Ni,${N0}[0] + add $tinptr,sp,#16 + vmlal.u32 $A1xB,$Ni,${N0}[1] + sub $aptr,$aptr,$num,lsl#2 @ rewind $aptr + vmlal.u32 $A2xB,$Ni,${N1}[0] + vld1.64 {$Temp}, [sp,:128] + vmlal.u32 $A3xB,$Ni,${N1}[1] + sub $outer,$num,#1 + + vmlal.u32 $A4xB,$Ni,${N2}[0] + vst1.64 {$A0xB-$A1xB}, [$toutptr,:256]! + vmlal.u32 $A5xB,$Ni,${N2}[1] + vshr.u64 $temp,$temp,#16 + vld1.64 {$A0xB}, [$tinptr, :128]! + vmlal.u32 $A6xB,$Ni,${N3}[0] + vst1.64 {$A2xB-$A3xB}, [$toutptr,:256]! + vmlal.u32 $A7xB,$Ni,${N3}[1] + + vst1.64 {$A4xB-$A5xB}, [$toutptr,:256]! + vadd.u64 $temp,$temp,`&Dhi("$Temp")` + veor $Z,$Z,$Z + vst1.64 {$A6xB-$A7xB}, [$toutptr,:256]! + vld1.64 {$A1xB-$A2xB}, [$tinptr, :256]! + vst1.64 {$Z}, [$toutptr,:128] + vshr.u64 $temp,$temp,#16 + + b .LNEON_outer + +.align 4 +.LNEON_outer: + vld1.32 {${Bi}[0]}, [$bptr,:32]! + sub $nptr,$nptr,$num,lsl#2 @ rewind $nptr + vld1.32 {$A0-$A3}, [$aptr]! + veor $zero,$zero,$zero + mov $toutptr,sp + vzip.16 $Bi,$zero + sub $inner,$num,#8 + vadd.u64 `&Dlo("$A0xB")`,`&Dlo("$A0xB")`,$temp + + vmlal.u32 $A0xB,$Bi,${A0}[0] + vld1.64 {$A3xB-$A4xB},[$tinptr,:256]! + vmlal.u32 $A1xB,$Bi,${A0}[1] + vmlal.u32 $A2xB,$Bi,${A1}[0] + vld1.64 {$A5xB-$A6xB},[$tinptr,:256]! + vmlal.u32 $A3xB,$Bi,${A1}[1] + + vshl.i64 $temp,`&Dhi("$A0xB")`,#16 + veor $zero,$zero,$zero + vadd.u64 $temp,$temp,`&Dlo("$A0xB")` + vld1.64 {$A7xB},[$tinptr,:128]! + vmul.u32 $Ni,$temp,$M0 + + vmlal.u32 $A4xB,$Bi,${A2}[0] + vld1.32 {$N0-$N3}, [$nptr]! + vmlal.u32 $A5xB,$Bi,${A2}[1] + vmlal.u32 $A6xB,$Bi,${A3}[0] + vzip.16 $Ni,$zero + vmlal.u32 $A7xB,$Bi,${A3}[1] + +.LNEON_inner: + vmlal.u32 $A0xB,$Ni,${N0}[0] + vld1.32 {$A0-$A3}, [$aptr]! + vmlal.u32 $A1xB,$Ni,${N0}[1] + subs $inner,$inner,#8 + vmlal.u32 $A2xB,$Ni,${N1}[0] + vmlal.u32 $A3xB,$Ni,${N1}[1] + vst1.64 {$A0xB-$A1xB}, [$toutptr,:256]! + + vmlal.u32 $A4xB,$Ni,${N2}[0] + vld1.64 {$A0xB}, [$tinptr, :128]! + vmlal.u32 $A5xB,$Ni,${N2}[1] + vst1.64 {$A2xB-$A3xB}, [$toutptr,:256]! + vmlal.u32 $A6xB,$Ni,${N3}[0] + vld1.64 {$A1xB-$A2xB}, [$tinptr, :256]! + vmlal.u32 $A7xB,$Ni,${N3}[1] + vst1.64 {$A4xB-$A5xB}, [$toutptr,:256]! + + vmlal.u32 $A0xB,$Bi,${A0}[0] + vld1.64 {$A3xB-$A4xB}, [$tinptr, :256]! + vmlal.u32 $A1xB,$Bi,${A0}[1] + vst1.64 {$A6xB-$A7xB}, [$toutptr,:256]! + vmlal.u32 $A2xB,$Bi,${A1}[0] + vld1.64 {$A5xB-$A6xB}, [$tinptr, :256]! + vmlal.u32 $A3xB,$Bi,${A1}[1] + vld1.32 {$N0-$N3}, [$nptr]! + + vmlal.u32 $A4xB,$Bi,${A2}[0] + vld1.64 {$A7xB}, [$tinptr, :128]! + vmlal.u32 $A5xB,$Bi,${A2}[1] + vmlal.u32 $A6xB,$Bi,${A3}[0] + vmlal.u32 $A7xB,$Bi,${A3}[1] + + bne .LNEON_inner + + vmlal.u32 $A0xB,$Ni,${N0}[0] + add $tinptr,sp,#16 + vmlal.u32 $A1xB,$Ni,${N0}[1] + sub $aptr,$aptr,$num,lsl#2 @ rewind $aptr + vmlal.u32 $A2xB,$Ni,${N1}[0] + vld1.64 {$Temp}, [sp,:128] + vmlal.u32 $A3xB,$Ni,${N1}[1] + subs $outer,$outer,#1 + + vmlal.u32 $A4xB,$Ni,${N2}[0] + vst1.64 {$A0xB-$A1xB}, [$toutptr,:256]! + vmlal.u32 $A5xB,$Ni,${N2}[1] + vld1.64 {$A0xB}, [$tinptr, :128]! + vshr.u64 $temp,$temp,#16 + vst1.64 {$A2xB-$A3xB}, [$toutptr,:256]! + vmlal.u32 $A6xB,$Ni,${N3}[0] + vld1.64 {$A1xB-$A2xB}, [$tinptr, :256]! + vmlal.u32 $A7xB,$Ni,${N3}[1] + + vst1.64 {$A4xB-$A5xB}, [$toutptr,:256]! + vadd.u64 $temp,$temp,`&Dhi("$Temp")` + vst1.64 {$A6xB-$A7xB}, [$toutptr,:256]! + vshr.u64 $temp,$temp,#16 + + bne .LNEON_outer + + mov $toutptr,sp + mov $inner,$num + +.LNEON_tail: + vadd.u64 `&Dlo("$A0xB")`,`&Dlo("$A0xB")`,$temp + vld1.64 {$A3xB-$A4xB}, [$tinptr, :256]! + vshr.u64 $temp,`&Dlo("$A0xB")`,#16 + vadd.u64 `&Dhi("$A0xB")`,`&Dhi("$A0xB")`,$temp + vld1.64 {$A5xB-$A6xB}, [$tinptr, :256]! + vshr.u64 $temp,`&Dhi("$A0xB")`,#16 + vld1.64 {$A7xB}, [$tinptr, :128]! + vzip.16 `&Dlo("$A0xB")`,`&Dhi("$A0xB")` + +.LNEON_tail2: + vadd.u64 `&Dlo("$A1xB")`,`&Dlo("$A1xB")`,$temp + vst1.32 {`&Dlo("$A0xB")`[0]}, [$toutptr, :32]! + vshr.u64 $temp,`&Dlo("$A1xB")`,#16 + vadd.u64 `&Dhi("$A1xB")`,`&Dhi("$A1xB")`,$temp + vshr.u64 $temp,`&Dhi("$A1xB")`,#16 + vzip.16 `&Dlo("$A1xB")`,`&Dhi("$A1xB")` + + vadd.u64 `&Dlo("$A2xB")`,`&Dlo("$A2xB")`,$temp + vst1.32 {`&Dlo("$A1xB")`[0]}, [$toutptr, :32]! + vshr.u64 $temp,`&Dlo("$A2xB")`,#16 + vadd.u64 `&Dhi("$A2xB")`,`&Dhi("$A2xB")`,$temp + vshr.u64 $temp,`&Dhi("$A2xB")`,#16 + vzip.16 `&Dlo("$A2xB")`,`&Dhi("$A2xB")` + + vadd.u64 `&Dlo("$A3xB")`,`&Dlo("$A3xB")`,$temp + vst1.32 {`&Dlo("$A2xB")`[0]}, [$toutptr, :32]! + vshr.u64 $temp,`&Dlo("$A3xB")`,#16 + vadd.u64 `&Dhi("$A3xB")`,`&Dhi("$A3xB")`,$temp + vshr.u64 $temp,`&Dhi("$A3xB")`,#16 + vzip.16 `&Dlo("$A3xB")`,`&Dhi("$A3xB")` + + vadd.u64 `&Dlo("$A4xB")`,`&Dlo("$A4xB")`,$temp + vst1.32 {`&Dlo("$A3xB")`[0]}, [$toutptr, :32]! + vshr.u64 $temp,`&Dlo("$A4xB")`,#16 + vadd.u64 `&Dhi("$A4xB")`,`&Dhi("$A4xB")`,$temp + vshr.u64 $temp,`&Dhi("$A4xB")`,#16 + vzip.16 `&Dlo("$A4xB")`,`&Dhi("$A4xB")` + + vadd.u64 `&Dlo("$A5xB")`,`&Dlo("$A5xB")`,$temp + vst1.32 {`&Dlo("$A4xB")`[0]}, [$toutptr, :32]! + vshr.u64 $temp,`&Dlo("$A5xB")`,#16 + vadd.u64 `&Dhi("$A5xB")`,`&Dhi("$A5xB")`,$temp + vshr.u64 $temp,`&Dhi("$A5xB")`,#16 + vzip.16 `&Dlo("$A5xB")`,`&Dhi("$A5xB")` + + vadd.u64 `&Dlo("$A6xB")`,`&Dlo("$A6xB")`,$temp + vst1.32 {`&Dlo("$A5xB")`[0]}, [$toutptr, :32]! + vshr.u64 $temp,`&Dlo("$A6xB")`,#16 + vadd.u64 `&Dhi("$A6xB")`,`&Dhi("$A6xB")`,$temp + vld1.64 {$A0xB}, [$tinptr, :128]! + vshr.u64 $temp,`&Dhi("$A6xB")`,#16 + vzip.16 `&Dlo("$A6xB")`,`&Dhi("$A6xB")` + + vadd.u64 `&Dlo("$A7xB")`,`&Dlo("$A7xB")`,$temp + vst1.32 {`&Dlo("$A6xB")`[0]}, [$toutptr, :32]! + vshr.u64 $temp,`&Dlo("$A7xB")`,#16 + vadd.u64 `&Dhi("$A7xB")`,`&Dhi("$A7xB")`,$temp + vld1.64 {$A1xB-$A2xB}, [$tinptr, :256]! + vshr.u64 $temp,`&Dhi("$A7xB")`,#16 + vzip.16 `&Dlo("$A7xB")`,`&Dhi("$A7xB")` + subs $inner,$inner,#8 + vst1.32 {`&Dlo("$A7xB")`[0]}, [$toutptr, :32]! + + bne .LNEON_tail + + vst1.32 {${temp}[0]}, [$toutptr, :32] @ top-most bit + sub $nptr,$nptr,$num,lsl#2 @ rewind $nptr + subs $aptr,sp,#0 @ clear carry flag + add $bptr,sp,$num,lsl#2 + +.LNEON_sub: + ldmia $aptr!, {r4-r7} + ldmia $nptr!, {r8-r11} + sbcs r8, r4,r8 + sbcs r9, r5,r9 + sbcs r10,r6,r10 + sbcs r11,r7,r11 + teq $aptr,$bptr @ preserves carry + stmia $rptr!, {r8-r11} + bne .LNEON_sub + + ldr r10, [$aptr] @ load top-most bit + veor q0,q0,q0 + sub r11,$bptr,sp @ this is num*4 + veor q1,q1,q1 + mov $aptr,sp + sub $rptr,$rptr,r11 @ rewind $rptr + mov $nptr,$bptr @ second 3/4th of frame + sbcs r10,r10,#0 @ result is carry flag + +.LNEON_copy_n_zap: + ldmia $aptr!, {r4-r7} + ldmia $rptr, {r8-r11} + movcc r8, r4 + vst1.64 {q0-q1}, [$nptr,:256]! @ wipe + movcc r9, r5 + movcc r10,r6 + vst1.64 {q0-q1}, [$nptr,:256]! @ wipe + movcc r11,r7 + ldmia $aptr, {r4-r7} + stmia $rptr!, {r8-r11} + sub $aptr,$aptr,#16 + ldmia $rptr, {r8-r11} + movcc r8, r4 + vst1.64 {q0-q1}, [$aptr,:256]! @ wipe + movcc r9, r5 + movcc r10,r6 + vst1.64 {q0-q1}, [$nptr,:256]! @ wipe + movcc r11,r7 + teq $aptr,$bptr @ preserves carry + stmia $rptr!, {r8-r11} + bne .LNEON_copy_n_zap + + sub sp,ip,#96 + vldmia sp!,{d8-d15} + ldmia sp!,{r4-r11} + ret @ bx lr +.size bn_mul8x_mont_neon,.-bn_mul8x_mont_neon +#endif +___ +} +$code.=<<___; +.asciz "Montgomery multiplication for ARMv4/NEON, CRYPTOGAMS by " +.align 2 +#if __ARM_MAX_ARCH__>=7 +.comm OPENSSL_armcap_P,4,4 +.hidden OPENSSL_armcap_P +#endif +___ + +$code =~ s/\`([^\`]*)\`/eval $1/gem; +$code =~ s/\bbx\s+lr\b/.word\t0xe12fff1e/gm; # make it possible to compile with -march=armv4 +$code =~ s/\bret\b/bx lr/gm; +print $code; +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/bn/asm/bn-586.pl b/TMessagesProj/jni/boringssl/crypto/bn/asm/bn-586.pl new file mode 100644 index 00000000..26d9bcbb --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/asm/bn-586.pl @@ -0,0 +1,774 @@ +#!/usr/bin/env perl + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +push(@INC,"${dir}","${dir}../../perlasm"); +require "x86asm.pl"; + +&asm_init($ARGV[0],$0); + +$sse2=0; +for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); } + +&external_label("OPENSSL_ia32cap_P") if ($sse2); + +&bn_mul_add_words("bn_mul_add_words"); +&bn_mul_words("bn_mul_words"); +&bn_sqr_words("bn_sqr_words"); +&bn_div_words("bn_div_words"); +&bn_add_words("bn_add_words"); +&bn_sub_words("bn_sub_words"); +&bn_sub_part_words("bn_sub_part_words"); + +&asm_finish(); + +sub bn_mul_add_words + { + local($name)=@_; + + &function_begin_B($name,$sse2?"EXTRN\t_OPENSSL_ia32cap_P:DWORD":""); + + $r="eax"; + $a="edx"; + $c="ecx"; + + if ($sse2) { + &picmeup("eax","OPENSSL_ia32cap_P"); + &bt(&DWP(0,"eax"),26); + &jnc(&label("maw_non_sse2")); + + &mov($r,&wparam(0)); + &mov($a,&wparam(1)); + &mov($c,&wparam(2)); + &movd("mm0",&wparam(3)); # mm0 = w + &pxor("mm1","mm1"); # mm1 = carry_in + &jmp(&label("maw_sse2_entry")); + + &set_label("maw_sse2_unrolled",16); + &movd("mm3",&DWP(0,$r,"",0)); # mm3 = r[0] + &paddq("mm1","mm3"); # mm1 = carry_in + r[0] + &movd("mm2",&DWP(0,$a,"",0)); # mm2 = a[0] + &pmuludq("mm2","mm0"); # mm2 = w*a[0] + &movd("mm4",&DWP(4,$a,"",0)); # mm4 = a[1] + &pmuludq("mm4","mm0"); # mm4 = w*a[1] + &movd("mm6",&DWP(8,$a,"",0)); # mm6 = a[2] + &pmuludq("mm6","mm0"); # mm6 = w*a[2] + &movd("mm7",&DWP(12,$a,"",0)); # mm7 = a[3] + &pmuludq("mm7","mm0"); # mm7 = w*a[3] + &paddq("mm1","mm2"); # mm1 = carry_in + r[0] + w*a[0] + &movd("mm3",&DWP(4,$r,"",0)); # mm3 = r[1] + &paddq("mm3","mm4"); # mm3 = r[1] + w*a[1] + &movd("mm5",&DWP(8,$r,"",0)); # mm5 = r[2] + &paddq("mm5","mm6"); # mm5 = r[2] + w*a[2] + &movd("mm4",&DWP(12,$r,"",0)); # mm4 = r[3] + &paddq("mm7","mm4"); # mm7 = r[3] + w*a[3] + &movd(&DWP(0,$r,"",0),"mm1"); + &movd("mm2",&DWP(16,$a,"",0)); # mm2 = a[4] + &pmuludq("mm2","mm0"); # mm2 = w*a[4] + &psrlq("mm1",32); # mm1 = carry0 + &movd("mm4",&DWP(20,$a,"",0)); # mm4 = a[5] + &pmuludq("mm4","mm0"); # mm4 = w*a[5] + &paddq("mm1","mm3"); # mm1 = carry0 + r[1] + w*a[1] + &movd("mm6",&DWP(24,$a,"",0)); # mm6 = a[6] + &pmuludq("mm6","mm0"); # mm6 = w*a[6] + &movd(&DWP(4,$r,"",0),"mm1"); + &psrlq("mm1",32); # mm1 = carry1 + &movd("mm3",&DWP(28,$a,"",0)); # mm3 = a[7] + &add($a,32); + &pmuludq("mm3","mm0"); # mm3 = w*a[7] + &paddq("mm1","mm5"); # mm1 = carry1 + r[2] + w*a[2] + &movd("mm5",&DWP(16,$r,"",0)); # mm5 = r[4] + &paddq("mm2","mm5"); # mm2 = r[4] + w*a[4] + &movd(&DWP(8,$r,"",0),"mm1"); + &psrlq("mm1",32); # mm1 = carry2 + &paddq("mm1","mm7"); # mm1 = carry2 + r[3] + w*a[3] + &movd("mm5",&DWP(20,$r,"",0)); # mm5 = r[5] + &paddq("mm4","mm5"); # mm4 = r[5] + w*a[5] + &movd(&DWP(12,$r,"",0),"mm1"); + &psrlq("mm1",32); # mm1 = carry3 + &paddq("mm1","mm2"); # mm1 = carry3 + r[4] + w*a[4] + &movd("mm5",&DWP(24,$r,"",0)); # mm5 = r[6] + &paddq("mm6","mm5"); # mm6 = r[6] + w*a[6] + &movd(&DWP(16,$r,"",0),"mm1"); + &psrlq("mm1",32); # mm1 = carry4 + &paddq("mm1","mm4"); # mm1 = carry4 + r[5] + w*a[5] + &movd("mm5",&DWP(28,$r,"",0)); # mm5 = r[7] + &paddq("mm3","mm5"); # mm3 = r[7] + w*a[7] + &movd(&DWP(20,$r,"",0),"mm1"); + &psrlq("mm1",32); # mm1 = carry5 + &paddq("mm1","mm6"); # mm1 = carry5 + r[6] + w*a[6] + &movd(&DWP(24,$r,"",0),"mm1"); + &psrlq("mm1",32); # mm1 = carry6 + &paddq("mm1","mm3"); # mm1 = carry6 + r[7] + w*a[7] + &movd(&DWP(28,$r,"",0),"mm1"); + &lea($r,&DWP(32,$r)); + &psrlq("mm1",32); # mm1 = carry_out + + &sub($c,8); + &jz(&label("maw_sse2_exit")); + &set_label("maw_sse2_entry"); + &test($c,0xfffffff8); + &jnz(&label("maw_sse2_unrolled")); + + &set_label("maw_sse2_loop",4); + &movd("mm2",&DWP(0,$a)); # mm2 = a[i] + &movd("mm3",&DWP(0,$r)); # mm3 = r[i] + &pmuludq("mm2","mm0"); # a[i] *= w + &lea($a,&DWP(4,$a)); + &paddq("mm1","mm3"); # carry += r[i] + &paddq("mm1","mm2"); # carry += a[i]*w + &movd(&DWP(0,$r),"mm1"); # r[i] = carry_low + &sub($c,1); + &psrlq("mm1",32); # carry = carry_high + &lea($r,&DWP(4,$r)); + &jnz(&label("maw_sse2_loop")); + &set_label("maw_sse2_exit"); + &movd("eax","mm1"); # c = carry_out + &emms(); + &ret(); + + &set_label("maw_non_sse2",16); + } + + # function_begin prologue + &push("ebp"); + &push("ebx"); + &push("esi"); + &push("edi"); + + &comment(""); + $Low="eax"; + $High="edx"; + $a="ebx"; + $w="ebp"; + $r="edi"; + $c="esi"; + + &xor($c,$c); # clear carry + &mov($r,&wparam(0)); # + + &mov("ecx",&wparam(2)); # + &mov($a,&wparam(1)); # + + &and("ecx",0xfffffff8); # num / 8 + &mov($w,&wparam(3)); # + + &push("ecx"); # Up the stack for a tmp variable + + &jz(&label("maw_finish")); + + &set_label("maw_loop",16); + + for ($i=0; $i<32; $i+=4) + { + &comment("Round $i"); + + &mov("eax",&DWP($i,$a)); # *a + &mul($w); # *a * w + &add("eax",$c); # L(t)+= c + &adc("edx",0); # H(t)+=carry + &add("eax",&DWP($i,$r)); # L(t)+= *r + &adc("edx",0); # H(t)+=carry + &mov(&DWP($i,$r),"eax"); # *r= L(t); + &mov($c,"edx"); # c= H(t); + } + + &comment(""); + &sub("ecx",8); + &lea($a,&DWP(32,$a)); + &lea($r,&DWP(32,$r)); + &jnz(&label("maw_loop")); + + &set_label("maw_finish",0); + &mov("ecx",&wparam(2)); # get num + &and("ecx",7); + &jnz(&label("maw_finish2")); # helps branch prediction + &jmp(&label("maw_end")); + + &set_label("maw_finish2",1); + for ($i=0; $i<7; $i++) + { + &comment("Tail Round $i"); + &mov("eax",&DWP($i*4,$a)); # *a + &mul($w); # *a * w + &add("eax",$c); # L(t)+=c + &adc("edx",0); # H(t)+=carry + &add("eax",&DWP($i*4,$r)); # L(t)+= *r + &adc("edx",0); # H(t)+=carry + &dec("ecx") if ($i != 7-1); + &mov(&DWP($i*4,$r),"eax"); # *r= L(t); + &mov($c,"edx"); # c= H(t); + &jz(&label("maw_end")) if ($i != 7-1); + } + &set_label("maw_end",0); + &mov("eax",$c); + + &pop("ecx"); # clear variable from + + &function_end($name); + } + +sub bn_mul_words + { + local($name)=@_; + + &function_begin_B($name,$sse2?"EXTRN\t_OPENSSL_ia32cap_P:DWORD":""); + + $r="eax"; + $a="edx"; + $c="ecx"; + + if ($sse2) { + &picmeup("eax","OPENSSL_ia32cap_P"); + &bt(&DWP(0,"eax"),26); + &jnc(&label("mw_non_sse2")); + + &mov($r,&wparam(0)); + &mov($a,&wparam(1)); + &mov($c,&wparam(2)); + &movd("mm0",&wparam(3)); # mm0 = w + &pxor("mm1","mm1"); # mm1 = carry = 0 + + &set_label("mw_sse2_loop",16); + &movd("mm2",&DWP(0,$a)); # mm2 = a[i] + &pmuludq("mm2","mm0"); # a[i] *= w + &lea($a,&DWP(4,$a)); + &paddq("mm1","mm2"); # carry += a[i]*w + &movd(&DWP(0,$r),"mm1"); # r[i] = carry_low + &sub($c,1); + &psrlq("mm1",32); # carry = carry_high + &lea($r,&DWP(4,$r)); + &jnz(&label("mw_sse2_loop")); + + &movd("eax","mm1"); # return carry + &emms(); + &ret(); + &set_label("mw_non_sse2",16); + } + + # function_begin prologue + &push("ebp"); + &push("ebx"); + &push("esi"); + &push("edi"); + + &comment(""); + $Low="eax"; + $High="edx"; + $a="ebx"; + $w="ecx"; + $r="edi"; + $c="esi"; + $num="ebp"; + + &xor($c,$c); # clear carry + &mov($r,&wparam(0)); # + &mov($a,&wparam(1)); # + &mov($num,&wparam(2)); # + &mov($w,&wparam(3)); # + + &and($num,0xfffffff8); # num / 8 + &jz(&label("mw_finish")); + + &set_label("mw_loop",0); + for ($i=0; $i<32; $i+=4) + { + &comment("Round $i"); + + &mov("eax",&DWP($i,$a,"",0)); # *a + &mul($w); # *a * w + &add("eax",$c); # L(t)+=c + # XXX + + &adc("edx",0); # H(t)+=carry + &mov(&DWP($i,$r,"",0),"eax"); # *r= L(t); + + &mov($c,"edx"); # c= H(t); + } + + &comment(""); + &add($a,32); + &add($r,32); + &sub($num,8); + &jz(&label("mw_finish")); + &jmp(&label("mw_loop")); + + &set_label("mw_finish",0); + &mov($num,&wparam(2)); # get num + &and($num,7); + &jnz(&label("mw_finish2")); + &jmp(&label("mw_end")); + + &set_label("mw_finish2",1); + for ($i=0; $i<7; $i++) + { + &comment("Tail Round $i"); + &mov("eax",&DWP($i*4,$a,"",0));# *a + &mul($w); # *a * w + &add("eax",$c); # L(t)+=c + # XXX + &adc("edx",0); # H(t)+=carry + &mov(&DWP($i*4,$r,"",0),"eax");# *r= L(t); + &mov($c,"edx"); # c= H(t); + &dec($num) if ($i != 7-1); + &jz(&label("mw_end")) if ($i != 7-1); + } + &set_label("mw_end",0); + &mov("eax",$c); + + &function_end($name); + } + +sub bn_sqr_words + { + local($name)=@_; + + &function_begin_B($name,$sse2?"EXTRN\t_OPENSSL_ia32cap_P:DWORD":""); + + $r="eax"; + $a="edx"; + $c="ecx"; + + if ($sse2) { + &picmeup("eax","OPENSSL_ia32cap_P"); + &bt(&DWP(0,"eax"),26); + &jnc(&label("sqr_non_sse2")); + + &mov($r,&wparam(0)); + &mov($a,&wparam(1)); + &mov($c,&wparam(2)); + + &set_label("sqr_sse2_loop",16); + &movd("mm0",&DWP(0,$a)); # mm0 = a[i] + &pmuludq("mm0","mm0"); # a[i] *= a[i] + &lea($a,&DWP(4,$a)); # a++ + &movq(&QWP(0,$r),"mm0"); # r[i] = a[i]*a[i] + &sub($c,1); + &lea($r,&DWP(8,$r)); # r += 2 + &jnz(&label("sqr_sse2_loop")); + + &emms(); + &ret(); + &set_label("sqr_non_sse2",16); + } + + # function_begin prologue + &push("ebp"); + &push("ebx"); + &push("esi"); + &push("edi"); + + &comment(""); + $r="esi"; + $a="edi"; + $num="ebx"; + + &mov($r,&wparam(0)); # + &mov($a,&wparam(1)); # + &mov($num,&wparam(2)); # + + &and($num,0xfffffff8); # num / 8 + &jz(&label("sw_finish")); + + &set_label("sw_loop",0); + for ($i=0; $i<32; $i+=4) + { + &comment("Round $i"); + &mov("eax",&DWP($i,$a,"",0)); # *a + # XXX + &mul("eax"); # *a * *a + &mov(&DWP($i*2,$r,"",0),"eax"); # + &mov(&DWP($i*2+4,$r,"",0),"edx");# + } + + &comment(""); + &add($a,32); + &add($r,64); + &sub($num,8); + &jnz(&label("sw_loop")); + + &set_label("sw_finish",0); + &mov($num,&wparam(2)); # get num + &and($num,7); + &jz(&label("sw_end")); + + for ($i=0; $i<7; $i++) + { + &comment("Tail Round $i"); + &mov("eax",&DWP($i*4,$a,"",0)); # *a + # XXX + &mul("eax"); # *a * *a + &mov(&DWP($i*8,$r,"",0),"eax"); # + &dec($num) if ($i != 7-1); + &mov(&DWP($i*8+4,$r,"",0),"edx"); + &jz(&label("sw_end")) if ($i != 7-1); + } + &set_label("sw_end",0); + + &function_end($name); + } + +sub bn_div_words + { + local($name)=@_; + + &function_begin_B($name,""); + &mov("edx",&wparam(0)); # + &mov("eax",&wparam(1)); # + &mov("ecx",&wparam(2)); # + &div("ecx"); + &ret(); + &function_end_B($name); + } + +sub bn_add_words + { + local($name)=@_; + + &function_begin($name,""); + + &comment(""); + $a="esi"; + $b="edi"; + $c="eax"; + $r="ebx"; + $tmp1="ecx"; + $tmp2="edx"; + $num="ebp"; + + &mov($r,&wparam(0)); # get r + &mov($a,&wparam(1)); # get a + &mov($b,&wparam(2)); # get b + &mov($num,&wparam(3)); # get num + &xor($c,$c); # clear carry + &and($num,0xfffffff8); # num / 8 + + &jz(&label("aw_finish")); + + &set_label("aw_loop",0); + for ($i=0; $i<8; $i++) + { + &comment("Round $i"); + + &mov($tmp1,&DWP($i*4,$a,"",0)); # *a + &mov($tmp2,&DWP($i*4,$b,"",0)); # *b + &add($tmp1,$c); + &mov($c,0); + &adc($c,$c); + &add($tmp1,$tmp2); + &adc($c,0); + &mov(&DWP($i*4,$r,"",0),$tmp1); # *r + } + + &comment(""); + &add($a,32); + &add($b,32); + &add($r,32); + &sub($num,8); + &jnz(&label("aw_loop")); + + &set_label("aw_finish",0); + &mov($num,&wparam(3)); # get num + &and($num,7); + &jz(&label("aw_end")); + + for ($i=0; $i<7; $i++) + { + &comment("Tail Round $i"); + &mov($tmp1,&DWP($i*4,$a,"",0)); # *a + &mov($tmp2,&DWP($i*4,$b,"",0));# *b + &add($tmp1,$c); + &mov($c,0); + &adc($c,$c); + &add($tmp1,$tmp2); + &adc($c,0); + &dec($num) if ($i != 6); + &mov(&DWP($i*4,$r,"",0),$tmp1); # *r + &jz(&label("aw_end")) if ($i != 6); + } + &set_label("aw_end",0); + +# &mov("eax",$c); # $c is "eax" + + &function_end($name); + } + +sub bn_sub_words + { + local($name)=@_; + + &function_begin($name,""); + + &comment(""); + $a="esi"; + $b="edi"; + $c="eax"; + $r="ebx"; + $tmp1="ecx"; + $tmp2="edx"; + $num="ebp"; + + &mov($r,&wparam(0)); # get r + &mov($a,&wparam(1)); # get a + &mov($b,&wparam(2)); # get b + &mov($num,&wparam(3)); # get num + &xor($c,$c); # clear carry + &and($num,0xfffffff8); # num / 8 + + &jz(&label("aw_finish")); + + &set_label("aw_loop",0); + for ($i=0; $i<8; $i++) + { + &comment("Round $i"); + + &mov($tmp1,&DWP($i*4,$a,"",0)); # *a + &mov($tmp2,&DWP($i*4,$b,"",0)); # *b + &sub($tmp1,$c); + &mov($c,0); + &adc($c,$c); + &sub($tmp1,$tmp2); + &adc($c,0); + &mov(&DWP($i*4,$r,"",0),$tmp1); # *r + } + + &comment(""); + &add($a,32); + &add($b,32); + &add($r,32); + &sub($num,8); + &jnz(&label("aw_loop")); + + &set_label("aw_finish",0); + &mov($num,&wparam(3)); # get num + &and($num,7); + &jz(&label("aw_end")); + + for ($i=0; $i<7; $i++) + { + &comment("Tail Round $i"); + &mov($tmp1,&DWP($i*4,$a,"",0)); # *a + &mov($tmp2,&DWP($i*4,$b,"",0));# *b + &sub($tmp1,$c); + &mov($c,0); + &adc($c,$c); + &sub($tmp1,$tmp2); + &adc($c,0); + &dec($num) if ($i != 6); + &mov(&DWP($i*4,$r,"",0),$tmp1); # *r + &jz(&label("aw_end")) if ($i != 6); + } + &set_label("aw_end",0); + +# &mov("eax",$c); # $c is "eax" + + &function_end($name); + } + +sub bn_sub_part_words + { + local($name)=@_; + + &function_begin($name,""); + + &comment(""); + $a="esi"; + $b="edi"; + $c="eax"; + $r="ebx"; + $tmp1="ecx"; + $tmp2="edx"; + $num="ebp"; + + &mov($r,&wparam(0)); # get r + &mov($a,&wparam(1)); # get a + &mov($b,&wparam(2)); # get b + &mov($num,&wparam(3)); # get num + &xor($c,$c); # clear carry + &and($num,0xfffffff8); # num / 8 + + &jz(&label("aw_finish")); + + &set_label("aw_loop",0); + for ($i=0; $i<8; $i++) + { + &comment("Round $i"); + + &mov($tmp1,&DWP($i*4,$a,"",0)); # *a + &mov($tmp2,&DWP($i*4,$b,"",0)); # *b + &sub($tmp1,$c); + &mov($c,0); + &adc($c,$c); + &sub($tmp1,$tmp2); + &adc($c,0); + &mov(&DWP($i*4,$r,"",0),$tmp1); # *r + } + + &comment(""); + &add($a,32); + &add($b,32); + &add($r,32); + &sub($num,8); + &jnz(&label("aw_loop")); + + &set_label("aw_finish",0); + &mov($num,&wparam(3)); # get num + &and($num,7); + &jz(&label("aw_end")); + + for ($i=0; $i<7; $i++) + { + &comment("Tail Round $i"); + &mov($tmp1,&DWP(0,$a,"",0)); # *a + &mov($tmp2,&DWP(0,$b,"",0));# *b + &sub($tmp1,$c); + &mov($c,0); + &adc($c,$c); + &sub($tmp1,$tmp2); + &adc($c,0); + &mov(&DWP(0,$r,"",0),$tmp1); # *r + &add($a, 4); + &add($b, 4); + &add($r, 4); + &dec($num) if ($i != 6); + &jz(&label("aw_end")) if ($i != 6); + } + &set_label("aw_end",0); + + &cmp(&wparam(4),0); + &je(&label("pw_end")); + + &mov($num,&wparam(4)); # get dl + &cmp($num,0); + &je(&label("pw_end")); + &jge(&label("pw_pos")); + + &comment("pw_neg"); + &mov($tmp2,0); + &sub($tmp2,$num); + &mov($num,$tmp2); + &and($num,0xfffffff8); # num / 8 + &jz(&label("pw_neg_finish")); + + &set_label("pw_neg_loop",0); + for ($i=0; $i<8; $i++) + { + &comment("dl<0 Round $i"); + + &mov($tmp1,0); + &mov($tmp2,&DWP($i*4,$b,"",0)); # *b + &sub($tmp1,$c); + &mov($c,0); + &adc($c,$c); + &sub($tmp1,$tmp2); + &adc($c,0); + &mov(&DWP($i*4,$r,"",0),$tmp1); # *r + } + + &comment(""); + &add($b,32); + &add($r,32); + &sub($num,8); + &jnz(&label("pw_neg_loop")); + + &set_label("pw_neg_finish",0); + &mov($tmp2,&wparam(4)); # get dl + &mov($num,0); + &sub($num,$tmp2); + &and($num,7); + &jz(&label("pw_end")); + + for ($i=0; $i<7; $i++) + { + &comment("dl<0 Tail Round $i"); + &mov($tmp1,0); + &mov($tmp2,&DWP($i*4,$b,"",0));# *b + &sub($tmp1,$c); + &mov($c,0); + &adc($c,$c); + &sub($tmp1,$tmp2); + &adc($c,0); + &dec($num) if ($i != 6); + &mov(&DWP($i*4,$r,"",0),$tmp1); # *r + &jz(&label("pw_end")) if ($i != 6); + } + + &jmp(&label("pw_end")); + + &set_label("pw_pos",0); + + &and($num,0xfffffff8); # num / 8 + &jz(&label("pw_pos_finish")); + + &set_label("pw_pos_loop",0); + + for ($i=0; $i<8; $i++) + { + &comment("dl>0 Round $i"); + + &mov($tmp1,&DWP($i*4,$a,"",0)); # *a + &sub($tmp1,$c); + &mov(&DWP($i*4,$r,"",0),$tmp1); # *r + &jnc(&label("pw_nc".$i)); + } + + &comment(""); + &add($a,32); + &add($r,32); + &sub($num,8); + &jnz(&label("pw_pos_loop")); + + &set_label("pw_pos_finish",0); + &mov($num,&wparam(4)); # get dl + &and($num,7); + &jz(&label("pw_end")); + + for ($i=0; $i<7; $i++) + { + &comment("dl>0 Tail Round $i"); + &mov($tmp1,&DWP($i*4,$a,"",0)); # *a + &sub($tmp1,$c); + &mov(&DWP($i*4,$r,"",0),$tmp1); # *r + &jnc(&label("pw_tail_nc".$i)); + &dec($num) if ($i != 6); + &jz(&label("pw_end")) if ($i != 6); + } + &mov($c,1); + &jmp(&label("pw_end")); + + &set_label("pw_nc_loop",0); + for ($i=0; $i<8; $i++) + { + &mov($tmp1,&DWP($i*4,$a,"",0)); # *a + &mov(&DWP($i*4,$r,"",0),$tmp1); # *r + &set_label("pw_nc".$i,0); + } + + &comment(""); + &add($a,32); + &add($r,32); + &sub($num,8); + &jnz(&label("pw_nc_loop")); + + &mov($num,&wparam(4)); # get dl + &and($num,7); + &jz(&label("pw_nc_end")); + + for ($i=0; $i<7; $i++) + { + &mov($tmp1,&DWP($i*4,$a,"",0)); # *a + &mov(&DWP($i*4,$r,"",0),$tmp1); # *r + &set_label("pw_tail_nc".$i,0); + &dec($num) if ($i != 6); + &jz(&label("pw_nc_end")) if ($i != 6); + } + + &set_label("pw_nc_end",0); + &mov($c,0); + + &set_label("pw_end",0); + +# &mov("eax",$c); # $c is "eax" + + &function_end($name); + } + diff --git a/TMessagesProj/jni/boringssl/crypto/bn/asm/co-586.pl b/TMessagesProj/jni/boringssl/crypto/bn/asm/co-586.pl new file mode 100644 index 00000000..57101a6b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/asm/co-586.pl @@ -0,0 +1,287 @@ +#!/usr/local/bin/perl + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +push(@INC,"${dir}","${dir}../../perlasm"); +require "x86asm.pl"; + +&asm_init($ARGV[0],$0); + +&bn_mul_comba("bn_mul_comba8",8); +&bn_mul_comba("bn_mul_comba4",4); +&bn_sqr_comba("bn_sqr_comba8",8); +&bn_sqr_comba("bn_sqr_comba4",4); + +&asm_finish(); + +sub mul_add_c + { + local($a,$ai,$b,$bi,$c0,$c1,$c2,$pos,$i,$na,$nb)=@_; + + # pos == -1 if eax and edx are pre-loaded, 0 to load from next + # words, and 1 if load return value + + &comment("mul a[$ai]*b[$bi]"); + + # "eax" and "edx" will always be pre-loaded. + # &mov("eax",&DWP($ai*4,$a,"",0)) ; + # &mov("edx",&DWP($bi*4,$b,"",0)); + + &mul("edx"); + &add($c0,"eax"); + &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 0; # laod next a + &mov("eax",&wparam(0)) if $pos > 0; # load r[] + ### + &adc($c1,"edx"); + &mov("edx",&DWP(($nb)*4,$b,"",0)) if $pos == 0; # laod next b + &mov("edx",&DWP(($nb)*4,$b,"",0)) if $pos == 1; # laod next b + ### + &adc($c2,0); + # is pos > 1, it means it is the last loop + &mov(&DWP($i*4,"eax","",0),$c0) if $pos > 0; # save r[]; + &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 1; # laod next a + } + +sub sqr_add_c + { + local($r,$a,$ai,$bi,$c0,$c1,$c2,$pos,$i,$na,$nb)=@_; + + # pos == -1 if eax and edx are pre-loaded, 0 to load from next + # words, and 1 if load return value + + &comment("sqr a[$ai]*a[$bi]"); + + # "eax" and "edx" will always be pre-loaded. + # &mov("eax",&DWP($ai*4,$a,"",0)) ; + # &mov("edx",&DWP($bi*4,$b,"",0)); + + if ($ai == $bi) + { &mul("eax");} + else + { &mul("edx");} + &add($c0,"eax"); + &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 0; # load next a + ### + &adc($c1,"edx"); + &mov("edx",&DWP(($nb)*4,$a,"",0)) if ($pos == 1) && ($na != $nb); + ### + &adc($c2,0); + # is pos > 1, it means it is the last loop + &mov(&DWP($i*4,$r,"",0),$c0) if $pos > 0; # save r[]; + &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 1; # load next b + } + +sub sqr_add_c2 + { + local($r,$a,$ai,$bi,$c0,$c1,$c2,$pos,$i,$na,$nb)=@_; + + # pos == -1 if eax and edx are pre-loaded, 0 to load from next + # words, and 1 if load return value + + &comment("sqr a[$ai]*a[$bi]"); + + # "eax" and "edx" will always be pre-loaded. + # &mov("eax",&DWP($ai*4,$a,"",0)) ; + # &mov("edx",&DWP($bi*4,$a,"",0)); + + if ($ai == $bi) + { &mul("eax");} + else + { &mul("edx");} + &add("eax","eax"); + ### + &adc("edx","edx"); + ### + &adc($c2,0); + &add($c0,"eax"); + &adc($c1,"edx"); + &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 0; # load next a + &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 1; # load next b + &adc($c2,0); + &mov(&DWP($i*4,$r,"",0),$c0) if $pos > 0; # save r[]; + &mov("edx",&DWP(($nb)*4,$a,"",0)) if ($pos <= 1) && ($na != $nb); + ### + } + +sub bn_mul_comba + { + local($name,$num)=@_; + local($a,$b,$c0,$c1,$c2); + local($i,$as,$ae,$bs,$be,$ai,$bi); + local($tot,$end); + + &function_begin_B($name,""); + + $c0="ebx"; + $c1="ecx"; + $c2="ebp"; + $a="esi"; + $b="edi"; + + $as=0; + $ae=0; + $bs=0; + $be=0; + $tot=$num+$num-1; + + &push("esi"); + &mov($a,&wparam(1)); + &push("edi"); + &mov($b,&wparam(2)); + &push("ebp"); + &push("ebx"); + + &xor($c0,$c0); + &mov("eax",&DWP(0,$a,"",0)); # load the first word + &xor($c1,$c1); + &mov("edx",&DWP(0,$b,"",0)); # load the first second + + for ($i=0; $i<$tot; $i++) + { + $ai=$as; + $bi=$bs; + $end=$be+1; + + &comment("################## Calculate word $i"); + + for ($j=$bs; $j<$end; $j++) + { + &xor($c2,$c2) if ($j == $bs); + if (($j+1) == $end) + { + $v=1; + $v=2 if (($i+1) == $tot); + } + else + { $v=0; } + if (($j+1) != $end) + { + $na=($ai-1); + $nb=($bi+1); + } + else + { + $na=$as+($i < ($num-1)); + $nb=$bs+($i >= ($num-1)); + } +#printf STDERR "[$ai,$bi] -> [$na,$nb]\n"; + &mul_add_c($a,$ai,$b,$bi,$c0,$c1,$c2,$v,$i,$na,$nb); + if ($v) + { + &comment("saved r[$i]"); + # &mov("eax",&wparam(0)); + # &mov(&DWP($i*4,"eax","",0),$c0); + ($c0,$c1,$c2)=($c1,$c2,$c0); + } + $ai--; + $bi++; + } + $as++ if ($i < ($num-1)); + $ae++ if ($i >= ($num-1)); + + $bs++ if ($i >= ($num-1)); + $be++ if ($i < ($num-1)); + } + &comment("save r[$i]"); + # &mov("eax",&wparam(0)); + &mov(&DWP($i*4,"eax","",0),$c0); + + &pop("ebx"); + &pop("ebp"); + &pop("edi"); + &pop("esi"); + &ret(); + &function_end_B($name); + } + +sub bn_sqr_comba + { + local($name,$num)=@_; + local($r,$a,$c0,$c1,$c2)=@_; + local($i,$as,$ae,$bs,$be,$ai,$bi); + local($b,$tot,$end,$half); + + &function_begin_B($name,""); + + $c0="ebx"; + $c1="ecx"; + $c2="ebp"; + $a="esi"; + $r="edi"; + + &push("esi"); + &push("edi"); + &push("ebp"); + &push("ebx"); + &mov($r,&wparam(0)); + &mov($a,&wparam(1)); + &xor($c0,$c0); + &xor($c1,$c1); + &mov("eax",&DWP(0,$a,"",0)); # load the first word + + $as=0; + $ae=0; + $bs=0; + $be=0; + $tot=$num+$num-1; + + for ($i=0; $i<$tot; $i++) + { + $ai=$as; + $bi=$bs; + $end=$be+1; + + &comment("############### Calculate word $i"); + for ($j=$bs; $j<$end; $j++) + { + &xor($c2,$c2) if ($j == $bs); + if (($ai-1) < ($bi+1)) + { + $v=1; + $v=2 if ($i+1) == $tot; + } + else + { $v=0; } + if (!$v) + { + $na=$ai-1; + $nb=$bi+1; + } + else + { + $na=$as+($i < ($num-1)); + $nb=$bs+($i >= ($num-1)); + } + if ($ai == $bi) + { + &sqr_add_c($r,$a,$ai,$bi, + $c0,$c1,$c2,$v,$i,$na,$nb); + } + else + { + &sqr_add_c2($r,$a,$ai,$bi, + $c0,$c1,$c2,$v,$i,$na,$nb); + } + if ($v) + { + &comment("saved r[$i]"); + #&mov(&DWP($i*4,$r,"",0),$c0); + ($c0,$c1,$c2)=($c1,$c2,$c0); + last; + } + $ai--; + $bi++; + } + $as++ if ($i < ($num-1)); + $ae++ if ($i >= ($num-1)); + + $bs++ if ($i >= ($num-1)); + $be++ if ($i < ($num-1)); + } + &mov(&DWP($i*4,$r,"",0),$c0); + &pop("ebx"); + &pop("ebp"); + &pop("edi"); + &pop("esi"); + &ret(); + &function_end_B($name); + } diff --git a/TMessagesProj/jni/boringssl/crypto/bn/asm/rsaz-avx2.pl b/TMessagesProj/jni/boringssl/crypto/bn/asm/rsaz-avx2.pl new file mode 100644 index 00000000..3b6ccf83 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/asm/rsaz-avx2.pl @@ -0,0 +1,1898 @@ +#!/usr/bin/env perl + +############################################################################## +# # +# Copyright (c) 2012, Intel Corporation # +# # +# All rights reserved. # +# # +# Redistribution and use in source and binary forms, with or without # +# modification, are permitted provided that the following conditions are # +# met: # +# # +# * Redistributions of source code must retain the above copyright # +# notice, this list of conditions and the following disclaimer. # +# # +# * Redistributions in binary form must reproduce the above copyright # +# notice, this list of conditions and the following disclaimer in the # +# documentation and/or other materials provided with the # +# distribution. # +# # +# * Neither the name of the Intel Corporation nor the names of its # +# contributors may be used to endorse or promote products derived from # +# this software without specific prior written permission. # +# # +# # +# THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""AS IS"" AND ANY # +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR # +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR # +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR # +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF # +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # +# # +############################################################################## +# Developers and authors: # +# Shay Gueron (1, 2), and Vlad Krasnov (1) # +# (1) Intel Corporation, Israel Development Center, Haifa, Israel # +# (2) University of Haifa, Israel # +############################################################################## +# Reference: # +# [1] S. Gueron, V. Krasnov: "Software Implementation of Modular # +# Exponentiation, Using Advanced Vector Instructions Architectures", # +# F. Ozbudak and F. Rodriguez-Henriquez (Eds.): WAIFI 2012, LNCS 7369, # +# pp. 119?135, 2012. Springer-Verlag Berlin Heidelberg 2012 # +# [2] S. Gueron: "Efficient Software Implementations of Modular # +# Exponentiation", Journal of Cryptographic Engineering 2:31-43 (2012). # +# [3] S. Gueron, V. Krasnov: "Speeding up Big-numbers Squaring",IEEE # +# Proceedings of 9th International Conference on Information Technology: # +# New Generations (ITNG 2012), pp.821-823 (2012) # +# [4] S. Gueron, V. Krasnov: "[PATCH] Efficient and side channel analysis # +# resistant 1024-bit modular exponentiation, for optimizing RSA2048 # +# on AVX2 capable x86_64 platforms", # +# http://rt.openssl.org/Ticket/Display.html?id=2850&user=guest&pass=guest# +############################################################################## +# +# +13% improvement over original submission by +# +# rsa2048 sign/sec OpenSSL 1.0.1 scalar(*) this +# 2.3GHz Haswell 621 765/+23% 1113/+79% +# 2.3GHz Broadwell(**) 688 1200(***)/+74% 1120/+63% +# +# (*) if system doesn't support AVX2, for reference purposes; +# (**) scaled to 2.3GHz to simplify comparison; +# (***) scalar AD*X code is faster than AVX2 and is preferred code +# path for Broadwell; + +$flavour = shift; +$output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or +die "can't locate x86_64-xlate.pl"; + +if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1` + =~ /GNU assembler version ([2-9]\.[0-9]+)/) { + $avx = ($1>=2.19) + ($1>=2.22); + $addx = ($1>=2.23); +} + +if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) && + `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) { + $avx = ($1>=2.09) + ($1>=2.10); + $addx = ($1>=2.10); +} + +if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) && + `ml64 2>&1` =~ /Version ([0-9]+)\./) { + $avx = ($1>=10) + ($1>=11); + $addx = ($1>=11); +} + +if (!$avx && `$ENV{CC} -v 2>&1` =~ /(^clang version|based on LLVM) ([3-9])\.([0-9]+)/) { + my $ver = $2 + $3/100.0; # 3.1->3.01, 3.10->3.10 + $avx = ($ver>=3.0) + ($ver>=3.01); + $addx = ($ver>=3.03); +} + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT = *OUT; + +if ($avx>1) {{{ +{ # void AMS_WW( +my $rp="%rdi"; # BN_ULONG *rp, +my $ap="%rsi"; # const BN_ULONG *ap, +my $np="%rdx"; # const BN_ULONG *np, +my $n0="%ecx"; # const BN_ULONG n0, +my $rep="%r8d"; # int repeat); + +# The registers that hold the accumulated redundant result +# The AMM works on 1024 bit operands, and redundant word size is 29 +# Therefore: ceil(1024/29)/4 = 9 +my $ACC0="%ymm0"; +my $ACC1="%ymm1"; +my $ACC2="%ymm2"; +my $ACC3="%ymm3"; +my $ACC4="%ymm4"; +my $ACC5="%ymm5"; +my $ACC6="%ymm6"; +my $ACC7="%ymm7"; +my $ACC8="%ymm8"; +my $ACC9="%ymm9"; +# Registers that hold the broadcasted words of bp, currently used +my $B1="%ymm10"; +my $B2="%ymm11"; +# Registers that hold the broadcasted words of Y, currently used +my $Y1="%ymm12"; +my $Y2="%ymm13"; +# Helper registers +my $TEMP1="%ymm14"; +my $AND_MASK="%ymm15"; +# alu registers that hold the first words of the ACC +my $r0="%r9"; +my $r1="%r10"; +my $r2="%r11"; +my $r3="%r12"; + +my $i="%r14d"; # loop counter +my $tmp = "%r15"; + +my $FrameSize=32*18+32*8; # place for A^2 and 2*A + +my $aap=$r0; +my $tp0="%rbx"; +my $tp1=$r3; +my $tpa=$tmp; + +$np="%r13"; # reassigned argument + +$code.=<<___; +.text + +.globl rsaz_1024_sqr_avx2 +.type rsaz_1024_sqr_avx2,\@function,5 +.align 64 +rsaz_1024_sqr_avx2: # 702 cycles, 14% faster than rsaz_1024_mul_avx2 + lea (%rsp), %rax + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + vzeroupper +___ +$code.=<<___ if ($win64); + lea -0xa8(%rsp),%rsp + vmovaps %xmm6,-0xd8(%rax) + vmovaps %xmm7,-0xc8(%rax) + vmovaps %xmm8,-0xb8(%rax) + vmovaps %xmm9,-0xa8(%rax) + vmovaps %xmm10,-0x98(%rax) + vmovaps %xmm11,-0x88(%rax) + vmovaps %xmm12,-0x78(%rax) + vmovaps %xmm13,-0x68(%rax) + vmovaps %xmm14,-0x58(%rax) + vmovaps %xmm15,-0x48(%rax) +.Lsqr_1024_body: +___ +$code.=<<___; + mov %rax,%rbp + mov %rdx, $np # reassigned argument + sub \$$FrameSize, %rsp + mov $np, $tmp + sub \$-128, $rp # size optimization + sub \$-128, $ap + sub \$-128, $np + + and \$4095, $tmp # see if $np crosses page + add \$32*10, $tmp + shr \$12, $tmp + vpxor $ACC9,$ACC9,$ACC9 + jz .Lsqr_1024_no_n_copy + + # unaligned 256-bit load that crosses page boundary can + # cause >2x performance degradation here, so if $np does + # cross page boundary, copy it to stack and make sure stack + # frame doesn't... + sub \$32*10,%rsp + vmovdqu 32*0-128($np), $ACC0 + and \$-2048, %rsp + vmovdqu 32*1-128($np), $ACC1 + vmovdqu 32*2-128($np), $ACC2 + vmovdqu 32*3-128($np), $ACC3 + vmovdqu 32*4-128($np), $ACC4 + vmovdqu 32*5-128($np), $ACC5 + vmovdqu 32*6-128($np), $ACC6 + vmovdqu 32*7-128($np), $ACC7 + vmovdqu 32*8-128($np), $ACC8 + lea $FrameSize+128(%rsp),$np + vmovdqu $ACC0, 32*0-128($np) + vmovdqu $ACC1, 32*1-128($np) + vmovdqu $ACC2, 32*2-128($np) + vmovdqu $ACC3, 32*3-128($np) + vmovdqu $ACC4, 32*4-128($np) + vmovdqu $ACC5, 32*5-128($np) + vmovdqu $ACC6, 32*6-128($np) + vmovdqu $ACC7, 32*7-128($np) + vmovdqu $ACC8, 32*8-128($np) + vmovdqu $ACC9, 32*9-128($np) # $ACC9 is zero + +.Lsqr_1024_no_n_copy: + and \$-1024, %rsp + + vmovdqu 32*1-128($ap), $ACC1 + vmovdqu 32*2-128($ap), $ACC2 + vmovdqu 32*3-128($ap), $ACC3 + vmovdqu 32*4-128($ap), $ACC4 + vmovdqu 32*5-128($ap), $ACC5 + vmovdqu 32*6-128($ap), $ACC6 + vmovdqu 32*7-128($ap), $ACC7 + vmovdqu 32*8-128($ap), $ACC8 + + lea 192(%rsp), $tp0 # 64+128=192 + vpbroadcastq .Land_mask(%rip), $AND_MASK + jmp .LOOP_GRANDE_SQR_1024 + +.align 32 +.LOOP_GRANDE_SQR_1024: + lea 32*18+128(%rsp), $aap # size optimization + lea 448(%rsp), $tp1 # 64+128+256=448 + + # the squaring is performed as described in Variant B of + # "Speeding up Big-Number Squaring", so start by calculating + # the A*2=A+A vector + vpaddq $ACC1, $ACC1, $ACC1 + vpbroadcastq 32*0-128($ap), $B1 + vpaddq $ACC2, $ACC2, $ACC2 + vmovdqa $ACC1, 32*0-128($aap) + vpaddq $ACC3, $ACC3, $ACC3 + vmovdqa $ACC2, 32*1-128($aap) + vpaddq $ACC4, $ACC4, $ACC4 + vmovdqa $ACC3, 32*2-128($aap) + vpaddq $ACC5, $ACC5, $ACC5 + vmovdqa $ACC4, 32*3-128($aap) + vpaddq $ACC6, $ACC6, $ACC6 + vmovdqa $ACC5, 32*4-128($aap) + vpaddq $ACC7, $ACC7, $ACC7 + vmovdqa $ACC6, 32*5-128($aap) + vpaddq $ACC8, $ACC8, $ACC8 + vmovdqa $ACC7, 32*6-128($aap) + vpxor $ACC9, $ACC9, $ACC9 + vmovdqa $ACC8, 32*7-128($aap) + + vpmuludq 32*0-128($ap), $B1, $ACC0 + vpbroadcastq 32*1-128($ap), $B2 + vmovdqu $ACC9, 32*9-192($tp0) # zero upper half + vpmuludq $B1, $ACC1, $ACC1 + vmovdqu $ACC9, 32*10-448($tp1) + vpmuludq $B1, $ACC2, $ACC2 + vmovdqu $ACC9, 32*11-448($tp1) + vpmuludq $B1, $ACC3, $ACC3 + vmovdqu $ACC9, 32*12-448($tp1) + vpmuludq $B1, $ACC4, $ACC4 + vmovdqu $ACC9, 32*13-448($tp1) + vpmuludq $B1, $ACC5, $ACC5 + vmovdqu $ACC9, 32*14-448($tp1) + vpmuludq $B1, $ACC6, $ACC6 + vmovdqu $ACC9, 32*15-448($tp1) + vpmuludq $B1, $ACC7, $ACC7 + vmovdqu $ACC9, 32*16-448($tp1) + vpmuludq $B1, $ACC8, $ACC8 + vpbroadcastq 32*2-128($ap), $B1 + vmovdqu $ACC9, 32*17-448($tp1) + + mov $ap, $tpa + mov \$4, $i + jmp .Lsqr_entry_1024 +___ +$TEMP0=$Y1; +$TEMP2=$Y2; +$code.=<<___; +.align 32 +.LOOP_SQR_1024: + vpbroadcastq 32*1-128($tpa), $B2 + vpmuludq 32*0-128($ap), $B1, $ACC0 + vpaddq 32*0-192($tp0), $ACC0, $ACC0 + vpmuludq 32*0-128($aap), $B1, $ACC1 + vpaddq 32*1-192($tp0), $ACC1, $ACC1 + vpmuludq 32*1-128($aap), $B1, $ACC2 + vpaddq 32*2-192($tp0), $ACC2, $ACC2 + vpmuludq 32*2-128($aap), $B1, $ACC3 + vpaddq 32*3-192($tp0), $ACC3, $ACC3 + vpmuludq 32*3-128($aap), $B1, $ACC4 + vpaddq 32*4-192($tp0), $ACC4, $ACC4 + vpmuludq 32*4-128($aap), $B1, $ACC5 + vpaddq 32*5-192($tp0), $ACC5, $ACC5 + vpmuludq 32*5-128($aap), $B1, $ACC6 + vpaddq 32*6-192($tp0), $ACC6, $ACC6 + vpmuludq 32*6-128($aap), $B1, $ACC7 + vpaddq 32*7-192($tp0), $ACC7, $ACC7 + vpmuludq 32*7-128($aap), $B1, $ACC8 + vpbroadcastq 32*2-128($tpa), $B1 + vpaddq 32*8-192($tp0), $ACC8, $ACC8 +.Lsqr_entry_1024: + vmovdqu $ACC0, 32*0-192($tp0) + vmovdqu $ACC1, 32*1-192($tp0) + + vpmuludq 32*1-128($ap), $B2, $TEMP0 + vpaddq $TEMP0, $ACC2, $ACC2 + vpmuludq 32*1-128($aap), $B2, $TEMP1 + vpaddq $TEMP1, $ACC3, $ACC3 + vpmuludq 32*2-128($aap), $B2, $TEMP2 + vpaddq $TEMP2, $ACC4, $ACC4 + vpmuludq 32*3-128($aap), $B2, $TEMP0 + vpaddq $TEMP0, $ACC5, $ACC5 + vpmuludq 32*4-128($aap), $B2, $TEMP1 + vpaddq $TEMP1, $ACC6, $ACC6 + vpmuludq 32*5-128($aap), $B2, $TEMP2 + vpaddq $TEMP2, $ACC7, $ACC7 + vpmuludq 32*6-128($aap), $B2, $TEMP0 + vpaddq $TEMP0, $ACC8, $ACC8 + vpmuludq 32*7-128($aap), $B2, $ACC0 + vpbroadcastq 32*3-128($tpa), $B2 + vpaddq 32*9-192($tp0), $ACC0, $ACC0 + + vmovdqu $ACC2, 32*2-192($tp0) + vmovdqu $ACC3, 32*3-192($tp0) + + vpmuludq 32*2-128($ap), $B1, $TEMP2 + vpaddq $TEMP2, $ACC4, $ACC4 + vpmuludq 32*2-128($aap), $B1, $TEMP0 + vpaddq $TEMP0, $ACC5, $ACC5 + vpmuludq 32*3-128($aap), $B1, $TEMP1 + vpaddq $TEMP1, $ACC6, $ACC6 + vpmuludq 32*4-128($aap), $B1, $TEMP2 + vpaddq $TEMP2, $ACC7, $ACC7 + vpmuludq 32*5-128($aap), $B1, $TEMP0 + vpaddq $TEMP0, $ACC8, $ACC8 + vpmuludq 32*6-128($aap), $B1, $TEMP1 + vpaddq $TEMP1, $ACC0, $ACC0 + vpmuludq 32*7-128($aap), $B1, $ACC1 + vpbroadcastq 32*4-128($tpa), $B1 + vpaddq 32*10-448($tp1), $ACC1, $ACC1 + + vmovdqu $ACC4, 32*4-192($tp0) + vmovdqu $ACC5, 32*5-192($tp0) + + vpmuludq 32*3-128($ap), $B2, $TEMP0 + vpaddq $TEMP0, $ACC6, $ACC6 + vpmuludq 32*3-128($aap), $B2, $TEMP1 + vpaddq $TEMP1, $ACC7, $ACC7 + vpmuludq 32*4-128($aap), $B2, $TEMP2 + vpaddq $TEMP2, $ACC8, $ACC8 + vpmuludq 32*5-128($aap), $B2, $TEMP0 + vpaddq $TEMP0, $ACC0, $ACC0 + vpmuludq 32*6-128($aap), $B2, $TEMP1 + vpaddq $TEMP1, $ACC1, $ACC1 + vpmuludq 32*7-128($aap), $B2, $ACC2 + vpbroadcastq 32*5-128($tpa), $B2 + vpaddq 32*11-448($tp1), $ACC2, $ACC2 + + vmovdqu $ACC6, 32*6-192($tp0) + vmovdqu $ACC7, 32*7-192($tp0) + + vpmuludq 32*4-128($ap), $B1, $TEMP0 + vpaddq $TEMP0, $ACC8, $ACC8 + vpmuludq 32*4-128($aap), $B1, $TEMP1 + vpaddq $TEMP1, $ACC0, $ACC0 + vpmuludq 32*5-128($aap), $B1, $TEMP2 + vpaddq $TEMP2, $ACC1, $ACC1 + vpmuludq 32*6-128($aap), $B1, $TEMP0 + vpaddq $TEMP0, $ACC2, $ACC2 + vpmuludq 32*7-128($aap), $B1, $ACC3 + vpbroadcastq 32*6-128($tpa), $B1 + vpaddq 32*12-448($tp1), $ACC3, $ACC3 + + vmovdqu $ACC8, 32*8-192($tp0) + vmovdqu $ACC0, 32*9-192($tp0) + lea 8($tp0), $tp0 + + vpmuludq 32*5-128($ap), $B2, $TEMP2 + vpaddq $TEMP2, $ACC1, $ACC1 + vpmuludq 32*5-128($aap), $B2, $TEMP0 + vpaddq $TEMP0, $ACC2, $ACC2 + vpmuludq 32*6-128($aap), $B2, $TEMP1 + vpaddq $TEMP1, $ACC3, $ACC3 + vpmuludq 32*7-128($aap), $B2, $ACC4 + vpbroadcastq 32*7-128($tpa), $B2 + vpaddq 32*13-448($tp1), $ACC4, $ACC4 + + vmovdqu $ACC1, 32*10-448($tp1) + vmovdqu $ACC2, 32*11-448($tp1) + + vpmuludq 32*6-128($ap), $B1, $TEMP0 + vpaddq $TEMP0, $ACC3, $ACC3 + vpmuludq 32*6-128($aap), $B1, $TEMP1 + vpbroadcastq 32*8-128($tpa), $ACC0 # borrow $ACC0 for $B1 + vpaddq $TEMP1, $ACC4, $ACC4 + vpmuludq 32*7-128($aap), $B1, $ACC5 + vpbroadcastq 32*0+8-128($tpa), $B1 # for next iteration + vpaddq 32*14-448($tp1), $ACC5, $ACC5 + + vmovdqu $ACC3, 32*12-448($tp1) + vmovdqu $ACC4, 32*13-448($tp1) + lea 8($tpa), $tpa + + vpmuludq 32*7-128($ap), $B2, $TEMP0 + vpaddq $TEMP0, $ACC5, $ACC5 + vpmuludq 32*7-128($aap), $B2, $ACC6 + vpaddq 32*15-448($tp1), $ACC6, $ACC6 + + vpmuludq 32*8-128($ap), $ACC0, $ACC7 + vmovdqu $ACC5, 32*14-448($tp1) + vpaddq 32*16-448($tp1), $ACC7, $ACC7 + vmovdqu $ACC6, 32*15-448($tp1) + vmovdqu $ACC7, 32*16-448($tp1) + lea 8($tp1), $tp1 + + dec $i + jnz .LOOP_SQR_1024 +___ +$ZERO = $ACC9; +$TEMP0 = $B1; +$TEMP2 = $B2; +$TEMP3 = $Y1; +$TEMP4 = $Y2; +$code.=<<___; + #we need to fix indexes 32-39 to avoid overflow + vmovdqu 32*8(%rsp), $ACC8 # 32*8-192($tp0), + vmovdqu 32*9(%rsp), $ACC1 # 32*9-192($tp0) + vmovdqu 32*10(%rsp), $ACC2 # 32*10-192($tp0) + lea 192(%rsp), $tp0 # 64+128=192 + + vpsrlq \$29, $ACC8, $TEMP1 + vpand $AND_MASK, $ACC8, $ACC8 + vpsrlq \$29, $ACC1, $TEMP2 + vpand $AND_MASK, $ACC1, $ACC1 + + vpermq \$0x93, $TEMP1, $TEMP1 + vpxor $ZERO, $ZERO, $ZERO + vpermq \$0x93, $TEMP2, $TEMP2 + + vpblendd \$3, $ZERO, $TEMP1, $TEMP0 + vpblendd \$3, $TEMP1, $TEMP2, $TEMP1 + vpaddq $TEMP0, $ACC8, $ACC8 + vpblendd \$3, $TEMP2, $ZERO, $TEMP2 + vpaddq $TEMP1, $ACC1, $ACC1 + vpaddq $TEMP2, $ACC2, $ACC2 + vmovdqu $ACC1, 32*9-192($tp0) + vmovdqu $ACC2, 32*10-192($tp0) + + mov (%rsp), %rax + mov 8(%rsp), $r1 + mov 16(%rsp), $r2 + mov 24(%rsp), $r3 + vmovdqu 32*1(%rsp), $ACC1 + vmovdqu 32*2-192($tp0), $ACC2 + vmovdqu 32*3-192($tp0), $ACC3 + vmovdqu 32*4-192($tp0), $ACC4 + vmovdqu 32*5-192($tp0), $ACC5 + vmovdqu 32*6-192($tp0), $ACC6 + vmovdqu 32*7-192($tp0), $ACC7 + + mov %rax, $r0 + imull $n0, %eax + and \$0x1fffffff, %eax + vmovd %eax, $Y1 + + mov %rax, %rdx + imulq -128($np), %rax + vpbroadcastq $Y1, $Y1 + add %rax, $r0 + mov %rdx, %rax + imulq 8-128($np), %rax + shr \$29, $r0 + add %rax, $r1 + mov %rdx, %rax + imulq 16-128($np), %rax + add $r0, $r1 + add %rax, $r2 + imulq 24-128($np), %rdx + add %rdx, $r3 + + mov $r1, %rax + imull $n0, %eax + and \$0x1fffffff, %eax + + mov \$9, $i + jmp .LOOP_REDUCE_1024 + +.align 32 +.LOOP_REDUCE_1024: + vmovd %eax, $Y2 + vpbroadcastq $Y2, $Y2 + + vpmuludq 32*1-128($np), $Y1, $TEMP0 + mov %rax, %rdx + imulq -128($np), %rax + vpaddq $TEMP0, $ACC1, $ACC1 + add %rax, $r1 + vpmuludq 32*2-128($np), $Y1, $TEMP1 + mov %rdx, %rax + imulq 8-128($np), %rax + vpaddq $TEMP1, $ACC2, $ACC2 + vpmuludq 32*3-128($np), $Y1, $TEMP2 + .byte 0x67 + add %rax, $r2 + .byte 0x67 + mov %rdx, %rax + imulq 16-128($np), %rax + shr \$29, $r1 + vpaddq $TEMP2, $ACC3, $ACC3 + vpmuludq 32*4-128($np), $Y1, $TEMP0 + add %rax, $r3 + add $r1, $r2 + vpaddq $TEMP0, $ACC4, $ACC4 + vpmuludq 32*5-128($np), $Y1, $TEMP1 + mov $r2, %rax + imull $n0, %eax + vpaddq $TEMP1, $ACC5, $ACC5 + vpmuludq 32*6-128($np), $Y1, $TEMP2 + and \$0x1fffffff, %eax + vpaddq $TEMP2, $ACC6, $ACC6 + vpmuludq 32*7-128($np), $Y1, $TEMP0 + vpaddq $TEMP0, $ACC7, $ACC7 + vpmuludq 32*8-128($np), $Y1, $TEMP1 + vmovd %eax, $Y1 + #vmovdqu 32*1-8-128($np), $TEMP2 # moved below + vpaddq $TEMP1, $ACC8, $ACC8 + #vmovdqu 32*2-8-128($np), $TEMP0 # moved below + vpbroadcastq $Y1, $Y1 + + vpmuludq 32*1-8-128($np), $Y2, $TEMP2 # see above + vmovdqu 32*3-8-128($np), $TEMP1 + mov %rax, %rdx + imulq -128($np), %rax + vpaddq $TEMP2, $ACC1, $ACC1 + vpmuludq 32*2-8-128($np), $Y2, $TEMP0 # see above + vmovdqu 32*4-8-128($np), $TEMP2 + add %rax, $r2 + mov %rdx, %rax + imulq 8-128($np), %rax + vpaddq $TEMP0, $ACC2, $ACC2 + add $r3, %rax + shr \$29, $r2 + vpmuludq $Y2, $TEMP1, $TEMP1 + vmovdqu 32*5-8-128($np), $TEMP0 + add $r2, %rax + vpaddq $TEMP1, $ACC3, $ACC3 + vpmuludq $Y2, $TEMP2, $TEMP2 + vmovdqu 32*6-8-128($np), $TEMP1 + .byte 0x67 + mov %rax, $r3 + imull $n0, %eax + vpaddq $TEMP2, $ACC4, $ACC4 + vpmuludq $Y2, $TEMP0, $TEMP0 + .byte 0xc4,0x41,0x7e,0x6f,0x9d,0x58,0x00,0x00,0x00 # vmovdqu 32*7-8-128($np), $TEMP2 + and \$0x1fffffff, %eax + vpaddq $TEMP0, $ACC5, $ACC5 + vpmuludq $Y2, $TEMP1, $TEMP1 + vmovdqu 32*8-8-128($np), $TEMP0 + vpaddq $TEMP1, $ACC6, $ACC6 + vpmuludq $Y2, $TEMP2, $TEMP2 + vmovdqu 32*9-8-128($np), $ACC9 + vmovd %eax, $ACC0 # borrow ACC0 for Y2 + imulq -128($np), %rax + vpaddq $TEMP2, $ACC7, $ACC7 + vpmuludq $Y2, $TEMP0, $TEMP0 + vmovdqu 32*1-16-128($np), $TEMP1 + vpbroadcastq $ACC0, $ACC0 + vpaddq $TEMP0, $ACC8, $ACC8 + vpmuludq $Y2, $ACC9, $ACC9 + vmovdqu 32*2-16-128($np), $TEMP2 + add %rax, $r3 + +___ +($ACC0,$Y2)=($Y2,$ACC0); +$code.=<<___; + vmovdqu 32*1-24-128($np), $ACC0 + vpmuludq $Y1, $TEMP1, $TEMP1 + vmovdqu 32*3-16-128($np), $TEMP0 + vpaddq $TEMP1, $ACC1, $ACC1 + vpmuludq $Y2, $ACC0, $ACC0 + vpmuludq $Y1, $TEMP2, $TEMP2 + .byte 0xc4,0x41,0x7e,0x6f,0xb5,0xf0,0xff,0xff,0xff # vmovdqu 32*4-16-128($np), $TEMP1 + vpaddq $ACC1, $ACC0, $ACC0 + vpaddq $TEMP2, $ACC2, $ACC2 + vpmuludq $Y1, $TEMP0, $TEMP0 + vmovdqu 32*5-16-128($np), $TEMP2 + .byte 0x67 + vmovq $ACC0, %rax + vmovdqu $ACC0, (%rsp) # transfer $r0-$r3 + vpaddq $TEMP0, $ACC3, $ACC3 + vpmuludq $Y1, $TEMP1, $TEMP1 + vmovdqu 32*6-16-128($np), $TEMP0 + vpaddq $TEMP1, $ACC4, $ACC4 + vpmuludq $Y1, $TEMP2, $TEMP2 + vmovdqu 32*7-16-128($np), $TEMP1 + vpaddq $TEMP2, $ACC5, $ACC5 + vpmuludq $Y1, $TEMP0, $TEMP0 + vmovdqu 32*8-16-128($np), $TEMP2 + vpaddq $TEMP0, $ACC6, $ACC6 + vpmuludq $Y1, $TEMP1, $TEMP1 + shr \$29, $r3 + vmovdqu 32*9-16-128($np), $TEMP0 + add $r3, %rax + vpaddq $TEMP1, $ACC7, $ACC7 + vpmuludq $Y1, $TEMP2, $TEMP2 + #vmovdqu 32*2-24-128($np), $TEMP1 # moved below + mov %rax, $r0 + imull $n0, %eax + vpaddq $TEMP2, $ACC8, $ACC8 + vpmuludq $Y1, $TEMP0, $TEMP0 + and \$0x1fffffff, %eax + vmovd %eax, $Y1 + vmovdqu 32*3-24-128($np), $TEMP2 + .byte 0x67 + vpaddq $TEMP0, $ACC9, $ACC9 + vpbroadcastq $Y1, $Y1 + + vpmuludq 32*2-24-128($np), $Y2, $TEMP1 # see above + vmovdqu 32*4-24-128($np), $TEMP0 + mov %rax, %rdx + imulq -128($np), %rax + mov 8(%rsp), $r1 + vpaddq $TEMP1, $ACC2, $ACC1 + vpmuludq $Y2, $TEMP2, $TEMP2 + vmovdqu 32*5-24-128($np), $TEMP1 + add %rax, $r0 + mov %rdx, %rax + imulq 8-128($np), %rax + .byte 0x67 + shr \$29, $r0 + mov 16(%rsp), $r2 + vpaddq $TEMP2, $ACC3, $ACC2 + vpmuludq $Y2, $TEMP0, $TEMP0 + vmovdqu 32*6-24-128($np), $TEMP2 + add %rax, $r1 + mov %rdx, %rax + imulq 16-128($np), %rax + vpaddq $TEMP0, $ACC4, $ACC3 + vpmuludq $Y2, $TEMP1, $TEMP1 + vmovdqu 32*7-24-128($np), $TEMP0 + imulq 24-128($np), %rdx # future $r3 + add %rax, $r2 + lea ($r0,$r1), %rax + vpaddq $TEMP1, $ACC5, $ACC4 + vpmuludq $Y2, $TEMP2, $TEMP2 + vmovdqu 32*8-24-128($np), $TEMP1 + mov %rax, $r1 + imull $n0, %eax + vpmuludq $Y2, $TEMP0, $TEMP0 + vpaddq $TEMP2, $ACC6, $ACC5 + vmovdqu 32*9-24-128($np), $TEMP2 + and \$0x1fffffff, %eax + vpaddq $TEMP0, $ACC7, $ACC6 + vpmuludq $Y2, $TEMP1, $TEMP1 + add 24(%rsp), %rdx + vpaddq $TEMP1, $ACC8, $ACC7 + vpmuludq $Y2, $TEMP2, $TEMP2 + vpaddq $TEMP2, $ACC9, $ACC8 + vmovq $r3, $ACC9 + mov %rdx, $r3 + + dec $i + jnz .LOOP_REDUCE_1024 +___ +($ACC0,$Y2)=($Y2,$ACC0); +$code.=<<___; + lea 448(%rsp), $tp1 # size optimization + vpaddq $ACC9, $Y2, $ACC0 + vpxor $ZERO, $ZERO, $ZERO + + vpaddq 32*9-192($tp0), $ACC0, $ACC0 + vpaddq 32*10-448($tp1), $ACC1, $ACC1 + vpaddq 32*11-448($tp1), $ACC2, $ACC2 + vpaddq 32*12-448($tp1), $ACC3, $ACC3 + vpaddq 32*13-448($tp1), $ACC4, $ACC4 + vpaddq 32*14-448($tp1), $ACC5, $ACC5 + vpaddq 32*15-448($tp1), $ACC6, $ACC6 + vpaddq 32*16-448($tp1), $ACC7, $ACC7 + vpaddq 32*17-448($tp1), $ACC8, $ACC8 + + vpsrlq \$29, $ACC0, $TEMP1 + vpand $AND_MASK, $ACC0, $ACC0 + vpsrlq \$29, $ACC1, $TEMP2 + vpand $AND_MASK, $ACC1, $ACC1 + vpsrlq \$29, $ACC2, $TEMP3 + vpermq \$0x93, $TEMP1, $TEMP1 + vpand $AND_MASK, $ACC2, $ACC2 + vpsrlq \$29, $ACC3, $TEMP4 + vpermq \$0x93, $TEMP2, $TEMP2 + vpand $AND_MASK, $ACC3, $ACC3 + vpermq \$0x93, $TEMP3, $TEMP3 + + vpblendd \$3, $ZERO, $TEMP1, $TEMP0 + vpermq \$0x93, $TEMP4, $TEMP4 + vpblendd \$3, $TEMP1, $TEMP2, $TEMP1 + vpaddq $TEMP0, $ACC0, $ACC0 + vpblendd \$3, $TEMP2, $TEMP3, $TEMP2 + vpaddq $TEMP1, $ACC1, $ACC1 + vpblendd \$3, $TEMP3, $TEMP4, $TEMP3 + vpaddq $TEMP2, $ACC2, $ACC2 + vpblendd \$3, $TEMP4, $ZERO, $TEMP4 + vpaddq $TEMP3, $ACC3, $ACC3 + vpaddq $TEMP4, $ACC4, $ACC4 + + vpsrlq \$29, $ACC0, $TEMP1 + vpand $AND_MASK, $ACC0, $ACC0 + vpsrlq \$29, $ACC1, $TEMP2 + vpand $AND_MASK, $ACC1, $ACC1 + vpsrlq \$29, $ACC2, $TEMP3 + vpermq \$0x93, $TEMP1, $TEMP1 + vpand $AND_MASK, $ACC2, $ACC2 + vpsrlq \$29, $ACC3, $TEMP4 + vpermq \$0x93, $TEMP2, $TEMP2 + vpand $AND_MASK, $ACC3, $ACC3 + vpermq \$0x93, $TEMP3, $TEMP3 + + vpblendd \$3, $ZERO, $TEMP1, $TEMP0 + vpermq \$0x93, $TEMP4, $TEMP4 + vpblendd \$3, $TEMP1, $TEMP2, $TEMP1 + vpaddq $TEMP0, $ACC0, $ACC0 + vpblendd \$3, $TEMP2, $TEMP3, $TEMP2 + vpaddq $TEMP1, $ACC1, $ACC1 + vmovdqu $ACC0, 32*0-128($rp) + vpblendd \$3, $TEMP3, $TEMP4, $TEMP3 + vpaddq $TEMP2, $ACC2, $ACC2 + vmovdqu $ACC1, 32*1-128($rp) + vpblendd \$3, $TEMP4, $ZERO, $TEMP4 + vpaddq $TEMP3, $ACC3, $ACC3 + vmovdqu $ACC2, 32*2-128($rp) + vpaddq $TEMP4, $ACC4, $ACC4 + vmovdqu $ACC3, 32*3-128($rp) +___ +$TEMP5=$ACC0; +$code.=<<___; + vpsrlq \$29, $ACC4, $TEMP1 + vpand $AND_MASK, $ACC4, $ACC4 + vpsrlq \$29, $ACC5, $TEMP2 + vpand $AND_MASK, $ACC5, $ACC5 + vpsrlq \$29, $ACC6, $TEMP3 + vpermq \$0x93, $TEMP1, $TEMP1 + vpand $AND_MASK, $ACC6, $ACC6 + vpsrlq \$29, $ACC7, $TEMP4 + vpermq \$0x93, $TEMP2, $TEMP2 + vpand $AND_MASK, $ACC7, $ACC7 + vpsrlq \$29, $ACC8, $TEMP5 + vpermq \$0x93, $TEMP3, $TEMP3 + vpand $AND_MASK, $ACC8, $ACC8 + vpermq \$0x93, $TEMP4, $TEMP4 + + vpblendd \$3, $ZERO, $TEMP1, $TEMP0 + vpermq \$0x93, $TEMP5, $TEMP5 + vpblendd \$3, $TEMP1, $TEMP2, $TEMP1 + vpaddq $TEMP0, $ACC4, $ACC4 + vpblendd \$3, $TEMP2, $TEMP3, $TEMP2 + vpaddq $TEMP1, $ACC5, $ACC5 + vpblendd \$3, $TEMP3, $TEMP4, $TEMP3 + vpaddq $TEMP2, $ACC6, $ACC6 + vpblendd \$3, $TEMP4, $TEMP5, $TEMP4 + vpaddq $TEMP3, $ACC7, $ACC7 + vpaddq $TEMP4, $ACC8, $ACC8 + + vpsrlq \$29, $ACC4, $TEMP1 + vpand $AND_MASK, $ACC4, $ACC4 + vpsrlq \$29, $ACC5, $TEMP2 + vpand $AND_MASK, $ACC5, $ACC5 + vpsrlq \$29, $ACC6, $TEMP3 + vpermq \$0x93, $TEMP1, $TEMP1 + vpand $AND_MASK, $ACC6, $ACC6 + vpsrlq \$29, $ACC7, $TEMP4 + vpermq \$0x93, $TEMP2, $TEMP2 + vpand $AND_MASK, $ACC7, $ACC7 + vpsrlq \$29, $ACC8, $TEMP5 + vpermq \$0x93, $TEMP3, $TEMP3 + vpand $AND_MASK, $ACC8, $ACC8 + vpermq \$0x93, $TEMP4, $TEMP4 + + vpblendd \$3, $ZERO, $TEMP1, $TEMP0 + vpermq \$0x93, $TEMP5, $TEMP5 + vpblendd \$3, $TEMP1, $TEMP2, $TEMP1 + vpaddq $TEMP0, $ACC4, $ACC4 + vpblendd \$3, $TEMP2, $TEMP3, $TEMP2 + vpaddq $TEMP1, $ACC5, $ACC5 + vmovdqu $ACC4, 32*4-128($rp) + vpblendd \$3, $TEMP3, $TEMP4, $TEMP3 + vpaddq $TEMP2, $ACC6, $ACC6 + vmovdqu $ACC5, 32*5-128($rp) + vpblendd \$3, $TEMP4, $TEMP5, $TEMP4 + vpaddq $TEMP3, $ACC7, $ACC7 + vmovdqu $ACC6, 32*6-128($rp) + vpaddq $TEMP4, $ACC8, $ACC8 + vmovdqu $ACC7, 32*7-128($rp) + vmovdqu $ACC8, 32*8-128($rp) + + mov $rp, $ap + dec $rep + jne .LOOP_GRANDE_SQR_1024 + + vzeroall + mov %rbp, %rax +___ +$code.=<<___ if ($win64); + movaps -0xd8(%rax),%xmm6 + movaps -0xc8(%rax),%xmm7 + movaps -0xb8(%rax),%xmm8 + movaps -0xa8(%rax),%xmm9 + movaps -0x98(%rax),%xmm10 + movaps -0x88(%rax),%xmm11 + movaps -0x78(%rax),%xmm12 + movaps -0x68(%rax),%xmm13 + movaps -0x58(%rax),%xmm14 + movaps -0x48(%rax),%xmm15 +___ +$code.=<<___; + mov -48(%rax),%r15 + mov -40(%rax),%r14 + mov -32(%rax),%r13 + mov -24(%rax),%r12 + mov -16(%rax),%rbp + mov -8(%rax),%rbx + lea (%rax),%rsp # restore %rsp +.Lsqr_1024_epilogue: + ret +.size rsaz_1024_sqr_avx2,.-rsaz_1024_sqr_avx2 +___ +} + +{ # void AMM_WW( +my $rp="%rdi"; # BN_ULONG *rp, +my $ap="%rsi"; # const BN_ULONG *ap, +my $bp="%rdx"; # const BN_ULONG *bp, +my $np="%rcx"; # const BN_ULONG *np, +my $n0="%r8d"; # unsigned int n0); + +# The registers that hold the accumulated redundant result +# The AMM works on 1024 bit operands, and redundant word size is 29 +# Therefore: ceil(1024/29)/4 = 9 +my $ACC0="%ymm0"; +my $ACC1="%ymm1"; +my $ACC2="%ymm2"; +my $ACC3="%ymm3"; +my $ACC4="%ymm4"; +my $ACC5="%ymm5"; +my $ACC6="%ymm6"; +my $ACC7="%ymm7"; +my $ACC8="%ymm8"; +my $ACC9="%ymm9"; + +# Registers that hold the broadcasted words of multiplier, currently used +my $Bi="%ymm10"; +my $Yi="%ymm11"; + +# Helper registers +my $TEMP0=$ACC0; +my $TEMP1="%ymm12"; +my $TEMP2="%ymm13"; +my $ZERO="%ymm14"; +my $AND_MASK="%ymm15"; + +# alu registers that hold the first words of the ACC +my $r0="%r9"; +my $r1="%r10"; +my $r2="%r11"; +my $r3="%r12"; + +my $i="%r14d"; +my $tmp="%r15"; + +$bp="%r13"; # reassigned argument + +$code.=<<___; +.globl rsaz_1024_mul_avx2 +.type rsaz_1024_mul_avx2,\@function,5 +.align 64 +rsaz_1024_mul_avx2: + lea (%rsp), %rax + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 +___ +$code.=<<___ if ($win64); + vzeroupper + lea -0xa8(%rsp),%rsp + vmovaps %xmm6,-0xd8(%rax) + vmovaps %xmm7,-0xc8(%rax) + vmovaps %xmm8,-0xb8(%rax) + vmovaps %xmm9,-0xa8(%rax) + vmovaps %xmm10,-0x98(%rax) + vmovaps %xmm11,-0x88(%rax) + vmovaps %xmm12,-0x78(%rax) + vmovaps %xmm13,-0x68(%rax) + vmovaps %xmm14,-0x58(%rax) + vmovaps %xmm15,-0x48(%rax) +.Lmul_1024_body: +___ +$code.=<<___; + mov %rax,%rbp + vzeroall + mov %rdx, $bp # reassigned argument + sub \$64,%rsp + + # unaligned 256-bit load that crosses page boundary can + # cause severe performance degradation here, so if $ap does + # cross page boundary, swap it with $bp [meaning that caller + # is advised to lay down $ap and $bp next to each other, so + # that only one can cross page boundary]. + .byte 0x67,0x67 + mov $ap, $tmp + and \$4095, $tmp + add \$32*10, $tmp + shr \$12, $tmp + mov $ap, $tmp + cmovnz $bp, $ap + cmovnz $tmp, $bp + + mov $np, $tmp + sub \$-128,$ap # size optimization + sub \$-128,$np + sub \$-128,$rp + + and \$4095, $tmp # see if $np crosses page + add \$32*10, $tmp + .byte 0x67,0x67 + shr \$12, $tmp + jz .Lmul_1024_no_n_copy + + # unaligned 256-bit load that crosses page boundary can + # cause severe performance degradation here, so if $np does + # cross page boundary, copy it to stack and make sure stack + # frame doesn't... + sub \$32*10,%rsp + vmovdqu 32*0-128($np), $ACC0 + and \$-512, %rsp + vmovdqu 32*1-128($np), $ACC1 + vmovdqu 32*2-128($np), $ACC2 + vmovdqu 32*3-128($np), $ACC3 + vmovdqu 32*4-128($np), $ACC4 + vmovdqu 32*5-128($np), $ACC5 + vmovdqu 32*6-128($np), $ACC6 + vmovdqu 32*7-128($np), $ACC7 + vmovdqu 32*8-128($np), $ACC8 + lea 64+128(%rsp),$np + vmovdqu $ACC0, 32*0-128($np) + vpxor $ACC0, $ACC0, $ACC0 + vmovdqu $ACC1, 32*1-128($np) + vpxor $ACC1, $ACC1, $ACC1 + vmovdqu $ACC2, 32*2-128($np) + vpxor $ACC2, $ACC2, $ACC2 + vmovdqu $ACC3, 32*3-128($np) + vpxor $ACC3, $ACC3, $ACC3 + vmovdqu $ACC4, 32*4-128($np) + vpxor $ACC4, $ACC4, $ACC4 + vmovdqu $ACC5, 32*5-128($np) + vpxor $ACC5, $ACC5, $ACC5 + vmovdqu $ACC6, 32*6-128($np) + vpxor $ACC6, $ACC6, $ACC6 + vmovdqu $ACC7, 32*7-128($np) + vpxor $ACC7, $ACC7, $ACC7 + vmovdqu $ACC8, 32*8-128($np) + vmovdqa $ACC0, $ACC8 + vmovdqu $ACC9, 32*9-128($np) # $ACC9 is zero after vzeroall +.Lmul_1024_no_n_copy: + and \$-64,%rsp + + mov ($bp), %rbx + vpbroadcastq ($bp), $Bi + vmovdqu $ACC0, (%rsp) # clear top of stack + xor $r0, $r0 + .byte 0x67 + xor $r1, $r1 + xor $r2, $r2 + xor $r3, $r3 + + vmovdqu .Land_mask(%rip), $AND_MASK + mov \$9, $i + vmovdqu $ACC9, 32*9-128($rp) # $ACC9 is zero after vzeroall + jmp .Loop_mul_1024 + +.align 32 +.Loop_mul_1024: + vpsrlq \$29, $ACC3, $ACC9 # correct $ACC3(*) + mov %rbx, %rax + imulq -128($ap), %rax + add $r0, %rax + mov %rbx, $r1 + imulq 8-128($ap), $r1 + add 8(%rsp), $r1 + + mov %rax, $r0 + imull $n0, %eax + and \$0x1fffffff, %eax + + mov %rbx, $r2 + imulq 16-128($ap), $r2 + add 16(%rsp), $r2 + + mov %rbx, $r3 + imulq 24-128($ap), $r3 + add 24(%rsp), $r3 + vpmuludq 32*1-128($ap),$Bi,$TEMP0 + vmovd %eax, $Yi + vpaddq $TEMP0,$ACC1,$ACC1 + vpmuludq 32*2-128($ap),$Bi,$TEMP1 + vpbroadcastq $Yi, $Yi + vpaddq $TEMP1,$ACC2,$ACC2 + vpmuludq 32*3-128($ap),$Bi,$TEMP2 + vpand $AND_MASK, $ACC3, $ACC3 # correct $ACC3 + vpaddq $TEMP2,$ACC3,$ACC3 + vpmuludq 32*4-128($ap),$Bi,$TEMP0 + vpaddq $TEMP0,$ACC4,$ACC4 + vpmuludq 32*5-128($ap),$Bi,$TEMP1 + vpaddq $TEMP1,$ACC5,$ACC5 + vpmuludq 32*6-128($ap),$Bi,$TEMP2 + vpaddq $TEMP2,$ACC6,$ACC6 + vpmuludq 32*7-128($ap),$Bi,$TEMP0 + vpermq \$0x93, $ACC9, $ACC9 # correct $ACC3 + vpaddq $TEMP0,$ACC7,$ACC7 + vpmuludq 32*8-128($ap),$Bi,$TEMP1 + vpbroadcastq 8($bp), $Bi + vpaddq $TEMP1,$ACC8,$ACC8 + + mov %rax,%rdx + imulq -128($np),%rax + add %rax,$r0 + mov %rdx,%rax + imulq 8-128($np),%rax + add %rax,$r1 + mov %rdx,%rax + imulq 16-128($np),%rax + add %rax,$r2 + shr \$29, $r0 + imulq 24-128($np),%rdx + add %rdx,$r3 + add $r0, $r1 + + vpmuludq 32*1-128($np),$Yi,$TEMP2 + vmovq $Bi, %rbx + vpaddq $TEMP2,$ACC1,$ACC1 + vpmuludq 32*2-128($np),$Yi,$TEMP0 + vpaddq $TEMP0,$ACC2,$ACC2 + vpmuludq 32*3-128($np),$Yi,$TEMP1 + vpaddq $TEMP1,$ACC3,$ACC3 + vpmuludq 32*4-128($np),$Yi,$TEMP2 + vpaddq $TEMP2,$ACC4,$ACC4 + vpmuludq 32*5-128($np),$Yi,$TEMP0 + vpaddq $TEMP0,$ACC5,$ACC5 + vpmuludq 32*6-128($np),$Yi,$TEMP1 + vpaddq $TEMP1,$ACC6,$ACC6 + vpmuludq 32*7-128($np),$Yi,$TEMP2 + vpblendd \$3, $ZERO, $ACC9, $ACC9 # correct $ACC3 + vpaddq $TEMP2,$ACC7,$ACC7 + vpmuludq 32*8-128($np),$Yi,$TEMP0 + vpaddq $ACC9, $ACC3, $ACC3 # correct $ACC3 + vpaddq $TEMP0,$ACC8,$ACC8 + + mov %rbx, %rax + imulq -128($ap),%rax + add %rax,$r1 + vmovdqu -8+32*1-128($ap),$TEMP1 + mov %rbx, %rax + imulq 8-128($ap),%rax + add %rax,$r2 + vmovdqu -8+32*2-128($ap),$TEMP2 + + mov $r1, %rax + imull $n0, %eax + and \$0x1fffffff, %eax + + imulq 16-128($ap),%rbx + add %rbx,$r3 + vpmuludq $Bi,$TEMP1,$TEMP1 + vmovd %eax, $Yi + vmovdqu -8+32*3-128($ap),$TEMP0 + vpaddq $TEMP1,$ACC1,$ACC1 + vpmuludq $Bi,$TEMP2,$TEMP2 + vpbroadcastq $Yi, $Yi + vmovdqu -8+32*4-128($ap),$TEMP1 + vpaddq $TEMP2,$ACC2,$ACC2 + vpmuludq $Bi,$TEMP0,$TEMP0 + vmovdqu -8+32*5-128($ap),$TEMP2 + vpaddq $TEMP0,$ACC3,$ACC3 + vpmuludq $Bi,$TEMP1,$TEMP1 + vmovdqu -8+32*6-128($ap),$TEMP0 + vpaddq $TEMP1,$ACC4,$ACC4 + vpmuludq $Bi,$TEMP2,$TEMP2 + vmovdqu -8+32*7-128($ap),$TEMP1 + vpaddq $TEMP2,$ACC5,$ACC5 + vpmuludq $Bi,$TEMP0,$TEMP0 + vmovdqu -8+32*8-128($ap),$TEMP2 + vpaddq $TEMP0,$ACC6,$ACC6 + vpmuludq $Bi,$TEMP1,$TEMP1 + vmovdqu -8+32*9-128($ap),$ACC9 + vpaddq $TEMP1,$ACC7,$ACC7 + vpmuludq $Bi,$TEMP2,$TEMP2 + vpaddq $TEMP2,$ACC8,$ACC8 + vpmuludq $Bi,$ACC9,$ACC9 + vpbroadcastq 16($bp), $Bi + + mov %rax,%rdx + imulq -128($np),%rax + add %rax,$r1 + vmovdqu -8+32*1-128($np),$TEMP0 + mov %rdx,%rax + imulq 8-128($np),%rax + add %rax,$r2 + vmovdqu -8+32*2-128($np),$TEMP1 + shr \$29, $r1 + imulq 16-128($np),%rdx + add %rdx,$r3 + add $r1, $r2 + + vpmuludq $Yi,$TEMP0,$TEMP0 + vmovq $Bi, %rbx + vmovdqu -8+32*3-128($np),$TEMP2 + vpaddq $TEMP0,$ACC1,$ACC1 + vpmuludq $Yi,$TEMP1,$TEMP1 + vmovdqu -8+32*4-128($np),$TEMP0 + vpaddq $TEMP1,$ACC2,$ACC2 + vpmuludq $Yi,$TEMP2,$TEMP2 + vmovdqu -8+32*5-128($np),$TEMP1 + vpaddq $TEMP2,$ACC3,$ACC3 + vpmuludq $Yi,$TEMP0,$TEMP0 + vmovdqu -8+32*6-128($np),$TEMP2 + vpaddq $TEMP0,$ACC4,$ACC4 + vpmuludq $Yi,$TEMP1,$TEMP1 + vmovdqu -8+32*7-128($np),$TEMP0 + vpaddq $TEMP1,$ACC5,$ACC5 + vpmuludq $Yi,$TEMP2,$TEMP2 + vmovdqu -8+32*8-128($np),$TEMP1 + vpaddq $TEMP2,$ACC6,$ACC6 + vpmuludq $Yi,$TEMP0,$TEMP0 + vmovdqu -8+32*9-128($np),$TEMP2 + vpaddq $TEMP0,$ACC7,$ACC7 + vpmuludq $Yi,$TEMP1,$TEMP1 + vpaddq $TEMP1,$ACC8,$ACC8 + vpmuludq $Yi,$TEMP2,$TEMP2 + vpaddq $TEMP2,$ACC9,$ACC9 + + vmovdqu -16+32*1-128($ap),$TEMP0 + mov %rbx,%rax + imulq -128($ap),%rax + add $r2,%rax + + vmovdqu -16+32*2-128($ap),$TEMP1 + mov %rax,$r2 + imull $n0, %eax + and \$0x1fffffff, %eax + + imulq 8-128($ap),%rbx + add %rbx,$r3 + vpmuludq $Bi,$TEMP0,$TEMP0 + vmovd %eax, $Yi + vmovdqu -16+32*3-128($ap),$TEMP2 + vpaddq $TEMP0,$ACC1,$ACC1 + vpmuludq $Bi,$TEMP1,$TEMP1 + vpbroadcastq $Yi, $Yi + vmovdqu -16+32*4-128($ap),$TEMP0 + vpaddq $TEMP1,$ACC2,$ACC2 + vpmuludq $Bi,$TEMP2,$TEMP2 + vmovdqu -16+32*5-128($ap),$TEMP1 + vpaddq $TEMP2,$ACC3,$ACC3 + vpmuludq $Bi,$TEMP0,$TEMP0 + vmovdqu -16+32*6-128($ap),$TEMP2 + vpaddq $TEMP0,$ACC4,$ACC4 + vpmuludq $Bi,$TEMP1,$TEMP1 + vmovdqu -16+32*7-128($ap),$TEMP0 + vpaddq $TEMP1,$ACC5,$ACC5 + vpmuludq $Bi,$TEMP2,$TEMP2 + vmovdqu -16+32*8-128($ap),$TEMP1 + vpaddq $TEMP2,$ACC6,$ACC6 + vpmuludq $Bi,$TEMP0,$TEMP0 + vmovdqu -16+32*9-128($ap),$TEMP2 + vpaddq $TEMP0,$ACC7,$ACC7 + vpmuludq $Bi,$TEMP1,$TEMP1 + vpaddq $TEMP1,$ACC8,$ACC8 + vpmuludq $Bi,$TEMP2,$TEMP2 + vpbroadcastq 24($bp), $Bi + vpaddq $TEMP2,$ACC9,$ACC9 + + vmovdqu -16+32*1-128($np),$TEMP0 + mov %rax,%rdx + imulq -128($np),%rax + add %rax,$r2 + vmovdqu -16+32*2-128($np),$TEMP1 + imulq 8-128($np),%rdx + add %rdx,$r3 + shr \$29, $r2 + + vpmuludq $Yi,$TEMP0,$TEMP0 + vmovq $Bi, %rbx + vmovdqu -16+32*3-128($np),$TEMP2 + vpaddq $TEMP0,$ACC1,$ACC1 + vpmuludq $Yi,$TEMP1,$TEMP1 + vmovdqu -16+32*4-128($np),$TEMP0 + vpaddq $TEMP1,$ACC2,$ACC2 + vpmuludq $Yi,$TEMP2,$TEMP2 + vmovdqu -16+32*5-128($np),$TEMP1 + vpaddq $TEMP2,$ACC3,$ACC3 + vpmuludq $Yi,$TEMP0,$TEMP0 + vmovdqu -16+32*6-128($np),$TEMP2 + vpaddq $TEMP0,$ACC4,$ACC4 + vpmuludq $Yi,$TEMP1,$TEMP1 + vmovdqu -16+32*7-128($np),$TEMP0 + vpaddq $TEMP1,$ACC5,$ACC5 + vpmuludq $Yi,$TEMP2,$TEMP2 + vmovdqu -16+32*8-128($np),$TEMP1 + vpaddq $TEMP2,$ACC6,$ACC6 + vpmuludq $Yi,$TEMP0,$TEMP0 + vmovdqu -16+32*9-128($np),$TEMP2 + vpaddq $TEMP0,$ACC7,$ACC7 + vpmuludq $Yi,$TEMP1,$TEMP1 + vmovdqu -24+32*1-128($ap),$TEMP0 + vpaddq $TEMP1,$ACC8,$ACC8 + vpmuludq $Yi,$TEMP2,$TEMP2 + vmovdqu -24+32*2-128($ap),$TEMP1 + vpaddq $TEMP2,$ACC9,$ACC9 + + add $r2, $r3 + imulq -128($ap),%rbx + add %rbx,$r3 + + mov $r3, %rax + imull $n0, %eax + and \$0x1fffffff, %eax + + vpmuludq $Bi,$TEMP0,$TEMP0 + vmovd %eax, $Yi + vmovdqu -24+32*3-128($ap),$TEMP2 + vpaddq $TEMP0,$ACC1,$ACC1 + vpmuludq $Bi,$TEMP1,$TEMP1 + vpbroadcastq $Yi, $Yi + vmovdqu -24+32*4-128($ap),$TEMP0 + vpaddq $TEMP1,$ACC2,$ACC2 + vpmuludq $Bi,$TEMP2,$TEMP2 + vmovdqu -24+32*5-128($ap),$TEMP1 + vpaddq $TEMP2,$ACC3,$ACC3 + vpmuludq $Bi,$TEMP0,$TEMP0 + vmovdqu -24+32*6-128($ap),$TEMP2 + vpaddq $TEMP0,$ACC4,$ACC4 + vpmuludq $Bi,$TEMP1,$TEMP1 + vmovdqu -24+32*7-128($ap),$TEMP0 + vpaddq $TEMP1,$ACC5,$ACC5 + vpmuludq $Bi,$TEMP2,$TEMP2 + vmovdqu -24+32*8-128($ap),$TEMP1 + vpaddq $TEMP2,$ACC6,$ACC6 + vpmuludq $Bi,$TEMP0,$TEMP0 + vmovdqu -24+32*9-128($ap),$TEMP2 + vpaddq $TEMP0,$ACC7,$ACC7 + vpmuludq $Bi,$TEMP1,$TEMP1 + vpaddq $TEMP1,$ACC8,$ACC8 + vpmuludq $Bi,$TEMP2,$TEMP2 + vpbroadcastq 32($bp), $Bi + vpaddq $TEMP2,$ACC9,$ACC9 + add \$32, $bp # $bp++ + + vmovdqu -24+32*1-128($np),$TEMP0 + imulq -128($np),%rax + add %rax,$r3 + shr \$29, $r3 + + vmovdqu -24+32*2-128($np),$TEMP1 + vpmuludq $Yi,$TEMP0,$TEMP0 + vmovq $Bi, %rbx + vmovdqu -24+32*3-128($np),$TEMP2 + vpaddq $TEMP0,$ACC1,$ACC0 # $ACC0==$TEMP0 + vpmuludq $Yi,$TEMP1,$TEMP1 + vmovdqu $ACC0, (%rsp) # transfer $r0-$r3 + vpaddq $TEMP1,$ACC2,$ACC1 + vmovdqu -24+32*4-128($np),$TEMP0 + vpmuludq $Yi,$TEMP2,$TEMP2 + vmovdqu -24+32*5-128($np),$TEMP1 + vpaddq $TEMP2,$ACC3,$ACC2 + vpmuludq $Yi,$TEMP0,$TEMP0 + vmovdqu -24+32*6-128($np),$TEMP2 + vpaddq $TEMP0,$ACC4,$ACC3 + vpmuludq $Yi,$TEMP1,$TEMP1 + vmovdqu -24+32*7-128($np),$TEMP0 + vpaddq $TEMP1,$ACC5,$ACC4 + vpmuludq $Yi,$TEMP2,$TEMP2 + vmovdqu -24+32*8-128($np),$TEMP1 + vpaddq $TEMP2,$ACC6,$ACC5 + vpmuludq $Yi,$TEMP0,$TEMP0 + vmovdqu -24+32*9-128($np),$TEMP2 + mov $r3, $r0 + vpaddq $TEMP0,$ACC7,$ACC6 + vpmuludq $Yi,$TEMP1,$TEMP1 + add (%rsp), $r0 + vpaddq $TEMP1,$ACC8,$ACC7 + vpmuludq $Yi,$TEMP2,$TEMP2 + vmovq $r3, $TEMP1 + vpaddq $TEMP2,$ACC9,$ACC8 + + dec $i + jnz .Loop_mul_1024 +___ + +# (*) Original implementation was correcting ACC1-ACC3 for overflow +# after 7 loop runs, or after 28 iterations, or 56 additions. +# But as we underutilize resources, it's possible to correct in +# each iteration with marginal performance loss. But then, as +# we do it in each iteration, we can correct less digits, and +# avoid performance penalties completely. Also note that we +# correct only three digits out of four. This works because +# most significant digit is subjected to less additions. + +$TEMP0 = $ACC9; +$TEMP3 = $Bi; +$TEMP4 = $Yi; +$code.=<<___; + vpermq \$0, $AND_MASK, $AND_MASK + vpaddq (%rsp), $TEMP1, $ACC0 + + vpsrlq \$29, $ACC0, $TEMP1 + vpand $AND_MASK, $ACC0, $ACC0 + vpsrlq \$29, $ACC1, $TEMP2 + vpand $AND_MASK, $ACC1, $ACC1 + vpsrlq \$29, $ACC2, $TEMP3 + vpermq \$0x93, $TEMP1, $TEMP1 + vpand $AND_MASK, $ACC2, $ACC2 + vpsrlq \$29, $ACC3, $TEMP4 + vpermq \$0x93, $TEMP2, $TEMP2 + vpand $AND_MASK, $ACC3, $ACC3 + + vpblendd \$3, $ZERO, $TEMP1, $TEMP0 + vpermq \$0x93, $TEMP3, $TEMP3 + vpblendd \$3, $TEMP1, $TEMP2, $TEMP1 + vpermq \$0x93, $TEMP4, $TEMP4 + vpaddq $TEMP0, $ACC0, $ACC0 + vpblendd \$3, $TEMP2, $TEMP3, $TEMP2 + vpaddq $TEMP1, $ACC1, $ACC1 + vpblendd \$3, $TEMP3, $TEMP4, $TEMP3 + vpaddq $TEMP2, $ACC2, $ACC2 + vpblendd \$3, $TEMP4, $ZERO, $TEMP4 + vpaddq $TEMP3, $ACC3, $ACC3 + vpaddq $TEMP4, $ACC4, $ACC4 + + vpsrlq \$29, $ACC0, $TEMP1 + vpand $AND_MASK, $ACC0, $ACC0 + vpsrlq \$29, $ACC1, $TEMP2 + vpand $AND_MASK, $ACC1, $ACC1 + vpsrlq \$29, $ACC2, $TEMP3 + vpermq \$0x93, $TEMP1, $TEMP1 + vpand $AND_MASK, $ACC2, $ACC2 + vpsrlq \$29, $ACC3, $TEMP4 + vpermq \$0x93, $TEMP2, $TEMP2 + vpand $AND_MASK, $ACC3, $ACC3 + vpermq \$0x93, $TEMP3, $TEMP3 + + vpblendd \$3, $ZERO, $TEMP1, $TEMP0 + vpermq \$0x93, $TEMP4, $TEMP4 + vpblendd \$3, $TEMP1, $TEMP2, $TEMP1 + vpaddq $TEMP0, $ACC0, $ACC0 + vpblendd \$3, $TEMP2, $TEMP3, $TEMP2 + vpaddq $TEMP1, $ACC1, $ACC1 + vpblendd \$3, $TEMP3, $TEMP4, $TEMP3 + vpaddq $TEMP2, $ACC2, $ACC2 + vpblendd \$3, $TEMP4, $ZERO, $TEMP4 + vpaddq $TEMP3, $ACC3, $ACC3 + vpaddq $TEMP4, $ACC4, $ACC4 + + vmovdqu $ACC0, 0-128($rp) + vmovdqu $ACC1, 32-128($rp) + vmovdqu $ACC2, 64-128($rp) + vmovdqu $ACC3, 96-128($rp) +___ + +$TEMP5=$ACC0; +$code.=<<___; + vpsrlq \$29, $ACC4, $TEMP1 + vpand $AND_MASK, $ACC4, $ACC4 + vpsrlq \$29, $ACC5, $TEMP2 + vpand $AND_MASK, $ACC5, $ACC5 + vpsrlq \$29, $ACC6, $TEMP3 + vpermq \$0x93, $TEMP1, $TEMP1 + vpand $AND_MASK, $ACC6, $ACC6 + vpsrlq \$29, $ACC7, $TEMP4 + vpermq \$0x93, $TEMP2, $TEMP2 + vpand $AND_MASK, $ACC7, $ACC7 + vpsrlq \$29, $ACC8, $TEMP5 + vpermq \$0x93, $TEMP3, $TEMP3 + vpand $AND_MASK, $ACC8, $ACC8 + vpermq \$0x93, $TEMP4, $TEMP4 + + vpblendd \$3, $ZERO, $TEMP1, $TEMP0 + vpermq \$0x93, $TEMP5, $TEMP5 + vpblendd \$3, $TEMP1, $TEMP2, $TEMP1 + vpaddq $TEMP0, $ACC4, $ACC4 + vpblendd \$3, $TEMP2, $TEMP3, $TEMP2 + vpaddq $TEMP1, $ACC5, $ACC5 + vpblendd \$3, $TEMP3, $TEMP4, $TEMP3 + vpaddq $TEMP2, $ACC6, $ACC6 + vpblendd \$3, $TEMP4, $TEMP5, $TEMP4 + vpaddq $TEMP3, $ACC7, $ACC7 + vpaddq $TEMP4, $ACC8, $ACC8 + + vpsrlq \$29, $ACC4, $TEMP1 + vpand $AND_MASK, $ACC4, $ACC4 + vpsrlq \$29, $ACC5, $TEMP2 + vpand $AND_MASK, $ACC5, $ACC5 + vpsrlq \$29, $ACC6, $TEMP3 + vpermq \$0x93, $TEMP1, $TEMP1 + vpand $AND_MASK, $ACC6, $ACC6 + vpsrlq \$29, $ACC7, $TEMP4 + vpermq \$0x93, $TEMP2, $TEMP2 + vpand $AND_MASK, $ACC7, $ACC7 + vpsrlq \$29, $ACC8, $TEMP5 + vpermq \$0x93, $TEMP3, $TEMP3 + vpand $AND_MASK, $ACC8, $ACC8 + vpermq \$0x93, $TEMP4, $TEMP4 + + vpblendd \$3, $ZERO, $TEMP1, $TEMP0 + vpermq \$0x93, $TEMP5, $TEMP5 + vpblendd \$3, $TEMP1, $TEMP2, $TEMP1 + vpaddq $TEMP0, $ACC4, $ACC4 + vpblendd \$3, $TEMP2, $TEMP3, $TEMP2 + vpaddq $TEMP1, $ACC5, $ACC5 + vpblendd \$3, $TEMP3, $TEMP4, $TEMP3 + vpaddq $TEMP2, $ACC6, $ACC6 + vpblendd \$3, $TEMP4, $TEMP5, $TEMP4 + vpaddq $TEMP3, $ACC7, $ACC7 + vpaddq $TEMP4, $ACC8, $ACC8 + + vmovdqu $ACC4, 128-128($rp) + vmovdqu $ACC5, 160-128($rp) + vmovdqu $ACC6, 192-128($rp) + vmovdqu $ACC7, 224-128($rp) + vmovdqu $ACC8, 256-128($rp) + vzeroupper + + mov %rbp, %rax +___ +$code.=<<___ if ($win64); + movaps -0xd8(%rax),%xmm6 + movaps -0xc8(%rax),%xmm7 + movaps -0xb8(%rax),%xmm8 + movaps -0xa8(%rax),%xmm9 + movaps -0x98(%rax),%xmm10 + movaps -0x88(%rax),%xmm11 + movaps -0x78(%rax),%xmm12 + movaps -0x68(%rax),%xmm13 + movaps -0x58(%rax),%xmm14 + movaps -0x48(%rax),%xmm15 +___ +$code.=<<___; + mov -48(%rax),%r15 + mov -40(%rax),%r14 + mov -32(%rax),%r13 + mov -24(%rax),%r12 + mov -16(%rax),%rbp + mov -8(%rax),%rbx + lea (%rax),%rsp # restore %rsp +.Lmul_1024_epilogue: + ret +.size rsaz_1024_mul_avx2,.-rsaz_1024_mul_avx2 +___ +} +{ +my ($out,$inp) = $win64 ? ("%rcx","%rdx") : ("%rdi","%rsi"); +my @T = map("%r$_",(8..11)); + +$code.=<<___; +.globl rsaz_1024_red2norm_avx2 +.type rsaz_1024_red2norm_avx2,\@abi-omnipotent +.align 32 +rsaz_1024_red2norm_avx2: + sub \$-128,$inp # size optimization + xor %rax,%rax +___ + +for ($j=0,$i=0; $i<16; $i++) { + my $k=0; + while (29*$j<64*($i+1)) { # load data till boundary + $code.=" mov `8*$j-128`($inp), @T[0]\n"; + $j++; $k++; push(@T,shift(@T)); + } + $l=$k; + while ($k>1) { # shift loaded data but last value + $code.=" shl \$`29*($j-$k)`,@T[-$k]\n"; + $k--; + } + $code.=<<___; # shift last value + mov @T[-1], @T[0] + shl \$`29*($j-1)`, @T[-1] + shr \$`-29*($j-1)`, @T[0] +___ + while ($l) { # accumulate all values + $code.=" add @T[-$l], %rax\n"; + $l--; + } + $code.=<<___; + adc \$0, @T[0] # consume eventual carry + mov %rax, 8*$i($out) + mov @T[0], %rax +___ + push(@T,shift(@T)); +} +$code.=<<___; + ret +.size rsaz_1024_red2norm_avx2,.-rsaz_1024_red2norm_avx2 + +.globl rsaz_1024_norm2red_avx2 +.type rsaz_1024_norm2red_avx2,\@abi-omnipotent +.align 32 +rsaz_1024_norm2red_avx2: + sub \$-128,$out # size optimization + mov ($inp),@T[0] + mov \$0x1fffffff,%eax +___ +for ($j=0,$i=0; $i<16; $i++) { + $code.=" mov `8*($i+1)`($inp),@T[1]\n" if ($i<15); + $code.=" xor @T[1],@T[1]\n" if ($i==15); + my $k=1; + while (29*($j+1)<64*($i+1)) { + $code.=<<___; + mov @T[0],@T[-$k] + shr \$`29*$j`,@T[-$k] + and %rax,@T[-$k] # &0x1fffffff + mov @T[-$k],`8*$j-128`($out) +___ + $j++; $k++; + } + $code.=<<___; + shrd \$`29*$j`,@T[1],@T[0] + and %rax,@T[0] + mov @T[0],`8*$j-128`($out) +___ + $j++; + push(@T,shift(@T)); +} +$code.=<<___; + mov @T[0],`8*$j-128`($out) # zero + mov @T[0],`8*($j+1)-128`($out) + mov @T[0],`8*($j+2)-128`($out) + mov @T[0],`8*($j+3)-128`($out) + ret +.size rsaz_1024_norm2red_avx2,.-rsaz_1024_norm2red_avx2 +___ +} +{ +my ($out,$inp,$power) = $win64 ? ("%rcx","%rdx","%r8d") : ("%rdi","%rsi","%edx"); + +$code.=<<___; +.globl rsaz_1024_scatter5_avx2 +.type rsaz_1024_scatter5_avx2,\@abi-omnipotent +.align 32 +rsaz_1024_scatter5_avx2: + vzeroupper + vmovdqu .Lscatter_permd(%rip),%ymm5 + shl \$4,$power + lea ($out,$power),$out + mov \$9,%eax + jmp .Loop_scatter_1024 + +.align 32 +.Loop_scatter_1024: + vmovdqu ($inp),%ymm0 + lea 32($inp),$inp + vpermd %ymm0,%ymm5,%ymm0 + vmovdqu %xmm0,($out) + lea 16*32($out),$out + dec %eax + jnz .Loop_scatter_1024 + + vzeroupper + ret +.size rsaz_1024_scatter5_avx2,.-rsaz_1024_scatter5_avx2 + +.globl rsaz_1024_gather5_avx2 +.type rsaz_1024_gather5_avx2,\@abi-omnipotent +.align 32 +rsaz_1024_gather5_avx2: +___ +$code.=<<___ if ($win64); + lea -0x88(%rsp),%rax + vzeroupper +.LSEH_begin_rsaz_1024_gather5: + # I can't trust assembler to use specific encoding:-( + .byte 0x48,0x8d,0x60,0xe0 #lea -0x20(%rax),%rsp + .byte 0xc5,0xf8,0x29,0x70,0xe0 #vmovaps %xmm6,-0x20(%rax) + .byte 0xc5,0xf8,0x29,0x78,0xf0 #vmovaps %xmm7,-0x10(%rax) + .byte 0xc5,0x78,0x29,0x40,0x00 #vmovaps %xmm8,0(%rax) + .byte 0xc5,0x78,0x29,0x48,0x10 #vmovaps %xmm9,0x10(%rax) + .byte 0xc5,0x78,0x29,0x50,0x20 #vmovaps %xmm10,0x20(%rax) + .byte 0xc5,0x78,0x29,0x58,0x30 #vmovaps %xmm11,0x30(%rax) + .byte 0xc5,0x78,0x29,0x60,0x40 #vmovaps %xmm12,0x40(%rax) + .byte 0xc5,0x78,0x29,0x68,0x50 #vmovaps %xmm13,0x50(%rax) + .byte 0xc5,0x78,0x29,0x70,0x60 #vmovaps %xmm14,0x60(%rax) + .byte 0xc5,0x78,0x29,0x78,0x70 #vmovaps %xmm15,0x70(%rax) +___ +$code.=<<___; + lea .Lgather_table(%rip),%r11 + mov $power,%eax + and \$3,$power + shr \$2,%eax # cache line number + shl \$4,$power # offset within cache line + + vmovdqu -32(%r11),%ymm7 # .Lgather_permd + vpbroadcastb 8(%r11,%rax), %xmm8 + vpbroadcastb 7(%r11,%rax), %xmm9 + vpbroadcastb 6(%r11,%rax), %xmm10 + vpbroadcastb 5(%r11,%rax), %xmm11 + vpbroadcastb 4(%r11,%rax), %xmm12 + vpbroadcastb 3(%r11,%rax), %xmm13 + vpbroadcastb 2(%r11,%rax), %xmm14 + vpbroadcastb 1(%r11,%rax), %xmm15 + + lea 64($inp,$power),$inp + mov \$64,%r11 # size optimization + mov \$9,%eax + jmp .Loop_gather_1024 + +.align 32 +.Loop_gather_1024: + vpand -64($inp), %xmm8,%xmm0 + vpand ($inp), %xmm9,%xmm1 + vpand 64($inp), %xmm10,%xmm2 + vpand ($inp,%r11,2), %xmm11,%xmm3 + vpor %xmm0,%xmm1,%xmm1 + vpand 64($inp,%r11,2), %xmm12,%xmm4 + vpor %xmm2,%xmm3,%xmm3 + vpand ($inp,%r11,4), %xmm13,%xmm5 + vpor %xmm1,%xmm3,%xmm3 + vpand 64($inp,%r11,4), %xmm14,%xmm6 + vpor %xmm4,%xmm5,%xmm5 + vpand -128($inp,%r11,8), %xmm15,%xmm2 + lea ($inp,%r11,8),$inp + vpor %xmm3,%xmm5,%xmm5 + vpor %xmm2,%xmm6,%xmm6 + vpor %xmm5,%xmm6,%xmm6 + vpermd %ymm6,%ymm7,%ymm6 + vmovdqu %ymm6,($out) + lea 32($out),$out + dec %eax + jnz .Loop_gather_1024 + + vpxor %ymm0,%ymm0,%ymm0 + vmovdqu %ymm0,($out) + vzeroupper +___ +$code.=<<___ if ($win64); + movaps (%rsp),%xmm6 + movaps 0x10(%rsp),%xmm7 + movaps 0x20(%rsp),%xmm8 + movaps 0x30(%rsp),%xmm9 + movaps 0x40(%rsp),%xmm10 + movaps 0x50(%rsp),%xmm11 + movaps 0x60(%rsp),%xmm12 + movaps 0x70(%rsp),%xmm13 + movaps 0x80(%rsp),%xmm14 + movaps 0x90(%rsp),%xmm15 + lea 0xa8(%rsp),%rsp +.LSEH_end_rsaz_1024_gather5: +___ +$code.=<<___; + ret +.size rsaz_1024_gather5_avx2,.-rsaz_1024_gather5_avx2 +___ +} + +$code.=<<___; +.extern OPENSSL_ia32cap_P +.globl rsaz_avx2_eligible +.type rsaz_avx2_eligible,\@abi-omnipotent +.align 32 +rsaz_avx2_eligible: + mov OPENSSL_ia32cap_P+8(%rip),%eax +___ +$code.=<<___ if ($addx); + mov \$`1<<8|1<<19`,%ecx + mov \$0,%edx + and %eax,%ecx + cmp \$`1<<8|1<<19`,%ecx # check for BMI2+AD*X + cmove %edx,%eax +___ +$code.=<<___; + and \$`1<<5`,%eax + shr \$5,%eax + ret +.size rsaz_avx2_eligible,.-rsaz_avx2_eligible + +.align 64 +.Land_mask: + .quad 0x1fffffff,0x1fffffff,0x1fffffff,-1 +.Lscatter_permd: + .long 0,2,4,6,7,7,7,7 +.Lgather_permd: + .long 0,7,1,7,2,7,3,7 +.Lgather_table: + .byte 0,0,0,0,0,0,0,0, 0xff,0,0,0,0,0,0,0 +.align 64 +___ + +if ($win64) { +$rec="%rcx"; +$frame="%rdx"; +$context="%r8"; +$disp="%r9"; + +$code.=<<___ +.extern __imp_RtlVirtualUnwind +.type rsaz_se_handler,\@abi-omnipotent +.align 16 +rsaz_se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + mov 8($disp),%rsi # disp->ImageBase + mov 56($disp),%r11 # disp->HandlerData + + mov 0(%r11),%r10d # HandlerData[0] + lea (%rsi,%r10),%r10 # prologue label + cmp %r10,%rbx # context->RipRsp + + mov 4(%r11),%r10d # HandlerData[1] + lea (%rsi,%r10),%r10 # epilogue label + cmp %r10,%rbx # context->Rip>=epilogue label + jae .Lcommon_seh_tail + + mov 160($context),%rax # pull context->Rbp + + mov -48(%rax),%r15 + mov -40(%rax),%r14 + mov -32(%rax),%r13 + mov -24(%rax),%r12 + mov -16(%rax),%rbp + mov -8(%rax),%rbx + mov %r15,240($context) + mov %r14,232($context) + mov %r13,224($context) + mov %r12,216($context) + mov %rbp,160($context) + mov %rbx,144($context) + + lea -0xd8(%rax),%rsi # %xmm save area + lea 512($context),%rdi # & context.Xmm6 + mov \$20,%ecx # 10*sizeof(%xmm0)/sizeof(%rax) + .long 0xa548f3fc # cld; rep movsq + +.Lcommon_seh_tail: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + + mov 40($disp),%rdi # disp->ContextRecord + mov $context,%rsi # context + mov \$154,%ecx # sizeof(CONTEXT) + .long 0xa548f3fc # cld; rep movsq + + mov $disp,%rsi + xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER + mov 8(%rsi),%rdx # arg2, disp->ImageBase + mov 0(%rsi),%r8 # arg3, disp->ControlPc + mov 16(%rsi),%r9 # arg4, disp->FunctionEntry + mov 40(%rsi),%r10 # disp->ContextRecord + lea 56(%rsi),%r11 # &disp->HandlerData + lea 24(%rsi),%r12 # &disp->EstablisherFrame + mov %r10,32(%rsp) # arg5 + mov %r11,40(%rsp) # arg6 + mov %r12,48(%rsp) # arg7 + mov %rcx,56(%rsp) # arg8, (NULL) + call *__imp_RtlVirtualUnwind(%rip) + + mov \$1,%eax # ExceptionContinueSearch + add \$64,%rsp + popfq + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + pop %rdi + pop %rsi + ret +.size rsaz_se_handler,.-rsaz_se_handler + +.section .pdata +.align 4 + .rva .LSEH_begin_rsaz_1024_sqr_avx2 + .rva .LSEH_end_rsaz_1024_sqr_avx2 + .rva .LSEH_info_rsaz_1024_sqr_avx2 + + .rva .LSEH_begin_rsaz_1024_mul_avx2 + .rva .LSEH_end_rsaz_1024_mul_avx2 + .rva .LSEH_info_rsaz_1024_mul_avx2 + + .rva .LSEH_begin_rsaz_1024_gather5 + .rva .LSEH_end_rsaz_1024_gather5 + .rva .LSEH_info_rsaz_1024_gather5 +.section .xdata +.align 8 +.LSEH_info_rsaz_1024_sqr_avx2: + .byte 9,0,0,0 + .rva rsaz_se_handler + .rva .Lsqr_1024_body,.Lsqr_1024_epilogue +.LSEH_info_rsaz_1024_mul_avx2: + .byte 9,0,0,0 + .rva rsaz_se_handler + .rva .Lmul_1024_body,.Lmul_1024_epilogue +.LSEH_info_rsaz_1024_gather5: + .byte 0x01,0x33,0x16,0x00 + .byte 0x36,0xf8,0x09,0x00 #vmovaps 0x90(rsp),xmm15 + .byte 0x31,0xe8,0x08,0x00 #vmovaps 0x80(rsp),xmm14 + .byte 0x2c,0xd8,0x07,0x00 #vmovaps 0x70(rsp),xmm13 + .byte 0x27,0xc8,0x06,0x00 #vmovaps 0x60(rsp),xmm12 + .byte 0x22,0xb8,0x05,0x00 #vmovaps 0x50(rsp),xmm11 + .byte 0x1d,0xa8,0x04,0x00 #vmovaps 0x40(rsp),xmm10 + .byte 0x18,0x98,0x03,0x00 #vmovaps 0x30(rsp),xmm9 + .byte 0x13,0x88,0x02,0x00 #vmovaps 0x20(rsp),xmm8 + .byte 0x0e,0x78,0x01,0x00 #vmovaps 0x10(rsp),xmm7 + .byte 0x09,0x68,0x00,0x00 #vmovaps 0x00(rsp),xmm6 + .byte 0x04,0x01,0x15,0x00 #sub rsp,0xa8 +___ +} + +foreach (split("\n",$code)) { + s/\`([^\`]*)\`/eval($1)/ge; + + s/\b(sh[rl]d?\s+\$)(-?[0-9]+)/$1.$2%64/ge or + + s/\b(vmov[dq])\b(.+)%ymm([0-9]+)/$1$2%xmm$3/go or + s/\b(vmovdqu)\b(.+)%x%ymm([0-9]+)/$1$2%xmm$3/go or + s/\b(vpinsr[qd])\b(.+)%ymm([0-9]+)/$1$2%xmm$3/go or + s/\b(vpextr[qd])\b(.+)%ymm([0-9]+)/$1$2%xmm$3/go or + s/\b(vpbroadcast[qd]\s+)%ymm([0-9]+)/$1%xmm$2/go; + print $_,"\n"; +} + +}}} else {{{ +print <<___; # assembler is too old +.text + +.globl rsaz_avx2_eligible +.type rsaz_avx2_eligible,\@abi-omnipotent +rsaz_avx2_eligible: + xor %eax,%eax + ret +.size rsaz_avx2_eligible,.-rsaz_avx2_eligible + +.globl rsaz_1024_sqr_avx2 +.globl rsaz_1024_mul_avx2 +.globl rsaz_1024_norm2red_avx2 +.globl rsaz_1024_red2norm_avx2 +.globl rsaz_1024_scatter5_avx2 +.globl rsaz_1024_gather5_avx2 +.type rsaz_1024_sqr_avx2,\@abi-omnipotent +rsaz_1024_sqr_avx2: +rsaz_1024_mul_avx2: +rsaz_1024_norm2red_avx2: +rsaz_1024_red2norm_avx2: +rsaz_1024_scatter5_avx2: +rsaz_1024_gather5_avx2: + .byte 0x0f,0x0b # ud2 + ret +.size rsaz_1024_sqr_avx2,.-rsaz_1024_sqr_avx2 +___ +}}} + +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/bn/asm/rsaz-x86_64.pl b/TMessagesProj/jni/boringssl/crypto/bn/asm/rsaz-x86_64.pl new file mode 100644 index 00000000..3bd45dba --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/asm/rsaz-x86_64.pl @@ -0,0 +1,2144 @@ +#!/usr/bin/env perl + +############################################################################## +# # +# Copyright (c) 2012, Intel Corporation # +# # +# All rights reserved. # +# # +# Redistribution and use in source and binary forms, with or without # +# modification, are permitted provided that the following conditions are # +# met: # +# # +# * Redistributions of source code must retain the above copyright # +# notice, this list of conditions and the following disclaimer. # +# # +# * Redistributions in binary form must reproduce the above copyright # +# notice, this list of conditions and the following disclaimer in the # +# documentation and/or other materials provided with the # +# distribution. # +# # +# * Neither the name of the Intel Corporation nor the names of its # +# contributors may be used to endorse or promote products derived from # +# this software without specific prior written permission. # +# # +# # +# THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""AS IS"" AND ANY # +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR # +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR # +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR # +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF # +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # +# # +############################################################################## +# Developers and authors: # +# Shay Gueron (1, 2), and Vlad Krasnov (1) # +# (1) Intel Architecture Group, Microprocessor and Chipset Development, # +# Israel Development Center, Haifa, Israel # +# (2) University of Haifa # +############################################################################## +# Reference: # +# [1] S. Gueron, "Efficient Software Implementations of Modular # +# Exponentiation", http://eprint.iacr.org/2011/239 # +# [2] S. Gueron, V. Krasnov. "Speeding up Big-Numbers Squaring". # +# IEEE Proceedings of 9th International Conference on Information # +# Technology: New Generations (ITNG 2012), 821-823 (2012). # +# [3] S. Gueron, Efficient Software Implementations of Modular Exponentiation# +# Journal of Cryptographic Engineering 2:31-43 (2012). # +# [4] S. Gueron, V. Krasnov: "[PATCH] Efficient and side channel analysis # +# resistant 512-bit and 1024-bit modular exponentiation for optimizing # +# RSA1024 and RSA2048 on x86_64 platforms", # +# http://rt.openssl.org/Ticket/Display.html?id=2582&user=guest&pass=guest# +############################################################################## + +# While original submission covers 512- and 1024-bit exponentiation, +# this module is limited to 512-bit version only (and as such +# accelerates RSA1024 sign). This is because improvement for longer +# keys is not high enough to justify the effort, highest measured +# was ~5% on Westmere. [This is relative to OpenSSL 1.0.2, upcoming +# for the moment of this writing!] Nor does this module implement +# "monolithic" complete exponentiation jumbo-subroutine, but adheres +# to more modular mixture of C and assembly. And it's optimized even +# for processors other than Intel Core family (see table below for +# improvement coefficients). +# +# +# RSA1024 sign/sec this/original |this/rsax(*) this/fips(*) +# ----------------+--------------------------- +# Opteron +13% |+5% +20% +# Bulldozer -0% |-1% +10% +# P4 +11% |+7% +8% +# Westmere +5% |+14% +17% +# Sandy Bridge +2% |+12% +29% +# Ivy Bridge +1% |+11% +35% +# Haswell(**) -0% |+12% +39% +# Atom +13% |+11% +4% +# VIA Nano +70% |+9% +25% +# +# (*) rsax engine and fips numbers are presented for reference +# purposes; +# (**) MULX was attempted, but found to give only marginal improvement; + +$flavour = shift; +$output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or +die "can't locate x86_64-xlate.pl"; + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1` + =~ /GNU assembler version ([2-9]\.[0-9]+)/) { + $addx = ($1>=2.23); +} + +if (!$addx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) && + `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) { + $addx = ($1>=2.10); +} + +if (!$addx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) && + `ml64 2>&1` =~ /Version ([0-9]+)\./) { + $addx = ($1>=12); +} + +if (!$addx && `$ENV{CC} -v 2>&1` =~ /(^clang version|based on LLVM) ([3-9])\.([0-9]+)/) { + my $ver = $2 + $3/100.0; # 3.1->3.01, 3.10->3.10 + $addx = ($ver>=3.03); +} + +($out, $inp, $mod) = ("%rdi", "%rsi", "%rbp"); # common internal API +{ +my ($out,$inp,$mod,$n0,$times) = ("%rdi","%rsi","%rdx","%rcx","%r8d"); + +$code.=<<___; +.text + +.extern OPENSSL_ia32cap_P + +.globl rsaz_512_sqr +.type rsaz_512_sqr,\@function,5 +.align 32 +rsaz_512_sqr: # 25-29% faster than rsaz_512_mul + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + + subq \$128+24, %rsp +.Lsqr_body: + movq $mod, %rbp # common argument + movq ($inp), %rdx + movq 8($inp), %rax + movq $n0, 128(%rsp) +___ +$code.=<<___ if ($addx); + movl \$0x80100,%r11d + andl OPENSSL_ia32cap_P+8(%rip),%r11d + cmpl \$0x80100,%r11d # check for MULX and ADO/CX + je .Loop_sqrx +___ +$code.=<<___; + jmp .Loop_sqr + +.align 32 +.Loop_sqr: + movl $times,128+8(%rsp) +#first iteration + movq %rdx, %rbx + mulq %rdx + movq %rax, %r8 + movq 16($inp), %rax + movq %rdx, %r9 + + mulq %rbx + addq %rax, %r9 + movq 24($inp), %rax + movq %rdx, %r10 + adcq \$0, %r10 + + mulq %rbx + addq %rax, %r10 + movq 32($inp), %rax + movq %rdx, %r11 + adcq \$0, %r11 + + mulq %rbx + addq %rax, %r11 + movq 40($inp), %rax + movq %rdx, %r12 + adcq \$0, %r12 + + mulq %rbx + addq %rax, %r12 + movq 48($inp), %rax + movq %rdx, %r13 + adcq \$0, %r13 + + mulq %rbx + addq %rax, %r13 + movq 56($inp), %rax + movq %rdx, %r14 + adcq \$0, %r14 + + mulq %rbx + addq %rax, %r14 + movq %rbx, %rax + movq %rdx, %r15 + adcq \$0, %r15 + + addq %r8, %r8 #shlq \$1, %r8 + movq %r9, %rcx + adcq %r9, %r9 #shld \$1, %r8, %r9 + + mulq %rax + movq %rax, (%rsp) + addq %rdx, %r8 + adcq \$0, %r9 + + movq %r8, 8(%rsp) + shrq \$63, %rcx + +#second iteration + movq 8($inp), %r8 + movq 16($inp), %rax + mulq %r8 + addq %rax, %r10 + movq 24($inp), %rax + movq %rdx, %rbx + adcq \$0, %rbx + + mulq %r8 + addq %rax, %r11 + movq 32($inp), %rax + adcq \$0, %rdx + addq %rbx, %r11 + movq %rdx, %rbx + adcq \$0, %rbx + + mulq %r8 + addq %rax, %r12 + movq 40($inp), %rax + adcq \$0, %rdx + addq %rbx, %r12 + movq %rdx, %rbx + adcq \$0, %rbx + + mulq %r8 + addq %rax, %r13 + movq 48($inp), %rax + adcq \$0, %rdx + addq %rbx, %r13 + movq %rdx, %rbx + adcq \$0, %rbx + + mulq %r8 + addq %rax, %r14 + movq 56($inp), %rax + adcq \$0, %rdx + addq %rbx, %r14 + movq %rdx, %rbx + adcq \$0, %rbx + + mulq %r8 + addq %rax, %r15 + movq %r8, %rax + adcq \$0, %rdx + addq %rbx, %r15 + movq %rdx, %r8 + movq %r10, %rdx + adcq \$0, %r8 + + add %rdx, %rdx + lea (%rcx,%r10,2), %r10 #shld \$1, %rcx, %r10 + movq %r11, %rbx + adcq %r11, %r11 #shld \$1, %r10, %r11 + + mulq %rax + addq %rax, %r9 + adcq %rdx, %r10 + adcq \$0, %r11 + + movq %r9, 16(%rsp) + movq %r10, 24(%rsp) + shrq \$63, %rbx + +#third iteration + movq 16($inp), %r9 + movq 24($inp), %rax + mulq %r9 + addq %rax, %r12 + movq 32($inp), %rax + movq %rdx, %rcx + adcq \$0, %rcx + + mulq %r9 + addq %rax, %r13 + movq 40($inp), %rax + adcq \$0, %rdx + addq %rcx, %r13 + movq %rdx, %rcx + adcq \$0, %rcx + + mulq %r9 + addq %rax, %r14 + movq 48($inp), %rax + adcq \$0, %rdx + addq %rcx, %r14 + movq %rdx, %rcx + adcq \$0, %rcx + + mulq %r9 + movq %r12, %r10 + lea (%rbx,%r12,2), %r12 #shld \$1, %rbx, %r12 + addq %rax, %r15 + movq 56($inp), %rax + adcq \$0, %rdx + addq %rcx, %r15 + movq %rdx, %rcx + adcq \$0, %rcx + + mulq %r9 + shrq \$63, %r10 + addq %rax, %r8 + movq %r9, %rax + adcq \$0, %rdx + addq %rcx, %r8 + movq %rdx, %r9 + adcq \$0, %r9 + + movq %r13, %rcx + leaq (%r10,%r13,2), %r13 #shld \$1, %r12, %r13 + + mulq %rax + addq %rax, %r11 + adcq %rdx, %r12 + adcq \$0, %r13 + + movq %r11, 32(%rsp) + movq %r12, 40(%rsp) + shrq \$63, %rcx + +#fourth iteration + movq 24($inp), %r10 + movq 32($inp), %rax + mulq %r10 + addq %rax, %r14 + movq 40($inp), %rax + movq %rdx, %rbx + adcq \$0, %rbx + + mulq %r10 + addq %rax, %r15 + movq 48($inp), %rax + adcq \$0, %rdx + addq %rbx, %r15 + movq %rdx, %rbx + adcq \$0, %rbx + + mulq %r10 + movq %r14, %r12 + leaq (%rcx,%r14,2), %r14 #shld \$1, %rcx, %r14 + addq %rax, %r8 + movq 56($inp), %rax + adcq \$0, %rdx + addq %rbx, %r8 + movq %rdx, %rbx + adcq \$0, %rbx + + mulq %r10 + shrq \$63, %r12 + addq %rax, %r9 + movq %r10, %rax + adcq \$0, %rdx + addq %rbx, %r9 + movq %rdx, %r10 + adcq \$0, %r10 + + movq %r15, %rbx + leaq (%r12,%r15,2),%r15 #shld \$1, %r14, %r15 + + mulq %rax + addq %rax, %r13 + adcq %rdx, %r14 + adcq \$0, %r15 + + movq %r13, 48(%rsp) + movq %r14, 56(%rsp) + shrq \$63, %rbx + +#fifth iteration + movq 32($inp), %r11 + movq 40($inp), %rax + mulq %r11 + addq %rax, %r8 + movq 48($inp), %rax + movq %rdx, %rcx + adcq \$0, %rcx + + mulq %r11 + addq %rax, %r9 + movq 56($inp), %rax + adcq \$0, %rdx + movq %r8, %r12 + leaq (%rbx,%r8,2), %r8 #shld \$1, %rbx, %r8 + addq %rcx, %r9 + movq %rdx, %rcx + adcq \$0, %rcx + + mulq %r11 + shrq \$63, %r12 + addq %rax, %r10 + movq %r11, %rax + adcq \$0, %rdx + addq %rcx, %r10 + movq %rdx, %r11 + adcq \$0, %r11 + + movq %r9, %rcx + leaq (%r12,%r9,2), %r9 #shld \$1, %r8, %r9 + + mulq %rax + addq %rax, %r15 + adcq %rdx, %r8 + adcq \$0, %r9 + + movq %r15, 64(%rsp) + movq %r8, 72(%rsp) + shrq \$63, %rcx + +#sixth iteration + movq 40($inp), %r12 + movq 48($inp), %rax + mulq %r12 + addq %rax, %r10 + movq 56($inp), %rax + movq %rdx, %rbx + adcq \$0, %rbx + + mulq %r12 + addq %rax, %r11 + movq %r12, %rax + movq %r10, %r15 + leaq (%rcx,%r10,2), %r10 #shld \$1, %rcx, %r10 + adcq \$0, %rdx + shrq \$63, %r15 + addq %rbx, %r11 + movq %rdx, %r12 + adcq \$0, %r12 + + movq %r11, %rbx + leaq (%r15,%r11,2), %r11 #shld \$1, %r10, %r11 + + mulq %rax + addq %rax, %r9 + adcq %rdx, %r10 + adcq \$0, %r11 + + movq %r9, 80(%rsp) + movq %r10, 88(%rsp) + +#seventh iteration + movq 48($inp), %r13 + movq 56($inp), %rax + mulq %r13 + addq %rax, %r12 + movq %r13, %rax + movq %rdx, %r13 + adcq \$0, %r13 + + xorq %r14, %r14 + shlq \$1, %rbx + adcq %r12, %r12 #shld \$1, %rbx, %r12 + adcq %r13, %r13 #shld \$1, %r12, %r13 + adcq %r14, %r14 #shld \$1, %r13, %r14 + + mulq %rax + addq %rax, %r11 + adcq %rdx, %r12 + adcq \$0, %r13 + + movq %r11, 96(%rsp) + movq %r12, 104(%rsp) + +#eighth iteration + movq 56($inp), %rax + mulq %rax + addq %rax, %r13 + adcq \$0, %rdx + + addq %rdx, %r14 + + movq %r13, 112(%rsp) + movq %r14, 120(%rsp) + + movq (%rsp), %r8 + movq 8(%rsp), %r9 + movq 16(%rsp), %r10 + movq 24(%rsp), %r11 + movq 32(%rsp), %r12 + movq 40(%rsp), %r13 + movq 48(%rsp), %r14 + movq 56(%rsp), %r15 + + call __rsaz_512_reduce + + addq 64(%rsp), %r8 + adcq 72(%rsp), %r9 + adcq 80(%rsp), %r10 + adcq 88(%rsp), %r11 + adcq 96(%rsp), %r12 + adcq 104(%rsp), %r13 + adcq 112(%rsp), %r14 + adcq 120(%rsp), %r15 + sbbq %rcx, %rcx + + call __rsaz_512_subtract + + movq %r8, %rdx + movq %r9, %rax + movl 128+8(%rsp), $times + movq $out, $inp + + decl $times + jnz .Loop_sqr +___ +if ($addx) { +$code.=<<___; + jmp .Lsqr_tail + +.align 32 +.Loop_sqrx: + movl $times,128+8(%rsp) + movq $out, %xmm0 # off-load + movq %rbp, %xmm1 # off-load +#first iteration + mulx %rax, %r8, %r9 + + mulx 16($inp), %rcx, %r10 + xor %rbp, %rbp # cf=0, of=0 + + mulx 24($inp), %rax, %r11 + adcx %rcx, %r9 + + mulx 32($inp), %rcx, %r12 + adcx %rax, %r10 + + mulx 40($inp), %rax, %r13 + adcx %rcx, %r11 + + .byte 0xc4,0x62,0xf3,0xf6,0xb6,0x30,0x00,0x00,0x00 # mulx 48($inp), %rcx, %r14 + adcx %rax, %r12 + adcx %rcx, %r13 + + .byte 0xc4,0x62,0xfb,0xf6,0xbe,0x38,0x00,0x00,0x00 # mulx 56($inp), %rax, %r15 + adcx %rax, %r14 + adcx %rbp, %r15 # %rbp is 0 + + mov %r9, %rcx + shld \$1, %r8, %r9 + shl \$1, %r8 + + xor %ebp, %ebp + mulx %rdx, %rax, %rdx + adcx %rdx, %r8 + mov 8($inp), %rdx + adcx %rbp, %r9 + + mov %rax, (%rsp) + mov %r8, 8(%rsp) + +#second iteration + mulx 16($inp), %rax, %rbx + adox %rax, %r10 + adcx %rbx, %r11 + + .byte 0xc4,0x62,0xc3,0xf6,0x86,0x18,0x00,0x00,0x00 # mulx 24($inp), $out, %r8 + adox $out, %r11 + adcx %r8, %r12 + + mulx 32($inp), %rax, %rbx + adox %rax, %r12 + adcx %rbx, %r13 + + mulx 40($inp), $out, %r8 + adox $out, %r13 + adcx %r8, %r14 + + .byte 0xc4,0xe2,0xfb,0xf6,0x9e,0x30,0x00,0x00,0x00 # mulx 48($inp), %rax, %rbx + adox %rax, %r14 + adcx %rbx, %r15 + + .byte 0xc4,0x62,0xc3,0xf6,0x86,0x38,0x00,0x00,0x00 # mulx 56($inp), $out, %r8 + adox $out, %r15 + adcx %rbp, %r8 + adox %rbp, %r8 + + mov %r11, %rbx + shld \$1, %r10, %r11 + shld \$1, %rcx, %r10 + + xor %ebp,%ebp + mulx %rdx, %rax, %rcx + mov 16($inp), %rdx + adcx %rax, %r9 + adcx %rcx, %r10 + adcx %rbp, %r11 + + mov %r9, 16(%rsp) + .byte 0x4c,0x89,0x94,0x24,0x18,0x00,0x00,0x00 # mov %r10, 24(%rsp) + +#third iteration + .byte 0xc4,0x62,0xc3,0xf6,0x8e,0x18,0x00,0x00,0x00 # mulx 24($inp), $out, %r9 + adox $out, %r12 + adcx %r9, %r13 + + mulx 32($inp), %rax, %rcx + adox %rax, %r13 + adcx %rcx, %r14 + + mulx 40($inp), $out, %r9 + adox $out, %r14 + adcx %r9, %r15 + + .byte 0xc4,0xe2,0xfb,0xf6,0x8e,0x30,0x00,0x00,0x00 # mulx 48($inp), %rax, %rcx + adox %rax, %r15 + adcx %rcx, %r8 + + .byte 0xc4,0x62,0xc3,0xf6,0x8e,0x38,0x00,0x00,0x00 # mulx 56($inp), $out, %r9 + adox $out, %r8 + adcx %rbp, %r9 + adox %rbp, %r9 + + mov %r13, %rcx + shld \$1, %r12, %r13 + shld \$1, %rbx, %r12 + + xor %ebp, %ebp + mulx %rdx, %rax, %rdx + adcx %rax, %r11 + adcx %rdx, %r12 + mov 24($inp), %rdx + adcx %rbp, %r13 + + mov %r11, 32(%rsp) + .byte 0x4c,0x89,0xa4,0x24,0x28,0x00,0x00,0x00 # mov %r12, 40(%rsp) + +#fourth iteration + .byte 0xc4,0xe2,0xfb,0xf6,0x9e,0x20,0x00,0x00,0x00 # mulx 32($inp), %rax, %rbx + adox %rax, %r14 + adcx %rbx, %r15 + + mulx 40($inp), $out, %r10 + adox $out, %r15 + adcx %r10, %r8 + + mulx 48($inp), %rax, %rbx + adox %rax, %r8 + adcx %rbx, %r9 + + mulx 56($inp), $out, %r10 + adox $out, %r9 + adcx %rbp, %r10 + adox %rbp, %r10 + + .byte 0x66 + mov %r15, %rbx + shld \$1, %r14, %r15 + shld \$1, %rcx, %r14 + + xor %ebp, %ebp + mulx %rdx, %rax, %rdx + adcx %rax, %r13 + adcx %rdx, %r14 + mov 32($inp), %rdx + adcx %rbp, %r15 + + mov %r13, 48(%rsp) + mov %r14, 56(%rsp) + +#fifth iteration + .byte 0xc4,0x62,0xc3,0xf6,0x9e,0x28,0x00,0x00,0x00 # mulx 40($inp), $out, %r11 + adox $out, %r8 + adcx %r11, %r9 + + mulx 48($inp), %rax, %rcx + adox %rax, %r9 + adcx %rcx, %r10 + + mulx 56($inp), $out, %r11 + adox $out, %r10 + adcx %rbp, %r11 + adox %rbp, %r11 + + mov %r9, %rcx + shld \$1, %r8, %r9 + shld \$1, %rbx, %r8 + + xor %ebp, %ebp + mulx %rdx, %rax, %rdx + adcx %rax, %r15 + adcx %rdx, %r8 + mov 40($inp), %rdx + adcx %rbp, %r9 + + mov %r15, 64(%rsp) + mov %r8, 72(%rsp) + +#sixth iteration + .byte 0xc4,0xe2,0xfb,0xf6,0x9e,0x30,0x00,0x00,0x00 # mulx 48($inp), %rax, %rbx + adox %rax, %r10 + adcx %rbx, %r11 + + .byte 0xc4,0x62,0xc3,0xf6,0xa6,0x38,0x00,0x00,0x00 # mulx 56($inp), $out, %r12 + adox $out, %r11 + adcx %rbp, %r12 + adox %rbp, %r12 + + mov %r11, %rbx + shld \$1, %r10, %r11 + shld \$1, %rcx, %r10 + + xor %ebp, %ebp + mulx %rdx, %rax, %rdx + adcx %rax, %r9 + adcx %rdx, %r10 + mov 48($inp), %rdx + adcx %rbp, %r11 + + mov %r9, 80(%rsp) + mov %r10, 88(%rsp) + +#seventh iteration + .byte 0xc4,0x62,0xfb,0xf6,0xae,0x38,0x00,0x00,0x00 # mulx 56($inp), %rax, %r13 + adox %rax, %r12 + adox %rbp, %r13 + + xor %r14, %r14 + shld \$1, %r13, %r14 + shld \$1, %r12, %r13 + shld \$1, %rbx, %r12 + + xor %ebp, %ebp + mulx %rdx, %rax, %rdx + adcx %rax, %r11 + adcx %rdx, %r12 + mov 56($inp), %rdx + adcx %rbp, %r13 + + .byte 0x4c,0x89,0x9c,0x24,0x60,0x00,0x00,0x00 # mov %r11, 96(%rsp) + .byte 0x4c,0x89,0xa4,0x24,0x68,0x00,0x00,0x00 # mov %r12, 104(%rsp) + +#eighth iteration + mulx %rdx, %rax, %rdx + adox %rax, %r13 + adox %rbp, %rdx + + .byte 0x66 + add %rdx, %r14 + + movq %r13, 112(%rsp) + movq %r14, 120(%rsp) + movq %xmm0, $out + movq %xmm1, %rbp + + movq 128(%rsp), %rdx # pull $n0 + movq (%rsp), %r8 + movq 8(%rsp), %r9 + movq 16(%rsp), %r10 + movq 24(%rsp), %r11 + movq 32(%rsp), %r12 + movq 40(%rsp), %r13 + movq 48(%rsp), %r14 + movq 56(%rsp), %r15 + + call __rsaz_512_reducex + + addq 64(%rsp), %r8 + adcq 72(%rsp), %r9 + adcq 80(%rsp), %r10 + adcq 88(%rsp), %r11 + adcq 96(%rsp), %r12 + adcq 104(%rsp), %r13 + adcq 112(%rsp), %r14 + adcq 120(%rsp), %r15 + sbbq %rcx, %rcx + + call __rsaz_512_subtract + + movq %r8, %rdx + movq %r9, %rax + movl 128+8(%rsp), $times + movq $out, $inp + + decl $times + jnz .Loop_sqrx + +.Lsqr_tail: +___ +} +$code.=<<___; + + leaq 128+24+48(%rsp), %rax + movq -48(%rax), %r15 + movq -40(%rax), %r14 + movq -32(%rax), %r13 + movq -24(%rax), %r12 + movq -16(%rax), %rbp + movq -8(%rax), %rbx + leaq (%rax), %rsp +.Lsqr_epilogue: + ret +.size rsaz_512_sqr,.-rsaz_512_sqr +___ +} +{ +my ($out,$ap,$bp,$mod,$n0) = ("%rdi","%rsi","%rdx","%rcx","%r8"); +$code.=<<___; +.globl rsaz_512_mul +.type rsaz_512_mul,\@function,5 +.align 32 +rsaz_512_mul: + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + + subq \$128+24, %rsp +.Lmul_body: + movq $out, %xmm0 # off-load arguments + movq $mod, %xmm1 + movq $n0, 128(%rsp) +___ +$code.=<<___ if ($addx); + movl \$0x80100,%r11d + andl OPENSSL_ia32cap_P+8(%rip),%r11d + cmpl \$0x80100,%r11d # check for MULX and ADO/CX + je .Lmulx +___ +$code.=<<___; + movq ($bp), %rbx # pass b[0] + movq $bp, %rbp # pass argument + call __rsaz_512_mul + + movq %xmm0, $out + movq %xmm1, %rbp + + movq (%rsp), %r8 + movq 8(%rsp), %r9 + movq 16(%rsp), %r10 + movq 24(%rsp), %r11 + movq 32(%rsp), %r12 + movq 40(%rsp), %r13 + movq 48(%rsp), %r14 + movq 56(%rsp), %r15 + + call __rsaz_512_reduce +___ +$code.=<<___ if ($addx); + jmp .Lmul_tail + +.align 32 +.Lmulx: + movq $bp, %rbp # pass argument + movq ($bp), %rdx # pass b[0] + call __rsaz_512_mulx + + movq %xmm0, $out + movq %xmm1, %rbp + + movq 128(%rsp), %rdx # pull $n0 + movq (%rsp), %r8 + movq 8(%rsp), %r9 + movq 16(%rsp), %r10 + movq 24(%rsp), %r11 + movq 32(%rsp), %r12 + movq 40(%rsp), %r13 + movq 48(%rsp), %r14 + movq 56(%rsp), %r15 + + call __rsaz_512_reducex +.Lmul_tail: +___ +$code.=<<___; + addq 64(%rsp), %r8 + adcq 72(%rsp), %r9 + adcq 80(%rsp), %r10 + adcq 88(%rsp), %r11 + adcq 96(%rsp), %r12 + adcq 104(%rsp), %r13 + adcq 112(%rsp), %r14 + adcq 120(%rsp), %r15 + sbbq %rcx, %rcx + + call __rsaz_512_subtract + + leaq 128+24+48(%rsp), %rax + movq -48(%rax), %r15 + movq -40(%rax), %r14 + movq -32(%rax), %r13 + movq -24(%rax), %r12 + movq -16(%rax), %rbp + movq -8(%rax), %rbx + leaq (%rax), %rsp +.Lmul_epilogue: + ret +.size rsaz_512_mul,.-rsaz_512_mul +___ +} +{ +my ($out,$ap,$bp,$mod,$n0,$pwr) = ("%rdi","%rsi","%rdx","%rcx","%r8","%r9d"); +$code.=<<___; +.globl rsaz_512_mul_gather4 +.type rsaz_512_mul_gather4,\@function,6 +.align 32 +rsaz_512_mul_gather4: + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + + mov $pwr, $pwr + subq \$128+24, %rsp +.Lmul_gather4_body: +___ +$code.=<<___ if ($addx); + movl \$0x80100,%r11d + andl OPENSSL_ia32cap_P+8(%rip),%r11d + cmpl \$0x80100,%r11d # check for MULX and ADO/CX + je .Lmulx_gather +___ +$code.=<<___; + movl 64($bp,$pwr,4), %eax + movq $out, %xmm0 # off-load arguments + movl ($bp,$pwr,4), %ebx + movq $mod, %xmm1 + movq $n0, 128(%rsp) + + shlq \$32, %rax + or %rax, %rbx + movq ($ap), %rax + movq 8($ap), %rcx + leaq 128($bp,$pwr,4), %rbp + mulq %rbx # 0 iteration + movq %rax, (%rsp) + movq %rcx, %rax + movq %rdx, %r8 + + mulq %rbx + movd (%rbp), %xmm4 + addq %rax, %r8 + movq 16($ap), %rax + movq %rdx, %r9 + adcq \$0, %r9 + + mulq %rbx + movd 64(%rbp), %xmm5 + addq %rax, %r9 + movq 24($ap), %rax + movq %rdx, %r10 + adcq \$0, %r10 + + mulq %rbx + pslldq \$4, %xmm5 + addq %rax, %r10 + movq 32($ap), %rax + movq %rdx, %r11 + adcq \$0, %r11 + + mulq %rbx + por %xmm5, %xmm4 + addq %rax, %r11 + movq 40($ap), %rax + movq %rdx, %r12 + adcq \$0, %r12 + + mulq %rbx + addq %rax, %r12 + movq 48($ap), %rax + movq %rdx, %r13 + adcq \$0, %r13 + + mulq %rbx + leaq 128(%rbp), %rbp + addq %rax, %r13 + movq 56($ap), %rax + movq %rdx, %r14 + adcq \$0, %r14 + + mulq %rbx + movq %xmm4, %rbx + addq %rax, %r14 + movq ($ap), %rax + movq %rdx, %r15 + adcq \$0, %r15 + + leaq 8(%rsp), %rdi + movl \$7, %ecx + jmp .Loop_mul_gather + +.align 32 +.Loop_mul_gather: + mulq %rbx + addq %rax, %r8 + movq 8($ap), %rax + movq %r8, (%rdi) + movq %rdx, %r8 + adcq \$0, %r8 + + mulq %rbx + movd (%rbp), %xmm4 + addq %rax, %r9 + movq 16($ap), %rax + adcq \$0, %rdx + addq %r9, %r8 + movq %rdx, %r9 + adcq \$0, %r9 + + mulq %rbx + movd 64(%rbp), %xmm5 + addq %rax, %r10 + movq 24($ap), %rax + adcq \$0, %rdx + addq %r10, %r9 + movq %rdx, %r10 + adcq \$0, %r10 + + mulq %rbx + pslldq \$4, %xmm5 + addq %rax, %r11 + movq 32($ap), %rax + adcq \$0, %rdx + addq %r11, %r10 + movq %rdx, %r11 + adcq \$0, %r11 + + mulq %rbx + por %xmm5, %xmm4 + addq %rax, %r12 + movq 40($ap), %rax + adcq \$0, %rdx + addq %r12, %r11 + movq %rdx, %r12 + adcq \$0, %r12 + + mulq %rbx + addq %rax, %r13 + movq 48($ap), %rax + adcq \$0, %rdx + addq %r13, %r12 + movq %rdx, %r13 + adcq \$0, %r13 + + mulq %rbx + addq %rax, %r14 + movq 56($ap), %rax + adcq \$0, %rdx + addq %r14, %r13 + movq %rdx, %r14 + adcq \$0, %r14 + + mulq %rbx + movq %xmm4, %rbx + addq %rax, %r15 + movq ($ap), %rax + adcq \$0, %rdx + addq %r15, %r14 + movq %rdx, %r15 + adcq \$0, %r15 + + leaq 128(%rbp), %rbp + leaq 8(%rdi), %rdi + + decl %ecx + jnz .Loop_mul_gather + + movq %r8, (%rdi) + movq %r9, 8(%rdi) + movq %r10, 16(%rdi) + movq %r11, 24(%rdi) + movq %r12, 32(%rdi) + movq %r13, 40(%rdi) + movq %r14, 48(%rdi) + movq %r15, 56(%rdi) + + movq %xmm0, $out + movq %xmm1, %rbp + + movq (%rsp), %r8 + movq 8(%rsp), %r9 + movq 16(%rsp), %r10 + movq 24(%rsp), %r11 + movq 32(%rsp), %r12 + movq 40(%rsp), %r13 + movq 48(%rsp), %r14 + movq 56(%rsp), %r15 + + call __rsaz_512_reduce +___ +$code.=<<___ if ($addx); + jmp .Lmul_gather_tail + +.align 32 +.Lmulx_gather: + mov 64($bp,$pwr,4), %eax + movq $out, %xmm0 # off-load arguments + lea 128($bp,$pwr,4), %rbp + mov ($bp,$pwr,4), %edx + movq $mod, %xmm1 + mov $n0, 128(%rsp) + + shl \$32, %rax + or %rax, %rdx + mulx ($ap), %rbx, %r8 # 0 iteration + mov %rbx, (%rsp) + xor %edi, %edi # cf=0, of=0 + + mulx 8($ap), %rax, %r9 + movd (%rbp), %xmm4 + + mulx 16($ap), %rbx, %r10 + movd 64(%rbp), %xmm5 + adcx %rax, %r8 + + mulx 24($ap), %rax, %r11 + pslldq \$4, %xmm5 + adcx %rbx, %r9 + + mulx 32($ap), %rbx, %r12 + por %xmm5, %xmm4 + adcx %rax, %r10 + + mulx 40($ap), %rax, %r13 + adcx %rbx, %r11 + + mulx 48($ap), %rbx, %r14 + lea 128(%rbp), %rbp + adcx %rax, %r12 + + mulx 56($ap), %rax, %r15 + movq %xmm4, %rdx + adcx %rbx, %r13 + adcx %rax, %r14 + mov %r8, %rbx + adcx %rdi, %r15 # %rdi is 0 + + mov \$-7, %rcx + jmp .Loop_mulx_gather + +.align 32 +.Loop_mulx_gather: + mulx ($ap), %rax, %r8 + adcx %rax, %rbx + adox %r9, %r8 + + mulx 8($ap), %rax, %r9 + .byte 0x66,0x0f,0x6e,0xa5,0x00,0x00,0x00,0x00 # movd (%rbp), %xmm4 + adcx %rax, %r8 + adox %r10, %r9 + + mulx 16($ap), %rax, %r10 + movd 64(%rbp), %xmm5 + lea 128(%rbp), %rbp + adcx %rax, %r9 + adox %r11, %r10 + + .byte 0xc4,0x62,0xfb,0xf6,0x9e,0x18,0x00,0x00,0x00 # mulx 24($ap), %rax, %r11 + pslldq \$4, %xmm5 + por %xmm5, %xmm4 + adcx %rax, %r10 + adox %r12, %r11 + + mulx 32($ap), %rax, %r12 + adcx %rax, %r11 + adox %r13, %r12 + + mulx 40($ap), %rax, %r13 + adcx %rax, %r12 + adox %r14, %r13 + + .byte 0xc4,0x62,0xfb,0xf6,0xb6,0x30,0x00,0x00,0x00 # mulx 48($ap), %rax, %r14 + adcx %rax, %r13 + adox %r15, %r14 + + mulx 56($ap), %rax, %r15 + movq %xmm4, %rdx + mov %rbx, 64(%rsp,%rcx,8) + adcx %rax, %r14 + adox %rdi, %r15 + mov %r8, %rbx + adcx %rdi, %r15 # cf=0 + + inc %rcx # of=0 + jnz .Loop_mulx_gather + + mov %r8, 64(%rsp) + mov %r9, 64+8(%rsp) + mov %r10, 64+16(%rsp) + mov %r11, 64+24(%rsp) + mov %r12, 64+32(%rsp) + mov %r13, 64+40(%rsp) + mov %r14, 64+48(%rsp) + mov %r15, 64+56(%rsp) + + movq %xmm0, $out + movq %xmm1, %rbp + + mov 128(%rsp), %rdx # pull $n0 + mov (%rsp), %r8 + mov 8(%rsp), %r9 + mov 16(%rsp), %r10 + mov 24(%rsp), %r11 + mov 32(%rsp), %r12 + mov 40(%rsp), %r13 + mov 48(%rsp), %r14 + mov 56(%rsp), %r15 + + call __rsaz_512_reducex + +.Lmul_gather_tail: +___ +$code.=<<___; + addq 64(%rsp), %r8 + adcq 72(%rsp), %r9 + adcq 80(%rsp), %r10 + adcq 88(%rsp), %r11 + adcq 96(%rsp), %r12 + adcq 104(%rsp), %r13 + adcq 112(%rsp), %r14 + adcq 120(%rsp), %r15 + sbbq %rcx, %rcx + + call __rsaz_512_subtract + + leaq 128+24+48(%rsp), %rax + movq -48(%rax), %r15 + movq -40(%rax), %r14 + movq -32(%rax), %r13 + movq -24(%rax), %r12 + movq -16(%rax), %rbp + movq -8(%rax), %rbx + leaq (%rax), %rsp +.Lmul_gather4_epilogue: + ret +.size rsaz_512_mul_gather4,.-rsaz_512_mul_gather4 +___ +} +{ +my ($out,$ap,$mod,$n0,$tbl,$pwr) = ("%rdi","%rsi","%rdx","%rcx","%r8","%r9d"); +$code.=<<___; +.globl rsaz_512_mul_scatter4 +.type rsaz_512_mul_scatter4,\@function,6 +.align 32 +rsaz_512_mul_scatter4: + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + + mov $pwr, $pwr + subq \$128+24, %rsp +.Lmul_scatter4_body: + leaq ($tbl,$pwr,4), $tbl + movq $out, %xmm0 # off-load arguments + movq $mod, %xmm1 + movq $tbl, %xmm2 + movq $n0, 128(%rsp) + + movq $out, %rbp +___ +$code.=<<___ if ($addx); + movl \$0x80100,%r11d + andl OPENSSL_ia32cap_P+8(%rip),%r11d + cmpl \$0x80100,%r11d # check for MULX and ADO/CX + je .Lmulx_scatter +___ +$code.=<<___; + movq ($out),%rbx # pass b[0] + call __rsaz_512_mul + + movq %xmm0, $out + movq %xmm1, %rbp + + movq (%rsp), %r8 + movq 8(%rsp), %r9 + movq 16(%rsp), %r10 + movq 24(%rsp), %r11 + movq 32(%rsp), %r12 + movq 40(%rsp), %r13 + movq 48(%rsp), %r14 + movq 56(%rsp), %r15 + + call __rsaz_512_reduce +___ +$code.=<<___ if ($addx); + jmp .Lmul_scatter_tail + +.align 32 +.Lmulx_scatter: + movq ($out), %rdx # pass b[0] + call __rsaz_512_mulx + + movq %xmm0, $out + movq %xmm1, %rbp + + movq 128(%rsp), %rdx # pull $n0 + movq (%rsp), %r8 + movq 8(%rsp), %r9 + movq 16(%rsp), %r10 + movq 24(%rsp), %r11 + movq 32(%rsp), %r12 + movq 40(%rsp), %r13 + movq 48(%rsp), %r14 + movq 56(%rsp), %r15 + + call __rsaz_512_reducex + +.Lmul_scatter_tail: +___ +$code.=<<___; + addq 64(%rsp), %r8 + adcq 72(%rsp), %r9 + adcq 80(%rsp), %r10 + adcq 88(%rsp), %r11 + adcq 96(%rsp), %r12 + adcq 104(%rsp), %r13 + adcq 112(%rsp), %r14 + adcq 120(%rsp), %r15 + movq %xmm2, $inp + sbbq %rcx, %rcx + + call __rsaz_512_subtract + + movl %r8d, 64*0($inp) # scatter + shrq \$32, %r8 + movl %r9d, 64*2($inp) + shrq \$32, %r9 + movl %r10d, 64*4($inp) + shrq \$32, %r10 + movl %r11d, 64*6($inp) + shrq \$32, %r11 + movl %r12d, 64*8($inp) + shrq \$32, %r12 + movl %r13d, 64*10($inp) + shrq \$32, %r13 + movl %r14d, 64*12($inp) + shrq \$32, %r14 + movl %r15d, 64*14($inp) + shrq \$32, %r15 + movl %r8d, 64*1($inp) + movl %r9d, 64*3($inp) + movl %r10d, 64*5($inp) + movl %r11d, 64*7($inp) + movl %r12d, 64*9($inp) + movl %r13d, 64*11($inp) + movl %r14d, 64*13($inp) + movl %r15d, 64*15($inp) + + leaq 128+24+48(%rsp), %rax + movq -48(%rax), %r15 + movq -40(%rax), %r14 + movq -32(%rax), %r13 + movq -24(%rax), %r12 + movq -16(%rax), %rbp + movq -8(%rax), %rbx + leaq (%rax), %rsp +.Lmul_scatter4_epilogue: + ret +.size rsaz_512_mul_scatter4,.-rsaz_512_mul_scatter4 +___ +} +{ +my ($out,$inp,$mod,$n0) = ("%rdi","%rsi","%rdx","%rcx"); +$code.=<<___; +.globl rsaz_512_mul_by_one +.type rsaz_512_mul_by_one,\@function,4 +.align 32 +rsaz_512_mul_by_one: + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + + subq \$128+24, %rsp +.Lmul_by_one_body: +___ +$code.=<<___ if ($addx); + movl OPENSSL_ia32cap_P+8(%rip),%eax +___ +$code.=<<___; + movq $mod, %rbp # reassign argument + movq $n0, 128(%rsp) + + movq ($inp), %r8 + pxor %xmm0, %xmm0 + movq 8($inp), %r9 + movq 16($inp), %r10 + movq 24($inp), %r11 + movq 32($inp), %r12 + movq 40($inp), %r13 + movq 48($inp), %r14 + movq 56($inp), %r15 + + movdqa %xmm0, (%rsp) + movdqa %xmm0, 16(%rsp) + movdqa %xmm0, 32(%rsp) + movdqa %xmm0, 48(%rsp) + movdqa %xmm0, 64(%rsp) + movdqa %xmm0, 80(%rsp) + movdqa %xmm0, 96(%rsp) +___ +$code.=<<___ if ($addx); + andl \$0x80100,%eax + cmpl \$0x80100,%eax # check for MULX and ADO/CX + je .Lby_one_callx +___ +$code.=<<___; + call __rsaz_512_reduce +___ +$code.=<<___ if ($addx); + jmp .Lby_one_tail +.align 32 +.Lby_one_callx: + movq 128(%rsp), %rdx # pull $n0 + call __rsaz_512_reducex +.Lby_one_tail: +___ +$code.=<<___; + movq %r8, ($out) + movq %r9, 8($out) + movq %r10, 16($out) + movq %r11, 24($out) + movq %r12, 32($out) + movq %r13, 40($out) + movq %r14, 48($out) + movq %r15, 56($out) + + leaq 128+24+48(%rsp), %rax + movq -48(%rax), %r15 + movq -40(%rax), %r14 + movq -32(%rax), %r13 + movq -24(%rax), %r12 + movq -16(%rax), %rbp + movq -8(%rax), %rbx + leaq (%rax), %rsp +.Lmul_by_one_epilogue: + ret +.size rsaz_512_mul_by_one,.-rsaz_512_mul_by_one +___ +} +{ # __rsaz_512_reduce + # + # input: %r8-%r15, %rbp - mod, 128(%rsp) - n0 + # output: %r8-%r15 + # clobbers: everything except %rbp and %rdi +$code.=<<___; +.type __rsaz_512_reduce,\@abi-omnipotent +.align 32 +__rsaz_512_reduce: + movq %r8, %rbx + imulq 128+8(%rsp), %rbx + movq 0(%rbp), %rax + movl \$8, %ecx + jmp .Lreduction_loop + +.align 32 +.Lreduction_loop: + mulq %rbx + movq 8(%rbp), %rax + negq %r8 + movq %rdx, %r8 + adcq \$0, %r8 + + mulq %rbx + addq %rax, %r9 + movq 16(%rbp), %rax + adcq \$0, %rdx + addq %r9, %r8 + movq %rdx, %r9 + adcq \$0, %r9 + + mulq %rbx + addq %rax, %r10 + movq 24(%rbp), %rax + adcq \$0, %rdx + addq %r10, %r9 + movq %rdx, %r10 + adcq \$0, %r10 + + mulq %rbx + addq %rax, %r11 + movq 32(%rbp), %rax + adcq \$0, %rdx + addq %r11, %r10 + movq 128+8(%rsp), %rsi + #movq %rdx, %r11 + #adcq \$0, %r11 + adcq \$0, %rdx + movq %rdx, %r11 + + mulq %rbx + addq %rax, %r12 + movq 40(%rbp), %rax + adcq \$0, %rdx + imulq %r8, %rsi + addq %r12, %r11 + movq %rdx, %r12 + adcq \$0, %r12 + + mulq %rbx + addq %rax, %r13 + movq 48(%rbp), %rax + adcq \$0, %rdx + addq %r13, %r12 + movq %rdx, %r13 + adcq \$0, %r13 + + mulq %rbx + addq %rax, %r14 + movq 56(%rbp), %rax + adcq \$0, %rdx + addq %r14, %r13 + movq %rdx, %r14 + adcq \$0, %r14 + + mulq %rbx + movq %rsi, %rbx + addq %rax, %r15 + movq 0(%rbp), %rax + adcq \$0, %rdx + addq %r15, %r14 + movq %rdx, %r15 + adcq \$0, %r15 + + decl %ecx + jne .Lreduction_loop + + ret +.size __rsaz_512_reduce,.-__rsaz_512_reduce +___ +} +if ($addx) { + # __rsaz_512_reducex + # + # input: %r8-%r15, %rbp - mod, 128(%rsp) - n0 + # output: %r8-%r15 + # clobbers: everything except %rbp and %rdi +$code.=<<___; +.type __rsaz_512_reducex,\@abi-omnipotent +.align 32 +__rsaz_512_reducex: + #movq 128+8(%rsp), %rdx # pull $n0 + imulq %r8, %rdx + xorq %rsi, %rsi # cf=0,of=0 + movl \$8, %ecx + jmp .Lreduction_loopx + +.align 32 +.Lreduction_loopx: + mov %r8, %rbx + mulx 0(%rbp), %rax, %r8 + adcx %rbx, %rax + adox %r9, %r8 + + mulx 8(%rbp), %rax, %r9 + adcx %rax, %r8 + adox %r10, %r9 + + mulx 16(%rbp), %rbx, %r10 + adcx %rbx, %r9 + adox %r11, %r10 + + mulx 24(%rbp), %rbx, %r11 + adcx %rbx, %r10 + adox %r12, %r11 + + .byte 0xc4,0x62,0xe3,0xf6,0xa5,0x20,0x00,0x00,0x00 # mulx 32(%rbp), %rbx, %r12 + mov %rdx, %rax + mov %r8, %rdx + adcx %rbx, %r11 + adox %r13, %r12 + + mulx 128+8(%rsp), %rbx, %rdx + mov %rax, %rdx + + mulx 40(%rbp), %rax, %r13 + adcx %rax, %r12 + adox %r14, %r13 + + .byte 0xc4,0x62,0xfb,0xf6,0xb5,0x30,0x00,0x00,0x00 # mulx 48(%rbp), %rax, %r14 + adcx %rax, %r13 + adox %r15, %r14 + + mulx 56(%rbp), %rax, %r15 + mov %rbx, %rdx + adcx %rax, %r14 + adox %rsi, %r15 # %rsi is 0 + adcx %rsi, %r15 # cf=0 + + decl %ecx # of=0 + jne .Lreduction_loopx + + ret +.size __rsaz_512_reducex,.-__rsaz_512_reducex +___ +} +{ # __rsaz_512_subtract + # input: %r8-%r15, %rdi - $out, %rbp - $mod, %rcx - mask + # output: + # clobbers: everything but %rdi, %rsi and %rbp +$code.=<<___; +.type __rsaz_512_subtract,\@abi-omnipotent +.align 32 +__rsaz_512_subtract: + movq %r8, ($out) + movq %r9, 8($out) + movq %r10, 16($out) + movq %r11, 24($out) + movq %r12, 32($out) + movq %r13, 40($out) + movq %r14, 48($out) + movq %r15, 56($out) + + movq 0($mod), %r8 + movq 8($mod), %r9 + negq %r8 + notq %r9 + andq %rcx, %r8 + movq 16($mod), %r10 + andq %rcx, %r9 + notq %r10 + movq 24($mod), %r11 + andq %rcx, %r10 + notq %r11 + movq 32($mod), %r12 + andq %rcx, %r11 + notq %r12 + movq 40($mod), %r13 + andq %rcx, %r12 + notq %r13 + movq 48($mod), %r14 + andq %rcx, %r13 + notq %r14 + movq 56($mod), %r15 + andq %rcx, %r14 + notq %r15 + andq %rcx, %r15 + + addq ($out), %r8 + adcq 8($out), %r9 + adcq 16($out), %r10 + adcq 24($out), %r11 + adcq 32($out), %r12 + adcq 40($out), %r13 + adcq 48($out), %r14 + adcq 56($out), %r15 + + movq %r8, ($out) + movq %r9, 8($out) + movq %r10, 16($out) + movq %r11, 24($out) + movq %r12, 32($out) + movq %r13, 40($out) + movq %r14, 48($out) + movq %r15, 56($out) + + ret +.size __rsaz_512_subtract,.-__rsaz_512_subtract +___ +} +{ # __rsaz_512_mul + # + # input: %rsi - ap, %rbp - bp + # ouput: + # clobbers: everything +my ($ap,$bp) = ("%rsi","%rbp"); +$code.=<<___; +.type __rsaz_512_mul,\@abi-omnipotent +.align 32 +__rsaz_512_mul: + leaq 8(%rsp), %rdi + + movq ($ap), %rax + mulq %rbx + movq %rax, (%rdi) + movq 8($ap), %rax + movq %rdx, %r8 + + mulq %rbx + addq %rax, %r8 + movq 16($ap), %rax + movq %rdx, %r9 + adcq \$0, %r9 + + mulq %rbx + addq %rax, %r9 + movq 24($ap), %rax + movq %rdx, %r10 + adcq \$0, %r10 + + mulq %rbx + addq %rax, %r10 + movq 32($ap), %rax + movq %rdx, %r11 + adcq \$0, %r11 + + mulq %rbx + addq %rax, %r11 + movq 40($ap), %rax + movq %rdx, %r12 + adcq \$0, %r12 + + mulq %rbx + addq %rax, %r12 + movq 48($ap), %rax + movq %rdx, %r13 + adcq \$0, %r13 + + mulq %rbx + addq %rax, %r13 + movq 56($ap), %rax + movq %rdx, %r14 + adcq \$0, %r14 + + mulq %rbx + addq %rax, %r14 + movq ($ap), %rax + movq %rdx, %r15 + adcq \$0, %r15 + + leaq 8($bp), $bp + leaq 8(%rdi), %rdi + + movl \$7, %ecx + jmp .Loop_mul + +.align 32 +.Loop_mul: + movq ($bp), %rbx + mulq %rbx + addq %rax, %r8 + movq 8($ap), %rax + movq %r8, (%rdi) + movq %rdx, %r8 + adcq \$0, %r8 + + mulq %rbx + addq %rax, %r9 + movq 16($ap), %rax + adcq \$0, %rdx + addq %r9, %r8 + movq %rdx, %r9 + adcq \$0, %r9 + + mulq %rbx + addq %rax, %r10 + movq 24($ap), %rax + adcq \$0, %rdx + addq %r10, %r9 + movq %rdx, %r10 + adcq \$0, %r10 + + mulq %rbx + addq %rax, %r11 + movq 32($ap), %rax + adcq \$0, %rdx + addq %r11, %r10 + movq %rdx, %r11 + adcq \$0, %r11 + + mulq %rbx + addq %rax, %r12 + movq 40($ap), %rax + adcq \$0, %rdx + addq %r12, %r11 + movq %rdx, %r12 + adcq \$0, %r12 + + mulq %rbx + addq %rax, %r13 + movq 48($ap), %rax + adcq \$0, %rdx + addq %r13, %r12 + movq %rdx, %r13 + adcq \$0, %r13 + + mulq %rbx + addq %rax, %r14 + movq 56($ap), %rax + adcq \$0, %rdx + addq %r14, %r13 + movq %rdx, %r14 + leaq 8($bp), $bp + adcq \$0, %r14 + + mulq %rbx + addq %rax, %r15 + movq ($ap), %rax + adcq \$0, %rdx + addq %r15, %r14 + movq %rdx, %r15 + adcq \$0, %r15 + + leaq 8(%rdi), %rdi + + decl %ecx + jnz .Loop_mul + + movq %r8, (%rdi) + movq %r9, 8(%rdi) + movq %r10, 16(%rdi) + movq %r11, 24(%rdi) + movq %r12, 32(%rdi) + movq %r13, 40(%rdi) + movq %r14, 48(%rdi) + movq %r15, 56(%rdi) + + ret +.size __rsaz_512_mul,.-__rsaz_512_mul +___ +} +if ($addx) { + # __rsaz_512_mulx + # + # input: %rsi - ap, %rbp - bp + # ouput: + # clobbers: everything +my ($ap,$bp,$zero) = ("%rsi","%rbp","%rdi"); +$code.=<<___; +.type __rsaz_512_mulx,\@abi-omnipotent +.align 32 +__rsaz_512_mulx: + mulx ($ap), %rbx, %r8 # initial %rdx preloaded by caller + mov \$-6, %rcx + + mulx 8($ap), %rax, %r9 + movq %rbx, 8(%rsp) + + mulx 16($ap), %rbx, %r10 + adc %rax, %r8 + + mulx 24($ap), %rax, %r11 + adc %rbx, %r9 + + mulx 32($ap), %rbx, %r12 + adc %rax, %r10 + + mulx 40($ap), %rax, %r13 + adc %rbx, %r11 + + mulx 48($ap), %rbx, %r14 + adc %rax, %r12 + + mulx 56($ap), %rax, %r15 + mov 8($bp), %rdx + adc %rbx, %r13 + adc %rax, %r14 + adc \$0, %r15 + + xor $zero, $zero # cf=0,of=0 + jmp .Loop_mulx + +.align 32 +.Loop_mulx: + movq %r8, %rbx + mulx ($ap), %rax, %r8 + adcx %rax, %rbx + adox %r9, %r8 + + mulx 8($ap), %rax, %r9 + adcx %rax, %r8 + adox %r10, %r9 + + mulx 16($ap), %rax, %r10 + adcx %rax, %r9 + adox %r11, %r10 + + mulx 24($ap), %rax, %r11 + adcx %rax, %r10 + adox %r12, %r11 + + .byte 0x3e,0xc4,0x62,0xfb,0xf6,0xa6,0x20,0x00,0x00,0x00 # mulx 32($ap), %rax, %r12 + adcx %rax, %r11 + adox %r13, %r12 + + mulx 40($ap), %rax, %r13 + adcx %rax, %r12 + adox %r14, %r13 + + mulx 48($ap), %rax, %r14 + adcx %rax, %r13 + adox %r15, %r14 + + mulx 56($ap), %rax, %r15 + movq 64($bp,%rcx,8), %rdx + movq %rbx, 8+64-8(%rsp,%rcx,8) + adcx %rax, %r14 + adox $zero, %r15 + adcx $zero, %r15 # cf=0 + + inc %rcx # of=0 + jnz .Loop_mulx + + movq %r8, %rbx + mulx ($ap), %rax, %r8 + adcx %rax, %rbx + adox %r9, %r8 + + .byte 0xc4,0x62,0xfb,0xf6,0x8e,0x08,0x00,0x00,0x00 # mulx 8($ap), %rax, %r9 + adcx %rax, %r8 + adox %r10, %r9 + + .byte 0xc4,0x62,0xfb,0xf6,0x96,0x10,0x00,0x00,0x00 # mulx 16($ap), %rax, %r10 + adcx %rax, %r9 + adox %r11, %r10 + + mulx 24($ap), %rax, %r11 + adcx %rax, %r10 + adox %r12, %r11 + + mulx 32($ap), %rax, %r12 + adcx %rax, %r11 + adox %r13, %r12 + + mulx 40($ap), %rax, %r13 + adcx %rax, %r12 + adox %r14, %r13 + + .byte 0xc4,0x62,0xfb,0xf6,0xb6,0x30,0x00,0x00,0x00 # mulx 48($ap), %rax, %r14 + adcx %rax, %r13 + adox %r15, %r14 + + .byte 0xc4,0x62,0xfb,0xf6,0xbe,0x38,0x00,0x00,0x00 # mulx 56($ap), %rax, %r15 + adcx %rax, %r14 + adox $zero, %r15 + adcx $zero, %r15 + + mov %rbx, 8+64-8(%rsp) + mov %r8, 8+64(%rsp) + mov %r9, 8+64+8(%rsp) + mov %r10, 8+64+16(%rsp) + mov %r11, 8+64+24(%rsp) + mov %r12, 8+64+32(%rsp) + mov %r13, 8+64+40(%rsp) + mov %r14, 8+64+48(%rsp) + mov %r15, 8+64+56(%rsp) + + ret +.size __rsaz_512_mulx,.-__rsaz_512_mulx +___ +} +{ +my ($out,$inp,$power)= $win64 ? ("%rcx","%rdx","%r8d") : ("%rdi","%rsi","%edx"); +$code.=<<___; +.globl rsaz_512_scatter4 +.type rsaz_512_scatter4,\@abi-omnipotent +.align 16 +rsaz_512_scatter4: + leaq ($out,$power,4), $out + movl \$8, %r9d + jmp .Loop_scatter +.align 16 +.Loop_scatter: + movq ($inp), %rax + leaq 8($inp), $inp + movl %eax, ($out) + shrq \$32, %rax + movl %eax, 64($out) + leaq 128($out), $out + decl %r9d + jnz .Loop_scatter + ret +.size rsaz_512_scatter4,.-rsaz_512_scatter4 + +.globl rsaz_512_gather4 +.type rsaz_512_gather4,\@abi-omnipotent +.align 16 +rsaz_512_gather4: + leaq ($inp,$power,4), $inp + movl \$8, %r9d + jmp .Loop_gather +.align 16 +.Loop_gather: + movl ($inp), %eax + movl 64($inp), %r8d + leaq 128($inp), $inp + shlq \$32, %r8 + or %r8, %rax + movq %rax, ($out) + leaq 8($out), $out + decl %r9d + jnz .Loop_gather + ret +.size rsaz_512_gather4,.-rsaz_512_gather4 +___ +} + +# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame, +# CONTEXT *context,DISPATCHER_CONTEXT *disp) +if ($win64) { +$rec="%rcx"; +$frame="%rdx"; +$context="%r8"; +$disp="%r9"; + +$code.=<<___; +.extern __imp_RtlVirtualUnwind +.type se_handler,\@abi-omnipotent +.align 16 +se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + mov 8($disp),%rsi # disp->ImageBase + mov 56($disp),%r11 # disp->HandlerData + + mov 0(%r11),%r10d # HandlerData[0] + lea (%rsi,%r10),%r10 # end of prologue label + cmp %r10,%rbx # context->RipRsp + + mov 4(%r11),%r10d # HandlerData[1] + lea (%rsi,%r10),%r10 # epilogue label + cmp %r10,%rbx # context->Rip>=epilogue label + jae .Lcommon_seh_tail + + lea 128+24+48(%rax),%rax + + mov -8(%rax),%rbx + mov -16(%rax),%rbp + mov -24(%rax),%r12 + mov -32(%rax),%r13 + mov -40(%rax),%r14 + mov -48(%rax),%r15 + mov %rbx,144($context) # restore context->Rbx + mov %rbp,160($context) # restore context->Rbp + mov %r12,216($context) # restore context->R12 + mov %r13,224($context) # restore context->R13 + mov %r14,232($context) # restore context->R14 + mov %r15,240($context) # restore context->R15 + +.Lcommon_seh_tail: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + + mov 40($disp),%rdi # disp->ContextRecord + mov $context,%rsi # context + mov \$154,%ecx # sizeof(CONTEXT) + .long 0xa548f3fc # cld; rep movsq + + mov $disp,%rsi + xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER + mov 8(%rsi),%rdx # arg2, disp->ImageBase + mov 0(%rsi),%r8 # arg3, disp->ControlPc + mov 16(%rsi),%r9 # arg4, disp->FunctionEntry + mov 40(%rsi),%r10 # disp->ContextRecord + lea 56(%rsi),%r11 # &disp->HandlerData + lea 24(%rsi),%r12 # &disp->EstablisherFrame + mov %r10,32(%rsp) # arg5 + mov %r11,40(%rsp) # arg6 + mov %r12,48(%rsp) # arg7 + mov %rcx,56(%rsp) # arg8, (NULL) + call *__imp_RtlVirtualUnwind(%rip) + + mov \$1,%eax # ExceptionContinueSearch + add \$64,%rsp + popfq + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + pop %rdi + pop %rsi + ret +.size sqr_handler,.-sqr_handler + +.section .pdata +.align 4 + .rva .LSEH_begin_rsaz_512_sqr + .rva .LSEH_end_rsaz_512_sqr + .rva .LSEH_info_rsaz_512_sqr + + .rva .LSEH_begin_rsaz_512_mul + .rva .LSEH_end_rsaz_512_mul + .rva .LSEH_info_rsaz_512_mul + + .rva .LSEH_begin_rsaz_512_mul_gather4 + .rva .LSEH_end_rsaz_512_mul_gather4 + .rva .LSEH_info_rsaz_512_mul_gather4 + + .rva .LSEH_begin_rsaz_512_mul_scatter4 + .rva .LSEH_end_rsaz_512_mul_scatter4 + .rva .LSEH_info_rsaz_512_mul_scatter4 + + .rva .LSEH_begin_rsaz_512_mul_by_one + .rva .LSEH_end_rsaz_512_mul_by_one + .rva .LSEH_info_rsaz_512_mul_by_one + +.section .xdata +.align 8 +.LSEH_info_rsaz_512_sqr: + .byte 9,0,0,0 + .rva se_handler + .rva .Lsqr_body,.Lsqr_epilogue # HandlerData[] +.LSEH_info_rsaz_512_mul: + .byte 9,0,0,0 + .rva se_handler + .rva .Lmul_body,.Lmul_epilogue # HandlerData[] +.LSEH_info_rsaz_512_mul_gather4: + .byte 9,0,0,0 + .rva se_handler + .rva .Lmul_gather4_body,.Lmul_gather4_epilogue # HandlerData[] +.LSEH_info_rsaz_512_mul_scatter4: + .byte 9,0,0,0 + .rva se_handler + .rva .Lmul_scatter4_body,.Lmul_scatter4_epilogue # HandlerData[] +.LSEH_info_rsaz_512_mul_by_one: + .byte 9,0,0,0 + .rva se_handler + .rva .Lmul_by_one_body,.Lmul_by_one_epilogue # HandlerData[] +___ +} + +$code =~ s/\`([^\`]*)\`/eval $1/gem; +print $code; +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/bn/asm/x86-mont.pl b/TMessagesProj/jni/boringssl/crypto/bn/asm/x86-mont.pl new file mode 100644 index 00000000..0626b487 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/asm/x86-mont.pl @@ -0,0 +1,592 @@ +#!/usr/bin/env perl + +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== + +# October 2005 +# +# This is a "teaser" code, as it can be improved in several ways... +# First of all non-SSE2 path should be implemented (yes, for now it +# performs Montgomery multiplication/convolution only on SSE2-capable +# CPUs such as P4, others fall down to original code). Then inner loop +# can be unrolled and modulo-scheduled to improve ILP and possibly +# moved to 128-bit XMM register bank (though it would require input +# rearrangement and/or increase bus bandwidth utilization). Dedicated +# squaring procedure should give further performance improvement... +# Yet, for being draft, the code improves rsa512 *sign* benchmark by +# 110%(!), rsa1024 one - by 70% and rsa4096 - by 20%:-) + +# December 2006 +# +# Modulo-scheduling SSE2 loops results in further 15-20% improvement. +# Integer-only code [being equipped with dedicated squaring procedure] +# gives ~40% on rsa512 sign benchmark... + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +push(@INC,"${dir}","${dir}../../perlasm"); +require "x86asm.pl"; + +&asm_init($ARGV[0],$0); + +$sse2=0; +for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); } + +&external_label("OPENSSL_ia32cap_P") if ($sse2); + +&function_begin("bn_mul_mont"); + +$i="edx"; +$j="ecx"; +$ap="esi"; $tp="esi"; # overlapping variables!!! +$rp="edi"; $bp="edi"; # overlapping variables!!! +$np="ebp"; +$num="ebx"; + +$_num=&DWP(4*0,"esp"); # stack top layout +$_rp=&DWP(4*1,"esp"); +$_ap=&DWP(4*2,"esp"); +$_bp=&DWP(4*3,"esp"); +$_np=&DWP(4*4,"esp"); +$_n0=&DWP(4*5,"esp"); $_n0q=&QWP(4*5,"esp"); +$_sp=&DWP(4*6,"esp"); +$_bpend=&DWP(4*7,"esp"); +$frame=32; # size of above frame rounded up to 16n + + &xor ("eax","eax"); + &mov ("edi",&wparam(5)); # int num + &cmp ("edi",4); + &jl (&label("just_leave")); + + &lea ("esi",&wparam(0)); # put aside pointer to argument block + &lea ("edx",&wparam(1)); # load ap + &mov ("ebp","esp"); # saved stack pointer! + &add ("edi",2); # extra two words on top of tp + &neg ("edi"); + &lea ("esp",&DWP(-$frame,"esp","edi",4)); # alloca($frame+4*(num+2)) + &neg ("edi"); + + # minimize cache contention by arraning 2K window between stack + # pointer and ap argument [np is also position sensitive vector, + # but it's assumed to be near ap, as it's allocated at ~same + # time]. + &mov ("eax","esp"); + &sub ("eax","edx"); + &and ("eax",2047); + &sub ("esp","eax"); # this aligns sp and ap modulo 2048 + + &xor ("edx","esp"); + &and ("edx",2048); + &xor ("edx",2048); + &sub ("esp","edx"); # this splits them apart modulo 4096 + + &and ("esp",-64); # align to cache line + + ################################# load argument block... + &mov ("eax",&DWP(0*4,"esi"));# BN_ULONG *rp + &mov ("ebx",&DWP(1*4,"esi"));# const BN_ULONG *ap + &mov ("ecx",&DWP(2*4,"esi"));# const BN_ULONG *bp + &mov ("edx",&DWP(3*4,"esi"));# const BN_ULONG *np + &mov ("esi",&DWP(4*4,"esi"));# const BN_ULONG *n0 + #&mov ("edi",&DWP(5*4,"esi"));# int num + + &mov ("esi",&DWP(0,"esi")); # pull n0[0] + &mov ($_rp,"eax"); # ... save a copy of argument block + &mov ($_ap,"ebx"); + &mov ($_bp,"ecx"); + &mov ($_np,"edx"); + &mov ($_n0,"esi"); + &lea ($num,&DWP(-3,"edi")); # num=num-1 to assist modulo-scheduling + #&mov ($_num,$num); # redundant as $num is not reused + &mov ($_sp,"ebp"); # saved stack pointer! + +if($sse2) { +$acc0="mm0"; # mmx register bank layout +$acc1="mm1"; +$car0="mm2"; +$car1="mm3"; +$mul0="mm4"; +$mul1="mm5"; +$temp="mm6"; +$mask="mm7"; + + &picmeup("eax","OPENSSL_ia32cap_P"); + &bt (&DWP(0,"eax"),26); + &jnc (&label("non_sse2")); + + &mov ("eax",-1); + &movd ($mask,"eax"); # mask 32 lower bits + + &mov ($ap,$_ap); # load input pointers + &mov ($bp,$_bp); + &mov ($np,$_np); + + &xor ($i,$i); # i=0 + &xor ($j,$j); # j=0 + + &movd ($mul0,&DWP(0,$bp)); # bp[0] + &movd ($mul1,&DWP(0,$ap)); # ap[0] + &movd ($car1,&DWP(0,$np)); # np[0] + + &pmuludq($mul1,$mul0); # ap[0]*bp[0] + &movq ($car0,$mul1); + &movq ($acc0,$mul1); # I wish movd worked for + &pand ($acc0,$mask); # inter-register transfers + + &pmuludq($mul1,$_n0q); # *=n0 + + &pmuludq($car1,$mul1); # "t[0]"*np[0]*n0 + &paddq ($car1,$acc0); + + &movd ($acc1,&DWP(4,$np)); # np[1] + &movd ($acc0,&DWP(4,$ap)); # ap[1] + + &psrlq ($car0,32); + &psrlq ($car1,32); + + &inc ($j); # j++ +&set_label("1st",16); + &pmuludq($acc0,$mul0); # ap[j]*bp[0] + &pmuludq($acc1,$mul1); # np[j]*m1 + &paddq ($car0,$acc0); # +=c0 + &paddq ($car1,$acc1); # +=c1 + + &movq ($acc0,$car0); + &pand ($acc0,$mask); + &movd ($acc1,&DWP(4,$np,$j,4)); # np[j+1] + &paddq ($car1,$acc0); # +=ap[j]*bp[0]; + &movd ($acc0,&DWP(4,$ap,$j,4)); # ap[j+1] + &psrlq ($car0,32); + &movd (&DWP($frame-4,"esp",$j,4),$car1); # tp[j-1]= + &psrlq ($car1,32); + + &lea ($j,&DWP(1,$j)); + &cmp ($j,$num); + &jl (&label("1st")); + + &pmuludq($acc0,$mul0); # ap[num-1]*bp[0] + &pmuludq($acc1,$mul1); # np[num-1]*m1 + &paddq ($car0,$acc0); # +=c0 + &paddq ($car1,$acc1); # +=c1 + + &movq ($acc0,$car0); + &pand ($acc0,$mask); + &paddq ($car1,$acc0); # +=ap[num-1]*bp[0]; + &movd (&DWP($frame-4,"esp",$j,4),$car1); # tp[num-2]= + + &psrlq ($car0,32); + &psrlq ($car1,32); + + &paddq ($car1,$car0); + &movq (&QWP($frame,"esp",$num,4),$car1); # tp[num].tp[num-1] + + &inc ($i); # i++ +&set_label("outer"); + &xor ($j,$j); # j=0 + + &movd ($mul0,&DWP(0,$bp,$i,4)); # bp[i] + &movd ($mul1,&DWP(0,$ap)); # ap[0] + &movd ($temp,&DWP($frame,"esp")); # tp[0] + &movd ($car1,&DWP(0,$np)); # np[0] + &pmuludq($mul1,$mul0); # ap[0]*bp[i] + + &paddq ($mul1,$temp); # +=tp[0] + &movq ($acc0,$mul1); + &movq ($car0,$mul1); + &pand ($acc0,$mask); + + &pmuludq($mul1,$_n0q); # *=n0 + + &pmuludq($car1,$mul1); + &paddq ($car1,$acc0); + + &movd ($temp,&DWP($frame+4,"esp")); # tp[1] + &movd ($acc1,&DWP(4,$np)); # np[1] + &movd ($acc0,&DWP(4,$ap)); # ap[1] + + &psrlq ($car0,32); + &psrlq ($car1,32); + &paddq ($car0,$temp); # +=tp[1] + + &inc ($j); # j++ + &dec ($num); +&set_label("inner"); + &pmuludq($acc0,$mul0); # ap[j]*bp[i] + &pmuludq($acc1,$mul1); # np[j]*m1 + &paddq ($car0,$acc0); # +=c0 + &paddq ($car1,$acc1); # +=c1 + + &movq ($acc0,$car0); + &movd ($temp,&DWP($frame+4,"esp",$j,4));# tp[j+1] + &pand ($acc0,$mask); + &movd ($acc1,&DWP(4,$np,$j,4)); # np[j+1] + &paddq ($car1,$acc0); # +=ap[j]*bp[i]+tp[j] + &movd ($acc0,&DWP(4,$ap,$j,4)); # ap[j+1] + &psrlq ($car0,32); + &movd (&DWP($frame-4,"esp",$j,4),$car1);# tp[j-1]= + &psrlq ($car1,32); + &paddq ($car0,$temp); # +=tp[j+1] + + &dec ($num); + &lea ($j,&DWP(1,$j)); # j++ + &jnz (&label("inner")); + + &mov ($num,$j); + &pmuludq($acc0,$mul0); # ap[num-1]*bp[i] + &pmuludq($acc1,$mul1); # np[num-1]*m1 + &paddq ($car0,$acc0); # +=c0 + &paddq ($car1,$acc1); # +=c1 + + &movq ($acc0,$car0); + &pand ($acc0,$mask); + &paddq ($car1,$acc0); # +=ap[num-1]*bp[i]+tp[num-1] + &movd (&DWP($frame-4,"esp",$j,4),$car1); # tp[num-2]= + &psrlq ($car0,32); + &psrlq ($car1,32); + + &movd ($temp,&DWP($frame+4,"esp",$num,4)); # += tp[num] + &paddq ($car1,$car0); + &paddq ($car1,$temp); + &movq (&QWP($frame,"esp",$num,4),$car1); # tp[num].tp[num-1] + + &lea ($i,&DWP(1,$i)); # i++ + &cmp ($i,$num); + &jle (&label("outer")); + + &emms (); # done with mmx bank + &jmp (&label("common_tail")); + +&set_label("non_sse2",16); +} + +if (0) { + &mov ("esp",$_sp); + &xor ("eax","eax"); # signal "not fast enough [yet]" + &jmp (&label("just_leave")); + # While the below code provides competitive performance for + # all key lengthes on modern Intel cores, it's still more + # than 10% slower for 4096-bit key elsewhere:-( "Competitive" + # means compared to the original integer-only assembler. + # 512-bit RSA sign is better by ~40%, but that's about all + # one can say about all CPUs... +} else { +$inp="esi"; # integer path uses these registers differently +$word="edi"; +$carry="ebp"; + + &mov ($inp,$_ap); + &lea ($carry,&DWP(1,$num)); + &mov ($word,$_bp); + &xor ($j,$j); # j=0 + &mov ("edx",$inp); + &and ($carry,1); # see if num is even + &sub ("edx",$word); # see if ap==bp + &lea ("eax",&DWP(4,$word,$num,4)); # &bp[num] + &or ($carry,"edx"); + &mov ($word,&DWP(0,$word)); # bp[0] + &jz (&label("bn_sqr_mont")); + &mov ($_bpend,"eax"); + &mov ("eax",&DWP(0,$inp)); + &xor ("edx","edx"); + +&set_label("mull",16); + &mov ($carry,"edx"); + &mul ($word); # ap[j]*bp[0] + &add ($carry,"eax"); + &lea ($j,&DWP(1,$j)); + &adc ("edx",0); + &mov ("eax",&DWP(0,$inp,$j,4)); # ap[j+1] + &cmp ($j,$num); + &mov (&DWP($frame-4,"esp",$j,4),$carry); # tp[j]= + &jl (&label("mull")); + + &mov ($carry,"edx"); + &mul ($word); # ap[num-1]*bp[0] + &mov ($word,$_n0); + &add ("eax",$carry); + &mov ($inp,$_np); + &adc ("edx",0); + &imul ($word,&DWP($frame,"esp")); # n0*tp[0] + + &mov (&DWP($frame,"esp",$num,4),"eax"); # tp[num-1]= + &xor ($j,$j); + &mov (&DWP($frame+4,"esp",$num,4),"edx"); # tp[num]= + &mov (&DWP($frame+8,"esp",$num,4),$j); # tp[num+1]= + + &mov ("eax",&DWP(0,$inp)); # np[0] + &mul ($word); # np[0]*m + &add ("eax",&DWP($frame,"esp")); # +=tp[0] + &mov ("eax",&DWP(4,$inp)); # np[1] + &adc ("edx",0); + &inc ($j); + + &jmp (&label("2ndmadd")); + +&set_label("1stmadd",16); + &mov ($carry,"edx"); + &mul ($word); # ap[j]*bp[i] + &add ($carry,&DWP($frame,"esp",$j,4)); # +=tp[j] + &lea ($j,&DWP(1,$j)); + &adc ("edx",0); + &add ($carry,"eax"); + &mov ("eax",&DWP(0,$inp,$j,4)); # ap[j+1] + &adc ("edx",0); + &cmp ($j,$num); + &mov (&DWP($frame-4,"esp",$j,4),$carry); # tp[j]= + &jl (&label("1stmadd")); + + &mov ($carry,"edx"); + &mul ($word); # ap[num-1]*bp[i] + &add ("eax",&DWP($frame,"esp",$num,4)); # +=tp[num-1] + &mov ($word,$_n0); + &adc ("edx",0); + &mov ($inp,$_np); + &add ($carry,"eax"); + &adc ("edx",0); + &imul ($word,&DWP($frame,"esp")); # n0*tp[0] + + &xor ($j,$j); + &add ("edx",&DWP($frame+4,"esp",$num,4)); # carry+=tp[num] + &mov (&DWP($frame,"esp",$num,4),$carry); # tp[num-1]= + &adc ($j,0); + &mov ("eax",&DWP(0,$inp)); # np[0] + &mov (&DWP($frame+4,"esp",$num,4),"edx"); # tp[num]= + &mov (&DWP($frame+8,"esp",$num,4),$j); # tp[num+1]= + + &mul ($word); # np[0]*m + &add ("eax",&DWP($frame,"esp")); # +=tp[0] + &mov ("eax",&DWP(4,$inp)); # np[1] + &adc ("edx",0); + &mov ($j,1); + +&set_label("2ndmadd",16); + &mov ($carry,"edx"); + &mul ($word); # np[j]*m + &add ($carry,&DWP($frame,"esp",$j,4)); # +=tp[j] + &lea ($j,&DWP(1,$j)); + &adc ("edx",0); + &add ($carry,"eax"); + &mov ("eax",&DWP(0,$inp,$j,4)); # np[j+1] + &adc ("edx",0); + &cmp ($j,$num); + &mov (&DWP($frame-8,"esp",$j,4),$carry); # tp[j-1]= + &jl (&label("2ndmadd")); + + &mov ($carry,"edx"); + &mul ($word); # np[j]*m + &add ($carry,&DWP($frame,"esp",$num,4)); # +=tp[num-1] + &adc ("edx",0); + &add ($carry,"eax"); + &adc ("edx",0); + &mov (&DWP($frame-4,"esp",$num,4),$carry); # tp[num-2]= + + &xor ("eax","eax"); + &mov ($j,$_bp); # &bp[i] + &add ("edx",&DWP($frame+4,"esp",$num,4)); # carry+=tp[num] + &adc ("eax",&DWP($frame+8,"esp",$num,4)); # +=tp[num+1] + &lea ($j,&DWP(4,$j)); + &mov (&DWP($frame,"esp",$num,4),"edx"); # tp[num-1]= + &cmp ($j,$_bpend); + &mov (&DWP($frame+4,"esp",$num,4),"eax"); # tp[num]= + &je (&label("common_tail")); + + &mov ($word,&DWP(0,$j)); # bp[i+1] + &mov ($inp,$_ap); + &mov ($_bp,$j); # &bp[++i] + &xor ($j,$j); + &xor ("edx","edx"); + &mov ("eax",&DWP(0,$inp)); + &jmp (&label("1stmadd")); + +&set_label("bn_sqr_mont",16); +$sbit=$num; + &mov ($_num,$num); + &mov ($_bp,$j); # i=0 + + &mov ("eax",$word); # ap[0] + &mul ($word); # ap[0]*ap[0] + &mov (&DWP($frame,"esp"),"eax"); # tp[0]= + &mov ($sbit,"edx"); + &shr ("edx",1); + &and ($sbit,1); + &inc ($j); +&set_label("sqr",16); + &mov ("eax",&DWP(0,$inp,$j,4)); # ap[j] + &mov ($carry,"edx"); + &mul ($word); # ap[j]*ap[0] + &add ("eax",$carry); + &lea ($j,&DWP(1,$j)); + &adc ("edx",0); + &lea ($carry,&DWP(0,$sbit,"eax",2)); + &shr ("eax",31); + &cmp ($j,$_num); + &mov ($sbit,"eax"); + &mov (&DWP($frame-4,"esp",$j,4),$carry); # tp[j]= + &jl (&label("sqr")); + + &mov ("eax",&DWP(0,$inp,$j,4)); # ap[num-1] + &mov ($carry,"edx"); + &mul ($word); # ap[num-1]*ap[0] + &add ("eax",$carry); + &mov ($word,$_n0); + &adc ("edx",0); + &mov ($inp,$_np); + &lea ($carry,&DWP(0,$sbit,"eax",2)); + &imul ($word,&DWP($frame,"esp")); # n0*tp[0] + &shr ("eax",31); + &mov (&DWP($frame,"esp",$j,4),$carry); # tp[num-1]= + + &lea ($carry,&DWP(0,"eax","edx",2)); + &mov ("eax",&DWP(0,$inp)); # np[0] + &shr ("edx",31); + &mov (&DWP($frame+4,"esp",$j,4),$carry); # tp[num]= + &mov (&DWP($frame+8,"esp",$j,4),"edx"); # tp[num+1]= + + &mul ($word); # np[0]*m + &add ("eax",&DWP($frame,"esp")); # +=tp[0] + &mov ($num,$j); + &adc ("edx",0); + &mov ("eax",&DWP(4,$inp)); # np[1] + &mov ($j,1); + +&set_label("3rdmadd",16); + &mov ($carry,"edx"); + &mul ($word); # np[j]*m + &add ($carry,&DWP($frame,"esp",$j,4)); # +=tp[j] + &adc ("edx",0); + &add ($carry,"eax"); + &mov ("eax",&DWP(4,$inp,$j,4)); # np[j+1] + &adc ("edx",0); + &mov (&DWP($frame-4,"esp",$j,4),$carry); # tp[j-1]= + + &mov ($carry,"edx"); + &mul ($word); # np[j+1]*m + &add ($carry,&DWP($frame+4,"esp",$j,4)); # +=tp[j+1] + &lea ($j,&DWP(2,$j)); + &adc ("edx",0); + &add ($carry,"eax"); + &mov ("eax",&DWP(0,$inp,$j,4)); # np[j+2] + &adc ("edx",0); + &cmp ($j,$num); + &mov (&DWP($frame-8,"esp",$j,4),$carry); # tp[j]= + &jl (&label("3rdmadd")); + + &mov ($carry,"edx"); + &mul ($word); # np[j]*m + &add ($carry,&DWP($frame,"esp",$num,4)); # +=tp[num-1] + &adc ("edx",0); + &add ($carry,"eax"); + &adc ("edx",0); + &mov (&DWP($frame-4,"esp",$num,4),$carry); # tp[num-2]= + + &mov ($j,$_bp); # i + &xor ("eax","eax"); + &mov ($inp,$_ap); + &add ("edx",&DWP($frame+4,"esp",$num,4)); # carry+=tp[num] + &adc ("eax",&DWP($frame+8,"esp",$num,4)); # +=tp[num+1] + &mov (&DWP($frame,"esp",$num,4),"edx"); # tp[num-1]= + &cmp ($j,$num); + &mov (&DWP($frame+4,"esp",$num,4),"eax"); # tp[num]= + &je (&label("common_tail")); + + &mov ($word,&DWP(4,$inp,$j,4)); # ap[i] + &lea ($j,&DWP(1,$j)); + &mov ("eax",$word); + &mov ($_bp,$j); # ++i + &mul ($word); # ap[i]*ap[i] + &add ("eax",&DWP($frame,"esp",$j,4)); # +=tp[i] + &adc ("edx",0); + &mov (&DWP($frame,"esp",$j,4),"eax"); # tp[i]= + &xor ($carry,$carry); + &cmp ($j,$num); + &lea ($j,&DWP(1,$j)); + &je (&label("sqrlast")); + + &mov ($sbit,"edx"); # zaps $num + &shr ("edx",1); + &and ($sbit,1); +&set_label("sqradd",16); + &mov ("eax",&DWP(0,$inp,$j,4)); # ap[j] + &mov ($carry,"edx"); + &mul ($word); # ap[j]*ap[i] + &add ("eax",$carry); + &lea ($carry,&DWP(0,"eax","eax")); + &adc ("edx",0); + &shr ("eax",31); + &add ($carry,&DWP($frame,"esp",$j,4)); # +=tp[j] + &lea ($j,&DWP(1,$j)); + &adc ("eax",0); + &add ($carry,$sbit); + &adc ("eax",0); + &cmp ($j,$_num); + &mov (&DWP($frame-4,"esp",$j,4),$carry); # tp[j]= + &mov ($sbit,"eax"); + &jle (&label("sqradd")); + + &mov ($carry,"edx"); + &add ("edx","edx"); + &shr ($carry,31); + &add ("edx",$sbit); + &adc ($carry,0); +&set_label("sqrlast"); + &mov ($word,$_n0); + &mov ($inp,$_np); + &imul ($word,&DWP($frame,"esp")); # n0*tp[0] + + &add ("edx",&DWP($frame,"esp",$j,4)); # +=tp[num] + &mov ("eax",&DWP(0,$inp)); # np[0] + &adc ($carry,0); + &mov (&DWP($frame,"esp",$j,4),"edx"); # tp[num]= + &mov (&DWP($frame+4,"esp",$j,4),$carry); # tp[num+1]= + + &mul ($word); # np[0]*m + &add ("eax",&DWP($frame,"esp")); # +=tp[0] + &lea ($num,&DWP(-1,$j)); + &adc ("edx",0); + &mov ($j,1); + &mov ("eax",&DWP(4,$inp)); # np[1] + + &jmp (&label("3rdmadd")); +} + +&set_label("common_tail",16); + &mov ($np,$_np); # load modulus pointer + &mov ($rp,$_rp); # load result pointer + &lea ($tp,&DWP($frame,"esp")); # [$ap and $bp are zapped] + + &mov ("eax",&DWP(0,$tp)); # tp[0] + &mov ($j,$num); # j=num-1 + &xor ($i,$i); # i=0 and clear CF! + +&set_label("sub",16); + &sbb ("eax",&DWP(0,$np,$i,4)); + &mov (&DWP(0,$rp,$i,4),"eax"); # rp[i]=tp[i]-np[i] + &dec ($j); # doesn't affect CF! + &mov ("eax",&DWP(4,$tp,$i,4)); # tp[i+1] + &lea ($i,&DWP(1,$i)); # i++ + &jge (&label("sub")); + + &sbb ("eax",0); # handle upmost overflow bit + +&set_label("copy",16); # copy or in-place refresh + &mov ("edx",&DWP(0,$tp,$num,4)); + &mov ($np,&DWP(0,$rp,$num,4)); + &xor ("edx",$np); # conditional select + &and ("edx","eax"); + &xor ("edx",$np); + &mov (&DWP(0,$tp,$num,4),$j) # zap temporary vector + &mov (&DWP(0,$rp,$num,4),"edx"); # rp[i]=tp[i] + &dec ($num); + &jge (&label("copy")); + + &mov ("esp",$_sp); # pull saved stack pointer + &mov ("eax",1); +&set_label("just_leave"); +&function_end("bn_mul_mont"); + +&asciz("Montgomery Multiplication for x86, CRYPTOGAMS by "); + +&asm_finish(); diff --git a/TMessagesProj/jni/boringssl/crypto/bn/asm/x86_64-gcc.c b/TMessagesProj/jni/boringssl/crypto/bn/asm/x86_64-gcc.c new file mode 100644 index 00000000..0496b959 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/asm/x86_64-gcc.c @@ -0,0 +1,599 @@ +#include + +#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && !defined(OPENSSL_WINDOWS) + +#include "../internal.h" + +/* x86_64 BIGNUM accelerator version 0.1, December 2002. + * + * Implemented by Andy Polyakov for the OpenSSL + * project. + * + * Rights for redistribution and usage in source and binary forms are + * granted according to the OpenSSL license. Warranty of any kind is + * disclaimed. + * + * Q. Version 0.1? It doesn't sound like Andy, he used to assign real + * versions, like 1.0... + * A. Well, that's because this code is basically a quick-n-dirty + * proof-of-concept hack. As you can see it's implemented with + * inline assembler, which means that you're bound to GCC and that + * there might be enough room for further improvement. + * + * Q. Why inline assembler? + * A. x86_64 features own ABI which I'm not familiar with. This is + * why I decided to let the compiler take care of subroutine + * prologue/epilogue as well as register allocation. For reference. + * Win64 implements different ABI for AMD64, different from Linux. + * + * Q. How much faster does it get? + * A. 'apps/openssl speed rsa dsa' output with no-asm: + * + * sign verify sign/s verify/s + * rsa 512 bits 0.0006s 0.0001s 1683.8 18456.2 + * rsa 1024 bits 0.0028s 0.0002s 356.0 6407.0 + * rsa 2048 bits 0.0172s 0.0005s 58.0 1957.8 + * rsa 4096 bits 0.1155s 0.0018s 8.7 555.6 + * sign verify sign/s verify/s + * dsa 512 bits 0.0005s 0.0006s 2100.8 1768.3 + * dsa 1024 bits 0.0014s 0.0018s 692.3 559.2 + * dsa 2048 bits 0.0049s 0.0061s 204.7 165.0 + * + * 'apps/openssl speed rsa dsa' output with this module: + * + * sign verify sign/s verify/s + * rsa 512 bits 0.0004s 0.0000s 2767.1 33297.9 + * rsa 1024 bits 0.0012s 0.0001s 867.4 14674.7 + * rsa 2048 bits 0.0061s 0.0002s 164.0 5270.0 + * rsa 4096 bits 0.0384s 0.0006s 26.1 1650.8 + * sign verify sign/s verify/s + * dsa 512 bits 0.0002s 0.0003s 4442.2 3786.3 + * dsa 1024 bits 0.0005s 0.0007s 1835.1 1497.4 + * dsa 2048 bits 0.0016s 0.0020s 620.4 504.6 + * + * For the reference. IA-32 assembler implementation performs + * very much like 64-bit code compiled with no-asm on the same + * machine. + */ + + /* TODO(davidben): Get this file working on Windows x64. */ + +#undef mul +#undef mul_add + +#define asm __asm__ + +/* + * "m"(a), "+m"(r) is the way to favor DirectPath µ-code; + * "g"(0) let the compiler to decide where does it + * want to keep the value of zero; + */ +#define mul_add(r, a, word, carry) \ + do { \ + register BN_ULONG high, low; \ + asm("mulq %3" : "=a"(low), "=d"(high) : "a"(word), "m"(a) : "cc"); \ + asm("addq %2,%0; adcq %3,%1" \ + : "+r"(carry), "+d"(high) \ + : "a"(low), "g"(0) \ + : "cc"); \ + asm("addq %2,%0; adcq %3,%1" \ + : "+m"(r), "+d"(high) \ + : "r"(carry), "g"(0) \ + : "cc"); \ + carry = high; \ + } while (0) + +#define mul(r, a, word, carry) \ + do { \ + register BN_ULONG high, low; \ + asm("mulq %3" : "=a"(low), "=d"(high) : "a"(word), "g"(a) : "cc"); \ + asm("addq %2,%0; adcq %3,%1" \ + : "+r"(carry), "+d"(high) \ + : "a"(low), "g"(0) \ + : "cc"); \ + (r) = carry, carry = high; \ + } while (0) +#undef sqr +#define sqr(r0, r1, a) asm("mulq %2" : "=a"(r0), "=d"(r1) : "a"(a) : "cc"); + +BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num, + BN_ULONG w) { + BN_ULONG c1 = 0; + + if (num <= 0) { + return (c1); + } + + while (num & ~3) { + mul_add(rp[0], ap[0], w, c1); + mul_add(rp[1], ap[1], w, c1); + mul_add(rp[2], ap[2], w, c1); + mul_add(rp[3], ap[3], w, c1); + ap += 4; + rp += 4; + num -= 4; + } + if (num) { + mul_add(rp[0], ap[0], w, c1); + if (--num == 0) { + return c1; + } + mul_add(rp[1], ap[1], w, c1); + if (--num == 0) { + return c1; + } + mul_add(rp[2], ap[2], w, c1); + return c1; + } + + return c1; +} + +BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w) { + BN_ULONG c1 = 0; + + if (num <= 0) { + return c1; + } + + while (num & ~3) { + mul(rp[0], ap[0], w, c1); + mul(rp[1], ap[1], w, c1); + mul(rp[2], ap[2], w, c1); + mul(rp[3], ap[3], w, c1); + ap += 4; + rp += 4; + num -= 4; + } + if (num) { + mul(rp[0], ap[0], w, c1); + if (--num == 0) { + return c1; + } + mul(rp[1], ap[1], w, c1); + if (--num == 0) { + return c1; + } + mul(rp[2], ap[2], w, c1); + } + return c1; +} + +void bn_sqr_words(BN_ULONG *r, const BN_ULONG *a, int n) { + if (n <= 0) { + return; + } + + while (n & ~3) { + sqr(r[0], r[1], a[0]); + sqr(r[2], r[3], a[1]); + sqr(r[4], r[5], a[2]); + sqr(r[6], r[7], a[3]); + a += 4; + r += 8; + n -= 4; + } + if (n) { + sqr(r[0], r[1], a[0]); + if (--n == 0) { + return; + } + sqr(r[2], r[3], a[1]); + if (--n == 0) { + return; + } + sqr(r[4], r[5], a[2]); + } +} + +BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d) { + BN_ULONG ret, waste; + + asm("divq %4" : "=a"(ret), "=d"(waste) : "a"(l), "d"(h), "g"(d) : "cc"); + + return ret; +} + +BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, + int n) { + BN_ULONG ret; + size_t i = 0; + + if (n <= 0) { + return 0; + } + + asm volatile ( + " subq %0,%0 \n" /* clear carry */ + " jmp 1f \n" + ".p2align 4 \n" + "1: movq (%4,%2,8),%0 \n" + " adcq (%5,%2,8),%0 \n" + " movq %0,(%3,%2,8) \n" + " lea 1(%2),%2 \n" + " loop 1b \n" + " sbbq %0,%0 \n" + : "=&r"(ret), "+c"(n), "+r"(i) + : "r"(rp), "r"(ap), "r"(bp) + : "cc", "memory"); + + return ret & 1; +} + +#ifndef SIMICS +BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, + int n) { + BN_ULONG ret; + size_t i = 0; + + if (n <= 0) { + return 0; + } + + asm volatile ( + " subq %0,%0 \n" /* clear borrow */ + " jmp 1f \n" + ".p2align 4 \n" + "1: movq (%4,%2,8),%0 \n" + " sbbq (%5,%2,8),%0 \n" + " movq %0,(%3,%2,8) \n" + " lea 1(%2),%2 \n" + " loop 1b \n" + " sbbq %0,%0 \n" + : "=&r"(ret), "+c"(n), "+r"(i) + : "r"(rp), "r"(ap), "r"(bp) + : "cc", "memory"); + + return ret & 1; +} +#else +/* Simics 1.4<7 has buggy sbbq:-( */ +#define BN_MASK2 0xffffffffffffffffL +BN_ULONG bn_sub_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n) { + BN_ULONG t1, t2; + int c = 0; + + if (n <= 0) { + return (BN_ULONG)0; + } + + for (;;) { + t1 = a[0]; + t2 = b[0]; + r[0] = (t1 - t2 - c) & BN_MASK2; + if (t1 != t2) { + c = (t1 < t2); + } + if (--n <= 0) { + break; + } + + t1 = a[1]; + t2 = b[1]; + r[1] = (t1 - t2 - c) & BN_MASK2; + if (t1 != t2) { + c = (t1 < t2); + } + if (--n <= 0) { + break; + } + + t1 = a[2]; + t2 = b[2]; + r[2] = (t1 - t2 - c) & BN_MASK2; + if (t1 != t2) { + c = (t1 < t2); + } + if (--n <= 0) { + break; + } + + t1 = a[3]; + t2 = b[3]; + r[3] = (t1 - t2 - c) & BN_MASK2; + if (t1 != t2) { + c = (t1 < t2); + } + if (--n <= 0) { + break; + } + + a += 4; + b += 4; + r += 4; + } + return c; +} +#endif + +/* mul_add_c(a,b,c0,c1,c2) -- c+=a*b for three word number c=(c2,c1,c0) */ +/* mul_add_c2(a,b,c0,c1,c2) -- c+=2*a*b for three word number c=(c2,c1,c0) */ +/* sqr_add_c(a,i,c0,c1,c2) -- c+=a[i]^2 for three word number c=(c2,c1,c0) */ +/* sqr_add_c2(a,i,c0,c1,c2) -- c+=2*a[i]*a[j] for three word number c=(c2,c1,c0) + */ + +/* Keep in mind that carrying into high part of multiplication result can not + * overflow, because it cannot be all-ones. */ +#define mul_add_c(a, b, c0, c1, c2) \ + do { \ + BN_ULONG t1, t2; \ + asm("mulq %3" : "=a"(t1), "=d"(t2) : "a"(a), "m"(b) : "cc"); \ + asm("addq %3,%0; adcq %4,%1; adcq %5,%2" \ + : "+r"(c0), "+r"(c1), "+r"(c2) \ + : "r"(t1), "r"(t2), "g"(0) \ + : "cc"); \ + } while (0) + +#define sqr_add_c(a, i, c0, c1, c2) \ + do { \ + BN_ULONG t1, t2; \ + asm("mulq %2" : "=a"(t1), "=d"(t2) : "a"(a[i]) : "cc"); \ + asm("addq %3,%0; adcq %4,%1; adcq %5,%2" \ + : "+r"(c0), "+r"(c1), "+r"(c2) \ + : "r"(t1), "r"(t2), "g"(0) \ + : "cc"); \ + } while (0) + +#define mul_add_c2(a, b, c0, c1, c2) \ + do { \ + BN_ULONG t1, t2; \ + asm("mulq %3" : "=a"(t1), "=d"(t2) : "a"(a), "m"(b) : "cc"); \ + asm("addq %3,%0; adcq %4,%1; adcq %5,%2" \ + : "+r"(c0), "+r"(c1), "+r"(c2) \ + : "r"(t1), "r"(t2), "g"(0) \ + : "cc"); \ + asm("addq %3,%0; adcq %4,%1; adcq %5,%2" \ + : "+r"(c0), "+r"(c1), "+r"(c2) \ + : "r"(t1), "r"(t2), "g"(0) \ + : "cc"); \ + } while (0) + +#define sqr_add_c2(a, i, j, c0, c1, c2) mul_add_c2((a)[i], (a)[j], c0, c1, c2) + +void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) { + BN_ULONG c1, c2, c3; + + c1 = 0; + c2 = 0; + c3 = 0; + mul_add_c(a[0], b[0], c1, c2, c3); + r[0] = c1; + c1 = 0; + mul_add_c(a[0], b[1], c2, c3, c1); + mul_add_c(a[1], b[0], c2, c3, c1); + r[1] = c2; + c2 = 0; + mul_add_c(a[2], b[0], c3, c1, c2); + mul_add_c(a[1], b[1], c3, c1, c2); + mul_add_c(a[0], b[2], c3, c1, c2); + r[2] = c3; + c3 = 0; + mul_add_c(a[0], b[3], c1, c2, c3); + mul_add_c(a[1], b[2], c1, c2, c3); + mul_add_c(a[2], b[1], c1, c2, c3); + mul_add_c(a[3], b[0], c1, c2, c3); + r[3] = c1; + c1 = 0; + mul_add_c(a[4], b[0], c2, c3, c1); + mul_add_c(a[3], b[1], c2, c3, c1); + mul_add_c(a[2], b[2], c2, c3, c1); + mul_add_c(a[1], b[3], c2, c3, c1); + mul_add_c(a[0], b[4], c2, c3, c1); + r[4] = c2; + c2 = 0; + mul_add_c(a[0], b[5], c3, c1, c2); + mul_add_c(a[1], b[4], c3, c1, c2); + mul_add_c(a[2], b[3], c3, c1, c2); + mul_add_c(a[3], b[2], c3, c1, c2); + mul_add_c(a[4], b[1], c3, c1, c2); + mul_add_c(a[5], b[0], c3, c1, c2); + r[5] = c3; + c3 = 0; + mul_add_c(a[6], b[0], c1, c2, c3); + mul_add_c(a[5], b[1], c1, c2, c3); + mul_add_c(a[4], b[2], c1, c2, c3); + mul_add_c(a[3], b[3], c1, c2, c3); + mul_add_c(a[2], b[4], c1, c2, c3); + mul_add_c(a[1], b[5], c1, c2, c3); + mul_add_c(a[0], b[6], c1, c2, c3); + r[6] = c1; + c1 = 0; + mul_add_c(a[0], b[7], c2, c3, c1); + mul_add_c(a[1], b[6], c2, c3, c1); + mul_add_c(a[2], b[5], c2, c3, c1); + mul_add_c(a[3], b[4], c2, c3, c1); + mul_add_c(a[4], b[3], c2, c3, c1); + mul_add_c(a[5], b[2], c2, c3, c1); + mul_add_c(a[6], b[1], c2, c3, c1); + mul_add_c(a[7], b[0], c2, c3, c1); + r[7] = c2; + c2 = 0; + mul_add_c(a[7], b[1], c3, c1, c2); + mul_add_c(a[6], b[2], c3, c1, c2); + mul_add_c(a[5], b[3], c3, c1, c2); + mul_add_c(a[4], b[4], c3, c1, c2); + mul_add_c(a[3], b[5], c3, c1, c2); + mul_add_c(a[2], b[6], c3, c1, c2); + mul_add_c(a[1], b[7], c3, c1, c2); + r[8] = c3; + c3 = 0; + mul_add_c(a[2], b[7], c1, c2, c3); + mul_add_c(a[3], b[6], c1, c2, c3); + mul_add_c(a[4], b[5], c1, c2, c3); + mul_add_c(a[5], b[4], c1, c2, c3); + mul_add_c(a[6], b[3], c1, c2, c3); + mul_add_c(a[7], b[2], c1, c2, c3); + r[9] = c1; + c1 = 0; + mul_add_c(a[7], b[3], c2, c3, c1); + mul_add_c(a[6], b[4], c2, c3, c1); + mul_add_c(a[5], b[5], c2, c3, c1); + mul_add_c(a[4], b[6], c2, c3, c1); + mul_add_c(a[3], b[7], c2, c3, c1); + r[10] = c2; + c2 = 0; + mul_add_c(a[4], b[7], c3, c1, c2); + mul_add_c(a[5], b[6], c3, c1, c2); + mul_add_c(a[6], b[5], c3, c1, c2); + mul_add_c(a[7], b[4], c3, c1, c2); + r[11] = c3; + c3 = 0; + mul_add_c(a[7], b[5], c1, c2, c3); + mul_add_c(a[6], b[6], c1, c2, c3); + mul_add_c(a[5], b[7], c1, c2, c3); + r[12] = c1; + c1 = 0; + mul_add_c(a[6], b[7], c2, c3, c1); + mul_add_c(a[7], b[6], c2, c3, c1); + r[13] = c2; + c2 = 0; + mul_add_c(a[7], b[7], c3, c1, c2); + r[14] = c3; + r[15] = c1; +} + +void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) { + BN_ULONG c1, c2, c3; + + c1 = 0; + c2 = 0; + c3 = 0; + mul_add_c(a[0], b[0], c1, c2, c3); + r[0] = c1; + c1 = 0; + mul_add_c(a[0], b[1], c2, c3, c1); + mul_add_c(a[1], b[0], c2, c3, c1); + r[1] = c2; + c2 = 0; + mul_add_c(a[2], b[0], c3, c1, c2); + mul_add_c(a[1], b[1], c3, c1, c2); + mul_add_c(a[0], b[2], c3, c1, c2); + r[2] = c3; + c3 = 0; + mul_add_c(a[0], b[3], c1, c2, c3); + mul_add_c(a[1], b[2], c1, c2, c3); + mul_add_c(a[2], b[1], c1, c2, c3); + mul_add_c(a[3], b[0], c1, c2, c3); + r[3] = c1; + c1 = 0; + mul_add_c(a[3], b[1], c2, c3, c1); + mul_add_c(a[2], b[2], c2, c3, c1); + mul_add_c(a[1], b[3], c2, c3, c1); + r[4] = c2; + c2 = 0; + mul_add_c(a[2], b[3], c3, c1, c2); + mul_add_c(a[3], b[2], c3, c1, c2); + r[5] = c3; + c3 = 0; + mul_add_c(a[3], b[3], c1, c2, c3); + r[6] = c1; + r[7] = c2; +} + +void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a) { + BN_ULONG c1, c2, c3; + + c1 = 0; + c2 = 0; + c3 = 0; + sqr_add_c(a, 0, c1, c2, c3); + r[0] = c1; + c1 = 0; + sqr_add_c2(a, 1, 0, c2, c3, c1); + r[1] = c2; + c2 = 0; + sqr_add_c(a, 1, c3, c1, c2); + sqr_add_c2(a, 2, 0, c3, c1, c2); + r[2] = c3; + c3 = 0; + sqr_add_c2(a, 3, 0, c1, c2, c3); + sqr_add_c2(a, 2, 1, c1, c2, c3); + r[3] = c1; + c1 = 0; + sqr_add_c(a, 2, c2, c3, c1); + sqr_add_c2(a, 3, 1, c2, c3, c1); + sqr_add_c2(a, 4, 0, c2, c3, c1); + r[4] = c2; + c2 = 0; + sqr_add_c2(a, 5, 0, c3, c1, c2); + sqr_add_c2(a, 4, 1, c3, c1, c2); + sqr_add_c2(a, 3, 2, c3, c1, c2); + r[5] = c3; + c3 = 0; + sqr_add_c(a, 3, c1, c2, c3); + sqr_add_c2(a, 4, 2, c1, c2, c3); + sqr_add_c2(a, 5, 1, c1, c2, c3); + sqr_add_c2(a, 6, 0, c1, c2, c3); + r[6] = c1; + c1 = 0; + sqr_add_c2(a, 7, 0, c2, c3, c1); + sqr_add_c2(a, 6, 1, c2, c3, c1); + sqr_add_c2(a, 5, 2, c2, c3, c1); + sqr_add_c2(a, 4, 3, c2, c3, c1); + r[7] = c2; + c2 = 0; + sqr_add_c(a, 4, c3, c1, c2); + sqr_add_c2(a, 5, 3, c3, c1, c2); + sqr_add_c2(a, 6, 2, c3, c1, c2); + sqr_add_c2(a, 7, 1, c3, c1, c2); + r[8] = c3; + c3 = 0; + sqr_add_c2(a, 7, 2, c1, c2, c3); + sqr_add_c2(a, 6, 3, c1, c2, c3); + sqr_add_c2(a, 5, 4, c1, c2, c3); + r[9] = c1; + c1 = 0; + sqr_add_c(a, 5, c2, c3, c1); + sqr_add_c2(a, 6, 4, c2, c3, c1); + sqr_add_c2(a, 7, 3, c2, c3, c1); + r[10] = c2; + c2 = 0; + sqr_add_c2(a, 7, 4, c3, c1, c2); + sqr_add_c2(a, 6, 5, c3, c1, c2); + r[11] = c3; + c3 = 0; + sqr_add_c(a, 6, c1, c2, c3); + sqr_add_c2(a, 7, 5, c1, c2, c3); + r[12] = c1; + c1 = 0; + sqr_add_c2(a, 7, 6, c2, c3, c1); + r[13] = c2; + c2 = 0; + sqr_add_c(a, 7, c3, c1, c2); + r[14] = c3; + r[15] = c1; +} + +void bn_sqr_comba4(BN_ULONG *r, const BN_ULONG *a) { + BN_ULONG c1, c2, c3; + + c1 = 0; + c2 = 0; + c3 = 0; + sqr_add_c(a, 0, c1, c2, c3); + r[0] = c1; + c1 = 0; + sqr_add_c2(a, 1, 0, c2, c3, c1); + r[1] = c2; + c2 = 0; + sqr_add_c(a, 1, c3, c1, c2); + sqr_add_c2(a, 2, 0, c3, c1, c2); + r[2] = c3; + c3 = 0; + sqr_add_c2(a, 3, 0, c1, c2, c3); + sqr_add_c2(a, 2, 1, c1, c2, c3); + r[3] = c1; + c1 = 0; + sqr_add_c(a, 2, c2, c3, c1); + sqr_add_c2(a, 3, 1, c2, c3, c1); + r[4] = c2; + c2 = 0; + sqr_add_c2(a, 3, 2, c3, c1, c2); + r[5] = c3; + c3 = 0; + sqr_add_c(a, 3, c1, c2, c3); + r[6] = c1; + r[7] = c2; +} + +#endif /* !NO_ASM && X86_64 && !WINDOWS */ diff --git a/TMessagesProj/jni/boringssl/crypto/bn/asm/x86_64-mont.pl b/TMessagesProj/jni/boringssl/crypto/bn/asm/x86_64-mont.pl new file mode 100644 index 00000000..39476ab0 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/asm/x86_64-mont.pl @@ -0,0 +1,1401 @@ +#!/usr/bin/env perl + +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== + +# October 2005. +# +# Montgomery multiplication routine for x86_64. While it gives modest +# 9% improvement of rsa4096 sign on Opteron, rsa512 sign runs more +# than twice, >2x, as fast. Most common rsa1024 sign is improved by +# respectful 50%. It remains to be seen if loop unrolling and +# dedicated squaring routine can provide further improvement... + +# July 2011. +# +# Add dedicated squaring procedure. Performance improvement varies +# from platform to platform, but in average it's ~5%/15%/25%/33% +# for 512-/1024-/2048-/4096-bit RSA *sign* benchmarks respectively. + +# August 2011. +# +# Unroll and modulo-schedule inner loops in such manner that they +# are "fallen through" for input lengths of 8, which is critical for +# 1024-bit RSA *sign*. Average performance improvement in comparison +# to *initial* version of this module from 2005 is ~0%/30%/40%/45% +# for 512-/1024-/2048-/4096-bit RSA *sign* benchmarks respectively. + +# June 2013. +# +# Optimize reduction in squaring procedure and improve 1024+-bit RSA +# sign performance by 10-16% on Intel Sandy Bridge and later +# (virtually same on non-Intel processors). + +# August 2013. +# +# Add MULX/ADOX/ADCX code path. + +$flavour = shift; +$output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or +die "can't locate x86_64-xlate.pl"; + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1` + =~ /GNU assembler version ([2-9]\.[0-9]+)/) { + $addx = ($1>=2.23); +} + +if (!$addx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) && + `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) { + $addx = ($1>=2.10); +} + +if (!$addx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) && + `ml64 2>&1` =~ /Version ([0-9]+)\./) { + $addx = ($1>=12); +} + +# int bn_mul_mont( +$rp="%rdi"; # BN_ULONG *rp, +$ap="%rsi"; # const BN_ULONG *ap, +$bp="%rdx"; # const BN_ULONG *bp, +$np="%rcx"; # const BN_ULONG *np, +$n0="%r8"; # const BN_ULONG *n0, +$num="%r9"; # int num); +$lo0="%r10"; +$hi0="%r11"; +$hi1="%r13"; +$i="%r14"; +$j="%r15"; +$m0="%rbx"; +$m1="%rbp"; + +$code=<<___; +.text + +.extern OPENSSL_ia32cap_P + +.globl bn_mul_mont +.type bn_mul_mont,\@function,6 +.align 16 +bn_mul_mont: + test \$3,${num}d + jnz .Lmul_enter + cmp \$8,${num}d + jb .Lmul_enter +___ +$code.=<<___ if ($addx); + mov OPENSSL_ia32cap_P+8(%rip),%r11d +___ +$code.=<<___; + cmp $ap,$bp + jne .Lmul4x_enter + test \$7,${num}d + jz .Lsqr8x_enter + jmp .Lmul4x_enter + +.align 16 +.Lmul_enter: + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + + mov ${num}d,${num}d + lea 2($num),%r10 + mov %rsp,%r11 + neg %r10 + lea (%rsp,%r10,8),%rsp # tp=alloca(8*(num+2)) + and \$-1024,%rsp # minimize TLB usage + + mov %r11,8(%rsp,$num,8) # tp[num+1]=%rsp +.Lmul_body: + mov $bp,%r12 # reassign $bp +___ + $bp="%r12"; +$code.=<<___; + mov ($n0),$n0 # pull n0[0] value + mov ($bp),$m0 # m0=bp[0] + mov ($ap),%rax + + xor $i,$i # i=0 + xor $j,$j # j=0 + + mov $n0,$m1 + mulq $m0 # ap[0]*bp[0] + mov %rax,$lo0 + mov ($np),%rax + + imulq $lo0,$m1 # "tp[0]"*n0 + mov %rdx,$hi0 + + mulq $m1 # np[0]*m1 + add %rax,$lo0 # discarded + mov 8($ap),%rax + adc \$0,%rdx + mov %rdx,$hi1 + + lea 1($j),$j # j++ + jmp .L1st_enter + +.align 16 +.L1st: + add %rax,$hi1 + mov ($ap,$j,8),%rax + adc \$0,%rdx + add $hi0,$hi1 # np[j]*m1+ap[j]*bp[0] + mov $lo0,$hi0 + adc \$0,%rdx + mov $hi1,-16(%rsp,$j,8) # tp[j-1] + mov %rdx,$hi1 + +.L1st_enter: + mulq $m0 # ap[j]*bp[0] + add %rax,$hi0 + mov ($np,$j,8),%rax + adc \$0,%rdx + lea 1($j),$j # j++ + mov %rdx,$lo0 + + mulq $m1 # np[j]*m1 + cmp $num,$j + jne .L1st + + add %rax,$hi1 + mov ($ap),%rax # ap[0] + adc \$0,%rdx + add $hi0,$hi1 # np[j]*m1+ap[j]*bp[0] + adc \$0,%rdx + mov $hi1,-16(%rsp,$j,8) # tp[j-1] + mov %rdx,$hi1 + mov $lo0,$hi0 + + xor %rdx,%rdx + add $hi0,$hi1 + adc \$0,%rdx + mov $hi1,-8(%rsp,$num,8) + mov %rdx,(%rsp,$num,8) # store upmost overflow bit + + lea 1($i),$i # i++ + jmp .Louter +.align 16 +.Louter: + mov ($bp,$i,8),$m0 # m0=bp[i] + xor $j,$j # j=0 + mov $n0,$m1 + mov (%rsp),$lo0 + mulq $m0 # ap[0]*bp[i] + add %rax,$lo0 # ap[0]*bp[i]+tp[0] + mov ($np),%rax + adc \$0,%rdx + + imulq $lo0,$m1 # tp[0]*n0 + mov %rdx,$hi0 + + mulq $m1 # np[0]*m1 + add %rax,$lo0 # discarded + mov 8($ap),%rax + adc \$0,%rdx + mov 8(%rsp),$lo0 # tp[1] + mov %rdx,$hi1 + + lea 1($j),$j # j++ + jmp .Linner_enter + +.align 16 +.Linner: + add %rax,$hi1 + mov ($ap,$j,8),%rax + adc \$0,%rdx + add $lo0,$hi1 # np[j]*m1+ap[j]*bp[i]+tp[j] + mov (%rsp,$j,8),$lo0 + adc \$0,%rdx + mov $hi1,-16(%rsp,$j,8) # tp[j-1] + mov %rdx,$hi1 + +.Linner_enter: + mulq $m0 # ap[j]*bp[i] + add %rax,$hi0 + mov ($np,$j,8),%rax + adc \$0,%rdx + add $hi0,$lo0 # ap[j]*bp[i]+tp[j] + mov %rdx,$hi0 + adc \$0,$hi0 + lea 1($j),$j # j++ + + mulq $m1 # np[j]*m1 + cmp $num,$j + jne .Linner + + add %rax,$hi1 + mov ($ap),%rax # ap[0] + adc \$0,%rdx + add $lo0,$hi1 # np[j]*m1+ap[j]*bp[i]+tp[j] + mov (%rsp,$j,8),$lo0 + adc \$0,%rdx + mov $hi1,-16(%rsp,$j,8) # tp[j-1] + mov %rdx,$hi1 + + xor %rdx,%rdx + add $hi0,$hi1 + adc \$0,%rdx + add $lo0,$hi1 # pull upmost overflow bit + adc \$0,%rdx + mov $hi1,-8(%rsp,$num,8) + mov %rdx,(%rsp,$num,8) # store upmost overflow bit + + lea 1($i),$i # i++ + cmp $num,$i + jb .Louter + + xor $i,$i # i=0 and clear CF! + mov (%rsp),%rax # tp[0] + lea (%rsp),$ap # borrow ap for tp + mov $num,$j # j=num + jmp .Lsub +.align 16 +.Lsub: sbb ($np,$i,8),%rax + mov %rax,($rp,$i,8) # rp[i]=tp[i]-np[i] + mov 8($ap,$i,8),%rax # tp[i+1] + lea 1($i),$i # i++ + dec $j # doesn't affect CF! + jnz .Lsub + + sbb \$0,%rax # handle upmost overflow bit + xor $i,$i + mov $num,$j # j=num +.align 16 +.Lcopy: # copy or in-place refresh + mov (%rsp,$i,8),$ap + mov ($rp,$i,8),$np + xor $np,$ap # conditional select: + and %rax,$ap # ((ap ^ np) & %rax) ^ np + xor $np,$ap # ap = borrow?tp:rp + mov $i,(%rsp,$i,8) # zap temporary vector + mov $ap,($rp,$i,8) # rp[i]=tp[i] + lea 1($i),$i + sub \$1,$j + jnz .Lcopy + + mov 8(%rsp,$num,8),%rsi # restore %rsp + mov \$1,%rax + mov (%rsi),%r15 + mov 8(%rsi),%r14 + mov 16(%rsi),%r13 + mov 24(%rsi),%r12 + mov 32(%rsi),%rbp + mov 40(%rsi),%rbx + lea 48(%rsi),%rsp +.Lmul_epilogue: + ret +.size bn_mul_mont,.-bn_mul_mont +___ +{{{ +my @A=("%r10","%r11"); +my @N=("%r13","%rdi"); +$code.=<<___; +.type bn_mul4x_mont,\@function,6 +.align 16 +bn_mul4x_mont: +.Lmul4x_enter: +___ +$code.=<<___ if ($addx); + and \$0x80100,%r11d + cmp \$0x80100,%r11d + je .Lmulx4x_enter +___ +$code.=<<___; + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + + mov ${num}d,${num}d + lea 4($num),%r10 + mov %rsp,%r11 + neg %r10 + lea (%rsp,%r10,8),%rsp # tp=alloca(8*(num+4)) + and \$-1024,%rsp # minimize TLB usage + + mov %r11,8(%rsp,$num,8) # tp[num+1]=%rsp +.Lmul4x_body: + mov $rp,16(%rsp,$num,8) # tp[num+2]=$rp + mov %rdx,%r12 # reassign $bp +___ + $bp="%r12"; +$code.=<<___; + mov ($n0),$n0 # pull n0[0] value + mov ($bp),$m0 # m0=bp[0] + mov ($ap),%rax + + xor $i,$i # i=0 + xor $j,$j # j=0 + + mov $n0,$m1 + mulq $m0 # ap[0]*bp[0] + mov %rax,$A[0] + mov ($np),%rax + + imulq $A[0],$m1 # "tp[0]"*n0 + mov %rdx,$A[1] + + mulq $m1 # np[0]*m1 + add %rax,$A[0] # discarded + mov 8($ap),%rax + adc \$0,%rdx + mov %rdx,$N[1] + + mulq $m0 + add %rax,$A[1] + mov 8($np),%rax + adc \$0,%rdx + mov %rdx,$A[0] + + mulq $m1 + add %rax,$N[1] + mov 16($ap),%rax + adc \$0,%rdx + add $A[1],$N[1] + lea 4($j),$j # j++ + adc \$0,%rdx + mov $N[1],(%rsp) + mov %rdx,$N[0] + jmp .L1st4x +.align 16 +.L1st4x: + mulq $m0 # ap[j]*bp[0] + add %rax,$A[0] + mov -16($np,$j,8),%rax + adc \$0,%rdx + mov %rdx,$A[1] + + mulq $m1 # np[j]*m1 + add %rax,$N[0] + mov -8($ap,$j,8),%rax + adc \$0,%rdx + add $A[0],$N[0] # np[j]*m1+ap[j]*bp[0] + adc \$0,%rdx + mov $N[0],-24(%rsp,$j,8) # tp[j-1] + mov %rdx,$N[1] + + mulq $m0 # ap[j]*bp[0] + add %rax,$A[1] + mov -8($np,$j,8),%rax + adc \$0,%rdx + mov %rdx,$A[0] + + mulq $m1 # np[j]*m1 + add %rax,$N[1] + mov ($ap,$j,8),%rax + adc \$0,%rdx + add $A[1],$N[1] # np[j]*m1+ap[j]*bp[0] + adc \$0,%rdx + mov $N[1],-16(%rsp,$j,8) # tp[j-1] + mov %rdx,$N[0] + + mulq $m0 # ap[j]*bp[0] + add %rax,$A[0] + mov ($np,$j,8),%rax + adc \$0,%rdx + mov %rdx,$A[1] + + mulq $m1 # np[j]*m1 + add %rax,$N[0] + mov 8($ap,$j,8),%rax + adc \$0,%rdx + add $A[0],$N[0] # np[j]*m1+ap[j]*bp[0] + adc \$0,%rdx + mov $N[0],-8(%rsp,$j,8) # tp[j-1] + mov %rdx,$N[1] + + mulq $m0 # ap[j]*bp[0] + add %rax,$A[1] + mov 8($np,$j,8),%rax + adc \$0,%rdx + lea 4($j),$j # j++ + mov %rdx,$A[0] + + mulq $m1 # np[j]*m1 + add %rax,$N[1] + mov -16($ap,$j,8),%rax + adc \$0,%rdx + add $A[1],$N[1] # np[j]*m1+ap[j]*bp[0] + adc \$0,%rdx + mov $N[1],-32(%rsp,$j,8) # tp[j-1] + mov %rdx,$N[0] + cmp $num,$j + jb .L1st4x + + mulq $m0 # ap[j]*bp[0] + add %rax,$A[0] + mov -16($np,$j,8),%rax + adc \$0,%rdx + mov %rdx,$A[1] + + mulq $m1 # np[j]*m1 + add %rax,$N[0] + mov -8($ap,$j,8),%rax + adc \$0,%rdx + add $A[0],$N[0] # np[j]*m1+ap[j]*bp[0] + adc \$0,%rdx + mov $N[0],-24(%rsp,$j,8) # tp[j-1] + mov %rdx,$N[1] + + mulq $m0 # ap[j]*bp[0] + add %rax,$A[1] + mov -8($np,$j,8),%rax + adc \$0,%rdx + mov %rdx,$A[0] + + mulq $m1 # np[j]*m1 + add %rax,$N[1] + mov ($ap),%rax # ap[0] + adc \$0,%rdx + add $A[1],$N[1] # np[j]*m1+ap[j]*bp[0] + adc \$0,%rdx + mov $N[1],-16(%rsp,$j,8) # tp[j-1] + mov %rdx,$N[0] + + xor $N[1],$N[1] + add $A[0],$N[0] + adc \$0,$N[1] + mov $N[0],-8(%rsp,$j,8) + mov $N[1],(%rsp,$j,8) # store upmost overflow bit + + lea 1($i),$i # i++ +.align 4 +.Louter4x: + mov ($bp,$i,8),$m0 # m0=bp[i] + xor $j,$j # j=0 + mov (%rsp),$A[0] + mov $n0,$m1 + mulq $m0 # ap[0]*bp[i] + add %rax,$A[0] # ap[0]*bp[i]+tp[0] + mov ($np),%rax + adc \$0,%rdx + + imulq $A[0],$m1 # tp[0]*n0 + mov %rdx,$A[1] + + mulq $m1 # np[0]*m1 + add %rax,$A[0] # "$N[0]", discarded + mov 8($ap),%rax + adc \$0,%rdx + mov %rdx,$N[1] + + mulq $m0 # ap[j]*bp[i] + add %rax,$A[1] + mov 8($np),%rax + adc \$0,%rdx + add 8(%rsp),$A[1] # +tp[1] + adc \$0,%rdx + mov %rdx,$A[0] + + mulq $m1 # np[j]*m1 + add %rax,$N[1] + mov 16($ap),%rax + adc \$0,%rdx + add $A[1],$N[1] # np[j]*m1+ap[j]*bp[i]+tp[j] + lea 4($j),$j # j+=2 + adc \$0,%rdx + mov $N[1],(%rsp) # tp[j-1] + mov %rdx,$N[0] + jmp .Linner4x +.align 16 +.Linner4x: + mulq $m0 # ap[j]*bp[i] + add %rax,$A[0] + mov -16($np,$j,8),%rax + adc \$0,%rdx + add -16(%rsp,$j,8),$A[0] # ap[j]*bp[i]+tp[j] + adc \$0,%rdx + mov %rdx,$A[1] + + mulq $m1 # np[j]*m1 + add %rax,$N[0] + mov -8($ap,$j,8),%rax + adc \$0,%rdx + add $A[0],$N[0] + adc \$0,%rdx + mov $N[0],-24(%rsp,$j,8) # tp[j-1] + mov %rdx,$N[1] + + mulq $m0 # ap[j]*bp[i] + add %rax,$A[1] + mov -8($np,$j,8),%rax + adc \$0,%rdx + add -8(%rsp,$j,8),$A[1] + adc \$0,%rdx + mov %rdx,$A[0] + + mulq $m1 # np[j]*m1 + add %rax,$N[1] + mov ($ap,$j,8),%rax + adc \$0,%rdx + add $A[1],$N[1] + adc \$0,%rdx + mov $N[1],-16(%rsp,$j,8) # tp[j-1] + mov %rdx,$N[0] + + mulq $m0 # ap[j]*bp[i] + add %rax,$A[0] + mov ($np,$j,8),%rax + adc \$0,%rdx + add (%rsp,$j,8),$A[0] # ap[j]*bp[i]+tp[j] + adc \$0,%rdx + mov %rdx,$A[1] + + mulq $m1 # np[j]*m1 + add %rax,$N[0] + mov 8($ap,$j,8),%rax + adc \$0,%rdx + add $A[0],$N[0] + adc \$0,%rdx + mov $N[0],-8(%rsp,$j,8) # tp[j-1] + mov %rdx,$N[1] + + mulq $m0 # ap[j]*bp[i] + add %rax,$A[1] + mov 8($np,$j,8),%rax + adc \$0,%rdx + add 8(%rsp,$j,8),$A[1] + adc \$0,%rdx + lea 4($j),$j # j++ + mov %rdx,$A[0] + + mulq $m1 # np[j]*m1 + add %rax,$N[1] + mov -16($ap,$j,8),%rax + adc \$0,%rdx + add $A[1],$N[1] + adc \$0,%rdx + mov $N[1],-32(%rsp,$j,8) # tp[j-1] + mov %rdx,$N[0] + cmp $num,$j + jb .Linner4x + + mulq $m0 # ap[j]*bp[i] + add %rax,$A[0] + mov -16($np,$j,8),%rax + adc \$0,%rdx + add -16(%rsp,$j,8),$A[0] # ap[j]*bp[i]+tp[j] + adc \$0,%rdx + mov %rdx,$A[1] + + mulq $m1 # np[j]*m1 + add %rax,$N[0] + mov -8($ap,$j,8),%rax + adc \$0,%rdx + add $A[0],$N[0] + adc \$0,%rdx + mov $N[0],-24(%rsp,$j,8) # tp[j-1] + mov %rdx,$N[1] + + mulq $m0 # ap[j]*bp[i] + add %rax,$A[1] + mov -8($np,$j,8),%rax + adc \$0,%rdx + add -8(%rsp,$j,8),$A[1] + adc \$0,%rdx + lea 1($i),$i # i++ + mov %rdx,$A[0] + + mulq $m1 # np[j]*m1 + add %rax,$N[1] + mov ($ap),%rax # ap[0] + adc \$0,%rdx + add $A[1],$N[1] + adc \$0,%rdx + mov $N[1],-16(%rsp,$j,8) # tp[j-1] + mov %rdx,$N[0] + + xor $N[1],$N[1] + add $A[0],$N[0] + adc \$0,$N[1] + add (%rsp,$num,8),$N[0] # pull upmost overflow bit + adc \$0,$N[1] + mov $N[0],-8(%rsp,$j,8) + mov $N[1],(%rsp,$j,8) # store upmost overflow bit + + cmp $num,$i + jb .Louter4x +___ +{ +my @ri=("%rax","%rdx",$m0,$m1); +$code.=<<___; + mov 16(%rsp,$num,8),$rp # restore $rp + mov 0(%rsp),@ri[0] # tp[0] + mov 8(%rsp),@ri[1] # tp[1] + shr \$2,$num # num/=4 + lea (%rsp),$ap # borrow ap for tp + xor $i,$i # i=0 and clear CF! + + sub 0($np),@ri[0] + mov 16($ap),@ri[2] # tp[2] + mov 24($ap),@ri[3] # tp[3] + sbb 8($np),@ri[1] + lea -1($num),$j # j=num/4-1 + jmp .Lsub4x +.align 16 +.Lsub4x: + mov @ri[0],0($rp,$i,8) # rp[i]=tp[i]-np[i] + mov @ri[1],8($rp,$i,8) # rp[i]=tp[i]-np[i] + sbb 16($np,$i,8),@ri[2] + mov 32($ap,$i,8),@ri[0] # tp[i+1] + mov 40($ap,$i,8),@ri[1] + sbb 24($np,$i,8),@ri[3] + mov @ri[2],16($rp,$i,8) # rp[i]=tp[i]-np[i] + mov @ri[3],24($rp,$i,8) # rp[i]=tp[i]-np[i] + sbb 32($np,$i,8),@ri[0] + mov 48($ap,$i,8),@ri[2] + mov 56($ap,$i,8),@ri[3] + sbb 40($np,$i,8),@ri[1] + lea 4($i),$i # i++ + dec $j # doesnn't affect CF! + jnz .Lsub4x + + mov @ri[0],0($rp,$i,8) # rp[i]=tp[i]-np[i] + mov 32($ap,$i,8),@ri[0] # load overflow bit + sbb 16($np,$i,8),@ri[2] + mov @ri[1],8($rp,$i,8) # rp[i]=tp[i]-np[i] + sbb 24($np,$i,8),@ri[3] + mov @ri[2],16($rp,$i,8) # rp[i]=tp[i]-np[i] + + sbb \$0,@ri[0] # handle upmost overflow bit + mov @ri[0],%xmm0 + punpcklqdq %xmm0,%xmm0 # extend mask to 128 bits + mov @ri[3],24($rp,$i,8) # rp[i]=tp[i]-np[i] + xor $i,$i # i=0 + + mov $num,$j + pxor %xmm5,%xmm5 + jmp .Lcopy4x +.align 16 +.Lcopy4x: # copy or in-place refresh + movdqu (%rsp,$i),%xmm2 + movdqu 16(%rsp,$i),%xmm4 + movdqu ($rp,$i),%xmm1 + movdqu 16($rp,$i),%xmm3 + pxor %xmm1,%xmm2 # conditional select + pxor %xmm3,%xmm4 + pand %xmm0,%xmm2 + pand %xmm0,%xmm4 + pxor %xmm1,%xmm2 + pxor %xmm3,%xmm4 + movdqu %xmm2,($rp,$i) + movdqu %xmm4,16($rp,$i) + movdqa %xmm5,(%rsp,$i) # zap temporary vectors + movdqa %xmm5,16(%rsp,$i) + + lea 32($i),$i + dec $j + jnz .Lcopy4x + + shl \$2,$num +___ +} +$code.=<<___; + mov 8(%rsp,$num,8),%rsi # restore %rsp + mov \$1,%rax + mov (%rsi),%r15 + mov 8(%rsi),%r14 + mov 16(%rsi),%r13 + mov 24(%rsi),%r12 + mov 32(%rsi),%rbp + mov 40(%rsi),%rbx + lea 48(%rsi),%rsp +.Lmul4x_epilogue: + ret +.size bn_mul4x_mont,.-bn_mul4x_mont +___ +}}} + {{{ +###################################################################### +# void bn_sqr8x_mont( +my $rptr="%rdi"; # const BN_ULONG *rptr, +my $aptr="%rsi"; # const BN_ULONG *aptr, +my $bptr="%rdx"; # not used +my $nptr="%rcx"; # const BN_ULONG *nptr, +my $n0 ="%r8"; # const BN_ULONG *n0); +my $num ="%r9"; # int num, has to be divisible by 8 + +my ($i,$j,$tptr)=("%rbp","%rcx",$rptr); +my @A0=("%r10","%r11"); +my @A1=("%r12","%r13"); +my ($a0,$a1,$ai)=("%r14","%r15","%rbx"); + +$code.=<<___ if ($addx); +.extern bn_sqrx8x_internal # see x86_64-mont5 module +___ +$code.=<<___; +.extern bn_sqr8x_internal # see x86_64-mont5 module + +.type bn_sqr8x_mont,\@function,6 +.align 32 +bn_sqr8x_mont: +.Lsqr8x_enter: + mov %rsp,%rax + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + + mov ${num}d,%r10d + shl \$3,${num}d # convert $num to bytes + shl \$3+2,%r10 # 4*$num + neg $num + + ############################################################## + # ensure that stack frame doesn't alias with $aptr modulo + # 4096. this is done to allow memory disambiguation logic + # do its job. + # + lea -64(%rsp,$num,4),%r11 + mov ($n0),$n0 # *n0 + sub $aptr,%r11 + and \$4095,%r11 + cmp %r11,%r10 + jb .Lsqr8x_sp_alt + sub %r11,%rsp # align with $aptr + lea -64(%rsp,$num,4),%rsp # alloca(frame+4*$num) + jmp .Lsqr8x_sp_done + +.align 32 +.Lsqr8x_sp_alt: + lea 4096-64(,$num,4),%r10 # 4096-frame-4*$num + lea -64(%rsp,$num,4),%rsp # alloca(frame+4*$num) + sub %r10,%r11 + mov \$0,%r10 + cmovc %r10,%r11 + sub %r11,%rsp +.Lsqr8x_sp_done: + and \$-64,%rsp + mov $num,%r10 + neg $num + + lea 64(%rsp,$num,2),%r11 # copy of modulus + mov $n0, 32(%rsp) + mov %rax, 40(%rsp) # save original %rsp +.Lsqr8x_body: + + mov $num,$i + movq %r11, %xmm2 # save pointer to modulus copy + shr \$3+2,$i + mov OPENSSL_ia32cap_P+8(%rip),%eax + jmp .Lsqr8x_copy_n + +.align 32 +.Lsqr8x_copy_n: + movq 8*0($nptr),%xmm0 + movq 8*1($nptr),%xmm1 + movq 8*2($nptr),%xmm3 + movq 8*3($nptr),%xmm4 + lea 8*4($nptr),$nptr + movdqa %xmm0,16*0(%r11) + movdqa %xmm1,16*1(%r11) + movdqa %xmm3,16*2(%r11) + movdqa %xmm4,16*3(%r11) + lea 16*4(%r11),%r11 + dec $i + jnz .Lsqr8x_copy_n + + pxor %xmm0,%xmm0 + movq $rptr,%xmm1 # save $rptr + movq %r10, %xmm3 # -$num +___ +$code.=<<___ if ($addx); + and \$0x80100,%eax + cmp \$0x80100,%eax + jne .Lsqr8x_nox + + call bn_sqrx8x_internal # see x86_64-mont5 module + + pxor %xmm0,%xmm0 + lea 48(%rsp),%rax + lea 64(%rsp,$num,2),%rdx + shr \$3+2,$num + mov 40(%rsp),%rsi # restore %rsp + jmp .Lsqr8x_zero + +.align 32 +.Lsqr8x_nox: +___ +$code.=<<___; + call bn_sqr8x_internal # see x86_64-mont5 module + + pxor %xmm0,%xmm0 + lea 48(%rsp),%rax + lea 64(%rsp,$num,2),%rdx + shr \$3+2,$num + mov 40(%rsp),%rsi # restore %rsp + jmp .Lsqr8x_zero + +.align 32 +.Lsqr8x_zero: + movdqa %xmm0,16*0(%rax) # wipe t + movdqa %xmm0,16*1(%rax) + movdqa %xmm0,16*2(%rax) + movdqa %xmm0,16*3(%rax) + lea 16*4(%rax),%rax + movdqa %xmm0,16*0(%rdx) # wipe n + movdqa %xmm0,16*1(%rdx) + movdqa %xmm0,16*2(%rdx) + movdqa %xmm0,16*3(%rdx) + lea 16*4(%rdx),%rdx + dec $num + jnz .Lsqr8x_zero + + mov \$1,%rax + mov -48(%rsi),%r15 + mov -40(%rsi),%r14 + mov -32(%rsi),%r13 + mov -24(%rsi),%r12 + mov -16(%rsi),%rbp + mov -8(%rsi),%rbx + lea (%rsi),%rsp +.Lsqr8x_epilogue: + ret +.size bn_sqr8x_mont,.-bn_sqr8x_mont +___ +}}} + +if ($addx) {{{ +my $bp="%rdx"; # original value + +$code.=<<___; +.type bn_mulx4x_mont,\@function,6 +.align 32 +bn_mulx4x_mont: +.Lmulx4x_enter: + mov %rsp,%rax + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + + shl \$3,${num}d # convert $num to bytes + .byte 0x67 + xor %r10,%r10 + sub $num,%r10 # -$num + mov ($n0),$n0 # *n0 + lea -72(%rsp,%r10),%rsp # alloca(frame+$num+8) + lea ($bp,$num),%r10 + and \$-128,%rsp + ############################################################## + # Stack layout + # +0 num + # +8 off-loaded &b[i] + # +16 end of b[num] + # +24 saved n0 + # +32 saved rp + # +40 saved %rsp + # +48 inner counter + # +56 + # +64 tmp[num+1] + # + mov $num,0(%rsp) # save $num + shr \$5,$num + mov %r10,16(%rsp) # end of b[num] + sub \$1,$num + mov $n0, 24(%rsp) # save *n0 + mov $rp, 32(%rsp) # save $rp + mov %rax,40(%rsp) # save original %rsp + mov $num,48(%rsp) # inner counter + jmp .Lmulx4x_body + +.align 32 +.Lmulx4x_body: +___ +my ($aptr, $bptr, $nptr, $tptr, $mi, $bi, $zero, $num)= + ("%rsi","%rdi","%rcx","%rbx","%r8","%r9","%rbp","%rax"); +my $rptr=$bptr; +$code.=<<___; + lea 8($bp),$bptr + mov ($bp),%rdx # b[0], $bp==%rdx actually + lea 64+32(%rsp),$tptr + mov %rdx,$bi + + mulx 0*8($aptr),$mi,%rax # a[0]*b[0] + mulx 1*8($aptr),%r11,%r14 # a[1]*b[0] + add %rax,%r11 + mov $bptr,8(%rsp) # off-load &b[i] + mulx 2*8($aptr),%r12,%r13 # ... + adc %r14,%r12 + adc \$0,%r13 + + mov $mi,$bptr # borrow $bptr + imulq 24(%rsp),$mi # "t[0]"*n0 + xor $zero,$zero # cf=0, of=0 + + mulx 3*8($aptr),%rax,%r14 + mov $mi,%rdx + lea 4*8($aptr),$aptr + adcx %rax,%r13 + adcx $zero,%r14 # cf=0 + + mulx 0*8($nptr),%rax,%r10 + adcx %rax,$bptr # discarded + adox %r11,%r10 + mulx 1*8($nptr),%rax,%r11 + adcx %rax,%r10 + adox %r12,%r11 + .byte 0xc4,0x62,0xfb,0xf6,0xa1,0x10,0x00,0x00,0x00 # mulx 2*8($nptr),%rax,%r12 + mov 48(%rsp),$bptr # counter value + mov %r10,-4*8($tptr) + adcx %rax,%r11 + adox %r13,%r12 + mulx 3*8($nptr),%rax,%r15 + mov $bi,%rdx + mov %r11,-3*8($tptr) + adcx %rax,%r12 + adox $zero,%r15 # of=0 + lea 4*8($nptr),$nptr + mov %r12,-2*8($tptr) + + jmp .Lmulx4x_1st + +.align 32 +.Lmulx4x_1st: + adcx $zero,%r15 # cf=0, modulo-scheduled + mulx 0*8($aptr),%r10,%rax # a[4]*b[0] + adcx %r14,%r10 + mulx 1*8($aptr),%r11,%r14 # a[5]*b[0] + adcx %rax,%r11 + mulx 2*8($aptr),%r12,%rax # ... + adcx %r14,%r12 + mulx 3*8($aptr),%r13,%r14 + .byte 0x67,0x67 + mov $mi,%rdx + adcx %rax,%r13 + adcx $zero,%r14 # cf=0 + lea 4*8($aptr),$aptr + lea 4*8($tptr),$tptr + + adox %r15,%r10 + mulx 0*8($nptr),%rax,%r15 + adcx %rax,%r10 + adox %r15,%r11 + mulx 1*8($nptr),%rax,%r15 + adcx %rax,%r11 + adox %r15,%r12 + mulx 2*8($nptr),%rax,%r15 + mov %r10,-5*8($tptr) + adcx %rax,%r12 + mov %r11,-4*8($tptr) + adox %r15,%r13 + mulx 3*8($nptr),%rax,%r15 + mov $bi,%rdx + mov %r12,-3*8($tptr) + adcx %rax,%r13 + adox $zero,%r15 + lea 4*8($nptr),$nptr + mov %r13,-2*8($tptr) + + dec $bptr # of=0, pass cf + jnz .Lmulx4x_1st + + mov 0(%rsp),$num # load num + mov 8(%rsp),$bptr # re-load &b[i] + adc $zero,%r15 # modulo-scheduled + add %r15,%r14 + sbb %r15,%r15 # top-most carry + mov %r14,-1*8($tptr) + jmp .Lmulx4x_outer + +.align 32 +.Lmulx4x_outer: + mov ($bptr),%rdx # b[i] + lea 8($bptr),$bptr # b++ + sub $num,$aptr # rewind $aptr + mov %r15,($tptr) # save top-most carry + lea 64+4*8(%rsp),$tptr + sub $num,$nptr # rewind $nptr + + mulx 0*8($aptr),$mi,%r11 # a[0]*b[i] + xor %ebp,%ebp # xor $zero,$zero # cf=0, of=0 + mov %rdx,$bi + mulx 1*8($aptr),%r14,%r12 # a[1]*b[i] + adox -4*8($tptr),$mi + adcx %r14,%r11 + mulx 2*8($aptr),%r15,%r13 # ... + adox -3*8($tptr),%r11 + adcx %r15,%r12 + adox $zero,%r12 + adcx $zero,%r13 + + mov $bptr,8(%rsp) # off-load &b[i] + .byte 0x67 + mov $mi,%r15 + imulq 24(%rsp),$mi # "t[0]"*n0 + xor %ebp,%ebp # xor $zero,$zero # cf=0, of=0 + + mulx 3*8($aptr),%rax,%r14 + mov $mi,%rdx + adox -2*8($tptr),%r12 + adcx %rax,%r13 + adox -1*8($tptr),%r13 + adcx $zero,%r14 + lea 4*8($aptr),$aptr + adox $zero,%r14 + + mulx 0*8($nptr),%rax,%r10 + adcx %rax,%r15 # discarded + adox %r11,%r10 + mulx 1*8($nptr),%rax,%r11 + adcx %rax,%r10 + adox %r12,%r11 + mulx 2*8($nptr),%rax,%r12 + mov %r10,-4*8($tptr) + adcx %rax,%r11 + adox %r13,%r12 + mulx 3*8($nptr),%rax,%r15 + mov $bi,%rdx + mov %r11,-3*8($tptr) + lea 4*8($nptr),$nptr + adcx %rax,%r12 + adox $zero,%r15 # of=0 + mov 48(%rsp),$bptr # counter value + mov %r12,-2*8($tptr) + + jmp .Lmulx4x_inner + +.align 32 +.Lmulx4x_inner: + mulx 0*8($aptr),%r10,%rax # a[4]*b[i] + adcx $zero,%r15 # cf=0, modulo-scheduled + adox %r14,%r10 + mulx 1*8($aptr),%r11,%r14 # a[5]*b[i] + adcx 0*8($tptr),%r10 + adox %rax,%r11 + mulx 2*8($aptr),%r12,%rax # ... + adcx 1*8($tptr),%r11 + adox %r14,%r12 + mulx 3*8($aptr),%r13,%r14 + mov $mi,%rdx + adcx 2*8($tptr),%r12 + adox %rax,%r13 + adcx 3*8($tptr),%r13 + adox $zero,%r14 # of=0 + lea 4*8($aptr),$aptr + lea 4*8($tptr),$tptr + adcx $zero,%r14 # cf=0 + + adox %r15,%r10 + mulx 0*8($nptr),%rax,%r15 + adcx %rax,%r10 + adox %r15,%r11 + mulx 1*8($nptr),%rax,%r15 + adcx %rax,%r11 + adox %r15,%r12 + mulx 2*8($nptr),%rax,%r15 + mov %r10,-5*8($tptr) + adcx %rax,%r12 + adox %r15,%r13 + mulx 3*8($nptr),%rax,%r15 + mov $bi,%rdx + mov %r11,-4*8($tptr) + mov %r12,-3*8($tptr) + adcx %rax,%r13 + adox $zero,%r15 + lea 4*8($nptr),$nptr + mov %r13,-2*8($tptr) + + dec $bptr # of=0, pass cf + jnz .Lmulx4x_inner + + mov 0(%rsp),$num # load num + mov 8(%rsp),$bptr # re-load &b[i] + adc $zero,%r15 # modulo-scheduled + sub 0*8($tptr),$zero # pull top-most carry + adc %r15,%r14 + mov -8($nptr),$mi + sbb %r15,%r15 # top-most carry + mov %r14,-1*8($tptr) + + cmp 16(%rsp),$bptr + jne .Lmulx4x_outer + + sub %r14,$mi # compare top-most words + sbb $mi,$mi + or $mi,%r15 + + neg $num + xor %rdx,%rdx + mov 32(%rsp),$rptr # restore rp + lea 64(%rsp),$tptr + + pxor %xmm0,%xmm0 + mov 0*8($nptr,$num),%r8 + mov 1*8($nptr,$num),%r9 + neg %r8 + jmp .Lmulx4x_sub_entry + +.align 32 +.Lmulx4x_sub: + mov 0*8($nptr,$num),%r8 + mov 1*8($nptr,$num),%r9 + not %r8 +.Lmulx4x_sub_entry: + mov 2*8($nptr,$num),%r10 + not %r9 + and %r15,%r8 + mov 3*8($nptr,$num),%r11 + not %r10 + and %r15,%r9 + not %r11 + and %r15,%r10 + and %r15,%r11 + + neg %rdx # mov %rdx,%cf + adc 0*8($tptr),%r8 + adc 1*8($tptr),%r9 + movdqa %xmm0,($tptr) + adc 2*8($tptr),%r10 + adc 3*8($tptr),%r11 + movdqa %xmm0,16($tptr) + lea 4*8($tptr),$tptr + sbb %rdx,%rdx # mov %cf,%rdx + + mov %r8,0*8($rptr) + mov %r9,1*8($rptr) + mov %r10,2*8($rptr) + mov %r11,3*8($rptr) + lea 4*8($rptr),$rptr + + add \$32,$num + jnz .Lmulx4x_sub + + mov 40(%rsp),%rsi # restore %rsp + mov \$1,%rax + mov -48(%rsi),%r15 + mov -40(%rsi),%r14 + mov -32(%rsi),%r13 + mov -24(%rsi),%r12 + mov -16(%rsi),%rbp + mov -8(%rsi),%rbx + lea (%rsi),%rsp +.Lmulx4x_epilogue: + ret +.size bn_mulx4x_mont,.-bn_mulx4x_mont +___ +}}} +$code.=<<___; +.asciz "Montgomery Multiplication for x86_64, CRYPTOGAMS by " +.align 16 +___ + +# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame, +# CONTEXT *context,DISPATCHER_CONTEXT *disp) +if ($win64) { +$rec="%rcx"; +$frame="%rdx"; +$context="%r8"; +$disp="%r9"; + +$code.=<<___; +.extern __imp_RtlVirtualUnwind +.type mul_handler,\@abi-omnipotent +.align 16 +mul_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + mov 8($disp),%rsi # disp->ImageBase + mov 56($disp),%r11 # disp->HandlerData + + mov 0(%r11),%r10d # HandlerData[0] + lea (%rsi,%r10),%r10 # end of prologue label + cmp %r10,%rbx # context->RipRsp + + mov 4(%r11),%r10d # HandlerData[1] + lea (%rsi,%r10),%r10 # epilogue label + cmp %r10,%rbx # context->Rip>=epilogue label + jae .Lcommon_seh_tail + + mov 192($context),%r10 # pull $num + mov 8(%rax,%r10,8),%rax # pull saved stack pointer + lea 48(%rax),%rax + + mov -8(%rax),%rbx + mov -16(%rax),%rbp + mov -24(%rax),%r12 + mov -32(%rax),%r13 + mov -40(%rax),%r14 + mov -48(%rax),%r15 + mov %rbx,144($context) # restore context->Rbx + mov %rbp,160($context) # restore context->Rbp + mov %r12,216($context) # restore context->R12 + mov %r13,224($context) # restore context->R13 + mov %r14,232($context) # restore context->R14 + mov %r15,240($context) # restore context->R15 + + jmp .Lcommon_seh_tail +.size mul_handler,.-mul_handler + +.type sqr_handler,\@abi-omnipotent +.align 16 +sqr_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + mov 8($disp),%rsi # disp->ImageBase + mov 56($disp),%r11 # disp->HandlerData + + mov 0(%r11),%r10d # HandlerData[0] + lea (%rsi,%r10),%r10 # end of prologue label + cmp %r10,%rbx # context->Rip<.Lsqr_body + jb .Lcommon_seh_tail + + mov 152($context),%rax # pull context->Rsp + + mov 4(%r11),%r10d # HandlerData[1] + lea (%rsi,%r10),%r10 # epilogue label + cmp %r10,%rbx # context->Rip>=.Lsqr_epilogue + jae .Lcommon_seh_tail + + mov 40(%rax),%rax # pull saved stack pointer + + mov -8(%rax),%rbx + mov -16(%rax),%rbp + mov -24(%rax),%r12 + mov -32(%rax),%r13 + mov -40(%rax),%r14 + mov -48(%rax),%r15 + mov %rbx,144($context) # restore context->Rbx + mov %rbp,160($context) # restore context->Rbp + mov %r12,216($context) # restore context->R12 + mov %r13,224($context) # restore context->R13 + mov %r14,232($context) # restore context->R14 + mov %r15,240($context) # restore context->R15 + +.Lcommon_seh_tail: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + + mov 40($disp),%rdi # disp->ContextRecord + mov $context,%rsi # context + mov \$154,%ecx # sizeof(CONTEXT) + .long 0xa548f3fc # cld; rep movsq + + mov $disp,%rsi + xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER + mov 8(%rsi),%rdx # arg2, disp->ImageBase + mov 0(%rsi),%r8 # arg3, disp->ControlPc + mov 16(%rsi),%r9 # arg4, disp->FunctionEntry + mov 40(%rsi),%r10 # disp->ContextRecord + lea 56(%rsi),%r11 # &disp->HandlerData + lea 24(%rsi),%r12 # &disp->EstablisherFrame + mov %r10,32(%rsp) # arg5 + mov %r11,40(%rsp) # arg6 + mov %r12,48(%rsp) # arg7 + mov %rcx,56(%rsp) # arg8, (NULL) + call *__imp_RtlVirtualUnwind(%rip) + + mov \$1,%eax # ExceptionContinueSearch + add \$64,%rsp + popfq + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + pop %rdi + pop %rsi + ret +.size sqr_handler,.-sqr_handler + +.section .pdata +.align 4 + .rva .LSEH_begin_bn_mul_mont + .rva .LSEH_end_bn_mul_mont + .rva .LSEH_info_bn_mul_mont + + .rva .LSEH_begin_bn_mul4x_mont + .rva .LSEH_end_bn_mul4x_mont + .rva .LSEH_info_bn_mul4x_mont + + .rva .LSEH_begin_bn_sqr8x_mont + .rva .LSEH_end_bn_sqr8x_mont + .rva .LSEH_info_bn_sqr8x_mont +___ +$code.=<<___ if ($addx); + .rva .LSEH_begin_bn_mulx4x_mont + .rva .LSEH_end_bn_mulx4x_mont + .rva .LSEH_info_bn_mulx4x_mont +___ +$code.=<<___; +.section .xdata +.align 8 +.LSEH_info_bn_mul_mont: + .byte 9,0,0,0 + .rva mul_handler + .rva .Lmul_body,.Lmul_epilogue # HandlerData[] +.LSEH_info_bn_mul4x_mont: + .byte 9,0,0,0 + .rva mul_handler + .rva .Lmul4x_body,.Lmul4x_epilogue # HandlerData[] +.LSEH_info_bn_sqr8x_mont: + .byte 9,0,0,0 + .rva sqr_handler + .rva .Lsqr8x_body,.Lsqr8x_epilogue # HandlerData[] +___ +$code.=<<___ if ($addx); +.LSEH_info_bn_mulx4x_mont: + .byte 9,0,0,0 + .rva sqr_handler + .rva .Lmulx4x_body,.Lmulx4x_epilogue # HandlerData[] +___ +} + +print $code; +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/bn/asm/x86_64-mont5.pl b/TMessagesProj/jni/boringssl/crypto/bn/asm/x86_64-mont5.pl new file mode 100644 index 00000000..80e91268 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/asm/x86_64-mont5.pl @@ -0,0 +1,3499 @@ +#!/usr/bin/env perl + +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== + +# August 2011. +# +# Companion to x86_64-mont.pl that optimizes cache-timing attack +# countermeasures. The subroutines are produced by replacing bp[i] +# references in their x86_64-mont.pl counterparts with cache-neutral +# references to powers table computed in BN_mod_exp_mont_consttime. +# In addition subroutine that scatters elements of the powers table +# is implemented, so that scatter-/gathering can be tuned without +# bn_exp.c modifications. + +# August 2013. +# +# Add MULX/AD*X code paths and additional interfaces to optimize for +# branch prediction unit. For input lengths that are multiples of 8 +# the np argument is not just modulus value, but one interleaved +# with 0. This is to optimize post-condition... + +$flavour = shift; +$output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or +die "can't locate x86_64-xlate.pl"; + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1` + =~ /GNU assembler version ([2-9]\.[0-9]+)/) { + $addx = ($1>=2.23); +} + +if (!$addx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) && + `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) { + $addx = ($1>=2.10); +} + +if (!$addx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) && + `ml64 2>&1` =~ /Version ([0-9]+)\./) { + $addx = ($1>=12); +} + +# int bn_mul_mont_gather5( +$rp="%rdi"; # BN_ULONG *rp, +$ap="%rsi"; # const BN_ULONG *ap, +$bp="%rdx"; # const BN_ULONG *bp, +$np="%rcx"; # const BN_ULONG *np, +$n0="%r8"; # const BN_ULONG *n0, +$num="%r9"; # int num, + # int idx); # 0 to 2^5-1, "index" in $bp holding + # pre-computed powers of a', interlaced + # in such manner that b[0] is $bp[idx], + # b[1] is [2^5+idx], etc. +$lo0="%r10"; +$hi0="%r11"; +$hi1="%r13"; +$i="%r14"; +$j="%r15"; +$m0="%rbx"; +$m1="%rbp"; + +$code=<<___; +.text + +.extern OPENSSL_ia32cap_P + +.globl bn_mul_mont_gather5 +.type bn_mul_mont_gather5,\@function,6 +.align 64 +bn_mul_mont_gather5: + test \$7,${num}d + jnz .Lmul_enter +___ +$code.=<<___ if ($addx); + mov OPENSSL_ia32cap_P+8(%rip),%r11d +___ +$code.=<<___; + jmp .Lmul4x_enter + +.align 16 +.Lmul_enter: + mov ${num}d,${num}d + mov %rsp,%rax + mov `($win64?56:8)`(%rsp),%r10d # load 7th argument + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 +___ +$code.=<<___ if ($win64); + lea -0x28(%rsp),%rsp + movaps %xmm6,(%rsp) + movaps %xmm7,0x10(%rsp) +___ +$code.=<<___; + lea 2($num),%r11 + neg %r11 + lea (%rsp,%r11,8),%rsp # tp=alloca(8*(num+2)) + and \$-1024,%rsp # minimize TLB usage + + mov %rax,8(%rsp,$num,8) # tp[num+1]=%rsp +.Lmul_body: + mov $bp,%r12 # reassign $bp +___ + $bp="%r12"; + $STRIDE=2**5*8; # 5 is "window size" + $N=$STRIDE/4; # should match cache line size +$code.=<<___; + mov %r10,%r11 + shr \$`log($N/8)/log(2)`,%r10 + and \$`$N/8-1`,%r11 + not %r10 + lea .Lmagic_masks(%rip),%rax + and \$`2**5/($N/8)-1`,%r10 # 5 is "window size" + lea 96($bp,%r11,8),$bp # pointer within 1st cache line + movq 0(%rax,%r10,8),%xmm4 # set of masks denoting which + movq 8(%rax,%r10,8),%xmm5 # cache line contains element + movq 16(%rax,%r10,8),%xmm6 # denoted by 7th argument + movq 24(%rax,%r10,8),%xmm7 + + movq `0*$STRIDE/4-96`($bp),%xmm0 + movq `1*$STRIDE/4-96`($bp),%xmm1 + pand %xmm4,%xmm0 + movq `2*$STRIDE/4-96`($bp),%xmm2 + pand %xmm5,%xmm1 + movq `3*$STRIDE/4-96`($bp),%xmm3 + pand %xmm6,%xmm2 + por %xmm1,%xmm0 + pand %xmm7,%xmm3 + por %xmm2,%xmm0 + lea $STRIDE($bp),$bp + por %xmm3,%xmm0 + + movq %xmm0,$m0 # m0=bp[0] + + mov ($n0),$n0 # pull n0[0] value + mov ($ap),%rax + + xor $i,$i # i=0 + xor $j,$j # j=0 + + movq `0*$STRIDE/4-96`($bp),%xmm0 + movq `1*$STRIDE/4-96`($bp),%xmm1 + pand %xmm4,%xmm0 + movq `2*$STRIDE/4-96`($bp),%xmm2 + pand %xmm5,%xmm1 + + mov $n0,$m1 + mulq $m0 # ap[0]*bp[0] + mov %rax,$lo0 + mov ($np),%rax + + movq `3*$STRIDE/4-96`($bp),%xmm3 + pand %xmm6,%xmm2 + por %xmm1,%xmm0 + pand %xmm7,%xmm3 + + imulq $lo0,$m1 # "tp[0]"*n0 + mov %rdx,$hi0 + + por %xmm2,%xmm0 + lea $STRIDE($bp),$bp + por %xmm3,%xmm0 + + mulq $m1 # np[0]*m1 + add %rax,$lo0 # discarded + mov 8($ap),%rax + adc \$0,%rdx + mov %rdx,$hi1 + + lea 1($j),$j # j++ + jmp .L1st_enter + +.align 16 +.L1st: + add %rax,$hi1 + mov ($ap,$j,8),%rax + adc \$0,%rdx + add $hi0,$hi1 # np[j]*m1+ap[j]*bp[0] + mov $lo0,$hi0 + adc \$0,%rdx + mov $hi1,-16(%rsp,$j,8) # tp[j-1] + mov %rdx,$hi1 + +.L1st_enter: + mulq $m0 # ap[j]*bp[0] + add %rax,$hi0 + mov ($np,$j,8),%rax + adc \$0,%rdx + lea 1($j),$j # j++ + mov %rdx,$lo0 + + mulq $m1 # np[j]*m1 + cmp $num,$j + jne .L1st + + movq %xmm0,$m0 # bp[1] + + add %rax,$hi1 + mov ($ap),%rax # ap[0] + adc \$0,%rdx + add $hi0,$hi1 # np[j]*m1+ap[j]*bp[0] + adc \$0,%rdx + mov $hi1,-16(%rsp,$j,8) # tp[j-1] + mov %rdx,$hi1 + mov $lo0,$hi0 + + xor %rdx,%rdx + add $hi0,$hi1 + adc \$0,%rdx + mov $hi1,-8(%rsp,$num,8) + mov %rdx,(%rsp,$num,8) # store upmost overflow bit + + lea 1($i),$i # i++ + jmp .Louter +.align 16 +.Louter: + xor $j,$j # j=0 + mov $n0,$m1 + mov (%rsp),$lo0 + + movq `0*$STRIDE/4-96`($bp),%xmm0 + movq `1*$STRIDE/4-96`($bp),%xmm1 + pand %xmm4,%xmm0 + movq `2*$STRIDE/4-96`($bp),%xmm2 + pand %xmm5,%xmm1 + + mulq $m0 # ap[0]*bp[i] + add %rax,$lo0 # ap[0]*bp[i]+tp[0] + mov ($np),%rax + adc \$0,%rdx + + movq `3*$STRIDE/4-96`($bp),%xmm3 + pand %xmm6,%xmm2 + por %xmm1,%xmm0 + pand %xmm7,%xmm3 + + imulq $lo0,$m1 # tp[0]*n0 + mov %rdx,$hi0 + + por %xmm2,%xmm0 + lea $STRIDE($bp),$bp + por %xmm3,%xmm0 + + mulq $m1 # np[0]*m1 + add %rax,$lo0 # discarded + mov 8($ap),%rax + adc \$0,%rdx + mov 8(%rsp),$lo0 # tp[1] + mov %rdx,$hi1 + + lea 1($j),$j # j++ + jmp .Linner_enter + +.align 16 +.Linner: + add %rax,$hi1 + mov ($ap,$j,8),%rax + adc \$0,%rdx + add $lo0,$hi1 # np[j]*m1+ap[j]*bp[i]+tp[j] + mov (%rsp,$j,8),$lo0 + adc \$0,%rdx + mov $hi1,-16(%rsp,$j,8) # tp[j-1] + mov %rdx,$hi1 + +.Linner_enter: + mulq $m0 # ap[j]*bp[i] + add %rax,$hi0 + mov ($np,$j,8),%rax + adc \$0,%rdx + add $hi0,$lo0 # ap[j]*bp[i]+tp[j] + mov %rdx,$hi0 + adc \$0,$hi0 + lea 1($j),$j # j++ + + mulq $m1 # np[j]*m1 + cmp $num,$j + jne .Linner + + movq %xmm0,$m0 # bp[i+1] + + add %rax,$hi1 + mov ($ap),%rax # ap[0] + adc \$0,%rdx + add $lo0,$hi1 # np[j]*m1+ap[j]*bp[i]+tp[j] + mov (%rsp,$j,8),$lo0 + adc \$0,%rdx + mov $hi1,-16(%rsp,$j,8) # tp[j-1] + mov %rdx,$hi1 + + xor %rdx,%rdx + add $hi0,$hi1 + adc \$0,%rdx + add $lo0,$hi1 # pull upmost overflow bit + adc \$0,%rdx + mov $hi1,-8(%rsp,$num,8) + mov %rdx,(%rsp,$num,8) # store upmost overflow bit + + lea 1($i),$i # i++ + cmp $num,$i + jb .Louter + + xor $i,$i # i=0 and clear CF! + mov (%rsp),%rax # tp[0] + lea (%rsp),$ap # borrow ap for tp + mov $num,$j # j=num + jmp .Lsub +.align 16 +.Lsub: sbb ($np,$i,8),%rax + mov %rax,($rp,$i,8) # rp[i]=tp[i]-np[i] + mov 8($ap,$i,8),%rax # tp[i+1] + lea 1($i),$i # i++ + dec $j # doesnn't affect CF! + jnz .Lsub + + sbb \$0,%rax # handle upmost overflow bit + xor $i,$i + mov $num,$j # j=num +.align 16 +.Lcopy: # copy or in-place refresh + mov (%rsp,$i,8),$ap + mov ($rp,$i,8),$np + xor $np,$ap # conditional select: + and %rax,$ap # ((ap ^ np) & %rax) ^ np + xor $np,$ap # ap = borrow?tp:rp + mov $i,(%rsp,$i,8) # zap temporary vector + mov $ap,($rp,$i,8) # rp[i]=tp[i] + lea 1($i),$i + sub \$1,$j + jnz .Lcopy + + mov 8(%rsp,$num,8),%rsi # restore %rsp + mov \$1,%rax +___ +$code.=<<___ if ($win64); + movaps -88(%rsi),%xmm6 + movaps -72(%rsi),%xmm7 +___ +$code.=<<___; + mov -48(%rsi),%r15 + mov -40(%rsi),%r14 + mov -32(%rsi),%r13 + mov -24(%rsi),%r12 + mov -16(%rsi),%rbp + mov -8(%rsi),%rbx + lea (%rsi),%rsp +.Lmul_epilogue: + ret +.size bn_mul_mont_gather5,.-bn_mul_mont_gather5 +___ +{{{ +my @A=("%r10","%r11"); +my @N=("%r13","%rdi"); +$code.=<<___; +.type bn_mul4x_mont_gather5,\@function,6 +.align 32 +bn_mul4x_mont_gather5: +.Lmul4x_enter: +___ +$code.=<<___ if ($addx); + and \$0x80100,%r11d + cmp \$0x80100,%r11d + je .Lmulx4x_enter +___ +$code.=<<___; + .byte 0x67 + mov %rsp,%rax + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 +___ +$code.=<<___ if ($win64); + lea -0x28(%rsp),%rsp + movaps %xmm6,(%rsp) + movaps %xmm7,0x10(%rsp) +___ +$code.=<<___; + .byte 0x67 + mov ${num}d,%r10d + shl \$3,${num}d + shl \$3+2,%r10d # 4*$num + neg $num # -$num + + ############################################################## + # ensure that stack frame doesn't alias with $aptr+4*$num + # modulo 4096, which covers ret[num], am[num] and n[2*num] + # (see bn_exp.c). this is done to allow memory disambiguation + # logic do its magic. [excessive frame is allocated in order + # to allow bn_from_mont8x to clear it.] + # + lea -64(%rsp,$num,2),%r11 + sub $ap,%r11 + and \$4095,%r11 + cmp %r11,%r10 + jb .Lmul4xsp_alt + sub %r11,%rsp # align with $ap + lea -64(%rsp,$num,2),%rsp # alloca(128+num*8) + jmp .Lmul4xsp_done + +.align 32 +.Lmul4xsp_alt: + lea 4096-64(,$num,2),%r10 + lea -64(%rsp,$num,2),%rsp # alloca(128+num*8) + sub %r10,%r11 + mov \$0,%r10 + cmovc %r10,%r11 + sub %r11,%rsp +.Lmul4xsp_done: + and \$-64,%rsp + neg $num + + mov %rax,40(%rsp) +.Lmul4x_body: + + call mul4x_internal + + mov 40(%rsp),%rsi # restore %rsp + mov \$1,%rax +___ +$code.=<<___ if ($win64); + movaps -88(%rsi),%xmm6 + movaps -72(%rsi),%xmm7 +___ +$code.=<<___; + mov -48(%rsi),%r15 + mov -40(%rsi),%r14 + mov -32(%rsi),%r13 + mov -24(%rsi),%r12 + mov -16(%rsi),%rbp + mov -8(%rsi),%rbx + lea (%rsi),%rsp +.Lmul4x_epilogue: + ret +.size bn_mul4x_mont_gather5,.-bn_mul4x_mont_gather5 + +.type mul4x_internal,\@abi-omnipotent +.align 32 +mul4x_internal: + shl \$5,$num + mov `($win64?56:8)`(%rax),%r10d # load 7th argument + lea 256(%rdx,$num),%r13 + shr \$5,$num # restore $num +___ + $bp="%r12"; + $STRIDE=2**5*8; # 5 is "window size" + $N=$STRIDE/4; # should match cache line size + $tp=$i; +$code.=<<___; + mov %r10,%r11 + shr \$`log($N/8)/log(2)`,%r10 + and \$`$N/8-1`,%r11 + not %r10 + lea .Lmagic_masks(%rip),%rax + and \$`2**5/($N/8)-1`,%r10 # 5 is "window size" + lea 96(%rdx,%r11,8),$bp # pointer within 1st cache line + movq 0(%rax,%r10,8),%xmm4 # set of masks denoting which + movq 8(%rax,%r10,8),%xmm5 # cache line contains element + add \$7,%r11 + movq 16(%rax,%r10,8),%xmm6 # denoted by 7th argument + movq 24(%rax,%r10,8),%xmm7 + and \$7,%r11 + + movq `0*$STRIDE/4-96`($bp),%xmm0 + lea $STRIDE($bp),$tp # borrow $tp + movq `1*$STRIDE/4-96`($bp),%xmm1 + pand %xmm4,%xmm0 + movq `2*$STRIDE/4-96`($bp),%xmm2 + pand %xmm5,%xmm1 + movq `3*$STRIDE/4-96`($bp),%xmm3 + pand %xmm6,%xmm2 + .byte 0x67 + por %xmm1,%xmm0 + movq `0*$STRIDE/4-96`($tp),%xmm1 + .byte 0x67 + pand %xmm7,%xmm3 + .byte 0x67 + por %xmm2,%xmm0 + movq `1*$STRIDE/4-96`($tp),%xmm2 + .byte 0x67 + pand %xmm4,%xmm1 + .byte 0x67 + por %xmm3,%xmm0 + movq `2*$STRIDE/4-96`($tp),%xmm3 + + movq %xmm0,$m0 # m0=bp[0] + movq `3*$STRIDE/4-96`($tp),%xmm0 + mov %r13,16+8(%rsp) # save end of b[num] + mov $rp, 56+8(%rsp) # save $rp + + mov ($n0),$n0 # pull n0[0] value + mov ($ap),%rax + lea ($ap,$num),$ap # end of a[num] + neg $num + + mov $n0,$m1 + mulq $m0 # ap[0]*bp[0] + mov %rax,$A[0] + mov ($np),%rax + + pand %xmm5,%xmm2 + pand %xmm6,%xmm3 + por %xmm2,%xmm1 + + imulq $A[0],$m1 # "tp[0]"*n0 + ############################################################## + # $tp is chosen so that writing to top-most element of the + # vector occurs just "above" references to powers table, + # "above" modulo cache-line size, which effectively precludes + # possibility of memory disambiguation logic failure when + # accessing the table. + # + lea 64+8(%rsp,%r11,8),$tp + mov %rdx,$A[1] + + pand %xmm7,%xmm0 + por %xmm3,%xmm1 + lea 2*$STRIDE($bp),$bp + por %xmm1,%xmm0 + + mulq $m1 # np[0]*m1 + add %rax,$A[0] # discarded + mov 8($ap,$num),%rax + adc \$0,%rdx + mov %rdx,$N[1] + + mulq $m0 + add %rax,$A[1] + mov 16*1($np),%rax # interleaved with 0, therefore 16*n + adc \$0,%rdx + mov %rdx,$A[0] + + mulq $m1 + add %rax,$N[1] + mov 16($ap,$num),%rax + adc \$0,%rdx + add $A[1],$N[1] + lea 4*8($num),$j # j=4 + lea 16*4($np),$np + adc \$0,%rdx + mov $N[1],($tp) + mov %rdx,$N[0] + jmp .L1st4x + +.align 32 +.L1st4x: + mulq $m0 # ap[j]*bp[0] + add %rax,$A[0] + mov -16*2($np),%rax + lea 32($tp),$tp + adc \$0,%rdx + mov %rdx,$A[1] + + mulq $m1 # np[j]*m1 + add %rax,$N[0] + mov -8($ap,$j),%rax + adc \$0,%rdx + add $A[0],$N[0] # np[j]*m1+ap[j]*bp[0] + adc \$0,%rdx + mov $N[0],-24($tp) # tp[j-1] + mov %rdx,$N[1] + + mulq $m0 # ap[j]*bp[0] + add %rax,$A[1] + mov -16*1($np),%rax + adc \$0,%rdx + mov %rdx,$A[0] + + mulq $m1 # np[j]*m1 + add %rax,$N[1] + mov ($ap,$j),%rax + adc \$0,%rdx + add $A[1],$N[1] # np[j]*m1+ap[j]*bp[0] + adc \$0,%rdx + mov $N[1],-16($tp) # tp[j-1] + mov %rdx,$N[0] + + mulq $m0 # ap[j]*bp[0] + add %rax,$A[0] + mov 16*0($np),%rax + adc \$0,%rdx + mov %rdx,$A[1] + + mulq $m1 # np[j]*m1 + add %rax,$N[0] + mov 8($ap,$j),%rax + adc \$0,%rdx + add $A[0],$N[0] # np[j]*m1+ap[j]*bp[0] + adc \$0,%rdx + mov $N[0],-8($tp) # tp[j-1] + mov %rdx,$N[1] + + mulq $m0 # ap[j]*bp[0] + add %rax,$A[1] + mov 16*1($np),%rax + adc \$0,%rdx + mov %rdx,$A[0] + + mulq $m1 # np[j]*m1 + add %rax,$N[1] + mov 16($ap,$j),%rax + adc \$0,%rdx + add $A[1],$N[1] # np[j]*m1+ap[j]*bp[0] + lea 16*4($np),$np + adc \$0,%rdx + mov $N[1],($tp) # tp[j-1] + mov %rdx,$N[0] + + add \$32,$j # j+=4 + jnz .L1st4x + + mulq $m0 # ap[j]*bp[0] + add %rax,$A[0] + mov -16*2($np),%rax + lea 32($tp),$tp + adc \$0,%rdx + mov %rdx,$A[1] + + mulq $m1 # np[j]*m1 + add %rax,$N[0] + mov -8($ap),%rax + adc \$0,%rdx + add $A[0],$N[0] # np[j]*m1+ap[j]*bp[0] + adc \$0,%rdx + mov $N[0],-24($tp) # tp[j-1] + mov %rdx,$N[1] + + mulq $m0 # ap[j]*bp[0] + add %rax,$A[1] + mov -16*1($np),%rax + adc \$0,%rdx + mov %rdx,$A[0] + + mulq $m1 # np[j]*m1 + add %rax,$N[1] + mov ($ap,$num),%rax # ap[0] + adc \$0,%rdx + add $A[1],$N[1] # np[j]*m1+ap[j]*bp[0] + adc \$0,%rdx + mov $N[1],-16($tp) # tp[j-1] + mov %rdx,$N[0] + + movq %xmm0,$m0 # bp[1] + lea ($np,$num,2),$np # rewind $np + + xor $N[1],$N[1] + add $A[0],$N[0] + adc \$0,$N[1] + mov $N[0],-8($tp) + + jmp .Louter4x + +.align 32 +.Louter4x: + mov ($tp,$num),$A[0] + mov $n0,$m1 + mulq $m0 # ap[0]*bp[i] + add %rax,$A[0] # ap[0]*bp[i]+tp[0] + mov ($np),%rax + adc \$0,%rdx + + movq `0*$STRIDE/4-96`($bp),%xmm0 + movq `1*$STRIDE/4-96`($bp),%xmm1 + pand %xmm4,%xmm0 + movq `2*$STRIDE/4-96`($bp),%xmm2 + pand %xmm5,%xmm1 + movq `3*$STRIDE/4-96`($bp),%xmm3 + + imulq $A[0],$m1 # tp[0]*n0 + .byte 0x67 + mov %rdx,$A[1] + mov $N[1],($tp) # store upmost overflow bit + + pand %xmm6,%xmm2 + por %xmm1,%xmm0 + pand %xmm7,%xmm3 + por %xmm2,%xmm0 + lea ($tp,$num),$tp # rewind $tp + lea $STRIDE($bp),$bp + por %xmm3,%xmm0 + + mulq $m1 # np[0]*m1 + add %rax,$A[0] # "$N[0]", discarded + mov 8($ap,$num),%rax + adc \$0,%rdx + mov %rdx,$N[1] + + mulq $m0 # ap[j]*bp[i] + add %rax,$A[1] + mov 16*1($np),%rax # interleaved with 0, therefore 16*n + adc \$0,%rdx + add 8($tp),$A[1] # +tp[1] + adc \$0,%rdx + mov %rdx,$A[0] + + mulq $m1 # np[j]*m1 + add %rax,$N[1] + mov 16($ap,$num),%rax + adc \$0,%rdx + add $A[1],$N[1] # np[j]*m1+ap[j]*bp[i]+tp[j] + lea 4*8($num),$j # j=4 + lea 16*4($np),$np + adc \$0,%rdx + mov %rdx,$N[0] + jmp .Linner4x + +.align 32 +.Linner4x: + mulq $m0 # ap[j]*bp[i] + add %rax,$A[0] + mov -16*2($np),%rax + adc \$0,%rdx + add 16($tp),$A[0] # ap[j]*bp[i]+tp[j] + lea 32($tp),$tp + adc \$0,%rdx + mov %rdx,$A[1] + + mulq $m1 # np[j]*m1 + add %rax,$N[0] + mov -8($ap,$j),%rax + adc \$0,%rdx + add $A[0],$N[0] + adc \$0,%rdx + mov $N[1],-32($tp) # tp[j-1] + mov %rdx,$N[1] + + mulq $m0 # ap[j]*bp[i] + add %rax,$A[1] + mov -16*1($np),%rax + adc \$0,%rdx + add -8($tp),$A[1] + adc \$0,%rdx + mov %rdx,$A[0] + + mulq $m1 # np[j]*m1 + add %rax,$N[1] + mov ($ap,$j),%rax + adc \$0,%rdx + add $A[1],$N[1] + adc \$0,%rdx + mov $N[0],-24($tp) # tp[j-1] + mov %rdx,$N[0] + + mulq $m0 # ap[j]*bp[i] + add %rax,$A[0] + mov 16*0($np),%rax + adc \$0,%rdx + add ($tp),$A[0] # ap[j]*bp[i]+tp[j] + adc \$0,%rdx + mov %rdx,$A[1] + + mulq $m1 # np[j]*m1 + add %rax,$N[0] + mov 8($ap,$j),%rax + adc \$0,%rdx + add $A[0],$N[0] + adc \$0,%rdx + mov $N[1],-16($tp) # tp[j-1] + mov %rdx,$N[1] + + mulq $m0 # ap[j]*bp[i] + add %rax,$A[1] + mov 16*1($np),%rax + adc \$0,%rdx + add 8($tp),$A[1] + adc \$0,%rdx + mov %rdx,$A[0] + + mulq $m1 # np[j]*m1 + add %rax,$N[1] + mov 16($ap,$j),%rax + adc \$0,%rdx + add $A[1],$N[1] + lea 16*4($np),$np + adc \$0,%rdx + mov $N[0],-8($tp) # tp[j-1] + mov %rdx,$N[0] + + add \$32,$j # j+=4 + jnz .Linner4x + + mulq $m0 # ap[j]*bp[i] + add %rax,$A[0] + mov -16*2($np),%rax + adc \$0,%rdx + add 16($tp),$A[0] # ap[j]*bp[i]+tp[j] + lea 32($tp),$tp + adc \$0,%rdx + mov %rdx,$A[1] + + mulq $m1 # np[j]*m1 + add %rax,$N[0] + mov -8($ap),%rax + adc \$0,%rdx + add $A[0],$N[0] + adc \$0,%rdx + mov $N[1],-32($tp) # tp[j-1] + mov %rdx,$N[1] + + mulq $m0 # ap[j]*bp[i] + add %rax,$A[1] + mov $m1,%rax + mov -16*1($np),$m1 + adc \$0,%rdx + add -8($tp),$A[1] + adc \$0,%rdx + mov %rdx,$A[0] + + mulq $m1 # np[j]*m1 + add %rax,$N[1] + mov ($ap,$num),%rax # ap[0] + adc \$0,%rdx + add $A[1],$N[1] + adc \$0,%rdx + mov $N[0],-24($tp) # tp[j-1] + mov %rdx,$N[0] + + movq %xmm0,$m0 # bp[i+1] + mov $N[1],-16($tp) # tp[j-1] + lea ($np,$num,2),$np # rewind $np + + xor $N[1],$N[1] + add $A[0],$N[0] + adc \$0,$N[1] + add ($tp),$N[0] # pull upmost overflow bit + adc \$0,$N[1] # upmost overflow bit + mov $N[0],-8($tp) + + cmp 16+8(%rsp),$bp + jb .Louter4x +___ +if (1) { +$code.=<<___; + sub $N[0],$m1 # compare top-most words + adc $j,$j # $j is zero + or $j,$N[1] + xor \$1,$N[1] + lea ($tp,$num),%rbx # tptr in .sqr4x_sub + lea ($np,$N[1],8),%rbp # nptr in .sqr4x_sub + mov %r9,%rcx + sar \$3+2,%rcx # cf=0 + mov 56+8(%rsp),%rdi # rptr in .sqr4x_sub + jmp .Lsqr4x_sub +___ +} else { +my @ri=("%rax",$bp,$m0,$m1); +my $rp="%rdx"; +$code.=<<___ + xor \$1,$N[1] + lea ($tp,$num),$tp # rewind $tp + sar \$5,$num # cf=0 + lea ($np,$N[1],8),$np + mov 56+8(%rsp),$rp # restore $rp + jmp .Lsub4x + +.align 32 +.Lsub4x: + .byte 0x66 + mov 8*0($tp),@ri[0] + mov 8*1($tp),@ri[1] + .byte 0x66 + sbb 16*0($np),@ri[0] + mov 8*2($tp),@ri[2] + sbb 16*1($np),@ri[1] + mov 3*8($tp),@ri[3] + lea 4*8($tp),$tp + sbb 16*2($np),@ri[2] + mov @ri[0],8*0($rp) + sbb 16*3($np),@ri[3] + lea 16*4($np),$np + mov @ri[1],8*1($rp) + mov @ri[2],8*2($rp) + mov @ri[3],8*3($rp) + lea 8*4($rp),$rp + + inc $num + jnz .Lsub4x + + ret +___ +} +$code.=<<___; +.size mul4x_internal,.-mul4x_internal +___ +}}} + {{{ +###################################################################### +# void bn_power5( +my $rptr="%rdi"; # BN_ULONG *rptr, +my $aptr="%rsi"; # const BN_ULONG *aptr, +my $bptr="%rdx"; # const void *table, +my $nptr="%rcx"; # const BN_ULONG *nptr, +my $n0 ="%r8"; # const BN_ULONG *n0); +my $num ="%r9"; # int num, has to be divisible by 8 + # int pwr + +my ($i,$j,$tptr)=("%rbp","%rcx",$rptr); +my @A0=("%r10","%r11"); +my @A1=("%r12","%r13"); +my ($a0,$a1,$ai)=("%r14","%r15","%rbx"); + +$code.=<<___; +.globl bn_power5 +.type bn_power5,\@function,6 +.align 32 +bn_power5: +___ +$code.=<<___ if ($addx); + mov OPENSSL_ia32cap_P+8(%rip),%r11d + and \$0x80100,%r11d + cmp \$0x80100,%r11d + je .Lpowerx5_enter +___ +$code.=<<___; + mov %rsp,%rax + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 +___ +$code.=<<___ if ($win64); + lea -0x28(%rsp),%rsp + movaps %xmm6,(%rsp) + movaps %xmm7,0x10(%rsp) +___ +$code.=<<___; + mov ${num}d,%r10d + shl \$3,${num}d # convert $num to bytes + shl \$3+2,%r10d # 4*$num + neg $num + mov ($n0),$n0 # *n0 + + ############################################################## + # ensure that stack frame doesn't alias with $aptr+4*$num + # modulo 4096, which covers ret[num], am[num] and n[2*num] + # (see bn_exp.c). this is done to allow memory disambiguation + # logic do its magic. + # + lea -64(%rsp,$num,2),%r11 + sub $aptr,%r11 + and \$4095,%r11 + cmp %r11,%r10 + jb .Lpwr_sp_alt + sub %r11,%rsp # align with $aptr + lea -64(%rsp,$num,2),%rsp # alloca(frame+2*$num) + jmp .Lpwr_sp_done + +.align 32 +.Lpwr_sp_alt: + lea 4096-64(,$num,2),%r10 # 4096-frame-2*$num + lea -64(%rsp,$num,2),%rsp # alloca(frame+2*$num) + sub %r10,%r11 + mov \$0,%r10 + cmovc %r10,%r11 + sub %r11,%rsp +.Lpwr_sp_done: + and \$-64,%rsp + mov $num,%r10 + neg $num + + ############################################################## + # Stack layout + # + # +0 saved $num, used in reduction section + # +8 &t[2*$num], used in reduction section + # +32 saved *n0 + # +40 saved %rsp + # +48 t[2*$num] + # + mov $n0, 32(%rsp) + mov %rax, 40(%rsp) # save original %rsp +.Lpower5_body: + movq $rptr,%xmm1 # save $rptr + movq $nptr,%xmm2 # save $nptr + movq %r10, %xmm3 # -$num + movq $bptr,%xmm4 + + call __bn_sqr8x_internal + call __bn_sqr8x_internal + call __bn_sqr8x_internal + call __bn_sqr8x_internal + call __bn_sqr8x_internal + + movq %xmm2,$nptr + movq %xmm4,$bptr + mov $aptr,$rptr + mov 40(%rsp),%rax + lea 32(%rsp),$n0 + + call mul4x_internal + + mov 40(%rsp),%rsi # restore %rsp + mov \$1,%rax + mov -48(%rsi),%r15 + mov -40(%rsi),%r14 + mov -32(%rsi),%r13 + mov -24(%rsi),%r12 + mov -16(%rsi),%rbp + mov -8(%rsi),%rbx + lea (%rsi),%rsp +.Lpower5_epilogue: + ret +.size bn_power5,.-bn_power5 + +.globl bn_sqr8x_internal +.hidden bn_sqr8x_internal +.type bn_sqr8x_internal,\@abi-omnipotent +.align 32 +bn_sqr8x_internal: +__bn_sqr8x_internal: + ############################################################## + # Squaring part: + # + # a) multiply-n-add everything but a[i]*a[i]; + # b) shift result of a) by 1 to the left and accumulate + # a[i]*a[i] products; + # + ############################################################## + # a[1]a[0] + # a[2]a[0] + # a[3]a[0] + # a[2]a[1] + # a[4]a[0] + # a[3]a[1] + # a[5]a[0] + # a[4]a[1] + # a[3]a[2] + # a[6]a[0] + # a[5]a[1] + # a[4]a[2] + # a[7]a[0] + # a[6]a[1] + # a[5]a[2] + # a[4]a[3] + # a[7]a[1] + # a[6]a[2] + # a[5]a[3] + # a[7]a[2] + # a[6]a[3] + # a[5]a[4] + # a[7]a[3] + # a[6]a[4] + # a[7]a[4] + # a[6]a[5] + # a[7]a[5] + # a[7]a[6] + # a[1]a[0] + # a[2]a[0] + # a[3]a[0] + # a[4]a[0] + # a[5]a[0] + # a[6]a[0] + # a[7]a[0] + # a[2]a[1] + # a[3]a[1] + # a[4]a[1] + # a[5]a[1] + # a[6]a[1] + # a[7]a[1] + # a[3]a[2] + # a[4]a[2] + # a[5]a[2] + # a[6]a[2] + # a[7]a[2] + # a[4]a[3] + # a[5]a[3] + # a[6]a[3] + # a[7]a[3] + # a[5]a[4] + # a[6]a[4] + # a[7]a[4] + # a[6]a[5] + # a[7]a[5] + # a[7]a[6] + # a[0]a[0] + # a[1]a[1] + # a[2]a[2] + # a[3]a[3] + # a[4]a[4] + # a[5]a[5] + # a[6]a[6] + # a[7]a[7] + + lea 32(%r10),$i # $i=-($num-32) + lea ($aptr,$num),$aptr # end of a[] buffer, ($aptr,$i)=&ap[2] + + mov $num,$j # $j=$num + + # comments apply to $num==8 case + mov -32($aptr,$i),$a0 # a[0] + lea 48+8(%rsp,$num,2),$tptr # end of tp[] buffer, &tp[2*$num] + mov -24($aptr,$i),%rax # a[1] + lea -32($tptr,$i),$tptr # end of tp[] window, &tp[2*$num-"$i"] + mov -16($aptr,$i),$ai # a[2] + mov %rax,$a1 + + mul $a0 # a[1]*a[0] + mov %rax,$A0[0] # a[1]*a[0] + mov $ai,%rax # a[2] + mov %rdx,$A0[1] + mov $A0[0],-24($tptr,$i) # t[1] + + mul $a0 # a[2]*a[0] + add %rax,$A0[1] + mov $ai,%rax + adc \$0,%rdx + mov $A0[1],-16($tptr,$i) # t[2] + mov %rdx,$A0[0] + + + mov -8($aptr,$i),$ai # a[3] + mul $a1 # a[2]*a[1] + mov %rax,$A1[0] # a[2]*a[1]+t[3] + mov $ai,%rax + mov %rdx,$A1[1] + + lea ($i),$j + mul $a0 # a[3]*a[0] + add %rax,$A0[0] # a[3]*a[0]+a[2]*a[1]+t[3] + mov $ai,%rax + mov %rdx,$A0[1] + adc \$0,$A0[1] + add $A1[0],$A0[0] + adc \$0,$A0[1] + mov $A0[0],-8($tptr,$j) # t[3] + jmp .Lsqr4x_1st + +.align 32 +.Lsqr4x_1st: + mov ($aptr,$j),$ai # a[4] + mul $a1 # a[3]*a[1] + add %rax,$A1[1] # a[3]*a[1]+t[4] + mov $ai,%rax + mov %rdx,$A1[0] + adc \$0,$A1[0] + + mul $a0 # a[4]*a[0] + add %rax,$A0[1] # a[4]*a[0]+a[3]*a[1]+t[4] + mov $ai,%rax # a[3] + mov 8($aptr,$j),$ai # a[5] + mov %rdx,$A0[0] + adc \$0,$A0[0] + add $A1[1],$A0[1] + adc \$0,$A0[0] + + + mul $a1 # a[4]*a[3] + add %rax,$A1[0] # a[4]*a[3]+t[5] + mov $ai,%rax + mov $A0[1],($tptr,$j) # t[4] + mov %rdx,$A1[1] + adc \$0,$A1[1] + + mul $a0 # a[5]*a[2] + add %rax,$A0[0] # a[5]*a[2]+a[4]*a[3]+t[5] + mov $ai,%rax + mov 16($aptr,$j),$ai # a[6] + mov %rdx,$A0[1] + adc \$0,$A0[1] + add $A1[0],$A0[0] + adc \$0,$A0[1] + + mul $a1 # a[5]*a[3] + add %rax,$A1[1] # a[5]*a[3]+t[6] + mov $ai,%rax + mov $A0[0],8($tptr,$j) # t[5] + mov %rdx,$A1[0] + adc \$0,$A1[0] + + mul $a0 # a[6]*a[2] + add %rax,$A0[1] # a[6]*a[2]+a[5]*a[3]+t[6] + mov $ai,%rax # a[3] + mov 24($aptr,$j),$ai # a[7] + mov %rdx,$A0[0] + adc \$0,$A0[0] + add $A1[1],$A0[1] + adc \$0,$A0[0] + + + mul $a1 # a[6]*a[5] + add %rax,$A1[0] # a[6]*a[5]+t[7] + mov $ai,%rax + mov $A0[1],16($tptr,$j) # t[6] + mov %rdx,$A1[1] + adc \$0,$A1[1] + lea 32($j),$j + + mul $a0 # a[7]*a[4] + add %rax,$A0[0] # a[7]*a[4]+a[6]*a[5]+t[6] + mov $ai,%rax + mov %rdx,$A0[1] + adc \$0,$A0[1] + add $A1[0],$A0[0] + adc \$0,$A0[1] + mov $A0[0],-8($tptr,$j) # t[7] + + cmp \$0,$j + jne .Lsqr4x_1st + + mul $a1 # a[7]*a[5] + add %rax,$A1[1] + lea 16($i),$i + adc \$0,%rdx + add $A0[1],$A1[1] + adc \$0,%rdx + + mov $A1[1],($tptr) # t[8] + mov %rdx,$A1[0] + mov %rdx,8($tptr) # t[9] + jmp .Lsqr4x_outer + +.align 32 +.Lsqr4x_outer: # comments apply to $num==6 case + mov -32($aptr,$i),$a0 # a[0] + lea 48+8(%rsp,$num,2),$tptr # end of tp[] buffer, &tp[2*$num] + mov -24($aptr,$i),%rax # a[1] + lea -32($tptr,$i),$tptr # end of tp[] window, &tp[2*$num-"$i"] + mov -16($aptr,$i),$ai # a[2] + mov %rax,$a1 + + mul $a0 # a[1]*a[0] + mov -24($tptr,$i),$A0[0] # t[1] + add %rax,$A0[0] # a[1]*a[0]+t[1] + mov $ai,%rax # a[2] + adc \$0,%rdx + mov $A0[0],-24($tptr,$i) # t[1] + mov %rdx,$A0[1] + + mul $a0 # a[2]*a[0] + add %rax,$A0[1] + mov $ai,%rax + adc \$0,%rdx + add -16($tptr,$i),$A0[1] # a[2]*a[0]+t[2] + mov %rdx,$A0[0] + adc \$0,$A0[0] + mov $A0[1],-16($tptr,$i) # t[2] + + xor $A1[0],$A1[0] + + mov -8($aptr,$i),$ai # a[3] + mul $a1 # a[2]*a[1] + add %rax,$A1[0] # a[2]*a[1]+t[3] + mov $ai,%rax + adc \$0,%rdx + add -8($tptr,$i),$A1[0] + mov %rdx,$A1[1] + adc \$0,$A1[1] + + mul $a0 # a[3]*a[0] + add %rax,$A0[0] # a[3]*a[0]+a[2]*a[1]+t[3] + mov $ai,%rax + adc \$0,%rdx + add $A1[0],$A0[0] + mov %rdx,$A0[1] + adc \$0,$A0[1] + mov $A0[0],-8($tptr,$i) # t[3] + + lea ($i),$j + jmp .Lsqr4x_inner + +.align 32 +.Lsqr4x_inner: + mov ($aptr,$j),$ai # a[4] + mul $a1 # a[3]*a[1] + add %rax,$A1[1] # a[3]*a[1]+t[4] + mov $ai,%rax + mov %rdx,$A1[0] + adc \$0,$A1[0] + add ($tptr,$j),$A1[1] + adc \$0,$A1[0] + + .byte 0x67 + mul $a0 # a[4]*a[0] + add %rax,$A0[1] # a[4]*a[0]+a[3]*a[1]+t[4] + mov $ai,%rax # a[3] + mov 8($aptr,$j),$ai # a[5] + mov %rdx,$A0[0] + adc \$0,$A0[0] + add $A1[1],$A0[1] + adc \$0,$A0[0] + + mul $a1 # a[4]*a[3] + add %rax,$A1[0] # a[4]*a[3]+t[5] + mov $A0[1],($tptr,$j) # t[4] + mov $ai,%rax + mov %rdx,$A1[1] + adc \$0,$A1[1] + add 8($tptr,$j),$A1[0] + lea 16($j),$j # j++ + adc \$0,$A1[1] + + mul $a0 # a[5]*a[2] + add %rax,$A0[0] # a[5]*a[2]+a[4]*a[3]+t[5] + mov $ai,%rax + adc \$0,%rdx + add $A1[0],$A0[0] + mov %rdx,$A0[1] + adc \$0,$A0[1] + mov $A0[0],-8($tptr,$j) # t[5], "preloaded t[1]" below + + cmp \$0,$j + jne .Lsqr4x_inner + + .byte 0x67 + mul $a1 # a[5]*a[3] + add %rax,$A1[1] + adc \$0,%rdx + add $A0[1],$A1[1] + adc \$0,%rdx + + mov $A1[1],($tptr) # t[6], "preloaded t[2]" below + mov %rdx,$A1[0] + mov %rdx,8($tptr) # t[7], "preloaded t[3]" below + + add \$16,$i + jnz .Lsqr4x_outer + + # comments apply to $num==4 case + mov -32($aptr),$a0 # a[0] + lea 48+8(%rsp,$num,2),$tptr # end of tp[] buffer, &tp[2*$num] + mov -24($aptr),%rax # a[1] + lea -32($tptr,$i),$tptr # end of tp[] window, &tp[2*$num-"$i"] + mov -16($aptr),$ai # a[2] + mov %rax,$a1 + + mul $a0 # a[1]*a[0] + add %rax,$A0[0] # a[1]*a[0]+t[1], preloaded t[1] + mov $ai,%rax # a[2] + mov %rdx,$A0[1] + adc \$0,$A0[1] + + mul $a0 # a[2]*a[0] + add %rax,$A0[1] + mov $ai,%rax + mov $A0[0],-24($tptr) # t[1] + mov %rdx,$A0[0] + adc \$0,$A0[0] + add $A1[1],$A0[1] # a[2]*a[0]+t[2], preloaded t[2] + mov -8($aptr),$ai # a[3] + adc \$0,$A0[0] + + mul $a1 # a[2]*a[1] + add %rax,$A1[0] # a[2]*a[1]+t[3], preloaded t[3] + mov $ai,%rax + mov $A0[1],-16($tptr) # t[2] + mov %rdx,$A1[1] + adc \$0,$A1[1] + + mul $a0 # a[3]*a[0] + add %rax,$A0[0] # a[3]*a[0]+a[2]*a[1]+t[3] + mov $ai,%rax + mov %rdx,$A0[1] + adc \$0,$A0[1] + add $A1[0],$A0[0] + adc \$0,$A0[1] + mov $A0[0],-8($tptr) # t[3] + + mul $a1 # a[3]*a[1] + add %rax,$A1[1] + mov -16($aptr),%rax # a[2] + adc \$0,%rdx + add $A0[1],$A1[1] + adc \$0,%rdx + + mov $A1[1],($tptr) # t[4] + mov %rdx,$A1[0] + mov %rdx,8($tptr) # t[5] + + mul $ai # a[2]*a[3] +___ +{ +my ($shift,$carry)=($a0,$a1); +my @S=(@A1,$ai,$n0); +$code.=<<___; + add \$16,$i + xor $shift,$shift + sub $num,$i # $i=16-$num + xor $carry,$carry + + add $A1[0],%rax # t[5] + adc \$0,%rdx + mov %rax,8($tptr) # t[5] + mov %rdx,16($tptr) # t[6] + mov $carry,24($tptr) # t[7] + + mov -16($aptr,$i),%rax # a[0] + lea 48+8(%rsp),$tptr + xor $A0[0],$A0[0] # t[0] + mov 8($tptr),$A0[1] # t[1] + + lea ($shift,$A0[0],2),$S[0] # t[2*i]<<1 | shift + shr \$63,$A0[0] + lea ($j,$A0[1],2),$S[1] # t[2*i+1]<<1 | + shr \$63,$A0[1] + or $A0[0],$S[1] # | t[2*i]>>63 + mov 16($tptr),$A0[0] # t[2*i+2] # prefetch + mov $A0[1],$shift # shift=t[2*i+1]>>63 + mul %rax # a[i]*a[i] + neg $carry # mov $carry,cf + mov 24($tptr),$A0[1] # t[2*i+2+1] # prefetch + adc %rax,$S[0] + mov -8($aptr,$i),%rax # a[i+1] # prefetch + mov $S[0],($tptr) + adc %rdx,$S[1] + + lea ($shift,$A0[0],2),$S[2] # t[2*i]<<1 | shift + mov $S[1],8($tptr) + sbb $carry,$carry # mov cf,$carry + shr \$63,$A0[0] + lea ($j,$A0[1],2),$S[3] # t[2*i+1]<<1 | + shr \$63,$A0[1] + or $A0[0],$S[3] # | t[2*i]>>63 + mov 32($tptr),$A0[0] # t[2*i+2] # prefetch + mov $A0[1],$shift # shift=t[2*i+1]>>63 + mul %rax # a[i]*a[i] + neg $carry # mov $carry,cf + mov 40($tptr),$A0[1] # t[2*i+2+1] # prefetch + adc %rax,$S[2] + mov 0($aptr,$i),%rax # a[i+1] # prefetch + mov $S[2],16($tptr) + adc %rdx,$S[3] + lea 16($i),$i + mov $S[3],24($tptr) + sbb $carry,$carry # mov cf,$carry + lea 64($tptr),$tptr + jmp .Lsqr4x_shift_n_add + +.align 32 +.Lsqr4x_shift_n_add: + lea ($shift,$A0[0],2),$S[0] # t[2*i]<<1 | shift + shr \$63,$A0[0] + lea ($j,$A0[1],2),$S[1] # t[2*i+1]<<1 | + shr \$63,$A0[1] + or $A0[0],$S[1] # | t[2*i]>>63 + mov -16($tptr),$A0[0] # t[2*i+2] # prefetch + mov $A0[1],$shift # shift=t[2*i+1]>>63 + mul %rax # a[i]*a[i] + neg $carry # mov $carry,cf + mov -8($tptr),$A0[1] # t[2*i+2+1] # prefetch + adc %rax,$S[0] + mov -8($aptr,$i),%rax # a[i+1] # prefetch + mov $S[0],-32($tptr) + adc %rdx,$S[1] + + lea ($shift,$A0[0],2),$S[2] # t[2*i]<<1 | shift + mov $S[1],-24($tptr) + sbb $carry,$carry # mov cf,$carry + shr \$63,$A0[0] + lea ($j,$A0[1],2),$S[3] # t[2*i+1]<<1 | + shr \$63,$A0[1] + or $A0[0],$S[3] # | t[2*i]>>63 + mov 0($tptr),$A0[0] # t[2*i+2] # prefetch + mov $A0[1],$shift # shift=t[2*i+1]>>63 + mul %rax # a[i]*a[i] + neg $carry # mov $carry,cf + mov 8($tptr),$A0[1] # t[2*i+2+1] # prefetch + adc %rax,$S[2] + mov 0($aptr,$i),%rax # a[i+1] # prefetch + mov $S[2],-16($tptr) + adc %rdx,$S[3] + + lea ($shift,$A0[0],2),$S[0] # t[2*i]<<1 | shift + mov $S[3],-8($tptr) + sbb $carry,$carry # mov cf,$carry + shr \$63,$A0[0] + lea ($j,$A0[1],2),$S[1] # t[2*i+1]<<1 | + shr \$63,$A0[1] + or $A0[0],$S[1] # | t[2*i]>>63 + mov 16($tptr),$A0[0] # t[2*i+2] # prefetch + mov $A0[1],$shift # shift=t[2*i+1]>>63 + mul %rax # a[i]*a[i] + neg $carry # mov $carry,cf + mov 24($tptr),$A0[1] # t[2*i+2+1] # prefetch + adc %rax,$S[0] + mov 8($aptr,$i),%rax # a[i+1] # prefetch + mov $S[0],0($tptr) + adc %rdx,$S[1] + + lea ($shift,$A0[0],2),$S[2] # t[2*i]<<1 | shift + mov $S[1],8($tptr) + sbb $carry,$carry # mov cf,$carry + shr \$63,$A0[0] + lea ($j,$A0[1],2),$S[3] # t[2*i+1]<<1 | + shr \$63,$A0[1] + or $A0[0],$S[3] # | t[2*i]>>63 + mov 32($tptr),$A0[0] # t[2*i+2] # prefetch + mov $A0[1],$shift # shift=t[2*i+1]>>63 + mul %rax # a[i]*a[i] + neg $carry # mov $carry,cf + mov 40($tptr),$A0[1] # t[2*i+2+1] # prefetch + adc %rax,$S[2] + mov 16($aptr,$i),%rax # a[i+1] # prefetch + mov $S[2],16($tptr) + adc %rdx,$S[3] + mov $S[3],24($tptr) + sbb $carry,$carry # mov cf,$carry + lea 64($tptr),$tptr + add \$32,$i + jnz .Lsqr4x_shift_n_add + + lea ($shift,$A0[0],2),$S[0] # t[2*i]<<1 | shift + .byte 0x67 + shr \$63,$A0[0] + lea ($j,$A0[1],2),$S[1] # t[2*i+1]<<1 | + shr \$63,$A0[1] + or $A0[0],$S[1] # | t[2*i]>>63 + mov -16($tptr),$A0[0] # t[2*i+2] # prefetch + mov $A0[1],$shift # shift=t[2*i+1]>>63 + mul %rax # a[i]*a[i] + neg $carry # mov $carry,cf + mov -8($tptr),$A0[1] # t[2*i+2+1] # prefetch + adc %rax,$S[0] + mov -8($aptr),%rax # a[i+1] # prefetch + mov $S[0],-32($tptr) + adc %rdx,$S[1] + + lea ($shift,$A0[0],2),$S[2] # t[2*i]<<1|shift + mov $S[1],-24($tptr) + sbb $carry,$carry # mov cf,$carry + shr \$63,$A0[0] + lea ($j,$A0[1],2),$S[3] # t[2*i+1]<<1 | + shr \$63,$A0[1] + or $A0[0],$S[3] # | t[2*i]>>63 + mul %rax # a[i]*a[i] + neg $carry # mov $carry,cf + adc %rax,$S[2] + adc %rdx,$S[3] + mov $S[2],-16($tptr) + mov $S[3],-8($tptr) +___ +} +###################################################################### +# Montgomery reduction part, "word-by-word" algorithm. +# +# This new path is inspired by multiple submissions from Intel, by +# Shay Gueron, Vlad Krasnov, Erdinc Ozturk, James Guilford, +# Vinodh Gopal... +{ +my ($nptr,$tptr,$carry,$m0)=("%rbp","%rdi","%rsi","%rbx"); + +$code.=<<___; + movq %xmm2,$nptr +sqr8x_reduction: + xor %rax,%rax + lea ($nptr,$num,2),%rcx # end of n[] + lea 48+8(%rsp,$num,2),%rdx # end of t[] buffer + mov %rcx,0+8(%rsp) + lea 48+8(%rsp,$num),$tptr # end of initial t[] window + mov %rdx,8+8(%rsp) + neg $num + jmp .L8x_reduction_loop + +.align 32 +.L8x_reduction_loop: + lea ($tptr,$num),$tptr # start of current t[] window + .byte 0x66 + mov 8*0($tptr),$m0 + mov 8*1($tptr),%r9 + mov 8*2($tptr),%r10 + mov 8*3($tptr),%r11 + mov 8*4($tptr),%r12 + mov 8*5($tptr),%r13 + mov 8*6($tptr),%r14 + mov 8*7($tptr),%r15 + mov %rax,(%rdx) # store top-most carry bit + lea 8*8($tptr),$tptr + + .byte 0x67 + mov $m0,%r8 + imulq 32+8(%rsp),$m0 # n0*a[0] + mov 16*0($nptr),%rax # n[0] + mov \$8,%ecx + jmp .L8x_reduce + +.align 32 +.L8x_reduce: + mulq $m0 + mov 16*1($nptr),%rax # n[1] + neg %r8 + mov %rdx,%r8 + adc \$0,%r8 + + mulq $m0 + add %rax,%r9 + mov 16*2($nptr),%rax + adc \$0,%rdx + add %r9,%r8 + mov $m0,48-8+8(%rsp,%rcx,8) # put aside n0*a[i] + mov %rdx,%r9 + adc \$0,%r9 + + mulq $m0 + add %rax,%r10 + mov 16*3($nptr),%rax + adc \$0,%rdx + add %r10,%r9 + mov 32+8(%rsp),$carry # pull n0, borrow $carry + mov %rdx,%r10 + adc \$0,%r10 + + mulq $m0 + add %rax,%r11 + mov 16*4($nptr),%rax + adc \$0,%rdx + imulq %r8,$carry # modulo-scheduled + add %r11,%r10 + mov %rdx,%r11 + adc \$0,%r11 + + mulq $m0 + add %rax,%r12 + mov 16*5($nptr),%rax + adc \$0,%rdx + add %r12,%r11 + mov %rdx,%r12 + adc \$0,%r12 + + mulq $m0 + add %rax,%r13 + mov 16*6($nptr),%rax + adc \$0,%rdx + add %r13,%r12 + mov %rdx,%r13 + adc \$0,%r13 + + mulq $m0 + add %rax,%r14 + mov 16*7($nptr),%rax + adc \$0,%rdx + add %r14,%r13 + mov %rdx,%r14 + adc \$0,%r14 + + mulq $m0 + mov $carry,$m0 # n0*a[i] + add %rax,%r15 + mov 16*0($nptr),%rax # n[0] + adc \$0,%rdx + add %r15,%r14 + mov %rdx,%r15 + adc \$0,%r15 + + dec %ecx + jnz .L8x_reduce + + lea 16*8($nptr),$nptr + xor %rax,%rax + mov 8+8(%rsp),%rdx # pull end of t[] + cmp 0+8(%rsp),$nptr # end of n[]? + jae .L8x_no_tail + + .byte 0x66 + add 8*0($tptr),%r8 + adc 8*1($tptr),%r9 + adc 8*2($tptr),%r10 + adc 8*3($tptr),%r11 + adc 8*4($tptr),%r12 + adc 8*5($tptr),%r13 + adc 8*6($tptr),%r14 + adc 8*7($tptr),%r15 + sbb $carry,$carry # top carry + + mov 48+56+8(%rsp),$m0 # pull n0*a[0] + mov \$8,%ecx + mov 16*0($nptr),%rax + jmp .L8x_tail + +.align 32 +.L8x_tail: + mulq $m0 + add %rax,%r8 + mov 16*1($nptr),%rax + mov %r8,($tptr) # save result + mov %rdx,%r8 + adc \$0,%r8 + + mulq $m0 + add %rax,%r9 + mov 16*2($nptr),%rax + adc \$0,%rdx + add %r9,%r8 + lea 8($tptr),$tptr # $tptr++ + mov %rdx,%r9 + adc \$0,%r9 + + mulq $m0 + add %rax,%r10 + mov 16*3($nptr),%rax + adc \$0,%rdx + add %r10,%r9 + mov %rdx,%r10 + adc \$0,%r10 + + mulq $m0 + add %rax,%r11 + mov 16*4($nptr),%rax + adc \$0,%rdx + add %r11,%r10 + mov %rdx,%r11 + adc \$0,%r11 + + mulq $m0 + add %rax,%r12 + mov 16*5($nptr),%rax + adc \$0,%rdx + add %r12,%r11 + mov %rdx,%r12 + adc \$0,%r12 + + mulq $m0 + add %rax,%r13 + mov 16*6($nptr),%rax + adc \$0,%rdx + add %r13,%r12 + mov %rdx,%r13 + adc \$0,%r13 + + mulq $m0 + add %rax,%r14 + mov 16*7($nptr),%rax + adc \$0,%rdx + add %r14,%r13 + mov %rdx,%r14 + adc \$0,%r14 + + mulq $m0 + mov 48-16+8(%rsp,%rcx,8),$m0# pull n0*a[i] + add %rax,%r15 + adc \$0,%rdx + add %r15,%r14 + mov 16*0($nptr),%rax # pull n[0] + mov %rdx,%r15 + adc \$0,%r15 + + dec %ecx + jnz .L8x_tail + + lea 16*8($nptr),$nptr + mov 8+8(%rsp),%rdx # pull end of t[] + cmp 0+8(%rsp),$nptr # end of n[]? + jae .L8x_tail_done # break out of loop + + mov 48+56+8(%rsp),$m0 # pull n0*a[0] + neg $carry + mov 8*0($nptr),%rax # pull n[0] + adc 8*0($tptr),%r8 + adc 8*1($tptr),%r9 + adc 8*2($tptr),%r10 + adc 8*3($tptr),%r11 + adc 8*4($tptr),%r12 + adc 8*5($tptr),%r13 + adc 8*6($tptr),%r14 + adc 8*7($tptr),%r15 + sbb $carry,$carry # top carry + + mov \$8,%ecx + jmp .L8x_tail + +.align 32 +.L8x_tail_done: + add (%rdx),%r8 # can this overflow? + xor %rax,%rax + + neg $carry +.L8x_no_tail: + adc 8*0($tptr),%r8 + adc 8*1($tptr),%r9 + adc 8*2($tptr),%r10 + adc 8*3($tptr),%r11 + adc 8*4($tptr),%r12 + adc 8*5($tptr),%r13 + adc 8*6($tptr),%r14 + adc 8*7($tptr),%r15 + adc \$0,%rax # top-most carry + mov -16($nptr),%rcx # np[num-1] + xor $carry,$carry + + movq %xmm2,$nptr # restore $nptr + + mov %r8,8*0($tptr) # store top 512 bits + mov %r9,8*1($tptr) + movq %xmm3,$num # $num is %r9, can't be moved upwards + mov %r10,8*2($tptr) + mov %r11,8*3($tptr) + mov %r12,8*4($tptr) + mov %r13,8*5($tptr) + mov %r14,8*6($tptr) + mov %r15,8*7($tptr) + lea 8*8($tptr),$tptr + + cmp %rdx,$tptr # end of t[]? + jb .L8x_reduction_loop +___ +} +############################################################## +# Post-condition, 4x unrolled +# +{ +my ($tptr,$nptr)=("%rbx","%rbp"); +$code.=<<___; + #xor %rsi,%rsi # %rsi was $carry above + sub %r15,%rcx # compare top-most words + lea (%rdi,$num),$tptr # %rdi was $tptr above + adc %rsi,%rsi + mov $num,%rcx + or %rsi,%rax + movq %xmm1,$rptr # restore $rptr + xor \$1,%rax + movq %xmm1,$aptr # prepare for back-to-back call + lea ($nptr,%rax,8),$nptr + sar \$3+2,%rcx # cf=0 + jmp .Lsqr4x_sub + +.align 32 +.Lsqr4x_sub: + .byte 0x66 + mov 8*0($tptr),%r12 + mov 8*1($tptr),%r13 + sbb 16*0($nptr),%r12 + mov 8*2($tptr),%r14 + sbb 16*1($nptr),%r13 + mov 8*3($tptr),%r15 + lea 8*4($tptr),$tptr + sbb 16*2($nptr),%r14 + mov %r12,8*0($rptr) + sbb 16*3($nptr),%r15 + lea 16*4($nptr),$nptr + mov %r13,8*1($rptr) + mov %r14,8*2($rptr) + mov %r15,8*3($rptr) + lea 8*4($rptr),$rptr + + inc %rcx # pass %cf + jnz .Lsqr4x_sub +___ +} +$code.=<<___; + mov $num,%r10 # prepare for back-to-back call + neg $num # restore $num + ret +.size bn_sqr8x_internal,.-bn_sqr8x_internal +___ +{ +$code.=<<___; +.globl bn_from_montgomery +.type bn_from_montgomery,\@abi-omnipotent +.align 32 +bn_from_montgomery: + testl \$7,`($win64?"48(%rsp)":"%r9d")` + jz bn_from_mont8x + xor %eax,%eax + ret +.size bn_from_montgomery,.-bn_from_montgomery + +.type bn_from_mont8x,\@function,6 +.align 32 +bn_from_mont8x: + .byte 0x67 + mov %rsp,%rax + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 +___ +$code.=<<___ if ($win64); + lea -0x28(%rsp),%rsp + movaps %xmm6,(%rsp) + movaps %xmm7,0x10(%rsp) +___ +$code.=<<___; + .byte 0x67 + mov ${num}d,%r10d + shl \$3,${num}d # convert $num to bytes + shl \$3+2,%r10d # 4*$num + neg $num + mov ($n0),$n0 # *n0 + + ############################################################## + # ensure that stack frame doesn't alias with $aptr+4*$num + # modulo 4096, which covers ret[num], am[num] and n[2*num] + # (see bn_exp.c). this is done to allow memory disambiguation + # logic do its magic. + # + lea -64(%rsp,$num,2),%r11 + sub $aptr,%r11 + and \$4095,%r11 + cmp %r11,%r10 + jb .Lfrom_sp_alt + sub %r11,%rsp # align with $aptr + lea -64(%rsp,$num,2),%rsp # alloca(frame+2*$num) + jmp .Lfrom_sp_done + +.align 32 +.Lfrom_sp_alt: + lea 4096-64(,$num,2),%r10 # 4096-frame-2*$num + lea -64(%rsp,$num,2),%rsp # alloca(frame+2*$num) + sub %r10,%r11 + mov \$0,%r10 + cmovc %r10,%r11 + sub %r11,%rsp +.Lfrom_sp_done: + and \$-64,%rsp + mov $num,%r10 + neg $num + + ############################################################## + # Stack layout + # + # +0 saved $num, used in reduction section + # +8 &t[2*$num], used in reduction section + # +32 saved *n0 + # +40 saved %rsp + # +48 t[2*$num] + # + mov $n0, 32(%rsp) + mov %rax, 40(%rsp) # save original %rsp +.Lfrom_body: + mov $num,%r11 + lea 48(%rsp),%rax + pxor %xmm0,%xmm0 + jmp .Lmul_by_1 + +.align 32 +.Lmul_by_1: + movdqu ($aptr),%xmm1 + movdqu 16($aptr),%xmm2 + movdqu 32($aptr),%xmm3 + movdqa %xmm0,(%rax,$num) + movdqu 48($aptr),%xmm4 + movdqa %xmm0,16(%rax,$num) + .byte 0x48,0x8d,0xb6,0x40,0x00,0x00,0x00 # lea 64($aptr),$aptr + movdqa %xmm1,(%rax) + movdqa %xmm0,32(%rax,$num) + movdqa %xmm2,16(%rax) + movdqa %xmm0,48(%rax,$num) + movdqa %xmm3,32(%rax) + movdqa %xmm4,48(%rax) + lea 64(%rax),%rax + sub \$64,%r11 + jnz .Lmul_by_1 + + movq $rptr,%xmm1 + movq $nptr,%xmm2 + .byte 0x67 + mov $nptr,%rbp + movq %r10, %xmm3 # -num +___ +$code.=<<___ if ($addx); + mov OPENSSL_ia32cap_P+8(%rip),%r11d + and \$0x80100,%r11d + cmp \$0x80100,%r11d + jne .Lfrom_mont_nox + + lea (%rax,$num),$rptr + call sqrx8x_reduction + + pxor %xmm0,%xmm0 + lea 48(%rsp),%rax + mov 40(%rsp),%rsi # restore %rsp + jmp .Lfrom_mont_zero + +.align 32 +.Lfrom_mont_nox: +___ +$code.=<<___; + call sqr8x_reduction + + pxor %xmm0,%xmm0 + lea 48(%rsp),%rax + mov 40(%rsp),%rsi # restore %rsp + jmp .Lfrom_mont_zero + +.align 32 +.Lfrom_mont_zero: + movdqa %xmm0,16*0(%rax) + movdqa %xmm0,16*1(%rax) + movdqa %xmm0,16*2(%rax) + movdqa %xmm0,16*3(%rax) + lea 16*4(%rax),%rax + sub \$32,$num + jnz .Lfrom_mont_zero + + mov \$1,%rax + mov -48(%rsi),%r15 + mov -40(%rsi),%r14 + mov -32(%rsi),%r13 + mov -24(%rsi),%r12 + mov -16(%rsi),%rbp + mov -8(%rsi),%rbx + lea (%rsi),%rsp +.Lfrom_epilogue: + ret +.size bn_from_mont8x,.-bn_from_mont8x +___ +} +}}} + +if ($addx) {{{ +my $bp="%rdx"; # restore original value + +$code.=<<___; +.type bn_mulx4x_mont_gather5,\@function,6 +.align 32 +bn_mulx4x_mont_gather5: +.Lmulx4x_enter: + .byte 0x67 + mov %rsp,%rax + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 +___ +$code.=<<___ if ($win64); + lea -0x28(%rsp),%rsp + movaps %xmm6,(%rsp) + movaps %xmm7,0x10(%rsp) +___ +$code.=<<___; + .byte 0x67 + mov ${num}d,%r10d + shl \$3,${num}d # convert $num to bytes + shl \$3+2,%r10d # 4*$num + neg $num # -$num + mov ($n0),$n0 # *n0 + + ############################################################## + # ensure that stack frame doesn't alias with $aptr+4*$num + # modulo 4096, which covers a[num], ret[num] and n[2*num] + # (see bn_exp.c). this is done to allow memory disambiguation + # logic do its magic. [excessive frame is allocated in order + # to allow bn_from_mont8x to clear it.] + # + lea -64(%rsp,$num,2),%r11 + sub $ap,%r11 + and \$4095,%r11 + cmp %r11,%r10 + jb .Lmulx4xsp_alt + sub %r11,%rsp # align with $aptr + lea -64(%rsp,$num,2),%rsp # alloca(frame+$num) + jmp .Lmulx4xsp_done + +.align 32 +.Lmulx4xsp_alt: + lea 4096-64(,$num,2),%r10 # 4096-frame-$num + lea -64(%rsp,$num,2),%rsp # alloca(frame+$num) + sub %r10,%r11 + mov \$0,%r10 + cmovc %r10,%r11 + sub %r11,%rsp +.Lmulx4xsp_done: + and \$-64,%rsp # ensure alignment + ############################################################## + # Stack layout + # +0 -num + # +8 off-loaded &b[i] + # +16 end of b[num] + # +24 inner counter + # +32 saved n0 + # +40 saved %rsp + # +48 + # +56 saved rp + # +64 tmp[num+1] + # + mov $n0, 32(%rsp) # save *n0 + mov %rax,40(%rsp) # save original %rsp +.Lmulx4x_body: + call mulx4x_internal + + mov 40(%rsp),%rsi # restore %rsp + mov \$1,%rax +___ +$code.=<<___ if ($win64); + movaps -88(%rsi),%xmm6 + movaps -72(%rsi),%xmm7 +___ +$code.=<<___; + mov -48(%rsi),%r15 + mov -40(%rsi),%r14 + mov -32(%rsi),%r13 + mov -24(%rsi),%r12 + mov -16(%rsi),%rbp + mov -8(%rsi),%rbx + lea (%rsi),%rsp +.Lmulx4x_epilogue: + ret +.size bn_mulx4x_mont_gather5,.-bn_mulx4x_mont_gather5 + +.type mulx4x_internal,\@abi-omnipotent +.align 32 +mulx4x_internal: + .byte 0x4c,0x89,0x8c,0x24,0x08,0x00,0x00,0x00 # mov $num,8(%rsp) # save -$num + .byte 0x67 + neg $num # restore $num + shl \$5,$num + lea 256($bp,$num),%r13 + shr \$5+5,$num + mov `($win64?56:8)`(%rax),%r10d # load 7th argument + sub \$1,$num + mov %r13,16+8(%rsp) # end of b[num] + mov $num,24+8(%rsp) # inner counter + mov $rp, 56+8(%rsp) # save $rp +___ +my ($aptr, $bptr, $nptr, $tptr, $mi, $bi, $zero, $num)= + ("%rsi","%rdi","%rcx","%rbx","%r8","%r9","%rbp","%rax"); +my $rptr=$bptr; +my $STRIDE=2**5*8; # 5 is "window size" +my $N=$STRIDE/4; # should match cache line size +$code.=<<___; + mov %r10,%r11 + shr \$`log($N/8)/log(2)`,%r10 + and \$`$N/8-1`,%r11 + not %r10 + lea .Lmagic_masks(%rip),%rax + and \$`2**5/($N/8)-1`,%r10 # 5 is "window size" + lea 96($bp,%r11,8),$bptr # pointer within 1st cache line + movq 0(%rax,%r10,8),%xmm4 # set of masks denoting which + movq 8(%rax,%r10,8),%xmm5 # cache line contains element + add \$7,%r11 + movq 16(%rax,%r10,8),%xmm6 # denoted by 7th argument + movq 24(%rax,%r10,8),%xmm7 + and \$7,%r11 + + movq `0*$STRIDE/4-96`($bptr),%xmm0 + lea $STRIDE($bptr),$tptr # borrow $tptr + movq `1*$STRIDE/4-96`($bptr),%xmm1 + pand %xmm4,%xmm0 + movq `2*$STRIDE/4-96`($bptr),%xmm2 + pand %xmm5,%xmm1 + movq `3*$STRIDE/4-96`($bptr),%xmm3 + pand %xmm6,%xmm2 + por %xmm1,%xmm0 + movq `0*$STRIDE/4-96`($tptr),%xmm1 + pand %xmm7,%xmm3 + por %xmm2,%xmm0 + movq `1*$STRIDE/4-96`($tptr),%xmm2 + por %xmm3,%xmm0 + .byte 0x67,0x67 + pand %xmm4,%xmm1 + movq `2*$STRIDE/4-96`($tptr),%xmm3 + + movq %xmm0,%rdx # bp[0] + movq `3*$STRIDE/4-96`($tptr),%xmm0 + lea 2*$STRIDE($bptr),$bptr # next &b[i] + pand %xmm5,%xmm2 + .byte 0x67,0x67 + pand %xmm6,%xmm3 + ############################################################## + # $tptr is chosen so that writing to top-most element of the + # vector occurs just "above" references to powers table, + # "above" modulo cache-line size, which effectively precludes + # possibility of memory disambiguation logic failure when + # accessing the table. + # + lea 64+8*4+8(%rsp,%r11,8),$tptr + + mov %rdx,$bi + mulx 0*8($aptr),$mi,%rax # a[0]*b[0] + mulx 1*8($aptr),%r11,%r12 # a[1]*b[0] + add %rax,%r11 + mulx 2*8($aptr),%rax,%r13 # ... + adc %rax,%r12 + adc \$0,%r13 + mulx 3*8($aptr),%rax,%r14 + + mov $mi,%r15 + imulq 32+8(%rsp),$mi # "t[0]"*n0 + xor $zero,$zero # cf=0, of=0 + mov $mi,%rdx + + por %xmm2,%xmm1 + pand %xmm7,%xmm0 + por %xmm3,%xmm1 + mov $bptr,8+8(%rsp) # off-load &b[i] + por %xmm1,%xmm0 + + .byte 0x48,0x8d,0xb6,0x20,0x00,0x00,0x00 # lea 4*8($aptr),$aptr + adcx %rax,%r13 + adcx $zero,%r14 # cf=0 + + mulx 0*16($nptr),%rax,%r10 + adcx %rax,%r15 # discarded + adox %r11,%r10 + mulx 1*16($nptr),%rax,%r11 + adcx %rax,%r10 + adox %r12,%r11 + mulx 2*16($nptr),%rax,%r12 + mov 24+8(%rsp),$bptr # counter value + .byte 0x66 + mov %r10,-8*4($tptr) + adcx %rax,%r11 + adox %r13,%r12 + mulx 3*16($nptr),%rax,%r15 + .byte 0x67,0x67 + mov $bi,%rdx + mov %r11,-8*3($tptr) + adcx %rax,%r12 + adox $zero,%r15 # of=0 + .byte 0x48,0x8d,0x89,0x40,0x00,0x00,0x00 # lea 4*16($nptr),$nptr + mov %r12,-8*2($tptr) + #jmp .Lmulx4x_1st + +.align 32 +.Lmulx4x_1st: + adcx $zero,%r15 # cf=0, modulo-scheduled + mulx 0*8($aptr),%r10,%rax # a[4]*b[0] + adcx %r14,%r10 + mulx 1*8($aptr),%r11,%r14 # a[5]*b[0] + adcx %rax,%r11 + mulx 2*8($aptr),%r12,%rax # ... + adcx %r14,%r12 + mulx 3*8($aptr),%r13,%r14 + .byte 0x67,0x67 + mov $mi,%rdx + adcx %rax,%r13 + adcx $zero,%r14 # cf=0 + lea 4*8($aptr),$aptr + lea 4*8($tptr),$tptr + + adox %r15,%r10 + mulx 0*16($nptr),%rax,%r15 + adcx %rax,%r10 + adox %r15,%r11 + mulx 1*16($nptr),%rax,%r15 + adcx %rax,%r11 + adox %r15,%r12 + mulx 2*16($nptr),%rax,%r15 + mov %r10,-5*8($tptr) + adcx %rax,%r12 + mov %r11,-4*8($tptr) + adox %r15,%r13 + mulx 3*16($nptr),%rax,%r15 + mov $bi,%rdx + mov %r12,-3*8($tptr) + adcx %rax,%r13 + adox $zero,%r15 + lea 4*16($nptr),$nptr + mov %r13,-2*8($tptr) + + dec $bptr # of=0, pass cf + jnz .Lmulx4x_1st + + mov 8(%rsp),$num # load -num + movq %xmm0,%rdx # bp[1] + adc $zero,%r15 # modulo-scheduled + lea ($aptr,$num),$aptr # rewind $aptr + add %r15,%r14 + mov 8+8(%rsp),$bptr # re-load &b[i] + adc $zero,$zero # top-most carry + mov %r14,-1*8($tptr) + jmp .Lmulx4x_outer + +.align 32 +.Lmulx4x_outer: + mov $zero,($tptr) # save top-most carry + lea 4*8($tptr,$num),$tptr # rewind $tptr + mulx 0*8($aptr),$mi,%r11 # a[0]*b[i] + xor $zero,$zero # cf=0, of=0 + mov %rdx,$bi + mulx 1*8($aptr),%r14,%r12 # a[1]*b[i] + adox -4*8($tptr),$mi # +t[0] + adcx %r14,%r11 + mulx 2*8($aptr),%r15,%r13 # ... + adox -3*8($tptr),%r11 + adcx %r15,%r12 + mulx 3*8($aptr),%rdx,%r14 + adox -2*8($tptr),%r12 + adcx %rdx,%r13 + lea ($nptr,$num,2),$nptr # rewind $nptr + lea 4*8($aptr),$aptr + adox -1*8($tptr),%r13 + adcx $zero,%r14 + adox $zero,%r14 + + .byte 0x67 + mov $mi,%r15 + imulq 32+8(%rsp),$mi # "t[0]"*n0 + + movq `0*$STRIDE/4-96`($bptr),%xmm0 + .byte 0x67,0x67 + mov $mi,%rdx + movq `1*$STRIDE/4-96`($bptr),%xmm1 + .byte 0x67 + pand %xmm4,%xmm0 + movq `2*$STRIDE/4-96`($bptr),%xmm2 + .byte 0x67 + pand %xmm5,%xmm1 + movq `3*$STRIDE/4-96`($bptr),%xmm3 + add \$$STRIDE,$bptr # next &b[i] + .byte 0x67 + pand %xmm6,%xmm2 + por %xmm1,%xmm0 + pand %xmm7,%xmm3 + xor $zero,$zero # cf=0, of=0 + mov $bptr,8+8(%rsp) # off-load &b[i] + + mulx 0*16($nptr),%rax,%r10 + adcx %rax,%r15 # discarded + adox %r11,%r10 + mulx 1*16($nptr),%rax,%r11 + adcx %rax,%r10 + adox %r12,%r11 + mulx 2*16($nptr),%rax,%r12 + adcx %rax,%r11 + adox %r13,%r12 + mulx 3*16($nptr),%rax,%r15 + mov $bi,%rdx + por %xmm2,%xmm0 + mov 24+8(%rsp),$bptr # counter value + mov %r10,-8*4($tptr) + por %xmm3,%xmm0 + adcx %rax,%r12 + mov %r11,-8*3($tptr) + adox $zero,%r15 # of=0 + mov %r12,-8*2($tptr) + lea 4*16($nptr),$nptr + jmp .Lmulx4x_inner + +.align 32 +.Lmulx4x_inner: + mulx 0*8($aptr),%r10,%rax # a[4]*b[i] + adcx $zero,%r15 # cf=0, modulo-scheduled + adox %r14,%r10 + mulx 1*8($aptr),%r11,%r14 # a[5]*b[i] + adcx 0*8($tptr),%r10 + adox %rax,%r11 + mulx 2*8($aptr),%r12,%rax # ... + adcx 1*8($tptr),%r11 + adox %r14,%r12 + mulx 3*8($aptr),%r13,%r14 + mov $mi,%rdx + adcx 2*8($tptr),%r12 + adox %rax,%r13 + adcx 3*8($tptr),%r13 + adox $zero,%r14 # of=0 + lea 4*8($aptr),$aptr + lea 4*8($tptr),$tptr + adcx $zero,%r14 # cf=0 + + adox %r15,%r10 + mulx 0*16($nptr),%rax,%r15 + adcx %rax,%r10 + adox %r15,%r11 + mulx 1*16($nptr),%rax,%r15 + adcx %rax,%r11 + adox %r15,%r12 + mulx 2*16($nptr),%rax,%r15 + mov %r10,-5*8($tptr) + adcx %rax,%r12 + adox %r15,%r13 + mov %r11,-4*8($tptr) + mulx 3*16($nptr),%rax,%r15 + mov $bi,%rdx + lea 4*16($nptr),$nptr + mov %r12,-3*8($tptr) + adcx %rax,%r13 + adox $zero,%r15 + mov %r13,-2*8($tptr) + + dec $bptr # of=0, pass cf + jnz .Lmulx4x_inner + + mov 0+8(%rsp),$num # load -num + movq %xmm0,%rdx # bp[i+1] + adc $zero,%r15 # modulo-scheduled + sub 0*8($tptr),$bptr # pull top-most carry to %cf + mov 8+8(%rsp),$bptr # re-load &b[i] + mov 16+8(%rsp),%r10 + adc %r15,%r14 + lea ($aptr,$num),$aptr # rewind $aptr + adc $zero,$zero # top-most carry + mov %r14,-1*8($tptr) + + cmp %r10,$bptr + jb .Lmulx4x_outer + + mov -16($nptr),%r10 + xor %r15,%r15 + sub %r14,%r10 # compare top-most words + adc %r15,%r15 + or %r15,$zero + xor \$1,$zero + lea ($tptr,$num),%rdi # rewind $tptr + lea ($nptr,$num,2),$nptr # rewind $nptr + .byte 0x67,0x67 + sar \$3+2,$num # cf=0 + lea ($nptr,$zero,8),%rbp + mov 56+8(%rsp),%rdx # restore rp + mov $num,%rcx + jmp .Lsqrx4x_sub # common post-condition +.size mulx4x_internal,.-mulx4x_internal +___ +} { +###################################################################### +# void bn_power5( +my $rptr="%rdi"; # BN_ULONG *rptr, +my $aptr="%rsi"; # const BN_ULONG *aptr, +my $bptr="%rdx"; # const void *table, +my $nptr="%rcx"; # const BN_ULONG *nptr, +my $n0 ="%r8"; # const BN_ULONG *n0); +my $num ="%r9"; # int num, has to be divisible by 8 + # int pwr); + +my ($i,$j,$tptr)=("%rbp","%rcx",$rptr); +my @A0=("%r10","%r11"); +my @A1=("%r12","%r13"); +my ($a0,$a1,$ai)=("%r14","%r15","%rbx"); + +$code.=<<___; +.type bn_powerx5,\@function,6 +.align 32 +bn_powerx5: +.Lpowerx5_enter: + .byte 0x67 + mov %rsp,%rax + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 +___ +$code.=<<___ if ($win64); + lea -0x28(%rsp),%rsp + movaps %xmm6,(%rsp) + movaps %xmm7,0x10(%rsp) +___ +$code.=<<___; + .byte 0x67 + mov ${num}d,%r10d + shl \$3,${num}d # convert $num to bytes + shl \$3+2,%r10d # 4*$num + neg $num + mov ($n0),$n0 # *n0 + + ############################################################## + # ensure that stack frame doesn't alias with $aptr+4*$num + # modulo 4096, which covers ret[num], am[num] and n[2*num] + # (see bn_exp.c). this is done to allow memory disambiguation + # logic do its magic. + # + lea -64(%rsp,$num,2),%r11 + sub $aptr,%r11 + and \$4095,%r11 + cmp %r11,%r10 + jb .Lpwrx_sp_alt + sub %r11,%rsp # align with $aptr + lea -64(%rsp,$num,2),%rsp # alloca(frame+2*$num) + jmp .Lpwrx_sp_done + +.align 32 +.Lpwrx_sp_alt: + lea 4096-64(,$num,2),%r10 # 4096-frame-2*$num + lea -64(%rsp,$num,2),%rsp # alloca(frame+2*$num) + sub %r10,%r11 + mov \$0,%r10 + cmovc %r10,%r11 + sub %r11,%rsp +.Lpwrx_sp_done: + and \$-64,%rsp + mov $num,%r10 + neg $num + + ############################################################## + # Stack layout + # + # +0 saved $num, used in reduction section + # +8 &t[2*$num], used in reduction section + # +16 intermediate carry bit + # +24 top-most carry bit, used in reduction section + # +32 saved *n0 + # +40 saved %rsp + # +48 t[2*$num] + # + pxor %xmm0,%xmm0 + movq $rptr,%xmm1 # save $rptr + movq $nptr,%xmm2 # save $nptr + movq %r10, %xmm3 # -$num + movq $bptr,%xmm4 + mov $n0, 32(%rsp) + mov %rax, 40(%rsp) # save original %rsp +.Lpowerx5_body: + + call __bn_sqrx8x_internal + call __bn_sqrx8x_internal + call __bn_sqrx8x_internal + call __bn_sqrx8x_internal + call __bn_sqrx8x_internal + + mov %r10,$num # -num + mov $aptr,$rptr + movq %xmm2,$nptr + movq %xmm4,$bptr + mov 40(%rsp),%rax + + call mulx4x_internal + + mov 40(%rsp),%rsi # restore %rsp + mov \$1,%rax +___ +$code.=<<___ if ($win64); + movaps -88(%rsi),%xmm6 + movaps -72(%rsi),%xmm7 +___ +$code.=<<___; + mov -48(%rsi),%r15 + mov -40(%rsi),%r14 + mov -32(%rsi),%r13 + mov -24(%rsi),%r12 + mov -16(%rsi),%rbp + mov -8(%rsi),%rbx + lea (%rsi),%rsp +.Lpowerx5_epilogue: + ret +.size bn_powerx5,.-bn_powerx5 + +.globl bn_sqrx8x_internal +.hidden bn_sqrx8x_internal +.type bn_sqrx8x_internal,\@abi-omnipotent +.align 32 +bn_sqrx8x_internal: +__bn_sqrx8x_internal: + ################################################################## + # Squaring part: + # + # a) multiply-n-add everything but a[i]*a[i]; + # b) shift result of a) by 1 to the left and accumulate + # a[i]*a[i] products; + # + ################################################################## + # a[7]a[7]a[6]a[6]a[5]a[5]a[4]a[4]a[3]a[3]a[2]a[2]a[1]a[1]a[0]a[0] + # a[1]a[0] + # a[2]a[0] + # a[3]a[0] + # a[2]a[1] + # a[3]a[1] + # a[3]a[2] + # + # a[4]a[0] + # a[5]a[0] + # a[6]a[0] + # a[7]a[0] + # a[4]a[1] + # a[5]a[1] + # a[6]a[1] + # a[7]a[1] + # a[4]a[2] + # a[5]a[2] + # a[6]a[2] + # a[7]a[2] + # a[4]a[3] + # a[5]a[3] + # a[6]a[3] + # a[7]a[3] + # + # a[5]a[4] + # a[6]a[4] + # a[7]a[4] + # a[6]a[5] + # a[7]a[5] + # a[7]a[6] + # a[7]a[7]a[6]a[6]a[5]a[5]a[4]a[4]a[3]a[3]a[2]a[2]a[1]a[1]a[0]a[0] +___ +{ +my ($zero,$carry)=("%rbp","%rcx"); +my $aaptr=$zero; +$code.=<<___; + lea 48+8(%rsp),$tptr + lea ($aptr,$num),$aaptr + mov $num,0+8(%rsp) # save $num + mov $aaptr,8+8(%rsp) # save end of $aptr + jmp .Lsqr8x_zero_start + +.align 32 +.byte 0x66,0x66,0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00 +.Lsqrx8x_zero: + .byte 0x3e + movdqa %xmm0,0*8($tptr) + movdqa %xmm0,2*8($tptr) + movdqa %xmm0,4*8($tptr) + movdqa %xmm0,6*8($tptr) +.Lsqr8x_zero_start: # aligned at 32 + movdqa %xmm0,8*8($tptr) + movdqa %xmm0,10*8($tptr) + movdqa %xmm0,12*8($tptr) + movdqa %xmm0,14*8($tptr) + lea 16*8($tptr),$tptr + sub \$64,$num + jnz .Lsqrx8x_zero + + mov 0*8($aptr),%rdx # a[0], modulo-scheduled + #xor %r9,%r9 # t[1], ex-$num, zero already + xor %r10,%r10 + xor %r11,%r11 + xor %r12,%r12 + xor %r13,%r13 + xor %r14,%r14 + xor %r15,%r15 + lea 48+8(%rsp),$tptr + xor $zero,$zero # cf=0, cf=0 + jmp .Lsqrx8x_outer_loop + +.align 32 +.Lsqrx8x_outer_loop: + mulx 1*8($aptr),%r8,%rax # a[1]*a[0] + adcx %r9,%r8 # a[1]*a[0]+=t[1] + adox %rax,%r10 + mulx 2*8($aptr),%r9,%rax # a[2]*a[0] + adcx %r10,%r9 + adox %rax,%r11 + .byte 0xc4,0xe2,0xab,0xf6,0x86,0x18,0x00,0x00,0x00 # mulx 3*8($aptr),%r10,%rax # ... + adcx %r11,%r10 + adox %rax,%r12 + .byte 0xc4,0xe2,0xa3,0xf6,0x86,0x20,0x00,0x00,0x00 # mulx 4*8($aptr),%r11,%rax + adcx %r12,%r11 + adox %rax,%r13 + mulx 5*8($aptr),%r12,%rax + adcx %r13,%r12 + adox %rax,%r14 + mulx 6*8($aptr),%r13,%rax + adcx %r14,%r13 + adox %r15,%rax + mulx 7*8($aptr),%r14,%r15 + mov 1*8($aptr),%rdx # a[1] + adcx %rax,%r14 + adox $zero,%r15 + adc 8*8($tptr),%r15 + mov %r8,1*8($tptr) # t[1] + mov %r9,2*8($tptr) # t[2] + sbb $carry,$carry # mov %cf,$carry + xor $zero,$zero # cf=0, of=0 + + + mulx 2*8($aptr),%r8,%rbx # a[2]*a[1] + mulx 3*8($aptr),%r9,%rax # a[3]*a[1] + adcx %r10,%r8 + adox %rbx,%r9 + mulx 4*8($aptr),%r10,%rbx # ... + adcx %r11,%r9 + adox %rax,%r10 + .byte 0xc4,0xe2,0xa3,0xf6,0x86,0x28,0x00,0x00,0x00 # mulx 5*8($aptr),%r11,%rax + adcx %r12,%r10 + adox %rbx,%r11 + .byte 0xc4,0xe2,0x9b,0xf6,0x9e,0x30,0x00,0x00,0x00 # mulx 6*8($aptr),%r12,%rbx + adcx %r13,%r11 + adox %r14,%r12 + .byte 0xc4,0x62,0x93,0xf6,0xb6,0x38,0x00,0x00,0x00 # mulx 7*8($aptr),%r13,%r14 + mov 2*8($aptr),%rdx # a[2] + adcx %rax,%r12 + adox %rbx,%r13 + adcx %r15,%r13 + adox $zero,%r14 # of=0 + adcx $zero,%r14 # cf=0 + + mov %r8,3*8($tptr) # t[3] + mov %r9,4*8($tptr) # t[4] + + mulx 3*8($aptr),%r8,%rbx # a[3]*a[2] + mulx 4*8($aptr),%r9,%rax # a[4]*a[2] + adcx %r10,%r8 + adox %rbx,%r9 + mulx 5*8($aptr),%r10,%rbx # ... + adcx %r11,%r9 + adox %rax,%r10 + .byte 0xc4,0xe2,0xa3,0xf6,0x86,0x30,0x00,0x00,0x00 # mulx 6*8($aptr),%r11,%rax + adcx %r12,%r10 + adox %r13,%r11 + .byte 0xc4,0x62,0x9b,0xf6,0xae,0x38,0x00,0x00,0x00 # mulx 7*8($aptr),%r12,%r13 + .byte 0x3e + mov 3*8($aptr),%rdx # a[3] + adcx %rbx,%r11 + adox %rax,%r12 + adcx %r14,%r12 + mov %r8,5*8($tptr) # t[5] + mov %r9,6*8($tptr) # t[6] + mulx 4*8($aptr),%r8,%rax # a[4]*a[3] + adox $zero,%r13 # of=0 + adcx $zero,%r13 # cf=0 + + mulx 5*8($aptr),%r9,%rbx # a[5]*a[3] + adcx %r10,%r8 + adox %rax,%r9 + mulx 6*8($aptr),%r10,%rax # ... + adcx %r11,%r9 + adox %r12,%r10 + mulx 7*8($aptr),%r11,%r12 + mov 4*8($aptr),%rdx # a[4] + mov 5*8($aptr),%r14 # a[5] + adcx %rbx,%r10 + adox %rax,%r11 + mov 6*8($aptr),%r15 # a[6] + adcx %r13,%r11 + adox $zero,%r12 # of=0 + adcx $zero,%r12 # cf=0 + + mov %r8,7*8($tptr) # t[7] + mov %r9,8*8($tptr) # t[8] + + mulx %r14,%r9,%rax # a[5]*a[4] + mov 7*8($aptr),%r8 # a[7] + adcx %r10,%r9 + mulx %r15,%r10,%rbx # a[6]*a[4] + adox %rax,%r10 + adcx %r11,%r10 + mulx %r8,%r11,%rax # a[7]*a[4] + mov %r14,%rdx # a[5] + adox %rbx,%r11 + adcx %r12,%r11 + #adox $zero,%rax # of=0 + adcx $zero,%rax # cf=0 + + mulx %r15,%r14,%rbx # a[6]*a[5] + mulx %r8,%r12,%r13 # a[7]*a[5] + mov %r15,%rdx # a[6] + lea 8*8($aptr),$aptr + adcx %r14,%r11 + adox %rbx,%r12 + adcx %rax,%r12 + adox $zero,%r13 + + .byte 0x67,0x67 + mulx %r8,%r8,%r14 # a[7]*a[6] + adcx %r8,%r13 + adcx $zero,%r14 + + cmp 8+8(%rsp),$aptr + je .Lsqrx8x_outer_break + + neg $carry # mov $carry,%cf + mov \$-8,%rcx + mov $zero,%r15 + mov 8*8($tptr),%r8 + adcx 9*8($tptr),%r9 # +=t[9] + adcx 10*8($tptr),%r10 # ... + adcx 11*8($tptr),%r11 + adc 12*8($tptr),%r12 + adc 13*8($tptr),%r13 + adc 14*8($tptr),%r14 + adc 15*8($tptr),%r15 + lea ($aptr),$aaptr + lea 2*64($tptr),$tptr + sbb %rax,%rax # mov %cf,$carry + + mov -64($aptr),%rdx # a[0] + mov %rax,16+8(%rsp) # offload $carry + mov $tptr,24+8(%rsp) + + #lea 8*8($tptr),$tptr # see 2*8*8($tptr) above + xor %eax,%eax # cf=0, of=0 + jmp .Lsqrx8x_loop + +.align 32 +.Lsqrx8x_loop: + mov %r8,%rbx + mulx 0*8($aaptr),%rax,%r8 # a[8]*a[i] + adcx %rax,%rbx # +=t[8] + adox %r9,%r8 + + mulx 1*8($aaptr),%rax,%r9 # ... + adcx %rax,%r8 + adox %r10,%r9 + + mulx 2*8($aaptr),%rax,%r10 + adcx %rax,%r9 + adox %r11,%r10 + + mulx 3*8($aaptr),%rax,%r11 + adcx %rax,%r10 + adox %r12,%r11 + + .byte 0xc4,0x62,0xfb,0xf6,0xa5,0x20,0x00,0x00,0x00 # mulx 4*8($aaptr),%rax,%r12 + adcx %rax,%r11 + adox %r13,%r12 + + mulx 5*8($aaptr),%rax,%r13 + adcx %rax,%r12 + adox %r14,%r13 + + mulx 6*8($aaptr),%rax,%r14 + mov %rbx,($tptr,%rcx,8) # store t[8+i] + mov \$0,%ebx + adcx %rax,%r13 + adox %r15,%r14 + + .byte 0xc4,0x62,0xfb,0xf6,0xbd,0x38,0x00,0x00,0x00 # mulx 7*8($aaptr),%rax,%r15 + mov 8($aptr,%rcx,8),%rdx # a[i] + adcx %rax,%r14 + adox %rbx,%r15 # %rbx is 0, of=0 + adcx %rbx,%r15 # cf=0 + + .byte 0x67 + inc %rcx # of=0 + jnz .Lsqrx8x_loop + + lea 8*8($aaptr),$aaptr + mov \$-8,%rcx + cmp 8+8(%rsp),$aaptr # done? + je .Lsqrx8x_break + + sub 16+8(%rsp),%rbx # mov 16(%rsp),%cf + .byte 0x66 + mov -64($aptr),%rdx + adcx 0*8($tptr),%r8 + adcx 1*8($tptr),%r9 + adc 2*8($tptr),%r10 + adc 3*8($tptr),%r11 + adc 4*8($tptr),%r12 + adc 5*8($tptr),%r13 + adc 6*8($tptr),%r14 + adc 7*8($tptr),%r15 + lea 8*8($tptr),$tptr + .byte 0x67 + sbb %rax,%rax # mov %cf,%rax + xor %ebx,%ebx # cf=0, of=0 + mov %rax,16+8(%rsp) # offload carry + jmp .Lsqrx8x_loop + +.align 32 +.Lsqrx8x_break: + sub 16+8(%rsp),%r8 # consume last carry + mov 24+8(%rsp),$carry # initial $tptr, borrow $carry + mov 0*8($aptr),%rdx # a[8], modulo-scheduled + xor %ebp,%ebp # xor $zero,$zero + mov %r8,0*8($tptr) + cmp $carry,$tptr # cf=0, of=0 + je .Lsqrx8x_outer_loop + + mov %r9,1*8($tptr) + mov 1*8($carry),%r9 + mov %r10,2*8($tptr) + mov 2*8($carry),%r10 + mov %r11,3*8($tptr) + mov 3*8($carry),%r11 + mov %r12,4*8($tptr) + mov 4*8($carry),%r12 + mov %r13,5*8($tptr) + mov 5*8($carry),%r13 + mov %r14,6*8($tptr) + mov 6*8($carry),%r14 + mov %r15,7*8($tptr) + mov 7*8($carry),%r15 + mov $carry,$tptr + jmp .Lsqrx8x_outer_loop + +.align 32 +.Lsqrx8x_outer_break: + mov %r9,9*8($tptr) # t[9] + movq %xmm3,%rcx # -$num + mov %r10,10*8($tptr) # ... + mov %r11,11*8($tptr) + mov %r12,12*8($tptr) + mov %r13,13*8($tptr) + mov %r14,14*8($tptr) +___ +} { +my $i="%rcx"; +$code.=<<___; + lea 48+8(%rsp),$tptr + mov ($aptr,$i),%rdx # a[0] + + mov 8($tptr),$A0[1] # t[1] + xor $A0[0],$A0[0] # t[0], of=0, cf=0 + mov 0+8(%rsp),$num # restore $num + adox $A0[1],$A0[1] + mov 16($tptr),$A1[0] # t[2] # prefetch + mov 24($tptr),$A1[1] # t[3] # prefetch + #jmp .Lsqrx4x_shift_n_add # happens to be aligned + +.align 32 +.Lsqrx4x_shift_n_add: + mulx %rdx,%rax,%rbx + adox $A1[0],$A1[0] + adcx $A0[0],%rax + .byte 0x48,0x8b,0x94,0x0e,0x08,0x00,0x00,0x00 # mov 8($aptr,$i),%rdx # a[i+1] # prefetch + .byte 0x4c,0x8b,0x97,0x20,0x00,0x00,0x00 # mov 32($tptr),$A0[0] # t[2*i+4] # prefetch + adox $A1[1],$A1[1] + adcx $A0[1],%rbx + mov 40($tptr),$A0[1] # t[2*i+4+1] # prefetch + mov %rax,0($tptr) + mov %rbx,8($tptr) + + mulx %rdx,%rax,%rbx + adox $A0[0],$A0[0] + adcx $A1[0],%rax + mov 16($aptr,$i),%rdx # a[i+2] # prefetch + mov 48($tptr),$A1[0] # t[2*i+6] # prefetch + adox $A0[1],$A0[1] + adcx $A1[1],%rbx + mov 56($tptr),$A1[1] # t[2*i+6+1] # prefetch + mov %rax,16($tptr) + mov %rbx,24($tptr) + + mulx %rdx,%rax,%rbx + adox $A1[0],$A1[0] + adcx $A0[0],%rax + mov 24($aptr,$i),%rdx # a[i+3] # prefetch + lea 32($i),$i + mov 64($tptr),$A0[0] # t[2*i+8] # prefetch + adox $A1[1],$A1[1] + adcx $A0[1],%rbx + mov 72($tptr),$A0[1] # t[2*i+8+1] # prefetch + mov %rax,32($tptr) + mov %rbx,40($tptr) + + mulx %rdx,%rax,%rbx + adox $A0[0],$A0[0] + adcx $A1[0],%rax + jrcxz .Lsqrx4x_shift_n_add_break + .byte 0x48,0x8b,0x94,0x0e,0x00,0x00,0x00,0x00 # mov 0($aptr,$i),%rdx # a[i+4] # prefetch + adox $A0[1],$A0[1] + adcx $A1[1],%rbx + mov 80($tptr),$A1[0] # t[2*i+10] # prefetch + mov 88($tptr),$A1[1] # t[2*i+10+1] # prefetch + mov %rax,48($tptr) + mov %rbx,56($tptr) + lea 64($tptr),$tptr + nop + jmp .Lsqrx4x_shift_n_add + +.align 32 +.Lsqrx4x_shift_n_add_break: + adcx $A1[1],%rbx + mov %rax,48($tptr) + mov %rbx,56($tptr) + lea 64($tptr),$tptr # end of t[] buffer +___ +} +###################################################################### +# Montgomery reduction part, "word-by-word" algorithm. +# +# This new path is inspired by multiple submissions from Intel, by +# Shay Gueron, Vlad Krasnov, Erdinc Ozturk, James Guilford, +# Vinodh Gopal... +{ +my ($nptr,$carry,$m0)=("%rbp","%rsi","%rdx"); + +$code.=<<___; + movq %xmm2,$nptr +sqrx8x_reduction: + xor %eax,%eax # initial top-most carry bit + mov 32+8(%rsp),%rbx # n0 + mov 48+8(%rsp),%rdx # "%r8", 8*0($tptr) + lea -128($nptr,$num,2),%rcx # end of n[] + #lea 48+8(%rsp,$num,2),$tptr # end of t[] buffer + mov %rcx, 0+8(%rsp) # save end of n[] + mov $tptr,8+8(%rsp) # save end of t[] + + lea 48+8(%rsp),$tptr # initial t[] window + jmp .Lsqrx8x_reduction_loop + +.align 32 +.Lsqrx8x_reduction_loop: + mov 8*1($tptr),%r9 + mov 8*2($tptr),%r10 + mov 8*3($tptr),%r11 + mov 8*4($tptr),%r12 + mov %rdx,%r8 + imulq %rbx,%rdx # n0*a[i] + mov 8*5($tptr),%r13 + mov 8*6($tptr),%r14 + mov 8*7($tptr),%r15 + mov %rax,24+8(%rsp) # store top-most carry bit + + lea 8*8($tptr),$tptr + xor $carry,$carry # cf=0,of=0 + mov \$-8,%rcx + jmp .Lsqrx8x_reduce + +.align 32 +.Lsqrx8x_reduce: + mov %r8, %rbx + mulx 16*0($nptr),%rax,%r8 # n[0] + adcx %rbx,%rax # discarded + adox %r9,%r8 + + mulx 16*1($nptr),%rbx,%r9 # n[1] + adcx %rbx,%r8 + adox %r10,%r9 + + mulx 16*2($nptr),%rbx,%r10 + adcx %rbx,%r9 + adox %r11,%r10 + + mulx 16*3($nptr),%rbx,%r11 + adcx %rbx,%r10 + adox %r12,%r11 + + .byte 0xc4,0x62,0xe3,0xf6,0xa5,0x40,0x00,0x00,0x00 # mulx 16*4($nptr),%rbx,%r12 + mov %rdx,%rax + mov %r8,%rdx + adcx %rbx,%r11 + adox %r13,%r12 + + mulx 32+8(%rsp),%rbx,%rdx # %rdx discarded + mov %rax,%rdx + mov %rax,64+48+8(%rsp,%rcx,8) # put aside n0*a[i] + + mulx 16*5($nptr),%rax,%r13 + adcx %rax,%r12 + adox %r14,%r13 + + mulx 16*6($nptr),%rax,%r14 + adcx %rax,%r13 + adox %r15,%r14 + + mulx 16*7($nptr),%rax,%r15 + mov %rbx,%rdx + adcx %rax,%r14 + adox $carry,%r15 # $carry is 0 + adcx $carry,%r15 # cf=0 + + .byte 0x67,0x67,0x67 + inc %rcx # of=0 + jnz .Lsqrx8x_reduce + + mov $carry,%rax # xor %rax,%rax + cmp 0+8(%rsp),$nptr # end of n[]? + jae .Lsqrx8x_no_tail + + mov 48+8(%rsp),%rdx # pull n0*a[0] + add 8*0($tptr),%r8 + lea 16*8($nptr),$nptr + mov \$-8,%rcx + adcx 8*1($tptr),%r9 + adcx 8*2($tptr),%r10 + adc 8*3($tptr),%r11 + adc 8*4($tptr),%r12 + adc 8*5($tptr),%r13 + adc 8*6($tptr),%r14 + adc 8*7($tptr),%r15 + lea 8*8($tptr),$tptr + sbb %rax,%rax # top carry + + xor $carry,$carry # of=0, cf=0 + mov %rax,16+8(%rsp) + jmp .Lsqrx8x_tail + +.align 32 +.Lsqrx8x_tail: + mov %r8,%rbx + mulx 16*0($nptr),%rax,%r8 + adcx %rax,%rbx + adox %r9,%r8 + + mulx 16*1($nptr),%rax,%r9 + adcx %rax,%r8 + adox %r10,%r9 + + mulx 16*2($nptr),%rax,%r10 + adcx %rax,%r9 + adox %r11,%r10 + + mulx 16*3($nptr),%rax,%r11 + adcx %rax,%r10 + adox %r12,%r11 + + .byte 0xc4,0x62,0xfb,0xf6,0xa5,0x40,0x00,0x00,0x00 # mulx 16*4($nptr),%rax,%r12 + adcx %rax,%r11 + adox %r13,%r12 + + mulx 16*5($nptr),%rax,%r13 + adcx %rax,%r12 + adox %r14,%r13 + + mulx 16*6($nptr),%rax,%r14 + adcx %rax,%r13 + adox %r15,%r14 + + mulx 16*7($nptr),%rax,%r15 + mov 72+48+8(%rsp,%rcx,8),%rdx # pull n0*a[i] + adcx %rax,%r14 + adox $carry,%r15 + mov %rbx,($tptr,%rcx,8) # save result + mov %r8,%rbx + adcx $carry,%r15 # cf=0 + + inc %rcx # of=0 + jnz .Lsqrx8x_tail + + cmp 0+8(%rsp),$nptr # end of n[]? + jae .Lsqrx8x_tail_done # break out of loop + + sub 16+8(%rsp),$carry # mov 16(%rsp),%cf + mov 48+8(%rsp),%rdx # pull n0*a[0] + lea 16*8($nptr),$nptr + adc 8*0($tptr),%r8 + adc 8*1($tptr),%r9 + adc 8*2($tptr),%r10 + adc 8*3($tptr),%r11 + adc 8*4($tptr),%r12 + adc 8*5($tptr),%r13 + adc 8*6($tptr),%r14 + adc 8*7($tptr),%r15 + lea 8*8($tptr),$tptr + sbb %rax,%rax + sub \$8,%rcx # mov \$-8,%rcx + + xor $carry,$carry # of=0, cf=0 + mov %rax,16+8(%rsp) + jmp .Lsqrx8x_tail + +.align 32 +.Lsqrx8x_tail_done: + add 24+8(%rsp),%r8 # can this overflow? + mov $carry,%rax # xor %rax,%rax + + sub 16+8(%rsp),$carry # mov 16(%rsp),%cf +.Lsqrx8x_no_tail: # %cf is 0 if jumped here + adc 8*0($tptr),%r8 + movq %xmm3,%rcx + adc 8*1($tptr),%r9 + mov 16*7($nptr),$carry + movq %xmm2,$nptr # restore $nptr + adc 8*2($tptr),%r10 + adc 8*3($tptr),%r11 + adc 8*4($tptr),%r12 + adc 8*5($tptr),%r13 + adc 8*6($tptr),%r14 + adc 8*7($tptr),%r15 + adc %rax,%rax # top-most carry + + mov 32+8(%rsp),%rbx # n0 + mov 8*8($tptr,%rcx),%rdx # modulo-scheduled "%r8" + + mov %r8,8*0($tptr) # store top 512 bits + lea 8*8($tptr),%r8 # borrow %r8 + mov %r9,8*1($tptr) + mov %r10,8*2($tptr) + mov %r11,8*3($tptr) + mov %r12,8*4($tptr) + mov %r13,8*5($tptr) + mov %r14,8*6($tptr) + mov %r15,8*7($tptr) + + lea 8*8($tptr,%rcx),$tptr # start of current t[] window + cmp 8+8(%rsp),%r8 # end of t[]? + jb .Lsqrx8x_reduction_loop +___ +} +############################################################## +# Post-condition, 4x unrolled +# +{ +my ($rptr,$nptr)=("%rdx","%rbp"); +my @ri=map("%r$_",(10..13)); +my @ni=map("%r$_",(14..15)); +$code.=<<___; + xor %rbx,%rbx + sub %r15,%rsi # compare top-most words + adc %rbx,%rbx + mov %rcx,%r10 # -$num + .byte 0x67 + or %rbx,%rax + .byte 0x67 + mov %rcx,%r9 # -$num + xor \$1,%rax + sar \$3+2,%rcx # cf=0 + #lea 48+8(%rsp,%r9),$tptr + lea ($nptr,%rax,8),$nptr + movq %xmm1,$rptr # restore $rptr + movq %xmm1,$aptr # prepare for back-to-back call + jmp .Lsqrx4x_sub + +.align 32 +.Lsqrx4x_sub: + .byte 0x66 + mov 8*0($tptr),%r12 + mov 8*1($tptr),%r13 + sbb 16*0($nptr),%r12 + mov 8*2($tptr),%r14 + sbb 16*1($nptr),%r13 + mov 8*3($tptr),%r15 + lea 8*4($tptr),$tptr + sbb 16*2($nptr),%r14 + mov %r12,8*0($rptr) + sbb 16*3($nptr),%r15 + lea 16*4($nptr),$nptr + mov %r13,8*1($rptr) + mov %r14,8*2($rptr) + mov %r15,8*3($rptr) + lea 8*4($rptr),$rptr + + inc %rcx + jnz .Lsqrx4x_sub +___ +} +$code.=<<___; + neg %r9 # restore $num + + ret +.size bn_sqrx8x_internal,.-bn_sqrx8x_internal +___ +}}} +{ +my ($inp,$num,$tbl,$idx)=$win64?("%rcx","%edx","%r8", "%r9d") : # Win64 order + ("%rdi","%esi","%rdx","%ecx"); # Unix order +my $out=$inp; +my $STRIDE=2**5*8; +my $N=$STRIDE/4; + +$code.=<<___; +.globl bn_scatter5 +.type bn_scatter5,\@abi-omnipotent +.align 16 +bn_scatter5: + cmp \$0, $num + jz .Lscatter_epilogue + lea ($tbl,$idx,8),$tbl +.Lscatter: + mov ($inp),%rax + lea 8($inp),$inp + mov %rax,($tbl) + lea 32*8($tbl),$tbl + sub \$1,$num + jnz .Lscatter +.Lscatter_epilogue: + ret +.size bn_scatter5,.-bn_scatter5 + +.globl bn_gather5 +.type bn_gather5,\@abi-omnipotent +.align 16 +bn_gather5: +___ +$code.=<<___ if ($win64); +.LSEH_begin_bn_gather5: + # I can't trust assembler to use specific encoding:-( + .byte 0x48,0x83,0xec,0x28 #sub \$0x28,%rsp + .byte 0x0f,0x29,0x34,0x24 #movaps %xmm6,(%rsp) + .byte 0x0f,0x29,0x7c,0x24,0x10 #movdqa %xmm7,0x10(%rsp) +___ +$code.=<<___; + mov $idx,%r11d + shr \$`log($N/8)/log(2)`,$idx + and \$`$N/8-1`,%r11 + not $idx + lea .Lmagic_masks(%rip),%rax + and \$`2**5/($N/8)-1`,$idx # 5 is "window size" + lea 128($tbl,%r11,8),$tbl # pointer within 1st cache line + movq 0(%rax,$idx,8),%xmm4 # set of masks denoting which + movq 8(%rax,$idx,8),%xmm5 # cache line contains element + movq 16(%rax,$idx,8),%xmm6 # denoted by 7th argument + movq 24(%rax,$idx,8),%xmm7 + jmp .Lgather +.align 16 +.Lgather: + movq `0*$STRIDE/4-128`($tbl),%xmm0 + movq `1*$STRIDE/4-128`($tbl),%xmm1 + pand %xmm4,%xmm0 + movq `2*$STRIDE/4-128`($tbl),%xmm2 + pand %xmm5,%xmm1 + movq `3*$STRIDE/4-128`($tbl),%xmm3 + pand %xmm6,%xmm2 + por %xmm1,%xmm0 + pand %xmm7,%xmm3 + .byte 0x67,0x67 + por %xmm2,%xmm0 + lea $STRIDE($tbl),$tbl + por %xmm3,%xmm0 + + movq %xmm0,($out) # m0=bp[0] + lea 8($out),$out + sub \$1,$num + jnz .Lgather +___ +$code.=<<___ if ($win64); + movaps (%rsp),%xmm6 + movaps 0x10(%rsp),%xmm7 + lea 0x28(%rsp),%rsp +___ +$code.=<<___; + ret +.LSEH_end_bn_gather5: +.size bn_gather5,.-bn_gather5 +___ +} +$code.=<<___; +.align 64 +.Lmagic_masks: + .long 0,0, 0,0, 0,0, -1,-1 + .long 0,0, 0,0, 0,0, 0,0 +.asciz "Montgomery Multiplication with scatter/gather for x86_64, CRYPTOGAMS by " +___ + +# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame, +# CONTEXT *context,DISPATCHER_CONTEXT *disp) +if ($win64) { +$rec="%rcx"; +$frame="%rdx"; +$context="%r8"; +$disp="%r9"; + +$code.=<<___; +.extern __imp_RtlVirtualUnwind +.type mul_handler,\@abi-omnipotent +.align 16 +mul_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + mov 8($disp),%rsi # disp->ImageBase + mov 56($disp),%r11 # disp->HandlerData + + mov 0(%r11),%r10d # HandlerData[0] + lea (%rsi,%r10),%r10 # end of prologue label + cmp %r10,%rbx # context->RipRsp + + mov 4(%r11),%r10d # HandlerData[1] + lea (%rsi,%r10),%r10 # epilogue label + cmp %r10,%rbx # context->Rip>=epilogue label + jae .Lcommon_seh_tail + + lea .Lmul_epilogue(%rip),%r10 + cmp %r10,%rbx + jb .Lbody_40 + + mov 192($context),%r10 # pull $num + mov 8(%rax,%r10,8),%rax # pull saved stack pointer + jmp .Lbody_proceed + +.Lbody_40: + mov 40(%rax),%rax # pull saved stack pointer +.Lbody_proceed: + + movaps -88(%rax),%xmm0 + movaps -72(%rax),%xmm1 + + mov -8(%rax),%rbx + mov -16(%rax),%rbp + mov -24(%rax),%r12 + mov -32(%rax),%r13 + mov -40(%rax),%r14 + mov -48(%rax),%r15 + mov %rbx,144($context) # restore context->Rbx + mov %rbp,160($context) # restore context->Rbp + mov %r12,216($context) # restore context->R12 + mov %r13,224($context) # restore context->R13 + mov %r14,232($context) # restore context->R14 + mov %r15,240($context) # restore context->R15 + movups %xmm0,512($context) # restore context->Xmm6 + movups %xmm1,528($context) # restore context->Xmm7 + +.Lcommon_seh_tail: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + + mov 40($disp),%rdi # disp->ContextRecord + mov $context,%rsi # context + mov \$154,%ecx # sizeof(CONTEXT) + .long 0xa548f3fc # cld; rep movsq + + mov $disp,%rsi + xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER + mov 8(%rsi),%rdx # arg2, disp->ImageBase + mov 0(%rsi),%r8 # arg3, disp->ControlPc + mov 16(%rsi),%r9 # arg4, disp->FunctionEntry + mov 40(%rsi),%r10 # disp->ContextRecord + lea 56(%rsi),%r11 # &disp->HandlerData + lea 24(%rsi),%r12 # &disp->EstablisherFrame + mov %r10,32(%rsp) # arg5 + mov %r11,40(%rsp) # arg6 + mov %r12,48(%rsp) # arg7 + mov %rcx,56(%rsp) # arg8, (NULL) + call *__imp_RtlVirtualUnwind(%rip) + + mov \$1,%eax # ExceptionContinueSearch + add \$64,%rsp + popfq + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + pop %rdi + pop %rsi + ret +.size mul_handler,.-mul_handler + +.section .pdata +.align 4 + .rva .LSEH_begin_bn_mul_mont_gather5 + .rva .LSEH_end_bn_mul_mont_gather5 + .rva .LSEH_info_bn_mul_mont_gather5 + + .rva .LSEH_begin_bn_mul4x_mont_gather5 + .rva .LSEH_end_bn_mul4x_mont_gather5 + .rva .LSEH_info_bn_mul4x_mont_gather5 + + .rva .LSEH_begin_bn_power5 + .rva .LSEH_end_bn_power5 + .rva .LSEH_info_bn_power5 + + .rva .LSEH_begin_bn_from_mont8x + .rva .LSEH_end_bn_from_mont8x + .rva .LSEH_info_bn_from_mont8x +___ +$code.=<<___ if ($addx); + .rva .LSEH_begin_bn_mulx4x_mont_gather5 + .rva .LSEH_end_bn_mulx4x_mont_gather5 + .rva .LSEH_info_bn_mulx4x_mont_gather5 + + .rva .LSEH_begin_bn_powerx5 + .rva .LSEH_end_bn_powerx5 + .rva .LSEH_info_bn_powerx5 +___ +$code.=<<___; + .rva .LSEH_begin_bn_gather5 + .rva .LSEH_end_bn_gather5 + .rva .LSEH_info_bn_gather5 + +.section .xdata +.align 8 +.LSEH_info_bn_mul_mont_gather5: + .byte 9,0,0,0 + .rva mul_handler + .rva .Lmul_body,.Lmul_epilogue # HandlerData[] +.align 8 +.LSEH_info_bn_mul4x_mont_gather5: + .byte 9,0,0,0 + .rva mul_handler + .rva .Lmul4x_body,.Lmul4x_epilogue # HandlerData[] +.align 8 +.LSEH_info_bn_power5: + .byte 9,0,0,0 + .rva mul_handler + .rva .Lpower5_body,.Lpower5_epilogue # HandlerData[] +.align 8 +.LSEH_info_bn_from_mont8x: + .byte 9,0,0,0 + .rva mul_handler + .rva .Lfrom_body,.Lfrom_epilogue # HandlerData[] +___ +$code.=<<___ if ($addx); +.align 8 +.LSEH_info_bn_mulx4x_mont_gather5: + .byte 9,0,0,0 + .rva mul_handler + .rva .Lmulx4x_body,.Lmulx4x_epilogue # HandlerData[] +.align 8 +.LSEH_info_bn_powerx5: + .byte 9,0,0,0 + .rva mul_handler + .rva .Lpowerx5_body,.Lpowerx5_epilogue # HandlerData[] +___ +$code.=<<___; +.align 8 +.LSEH_info_bn_gather5: + .byte 0x01,0x0d,0x05,0x00 + .byte 0x0d,0x78,0x01,0x00 #movaps 0x10(rsp),xmm7 + .byte 0x08,0x68,0x00,0x00 #movaps (rsp),xmm6 + .byte 0x04,0x42,0x00,0x00 #sub rsp,0x28 +.align 8 +___ +} + +$code =~ s/\`([^\`]*)\`/eval($1)/gem; + +print $code; +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/bn/bn.c b/TMessagesProj/jni/boringssl/crypto/bn/bn.c new file mode 100644 index 00000000..ad8190b1 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/bn.c @@ -0,0 +1,338 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include + +#include "internal.h" + + +BIGNUM *BN_new(void) { + BIGNUM *bn = OPENSSL_malloc(sizeof(BIGNUM)); + + if (bn == NULL) { + OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); + return NULL; + } + + memset(bn, 0, sizeof(BIGNUM)); + bn->flags = BN_FLG_MALLOCED; + + return bn; +} + +void BN_init(BIGNUM *bn) { + memset(bn, 0, sizeof(BIGNUM)); +} + +void BN_free(BIGNUM *bn) { + if (bn == NULL) { + return; + } + + if ((bn->flags & BN_FLG_STATIC_DATA) == 0) { + OPENSSL_free(bn->d); + } + + if (bn->flags & BN_FLG_MALLOCED) { + OPENSSL_free(bn); + } else { + bn->d = NULL; + } +} + +void BN_clear_free(BIGNUM *bn) { + char should_free; + + if (bn == NULL) { + return; + } + + if (bn->d != NULL) { + OPENSSL_cleanse(bn->d, bn->dmax * sizeof(bn->d[0])); + if ((bn->flags & BN_FLG_STATIC_DATA) == 0) { + OPENSSL_free(bn->d); + } + } + + should_free = (bn->flags & BN_FLG_MALLOCED) != 0; + OPENSSL_cleanse(bn, sizeof(BIGNUM)); + if (should_free) { + OPENSSL_free(bn); + } +} + +BIGNUM *BN_dup(const BIGNUM *src) { + BIGNUM *copy; + + if (src == NULL) { + return NULL; + } + + copy = BN_new(); + if (copy == NULL) { + return NULL; + } + + if (!BN_copy(copy, src)) { + BN_free(copy); + return NULL; + } + + return copy; +} + +BIGNUM *BN_copy(BIGNUM *dest, const BIGNUM *src) { + if (src == dest) { + return dest; + } + + if (bn_wexpand(dest, src->top) == NULL) { + return NULL; + } + + memcpy(dest->d, src->d, sizeof(src->d[0]) * src->top); + + dest->top = src->top; + dest->neg = src->neg; + return dest; +} + +void BN_clear(BIGNUM *bn) { + if (bn->d != NULL) { + memset(bn->d, 0, bn->dmax * sizeof(bn->d[0])); + } + + bn->top = 0; + bn->neg = 0; +} + +const BIGNUM *BN_value_one(void) { + static const BN_ULONG data_one = 1; + static const BIGNUM const_one = {(BN_ULONG *)&data_one, 1, 1, 0, + BN_FLG_STATIC_DATA}; + + return &const_one; +} + +void BN_with_flags(BIGNUM *out, const BIGNUM *in, int flags) { + memcpy(out, in, sizeof(BIGNUM)); + out->flags &= ~BN_FLG_MALLOCED; + out->flags |= BN_FLG_STATIC_DATA | flags; +} + +/* BN_num_bits_word returns the minimum number of bits needed to represent the + * value in |l|. */ +unsigned BN_num_bits_word(BN_ULONG l) { + static const unsigned char bits[256] = { + 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}; + +#if defined(OPENSSL_64_BIT) + if (l & 0xffffffff00000000L) { + if (l & 0xffff000000000000L) { + if (l & 0xff00000000000000L) { + return (bits[(int)(l >> 56)] + 56); + } else { + return (bits[(int)(l >> 48)] + 48); + } + } else { + if (l & 0x0000ff0000000000L) { + return (bits[(int)(l >> 40)] + 40); + } else { + return (bits[(int)(l >> 32)] + 32); + } + } + } else +#endif + { + if (l & 0xffff0000L) { + if (l & 0xff000000L) { + return (bits[(int)(l >> 24L)] + 24); + } else { + return (bits[(int)(l >> 16L)] + 16); + } + } else { + if (l & 0xff00L) { + return (bits[(int)(l >> 8)] + 8); + } else { + return (bits[(int)(l)]); + } + } + } +} + +unsigned BN_num_bits(const BIGNUM *bn) { + const int max = bn->top - 1; + + if (BN_is_zero(bn)) { + return 0; + } + + return max*BN_BITS2 + BN_num_bits_word(bn->d[max]); +} + +unsigned BN_num_bytes(const BIGNUM *bn) { + return (BN_num_bits(bn) + 7) / 8; +} + +void BN_zero(BIGNUM *bn) { + bn->top = bn->neg = 0; +} + +int BN_one(BIGNUM *bn) { + return BN_set_word(bn, 1); +} + +int BN_set_word(BIGNUM *bn, BN_ULONG value) { + if (value == 0) { + BN_zero(bn); + return 1; + } + + if (bn_wexpand(bn, 1) == NULL) { + return 0; + } + + bn->neg = 0; + bn->d[0] = value; + bn->top = 1; + return 1; +} + +int BN_is_negative(const BIGNUM *bn) { + return bn->neg != 0; +} + +void BN_set_negative(BIGNUM *bn, int sign) { + if (sign && !BN_is_zero(bn)) { + bn->neg = 1; + } else { + bn->neg = 0; + } +} + +BIGNUM *bn_wexpand(BIGNUM *bn, unsigned words) { + BN_ULONG *a; + + if (words <= (unsigned) bn->dmax) { + return bn; + } + + if (words > (INT_MAX / (4 * BN_BITS2))) { + OPENSSL_PUT_ERROR(BN, BN_R_BIGNUM_TOO_LONG); + return NULL; + } + + if (bn->flags & BN_FLG_STATIC_DATA) { + OPENSSL_PUT_ERROR(BN, BN_R_EXPAND_ON_STATIC_BIGNUM_DATA); + return NULL; + } + + a = (BN_ULONG *)OPENSSL_malloc(sizeof(BN_ULONG) * words); + if (a == NULL) { + OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); + return NULL; + } + + memcpy(a, bn->d, sizeof(BN_ULONG) * bn->top); + + OPENSSL_free(bn->d); + bn->d = a; + bn->dmax = words; + + return bn; +} + +BIGNUM *bn_expand(BIGNUM *bn, unsigned bits) { + return bn_wexpand(bn, (bits+BN_BITS2-1)/BN_BITS2); +} + +void bn_correct_top(BIGNUM *bn) { + BN_ULONG *ftl; + int tmp_top = bn->top; + + if (tmp_top > 0) { + for (ftl = &(bn->d[tmp_top - 1]); tmp_top > 0; tmp_top--) { + if (*(ftl--)) { + break; + } + } + bn->top = tmp_top; + } +} + +int BN_get_flags(const BIGNUM *bn, int flags) { + return bn->flags & flags; +} + +void BN_set_flags(BIGNUM *bn, int flags) { + bn->flags |= flags; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/bn_asn1.c b/TMessagesProj/jni/boringssl/crypto/bn/bn_asn1.c new file mode 100644 index 00000000..5c47a061 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/bn_asn1.c @@ -0,0 +1,74 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#include +#include + + +int BN_cbs2unsigned(CBS *cbs, BIGNUM *ret) { + CBS child; + if (!CBS_get_asn1(cbs, &child, CBS_ASN1_INTEGER) || + CBS_len(&child) == 0) { + OPENSSL_PUT_ERROR(BN, BN_R_BAD_ENCODING); + return 0; + } + if (CBS_data(&child)[0] & 0x80) { + OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER); + return 0; + } + /* INTEGERs must be minimal. */ + if (CBS_data(&child)[0] == 0x00 && + CBS_len(&child) > 1 && + !(CBS_data(&child)[1] & 0x80)) { + OPENSSL_PUT_ERROR(BN, BN_R_BAD_ENCODING); + return 0; + } + return BN_bin2bn(CBS_data(&child), CBS_len(&child), ret) != NULL; +} + +int BN_bn2cbb(CBB *cbb, const BIGNUM *bn) { + /* Negative numbers are unsupported. */ + if (BN_is_negative(bn)) { + OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER); + return 0; + } + + CBB child; + if (!CBB_add_asn1(cbb, &child, CBS_ASN1_INTEGER)) { + OPENSSL_PUT_ERROR(BN, BN_R_ENCODE_ERROR); + return 0; + } + + /* The number must be padded with a leading zero if the high bit would + * otherwise be set (or |bn| is zero). */ + if (BN_num_bits(bn) % 8 == 0 && + !CBB_add_u8(&child, 0x00)) { + OPENSSL_PUT_ERROR(BN, BN_R_ENCODE_ERROR); + return 0; + } + + uint8_t *out; + if (!CBB_add_space(&child, &out, BN_num_bytes(bn))) { + OPENSSL_PUT_ERROR(BN, BN_R_ENCODE_ERROR); + return 0; + } + BN_bn2bin(bn, out); + if (!CBB_flush(cbb)) { + OPENSSL_PUT_ERROR(BN, BN_R_ENCODE_ERROR); + return 0; + } + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/cmp.c b/TMessagesProj/jni/boringssl/crypto/bn/cmp.c new file mode 100644 index 00000000..fce72339 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/cmp.c @@ -0,0 +1,200 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include "internal.h" + + +int BN_ucmp(const BIGNUM *a, const BIGNUM *b) { + int i; + BN_ULONG t1, t2, *ap, *bp; + + i = a->top - b->top; + if (i != 0) { + return i; + } + + ap = a->d; + bp = b->d; + for (i = a->top - 1; i >= 0; i--) { + t1 = ap[i]; + t2 = bp[i]; + if (t1 != t2) { + return (t1 > t2) ? 1 : -1; + } + } + + return 0; +} + +int BN_cmp(const BIGNUM *a, const BIGNUM *b) { + int i; + int gt, lt; + BN_ULONG t1, t2; + + if ((a == NULL) || (b == NULL)) { + if (a != NULL) { + return -1; + } else if (b != NULL) { + return 1; + } else { + return 0; + } + } + + if (a->neg != b->neg) { + if (a->neg) { + return -1; + } + return 1; + } + if (a->neg == 0) { + gt = 1; + lt = -1; + } else { + gt = -1; + lt = 1; + } + + if (a->top > b->top) { + return gt; + } + if (a->top < b->top) { + return lt; + } + + for (i = a->top - 1; i >= 0; i--) { + t1 = a->d[i]; + t2 = b->d[i]; + if (t1 > t2) { + return gt; + } if (t1 < t2) { + return lt; + } + } + + return 0; +} + +int bn_cmp_words(const BN_ULONG *a, const BN_ULONG *b, int n) { + int i; + BN_ULONG aa, bb; + + aa = a[n - 1]; + bb = b[n - 1]; + if (aa != bb) { + return (aa > bb) ? 1 : -1; + } + + for (i = n - 2; i >= 0; i--) { + aa = a[i]; + bb = b[i]; + if (aa != bb) { + return (aa > bb) ? 1 : -1; + } + } + return 0; +} + +int bn_cmp_part_words(const BN_ULONG *a, const BN_ULONG *b, int cl, int dl) { + int n, i; + n = cl - 1; + + if (dl < 0) { + for (i = dl; i < 0; i++) { + if (b[n - i] != 0) { + return -1; /* a < b */ + } + } + } + if (dl > 0) { + for (i = dl; i > 0; i--) { + if (a[n + i] != 0) { + return 1; /* a > b */ + } + } + } + + return bn_cmp_words(a, b, cl); +} + +int BN_abs_is_word(const BIGNUM *bn, BN_ULONG w) { + switch (bn->top) { + case 1: + return bn->d[0] == w; + case 0: + return w == 0; + default: + return 0; + } +} + +int BN_is_zero(const BIGNUM *bn) { + return bn->top == 0; +} + +int BN_is_one(const BIGNUM *bn) { + return bn->neg == 0 && BN_abs_is_word(bn, 1); +} + +int BN_is_word(const BIGNUM *bn, BN_ULONG w) { + return BN_abs_is_word(bn, w) && (w == 0 || bn->neg == 0); +} + +int BN_is_odd(const BIGNUM *bn) { + return bn->top > 0 && (bn->d[0] & 1) == 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/convert.c b/TMessagesProj/jni/boringssl/crypto/bn/convert.c new file mode 100644 index 00000000..4c707473 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/convert.c @@ -0,0 +1,501 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include + +#include +#include +#include + +#include "internal.h" + +BIGNUM *BN_bin2bn(const uint8_t *in, size_t len, BIGNUM *ret) { + unsigned num_words, m; + BN_ULONG word = 0; + BIGNUM *bn = NULL; + + if (ret == NULL) { + ret = bn = BN_new(); + } + + if (ret == NULL) { + return NULL; + } + + if (len == 0) { + ret->top = 0; + return ret; + } + + num_words = ((len - 1) / BN_BYTES) + 1; + m = (len - 1) % BN_BYTES; + if (bn_wexpand(ret, num_words) == NULL) { + if (bn) { + BN_free(bn); + } + return NULL; + } + + ret->top = num_words; + ret->neg = 0; + + while (len--) { + word = (word << 8) | *(in++); + if (m-- == 0) { + ret->d[--num_words] = word; + word = 0; + m = BN_BYTES - 1; + } + } + + /* need to call this due to clear byte at top if avoiding having the top bit + * set (-ve number) */ + bn_correct_top(ret); + return ret; +} + +size_t BN_bn2bin(const BIGNUM *in, uint8_t *out) { + size_t n, i; + BN_ULONG l; + + n = i = BN_num_bytes(in); + while (i--) { + l = in->d[i / BN_BYTES]; + *(out++) = (unsigned char)(l >> (8 * (i % BN_BYTES))) & 0xff; + } + return n; +} + +/* constant_time_select_ulong returns |x| if |v| is 1 and |y| if |v| is 0. Its + * behavior is undefined if |v| takes any other value. */ +static BN_ULONG constant_time_select_ulong(int v, BN_ULONG x, BN_ULONG y) { + BN_ULONG mask = v; + mask--; + + return (~mask & x) | (mask & y); +} + +/* constant_time_le_size_t returns 1 if |x| <= |y| and 0 otherwise. |x| and |y| + * must not have their MSBs set. */ +static int constant_time_le_size_t(size_t x, size_t y) { + return ((x - y - 1) >> (sizeof(size_t) * 8 - 1)) & 1; +} + +/* read_word_padded returns the |i|'th word of |in|, if it is not out of + * bounds. Otherwise, it returns 0. It does so without branches on the size of + * |in|, however it necessarily does not have the same memory access pattern. If + * the access would be out of bounds, it reads the last word of |in|. |in| must + * not be zero. */ +static BN_ULONG read_word_padded(const BIGNUM *in, size_t i) { + /* Read |in->d[i]| if valid. Otherwise, read the last word. */ + BN_ULONG l = in->d[constant_time_select_ulong( + constant_time_le_size_t(in->dmax, i), in->dmax - 1, i)]; + + /* Clamp to zero if above |d->top|. */ + return constant_time_select_ulong(constant_time_le_size_t(in->top, i), 0, l); +} + +int BN_bn2bin_padded(uint8_t *out, size_t len, const BIGNUM *in) { + size_t i; + BN_ULONG l; + + /* Special case for |in| = 0. Just branch as the probability is negligible. */ + if (BN_is_zero(in)) { + memset(out, 0, len); + return 1; + } + + /* Check if the integer is too big. This case can exit early in non-constant + * time. */ + if ((size_t)in->top > (len + (BN_BYTES - 1)) / BN_BYTES) { + return 0; + } + if ((len % BN_BYTES) != 0) { + l = read_word_padded(in, len / BN_BYTES); + if (l >> (8 * (len % BN_BYTES)) != 0) { + return 0; + } + } + + /* Write the bytes out one by one. Serialization is done without branching on + * the bits of |in| or on |in->top|, but if the routine would otherwise read + * out of bounds, the memory access pattern can't be fixed. However, for an + * RSA key of size a multiple of the word size, the probability of BN_BYTES + * leading zero octets is low. + * + * See Falko Stenzke, "Manger's Attack revisited", ICICS 2010. */ + i = len; + while (i--) { + l = read_word_padded(in, i / BN_BYTES); + *(out++) = (uint8_t)(l >> (8 * (i % BN_BYTES))) & 0xff; + } + return 1; +} + +static const char hextable[] = "0123456789abcdef"; + +char *BN_bn2hex(const BIGNUM *bn) { + int i, j, v, z = 0; + char *buf; + char *p; + + buf = (char *)OPENSSL_malloc(bn->top * BN_BYTES * 2 + 2); + if (buf == NULL) { + OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); + return NULL; + } + + p = buf; + if (bn->neg) { + *(p++) = '-'; + } + + if (BN_is_zero(bn)) { + *(p++) = '0'; + } + + for (i = bn->top - 1; i >= 0; i--) { + for (j = BN_BITS2 - 8; j >= 0; j -= 8) { + /* strip leading zeros */ + v = ((int)(bn->d[i] >> (long)j)) & 0xff; + if (z || v != 0) { + *(p++) = hextable[v >> 4]; + *(p++) = hextable[v & 0x0f]; + z = 1; + } + } + } + *p = '\0'; + + return buf; +} + +/* decode_hex decodes |i| bytes of hex data from |in| and updates |bn|. */ +static void decode_hex(BIGNUM *bn, const char *in, int i) { + int h, m, j, k, c; + BN_ULONG l=0; + + j = i; /* least significant 'hex' */ + h = 0; + while (j > 0) { + m = ((BN_BYTES * 2) <= j) ? (BN_BYTES * 2) : j; + l = 0; + for (;;) { + c = in[j - m]; + if ((c >= '0') && (c <= '9')) { + k = c - '0'; + } else if ((c >= 'a') && (c <= 'f')) { + k = c - 'a' + 10; + } else if ((c >= 'A') && (c <= 'F')) { + k = c - 'A' + 10; + } else { + k = 0; /* paranoia */ + } + + l = (l << 4) | k; + + if (--m <= 0) { + bn->d[h++] = l; + break; + } + } + + j -= (BN_BYTES * 2); + } + + bn->top = h; +} + +/* decode_dec decodes |in_len| bytes of decimal data from |in| and updates |bn|. */ +static void decode_dec(BIGNUM *bn, const char *in, int in_len) { + int i, j; + BN_ULONG l = 0; + + j = BN_DEC_NUM - (in_len % BN_DEC_NUM); + if (j == BN_DEC_NUM) { + j = 0; + } + l = 0; + for (i = 0; i < in_len; i++) { + l *= 10; + l += in[i] - '0'; + if (++j == BN_DEC_NUM) { + BN_mul_word(bn, BN_DEC_CONV); + BN_add_word(bn, l); + l = 0; + j = 0; + } + } +} + +typedef void (*decode_func) (BIGNUM *bn, const char *in, int i); +typedef int (*char_test_func) (int c); + +static int bn_x2bn(BIGNUM **outp, const char *in, decode_func decode, char_test_func want_char) { + BIGNUM *ret = NULL; + int neg = 0, i; + int num; + + if (in == NULL || *in == 0) { + return 0; + } + + if (*in == '-') { + neg = 1; + in++; + } + + for (i = 0; want_char((unsigned char)in[i]); i++) {} + + num = i + neg; + if (outp == NULL) { + return num; + } + + /* in is the start of the hex digits, and it is 'i' long */ + if (*outp == NULL) { + ret = BN_new(); + if (ret == NULL) { + return 0; + } + } else { + ret = *outp; + BN_zero(ret); + } + + /* i is the number of hex digests; */ + if (bn_expand(ret, i * 4) == NULL) { + goto err; + } + + decode(ret, in, i); + + bn_correct_top(ret); + if (!BN_is_zero(ret)) { + ret->neg = neg; + } + + *outp = ret; + return num; + +err: + if (*outp == NULL) { + BN_free(ret); + } + + return 0; +} + +int BN_hex2bn(BIGNUM **outp, const char *in) { + return bn_x2bn(outp, in, decode_hex, isxdigit); +} + +char *BN_bn2dec(const BIGNUM *a) { + int i = 0, num, ok = 0; + char *buf = NULL; + char *p; + BIGNUM *t = NULL; + BN_ULONG *bn_data = NULL, *lp; + + /* get an upper bound for the length of the decimal integer + * num <= (BN_num_bits(a) + 1) * log(2) + * <= 3 * BN_num_bits(a) * 0.1001 + log(2) + 1 (rounding error) + * <= BN_num_bits(a)/10 + BN_num_bits/1000 + 1 + 1 + */ + i = BN_num_bits(a) * 3; + num = i / 10 + i / 1000 + 1 + 1; + bn_data = + (BN_ULONG *)OPENSSL_malloc((num / BN_DEC_NUM + 1) * sizeof(BN_ULONG)); + buf = (char *)OPENSSL_malloc(num + 3); + if ((buf == NULL) || (bn_data == NULL)) { + OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); + goto err; + } + t = BN_dup(a); + if (t == NULL) { + goto err; + } + +#define BUF_REMAIN (num + 3 - (size_t)(p - buf)) + p = buf; + lp = bn_data; + if (BN_is_zero(t)) { + *(p++) = '0'; + *(p++) = '\0'; + } else { + if (BN_is_negative(t)) { + *p++ = '-'; + } + + while (!BN_is_zero(t)) { + *lp = BN_div_word(t, BN_DEC_CONV); + lp++; + } + lp--; + /* We now have a series of blocks, BN_DEC_NUM chars + * in length, where the last one needs truncation. + * The blocks need to be reversed in order. */ + BIO_snprintf(p, BUF_REMAIN, BN_DEC_FMT1, *lp); + while (*p) { + p++; + } + while (lp != bn_data) { + lp--; + BIO_snprintf(p, BUF_REMAIN, BN_DEC_FMT2, *lp); + while (*p) { + p++; + } + } + } + ok = 1; + +err: + OPENSSL_free(bn_data); + BN_free(t); + if (!ok) { + OPENSSL_free(buf); + buf = NULL; + } + + return buf; +} + +int BN_dec2bn(BIGNUM **outp, const char *in) { + return bn_x2bn(outp, in, decode_dec, isdigit); +} + +int BN_asc2bn(BIGNUM **outp, const char *in) { + const char *const orig_in = in; + if (*in == '-') { + in++; + } + + if (in[0] == '0' && (in[1] == 'X' || in[1] == 'x')) { + if (!BN_hex2bn(outp, in+2)) { + return 0; + } + } else { + if (!BN_dec2bn(outp, in)) { + return 0; + } + } + + if (*orig_in == '-' && !BN_is_zero(*outp)) { + (*outp)->neg = 1; + } + + return 1; +} + +int BN_print(BIO *bp, const BIGNUM *a) { + int i, j, v, z = 0; + int ret = 0; + + if (a->neg && BIO_write(bp, "-", 1) != 1) { + goto end; + } + + if (BN_is_zero(a) && BIO_write(bp, "0", 1) != 1) { + goto end; + } + + for (i = a->top - 1; i >= 0; i--) { + for (j = BN_BITS2 - 4; j >= 0; j -= 4) { + /* strip leading zeros */ + v = ((int)(a->d[i] >> (long)j)) & 0x0f; + if (z || v != 0) { + if (BIO_write(bp, &hextable[v], 1) != 1) { + goto end; + } + z = 1; + } + } + } + ret = 1; + +end: + return ret; +} + +int BN_print_fp(FILE *fp, const BIGNUM *a) { + BIO *b; + int ret; + + b = BIO_new(BIO_s_file()); + if (b == NULL) { + return 0; + } + BIO_set_fp(b, fp, BIO_NOCLOSE); + ret = BN_print(b, a); + BIO_free(b); + + return ret; +} + +BN_ULONG BN_get_word(const BIGNUM *bn) { + switch (bn->top) { + case 0: + return 0; + case 1: + return bn->d[0]; + default: + return BN_MASK2; + } +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/ctx.c b/TMessagesProj/jni/boringssl/crypto/bn/ctx.c new file mode 100644 index 00000000..48d9adf6 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/ctx.c @@ -0,0 +1,311 @@ +/* Written by Ulf Moeller for the OpenSSL project. */ +/* ==================================================================== + * Copyright (c) 1998-2004 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + + +#include + +#include + +#include +#include + + +/* How many bignums are in each "pool item"; */ +#define BN_CTX_POOL_SIZE 16 +/* The stack frame info is resizing, set a first-time expansion size; */ +#define BN_CTX_START_FRAMES 32 + +/* A bundle of bignums that can be linked with other bundles */ +typedef struct bignum_pool_item { + /* The bignum values */ + BIGNUM vals[BN_CTX_POOL_SIZE]; + /* Linked-list admin */ + struct bignum_pool_item *prev, *next; +} BN_POOL_ITEM; + + +typedef struct bignum_pool { + /* Linked-list admin */ + BN_POOL_ITEM *head, *current, *tail; + /* Stack depth and allocation size */ + unsigned used, size; +} BN_POOL; + +static void BN_POOL_init(BN_POOL *); +static void BN_POOL_finish(BN_POOL *); +static BIGNUM *BN_POOL_get(BN_POOL *); +static void BN_POOL_release(BN_POOL *, unsigned int); + +/************/ +/* BN_STACK */ +/************/ + +/* A wrapper to manage the "stack frames" */ +typedef struct bignum_ctx_stack { + /* Array of indexes into the bignum stack */ + unsigned int *indexes; + /* Number of stack frames, and the size of the allocated array */ + unsigned int depth, size; +} BN_STACK; + +static void BN_STACK_init(BN_STACK *); +static void BN_STACK_finish(BN_STACK *); +static int BN_STACK_push(BN_STACK *, unsigned int); +static unsigned int BN_STACK_pop(BN_STACK *); + +/**********/ +/* BN_CTX */ +/**********/ + +/* The opaque BN_CTX type */ +struct bignum_ctx { + /* The bignum bundles */ + BN_POOL pool; + /* The "stack frames", if you will */ + BN_STACK stack; + /* The number of bignums currently assigned */ + unsigned int used; + /* Depth of stack overflow */ + int err_stack; + /* Block "gets" until an "end" (compatibility behaviour) */ + int too_many; +}; + +BN_CTX *BN_CTX_new(void) { + BN_CTX *ret = OPENSSL_malloc(sizeof(BN_CTX)); + if (!ret) { + OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); + return NULL; + } + + /* Initialise the structure */ + BN_POOL_init(&ret->pool); + BN_STACK_init(&ret->stack); + ret->used = 0; + ret->err_stack = 0; + ret->too_many = 0; + return ret; +} + +void BN_CTX_free(BN_CTX *ctx) { + if (ctx == NULL) { + return; + } + + BN_STACK_finish(&ctx->stack); + BN_POOL_finish(&ctx->pool); + OPENSSL_free(ctx); +} + +void BN_CTX_start(BN_CTX *ctx) { + /* If we're already overflowing ... */ + if (ctx->err_stack || ctx->too_many) { + ctx->err_stack++; + } else if (!BN_STACK_push(&ctx->stack, ctx->used)) { + /* (Try to) get a new frame pointer */ + OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_TEMPORARY_VARIABLES); + ctx->err_stack++; + } +} + +BIGNUM *BN_CTX_get(BN_CTX *ctx) { + BIGNUM *ret; + if (ctx->err_stack || ctx->too_many) { + return NULL; + } + + ret = BN_POOL_get(&ctx->pool); + if (ret == NULL) { + /* Setting too_many prevents repeated "get" attempts from + * cluttering the error stack. */ + ctx->too_many = 1; + OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_TEMPORARY_VARIABLES); + return NULL; + } + + /* OK, make sure the returned bignum is "zero" */ + BN_zero(ret); + ctx->used++; + return ret; +} + +void BN_CTX_end(BN_CTX *ctx) { + if (ctx->err_stack) { + ctx->err_stack--; + } else { + unsigned int fp = BN_STACK_pop(&ctx->stack); + /* Does this stack frame have anything to release? */ + if (fp < ctx->used) { + BN_POOL_release(&ctx->pool, ctx->used - fp); + } + + ctx->used = fp; + /* Unjam "too_many" in case "get" had failed */ + ctx->too_many = 0; + } +} + +/************/ +/* BN_STACK */ +/************/ + +static void BN_STACK_init(BN_STACK *st) { + st->indexes = NULL; + st->depth = st->size = 0; +} + +static void BN_STACK_finish(BN_STACK *st) { + OPENSSL_free(st->indexes); +} + +static int BN_STACK_push(BN_STACK *st, unsigned int idx) { + if (st->depth == st->size) { + /* Need to expand */ + unsigned int newsize = + (st->size ? (st->size * 3 / 2) : BN_CTX_START_FRAMES); + unsigned int *newitems = OPENSSL_malloc(newsize * sizeof(unsigned int)); + if (!newitems) { + return 0; + } + if (st->depth) { + memcpy(newitems, st->indexes, st->depth * sizeof(unsigned int)); + } + OPENSSL_free(st->indexes); + st->indexes = newitems; + st->size = newsize; + } + + st->indexes[(st->depth)++] = idx; + return 1; +} + +static unsigned int BN_STACK_pop(BN_STACK *st) { + return st->indexes[--(st->depth)]; +} + +static void BN_POOL_init(BN_POOL *p) { + p->head = p->current = p->tail = NULL; + p->used = p->size = 0; +} + +static void BN_POOL_finish(BN_POOL *p) { + while (p->head) { + unsigned int loop = 0; + BIGNUM *bn = p->head->vals; + while (loop++ < BN_CTX_POOL_SIZE) { + if (bn->d) { + BN_clear_free(bn); + } + bn++; + } + + p->current = p->head->next; + OPENSSL_free(p->head); + p->head = p->current; + } +} + +static BIGNUM *BN_POOL_get(BN_POOL *p) { + if (p->used == p->size) { + BIGNUM *bn; + unsigned int loop = 0; + BN_POOL_ITEM *item = OPENSSL_malloc(sizeof(BN_POOL_ITEM)); + if (!item) { + return NULL; + } + + /* Initialise the structure */ + bn = item->vals; + while (loop++ < BN_CTX_POOL_SIZE) { + BN_init(bn++); + } + + item->prev = p->tail; + item->next = NULL; + /* Link it in */ + if (!p->head) { + p->head = p->current = p->tail = item; + } else { + p->tail->next = item; + p->tail = item; + p->current = item; + } + + p->size += BN_CTX_POOL_SIZE; + p->used++; + /* Return the first bignum from the new pool */ + return item->vals; + } + + if (!p->used) { + p->current = p->head; + } else if ((p->used % BN_CTX_POOL_SIZE) == 0) { + p->current = p->current->next; + } + + return p->current->vals + ((p->used++) % BN_CTX_POOL_SIZE); +} + +static void BN_POOL_release(BN_POOL *p, unsigned int num) { + unsigned int offset = (p->used - 1) % BN_CTX_POOL_SIZE; + p->used -= num; + + while (num--) { + if (!offset) { + offset = BN_CTX_POOL_SIZE - 1; + p->current = p->current->prev; + } else { + offset--; + } + } +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/div.c b/TMessagesProj/jni/boringssl/crypto/bn/div.c new file mode 100644 index 00000000..779dda2d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/div.c @@ -0,0 +1,625 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include "internal.h" + + +#define asm __asm__ + +#if !defined(OPENSSL_NO_ASM) +# if defined(__GNUC__) && __GNUC__>=2 +# if defined(OPENSSL_X86) + /* + * There were two reasons for implementing this template: + * - GNU C generates a call to a function (__udivdi3 to be exact) + * in reply to ((((BN_ULLONG)n0)< + */ +#undef div_asm +# define div_asm(n0,n1,d0) \ + ({ asm volatile ( \ + "divl %4" \ + : "=a"(q), "=d"(rem) \ + : "a"(n1), "d"(n0), "g"(d0) \ + : "cc"); \ + q; \ + }) +# define REMAINDER_IS_ALREADY_CALCULATED +# elif defined(OPENSSL_X86_64) + /* + * Same story here, but it's 128-bit by 64-bit division. Wow! + * + */ +# undef div_asm +# define div_asm(n0,n1,d0) \ + ({ asm volatile ( \ + "divq %4" \ + : "=a"(q), "=d"(rem) \ + : "a"(n1), "d"(n0), "g"(d0) \ + : "cc"); \ + q; \ + }) +# define REMAINDER_IS_ALREADY_CALCULATED +# endif /* __ */ +# endif /* __GNUC__ */ +#endif /* OPENSSL_NO_ASM */ + +/* BN_div computes dv := num / divisor, rounding towards + * zero, and sets up rm such that dv*divisor + rm = num holds. + * Thus: + * dv->neg == num->neg ^ divisor->neg (unless the result is zero) + * rm->neg == num->neg (unless the remainder is zero) + * If 'dv' or 'rm' is NULL, the respective value is not returned. */ +int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor, + BN_CTX *ctx) { + int norm_shift, i, loop; + BIGNUM *tmp, wnum, *snum, *sdiv, *res; + BN_ULONG *resp, *wnump; + BN_ULONG d0, d1; + int num_n, div_n; + int no_branch = 0; + + /* Invalid zero-padding would have particularly bad consequences + * so don't just rely on bn_check_top() here */ + if ((num->top > 0 && num->d[num->top - 1] == 0) || + (divisor->top > 0 && divisor->d[divisor->top - 1] == 0)) { + OPENSSL_PUT_ERROR(BN, BN_R_NOT_INITIALIZED); + return 0; + } + + if ((num->flags & BN_FLG_CONSTTIME) != 0 || + (divisor->flags & BN_FLG_CONSTTIME) != 0) { + no_branch = 1; + } + + if (BN_is_zero(divisor)) { + OPENSSL_PUT_ERROR(BN, BN_R_DIV_BY_ZERO); + return 0; + } + + if (!no_branch && BN_ucmp(num, divisor) < 0) { + if (rm != NULL) { + if (BN_copy(rm, num) == NULL) { + return 0; + } + } + if (dv != NULL) { + BN_zero(dv); + } + return 1; + } + + BN_CTX_start(ctx); + tmp = BN_CTX_get(ctx); + snum = BN_CTX_get(ctx); + sdiv = BN_CTX_get(ctx); + if (dv == NULL) { + res = BN_CTX_get(ctx); + } else { + res = dv; + } + if (sdiv == NULL || res == NULL || tmp == NULL || snum == NULL) { + goto err; + } + + /* First we normalise the numbers */ + norm_shift = BN_BITS2 - ((BN_num_bits(divisor)) % BN_BITS2); + if (!(BN_lshift(sdiv, divisor, norm_shift))) { + goto err; + } + sdiv->neg = 0; + norm_shift += BN_BITS2; + if (!(BN_lshift(snum, num, norm_shift))) { + goto err; + } + snum->neg = 0; + + if (no_branch) { + /* Since we don't know whether snum is larger than sdiv, + * we pad snum with enough zeroes without changing its + * value. + */ + if (snum->top <= sdiv->top + 1) { + if (bn_wexpand(snum, sdiv->top + 2) == NULL) { + goto err; + } + for (i = snum->top; i < sdiv->top + 2; i++) { + snum->d[i] = 0; + } + snum->top = sdiv->top + 2; + } else { + if (bn_wexpand(snum, snum->top + 1) == NULL) { + goto err; + } + snum->d[snum->top] = 0; + snum->top++; + } + } + + div_n = sdiv->top; + num_n = snum->top; + loop = num_n - div_n; + /* Lets setup a 'window' into snum + * This is the part that corresponds to the current + * 'area' being divided */ + wnum.neg = 0; + wnum.d = &(snum->d[loop]); + wnum.top = div_n; + /* only needed when BN_ucmp messes up the values between top and max */ + wnum.dmax = snum->dmax - loop; /* so we don't step out of bounds */ + + /* Get the top 2 words of sdiv */ + /* div_n=sdiv->top; */ + d0 = sdiv->d[div_n - 1]; + d1 = (div_n == 1) ? 0 : sdiv->d[div_n - 2]; + + /* pointer to the 'top' of snum */ + wnump = &(snum->d[num_n - 1]); + + /* Setup to 'res' */ + res->neg = (num->neg ^ divisor->neg); + if (!bn_wexpand(res, (loop + 1))) { + goto err; + } + res->top = loop - no_branch; + resp = &(res->d[loop - 1]); + + /* space for temp */ + if (!bn_wexpand(tmp, (div_n + 1))) { + goto err; + } + + if (!no_branch) { + if (BN_ucmp(&wnum, sdiv) >= 0) { + bn_sub_words(wnum.d, wnum.d, sdiv->d, div_n); + *resp = 1; + } else { + res->top--; + } + } + + /* if res->top == 0 then clear the neg value otherwise decrease + * the resp pointer */ + if (res->top == 0) { + res->neg = 0; + } else { + resp--; + } + + for (i = 0; i < loop - 1; i++, wnump--, resp--) { + BN_ULONG q, l0; + /* the first part of the loop uses the top two words of snum and sdiv to + * calculate a BN_ULONG q such that | wnum - sdiv * q | < sdiv */ + BN_ULONG n0, n1, rem = 0; + + n0 = wnump[0]; + n1 = wnump[-1]; + if (n0 == d0) { + q = BN_MASK2; + } else { + /* n0 < d0 */ +#ifdef BN_LLONG + BN_ULLONG t2; + +#if defined(BN_LLONG) && !defined(div_asm) + q = (BN_ULONG)(((((BN_ULLONG)n0) << BN_BITS2) | n1) / d0); +#else + q = div_asm(n0, n1, d0); +#endif + +#ifndef REMAINDER_IS_ALREADY_CALCULATED + /* rem doesn't have to be BN_ULLONG. The least we know it's less that d0, + * isn't it? */ + rem = (n1 - q * d0) & BN_MASK2; +#endif + + t2 = (BN_ULLONG)d1 * q; + + for (;;) { + if (t2 <= ((((BN_ULLONG)rem) << BN_BITS2) | wnump[-2])) { + break; + } + q--; + rem += d0; + if (rem < d0) { + break; /* don't let rem overflow */ + } + t2 -= d1; + } +#else /* !BN_LLONG */ + BN_ULONG t2l, t2h; + +#if defined(div_asm) + q = div_asm(n0, n1, d0); +#else + q = bn_div_words(n0, n1, d0); +#endif + +#ifndef REMAINDER_IS_ALREADY_CALCULATED + rem = (n1 - q * d0) & BN_MASK2; +#endif + +#if defined(BN_UMULT_LOHI) + BN_UMULT_LOHI(t2l, t2h, d1, q); +#elif defined(BN_UMULT_HIGH) + t2l = d1 * q; + t2h = BN_UMULT_HIGH(d1, q); +#else + { + BN_ULONG ql, qh; + t2l = LBITS(d1); + t2h = HBITS(d1); + ql = LBITS(q); + qh = HBITS(q); + mul64(t2l, t2h, ql, qh); /* t2=(BN_ULLONG)d1*q; */ + } +#endif + + for (;;) { + if ((t2h < rem) || ((t2h == rem) && (t2l <= wnump[-2]))) { + break; + } + q--; + rem += d0; + if (rem < d0) { + break; /* don't let rem overflow */ + } + if (t2l < d1) { + t2h--; + } + t2l -= d1; + } +#endif /* !BN_LLONG */ + } + + l0 = bn_mul_words(tmp->d, sdiv->d, div_n, q); + tmp->d[div_n] = l0; + wnum.d--; + /* ingore top values of the bignums just sub the two + * BN_ULONG arrays with bn_sub_words */ + if (bn_sub_words(wnum.d, wnum.d, tmp->d, div_n + 1)) { + /* Note: As we have considered only the leading + * two BN_ULONGs in the calculation of q, sdiv * q + * might be greater than wnum (but then (q-1) * sdiv + * is less or equal than wnum) + */ + q--; + if (bn_add_words(wnum.d, wnum.d, sdiv->d, div_n)) { + /* we can't have an overflow here (assuming + * that q != 0, but if q == 0 then tmp is + * zero anyway) */ + (*wnump)++; + } + } + /* store part of the result */ + *resp = q; + } + bn_correct_top(snum); + if (rm != NULL) { + /* Keep a copy of the neg flag in num because if rm==num + * BN_rshift() will overwrite it. + */ + int neg = num->neg; + if (!BN_rshift(rm, snum, norm_shift)) { + goto err; + } + if (!BN_is_zero(rm)) { + rm->neg = neg; + } + } + if (no_branch) { + bn_correct_top(res); + } + BN_CTX_end(ctx); + return 1; + +err: + BN_CTX_end(ctx); + return 0; +} + +int BN_nnmod(BIGNUM *r, const BIGNUM *m, const BIGNUM *d, BN_CTX *ctx) { + if (!(BN_mod(r, m, d, ctx))) { + return 0; + } + if (!r->neg) { + return 1; + } + + /* now -|d| < r < 0, so we have to set r := r + |d|. */ + return (d->neg ? BN_sub : BN_add)(r, r, d); +} + +int BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, + BN_CTX *ctx) { + if (!BN_add(r, a, b)) { + return 0; + } + return BN_nnmod(r, r, m, ctx); +} + +int BN_mod_add_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const BIGNUM *m) { + if (!BN_uadd(r, a, b)) { + return 0; + } + if (BN_ucmp(r, m) >= 0) { + return BN_usub(r, r, m); + } + return 1; +} + +int BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, + BN_CTX *ctx) { + if (!BN_sub(r, a, b)) { + return 0; + } + return BN_nnmod(r, r, m, ctx); +} + +/* BN_mod_sub variant that may be used if both a and b are non-negative + * and less than m */ +int BN_mod_sub_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const BIGNUM *m) { + if (!BN_sub(r, a, b)) { + return 0; + } + if (r->neg) { + return BN_add(r, r, m); + } + return 1; +} + +int BN_mod_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, + BN_CTX *ctx) { + BIGNUM *t; + int ret = 0; + + BN_CTX_start(ctx); + t = BN_CTX_get(ctx); + if (t == NULL) { + goto err; + } + + if (a == b) { + if (!BN_sqr(t, a, ctx)) { + goto err; + } + } else { + if (!BN_mul(t, a, b, ctx)) { + goto err; + } + } + + if (!BN_nnmod(r, t, m, ctx)) { + goto err; + } + + ret = 1; + +err: + BN_CTX_end(ctx); + return ret; +} + +int BN_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx) { + if (!BN_sqr(r, a, ctx)) { + return 0; + } + + /* r->neg == 0, thus we don't need BN_nnmod */ + return BN_mod(r, r, m, ctx); +} + +int BN_mod_lshift(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m, + BN_CTX *ctx) { + BIGNUM *abs_m = NULL; + int ret; + + if (!BN_nnmod(r, a, m, ctx)) { + return 0; + } + + if (m->neg) { + abs_m = BN_dup(m); + if (abs_m == NULL) { + return 0; + } + abs_m->neg = 0; + } + + ret = BN_mod_lshift_quick(r, r, n, (abs_m ? abs_m : m)); + + BN_free(abs_m); + return ret; +} + +int BN_mod_lshift_quick(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m) { + if (r != a) { + if (BN_copy(r, a) == NULL) { + return 0; + } + } + + while (n > 0) { + int max_shift; + + /* 0 < r < m */ + max_shift = BN_num_bits(m) - BN_num_bits(r); + /* max_shift >= 0 */ + + if (max_shift < 0) { + OPENSSL_PUT_ERROR(BN, BN_R_INPUT_NOT_REDUCED); + return 0; + } + + if (max_shift > n) { + max_shift = n; + } + + if (max_shift) { + if (!BN_lshift(r, r, max_shift)) { + return 0; + } + n -= max_shift; + } else { + if (!BN_lshift1(r, r)) { + return 0; + } + --n; + } + + /* BN_num_bits(r) <= BN_num_bits(m) */ + if (BN_cmp(r, m) >= 0) { + if (!BN_sub(r, r, m)) { + return 0; + } + } + } + + return 1; +} + +int BN_mod_lshift1(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx) { + if (!BN_lshift1(r, a)) { + return 0; + } + + return BN_nnmod(r, r, m, ctx); +} + +int BN_mod_lshift1_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *m) { + if (!BN_lshift1(r, a)) { + return 0; + } + if (BN_cmp(r, m) >= 0) { + return BN_sub(r, r, m); + } + + return 1; +} + +BN_ULONG BN_div_word(BIGNUM *a, BN_ULONG w) { + BN_ULONG ret = 0; + int i, j; + + w &= BN_MASK2; + + if (!w) { + /* actually this an error (division by zero) */ + return (BN_ULONG) - 1; + } + + if (a->top == 0) { + return 0; + } + + /* normalize input (so bn_div_words doesn't complain) */ + j = BN_BITS2 - BN_num_bits_word(w); + w <<= j; + if (!BN_lshift(a, a, j)) { + return (BN_ULONG) - 1; + } + + for (i = a->top - 1; i >= 0; i--) { + BN_ULONG l, d; + + l = a->d[i]; + d = bn_div_words(ret, l, w); + ret = (l - ((d * w) & BN_MASK2)) & BN_MASK2; + a->d[i] = d; + } + + if ((a->top > 0) && (a->d[a->top - 1] == 0)) { + a->top--; + } + + ret >>= j; + return ret; +} + +BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w) { +#ifndef BN_LLONG + BN_ULONG ret = 0; +#else + BN_ULLONG ret = 0; +#endif + int i; + + if (w == 0) { + return (BN_ULONG) -1; + } + + w &= BN_MASK2; + for (i = a->top - 1; i >= 0; i--) { +#ifndef BN_LLONG + ret = ((ret << BN_BITS4) | ((a->d[i] >> BN_BITS4) & BN_MASK2l)) % w; + ret = ((ret << BN_BITS4) | (a->d[i] & BN_MASK2l)) % w; +#else + ret = (BN_ULLONG)(((ret << (BN_ULLONG)BN_BITS2) | a->d[i]) % (BN_ULLONG)w); +#endif + } + return (BN_ULONG)ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/exponentiation.c b/TMessagesProj/jni/boringssl/crypto/bn/exponentiation.c new file mode 100644 index 00000000..a829810a --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/exponentiation.c @@ -0,0 +1,1559 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include + +#include +#include +#include + +#include "internal.h" + + +#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) +#define OPENSSL_BN_ASM_MONT5 +#define RSAZ_ENABLED + +#include "rsaz_exp.h" +#endif + +int BN_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx) { + int i, bits, ret = 0; + BIGNUM *v, *rr; + + if ((p->flags & BN_FLG_CONSTTIME) != 0) { + /* BN_FLG_CONSTTIME only supported by BN_mod_exp_mont() */ + OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + + BN_CTX_start(ctx); + if (r == a || r == p) { + rr = BN_CTX_get(ctx); + } else { + rr = r; + } + + v = BN_CTX_get(ctx); + if (rr == NULL || v == NULL) { + goto err; + } + + if (BN_copy(v, a) == NULL) { + goto err; + } + bits = BN_num_bits(p); + + if (BN_is_odd(p)) { + if (BN_copy(rr, a) == NULL) { + goto err; + } + } else { + if (!BN_one(rr)) { + goto err; + } + } + + for (i = 1; i < bits; i++) { + if (!BN_sqr(v, v, ctx)) { + goto err; + } + if (BN_is_bit_set(p, i)) { + if (!BN_mul(rr, rr, v, ctx)) { + goto err; + } + } + } + + if (r != rr && !BN_copy(r, rr)) { + goto err; + } + ret = 1; + +err: + BN_CTX_end(ctx); + return ret; +} + +/* maximum precomputation table size for *variable* sliding windows */ +#define TABLE_SIZE 32 + +typedef struct bn_recp_ctx_st { + BIGNUM N; /* the divisor */ + BIGNUM Nr; /* the reciprocal */ + int num_bits; + int shift; + int flags; +} BN_RECP_CTX; + +static void BN_RECP_CTX_init(BN_RECP_CTX *recp) { + BN_init(&recp->N); + BN_init(&recp->Nr); + recp->num_bits = 0; + recp->flags = 0; +} + +static void BN_RECP_CTX_free(BN_RECP_CTX *recp) { + if (recp == NULL) { + return; + } + + BN_free(&recp->N); + BN_free(&recp->Nr); +} + +static int BN_RECP_CTX_set(BN_RECP_CTX *recp, const BIGNUM *d, BN_CTX *ctx) { + if (!BN_copy(&(recp->N), d)) { + return 0; + } + BN_zero(&recp->Nr); + recp->num_bits = BN_num_bits(d); + recp->shift = 0; + + return 1; +} + +/* len is the expected size of the result We actually calculate with an extra + * word of precision, so we can do faster division if the remainder is not + * required. + * r := 2^len / m */ +static int BN_reciprocal(BIGNUM *r, const BIGNUM *m, int len, BN_CTX *ctx) { + int ret = -1; + BIGNUM *t; + + BN_CTX_start(ctx); + t = BN_CTX_get(ctx); + if (t == NULL) { + goto err; + } + + if (!BN_set_bit(t, len)) { + goto err; + } + + if (!BN_div(r, NULL, t, m, ctx)) { + goto err; + } + + ret = len; + +err: + BN_CTX_end(ctx); + return ret; +} + +static int BN_div_recp(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, + BN_RECP_CTX *recp, BN_CTX *ctx) { + int i, j, ret = 0; + BIGNUM *a, *b, *d, *r; + + BN_CTX_start(ctx); + a = BN_CTX_get(ctx); + b = BN_CTX_get(ctx); + if (dv != NULL) { + d = dv; + } else { + d = BN_CTX_get(ctx); + } + + if (rem != NULL) { + r = rem; + } else { + r = BN_CTX_get(ctx); + } + + if (a == NULL || b == NULL || d == NULL || r == NULL) { + goto err; + } + + if (BN_ucmp(m, &(recp->N)) < 0) { + BN_zero(d); + if (!BN_copy(r, m)) { + return 0; + } + BN_CTX_end(ctx); + return 1; + } + + /* We want the remainder + * Given input of ABCDEF / ab + * we need multiply ABCDEF by 3 digests of the reciprocal of ab */ + + /* i := max(BN_num_bits(m), 2*BN_num_bits(N)) */ + i = BN_num_bits(m); + j = recp->num_bits << 1; + if (j > i) { + i = j; + } + + /* Nr := round(2^i / N) */ + if (i != recp->shift) { + recp->shift = + BN_reciprocal(&(recp->Nr), &(recp->N), i, + ctx); /* BN_reciprocal returns i, or -1 for an error */ + } + + if (recp->shift == -1) { + goto err; + } + + /* d := |round(round(m / 2^BN_num_bits(N)) * recp->Nr / 2^(i - + * BN_num_bits(N)))| + * = |round(round(m / 2^BN_num_bits(N)) * round(2^i / N) / 2^(i - + * BN_num_bits(N)))| + * <= |(m / 2^BN_num_bits(N)) * (2^i / N) * (2^BN_num_bits(N) / 2^i)| + * = |m/N| */ + if (!BN_rshift(a, m, recp->num_bits)) { + goto err; + } + if (!BN_mul(b, a, &(recp->Nr), ctx)) { + goto err; + } + if (!BN_rshift(d, b, i - recp->num_bits)) { + goto err; + } + d->neg = 0; + + if (!BN_mul(b, &(recp->N), d, ctx)) { + goto err; + } + if (!BN_usub(r, m, b)) { + goto err; + } + r->neg = 0; + + j = 0; + while (BN_ucmp(r, &(recp->N)) >= 0) { + if (j++ > 2) { + OPENSSL_PUT_ERROR(BN, BN_R_BAD_RECIPROCAL); + goto err; + } + if (!BN_usub(r, r, &(recp->N))) { + goto err; + } + if (!BN_add_word(d, 1)) { + goto err; + } + } + + r->neg = BN_is_zero(r) ? 0 : m->neg; + d->neg = m->neg ^ recp->N.neg; + ret = 1; + +err: + BN_CTX_end(ctx); + return ret; +} + +static int BN_mod_mul_reciprocal(BIGNUM *r, const BIGNUM *x, const BIGNUM *y, + BN_RECP_CTX *recp, BN_CTX *ctx) { + int ret = 0; + BIGNUM *a; + const BIGNUM *ca; + + BN_CTX_start(ctx); + a = BN_CTX_get(ctx); + if (a == NULL) { + goto err; + } + + if (y != NULL) { + if (x == y) { + if (!BN_sqr(a, x, ctx)) { + goto err; + } + } else { + if (!BN_mul(a, x, y, ctx)) { + goto err; + } + } + ca = a; + } else { + ca = x; /* Just do the mod */ + } + + ret = BN_div_recp(NULL, r, ca, recp, ctx); + +err: + BN_CTX_end(ctx); + return ret; +} + +/* BN_window_bits_for_exponent_size -- macro for sliding window mod_exp + * functions + * + * For window size 'w' (w >= 2) and a random 'b' bits exponent, the number of + * multiplications is a constant plus on average + * + * 2^(w-1) + (b-w)/(w+1); + * + * here 2^(w-1) is for precomputing the table (we actually need entries only + * for windows that have the lowest bit set), and (b-w)/(w+1) is an + * approximation for the expected number of w-bit windows, not counting the + * first one. + * + * Thus we should use + * + * w >= 6 if b > 671 + * w = 5 if 671 > b > 239 + * w = 4 if 239 > b > 79 + * w = 3 if 79 > b > 23 + * w <= 2 if 23 > b + * + * (with draws in between). Very small exponents are often selected + * with low Hamming weight, so we use w = 1 for b <= 23. */ +#define BN_window_bits_for_exponent_size(b) \ + ((b) > 671 ? 6 : \ + (b) > 239 ? 5 : \ + (b) > 79 ? 4 : \ + (b) > 23 ? 3 : 1) + +static int mod_exp_recp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx) { + int i, j, bits, ret = 0, wstart, window; + int start = 1; + BIGNUM *aa; + /* Table of variables obtained from 'ctx' */ + BIGNUM *val[TABLE_SIZE]; + BN_RECP_CTX recp; + + if (BN_get_flags(p, BN_FLG_CONSTTIME) != 0) { + /* BN_FLG_CONSTTIME only supported by BN_mod_exp_mont() */ + OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + + bits = BN_num_bits(p); + + if (bits == 0) { + ret = BN_one(r); + return ret; + } + + BN_CTX_start(ctx); + aa = BN_CTX_get(ctx); + val[0] = BN_CTX_get(ctx); + if (!aa || !val[0]) { + goto err; + } + + BN_RECP_CTX_init(&recp); + if (m->neg) { + /* ignore sign of 'm' */ + if (!BN_copy(aa, m)) { + goto err; + } + aa->neg = 0; + if (BN_RECP_CTX_set(&recp, aa, ctx) <= 0) { + goto err; + } + } else { + if (BN_RECP_CTX_set(&recp, m, ctx) <= 0) { + goto err; + } + } + + if (!BN_nnmod(val[0], a, m, ctx)) { + goto err; /* 1 */ + } + if (BN_is_zero(val[0])) { + BN_zero(r); + ret = 1; + goto err; + } + + window = BN_window_bits_for_exponent_size(bits); + if (window > 1) { + if (!BN_mod_mul_reciprocal(aa, val[0], val[0], &recp, ctx)) { + goto err; /* 2 */ + } + j = 1 << (window - 1); + for (i = 1; i < j; i++) { + if (((val[i] = BN_CTX_get(ctx)) == NULL) || + !BN_mod_mul_reciprocal(val[i], val[i - 1], aa, &recp, ctx)) { + goto err; + } + } + } + + start = 1; /* This is used to avoid multiplication etc + * when there is only the value '1' in the + * buffer. */ + wstart = bits - 1; /* The top bit of the window */ + + if (!BN_one(r)) { + goto err; + } + + for (;;) { + int wvalue; /* The 'value' of the window */ + int wend; /* The bottom bit of the window */ + + if (BN_is_bit_set(p, wstart) == 0) { + if (!start) { + if (!BN_mod_mul_reciprocal(r, r, r, &recp, ctx)) { + goto err; + } + } + if (wstart == 0) { + break; + } + wstart--; + continue; + } + + /* We now have wstart on a 'set' bit, we now need to work out + * how bit a window to do. To do this we need to scan + * forward until the last set bit before the end of the + * window */ + wvalue = 1; + wend = 0; + for (i = 1; i < window; i++) { + if (wstart - i < 0) { + break; + } + if (BN_is_bit_set(p, wstart - i)) { + wvalue <<= (i - wend); + wvalue |= 1; + wend = i; + } + } + + /* wend is the size of the current window */ + j = wend + 1; + /* add the 'bytes above' */ + if (!start) { + for (i = 0; i < j; i++) { + if (!BN_mod_mul_reciprocal(r, r, r, &recp, ctx)) { + goto err; + } + } + } + + /* wvalue will be an odd number < 2^window */ + if (!BN_mod_mul_reciprocal(r, r, val[wvalue >> 1], &recp, ctx)) { + goto err; + } + + /* move the 'window' down further */ + wstart -= wend + 1; + start = 0; + if (wstart < 0) { + break; + } + } + ret = 1; + +err: + BN_CTX_end(ctx); + BN_RECP_CTX_free(&recp); + return ret; +} + +int BN_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m, + BN_CTX *ctx) { + /* For even modulus m = 2^k*m_odd, it might make sense to compute + * a^p mod m_odd and a^p mod 2^k separately (with Montgomery + * exponentiation for the odd part), using appropriate exponent + * reductions, and combine the results using the CRT. + * + * For now, we use Montgomery only if the modulus is odd; otherwise, + * exponentiation using the reciprocal-based quick remaindering + * algorithm is used. + * + * (Timing obtained with expspeed.c [computations a^p mod m + * where a, p, m are of the same length: 256, 512, 1024, 2048, + * 4096, 8192 bits], compared to the running time of the + * standard algorithm: + * + * BN_mod_exp_mont 33 .. 40 % [AMD K6-2, Linux, debug configuration] + * 55 .. 77 % [UltraSparc processor, but + * debug-solaris-sparcv8-gcc conf.] + * + * BN_mod_exp_recp 50 .. 70 % [AMD K6-2, Linux, debug configuration] + * 62 .. 118 % [UltraSparc, debug-solaris-sparcv8-gcc] + * + * On the Sparc, BN_mod_exp_recp was faster than BN_mod_exp_mont + * at 2048 and more bits, but at 512 and 1024 bits, it was + * slower even than the standard algorithm! + * + * "Real" timings [linux-elf, solaris-sparcv9-gcc configurations] + * should be obtained when the new Montgomery reduction code + * has been integrated into OpenSSL.) */ + + if (BN_is_odd(m)) { + if (a->top == 1 && !a->neg && BN_get_flags(p, BN_FLG_CONSTTIME) == 0) { + BN_ULONG A = a->d[0]; + return BN_mod_exp_mont_word(r, A, p, m, ctx, NULL); + } + + return BN_mod_exp_mont(r, a, p, m, ctx, NULL); + } + + return mod_exp_recp(r, a, p, m, ctx); +} + +int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *in_mont) { + int i, j, bits, ret = 0, wstart, window; + int start = 1; + BIGNUM *d, *r; + const BIGNUM *aa; + /* Table of variables obtained from 'ctx' */ + BIGNUM *val[TABLE_SIZE]; + BN_MONT_CTX *mont = NULL; + + if (BN_get_flags(p, BN_FLG_CONSTTIME) != 0) { + return BN_mod_exp_mont_consttime(rr, a, p, m, ctx, in_mont); + } + + if (!BN_is_odd(m)) { + OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS); + return 0; + } + bits = BN_num_bits(p); + if (bits == 0) { + ret = BN_one(rr); + return ret; + } + + BN_CTX_start(ctx); + d = BN_CTX_get(ctx); + r = BN_CTX_get(ctx); + val[0] = BN_CTX_get(ctx); + if (!d || !r || !val[0]) { + goto err; + } + + /* If this is not done, things will break in the montgomery part */ + + if (in_mont != NULL) { + mont = in_mont; + } else { + mont = BN_MONT_CTX_new(); + if (mont == NULL) { + goto err; + } + if (!BN_MONT_CTX_set(mont, m, ctx)) { + goto err; + } + } + + if (a->neg || BN_ucmp(a, m) >= 0) { + if (!BN_nnmod(val[0], a, m, ctx)) { + goto err; + } + aa = val[0]; + } else { + aa = a; + } + + if (BN_is_zero(aa)) { + BN_zero(rr); + ret = 1; + goto err; + } + if (!BN_to_montgomery(val[0], aa, mont, ctx)) { + goto err; /* 1 */ + } + + window = BN_window_bits_for_exponent_size(bits); + if (window > 1) { + if (!BN_mod_mul_montgomery(d, val[0], val[0], mont, ctx)) { + goto err; /* 2 */ + } + j = 1 << (window - 1); + for (i = 1; i < j; i++) { + if (((val[i] = BN_CTX_get(ctx)) == NULL) || + !BN_mod_mul_montgomery(val[i], val[i - 1], d, mont, ctx)) { + goto err; + } + } + } + + start = 1; /* This is used to avoid multiplication etc + * when there is only the value '1' in the + * buffer. */ + wstart = bits - 1; /* The top bit of the window */ + + j = m->top; /* borrow j */ + if (m->d[j - 1] & (((BN_ULONG)1) << (BN_BITS2 - 1))) { + if (bn_wexpand(r, j) == NULL) { + goto err; + } + /* 2^(top*BN_BITS2) - m */ + r->d[0] = (0 - m->d[0]) & BN_MASK2; + for (i = 1; i < j; i++) { + r->d[i] = (~m->d[i]) & BN_MASK2; + } + r->top = j; + /* Upper words will be zero if the corresponding words of 'm' + * were 0xfff[...], so decrement r->top accordingly. */ + bn_correct_top(r); + } else if (!BN_to_montgomery(r, BN_value_one(), mont, ctx)) { + goto err; + } + + for (;;) { + int wvalue; /* The 'value' of the window */ + int wend; /* The bottom bit of the window */ + + if (BN_is_bit_set(p, wstart) == 0) { + if (!start && !BN_mod_mul_montgomery(r, r, r, mont, ctx)) { + goto err; + } + if (wstart == 0) { + break; + } + wstart--; + continue; + } + + /* We now have wstart on a 'set' bit, we now need to work out how bit a + * window to do. To do this we need to scan forward until the last set bit + * before the end of the window */ + wvalue = 1; + wend = 0; + for (i = 1; i < window; i++) { + if (wstart - i < 0) { + break; + } + if (BN_is_bit_set(p, wstart - i)) { + wvalue <<= (i - wend); + wvalue |= 1; + wend = i; + } + } + + /* wend is the size of the current window */ + j = wend + 1; + /* add the 'bytes above' */ + if (!start) { + for (i = 0; i < j; i++) { + if (!BN_mod_mul_montgomery(r, r, r, mont, ctx)) { + goto err; + } + } + } + + /* wvalue will be an odd number < 2^window */ + if (!BN_mod_mul_montgomery(r, r, val[wvalue >> 1], mont, ctx)) { + goto err; + } + + /* move the 'window' down further */ + wstart -= wend + 1; + start = 0; + if (wstart < 0) { + break; + } + } + + if (!BN_from_montgomery(rr, r, mont, ctx)) { + goto err; + } + ret = 1; + +err: + if (in_mont == NULL) { + BN_MONT_CTX_free(mont); + } + BN_CTX_end(ctx); + return ret; +} + +/* BN_mod_exp_mont_consttime() stores the precomputed powers in a specific + * layout so that accessing any of these table values shows the same access + * pattern as far as cache lines are concerned. The following functions are + * used to transfer a BIGNUM from/to that table. */ +static int copy_to_prebuf(const BIGNUM *b, int top, unsigned char *buf, int idx, + int width) { + size_t i, j; + + if (top > b->top) { + top = b->top; /* this works because 'buf' is explicitly zeroed */ + } + for (i = 0, j = idx; i < top * sizeof b->d[0]; i++, j += width) { + buf[j] = ((unsigned char *)b->d)[i]; + } + + return 1; +} + +static int copy_from_prebuf(BIGNUM *b, int top, unsigned char *buf, int idx, + int width) { + size_t i, j; + + if (bn_wexpand(b, top) == NULL) { + return 0; + } + + for (i = 0, j = idx; i < top * sizeof b->d[0]; i++, j += width) { + ((unsigned char *)b->d)[i] = buf[j]; + } + + b->top = top; + bn_correct_top(b); + return 1; +} + +/* BN_mod_exp_mont_conttime is based on the assumption that the L1 data cache + * line width of the target processor is at least the following value. */ +#define MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH (64) +#define MOD_EXP_CTIME_MIN_CACHE_LINE_MASK \ + (MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH - 1) + +/* Window sizes optimized for fixed window size modular exponentiation + * algorithm (BN_mod_exp_mont_consttime). + * + * To achieve the security goals of BN_mode_exp_mont_consttime, the maximum + * size of the window must not exceed + * log_2(MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH). + * + * Window size thresholds are defined for cache line sizes of 32 and 64, cache + * line sizes where log_2(32)=5 and log_2(64)=6 respectively. A window size of + * 7 should only be used on processors that have a 128 byte or greater cache + * line size. */ +#if MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH == 64 + +#define BN_window_bits_for_ctime_exponent_size(b) \ + ((b) > 937 ? 6 : (b) > 306 ? 5 : (b) > 89 ? 4 : (b) > 22 ? 3 : 1) +#define BN_MAX_WINDOW_BITS_FOR_CTIME_EXPONENT_SIZE (6) + +#elif MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH == 32 + +#define BN_window_bits_for_ctime_exponent_size(b) \ + ((b) > 306 ? 5 : (b) > 89 ? 4 : (b) > 22 ? 3 : 1) +#define BN_MAX_WINDOW_BITS_FOR_CTIME_EXPONENT_SIZE (5) + +#endif + +/* Given a pointer value, compute the next address that is a cache line + * multiple. */ +#define MOD_EXP_CTIME_ALIGN(x_) \ + ((unsigned char *)(x_) + \ + (MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH - \ + (((size_t)(x_)) & (MOD_EXP_CTIME_MIN_CACHE_LINE_MASK)))) + +/* This variant of BN_mod_exp_mont() uses fixed windows and the special + * precomputation memory layout to limit data-dependency to a minimum + * to protect secret exponents (cf. the hyper-threading timing attacks + * pointed out by Colin Percival, + * http://www.daemonology.net/hyperthreading-considered-harmful/) + */ +int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, + BN_MONT_CTX *in_mont) { + int i, bits, ret = 0, window, wvalue; + int top; + BN_MONT_CTX *mont = NULL; + + int numPowers; + unsigned char *powerbufFree = NULL; + int powerbufLen = 0; + unsigned char *powerbuf = NULL; + BIGNUM tmp, am; + + top = m->top; + + if (!(m->d[0] & 1)) { + OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS); + return 0; + } + bits = BN_num_bits(p); + if (bits == 0) { + ret = BN_one(rr); + return ret; + } + + BN_CTX_start(ctx); + + /* Allocate a montgomery context if it was not supplied by the caller. + * If this is not done, things will break in the montgomery part. */ + if (in_mont != NULL) { + mont = in_mont; + } else { + mont = BN_MONT_CTX_new(); + if (mont == NULL || !BN_MONT_CTX_set(mont, m, ctx)) { + goto err; + } + } + +#ifdef RSAZ_ENABLED + /* If the size of the operands allow it, perform the optimized + * RSAZ exponentiation. For further information see + * crypto/bn/rsaz_exp.c and accompanying assembly modules. */ + if ((16 == a->top) && (16 == p->top) && (BN_num_bits(m) == 1024) && + rsaz_avx2_eligible()) { + if (NULL == bn_wexpand(rr, 16)) { + goto err; + } + RSAZ_1024_mod_exp_avx2(rr->d, a->d, p->d, m->d, mont->RR.d, mont->n0[0]); + rr->top = 16; + rr->neg = 0; + bn_correct_top(rr); + ret = 1; + goto err; + } else if ((8 == a->top) && (8 == p->top) && (BN_num_bits(m) == 512)) { + if (NULL == bn_wexpand(rr, 8)) { + goto err; + } + RSAZ_512_mod_exp(rr->d, a->d, p->d, m->d, mont->n0[0], mont->RR.d); + rr->top = 8; + rr->neg = 0; + bn_correct_top(rr); + ret = 1; + goto err; + } +#endif + + /* Get the window size to use with size of p. */ + window = BN_window_bits_for_ctime_exponent_size(bits); +#if defined(OPENSSL_BN_ASM_MONT5) + if (window >= 5) { + window = 5; /* ~5% improvement for RSA2048 sign, and even for RSA4096 */ + if ((top & 7) == 0) { + powerbufLen += 2 * top * sizeof(m->d[0]); + } + } +#endif + + /* Allocate a buffer large enough to hold all of the pre-computed + * powers of am, am itself and tmp. + */ + numPowers = 1 << window; + powerbufLen += + sizeof(m->d[0]) * + (top * numPowers + ((2 * top) > numPowers ? (2 * top) : numPowers)); +#ifdef alloca + if (powerbufLen < 3072) { + powerbufFree = alloca(powerbufLen + MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH); + } else +#endif + { + if ((powerbufFree = (unsigned char *)OPENSSL_malloc( + powerbufLen + MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH)) == NULL) { + goto err; + } + } + + powerbuf = MOD_EXP_CTIME_ALIGN(powerbufFree); + memset(powerbuf, 0, powerbufLen); + +#ifdef alloca + if (powerbufLen < 3072) { + powerbufFree = NULL; + } +#endif + + /* lay down tmp and am right after powers table */ + tmp.d = (BN_ULONG *)(powerbuf + sizeof(m->d[0]) * top * numPowers); + am.d = tmp.d + top; + tmp.top = am.top = 0; + tmp.dmax = am.dmax = top; + tmp.neg = am.neg = 0; + tmp.flags = am.flags = BN_FLG_STATIC_DATA; + +/* prepare a^0 in Montgomery domain */ +/* by Shay Gueron's suggestion */ + if (m->d[top - 1] & (((BN_ULONG)1) << (BN_BITS2 - 1))) { + /* 2^(top*BN_BITS2) - m */ + tmp.d[0] = (0 - m->d[0]) & BN_MASK2; + for (i = 1; i < top; i++) { + tmp.d[i] = (~m->d[i]) & BN_MASK2; + } + tmp.top = top; + } else if (!BN_to_montgomery(&tmp, BN_value_one(), mont, ctx)) { + goto err; + } + + /* prepare a^1 in Montgomery domain */ + if (a->neg || BN_ucmp(a, m) >= 0) { + if (!BN_mod(&am, a, m, ctx) || + !BN_to_montgomery(&am, &am, mont, ctx)) { + goto err; + } + } else if (!BN_to_montgomery(&am, a, mont, ctx)) { + goto err; + } + +#if defined(OPENSSL_BN_ASM_MONT5) + /* This optimization uses ideas from http://eprint.iacr.org/2011/239, + * specifically optimization of cache-timing attack countermeasures + * and pre-computation optimization. */ + + /* Dedicated window==4 case improves 512-bit RSA sign by ~15%, but as + * 512-bit RSA is hardly relevant, we omit it to spare size... */ + if (window == 5 && top > 1) { + void bn_mul_mont_gather5(BN_ULONG * rp, const BN_ULONG * ap, + const void * table, const BN_ULONG * np, + const BN_ULONG * n0, int num, int power); + void bn_scatter5(const BN_ULONG * inp, size_t num, void * table, + size_t power); + void bn_gather5(BN_ULONG * out, size_t num, void * table, size_t power); + void bn_power5(BN_ULONG * rp, const BN_ULONG * ap, const void * table, + const BN_ULONG * np, const BN_ULONG * n0, int num, + int power); + int bn_from_montgomery(BN_ULONG * rp, const BN_ULONG * ap, + const BN_ULONG * not_used, const BN_ULONG * np, + const BN_ULONG * n0, int num); + + BN_ULONG *np = mont->N.d, *n0 = mont->n0, *np2; + + /* BN_to_montgomery can contaminate words above .top + * [in BN_DEBUG[_DEBUG] build]... */ + for (i = am.top; i < top; i++) { + am.d[i] = 0; + } + for (i = tmp.top; i < top; i++) { + tmp.d[i] = 0; + } + + if (top & 7) { + np2 = np; + } else { + for (np2 = am.d + top, i = 0; i < top; i++) { + np2[2 * i] = np[i]; + } + } + + bn_scatter5(tmp.d, top, powerbuf, 0); + bn_scatter5(am.d, am.top, powerbuf, 1); + bn_mul_mont(tmp.d, am.d, am.d, np, n0, top); + bn_scatter5(tmp.d, top, powerbuf, 2); + + /* same as above, but uses squaring for 1/2 of operations */ + for (i = 4; i < 32; i *= 2) { + bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top); + bn_scatter5(tmp.d, top, powerbuf, i); + } + for (i = 3; i < 8; i += 2) { + int j; + bn_mul_mont_gather5(tmp.d, am.d, powerbuf, np2, n0, top, i - 1); + bn_scatter5(tmp.d, top, powerbuf, i); + for (j = 2 * i; j < 32; j *= 2) { + bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top); + bn_scatter5(tmp.d, top, powerbuf, j); + } + } + for (; i < 16; i += 2) { + bn_mul_mont_gather5(tmp.d, am.d, powerbuf, np2, n0, top, i - 1); + bn_scatter5(tmp.d, top, powerbuf, i); + bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top); + bn_scatter5(tmp.d, top, powerbuf, 2 * i); + } + for (; i < 32; i += 2) { + bn_mul_mont_gather5(tmp.d, am.d, powerbuf, np2, n0, top, i - 1); + bn_scatter5(tmp.d, top, powerbuf, i); + } + + bits--; + for (wvalue = 0, i = bits % 5; i >= 0; i--, bits--) { + wvalue = (wvalue << 1) + BN_is_bit_set(p, bits); + } + bn_gather5(tmp.d, top, powerbuf, wvalue); + + /* At this point |bits| is 4 mod 5 and at least -1. (|bits| is the first bit + * that has not been read yet.) */ + assert(bits >= -1 && (bits == -1 || bits % 5 == 4)); + + /* Scan the exponent one window at a time starting from the most + * significant bits. + */ + if (top & 7) { + while (bits >= 0) { + for (wvalue = 0, i = 0; i < 5; i++, bits--) { + wvalue = (wvalue << 1) + BN_is_bit_set(p, bits); + } + + bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top); + bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top); + bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top); + bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top); + bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top); + bn_mul_mont_gather5(tmp.d, tmp.d, powerbuf, np, n0, top, wvalue); + } + } else { + const uint8_t *p_bytes = (const uint8_t *)p->d; + int max_bits = p->top * BN_BITS2; + assert(bits < max_bits); + /* |p = 0| has been handled as a special case, so |max_bits| is at least + * one word. */ + assert(max_bits >= 64); + + /* If the first bit to be read lands in the last byte, unroll the first + * iteration to avoid reading past the bounds of |p->d|. (After the first + * iteration, we are guaranteed to be past the last byte.) Note |bits| + * here is the top bit, inclusive. */ + if (bits - 4 >= max_bits - 8) { + /* Read five bits from |bits-4| through |bits|, inclusive. */ + wvalue = p_bytes[p->top * BN_BYTES - 1]; + wvalue >>= (bits - 4) & 7; + wvalue &= 0x1f; + bits -= 5; + bn_power5(tmp.d, tmp.d, powerbuf, np2, n0, top, wvalue); + } + while (bits >= 0) { + /* Read five bits from |bits-4| through |bits|, inclusive. */ + int first_bit = bits - 4; + wvalue = *(const uint16_t *) (p_bytes + (first_bit >> 3)); + wvalue >>= first_bit & 7; + wvalue &= 0x1f; + bits -= 5; + bn_power5(tmp.d, tmp.d, powerbuf, np2, n0, top, wvalue); + } + } + + ret = bn_from_montgomery(tmp.d, tmp.d, NULL, np2, n0, top); + tmp.top = top; + bn_correct_top(&tmp); + if (ret) { + if (!BN_copy(rr, &tmp)) { + ret = 0; + } + goto err; /* non-zero ret means it's not error */ + } + } else +#endif + { + if (!copy_to_prebuf(&tmp, top, powerbuf, 0, numPowers) || + !copy_to_prebuf(&am, top, powerbuf, 1, numPowers)) { + goto err; + } + + /* If the window size is greater than 1, then calculate + * val[i=2..2^winsize-1]. Powers are computed as a*a^(i-1) + * (even powers could instead be computed as (a^(i/2))^2 + * to use the slight performance advantage of sqr over mul). + */ + if (window > 1) { + if (!BN_mod_mul_montgomery(&tmp, &am, &am, mont, ctx) || + !copy_to_prebuf(&tmp, top, powerbuf, 2, numPowers)) { + goto err; + } + for (i = 3; i < numPowers; i++) { + /* Calculate a^i = a^(i-1) * a */ + if (!BN_mod_mul_montgomery(&tmp, &am, &tmp, mont, ctx) || + !copy_to_prebuf(&tmp, top, powerbuf, i, numPowers)) { + goto err; + } + } + } + + bits--; + for (wvalue = 0, i = bits % window; i >= 0; i--, bits--) { + wvalue = (wvalue << 1) + BN_is_bit_set(p, bits); + } + if (!copy_from_prebuf(&tmp, top, powerbuf, wvalue, numPowers)) { + goto err; + } + + /* Scan the exponent one window at a time starting from the most + * significant bits. + */ + while (bits >= 0) { + wvalue = 0; /* The 'value' of the window */ + + /* Scan the window, squaring the result as we go */ + for (i = 0; i < window; i++, bits--) { + if (!BN_mod_mul_montgomery(&tmp, &tmp, &tmp, mont, ctx)) { + goto err; + } + wvalue = (wvalue << 1) + BN_is_bit_set(p, bits); + } + + /* Fetch the appropriate pre-computed value from the pre-buf */ + if (!copy_from_prebuf(&am, top, powerbuf, wvalue, numPowers)) { + goto err; + } + + /* Multiply the result into the intermediate result */ + if (!BN_mod_mul_montgomery(&tmp, &tmp, &am, mont, ctx)) { + goto err; + } + } + } + + /* Convert the final result from montgomery to standard format */ + if (!BN_from_montgomery(rr, &tmp, mont, ctx)) { + goto err; + } + ret = 1; +err: + if (in_mont == NULL) { + BN_MONT_CTX_free(mont); + } + if (powerbuf != NULL) { + OPENSSL_cleanse(powerbuf, powerbufLen); + OPENSSL_free(powerbufFree); + } + BN_CTX_end(ctx); + return (ret); +} + +int BN_mod_exp_mont_word(BIGNUM *rr, BN_ULONG a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *in_mont) { + BN_MONT_CTX *mont = NULL; + int b, bits, ret = 0; + int r_is_one; + BN_ULONG w, next_w; + BIGNUM *d, *r, *t; + BIGNUM *swap_tmp; +#define BN_MOD_MUL_WORD(r, w, m) \ + (BN_mul_word(r, (w)) && \ + (/* BN_ucmp(r, (m)) < 0 ? 1 :*/ \ + (BN_mod(t, r, m, ctx) && (swap_tmp = r, r = t, t = swap_tmp, 1)))) + /* BN_MOD_MUL_WORD is only used with 'w' large, so the BN_ucmp test is + * probably more overhead than always using BN_mod (which uses BN_copy if a + * similar test returns true). We can use BN_mod and do not need BN_nnmod + * because our accumulator is never negative (the result of BN_mod does not + * depend on the sign of the modulus). */ +#define BN_TO_MONTGOMERY_WORD(r, w, mont) \ + (BN_set_word(r, (w)) && BN_to_montgomery(r, r, (mont), ctx)) + + if (BN_get_flags(p, BN_FLG_CONSTTIME) != 0) { + /* BN_FLG_CONSTTIME only supported by BN_mod_exp_mont() */ + OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + + if (!BN_is_odd(m)) { + OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS); + return 0; + } + + if (m->top == 1) { + a %= m->d[0]; /* make sure that 'a' is reduced */ + } + + bits = BN_num_bits(p); + if (bits == 0) { + /* x**0 mod 1 is still zero. */ + if (BN_is_one(m)) { + ret = 1; + BN_zero(rr); + } else { + ret = BN_one(rr); + } + return ret; + } + if (a == 0) { + BN_zero(rr); + ret = 1; + return ret; + } + + BN_CTX_start(ctx); + d = BN_CTX_get(ctx); + r = BN_CTX_get(ctx); + t = BN_CTX_get(ctx); + if (d == NULL || r == NULL || t == NULL) { + goto err; + } + + if (in_mont != NULL) { + mont = in_mont; + } else { + mont = BN_MONT_CTX_new(); + if (mont == NULL || !BN_MONT_CTX_set(mont, m, ctx)) { + goto err; + } + } + + r_is_one = 1; /* except for Montgomery factor */ + + /* bits-1 >= 0 */ + + /* The result is accumulated in the product r*w. */ + w = a; /* bit 'bits-1' of 'p' is always set */ + for (b = bits - 2; b >= 0; b--) { + /* First, square r*w. */ + next_w = w * w; + if ((next_w / w) != w) { + /* overflow */ + if (r_is_one) { + if (!BN_TO_MONTGOMERY_WORD(r, w, mont)) { + goto err; + } + r_is_one = 0; + } else { + if (!BN_MOD_MUL_WORD(r, w, m)) { + goto err; + } + } + next_w = 1; + } + + w = next_w; + if (!r_is_one) { + if (!BN_mod_mul_montgomery(r, r, r, mont, ctx)) { + goto err; + } + } + + /* Second, multiply r*w by 'a' if exponent bit is set. */ + if (BN_is_bit_set(p, b)) { + next_w = w * a; + if ((next_w / a) != w) { + /* overflow */ + if (r_is_one) { + if (!BN_TO_MONTGOMERY_WORD(r, w, mont)) { + goto err; + } + r_is_one = 0; + } else { + if (!BN_MOD_MUL_WORD(r, w, m)) { + goto err; + } + } + next_w = a; + } + w = next_w; + } + } + + /* Finally, set r:=r*w. */ + if (w != 1) { + if (r_is_one) { + if (!BN_TO_MONTGOMERY_WORD(r, w, mont)) { + goto err; + } + r_is_one = 0; + } else { + if (!BN_MOD_MUL_WORD(r, w, m)) { + goto err; + } + } + } + + if (r_is_one) { + /* can happen only if a == 1*/ + if (!BN_one(rr)) { + goto err; + } + } else { + if (!BN_from_montgomery(rr, r, mont, ctx)) { + goto err; + } + } + ret = 1; + +err: + if (in_mont == NULL) { + BN_MONT_CTX_free(mont); + } + BN_CTX_end(ctx); + return ret; +} + +#define TABLE_SIZE 32 + +int BN_mod_exp2_mont(BIGNUM *rr, const BIGNUM *a1, const BIGNUM *p1, + const BIGNUM *a2, const BIGNUM *p2, const BIGNUM *m, + BN_CTX *ctx, BN_MONT_CTX *in_mont) { + int i, j, bits, b, bits1, bits2, ret = 0, wpos1, wpos2, window1, window2, + wvalue1, wvalue2; + int r_is_one = 1; + BIGNUM *d, *r; + const BIGNUM *a_mod_m; + /* Tables of variables obtained from 'ctx' */ + BIGNUM *val1[TABLE_SIZE], *val2[TABLE_SIZE]; + BN_MONT_CTX *mont = NULL; + + if (!(m->d[0] & 1)) { + OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS); + return 0; + } + bits1 = BN_num_bits(p1); + bits2 = BN_num_bits(p2); + if (bits1 == 0 && bits2 == 0) { + ret = BN_one(rr); + return ret; + } + + bits = (bits1 > bits2) ? bits1 : bits2; + + BN_CTX_start(ctx); + d = BN_CTX_get(ctx); + r = BN_CTX_get(ctx); + val1[0] = BN_CTX_get(ctx); + val2[0] = BN_CTX_get(ctx); + if (!d || !r || !val1[0] || !val2[0]) { + goto err; + } + + if (in_mont != NULL) { + mont = in_mont; + } else { + mont = BN_MONT_CTX_new(); + if (mont == NULL) { + goto err; + } + if (!BN_MONT_CTX_set(mont, m, ctx)) { + goto err; + } + } + + window1 = BN_window_bits_for_exponent_size(bits1); + window2 = BN_window_bits_for_exponent_size(bits2); + + /* Build table for a1: val1[i] := a1^(2*i + 1) mod m for i = 0 .. + * 2^(window1-1) */ + if (a1->neg || BN_ucmp(a1, m) >= 0) { + if (!BN_mod(val1[0], a1, m, ctx)) { + goto err; + } + a_mod_m = val1[0]; + } else { + a_mod_m = a1; + } + + if (BN_is_zero(a_mod_m)) { + BN_zero(rr); + ret = 1; + goto err; + } + + if (!BN_to_montgomery(val1[0], a_mod_m, mont, ctx)) { + goto err; + } + + if (window1 > 1) { + if (!BN_mod_mul_montgomery(d, val1[0], val1[0], mont, ctx)) { + goto err; + } + + j = 1 << (window1 - 1); + for (i = 1; i < j; i++) { + if (((val1[i] = BN_CTX_get(ctx)) == NULL) || + !BN_mod_mul_montgomery(val1[i], val1[i - 1], d, mont, ctx)) { + goto err; + } + } + } + + /* Build table for a2: val2[i] := a2^(2*i + 1) mod m for i = 0 .. + * 2^(window2-1) */ + if (a2->neg || BN_ucmp(a2, m) >= 0) { + if (!BN_mod(val2[0], a2, m, ctx)) { + goto err; + } + a_mod_m = val2[0]; + } else { + a_mod_m = a2; + } + + if (BN_is_zero(a_mod_m)) { + BN_zero(rr); + ret = 1; + goto err; + } + + if (!BN_to_montgomery(val2[0], a_mod_m, mont, ctx)) { + goto err; + } + + if (window2 > 1) { + if (!BN_mod_mul_montgomery(d, val2[0], val2[0], mont, ctx)) { + goto err; + } + + j = 1 << (window2 - 1); + for (i = 1; i < j; i++) { + if (((val2[i] = BN_CTX_get(ctx)) == NULL) || + !BN_mod_mul_montgomery(val2[i], val2[i - 1], d, mont, ctx)) { + goto err; + } + } + } + + /* Now compute the power product, using independent windows. */ + r_is_one = 1; + wvalue1 = 0; /* The 'value' of the first window */ + wvalue2 = 0; /* The 'value' of the second window */ + wpos1 = 0; /* If wvalue1 > 0, the bottom bit of the first window */ + wpos2 = 0; /* If wvalue2 > 0, the bottom bit of the second window */ + + if (!BN_to_montgomery(r, BN_value_one(), mont, ctx)) { + goto err; + } + + for (b = bits - 1; b >= 0; b--) { + if (!r_is_one) { + if (!BN_mod_mul_montgomery(r, r, r, mont, ctx)) { + goto err; + } + } + + if (!wvalue1 && BN_is_bit_set(p1, b)) { + /* consider bits b-window1+1 .. b for this window */ + i = b - window1 + 1; + /* works for i<0 */ + while (!BN_is_bit_set(p1, i)) { + i++; + } + wpos1 = i; + wvalue1 = 1; + for (i = b - 1; i >= wpos1; i--) { + wvalue1 <<= 1; + if (BN_is_bit_set(p1, i)) { + wvalue1++; + } + } + } + + if (!wvalue2 && BN_is_bit_set(p2, b)) { + /* consider bits b-window2+1 .. b for this window */ + i = b - window2 + 1; + while (!BN_is_bit_set(p2, i)) { + i++; + } + wpos2 = i; + wvalue2 = 1; + for (i = b - 1; i >= wpos2; i--) { + wvalue2 <<= 1; + if (BN_is_bit_set(p2, i)) { + wvalue2++; + } + } + } + + if (wvalue1 && b == wpos1) { + /* wvalue1 is odd and < 2^window1 */ + if (!BN_mod_mul_montgomery(r, r, val1[wvalue1 >> 1], mont, ctx)) { + goto err; + } + wvalue1 = 0; + r_is_one = 0; + } + + if (wvalue2 && b == wpos2) { + /* wvalue2 is odd and < 2^window2 */ + if (!BN_mod_mul_montgomery(r, r, val2[wvalue2 >> 1], mont, ctx)) { + goto err; + } + wvalue2 = 0; + r_is_one = 0; + } + } + + if (!BN_from_montgomery(rr, r, mont, ctx)) { + goto err; + } + ret = 1; + +err: + if (in_mont == NULL) { + BN_MONT_CTX_free(mont); + } + BN_CTX_end(ctx); + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/gcd.c b/TMessagesProj/jni/boringssl/crypto/bn/gcd.c new file mode 100644 index 00000000..c33a3cd5 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/gcd.c @@ -0,0 +1,697 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include + +#include "internal.h" + +static BIGNUM *euclid(BIGNUM *a, BIGNUM *b) { + BIGNUM *t; + int shifts = 0; + + /* 0 <= b <= a */ + while (!BN_is_zero(b)) { + /* 0 < b <= a */ + + if (BN_is_odd(a)) { + if (BN_is_odd(b)) { + if (!BN_sub(a, a, b)) { + goto err; + } + if (!BN_rshift1(a, a)) { + goto err; + } + if (BN_cmp(a, b) < 0) { + t = a; + a = b; + b = t; + } + } else { + /* a odd - b even */ + if (!BN_rshift1(b, b)) { + goto err; + } + if (BN_cmp(a, b) < 0) { + t = a; + a = b; + b = t; + } + } + } else { + /* a is even */ + if (BN_is_odd(b)) { + if (!BN_rshift1(a, a)) { + goto err; + } + if (BN_cmp(a, b) < 0) { + t = a; + a = b; + b = t; + } + } else { + /* a even - b even */ + if (!BN_rshift1(a, a)) { + goto err; + } + if (!BN_rshift1(b, b)) { + goto err; + } + shifts++; + } + } + /* 0 <= b <= a */ + } + + if (shifts) { + if (!BN_lshift(a, a, shifts)) { + goto err; + } + } + + return a; + +err: + return NULL; +} + +int BN_gcd(BIGNUM *r, const BIGNUM *in_a, const BIGNUM *in_b, BN_CTX *ctx) { + BIGNUM *a, *b, *t; + int ret = 0; + + BN_CTX_start(ctx); + a = BN_CTX_get(ctx); + b = BN_CTX_get(ctx); + + if (a == NULL || b == NULL) { + goto err; + } + if (BN_copy(a, in_a) == NULL) { + goto err; + } + if (BN_copy(b, in_b) == NULL) { + goto err; + } + + a->neg = 0; + b->neg = 0; + + if (BN_cmp(a, b) < 0) { + t = a; + a = b; + b = t; + } + t = euclid(a, b); + if (t == NULL) { + goto err; + } + + if (BN_copy(r, t) == NULL) { + goto err; + } + ret = 1; + +err: + BN_CTX_end(ctx); + return ret; +} + +/* solves ax == 1 (mod n) */ +static BIGNUM *BN_mod_inverse_no_branch(BIGNUM *out, const BIGNUM *a, + const BIGNUM *n, BN_CTX *ctx); + +BIGNUM *BN_mod_inverse(BIGNUM *out, const BIGNUM *a, const BIGNUM *n, + BN_CTX *ctx) { + BIGNUM *A, *B, *X, *Y, *M, *D, *T, *R = NULL; + BIGNUM *ret = NULL; + int sign; + + if ((a->flags & BN_FLG_CONSTTIME) != 0 || + (n->flags & BN_FLG_CONSTTIME) != 0) { + return BN_mod_inverse_no_branch(out, a, n, ctx); + } + + BN_CTX_start(ctx); + A = BN_CTX_get(ctx); + B = BN_CTX_get(ctx); + X = BN_CTX_get(ctx); + D = BN_CTX_get(ctx); + M = BN_CTX_get(ctx); + Y = BN_CTX_get(ctx); + T = BN_CTX_get(ctx); + if (T == NULL) { + goto err; + } + + if (out == NULL) { + R = BN_new(); + } else { + R = out; + } + if (R == NULL) { + goto err; + } + + BN_zero(Y); + if (!BN_one(X) || BN_copy(B, a) == NULL || BN_copy(A, n) == NULL) { + goto err; + } + A->neg = 0; + if (B->neg || (BN_ucmp(B, A) >= 0)) { + if (!BN_nnmod(B, B, A, ctx)) { + goto err; + } + } + sign = -1; + /* From B = a mod |n|, A = |n| it follows that + * + * 0 <= B < A, + * -sign*X*a == B (mod |n|), + * sign*Y*a == A (mod |n|). + */ + + if (BN_is_odd(n) && (BN_num_bits(n) <= (BN_BITS <= 32 ? 450 : 2048))) { + /* Binary inversion algorithm; requires odd modulus. + * This is faster than the general algorithm if the modulus + * is sufficiently small (about 400 .. 500 bits on 32-bit + * sytems, but much more on 64-bit systems) */ + int shift; + + while (!BN_is_zero(B)) { + /* 0 < B < |n|, + * 0 < A <= |n|, + * (1) -sign*X*a == B (mod |n|), + * (2) sign*Y*a == A (mod |n|) */ + + /* Now divide B by the maximum possible power of two in the integers, + * and divide X by the same value mod |n|. + * When we're done, (1) still holds. */ + shift = 0; + while (!BN_is_bit_set(B, shift)) { + /* note that 0 < B */ + shift++; + + if (BN_is_odd(X)) { + if (!BN_uadd(X, X, n)) { + goto err; + } + } + /* now X is even, so we can easily divide it by two */ + if (!BN_rshift1(X, X)) { + goto err; + } + } + if (shift > 0) { + if (!BN_rshift(B, B, shift)) { + goto err; + } + } + + /* Same for A and Y. Afterwards, (2) still holds. */ + shift = 0; + while (!BN_is_bit_set(A, shift)) { + /* note that 0 < A */ + shift++; + + if (BN_is_odd(Y)) { + if (!BN_uadd(Y, Y, n)) { + goto err; + } + } + /* now Y is even */ + if (!BN_rshift1(Y, Y)) { + goto err; + } + } + if (shift > 0) { + if (!BN_rshift(A, A, shift)) { + goto err; + } + } + + /* We still have (1) and (2). + * Both A and B are odd. + * The following computations ensure that + * + * 0 <= B < |n|, + * 0 < A < |n|, + * (1) -sign*X*a == B (mod |n|), + * (2) sign*Y*a == A (mod |n|), + * + * and that either A or B is even in the next iteration. */ + if (BN_ucmp(B, A) >= 0) { + /* -sign*(X + Y)*a == B - A (mod |n|) */ + if (!BN_uadd(X, X, Y)) { + goto err; + } + /* NB: we could use BN_mod_add_quick(X, X, Y, n), but that + * actually makes the algorithm slower */ + if (!BN_usub(B, B, A)) { + goto err; + } + } else { + /* sign*(X + Y)*a == A - B (mod |n|) */ + if (!BN_uadd(Y, Y, X)) { + goto err; + } + /* as above, BN_mod_add_quick(Y, Y, X, n) would slow things down */ + if (!BN_usub(A, A, B)) { + goto err; + } + } + } + } else { + /* general inversion algorithm */ + + while (!BN_is_zero(B)) { + BIGNUM *tmp; + + /* + * 0 < B < A, + * (*) -sign*X*a == B (mod |n|), + * sign*Y*a == A (mod |n|) */ + + /* (D, M) := (A/B, A%B) ... */ + if (BN_num_bits(A) == BN_num_bits(B)) { + if (!BN_one(D)) { + goto err; + } + if (!BN_sub(M, A, B)) { + goto err; + } + } else if (BN_num_bits(A) == BN_num_bits(B) + 1) { + /* A/B is 1, 2, or 3 */ + if (!BN_lshift1(T, B)) { + goto err; + } + if (BN_ucmp(A, T) < 0) { + /* A < 2*B, so D=1 */ + if (!BN_one(D)) { + goto err; + } + if (!BN_sub(M, A, B)) { + goto err; + } + } else { + /* A >= 2*B, so D=2 or D=3 */ + if (!BN_sub(M, A, T)) { + goto err; + } + if (!BN_add(D, T, B)) { + goto err; /* use D (:= 3*B) as temp */ + } + if (BN_ucmp(A, D) < 0) { + /* A < 3*B, so D=2 */ + if (!BN_set_word(D, 2)) { + goto err; + } + /* M (= A - 2*B) already has the correct value */ + } else { + /* only D=3 remains */ + if (!BN_set_word(D, 3)) { + goto err; + } + /* currently M = A - 2*B, but we need M = A - 3*B */ + if (!BN_sub(M, M, B)) { + goto err; + } + } + } + } else { + if (!BN_div(D, M, A, B, ctx)) { + goto err; + } + } + + /* Now + * A = D*B + M; + * thus we have + * (**) sign*Y*a == D*B + M (mod |n|). */ + + tmp = A; /* keep the BIGNUM object, the value does not matter */ + + /* (A, B) := (B, A mod B) ... */ + A = B; + B = M; + /* ... so we have 0 <= B < A again */ + + /* Since the former M is now B and the former B is now A, + * (**) translates into + * sign*Y*a == D*A + B (mod |n|), + * i.e. + * sign*Y*a - D*A == B (mod |n|). + * Similarly, (*) translates into + * -sign*X*a == A (mod |n|). + * + * Thus, + * sign*Y*a + D*sign*X*a == B (mod |n|), + * i.e. + * sign*(Y + D*X)*a == B (mod |n|). + * + * So if we set (X, Y, sign) := (Y + D*X, X, -sign), we arrive back at + * -sign*X*a == B (mod |n|), + * sign*Y*a == A (mod |n|). + * Note that X and Y stay non-negative all the time. */ + + /* most of the time D is very small, so we can optimize tmp := D*X+Y */ + if (BN_is_one(D)) { + if (!BN_add(tmp, X, Y)) { + goto err; + } + } else { + if (BN_is_word(D, 2)) { + if (!BN_lshift1(tmp, X)) { + goto err; + } + } else if (BN_is_word(D, 4)) { + if (!BN_lshift(tmp, X, 2)) { + goto err; + } + } else if (D->top == 1) { + if (!BN_copy(tmp, X)) { + goto err; + } + if (!BN_mul_word(tmp, D->d[0])) { + goto err; + } + } else { + if (!BN_mul(tmp, D, X, ctx)) { + goto err; + } + } + if (!BN_add(tmp, tmp, Y)) { + goto err; + } + } + + M = Y; /* keep the BIGNUM object, the value does not matter */ + Y = X; + X = tmp; + sign = -sign; + } + } + + /* The while loop (Euclid's algorithm) ends when + * A == gcd(a,n); + * we have + * sign*Y*a == A (mod |n|), + * where Y is non-negative. */ + + if (sign < 0) { + if (!BN_sub(Y, n, Y)) { + goto err; + } + } + /* Now Y*a == A (mod |n|). */ + + if (BN_is_one(A)) { + /* Y*a == 1 (mod |n|) */ + if (!Y->neg && BN_ucmp(Y, n) < 0) { + if (!BN_copy(R, Y)) { + goto err; + } + } else { + if (!BN_nnmod(R, Y, n, ctx)) { + goto err; + } + } + } else { + OPENSSL_PUT_ERROR(BN, BN_R_NO_INVERSE); + goto err; + } + ret = R; + +err: + if (ret == NULL && out == NULL) { + BN_free(R); + } + BN_CTX_end(ctx); + return ret; +} + +/* BN_mod_inverse_no_branch is a special version of BN_mod_inverse. + * It does not contain branches that may leak sensitive information. */ +static BIGNUM *BN_mod_inverse_no_branch(BIGNUM *out, const BIGNUM *a, + const BIGNUM *n, BN_CTX *ctx) { + BIGNUM *A, *B, *X, *Y, *M, *D, *T, *R = NULL; + BIGNUM local_A, local_B; + BIGNUM *pA, *pB; + BIGNUM *ret = NULL; + int sign; + + BN_CTX_start(ctx); + A = BN_CTX_get(ctx); + B = BN_CTX_get(ctx); + X = BN_CTX_get(ctx); + D = BN_CTX_get(ctx); + M = BN_CTX_get(ctx); + Y = BN_CTX_get(ctx); + T = BN_CTX_get(ctx); + if (T == NULL) { + goto err; + } + + if (out == NULL) { + R = BN_new(); + } else { + R = out; + } + if (R == NULL) { + goto err; + } + + BN_zero(Y); + if (!BN_one(X) || BN_copy(B, a) == NULL || BN_copy(A, n) == NULL) { + goto err; + } + A->neg = 0; + + if (B->neg || (BN_ucmp(B, A) >= 0)) { + /* Turn BN_FLG_CONSTTIME flag on, so that when BN_div is invoked, + * BN_div_no_branch will be called eventually. + */ + pB = &local_B; + BN_with_flags(pB, B, BN_FLG_CONSTTIME); + if (!BN_nnmod(B, pB, A, ctx)) { + goto err; + } + } + sign = -1; + /* From B = a mod |n|, A = |n| it follows that + * + * 0 <= B < A, + * -sign*X*a == B (mod |n|), + * sign*Y*a == A (mod |n|). + */ + + while (!BN_is_zero(B)) { + BIGNUM *tmp; + + /* + * 0 < B < A, + * (*) -sign*X*a == B (mod |n|), + * sign*Y*a == A (mod |n|) + */ + + /* Turn BN_FLG_CONSTTIME flag on, so that when BN_div is invoked, + * BN_div_no_branch will be called eventually. + */ + pA = &local_A; + BN_with_flags(pA, A, BN_FLG_CONSTTIME); + + /* (D, M) := (A/B, A%B) ... */ + if (!BN_div(D, M, pA, B, ctx)) { + goto err; + } + + /* Now + * A = D*B + M; + * thus we have + * (**) sign*Y*a == D*B + M (mod |n|). + */ + + tmp = A; /* keep the BIGNUM object, the value does not matter */ + + /* (A, B) := (B, A mod B) ... */ + A = B; + B = M; + /* ... so we have 0 <= B < A again */ + + /* Since the former M is now B and the former B is now A, + * (**) translates into + * sign*Y*a == D*A + B (mod |n|), + * i.e. + * sign*Y*a - D*A == B (mod |n|). + * Similarly, (*) translates into + * -sign*X*a == A (mod |n|). + * + * Thus, + * sign*Y*a + D*sign*X*a == B (mod |n|), + * i.e. + * sign*(Y + D*X)*a == B (mod |n|). + * + * So if we set (X, Y, sign) := (Y + D*X, X, -sign), we arrive back at + * -sign*X*a == B (mod |n|), + * sign*Y*a == A (mod |n|). + * Note that X and Y stay non-negative all the time. + */ + + if (!BN_mul(tmp, D, X, ctx)) { + goto err; + } + if (!BN_add(tmp, tmp, Y)) { + goto err; + } + + M = Y; /* keep the BIGNUM object, the value does not matter */ + Y = X; + X = tmp; + sign = -sign; + } + + /* + * The while loop (Euclid's algorithm) ends when + * A == gcd(a,n); + * we have + * sign*Y*a == A (mod |n|), + * where Y is non-negative. + */ + + if (sign < 0) { + if (!BN_sub(Y, n, Y)) { + goto err; + } + } + /* Now Y*a == A (mod |n|). */ + + if (BN_is_one(A)) { + /* Y*a == 1 (mod |n|) */ + if (!Y->neg && BN_ucmp(Y, n) < 0) { + if (!BN_copy(R, Y)) { + goto err; + } + } else { + if (!BN_nnmod(R, Y, n, ctx)) { + goto err; + } + } + } else { + OPENSSL_PUT_ERROR(BN, BN_R_NO_INVERSE); + goto err; + } + ret = R; + +err: + if (ret == NULL && out == NULL) { + BN_free(R); + } + + BN_CTX_end(ctx); + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/generic.c b/TMessagesProj/jni/boringssl/crypto/bn/generic.c new file mode 100644 index 00000000..0e7d867c --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/generic.c @@ -0,0 +1,1131 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include "internal.h" + + +/* Generic implementations of most operations are needed for: + * - Configurations without inline assembly. + * - Architectures other than x86 or x86_64. + * - Windows x84_64; x86_64-gcc.c does not build on MSVC. */ +#if defined(OPENSSL_NO_ASM) || \ + (!defined(OPENSSL_X86_64) && !defined(OPENSSL_X86)) || \ + (defined(OPENSSL_X86_64) && defined(OPENSSL_WINDOWS)) + +#if defined(OPENSSL_WINDOWS) +#define alloca _alloca +#else +#include +#endif + +#ifdef BN_LLONG +#define mul_add(r, a, w, c) \ + { \ + BN_ULLONG t; \ + t = (BN_ULLONG)w * (a) + (r) + (c); \ + (r) = Lw(t); \ + (c) = Hw(t); \ + } + +#define mul(r, a, w, c) \ + { \ + BN_ULLONG t; \ + t = (BN_ULLONG)w * (a) + (c); \ + (r) = Lw(t); \ + (c) = Hw(t); \ + } + +#define sqr(r0, r1, a) \ + { \ + BN_ULLONG t; \ + t = (BN_ULLONG)(a) * (a); \ + (r0) = Lw(t); \ + (r1) = Hw(t); \ + } + +#elif defined(BN_UMULT_LOHI) +#define mul_add(r, a, w, c) \ + { \ + BN_ULONG high, low, ret, tmp = (a); \ + ret = (r); \ + BN_UMULT_LOHI(low, high, w, tmp); \ + ret += (c); \ + (c) = (ret < (c)) ? 1 : 0; \ + (c) += high; \ + ret += low; \ + (c) += (ret < low) ? 1 : 0; \ + (r) = ret; \ + } + +#define mul(r, a, w, c) \ + { \ + BN_ULONG high, low, ret, ta = (a); \ + BN_UMULT_LOHI(low, high, w, ta); \ + ret = low + (c); \ + (c) = high; \ + (c) += (ret < low) ? 1 : 0; \ + (r) = ret; \ + } + +#define sqr(r0, r1, a) \ + { \ + BN_ULONG tmp = (a); \ + BN_UMULT_LOHI(r0, r1, tmp, tmp); \ + } + +#else + +/************************************************************* + * No long long type + */ + +#define LBITS(a) ((a) & BN_MASK2l) +#define HBITS(a) (((a) >> BN_BITS4) & BN_MASK2l) +#define L2HBITS(a) (((a) << BN_BITS4) & BN_MASK2) + +#define LLBITS(a) ((a) & BN_MASKl) +#define LHBITS(a) (((a) >> BN_BITS2) & BN_MASKl) +#define LL2HBITS(a) ((BN_ULLONG)((a) & BN_MASKl) << BN_BITS2) + +#define mul64(l, h, bl, bh) \ + { \ + BN_ULONG m, m1, lt, ht; \ + \ + lt = l; \ + ht = h; \ + m = (bh) * (lt); \ + lt = (bl) * (lt); \ + m1 = (bl) * (ht); \ + ht = (bh) * (ht); \ + m = (m + m1) & BN_MASK2; \ + if (m < m1) \ + ht += L2HBITS((BN_ULONG)1); \ + ht += HBITS(m); \ + m1 = L2HBITS(m); \ + lt = (lt + m1) & BN_MASK2; \ + if (lt < m1) \ + ht++; \ + (l) = lt; \ + (h) = ht; \ + } + +#define sqr64(lo, ho, in) \ + { \ + BN_ULONG l, h, m; \ + \ + h = (in); \ + l = LBITS(h); \ + h = HBITS(h); \ + m = (l) * (h); \ + l *= l; \ + h *= h; \ + h += (m & BN_MASK2h1) >> (BN_BITS4 - 1); \ + m = (m & BN_MASK2l) << (BN_BITS4 + 1); \ + l = (l + m) & BN_MASK2; \ + if (l < m) \ + h++; \ + (lo) = l; \ + (ho) = h; \ + } + +#define mul_add(r, a, bl, bh, c) \ + { \ + BN_ULONG l, h; \ + \ + h = (a); \ + l = LBITS(h); \ + h = HBITS(h); \ + mul64(l, h, (bl), (bh)); \ + \ + /* non-multiply part */ \ + l = (l + (c)) & BN_MASK2; \ + if (l < (c)) \ + h++; \ + (c) = (r); \ + l = (l + (c)) & BN_MASK2; \ + if (l < (c)) \ + h++; \ + (c) = h & BN_MASK2; \ + (r) = l; \ + } + +#define mul(r, a, bl, bh, c) \ + { \ + BN_ULONG l, h; \ + \ + h = (a); \ + l = LBITS(h); \ + h = HBITS(h); \ + mul64(l, h, (bl), (bh)); \ + \ + /* non-multiply part */ \ + l += (c); \ + if ((l & BN_MASK2) < (c)) \ + h++; \ + (c) = h & BN_MASK2; \ + (r) = l & BN_MASK2; \ + } +#endif /* !BN_LLONG */ + +#if defined(BN_LLONG) || defined(BN_UMULT_HIGH) + +BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num, + BN_ULONG w) { + BN_ULONG c1 = 0; + + assert(num >= 0); + if (num <= 0) { + return c1; + } + + while (num & ~3) { + mul_add(rp[0], ap[0], w, c1); + mul_add(rp[1], ap[1], w, c1); + mul_add(rp[2], ap[2], w, c1); + mul_add(rp[3], ap[3], w, c1); + ap += 4; + rp += 4; + num -= 4; + } + + while (num) { + mul_add(rp[0], ap[0], w, c1); + ap++; + rp++; + num--; + } + + return c1; +} + +BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w) { + BN_ULONG c1 = 0; + + assert(num >= 0); + if (num <= 0) { + return c1; + } + + while (num & ~3) { + mul(rp[0], ap[0], w, c1); + mul(rp[1], ap[1], w, c1); + mul(rp[2], ap[2], w, c1); + mul(rp[3], ap[3], w, c1); + ap += 4; + rp += 4; + num -= 4; + } + while (num) { + mul(rp[0], ap[0], w, c1); + ap++; + rp++; + num--; + } + return c1; +} + +void bn_sqr_words(BN_ULONG *r, const BN_ULONG *a, int n) { + assert(n >= 0); + if (n <= 0) { + return; + } + + while (n & ~3) { + sqr(r[0], r[1], a[0]); + sqr(r[2], r[3], a[1]); + sqr(r[4], r[5], a[2]); + sqr(r[6], r[7], a[3]); + a += 4; + r += 8; + n -= 4; + } + while (n) { + sqr(r[0], r[1], a[0]); + a++; + r += 2; + n--; + } +} + +#else /* !(defined(BN_LLONG) || defined(BN_UMULT_HIGH)) */ + +BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num, + BN_ULONG w) { + BN_ULONG c = 0; + BN_ULONG bl, bh; + + assert(num >= 0); + if (num <= 0) { + return (BN_ULONG)0; + } + + bl = LBITS(w); + bh = HBITS(w); + + while (num & ~3) { + mul_add(rp[0], ap[0], bl, bh, c); + mul_add(rp[1], ap[1], bl, bh, c); + mul_add(rp[2], ap[2], bl, bh, c); + mul_add(rp[3], ap[3], bl, bh, c); + ap += 4; + rp += 4; + num -= 4; + } + while (num) { + mul_add(rp[0], ap[0], bl, bh, c); + ap++; + rp++; + num--; + } + return c; +} + +BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w) { + BN_ULONG carry = 0; + BN_ULONG bl, bh; + + assert(num >= 0); + if (num <= 0) { + return (BN_ULONG)0; + } + + bl = LBITS(w); + bh = HBITS(w); + + while (num & ~3) { + mul(rp[0], ap[0], bl, bh, carry); + mul(rp[1], ap[1], bl, bh, carry); + mul(rp[2], ap[2], bl, bh, carry); + mul(rp[3], ap[3], bl, bh, carry); + ap += 4; + rp += 4; + num -= 4; + } + while (num) { + mul(rp[0], ap[0], bl, bh, carry); + ap++; + rp++; + num--; + } + return carry; +} + +void bn_sqr_words(BN_ULONG *r, const BN_ULONG *a, int n) { + assert(n >= 0); + if (n <= 0) { + return; + } + + while (n & ~3) { + sqr64(r[0], r[1], a[0]); + sqr64(r[2], r[3], a[1]); + sqr64(r[4], r[5], a[2]); + sqr64(r[6], r[7], a[3]); + a += 4; + r += 8; + n -= 4; + } + while (n) { + sqr64(r[0], r[1], a[0]); + a++; + r += 2; + n--; + } +} + +#endif /* !(defined(BN_LLONG) || defined(BN_UMULT_HIGH)) */ + +#if defined(BN_LLONG) + +BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d) { + return (BN_ULONG)(((((BN_ULLONG)h) << BN_BITS2) | l) / (BN_ULLONG)d); +} + +#else + +/* Divide h,l by d and return the result. */ +BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d) { + BN_ULONG dh, dl, q, ret = 0, th, tl, t; + int i, count = 2; + + if (d == 0) { + return BN_MASK2; + } + + i = BN_num_bits_word(d); + assert((i == BN_BITS2) || (h <= (BN_ULONG)1 << i)); + + i = BN_BITS2 - i; + if (h >= d) { + h -= d; + } + + if (i) { + d <<= i; + h = (h << i) | (l >> (BN_BITS2 - i)); + l <<= i; + } + dh = (d & BN_MASK2h) >> BN_BITS4; + dl = (d & BN_MASK2l); + for (;;) { + if ((h >> BN_BITS4) == dh) { + q = BN_MASK2l; + } else { + q = h / dh; + } + + th = q * dh; + tl = dl * q; + for (;;) { + t = h - th; + if ((t & BN_MASK2h) || + ((tl) <= ((t << BN_BITS4) | ((l & BN_MASK2h) >> BN_BITS4)))) { + break; + } + q--; + th -= dh; + tl -= dl; + } + t = (tl >> BN_BITS4); + tl = (tl << BN_BITS4) & BN_MASK2h; + th += t; + + if (l < tl) { + th++; + } + l -= tl; + if (h < th) { + h += d; + q--; + } + h -= th; + + if (--count == 0) { + break; + } + + ret = q << BN_BITS4; + h = ((h << BN_BITS4) | (l >> BN_BITS4)) & BN_MASK2; + l = (l & BN_MASK2l) << BN_BITS4; + } + + ret |= q; + return ret; +} + +#endif /* !defined(BN_LLONG) */ + +#ifdef BN_LLONG +BN_ULONG bn_add_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, + int n) { + BN_ULLONG ll = 0; + + assert(n >= 0); + if (n <= 0) { + return (BN_ULONG)0; + } + + while (n & ~3) { + ll += (BN_ULLONG)a[0] + b[0]; + r[0] = (BN_ULONG)ll & BN_MASK2; + ll >>= BN_BITS2; + ll += (BN_ULLONG)a[1] + b[1]; + r[1] = (BN_ULONG)ll & BN_MASK2; + ll >>= BN_BITS2; + ll += (BN_ULLONG)a[2] + b[2]; + r[2] = (BN_ULONG)ll & BN_MASK2; + ll >>= BN_BITS2; + ll += (BN_ULLONG)a[3] + b[3]; + r[3] = (BN_ULONG)ll & BN_MASK2; + ll >>= BN_BITS2; + a += 4; + b += 4; + r += 4; + n -= 4; + } + while (n) { + ll += (BN_ULLONG)a[0] + b[0]; + r[0] = (BN_ULONG)ll & BN_MASK2; + ll >>= BN_BITS2; + a++; + b++; + r++; + n--; + } + return (BN_ULONG)ll; +} + +#else /* !BN_LLONG */ + +BN_ULONG bn_add_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, + int n) { + BN_ULONG c, l, t; + + assert(n >= 0); + if (n <= 0) { + return (BN_ULONG)0; + } + + c = 0; + while (n & ~3) { + t = a[0]; + t = (t + c) & BN_MASK2; + c = (t < c); + l = (t + b[0]) & BN_MASK2; + c += (l < t); + r[0] = l; + t = a[1]; + t = (t + c) & BN_MASK2; + c = (t < c); + l = (t + b[1]) & BN_MASK2; + c += (l < t); + r[1] = l; + t = a[2]; + t = (t + c) & BN_MASK2; + c = (t < c); + l = (t + b[2]) & BN_MASK2; + c += (l < t); + r[2] = l; + t = a[3]; + t = (t + c) & BN_MASK2; + c = (t < c); + l = (t + b[3]) & BN_MASK2; + c += (l < t); + r[3] = l; + a += 4; + b += 4; + r += 4; + n -= 4; + } + while (n) { + t = a[0]; + t = (t + c) & BN_MASK2; + c = (t < c); + l = (t + b[0]) & BN_MASK2; + c += (l < t); + r[0] = l; + a++; + b++; + r++; + n--; + } + return (BN_ULONG)c; +} + +#endif /* !BN_LLONG */ + +BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, + int n) { + BN_ULONG t1, t2; + int c = 0; + + assert(n >= 0); + if (n <= 0) { + return (BN_ULONG)0; + } + + while (n & ~3) { + t1 = a[0]; + t2 = b[0]; + r[0] = (t1 - t2 - c) & BN_MASK2; + if (t1 != t2) { + c = (t1 < t2); + } + t1 = a[1]; + t2 = b[1]; + r[1] = (t1 - t2 - c) & BN_MASK2; + if (t1 != t2) { + c = (t1 < t2); + } + t1 = a[2]; + t2 = b[2]; + r[2] = (t1 - t2 - c) & BN_MASK2; + if (t1 != t2) { + c = (t1 < t2); + } + t1 = a[3]; + t2 = b[3]; + r[3] = (t1 - t2 - c) & BN_MASK2; + if (t1 != t2) { + c = (t1 < t2); + } + a += 4; + b += 4; + r += 4; + n -= 4; + } + while (n) { + t1 = a[0]; + t2 = b[0]; + r[0] = (t1 - t2 - c) & BN_MASK2; + if (t1 != t2) { + c = (t1 < t2); + } + a++; + b++; + r++; + n--; + } + return c; +} + +/* mul_add_c(a,b,c0,c1,c2) -- c+=a*b for three word number c=(c2,c1,c0) */ +/* mul_add_c2(a,b,c0,c1,c2) -- c+=2*a*b for three word number c=(c2,c1,c0) */ +/* sqr_add_c(a,i,c0,c1,c2) -- c+=a[i]^2 for three word number c=(c2,c1,c0) */ +/* sqr_add_c2(a,i,c0,c1,c2) -- c+=2*a[i]*a[j] for three word number c=(c2,c1,c0) */ + +#ifdef BN_LLONG + +/* Keep in mind that additions to multiplication result can not overflow, + * because its high half cannot be all-ones. */ +#define mul_add_c(a, b, c0, c1, c2) \ + do { \ + BN_ULONG hi; \ + BN_ULLONG t = (BN_ULLONG)(a) * (b); \ + t += c0; /* no carry */ \ + c0 = (BN_ULONG)Lw(t); \ + hi = (BN_ULONG)Hw(t); \ + c1 = (c1 + hi) & BN_MASK2; \ + if (c1 < hi) \ + c2++; \ + } while (0) + +#define mul_add_c2(a, b, c0, c1, c2) \ + do { \ + BN_ULONG hi; \ + BN_ULLONG t = (BN_ULLONG)(a) * (b); \ + BN_ULLONG tt = t + c0; /* no carry */ \ + c0 = (BN_ULONG)Lw(tt); \ + hi = (BN_ULONG)Hw(tt); \ + c1 = (c1 + hi) & BN_MASK2; \ + if (c1 < hi) \ + c2++; \ + t += c0; /* no carry */ \ + c0 = (BN_ULONG)Lw(t); \ + hi = (BN_ULONG)Hw(t); \ + c1 = (c1 + hi) & BN_MASK2; \ + if (c1 < hi) \ + c2++; \ + } while (0) + +#define sqr_add_c(a, i, c0, c1, c2) \ + do { \ + BN_ULONG hi; \ + BN_ULLONG t = (BN_ULLONG)a[i] * a[i]; \ + t += c0; /* no carry */ \ + c0 = (BN_ULONG)Lw(t); \ + hi = (BN_ULONG)Hw(t); \ + c1 = (c1 + hi) & BN_MASK2; \ + if (c1 < hi) \ + c2++; \ + } while (0) + +#define sqr_add_c2(a, i, j, c0, c1, c2) mul_add_c2((a)[i], (a)[j], c0, c1, c2) + +#elif defined(BN_UMULT_LOHI) + +/* Keep in mind that additions to hi can not overflow, because the high word of + * a multiplication result cannot be all-ones. */ +#define mul_add_c(a, b, c0, c1, c2) \ + do { \ + BN_ULONG ta = (a), tb = (b); \ + BN_ULONG lo, hi; \ + BN_UMULT_LOHI(lo, hi, ta, tb); \ + c0 += lo; \ + hi += (c0 < lo) ? 1 : 0; \ + c1 += hi; \ + c2 += (c1 < hi) ? 1 : 0; \ + } while (0) + +#define mul_add_c2(a, b, c0, c1, c2) \ + do { \ + BN_ULONG ta = (a), tb = (b); \ + BN_ULONG lo, hi, tt; \ + BN_UMULT_LOHI(lo, hi, ta, tb); \ + c0 += lo; \ + tt = hi + ((c0 < lo) ? 1 : 0); \ + c1 += tt; \ + c2 += (c1 < tt) ? 1 : 0; \ + c0 += lo; \ + hi += (c0 < lo) ? 1 : 0; \ + c1 += hi; \ + c2 += (c1 < hi) ? 1 : 0; \ + } while (0) + +#define sqr_add_c(a, i, c0, c1, c2) \ + do { \ + BN_ULONG ta = (a)[i]; \ + BN_ULONG lo, hi; \ + BN_UMULT_LOHI(lo, hi, ta, ta); \ + c0 += lo; \ + hi += (c0 < lo) ? 1 : 0; \ + c1 += hi; \ + c2 += (c1 < hi) ? 1 : 0; \ + } while (0) + +#define sqr_add_c2(a, i, j, c0, c1, c2) mul_add_c2((a)[i], (a)[j], c0, c1, c2) + +#else /* !BN_LLONG */ + +/* Keep in mind that additions to hi can not overflow, because + * the high word of a multiplication result cannot be all-ones. */ + +#define mul_add_c(a, b, c0, c1, c2) \ + do { \ + BN_ULONG lo = LBITS(a), hi = HBITS(a); \ + BN_ULONG bl = LBITS(b), bh = HBITS(b); \ + mul64(lo, hi, bl, bh); \ + c0 = (c0 + lo) & BN_MASK2; \ + if (c0 < lo) \ + hi++; \ + c1 = (c1 + hi) & BN_MASK2; \ + if (c1 < hi) \ + c2++; \ + } while (0) + +#define mul_add_c2(a, b, c0, c1, c2) \ + do { \ + BN_ULONG tt; \ + BN_ULONG lo = LBITS(a), hi = HBITS(a); \ + BN_ULONG bl = LBITS(b), bh = HBITS(b); \ + mul64(lo, hi, bl, bh); \ + tt = hi; \ + c0 = (c0 + lo) & BN_MASK2; \ + if (c0 < lo) \ + tt++; \ + c1 = (c1 + tt) & BN_MASK2; \ + if (c1 < tt) \ + c2++; \ + c0 = (c0 + lo) & BN_MASK2; \ + if (c0 < lo) \ + hi++; \ + c1 = (c1 + hi) & BN_MASK2; \ + if (c1 < hi) \ + c2++; \ + } while (0) + +#define sqr_add_c(a, i, c0, c1, c2) \ + do { \ + BN_ULONG lo, hi; \ + sqr64(lo, hi, (a)[i]); \ + c0 = (c0 + lo) & BN_MASK2; \ + if (c0 < lo) \ + hi++; \ + c1 = (c1 + hi) & BN_MASK2; \ + if (c1 < hi) \ + c2++; \ + } while (0) + +#define sqr_add_c2(a, i, j, c0, c1, c2) mul_add_c2((a)[i], (a)[j], c0, c1, c2) +#endif /* !BN_LLONG */ + +void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) { + BN_ULONG c1, c2, c3; + + c1 = 0; + c2 = 0; + c3 = 0; + mul_add_c(a[0], b[0], c1, c2, c3); + r[0] = c1; + c1 = 0; + mul_add_c(a[0], b[1], c2, c3, c1); + mul_add_c(a[1], b[0], c2, c3, c1); + r[1] = c2; + c2 = 0; + mul_add_c(a[2], b[0], c3, c1, c2); + mul_add_c(a[1], b[1], c3, c1, c2); + mul_add_c(a[0], b[2], c3, c1, c2); + r[2] = c3; + c3 = 0; + mul_add_c(a[0], b[3], c1, c2, c3); + mul_add_c(a[1], b[2], c1, c2, c3); + mul_add_c(a[2], b[1], c1, c2, c3); + mul_add_c(a[3], b[0], c1, c2, c3); + r[3] = c1; + c1 = 0; + mul_add_c(a[4], b[0], c2, c3, c1); + mul_add_c(a[3], b[1], c2, c3, c1); + mul_add_c(a[2], b[2], c2, c3, c1); + mul_add_c(a[1], b[3], c2, c3, c1); + mul_add_c(a[0], b[4], c2, c3, c1); + r[4] = c2; + c2 = 0; + mul_add_c(a[0], b[5], c3, c1, c2); + mul_add_c(a[1], b[4], c3, c1, c2); + mul_add_c(a[2], b[3], c3, c1, c2); + mul_add_c(a[3], b[2], c3, c1, c2); + mul_add_c(a[4], b[1], c3, c1, c2); + mul_add_c(a[5], b[0], c3, c1, c2); + r[5] = c3; + c3 = 0; + mul_add_c(a[6], b[0], c1, c2, c3); + mul_add_c(a[5], b[1], c1, c2, c3); + mul_add_c(a[4], b[2], c1, c2, c3); + mul_add_c(a[3], b[3], c1, c2, c3); + mul_add_c(a[2], b[4], c1, c2, c3); + mul_add_c(a[1], b[5], c1, c2, c3); + mul_add_c(a[0], b[6], c1, c2, c3); + r[6] = c1; + c1 = 0; + mul_add_c(a[0], b[7], c2, c3, c1); + mul_add_c(a[1], b[6], c2, c3, c1); + mul_add_c(a[2], b[5], c2, c3, c1); + mul_add_c(a[3], b[4], c2, c3, c1); + mul_add_c(a[4], b[3], c2, c3, c1); + mul_add_c(a[5], b[2], c2, c3, c1); + mul_add_c(a[6], b[1], c2, c3, c1); + mul_add_c(a[7], b[0], c2, c3, c1); + r[7] = c2; + c2 = 0; + mul_add_c(a[7], b[1], c3, c1, c2); + mul_add_c(a[6], b[2], c3, c1, c2); + mul_add_c(a[5], b[3], c3, c1, c2); + mul_add_c(a[4], b[4], c3, c1, c2); + mul_add_c(a[3], b[5], c3, c1, c2); + mul_add_c(a[2], b[6], c3, c1, c2); + mul_add_c(a[1], b[7], c3, c1, c2); + r[8] = c3; + c3 = 0; + mul_add_c(a[2], b[7], c1, c2, c3); + mul_add_c(a[3], b[6], c1, c2, c3); + mul_add_c(a[4], b[5], c1, c2, c3); + mul_add_c(a[5], b[4], c1, c2, c3); + mul_add_c(a[6], b[3], c1, c2, c3); + mul_add_c(a[7], b[2], c1, c2, c3); + r[9] = c1; + c1 = 0; + mul_add_c(a[7], b[3], c2, c3, c1); + mul_add_c(a[6], b[4], c2, c3, c1); + mul_add_c(a[5], b[5], c2, c3, c1); + mul_add_c(a[4], b[6], c2, c3, c1); + mul_add_c(a[3], b[7], c2, c3, c1); + r[10] = c2; + c2 = 0; + mul_add_c(a[4], b[7], c3, c1, c2); + mul_add_c(a[5], b[6], c3, c1, c2); + mul_add_c(a[6], b[5], c3, c1, c2); + mul_add_c(a[7], b[4], c3, c1, c2); + r[11] = c3; + c3 = 0; + mul_add_c(a[7], b[5], c1, c2, c3); + mul_add_c(a[6], b[6], c1, c2, c3); + mul_add_c(a[5], b[7], c1, c2, c3); + r[12] = c1; + c1 = 0; + mul_add_c(a[6], b[7], c2, c3, c1); + mul_add_c(a[7], b[6], c2, c3, c1); + r[13] = c2; + c2 = 0; + mul_add_c(a[7], b[7], c3, c1, c2); + r[14] = c3; + r[15] = c1; +} + +void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) { + BN_ULONG c1, c2, c3; + + c1 = 0; + c2 = 0; + c3 = 0; + mul_add_c(a[0], b[0], c1, c2, c3); + r[0] = c1; + c1 = 0; + mul_add_c(a[0], b[1], c2, c3, c1); + mul_add_c(a[1], b[0], c2, c3, c1); + r[1] = c2; + c2 = 0; + mul_add_c(a[2], b[0], c3, c1, c2); + mul_add_c(a[1], b[1], c3, c1, c2); + mul_add_c(a[0], b[2], c3, c1, c2); + r[2] = c3; + c3 = 0; + mul_add_c(a[0], b[3], c1, c2, c3); + mul_add_c(a[1], b[2], c1, c2, c3); + mul_add_c(a[2], b[1], c1, c2, c3); + mul_add_c(a[3], b[0], c1, c2, c3); + r[3] = c1; + c1 = 0; + mul_add_c(a[3], b[1], c2, c3, c1); + mul_add_c(a[2], b[2], c2, c3, c1); + mul_add_c(a[1], b[3], c2, c3, c1); + r[4] = c2; + c2 = 0; + mul_add_c(a[2], b[3], c3, c1, c2); + mul_add_c(a[3], b[2], c3, c1, c2); + r[5] = c3; + c3 = 0; + mul_add_c(a[3], b[3], c1, c2, c3); + r[6] = c1; + r[7] = c2; +} + +void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a) { + BN_ULONG c1, c2, c3; + + c1 = 0; + c2 = 0; + c3 = 0; + sqr_add_c(a, 0, c1, c2, c3); + r[0] = c1; + c1 = 0; + sqr_add_c2(a, 1, 0, c2, c3, c1); + r[1] = c2; + c2 = 0; + sqr_add_c(a, 1, c3, c1, c2); + sqr_add_c2(a, 2, 0, c3, c1, c2); + r[2] = c3; + c3 = 0; + sqr_add_c2(a, 3, 0, c1, c2, c3); + sqr_add_c2(a, 2, 1, c1, c2, c3); + r[3] = c1; + c1 = 0; + sqr_add_c(a, 2, c2, c3, c1); + sqr_add_c2(a, 3, 1, c2, c3, c1); + sqr_add_c2(a, 4, 0, c2, c3, c1); + r[4] = c2; + c2 = 0; + sqr_add_c2(a, 5, 0, c3, c1, c2); + sqr_add_c2(a, 4, 1, c3, c1, c2); + sqr_add_c2(a, 3, 2, c3, c1, c2); + r[5] = c3; + c3 = 0; + sqr_add_c(a, 3, c1, c2, c3); + sqr_add_c2(a, 4, 2, c1, c2, c3); + sqr_add_c2(a, 5, 1, c1, c2, c3); + sqr_add_c2(a, 6, 0, c1, c2, c3); + r[6] = c1; + c1 = 0; + sqr_add_c2(a, 7, 0, c2, c3, c1); + sqr_add_c2(a, 6, 1, c2, c3, c1); + sqr_add_c2(a, 5, 2, c2, c3, c1); + sqr_add_c2(a, 4, 3, c2, c3, c1); + r[7] = c2; + c2 = 0; + sqr_add_c(a, 4, c3, c1, c2); + sqr_add_c2(a, 5, 3, c3, c1, c2); + sqr_add_c2(a, 6, 2, c3, c1, c2); + sqr_add_c2(a, 7, 1, c3, c1, c2); + r[8] = c3; + c3 = 0; + sqr_add_c2(a, 7, 2, c1, c2, c3); + sqr_add_c2(a, 6, 3, c1, c2, c3); + sqr_add_c2(a, 5, 4, c1, c2, c3); + r[9] = c1; + c1 = 0; + sqr_add_c(a, 5, c2, c3, c1); + sqr_add_c2(a, 6, 4, c2, c3, c1); + sqr_add_c2(a, 7, 3, c2, c3, c1); + r[10] = c2; + c2 = 0; + sqr_add_c2(a, 7, 4, c3, c1, c2); + sqr_add_c2(a, 6, 5, c3, c1, c2); + r[11] = c3; + c3 = 0; + sqr_add_c(a, 6, c1, c2, c3); + sqr_add_c2(a, 7, 5, c1, c2, c3); + r[12] = c1; + c1 = 0; + sqr_add_c2(a, 7, 6, c2, c3, c1); + r[13] = c2; + c2 = 0; + sqr_add_c(a, 7, c3, c1, c2); + r[14] = c3; + r[15] = c1; +} + +void bn_sqr_comba4(BN_ULONG *r, const BN_ULONG *a) { + BN_ULONG c1, c2, c3; + + c1 = 0; + c2 = 0; + c3 = 0; + sqr_add_c(a, 0, c1, c2, c3); + r[0] = c1; + c1 = 0; + sqr_add_c2(a, 1, 0, c2, c3, c1); + r[1] = c2; + c2 = 0; + sqr_add_c(a, 1, c3, c1, c2); + sqr_add_c2(a, 2, 0, c3, c1, c2); + r[2] = c3; + c3 = 0; + sqr_add_c2(a, 3, 0, c1, c2, c3); + sqr_add_c2(a, 2, 1, c1, c2, c3); + r[3] = c1; + c1 = 0; + sqr_add_c(a, 2, c2, c3, c1); + sqr_add_c2(a, 3, 1, c2, c3, c1); + r[4] = c2; + c2 = 0; + sqr_add_c2(a, 3, 2, c3, c1, c2); + r[5] = c3; + c3 = 0; + sqr_add_c(a, 3, c1, c2, c3); + r[6] = c1; + r[7] = c2; +} + +#if defined(OPENSSL_NO_ASM) || (!defined(OPENSSL_ARM) && !defined(OPENSSL_X86_64)) +/* This is essentially reference implementation, which may or may not + * result in performance improvement. E.g. on IA-32 this routine was + * observed to give 40% faster rsa1024 private key operations and 10% + * faster rsa4096 ones, while on AMD64 it improves rsa1024 sign only + * by 10% and *worsens* rsa4096 sign by 15%. Once again, it's a + * reference implementation, one to be used as starting point for + * platform-specific assembler. Mentioned numbers apply to compiler + * generated code compiled with and without -DOPENSSL_BN_ASM_MONT and + * can vary not only from platform to platform, but even for compiler + * versions. Assembler vs. assembler improvement coefficients can + * [and are known to] differ and are to be documented elsewhere. */ +int bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, + const BN_ULONG *np, const BN_ULONG *n0p, int num) { + BN_ULONG c0, c1, ml, *tp, n0; +#ifdef mul64 + BN_ULONG mh; +#endif + volatile BN_ULONG *vp; + int i = 0, j; + +#if 0 /* template for platform-specific implementation */ + if (ap==bp) return bn_sqr_mont(rp,ap,np,n0p,num); +#endif + vp = tp = alloca((num + 2) * sizeof(BN_ULONG)); + + n0 = *n0p; + + c0 = 0; + ml = bp[0]; +#ifdef mul64 + mh = HBITS(ml); + ml = LBITS(ml); + for (j = 0; j < num; ++j) { + mul(tp[j], ap[j], ml, mh, c0); + } +#else + for (j = 0; j < num; ++j) { + mul(tp[j], ap[j], ml, c0); + } +#endif + + tp[num] = c0; + tp[num + 1] = 0; + goto enter; + + for (i = 0; i < num; i++) { + c0 = 0; + ml = bp[i]; +#ifdef mul64 + mh = HBITS(ml); + ml = LBITS(ml); + for (j = 0; j < num; ++j) { + mul_add(tp[j], ap[j], ml, mh, c0); + } +#else + for (j = 0; j < num; ++j) { + mul_add(tp[j], ap[j], ml, c0); + } +#endif + c1 = (tp[num] + c0) & BN_MASK2; + tp[num] = c1; + tp[num + 1] = (c1 < c0 ? 1 : 0); + enter: + c1 = tp[0]; + ml = (c1 * n0) & BN_MASK2; + c0 = 0; +#ifdef mul64 + mh = HBITS(ml); + ml = LBITS(ml); + mul_add(c1, np[0], ml, mh, c0); +#else + mul_add(c1, ml, np[0], c0); +#endif + for (j = 1; j < num; j++) { + c1 = tp[j]; +#ifdef mul64 + mul_add(c1, np[j], ml, mh, c0); +#else + mul_add(c1, ml, np[j], c0); +#endif + tp[j - 1] = c1 & BN_MASK2; + } + c1 = (tp[num] + c0) & BN_MASK2; + tp[num - 1] = c1; + tp[num] = tp[num + 1] + (c1 < c0 ? 1 : 0); + } + + if (tp[num] != 0 || tp[num - 1] >= np[num - 1]) { + c0 = bn_sub_words(rp, tp, np, num); + if (tp[num] != 0 || c0 == 0) { + for (i = 0; i < num + 2; i++) { + vp[i] = 0; + } + return 1; + } + } + for (i = 0; i < num; i++) { + rp[i] = tp[i], vp[i] = 0; + } + vp[num] = 0; + vp[num + 1] = 0; + return 1; +} +#endif + +#endif diff --git a/TMessagesProj/jni/boringssl/crypto/bn/internal.h b/TMessagesProj/jni/boringssl/crypto/bn/internal.h new file mode 100644 index 00000000..2674b3cd --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/internal.h @@ -0,0 +1,291 @@ +/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the Eric Young open source + * license provided above. + * + * The binary polynomial arithmetic software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems + * Laboratories. */ + +#ifndef OPENSSL_HEADER_BN_INTERNAL_H +#define OPENSSL_HEADER_BN_INTERNAL_H + +#include + +#if defined(OPENSSL_X86_64) && defined(_MSC_VER) && _MSC_VER >= 1400 +#pragma warning(push, 3) +#include +#pragma warning(pop) +#pragma intrinsic(__umulh, _umul128) +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +/* bn_expand acts the same as |BN_wexpand|, but takes a number of bits rather + * than a number of words. */ +BIGNUM *bn_expand(BIGNUM *bn, unsigned bits); + +#if defined(OPENSSL_64_BIT) + +#if !defined(_MSC_VER) +/* MSVC doesn't support two-word integers on 64-bit. */ +#define BN_LLONG __int128_t +#define BN_ULLONG __uint128_t +#endif + +#define BN_BITS 128 +#define BN_BITS2 64 +#define BN_BYTES 8 +#define BN_BITS4 32 +#define BN_MASK (0xffffffffffffffffffffffffffffffffLL) +#define BN_MASK2 (0xffffffffffffffffL) +#define BN_MASK2l (0xffffffffL) +#define BN_MASK2h (0xffffffff00000000L) +#define BN_MASK2h1 (0xffffffff80000000L) +#define BN_TBIT (0x8000000000000000L) +#define BN_DEC_CONV (10000000000000000000UL) +#define BN_DEC_NUM 19 + +#elif defined(OPENSSL_32_BIT) + +#define BN_LLONG int64_t +#define BN_ULLONG uint64_t +#define BN_MASK (0xffffffffffffffffLL) +#define BN_BITS 64 +#define BN_BITS2 32 +#define BN_BYTES 4 +#define BN_BITS4 16 +#define BN_MASK2 (0xffffffffL) +#define BN_MASK2l (0xffff) +#define BN_MASK2h1 (0xffff8000L) +#define BN_MASK2h (0xffff0000L) +#define BN_TBIT (0x80000000L) +#define BN_DEC_CONV (1000000000L) +#define BN_DEC_NUM 9 + +#else +#error "Must define either OPENSSL_32_BIT or OPENSSL_64_BIT" +#endif + +/* Pentium pro 16,16,16,32,64 */ +/* Alpha 16,16,16,16.64 */ +#define BN_MULL_SIZE_NORMAL (16) /* 32 */ +#define BN_MUL_RECURSIVE_SIZE_NORMAL (16) /* 32 less than */ +#define BN_SQR_RECURSIVE_SIZE_NORMAL (16) /* 32 */ +#define BN_MUL_LOW_RECURSIVE_SIZE_NORMAL (32) /* 32 */ +#define BN_MONT_CTX_SET_SIZE_WORD (64) /* 32 */ + +#if defined(BN_LLONG) +#define Lw(t) (((BN_ULONG)(t))&BN_MASK2) +#define Hw(t) (((BN_ULONG)((t)>>BN_BITS2))&BN_MASK2) +#endif + +BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w); +BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w); +void bn_sqr_words(BN_ULONG *rp, const BN_ULONG *ap, int num); +BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d); +BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,int num); +BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,int num); + +void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b); +void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b); +void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a); +void bn_sqr_comba4(BN_ULONG *r, const BN_ULONG *a); + +/* bn_cmp_words returns a value less than, equal to or greater than zero if + * the, length |n|, array |a| is less than, equal to or greater than |b|. */ +int bn_cmp_words(const BN_ULONG *a, const BN_ULONG *b, int n); + +/* bn_cmp_words returns a value less than, equal to or greater than zero if the + * array |a| is less than, equal to or greater than |b|. The arrays can be of + * different lengths: |cl| gives the minimum of the two lengths and |dl| gives + * the length of |a| minus the length of |b|. */ +int bn_cmp_part_words(const BN_ULONG *a, const BN_ULONG *b, int cl, int dl); + +int bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, + const BN_ULONG *np, const BN_ULONG *n0, int num); + +#if !defined(BN_LLONG) + +#define LBITS(a) ((a) & BN_MASK2l) +#define HBITS(a) (((a) >> BN_BITS4) & BN_MASK2l) +#define L2HBITS(a) (((a) << BN_BITS4) & BN_MASK2) + +#define LLBITS(a) ((a) & BN_MASKl) +#define LHBITS(a) (((a) >> BN_BITS2) & BN_MASKl) +#define LL2HBITS(a) ((BN_ULLONG)((a) & BN_MASKl) << BN_BITS2) + +#define mul64(l, h, bl, bh) \ + { \ + BN_ULONG m, m1, lt, ht; \ + \ + lt = l; \ + ht = h; \ + m = (bh) * (lt); \ + lt = (bl) * (lt); \ + m1 = (bl) * (ht); \ + ht = (bh) * (ht); \ + m = (m + m1) & BN_MASK2; \ + if (m < m1) \ + ht += L2HBITS((BN_ULONG)1); \ + ht += HBITS(m); \ + m1 = L2HBITS(m); \ + lt = (lt + m1) & BN_MASK2; \ + if (lt < m1) \ + ht++; \ + (l) = lt; \ + (h) = ht; \ + } + +#endif /* !defined(BN_LLONG) */ + +#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) +# if defined(__GNUC__) && __GNUC__ >= 2 +# define BN_UMULT_HIGH(a,b) ({ \ + register BN_ULONG ret,discard; \ + __asm__ ("mulq %3" \ + : "=a"(discard),"=d"(ret) \ + : "a"(a), "g"(b) \ + : "cc"); \ + ret; }) +# define BN_UMULT_LOHI(low,high,a,b) \ + __asm__ ("mulq %3" \ + : "=a"(low),"=d"(high) \ + : "a"(a),"g"(b) \ + : "cc"); +# elif defined(_MSC_VER) && _MSC_VER >= 1400 +# define BN_UMULT_HIGH(a, b) __umulh((a), (b)) +# define BN_UMULT_LOHI(low, high, a, b) ((low) = _umul128((a), (b), &(high))) +# endif +#elif !defined(OPENSSL_NO_ASM) && defined(OPENSSL_AARCH64) +# if defined(__GNUC__) && __GNUC__>=2 +# define BN_UMULT_HIGH(a,b) ({ \ + register BN_ULONG ret; \ + __asm__ ("umulh %0,%1,%2" \ + : "=r"(ret) \ + : "r"(a), "r"(b)); \ + ret; }) +# endif +#endif + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_BN_INTERNAL_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/bn/kronecker.c b/TMessagesProj/jni/boringssl/crypto/bn/kronecker.c new file mode 100644 index 00000000..23ef79af --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/kronecker.c @@ -0,0 +1,175 @@ +/* ==================================================================== + * Copyright (c) 1998-2000 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include "internal.h" + + +/* least significant word */ +#define BN_lsw(n) (((n)->top == 0) ? (BN_ULONG) 0 : (n)->d[0]) + +/* Returns -2 for errors because both -1 and 0 are valid results. */ +int BN_kronecker(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) { + int i; + int ret = -2; + BIGNUM *A, *B, *tmp; + /* In 'tab', only odd-indexed entries are relevant: + * For any odd BIGNUM n, + * tab[BN_lsw(n) & 7] + * is $(-1)^{(n^2-1)/8}$ (using TeX notation). + * Note that the sign of n does not matter. */ + static const int tab[8] = {0, 1, 0, -1, 0, -1, 0, 1}; + + BN_CTX_start(ctx); + A = BN_CTX_get(ctx); + B = BN_CTX_get(ctx); + if (B == NULL) { + goto end; + } + + if (!BN_copy(A, a) || + !BN_copy(B, b)) { + goto end; + } + + /* Kronecker symbol, imlemented according to Henri Cohen, + * "A Course in Computational Algebraic Number Theory" + * (algorithm 1.4.10). */ + + /* Cohen's step 1: */ + + if (BN_is_zero(B)) { + ret = BN_abs_is_word(A, 1); + goto end; + } + + /* Cohen's step 2: */ + + if (!BN_is_odd(A) && !BN_is_odd(B)) { + ret = 0; + goto end; + } + + /* now B is non-zero */ + i = 0; + while (!BN_is_bit_set(B, i)) { + i++; + } + if (!BN_rshift(B, B, i)) { + goto end; + } + if (i & 1) { + /* i is odd */ + /* (thus B was even, thus A must be odd!) */ + + /* set 'ret' to $(-1)^{(A^2-1)/8}$ */ + ret = tab[BN_lsw(A) & 7]; + } else { + /* i is even */ + ret = 1; + } + + if (B->neg) { + B->neg = 0; + if (A->neg) { + ret = -ret; + } + } + + /* now B is positive and odd, so what remains to be done is to compute the + * Jacobi symbol (A/B) and multiply it by 'ret' */ + + while (1) { + /* Cohen's step 3: */ + + /* B is positive and odd */ + if (BN_is_zero(A)) { + ret = BN_is_one(B) ? ret : 0; + goto end; + } + + /* now A is non-zero */ + i = 0; + while (!BN_is_bit_set(A, i)) { + i++; + } + if (!BN_rshift(A, A, i)) { + goto end; + } + if (i & 1) { + /* i is odd */ + /* multiply 'ret' by $(-1)^{(B^2-1)/8}$ */ + ret = ret * tab[BN_lsw(B) & 7]; + } + + /* Cohen's step 4: */ + /* multiply 'ret' by $(-1)^{(A-1)(B-1)/4}$ */ + if ((A->neg ? ~BN_lsw(A) : BN_lsw(A)) & BN_lsw(B) & 2) { + ret = -ret; + } + + /* (A, B) := (B mod |A|, |A|) */ + if (!BN_nnmod(B, B, A, ctx)) { + ret = -2; + goto end; + } + tmp = A; + A = B; + B = tmp; + tmp->neg = 0; + } + +end: + BN_CTX_end(ctx); + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/montgomery.c b/TMessagesProj/jni/boringssl/crypto/bn/montgomery.c new file mode 100644 index 00000000..152cf2d8 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/montgomery.c @@ -0,0 +1,565 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include + +#include +#include + +#include "internal.h" +#include "../internal.h" + + +#if !defined(OPENSSL_NO_ASM) && \ + (defined(OPENSSL_X86) || defined(OPENSSL_X86_64)) +#define OPENSSL_BN_ASM_MONT +#endif + +BN_MONT_CTX *BN_MONT_CTX_new(void) { + BN_MONT_CTX *ret = OPENSSL_malloc(sizeof(BN_MONT_CTX)); + + if (ret == NULL) { + return NULL; + } + + BN_MONT_CTX_init(ret); + ret->flags = BN_FLG_MALLOCED; + return ret; +} + +void BN_MONT_CTX_init(BN_MONT_CTX *mont) { + memset(mont, 0, sizeof(BN_MONT_CTX)); + BN_init(&mont->RR); + BN_init(&mont->N); + BN_init(&mont->Ni); +} + +void BN_MONT_CTX_free(BN_MONT_CTX *mont) { + if (mont == NULL) { + return; + } + + BN_free(&mont->RR); + BN_free(&mont->N); + BN_free(&mont->Ni); + if (mont->flags & BN_FLG_MALLOCED) { + OPENSSL_free(mont); + } +} + +BN_MONT_CTX *BN_MONT_CTX_copy(BN_MONT_CTX *to, BN_MONT_CTX *from) { + if (to == from) { + return to; + } + + if (!BN_copy(&to->RR, &from->RR) || + !BN_copy(&to->N, &from->N) || + !BN_copy(&to->Ni, &from->Ni)) { + return NULL; + } + to->ri = from->ri; + to->n0[0] = from->n0[0]; + to->n0[1] = from->n0[1]; + return to; +} + +int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, BN_CTX *ctx) { + int ret = 0; + BIGNUM *Ri, *R; + BIGNUM tmod; + BN_ULONG buf[2]; + + BN_CTX_start(ctx); + Ri = BN_CTX_get(ctx); + if (Ri == NULL) { + goto err; + } + R = &mont->RR; /* grab RR as a temp */ + if (!BN_copy(&mont->N, mod)) { + goto err; /* Set N */ + } + mont->N.neg = 0; + + BN_init(&tmod); + tmod.d = buf; + tmod.dmax = 2; + tmod.neg = 0; + + mont->ri = (BN_num_bits(mod) + (BN_BITS2 - 1)) / BN_BITS2 * BN_BITS2; + +#if defined(OPENSSL_BN_ASM_MONT) && (BN_BITS2 <= 32) + /* Only certain BN_BITS2<=32 platforms actually make use of + * n0[1], and we could use the #else case (with a shorter R + * value) for the others. However, currently only the assembler + * files do know which is which. */ + + BN_zero(R); + if (!BN_set_bit(R, 2 * BN_BITS2)) { + goto err; + } + + tmod.top = 0; + if ((buf[0] = mod->d[0])) { + tmod.top = 1; + } + if ((buf[1] = mod->top > 1 ? mod->d[1] : 0)) { + tmod.top = 2; + } + + if (BN_mod_inverse(Ri, R, &tmod, ctx) == NULL) { + goto err; + } + if (!BN_lshift(Ri, Ri, 2 * BN_BITS2)) { + goto err; /* R*Ri */ + } + if (!BN_is_zero(Ri)) { + if (!BN_sub_word(Ri, 1)) { + goto err; + } + } else { + /* if N mod word size == 1 */ + if (bn_expand(Ri, (int)sizeof(BN_ULONG) * 2) == NULL) { + goto err; + } + /* Ri-- (mod double word size) */ + Ri->neg = 0; + Ri->d[0] = BN_MASK2; + Ri->d[1] = BN_MASK2; + Ri->top = 2; + } + + if (!BN_div(Ri, NULL, Ri, &tmod, ctx)) { + goto err; + } + /* Ni = (R*Ri-1)/N, + * keep only couple of least significant words: */ + mont->n0[0] = (Ri->top > 0) ? Ri->d[0] : 0; + mont->n0[1] = (Ri->top > 1) ? Ri->d[1] : 0; +#else + BN_zero(R); + if (!BN_set_bit(R, BN_BITS2)) { + goto err; /* R */ + } + + buf[0] = mod->d[0]; /* tmod = N mod word size */ + buf[1] = 0; + tmod.top = buf[0] != 0 ? 1 : 0; + /* Ri = R^-1 mod N*/ + if (BN_mod_inverse(Ri, R, &tmod, ctx) == NULL) { + goto err; + } + if (!BN_lshift(Ri, Ri, BN_BITS2)) { + goto err; /* R*Ri */ + } + if (!BN_is_zero(Ri)) { + if (!BN_sub_word(Ri, 1)) { + goto err; + } + } else { + /* if N mod word size == 1 */ + if (!BN_set_word(Ri, BN_MASK2)) { + goto err; /* Ri-- (mod word size) */ + } + } + if (!BN_div(Ri, NULL, Ri, &tmod, ctx)) { + goto err; + } + /* Ni = (R*Ri-1)/N, + * keep only least significant word: */ + mont->n0[0] = (Ri->top > 0) ? Ri->d[0] : 0; + mont->n0[1] = 0; +#endif + + /* setup RR for conversions */ + BN_zero(&(mont->RR)); + if (!BN_set_bit(&(mont->RR), mont->ri * 2)) { + goto err; + } + if (!BN_mod(&(mont->RR), &(mont->RR), &(mont->N), ctx)) { + goto err; + } + + ret = 1; + +err: + BN_CTX_end(ctx); + return ret; +} + +BN_MONT_CTX *BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, CRYPTO_MUTEX *lock, + const BIGNUM *mod, BN_CTX *bn_ctx) { + CRYPTO_MUTEX_lock_read(lock); + BN_MONT_CTX *ctx = *pmont; + CRYPTO_MUTEX_unlock(lock); + + if (ctx) { + return ctx; + } + + CRYPTO_MUTEX_lock_write(lock); + ctx = *pmont; + if (ctx) { + goto out; + } + + ctx = BN_MONT_CTX_new(); + if (ctx == NULL) { + goto out; + } + if (!BN_MONT_CTX_set(ctx, mod, bn_ctx)) { + BN_MONT_CTX_free(ctx); + ctx = NULL; + goto out; + } + *pmont = ctx; + +out: + CRYPTO_MUTEX_unlock(lock); + return ctx; +} + +int BN_to_montgomery(BIGNUM *ret, const BIGNUM *a, const BN_MONT_CTX *mont, + BN_CTX *ctx) { + return BN_mod_mul_montgomery(ret, a, &mont->RR, mont, ctx); +} + +#if 0 +static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r, + const BN_MONT_CTX *mont) { + const BIGNUM *n; + BN_ULONG *ap, *np, *rp, n0, v, carry; + int nl, max, i; + + n = &mont->N; + nl = n->top; + if (nl == 0) { + ret->top = 0; + return 1; + } + + max = (2 * nl); /* carry is stored separately */ + if (bn_wexpand(r, max) == NULL) { + return 0; + } + + r->neg ^= n->neg; + np = n->d; + rp = r->d; + + /* clear the top words of T */ + if (max > r->top) { + memset(&rp[r->top], 0, (max - r->top) * sizeof(BN_ULONG)); + } + + r->top = max; + n0 = mont->n0[0]; + + for (carry = 0, i = 0; i < nl; i++, rp++) { + v = bn_mul_add_words(rp, np, nl, (rp[0] * n0) & BN_MASK2); + v = (v + carry + rp[nl]) & BN_MASK2; + carry |= (v != rp[nl]); + carry &= (v <= rp[nl]); + rp[nl] = v; + } + + if (bn_wexpand(ret, nl) == NULL) { + return 0; + } + ret->top = nl; + ret->neg = r->neg; + + rp = ret->d; + ap = &(r->d[nl]); + + { + BN_ULONG *nrp; + size_t m; + + v = bn_sub_words(rp, ap, np, nl) - carry; + /* if subtraction result is real, then trick unconditional memcpy below to + * perform in-place "refresh" instead of actual copy. */ + m = (0 - (size_t)v); + nrp = (BN_ULONG *)(((intptr_t)rp & ~m) | ((intptr_t)ap & m)); + + for (i = 0, nl -= 4; i < nl; i += 4) { + BN_ULONG t1, t2, t3, t4; + + t1 = nrp[i + 0]; + t2 = nrp[i + 1]; + t3 = nrp[i + 2]; + ap[i + 0] = 0; + t4 = nrp[i + 3]; + ap[i + 1] = 0; + rp[i + 0] = t1; + ap[i + 2] = 0; + rp[i + 1] = t2; + ap[i + 3] = 0; + rp[i + 2] = t3; + rp[i + 3] = t4; + } + + for (nl += 4; i < nl; i++) { + rp[i] = nrp[i], ap[i] = 0; + } + } + + bn_correct_top(r); + bn_correct_top(ret); + + return 1; +} +#endif + +#define PTR_SIZE_INT size_t + +static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r, const BN_MONT_CTX *mont) + { + BIGNUM *n; + BN_ULONG *ap,*np,*rp,n0,v,carry; + int nl,max,i; + + n= (BIGNUM*) &(mont->N); + nl=n->top; + if (nl == 0) { ret->top=0; return(1); } + + max=(2*nl); /* carry is stored separately */ + if (bn_wexpand(r,max) == NULL) return(0); + + r->neg^=n->neg; + np=n->d; + rp=r->d; + + /* clear the top words of T */ +#if 1 + for (i=r->top; itop]),0,(max-r->top)*sizeof(BN_ULONG)); +#endif + + r->top=max; + n0=mont->n0[0]; + + for (carry=0, i=0; itop=nl; + ret->neg=r->neg; + + rp=ret->d; + ap=&(r->d[nl]); + + { + BN_ULONG *nrp; + size_t m; + + v=bn_sub_words(rp,ap,np,nl)-carry; + /* if subtraction result is real, then + * trick unconditional memcpy below to perform in-place + * "refresh" instead of actual copy. */ + m=(0-(size_t)v); + nrp=(BN_ULONG *)(((PTR_SIZE_INT)rp&~m)|((PTR_SIZE_INT)ap&m)); + + for (i=0,nl-=4; iN.top; + + if (num > 1 && a->top == num && b->top == num) { + if (bn_wexpand(r, num) == NULL) { + return 0; + } + if (bn_mul_mont(r->d, a->d, b->d, mont->N.d, mont->n0, num)) { + r->neg = a->neg ^ b->neg; + r->top = num; + bn_correct_top(r); + return 1; + } + } +#endif + + BN_CTX_start(ctx); + tmp = BN_CTX_get(ctx); + if (tmp == NULL) { + goto err; + } + + if (a == b) { + if (!BN_sqr(tmp, a, ctx)) { + goto err; + } + } else { + if (!BN_mul(tmp, a, b, ctx)) { + goto err; + } + } + + /* reduce from aRR to aR */ + if (!BN_from_montgomery_word(r, tmp, mont)) { + goto err; + } + + ret = 1; + +err: + BN_CTX_end(ctx); + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/mul.c b/TMessagesProj/jni/boringssl/crypto/bn/mul.c new file mode 100644 index 00000000..029a59e2 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/mul.c @@ -0,0 +1,888 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include "internal.h" + + +void bn_mul_normal(BN_ULONG *r, BN_ULONG *a, int na, BN_ULONG *b, int nb) { + BN_ULONG *rr; + + if (na < nb) { + int itmp; + BN_ULONG *ltmp; + + itmp = na; + na = nb; + nb = itmp; + ltmp = a; + a = b; + b = ltmp; + } + rr = &(r[na]); + if (nb <= 0) { + (void)bn_mul_words(r, a, na, 0); + return; + } else { + rr[0] = bn_mul_words(r, a, na, b[0]); + } + + for (;;) { + if (--nb <= 0) { + return; + } + rr[1] = bn_mul_add_words(&(r[1]), a, na, b[1]); + if (--nb <= 0) { + return; + } + rr[2] = bn_mul_add_words(&(r[2]), a, na, b[2]); + if (--nb <= 0) { + return; + } + rr[3] = bn_mul_add_words(&(r[3]), a, na, b[3]); + if (--nb <= 0) { + return; + } + rr[4] = bn_mul_add_words(&(r[4]), a, na, b[4]); + rr += 4; + r += 4; + b += 4; + } +} + +void bn_mul_low_normal(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n) { + bn_mul_words(r, a, n, b[0]); + + for (;;) { + if (--n <= 0) { + return; + } + bn_mul_add_words(&(r[1]), a, n, b[1]); + if (--n <= 0) { + return; + } + bn_mul_add_words(&(r[2]), a, n, b[2]); + if (--n <= 0) { + return; + } + bn_mul_add_words(&(r[3]), a, n, b[3]); + if (--n <= 0) { + return; + } + bn_mul_add_words(&(r[4]), a, n, b[4]); + r += 4; + b += 4; + } +} + +#if !defined(OPENSSL_X86) || defined(OPENSSL_NO_ASM) +/* Here follows specialised variants of bn_add_words() and bn_sub_words(). They + * have the property performing operations on arrays of different sizes. The + * sizes of those arrays is expressed through cl, which is the common length ( + * basicall, min(len(a),len(b)) ), and dl, which is the delta between the two + * lengths, calculated as len(a)-len(b). All lengths are the number of + * BN_ULONGs... For the operations that require a result array as parameter, + * it must have the length cl+abs(dl). These functions should probably end up + * in bn_asm.c as soon as there are assembler counterparts for the systems that + * use assembler files. */ + +static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a, + const BN_ULONG *b, int cl, int dl) { + BN_ULONG c, t; + + assert(cl >= 0); + c = bn_sub_words(r, a, b, cl); + + if (dl == 0) { + return c; + } + + r += cl; + a += cl; + b += cl; + + if (dl < 0) { + for (;;) { + t = b[0]; + r[0] = (0 - t - c) & BN_MASK2; + if (t != 0) { + c = 1; + } + if (++dl >= 0) { + break; + } + + t = b[1]; + r[1] = (0 - t - c) & BN_MASK2; + if (t != 0) { + c = 1; + } + if (++dl >= 0) { + break; + } + + t = b[2]; + r[2] = (0 - t - c) & BN_MASK2; + if (t != 0) { + c = 1; + } + if (++dl >= 0) { + break; + } + + t = b[3]; + r[3] = (0 - t - c) & BN_MASK2; + if (t != 0) { + c = 1; + } + if (++dl >= 0) { + break; + } + + b += 4; + r += 4; + } + } else { + int save_dl = dl; + while (c) { + t = a[0]; + r[0] = (t - c) & BN_MASK2; + if (t != 0) { + c = 0; + } + if (--dl <= 0) { + break; + } + + t = a[1]; + r[1] = (t - c) & BN_MASK2; + if (t != 0) { + c = 0; + } + if (--dl <= 0) { + break; + } + + t = a[2]; + r[2] = (t - c) & BN_MASK2; + if (t != 0) { + c = 0; + } + if (--dl <= 0) { + break; + } + + t = a[3]; + r[3] = (t - c) & BN_MASK2; + if (t != 0) { + c = 0; + } + if (--dl <= 0) { + break; + } + + save_dl = dl; + a += 4; + r += 4; + } + if (dl > 0) { + if (save_dl > dl) { + switch (save_dl - dl) { + case 1: + r[1] = a[1]; + if (--dl <= 0) { + break; + } + case 2: + r[2] = a[2]; + if (--dl <= 0) { + break; + } + case 3: + r[3] = a[3]; + if (--dl <= 0) { + break; + } + } + a += 4; + r += 4; + } + } + + if (dl > 0) { + for (;;) { + r[0] = a[0]; + if (--dl <= 0) { + break; + } + r[1] = a[1]; + if (--dl <= 0) { + break; + } + r[2] = a[2]; + if (--dl <= 0) { + break; + } + r[3] = a[3]; + if (--dl <= 0) { + break; + } + + a += 4; + r += 4; + } + } + } + + return c; +} +#else +/* On other platforms the function is defined in asm. */ +BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, + int cl, int dl); +#endif + +/* Karatsuba recursive multiplication algorithm + * (cf. Knuth, The Art of Computer Programming, Vol. 2) */ + +/* r is 2*n2 words in size, + * a and b are both n2 words in size. + * n2 must be a power of 2. + * We multiply and return the result. + * t must be 2*n2 words in size + * We calculate + * a[0]*b[0] + * a[0]*b[0]+a[1]*b[1]+(a[0]-a[1])*(b[1]-b[0]) + * a[1]*b[1] + */ +/* dnX may not be positive, but n2/2+dnX has to be */ +static void bn_mul_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2, + int dna, int dnb, BN_ULONG *t) { + int n = n2 / 2, c1, c2; + int tna = n + dna, tnb = n + dnb; + unsigned int neg, zero; + BN_ULONG ln, lo, *p; + + /* Only call bn_mul_comba 8 if n2 == 8 and the + * two arrays are complete [steve] + */ + if (n2 == 8 && dna == 0 && dnb == 0) { + bn_mul_comba8(r, a, b); + return; + } + + /* Else do normal multiply */ + if (n2 < BN_MUL_RECURSIVE_SIZE_NORMAL) { + bn_mul_normal(r, a, n2 + dna, b, n2 + dnb); + if ((dna + dnb) < 0) { + memset(&r[2 * n2 + dna + dnb], 0, sizeof(BN_ULONG) * -(dna + dnb)); + } + return; + } + + /* r=(a[0]-a[1])*(b[1]-b[0]) */ + c1 = bn_cmp_part_words(a, &(a[n]), tna, n - tna); + c2 = bn_cmp_part_words(&(b[n]), b, tnb, tnb - n); + zero = neg = 0; + switch (c1 * 3 + c2) { + case -4: + bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */ + bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */ + break; + case -3: + zero = 1; + break; + case -2: + bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */ + bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n); /* + */ + neg = 1; + break; + case -1: + case 0: + case 1: + zero = 1; + break; + case 2: + bn_sub_part_words(t, a, &(a[n]), tna, n - tna); /* + */ + bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */ + neg = 1; + break; + case 3: + zero = 1; + break; + case 4: + bn_sub_part_words(t, a, &(a[n]), tna, n - tna); + bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n); + break; + } + + if (n == 4 && dna == 0 && dnb == 0) { + /* XXX: bn_mul_comba4 could take extra args to do this well */ + if (!zero) { + bn_mul_comba4(&(t[n2]), t, &(t[n])); + } else { + memset(&(t[n2]), 0, 8 * sizeof(BN_ULONG)); + } + + bn_mul_comba4(r, a, b); + bn_mul_comba4(&(r[n2]), &(a[n]), &(b[n])); + } else if (n == 8 && dna == 0 && dnb == 0) { + /* XXX: bn_mul_comba8 could take extra args to do this well */ + if (!zero) { + bn_mul_comba8(&(t[n2]), t, &(t[n])); + } else { + memset(&(t[n2]), 0, 16 * sizeof(BN_ULONG)); + } + + bn_mul_comba8(r, a, b); + bn_mul_comba8(&(r[n2]), &(a[n]), &(b[n])); + } else { + p = &(t[n2 * 2]); + if (!zero) { + bn_mul_recursive(&(t[n2]), t, &(t[n]), n, 0, 0, p); + } else { + memset(&(t[n2]), 0, n2 * sizeof(BN_ULONG)); + } + bn_mul_recursive(r, a, b, n, 0, 0, p); + bn_mul_recursive(&(r[n2]), &(a[n]), &(b[n]), n, dna, dnb, p); + } + + /* t[32] holds (a[0]-a[1])*(b[1]-b[0]), c1 is the sign + * r[10] holds (a[0]*b[0]) + * r[32] holds (b[1]*b[1]) */ + + c1 = (int)(bn_add_words(t, r, &(r[n2]), n2)); + + if (neg) { + /* if t[32] is negative */ + c1 -= (int)(bn_sub_words(&(t[n2]), t, &(t[n2]), n2)); + } else { + /* Might have a carry */ + c1 += (int)(bn_add_words(&(t[n2]), &(t[n2]), t, n2)); + } + + /* t[32] holds (a[0]-a[1])*(b[1]-b[0])+(a[0]*b[0])+(a[1]*b[1]) + * r[10] holds (a[0]*b[0]) + * r[32] holds (b[1]*b[1]) + * c1 holds the carry bits */ + c1 += (int)(bn_add_words(&(r[n]), &(r[n]), &(t[n2]), n2)); + if (c1) { + p = &(r[n + n2]); + lo = *p; + ln = (lo + c1) & BN_MASK2; + *p = ln; + + /* The overflow will stop before we over write + * words we should not overwrite */ + if (ln < (BN_ULONG)c1) { + do { + p++; + lo = *p; + ln = (lo + 1) & BN_MASK2; + *p = ln; + } while (ln == 0); + } + } +} + +/* n+tn is the word length + * t needs to be n*4 is size, as does r */ +/* tnX may not be negative but less than n */ +static void bn_mul_part_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n, + int tna, int tnb, BN_ULONG *t) { + int i, j, n2 = n * 2; + int c1, c2, neg; + BN_ULONG ln, lo, *p; + + if (n < 8) { + bn_mul_normal(r, a, n + tna, b, n + tnb); + return; + } + + /* r=(a[0]-a[1])*(b[1]-b[0]) */ + c1 = bn_cmp_part_words(a, &(a[n]), tna, n - tna); + c2 = bn_cmp_part_words(&(b[n]), b, tnb, tnb - n); + neg = 0; + switch (c1 * 3 + c2) { + case -4: + bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */ + bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */ + break; + case -3: + /* break; */ + case -2: + bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */ + bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n); /* + */ + neg = 1; + break; + case -1: + case 0: + case 1: + /* break; */ + case 2: + bn_sub_part_words(t, a, &(a[n]), tna, n - tna); /* + */ + bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */ + neg = 1; + break; + case 3: + /* break; */ + case 4: + bn_sub_part_words(t, a, &(a[n]), tna, n - tna); + bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n); + break; + } + + if (n == 8) { + bn_mul_comba8(&(t[n2]), t, &(t[n])); + bn_mul_comba8(r, a, b); + bn_mul_normal(&(r[n2]), &(a[n]), tna, &(b[n]), tnb); + memset(&(r[n2 + tna + tnb]), 0, sizeof(BN_ULONG) * (n2 - tna - tnb)); + } else { + p = &(t[n2 * 2]); + bn_mul_recursive(&(t[n2]), t, &(t[n]), n, 0, 0, p); + bn_mul_recursive(r, a, b, n, 0, 0, p); + i = n / 2; + /* If there is only a bottom half to the number, + * just do it */ + if (tna > tnb) { + j = tna - i; + } else { + j = tnb - i; + } + + if (j == 0) { + bn_mul_recursive(&(r[n2]), &(a[n]), &(b[n]), i, tna - i, tnb - i, p); + memset(&(r[n2 + i * 2]), 0, sizeof(BN_ULONG) * (n2 - i * 2)); + } else if (j > 0) { + /* eg, n == 16, i == 8 and tn == 11 */ + bn_mul_part_recursive(&(r[n2]), &(a[n]), &(b[n]), i, tna - i, tnb - i, p); + memset(&(r[n2 + tna + tnb]), 0, sizeof(BN_ULONG) * (n2 - tna - tnb)); + } else { + /* (j < 0) eg, n == 16, i == 8 and tn == 5 */ + memset(&(r[n2]), 0, sizeof(BN_ULONG) * n2); + if (tna < BN_MUL_RECURSIVE_SIZE_NORMAL && + tnb < BN_MUL_RECURSIVE_SIZE_NORMAL) { + bn_mul_normal(&(r[n2]), &(a[n]), tna, &(b[n]), tnb); + } else { + for (;;) { + i /= 2; + /* these simplified conditions work + * exclusively because difference + * between tna and tnb is 1 or 0 */ + if (i < tna || i < tnb) { + bn_mul_part_recursive(&(r[n2]), &(a[n]), &(b[n]), i, tna - i, + tnb - i, p); + break; + } else if (i == tna || i == tnb) { + bn_mul_recursive(&(r[n2]), &(a[n]), &(b[n]), i, tna - i, tnb - i, + p); + break; + } + } + } + } + } + + /* t[32] holds (a[0]-a[1])*(b[1]-b[0]), c1 is the sign + * r[10] holds (a[0]*b[0]) + * r[32] holds (b[1]*b[1]) + */ + + c1 = (int)(bn_add_words(t, r, &(r[n2]), n2)); + + if (neg) { + /* if t[32] is negative */ + c1 -= (int)(bn_sub_words(&(t[n2]), t, &(t[n2]), n2)); + } else { + /* Might have a carry */ + c1 += (int)(bn_add_words(&(t[n2]), &(t[n2]), t, n2)); + } + + /* t[32] holds (a[0]-a[1])*(b[1]-b[0])+(a[0]*b[0])+(a[1]*b[1]) + * r[10] holds (a[0]*b[0]) + * r[32] holds (b[1]*b[1]) + * c1 holds the carry bits */ + c1 += (int)(bn_add_words(&(r[n]), &(r[n]), &(t[n2]), n2)); + if (c1) { + p = &(r[n + n2]); + lo = *p; + ln = (lo + c1) & BN_MASK2; + *p = ln; + + /* The overflow will stop before we over write + * words we should not overwrite */ + if (ln < (BN_ULONG)c1) { + do { + p++; + lo = *p; + ln = (lo + 1) & BN_MASK2; + *p = ln; + } while (ln == 0); + } + } +} + +int BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) { + int ret = 0; + int top, al, bl; + BIGNUM *rr; + int i; + BIGNUM *t = NULL; + int j = 0, k; + + al = a->top; + bl = b->top; + + if ((al == 0) || (bl == 0)) { + BN_zero(r); + return 1; + } + top = al + bl; + + BN_CTX_start(ctx); + if ((r == a) || (r == b)) { + if ((rr = BN_CTX_get(ctx)) == NULL) { + goto err; + } + } else { + rr = r; + } + rr->neg = a->neg ^ b->neg; + + i = al - bl; + if (i == 0) { + if (al == 8) { + if (bn_wexpand(rr, 16) == NULL) { + goto err; + } + rr->top = 16; + bn_mul_comba8(rr->d, a->d, b->d); + goto end; + } + } + + if ((al >= BN_MULL_SIZE_NORMAL) && (bl >= BN_MULL_SIZE_NORMAL)) { + if (i >= -1 && i <= 1) { + /* Find out the power of two lower or equal + to the longest of the two numbers */ + if (i >= 0) { + j = BN_num_bits_word((BN_ULONG)al); + } + if (i == -1) { + j = BN_num_bits_word((BN_ULONG)bl); + } + j = 1 << (j - 1); + assert(j <= al || j <= bl); + k = j + j; + t = BN_CTX_get(ctx); + if (t == NULL) { + goto err; + } + if (al > j || bl > j) { + if (bn_wexpand(t, k * 4) == NULL) { + goto err; + } + if (bn_wexpand(rr, k * 4) == NULL) { + goto err; + } + bn_mul_part_recursive(rr->d, a->d, b->d, j, al - j, bl - j, t->d); + } else { + /* al <= j || bl <= j */ + if (bn_wexpand(t, k * 2) == NULL) { + goto err; + } + if (bn_wexpand(rr, k * 2) == NULL) { + goto err; + } + bn_mul_recursive(rr->d, a->d, b->d, j, al - j, bl - j, t->d); + } + rr->top = top; + goto end; + } + } + + if (bn_wexpand(rr, top) == NULL) { + goto err; + } + rr->top = top; + bn_mul_normal(rr->d, a->d, al, b->d, bl); + +end: + bn_correct_top(rr); + if (r != rr && !BN_copy(r, rr)) { + goto err; + } + ret = 1; + +err: + BN_CTX_end(ctx); + return ret; +} + +/* tmp must have 2*n words */ +static void bn_sqr_normal(BN_ULONG *r, const BN_ULONG *a, int n, BN_ULONG *tmp) { + int i, j, max; + const BN_ULONG *ap; + BN_ULONG *rp; + + max = n * 2; + ap = a; + rp = r; + rp[0] = rp[max - 1] = 0; + rp++; + j = n; + + if (--j > 0) { + ap++; + rp[j] = bn_mul_words(rp, ap, j, ap[-1]); + rp += 2; + } + + for (i = n - 2; i > 0; i--) { + j--; + ap++; + rp[j] = bn_mul_add_words(rp, ap, j, ap[-1]); + rp += 2; + } + + bn_add_words(r, r, r, max); + + /* There will not be a carry */ + + bn_sqr_words(tmp, a, n); + + bn_add_words(r, r, tmp, max); +} + +/* r is 2*n words in size, + * a and b are both n words in size. (There's not actually a 'b' here ...) + * n must be a power of 2. + * We multiply and return the result. + * t must be 2*n words in size + * We calculate + * a[0]*b[0] + * a[0]*b[0]+a[1]*b[1]+(a[0]-a[1])*(b[1]-b[0]) + * a[1]*b[1] + */ +static void bn_sqr_recursive(BN_ULONG *r, const BN_ULONG *a, int n2, BN_ULONG *t) { + int n = n2 / 2; + int zero, c1; + BN_ULONG ln, lo, *p; + + if (n2 == 4) { + bn_sqr_comba4(r, a); + return; + } else if (n2 == 8) { + bn_sqr_comba8(r, a); + return; + } + if (n2 < BN_SQR_RECURSIVE_SIZE_NORMAL) { + bn_sqr_normal(r, a, n2, t); + return; + } + /* r=(a[0]-a[1])*(a[1]-a[0]) */ + c1 = bn_cmp_words(a, &(a[n]), n); + zero = 0; + if (c1 > 0) { + bn_sub_words(t, a, &(a[n]), n); + } else if (c1 < 0) { + bn_sub_words(t, &(a[n]), a, n); + } else { + zero = 1; + } + + /* The result will always be negative unless it is zero */ + p = &(t[n2 * 2]); + + if (!zero) { + bn_sqr_recursive(&(t[n2]), t, n, p); + } else { + memset(&(t[n2]), 0, n2 * sizeof(BN_ULONG)); + } + bn_sqr_recursive(r, a, n, p); + bn_sqr_recursive(&(r[n2]), &(a[n]), n, p); + + /* t[32] holds (a[0]-a[1])*(a[1]-a[0]), it is negative or zero + * r[10] holds (a[0]*b[0]) + * r[32] holds (b[1]*b[1]) */ + + c1 = (int)(bn_add_words(t, r, &(r[n2]), n2)); + + /* t[32] is negative */ + c1 -= (int)(bn_sub_words(&(t[n2]), t, &(t[n2]), n2)); + + /* t[32] holds (a[0]-a[1])*(a[1]-a[0])+(a[0]*a[0])+(a[1]*a[1]) + * r[10] holds (a[0]*a[0]) + * r[32] holds (a[1]*a[1]) + * c1 holds the carry bits */ + c1 += (int)(bn_add_words(&(r[n]), &(r[n]), &(t[n2]), n2)); + if (c1) { + p = &(r[n + n2]); + lo = *p; + ln = (lo + c1) & BN_MASK2; + *p = ln; + + /* The overflow will stop before we over write + * words we should not overwrite */ + if (ln < (BN_ULONG)c1) { + do { + p++; + lo = *p; + ln = (lo + 1) & BN_MASK2; + *p = ln; + } while (ln == 0); + } + } +} + +int BN_mul_word(BIGNUM *bn, BN_ULONG w) { + BN_ULONG ll; + + w &= BN_MASK2; + if (!bn->top) { + return 1; + } + + if (w == 0) { + BN_zero(bn); + return 1; + } + + ll = bn_mul_words(bn->d, bn->d, bn->top, w); + if (ll) { + if (bn_wexpand(bn, bn->top + 1) == NULL) { + return 0; + } + bn->d[bn->top++] = ll; + } + + return 1; +} + +int BN_sqr(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx) { + int max, al; + int ret = 0; + BIGNUM *tmp, *rr; + + al = a->top; + if (al <= 0) { + r->top = 0; + r->neg = 0; + return 1; + } + + BN_CTX_start(ctx); + rr = (a != r) ? r : BN_CTX_get(ctx); + tmp = BN_CTX_get(ctx); + if (!rr || !tmp) { + goto err; + } + + max = 2 * al; /* Non-zero (from above) */ + if (bn_wexpand(rr, max) == NULL) { + goto err; + } + + if (al == 4) { + bn_sqr_comba4(rr->d, a->d); + } else if (al == 8) { + bn_sqr_comba8(rr->d, a->d); + } else { + if (al < BN_SQR_RECURSIVE_SIZE_NORMAL) { + BN_ULONG t[BN_SQR_RECURSIVE_SIZE_NORMAL * 2]; + bn_sqr_normal(rr->d, a->d, al, t); + } else { + int j, k; + + j = BN_num_bits_word((BN_ULONG)al); + j = 1 << (j - 1); + k = j + j; + if (al == j) { + if (bn_wexpand(tmp, k * 2) == NULL) { + goto err; + } + bn_sqr_recursive(rr->d, a->d, al, tmp->d); + } else { + if (bn_wexpand(tmp, max) == NULL) { + goto err; + } + bn_sqr_normal(rr->d, a->d, al, tmp->d); + } + } + } + + rr->neg = 0; + /* If the most-significant half of the top word of 'a' is zero, then + * the square of 'a' will max-1 words. */ + if (a->d[al - 1] == (a->d[al - 1] & BN_MASK2l)) { + rr->top = max - 1; + } else { + rr->top = max; + } + + if (rr != r && !BN_copy(r, rr)) { + goto err; + } + ret = 1; + +err: + BN_CTX_end(ctx); + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/prime.c b/TMessagesProj/jni/boringssl/crypto/bn/prime.c new file mode 100644 index 00000000..bbb8fe0f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/prime.c @@ -0,0 +1,845 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include + +#include "internal.h" + +/* number of Miller-Rabin iterations for an error rate of less than 2^-80 + * for random 'b'-bit input, b >= 100 (taken from table 4.4 in the Handbook + * of Applied Cryptography [Menezes, van Oorschot, Vanstone; CRC Press 1996]; + * original paper: Damgaard, Landrock, Pomerance: Average case error estimates + * for the strong probable prime test. -- Math. Comp. 61 (1993) 177-194) */ +#define BN_prime_checks_for_size(b) ((b) >= 1300 ? 2 : \ + (b) >= 850 ? 3 : \ + (b) >= 650 ? 4 : \ + (b) >= 550 ? 5 : \ + (b) >= 450 ? 6 : \ + (b) >= 400 ? 7 : \ + (b) >= 350 ? 8 : \ + (b) >= 300 ? 9 : \ + (b) >= 250 ? 12 : \ + (b) >= 200 ? 15 : \ + (b) >= 150 ? 18 : \ + /* b >= 100 */ 27) + +/* The quick sieve algorithm approach to weeding out primes is Philip + * Zimmermann's, as implemented in PGP. I have had a read of his comments and + * implemented my own version. */ + +/* NUMPRIMES is the number of primes that fit into a uint16_t. */ +#define NUMPRIMES 2048 + +/* primes contains all the primes that fit into a uint16_t. */ +static const uint16_t primes[NUMPRIMES] = { + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, + 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, + 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, + 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, + 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, + 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, + 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, + 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, + 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, + 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, + 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, + 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, + 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, + 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, + 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, + 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, + 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, + 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, + 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, + 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, + 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, + 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, + 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, + 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, + 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, + 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, + 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, + 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, + 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, + 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 2293, + 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, + 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, + 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, + 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, + 2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, + 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, + 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, + 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, + 2999, 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, + 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, + 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, + 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, + 3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461, + 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, 3539, + 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, + 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, + 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, + 3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, + 3907, 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, + 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073, + 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, + 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, + 4259, 4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349, + 4357, 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, 4451, + 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, + 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, 4643, + 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, + 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, + 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, + 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, + 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, + 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, + 5227, 5231, 5233, 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, + 5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407, 5413, 5417, + 5419, 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501, + 5503, 5507, 5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573, 5581, + 5591, 5623, 5639, 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, + 5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, + 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, + 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, + 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, + 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, + 6173, 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, + 6269, 6271, 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, 6337, + 6343, 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, + 6449, 6451, 6469, 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553, + 6563, 6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, + 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, + 6761, 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, + 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, + 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, + 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121, 7127, + 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, + 7237, 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, + 7349, 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, + 7481, 7487, 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, + 7549, 7559, 7561, 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, + 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, + 7723, 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, + 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, 7927, + 7933, 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017, 8039, 8053, + 8059, 8069, 8081, 8087, 8089, 8093, 8101, 8111, 8117, 8123, 8147, + 8161, 8167, 8171, 8179, 8191, 8209, 8219, 8221, 8231, 8233, 8237, + 8243, 8263, 8269, 8273, 8287, 8291, 8293, 8297, 8311, 8317, 8329, + 8353, 8363, 8369, 8377, 8387, 8389, 8419, 8423, 8429, 8431, 8443, + 8447, 8461, 8467, 8501, 8513, 8521, 8527, 8537, 8539, 8543, 8563, + 8573, 8581, 8597, 8599, 8609, 8623, 8627, 8629, 8641, 8647, 8663, + 8669, 8677, 8681, 8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, + 8741, 8747, 8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831, + 8837, 8839, 8849, 8861, 8863, 8867, 8887, 8893, 8923, 8929, 8933, + 8941, 8951, 8963, 8969, 8971, 8999, 9001, 9007, 9011, 9013, 9029, + 9041, 9043, 9049, 9059, 9067, 9091, 9103, 9109, 9127, 9133, 9137, + 9151, 9157, 9161, 9173, 9181, 9187, 9199, 9203, 9209, 9221, 9227, + 9239, 9241, 9257, 9277, 9281, 9283, 9293, 9311, 9319, 9323, 9337, + 9341, 9343, 9349, 9371, 9377, 9391, 9397, 9403, 9413, 9419, 9421, + 9431, 9433, 9437, 9439, 9461, 9463, 9467, 9473, 9479, 9491, 9497, + 9511, 9521, 9533, 9539, 9547, 9551, 9587, 9601, 9613, 9619, 9623, + 9629, 9631, 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721, + 9733, 9739, 9743, 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, + 9817, 9829, 9833, 9839, 9851, 9857, 9859, 9871, 9883, 9887, 9901, + 9907, 9923, 9929, 9931, 9941, 9949, 9967, 9973, 10007, 10009, 10037, + 10039, 10061, 10067, 10069, 10079, 10091, 10093, 10099, 10103, 10111, 10133, + 10139, 10141, 10151, 10159, 10163, 10169, 10177, 10181, 10193, 10211, 10223, + 10243, 10247, 10253, 10259, 10267, 10271, 10273, 10289, 10301, 10303, 10313, + 10321, 10331, 10333, 10337, 10343, 10357, 10369, 10391, 10399, 10427, 10429, + 10433, 10453, 10457, 10459, 10463, 10477, 10487, 10499, 10501, 10513, 10529, + 10531, 10559, 10567, 10589, 10597, 10601, 10607, 10613, 10627, 10631, 10639, + 10651, 10657, 10663, 10667, 10687, 10691, 10709, 10711, 10723, 10729, 10733, + 10739, 10753, 10771, 10781, 10789, 10799, 10831, 10837, 10847, 10853, 10859, + 10861, 10867, 10883, 10889, 10891, 10903, 10909, 10937, 10939, 10949, 10957, + 10973, 10979, 10987, 10993, 11003, 11027, 11047, 11057, 11059, 11069, 11071, + 11083, 11087, 11093, 11113, 11117, 11119, 11131, 11149, 11159, 11161, 11171, + 11173, 11177, 11197, 11213, 11239, 11243, 11251, 11257, 11261, 11273, 11279, + 11287, 11299, 11311, 11317, 11321, 11329, 11351, 11353, 11369, 11383, 11393, + 11399, 11411, 11423, 11437, 11443, 11447, 11467, 11471, 11483, 11489, 11491, + 11497, 11503, 11519, 11527, 11549, 11551, 11579, 11587, 11593, 11597, 11617, + 11621, 11633, 11657, 11677, 11681, 11689, 11699, 11701, 11717, 11719, 11731, + 11743, 11777, 11779, 11783, 11789, 11801, 11807, 11813, 11821, 11827, 11831, + 11833, 11839, 11863, 11867, 11887, 11897, 11903, 11909, 11923, 11927, 11933, + 11939, 11941, 11953, 11959, 11969, 11971, 11981, 11987, 12007, 12011, 12037, + 12041, 12043, 12049, 12071, 12073, 12097, 12101, 12107, 12109, 12113, 12119, + 12143, 12149, 12157, 12161, 12163, 12197, 12203, 12211, 12227, 12239, 12241, + 12251, 12253, 12263, 12269, 12277, 12281, 12289, 12301, 12323, 12329, 12343, + 12347, 12373, 12377, 12379, 12391, 12401, 12409, 12413, 12421, 12433, 12437, + 12451, 12457, 12473, 12479, 12487, 12491, 12497, 12503, 12511, 12517, 12527, + 12539, 12541, 12547, 12553, 12569, 12577, 12583, 12589, 12601, 12611, 12613, + 12619, 12637, 12641, 12647, 12653, 12659, 12671, 12689, 12697, 12703, 12713, + 12721, 12739, 12743, 12757, 12763, 12781, 12791, 12799, 12809, 12821, 12823, + 12829, 12841, 12853, 12889, 12893, 12899, 12907, 12911, 12917, 12919, 12923, + 12941, 12953, 12959, 12967, 12973, 12979, 12983, 13001, 13003, 13007, 13009, + 13033, 13037, 13043, 13049, 13063, 13093, 13099, 13103, 13109, 13121, 13127, + 13147, 13151, 13159, 13163, 13171, 13177, 13183, 13187, 13217, 13219, 13229, + 13241, 13249, 13259, 13267, 13291, 13297, 13309, 13313, 13327, 13331, 13337, + 13339, 13367, 13381, 13397, 13399, 13411, 13417, 13421, 13441, 13451, 13457, + 13463, 13469, 13477, 13487, 13499, 13513, 13523, 13537, 13553, 13567, 13577, + 13591, 13597, 13613, 13619, 13627, 13633, 13649, 13669, 13679, 13681, 13687, + 13691, 13693, 13697, 13709, 13711, 13721, 13723, 13729, 13751, 13757, 13759, + 13763, 13781, 13789, 13799, 13807, 13829, 13831, 13841, 13859, 13873, 13877, + 13879, 13883, 13901, 13903, 13907, 13913, 13921, 13931, 13933, 13963, 13967, + 13997, 13999, 14009, 14011, 14029, 14033, 14051, 14057, 14071, 14081, 14083, + 14087, 14107, 14143, 14149, 14153, 14159, 14173, 14177, 14197, 14207, 14221, + 14243, 14249, 14251, 14281, 14293, 14303, 14321, 14323, 14327, 14341, 14347, + 14369, 14387, 14389, 14401, 14407, 14411, 14419, 14423, 14431, 14437, 14447, + 14449, 14461, 14479, 14489, 14503, 14519, 14533, 14537, 14543, 14549, 14551, + 14557, 14561, 14563, 14591, 14593, 14621, 14627, 14629, 14633, 14639, 14653, + 14657, 14669, 14683, 14699, 14713, 14717, 14723, 14731, 14737, 14741, 14747, + 14753, 14759, 14767, 14771, 14779, 14783, 14797, 14813, 14821, 14827, 14831, + 14843, 14851, 14867, 14869, 14879, 14887, 14891, 14897, 14923, 14929, 14939, + 14947, 14951, 14957, 14969, 14983, 15013, 15017, 15031, 15053, 15061, 15073, + 15077, 15083, 15091, 15101, 15107, 15121, 15131, 15137, 15139, 15149, 15161, + 15173, 15187, 15193, 15199, 15217, 15227, 15233, 15241, 15259, 15263, 15269, + 15271, 15277, 15287, 15289, 15299, 15307, 15313, 15319, 15329, 15331, 15349, + 15359, 15361, 15373, 15377, 15383, 15391, 15401, 15413, 15427, 15439, 15443, + 15451, 15461, 15467, 15473, 15493, 15497, 15511, 15527, 15541, 15551, 15559, + 15569, 15581, 15583, 15601, 15607, 15619, 15629, 15641, 15643, 15647, 15649, + 15661, 15667, 15671, 15679, 15683, 15727, 15731, 15733, 15737, 15739, 15749, + 15761, 15767, 15773, 15787, 15791, 15797, 15803, 15809, 15817, 15823, 15859, + 15877, 15881, 15887, 15889, 15901, 15907, 15913, 15919, 15923, 15937, 15959, + 15971, 15973, 15991, 16001, 16007, 16033, 16057, 16061, 16063, 16067, 16069, + 16073, 16087, 16091, 16097, 16103, 16111, 16127, 16139, 16141, 16183, 16187, + 16189, 16193, 16217, 16223, 16229, 16231, 16249, 16253, 16267, 16273, 16301, + 16319, 16333, 16339, 16349, 16361, 16363, 16369, 16381, 16411, 16417, 16421, + 16427, 16433, 16447, 16451, 16453, 16477, 16481, 16487, 16493, 16519, 16529, + 16547, 16553, 16561, 16567, 16573, 16603, 16607, 16619, 16631, 16633, 16649, + 16651, 16657, 16661, 16673, 16691, 16693, 16699, 16703, 16729, 16741, 16747, + 16759, 16763, 16787, 16811, 16823, 16829, 16831, 16843, 16871, 16879, 16883, + 16889, 16901, 16903, 16921, 16927, 16931, 16937, 16943, 16963, 16979, 16981, + 16987, 16993, 17011, 17021, 17027, 17029, 17033, 17041, 17047, 17053, 17077, + 17093, 17099, 17107, 17117, 17123, 17137, 17159, 17167, 17183, 17189, 17191, + 17203, 17207, 17209, 17231, 17239, 17257, 17291, 17293, 17299, 17317, 17321, + 17327, 17333, 17341, 17351, 17359, 17377, 17383, 17387, 17389, 17393, 17401, + 17417, 17419, 17431, 17443, 17449, 17467, 17471, 17477, 17483, 17489, 17491, + 17497, 17509, 17519, 17539, 17551, 17569, 17573, 17579, 17581, 17597, 17599, + 17609, 17623, 17627, 17657, 17659, 17669, 17681, 17683, 17707, 17713, 17729, + 17737, 17747, 17749, 17761, 17783, 17789, 17791, 17807, 17827, 17837, 17839, + 17851, 17863, +}; + +static int witness(BIGNUM *w, const BIGNUM *a, const BIGNUM *a1, + const BIGNUM *a1_odd, int k, BN_CTX *ctx, BN_MONT_CTX *mont); +static int probable_prime(BIGNUM *rnd, int bits); +static int probable_prime_dh(BIGNUM *rnd, int bits, const BIGNUM *add, + const BIGNUM *rem, BN_CTX *ctx); +static int probable_prime_dh_safe(BIGNUM *rnd, int bits, const BIGNUM *add, + const BIGNUM *rem, BN_CTX *ctx); + +void BN_GENCB_set(BN_GENCB *callback, + int (*f)(int event, int n, struct bn_gencb_st *), + void *arg) { + callback->callback = f; + callback->arg = arg; +} + +int BN_GENCB_call(BN_GENCB *callback, int event, int n) { + if (!callback) { + return 1; + } + + return callback->callback(event, n, callback); +} + +int BN_generate_prime_ex(BIGNUM *ret, int bits, int safe, const BIGNUM *add, + const BIGNUM *rem, BN_GENCB *cb) { + BIGNUM *t; + int found = 0; + int i, j, c1 = 0; + BN_CTX *ctx; + int checks = BN_prime_checks_for_size(bits); + + if (bits < 2) { + /* There are no prime numbers this small. */ + OPENSSL_PUT_ERROR(BN, BN_R_BITS_TOO_SMALL); + return 0; + } else if (bits == 2 && safe) { + /* The smallest safe prime (7) is three bits. */ + OPENSSL_PUT_ERROR(BN, BN_R_BITS_TOO_SMALL); + return 0; + } + + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + BN_CTX_start(ctx); + t = BN_CTX_get(ctx); + if (!t) { + goto err; + } + +loop: + /* make a random number and set the top and bottom bits */ + if (add == NULL) { + if (!probable_prime(ret, bits)) { + goto err; + } + } else { + if (safe) { + if (!probable_prime_dh_safe(ret, bits, add, rem, ctx)) { + goto err; + } + } else { + if (!probable_prime_dh(ret, bits, add, rem, ctx)) { + goto err; + } + } + } + + if (!BN_GENCB_call(cb, BN_GENCB_GENERATED, c1++)) { + /* aborted */ + goto err; + } + + if (!safe) { + i = BN_is_prime_fasttest_ex(ret, checks, ctx, 0, cb); + if (i == -1) { + goto err; + } else if (i == 0) { + goto loop; + } + } else { + /* for "safe prime" generation, check that (p-1)/2 is prime. Since a prime + * is odd, We just need to divide by 2 */ + if (!BN_rshift1(t, ret)) { + goto err; + } + + for (i = 0; i < checks; i++) { + j = BN_is_prime_fasttest_ex(ret, 1, ctx, 0, NULL); + if (j == -1) { + goto err; + } else if (j == 0) { + goto loop; + } + + j = BN_is_prime_fasttest_ex(t, 1, ctx, 0, NULL); + if (j == -1) { + goto err; + } else if (j == 0) { + goto loop; + } + + if (!BN_GENCB_call(cb, i, c1 - 1)) { + goto err; + } + /* We have a safe prime test pass */ + } + } + + /* we have a prime :-) */ + found = 1; + +err: + if (ctx != NULL) { + BN_CTX_end(ctx); + BN_CTX_free(ctx); + } + + return found; +} + +int BN_primality_test(int *is_probably_prime, const BIGNUM *candidate, + int checks, BN_CTX *ctx, int do_trial_division, + BN_GENCB *cb) { + switch (BN_is_prime_fasttest_ex(candidate, checks, ctx, do_trial_division, cb)) { + case 1: + *is_probably_prime = 1; + return 1; + case 0: + *is_probably_prime = 0; + return 1; + default: + *is_probably_prime = 0; + return 0; + } +} + +int BN_is_prime_ex(const BIGNUM *candidate, int checks, BN_CTX *ctx, BN_GENCB *cb) { + return BN_is_prime_fasttest_ex(candidate, checks, ctx, 0, cb); +} + +int BN_is_prime_fasttest_ex(const BIGNUM *a, int checks, BN_CTX *ctx_passed, + int do_trial_division, BN_GENCB *cb) { + int i, j, ret = -1; + int k; + BN_CTX *ctx = NULL; + BIGNUM *A1, *A1_odd, *check; /* taken from ctx */ + BN_MONT_CTX *mont = NULL; + const BIGNUM *A = NULL; + + if (BN_cmp(a, BN_value_one()) <= 0) { + return 0; + } + + if (checks == BN_prime_checks) { + checks = BN_prime_checks_for_size(BN_num_bits(a)); + } + + /* first look for small factors */ + if (!BN_is_odd(a)) { + /* a is even => a is prime if and only if a == 2 */ + return BN_is_word(a, 2); + } + + if (do_trial_division) { + for (i = 1; i < NUMPRIMES; i++) { + if (BN_mod_word(a, primes[i]) == 0) { + return 0; + } + } + + if (!BN_GENCB_call(cb, 1, -1)) { + goto err; + } + } + + if (ctx_passed != NULL) { + ctx = ctx_passed; + } else if ((ctx = BN_CTX_new()) == NULL) { + goto err; + } + BN_CTX_start(ctx); + + /* A := abs(a) */ + if (a->neg) { + BIGNUM *t = BN_CTX_get(ctx); + if (t == NULL || !BN_copy(t, a)) { + goto err; + } + t->neg = 0; + A = t; + } else { + A = a; + } + + A1 = BN_CTX_get(ctx); + A1_odd = BN_CTX_get(ctx); + check = BN_CTX_get(ctx); + if (check == NULL) { + goto err; + } + + /* compute A1 := A - 1 */ + if (!BN_copy(A1, A)) { + goto err; + } + if (!BN_sub_word(A1, 1)) { + goto err; + } + if (BN_is_zero(A1)) { + ret = 0; + goto err; + } + + /* write A1 as A1_odd * 2^k */ + k = 1; + while (!BN_is_bit_set(A1, k)) { + k++; + } + if (!BN_rshift(A1_odd, A1, k)) { + goto err; + } + + /* Montgomery setup for computations mod A */ + mont = BN_MONT_CTX_new(); + if (mont == NULL) { + goto err; + } + if (!BN_MONT_CTX_set(mont, A, ctx)) { + goto err; + } + + for (i = 0; i < checks; i++) { + if (!BN_pseudo_rand_range(check, A1)) { + goto err; + } + if (!BN_add_word(check, 1)) { + goto err; + } + /* now 1 <= check < A */ + + j = witness(check, A, A1, A1_odd, k, ctx, mont); + if (j == -1) { + goto err; + } + if (j) { + ret = 0; + goto err; + } + if (!BN_GENCB_call(cb, 1, i)) { + goto err; + } + } + ret = 1; + +err: + if (ctx != NULL) { + BN_CTX_end(ctx); + if (ctx_passed == NULL) { + BN_CTX_free(ctx); + } + } + if (mont != NULL) { + BN_MONT_CTX_free(mont); + } + + return ret; +} + +static int witness(BIGNUM *w, const BIGNUM *a, const BIGNUM *a1, + const BIGNUM *a1_odd, int k, BN_CTX *ctx, + BN_MONT_CTX *mont) { + if (!BN_mod_exp_mont(w, w, a1_odd, a, ctx, mont)) { /* w := w^a1_odd mod a */ + return -1; + } + if (BN_is_one(w)) { + return 0; /* probably prime */ + } + if (BN_cmp(w, a1) == 0) { + return 0; /* w == -1 (mod a), 'a' is probably prime */ + } + + while (--k) { + if (!BN_mod_mul(w, w, w, a, ctx)) { /* w := w^2 mod a */ + return -1; + } + + if (BN_is_one(w)) { + return 1; /* 'a' is composite, otherwise a previous 'w' would + * have been == -1 (mod 'a') */ + } + + if (BN_cmp(w, a1) == 0) { + return 0; /* w == -1 (mod a), 'a' is probably prime */ + } + } + + /* If we get here, 'w' is the (a-1)/2-th power of the original 'w', + * and it is neither -1 nor +1 -- so 'a' cannot be prime */ + return 1; +} + +static BN_ULONG get_word(const BIGNUM *bn) { + if (bn->top == 1) { + return bn->d[0]; + } + return 0; +} + +static int probable_prime(BIGNUM *rnd, int bits) { + int i; + uint16_t mods[NUMPRIMES]; + BN_ULONG delta; + BN_ULONG maxdelta = BN_MASK2 - primes[NUMPRIMES - 1]; + char is_single_word = bits <= BN_BITS2; + +again: + if (!BN_rand(rnd, bits, 1, 1)) { + return 0; + } + + /* we now have a random number 'rnd' to test. */ + for (i = 1; i < NUMPRIMES; i++) { + mods[i] = (uint16_t)BN_mod_word(rnd, (BN_ULONG)primes[i]); + } + /* If bits is so small that it fits into a single word then we + * additionally don't want to exceed that many bits. */ + if (is_single_word) { + BN_ULONG size_limit; + if (bits == BN_BITS2) { + /* Avoid undefined behavior. */ + size_limit = ~((BN_ULONG)0) - get_word(rnd); + } else { + size_limit = (((BN_ULONG)1) << bits) - get_word(rnd) - 1; + } + if (size_limit < maxdelta) { + maxdelta = size_limit; + } + } + delta = 0; + +loop: + if (is_single_word) { + BN_ULONG rnd_word = get_word(rnd); + + /* In the case that the candidate prime is a single word then + * we check that: + * 1) It's greater than primes[i] because we shouldn't reject + * 3 as being a prime number because it's a multiple of + * three. + * 2) That it's not a multiple of a known prime. We don't + * check that rnd-1 is also coprime to all the known + * primes because there aren't many small primes where + * that's true. */ + for (i = 1; i < NUMPRIMES && primes[i] < rnd_word; i++) { + if ((mods[i] + delta) % primes[i] == 0) { + delta += 2; + if (delta > maxdelta) { + goto again; + } + goto loop; + } + } + } else { + for (i = 1; i < NUMPRIMES; i++) { + /* check that rnd is not a prime and also + * that gcd(rnd-1,primes) == 1 (except for 2) */ + if (((mods[i] + delta) % primes[i]) <= 1) { + delta += 2; + if (delta > maxdelta) { + goto again; + } + goto loop; + } + } + } + + if (!BN_add_word(rnd, delta)) { + return 0; + } + if (BN_num_bits(rnd) != bits) { + goto again; + } + + return 1; +} + +static int probable_prime_dh(BIGNUM *rnd, int bits, const BIGNUM *add, + const BIGNUM *rem, BN_CTX *ctx) { + int i, ret = 0; + BIGNUM *t1; + + BN_CTX_start(ctx); + if ((t1 = BN_CTX_get(ctx)) == NULL) { + goto err; + } + + if (!BN_rand(rnd, bits, 0, 1)) { + goto err; + } + + /* we need ((rnd-rem) % add) == 0 */ + + if (!BN_mod(t1, rnd, add, ctx)) { + goto err; + } + if (!BN_sub(rnd, rnd, t1)) { + goto err; + } + if (rem == NULL) { + if (!BN_add_word(rnd, 1)) { + goto err; + } + } else { + if (!BN_add(rnd, rnd, rem)) { + goto err; + } + } + /* we now have a random number 'rand' to test. */ + +loop: + for (i = 1; i < NUMPRIMES; i++) { + /* check that rnd is a prime */ + if (BN_mod_word(rnd, (BN_ULONG)primes[i]) <= 1) { + if (!BN_add(rnd, rnd, add)) { + goto err; + } + goto loop; + } + } + + ret = 1; + +err: + BN_CTX_end(ctx); + return ret; +} + +static int probable_prime_dh_safe(BIGNUM *p, int bits, const BIGNUM *padd, + const BIGNUM *rem, BN_CTX *ctx) { + int i, ret = 0; + BIGNUM *t1, *qadd, *q; + + bits--; + BN_CTX_start(ctx); + t1 = BN_CTX_get(ctx); + q = BN_CTX_get(ctx); + qadd = BN_CTX_get(ctx); + if (qadd == NULL) { + goto err; + } + + if (!BN_rshift1(qadd, padd)) { + goto err; + } + + if (!BN_rand(q, bits, 0, 1)) { + goto err; + } + + /* we need ((rnd-rem) % add) == 0 */ + if (!BN_mod(t1, q, qadd, ctx)) { + goto err; + } + + if (!BN_sub(q, q, t1)) { + goto err; + } + + if (rem == NULL) { + if (!BN_add_word(q, 1)) { + goto err; + } + } else { + if (!BN_rshift1(t1, rem)) { + goto err; + } + if (!BN_add(q, q, t1)) { + goto err; + } + } + + /* we now have a random number 'rand' to test. */ + if (!BN_lshift1(p, q)) { + goto err; + } + if (!BN_add_word(p, 1)) { + goto err; + } + +loop: + for (i = 1; i < NUMPRIMES; i++) { + /* check that p and q are prime */ + /* check that for p and q + * gcd(p-1,primes) == 1 (except for 2) */ + if ((BN_mod_word(p, (BN_ULONG)primes[i]) == 0) || + (BN_mod_word(q, (BN_ULONG)primes[i]) == 0)) { + if (!BN_add(p, p, padd)) { + goto err; + } + if (!BN_add(q, q, qadd)) { + goto err; + } + goto loop; + } + } + + ret = 1; + +err: + BN_CTX_end(ctx); + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/random.c b/TMessagesProj/jni/boringssl/crypto/bn/random.c new file mode 100644 index 00000000..3116e547 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/random.c @@ -0,0 +1,326 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include + +#include +#include +#include +#include + +int BN_rand(BIGNUM *rnd, int bits, int top, int bottom) { + uint8_t *buf = NULL; + int ret = 0, bit, bytes, mask; + + if (rnd == NULL) { + return 0; + } + + if (bits == 0) { + BN_zero(rnd); + return 1; + } + + bytes = (bits + 7) / 8; + bit = (bits - 1) % 8; + mask = 0xff << (bit + 1); + + buf = OPENSSL_malloc(bytes); + if (buf == NULL) { + OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* Make a random number and set the top and bottom bits. */ + if (!RAND_bytes(buf, bytes)) { + goto err; + } + + if (top != -1) { + if (top && bits > 1) { + if (bit == 0) { + buf[0] = 1; + buf[1] |= 0x80; + } else { + buf[0] |= (3 << (bit - 1)); + } + } else { + buf[0] |= (1 << bit); + } + } + + buf[0] &= ~mask; + + /* set bottom bit if requested */ + if (bottom) { + buf[bytes - 1] |= 1; + } + + if (!BN_bin2bn(buf, bytes, rnd)) { + goto err; + } + + ret = 1; + +err: + if (buf != NULL) { + OPENSSL_cleanse(buf, bytes); + OPENSSL_free(buf); + } + return (ret); +} + +int BN_pseudo_rand(BIGNUM *rnd, int bits, int top, int bottom) { + return BN_rand(rnd, bits, top, bottom); +} + +int BN_rand_range(BIGNUM *r, const BIGNUM *range) { + unsigned n; + unsigned count = 100; + + if (range->neg || BN_is_zero(range)) { + OPENSSL_PUT_ERROR(BN, BN_R_INVALID_RANGE); + return 0; + } + + n = BN_num_bits(range); /* n > 0 */ + + /* BN_is_bit_set(range, n - 1) always holds */ + if (n == 1) { + BN_zero(r); + } else if (!BN_is_bit_set(range, n - 2) && !BN_is_bit_set(range, n - 3)) { + /* range = 100..._2, + * so 3*range (= 11..._2) is exactly one bit longer than range */ + do { + if (!BN_rand(r, n + 1, -1 /* don't set most significant bits */, + 0 /* don't set least significant bits */)) { + return 0; + } + + /* If r < 3*range, use r := r MOD range (which is either r, r - range, or + * r - 2*range). Otherwise, iterate again. Since 3*range = 11..._2, each + * iteration succeeds with probability >= .75. */ + if (BN_cmp(r, range) >= 0) { + if (!BN_sub(r, r, range)) { + return 0; + } + if (BN_cmp(r, range) >= 0) { + if (!BN_sub(r, r, range)) { + return 0; + } + } + } + + if (!--count) { + OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_ITERATIONS); + return 0; + } + } while (BN_cmp(r, range) >= 0); + } else { + do { + /* range = 11..._2 or range = 101..._2 */ + if (!BN_rand(r, n, -1, 0)) { + return 0; + } + + if (!--count) { + OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_ITERATIONS); + return 0; + } + } while (BN_cmp(r, range) >= 0); + } + + return 1; +} + +int BN_pseudo_rand_range(BIGNUM *r, const BIGNUM *range) { + return BN_rand_range(r, range); +} + +int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range, const BIGNUM *priv, + const uint8_t *message, size_t message_len, + BN_CTX *ctx) { + SHA512_CTX sha; + /* We use 512 bits of random data per iteration to + * ensure that we have at least |range| bits of randomness. */ + uint8_t random_bytes[64]; + uint8_t digest[SHA512_DIGEST_LENGTH]; + size_t done, todo, attempt; + const unsigned num_k_bytes = BN_num_bytes(range); + const unsigned bits_to_mask = (8 - (BN_num_bits(range) % 8)) % 8; + uint8_t private_bytes[96]; + uint8_t *k_bytes = NULL; + int ret = 0; + + if (out == NULL) { + return 0; + } + + if (BN_is_zero(range)) { + OPENSSL_PUT_ERROR(BN, BN_R_DIV_BY_ZERO); + goto err; + } + + k_bytes = OPENSSL_malloc(num_k_bytes); + if (!k_bytes) { + OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* We copy |priv| into a local buffer to avoid furthur exposing its + * length. */ + todo = sizeof(priv->d[0]) * priv->top; + if (todo > sizeof(private_bytes)) { + /* No reasonable DSA or ECDSA key should have a private key + * this large and we don't handle this case in order to avoid + * leaking the length of the private key. */ + OPENSSL_PUT_ERROR(BN, BN_R_PRIVATE_KEY_TOO_LARGE); + goto err; + } + memcpy(private_bytes, priv->d, todo); + memset(private_bytes + todo, 0, sizeof(private_bytes) - todo); + + for (attempt = 0;; attempt++) { + for (done = 0; done < num_k_bytes;) { + if (!RAND_bytes(random_bytes, sizeof(random_bytes))) { + goto err; + } + SHA512_Init(&sha); + SHA512_Update(&sha, &attempt, sizeof(attempt)); + SHA512_Update(&sha, &done, sizeof(done)); + SHA512_Update(&sha, private_bytes, sizeof(private_bytes)); + SHA512_Update(&sha, message, message_len); + SHA512_Update(&sha, random_bytes, sizeof(random_bytes)); + SHA512_Final(digest, &sha); + + todo = num_k_bytes - done; + if (todo > SHA512_DIGEST_LENGTH) { + todo = SHA512_DIGEST_LENGTH; + } + memcpy(k_bytes + done, digest, todo); + done += todo; + } + + k_bytes[0] &= 0xff >> bits_to_mask; + + if (!BN_bin2bn(k_bytes, num_k_bytes, out)) { + goto err; + } + if (BN_cmp(out, range) < 0) { + break; + } + } + + ret = 1; + +err: + OPENSSL_free(k_bytes); + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/rsaz_exp.c b/TMessagesProj/jni/boringssl/crypto/bn/rsaz_exp.c new file mode 100644 index 00000000..c8027520 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/rsaz_exp.c @@ -0,0 +1,326 @@ +/***************************************************************************** +* * +* Copyright (c) 2012, Intel Corporation * +* * +* All rights reserved. * +* * +* Redistribution and use in source and binary forms, with or without * +* modification, are permitted provided that the following conditions are * +* met: * +* * +* * Redistributions of source code must retain the above copyright * +* notice, this list of conditions and the following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above copyright * +* notice, this list of conditions and the following disclaimer in the * +* documentation and/or other materials provided with the * +* distribution. * +* * +* * Neither the name of the Intel Corporation nor the names of its * +* contributors may be used to endorse or promote products derived from * +* this software without specific prior written permission. * +* * +* * +* THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""AS IS"" AND ANY * +* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * +* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR * +* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * +* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * +* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * +* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * +* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +* * +****************************************************************************** +* Developers and authors: * +* Shay Gueron (1, 2), and Vlad Krasnov (1) * +* (1) Intel Corporation, Israel Development Center, Haifa, Israel * +* (2) University of Haifa, Israel * +*****************************************************************************/ + +#include + +#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) + +#include "rsaz_exp.h" + +#include + +/* + * See crypto/bn/asm/rsaz-avx2.pl for further details. + */ +void rsaz_1024_norm2red_avx2(void *red,const void *norm); +void rsaz_1024_mul_avx2(void *ret,const void *a,const void *b,const void *n,BN_ULONG k); +void rsaz_1024_sqr_avx2(void *ret,const void *a,const void *n,BN_ULONG k,int cnt); +void rsaz_1024_scatter5_avx2(void *tbl,const void *val,int i); +void rsaz_1024_gather5_avx2(void *val,const void *tbl,int i); +void rsaz_1024_red2norm_avx2(void *norm,const void *red); + +#if defined(__GNUC__) +# define ALIGN64 __attribute__((aligned(64))) +#elif defined(_MSC_VER) +# define ALIGN64 __declspec(align(64)) +#elif defined(__SUNPRO_C) +# define ALIGN64 +# pragma align 64(one,two80) +#else +# define ALIGN64 /* not fatal, might hurt performance a little */ +#endif + +ALIGN64 static const BN_ULONG one[40] = + {1,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +ALIGN64 static const BN_ULONG two80[40] = + {0,0,1<<22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + +void RSAZ_1024_mod_exp_avx2(BN_ULONG result_norm[16], + const BN_ULONG base_norm[16], const BN_ULONG exponent[16], + const BN_ULONG m_norm[16], const BN_ULONG RR[16], BN_ULONG k0) +{ + unsigned char storage[320*3+32*9*16+64]; /* 5.5KB */ + unsigned char *p_str = storage + (64-((size_t)storage%64)); + unsigned char *a_inv, *m, *result, + *table_s = p_str+320*3, + *R2 = table_s; /* borrow */ + int index; + int wvalue; + + if ((((size_t)p_str&4095)+320)>>12) { + result = p_str; + a_inv = p_str + 320; + m = p_str + 320*2; /* should not cross page */ + } else { + m = p_str; /* should not cross page */ + result = p_str + 320; + a_inv = p_str + 320*2; + } + + rsaz_1024_norm2red_avx2(m, m_norm); + rsaz_1024_norm2red_avx2(a_inv, base_norm); + rsaz_1024_norm2red_avx2(R2, RR); + + rsaz_1024_mul_avx2(R2, R2, R2, m, k0); + rsaz_1024_mul_avx2(R2, R2, two80, m, k0); + + /* table[0] = 1 */ + rsaz_1024_mul_avx2(result, R2, one, m, k0); + /* table[1] = a_inv^1 */ + rsaz_1024_mul_avx2(a_inv, a_inv, R2, m, k0); + + rsaz_1024_scatter5_avx2(table_s,result,0); + rsaz_1024_scatter5_avx2(table_s,a_inv,1); + + /* table[2] = a_inv^2 */ + rsaz_1024_sqr_avx2(result, a_inv, m, k0, 1); + rsaz_1024_scatter5_avx2(table_s,result,2); +#if 0 + /* this is almost 2x smaller and less than 1% slower */ + for (index=3; index<32; index++) { + rsaz_1024_mul_avx2(result, result, a_inv, m, k0); + rsaz_1024_scatter5_avx2(table_s,result,index); + } +#else + /* table[4] = a_inv^4 */ + rsaz_1024_sqr_avx2(result, result, m, k0, 1); + rsaz_1024_scatter5_avx2(table_s,result,4); + /* table[8] = a_inv^8 */ + rsaz_1024_sqr_avx2(result, result, m, k0, 1); + rsaz_1024_scatter5_avx2(table_s,result,8); + /* table[16] = a_inv^16 */ + rsaz_1024_sqr_avx2(result, result, m, k0, 1); + rsaz_1024_scatter5_avx2(table_s,result,16); + /* table[17] = a_inv^17 */ + rsaz_1024_mul_avx2(result, result, a_inv, m, k0); + rsaz_1024_scatter5_avx2(table_s,result,17); + + /* table[3] */ + rsaz_1024_gather5_avx2(result,table_s,2); + rsaz_1024_mul_avx2(result,result,a_inv,m,k0); + rsaz_1024_scatter5_avx2(table_s,result,3); + /* table[6] */ + rsaz_1024_sqr_avx2(result, result, m, k0, 1); + rsaz_1024_scatter5_avx2(table_s,result,6); + /* table[12] */ + rsaz_1024_sqr_avx2(result, result, m, k0, 1); + rsaz_1024_scatter5_avx2(table_s,result,12); + /* table[24] */ + rsaz_1024_sqr_avx2(result, result, m, k0, 1); + rsaz_1024_scatter5_avx2(table_s,result,24); + /* table[25] */ + rsaz_1024_mul_avx2(result, result, a_inv, m, k0); + rsaz_1024_scatter5_avx2(table_s,result,25); + + /* table[5] */ + rsaz_1024_gather5_avx2(result,table_s,4); + rsaz_1024_mul_avx2(result,result,a_inv,m,k0); + rsaz_1024_scatter5_avx2(table_s,result,5); + /* table[10] */ + rsaz_1024_sqr_avx2(result, result, m, k0, 1); + rsaz_1024_scatter5_avx2(table_s,result,10); + /* table[20] */ + rsaz_1024_sqr_avx2(result, result, m, k0, 1); + rsaz_1024_scatter5_avx2(table_s,result,20); + /* table[21] */ + rsaz_1024_mul_avx2(result, result, a_inv, m, k0); + rsaz_1024_scatter5_avx2(table_s,result,21); + + /* table[7] */ + rsaz_1024_gather5_avx2(result,table_s,6); + rsaz_1024_mul_avx2(result,result,a_inv,m,k0); + rsaz_1024_scatter5_avx2(table_s,result,7); + /* table[14] */ + rsaz_1024_sqr_avx2(result, result, m, k0, 1); + rsaz_1024_scatter5_avx2(table_s,result,14); + /* table[28] */ + rsaz_1024_sqr_avx2(result, result, m, k0, 1); + rsaz_1024_scatter5_avx2(table_s,result,28); + /* table[29] */ + rsaz_1024_mul_avx2(result, result, a_inv, m, k0); + rsaz_1024_scatter5_avx2(table_s,result,29); + + /* table[9] */ + rsaz_1024_gather5_avx2(result,table_s,8); + rsaz_1024_mul_avx2(result,result,a_inv,m,k0); + rsaz_1024_scatter5_avx2(table_s,result,9); + /* table[18] */ + rsaz_1024_sqr_avx2(result, result, m, k0, 1); + rsaz_1024_scatter5_avx2(table_s,result,18); + /* table[19] */ + rsaz_1024_mul_avx2(result, result, a_inv, m, k0); + rsaz_1024_scatter5_avx2(table_s,result,19); + + /* table[11] */ + rsaz_1024_gather5_avx2(result,table_s,10); + rsaz_1024_mul_avx2(result,result,a_inv,m,k0); + rsaz_1024_scatter5_avx2(table_s,result,11); + /* table[22] */ + rsaz_1024_sqr_avx2(result, result, m, k0, 1); + rsaz_1024_scatter5_avx2(table_s,result,22); + /* table[23] */ + rsaz_1024_mul_avx2(result, result, a_inv, m, k0); + rsaz_1024_scatter5_avx2(table_s,result,23); + + /* table[13] */ + rsaz_1024_gather5_avx2(result,table_s,12); + rsaz_1024_mul_avx2(result,result,a_inv,m,k0); + rsaz_1024_scatter5_avx2(table_s,result,13); + /* table[26] */ + rsaz_1024_sqr_avx2(result, result, m, k0, 1); + rsaz_1024_scatter5_avx2(table_s,result,26); + /* table[27] */ + rsaz_1024_mul_avx2(result, result, a_inv, m, k0); + rsaz_1024_scatter5_avx2(table_s,result,27); + + /* table[15] */ + rsaz_1024_gather5_avx2(result,table_s,14); + rsaz_1024_mul_avx2(result,result,a_inv,m,k0); + rsaz_1024_scatter5_avx2(table_s,result,15); + /* table[30] */ + rsaz_1024_sqr_avx2(result, result, m, k0, 1); + rsaz_1024_scatter5_avx2(table_s,result,30); + /* table[31] */ + rsaz_1024_mul_avx2(result, result, a_inv, m, k0); + rsaz_1024_scatter5_avx2(table_s,result,31); +#endif + + /* load first window */ + p_str = (unsigned char*)exponent; + wvalue = p_str[127] >> 3; + rsaz_1024_gather5_avx2(result,table_s,wvalue); + + index = 1014; + + while(index > -1) { /* loop for the remaining 127 windows */ + + rsaz_1024_sqr_avx2(result, result, m, k0, 5); + + wvalue = *((unsigned short*)&p_str[index/8]); + wvalue = (wvalue>> (index%8)) & 31; + index-=5; + + rsaz_1024_gather5_avx2(a_inv,table_s,wvalue); /* borrow a_inv */ + rsaz_1024_mul_avx2(result, result, a_inv, m, k0); + } + + /* square four times */ + rsaz_1024_sqr_avx2(result, result, m, k0, 4); + + wvalue = p_str[0] & 15; + + rsaz_1024_gather5_avx2(a_inv,table_s,wvalue); /* borrow a_inv */ + rsaz_1024_mul_avx2(result, result, a_inv, m, k0); + + /* from Montgomery */ + rsaz_1024_mul_avx2(result, result, one, m, k0); + + rsaz_1024_red2norm_avx2(result_norm, result); + + OPENSSL_cleanse(storage,sizeof(storage)); +} + +/* + * See crypto/bn/rsaz-x86_64.pl for further details. + */ +void rsaz_512_mul(void *ret,const void *a,const void *b,const void *n,BN_ULONG k); +void rsaz_512_mul_scatter4(void *ret,const void *a,const void *n,BN_ULONG k,const void *tbl,unsigned int power); +void rsaz_512_mul_gather4(void *ret,const void *a,const void *tbl,const void *n,BN_ULONG k,unsigned int power); +void rsaz_512_mul_by_one(void *ret,const void *a,const void *n,BN_ULONG k); +void rsaz_512_sqr(void *ret,const void *a,const void *n,BN_ULONG k,int cnt); +void rsaz_512_scatter4(void *tbl, const BN_ULONG *val, int power); +void rsaz_512_gather4(BN_ULONG *val, const void *tbl, int power); + +void RSAZ_512_mod_exp(BN_ULONG result[8], + const BN_ULONG base[8], const BN_ULONG exponent[8], + const BN_ULONG m[8], BN_ULONG k0, const BN_ULONG RR[8]) +{ + unsigned char storage[16*8*8+64*2+64]; /* 1.2KB */ + unsigned char *table = storage + (64-((size_t)storage%64)); + BN_ULONG *a_inv = (BN_ULONG *)(table+16*8*8), + *temp = (BN_ULONG *)(table+16*8*8+8*8); + unsigned char *p_str = (unsigned char*)exponent; + int index; + unsigned int wvalue; + + /* table[0] = 1_inv */ + temp[0] = 0-m[0]; temp[1] = ~m[1]; + temp[2] = ~m[2]; temp[3] = ~m[3]; + temp[4] = ~m[4]; temp[5] = ~m[5]; + temp[6] = ~m[6]; temp[7] = ~m[7]; + rsaz_512_scatter4(table, temp, 0); + + /* table [1] = a_inv^1 */ + rsaz_512_mul(a_inv, base, RR, m, k0); + rsaz_512_scatter4(table, a_inv, 1); + + /* table [2] = a_inv^2 */ + rsaz_512_sqr(temp, a_inv, m, k0, 1); + rsaz_512_scatter4(table, temp, 2); + + for (index=3; index<16; index++) + rsaz_512_mul_scatter4(temp, a_inv, m, k0, table, index); + + /* load first window */ + wvalue = p_str[63]; + + rsaz_512_gather4(temp, table, wvalue>>4); + rsaz_512_sqr(temp, temp, m, k0, 4); + rsaz_512_mul_gather4(temp, temp, table, m, k0, wvalue&0xf); + + for (index=62; index>=0; index--) { + wvalue = p_str[index]; + + rsaz_512_sqr(temp, temp, m, k0, 4); + rsaz_512_mul_gather4(temp, temp, table, m, k0, wvalue>>4); + + rsaz_512_sqr(temp, temp, m, k0, 4); + rsaz_512_mul_gather4(temp, temp, table, m, k0, wvalue&0x0f); + } + + /* from Montgomery */ + rsaz_512_mul_by_one(result, temp, m, k0); + + OPENSSL_cleanse(storage,sizeof(storage)); +} + +#endif /* OPENSSL_X86_64 */ diff --git a/TMessagesProj/jni/boringssl/crypto/bn/rsaz_exp.h b/TMessagesProj/jni/boringssl/crypto/bn/rsaz_exp.h new file mode 100644 index 00000000..c752b45f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/rsaz_exp.h @@ -0,0 +1,56 @@ +/***************************************************************************** +* * +* Copyright (c) 2012, Intel Corporation * +* * +* All rights reserved. * +* * +* Redistribution and use in source and binary forms, with or without * +* modification, are permitted provided that the following conditions are * +* met: * +* * +* * Redistributions of source code must retain the above copyright * +* notice, this list of conditions and the following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above copyright * +* notice, this list of conditions and the following disclaimer in the * +* documentation and/or other materials provided with the * +* distribution. * +* * +* * Neither the name of the Intel Corporation nor the names of its * +* contributors may be used to endorse or promote products derived from * +* this software without specific prior written permission. * +* * +* * +* THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""AS IS"" AND ANY * +* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * +* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR * +* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * +* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * +* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * +* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * +* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +* * +****************************************************************************** +* Developers and authors: * +* Shay Gueron (1, 2), and Vlad Krasnov (1) * +* (1) Intel Corporation, Israel Development Center, Haifa, Israel * +* (2) University of Haifa, Israel * +*****************************************************************************/ + +#ifndef RSAZ_EXP_H +#define RSAZ_EXP_H + +#include + +void RSAZ_1024_mod_exp_avx2(BN_ULONG result[16], + const BN_ULONG base_norm[16], const BN_ULONG exponent[16], + const BN_ULONG m_norm[16], const BN_ULONG RR[16], BN_ULONG k0); +int rsaz_avx2_eligible(void); + +void RSAZ_512_mod_exp(BN_ULONG result[8], + const BN_ULONG base_norm[8], const BN_ULONG exponent[8], + const BN_ULONG m_norm[8], BN_ULONG k0, const BN_ULONG RR[8]); +#endif diff --git a/TMessagesProj/jni/boringssl/crypto/bn/shift.c b/TMessagesProj/jni/boringssl/crypto/bn/shift.c new file mode 100644 index 00000000..defec929 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/shift.c @@ -0,0 +1,299 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include + +#include "internal.h" + + +int BN_lshift(BIGNUM *r, const BIGNUM *a, int n) { + int i, nw, lb, rb; + BN_ULONG *t, *f; + BN_ULONG l; + + if (n < 0) { + OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER); + return 0; + } + + r->neg = a->neg; + nw = n / BN_BITS2; + if (bn_wexpand(r, a->top + nw + 1) == NULL) { + return 0; + } + lb = n % BN_BITS2; + rb = BN_BITS2 - lb; + f = a->d; + t = r->d; + t[a->top + nw] = 0; + if (lb == 0) { + for (i = a->top - 1; i >= 0; i--) { + t[nw + i] = f[i]; + } + } else { + for (i = a->top - 1; i >= 0; i--) { + l = f[i]; + t[nw + i + 1] |= (l >> rb) & BN_MASK2; + t[nw + i] = (l << lb) & BN_MASK2; + } + } + memset(t, 0, nw * sizeof(t[0])); + r->top = a->top + nw + 1; + bn_correct_top(r); + + return 1; +} + +int BN_lshift1(BIGNUM *r, const BIGNUM *a) { + BN_ULONG *ap, *rp, t, c; + int i; + + if (r != a) { + r->neg = a->neg; + if (bn_wexpand(r, a->top + 1) == NULL) { + return 0; + } + r->top = a->top; + } else { + if (bn_wexpand(r, a->top + 1) == NULL) { + return 0; + } + } + ap = a->d; + rp = r->d; + c = 0; + for (i = 0; i < a->top; i++) { + t = *(ap++); + *(rp++) = ((t << 1) | c) & BN_MASK2; + c = (t & BN_TBIT) ? 1 : 0; + } + if (c) { + *rp = 1; + r->top++; + } + + return 1; +} + +int BN_rshift(BIGNUM *r, const BIGNUM *a, int n) { + int i, j, nw, lb, rb; + BN_ULONG *t, *f; + BN_ULONG l, tmp; + + if (n < 0) { + OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER); + return 0; + } + + nw = n / BN_BITS2; + rb = n % BN_BITS2; + lb = BN_BITS2 - rb; + if (nw >= a->top || a->top == 0) { + BN_zero(r); + return 1; + } + i = (BN_num_bits(a) - n + (BN_BITS2 - 1)) / BN_BITS2; + if (r != a) { + r->neg = a->neg; + if (bn_wexpand(r, i) == NULL) { + return 0; + } + } else { + if (n == 0) { + return 1; /* or the copying loop will go berserk */ + } + } + + f = &(a->d[nw]); + t = r->d; + j = a->top - nw; + r->top = i; + + if (rb == 0) { + for (i = j; i != 0; i--) { + *(t++) = *(f++); + } + } else { + l = *(f++); + for (i = j - 1; i != 0; i--) { + tmp = (l >> rb) & BN_MASK2; + l = *(f++); + *(t++) = (tmp | (l << lb)) & BN_MASK2; + } + if ((l = (l >> rb) & BN_MASK2)) { + *(t) = l; + } + } + + return 1; +} + +int BN_rshift1(BIGNUM *r, const BIGNUM *a) { + BN_ULONG *ap, *rp, t, c; + int i, j; + + if (BN_is_zero(a)) { + BN_zero(r); + return 1; + } + i = a->top; + ap = a->d; + j = i - (ap[i - 1] == 1); + if (a != r) { + if (bn_wexpand(r, j) == NULL) { + return 0; + } + r->neg = a->neg; + } + rp = r->d; + t = ap[--i]; + c = (t & 1) ? BN_TBIT : 0; + if (t >>= 1) { + rp[i] = t; + } + while (i > 0) { + t = ap[--i]; + rp[i] = ((t >> 1) & BN_MASK2) | c; + c = (t & 1) ? BN_TBIT : 0; + } + r->top = j; + + return 1; +} + +int BN_set_bit(BIGNUM *a, int n) { + int i, j, k; + + if (n < 0) { + return 0; + } + + i = n / BN_BITS2; + j = n % BN_BITS2; + if (a->top <= i) { + if (bn_wexpand(a, i + 1) == NULL) { + return 0; + } + for (k = a->top; k < i + 1; k++) { + a->d[k] = 0; + } + a->top = i + 1; + } + + a->d[i] |= (((BN_ULONG)1) << j); + + return 1; +} + +int BN_clear_bit(BIGNUM *a, int n) { + int i, j; + + if (n < 0) { + return 0; + } + + i = n / BN_BITS2; + j = n % BN_BITS2; + if (a->top <= i) { + return 0; + } + + a->d[i] &= (~(((BN_ULONG)1) << j)); + bn_correct_top(a); + return 1; +} + +int BN_is_bit_set(const BIGNUM *a, int n) { + int i, j; + + if (n < 0) { + return 0; + } + i = n / BN_BITS2; + j = n % BN_BITS2; + if (a->top <= i) { + return 0; + } + + return (a->d[i]>>j)&1; +} + +int BN_mask_bits(BIGNUM *a, int n) { + int b, w; + + if (n < 0) { + return 0; + } + + w = n / BN_BITS2; + b = n % BN_BITS2; + if (w >= a->top) { + return 0; + } + if (b == 0) { + a->top = w; + } else { + a->top = w + 1; + a->d[w] &= ~(BN_MASK2 << b); + } + + bn_correct_top(a); + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/sqrt.c b/TMessagesProj/jni/boringssl/crypto/bn/sqrt.c new file mode 100644 index 00000000..2ed66c22 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/sqrt.c @@ -0,0 +1,505 @@ +/* Written by Lenka Fibikova + * and Bodo Moeller for the OpenSSL project. */ +/* ==================================================================== + * Copyright (c) 1998-2000 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include + + +/* Returns 'ret' such that + * ret^2 == a (mod p), + * using the Tonelli/Shanks algorithm (cf. Henri Cohen, "A Course + * in Algebraic Computational Number Theory", algorithm 1.5.1). + * 'p' must be prime! */ +BIGNUM *BN_mod_sqrt(BIGNUM *in, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx) { + BIGNUM *ret = in; + int err = 1; + int r; + BIGNUM *A, *b, *q, *t, *x, *y; + int e, i, j; + + if (!BN_is_odd(p) || BN_abs_is_word(p, 1)) { + if (BN_abs_is_word(p, 2)) { + if (ret == NULL) { + ret = BN_new(); + } + if (ret == NULL) { + goto end; + } + if (!BN_set_word(ret, BN_is_bit_set(a, 0))) { + if (ret != in) { + BN_free(ret); + } + return NULL; + } + return ret; + } + + OPENSSL_PUT_ERROR(BN, BN_R_P_IS_NOT_PRIME); + return (NULL); + } + + if (BN_is_zero(a) || BN_is_one(a)) { + if (ret == NULL) { + ret = BN_new(); + } + if (ret == NULL) { + goto end; + } + if (!BN_set_word(ret, BN_is_one(a))) { + if (ret != in) { + BN_free(ret); + } + return NULL; + } + return ret; + } + + BN_CTX_start(ctx); + A = BN_CTX_get(ctx); + b = BN_CTX_get(ctx); + q = BN_CTX_get(ctx); + t = BN_CTX_get(ctx); + x = BN_CTX_get(ctx); + y = BN_CTX_get(ctx); + if (y == NULL) { + goto end; + } + + if (ret == NULL) { + ret = BN_new(); + } + if (ret == NULL) { + goto end; + } + + /* A = a mod p */ + if (!BN_nnmod(A, a, p, ctx)) { + goto end; + } + + /* now write |p| - 1 as 2^e*q where q is odd */ + e = 1; + while (!BN_is_bit_set(p, e)) { + e++; + } + /* we'll set q later (if needed) */ + + if (e == 1) { + /* The easy case: (|p|-1)/2 is odd, so 2 has an inverse + * modulo (|p|-1)/2, and square roots can be computed + * directly by modular exponentiation. + * We have + * 2 * (|p|+1)/4 == 1 (mod (|p|-1)/2), + * so we can use exponent (|p|+1)/4, i.e. (|p|-3)/4 + 1. + */ + if (!BN_rshift(q, p, 2)) { + goto end; + } + q->neg = 0; + if (!BN_add_word(q, 1) || + !BN_mod_exp(ret, A, q, p, ctx)) { + goto end; + } + err = 0; + goto vrfy; + } + + if (e == 2) { + /* |p| == 5 (mod 8) + * + * In this case 2 is always a non-square since + * Legendre(2,p) = (-1)^((p^2-1)/8) for any odd prime. + * So if a really is a square, then 2*a is a non-square. + * Thus for + * b := (2*a)^((|p|-5)/8), + * i := (2*a)*b^2 + * we have + * i^2 = (2*a)^((1 + (|p|-5)/4)*2) + * = (2*a)^((p-1)/2) + * = -1; + * so if we set + * x := a*b*(i-1), + * then + * x^2 = a^2 * b^2 * (i^2 - 2*i + 1) + * = a^2 * b^2 * (-2*i) + * = a*(-i)*(2*a*b^2) + * = a*(-i)*i + * = a. + * + * (This is due to A.O.L. Atkin, + * , + * November 1992.) + */ + + /* t := 2*a */ + if (!BN_mod_lshift1_quick(t, A, p)) { + goto end; + } + + /* b := (2*a)^((|p|-5)/8) */ + if (!BN_rshift(q, p, 3)) { + goto end; + } + q->neg = 0; + if (!BN_mod_exp(b, t, q, p, ctx)) { + goto end; + } + + /* y := b^2 */ + if (!BN_mod_sqr(y, b, p, ctx)) { + goto end; + } + + /* t := (2*a)*b^2 - 1*/ + if (!BN_mod_mul(t, t, y, p, ctx) || + !BN_sub_word(t, 1)) { + goto end; + } + + /* x = a*b*t */ + if (!BN_mod_mul(x, A, b, p, ctx) || + !BN_mod_mul(x, x, t, p, ctx)) { + goto end; + } + + if (!BN_copy(ret, x)) { + goto end; + } + err = 0; + goto vrfy; + } + + /* e > 2, so we really have to use the Tonelli/Shanks algorithm. + * First, find some y that is not a square. */ + if (!BN_copy(q, p)) { + goto end; /* use 'q' as temp */ + } + q->neg = 0; + i = 2; + do { + /* For efficiency, try small numbers first; + * if this fails, try random numbers. + */ + if (i < 22) { + if (!BN_set_word(y, i)) { + goto end; + } + } else { + if (!BN_pseudo_rand(y, BN_num_bits(p), 0, 0)) { + goto end; + } + if (BN_ucmp(y, p) >= 0) { + if (!(p->neg ? BN_add : BN_sub)(y, y, p)) { + goto end; + } + } + /* now 0 <= y < |p| */ + if (BN_is_zero(y)) { + if (!BN_set_word(y, i)) { + goto end; + } + } + } + + r = BN_kronecker(y, q, ctx); /* here 'q' is |p| */ + if (r < -1) { + goto end; + } + if (r == 0) { + /* m divides p */ + OPENSSL_PUT_ERROR(BN, BN_R_P_IS_NOT_PRIME); + goto end; + } + } while (r == 1 && ++i < 82); + + if (r != -1) { + /* Many rounds and still no non-square -- this is more likely + * a bug than just bad luck. + * Even if p is not prime, we should have found some y + * such that r == -1. + */ + OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_ITERATIONS); + goto end; + } + + /* Here's our actual 'q': */ + if (!BN_rshift(q, q, e)) { + goto end; + } + + /* Now that we have some non-square, we can find an element + * of order 2^e by computing its q'th power. */ + if (!BN_mod_exp(y, y, q, p, ctx)) { + goto end; + } + if (BN_is_one(y)) { + OPENSSL_PUT_ERROR(BN, BN_R_P_IS_NOT_PRIME); + goto end; + } + + /* Now we know that (if p is indeed prime) there is an integer + * k, 0 <= k < 2^e, such that + * + * a^q * y^k == 1 (mod p). + * + * As a^q is a square and y is not, k must be even. + * q+1 is even, too, so there is an element + * + * X := a^((q+1)/2) * y^(k/2), + * + * and it satisfies + * + * X^2 = a^q * a * y^k + * = a, + * + * so it is the square root that we are looking for. + */ + + /* t := (q-1)/2 (note that q is odd) */ + if (!BN_rshift1(t, q)) { + goto end; + } + + /* x := a^((q-1)/2) */ + if (BN_is_zero(t)) /* special case: p = 2^e + 1 */ + { + if (!BN_nnmod(t, A, p, ctx)) { + goto end; + } + if (BN_is_zero(t)) { + /* special case: a == 0 (mod p) */ + BN_zero(ret); + err = 0; + goto end; + } else if (!BN_one(x)) { + goto end; + } + } else { + if (!BN_mod_exp(x, A, t, p, ctx)) { + goto end; + } + if (BN_is_zero(x)) { + /* special case: a == 0 (mod p) */ + BN_zero(ret); + err = 0; + goto end; + } + } + + /* b := a*x^2 (= a^q) */ + if (!BN_mod_sqr(b, x, p, ctx) || + !BN_mod_mul(b, b, A, p, ctx)) { + goto end; + } + + /* x := a*x (= a^((q+1)/2)) */ + if (!BN_mod_mul(x, x, A, p, ctx)) { + goto end; + } + + while (1) { + /* Now b is a^q * y^k for some even k (0 <= k < 2^E + * where E refers to the original value of e, which we + * don't keep in a variable), and x is a^((q+1)/2) * y^(k/2). + * + * We have a*b = x^2, + * y^2^(e-1) = -1, + * b^2^(e-1) = 1. + */ + + if (BN_is_one(b)) { + if (!BN_copy(ret, x)) { + goto end; + } + err = 0; + goto vrfy; + } + + + /* find smallest i such that b^(2^i) = 1 */ + i = 1; + if (!BN_mod_sqr(t, b, p, ctx)) { + goto end; + } + while (!BN_is_one(t)) { + i++; + if (i == e) { + OPENSSL_PUT_ERROR(BN, BN_R_NOT_A_SQUARE); + goto end; + } + if (!BN_mod_mul(t, t, t, p, ctx)) { + goto end; + } + } + + + /* t := y^2^(e - i - 1) */ + if (!BN_copy(t, y)) { + goto end; + } + for (j = e - i - 1; j > 0; j--) { + if (!BN_mod_sqr(t, t, p, ctx)) { + goto end; + } + } + if (!BN_mod_mul(y, t, t, p, ctx) || + !BN_mod_mul(x, x, t, p, ctx) || + !BN_mod_mul(b, b, y, p, ctx)) { + goto end; + } + e = i; + } + +vrfy: + if (!err) { + /* verify the result -- the input might have been not a square + * (test added in 0.9.8) */ + + if (!BN_mod_sqr(x, ret, p, ctx)) { + err = 1; + } + + if (!err && 0 != BN_cmp(x, A)) { + OPENSSL_PUT_ERROR(BN, BN_R_NOT_A_SQUARE); + err = 1; + } + } + +end: + if (err) { + if (ret != in) { + BN_clear_free(ret); + } + ret = NULL; + } + BN_CTX_end(ctx); + return ret; +} + +int BN_sqrt(BIGNUM *out_sqrt, const BIGNUM *in, BN_CTX *ctx) { + BIGNUM *estimate, *tmp, *delta, *last_delta, *tmp2; + int ok = 0, last_delta_valid = 0; + + if (in->neg) { + OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER); + return 0; + } + if (BN_is_zero(in)) { + BN_zero(out_sqrt); + return 1; + } + + BN_CTX_start(ctx); + if (out_sqrt == in) { + estimate = BN_CTX_get(ctx); + } else { + estimate = out_sqrt; + } + tmp = BN_CTX_get(ctx); + last_delta = BN_CTX_get(ctx); + delta = BN_CTX_get(ctx); + if (estimate == NULL || tmp == NULL || last_delta == NULL || delta == NULL) { + OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* We estimate that the square root of an n-bit number is 2^{n/2}. */ + BN_lshift(estimate, BN_value_one(), BN_num_bits(in)/2); + + /* This is Newton's method for finding a root of the equation |estimate|^2 - + * |in| = 0. */ + for (;;) { + /* |estimate| = 1/2 * (|estimate| + |in|/|estimate|) */ + if (!BN_div(tmp, NULL, in, estimate, ctx) || + !BN_add(tmp, tmp, estimate) || + !BN_rshift1(estimate, tmp) || + /* |tmp| = |estimate|^2 */ + !BN_sqr(tmp, estimate, ctx) || + /* |delta| = |in| - |tmp| */ + !BN_sub(delta, in, tmp)) { + OPENSSL_PUT_ERROR(BN, ERR_R_BN_LIB); + goto err; + } + + delta->neg = 0; + /* The difference between |in| and |estimate| squared is required to always + * decrease. This ensures that the loop always terminates, but I don't have + * a proof that it always finds the square root for a given square. */ + if (last_delta_valid && BN_cmp(delta, last_delta) >= 0) { + break; + } + + last_delta_valid = 1; + + tmp2 = last_delta; + last_delta = delta; + delta = tmp2; + } + + if (BN_cmp(tmp, in) != 0) { + OPENSSL_PUT_ERROR(BN, BN_R_NOT_A_SQUARE); + goto err; + } + + ok = 1; + +err: + if (ok && out_sqrt == in && !BN_copy(out_sqrt, estimate)) { + ok = 0; + } + BN_CTX_end(ctx); + return ok; +} diff --git a/TMessagesProj/jni/boringssl/crypto/buf/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/buf/CMakeLists.txt new file mode 100644 index 00000000..19edf7d5 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/buf/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories(. .. ../../include) + +add_library( + buf + + OBJECT + + buf.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/buf/buf.c b/TMessagesProj/jni/boringssl/crypto/buf/buf.c new file mode 100644 index 00000000..13b5cebd --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/buf/buf.c @@ -0,0 +1,235 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include + + +BUF_MEM *BUF_MEM_new(void) { + BUF_MEM *ret; + + ret = OPENSSL_malloc(sizeof(BUF_MEM)); + if (ret == NULL) { + OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE); + return NULL; + } + + memset(ret, 0, sizeof(BUF_MEM)); + return ret; +} + +void BUF_MEM_free(BUF_MEM *buf) { + if (buf == NULL) { + return; + } + + if (buf->data != NULL) { + OPENSSL_cleanse(buf->data, buf->max); + OPENSSL_free(buf->data); + } + + OPENSSL_free(buf); +} + +static size_t buf_mem_grow(BUF_MEM *buf, size_t len, char clean) { + char *new_buf; + size_t n, alloc_size; + + if (buf->length >= len) { + buf->length = len; + return len; + } + if (buf->max >= len) { + memset(&buf->data[buf->length], 0, len - buf->length); + buf->length = len; + return len; + } + + n = len + 3; + if (n < len) { + /* overflow */ + OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE); + return 0; + } + n = n / 3; + alloc_size = n * 4; + if (alloc_size / 4 != n) { + /* overflow */ + OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE); + return 0; + } + + if (buf->data == NULL) { + new_buf = OPENSSL_malloc(alloc_size); + } else { + if (clean) { + new_buf = OPENSSL_realloc_clean(buf->data, buf->max, alloc_size); + } else { + new_buf = OPENSSL_realloc(buf->data, alloc_size); + } + } + + if (new_buf == NULL) { + OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE); + len = 0; + } else { + buf->data = new_buf; + buf->max = alloc_size; + memset(&buf->data[buf->length], 0, len - buf->length); + buf->length = len; + } + + return len; +} + +size_t BUF_MEM_grow(BUF_MEM *buf, size_t len) { + return buf_mem_grow(buf, len, 0 /* don't clear old buffer contents. */); +} + +size_t BUF_MEM_grow_clean(BUF_MEM *buf, size_t len) { + return buf_mem_grow(buf, len, 1 /* clear old buffer contents. */); +} + +char *BUF_strdup(const char *buf) { + if (buf == NULL) { + return NULL; + } + + return BUF_strndup(buf, strlen(buf)); +} + +size_t BUF_strnlen(const char *str, size_t max_len) { + size_t i; + + for (i = 0; i < max_len; i++) { + if (str[i] == 0) { + break; + } + } + + return i; +} + +char *BUF_strndup(const char *buf, size_t size) { + char *ret; + size_t alloc_size; + + if (buf == NULL) { + return NULL; + } + + size = BUF_strnlen(buf, size); + + alloc_size = size + 1; + if (alloc_size < size) { + /* overflow */ + OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE); + return NULL; + } + ret = OPENSSL_malloc(alloc_size); + if (ret == NULL) { + OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE); + return NULL; + } + + memcpy(ret, buf, size); + ret[size] = '\0'; + return ret; +} + +size_t BUF_strlcpy(char *dst, const char *src, size_t dst_size) { + size_t l = 0; + + for (; dst_size > 1 && *src; dst_size--) { + *dst++ = *src++; + l++; + } + + if (dst_size) { + *dst = 0; + } + + return l + strlen(src); +} + +size_t BUF_strlcat(char *dst, const char *src, size_t dst_size) { + size_t l = 0; + for (; dst_size > 0 && *dst; dst_size--, dst++) { + l++; + } + return l + BUF_strlcpy(dst, src, dst_size); +} + +void *BUF_memdup(const void *data, size_t dst_size) { + void *ret; + + if (data == NULL) { + return NULL; + } + + ret = OPENSSL_malloc(dst_size); + if (ret == NULL) { + OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE); + return NULL; + } + + memcpy(ret, data, dst_size); + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bytestring/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/bytestring/CMakeLists.txt new file mode 100644 index 00000000..8326054b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bytestring/CMakeLists.txt @@ -0,0 +1,11 @@ +include_directories(. .. ../../include) + +add_library( + bytestring + + OBJECT + + ber.c + cbs.c + cbb.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/bytestring/ber.c b/TMessagesProj/jni/boringssl/crypto/bytestring/ber.c new file mode 100644 index 00000000..e3b150ca --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bytestring/ber.c @@ -0,0 +1,221 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#include + +#include "internal.h" + + +/* kMaxDepth is a just a sanity limit. The code should be such that the length + * of the input being processes always decreases. None the less, a very large + * input could otherwise cause the stack to overflow. */ +static const unsigned kMaxDepth = 2048; + +/* cbs_find_ber walks an ASN.1 structure in |orig_in| and sets |*ber_found| + * depending on whether an indefinite length element was found. The value of + * |in| is not changed. It returns one on success (i.e. |*ber_found| was set) + * and zero on error. */ +static int cbs_find_ber(CBS *orig_in, char *ber_found, unsigned depth) { + CBS in; + + if (depth > kMaxDepth) { + return 0; + } + + CBS_init(&in, CBS_data(orig_in), CBS_len(orig_in)); + *ber_found = 0; + + while (CBS_len(&in) > 0) { + CBS contents; + unsigned tag; + size_t header_len; + + if (!CBS_get_any_ber_asn1_element(&in, &contents, &tag, &header_len)) { + return 0; + } + if (CBS_len(&contents) == header_len && + header_len > 0 && + CBS_data(&contents)[header_len-1] == 0x80) { + *ber_found = 1; + return 1; + } + if (tag & CBS_ASN1_CONSTRUCTED) { + if (!CBS_skip(&contents, header_len) || + !cbs_find_ber(&contents, ber_found, depth + 1)) { + return 0; + } + } + } + + return 1; +} + +/* is_primitive_type returns true if |tag| likely a primitive type. Normally + * one can just test the "constructed" bit in the tag but, in BER, even + * primitive tags can have the constructed bit if they have indefinite + * length. */ +static char is_primitive_type(unsigned tag) { + return (tag & 0xc0) == 0 && + (tag & 0x1f) != (CBS_ASN1_SEQUENCE & 0x1f) && + (tag & 0x1f) != (CBS_ASN1_SET & 0x1f); +} + +/* is_eoc returns true if |header_len| and |contents|, as returned by + * |CBS_get_any_ber_asn1_element|, indicate an "end of contents" (EOC) value. */ +static char is_eoc(size_t header_len, CBS *contents) { + return header_len == 2 && CBS_len(contents) == 2 && + memcmp(CBS_data(contents), "\x00\x00", 2) == 0; +} + +/* cbs_convert_ber reads BER data from |in| and writes DER data to |out|. If + * |squash_header| is set then the top-level of elements from |in| will not + * have their headers written. This is used when concatenating the fragments of + * an indefinite length, primitive value. If |looking_for_eoc| is set then any + * EOC elements found will cause the function to return after consuming it. + * It returns one on success and zero on error. */ +static int cbs_convert_ber(CBS *in, CBB *out, char squash_header, + char looking_for_eoc, unsigned depth) { + if (depth > kMaxDepth) { + return 0; + } + + while (CBS_len(in) > 0) { + CBS contents; + unsigned tag; + size_t header_len; + CBB *out_contents, out_contents_storage; + + if (!CBS_get_any_ber_asn1_element(in, &contents, &tag, &header_len)) { + return 0; + } + out_contents = out; + + if (CBS_len(&contents) == header_len) { + if (is_eoc(header_len, &contents)) { + return looking_for_eoc; + } + + if (header_len > 0 && CBS_data(&contents)[header_len - 1] == 0x80) { + /* This is an indefinite length element. If it's a SEQUENCE or SET then + * we just need to write the out the contents as normal, but with a + * concrete length prefix. + * + * If it's a something else then the contents will be a series of BER + * elements of the same type which need to be concatenated. */ + const char context_specific = (tag & 0xc0) == 0x80; + char squash_child_headers = is_primitive_type(tag); + + /* This is a hack, but it sufficies to handle NSS's output. If we find + * an indefinite length, context-specific tag with a definite, primtive + * tag inside it, then we assume that the context-specific tag is + * implicit and the tags within are fragments of a primitive type that + * need to be concatenated. */ + if (context_specific && (tag & CBS_ASN1_CONSTRUCTED)) { + CBS in_copy, inner_contents; + unsigned inner_tag; + size_t inner_header_len; + + CBS_init(&in_copy, CBS_data(in), CBS_len(in)); + if (!CBS_get_any_ber_asn1_element(&in_copy, &inner_contents, + &inner_tag, &inner_header_len)) { + return 0; + } + if (CBS_len(&inner_contents) > inner_header_len && + is_primitive_type(inner_tag)) { + squash_child_headers = 1; + } + } + + if (!squash_header) { + unsigned out_tag = tag; + if (squash_child_headers) { + out_tag &= ~CBS_ASN1_CONSTRUCTED; + } + if (!CBB_add_asn1(out, &out_contents_storage, out_tag)) { + return 0; + } + out_contents = &out_contents_storage; + } + + if (!cbs_convert_ber(in, out_contents, + squash_child_headers, + 1 /* looking for eoc */, depth + 1)) { + return 0; + } + if (out_contents != out && !CBB_flush(out)) { + return 0; + } + continue; + } + } + + if (!squash_header) { + if (!CBB_add_asn1(out, &out_contents_storage, tag)) { + return 0; + } + out_contents = &out_contents_storage; + } + + if (!CBS_skip(&contents, header_len)) { + return 0; + } + + if (tag & CBS_ASN1_CONSTRUCTED) { + if (!cbs_convert_ber(&contents, out_contents, 0 /* don't squash header */, + 0 /* not looking for eoc */, depth + 1)) { + return 0; + } + } else { + if (!CBB_add_bytes(out_contents, CBS_data(&contents), + CBS_len(&contents))) { + return 0; + } + } + + if (out_contents != out && !CBB_flush(out)) { + return 0; + } + } + + return looking_for_eoc == 0; +} + +int CBS_asn1_ber_to_der(CBS *in, uint8_t **out, size_t *out_len) { + CBB cbb; + + /* First, do a quick walk to find any indefinite-length elements. Most of the + * time we hope that there aren't any and thus we can quickly return. */ + char conversion_needed; + if (!cbs_find_ber(in, &conversion_needed, 0)) { + return 0; + } + + if (!conversion_needed) { + *out = NULL; + *out_len = 0; + return 1; + } + + if (!CBB_init(&cbb, CBS_len(in))) { + return 0; + } + if (!cbs_convert_ber(in, &cbb, 0, 0, 0)) { + CBB_cleanup(&cbb); + return 0; + } + + return CBB_finish(&cbb, out, out_len); +} diff --git a/TMessagesProj/jni/boringssl/crypto/bytestring/cbb.c b/TMessagesProj/jni/boringssl/crypto/bytestring/cbb.c new file mode 100644 index 00000000..1da6a21e --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bytestring/cbb.c @@ -0,0 +1,393 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#include +#include + +#include + + +void CBB_zero(CBB *cbb) { + memset(cbb, 0, sizeof(CBB)); +} + +static int cbb_init(CBB *cbb, uint8_t *buf, size_t cap) { + struct cbb_buffer_st *base; + + base = OPENSSL_malloc(sizeof(struct cbb_buffer_st)); + if (base == NULL) { + return 0; + } + + base->buf = buf; + base->len = 0; + base->cap = cap; + base->can_resize = 1; + + memset(cbb, 0, sizeof(CBB)); + cbb->base = base; + cbb->is_top_level = 1; + return 1; +} + +int CBB_init(CBB *cbb, size_t initial_capacity) { + uint8_t *buf; + + buf = OPENSSL_malloc(initial_capacity); + if (initial_capacity > 0 && buf == NULL) { + return 0; + } + + if (!cbb_init(cbb, buf, initial_capacity)) { + OPENSSL_free(buf); + return 0; + } + + return 1; +} + +int CBB_init_fixed(CBB *cbb, uint8_t *buf, size_t len) { + if (!cbb_init(cbb, buf, len)) { + return 0; + } + + cbb->base->can_resize = 0; + return 1; +} + +void CBB_cleanup(CBB *cbb) { + if (cbb->base) { + if (cbb->base->can_resize) { + OPENSSL_free(cbb->base->buf); + } + OPENSSL_free(cbb->base); + } + cbb->base = NULL; +} + +static int cbb_buffer_add(struct cbb_buffer_st *base, uint8_t **out, + size_t len) { + size_t newlen; + + if (base == NULL) { + return 0; + } + + newlen = base->len + len; + if (newlen < base->len) { + /* Overflow */ + return 0; + } + + if (newlen > base->cap) { + size_t newcap = base->cap * 2; + uint8_t *newbuf; + + if (!base->can_resize) { + return 0; + } + + if (newcap < base->cap || newcap < newlen) { + newcap = newlen; + } + newbuf = OPENSSL_realloc(base->buf, newcap); + if (newbuf == NULL) { + return 0; + } + + base->buf = newbuf; + base->cap = newcap; + } + + if (out) { + *out = base->buf + base->len; + } + base->len = newlen; + return 1; +} + +static int cbb_buffer_add_u(struct cbb_buffer_st *base, uint32_t v, + size_t len_len) { + uint8_t *buf; + size_t i; + + if (len_len == 0) { + return 1; + } + if (!cbb_buffer_add(base, &buf, len_len)) { + return 0; + } + + for (i = len_len - 1; i < len_len; i--) { + buf[i] = v; + v >>= 8; + } + return 1; +} + +int CBB_finish(CBB *cbb, uint8_t **out_data, size_t *out_len) { + if (!cbb->is_top_level) { + return 0; + } + + if (!CBB_flush(cbb)) { + return 0; + } + + if (cbb->base->can_resize && (out_data == NULL || out_len == NULL)) { + /* |out_data| and |out_len| can only be NULL if the CBB is fixed. */ + return 0; + } + + if (out_data != NULL) { + *out_data = cbb->base->buf; + } + if (out_len != NULL) { + *out_len = cbb->base->len; + } + cbb->base->buf = NULL; + CBB_cleanup(cbb); + return 1; +} + +/* CBB_flush recurses and then writes out any pending length prefix. The + * current length of the underlying base is taken to be the length of the + * length-prefixed data. */ +int CBB_flush(CBB *cbb) { + size_t child_start, i, len; + + if (cbb->base == NULL) { + return 0; + } + + if (cbb->child == NULL || cbb->pending_len_len == 0) { + return 1; + } + + child_start = cbb->offset + cbb->pending_len_len; + + if (!CBB_flush(cbb->child) || + child_start < cbb->offset || + cbb->base->len < child_start) { + return 0; + } + + len = cbb->base->len - child_start; + + if (cbb->pending_is_asn1) { + /* For ASN.1 we assume that we'll only need a single byte for the length. + * If that turned out to be incorrect, we have to move the contents along + * in order to make space. */ + size_t len_len; + uint8_t initial_length_byte; + + assert (cbb->pending_len_len == 1); + + if (len > 0xfffffffe) { + /* Too large. */ + return 0; + } else if (len > 0xffffff) { + len_len = 5; + initial_length_byte = 0x80 | 4; + } else if (len > 0xffff) { + len_len = 4; + initial_length_byte = 0x80 | 3; + } else if (len > 0xff) { + len_len = 3; + initial_length_byte = 0x80 | 2; + } else if (len > 0x7f) { + len_len = 2; + initial_length_byte = 0x80 | 1; + } else { + len_len = 1; + initial_length_byte = len; + len = 0; + } + + if (len_len != 1) { + /* We need to move the contents along in order to make space. */ + size_t extra_bytes = len_len - 1; + if (!cbb_buffer_add(cbb->base, NULL, extra_bytes)) { + return 0; + } + memmove(cbb->base->buf + child_start + extra_bytes, + cbb->base->buf + child_start, len); + } + cbb->base->buf[cbb->offset++] = initial_length_byte; + cbb->pending_len_len = len_len - 1; + } + + for (i = cbb->pending_len_len - 1; i < cbb->pending_len_len; i--) { + cbb->base->buf[cbb->offset + i] = len; + len >>= 8; + } + if (len != 0) { + return 0; + } + + cbb->child->base = NULL; + cbb->child = NULL; + cbb->pending_len_len = 0; + cbb->pending_is_asn1 = 0; + cbb->offset = 0; + + return 1; +} + +size_t CBB_len(const CBB *cbb) { + assert(cbb->child == NULL); + + return cbb->base->len; +} + +static int cbb_add_length_prefixed(CBB *cbb, CBB *out_contents, + size_t len_len) { + uint8_t *prefix_bytes; + + if (!CBB_flush(cbb)) { + return 0; + } + + cbb->offset = cbb->base->len; + if (!cbb_buffer_add(cbb->base, &prefix_bytes, len_len)) { + return 0; + } + + memset(prefix_bytes, 0, len_len); + memset(out_contents, 0, sizeof(CBB)); + out_contents->base = cbb->base; + cbb->child = out_contents; + cbb->pending_len_len = len_len; + cbb->pending_is_asn1 = 0; + + return 1; +} + +int CBB_add_u8_length_prefixed(CBB *cbb, CBB *out_contents) { + return cbb_add_length_prefixed(cbb, out_contents, 1); +} + +int CBB_add_u16_length_prefixed(CBB *cbb, CBB *out_contents) { + return cbb_add_length_prefixed(cbb, out_contents, 2); +} + +int CBB_add_u24_length_prefixed(CBB *cbb, CBB *out_contents) { + return cbb_add_length_prefixed(cbb, out_contents, 3); +} + +int CBB_add_asn1(CBB *cbb, CBB *out_contents, uint8_t tag) { + if ((tag & 0x1f) == 0x1f) { + /* Long form identifier octets are not supported. */ + return 0; + } + + if (!CBB_flush(cbb) || + !CBB_add_u8(cbb, tag)) { + return 0; + } + + cbb->offset = cbb->base->len; + if (!CBB_add_u8(cbb, 0)) { + return 0; + } + + memset(out_contents, 0, sizeof(CBB)); + out_contents->base = cbb->base; + cbb->child = out_contents; + cbb->pending_len_len = 1; + cbb->pending_is_asn1 = 1; + + return 1; +} + +int CBB_add_bytes(CBB *cbb, const uint8_t *data, size_t len) { + uint8_t *dest; + + if (!CBB_flush(cbb) || + !cbb_buffer_add(cbb->base, &dest, len)) { + return 0; + } + memcpy(dest, data, len); + return 1; +} + +int CBB_add_space(CBB *cbb, uint8_t **out_data, size_t len) { + if (!CBB_flush(cbb) || + !cbb_buffer_add(cbb->base, out_data, len)) { + return 0; + } + return 1; +} + +int CBB_add_u8(CBB *cbb, uint8_t value) { + if (!CBB_flush(cbb)) { + return 0; + } + + return cbb_buffer_add_u(cbb->base, value, 1); +} + +int CBB_add_u16(CBB *cbb, uint16_t value) { + if (!CBB_flush(cbb)) { + return 0; + } + + return cbb_buffer_add_u(cbb->base, value, 2); +} + +int CBB_add_u24(CBB *cbb, uint32_t value) { + if (!CBB_flush(cbb)) { + return 0; + } + + return cbb_buffer_add_u(cbb->base, value, 3); +} + +int CBB_add_asn1_uint64(CBB *cbb, uint64_t value) { + CBB child; + size_t i; + int started = 0; + + if (!CBB_add_asn1(cbb, &child, CBS_ASN1_INTEGER)) { + return 0; + } + + for (i = 0; i < 8; i++) { + uint8_t byte = (value >> 8*(7-i)) & 0xff; + if (!started) { + if (byte == 0) { + /* Don't encode leading zeros. */ + continue; + } + /* If the high bit is set, add a padding byte to make it + * unsigned. */ + if ((byte & 0x80) && !CBB_add_u8(&child, 0)) { + return 0; + } + started = 1; + } + if (!CBB_add_u8(&child, byte)) { + return 0; + } + } + + /* 0 is encoded as a single 0, not the empty string. */ + if (!started && !CBB_add_u8(&child, 0)) { + return 0; + } + + return CBB_flush(cbb); +} diff --git a/TMessagesProj/jni/boringssl/crypto/bytestring/cbs.c b/TMessagesProj/jni/boringssl/crypto/bytestring/cbs.c new file mode 100644 index 00000000..b8caedd5 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bytestring/cbs.c @@ -0,0 +1,401 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include +#include +#include + +#include +#include + +#include "internal.h" + + +void CBS_init(CBS *cbs, const uint8_t *data, size_t len) { + cbs->data = data; + cbs->len = len; +} + +static int cbs_get(CBS *cbs, const uint8_t **p, size_t n) { + if (cbs->len < n) { + return 0; + } + + *p = cbs->data; + cbs->data += n; + cbs->len -= n; + return 1; +} + +int CBS_skip(CBS *cbs, size_t len) { + const uint8_t *dummy; + return cbs_get(cbs, &dummy, len); +} + +const uint8_t *CBS_data(const CBS *cbs) { + return cbs->data; +} + +size_t CBS_len(const CBS *cbs) { + return cbs->len; +} + +int CBS_stow(const CBS *cbs, uint8_t **out_ptr, size_t *out_len) { + OPENSSL_free(*out_ptr); + *out_ptr = NULL; + *out_len = 0; + + if (cbs->len == 0) { + return 1; + } + *out_ptr = BUF_memdup(cbs->data, cbs->len); + if (*out_ptr == NULL) { + return 0; + } + *out_len = cbs->len; + return 1; +} + +int CBS_strdup(const CBS *cbs, char **out_ptr) { + if (*out_ptr != NULL) { + OPENSSL_free(*out_ptr); + } + *out_ptr = BUF_strndup((const char*)cbs->data, cbs->len); + return (*out_ptr != NULL); +} + +int CBS_contains_zero_byte(const CBS *cbs) { + return memchr(cbs->data, 0, cbs->len) != NULL; +} + +int CBS_mem_equal(const CBS *cbs, const uint8_t *data, size_t len) { + if (len != cbs->len) { + return 0; + } + return CRYPTO_memcmp(cbs->data, data, len) == 0; +} + +static int cbs_get_u(CBS *cbs, uint32_t *out, size_t len) { + uint32_t result = 0; + size_t i; + const uint8_t *data; + + if (!cbs_get(cbs, &data, len)) { + return 0; + } + for (i = 0; i < len; i++) { + result <<= 8; + result |= data[i]; + } + *out = result; + return 1; +} + +int CBS_get_u8(CBS *cbs, uint8_t *out) { + const uint8_t *v; + if (!cbs_get(cbs, &v, 1)) { + return 0; + } + *out = *v; + return 1; +} + +int CBS_get_u16(CBS *cbs, uint16_t *out) { + uint32_t v; + if (!cbs_get_u(cbs, &v, 2)) { + return 0; + } + *out = v; + return 1; +} + +int CBS_get_u24(CBS *cbs, uint32_t *out) { + return cbs_get_u(cbs, out, 3); +} + +int CBS_get_u32(CBS *cbs, uint32_t *out) { + return cbs_get_u(cbs, out, 4); +} + +int CBS_get_bytes(CBS *cbs, CBS *out, size_t len) { + const uint8_t *v; + if (!cbs_get(cbs, &v, len)) { + return 0; + } + CBS_init(out, v, len); + return 1; +} + +static int cbs_get_length_prefixed(CBS *cbs, CBS *out, size_t len_len) { + uint32_t len; + if (!cbs_get_u(cbs, &len, len_len)) { + return 0; + } + return CBS_get_bytes(cbs, out, len); +} + +int CBS_get_u8_length_prefixed(CBS *cbs, CBS *out) { + return cbs_get_length_prefixed(cbs, out, 1); +} + +int CBS_get_u16_length_prefixed(CBS *cbs, CBS *out) { + return cbs_get_length_prefixed(cbs, out, 2); +} + +int CBS_get_u24_length_prefixed(CBS *cbs, CBS *out) { + return cbs_get_length_prefixed(cbs, out, 3); +} + +static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, + size_t *out_header_len, int ber_ok) { + uint8_t tag, length_byte; + CBS header = *cbs; + CBS throwaway; + + if (out == NULL) { + out = &throwaway; + } + + if (!CBS_get_u8(&header, &tag) || + !CBS_get_u8(&header, &length_byte)) { + return 0; + } + + if ((tag & 0x1f) == 0x1f) { + /* Long form tags are not supported. */ + return 0; + } + + if (out_tag != NULL) { + *out_tag = tag; + } + + size_t len; + if ((length_byte & 0x80) == 0) { + /* Short form length. */ + len = ((size_t) length_byte) + 2; + if (out_header_len != NULL) { + *out_header_len = 2; + } + } else { + /* Long form length. */ + const size_t num_bytes = length_byte & 0x7f; + uint32_t len32; + + if (ber_ok && (tag & CBS_ASN1_CONSTRUCTED) != 0 && num_bytes == 0) { + /* indefinite length */ + if (out_header_len != NULL) { + *out_header_len = 2; + } + return CBS_get_bytes(cbs, out, 2); + } + + if (num_bytes == 0 || num_bytes > 4) { + return 0; + } + if (!cbs_get_u(&header, &len32, num_bytes)) { + return 0; + } + if (len32 < 128) { + /* Length should have used short-form encoding. */ + return 0; + } + if ((len32 >> ((num_bytes-1)*8)) == 0) { + /* Length should have been at least one byte shorter. */ + return 0; + } + len = len32; + if (len + 2 + num_bytes < len) { + /* Overflow. */ + return 0; + } + len += 2 + num_bytes; + if (out_header_len != NULL) { + *out_header_len = 2 + num_bytes; + } + } + + return CBS_get_bytes(cbs, out, len); +} + +int CBS_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, + size_t *out_header_len) { + return cbs_get_any_asn1_element(cbs, out, out_tag, out_header_len, + 0 /* DER only */); +} + +int CBS_get_any_ber_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, + size_t *out_header_len) { + return cbs_get_any_asn1_element(cbs, out, out_tag, out_header_len, + 1 /* BER allowed */); +} + +static int cbs_get_asn1(CBS *cbs, CBS *out, unsigned tag_value, + int skip_header) { + size_t header_len; + unsigned tag; + CBS throwaway; + + if (out == NULL) { + out = &throwaway; + } + + if (!CBS_get_any_asn1_element(cbs, out, &tag, &header_len) || + tag != tag_value) { + return 0; + } + + if (skip_header && !CBS_skip(out, header_len)) { + assert(0); + return 0; + } + + return 1; +} + +int CBS_get_asn1(CBS *cbs, CBS *out, unsigned tag_value) { + return cbs_get_asn1(cbs, out, tag_value, 1 /* skip header */); +} + +int CBS_get_asn1_element(CBS *cbs, CBS *out, unsigned tag_value) { + return cbs_get_asn1(cbs, out, tag_value, 0 /* include header */); +} + +int CBS_peek_asn1_tag(const CBS *cbs, unsigned tag_value) { + if (CBS_len(cbs) < 1) { + return 0; + } + return CBS_data(cbs)[0] == tag_value; +} + +int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out) { + CBS bytes; + const uint8_t *data; + size_t i, len; + + if (!CBS_get_asn1(cbs, &bytes, CBS_ASN1_INTEGER)) { + return 0; + } + + *out = 0; + data = CBS_data(&bytes); + len = CBS_len(&bytes); + + if (len == 0) { + /* An INTEGER is encoded with at least one octet. */ + return 0; + } + + if ((data[0] & 0x80) != 0) { + /* Negative number. */ + return 0; + } + + if (data[0] == 0 && len > 1 && (data[1] & 0x80) == 0) { + /* Extra leading zeros. */ + return 0; + } + + for (i = 0; i < len; i++) { + if ((*out >> 56) != 0) { + /* Too large to represent as a uint64_t. */ + return 0; + } + *out <<= 8; + *out |= data[i]; + } + + return 1; +} + +int CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present, unsigned tag) { + if (CBS_peek_asn1_tag(cbs, tag)) { + if (!CBS_get_asn1(cbs, out, tag)) { + return 0; + } + *out_present = 1; + } else { + *out_present = 0; + } + return 1; +} + +int CBS_get_optional_asn1_octet_string(CBS *cbs, CBS *out, int *out_present, + unsigned tag) { + CBS child; + int present; + if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) { + return 0; + } + if (present) { + if (!CBS_get_asn1(&child, out, CBS_ASN1_OCTETSTRING) || + CBS_len(&child) != 0) { + return 0; + } + } else { + CBS_init(out, NULL, 0); + } + if (out_present) { + *out_present = present; + } + return 1; +} + +int CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out, unsigned tag, + uint64_t default_value) { + CBS child; + int present; + if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) { + return 0; + } + if (present) { + if (!CBS_get_asn1_uint64(&child, out) || + CBS_len(&child) != 0) { + return 0; + } + } else { + *out = default_value; + } + return 1; +} + +int CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned tag, + int default_value) { + CBS child, child2; + int present; + if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) { + return 0; + } + if (present) { + uint8_t boolean; + + if (!CBS_get_asn1(&child, &child2, CBS_ASN1_BOOLEAN) || + CBS_len(&child2) != 1 || + CBS_len(&child) != 0) { + return 0; + } + + boolean = CBS_data(&child2)[0]; + if (boolean == 0) { + *out = 0; + } else if (boolean == 0xff) { + *out = 1; + } else { + return 0; + } + } else { + *out = default_value; + } + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bytestring/internal.h b/TMessagesProj/jni/boringssl/crypto/bytestring/internal.h new file mode 100644 index 00000000..b4ea7e51 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bytestring/internal.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_BYTESTRING_INTERNAL_H +#define OPENSSL_HEADER_BYTESTRING_INTERNAL_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* CBS_asn1_ber_to_der reads an ASN.1 structure from |in|. If it finds + * indefinite-length elements then it attempts to convert the BER data to DER + * and sets |*out| and |*out_length| to describe a malloced buffer containing + * the DER data. Additionally, |*in| will be advanced over the ASN.1 data. + * + * If it doesn't find any indefinite-length elements then it sets |*out| to + * NULL and |*in| is unmodified. + * + * A sufficiently complex ASN.1 structure will break this function because it's + * not possible to generically convert BER to DER without knowledge of the + * structure itself. However, this sufficies to handle the PKCS#7 and #12 output + * from NSS. + * + * It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int CBS_asn1_ber_to_der(CBS *in, uint8_t **out, size_t *out_len); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_BYTESTRING_INTERNAL_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/chacha/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/chacha/CMakeLists.txt new file mode 100644 index 00000000..6c3f87ee --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/chacha/CMakeLists.txt @@ -0,0 +1,20 @@ +include_directories(. .. ../../include) + +if (${ARCH} STREQUAL "arm") + set( + CHACHA_ARCH_SOURCES + + chacha_vec_arm.S + ) +endif() + +add_library( + chacha + + OBJECT + + chacha_generic.c + chacha_vec.c + + ${CHACHA_ARCH_SOURCES} +) diff --git a/TMessagesProj/jni/boringssl/crypto/chacha/chacha_generic.c b/TMessagesProj/jni/boringssl/crypto/chacha/chacha_generic.c new file mode 100644 index 00000000..31cf4f02 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/chacha/chacha_generic.c @@ -0,0 +1,143 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* Adapted from the public domain, estream code by D. Bernstein. */ + +#include + +#include + +#include + + +#if defined(OPENSSL_WINDOWS) || (!defined(OPENSSL_X86_64) && !defined(OPENSSL_X86)) || !defined(__SSE2__) + +/* sigma contains the ChaCha constants, which happen to be an ASCII string. */ +static const uint8_t sigma[16] = { 'e', 'x', 'p', 'a', 'n', 'd', ' ', '3', + '2', '-', 'b', 'y', 't', 'e', ' ', 'k' }; + +#define ROTATE(v, n) (((v) << (n)) | ((v) >> (32 - (n)))) +#define XOR(v, w) ((v) ^ (w)) +#define PLUS(x, y) ((x) + (y)) +#define PLUSONE(v) (PLUS((v), 1)) + +#define U32TO8_LITTLE(p, v) \ + { \ + (p)[0] = (v >> 0) & 0xff; \ + (p)[1] = (v >> 8) & 0xff; \ + (p)[2] = (v >> 16) & 0xff; \ + (p)[3] = (v >> 24) & 0xff; \ + } + +#define U8TO32_LITTLE(p) \ + (((uint32_t)((p)[0])) | ((uint32_t)((p)[1]) << 8) | \ + ((uint32_t)((p)[2]) << 16) | ((uint32_t)((p)[3]) << 24)) + +/* QUARTERROUND updates a, b, c, d with a ChaCha "quarter" round. */ +#define QUARTERROUND(a,b,c,d) \ + x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]),16); \ + x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]),12); \ + x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]), 8); \ + x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]), 7); + +#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM) +/* Defined in chacha_vec.c */ +void CRYPTO_chacha_20_neon(uint8_t *out, const uint8_t *in, size_t in_len, + const uint8_t key[32], const uint8_t nonce[8], + size_t counter); +#endif + +/* chacha_core performs 20 rounds of ChaCha on the input words in + * |input| and writes the 64 output bytes to |output|. */ +static void chacha_core(uint8_t output[64], const uint32_t input[16]) { + uint32_t x[16]; + int i; + + memcpy(x, input, sizeof(uint32_t) * 16); + for (i = 20; i > 0; i -= 2) { + QUARTERROUND(0, 4, 8, 12) + QUARTERROUND(1, 5, 9, 13) + QUARTERROUND(2, 6, 10, 14) + QUARTERROUND(3, 7, 11, 15) + QUARTERROUND(0, 5, 10, 15) + QUARTERROUND(1, 6, 11, 12) + QUARTERROUND(2, 7, 8, 13) + QUARTERROUND(3, 4, 9, 14) + } + + for (i = 0; i < 16; ++i) { + x[i] = PLUS(x[i], input[i]); + } + for (i = 0; i < 16; ++i) { + U32TO8_LITTLE(output + 4 * i, x[i]); + } +} + +void CRYPTO_chacha_20(uint8_t *out, const uint8_t *in, size_t in_len, + const uint8_t key[32], const uint8_t nonce[8], + size_t counter) { + uint32_t input[16]; + uint8_t buf[64]; + size_t todo, i; + +#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM) + if (CRYPTO_is_NEON_capable()) { + CRYPTO_chacha_20_neon(out, in, in_len, key, nonce, counter); + return; + } +#endif + + input[0] = U8TO32_LITTLE(sigma + 0); + input[1] = U8TO32_LITTLE(sigma + 4); + input[2] = U8TO32_LITTLE(sigma + 8); + input[3] = U8TO32_LITTLE(sigma + 12); + + input[4] = U8TO32_LITTLE(key + 0); + input[5] = U8TO32_LITTLE(key + 4); + input[6] = U8TO32_LITTLE(key + 8); + input[7] = U8TO32_LITTLE(key + 12); + + input[8] = U8TO32_LITTLE(key + 16); + input[9] = U8TO32_LITTLE(key + 20); + input[10] = U8TO32_LITTLE(key + 24); + input[11] = U8TO32_LITTLE(key + 28); + + input[12] = counter; + input[13] = ((uint64_t)counter) >> 32; + input[14] = U8TO32_LITTLE(nonce + 0); + input[15] = U8TO32_LITTLE(nonce + 4); + + while (in_len > 0) { + todo = sizeof(buf); + if (in_len < todo) { + todo = in_len; + } + + chacha_core(buf, input); + for (i = 0; i < todo; i++) { + out[i] = in[i] ^ buf[i]; + } + + out += todo; + in += todo; + in_len -= todo; + + input[12]++; + if (input[12] == 0) { + input[13]++; + } + } +} + +#endif /* OPENSSL_WINDOWS || !OPENSSL_X86_64 && !OPENSSL_X86 || !__SSE2__ */ diff --git a/TMessagesProj/jni/boringssl/crypto/chacha/chacha_vec.c b/TMessagesProj/jni/boringssl/crypto/chacha/chacha_vec.c new file mode 100644 index 00000000..14b54a70 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/chacha/chacha_vec.c @@ -0,0 +1,327 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* ==================================================================== + * + * When updating this file, also update chacha_vec_arm.S + * + * ==================================================================== */ + + +/* This implementation is by Ted Krovetz and was submitted to SUPERCOP and + * marked as public domain. It was been altered to allow for non-aligned inputs + * and to allow the block counter to be passed in specifically. */ + +#include + +#if defined(ASM_GEN) || \ + !defined(OPENSSL_WINDOWS) && \ + (defined(OPENSSL_X86_64) || defined(OPENSSL_X86)) && defined(__SSE2__) + +#define CHACHA_RNDS 20 /* 8 (high speed), 20 (conservative), 12 (middle) */ + +/* Architecture-neutral way to specify 16-byte vector of ints */ +typedef unsigned vec __attribute__((vector_size(16))); + +/* This implementation is designed for Neon, SSE and AltiVec machines. The + * following specify how to do certain vector operations efficiently on + * each architecture, using intrinsics. + * This implementation supports parallel processing of multiple blocks, + * including potentially using general-purpose registers. */ +#if __ARM_NEON__ +#include +#include +#define GPR_TOO 1 +#define VBPI 2 +#define ONE (vec) vsetq_lane_u32(1, vdupq_n_u32(0), 0) +#define LOAD_ALIGNED(m) (vec)(*((vec *)(m))) +#define LOAD(m) ({ \ + memcpy(alignment_buffer, m, 16); \ + LOAD_ALIGNED(alignment_buffer); \ + }) +#define STORE(m, r) ({ \ + (*((vec *)(alignment_buffer))) = (r); \ + memcpy(m, alignment_buffer, 16); \ + }) +#define ROTV1(x) (vec) vextq_u32((uint32x4_t)x, (uint32x4_t)x, 1) +#define ROTV2(x) (vec) vextq_u32((uint32x4_t)x, (uint32x4_t)x, 2) +#define ROTV3(x) (vec) vextq_u32((uint32x4_t)x, (uint32x4_t)x, 3) +#define ROTW16(x) (vec) vrev32q_u16((uint16x8_t)x) +#if __clang__ +#define ROTW7(x) (x << ((vec) {7, 7, 7, 7})) ^ (x >> ((vec) {25, 25, 25, 25})) +#define ROTW8(x) (x << ((vec) {8, 8, 8, 8})) ^ (x >> ((vec) {24, 24, 24, 24})) +#define ROTW12(x) \ + (x << ((vec) {12, 12, 12, 12})) ^ (x >> ((vec) {20, 20, 20, 20})) +#else +#define ROTW7(x) \ + (vec) vsriq_n_u32(vshlq_n_u32((uint32x4_t)x, 7), (uint32x4_t)x, 25) +#define ROTW8(x) \ + (vec) vsriq_n_u32(vshlq_n_u32((uint32x4_t)x, 8), (uint32x4_t)x, 24) +#define ROTW12(x) \ + (vec) vsriq_n_u32(vshlq_n_u32((uint32x4_t)x, 12), (uint32x4_t)x, 20) +#endif +#elif __SSE2__ +#include +#define GPR_TOO 0 +#if __clang__ +#define VBPI 4 +#else +#define VBPI 3 +#endif +#define ONE (vec) _mm_set_epi32(0, 0, 0, 1) +#define LOAD(m) (vec) _mm_loadu_si128((__m128i *)(m)) +#define LOAD_ALIGNED(m) (vec) _mm_load_si128((__m128i *)(m)) +#define STORE(m, r) _mm_storeu_si128((__m128i *)(m), (__m128i)(r)) +#define ROTV1(x) (vec) _mm_shuffle_epi32((__m128i)x, _MM_SHUFFLE(0, 3, 2, 1)) +#define ROTV2(x) (vec) _mm_shuffle_epi32((__m128i)x, _MM_SHUFFLE(1, 0, 3, 2)) +#define ROTV3(x) (vec) _mm_shuffle_epi32((__m128i)x, _MM_SHUFFLE(2, 1, 0, 3)) +#define ROTW7(x) \ + (vec)(_mm_slli_epi32((__m128i)x, 7) ^ _mm_srli_epi32((__m128i)x, 25)) +#define ROTW12(x) \ + (vec)(_mm_slli_epi32((__m128i)x, 12) ^ _mm_srli_epi32((__m128i)x, 20)) +#if __SSSE3__ +#include +#define ROTW8(x) \ + (vec) _mm_shuffle_epi8((__m128i)x, _mm_set_epi8(14, 13, 12, 15, 10, 9, 8, \ + 11, 6, 5, 4, 7, 2, 1, 0, 3)) +#define ROTW16(x) \ + (vec) _mm_shuffle_epi8((__m128i)x, _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, \ + 10, 5, 4, 7, 6, 1, 0, 3, 2)) +#else +#define ROTW8(x) \ + (vec)(_mm_slli_epi32((__m128i)x, 8) ^ _mm_srli_epi32((__m128i)x, 24)) +#define ROTW16(x) \ + (vec)(_mm_slli_epi32((__m128i)x, 16) ^ _mm_srli_epi32((__m128i)x, 16)) +#endif +#else +#error-- Implementation supports only machines with neon or SSE2 +#endif + +#ifndef REVV_BE +#define REVV_BE(x) (x) +#endif + +#ifndef REVW_BE +#define REVW_BE(x) (x) +#endif + +#define BPI (VBPI + GPR_TOO) /* Blocks computed per loop iteration */ + +#define DQROUND_VECTORS(a,b,c,d) \ + a += b; d ^= a; d = ROTW16(d); \ + c += d; b ^= c; b = ROTW12(b); \ + a += b; d ^= a; d = ROTW8(d); \ + c += d; b ^= c; b = ROTW7(b); \ + b = ROTV1(b); c = ROTV2(c); d = ROTV3(d); \ + a += b; d ^= a; d = ROTW16(d); \ + c += d; b ^= c; b = ROTW12(b); \ + a += b; d ^= a; d = ROTW8(d); \ + c += d; b ^= c; b = ROTW7(b); \ + b = ROTV3(b); c = ROTV2(c); d = ROTV1(d); + +#define QROUND_WORDS(a,b,c,d) \ + a = a+b; d ^= a; d = d<<16 | d>>16; \ + c = c+d; b ^= c; b = b<<12 | b>>20; \ + a = a+b; d ^= a; d = d<< 8 | d>>24; \ + c = c+d; b ^= c; b = b<< 7 | b>>25; + +#define WRITE_XOR(in, op, d, v0, v1, v2, v3) \ + STORE(op + d + 0, LOAD(in + d + 0) ^ REVV_BE(v0)); \ + STORE(op + d + 4, LOAD(in + d + 4) ^ REVV_BE(v1)); \ + STORE(op + d + 8, LOAD(in + d + 8) ^ REVV_BE(v2)); \ + STORE(op + d +12, LOAD(in + d +12) ^ REVV_BE(v3)); + +#if __ARM_NEON__ +/* For ARM, we can't depend on NEON support, so this function is compiled with + * a different name, along with the generic code, and can be enabled at + * run-time. */ +void CRYPTO_chacha_20_neon( +#else +void CRYPTO_chacha_20( +#endif + uint8_t *out, + const uint8_t *in, + size_t inlen, + const uint8_t key[32], + const uint8_t nonce[8], + size_t counter) + { + unsigned iters, i, *op=(unsigned *)out, *ip=(unsigned *)in, *kp; +#if defined(__ARM_NEON__) + uint32_t np[2]; + uint8_t alignment_buffer[16] __attribute__((aligned(16))); +#endif + vec s0, s1, s2, s3; + __attribute__ ((aligned (16))) unsigned chacha_const[] = + {0x61707865,0x3320646E,0x79622D32,0x6B206574}; + kp = (unsigned *)key; +#if defined(__ARM_NEON__) + memcpy(np, nonce, 8); +#endif + s0 = LOAD_ALIGNED(chacha_const); + s1 = LOAD(&((vec*)kp)[0]); + s2 = LOAD(&((vec*)kp)[1]); + s3 = (vec){ + counter & 0xffffffff, +#if __ARM_NEON__ || defined(OPENSSL_X86) + 0, /* can't right-shift 32 bits on a 32-bit system. */ +#else + counter >> 32, +#endif + ((uint32_t*)nonce)[0], + ((uint32_t*)nonce)[1] + }; + + for (iters = 0; iters < inlen/(BPI*64); iters++) + { +#if GPR_TOO + register unsigned x0, x1, x2, x3, x4, x5, x6, x7, x8, + x9, x10, x11, x12, x13, x14, x15; +#endif +#if VBPI > 2 + vec v8,v9,v10,v11; +#endif +#if VBPI > 3 + vec v12,v13,v14,v15; +#endif + + vec v0,v1,v2,v3,v4,v5,v6,v7; + v4 = v0 = s0; v5 = v1 = s1; v6 = v2 = s2; v3 = s3; + v7 = v3 + ONE; +#if VBPI > 2 + v8 = v4; v9 = v5; v10 = v6; + v11 = v7 + ONE; +#endif +#if VBPI > 3 + v12 = v8; v13 = v9; v14 = v10; + v15 = v11 + ONE; +#endif +#if GPR_TOO + x0 = chacha_const[0]; x1 = chacha_const[1]; + x2 = chacha_const[2]; x3 = chacha_const[3]; + x4 = kp[0]; x5 = kp[1]; x6 = kp[2]; x7 = kp[3]; + x8 = kp[4]; x9 = kp[5]; x10 = kp[6]; x11 = kp[7]; + x12 = counter+BPI*iters+(BPI-1); x13 = 0; + x14 = np[0]; x15 = np[1]; +#endif + for (i = CHACHA_RNDS/2; i; i--) + { + DQROUND_VECTORS(v0,v1,v2,v3) + DQROUND_VECTORS(v4,v5,v6,v7) +#if VBPI > 2 + DQROUND_VECTORS(v8,v9,v10,v11) +#endif +#if VBPI > 3 + DQROUND_VECTORS(v12,v13,v14,v15) +#endif +#if GPR_TOO + QROUND_WORDS( x0, x4, x8,x12) + QROUND_WORDS( x1, x5, x9,x13) + QROUND_WORDS( x2, x6,x10,x14) + QROUND_WORDS( x3, x7,x11,x15) + QROUND_WORDS( x0, x5,x10,x15) + QROUND_WORDS( x1, x6,x11,x12) + QROUND_WORDS( x2, x7, x8,x13) + QROUND_WORDS( x3, x4, x9,x14) +#endif + } + + WRITE_XOR(ip, op, 0, v0+s0, v1+s1, v2+s2, v3+s3) + s3 += ONE; + WRITE_XOR(ip, op, 16, v4+s0, v5+s1, v6+s2, v7+s3) + s3 += ONE; +#if VBPI > 2 + WRITE_XOR(ip, op, 32, v8+s0, v9+s1, v10+s2, v11+s3) + s3 += ONE; +#endif +#if VBPI > 3 + WRITE_XOR(ip, op, 48, v12+s0, v13+s1, v14+s2, v15+s3) + s3 += ONE; +#endif + ip += VBPI*16; + op += VBPI*16; +#if GPR_TOO + op[0] = REVW_BE(REVW_BE(ip[0]) ^ (x0 + chacha_const[0])); + op[1] = REVW_BE(REVW_BE(ip[1]) ^ (x1 + chacha_const[1])); + op[2] = REVW_BE(REVW_BE(ip[2]) ^ (x2 + chacha_const[2])); + op[3] = REVW_BE(REVW_BE(ip[3]) ^ (x3 + chacha_const[3])); + op[4] = REVW_BE(REVW_BE(ip[4]) ^ (x4 + kp[0])); + op[5] = REVW_BE(REVW_BE(ip[5]) ^ (x5 + kp[1])); + op[6] = REVW_BE(REVW_BE(ip[6]) ^ (x6 + kp[2])); + op[7] = REVW_BE(REVW_BE(ip[7]) ^ (x7 + kp[3])); + op[8] = REVW_BE(REVW_BE(ip[8]) ^ (x8 + kp[4])); + op[9] = REVW_BE(REVW_BE(ip[9]) ^ (x9 + kp[5])); + op[10] = REVW_BE(REVW_BE(ip[10]) ^ (x10 + kp[6])); + op[11] = REVW_BE(REVW_BE(ip[11]) ^ (x11 + kp[7])); + op[12] = REVW_BE(REVW_BE(ip[12]) ^ (x12 + counter+BPI*iters+(BPI-1))); + op[13] = REVW_BE(REVW_BE(ip[13]) ^ (x13)); + op[14] = REVW_BE(REVW_BE(ip[14]) ^ (x14 + np[0])); + op[15] = REVW_BE(REVW_BE(ip[15]) ^ (x15 + np[1])); + s3 += ONE; + ip += 16; + op += 16; +#endif + } + + for (iters = inlen%(BPI*64)/64; iters != 0; iters--) + { + vec v0 = s0, v1 = s1, v2 = s2, v3 = s3; + for (i = CHACHA_RNDS/2; i; i--) + { + DQROUND_VECTORS(v0,v1,v2,v3); + } + WRITE_XOR(ip, op, 0, v0+s0, v1+s1, v2+s2, v3+s3) + s3 += ONE; + ip += 16; + op += 16; + } + + inlen = inlen % 64; + if (inlen) + { + __attribute__ ((aligned (16))) vec buf[4]; + vec v0,v1,v2,v3; + v0 = s0; v1 = s1; v2 = s2; v3 = s3; + for (i = CHACHA_RNDS/2; i; i--) + { + DQROUND_VECTORS(v0,v1,v2,v3); + } + + if (inlen >= 16) + { + STORE(op + 0, LOAD(ip + 0) ^ REVV_BE(v0 + s0)); + if (inlen >= 32) + { + STORE(op + 4, LOAD(ip + 4) ^ REVV_BE(v1 + s1)); + if (inlen >= 48) + { + STORE(op + 8, LOAD(ip + 8) ^ + REVV_BE(v2 + s2)); + buf[3] = REVV_BE(v3 + s3); + } + else + buf[2] = REVV_BE(v2 + s2); + } + else + buf[1] = REVV_BE(v1 + s1); + } + else + buf[0] = REVV_BE(v0 + s0); + + for (i=inlen & ~15; i 1 { + compiler = os.Args[1] + } + + args := []string{ + "-O3", + "-mcpu=cortex-a8", + "-mfpu=neon", + "-fpic", + "-DASM_GEN", + "-I", "../../include", + "-S", "chacha_vec.c", + "-o", "-", + } + + output, err := os.OpenFile("chacha_vec_arm.S", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644) + if err != nil { + panic(err) + } + defer output.Close() + + output.WriteString(preamble) + output.WriteString(compiler) + output.WriteString(" ") + output.WriteString(strings.Join(args, " ")) + output.WriteString("\n\n#if !defined(OPENSSL_NO_ASM)\n") + output.WriteString("#if defined(__arm__) || defined(__aarch64__)\n\n") + + cmd := exec.Command(compiler, args...) + cmd.Stderr = os.Stderr + asm, err := cmd.StdoutPipe() + if err != nil { + panic(err) + } + if err := cmd.Start(); err != nil { + panic(err) + } + + attr28 := []byte(".eabi_attribute 28,") + globalDirective := []byte(".global\t") + newLine := []byte("\n") + attr28Handled := false + + scanner := bufio.NewScanner(asm) + for scanner.Scan() { + line := scanner.Bytes() + + if bytes.Contains(line, attr28) { + output.WriteString(attr28Block) + attr28Handled = true + continue + } + + output.Write(line) + output.Write(newLine) + + if i := bytes.Index(line, globalDirective); i >= 0 { + output.Write(line[:i]) + output.WriteString(".hidden\t") + output.Write(line[i+len(globalDirective):]) + output.Write(newLine) + } + } + + if err := scanner.Err(); err != nil { + panic(err) + } + + if !attr28Handled { + panic("EABI attribute 28 not seen in processing") + } + + if err := cmd.Wait(); err != nil { + panic(err) + } + + output.WriteString(trailer) +} + +const preamble = `# Copyright (c) 2014, Google Inc. +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +# This file contains a pre-compiled version of chacha_vec.c for ARM. This is +# needed to support switching on NEON code at runtime. If the whole of OpenSSL +# were to be compiled with the needed flags to build chacha_vec.c, then it +# wouldn't be possible to run on non-NEON systems. +# +# This file was generated by chacha_vec_arm_generate.go using the following +# compiler command: +# +# ` + +const attr28Block = ` +# EABI attribute 28 sets whether VFP register arguments were used to build this +# file. If object files are inconsistent on this point, the linker will refuse +# to link them. Thus we report whatever the compiler expects since we don't use +# VFP arguments. + +#if defined(__ARM_PCS_VFP) + .eabi_attribute 28, 1 +#else + .eabi_attribute 28, 0 +#endif + +` + +const trailer = ` +#endif /* __arm__ || __aarch64__ */ +#endif /* !OPENSSL_NO_ASM */ +` diff --git a/TMessagesProj/jni/boringssl/crypto/cipher/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/cipher/CMakeLists.txt new file mode 100644 index 00000000..f3c8bf15 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cipher/CMakeLists.txt @@ -0,0 +1,22 @@ +include_directories(. .. ../../include) + +add_library( + cipher + + OBJECT + + cipher.c + derive_key.c + aead.c + + e_null.c + e_rc2.c + e_rc4.c + e_des.c + e_aes.c + e_chacha20poly1305.c + + tls_cbc.c + e_tls.c + e_ssl3.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/cipher/aead.c b/TMessagesProj/jni/boringssl/crypto/cipher/aead.c new file mode 100644 index 00000000..1b2f9212 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cipher/aead.c @@ -0,0 +1,154 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#include + +#include +#include + +#include "internal.h" + + +size_t EVP_AEAD_key_length(const EVP_AEAD *aead) { return aead->key_len; } + +size_t EVP_AEAD_nonce_length(const EVP_AEAD *aead) { return aead->nonce_len; } + +size_t EVP_AEAD_max_overhead(const EVP_AEAD *aead) { return aead->overhead; } + +size_t EVP_AEAD_max_tag_len(const EVP_AEAD *aead) { return aead->max_tag_len; } + +int EVP_AEAD_CTX_init(EVP_AEAD_CTX *ctx, const EVP_AEAD *aead, + const uint8_t *key, size_t key_len, size_t tag_len, + ENGINE *impl) { + if (!aead->init) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_NO_DIRECTION_SET); + ctx->aead = NULL; + return 0; + } + return EVP_AEAD_CTX_init_with_direction(ctx, aead, key, key_len, tag_len, + evp_aead_open); +} + +int EVP_AEAD_CTX_init_with_direction(EVP_AEAD_CTX *ctx, const EVP_AEAD *aead, + const uint8_t *key, size_t key_len, + size_t tag_len, + enum evp_aead_direction_t dir) { + if (key_len != aead->key_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_KEY_SIZE); + ctx->aead = NULL; + return 0; + } + + ctx->aead = aead; + + int ok; + if (aead->init) { + ok = aead->init(ctx, key, key_len, tag_len); + } else { + ok = aead->init_with_direction(ctx, key, key_len, tag_len, dir); + } + + if (!ok) { + ctx->aead = NULL; + } + + return ok; +} + +void EVP_AEAD_CTX_cleanup(EVP_AEAD_CTX *ctx) { + if (ctx->aead == NULL) { + return; + } + ctx->aead->cleanup(ctx); + ctx->aead = NULL; +} + +/* check_alias returns 0 if |out| points within the buffer determined by |in| + * and |in_len| and 1 otherwise. + * + * When processing, there's only an issue if |out| points within in[:in_len] + * and isn't equal to |in|. If that's the case then writing the output will + * stomp input that hasn't been read yet. + * + * This function checks for that case. */ +static int check_alias(const uint8_t *in, size_t in_len, const uint8_t *out) { + if (out <= in) { + return 1; + } else if (in + in_len <= out) { + return 1; + } + return 0; +} + +int EVP_AEAD_CTX_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, + size_t max_out_len, const uint8_t *nonce, + size_t nonce_len, const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + size_t possible_out_len = in_len + ctx->aead->overhead; + + if (possible_out_len < in_len /* overflow */) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + goto error; + } + + if (!check_alias(in, in_len, out)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT); + goto error; + } + + if (ctx->aead->seal(ctx, out, out_len, max_out_len, nonce, nonce_len, in, + in_len, ad, ad_len)) { + return 1; + } + +error: + /* In the event of an error, clear the output buffer so that a caller + * that doesn't check the return value doesn't send raw data. */ + memset(out, 0, max_out_len); + *out_len = 0; + return 0; +} + +int EVP_AEAD_CTX_open(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, + size_t max_out_len, const uint8_t *nonce, + size_t nonce_len, const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + if (!check_alias(in, in_len, out)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT); + goto error; + } + + if (ctx->aead->open(ctx, out, out_len, max_out_len, nonce, nonce_len, in, + in_len, ad, ad_len)) { + return 1; + } + +error: + /* In the event of an error, clear the output buffer so that a caller + * that doesn't check the return value doesn't try and process bad + * data. */ + memset(out, 0, max_out_len); + *out_len = 0; + return 0; +} + +int EVP_AEAD_CTX_get_rc4_state(const EVP_AEAD_CTX *ctx, const RC4_KEY **out_key) { + if (ctx->aead->get_rc4_state == NULL) { + return 0; + } + + return ctx->aead->get_rc4_state(ctx, out_key); +} diff --git a/TMessagesProj/jni/boringssl/crypto/cipher/cipher.c b/TMessagesProj/jni/boringssl/crypto/cipher/cipher.c new file mode 100644 index 00000000..44018675 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cipher/cipher.c @@ -0,0 +1,652 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include +#include + +#include "internal.h" + + +const EVP_CIPHER *EVP_get_cipherbynid(int nid) { + switch (nid) { + case NID_rc2_cbc: + return EVP_rc2_cbc(); + case NID_rc2_40_cbc: + return EVP_rc2_40_cbc(); + case NID_des_ede3_cbc: + return EVP_des_ede3_cbc(); + case NID_des_ede_cbc: + return EVP_des_cbc(); + case NID_aes_128_cbc: + return EVP_aes_128_cbc(); + case NID_aes_192_cbc: + return EVP_aes_192_cbc(); + case NID_aes_256_cbc: + return EVP_aes_256_cbc(); + default: + return NULL; + } +} + +void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *ctx) { + memset(ctx, 0, sizeof(EVP_CIPHER_CTX)); +} + +EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void) { + EVP_CIPHER_CTX *ctx = OPENSSL_malloc(sizeof(EVP_CIPHER_CTX)); + if (ctx) { + EVP_CIPHER_CTX_init(ctx); + } + return ctx; +} + +int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *c) { + if (c->cipher != NULL) { + if (c->cipher->cleanup) { + c->cipher->cleanup(c); + } + OPENSSL_cleanse(c->cipher_data, c->cipher->ctx_size); + } + OPENSSL_free(c->cipher_data); + + memset(c, 0, sizeof(EVP_CIPHER_CTX)); + return 1; +} + +void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx) { + if (ctx) { + EVP_CIPHER_CTX_cleanup(ctx); + OPENSSL_free(ctx); + } +} + +int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, const EVP_CIPHER_CTX *in) { + if (in == NULL || in->cipher == NULL) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INPUT_NOT_INITIALIZED); + return 0; + } + + EVP_CIPHER_CTX_cleanup(out); + memcpy(out, in, sizeof(EVP_CIPHER_CTX)); + + if (in->cipher_data && in->cipher->ctx_size) { + out->cipher_data = OPENSSL_malloc(in->cipher->ctx_size); + if (!out->cipher_data) { + OPENSSL_PUT_ERROR(CIPHER, ERR_R_MALLOC_FAILURE); + return 0; + } + memcpy(out->cipher_data, in->cipher_data, in->cipher->ctx_size); + } + + if (in->cipher->flags & EVP_CIPH_CUSTOM_COPY) { + return in->cipher->ctrl((EVP_CIPHER_CTX *)in, EVP_CTRL_COPY, 0, out); + } + + return 1; +} + +int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, + ENGINE *engine, const uint8_t *key, const uint8_t *iv, + int enc) { + if (enc == -1) { + enc = ctx->encrypt; + } else { + if (enc) { + enc = 1; + } + ctx->encrypt = enc; + } + + if (cipher) { + /* Ensure a context left from last time is cleared (the previous check + * attempted to avoid this if the same ENGINE and EVP_CIPHER could be + * used). */ + if (ctx->cipher) { + EVP_CIPHER_CTX_cleanup(ctx); + /* Restore encrypt and flags */ + ctx->encrypt = enc; + } + + ctx->cipher = cipher; + if (ctx->cipher->ctx_size) { + ctx->cipher_data = OPENSSL_malloc(ctx->cipher->ctx_size); + if (!ctx->cipher_data) { + ctx->cipher = NULL; + OPENSSL_PUT_ERROR(CIPHER, ERR_R_MALLOC_FAILURE); + return 0; + } + } else { + ctx->cipher_data = NULL; + } + + ctx->key_len = cipher->key_len; + ctx->flags = 0; + + if (ctx->cipher->flags & EVP_CIPH_CTRL_INIT) { + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_INIT, 0, NULL)) { + ctx->cipher = NULL; + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INITIALIZATION_ERROR); + return 0; + } + } + } else if (!ctx->cipher) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_NO_CIPHER_SET); + return 0; + } + + /* we assume block size is a power of 2 in *cryptUpdate */ + assert(ctx->cipher->block_size == 1 || ctx->cipher->block_size == 8 || + ctx->cipher->block_size == 16); + + if (!(EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_CUSTOM_IV)) { + switch (EVP_CIPHER_CTX_mode(ctx)) { + case EVP_CIPH_STREAM_CIPHER: + case EVP_CIPH_ECB_MODE: + break; + + case EVP_CIPH_CFB_MODE: + ctx->num = 0; + /* fall-through */ + + case EVP_CIPH_CBC_MODE: + assert(EVP_CIPHER_CTX_iv_length(ctx) <= sizeof(ctx->iv)); + if (iv) { + memcpy(ctx->oiv, iv, EVP_CIPHER_CTX_iv_length(ctx)); + } + memcpy(ctx->iv, ctx->oiv, EVP_CIPHER_CTX_iv_length(ctx)); + break; + + case EVP_CIPH_CTR_MODE: + case EVP_CIPH_OFB_MODE: + ctx->num = 0; + /* Don't reuse IV for CTR mode */ + if (iv) { + memcpy(ctx->iv, iv, EVP_CIPHER_CTX_iv_length(ctx)); + } + break; + + default: + return 0; + } + } + + if (key || (ctx->cipher->flags & EVP_CIPH_ALWAYS_CALL_INIT)) { + if (!ctx->cipher->init(ctx, key, iv, enc)) { + return 0; + } + } + + ctx->buf_len = 0; + ctx->final_used = 0; + ctx->block_mask = ctx->cipher->block_size - 1; + return 1; +} + +int EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, + ENGINE *impl, const uint8_t *key, const uint8_t *iv) { + return EVP_CipherInit_ex(ctx, cipher, impl, key, iv, 1); +} + +int EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, + ENGINE *impl, const uint8_t *key, const uint8_t *iv) { + return EVP_CipherInit_ex(ctx, cipher, impl, key, iv, 0); +} + +int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len, + const uint8_t *in, int in_len) { + int i, j, bl; + + if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) { + i = ctx->cipher->cipher(ctx, out, in, in_len); + if (i < 0) { + return 0; + } else { + *out_len = i; + } + return 1; + } + + if (in_len <= 0) { + *out_len = 0; + return in_len == 0; + } + + if (ctx->buf_len == 0 && (in_len & ctx->block_mask) == 0) { + if (ctx->cipher->cipher(ctx, out, in, in_len)) { + *out_len = in_len; + return 1; + } else { + *out_len = 0; + return 0; + } + } + + i = ctx->buf_len; + bl = ctx->cipher->block_size; + assert(bl <= (int)sizeof(ctx->buf)); + if (i != 0) { + if (i + in_len < bl) { + memcpy(&ctx->buf[i], in, in_len); + ctx->buf_len += in_len; + *out_len = 0; + return 1; + } else { + j = bl - i; + memcpy(&ctx->buf[i], in, j); + if (!ctx->cipher->cipher(ctx, out, ctx->buf, bl)) { + return 0; + } + in_len -= j; + in += j; + out += bl; + *out_len = bl; + } + } else { + *out_len = 0; + } + + i = in_len & ctx->block_mask; + in_len -= i; + if (in_len > 0) { + if (!ctx->cipher->cipher(ctx, out, in, in_len)) { + return 0; + } + *out_len += in_len; + } + + if (i != 0) { + memcpy(ctx->buf, &in[in_len], i); + } + ctx->buf_len = i; + return 1; +} + +int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len) { + int n, ret; + unsigned int i, b, bl; + + if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) { + ret = ctx->cipher->cipher(ctx, out, NULL, 0); + if (ret < 0) { + return 0; + } else { + *out_len = ret; + } + return 1; + } + + b = ctx->cipher->block_size; + assert(b <= sizeof(ctx->buf)); + if (b == 1) { + *out_len = 0; + return 1; + } + + bl = ctx->buf_len; + if (ctx->flags & EVP_CIPH_NO_PADDING) { + if (bl) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH); + return 0; + } + *out_len = 0; + return 1; + } + + n = b - bl; + for (i = bl; i < b; i++) { + ctx->buf[i] = n; + } + ret = ctx->cipher->cipher(ctx, out, ctx->buf, b); + + if (ret) { + *out_len = b; + } + + return ret; +} + +int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len, + const uint8_t *in, int in_len) { + int fix_len; + unsigned int b; + + if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) { + int r = ctx->cipher->cipher(ctx, out, in, in_len); + if (r < 0) { + *out_len = 0; + return 0; + } else { + *out_len = r; + } + return 1; + } + + if (in_len <= 0) { + *out_len = 0; + return in_len == 0; + } + + if (ctx->flags & EVP_CIPH_NO_PADDING) { + return EVP_EncryptUpdate(ctx, out, out_len, in, in_len); + } + + b = ctx->cipher->block_size; + assert(b <= sizeof(ctx->final)); + + if (ctx->final_used) { + memcpy(out, ctx->final, b); + out += b; + fix_len = 1; + } else { + fix_len = 0; + } + + if (!EVP_EncryptUpdate(ctx, out, out_len, in, in_len)) { + return 0; + } + + /* if we have 'decrypted' a multiple of block size, make sure + * we have a copy of this last block */ + if (b > 1 && !ctx->buf_len) { + *out_len -= b; + ctx->final_used = 1; + memcpy(ctx->final, &out[*out_len], b); + } else { + ctx->final_used = 0; + } + + if (fix_len) { + *out_len += b; + } + + return 1; +} + +int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len) { + int i, n; + unsigned int b; + *out_len = 0; + + if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) { + i = ctx->cipher->cipher(ctx, out, NULL, 0); + if (i < 0) { + return 0; + } else { + *out_len = i; + } + return 1; + } + + b = ctx->cipher->block_size; + if (ctx->flags & EVP_CIPH_NO_PADDING) { + if (ctx->buf_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH); + return 0; + } + *out_len = 0; + return 1; + } + + if (b > 1) { + if (ctx->buf_len || !ctx->final_used) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_WRONG_FINAL_BLOCK_LENGTH); + return 0; + } + assert(b <= sizeof(ctx->final)); + + /* The following assumes that the ciphertext has been authenticated. + * Otherwise it provides a padding oracle. */ + n = ctx->final[b - 1]; + if (n == 0 || n > (int)b) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + for (i = 0; i < n; i++) { + if (ctx->final[--b] != n) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + } + + n = ctx->cipher->block_size - n; + for (i = 0; i < n; i++) { + out[i] = ctx->final[i]; + } + *out_len = n; + } else { + *out_len = 0; + } + + return 1; +} + +int EVP_Cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, + size_t in_len) { + return ctx->cipher->cipher(ctx, out, in, in_len); +} + +int EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len, + const uint8_t *in, int in_len) { + if (ctx->encrypt) { + return EVP_EncryptUpdate(ctx, out, out_len, in, in_len); + } else { + return EVP_DecryptUpdate(ctx, out, out_len, in, in_len); + } +} + +int EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len) { + if (ctx->encrypt) { + return EVP_EncryptFinal_ex(ctx, out, out_len); + } else { + return EVP_DecryptFinal_ex(ctx, out, out_len); + } +} + +const EVP_CIPHER *EVP_CIPHER_CTX_cipher(const EVP_CIPHER_CTX *ctx) { + return ctx->cipher; +} + +int EVP_CIPHER_CTX_nid(const EVP_CIPHER_CTX *ctx) { + return ctx->cipher->nid; +} + +unsigned EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *ctx) { + return ctx->cipher->block_size; +} + +unsigned EVP_CIPHER_CTX_key_length(const EVP_CIPHER_CTX *ctx) { + return ctx->key_len; +} + +unsigned EVP_CIPHER_CTX_iv_length(const EVP_CIPHER_CTX *ctx) { + return ctx->cipher->iv_len; +} + +void *EVP_CIPHER_CTX_get_app_data(const EVP_CIPHER_CTX *ctx) { + return ctx->app_data; +} + +void EVP_CIPHER_CTX_set_app_data(EVP_CIPHER_CTX *ctx, void *data) { + ctx->app_data = data; +} + +uint32_t EVP_CIPHER_CTX_flags(const EVP_CIPHER_CTX *ctx) { + return ctx->cipher->flags & ~EVP_CIPH_MODE_MASK; +} + +uint32_t EVP_CIPHER_CTX_mode(const EVP_CIPHER_CTX *ctx) { + return ctx->cipher->flags & EVP_CIPH_MODE_MASK; +} + +int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int command, int arg, void *ptr) { + int ret; + if (!ctx->cipher) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_NO_CIPHER_SET); + return 0; + } + + if (!ctx->cipher->ctrl) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_CTRL_NOT_IMPLEMENTED); + return 0; + } + + ret = ctx->cipher->ctrl(ctx, command, arg, ptr); + if (ret == -1) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_CTRL_OPERATION_NOT_IMPLEMENTED); + return 0; + } + + return ret; +} + +int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *ctx, int pad) { + if (pad) { + ctx->flags &= ~EVP_CIPH_NO_PADDING; + } else { + ctx->flags |= EVP_CIPH_NO_PADDING; + } + return 1; +} + +int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *c, unsigned key_len) { + if (c->key_len == key_len) { + return 1; + } + + if (key_len == 0 || !(c->cipher->flags & EVP_CIPH_VARIABLE_LENGTH)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_KEY_LENGTH); + return 0; + } + + c->key_len = key_len; + return 1; +} + +int EVP_CIPHER_nid(const EVP_CIPHER *cipher) { return cipher->nid; } + +unsigned EVP_CIPHER_block_size(const EVP_CIPHER *cipher) { + return cipher->block_size; +} + +unsigned EVP_CIPHER_key_length(const EVP_CIPHER *cipher) { + return cipher->key_len; +} + +unsigned EVP_CIPHER_iv_length(const EVP_CIPHER *cipher) { + return cipher->iv_len; +} + +uint32_t EVP_CIPHER_flags(const EVP_CIPHER *cipher) { + return cipher->flags & ~EVP_CIPH_MODE_MASK; +} + +uint32_t EVP_CIPHER_mode(const EVP_CIPHER *cipher) { + return cipher->flags & EVP_CIPH_MODE_MASK; +} + +int EVP_CipherInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, + const uint8_t *key, const uint8_t *iv, int enc) { + if (cipher) { + EVP_CIPHER_CTX_init(ctx); + } + return EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, enc); +} + +int EVP_EncryptInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, + const uint8_t *key, const uint8_t *iv) { + return EVP_CipherInit(ctx, cipher, key, iv, 1); +} + +int EVP_DecryptInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, + const uint8_t *key, const uint8_t *iv) { + return EVP_CipherInit(ctx, cipher, key, iv, 0); +} + +int EVP_add_cipher_alias(const char *a, const char *b) { + return 1; +} + +const EVP_CIPHER *EVP_get_cipherbyname(const char *name) { + if (OPENSSL_strcasecmp(name, "rc4") == 0) { + return EVP_rc4(); + } else if (OPENSSL_strcasecmp(name, "des-cbc") == 0) { + return EVP_des_cbc(); + } else if (OPENSSL_strcasecmp(name, "des-ede3-cbc") == 0 || + OPENSSL_strcasecmp(name, "3des") == 0) { + return EVP_des_ede3_cbc(); + } else if (OPENSSL_strcasecmp(name, "aes-128-cbc") == 0) { + return EVP_aes_128_cbc(); + } else if (OPENSSL_strcasecmp(name, "aes-256-cbc") == 0) { + return EVP_aes_256_cbc(); + } else if (OPENSSL_strcasecmp(name, "aes-128-ctr") == 0) { + return EVP_aes_128_ctr(); + } else if (OPENSSL_strcasecmp(name, "aes-256-ctr") == 0) { + return EVP_aes_256_ctr(); + } else if (OPENSSL_strcasecmp(name, "aes-128-ecb") == 0) { + return EVP_aes_128_ecb(); + } else if (OPENSSL_strcasecmp(name, "aes-256-ecb") == 0) { + return EVP_aes_256_ecb(); + } + + return NULL; +} diff --git a/TMessagesProj/jni/boringssl/crypto/cipher/derive_key.c b/TMessagesProj/jni/boringssl/crypto/cipher/derive_key.c new file mode 100644 index 00000000..9e1634ab --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cipher/derive_key.c @@ -0,0 +1,154 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include + +#include "internal.h" + + +#define PKCS5_SALT_LEN 8 + +int EVP_BytesToKey(const EVP_CIPHER *type, const EVP_MD *md, + const uint8_t *salt, const uint8_t *data, size_t data_len, + unsigned count, uint8_t *key, uint8_t *iv) { + EVP_MD_CTX c; + uint8_t md_buf[EVP_MAX_MD_SIZE]; + unsigned niv, nkey, addmd = 0; + unsigned mds = 0, i; + int rv = 0; + + nkey = type->key_len; + niv = type->iv_len; + + assert(nkey <= EVP_MAX_KEY_LENGTH); + assert(niv <= EVP_MAX_IV_LENGTH); + + if (data == NULL) { + return nkey; + } + + EVP_MD_CTX_init(&c); + for (;;) { + if (!EVP_DigestInit_ex(&c, md, NULL)) { + return 0; + } + if (addmd++) { + if (!EVP_DigestUpdate(&c, md_buf, mds)) { + goto err; + } + } + if (!EVP_DigestUpdate(&c, data, data_len)) { + goto err; + } + if (salt != NULL) { + if (!EVP_DigestUpdate(&c, salt, PKCS5_SALT_LEN)) { + goto err; + } + } + if (!EVP_DigestFinal_ex(&c, md_buf, &mds)) { + goto err; + } + + for (i = 1; i < count; i++) { + if (!EVP_DigestInit_ex(&c, md, NULL) || + !EVP_DigestUpdate(&c, md_buf, mds) || + !EVP_DigestFinal_ex(&c, md_buf, &mds)) { + goto err; + } + } + + i = 0; + if (nkey) { + for (;;) { + if (nkey == 0 || i == mds) { + break; + } + if (key != NULL) { + *(key++) = md_buf[i]; + } + nkey--; + i++; + } + } + + if (niv && i != mds) { + for (;;) { + if (niv == 0 || i == mds) { + break; + } + if (iv != NULL) { + *(iv++) = md_buf[i]; + } + niv--; + i++; + } + } + if (nkey == 0 && niv == 0) { + break; + } + } + rv = type->key_len; + +err: + EVP_MD_CTX_cleanup(&c); + OPENSSL_cleanse(md_buf, EVP_MAX_MD_SIZE); + return rv; +} diff --git a/TMessagesProj/jni/boringssl/crypto/cipher/e_aes.c b/TMessagesProj/jni/boringssl/crypto/cipher/e_aes.c new file mode 100644 index 00000000..24013dcb --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cipher/e_aes.c @@ -0,0 +1,1760 @@ +/* ==================================================================== + * Copyright (c) 2001-2011 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" +#include "../internal.h" +#include "../modes/internal.h" + +#if defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) +#include "../arm_arch.h" +#endif + + +typedef struct { + union { + double align; + AES_KEY ks; + } ks; + block128_f block; + union { + cbc128_f cbc; + ctr128_f ctr; + } stream; +} EVP_AES_KEY; + +typedef struct { + union { + double align; + AES_KEY ks; + } ks; /* AES key schedule to use */ + int key_set; /* Set if key initialised */ + int iv_set; /* Set if an iv is set */ + GCM128_CONTEXT gcm; + uint8_t *iv; /* Temporary IV store */ + int ivlen; /* IV length */ + int taglen; + int iv_gen; /* It is OK to generate IVs */ + ctr128_f ctr; +} EVP_AES_GCM_CTX; + +#if !defined(OPENSSL_NO_ASM) && \ + (defined(OPENSSL_X86_64) || defined(OPENSSL_X86)) +#define VPAES +static char vpaes_capable(void) { + return (OPENSSL_ia32cap_P[1] & (1 << (41 - 32))) != 0; +} + +#if defined(OPENSSL_X86_64) +#define BSAES +static char bsaes_capable(void) { + return vpaes_capable(); +} +#endif + +#elif !defined(OPENSSL_NO_ASM) && \ + (defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) +#include "../arm_arch.h" + +#if defined(OPENSSL_ARM) && __ARM_MAX_ARCH__ >= 7 +#define BSAES +static char bsaes_capable(void) { + return CRYPTO_is_NEON_capable(); +} +#endif + +#define HWAES +static char hwaes_capable(void) { + return (OPENSSL_armcap_P & ARMV8_AES) != 0; +} + +int aes_v8_set_encrypt_key(const uint8_t *user_key, const int bits, + AES_KEY *key); +int aes_v8_set_decrypt_key(const uint8_t *user_key, const int bits, + AES_KEY *key); +void aes_v8_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); +void aes_v8_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); +void aes_v8_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, + const AES_KEY *key, uint8_t *ivec, const int enc); +void aes_v8_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t len, + const AES_KEY *key, const uint8_t ivec[16]); + +#endif /* OPENSSL_ARM */ + +#if defined(BSAES) +/* On platforms where BSAES gets defined (just above), then these functions are + * provided by asm. */ +void bsaes_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, + const AES_KEY *key, uint8_t ivec[16], int enc); +void bsaes_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t len, + const AES_KEY *key, const uint8_t ivec[16]); +#else +static char bsaes_capable(void) { + return 0; +} + +/* On other platforms, bsaes_capable() will always return false and so the + * following will never be called. */ +void bsaes_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, + const AES_KEY *key, uint8_t ivec[16], int enc) { + abort(); +} + +void bsaes_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t len, + const AES_KEY *key, const uint8_t ivec[16]) { + abort(); +} +#endif + +#if defined(VPAES) +/* On platforms where VPAES gets defined (just above), then these functions are + * provided by asm. */ +int vpaes_set_encrypt_key(const uint8_t *userKey, int bits, AES_KEY *key); +int vpaes_set_decrypt_key(const uint8_t *userKey, int bits, AES_KEY *key); + +void vpaes_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); +void vpaes_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); + +void vpaes_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, + const AES_KEY *key, uint8_t *ivec, int enc); +#else +static char vpaes_capable(void) { + return 0; +} + +/* On other platforms, vpaes_capable() will always return false and so the + * following will never be called. */ +int vpaes_set_encrypt_key(const uint8_t *userKey, int bits, AES_KEY *key) { + abort(); +} +int vpaes_set_decrypt_key(const uint8_t *userKey, int bits, AES_KEY *key) { + abort(); +} +void vpaes_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { + abort(); +} +void vpaes_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { + abort(); +} +void vpaes_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, + const AES_KEY *key, uint8_t *ivec, int enc) { + abort(); +} +#endif + +#if !defined(HWAES) +/* If HWAES isn't defined then we provide dummy functions for each of the hwaes + * functions. */ +int hwaes_capable(void) { + return 0; +} + +int aes_v8_set_encrypt_key(const uint8_t *user_key, int bits, + AES_KEY *key) { + abort(); +} + +int aes_v8_set_decrypt_key(const uint8_t *user_key, int bits, AES_KEY *key) { + abort(); +} + +void aes_v8_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { + abort(); +} + +void aes_v8_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { + abort(); +} + +void aes_v8_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, + const AES_KEY *key, uint8_t *ivec, int enc) { + abort(); +} + +void aes_v8_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t len, + const AES_KEY *key, const uint8_t ivec[16]) { + abort(); +} +#endif + +#if !defined(OPENSSL_NO_ASM) && \ + (defined(OPENSSL_X86_64) || defined(OPENSSL_X86)) +int aesni_set_encrypt_key(const uint8_t *userKey, int bits, AES_KEY *key); +int aesni_set_decrypt_key(const uint8_t *userKey, int bits, AES_KEY *key); + +void aesni_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); +void aesni_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); + +void aesni_ecb_encrypt(const uint8_t *in, uint8_t *out, size_t length, + const AES_KEY *key, int enc); +void aesni_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, + const AES_KEY *key, uint8_t *ivec, int enc); + +void aesni_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t blocks, + const void *key, const uint8_t *ivec); + +#if defined(OPENSSL_X86_64) +size_t aesni_gcm_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const void *key, uint8_t ivec[16], uint64_t *Xi); +#define AES_gcm_encrypt aesni_gcm_encrypt +size_t aesni_gcm_decrypt(const uint8_t *in, uint8_t *out, size_t len, + const void *key, uint8_t ivec[16], uint64_t *Xi); +#define AES_gcm_decrypt aesni_gcm_decrypt +void gcm_ghash_avx(uint64_t Xi[2], const u128 Htable[16], const uint8_t *in, + size_t len); +#define AES_GCM_ASM(gctx) \ + (gctx->ctr == aesni_ctr32_encrypt_blocks && gctx->gcm.ghash == gcm_ghash_avx) +#endif /* OPENSSL_X86_64 */ + +#else + +/* On other platforms, aesni_capable() will always return false and so the + * following will never be called. */ +void aesni_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { + abort(); +} +int aesni_set_encrypt_key(const uint8_t *userKey, int bits, AES_KEY *key) { + abort(); +} +void aesni_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t blocks, + const void *key, const uint8_t *ivec) { + abort(); +} + +#endif + +static int aes_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key, + const uint8_t *iv, int enc) + OPENSSL_SUPPRESS_UNREACHABLE_CODE_WARNINGS { + int ret, mode; + EVP_AES_KEY *dat = (EVP_AES_KEY *)ctx->cipher_data; + + mode = ctx->cipher->flags & EVP_CIPH_MODE_MASK; + if ((mode == EVP_CIPH_ECB_MODE || mode == EVP_CIPH_CBC_MODE) && !enc) { + if (hwaes_capable()) { + ret = aes_v8_set_decrypt_key(key, ctx->key_len * 8, &dat->ks.ks); + dat->block = (block128_f)aes_v8_decrypt; + dat->stream.cbc = NULL; + if (mode == EVP_CIPH_CBC_MODE) { + dat->stream.cbc = (cbc128_f)aes_v8_cbc_encrypt; + } + } else if (bsaes_capable() && mode == EVP_CIPH_CBC_MODE) { + ret = AES_set_decrypt_key(key, ctx->key_len * 8, &dat->ks.ks); + dat->block = (block128_f)AES_decrypt; + dat->stream.cbc = (cbc128_f)bsaes_cbc_encrypt; + } else if (vpaes_capable()) { + ret = vpaes_set_decrypt_key(key, ctx->key_len * 8, &dat->ks.ks); + dat->block = (block128_f)vpaes_decrypt; + dat->stream.cbc = + mode == EVP_CIPH_CBC_MODE ? (cbc128_f)vpaes_cbc_encrypt : NULL; + } else { + ret = AES_set_decrypt_key(key, ctx->key_len * 8, &dat->ks.ks); + dat->block = (block128_f)AES_decrypt; + dat->stream.cbc = + mode == EVP_CIPH_CBC_MODE ? (cbc128_f)AES_cbc_encrypt : NULL; + } + } else if (hwaes_capable()) { + ret = aes_v8_set_encrypt_key(key, ctx->key_len * 8, &dat->ks.ks); + dat->block = (block128_f)aes_v8_encrypt; + dat->stream.cbc = NULL; + if (mode == EVP_CIPH_CBC_MODE) { + dat->stream.cbc = (cbc128_f)aes_v8_cbc_encrypt; + } else if (mode == EVP_CIPH_CTR_MODE) { + dat->stream.ctr = (ctr128_f)aes_v8_ctr32_encrypt_blocks; + } + } else if (bsaes_capable() && mode == EVP_CIPH_CTR_MODE) { + ret = AES_set_encrypt_key(key, ctx->key_len * 8, &dat->ks.ks); + dat->block = (block128_f)AES_encrypt; + dat->stream.ctr = (ctr128_f)bsaes_ctr32_encrypt_blocks; + } else if (vpaes_capable()) { + ret = vpaes_set_encrypt_key(key, ctx->key_len * 8, &dat->ks.ks); + dat->block = (block128_f)vpaes_encrypt; + dat->stream.cbc = + mode == EVP_CIPH_CBC_MODE ? (cbc128_f)vpaes_cbc_encrypt : NULL; + } else { + ret = AES_set_encrypt_key(key, ctx->key_len * 8, &dat->ks.ks); + dat->block = (block128_f)AES_encrypt; + dat->stream.cbc = + mode == EVP_CIPH_CBC_MODE ? (cbc128_f)AES_cbc_encrypt : NULL; + } + + if (ret < 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_AES_KEY_SETUP_FAILED); + return 0; + } + + return 1; +} + +static int aes_cbc_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, + size_t len) { + EVP_AES_KEY *dat = (EVP_AES_KEY *)ctx->cipher_data; + + if (dat->stream.cbc) { + (*dat->stream.cbc)(in, out, len, &dat->ks, ctx->iv, ctx->encrypt); + } else if (ctx->encrypt) { + CRYPTO_cbc128_encrypt(in, out, len, &dat->ks, ctx->iv, dat->block); + } else { + CRYPTO_cbc128_decrypt(in, out, len, &dat->ks, ctx->iv, dat->block); + } + + return 1; +} + +static int aes_ecb_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, + size_t len) { + size_t bl = ctx->cipher->block_size; + size_t i; + EVP_AES_KEY *dat = (EVP_AES_KEY *)ctx->cipher_data; + + if (len < bl) { + return 1; + } + + for (i = 0, len -= bl; i <= len; i += bl) { + (*dat->block)(in + i, out + i, &dat->ks); + } + + return 1; +} + +static int aes_ctr_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, + size_t len) { + unsigned int num = ctx->num; + EVP_AES_KEY *dat = (EVP_AES_KEY *)ctx->cipher_data; + + if (dat->stream.ctr) { + CRYPTO_ctr128_encrypt_ctr32(in, out, len, &dat->ks, ctx->iv, ctx->buf, &num, + dat->stream.ctr); + } else { + CRYPTO_ctr128_encrypt(in, out, len, &dat->ks, ctx->iv, ctx->buf, &num, + dat->block); + } + ctx->num = (size_t)num; + return 1; +} + +static int aes_ofb_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, + size_t len) { + EVP_AES_KEY *dat = (EVP_AES_KEY *)ctx->cipher_data; + + CRYPTO_ofb128_encrypt(in, out, len, &dat->ks, ctx->iv, &ctx->num, dat->block); + return 1; +} + +static char aesni_capable(void); + +static ctr128_f aes_ctr_set_key(AES_KEY *aes_key, GCM128_CONTEXT *gcm_ctx, + block128_f *out_block, const uint8_t *key, + size_t key_len) + OPENSSL_SUPPRESS_UNREACHABLE_CODE_WARNINGS { + if (aesni_capable()) { + aesni_set_encrypt_key(key, key_len * 8, aes_key); + if (gcm_ctx != NULL) { + CRYPTO_gcm128_init(gcm_ctx, aes_key, (block128_f)aesni_encrypt); + } + if (out_block) { + *out_block = (block128_f) aesni_encrypt; + } + return (ctr128_f)aesni_ctr32_encrypt_blocks; + } + + if (hwaes_capable()) { + aes_v8_set_encrypt_key(key, key_len * 8, aes_key); + if (gcm_ctx != NULL) { + CRYPTO_gcm128_init(gcm_ctx, aes_key, (block128_f)aes_v8_encrypt); + } + if (out_block) { + *out_block = (block128_f) aes_v8_encrypt; + } + return (ctr128_f)aes_v8_ctr32_encrypt_blocks; + } + + if (bsaes_capable()) { + AES_set_encrypt_key(key, key_len * 8, aes_key); + if (gcm_ctx != NULL) { + CRYPTO_gcm128_init(gcm_ctx, aes_key, (block128_f)AES_encrypt); + } + if (out_block) { + *out_block = (block128_f) AES_encrypt; + } + return (ctr128_f)bsaes_ctr32_encrypt_blocks; + } + + if (vpaes_capable()) { + vpaes_set_encrypt_key(key, key_len * 8, aes_key); + if (out_block) { + *out_block = (block128_f) vpaes_encrypt; + } + if (gcm_ctx != NULL) { + CRYPTO_gcm128_init(gcm_ctx, aes_key, (block128_f)vpaes_encrypt); + } + return NULL; + } + + AES_set_encrypt_key(key, key_len * 8, aes_key); + if (gcm_ctx != NULL) { + CRYPTO_gcm128_init(gcm_ctx, aes_key, (block128_f)AES_encrypt); + } + if (out_block) { + *out_block = (block128_f) AES_encrypt; + } + return NULL; +} + +static int aes_gcm_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key, + const uint8_t *iv, int enc) { + EVP_AES_GCM_CTX *gctx = ctx->cipher_data; + if (!iv && !key) { + return 1; + } + if (key) { + gctx->ctr = + aes_ctr_set_key(&gctx->ks.ks, &gctx->gcm, NULL, key, ctx->key_len); + /* If we have an iv can set it directly, otherwise use saved IV. */ + if (iv == NULL && gctx->iv_set) { + iv = gctx->iv; + } + if (iv) { + CRYPTO_gcm128_setiv(&gctx->gcm, iv, gctx->ivlen); + gctx->iv_set = 1; + } + gctx->key_set = 1; + } else { + /* If key set use IV, otherwise copy */ + if (gctx->key_set) { + CRYPTO_gcm128_setiv(&gctx->gcm, iv, gctx->ivlen); + } else { + memcpy(gctx->iv, iv, gctx->ivlen); + } + gctx->iv_set = 1; + gctx->iv_gen = 0; + } + return 1; +} + +static void aes_gcm_cleanup(EVP_CIPHER_CTX *c) { + EVP_AES_GCM_CTX *gctx = c->cipher_data; + OPENSSL_cleanse(&gctx->gcm, sizeof(gctx->gcm)); + if (gctx->iv != c->iv) { + OPENSSL_free(gctx->iv); + } +} + +/* increment counter (64-bit int) by 1 */ +static void ctr64_inc(uint8_t *counter) { + int n = 8; + uint8_t c; + + do { + --n; + c = counter[n]; + ++c; + counter[n] = c; + if (c) { + return; + } + } while (n); +} + +static int aes_gcm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr) { + EVP_AES_GCM_CTX *gctx = c->cipher_data; + switch (type) { + case EVP_CTRL_INIT: + gctx->key_set = 0; + gctx->iv_set = 0; + gctx->ivlen = c->cipher->iv_len; + gctx->iv = c->iv; + gctx->taglen = -1; + gctx->iv_gen = 0; + return 1; + + case EVP_CTRL_GCM_SET_IVLEN: + if (arg <= 0) { + return 0; + } + + /* Allocate memory for IV if needed */ + if (arg > EVP_MAX_IV_LENGTH && arg > gctx->ivlen) { + if (gctx->iv != c->iv) { + OPENSSL_free(gctx->iv); + } + gctx->iv = OPENSSL_malloc(arg); + if (!gctx->iv) { + return 0; + } + } + gctx->ivlen = arg; + return 1; + + case EVP_CTRL_GCM_SET_TAG: + if (arg <= 0 || arg > 16 || c->encrypt) { + return 0; + } + memcpy(c->buf, ptr, arg); + gctx->taglen = arg; + return 1; + + case EVP_CTRL_GCM_GET_TAG: + if (arg <= 0 || arg > 16 || !c->encrypt || gctx->taglen < 0) { + return 0; + } + memcpy(ptr, c->buf, arg); + return 1; + + case EVP_CTRL_GCM_SET_IV_FIXED: + /* Special case: -1 length restores whole IV */ + if (arg == -1) { + memcpy(gctx->iv, ptr, gctx->ivlen); + gctx->iv_gen = 1; + return 1; + } + /* Fixed field must be at least 4 bytes and invocation field + * at least 8. */ + if (arg < 4 || (gctx->ivlen - arg) < 8) { + return 0; + } + if (arg) { + memcpy(gctx->iv, ptr, arg); + } + if (c->encrypt && !RAND_bytes(gctx->iv + arg, gctx->ivlen - arg)) { + return 0; + } + gctx->iv_gen = 1; + return 1; + + case EVP_CTRL_GCM_IV_GEN: + if (gctx->iv_gen == 0 || gctx->key_set == 0) { + return 0; + } + CRYPTO_gcm128_setiv(&gctx->gcm, gctx->iv, gctx->ivlen); + if (arg <= 0 || arg > gctx->ivlen) { + arg = gctx->ivlen; + } + memcpy(ptr, gctx->iv + gctx->ivlen - arg, arg); + /* Invocation field will be at least 8 bytes in size and + * so no need to check wrap around or increment more than + * last 8 bytes. */ + ctr64_inc(gctx->iv + gctx->ivlen - 8); + gctx->iv_set = 1; + return 1; + + case EVP_CTRL_GCM_SET_IV_INV: + if (gctx->iv_gen == 0 || gctx->key_set == 0 || c->encrypt) { + return 0; + } + memcpy(gctx->iv + gctx->ivlen - arg, ptr, arg); + CRYPTO_gcm128_setiv(&gctx->gcm, gctx->iv, gctx->ivlen); + gctx->iv_set = 1; + return 1; + + case EVP_CTRL_COPY: { + EVP_CIPHER_CTX *out = ptr; + EVP_AES_GCM_CTX *gctx_out = out->cipher_data; + if (gctx->gcm.key) { + if (gctx->gcm.key != &gctx->ks) { + return 0; + } + gctx_out->gcm.key = &gctx_out->ks; + } + if (gctx->iv == c->iv) { + gctx_out->iv = out->iv; + } else { + gctx_out->iv = OPENSSL_malloc(gctx->ivlen); + if (!gctx_out->iv) { + return 0; + } + memcpy(gctx_out->iv, gctx->iv, gctx->ivlen); + } + return 1; + } + + default: + return -1; + } +} + +static int aes_gcm_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, + size_t len) { + EVP_AES_GCM_CTX *gctx = ctx->cipher_data; + + /* If not set up, return error */ + if (!gctx->key_set) { + return -1; + } + if (!gctx->iv_set) { + return -1; + } + + if (in) { + if (out == NULL) { + if (!CRYPTO_gcm128_aad(&gctx->gcm, in, len)) { + return -1; + } + } else if (ctx->encrypt) { + if (gctx->ctr) { + size_t bulk = 0; +#if defined(AES_GCM_ASM) + if (len >= 32 && AES_GCM_ASM(gctx)) { + size_t res = (16 - gctx->gcm.mres) % 16; + + if (!CRYPTO_gcm128_encrypt(&gctx->gcm, in, out, res)) { + return -1; + } + + bulk = AES_gcm_encrypt(in + res, out + res, len - res, gctx->gcm.key, + gctx->gcm.Yi.c, gctx->gcm.Xi.u); + gctx->gcm.len.u[1] += bulk; + bulk += res; + } +#endif + if (!CRYPTO_gcm128_encrypt_ctr32(&gctx->gcm, in + bulk, out + bulk, + len - bulk, gctx->ctr)) { + return -1; + } + } else { + size_t bulk = 0; + if (!CRYPTO_gcm128_encrypt(&gctx->gcm, in + bulk, out + bulk, + len - bulk)) { + return -1; + } + } + } else { + if (gctx->ctr) { + size_t bulk = 0; +#if defined(AES_GCM_ASM) + if (len >= 16 && AES_GCM_ASM(gctx)) { + size_t res = (16 - gctx->gcm.mres) % 16; + + if (!CRYPTO_gcm128_decrypt(&gctx->gcm, in, out, res)) { + return -1; + } + + bulk = AES_gcm_decrypt(in + res, out + res, len - res, gctx->gcm.key, + gctx->gcm.Yi.c, gctx->gcm.Xi.u); + gctx->gcm.len.u[1] += bulk; + bulk += res; + } +#endif + if (!CRYPTO_gcm128_decrypt_ctr32(&gctx->gcm, in + bulk, out + bulk, + len - bulk, gctx->ctr)) { + return -1; + } + } else { + size_t bulk = 0; + if (!CRYPTO_gcm128_decrypt(&gctx->gcm, in + bulk, out + bulk, + len - bulk)) { + return -1; + } + } + } + return len; + } else { + if (!ctx->encrypt) { + if (gctx->taglen < 0 || + !CRYPTO_gcm128_finish(&gctx->gcm, ctx->buf, gctx->taglen) != 0) { + return -1; + } + gctx->iv_set = 0; + return 0; + } + CRYPTO_gcm128_tag(&gctx->gcm, ctx->buf, 16); + gctx->taglen = 16; + /* Don't reuse the IV */ + gctx->iv_set = 0; + return 0; + } +} + +static const EVP_CIPHER aes_128_cbc = { + NID_aes_128_cbc, 16 /* block_size */, 16 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CBC_MODE, + NULL /* app_data */, aes_init_key, aes_cbc_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aes_128_ctr = { + NID_aes_128_ctr, 1 /* block_size */, 16 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CTR_MODE, + NULL /* app_data */, aes_init_key, aes_ctr_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aes_128_ecb = { + NID_aes_128_ecb, 16 /* block_size */, 16 /* key_size */, + 0 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_ECB_MODE, + NULL /* app_data */, aes_init_key, aes_ecb_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aes_128_ofb = { + NID_aes_128_ofb128, 1 /* block_size */, 16 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_OFB_MODE, + NULL /* app_data */, aes_init_key, aes_ofb_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aes_128_gcm = { + NID_aes_128_gcm, 1 /* block_size */, 16 /* key_size */, 12 /* iv_len */, + sizeof(EVP_AES_GCM_CTX), + EVP_CIPH_GCM_MODE | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER | + EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT | + EVP_CIPH_FLAG_AEAD_CIPHER, + NULL /* app_data */, aes_gcm_init_key, aes_gcm_cipher, aes_gcm_cleanup, + aes_gcm_ctrl}; + + +static const EVP_CIPHER aes_192_cbc = { + NID_aes_192_cbc, 16 /* block_size */, 24 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CBC_MODE, + NULL /* app_data */, aes_init_key, aes_cbc_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aes_192_ctr = { + NID_aes_192_ctr, 1 /* block_size */, 24 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CTR_MODE, + NULL /* app_data */, aes_init_key, aes_ctr_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aes_192_ecb = { + NID_aes_192_ecb, 16 /* block_size */, 24 /* key_size */, + 0 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_ECB_MODE, + NULL /* app_data */, aes_init_key, aes_ecb_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aes_192_gcm = { + NID_aes_192_gcm, 1 /* block_size */, 24 /* key_size */, 12 /* iv_len */, + sizeof(EVP_AES_GCM_CTX), + EVP_CIPH_GCM_MODE | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER | + EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT | + EVP_CIPH_FLAG_AEAD_CIPHER, + NULL /* app_data */, aes_gcm_init_key, aes_gcm_cipher, aes_gcm_cleanup, + aes_gcm_ctrl}; + + +static const EVP_CIPHER aes_256_cbc = { + NID_aes_256_cbc, 16 /* block_size */, 32 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CBC_MODE, + NULL /* app_data */, aes_init_key, aes_cbc_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aes_256_ctr = { + NID_aes_256_ctr, 1 /* block_size */, 32 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CTR_MODE, + NULL /* app_data */, aes_init_key, aes_ctr_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aes_256_ecb = { + NID_aes_256_ecb, 16 /* block_size */, 32 /* key_size */, + 0 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_ECB_MODE, + NULL /* app_data */, aes_init_key, aes_ecb_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aes_256_ofb = { + NID_aes_256_ofb128, 1 /* block_size */, 32 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_OFB_MODE, + NULL /* app_data */, aes_init_key, aes_ofb_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aes_256_gcm = { + NID_aes_256_gcm, 1 /* block_size */, 32 /* key_size */, 12 /* iv_len */, + sizeof(EVP_AES_GCM_CTX), + EVP_CIPH_GCM_MODE | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER | + EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT | + EVP_CIPH_FLAG_AEAD_CIPHER, + NULL /* app_data */, aes_gcm_init_key, aes_gcm_cipher, aes_gcm_cleanup, + aes_gcm_ctrl}; + +#if !defined(OPENSSL_NO_ASM) && \ + (defined(OPENSSL_X86_64) || defined(OPENSSL_X86)) + +/* AES-NI section. */ + +static char aesni_capable(void) { + return (OPENSSL_ia32cap_P[1] & (1 << (57 - 32))) != 0; +} + +static int aesni_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key, + const uint8_t *iv, int enc) { + int ret, mode; + EVP_AES_KEY *dat = (EVP_AES_KEY *)ctx->cipher_data; + + mode = ctx->cipher->flags & EVP_CIPH_MODE_MASK; + if ((mode == EVP_CIPH_ECB_MODE || mode == EVP_CIPH_CBC_MODE) && !enc) { + ret = aesni_set_decrypt_key(key, ctx->key_len * 8, ctx->cipher_data); + dat->block = (block128_f)aesni_decrypt; + dat->stream.cbc = + mode == EVP_CIPH_CBC_MODE ? (cbc128_f)aesni_cbc_encrypt : NULL; + } else { + ret = aesni_set_encrypt_key(key, ctx->key_len * 8, ctx->cipher_data); + dat->block = (block128_f)aesni_encrypt; + if (mode == EVP_CIPH_CBC_MODE) { + dat->stream.cbc = (cbc128_f)aesni_cbc_encrypt; + } else if (mode == EVP_CIPH_CTR_MODE) { + dat->stream.ctr = (ctr128_f)aesni_ctr32_encrypt_blocks; + } else { + dat->stream.cbc = NULL; + } + } + + if (ret < 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_AES_KEY_SETUP_FAILED); + return 0; + } + + return 1; +} + +static int aesni_cbc_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, + const uint8_t *in, size_t len) { + aesni_cbc_encrypt(in, out, len, ctx->cipher_data, ctx->iv, ctx->encrypt); + + return 1; +} + +static int aesni_ecb_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, + const uint8_t *in, size_t len) { + size_t bl = ctx->cipher->block_size; + + if (len < bl) { + return 1; + } + + aesni_ecb_encrypt(in, out, len, ctx->cipher_data, ctx->encrypt); + + return 1; +} + +static int aesni_gcm_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key, + const uint8_t *iv, int enc) { + EVP_AES_GCM_CTX *gctx = ctx->cipher_data; + if (!iv && !key) { + return 1; + } + if (key) { + aesni_set_encrypt_key(key, ctx->key_len * 8, &gctx->ks.ks); + CRYPTO_gcm128_init(&gctx->gcm, &gctx->ks, (block128_f)aesni_encrypt); + gctx->ctr = (ctr128_f)aesni_ctr32_encrypt_blocks; + /* If we have an iv can set it directly, otherwise use + * saved IV. */ + if (iv == NULL && gctx->iv_set) { + iv = gctx->iv; + } + if (iv) { + CRYPTO_gcm128_setiv(&gctx->gcm, iv, gctx->ivlen); + gctx->iv_set = 1; + } + gctx->key_set = 1; + } else { + /* If key set use IV, otherwise copy */ + if (gctx->key_set) { + CRYPTO_gcm128_setiv(&gctx->gcm, iv, gctx->ivlen); + } else { + memcpy(gctx->iv, iv, gctx->ivlen); + } + gctx->iv_set = 1; + gctx->iv_gen = 0; + } + return 1; +} + +static const EVP_CIPHER aesni_128_cbc = { + NID_aes_128_cbc, 16 /* block_size */, 16 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CBC_MODE, + NULL /* app_data */, aesni_init_key, aesni_cbc_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aesni_128_ctr = { + NID_aes_128_ctr, 1 /* block_size */, 16 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CTR_MODE, + NULL /* app_data */, aesni_init_key, aes_ctr_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aesni_128_ecb = { + NID_aes_128_ecb, 16 /* block_size */, 16 /* key_size */, + 0 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_ECB_MODE, + NULL /* app_data */, aesni_init_key, aesni_ecb_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aesni_128_ofb = { + NID_aes_128_ofb128, 1 /* block_size */, 16 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_OFB_MODE, + NULL /* app_data */, aesni_init_key, aes_ofb_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aesni_128_gcm = { + NID_aes_128_gcm, 1 /* block_size */, 16 /* key_size */, 12 /* iv_len */, + sizeof(EVP_AES_GCM_CTX), + EVP_CIPH_GCM_MODE | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER | + EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT | + EVP_CIPH_FLAG_AEAD_CIPHER, + NULL /* app_data */, aesni_gcm_init_key, aes_gcm_cipher, aes_gcm_cleanup, + aes_gcm_ctrl}; + + +static const EVP_CIPHER aesni_192_cbc = { + NID_aes_192_cbc, 16 /* block_size */, 24 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CBC_MODE, + NULL /* app_data */, aesni_init_key, aesni_cbc_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aesni_192_ctr = { + NID_aes_192_ctr, 1 /* block_size */, 24 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CTR_MODE, + NULL /* app_data */, aesni_init_key, aes_ctr_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aesni_192_ecb = { + NID_aes_192_ecb, 16 /* block_size */, 24 /* key_size */, + 0 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_ECB_MODE, + NULL /* app_data */, aesni_init_key, aesni_ecb_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aesni_192_gcm = { + NID_aes_192_gcm, 1 /* block_size */, 24 /* key_size */, 12 /* iv_len */, + sizeof(EVP_AES_GCM_CTX), + EVP_CIPH_GCM_MODE | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER | + EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT | + EVP_CIPH_FLAG_AEAD_CIPHER, + NULL /* app_data */, aesni_gcm_init_key, aes_gcm_cipher, aes_gcm_cleanup, + aes_gcm_ctrl}; + + +static const EVP_CIPHER aesni_256_cbc = { + NID_aes_256_cbc, 16 /* block_size */, 32 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CBC_MODE, + NULL /* app_data */, aesni_init_key, aesni_cbc_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aesni_256_ctr = { + NID_aes_256_ctr, 1 /* block_size */, 32 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CTR_MODE, + NULL /* app_data */, aesni_init_key, aes_ctr_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aesni_256_ecb = { + NID_aes_256_ecb, 16 /* block_size */, 32 /* key_size */, + 0 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_ECB_MODE, + NULL /* app_data */, aesni_init_key, aesni_ecb_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aesni_256_ofb = { + NID_aes_256_ofb128, 1 /* block_size */, 32 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_OFB_MODE, + NULL /* app_data */, aesni_init_key, aes_ofb_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aesni_256_gcm = { + NID_aes_256_gcm, 1 /* block_size */, 32 /* key_size */, 12 /* iv_len */, + sizeof(EVP_AES_GCM_CTX), + EVP_CIPH_GCM_MODE | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER | + EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT | EVP_CIPH_CUSTOM_COPY | + EVP_CIPH_FLAG_AEAD_CIPHER, + NULL /* app_data */, aesni_gcm_init_key, aes_gcm_cipher, aes_gcm_cleanup, + aes_gcm_ctrl}; + +#define EVP_CIPHER_FUNCTION(keybits, mode) \ + const EVP_CIPHER *EVP_aes_##keybits##_##mode(void) { \ + if (aesni_capable()) { \ + return &aesni_##keybits##_##mode; \ + } else { \ + return &aes_##keybits##_##mode; \ + } \ + } + +#else /* ^^^ OPENSSL_X86_64 || OPENSSL_X86 */ + +static char aesni_capable(void) { + return 0; +} + +#define EVP_CIPHER_FUNCTION(keybits, mode) \ + const EVP_CIPHER *EVP_aes_##keybits##_##mode(void) { \ + return &aes_##keybits##_##mode; \ + } + +#endif + +EVP_CIPHER_FUNCTION(128, cbc) +EVP_CIPHER_FUNCTION(128, ctr) +EVP_CIPHER_FUNCTION(128, ecb) +EVP_CIPHER_FUNCTION(128, ofb) +EVP_CIPHER_FUNCTION(128, gcm) + +EVP_CIPHER_FUNCTION(192, cbc) +EVP_CIPHER_FUNCTION(192, ctr) +EVP_CIPHER_FUNCTION(192, ecb) +EVP_CIPHER_FUNCTION(192, gcm) + +EVP_CIPHER_FUNCTION(256, cbc) +EVP_CIPHER_FUNCTION(256, ctr) +EVP_CIPHER_FUNCTION(256, ecb) +EVP_CIPHER_FUNCTION(256, ofb) +EVP_CIPHER_FUNCTION(256, gcm) + + +#define EVP_AEAD_AES_GCM_TAG_LEN 16 + +struct aead_aes_gcm_ctx { + union { + double align; + AES_KEY ks; + } ks; + GCM128_CONTEXT gcm; + ctr128_f ctr; + uint8_t tag_len; +}; + +static int aead_aes_gcm_init(EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t tag_len) { + struct aead_aes_gcm_ctx *gcm_ctx; + const size_t key_bits = key_len * 8; + + if (key_bits != 128 && key_bits != 256) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH); + return 0; /* EVP_AEAD_CTX_init should catch this. */ + } + + if (tag_len == EVP_AEAD_DEFAULT_TAG_LENGTH) { + tag_len = EVP_AEAD_AES_GCM_TAG_LEN; + } + + if (tag_len > EVP_AEAD_AES_GCM_TAG_LEN) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TAG_TOO_LARGE); + return 0; + } + + gcm_ctx = OPENSSL_malloc(sizeof(struct aead_aes_gcm_ctx)); + if (gcm_ctx == NULL) { + return 0; + } + + gcm_ctx->ctr = + aes_ctr_set_key(&gcm_ctx->ks.ks, &gcm_ctx->gcm, NULL, key, key_len); + gcm_ctx->tag_len = tag_len; + ctx->aead_state = gcm_ctx; + + return 1; +} + +static void aead_aes_gcm_cleanup(EVP_AEAD_CTX *ctx) { + struct aead_aes_gcm_ctx *gcm_ctx = ctx->aead_state; + OPENSSL_cleanse(gcm_ctx, sizeof(struct aead_aes_gcm_ctx)); + OPENSSL_free(gcm_ctx); +} + +static int aead_aes_gcm_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + size_t bulk = 0; + const struct aead_aes_gcm_ctx *gcm_ctx = ctx->aead_state; + GCM128_CONTEXT gcm; + + if (in_len + gcm_ctx->tag_len < in_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (max_out_len < in_len + gcm_ctx->tag_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + memcpy(&gcm, &gcm_ctx->gcm, sizeof(gcm)); + CRYPTO_gcm128_setiv(&gcm, nonce, nonce_len); + + if (ad_len > 0 && !CRYPTO_gcm128_aad(&gcm, ad, ad_len)) { + return 0; + } + + if (gcm_ctx->ctr) { + if (!CRYPTO_gcm128_encrypt_ctr32(&gcm, in + bulk, out + bulk, in_len - bulk, + gcm_ctx->ctr)) { + return 0; + } + } else { + if (!CRYPTO_gcm128_encrypt(&gcm, in + bulk, out + bulk, in_len - bulk)) { + return 0; + } + } + + CRYPTO_gcm128_tag(&gcm, out + in_len, gcm_ctx->tag_len); + *out_len = in_len + gcm_ctx->tag_len; + return 1; +} + +static int aead_aes_gcm_open(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + size_t bulk = 0; + const struct aead_aes_gcm_ctx *gcm_ctx = ctx->aead_state; + uint8_t tag[EVP_AEAD_AES_GCM_TAG_LEN]; + size_t plaintext_len; + GCM128_CONTEXT gcm; + + if (in_len < gcm_ctx->tag_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + plaintext_len = in_len - gcm_ctx->tag_len; + + if (max_out_len < plaintext_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + memcpy(&gcm, &gcm_ctx->gcm, sizeof(gcm)); + CRYPTO_gcm128_setiv(&gcm, nonce, nonce_len); + + if (!CRYPTO_gcm128_aad(&gcm, ad, ad_len)) { + return 0; + } + + if (gcm_ctx->ctr) { + if (!CRYPTO_gcm128_decrypt_ctr32(&gcm, in + bulk, out + bulk, + in_len - bulk - gcm_ctx->tag_len, + gcm_ctx->ctr)) { + return 0; + } + } else { + if (!CRYPTO_gcm128_decrypt(&gcm, in + bulk, out + bulk, + in_len - bulk - gcm_ctx->tag_len)) { + return 0; + } + } + + CRYPTO_gcm128_tag(&gcm, tag, gcm_ctx->tag_len); + if (CRYPTO_memcmp(tag, in + plaintext_len, gcm_ctx->tag_len) != 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + *out_len = plaintext_len; + return 1; +} + +static const EVP_AEAD aead_aes_128_gcm = { + 16, /* key len */ + 12, /* nonce len */ + EVP_AEAD_AES_GCM_TAG_LEN, /* overhead */ + EVP_AEAD_AES_GCM_TAG_LEN, /* max tag length */ + aead_aes_gcm_init, + NULL, /* init_with_direction */ + aead_aes_gcm_cleanup, + aead_aes_gcm_seal, + aead_aes_gcm_open, + NULL, /* get_rc4_state */ +}; + +static const EVP_AEAD aead_aes_256_gcm = { + 32, /* key len */ + 12, /* nonce len */ + EVP_AEAD_AES_GCM_TAG_LEN, /* overhead */ + EVP_AEAD_AES_GCM_TAG_LEN, /* max tag length */ + aead_aes_gcm_init, + NULL, /* init_with_direction */ + aead_aes_gcm_cleanup, + aead_aes_gcm_seal, + aead_aes_gcm_open, + NULL, /* get_rc4_state */ +}; + +const EVP_AEAD *EVP_aead_aes_128_gcm(void) { return &aead_aes_128_gcm; } + +const EVP_AEAD *EVP_aead_aes_256_gcm(void) { return &aead_aes_256_gcm; } + + +/* AES Key Wrap is specified in + * http://csrc.nist.gov/groups/ST/toolkit/documents/kms/key-wrap.pdf + * or https://tools.ietf.org/html/rfc3394 */ + +struct aead_aes_key_wrap_ctx { + uint8_t key[32]; + unsigned key_bits; +}; + +static int aead_aes_key_wrap_init(EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t tag_len) { + struct aead_aes_key_wrap_ctx *kw_ctx; + const size_t key_bits = key_len * 8; + + if (key_bits != 128 && key_bits != 256) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH); + return 0; /* EVP_AEAD_CTX_init should catch this. */ + } + + if (tag_len == EVP_AEAD_DEFAULT_TAG_LENGTH) { + tag_len = 8; + } + + if (tag_len != 8) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_TAG_SIZE); + return 0; + } + + kw_ctx = OPENSSL_malloc(sizeof(struct aead_aes_key_wrap_ctx)); + if (kw_ctx == NULL) { + OPENSSL_PUT_ERROR(CIPHER, ERR_R_MALLOC_FAILURE); + return 0; + } + + memcpy(kw_ctx->key, key, key_len); + kw_ctx->key_bits = key_bits; + + ctx->aead_state = kw_ctx; + return 1; +} + +static void aead_aes_key_wrap_cleanup(EVP_AEAD_CTX *ctx) { + struct aead_aes_key_wrap_ctx *kw_ctx = ctx->aead_state; + OPENSSL_cleanse(kw_ctx, sizeof(struct aead_aes_key_wrap_ctx)); + OPENSSL_free(kw_ctx); +} + +/* kDefaultAESKeyWrapNonce is the default nonce value given in 2.2.3.1. */ +static const uint8_t kDefaultAESKeyWrapNonce[8] = {0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6}; + + +static int aead_aes_key_wrap_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + const struct aead_aes_key_wrap_ctx *kw_ctx = ctx->aead_state; + union { + double align; + AES_KEY ks; + } ks; + /* Variables in this function match up with the variables in the second half + * of section 2.2.1. */ + unsigned i, j, n; + uint8_t A[AES_BLOCK_SIZE]; + + if (ad_len != 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_AD_SIZE); + return 0; + } + + if (nonce_len == 0) { + nonce = kDefaultAESKeyWrapNonce; + nonce_len = sizeof(kDefaultAESKeyWrapNonce); + } + + if (nonce_len != 8) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE); + return 0; + } + + if (in_len % 8 != 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_INPUT_SIZE); + return 0; + } + + /* The code below only handles a 32-bit |t| thus 6*|n| must be less than + * 2^32, where |n| is |in_len| / 8. So in_len < 4/3 * 2^32 and we + * conservatively cap it to 2^32-16 to stop 32-bit platforms complaining that + * a comparison is always true. */ + if (in_len > 0xfffffff0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + n = in_len / 8; + + if (n < 2) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_INPUT_SIZE); + return 0; + } + + if (in_len + 8 < in_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (max_out_len < in_len + 8) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + if (AES_set_encrypt_key(kw_ctx->key, kw_ctx->key_bits, &ks.ks) < 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_AES_KEY_SETUP_FAILED); + return 0; + } + + memmove(out + 8, in, in_len); + memcpy(A, nonce, 8); + + for (j = 0; j < 6; j++) { + for (i = 1; i <= n; i++) { + uint32_t t; + + memcpy(A + 8, out + 8 * i, 8); + AES_encrypt(A, A, &ks.ks); + t = n * j + i; + A[7] ^= t & 0xff; + A[6] ^= (t >> 8) & 0xff; + A[5] ^= (t >> 16) & 0xff; + A[4] ^= (t >> 24) & 0xff; + memcpy(out + 8 * i, A + 8, 8); + } + } + + memcpy(out, A, 8); + *out_len = in_len + 8; + return 1; +} + +static int aead_aes_key_wrap_open(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + const struct aead_aes_key_wrap_ctx *kw_ctx = ctx->aead_state; + union { + double align; + AES_KEY ks; + } ks; + /* Variables in this function match up with the variables in the second half + * of section 2.2.1. */ + unsigned i, j, n; + uint8_t A[AES_BLOCK_SIZE]; + + if (ad_len != 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_AD_SIZE); + return 0; + } + + if (nonce_len == 0) { + nonce = kDefaultAESKeyWrapNonce; + nonce_len = sizeof(kDefaultAESKeyWrapNonce); + } + + if (nonce_len != 8) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE); + return 0; + } + + if (in_len % 8 != 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_INPUT_SIZE); + return 0; + } + + /* The code below only handles a 32-bit |t| thus 6*|n| must be less than + * 2^32, where |n| is |in_len| / 8. So in_len < 4/3 * 2^32 and we + * conservatively cap it to 2^32-8 to stop 32-bit platforms complaining that + * a comparison is always true. */ + if (in_len > 0xfffffff8) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (in_len < 24) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + n = (in_len / 8) - 1; + + if (max_out_len < in_len - 8) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + if (AES_set_decrypt_key(kw_ctx->key, kw_ctx->key_bits, &ks.ks) < 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_AES_KEY_SETUP_FAILED); + return 0; + } + + memcpy(A, in, 8); + memmove(out, in + 8, in_len - 8); + + for (j = 5; j < 6; j--) { + for (i = n; i > 0; i--) { + uint32_t t; + + t = n * j + i; + A[7] ^= t & 0xff; + A[6] ^= (t >> 8) & 0xff; + A[5] ^= (t >> 16) & 0xff; + A[4] ^= (t >> 24) & 0xff; + memcpy(A + 8, out + 8 * (i - 1), 8); + AES_decrypt(A, A, &ks.ks); + memcpy(out + 8 * (i - 1), A + 8, 8); + } + } + + if (CRYPTO_memcmp(A, nonce, 8) != 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + *out_len = in_len - 8; + return 1; +} + +static const EVP_AEAD aead_aes_128_key_wrap = { + 16, /* key len */ + 8, /* nonce len */ + 8, /* overhead */ + 8, /* max tag length */ + aead_aes_key_wrap_init, + NULL, /* init_with_direction */ + aead_aes_key_wrap_cleanup, + aead_aes_key_wrap_seal, + aead_aes_key_wrap_open, + NULL, /* get_rc4_state */ +}; + +static const EVP_AEAD aead_aes_256_key_wrap = { + 32, /* key len */ + 8, /* nonce len */ + 8, /* overhead */ + 8, /* max tag length */ + aead_aes_key_wrap_init, + NULL, /* init_with_direction */ + aead_aes_key_wrap_cleanup, + aead_aes_key_wrap_seal, + aead_aes_key_wrap_open, + NULL, /* get_rc4_state */ +}; + +const EVP_AEAD *EVP_aead_aes_128_key_wrap(void) { return &aead_aes_128_key_wrap; } + +const EVP_AEAD *EVP_aead_aes_256_key_wrap(void) { return &aead_aes_256_key_wrap; } + + +#define EVP_AEAD_AES_CTR_HMAC_SHA256_TAG_LEN SHA256_DIGEST_LENGTH +#define EVP_AEAD_AES_CTR_HMAC_SHA256_NONCE_LEN 12 + +struct aead_aes_ctr_hmac_sha256_ctx { + union { + double align; + AES_KEY ks; + } ks; + ctr128_f ctr; + block128_f block; + SHA256_CTX inner_init_state; + SHA256_CTX outer_init_state; + uint8_t tag_len; +}; + +static void hmac_init(SHA256_CTX *out_inner, SHA256_CTX *out_outer, + const uint8_t hmac_key[32]) { + static const size_t hmac_key_len = 32; + uint8_t block[SHA256_CBLOCK]; + memcpy(block, hmac_key, hmac_key_len); + memset(block + hmac_key_len, 0x36, sizeof(block) - hmac_key_len); + + unsigned i; + for (i = 0; i < hmac_key_len; i++) { + block[i] ^= 0x36; + } + + SHA256_Init(out_inner); + SHA256_Update(out_inner, block, sizeof(block)); + + memset(block + hmac_key_len, 0x5c, sizeof(block) - hmac_key_len); + for (i = 0; i < hmac_key_len; i++) { + block[i] ^= (0x36 ^ 0x5c); + } + + SHA256_Init(out_outer); + SHA256_Update(out_outer, block, sizeof(block)); +} + +static int aead_aes_ctr_hmac_sha256_init(EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t tag_len) { + struct aead_aes_ctr_hmac_sha256_ctx *aes_ctx; + static const size_t hmac_key_len = 32; + + if (key_len < hmac_key_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH); + return 0; /* EVP_AEAD_CTX_init should catch this. */ + } + + const size_t aes_key_len = key_len - hmac_key_len; + if (aes_key_len != 16 && aes_key_len != 32) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH); + return 0; /* EVP_AEAD_CTX_init should catch this. */ + } + + if (tag_len == EVP_AEAD_DEFAULT_TAG_LENGTH) { + tag_len = EVP_AEAD_AES_CTR_HMAC_SHA256_TAG_LEN; + } + + if (tag_len > EVP_AEAD_AES_CTR_HMAC_SHA256_TAG_LEN) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TAG_TOO_LARGE); + return 0; + } + + aes_ctx = OPENSSL_malloc(sizeof(struct aead_aes_ctr_hmac_sha256_ctx)); + if (aes_ctx == NULL) { + OPENSSL_PUT_ERROR(CIPHER, ERR_R_MALLOC_FAILURE); + return 0; + } + + aes_ctx->ctr = + aes_ctr_set_key(&aes_ctx->ks.ks, NULL, &aes_ctx->block, key, aes_key_len); + aes_ctx->tag_len = tag_len; + hmac_init(&aes_ctx->inner_init_state, &aes_ctx->outer_init_state, + key + aes_key_len); + + ctx->aead_state = aes_ctx; + + return 1; +} + +static void aead_aes_ctr_hmac_sha256_cleanup(EVP_AEAD_CTX *ctx) { + struct aead_aes_ctr_hmac_sha256_ctx *aes_ctx = ctx->aead_state; + OPENSSL_cleanse(aes_ctx, sizeof(struct aead_aes_ctr_hmac_sha256_ctx)); + OPENSSL_free(aes_ctx); +} + +static void hmac_update_uint64(SHA256_CTX *sha256, uint64_t value) { + unsigned i; + uint8_t bytes[8]; + + for (i = 0; i < sizeof(bytes); i++) { + bytes[i] = value & 0xff; + value >>= 8; + } + SHA256_Update(sha256, bytes, sizeof(bytes)); +} + +static void hmac_calculate(uint8_t out[SHA256_DIGEST_LENGTH], + const SHA256_CTX *inner_init_state, + const SHA256_CTX *outer_init_state, + const uint8_t *ad, size_t ad_len, + const uint8_t *nonce, const uint8_t *ciphertext, + size_t ciphertext_len) { + SHA256_CTX sha256; + memcpy(&sha256, inner_init_state, sizeof(sha256)); + hmac_update_uint64(&sha256, ad_len); + hmac_update_uint64(&sha256, ciphertext_len); + SHA256_Update(&sha256, nonce, EVP_AEAD_AES_CTR_HMAC_SHA256_NONCE_LEN); + SHA256_Update(&sha256, ad, ad_len); + + /* Pad with zeros to the end of the SHA-256 block. */ + const unsigned num_padding = + (SHA256_CBLOCK - ((sizeof(uint64_t)*2 + + EVP_AEAD_AES_CTR_HMAC_SHA256_NONCE_LEN + ad_len) % + SHA256_CBLOCK)) % + SHA256_CBLOCK; + uint8_t padding[SHA256_CBLOCK]; + memset(padding, 0, num_padding); + SHA256_Update(&sha256, padding, num_padding); + + SHA256_Update(&sha256, ciphertext, ciphertext_len); + + uint8_t inner_digest[SHA256_DIGEST_LENGTH]; + SHA256_Final(inner_digest, &sha256); + + memcpy(&sha256, outer_init_state, sizeof(sha256)); + SHA256_Update(&sha256, inner_digest, sizeof(inner_digest)); + SHA256_Final(out, &sha256); +} + +static void aead_aes_ctr_hmac_sha256_crypt( + const struct aead_aes_ctr_hmac_sha256_ctx *aes_ctx, uint8_t *out, + const uint8_t *in, size_t len, const uint8_t *nonce) { + /* Since the AEAD operation is one-shot, keeping a buffer of unused keystream + * bytes is pointless. However, |CRYPTO_ctr128_encrypt| requires it. */ + uint8_t partial_block_buffer[AES_BLOCK_SIZE]; + unsigned partial_block_offset = 0; + memset(partial_block_buffer, 0, sizeof(partial_block_buffer)); + + uint8_t counter[AES_BLOCK_SIZE]; + memcpy(counter, nonce, EVP_AEAD_AES_CTR_HMAC_SHA256_NONCE_LEN); + memset(counter + EVP_AEAD_AES_CTR_HMAC_SHA256_NONCE_LEN, 0, 4); + + if (aes_ctx->ctr) { + CRYPTO_ctr128_encrypt_ctr32(in, out, len, &aes_ctx->ks.ks, counter, + partial_block_buffer, &partial_block_offset, + aes_ctx->ctr); + } else { + CRYPTO_ctr128_encrypt(in, out, len, &aes_ctx->ks.ks, counter, + partial_block_buffer, &partial_block_offset, + aes_ctx->block); + } +} + +static int aead_aes_ctr_hmac_sha256_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + const struct aead_aes_ctr_hmac_sha256_ctx *aes_ctx = ctx->aead_state; + const uint64_t in_len_64 = in_len; + + if (in_len + aes_ctx->tag_len < in_len || + /* This input is so large it would overflow the 32-bit block counter. */ + in_len_64 >= (OPENSSL_U64(1) << 32) * AES_BLOCK_SIZE) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (max_out_len < in_len + aes_ctx->tag_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + if (nonce_len != EVP_AEAD_AES_CTR_HMAC_SHA256_NONCE_LEN) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE); + return 0; + } + + aead_aes_ctr_hmac_sha256_crypt(aes_ctx, out, in, in_len, nonce); + + uint8_t hmac_result[SHA256_DIGEST_LENGTH]; + hmac_calculate(hmac_result, &aes_ctx->inner_init_state, + &aes_ctx->outer_init_state, ad, ad_len, nonce, out, in_len); + memcpy(out + in_len, hmac_result, aes_ctx->tag_len); + *out_len = in_len + aes_ctx->tag_len; + + return 1; +} + +static int aead_aes_ctr_hmac_sha256_open(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + const struct aead_aes_ctr_hmac_sha256_ctx *aes_ctx = ctx->aead_state; + size_t plaintext_len; + + if (in_len < aes_ctx->tag_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + plaintext_len = in_len - aes_ctx->tag_len; + + if (max_out_len < plaintext_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + if (nonce_len != EVP_AEAD_AES_CTR_HMAC_SHA256_NONCE_LEN) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE); + return 0; + } + + uint8_t hmac_result[SHA256_DIGEST_LENGTH]; + hmac_calculate(hmac_result, &aes_ctx->inner_init_state, + &aes_ctx->outer_init_state, ad, ad_len, nonce, in, + plaintext_len); + if (CRYPTO_memcmp(hmac_result, in + plaintext_len, aes_ctx->tag_len) != 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + aead_aes_ctr_hmac_sha256_crypt(aes_ctx, out, in, plaintext_len, nonce); + + *out_len = plaintext_len; + return 1; +} + +static const EVP_AEAD aead_aes_128_ctr_hmac_sha256 = { + 16 /* AES key */ + 32 /* HMAC key */, + 12, /* nonce length */ + EVP_AEAD_AES_CTR_HMAC_SHA256_TAG_LEN, /* overhead */ + EVP_AEAD_AES_CTR_HMAC_SHA256_TAG_LEN, /* max tag length */ + + aead_aes_ctr_hmac_sha256_init, + NULL /* init_with_direction */, + aead_aes_ctr_hmac_sha256_cleanup, + aead_aes_ctr_hmac_sha256_seal, + aead_aes_ctr_hmac_sha256_open, + NULL /* get_rc4_state */, +}; + +static const EVP_AEAD aead_aes_256_ctr_hmac_sha256 = { + 32 /* AES key */ + 32 /* HMAC key */, + 12, /* nonce length */ + EVP_AEAD_AES_CTR_HMAC_SHA256_TAG_LEN, /* overhead */ + EVP_AEAD_AES_CTR_HMAC_SHA256_TAG_LEN, /* max tag length */ + + aead_aes_ctr_hmac_sha256_init, + NULL /* init_with_direction */, + aead_aes_ctr_hmac_sha256_cleanup, + aead_aes_ctr_hmac_sha256_seal, + aead_aes_ctr_hmac_sha256_open, + NULL /* get_rc4_state */, +}; + +const EVP_AEAD *EVP_aead_aes_128_ctr_hmac_sha256(void) { + return &aead_aes_128_ctr_hmac_sha256; +} + +const EVP_AEAD *EVP_aead_aes_256_ctr_hmac_sha256(void) { + return &aead_aes_256_ctr_hmac_sha256; +} + +int EVP_has_aes_hardware(void) { +#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) + return aesni_capable() && crypto_gcm_clmul_enabled(); +#elif defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) + return hwaes_capable() && (OPENSSL_armcap_P & ARMV8_PMULL); +#else + return 0; +#endif +} diff --git a/TMessagesProj/jni/boringssl/crypto/cipher/e_chacha20poly1305.c b/TMessagesProj/jni/boringssl/crypto/cipher/e_chacha20poly1305.c new file mode 100644 index 00000000..9dda1b0c --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cipher/e_chacha20poly1305.c @@ -0,0 +1,220 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#include + +#include +#include +#include +#include +#include + +#include "internal.h" + + +#define POLY1305_TAG_LEN 16 +#define CHACHA20_NONCE_LEN 8 + +struct aead_chacha20_poly1305_ctx { + unsigned char key[32]; + unsigned char tag_len; +}; + +static int aead_chacha20_poly1305_init(EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t tag_len) { + struct aead_chacha20_poly1305_ctx *c20_ctx; + + if (tag_len == 0) { + tag_len = POLY1305_TAG_LEN; + } + + if (tag_len > POLY1305_TAG_LEN) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (key_len != sizeof(c20_ctx->key)) { + return 0; /* internal error - EVP_AEAD_CTX_init should catch this. */ + } + + c20_ctx = OPENSSL_malloc(sizeof(struct aead_chacha20_poly1305_ctx)); + if (c20_ctx == NULL) { + return 0; + } + + memcpy(c20_ctx->key, key, key_len); + c20_ctx->tag_len = tag_len; + ctx->aead_state = c20_ctx; + + return 1; +} + +static void aead_chacha20_poly1305_cleanup(EVP_AEAD_CTX *ctx) { + struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state; + OPENSSL_cleanse(c20_ctx->key, sizeof(c20_ctx->key)); + OPENSSL_free(c20_ctx); +} + +static void poly1305_update_with_length(poly1305_state *poly1305, + const uint8_t *data, size_t data_len) { + size_t j = data_len; + uint8_t length_bytes[8]; + unsigned i; + + for (i = 0; i < sizeof(length_bytes); i++) { + length_bytes[i] = j; + j >>= 8; + } + + CRYPTO_poly1305_update(poly1305, data, data_len); + CRYPTO_poly1305_update(poly1305, length_bytes, sizeof(length_bytes)); +} + +#if defined(__arm__) +#define ALIGNED __attribute__((aligned(16))) +#else +#define ALIGNED +#endif + +static int aead_chacha20_poly1305_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state; + uint8_t poly1305_key[32] ALIGNED; + poly1305_state poly1305; + const uint64_t in_len_64 = in_len; + + /* The underlying ChaCha implementation may not overflow the block + * counter into the second counter word. Therefore we disallow + * individual operations that work on more than 256GB at a time. + * |in_len_64| is needed because, on 32-bit platforms, size_t is only + * 32-bits and this produces a warning because it's always false. + * Casting to uint64_t inside the conditional is not sufficient to stop + * the warning. */ + if (in_len_64 >= (1ull << 32) * 64 - 64) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (in_len + c20_ctx->tag_len < in_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (max_out_len < in_len + c20_ctx->tag_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + if (nonce_len != CHACHA20_NONCE_LEN) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_IV_TOO_LARGE); + return 0; + } + + memset(poly1305_key, 0, sizeof(poly1305_key)); + CRYPTO_chacha_20(poly1305_key, poly1305_key, sizeof(poly1305_key), + c20_ctx->key, nonce, 0); + + CRYPTO_poly1305_init(&poly1305, poly1305_key); + poly1305_update_with_length(&poly1305, ad, ad_len); + CRYPTO_chacha_20(out, in, in_len, c20_ctx->key, nonce, 1); + poly1305_update_with_length(&poly1305, out, in_len); + + uint8_t tag[POLY1305_TAG_LEN] ALIGNED; + CRYPTO_poly1305_finish(&poly1305, tag); + memcpy(out + in_len, tag, c20_ctx->tag_len); + *out_len = in_len + c20_ctx->tag_len; + return 1; +} + +static int aead_chacha20_poly1305_open(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state; + uint8_t mac[POLY1305_TAG_LEN]; + uint8_t poly1305_key[32] ALIGNED; + size_t plaintext_len; + poly1305_state poly1305; + const uint64_t in_len_64 = in_len; + + if (in_len < c20_ctx->tag_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + /* The underlying ChaCha implementation may not overflow the block + * counter into the second counter word. Therefore we disallow + * individual operations that work on more than 256GB at a time. + * |in_len_64| is needed because, on 32-bit platforms, size_t is only + * 32-bits and this produces a warning because it's always false. + * Casting to uint64_t inside the conditional is not sufficient to stop + * the warning. */ + if (in_len_64 >= (1ull << 32) * 64 - 64) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (nonce_len != CHACHA20_NONCE_LEN) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_IV_TOO_LARGE); + return 0; + } + + plaintext_len = in_len - c20_ctx->tag_len; + + if (max_out_len < plaintext_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + memset(poly1305_key, 0, sizeof(poly1305_key)); + CRYPTO_chacha_20(poly1305_key, poly1305_key, sizeof(poly1305_key), + c20_ctx->key, nonce, 0); + + CRYPTO_poly1305_init(&poly1305, poly1305_key); + poly1305_update_with_length(&poly1305, ad, ad_len); + poly1305_update_with_length(&poly1305, in, plaintext_len); + CRYPTO_poly1305_finish(&poly1305, mac); + + if (CRYPTO_memcmp(mac, in + plaintext_len, c20_ctx->tag_len) != 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + CRYPTO_chacha_20(out, in, plaintext_len, c20_ctx->key, nonce, 1); + *out_len = plaintext_len; + return 1; +} + +static const EVP_AEAD aead_chacha20_poly1305 = { + 32, /* key len */ + CHACHA20_NONCE_LEN, /* nonce len */ + POLY1305_TAG_LEN, /* overhead */ + POLY1305_TAG_LEN, /* max tag length */ + aead_chacha20_poly1305_init, + NULL, /* init_with_direction */ + aead_chacha20_poly1305_cleanup, + aead_chacha20_poly1305_seal, + aead_chacha20_poly1305_open, + NULL, /* get_rc4_state */ +}; + +const EVP_AEAD *EVP_aead_chacha20_poly1305(void) { + return &aead_chacha20_poly1305; +} diff --git a/TMessagesProj/jni/boringssl/crypto/cipher/e_des.c b/TMessagesProj/jni/boringssl/crypto/cipher/e_des.c new file mode 100644 index 00000000..4c09a81f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cipher/e_des.c @@ -0,0 +1,135 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include + +#include "internal.h" + + +typedef struct { + union { + double align; + DES_key_schedule ks; + } ks; +} EVP_DES_KEY; + +static int des_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key, + const uint8_t *iv, int enc) { + DES_cblock *deskey = (DES_cblock *)key; + EVP_DES_KEY *dat = (EVP_DES_KEY *)ctx->cipher_data; + + DES_set_key(deskey, &dat->ks.ks); + return 1; +} + +static int des_cbc_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, + size_t in_len) { + EVP_DES_KEY *dat = (EVP_DES_KEY *)ctx->cipher_data; + + DES_ncbc_encrypt(in, out, in_len, &dat->ks.ks, (DES_cblock *)ctx->iv, + ctx->encrypt); + + return 1; +} + +static const EVP_CIPHER des_cbc = { + NID_des_cbc, 8 /* block_size */, 8 /* key_size */, + 8 /* iv_len */, sizeof(EVP_DES_KEY), EVP_CIPH_CBC_MODE, + NULL /* app_data */, des_init_key, des_cbc_cipher, + NULL /* cleanup */, NULL /* ctrl */, }; + +const EVP_CIPHER *EVP_des_cbc(void) { return &des_cbc; } + + +typedef struct { + union { + double align; + DES_key_schedule ks[3]; + } ks; +} DES_EDE_KEY; + + +static int des_ede3_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key, + const uint8_t *iv, int enc) { + DES_cblock *deskey = (DES_cblock *)key; + DES_EDE_KEY *dat = (DES_EDE_KEY*) ctx->cipher_data; + + DES_set_key(&deskey[0], &dat->ks.ks[0]); + DES_set_key(&deskey[1], &dat->ks.ks[1]); + DES_set_key(&deskey[2], &dat->ks.ks[2]); + + return 1; +} + +static int des_ede3_cbc_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, + const uint8_t *in, size_t in_len) { + DES_EDE_KEY *dat = (DES_EDE_KEY*) ctx->cipher_data; + + DES_ede3_cbc_encrypt(in, out, in_len, &dat->ks.ks[0], &dat->ks.ks[1], + &dat->ks.ks[2], (DES_cblock *)ctx->iv, ctx->encrypt); + + return 1; +} + +static const EVP_CIPHER des3_cbc = { + NID_des_ede3_cbc, 8 /* block_size */, 24 /* key_size */, + 8 /* iv_len */, sizeof(DES_EDE_KEY), EVP_CIPH_CBC_MODE, + NULL /* app_data */, des_ede3_init_key, des_ede3_cbc_cipher, + NULL /* cleanup */, NULL /* ctrl */, }; + +const EVP_CIPHER *EVP_des_ede3_cbc(void) { return &des3_cbc; } diff --git a/TMessagesProj/jni/boringssl/crypto/cipher/e_null.c b/TMessagesProj/jni/boringssl/crypto/cipher/e_null.c new file mode 100644 index 00000000..cfe1d1b2 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cipher/e_null.c @@ -0,0 +1,85 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include + +#include "internal.h" + + +static int null_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key, + const uint8_t *iv, int enc) { + return 1; +} + +static int null_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, + const uint8_t *in, size_t in_len) { + if (in != out) { + memcpy(out, in, in_len); + } + return 1; +} + +static const EVP_CIPHER n_cipher = { + NID_undef, 1 /* block size */, 0 /* key_len */, 0 /* iv_len */, + 0 /* ctx_size */, 0 /* flags */, NULL /* app_data */, null_init_key, + null_cipher, NULL /* cleanup */, NULL /* ctrl */, +}; + +const EVP_CIPHER *EVP_enc_null(void) { return &n_cipher; } diff --git a/TMessagesProj/jni/boringssl/crypto/cipher/e_rc2.c b/TMessagesProj/jni/boringssl/crypto/cipher/e_rc2.c new file mode 100644 index 00000000..8ca7bba6 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cipher/e_rc2.c @@ -0,0 +1,443 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include + +#include "internal.h" + + +#define c2l(c, l) \ + (l = ((uint32_t)(*((c)++))), l |= ((uint32_t)(*((c)++))) << 8L, \ + l |= ((uint32_t)(*((c)++))) << 16L, \ + l |= ((uint32_t)(*((c)++))) << 24L) + +#define c2ln(c, l1, l2, n) \ + { \ + c += n; \ + l1 = l2 = 0; \ + switch (n) { \ + case 8: \ + l2 = ((uint32_t)(*(--(c)))) << 24L; \ + case 7: \ + l2 |= ((uint32_t)(*(--(c)))) << 16L; \ + case 6: \ + l2 |= ((uint32_t)(*(--(c)))) << 8L; \ + case 5: \ + l2 |= ((uint32_t)(*(--(c)))); \ + case 4: \ + l1 = ((uint32_t)(*(--(c)))) << 24L; \ + case 3: \ + l1 |= ((uint32_t)(*(--(c)))) << 16L; \ + case 2: \ + l1 |= ((uint32_t)(*(--(c)))) << 8L; \ + case 1: \ + l1 |= ((uint32_t)(*(--(c)))); \ + } \ + } + +#define l2c(l, c) \ + (*((c)++) = (uint8_t)(((l)) & 0xff), \ + *((c)++) = (uint8_t)(((l) >> 8L) & 0xff), \ + *((c)++) = (uint8_t)(((l) >> 16L) & 0xff), \ + *((c)++) = (uint8_t)(((l) >> 24L) & 0xff)) + +#define l2cn(l1, l2, c, n) \ + { \ + c += n; \ + switch (n) { \ + case 8: \ + *(--(c)) = (uint8_t)(((l2) >> 24L) & 0xff); \ + case 7: \ + *(--(c)) = (uint8_t)(((l2) >> 16L) & 0xff); \ + case 6: \ + *(--(c)) = (uint8_t)(((l2) >> 8L) & 0xff); \ + case 5: \ + *(--(c)) = (uint8_t)(((l2)) & 0xff); \ + case 4: \ + *(--(c)) = (uint8_t)(((l1) >> 24L) & 0xff); \ + case 3: \ + *(--(c)) = (uint8_t)(((l1) >> 16L) & 0xff); \ + case 2: \ + *(--(c)) = (uint8_t)(((l1) >> 8L) & 0xff); \ + case 1: \ + *(--(c)) = (uint8_t)(((l1)) & 0xff); \ + } \ + } + +typedef struct rc2_key_st { uint16_t data[64]; } RC2_KEY; + +static void RC2_encrypt(uint32_t *d, RC2_KEY *key) { + int i, n; + uint16_t *p0, *p1; + uint16_t x0, x1, x2, x3, t; + uint32_t l; + + l = d[0]; + x0 = (uint16_t)l & 0xffff; + x1 = (uint16_t)(l >> 16L); + l = d[1]; + x2 = (uint16_t)l & 0xffff; + x3 = (uint16_t)(l >> 16L); + + n = 3; + i = 5; + + p0 = p1 = &key->data[0]; + for (;;) { + t = (x0 + (x1 & ~x3) + (x2 & x3) + *(p0++)) & 0xffff; + x0 = (t << 1) | (t >> 15); + t = (x1 + (x2 & ~x0) + (x3 & x0) + *(p0++)) & 0xffff; + x1 = (t << 2) | (t >> 14); + t = (x2 + (x3 & ~x1) + (x0 & x1) + *(p0++)) & 0xffff; + x2 = (t << 3) | (t >> 13); + t = (x3 + (x0 & ~x2) + (x1 & x2) + *(p0++)) & 0xffff; + x3 = (t << 5) | (t >> 11); + + if (--i == 0) { + if (--n == 0) { + break; + } + i = (n == 2) ? 6 : 5; + + x0 += p1[x3 & 0x3f]; + x1 += p1[x0 & 0x3f]; + x2 += p1[x1 & 0x3f]; + x3 += p1[x2 & 0x3f]; + } + } + + d[0] = (uint32_t)(x0 & 0xffff) | ((uint32_t)(x1 & 0xffff) << 16L); + d[1] = (uint32_t)(x2 & 0xffff) | ((uint32_t)(x3 & 0xffff) << 16L); +} + +static void RC2_decrypt(uint32_t *d, RC2_KEY *key) { + int i, n; + uint16_t *p0, *p1; + uint16_t x0, x1, x2, x3, t; + uint32_t l; + + l = d[0]; + x0 = (uint16_t)l & 0xffff; + x1 = (uint16_t)(l >> 16L); + l = d[1]; + x2 = (uint16_t)l & 0xffff; + x3 = (uint16_t)(l >> 16L); + + n = 3; + i = 5; + + p0 = &key->data[63]; + p1 = &key->data[0]; + for (;;) { + t = ((x3 << 11) | (x3 >> 5)) & 0xffff; + x3 = (t - (x0 & ~x2) - (x1 & x2) - *(p0--)) & 0xffff; + t = ((x2 << 13) | (x2 >> 3)) & 0xffff; + x2 = (t - (x3 & ~x1) - (x0 & x1) - *(p0--)) & 0xffff; + t = ((x1 << 14) | (x1 >> 2)) & 0xffff; + x1 = (t - (x2 & ~x0) - (x3 & x0) - *(p0--)) & 0xffff; + t = ((x0 << 15) | (x0 >> 1)) & 0xffff; + x0 = (t - (x1 & ~x3) - (x2 & x3) - *(p0--)) & 0xffff; + + if (--i == 0) { + if (--n == 0) { + break; + } + i = (n == 2) ? 6 : 5; + + x3 = (x3 - p1[x2 & 0x3f]) & 0xffff; + x2 = (x2 - p1[x1 & 0x3f]) & 0xffff; + x1 = (x1 - p1[x0 & 0x3f]) & 0xffff; + x0 = (x0 - p1[x3 & 0x3f]) & 0xffff; + } + } + + d[0] = (uint32_t)(x0 & 0xffff) | ((uint32_t)(x1 & 0xffff) << 16L); + d[1] = (uint32_t)(x2 & 0xffff) | ((uint32_t)(x3 & 0xffff) << 16L); +} + +static void RC2_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, + RC2_KEY *ks, uint8_t *iv, int encrypt) { + uint32_t tin0, tin1; + uint32_t tout0, tout1, xor0, xor1; + long l = length; + uint32_t tin[2]; + + if (encrypt) { + c2l(iv, tout0); + c2l(iv, tout1); + iv -= 8; + for (l -= 8; l >= 0; l -= 8) { + c2l(in, tin0); + c2l(in, tin1); + tin0 ^= tout0; + tin1 ^= tout1; + tin[0] = tin0; + tin[1] = tin1; + RC2_encrypt(tin, ks); + tout0 = tin[0]; + l2c(tout0, out); + tout1 = tin[1]; + l2c(tout1, out); + } + if (l != -8) { + c2ln(in, tin0, tin1, l + 8); + tin0 ^= tout0; + tin1 ^= tout1; + tin[0] = tin0; + tin[1] = tin1; + RC2_encrypt(tin, ks); + tout0 = tin[0]; + l2c(tout0, out); + tout1 = tin[1]; + l2c(tout1, out); + } + l2c(tout0, iv); + l2c(tout1, iv); + } else { + c2l(iv, xor0); + c2l(iv, xor1); + iv -= 8; + for (l -= 8; l >= 0; l -= 8) { + c2l(in, tin0); + tin[0] = tin0; + c2l(in, tin1); + tin[1] = tin1; + RC2_decrypt(tin, ks); + tout0 = tin[0] ^ xor0; + tout1 = tin[1] ^ xor1; + l2c(tout0, out); + l2c(tout1, out); + xor0 = tin0; + xor1 = tin1; + } + if (l != -8) { + c2l(in, tin0); + tin[0] = tin0; + c2l(in, tin1); + tin[1] = tin1; + RC2_decrypt(tin, ks); + tout0 = tin[0] ^ xor0; + tout1 = tin[1] ^ xor1; + l2cn(tout0, tout1, out, l + 8); + xor0 = tin0; + xor1 = tin1; + } + l2c(xor0, iv); + l2c(xor1, iv); + } + tin[0] = tin[1] = 0; +} + +static const uint8_t key_table[256] = { + 0xd9, 0x78, 0xf9, 0xc4, 0x19, 0xdd, 0xb5, 0xed, 0x28, 0xe9, 0xfd, 0x79, + 0x4a, 0xa0, 0xd8, 0x9d, 0xc6, 0x7e, 0x37, 0x83, 0x2b, 0x76, 0x53, 0x8e, + 0x62, 0x4c, 0x64, 0x88, 0x44, 0x8b, 0xfb, 0xa2, 0x17, 0x9a, 0x59, 0xf5, + 0x87, 0xb3, 0x4f, 0x13, 0x61, 0x45, 0x6d, 0x8d, 0x09, 0x81, 0x7d, 0x32, + 0xbd, 0x8f, 0x40, 0xeb, 0x86, 0xb7, 0x7b, 0x0b, 0xf0, 0x95, 0x21, 0x22, + 0x5c, 0x6b, 0x4e, 0x82, 0x54, 0xd6, 0x65, 0x93, 0xce, 0x60, 0xb2, 0x1c, + 0x73, 0x56, 0xc0, 0x14, 0xa7, 0x8c, 0xf1, 0xdc, 0x12, 0x75, 0xca, 0x1f, + 0x3b, 0xbe, 0xe4, 0xd1, 0x42, 0x3d, 0xd4, 0x30, 0xa3, 0x3c, 0xb6, 0x26, + 0x6f, 0xbf, 0x0e, 0xda, 0x46, 0x69, 0x07, 0x57, 0x27, 0xf2, 0x1d, 0x9b, + 0xbc, 0x94, 0x43, 0x03, 0xf8, 0x11, 0xc7, 0xf6, 0x90, 0xef, 0x3e, 0xe7, + 0x06, 0xc3, 0xd5, 0x2f, 0xc8, 0x66, 0x1e, 0xd7, 0x08, 0xe8, 0xea, 0xde, + 0x80, 0x52, 0xee, 0xf7, 0x84, 0xaa, 0x72, 0xac, 0x35, 0x4d, 0x6a, 0x2a, + 0x96, 0x1a, 0xd2, 0x71, 0x5a, 0x15, 0x49, 0x74, 0x4b, 0x9f, 0xd0, 0x5e, + 0x04, 0x18, 0xa4, 0xec, 0xc2, 0xe0, 0x41, 0x6e, 0x0f, 0x51, 0xcb, 0xcc, + 0x24, 0x91, 0xaf, 0x50, 0xa1, 0xf4, 0x70, 0x39, 0x99, 0x7c, 0x3a, 0x85, + 0x23, 0xb8, 0xb4, 0x7a, 0xfc, 0x02, 0x36, 0x5b, 0x25, 0x55, 0x97, 0x31, + 0x2d, 0x5d, 0xfa, 0x98, 0xe3, 0x8a, 0x92, 0xae, 0x05, 0xdf, 0x29, 0x10, + 0x67, 0x6c, 0xba, 0xc9, 0xd3, 0x00, 0xe6, 0xcf, 0xe1, 0x9e, 0xa8, 0x2c, + 0x63, 0x16, 0x01, 0x3f, 0x58, 0xe2, 0x89, 0xa9, 0x0d, 0x38, 0x34, 0x1b, + 0xab, 0x33, 0xff, 0xb0, 0xbb, 0x48, 0x0c, 0x5f, 0xb9, 0xb1, 0xcd, 0x2e, + 0xc5, 0xf3, 0xdb, 0x47, 0xe5, 0xa5, 0x9c, 0x77, 0x0a, 0xa6, 0x20, 0x68, + 0xfe, 0x7f, 0xc1, 0xad, +}; + +static void RC2_set_key(RC2_KEY *key, int len, const uint8_t *data, int bits) { + int i, j; + uint8_t *k; + uint16_t *ki; + unsigned int c, d; + + k = (uint8_t *)&key->data[0]; + *k = 0; /* for if there is a zero length key */ + + if (len > 128) { + len = 128; + } + if (bits <= 0) { + bits = 1024; + } + if (bits > 1024) { + bits = 1024; + } + + for (i = 0; i < len; i++) { + k[i] = data[i]; + } + + /* expand table */ + d = k[len - 1]; + j = 0; + for (i = len; i < 128; i++, j++) { + d = key_table[(k[j] + d) & 0xff]; + k[i] = d; + } + + /* hmm.... key reduction to 'bits' bits */ + + j = (bits + 7) >> 3; + i = 128 - j; + c = (0xff >> (-bits & 0x07)); + + d = key_table[k[i] & c]; + k[i] = d; + while (i--) { + d = key_table[k[i + j] ^ d]; + k[i] = d; + } + + /* copy from bytes into uint16_t's */ + ki = &(key->data[63]); + for (i = 127; i >= 0; i -= 2) { + *(ki--) = ((k[i] << 8) | k[i - 1]) & 0xffff; + } +} + +typedef struct { + int key_bits; /* effective key bits */ + RC2_KEY ks; /* key schedule */ +} EVP_RC2_KEY; + +static int rc2_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key, + const uint8_t *iv, int enc) { + EVP_RC2_KEY *rc2_key = (EVP_RC2_KEY *)ctx->cipher_data; + RC2_set_key(&rc2_key->ks, EVP_CIPHER_CTX_key_length(ctx), key, + rc2_key->key_bits); + return 1; +} + +static int rc2_cbc_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, + size_t inl) { + EVP_RC2_KEY *key = (EVP_RC2_KEY *)ctx->cipher_data; + static const size_t kChunkSize = 0x10000; + + while (inl >= kChunkSize) { + RC2_cbc_encrypt(in, out, kChunkSize, &key->ks, ctx->iv, ctx->encrypt); + inl -= kChunkSize; + in += kChunkSize; + out += kChunkSize; + } + if (inl) { + RC2_cbc_encrypt(in, out, inl, &key->ks, ctx->iv, ctx->encrypt); + } + return 1; +} + +static int rc2_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr) { + EVP_RC2_KEY *key = (EVP_RC2_KEY *)ctx->cipher_data; + + switch (type) { + case EVP_CTRL_INIT: + key->key_bits = EVP_CIPHER_CTX_key_length(ctx) * 8; + return 1; + case EVP_CTRL_SET_RC2_KEY_BITS: + /* Should be overridden by later call to |EVP_CTRL_INIT|, but + * people call it, so it may as well work. */ + key->key_bits = arg; + return 1; + + default: + return -1; + } +} + +static const EVP_CIPHER rc2_40_cbc = { + NID_rc2_40_cbc, + 8 /* block size */, + 5 /* 40 bit */, + 8 /* iv len */, + sizeof(EVP_RC2_KEY), + EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH | EVP_CIPH_CTRL_INIT, + NULL /* app_data */, + rc2_init_key, + rc2_cbc_cipher, + NULL, + rc2_ctrl, +}; + +const EVP_CIPHER *EVP_rc2_40_cbc(void) { + return &rc2_40_cbc; +} + +static const EVP_CIPHER rc2_cbc = { + NID_rc2_cbc, + 8 /* block size */, + 16 /* 128 bit */, + 8 /* iv len */, + sizeof(EVP_RC2_KEY), + EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH | EVP_CIPH_CTRL_INIT, + NULL /* app_data */, + rc2_init_key, + rc2_cbc_cipher, + NULL, + rc2_ctrl, +}; + +const EVP_CIPHER *EVP_rc2_cbc(void) { + return &rc2_cbc; +} diff --git a/TMessagesProj/jni/boringssl/crypto/cipher/e_rc4.c b/TMessagesProj/jni/boringssl/crypto/cipher/e_rc4.c new file mode 100644 index 00000000..e05b9fda --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cipher/e_rc4.c @@ -0,0 +1,397 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" + + +static int rc4_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key, + const uint8_t *iv, int enc) { + RC4_KEY *rc4key = (RC4_KEY *)ctx->cipher_data; + + RC4_set_key(rc4key, EVP_CIPHER_CTX_key_length(ctx), key); + return 1; +} + +static int rc4_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, + size_t in_len) { + RC4_KEY *rc4key = (RC4_KEY *)ctx->cipher_data; + + RC4(rc4key, in_len, in, out); + return 1; +} + +static const EVP_CIPHER rc4 = { + NID_rc4, 1 /* block_size */, 16 /* key_size */, + 0 /* iv_len */, sizeof(RC4_KEY), EVP_CIPH_VARIABLE_LENGTH, + NULL /* app_data */, rc4_init_key, rc4_cipher, + NULL /* cleanup */, NULL /* ctrl */, }; + +const EVP_CIPHER *EVP_rc4(void) { return &rc4; } + + +struct aead_rc4_md5_tls_ctx { + RC4_KEY rc4; + MD5_CTX head, tail, md; + size_t payload_length; + unsigned char tag_len; +}; + + +static int +aead_rc4_md5_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, + size_t tag_len) { + struct aead_rc4_md5_tls_ctx *rc4_ctx; + size_t i; + uint8_t hmac_key[MD5_CBLOCK]; + + if (tag_len == EVP_AEAD_DEFAULT_TAG_LENGTH) { + tag_len = MD5_DIGEST_LENGTH; + } + + if (tag_len > MD5_DIGEST_LENGTH) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + /* The keys consists of |MD5_DIGEST_LENGTH| bytes of HMAC(MD5) key followed + * by some number of bytes of RC4 key. */ + if (key_len <= MD5_DIGEST_LENGTH) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH); + return 0; + } + + rc4_ctx = OPENSSL_malloc(sizeof(struct aead_rc4_md5_tls_ctx)); + if (rc4_ctx == NULL) { + OPENSSL_PUT_ERROR(CIPHER, ERR_R_MALLOC_FAILURE); + return 0; + } + memset(rc4_ctx, 0, sizeof(struct aead_rc4_md5_tls_ctx)); + + RC4_set_key(&rc4_ctx->rc4, key_len - MD5_DIGEST_LENGTH, + key + MD5_DIGEST_LENGTH); + + memset(hmac_key, 0, sizeof(hmac_key)); + memcpy(hmac_key, key, MD5_DIGEST_LENGTH); + for (i = 0; i < sizeof(hmac_key); i++) { + hmac_key[i] ^= 0x36; + } + MD5_Init(&rc4_ctx->head); + MD5_Update(&rc4_ctx->head, hmac_key, sizeof(hmac_key)); + for (i = 0; i < sizeof(hmac_key); i++) { + hmac_key[i] ^= 0x36 ^ 0x5c; + } + MD5_Init(&rc4_ctx->tail); + MD5_Update(&rc4_ctx->tail, hmac_key, sizeof(hmac_key)); + + rc4_ctx->tag_len = tag_len; + ctx->aead_state = rc4_ctx; + + return 1; +} + +static void aead_rc4_md5_tls_cleanup(EVP_AEAD_CTX *ctx) { + struct aead_rc4_md5_tls_ctx *rc4_ctx = ctx->aead_state; + OPENSSL_cleanse(rc4_ctx, sizeof(struct aead_rc4_md5_tls_ctx)); + OPENSSL_free(rc4_ctx); +} + +#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) +#define STITCHED_CALL + +/* rc4_md5_enc is defined in rc4_md5-x86_64.pl */ +void rc4_md5_enc(RC4_KEY *key, const void *in0, void *out, MD5_CTX *ctx, + const void *inp, size_t blocks); +#endif + +static int aead_rc4_md5_tls_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + struct aead_rc4_md5_tls_ctx *rc4_ctx = ctx->aead_state; + MD5_CTX md; +#if defined(STITCHED_CALL) + size_t rc4_off, md5_off, blocks; +#else + const size_t rc4_off = 0; + const size_t md5_off = 0; +#endif + uint8_t digest[MD5_DIGEST_LENGTH]; + + if (in_len + rc4_ctx->tag_len < in_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (nonce_len != 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_IV_TOO_LARGE); + return 0; + } + + if (max_out_len < in_len + rc4_ctx->tag_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + if (nonce_len != 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + memcpy(&md, &rc4_ctx->head, sizeof(MD5_CTX)); + /* The MAC's payload begins with the additional data. See + * https://tools.ietf.org/html/rfc5246#section-6.2.3.1 */ + MD5_Update(&md, ad, ad_len); + + /* To allow for CBC mode which changes cipher length, |ad| doesn't include the + * length for legacy ciphers. */ + uint8_t ad_extra[2]; + ad_extra[0] = (uint8_t)(in_len >> 8); + ad_extra[1] = (uint8_t)(in_len & 0xff); + MD5_Update(&md, ad_extra, sizeof(ad_extra)); + +#if defined(STITCHED_CALL) + /* 32 is $MOD from rc4_md5-x86_64.pl. */ + rc4_off = 32 - 1 - (rc4_ctx->rc4.x & (32 - 1)); + md5_off = MD5_CBLOCK - md.num; + /* Ensure RC4 is behind MD5. */ + if (rc4_off > md5_off) { + md5_off += MD5_CBLOCK; + } + assert(md5_off >= rc4_off); + + if (in_len > md5_off && (blocks = (in_len - md5_off) / MD5_CBLOCK) && + (OPENSSL_ia32cap_P[0] & (1 << 20)) == 0) { + /* Process the initial portions of the plaintext normally. */ + MD5_Update(&md, in, md5_off); + RC4(&rc4_ctx->rc4, rc4_off, in, out); + + /* Process the next |blocks| blocks of plaintext with stitched routines. */ + rc4_md5_enc(&rc4_ctx->rc4, in + rc4_off, out + rc4_off, &md, in + md5_off, + blocks); + blocks *= MD5_CBLOCK; + rc4_off += blocks; + md5_off += blocks; + md.Nh += blocks >> 29; + md.Nl += blocks <<= 3; + if (md.Nl < (unsigned int)blocks) { + md.Nh++; + } + } else { + rc4_off = 0; + md5_off = 0; + } +#endif + /* Finish computing the MAC. */ + MD5_Update(&md, in + md5_off, in_len - md5_off); + MD5_Final(digest, &md); + + memcpy(&md, &rc4_ctx->tail, sizeof(MD5_CTX)); + MD5_Update(&md, digest, sizeof(digest)); + if (rc4_ctx->tag_len == MD5_DIGEST_LENGTH) { + MD5_Final(out + in_len, &md); + } else { + MD5_Final(digest, &md); + memcpy(out + in_len, digest, rc4_ctx->tag_len); + } + + /* Encrypt the remainder of the plaintext and the MAC. */ + RC4(&rc4_ctx->rc4, in_len - rc4_off, in + rc4_off, out + rc4_off); + RC4(&rc4_ctx->rc4, MD5_DIGEST_LENGTH, out + in_len, out + in_len); + + *out_len = in_len + rc4_ctx->tag_len; + return 1; +} + +static int aead_rc4_md5_tls_open(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + struct aead_rc4_md5_tls_ctx *rc4_ctx = ctx->aead_state; + MD5_CTX md; + size_t plaintext_len; +#if defined(STITCHED_CALL) + unsigned int l; + size_t rc4_off, md5_off, blocks; + extern unsigned int OPENSSL_ia32cap_P[]; +#else + const size_t rc4_off = 0; + const size_t md5_off = 0; +#endif + uint8_t digest[MD5_DIGEST_LENGTH]; + + if (in_len < rc4_ctx->tag_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + plaintext_len = in_len - rc4_ctx->tag_len; + + if (nonce_len != 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (max_out_len < in_len) { + /* This requires that the caller provide space for the MAC, even though it + * will always be removed on return. */ + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + memcpy(&md, &rc4_ctx->head, sizeof(MD5_CTX)); + /* The MAC's payload begins with the additional data. See + * https://tools.ietf.org/html/rfc5246#section-6.2.3.1 */ + MD5_Update(&md, ad, ad_len); + + /* To allow for CBC mode which changes cipher length, |ad| doesn't include the + * length for legacy ciphers. */ + uint8_t ad_extra[2]; + ad_extra[0] = (uint8_t)(plaintext_len >> 8); + ad_extra[1] = (uint8_t)(plaintext_len & 0xff); + MD5_Update(&md, ad_extra, sizeof(ad_extra)); + +#if defined(STITCHED_CALL) + rc4_off = 32 - 1 - (rc4_ctx->rc4.x & (32 - 1)); + md5_off = MD5_CBLOCK - md.num; + /* Ensure MD5 is a full block behind RC4 so it has plaintext to operate on in + * both normal and stitched routines. */ + if (md5_off > rc4_off) { + rc4_off += 2 * MD5_CBLOCK; + } else { + rc4_off += MD5_CBLOCK; + } + + if (in_len > rc4_off && (blocks = (in_len - rc4_off) / MD5_CBLOCK) && + (OPENSSL_ia32cap_P[0] & (1 << 20)) == 0) { + /* Decrypt the initial portion of the ciphertext and digest the plaintext + * normally. */ + RC4(&rc4_ctx->rc4, rc4_off, in, out); + MD5_Update(&md, out, md5_off); + + /* Decrypt and digest the next |blocks| blocks of ciphertext with the + * stitched routines. */ + rc4_md5_enc(&rc4_ctx->rc4, in + rc4_off, out + rc4_off, &md, out + md5_off, + blocks); + blocks *= MD5_CBLOCK; + rc4_off += blocks; + md5_off += blocks; + l = (md.Nl + (blocks << 3)) & 0xffffffffU; + if (l < md.Nl) { + md.Nh++; + } + md.Nl = l; + md.Nh += blocks >> 29; + } else { + md5_off = 0; + rc4_off = 0; + } +#endif + + /* Process the remainder of the input. */ + RC4(&rc4_ctx->rc4, in_len - rc4_off, in + rc4_off, out + rc4_off); + MD5_Update(&md, out + md5_off, plaintext_len - md5_off); + MD5_Final(digest, &md); + + /* Calculate HMAC and verify it */ + memcpy(&md, &rc4_ctx->tail, sizeof(MD5_CTX)); + MD5_Update(&md, digest, MD5_DIGEST_LENGTH); + MD5_Final(digest, &md); + + if (CRYPTO_memcmp(out + plaintext_len, digest, rc4_ctx->tag_len)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + *out_len = plaintext_len; + return 1; +} + +static int aead_rc4_md5_tls_get_rc4_state(const EVP_AEAD_CTX *ctx, + const RC4_KEY **out_key) { + struct aead_rc4_md5_tls_ctx *rc4_ctx = ctx->aead_state; + *out_key = &rc4_ctx->rc4; + return 1; +} + +static const EVP_AEAD aead_rc4_md5_tls = { + 16 + MD5_DIGEST_LENGTH, /* key len (RC4 + MD5) */ + 0, /* nonce len */ + MD5_DIGEST_LENGTH, /* overhead */ + MD5_DIGEST_LENGTH, /* max tag length */ + aead_rc4_md5_tls_init, + NULL, /* init_with_direction */ + aead_rc4_md5_tls_cleanup, + aead_rc4_md5_tls_seal, + aead_rc4_md5_tls_open, + aead_rc4_md5_tls_get_rc4_state, +}; + +const EVP_AEAD *EVP_aead_rc4_md5_tls(void) { return &aead_rc4_md5_tls; } diff --git a/TMessagesProj/jni/boringssl/crypto/cipher/e_ssl3.c b/TMessagesProj/jni/boringssl/crypto/cipher/e_ssl3.c new file mode 100644 index 00000000..a4b55c90 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cipher/e_ssl3.c @@ -0,0 +1,422 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" + + +typedef struct { + EVP_CIPHER_CTX cipher_ctx; + EVP_MD_CTX md_ctx; +} AEAD_SSL3_CTX; + +static int ssl3_mac(AEAD_SSL3_CTX *ssl3_ctx, uint8_t *out, unsigned *out_len, + const uint8_t *ad, size_t ad_len, const uint8_t *in, + size_t in_len) { + size_t md_size = EVP_MD_CTX_size(&ssl3_ctx->md_ctx); + size_t pad_len = (md_size == 20) ? 40 : 48; + + /* To allow for CBC mode which changes cipher length, |ad| doesn't include the + * length for legacy ciphers. */ + uint8_t ad_extra[2]; + ad_extra[0] = (uint8_t)(in_len >> 8); + ad_extra[1] = (uint8_t)(in_len & 0xff); + + EVP_MD_CTX md_ctx; + EVP_MD_CTX_init(&md_ctx); + + uint8_t pad[48]; + uint8_t tmp[EVP_MAX_MD_SIZE]; + memset(pad, 0x36, pad_len); + if (!EVP_MD_CTX_copy_ex(&md_ctx, &ssl3_ctx->md_ctx) || + !EVP_DigestUpdate(&md_ctx, pad, pad_len) || + !EVP_DigestUpdate(&md_ctx, ad, ad_len) || + !EVP_DigestUpdate(&md_ctx, ad_extra, sizeof(ad_extra)) || + !EVP_DigestUpdate(&md_ctx, in, in_len) || + !EVP_DigestFinal_ex(&md_ctx, tmp, NULL)) { + EVP_MD_CTX_cleanup(&md_ctx); + return 0; + } + + memset(pad, 0x5c, pad_len); + if (!EVP_MD_CTX_copy_ex(&md_ctx, &ssl3_ctx->md_ctx) || + !EVP_DigestUpdate(&md_ctx, pad, pad_len) || + !EVP_DigestUpdate(&md_ctx, tmp, md_size) || + !EVP_DigestFinal_ex(&md_ctx, out, out_len)) { + EVP_MD_CTX_cleanup(&md_ctx); + return 0; + } + EVP_MD_CTX_cleanup(&md_ctx); + return 1; +} + +static void aead_ssl3_cleanup(EVP_AEAD_CTX *ctx) { + AEAD_SSL3_CTX *ssl3_ctx = (AEAD_SSL3_CTX *)ctx->aead_state; + EVP_CIPHER_CTX_cleanup(&ssl3_ctx->cipher_ctx); + EVP_MD_CTX_cleanup(&ssl3_ctx->md_ctx); + OPENSSL_free(ssl3_ctx); + ctx->aead_state = NULL; +} + +static int aead_ssl3_init(EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, + size_t tag_len, enum evp_aead_direction_t dir, + const EVP_CIPHER *cipher, const EVP_MD *md) { + if (tag_len != EVP_AEAD_DEFAULT_TAG_LENGTH && + tag_len != EVP_MD_size(md)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_TAG_SIZE); + return 0; + } + + if (key_len != EVP_AEAD_key_length(ctx->aead)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH); + return 0; + } + + size_t mac_key_len = EVP_MD_size(md); + size_t enc_key_len = EVP_CIPHER_key_length(cipher); + assert(mac_key_len + enc_key_len + EVP_CIPHER_iv_length(cipher) == key_len); + /* Although EVP_rc4() is a variable-length cipher, the default key size is + * correct for SSL3. */ + + AEAD_SSL3_CTX *ssl3_ctx = OPENSSL_malloc(sizeof(AEAD_SSL3_CTX)); + if (ssl3_ctx == NULL) { + OPENSSL_PUT_ERROR(CIPHER, ERR_R_MALLOC_FAILURE); + return 0; + } + EVP_CIPHER_CTX_init(&ssl3_ctx->cipher_ctx); + EVP_MD_CTX_init(&ssl3_ctx->md_ctx); + + ctx->aead_state = ssl3_ctx; + if (!EVP_CipherInit_ex(&ssl3_ctx->cipher_ctx, cipher, NULL, &key[mac_key_len], + &key[mac_key_len + enc_key_len], + dir == evp_aead_seal) || + !EVP_DigestInit_ex(&ssl3_ctx->md_ctx, md, NULL) || + !EVP_DigestUpdate(&ssl3_ctx->md_ctx, key, mac_key_len)) { + aead_ssl3_cleanup(ctx); + ctx->aead_state = NULL; + return 0; + } + EVP_CIPHER_CTX_set_padding(&ssl3_ctx->cipher_ctx, 0); + + return 1; +} + +static int aead_ssl3_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + AEAD_SSL3_CTX *ssl3_ctx = (AEAD_SSL3_CTX *)ctx->aead_state; + size_t total = 0; + + if (!ssl3_ctx->cipher_ctx.encrypt) { + /* Unlike a normal AEAD, an SSL3 AEAD may only be used in one direction. */ + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_OPERATION); + return 0; + } + + if (in_len + EVP_AEAD_max_overhead(ctx->aead) < in_len || + in_len > INT_MAX) { + /* EVP_CIPHER takes int as input. */ + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (max_out_len < in_len + EVP_AEAD_max_overhead(ctx->aead)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + if (nonce_len != 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_IV_TOO_LARGE); + return 0; + } + + if (ad_len != 11 - 2 /* length bytes */) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_AD_SIZE); + return 0; + } + + /* Compute the MAC. This must be first in case the operation is being done + * in-place. */ + uint8_t mac[EVP_MAX_MD_SIZE]; + unsigned mac_len; + if (!ssl3_mac(ssl3_ctx, mac, &mac_len, ad, ad_len, in, in_len)) { + return 0; + } + + /* Encrypt the input. */ + int len; + if (!EVP_EncryptUpdate(&ssl3_ctx->cipher_ctx, out, &len, in, + (int)in_len)) { + return 0; + } + total = len; + + /* Feed the MAC into the cipher. */ + if (!EVP_EncryptUpdate(&ssl3_ctx->cipher_ctx, out + total, &len, mac, + (int)mac_len)) { + return 0; + } + total += len; + + unsigned block_size = EVP_CIPHER_CTX_block_size(&ssl3_ctx->cipher_ctx); + if (block_size > 1) { + assert(block_size <= 256); + assert(EVP_CIPHER_CTX_mode(&ssl3_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE); + + /* Compute padding and feed that into the cipher. */ + uint8_t padding[256]; + unsigned padding_len = block_size - ((in_len + mac_len) % block_size); + memset(padding, 0, padding_len - 1); + padding[padding_len - 1] = padding_len - 1; + if (!EVP_EncryptUpdate(&ssl3_ctx->cipher_ctx, out + total, &len, padding, + (int)padding_len)) { + return 0; + } + total += len; + } + + if (!EVP_EncryptFinal_ex(&ssl3_ctx->cipher_ctx, out + total, &len)) { + return 0; + } + total += len; + + *out_len = total; + return 1; +} + +static int aead_ssl3_open(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + AEAD_SSL3_CTX *ssl3_ctx = (AEAD_SSL3_CTX *)ctx->aead_state; + + if (ssl3_ctx->cipher_ctx.encrypt) { + /* Unlike a normal AEAD, an SSL3 AEAD may only be used in one direction. */ + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_OPERATION); + return 0; + } + + size_t mac_len = EVP_MD_CTX_size(&ssl3_ctx->md_ctx); + if (in_len < mac_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + if (max_out_len < in_len) { + /* This requires that the caller provide space for the MAC, even though it + * will always be removed on return. */ + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + if (nonce_len != 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (ad_len != 11 - 2 /* length bytes */) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_AD_SIZE); + return 0; + } + + if (in_len > INT_MAX) { + /* EVP_CIPHER takes int as input. */ + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + /* Decrypt to get the plaintext + MAC + padding. */ + size_t total = 0; + int len; + if (!EVP_DecryptUpdate(&ssl3_ctx->cipher_ctx, out, &len, in, (int)in_len)) { + return 0; + } + total += len; + if (!EVP_DecryptFinal_ex(&ssl3_ctx->cipher_ctx, out + total, &len)) { + return 0; + } + total += len; + assert(total == in_len); + + /* Remove CBC padding and MAC. This would normally be timing-sensitive, but SSLv3 CBC + * ciphers are already broken. Support will be removed eventually. + * https://www.openssl.org/~bodo/ssl-poodle.pdf */ + unsigned data_len; + if (EVP_CIPHER_CTX_mode(&ssl3_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE) { + unsigned padding_length = out[total - 1]; + if (total < padding_length + 1 + mac_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + /* The padding must be minimal. */ + if (padding_length + 1 > EVP_CIPHER_CTX_block_size(&ssl3_ctx->cipher_ctx)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + data_len = total - padding_length - 1 - mac_len; + } else { + data_len = total - mac_len; + } + + /* Compute the MAC and compare against the one in the record. */ + uint8_t mac[EVP_MAX_MD_SIZE]; + if (!ssl3_mac(ssl3_ctx, mac, NULL, ad, ad_len, out, data_len)) { + return 0; + } + if (CRYPTO_memcmp(&out[data_len], mac, mac_len) != 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + *out_len = data_len; + return 1; +} + +static int aead_ssl3_get_rc4_state(const EVP_AEAD_CTX *ctx, const RC4_KEY **out_key) { + AEAD_SSL3_CTX *ssl3_ctx = (AEAD_SSL3_CTX *)ctx->aead_state; + if (EVP_CIPHER_CTX_cipher(&ssl3_ctx->cipher_ctx) != EVP_rc4()) { + return 0; + } + + *out_key = (RC4_KEY*) ssl3_ctx->cipher_ctx.cipher_data; + return 1; +} + +static int aead_rc4_md5_ssl3_init(EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_ssl3_init(ctx, key, key_len, tag_len, dir, EVP_rc4(), EVP_md5()); +} + +static int aead_rc4_sha1_ssl3_init(EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_ssl3_init(ctx, key, key_len, tag_len, dir, EVP_rc4(), EVP_sha1()); +} + +static int aead_aes_128_cbc_sha1_ssl3_init(EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_ssl3_init(ctx, key, key_len, tag_len, dir, EVP_aes_128_cbc(), + EVP_sha1()); +} + +static int aead_aes_256_cbc_sha1_ssl3_init(EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_ssl3_init(ctx, key, key_len, tag_len, dir, EVP_aes_256_cbc(), + EVP_sha1()); +} +static int aead_des_ede3_cbc_sha1_ssl3_init(EVP_AEAD_CTX *ctx, + const uint8_t *key, size_t key_len, + size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_ssl3_init(ctx, key, key_len, tag_len, dir, EVP_des_ede3_cbc(), + EVP_sha1()); +} + +static const EVP_AEAD aead_rc4_md5_ssl3 = { + MD5_DIGEST_LENGTH + 16, /* key len (MD5 + RC4) */ + 0, /* nonce len */ + MD5_DIGEST_LENGTH, /* overhead */ + MD5_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ + aead_rc4_md5_ssl3_init, + aead_ssl3_cleanup, + aead_ssl3_seal, + aead_ssl3_open, + aead_ssl3_get_rc4_state, +}; + +static const EVP_AEAD aead_rc4_sha1_ssl3 = { + SHA_DIGEST_LENGTH + 16, /* key len (SHA1 + RC4) */ + 0, /* nonce len */ + SHA_DIGEST_LENGTH, /* overhead */ + SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ + aead_rc4_sha1_ssl3_init, + aead_ssl3_cleanup, + aead_ssl3_seal, + aead_ssl3_open, + aead_ssl3_get_rc4_state, +}; + +static const EVP_AEAD aead_aes_128_cbc_sha1_ssl3 = { + SHA_DIGEST_LENGTH + 16 + 16, /* key len (SHA1 + AES128 + IV) */ + 0, /* nonce len */ + 16 + SHA_DIGEST_LENGTH, /* overhead (padding + SHA1) */ + SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ + aead_aes_128_cbc_sha1_ssl3_init, + aead_ssl3_cleanup, + aead_ssl3_seal, + aead_ssl3_open, + NULL, /* get_rc4_state */ +}; + +static const EVP_AEAD aead_aes_256_cbc_sha1_ssl3 = { + SHA_DIGEST_LENGTH + 32 + 16, /* key len (SHA1 + AES256 + IV) */ + 0, /* nonce len */ + 16 + SHA_DIGEST_LENGTH, /* overhead (padding + SHA1) */ + SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ + aead_aes_256_cbc_sha1_ssl3_init, + aead_ssl3_cleanup, + aead_ssl3_seal, + aead_ssl3_open, + NULL, /* get_rc4_state */ +}; + +static const EVP_AEAD aead_des_ede3_cbc_sha1_ssl3 = { + SHA_DIGEST_LENGTH + 24 + 8, /* key len (SHA1 + 3DES + IV) */ + 0, /* nonce len */ + 8 + SHA_DIGEST_LENGTH, /* overhead (padding + SHA1) */ + SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ + aead_des_ede3_cbc_sha1_ssl3_init, + aead_ssl3_cleanup, + aead_ssl3_seal, + aead_ssl3_open, + NULL, /* get_rc4_state */ +}; + +const EVP_AEAD *EVP_aead_rc4_md5_ssl3(void) { return &aead_rc4_md5_ssl3; } + +const EVP_AEAD *EVP_aead_rc4_sha1_ssl3(void) { return &aead_rc4_sha1_ssl3; } + +const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_ssl3(void) { + return &aead_aes_128_cbc_sha1_ssl3; +} + +const EVP_AEAD *EVP_aead_aes_256_cbc_sha1_ssl3(void) { + return &aead_aes_256_cbc_sha1_ssl3; +} + +const EVP_AEAD *EVP_aead_des_ede3_cbc_sha1_ssl3(void) { + return &aead_des_ede3_cbc_sha1_ssl3; +} diff --git a/TMessagesProj/jni/boringssl/crypto/cipher/e_tls.c b/TMessagesProj/jni/boringssl/crypto/cipher/e_tls.c new file mode 100644 index 00000000..7938c36d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cipher/e_tls.c @@ -0,0 +1,613 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../crypto/internal.h" +#include "internal.h" + + +typedef struct { + EVP_CIPHER_CTX cipher_ctx; + HMAC_CTX hmac_ctx; + /* mac_key is the portion of the key used for the MAC. It is retained + * separately for the constant-time CBC code. */ + uint8_t mac_key[EVP_MAX_MD_SIZE]; + uint8_t mac_key_len; + /* implicit_iv is one iff this is a pre-TLS-1.1 CBC cipher without an explicit + * IV. */ + char implicit_iv; +} AEAD_TLS_CTX; + +OPENSSL_COMPILE_ASSERT(EVP_MAX_MD_SIZE < 256, mac_key_len_fits_in_uint8_t); + +static void aead_tls_cleanup(EVP_AEAD_CTX *ctx) { + AEAD_TLS_CTX *tls_ctx = (AEAD_TLS_CTX *)ctx->aead_state; + EVP_CIPHER_CTX_cleanup(&tls_ctx->cipher_ctx); + HMAC_CTX_cleanup(&tls_ctx->hmac_ctx); + OPENSSL_cleanse(&tls_ctx->mac_key, sizeof(tls_ctx->mac_key)); + OPENSSL_free(tls_ctx); + ctx->aead_state = NULL; +} + +static int aead_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, + size_t tag_len, enum evp_aead_direction_t dir, + const EVP_CIPHER *cipher, const EVP_MD *md, + char implicit_iv) { + if (tag_len != EVP_AEAD_DEFAULT_TAG_LENGTH && + tag_len != EVP_MD_size(md)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_TAG_SIZE); + return 0; + } + + if (key_len != EVP_AEAD_key_length(ctx->aead)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH); + return 0; + } + + size_t mac_key_len = EVP_MD_size(md); + size_t enc_key_len = EVP_CIPHER_key_length(cipher); + assert(mac_key_len + enc_key_len + + (implicit_iv ? EVP_CIPHER_iv_length(cipher) : 0) == key_len); + /* Although EVP_rc4() is a variable-length cipher, the default key size is + * correct for TLS. */ + + AEAD_TLS_CTX *tls_ctx = OPENSSL_malloc(sizeof(AEAD_TLS_CTX)); + if (tls_ctx == NULL) { + OPENSSL_PUT_ERROR(CIPHER, ERR_R_MALLOC_FAILURE); + return 0; + } + EVP_CIPHER_CTX_init(&tls_ctx->cipher_ctx); + HMAC_CTX_init(&tls_ctx->hmac_ctx); + assert(mac_key_len <= EVP_MAX_MD_SIZE); + memcpy(tls_ctx->mac_key, key, mac_key_len); + tls_ctx->mac_key_len = (uint8_t)mac_key_len; + tls_ctx->implicit_iv = implicit_iv; + + ctx->aead_state = tls_ctx; + if (!EVP_CipherInit_ex(&tls_ctx->cipher_ctx, cipher, NULL, &key[mac_key_len], + implicit_iv ? &key[mac_key_len + enc_key_len] : NULL, + dir == evp_aead_seal) || + !HMAC_Init_ex(&tls_ctx->hmac_ctx, key, mac_key_len, md, NULL)) { + aead_tls_cleanup(ctx); + ctx->aead_state = NULL; + return 0; + } + EVP_CIPHER_CTX_set_padding(&tls_ctx->cipher_ctx, 0); + + return 1; +} + +static int aead_tls_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + AEAD_TLS_CTX *tls_ctx = (AEAD_TLS_CTX *)ctx->aead_state; + size_t total = 0; + + if (!tls_ctx->cipher_ctx.encrypt) { + /* Unlike a normal AEAD, a TLS AEAD may only be used in one direction. */ + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_OPERATION); + return 0; + + } + + if (in_len + EVP_AEAD_max_overhead(ctx->aead) < in_len || + in_len > INT_MAX) { + /* EVP_CIPHER takes int as input. */ + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (max_out_len < in_len + EVP_AEAD_max_overhead(ctx->aead)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + if (nonce_len != EVP_AEAD_nonce_length(ctx->aead)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_NONCE_SIZE); + return 0; + } + + if (ad_len != 13 - 2 /* length bytes */) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_AD_SIZE); + return 0; + } + + /* To allow for CBC mode which changes cipher length, |ad| doesn't include the + * length for legacy ciphers. */ + uint8_t ad_extra[2]; + ad_extra[0] = (uint8_t)(in_len >> 8); + ad_extra[1] = (uint8_t)(in_len & 0xff); + + /* Compute the MAC. This must be first in case the operation is being done + * in-place. */ + uint8_t mac[EVP_MAX_MD_SIZE]; + unsigned mac_len; + HMAC_CTX hmac_ctx; + HMAC_CTX_init(&hmac_ctx); + if (!HMAC_CTX_copy_ex(&hmac_ctx, &tls_ctx->hmac_ctx) || + !HMAC_Update(&hmac_ctx, ad, ad_len) || + !HMAC_Update(&hmac_ctx, ad_extra, sizeof(ad_extra)) || + !HMAC_Update(&hmac_ctx, in, in_len) || + !HMAC_Final(&hmac_ctx, mac, &mac_len)) { + HMAC_CTX_cleanup(&hmac_ctx); + return 0; + } + HMAC_CTX_cleanup(&hmac_ctx); + + /* Configure the explicit IV. */ + if (EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE && + !tls_ctx->implicit_iv && + !EVP_EncryptInit_ex(&tls_ctx->cipher_ctx, NULL, NULL, NULL, nonce)) { + return 0; + } + + /* Encrypt the input. */ + int len; + if (!EVP_EncryptUpdate(&tls_ctx->cipher_ctx, out, &len, in, + (int)in_len)) { + return 0; + } + total = len; + + /* Feed the MAC into the cipher. */ + if (!EVP_EncryptUpdate(&tls_ctx->cipher_ctx, out + total, &len, mac, + (int)mac_len)) { + return 0; + } + total += len; + + unsigned block_size = EVP_CIPHER_CTX_block_size(&tls_ctx->cipher_ctx); + if (block_size > 1) { + assert(block_size <= 256); + assert(EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE); + + /* Compute padding and feed that into the cipher. */ + uint8_t padding[256]; + unsigned padding_len = block_size - ((in_len + mac_len) % block_size); + memset(padding, padding_len - 1, padding_len); + if (!EVP_EncryptUpdate(&tls_ctx->cipher_ctx, out + total, &len, padding, + (int)padding_len)) { + return 0; + } + total += len; + } + + if (!EVP_EncryptFinal_ex(&tls_ctx->cipher_ctx, out + total, &len)) { + return 0; + } + total += len; + + *out_len = total; + return 1; +} + +static int aead_tls_open(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + AEAD_TLS_CTX *tls_ctx = (AEAD_TLS_CTX *)ctx->aead_state; + + if (tls_ctx->cipher_ctx.encrypt) { + /* Unlike a normal AEAD, a TLS AEAD may only be used in one direction. */ + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_OPERATION); + return 0; + + } + + if (in_len < HMAC_size(&tls_ctx->hmac_ctx)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + if (max_out_len < in_len) { + /* This requires that the caller provide space for the MAC, even though it + * will always be removed on return. */ + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + if (nonce_len != EVP_AEAD_nonce_length(ctx->aead)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_NONCE_SIZE); + return 0; + } + + if (ad_len != 13 - 2 /* length bytes */) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_AD_SIZE); + return 0; + } + + if (in_len > INT_MAX) { + /* EVP_CIPHER takes int as input. */ + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + /* Configure the explicit IV. */ + if (EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE && + !tls_ctx->implicit_iv && + !EVP_DecryptInit_ex(&tls_ctx->cipher_ctx, NULL, NULL, NULL, nonce)) { + return 0; + } + + /* Decrypt to get the plaintext + MAC + padding. */ + size_t total = 0; + int len; + if (!EVP_DecryptUpdate(&tls_ctx->cipher_ctx, out, &len, in, (int)in_len)) { + return 0; + } + total += len; + if (!EVP_DecryptFinal_ex(&tls_ctx->cipher_ctx, out + total, &len)) { + return 0; + } + total += len; + assert(total == in_len); + + /* Remove CBC padding. Code from here on is timing-sensitive with respect to + * |padding_ok| and |data_plus_mac_len| for CBC ciphers. */ + int padding_ok; + unsigned data_plus_mac_len, data_len; + if (EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE) { + padding_ok = EVP_tls_cbc_remove_padding( + &data_plus_mac_len, out, total, + EVP_CIPHER_CTX_block_size(&tls_ctx->cipher_ctx), + (unsigned)HMAC_size(&tls_ctx->hmac_ctx)); + /* Publicly invalid. This can be rejected in non-constant time. */ + if (padding_ok == 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + } else { + padding_ok = 1; + data_plus_mac_len = total; + /* |data_plus_mac_len| = |total| = |in_len| at this point. |in_len| has + * already been checked against the MAC size at the top of the function. */ + assert(data_plus_mac_len >= HMAC_size(&tls_ctx->hmac_ctx)); + } + data_len = data_plus_mac_len - HMAC_size(&tls_ctx->hmac_ctx); + + /* At this point, |padding_ok| is 1 or -1. If 1, the padding is valid and the + * first |data_plus_mac_size| bytes after |out| are the plaintext and + * MAC. Either way, |data_plus_mac_size| is large enough to extract a MAC. */ + + /* To allow for CBC mode which changes cipher length, |ad| doesn't include the + * length for legacy ciphers. */ + uint8_t ad_fixed[13]; + memcpy(ad_fixed, ad, 11); + ad_fixed[11] = (uint8_t)(data_len >> 8); + ad_fixed[12] = (uint8_t)(data_len & 0xff); + ad_len += 2; + + /* Compute the MAC and extract the one in the record. */ + uint8_t mac[EVP_MAX_MD_SIZE]; + size_t mac_len; + uint8_t record_mac_tmp[EVP_MAX_MD_SIZE]; + uint8_t *record_mac; + if (EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE && + EVP_tls_cbc_record_digest_supported(tls_ctx->hmac_ctx.md)) { + if (!EVP_tls_cbc_digest_record(tls_ctx->hmac_ctx.md, mac, &mac_len, + ad_fixed, out, data_plus_mac_len, total, + tls_ctx->mac_key, tls_ctx->mac_key_len)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + assert(mac_len == HMAC_size(&tls_ctx->hmac_ctx)); + + record_mac = record_mac_tmp; + EVP_tls_cbc_copy_mac(record_mac, mac_len, out, data_plus_mac_len, total); + } else { + /* We should support the constant-time path for all CBC-mode ciphers + * implemented. */ + assert(EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) != EVP_CIPH_CBC_MODE); + + HMAC_CTX hmac_ctx; + HMAC_CTX_init(&hmac_ctx); + unsigned mac_len_u; + if (!HMAC_CTX_copy_ex(&hmac_ctx, &tls_ctx->hmac_ctx) || + !HMAC_Update(&hmac_ctx, ad_fixed, ad_len) || + !HMAC_Update(&hmac_ctx, out, data_len) || + !HMAC_Final(&hmac_ctx, mac, &mac_len_u)) { + HMAC_CTX_cleanup(&hmac_ctx); + return 0; + } + mac_len = mac_len_u; + HMAC_CTX_cleanup(&hmac_ctx); + + assert(mac_len == HMAC_size(&tls_ctx->hmac_ctx)); + record_mac = &out[data_len]; + } + + /* Perform the MAC check and the padding check in constant-time. It should be + * safe to simply perform the padding check first, but it would not be under a + * different choice of MAC location on padding failure. See + * EVP_tls_cbc_remove_padding. */ + unsigned good = constant_time_eq_int(CRYPTO_memcmp(record_mac, mac, mac_len), + 0); + good &= constant_time_eq_int(padding_ok, 1); + if (!good) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + /* End of timing-sensitive code. */ + + *out_len = data_len; + return 1; +} + +static int aead_rc4_sha1_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_rc4(), EVP_sha1(), + 0); +} + +static int aead_aes_128_cbc_sha1_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_aes_128_cbc(), + EVP_sha1(), 0); +} + +static int aead_aes_128_cbc_sha1_tls_implicit_iv_init( + EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_aes_128_cbc(), + EVP_sha1(), 1); +} + +static int aead_aes_128_cbc_sha256_tls_init(EVP_AEAD_CTX *ctx, + const uint8_t *key, size_t key_len, + size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_aes_128_cbc(), + EVP_sha256(), 0); +} + +static int aead_aes_256_cbc_sha1_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_aes_256_cbc(), + EVP_sha1(), 0); +} + +static int aead_aes_256_cbc_sha1_tls_implicit_iv_init( + EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_aes_256_cbc(), + EVP_sha1(), 1); +} + +static int aead_aes_256_cbc_sha256_tls_init(EVP_AEAD_CTX *ctx, + const uint8_t *key, size_t key_len, + size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_aes_256_cbc(), + EVP_sha256(), 0); +} + +static int aead_aes_256_cbc_sha384_tls_init(EVP_AEAD_CTX *ctx, + const uint8_t *key, size_t key_len, + size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_aes_256_cbc(), + EVP_sha384(), 0); +} + +static int aead_des_ede3_cbc_sha1_tls_init(EVP_AEAD_CTX *ctx, + const uint8_t *key, size_t key_len, + size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_des_ede3_cbc(), + EVP_sha1(), 0); +} + +static int aead_des_ede3_cbc_sha1_tls_implicit_iv_init( + EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_des_ede3_cbc(), + EVP_sha1(), 1); +} + +static int aead_rc4_sha1_tls_get_rc4_state(const EVP_AEAD_CTX *ctx, + const RC4_KEY **out_key) { + const AEAD_TLS_CTX *tls_ctx = (AEAD_TLS_CTX*) ctx->aead_state; + if (EVP_CIPHER_CTX_cipher(&tls_ctx->cipher_ctx) != EVP_rc4()) { + return 0; + } + + *out_key = (const RC4_KEY*) tls_ctx->cipher_ctx.cipher_data; + return 1; +} + +static const EVP_AEAD aead_rc4_sha1_tls = { + SHA_DIGEST_LENGTH + 16, /* key len (SHA1 + RC4) */ + 0, /* nonce len */ + SHA_DIGEST_LENGTH, /* overhead */ + SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ + aead_rc4_sha1_tls_init, + aead_tls_cleanup, + aead_tls_seal, + aead_tls_open, + aead_rc4_sha1_tls_get_rc4_state, /* get_rc4_state */ +}; + +static const EVP_AEAD aead_aes_128_cbc_sha1_tls = { + SHA_DIGEST_LENGTH + 16, /* key len (SHA1 + AES128) */ + 16, /* nonce len (IV) */ + 16 + SHA_DIGEST_LENGTH, /* overhead (padding + SHA1) */ + SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ + aead_aes_128_cbc_sha1_tls_init, + aead_tls_cleanup, + aead_tls_seal, + aead_tls_open, + NULL, /* get_rc4_state */ +}; + +static const EVP_AEAD aead_aes_128_cbc_sha1_tls_implicit_iv = { + SHA_DIGEST_LENGTH + 16 + 16, /* key len (SHA1 + AES128 + IV) */ + 0, /* nonce len */ + 16 + SHA_DIGEST_LENGTH, /* overhead (padding + SHA1) */ + SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ + aead_aes_128_cbc_sha1_tls_implicit_iv_init, + aead_tls_cleanup, + aead_tls_seal, + aead_tls_open, + NULL, /* get_rc4_state */ +}; + +static const EVP_AEAD aead_aes_128_cbc_sha256_tls = { + SHA256_DIGEST_LENGTH + 16, /* key len (SHA256 + AES128) */ + 16, /* nonce len (IV) */ + 16 + SHA256_DIGEST_LENGTH, /* overhead (padding + SHA256) */ + SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ + aead_aes_128_cbc_sha256_tls_init, + aead_tls_cleanup, + aead_tls_seal, + aead_tls_open, + NULL, /* get_rc4_state */ +}; + +static const EVP_AEAD aead_aes_256_cbc_sha1_tls = { + SHA_DIGEST_LENGTH + 32, /* key len (SHA1 + AES256) */ + 16, /* nonce len (IV) */ + 16 + SHA_DIGEST_LENGTH, /* overhead (padding + SHA1) */ + SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ + aead_aes_256_cbc_sha1_tls_init, + aead_tls_cleanup, + aead_tls_seal, + aead_tls_open, + NULL, /* get_rc4_state */ +}; + +static const EVP_AEAD aead_aes_256_cbc_sha1_tls_implicit_iv = { + SHA_DIGEST_LENGTH + 32 + 16, /* key len (SHA1 + AES256 + IV) */ + 0, /* nonce len */ + 16 + SHA_DIGEST_LENGTH, /* overhead (padding + SHA1) */ + SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ + aead_aes_256_cbc_sha1_tls_implicit_iv_init, + aead_tls_cleanup, + aead_tls_seal, + aead_tls_open, + NULL, /* get_rc4_state */ +}; + +static const EVP_AEAD aead_aes_256_cbc_sha256_tls = { + SHA256_DIGEST_LENGTH + 32, /* key len (SHA256 + AES256) */ + 16, /* nonce len (IV) */ + 16 + SHA256_DIGEST_LENGTH, /* overhead (padding + SHA256) */ + SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ + aead_aes_256_cbc_sha256_tls_init, + aead_tls_cleanup, + aead_tls_seal, + aead_tls_open, + NULL, /* get_rc4_state */ +}; + +static const EVP_AEAD aead_aes_256_cbc_sha384_tls = { + SHA384_DIGEST_LENGTH + 32, /* key len (SHA384 + AES256) */ + 16, /* nonce len (IV) */ + 16 + SHA384_DIGEST_LENGTH, /* overhead (padding + SHA384) */ + SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ + aead_aes_256_cbc_sha384_tls_init, + aead_tls_cleanup, + aead_tls_seal, + aead_tls_open, + NULL, /* get_rc4_state */ +}; + +static const EVP_AEAD aead_des_ede3_cbc_sha1_tls = { + SHA_DIGEST_LENGTH + 24, /* key len (SHA1 + 3DES) */ + 8, /* nonce len (IV) */ + 8 + SHA_DIGEST_LENGTH, /* overhead (padding + SHA1) */ + SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ + aead_des_ede3_cbc_sha1_tls_init, + aead_tls_cleanup, + aead_tls_seal, + aead_tls_open, + NULL, /* get_rc4_state */ +}; + +static const EVP_AEAD aead_des_ede3_cbc_sha1_tls_implicit_iv = { + SHA_DIGEST_LENGTH + 24 + 8, /* key len (SHA1 + 3DES + IV) */ + 0, /* nonce len */ + 8 + SHA_DIGEST_LENGTH, /* overhead (padding + SHA1) */ + SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ + aead_des_ede3_cbc_sha1_tls_implicit_iv_init, + aead_tls_cleanup, + aead_tls_seal, + aead_tls_open, + NULL, /* get_rc4_state */ +}; + +const EVP_AEAD *EVP_aead_rc4_sha1_tls(void) { return &aead_rc4_sha1_tls; } + +const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_tls(void) { + return &aead_aes_128_cbc_sha1_tls; +} + +const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_tls_implicit_iv(void) { + return &aead_aes_128_cbc_sha1_tls_implicit_iv; +} + +const EVP_AEAD *EVP_aead_aes_128_cbc_sha256_tls(void) { + return &aead_aes_128_cbc_sha256_tls; +} + +const EVP_AEAD *EVP_aead_aes_256_cbc_sha1_tls(void) { + return &aead_aes_256_cbc_sha1_tls; +} + +const EVP_AEAD *EVP_aead_aes_256_cbc_sha1_tls_implicit_iv(void) { + return &aead_aes_256_cbc_sha1_tls_implicit_iv; +} + +const EVP_AEAD *EVP_aead_aes_256_cbc_sha256_tls(void) { + return &aead_aes_256_cbc_sha256_tls; +} + +const EVP_AEAD *EVP_aead_aes_256_cbc_sha384_tls(void) { + return &aead_aes_256_cbc_sha384_tls; +} + +const EVP_AEAD *EVP_aead_des_ede3_cbc_sha1_tls(void) { + return &aead_des_ede3_cbc_sha1_tls; +} + +const EVP_AEAD *EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv(void) { + return &aead_des_ede3_cbc_sha1_tls_implicit_iv; +} diff --git a/TMessagesProj/jni/boringssl/crypto/cipher/internal.h b/TMessagesProj/jni/boringssl/crypto/cipher/internal.h new file mode 100644 index 00000000..b2a94f44 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cipher/internal.h @@ -0,0 +1,161 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_CIPHER_INTERNAL_H +#define OPENSSL_HEADER_CIPHER_INTERNAL_H + +#include + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* EVP_CIPH_MODE_MASK contains the bits of |flags| that represent the mode. */ +#define EVP_CIPH_MODE_MASK 0x3f + + +/* EVP_AEAD represents a specific AEAD algorithm. */ +struct evp_aead_st { + uint8_t key_len; + uint8_t nonce_len; + uint8_t overhead; + uint8_t max_tag_len; + + /* init initialises an |EVP_AEAD_CTX|. If this call returns zero then + * |cleanup| will not be called for that context. */ + int (*init)(EVP_AEAD_CTX *, const uint8_t *key, size_t key_len, + size_t tag_len); + int (*init_with_direction)(EVP_AEAD_CTX *, const uint8_t *key, size_t key_len, + size_t tag_len, enum evp_aead_direction_t dir); + void (*cleanup)(EVP_AEAD_CTX *); + + int (*seal)(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, + size_t max_out_len, const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, const uint8_t *ad, + size_t ad_len); + + int (*open)(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, + size_t max_out_len, const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, const uint8_t *ad, + size_t ad_len); + + int (*get_rc4_state)(const EVP_AEAD_CTX *ctx, const RC4_KEY **out_key); +}; + + +/* EVP_tls_cbc_get_padding determines the padding from the decrypted, TLS, CBC + * record in |in|. This decrypted record should not include any "decrypted" + * explicit IV. It sets |*out_len| to the length with the padding removed or + * |in_len| if invalid. + * + * block_size: the block size of the cipher used to encrypt the record. + * returns: + * 0: (in non-constant time) if the record is publicly invalid. + * 1: if the padding was valid + * -1: otherwise. */ +int EVP_tls_cbc_remove_padding(unsigned *out_len, + const uint8_t *in, unsigned in_len, + unsigned block_size, unsigned mac_size); + +/* EVP_tls_cbc_copy_mac copies |md_size| bytes from the end of the first + * |in_len| bytes of |in| to |out| in constant time (independent of the concrete + * value of |in_len|, which may vary within a 256-byte window). |in| must point + * to a buffer of |orig_len| bytes. + * + * On entry: + * orig_len >= in_len >= md_size + * md_size <= EVP_MAX_MD_SIZE */ +void EVP_tls_cbc_copy_mac(uint8_t *out, unsigned md_size, + const uint8_t *in, unsigned in_len, + unsigned orig_len); + +/* EVP_tls_cbc_record_digest_supported returns 1 iff |md| is a hash function + * which EVP_tls_cbc_digest_record supports. */ +int EVP_tls_cbc_record_digest_supported(const EVP_MD *md); + +/* EVP_tls_cbc_digest_record computes the MAC of a decrypted, padded TLS + * record. + * + * md: the hash function used in the HMAC. + * EVP_tls_cbc_record_digest_supported must return true for this hash. + * md_out: the digest output. At most EVP_MAX_MD_SIZE bytes will be written. + * md_out_size: the number of output bytes is written here. + * header: the 13-byte, TLS record header. + * data: the record data itself + * data_plus_mac_size: the secret, reported length of the data and MAC + * once the padding has been removed. + * data_plus_mac_plus_padding_size: the public length of the whole + * record, including padding. + * + * On entry: by virtue of having been through one of the remove_padding + * functions, above, we know that data_plus_mac_size is large enough to contain + * a padding byte and MAC. (If the padding was invalid, it might contain the + * padding too. ) */ +int EVP_tls_cbc_digest_record(const EVP_MD *md, uint8_t *md_out, + size_t *md_out_size, const uint8_t header[13], + const uint8_t *data, size_t data_plus_mac_size, + size_t data_plus_mac_plus_padding_size, + const uint8_t *mac_secret, + unsigned mac_secret_length); + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_CIPHER_INTERNAL_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/cipher/tls_cbc.c b/TMessagesProj/jni/boringssl/crypto/cipher/tls_cbc.c new file mode 100644 index 00000000..8bca2f30 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cipher/tls_cbc.c @@ -0,0 +1,495 @@ +/* ==================================================================== + * Copyright (c) 2012 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include +#include + +#include +#include +#include + +#include "../internal.h" + + +/* TODO(davidben): unsigned should be size_t. The various constant_time + * functions need to be switched to size_t. */ + +/* MAX_HASH_BIT_COUNT_BYTES is the maximum number of bytes in the hash's length + * field. (SHA-384/512 have 128-bit length.) */ +#define MAX_HASH_BIT_COUNT_BYTES 16 + +/* MAX_HASH_BLOCK_SIZE is the maximum hash block size that we'll support. + * Currently SHA-384/512 has a 128-byte block size and that's the largest + * supported by TLS.) */ +#define MAX_HASH_BLOCK_SIZE 128 + +int EVP_tls_cbc_remove_padding(unsigned *out_len, + const uint8_t *in, unsigned in_len, + unsigned block_size, unsigned mac_size) { + unsigned padding_length, good, to_check, i; + const unsigned overhead = 1 /* padding length byte */ + mac_size; + + /* These lengths are all public so we can test them in non-constant time. */ + if (overhead > in_len) { + return 0; + } + + padding_length = in[in_len - 1]; + + good = constant_time_ge(in_len, overhead + padding_length); + /* The padding consists of a length byte at the end of the record and + * then that many bytes of padding, all with the same value as the + * length byte. Thus, with the length byte included, there are i+1 + * bytes of padding. + * + * We can't check just |padding_length+1| bytes because that leaks + * decrypted information. Therefore we always have to check the maximum + * amount of padding possible. (Again, the length of the record is + * public information so we can use it.) */ + to_check = 256; /* maximum amount of padding, inc length byte. */ + if (to_check > in_len) { + to_check = in_len; + } + + for (i = 0; i < to_check; i++) { + uint8_t mask = constant_time_ge_8(padding_length, i); + uint8_t b = in[in_len - 1 - i]; + /* The final |padding_length+1| bytes should all have the value + * |padding_length|. Therefore the XOR should be zero. */ + good &= ~(mask & (padding_length ^ b)); + } + + /* If any of the final |padding_length+1| bytes had the wrong value, + * one or more of the lower eight bits of |good| will be cleared. */ + good = constant_time_eq(0xff, good & 0xff); + + /* Always treat |padding_length| as zero on error. If, assuming block size of + * 16, a padding of [<15 arbitrary bytes> 15] treated |padding_length| as 16 + * and returned -1, distinguishing good MAC and bad padding from bad MAC and + * bad padding would give POODLE's padding oracle. */ + padding_length = good & (padding_length + 1); + *out_len = in_len - padding_length; + + return constant_time_select_int(good, 1, -1); +} + +/* If CBC_MAC_ROTATE_IN_PLACE is defined then EVP_tls_cbc_copy_mac is performed + * with variable accesses in a 64-byte-aligned buffer. Assuming that this fits + * into a single or pair of cache-lines, then the variable memory accesses don't + * actually affect the timing. CPUs with smaller cache-lines [if any] are not + * multi-core and are not considered vulnerable to cache-timing attacks. */ +#define CBC_MAC_ROTATE_IN_PLACE + +void EVP_tls_cbc_copy_mac(uint8_t *out, unsigned md_size, + const uint8_t *in, unsigned in_len, + unsigned orig_len) { +#if defined(CBC_MAC_ROTATE_IN_PLACE) + uint8_t rotated_mac_buf[64 + EVP_MAX_MD_SIZE]; + uint8_t *rotated_mac; +#else + uint8_t rotated_mac[EVP_MAX_MD_SIZE]; +#endif + + /* mac_end is the index of |in| just after the end of the MAC. */ + unsigned mac_end = in_len; + unsigned mac_start = mac_end - md_size; + /* scan_start contains the number of bytes that we can ignore because + * the MAC's position can only vary by 255 bytes. */ + unsigned scan_start = 0; + unsigned i, j; + unsigned div_spoiler; + unsigned rotate_offset; + + assert(orig_len >= in_len); + assert(in_len >= md_size); + assert(md_size <= EVP_MAX_MD_SIZE); + +#if defined(CBC_MAC_ROTATE_IN_PLACE) + rotated_mac = rotated_mac_buf + ((0 - (size_t)rotated_mac_buf) & 63); +#endif + + /* This information is public so it's safe to branch based on it. */ + if (orig_len > md_size + 255 + 1) { + scan_start = orig_len - (md_size + 255 + 1); + } + /* div_spoiler contains a multiple of md_size that is used to cause the + * modulo operation to be constant time. Without this, the time varies + * based on the amount of padding when running on Intel chips at least. + * + * The aim of right-shifting md_size is so that the compiler doesn't + * figure out that it can remove div_spoiler as that would require it + * to prove that md_size is always even, which I hope is beyond it. */ + div_spoiler = md_size >> 1; + div_spoiler <<= (sizeof(div_spoiler) - 1) * 8; + rotate_offset = (div_spoiler + mac_start - scan_start) % md_size; + + memset(rotated_mac, 0, md_size); + for (i = scan_start, j = 0; i < orig_len; i++) { + uint8_t mac_started = constant_time_ge_8(i, mac_start); + uint8_t mac_ended = constant_time_ge_8(i, mac_end); + uint8_t b = in[i]; + rotated_mac[j++] |= b & mac_started & ~mac_ended; + j &= constant_time_lt(j, md_size); + } + +/* Now rotate the MAC */ +#if defined(CBC_MAC_ROTATE_IN_PLACE) + j = 0; + for (i = 0; i < md_size; i++) { + /* in case cache-line is 32 bytes, touch second line */ + ((volatile uint8_t *)rotated_mac)[rotate_offset ^ 32]; + out[j++] = rotated_mac[rotate_offset++]; + rotate_offset &= constant_time_lt(rotate_offset, md_size); + } +#else + memset(out, 0, md_size); + rotate_offset = md_size - rotate_offset; + rotate_offset &= constant_time_lt(rotate_offset, md_size); + for (i = 0; i < md_size; i++) { + for (j = 0; j < md_size; j++) { + out[j] |= rotated_mac[i] & constant_time_eq_8(j, rotate_offset); + } + rotate_offset++; + rotate_offset &= constant_time_lt(rotate_offset, md_size); + } +#endif +} + +/* u32toBE serialises an unsigned, 32-bit number (n) as four bytes at (p) in + * big-endian order. The value of p is advanced by four. */ +#define u32toBE(n, p) \ + (*((p)++)=(uint8_t)(n>>24), \ + *((p)++)=(uint8_t)(n>>16), \ + *((p)++)=(uint8_t)(n>>8), \ + *((p)++)=(uint8_t)(n)) + +/* u64toBE serialises an unsigned, 64-bit number (n) as eight bytes at (p) in + * big-endian order. The value of p is advanced by eight. */ +#define u64toBE(n, p) \ + (*((p)++)=(uint8_t)(n>>56), \ + *((p)++)=(uint8_t)(n>>48), \ + *((p)++)=(uint8_t)(n>>40), \ + *((p)++)=(uint8_t)(n>>32), \ + *((p)++)=(uint8_t)(n>>24), \ + *((p)++)=(uint8_t)(n>>16), \ + *((p)++)=(uint8_t)(n>>8), \ + *((p)++)=(uint8_t)(n)) + +/* These functions serialize the state of a hash and thus perform the standard + * "final" operation without adding the padding and length that such a function + * typically does. */ +static void tls1_sha1_final_raw(void *ctx, uint8_t *md_out) { + SHA_CTX *sha1 = ctx; + u32toBE(sha1->h0, md_out); + u32toBE(sha1->h1, md_out); + u32toBE(sha1->h2, md_out); + u32toBE(sha1->h3, md_out); + u32toBE(sha1->h4, md_out); +} +#define LARGEST_DIGEST_CTX SHA_CTX + +static void tls1_sha256_final_raw(void *ctx, uint8_t *md_out) { + SHA256_CTX *sha256 = ctx; + unsigned i; + + for (i = 0; i < 8; i++) { + u32toBE(sha256->h[i], md_out); + } +} +#undef LARGEST_DIGEST_CTX +#define LARGEST_DIGEST_CTX SHA256_CTX + +static void tls1_sha512_final_raw(void *ctx, uint8_t *md_out) { + SHA512_CTX *sha512 = ctx; + unsigned i; + + for (i = 0; i < 8; i++) { + u64toBE(sha512->h[i], md_out); + } +} +#undef LARGEST_DIGEST_CTX +#define LARGEST_DIGEST_CTX SHA512_CTX + +int EVP_tls_cbc_record_digest_supported(const EVP_MD *md) { + switch (EVP_MD_type(md)) { + case NID_sha1: + case NID_sha256: + case NID_sha384: + return 1; + + default: + return 0; + } +} + +int EVP_tls_cbc_digest_record(const EVP_MD *md, uint8_t *md_out, + size_t *md_out_size, const uint8_t header[13], + const uint8_t *data, size_t data_plus_mac_size, + size_t data_plus_mac_plus_padding_size, + const uint8_t *mac_secret, + unsigned mac_secret_length) { + union { + double align; + uint8_t c[sizeof(LARGEST_DIGEST_CTX)]; + } md_state; + void (*md_final_raw)(void *ctx, uint8_t *md_out); + void (*md_transform)(void *ctx, const uint8_t *block); + unsigned md_size, md_block_size = 64; + unsigned len, max_mac_bytes, num_blocks, num_starting_blocks, k, + mac_end_offset, c, index_a, index_b; + unsigned int bits; /* at most 18 bits */ + uint8_t length_bytes[MAX_HASH_BIT_COUNT_BYTES]; + /* hmac_pad is the masked HMAC key. */ + uint8_t hmac_pad[MAX_HASH_BLOCK_SIZE]; + uint8_t first_block[MAX_HASH_BLOCK_SIZE]; + uint8_t mac_out[EVP_MAX_MD_SIZE]; + unsigned i, j, md_out_size_u; + EVP_MD_CTX md_ctx; + /* mdLengthSize is the number of bytes in the length field that terminates + * the hash. */ + unsigned md_length_size = 8; + + /* This is a, hopefully redundant, check that allows us to forget about + * many possible overflows later in this function. */ + assert(data_plus_mac_plus_padding_size < 1024 * 1024); + + switch (EVP_MD_type(md)) { + case NID_sha1: + SHA1_Init((SHA_CTX *)md_state.c); + md_final_raw = tls1_sha1_final_raw; + md_transform = + (void (*)(void *ctx, const uint8_t *block))SHA1_Transform; + md_size = 20; + break; + + case NID_sha256: + SHA256_Init((SHA256_CTX *)md_state.c); + md_final_raw = tls1_sha256_final_raw; + md_transform = + (void (*)(void *ctx, const uint8_t *block))SHA256_Transform; + md_size = 32; + break; + + case NID_sha384: + SHA384_Init((SHA512_CTX *)md_state.c); + md_final_raw = tls1_sha512_final_raw; + md_transform = + (void (*)(void *ctx, const uint8_t *block))SHA512_Transform; + md_size = 384 / 8; + md_block_size = 128; + md_length_size = 16; + break; + + default: + /* EVP_tls_cbc_record_digest_supported should have been called first to + * check that the hash function is supported. */ + assert(0); + *md_out_size = 0; + return 0; + } + + assert(md_length_size <= MAX_HASH_BIT_COUNT_BYTES); + assert(md_block_size <= MAX_HASH_BLOCK_SIZE); + assert(md_size <= EVP_MAX_MD_SIZE); + + static const unsigned kHeaderLength = 13; + + /* kVarianceBlocks is the number of blocks of the hash that we have to + * calculate in constant time because they could be altered by the + * padding value. + * + * TLSv1 has MACs up to 48 bytes long (SHA-384) and the padding is not + * required to be minimal. Therefore we say that the final six blocks + * can vary based on the padding. */ + static const unsigned kVarianceBlocks = 6; + + /* From now on we're dealing with the MAC, which conceptually has 13 + * bytes of `header' before the start of the data. */ + len = data_plus_mac_plus_padding_size + kHeaderLength; + /* max_mac_bytes contains the maximum bytes of bytes in the MAC, including + * |header|, assuming that there's no padding. */ + max_mac_bytes = len - md_size - 1; + /* num_blocks is the maximum number of hash blocks. */ + num_blocks = + (max_mac_bytes + 1 + md_length_size + md_block_size - 1) / md_block_size; + /* In order to calculate the MAC in constant time we have to handle + * the final blocks specially because the padding value could cause the + * end to appear somewhere in the final |kVarianceBlocks| blocks and we + * can't leak where. However, |num_starting_blocks| worth of data can + * be hashed right away because no padding value can affect whether + * they are plaintext. */ + num_starting_blocks = 0; + /* k is the starting byte offset into the conceptual header||data where + * we start processing. */ + k = 0; + /* mac_end_offset is the index just past the end of the data to be + * MACed. */ + mac_end_offset = data_plus_mac_size + kHeaderLength - md_size; + /* c is the index of the 0x80 byte in the final hash block that + * contains application data. */ + c = mac_end_offset % md_block_size; + /* index_a is the hash block number that contains the 0x80 terminating + * value. */ + index_a = mac_end_offset / md_block_size; + /* index_b is the hash block number that contains the 64-bit hash + * length, in bits. */ + index_b = (mac_end_offset + md_length_size) / md_block_size; + /* bits is the hash-length in bits. It includes the additional hash + * block for the masked HMAC key. */ + + if (num_blocks > kVarianceBlocks) { + num_starting_blocks = num_blocks - kVarianceBlocks; + k = md_block_size * num_starting_blocks; + } + + bits = 8 * mac_end_offset; + + /* Compute the initial HMAC block. */ + bits += 8 * md_block_size; + memset(hmac_pad, 0, md_block_size); + assert(mac_secret_length <= sizeof(hmac_pad)); + memcpy(hmac_pad, mac_secret, mac_secret_length); + for (i = 0; i < md_block_size; i++) { + hmac_pad[i] ^= 0x36; + } + + md_transform(md_state.c, hmac_pad); + + memset(length_bytes, 0, md_length_size - 4); + length_bytes[md_length_size - 4] = (uint8_t)(bits >> 24); + length_bytes[md_length_size - 3] = (uint8_t)(bits >> 16); + length_bytes[md_length_size - 2] = (uint8_t)(bits >> 8); + length_bytes[md_length_size - 1] = (uint8_t)bits; + + if (k > 0) { + /* k is a multiple of md_block_size. */ + memcpy(first_block, header, 13); + memcpy(first_block + 13, data, md_block_size - 13); + md_transform(md_state.c, first_block); + for (i = 1; i < k / md_block_size; i++) { + md_transform(md_state.c, data + md_block_size * i - 13); + } + } + + memset(mac_out, 0, sizeof(mac_out)); + + /* We now process the final hash blocks. For each block, we construct + * it in constant time. If the |i==index_a| then we'll include the 0x80 + * bytes and zero pad etc. For each block we selectively copy it, in + * constant time, to |mac_out|. */ + for (i = num_starting_blocks; i <= num_starting_blocks + kVarianceBlocks; + i++) { + uint8_t block[MAX_HASH_BLOCK_SIZE]; + uint8_t is_block_a = constant_time_eq_8(i, index_a); + uint8_t is_block_b = constant_time_eq_8(i, index_b); + for (j = 0; j < md_block_size; j++) { + uint8_t b = 0, is_past_c, is_past_cp1; + if (k < kHeaderLength) { + b = header[k]; + } else if (k < data_plus_mac_plus_padding_size + kHeaderLength) { + b = data[k - kHeaderLength]; + } + k++; + + is_past_c = is_block_a & constant_time_ge_8(j, c); + is_past_cp1 = is_block_a & constant_time_ge_8(j, c + 1); + /* If this is the block containing the end of the + * application data, and we are at the offset for the + * 0x80 value, then overwrite b with 0x80. */ + b = constant_time_select_8(is_past_c, 0x80, b); + /* If this the the block containing the end of the + * application data and we're past the 0x80 value then + * just write zero. */ + b = b & ~is_past_cp1; + /* If this is index_b (the final block), but not + * index_a (the end of the data), then the 64-bit + * length didn't fit into index_a and we're having to + * add an extra block of zeros. */ + b &= ~is_block_b | is_block_a; + + /* The final bytes of one of the blocks contains the + * length. */ + if (j >= md_block_size - md_length_size) { + /* If this is index_b, write a length byte. */ + b = constant_time_select_8( + is_block_b, length_bytes[j - (md_block_size - md_length_size)], b); + } + block[j] = b; + } + + md_transform(md_state.c, block); + md_final_raw(md_state.c, block); + /* If this is index_b, copy the hash value to |mac_out|. */ + for (j = 0; j < md_size; j++) { + mac_out[j] |= block[j] & is_block_b; + } + } + + EVP_MD_CTX_init(&md_ctx); + if (!EVP_DigestInit_ex(&md_ctx, md, NULL /* engine */)) { + EVP_MD_CTX_cleanup(&md_ctx); + return 0; + } + + /* Complete the HMAC in the standard manner. */ + for (i = 0; i < md_block_size; i++) { + hmac_pad[i] ^= 0x6a; + } + + EVP_DigestUpdate(&md_ctx, hmac_pad, md_block_size); + EVP_DigestUpdate(&md_ctx, mac_out, md_size); + EVP_DigestFinal(&md_ctx, md_out, &md_out_size_u); + *md_out_size = md_out_size_u; + EVP_MD_CTX_cleanup(&md_ctx); + + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/cmac/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/cmac/CMakeLists.txt new file mode 100644 index 00000000..4629af60 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cmac/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories(. .. ../../include) + +add_library( + cmac + + OBJECT + + cmac.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/cmac/cmac.c b/TMessagesProj/jni/boringssl/crypto/cmac/cmac.c new file mode 100644 index 00000000..fa4c3c49 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cmac/cmac.c @@ -0,0 +1,239 @@ +/* ==================================================================== + * Copyright (c) 2010 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== */ + +#include + +#include +#include + +#include +#include +#include + + +struct cmac_ctx_st { + EVP_CIPHER_CTX cipher_ctx; + /* k1 and k2 are the CMAC subkeys. See + * https://tools.ietf.org/html/rfc4493#section-2.3 */ + uint8_t k1[AES_BLOCK_SIZE]; + uint8_t k2[AES_BLOCK_SIZE]; + /* Last (possibly partial) scratch */ + uint8_t block[AES_BLOCK_SIZE]; + /* block_used contains the number of valid bytes in |block|. */ + unsigned block_used; +}; + +static void CMAC_CTX_init(CMAC_CTX *ctx) { + EVP_CIPHER_CTX_init(&ctx->cipher_ctx); +} + +static void CMAC_CTX_cleanup(CMAC_CTX *ctx) { + EVP_CIPHER_CTX_cleanup(&ctx->cipher_ctx); + OPENSSL_cleanse(ctx->k1, sizeof(ctx->k1)); + OPENSSL_cleanse(ctx->k2, sizeof(ctx->k2)); + OPENSSL_cleanse(ctx->block, sizeof(ctx->block)); +} + +int AES_CMAC(uint8_t out[16], const uint8_t *key, size_t key_len, + const uint8_t *in, size_t in_len) { + const EVP_CIPHER *cipher; + switch (key_len) { + case 16: + cipher = EVP_aes_128_cbc(); + break; + case 32: + cipher = EVP_aes_256_cbc(); + break; + default: + return 0; + } + + size_t scratch_out_len; + CMAC_CTX ctx; + CMAC_CTX_init(&ctx); + + const int ok = CMAC_Init(&ctx, key, key_len, cipher, NULL /* engine */) && + CMAC_Update(&ctx, in, in_len) && + CMAC_Final(&ctx, out, &scratch_out_len); + + CMAC_CTX_cleanup(&ctx); + return ok; +} + +CMAC_CTX *CMAC_CTX_new(void) { + CMAC_CTX *ctx = OPENSSL_malloc(sizeof(*ctx)); + if (ctx != NULL) { + CMAC_CTX_init(ctx); + } + return ctx; +} + +void CMAC_CTX_free(CMAC_CTX *ctx) { + if (ctx == NULL) { + return; + } + + CMAC_CTX_cleanup(ctx); + OPENSSL_free(ctx); +} + +/* binary_field_mul_x treats the 128 bits at |in| as an element of GF(2¹²⁸) + * with a hard-coded reduction polynomial and sets |out| as x times the + * input. + * + * See https://tools.ietf.org/html/rfc4493#section-2.3 */ +static void binary_field_mul_x(uint8_t out[16], const uint8_t in[16]) { + unsigned i; + + /* Shift |in| to left, including carry. */ + for (i = 0; i < 15; i++) { + out[i] = (in[i] << 1) | (in[i+1] >> 7); + } + + /* If MSB set fixup with R. */ + const uint8_t carry = in[0] >> 7; + out[i] = (in[i] << 1) ^ ((0 - carry) & 0x87); +} + +static const uint8_t kZeroIV[AES_BLOCK_SIZE] = {0}; + +int CMAC_Init(CMAC_CTX *ctx, const void *key, size_t key_len, + const EVP_CIPHER *cipher, ENGINE *engine) { + uint8_t scratch[AES_BLOCK_SIZE]; + + if (EVP_CIPHER_block_size(cipher) != AES_BLOCK_SIZE || + EVP_CIPHER_key_length(cipher) != key_len || + !EVP_EncryptInit_ex(&ctx->cipher_ctx, cipher, NULL, key, kZeroIV) || + !EVP_Cipher(&ctx->cipher_ctx, scratch, kZeroIV, AES_BLOCK_SIZE) || + /* Reset context again ready for first data. */ + !EVP_EncryptInit_ex(&ctx->cipher_ctx, NULL, NULL, NULL, kZeroIV)) { + return 0; + } + + binary_field_mul_x(ctx->k1, scratch); + binary_field_mul_x(ctx->k2, ctx->k1); + ctx->block_used = 0; + + return 1; +} + +int CMAC_Reset(CMAC_CTX *ctx) { + ctx->block_used = 0; + return EVP_EncryptInit_ex(&ctx->cipher_ctx, NULL, NULL, NULL, kZeroIV); +} + +int CMAC_Update(CMAC_CTX *ctx, const uint8_t *in, size_t in_len) { + uint8_t scratch[AES_BLOCK_SIZE]; + + if (ctx->block_used > 0) { + size_t todo = AES_BLOCK_SIZE - ctx->block_used; + if (in_len < todo) { + todo = in_len; + } + + memcpy(ctx->block + ctx->block_used, in, todo); + in += todo; + in_len -= todo; + ctx->block_used += todo; + + /* If |in_len| is zero then either |ctx->block_used| is less than + * |AES_BLOCK_SIZE|, in which case we can stop here, or |ctx->block_used| + * is exactly |AES_BLOCK_SIZE| but there's no more data to process. In the + * latter case we don't want to process this block now because it might be + * the last block and that block is treated specially. */ + if (in_len == 0) { + return 1; + } + + assert(ctx->block_used == AES_BLOCK_SIZE); + + if (!EVP_Cipher(&ctx->cipher_ctx, scratch, ctx->block, AES_BLOCK_SIZE)) { + return 0; + } + } + + /* Encrypt all but one of the remaining blocks. */ + while (in_len > AES_BLOCK_SIZE) { + if (!EVP_Cipher(&ctx->cipher_ctx, scratch, in, AES_BLOCK_SIZE)) { + return 0; + } + in += AES_BLOCK_SIZE; + in_len -= AES_BLOCK_SIZE; + } + + memcpy(ctx->block, in, in_len); + ctx->block_used = in_len; + + return 1; +} + +int CMAC_Final(CMAC_CTX *ctx, uint8_t *out, size_t *out_len) { + *out_len = AES_BLOCK_SIZE; + if (out == NULL) { + return 1; + } + + const uint8_t *mask = ctx->k1; + + if (ctx->block_used != AES_BLOCK_SIZE) { + /* If the last block is incomplete, terminate it with a single 'one' bit + * followed by zeros. */ + ctx->block[ctx->block_used] = 0x80; + memset(ctx->block + ctx->block_used + 1, 0, + AES_BLOCK_SIZE - (ctx->block_used + 1)); + + mask = ctx->k2; + } + + unsigned i; + for (i = 0; i < AES_BLOCK_SIZE; i++) { + out[i] = ctx->block[i] ^ mask[i]; + } + + return EVP_Cipher(&ctx->cipher_ctx, out, out, AES_BLOCK_SIZE); +} diff --git a/TMessagesProj/jni/boringssl/crypto/conf/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/conf/CMakeLists.txt new file mode 100644 index 00000000..8046bb84 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/conf/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories(. .. ../../include) + +add_library( + conf + + OBJECT + + conf.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/conf/conf.c b/TMessagesProj/jni/boringssl/crypto/conf/conf.c new file mode 100644 index 00000000..cd6b5652 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/conf/conf.c @@ -0,0 +1,774 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include +#include +#include + +#include "conf_def.h" + + +static uint32_t conf_value_hash(const CONF_VALUE *v) { + return (lh_strhash(v->section) << 2) ^ lh_strhash(v->name); +} + +static int conf_value_cmp(const CONF_VALUE *a, const CONF_VALUE *b) { + int i; + + if (a->section != b->section) { + i = strcmp(a->section, b->section); + if (i) { + return i; + } + } + + if (a->name != NULL && b->name != NULL) { + return strcmp(a->name, b->name); + } else if (a->name == b->name) { + return 0; + } else { + return (a->name == NULL) ? -1 : 1; + } +} + +CONF *NCONF_new(void *method) { + CONF *conf; + + if (method != NULL) { + return NULL; + } + + conf = OPENSSL_malloc(sizeof(CONF)); + if (conf == NULL) { + return NULL; + } + + conf->data = lh_CONF_VALUE_new(conf_value_hash, conf_value_cmp); + if (conf->data == NULL) { + OPENSSL_free(conf); + return NULL; + } + + return conf; +} + +static void value_free_contents(CONF_VALUE *value) { + if (value->section) { + OPENSSL_free(value->section); + } + if (value->name) { + OPENSSL_free(value->name); + if (value->value) { + OPENSSL_free(value->value); + } + } else { + if (value->value) { + sk_CONF_VALUE_free((STACK_OF(CONF_VALUE)*)value->value); + } + } +} + +static void value_free(CONF_VALUE *value) { + value_free_contents(value); + OPENSSL_free(value); +} + +void NCONF_free(CONF *conf) { + if (conf == NULL || conf->data == NULL) { + return; + } + + lh_CONF_VALUE_doall(conf->data, value_free_contents); + lh_CONF_VALUE_free(conf->data); + OPENSSL_free(conf); +} + +CONF_VALUE *NCONF_new_section(const CONF *conf, const char *section) { + STACK_OF(CONF_VALUE) *sk = NULL; + int ok = 0, i; + CONF_VALUE *v = NULL, *old_value; + + sk = sk_CONF_VALUE_new_null(); + v = OPENSSL_malloc(sizeof(CONF_VALUE)); + if (sk == NULL || v == NULL) { + goto err; + } + i = strlen(section) + 1; + v->section = OPENSSL_malloc(i); + if (v->section == NULL) { + goto err; + } + + memcpy(v->section, section, i); + v->section[i-1] = 0; + v->name = NULL; + v->value = (char *)sk; + + if (!lh_CONF_VALUE_insert(conf->data, &old_value, v)) { + goto err; + } + if (old_value) { + value_free(old_value); + } + ok = 1; + +err: + if (!ok) { + if (sk != NULL) { + sk_CONF_VALUE_free(sk); + } + if (v != NULL) { + OPENSSL_free(v); + } + v = NULL; + } + return v; +} + +static int str_copy(CONF *conf, char *section, char **pto, char *from) { + int q, r, rr = 0, to = 0, len = 0; + char *s, *e, *rp, *rrp, *np, *cp, v; + const char *p; + BUF_MEM *buf; + + buf = BUF_MEM_new(); + if (buf == NULL) { + return 0; + } + + len = strlen(from) + 1; + if (!BUF_MEM_grow(buf, len)) { + goto err; + } + + for (;;) { + if (IS_QUOTE(conf, *from)) { + q = *from; + from++; + while (!IS_EOF(conf, *from) && (*from != q)) { + if (IS_ESC(conf, *from)) { + from++; + if (IS_EOF(conf, *from)) { + break; + } + } + buf->data[to++] = *(from++); + } + if (*from == q) { + from++; + } + } else if (IS_DQUOTE(conf, *from)) { + q = *from; + from++; + while (!IS_EOF(conf, *from)) { + if (*from == q) { + if (*(from + 1) == q) { + from++; + } else { + break; + } + } + buf->data[to++] = *(from++); + } + if (*from == q) { + from++; + } + } else if (IS_ESC(conf, *from)) { + from++; + v = *(from++); + if (IS_EOF(conf, v)) { + break; + } else if (v == 'r') { + v = '\r'; + } else if (v == 'n') { + v = '\n'; + } else if (v == 'b') { + v = '\b'; + } else if (v == 't') { + v = '\t'; + } + buf->data[to++] = v; + } else if (IS_EOF(conf, *from)) { + break; + } else if (*from == '$') { + /* try to expand it */ + rrp = NULL; + s = &(from[1]); + if (*s == '{') { + q = '}'; + } else if (*s == '(') { + q = ')'; + } else { + q = 0; + } + + if (q) { + s++; + } + cp = section; + e = np = s; + while (IS_ALPHA_NUMERIC(conf, *e)) { + e++; + } + if (e[0] == ':' && e[1] == ':') { + cp = np; + rrp = e; + rr = *e; + *rrp = '\0'; + e += 2; + np = e; + while (IS_ALPHA_NUMERIC(conf, *e)) { + e++; + } + } + r = *e; + *e = '\0'; + rp = e; + if (q) { + if (r != q) { + OPENSSL_PUT_ERROR(CONF, CONF_R_NO_CLOSE_BRACE); + goto err; + } + e++; + } + /* So at this point we have + * np which is the start of the name string which is + * '\0' terminated. + * cp which is the start of the section string which is + * '\0' terminated. + * e is the 'next point after'. + * r and rr are the chars replaced by the '\0' + * rp and rrp is where 'r' and 'rr' came from. */ + p = NCONF_get_string(conf, cp, np); + if (rrp != NULL) { + *rrp = rr; + } + *rp = r; + if (p == NULL) { + OPENSSL_PUT_ERROR(CONF, CONF_R_VARIABLE_HAS_NO_VALUE); + goto err; + } + BUF_MEM_grow_clean(buf, (strlen(p) + buf->length - (e - from))); + while (*p) { + buf->data[to++] = *(p++); + } + + /* Since we change the pointer 'from', we also have + to change the perceived length of the string it + points at. /RL */ + len -= e - from; + from = e; + + /* In case there were no braces or parenthesis around + the variable reference, we have to put back the + character that was replaced with a '\0'. /RL */ + *rp = r; + } else { + buf->data[to++] = *(from++); + } + } + + buf->data[to] = '\0'; + if (*pto != NULL) { + OPENSSL_free(*pto); + } + *pto = buf->data; + OPENSSL_free(buf); + return 1; + +err: + if (buf != NULL) { + BUF_MEM_free(buf); + } + return 0; +} + +static CONF_VALUE *get_section(const CONF *conf, const char *section) { + CONF_VALUE template; + + memset(&template, 0, sizeof(template)); + template.section = (char *) section; + return lh_CONF_VALUE_retrieve(conf->data, &template); +} + +STACK_OF(CONF_VALUE) *NCONF_get_section(const CONF *conf, const char *section) { + CONF_VALUE *section_value = get_section(conf, section); + if (section_value == NULL) { + return NULL; + } + return (STACK_OF(CONF_VALUE)*) section_value->value; +} + +const char *NCONF_get_string(const CONF *conf, const char *section, + const char *name) { + CONF_VALUE template, *value; + + memset(&template, 0, sizeof(template)); + template.section = (char *) section; + template.name = (char *) name; + value = lh_CONF_VALUE_retrieve(conf->data, &template); + if (value == NULL) { + return NULL; + } + return value->value; +} + +int add_string(const CONF *conf, CONF_VALUE *section, CONF_VALUE *value) { + STACK_OF(CONF_VALUE) *section_stack = (STACK_OF(CONF_VALUE)*) section->value; + CONF_VALUE *old_value; + + value->section = section->section; + if (!sk_CONF_VALUE_push(section_stack, value)) { + return 0; + } + + if (!lh_CONF_VALUE_insert(conf->data, &old_value, value)) { + return 0; + } + if (old_value != NULL) { + (void)sk_CONF_VALUE_delete_ptr(section_stack, old_value); + value_free(old_value); + } + + return 1; +} + +static char *eat_ws(CONF *conf, char *p) { + while (IS_WS(conf, *p) && !IS_EOF(conf, *p)) { + p++; + } + return p; +} + +#define scan_esc(conf, p) (((IS_EOF((conf), (p)[1])) ? ((p) + 1) : ((p) + 2))) + +static char *eat_alpha_numeric(CONF *conf, char *p) { + for (;;) { + if (IS_ESC(conf, *p)) { + p = scan_esc(conf, p); + continue; + } + if (!IS_ALPHA_NUMERIC_PUNCT(conf, *p)) { + return p; + } + p++; + } +} + +static char *scan_quote(CONF *conf, char *p) { + int q = *p; + + p++; + while (!IS_EOF(conf, *p) && *p != q) { + if (IS_ESC(conf, *p)) { + p++; + if (IS_EOF(conf, *p)) { + return p; + } + } + p++; + } + if (*p == q) { + p++; + } + return p; +} + + +static char *scan_dquote(CONF *conf, char *p) { + int q = *p; + + p++; + while (!(IS_EOF(conf, *p))) { + if (*p == q) { + if (*(p + 1) == q) { + p++; + } else { + break; + } + } + p++; + } + if (*p == q) { + p++; + } + return p; +} + +static void clear_comments(CONF *conf, char *p) { + for (;;) { + if (IS_FCOMMENT(conf, *p)) { + *p = '\0'; + return; + } + if (!IS_WS(conf, *p)) { + break; + } + p++; + } + + for (;;) { + if (IS_COMMENT(conf, *p)) { + *p = '\0'; + return; + } + if (IS_DQUOTE(conf, *p)) { + p = scan_dquote(conf, p); + continue; + } + if (IS_QUOTE(conf, *p)) { + p = scan_quote(conf, p); + continue; + } + if (IS_ESC(conf, *p)) { + p = scan_esc(conf, p); + continue; + } + if (IS_EOF(conf, *p)) { + return; + } else { + p++; + } + } +} + +static int def_load_bio(CONF *conf, BIO *in, long *out_error_line) { + static const size_t CONFBUFSIZE = 512; + int bufnum = 0, i, ii; + BUF_MEM *buff = NULL; + char *s, *p, *end; + int again; + long eline = 0; + char btmp[DECIMAL_SIZE(eline) + 1]; + CONF_VALUE *v = NULL, *tv; + CONF_VALUE *sv = NULL; + char *section = NULL, *buf; + char *start, *psection, *pname; + + if ((buff = BUF_MEM_new()) == NULL) { + OPENSSL_PUT_ERROR(CONF, ERR_R_BUF_LIB); + goto err; + } + + section = (char *)OPENSSL_malloc(10); + if (section == NULL) { + OPENSSL_PUT_ERROR(CONF, ERR_R_MALLOC_FAILURE); + goto err; + } + BUF_strlcpy(section, "default", 10); + + sv = NCONF_new_section(conf, section); + if (sv == NULL) { + OPENSSL_PUT_ERROR(CONF, CONF_R_UNABLE_TO_CREATE_NEW_SECTION); + goto err; + } + + bufnum = 0; + again = 0; + for (;;) { + if (!BUF_MEM_grow(buff, bufnum + CONFBUFSIZE)) { + OPENSSL_PUT_ERROR(CONF, ERR_R_BUF_LIB); + goto err; + } + p = &(buff->data[bufnum]); + *p = '\0'; + BIO_gets(in, p, CONFBUFSIZE - 1); + p[CONFBUFSIZE - 1] = '\0'; + ii = i = strlen(p); + if (i == 0 && !again) { + break; + } + again = 0; + while (i > 0) { + if ((p[i - 1] != '\r') && (p[i - 1] != '\n')) { + break; + } else { + i--; + } + } + /* we removed some trailing stuff so there is a new + * line on the end. */ + if (ii && i == ii) { + again = 1; /* long line */ + } else { + p[i] = '\0'; + eline++; /* another input line */ + } + + /* we now have a line with trailing \r\n removed */ + + /* i is the number of bytes */ + bufnum += i; + + v = NULL; + /* check for line continuation */ + if (bufnum >= 1) { + /* If we have bytes and the last char '\\' and + * second last char is not '\\' */ + p = &(buff->data[bufnum - 1]); + if (IS_ESC(conf, p[0]) && ((bufnum <= 1) || !IS_ESC(conf, p[-1]))) { + bufnum--; + again = 1; + } + } + if (again) { + continue; + } + bufnum = 0; + buf = buff->data; + + clear_comments(conf, buf); + s = eat_ws(conf, buf); + if (IS_EOF(conf, *s)) { + continue; /* blank line */ + } + if (*s == '[') { + char *ss; + + s++; + start = eat_ws(conf, s); + ss = start; + again: + end = eat_alpha_numeric(conf, ss); + p = eat_ws(conf, end); + if (*p != ']') { + if (*p != '\0' && ss != p) { + ss = p; + goto again; + } + OPENSSL_PUT_ERROR(CONF, CONF_R_MISSING_CLOSE_SQUARE_BRACKET); + goto err; + } + *end = '\0'; + if (!str_copy(conf, NULL, §ion, start)) { + goto err; + } + if ((sv = get_section(conf, section)) == NULL) { + sv = NCONF_new_section(conf, section); + } + if (sv == NULL) { + OPENSSL_PUT_ERROR(CONF, CONF_R_UNABLE_TO_CREATE_NEW_SECTION); + goto err; + } + continue; + } else { + pname = s; + psection = NULL; + end = eat_alpha_numeric(conf, s); + if ((end[0] == ':') && (end[1] == ':')) { + *end = '\0'; + end += 2; + psection = pname; + pname = end; + end = eat_alpha_numeric(conf, end); + } + p = eat_ws(conf, end); + if (*p != '=') { + OPENSSL_PUT_ERROR(CONF, CONF_R_MISSING_EQUAL_SIGN); + goto err; + } + *end = '\0'; + p++; + start = eat_ws(conf, p); + while (!IS_EOF(conf, *p)) { + p++; + } + p--; + while ((p != start) && (IS_WS(conf, *p))) { + p--; + } + p++; + *p = '\0'; + + if (!(v = (CONF_VALUE *)OPENSSL_malloc(sizeof(CONF_VALUE)))) { + OPENSSL_PUT_ERROR(CONF, ERR_R_MALLOC_FAILURE); + goto err; + } + if (psection == NULL) { + psection = section; + } + v->name = (char *)OPENSSL_malloc(strlen(pname) + 1); + v->value = NULL; + if (v->name == NULL) { + OPENSSL_PUT_ERROR(CONF, ERR_R_MALLOC_FAILURE); + goto err; + } + BUF_strlcpy(v->name, pname, strlen(pname) + 1); + if (!str_copy(conf, psection, &(v->value), start)) { + goto err; + } + + if (strcmp(psection, section) != 0) { + if ((tv = get_section(conf, psection)) == NULL) { + tv = NCONF_new_section(conf, psection); + } + if (tv == NULL) { + OPENSSL_PUT_ERROR(CONF, CONF_R_UNABLE_TO_CREATE_NEW_SECTION); + goto err; + } + } else { + tv = sv; + } + if (add_string(conf, tv, v) == 0) { + OPENSSL_PUT_ERROR(CONF, ERR_R_MALLOC_FAILURE); + goto err; + } + v = NULL; + } + } + if (buff != NULL) { + BUF_MEM_free(buff); + } + if (section != NULL) { + OPENSSL_free(section); + } + return 1; + +err: + if (buff != NULL) { + BUF_MEM_free(buff); + } + if (section != NULL) { + OPENSSL_free(section); + } + if (out_error_line != NULL) { + *out_error_line = eline; + } + BIO_snprintf(btmp, sizeof btmp, "%ld", eline); + ERR_add_error_data(2, "line ", btmp); + + if (v != NULL) { + if (v->name != NULL) { + OPENSSL_free(v->name); + } + if (v->value != NULL) { + OPENSSL_free(v->value); + } + if (v != NULL) { + OPENSSL_free(v); + } + } + return 0; +} + +int NCONF_load(CONF *conf, const char *filename, long *out_error_line) { + BIO *in = BIO_new_file(filename, "rb"); + int ret; + + if (in == NULL) { + OPENSSL_PUT_ERROR(CONF, ERR_R_SYS_LIB); + return 0; + } + + ret = def_load_bio(conf, in, out_error_line); + BIO_free(in); + + return ret; +} + +int NCONF_load_bio(CONF *conf, BIO *bio, long *out_error_line) { + return def_load_bio(conf, bio, out_error_line); +} + +int CONF_parse_list(const char *list, char sep, int remove_whitespace, + int (*list_cb)(const char *elem, int len, void *usr), + void *arg) { + int ret; + const char *lstart, *tmpend, *p; + + if (list == NULL) { + OPENSSL_PUT_ERROR(CONF, CONF_R_LIST_CANNOT_BE_NULL); + return 0; + } + + lstart = list; + for (;;) { + if (remove_whitespace) { + while (*lstart && isspace((unsigned char)*lstart)) { + lstart++; + } + } + p = strchr(lstart, sep); + if (p == lstart || !*lstart) { + ret = list_cb(NULL, 0, arg); + } else { + if (p) { + tmpend = p - 1; + } else { + tmpend = lstart + strlen(lstart) - 1; + } + if (remove_whitespace) { + while (isspace((unsigned char)*tmpend)) { + tmpend--; + } + } + ret = list_cb(lstart, tmpend - lstart + 1, arg); + } + if (ret <= 0) { + return ret; + } + if (p == NULL) { + return 1; + } + lstart = p + 1; + } +} diff --git a/TMessagesProj/jni/boringssl/crypto/conf/conf_def.h b/TMessagesProj/jni/boringssl/crypto/conf/conf_def.h new file mode 100644 index 00000000..b1e6ba63 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/conf/conf_def.h @@ -0,0 +1,127 @@ +/* crypto/conf/conf_def.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +/* THIS FILE WAS AUTOMAGICALLY GENERATED! + Please modify and use keysets.pl to regenerate it. */ + +#define CONF_NUMBER 1 +#define CONF_UPPER 2 +#define CONF_LOWER 4 +#define CONF_UNDER 256 +#define CONF_PUNCTUATION 512 +#define CONF_WS 16 +#define CONF_ESC 32 +#define CONF_QUOTE 64 +#define CONF_DQUOTE 1024 +#define CONF_COMMENT 128 +#define CONF_FCOMMENT 2048 +#define CONF_EOF 8 +#define CONF_HIGHBIT 4096 +#define CONF_ALPHA (CONF_UPPER|CONF_LOWER) +#define CONF_ALPHA_NUMERIC (CONF_ALPHA|CONF_NUMBER|CONF_UNDER) +#define CONF_ALPHA_NUMERIC_PUNCT (CONF_ALPHA|CONF_NUMBER|CONF_UNDER| \ + CONF_PUNCTUATION) + +#define KEYTYPES(c) CONF_type_default +#define IS_COMMENT(c,a) (KEYTYPES(c)[(a)&0xff]&CONF_COMMENT) +#define IS_FCOMMENT(c,a) (KEYTYPES(c)[(a)&0xff]&CONF_FCOMMENT) +#define IS_EOF(c,a) (KEYTYPES(c)[(a)&0xff]&CONF_EOF) +#define IS_ESC(c,a) (KEYTYPES(c)[(a)&0xff]&CONF_ESC) +#define IS_NUMBER(c,a) (KEYTYPES(c)[(a)&0xff]&CONF_NUMBER) +#define IS_WS(c,a) (KEYTYPES(c)[(a)&0xff]&CONF_WS) +#define IS_ALPHA_NUMERIC(c,a) (KEYTYPES(c)[(a)&0xff]&CONF_ALPHA_NUMERIC) +#define IS_ALPHA_NUMERIC_PUNCT(c,a) \ + (KEYTYPES(c)[(a)&0xff]&CONF_ALPHA_NUMERIC_PUNCT) +#define IS_QUOTE(c,a) (KEYTYPES(c)[(a)&0xff]&CONF_QUOTE) +#define IS_DQUOTE(c,a) (KEYTYPES(c)[(a)&0xff]&CONF_DQUOTE) +#define IS_HIGHBIT(c,a) (KEYTYPES(c)[(a)&0xff]&CONF_HIGHBIT) + +static const unsigned short CONF_type_default[256]={ + 0x0008,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0010,0x0010,0x0000,0x0000,0x0010,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0010,0x0200,0x0040,0x0080,0x0000,0x0200,0x0200,0x0040, + 0x0000,0x0000,0x0200,0x0200,0x0200,0x0200,0x0200,0x0200, + 0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001, + 0x0001,0x0001,0x0000,0x0200,0x0000,0x0000,0x0000,0x0200, + 0x0200,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002, + 0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002, + 0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002, + 0x0002,0x0002,0x0002,0x0000,0x0020,0x0000,0x0200,0x0100, + 0x0040,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004, + 0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004, + 0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004, + 0x0004,0x0004,0x0004,0x0000,0x0200,0x0000,0x0200,0x0000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + }; diff --git a/TMessagesProj/jni/boringssl/crypto/cpu-arm-asm.S b/TMessagesProj/jni/boringssl/crypto/cpu-arm-asm.S new file mode 100644 index 00000000..faf3ad89 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cpu-arm-asm.S @@ -0,0 +1,32 @@ +# Copyright (c) 2014, Google Inc. +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#if !defined(OPENSSL_NO_ASM) && defined(__arm__) + +.syntax unified +.cpu cortex-a8 +.fpu neon +.text +.thumb +.align 2 +.global CRYPTO_arm_neon_probe +.hidden CRYPTO_arm_neon_probe +.type CRYPTO_arm_neon_probe, %function +.thumb_func +CRYPTO_arm_neon_probe: + vorr q1, q1, q1 + bx lr +.section .note.GNU-stack,"",%progbits + +#endif /* !OPENSSL_NO_ASM && __arm__ */ diff --git a/TMessagesProj/jni/boringssl/crypto/cpu-arm.c b/TMessagesProj/jni/boringssl/crypto/cpu-arm.c new file mode 100644 index 00000000..31b7de08 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cpu-arm.c @@ -0,0 +1,189 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#if defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) + +#include +#include + +#if !defined(OPENSSL_TRUSTY) +#include +#include +#endif + +#include "arm_arch.h" + + +/* We can't include because the Android SDK version against which + * Chromium builds is too old to have it. Instead we define all the constants + * that we need and have a weak pointer to getauxval. */ + +unsigned long getauxval(unsigned long type) __attribute__((weak)); + +char CRYPTO_is_NEON_capable(void) { + return (OPENSSL_armcap_P & ARMV7_NEON) != 0; +} + +static char g_set_neon_called = 0; + +void CRYPTO_set_NEON_capable(char neon_capable) { + g_set_neon_called = 1; + + if (neon_capable) { + OPENSSL_armcap_P |= ARMV7_NEON; + } else { + OPENSSL_armcap_P &= ~ARMV7_NEON; + } +} + +char CRYPTO_is_NEON_functional(void) { + static const uint32_t kWantFlags = ARMV7_NEON | ARMV7_NEON_FUNCTIONAL; + return (OPENSSL_armcap_P & kWantFlags) == kWantFlags; +} + +void CRYPTO_set_NEON_functional(char neon_functional) { + if (neon_functional) { + OPENSSL_armcap_P |= ARMV7_NEON_FUNCTIONAL; + } else { + OPENSSL_armcap_P &= ~ARMV7_NEON_FUNCTIONAL; + } +} + +#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_ARM) && !defined(OPENSSL_TRUSTY) + +static sigjmp_buf sigill_jmp; + +static void sigill_handler(int signal) { + siglongjmp(sigill_jmp, signal); +} + +void CRYPTO_arm_neon_probe(void); + +// probe_for_NEON returns 1 if a NEON instruction runs successfully. Because +// getauxval doesn't exist on Android until Jelly Bean, supporting NEON on +// older devices requires this. +static int probe_for_NEON(void) { + int supported = 0; + + sigset_t sigmask; + sigfillset(&sigmask); + sigdelset(&sigmask, SIGILL); + sigdelset(&sigmask, SIGTRAP); + sigdelset(&sigmask, SIGFPE); + sigdelset(&sigmask, SIGBUS); + sigdelset(&sigmask, SIGSEGV); + + struct sigaction sigill_original_action, sigill_action; + memset(&sigill_action, 0, sizeof(sigill_action)); + sigill_action.sa_handler = sigill_handler; + sigill_action.sa_mask = sigmask; + + sigset_t original_sigmask; + sigprocmask(SIG_SETMASK, &sigmask, &original_sigmask); + + if (sigsetjmp(sigill_jmp, 1 /* save signals */) == 0) { + sigaction(SIGILL, &sigill_action, &sigill_original_action); + + // This function cannot be inline asm because GCC will refuse to compile + // inline NEON instructions unless building with -mfpu=neon, which would + // defeat the point of probing for support at runtime. + CRYPTO_arm_neon_probe(); + supported = 1; + } + // Note that Android up to and including Lollipop doesn't restore the signal + // mask correctly after returning from a sigsetjmp. So that would need to be + // set again here if more probes were added. + // See https://android-review.googlesource.com/#/c/127624/ + + sigaction(SIGILL, &sigill_original_action, NULL); + sigprocmask(SIG_SETMASK, &original_sigmask, NULL); + + return supported; +} + +#else + +static int probe_for_NEON(void) { + return 0; +} + +#endif /* !OPENSSL_NO_ASM && OPENSSL_ARM && !OPENSSL_TRUSTY */ + +void OPENSSL_cpuid_setup(void) { + if (getauxval == NULL) { + // On ARM, but not AArch64, try a NEON instruction and see whether it works + // in order to probe for NEON support. + // + // Note that |CRYPTO_is_NEON_capable| can be true even if + // |CRYPTO_set_NEON_capable| has never been called if the code was compiled + // with NEON support enabled (e.g. -mfpu=neon). + if (!g_set_neon_called && !CRYPTO_is_NEON_capable() && probe_for_NEON()) { + OPENSSL_armcap_P |= ARMV7_NEON; + } + return; + } + + static const unsigned long AT_HWCAP = 16; + unsigned long hwcap = getauxval(AT_HWCAP); + +#if defined(OPENSSL_ARM) + static const unsigned long kNEON = 1 << 12; + if ((hwcap & kNEON) == 0) { + return; + } + + /* In 32-bit mode, the ARMv8 feature bits are in a different aux vector + * value. */ + static const unsigned long AT_HWCAP2 = 26; + hwcap = getauxval(AT_HWCAP2); + + /* See /usr/include/asm/hwcap.h on an ARM installation for the source of + * these values. */ + static const unsigned long kAES = 1 << 0; + static const unsigned long kPMULL = 1 << 1; + static const unsigned long kSHA1 = 1 << 2; + static const unsigned long kSHA256 = 1 << 3; +#elif defined(OPENSSL_AARCH64) + /* See /usr/include/asm/hwcap.h on an aarch64 installation for the source of + * these values. */ + static const unsigned long kNEON = 1 << 1; + static const unsigned long kAES = 1 << 3; + static const unsigned long kPMULL = 1 << 4; + static const unsigned long kSHA1 = 1 << 5; + static const unsigned long kSHA256 = 1 << 6; + + if ((hwcap & kNEON) == 0) { + return; + } +#endif + + OPENSSL_armcap_P |= ARMV7_NEON; + + if (hwcap & kAES) { + OPENSSL_armcap_P |= ARMV8_AES; + } + if (hwcap & kPMULL) { + OPENSSL_armcap_P |= ARMV8_PMULL; + } + if (hwcap & kSHA1) { + OPENSSL_armcap_P |= ARMV8_SHA1; + } + if (hwcap & kSHA256) { + OPENSSL_armcap_P |= ARMV8_SHA256; + } +} + +#endif /* defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) */ diff --git a/TMessagesProj/jni/boringssl/crypto/cpu-intel.c b/TMessagesProj/jni/boringssl/crypto/cpu-intel.c new file mode 100644 index 00000000..924bab04 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cpu-intel.c @@ -0,0 +1,261 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#if !defined(__STDC_FORMAT_MACROS) +#define __STDC_FORMAT_MACROS +#endif + +#include + + +#if !defined(OPENSSL_NO_ASM) && (defined(OPENSSL_X86) || defined(OPENSSL_X86_64)) + +#include +#include +#include +#include + +#if defined(OPENSSL_WINDOWS) +#pragma warning(push, 3) +#include +#include +#pragma warning(pop) +#endif + + +/* OPENSSL_cpuid runs the cpuid instruction. |leaf| is passed in as EAX and ECX + * is set to zero. It writes EAX, EBX, ECX, and EDX to |*out_eax| through + * |*out_edx|. */ +static void OPENSSL_cpuid(uint32_t *out_eax, uint32_t *out_ebx, + uint32_t *out_ecx, uint32_t *out_edx, uint32_t leaf) { +#if defined(OPENSSL_WINDOWS) + int tmp[4]; + __cpuid(tmp, (int)leaf); + *out_eax = (uint32_t)tmp[0]; + *out_ebx = (uint32_t)tmp[1]; + *out_ecx = (uint32_t)tmp[2]; + *out_edx = (uint32_t)tmp[3]; +#elif defined(__pic__) && defined(OPENSSL_32_BIT) + /* Inline assembly may not clobber the PIC register. For 32-bit, this is EBX. + * See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47602. */ + __asm__ volatile ( + "xor %%ecx, %%ecx\n" + "mov %%ebx, %%edi\n" + "cpuid\n" + "xchg %%edi, %%ebx\n" + : "=a"(*out_eax), "=D"(*out_ebx), "=c"(*out_ecx), "=d"(*out_edx) + : "a"(leaf) + ); +#else + __asm__ volatile ( + "xor %%ecx, %%ecx\n" + "cpuid\n" + : "=a"(*out_eax), "=b"(*out_ebx), "=c"(*out_ecx), "=d"(*out_edx) + : "a"(leaf) + ); +#endif +} + +/* OPENSSL_xgetbv returns the value of an Intel Extended Control Register (XCR). + * Currently only XCR0 is defined by Intel so |xcr| should always be zero. */ +static uint64_t OPENSSL_xgetbv(uint32_t xcr) { +#if defined(OPENSSL_WINDOWS) + return (uint64_t)_xgetbv(xcr); +#else + uint32_t eax, edx; + __asm__ volatile ("xgetbv" : "=a"(eax), "=d"(edx) : "c"(xcr)); + return (((uint64_t)edx) << 32) | eax; +#endif +} + +/* handle_cpu_env applies the value from |in| to the CPUID values in |out[0]| + * and |out[1]|. See the comment in |OPENSSL_cpuid_setup| about this. */ +static void handle_cpu_env(uint32_t *out, const char *in) { + const int invert = in[0] == '~'; + uint64_t v; + + if (!sscanf(in + invert, "%" PRIi64, &v)) { + return; + } + + if (invert) { + out[0] &= ~v; + out[1] &= ~(v >> 32); + } else { + out[0] = v; + out[1] = v >> 32; + } +} + +void OPENSSL_cpuid_setup(void) { + /* Determine the vendor and maximum input value. */ + uint32_t eax, ebx, ecx, edx; + OPENSSL_cpuid(&eax, &ebx, &ecx, &edx, 0); + + uint32_t num_ids = eax; + + int is_intel = ebx == 0x756e6547 /* Genu */ && + edx == 0x49656e69 /* ineI */ && + ecx == 0x6c65746e /* ntel */; + int is_amd = ebx == 0x68747541 /* Auth */ && + edx == 0x69746e65 /* enti */ && + ecx == 0x444d4163 /* cAMD */; + + int has_amd_xop = 0; + if (is_amd) { + /* AMD-specific logic. + * See http://developer.amd.com/wordpress/media/2012/10/254811.pdf */ + OPENSSL_cpuid(&eax, &ebx, &ecx, &edx, 0x80000000); + uint32_t num_extended_ids = eax; + if (num_extended_ids >= 0x80000001) { + OPENSSL_cpuid(&eax, &ebx, &ecx, &edx, 0x80000001); + if (ecx & (1 << 11)) { + has_amd_xop = 1; + } + } + } + + uint32_t extended_features = 0; + if (num_ids >= 7) { + OPENSSL_cpuid(&eax, &ebx, &ecx, &edx, 7); + extended_features = ebx; + } + + /* Determine the number of cores sharing an L1 data cache to adjust the + * hyper-threading bit. */ + uint32_t cores_per_cache = 0; + if (is_amd) { + /* AMD CPUs never share an L1 data cache between threads but do set the HTT + * bit on multi-core CPUs. */ + cores_per_cache = 1; + } else if (num_ids >= 4) { + /* TODO(davidben): The Intel manual says this CPUID leaf enumerates all + * caches using ECX and doesn't say which is first. Does this matter? */ + OPENSSL_cpuid(&eax, &ebx, &ecx, &edx, 4); + cores_per_cache = 1 + ((eax >> 14) & 0xfff); + } + + OPENSSL_cpuid(&eax, &ebx, &ecx, &edx, 1); + + /* Adjust the hyper-threading bit. */ + if (edx & (1 << 28)) { + uint32_t num_logical_cores = (ebx >> 16) & 0xff; + if (cores_per_cache == 1 || num_logical_cores <= 1) { + edx &= ~(1 << 28); + } + } + + /* Reserved bit #20 was historically repurposed to control the in-memory + * representation of RC4 state. Always set it to zero. */ + edx &= ~(1 << 20); + + /* Reserved bit #30 is repurposed to signal an Intel CPU. */ + if (is_intel) { + edx |= (1 << 30); + } else { + edx &= ~(1 << 30); + } + + /* The SDBG bit is repurposed to denote AMD XOP support. */ + if (has_amd_xop) { + ecx |= (1 << 11); + } else { + ecx &= ~(1 << 11); + } + + uint64_t xcr0 = 0; + if (ecx & (1 << 27)) { + /* XCR0 may only be queried if the OSXSAVE bit is set. */ + xcr0 = OPENSSL_xgetbv(0); + } + /* See Intel manual, section 14.3. */ + if ((xcr0 & 6) != 6) { + /* YMM registers cannot be used. */ + ecx &= ~(1 << 28); /* AVX */ + ecx &= ~(1 << 12); /* FMA */ + ecx &= ~(1 << 11); /* AMD XOP */ + extended_features &= ~(1 << 5); /* AVX2 */ + } + + OPENSSL_ia32cap_P[0] = edx; + OPENSSL_ia32cap_P[1] = ecx; + OPENSSL_ia32cap_P[2] = extended_features; + OPENSSL_ia32cap_P[3] = 0; + + const char *env1, *env2; + env1 = getenv("OPENSSL_ia32cap"); + if (env1 == NULL) { + return; + } + + /* OPENSSL_ia32cap can contain zero, one or two values, separated with a ':'. + * Each value is a 64-bit, unsigned value which may start with "0x" to + * indicate a hex value. Prior to the 64-bit value, a '~' may be given. + * + * If '~' isn't present, then the value is taken as the result of the CPUID. + * Otherwise the value is inverted and ANDed with the probed CPUID result. + * + * The first value determines OPENSSL_ia32cap_P[0] and [1]. The second [2] + * and [3]. */ + + handle_cpu_env(&OPENSSL_ia32cap_P[0], env1); + env2 = strchr(env1, ':'); + if (env2 != NULL) { + handle_cpu_env(&OPENSSL_ia32cap_P[2], env2 + 1); + } +} + +#endif /* !OPENSSL_NO_ASM && (OPENSSL_X86 || OPENSSL_X86_64) */ diff --git a/TMessagesProj/jni/boringssl/crypto/crypto.c b/TMessagesProj/jni/boringssl/crypto/crypto.c new file mode 100644 index 00000000..d9bb07e9 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/crypto.c @@ -0,0 +1,112 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#include "internal.h" + + +#if !defined(OPENSSL_NO_ASM) && \ + (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \ + defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) +/* x86, x86_64 and the ARMs need to record the result of a cpuid call for the + * asm to work correctly, unless compiled without asm code. */ +#define NEED_CPUID + +#else + +/* Otherwise, don't emit a static initialiser. */ + +#if !defined(BORINGSSL_NO_STATIC_INITIALIZER) +#define BORINGSSL_NO_STATIC_INITIALIZER +#endif + +#endif /* !OPENSSL_NO_ASM && (OPENSSL_X86 || OPENSSL_X86_64 || + OPENSSL_ARM || OPENSSL_AARCH64) */ + + +/* The capability variables are defined in this file in order to work around a + * linker bug. When linking with a .a, if no symbols in a .o are referenced + * then the .o is discarded, even if it has constructor functions. + * + * This still means that any binaries that don't include some functionality + * that tests the capability values will still skip the constructor but, so + * far, the init constructor function only sets the capability variables. */ + +#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) +/* This value must be explicitly initialised to zero in order to work around a + * bug in libtool or the linker on OS X. + * + * If not initialised then it becomes a "common symbol". When put into an + * archive, linking on OS X will fail to resolve common symbols. By + * initialising it to zero, it becomes a "data symbol", which isn't so + * affected. */ +uint32_t OPENSSL_ia32cap_P[4] = {0}; +#elif defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) + +#include "arm_arch.h" + +#if defined(__ARM_NEON__) +uint32_t OPENSSL_armcap_P = ARMV7_NEON | ARMV7_NEON_FUNCTIONAL; +#else +uint32_t OPENSSL_armcap_P = ARMV7_NEON_FUNCTIONAL; +#endif + +#endif + + +#if defined(OPENSSL_WINDOWS) +#define OPENSSL_CDECL __cdecl +#else +#define OPENSSL_CDECL +#endif + +#if !defined(BORINGSSL_NO_STATIC_INITIALIZER) +#if !defined(OPENSSL_WINDOWS) +static void do_library_init(void) __attribute__ ((constructor)); +#else +#pragma section(".CRT$XCU", read) +static void __cdecl do_library_init(void); +__declspec(allocate(".CRT$XCU")) void(*library_init_constructor)(void) = + do_library_init; +#endif +#endif /* !BORINGSSL_NO_STATIC_INITIALIZER */ + +/* do_library_init is the actual initialization function. If + * BORINGSSL_NO_STATIC_INITIALIZER isn't defined, this is set as a static + * initializer. Otherwise, it is called by CRYPTO_library_init. */ +static void OPENSSL_CDECL do_library_init(void) { + /* WARNING: this function may only configure the capability variables. See the + * note above about the linker bug. */ +#if defined(NEED_CPUID) + OPENSSL_cpuid_setup(); +#endif +} + +void CRYPTO_library_init(void) { + /* TODO(davidben): It would be tidier if this build knob could be replaced + * with an internal lazy-init mechanism that would handle things correctly + * in-library. */ +#if defined(BORINGSSL_NO_STATIC_INITIALIZER) + do_library_init(); +#endif +} + +const char *SSLeay_version(int unused) { + return "BoringSSL"; +} + +unsigned long SSLeay(void) { + return OPENSSL_VERSION_NUMBER; +} diff --git a/TMessagesProj/jni/boringssl/crypto/des/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/des/CMakeLists.txt new file mode 100644 index 00000000..7d49ff3c --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/des/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories(. .. ../../include) + +add_library( + des + + OBJECT + + des.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/des/des.c b/TMessagesProj/jni/boringssl/crypto/des/des.c new file mode 100644 index 00000000..a5669a62 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/des/des.c @@ -0,0 +1,773 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include "internal.h" + + +static const uint32_t des_skb[8][64] = { + {/* for C bits (numbered as per FIPS 46) 1 2 3 4 5 6 */ + 0x00000000L, 0x00000010L, 0x20000000L, 0x20000010L, 0x00010000L, + 0x00010010L, 0x20010000L, 0x20010010L, 0x00000800L, 0x00000810L, + 0x20000800L, 0x20000810L, 0x00010800L, 0x00010810L, 0x20010800L, + 0x20010810L, 0x00000020L, 0x00000030L, 0x20000020L, 0x20000030L, + 0x00010020L, 0x00010030L, 0x20010020L, 0x20010030L, 0x00000820L, + 0x00000830L, 0x20000820L, 0x20000830L, 0x00010820L, 0x00010830L, + 0x20010820L, 0x20010830L, 0x00080000L, 0x00080010L, 0x20080000L, + 0x20080010L, 0x00090000L, 0x00090010L, 0x20090000L, 0x20090010L, + 0x00080800L, 0x00080810L, 0x20080800L, 0x20080810L, 0x00090800L, + 0x00090810L, 0x20090800L, 0x20090810L, 0x00080020L, 0x00080030L, + 0x20080020L, 0x20080030L, 0x00090020L, 0x00090030L, 0x20090020L, + 0x20090030L, 0x00080820L, 0x00080830L, 0x20080820L, 0x20080830L, + 0x00090820L, 0x00090830L, 0x20090820L, 0x20090830L, }, + {/* for C bits (numbered as per FIPS 46) 7 8 10 11 12 13 */ + 0x00000000L, 0x02000000L, 0x00002000L, 0x02002000L, 0x00200000L, + 0x02200000L, 0x00202000L, 0x02202000L, 0x00000004L, 0x02000004L, + 0x00002004L, 0x02002004L, 0x00200004L, 0x02200004L, 0x00202004L, + 0x02202004L, 0x00000400L, 0x02000400L, 0x00002400L, 0x02002400L, + 0x00200400L, 0x02200400L, 0x00202400L, 0x02202400L, 0x00000404L, + 0x02000404L, 0x00002404L, 0x02002404L, 0x00200404L, 0x02200404L, + 0x00202404L, 0x02202404L, 0x10000000L, 0x12000000L, 0x10002000L, + 0x12002000L, 0x10200000L, 0x12200000L, 0x10202000L, 0x12202000L, + 0x10000004L, 0x12000004L, 0x10002004L, 0x12002004L, 0x10200004L, + 0x12200004L, 0x10202004L, 0x12202004L, 0x10000400L, 0x12000400L, + 0x10002400L, 0x12002400L, 0x10200400L, 0x12200400L, 0x10202400L, + 0x12202400L, 0x10000404L, 0x12000404L, 0x10002404L, 0x12002404L, + 0x10200404L, 0x12200404L, 0x10202404L, 0x12202404L, }, + {/* for C bits (numbered as per FIPS 46) 14 15 16 17 19 20 */ + 0x00000000L, 0x00000001L, 0x00040000L, 0x00040001L, 0x01000000L, + 0x01000001L, 0x01040000L, 0x01040001L, 0x00000002L, 0x00000003L, + 0x00040002L, 0x00040003L, 0x01000002L, 0x01000003L, 0x01040002L, + 0x01040003L, 0x00000200L, 0x00000201L, 0x00040200L, 0x00040201L, + 0x01000200L, 0x01000201L, 0x01040200L, 0x01040201L, 0x00000202L, + 0x00000203L, 0x00040202L, 0x00040203L, 0x01000202L, 0x01000203L, + 0x01040202L, 0x01040203L, 0x08000000L, 0x08000001L, 0x08040000L, + 0x08040001L, 0x09000000L, 0x09000001L, 0x09040000L, 0x09040001L, + 0x08000002L, 0x08000003L, 0x08040002L, 0x08040003L, 0x09000002L, + 0x09000003L, 0x09040002L, 0x09040003L, 0x08000200L, 0x08000201L, + 0x08040200L, 0x08040201L, 0x09000200L, 0x09000201L, 0x09040200L, + 0x09040201L, 0x08000202L, 0x08000203L, 0x08040202L, 0x08040203L, + 0x09000202L, 0x09000203L, 0x09040202L, 0x09040203L, }, + {/* for C bits (numbered as per FIPS 46) 21 23 24 26 27 28 */ + 0x00000000L, 0x00100000L, 0x00000100L, 0x00100100L, 0x00000008L, + 0x00100008L, 0x00000108L, 0x00100108L, 0x00001000L, 0x00101000L, + 0x00001100L, 0x00101100L, 0x00001008L, 0x00101008L, 0x00001108L, + 0x00101108L, 0x04000000L, 0x04100000L, 0x04000100L, 0x04100100L, + 0x04000008L, 0x04100008L, 0x04000108L, 0x04100108L, 0x04001000L, + 0x04101000L, 0x04001100L, 0x04101100L, 0x04001008L, 0x04101008L, + 0x04001108L, 0x04101108L, 0x00020000L, 0x00120000L, 0x00020100L, + 0x00120100L, 0x00020008L, 0x00120008L, 0x00020108L, 0x00120108L, + 0x00021000L, 0x00121000L, 0x00021100L, 0x00121100L, 0x00021008L, + 0x00121008L, 0x00021108L, 0x00121108L, 0x04020000L, 0x04120000L, + 0x04020100L, 0x04120100L, 0x04020008L, 0x04120008L, 0x04020108L, + 0x04120108L, 0x04021000L, 0x04121000L, 0x04021100L, 0x04121100L, + 0x04021008L, 0x04121008L, 0x04021108L, 0x04121108L, }, + {/* for D bits (numbered as per FIPS 46) 1 2 3 4 5 6 */ + 0x00000000L, 0x10000000L, 0x00010000L, 0x10010000L, 0x00000004L, + 0x10000004L, 0x00010004L, 0x10010004L, 0x20000000L, 0x30000000L, + 0x20010000L, 0x30010000L, 0x20000004L, 0x30000004L, 0x20010004L, + 0x30010004L, 0x00100000L, 0x10100000L, 0x00110000L, 0x10110000L, + 0x00100004L, 0x10100004L, 0x00110004L, 0x10110004L, 0x20100000L, + 0x30100000L, 0x20110000L, 0x30110000L, 0x20100004L, 0x30100004L, + 0x20110004L, 0x30110004L, 0x00001000L, 0x10001000L, 0x00011000L, + 0x10011000L, 0x00001004L, 0x10001004L, 0x00011004L, 0x10011004L, + 0x20001000L, 0x30001000L, 0x20011000L, 0x30011000L, 0x20001004L, + 0x30001004L, 0x20011004L, 0x30011004L, 0x00101000L, 0x10101000L, + 0x00111000L, 0x10111000L, 0x00101004L, 0x10101004L, 0x00111004L, + 0x10111004L, 0x20101000L, 0x30101000L, 0x20111000L, 0x30111000L, + 0x20101004L, 0x30101004L, 0x20111004L, 0x30111004L, }, + {/* for D bits (numbered as per FIPS 46) 8 9 11 12 13 14 */ + 0x00000000L, 0x08000000L, 0x00000008L, 0x08000008L, 0x00000400L, + 0x08000400L, 0x00000408L, 0x08000408L, 0x00020000L, 0x08020000L, + 0x00020008L, 0x08020008L, 0x00020400L, 0x08020400L, 0x00020408L, + 0x08020408L, 0x00000001L, 0x08000001L, 0x00000009L, 0x08000009L, + 0x00000401L, 0x08000401L, 0x00000409L, 0x08000409L, 0x00020001L, + 0x08020001L, 0x00020009L, 0x08020009L, 0x00020401L, 0x08020401L, + 0x00020409L, 0x08020409L, 0x02000000L, 0x0A000000L, 0x02000008L, + 0x0A000008L, 0x02000400L, 0x0A000400L, 0x02000408L, 0x0A000408L, + 0x02020000L, 0x0A020000L, 0x02020008L, 0x0A020008L, 0x02020400L, + 0x0A020400L, 0x02020408L, 0x0A020408L, 0x02000001L, 0x0A000001L, + 0x02000009L, 0x0A000009L, 0x02000401L, 0x0A000401L, 0x02000409L, + 0x0A000409L, 0x02020001L, 0x0A020001L, 0x02020009L, 0x0A020009L, + 0x02020401L, 0x0A020401L, 0x02020409L, 0x0A020409L, }, + {/* for D bits (numbered as per FIPS 46) 16 17 18 19 20 21 */ + 0x00000000L, 0x00000100L, 0x00080000L, 0x00080100L, 0x01000000L, + 0x01000100L, 0x01080000L, 0x01080100L, 0x00000010L, 0x00000110L, + 0x00080010L, 0x00080110L, 0x01000010L, 0x01000110L, 0x01080010L, + 0x01080110L, 0x00200000L, 0x00200100L, 0x00280000L, 0x00280100L, + 0x01200000L, 0x01200100L, 0x01280000L, 0x01280100L, 0x00200010L, + 0x00200110L, 0x00280010L, 0x00280110L, 0x01200010L, 0x01200110L, + 0x01280010L, 0x01280110L, 0x00000200L, 0x00000300L, 0x00080200L, + 0x00080300L, 0x01000200L, 0x01000300L, 0x01080200L, 0x01080300L, + 0x00000210L, 0x00000310L, 0x00080210L, 0x00080310L, 0x01000210L, + 0x01000310L, 0x01080210L, 0x01080310L, 0x00200200L, 0x00200300L, + 0x00280200L, 0x00280300L, 0x01200200L, 0x01200300L, 0x01280200L, + 0x01280300L, 0x00200210L, 0x00200310L, 0x00280210L, 0x00280310L, + 0x01200210L, 0x01200310L, 0x01280210L, 0x01280310L, }, + {/* for D bits (numbered as per FIPS 46) 22 23 24 25 27 28 */ + 0x00000000L, 0x04000000L, 0x00040000L, 0x04040000L, 0x00000002L, + 0x04000002L, 0x00040002L, 0x04040002L, 0x00002000L, 0x04002000L, + 0x00042000L, 0x04042000L, 0x00002002L, 0x04002002L, 0x00042002L, + 0x04042002L, 0x00000020L, 0x04000020L, 0x00040020L, 0x04040020L, + 0x00000022L, 0x04000022L, 0x00040022L, 0x04040022L, 0x00002020L, + 0x04002020L, 0x00042020L, 0x04042020L, 0x00002022L, 0x04002022L, + 0x00042022L, 0x04042022L, 0x00000800L, 0x04000800L, 0x00040800L, + 0x04040800L, 0x00000802L, 0x04000802L, 0x00040802L, 0x04040802L, + 0x00002800L, 0x04002800L, 0x00042800L, 0x04042800L, 0x00002802L, + 0x04002802L, 0x00042802L, 0x04042802L, 0x00000820L, 0x04000820L, + 0x00040820L, 0x04040820L, 0x00000822L, 0x04000822L, 0x00040822L, + 0x04040822L, 0x00002820L, 0x04002820L, 0x00042820L, 0x04042820L, + 0x00002822L, 0x04002822L, 0x00042822L, 0x04042822L, }}; + +static const uint32_t DES_SPtrans[8][64] = { + {/* nibble 0 */ + 0x02080800L, 0x00080000L, 0x02000002L, 0x02080802L, 0x02000000L, + 0x00080802L, 0x00080002L, 0x02000002L, 0x00080802L, 0x02080800L, + 0x02080000L, 0x00000802L, 0x02000802L, 0x02000000L, 0x00000000L, + 0x00080002L, 0x00080000L, 0x00000002L, 0x02000800L, 0x00080800L, + 0x02080802L, 0x02080000L, 0x00000802L, 0x02000800L, 0x00000002L, + 0x00000800L, 0x00080800L, 0x02080002L, 0x00000800L, 0x02000802L, + 0x02080002L, 0x00000000L, 0x00000000L, 0x02080802L, 0x02000800L, + 0x00080002L, 0x02080800L, 0x00080000L, 0x00000802L, 0x02000800L, + 0x02080002L, 0x00000800L, 0x00080800L, 0x02000002L, 0x00080802L, + 0x00000002L, 0x02000002L, 0x02080000L, 0x02080802L, 0x00080800L, + 0x02080000L, 0x02000802L, 0x02000000L, 0x00000802L, 0x00080002L, + 0x00000000L, 0x00080000L, 0x02000000L, 0x02000802L, 0x02080800L, + 0x00000002L, 0x02080002L, 0x00000800L, 0x00080802L, }, + {/* nibble 1 */ + 0x40108010L, 0x00000000L, 0x00108000L, 0x40100000L, 0x40000010L, + 0x00008010L, 0x40008000L, 0x00108000L, 0x00008000L, 0x40100010L, + 0x00000010L, 0x40008000L, 0x00100010L, 0x40108000L, 0x40100000L, + 0x00000010L, 0x00100000L, 0x40008010L, 0x40100010L, 0x00008000L, + 0x00108010L, 0x40000000L, 0x00000000L, 0x00100010L, 0x40008010L, + 0x00108010L, 0x40108000L, 0x40000010L, 0x40000000L, 0x00100000L, + 0x00008010L, 0x40108010L, 0x00100010L, 0x40108000L, 0x40008000L, + 0x00108010L, 0x40108010L, 0x00100010L, 0x40000010L, 0x00000000L, + 0x40000000L, 0x00008010L, 0x00100000L, 0x40100010L, 0x00008000L, + 0x40000000L, 0x00108010L, 0x40008010L, 0x40108000L, 0x00008000L, + 0x00000000L, 0x40000010L, 0x00000010L, 0x40108010L, 0x00108000L, + 0x40100000L, 0x40100010L, 0x00100000L, 0x00008010L, 0x40008000L, + 0x40008010L, 0x00000010L, 0x40100000L, 0x00108000L, }, + {/* nibble 2 */ + 0x04000001L, 0x04040100L, 0x00000100L, 0x04000101L, 0x00040001L, + 0x04000000L, 0x04000101L, 0x00040100L, 0x04000100L, 0x00040000L, + 0x04040000L, 0x00000001L, 0x04040101L, 0x00000101L, 0x00000001L, + 0x04040001L, 0x00000000L, 0x00040001L, 0x04040100L, 0x00000100L, + 0x00000101L, 0x04040101L, 0x00040000L, 0x04000001L, 0x04040001L, + 0x04000100L, 0x00040101L, 0x04040000L, 0x00040100L, 0x00000000L, + 0x04000000L, 0x00040101L, 0x04040100L, 0x00000100L, 0x00000001L, + 0x00040000L, 0x00000101L, 0x00040001L, 0x04040000L, 0x04000101L, + 0x00000000L, 0x04040100L, 0x00040100L, 0x04040001L, 0x00040001L, + 0x04000000L, 0x04040101L, 0x00000001L, 0x00040101L, 0x04000001L, + 0x04000000L, 0x04040101L, 0x00040000L, 0x04000100L, 0x04000101L, + 0x00040100L, 0x04000100L, 0x00000000L, 0x04040001L, 0x00000101L, + 0x04000001L, 0x00040101L, 0x00000100L, 0x04040000L, }, + {/* nibble 3 */ + 0x00401008L, 0x10001000L, 0x00000008L, 0x10401008L, 0x00000000L, + 0x10400000L, 0x10001008L, 0x00400008L, 0x10401000L, 0x10000008L, + 0x10000000L, 0x00001008L, 0x10000008L, 0x00401008L, 0x00400000L, + 0x10000000L, 0x10400008L, 0x00401000L, 0x00001000L, 0x00000008L, + 0x00401000L, 0x10001008L, 0x10400000L, 0x00001000L, 0x00001008L, + 0x00000000L, 0x00400008L, 0x10401000L, 0x10001000L, 0x10400008L, + 0x10401008L, 0x00400000L, 0x10400008L, 0x00001008L, 0x00400000L, + 0x10000008L, 0x00401000L, 0x10001000L, 0x00000008L, 0x10400000L, + 0x10001008L, 0x00000000L, 0x00001000L, 0x00400008L, 0x00000000L, + 0x10400008L, 0x10401000L, 0x00001000L, 0x10000000L, 0x10401008L, + 0x00401008L, 0x00400000L, 0x10401008L, 0x00000008L, 0x10001000L, + 0x00401008L, 0x00400008L, 0x00401000L, 0x10400000L, 0x10001008L, + 0x00001008L, 0x10000000L, 0x10000008L, 0x10401000L, }, + {/* nibble 4 */ + 0x08000000L, 0x00010000L, 0x00000400L, 0x08010420L, 0x08010020L, + 0x08000400L, 0x00010420L, 0x08010000L, 0x00010000L, 0x00000020L, + 0x08000020L, 0x00010400L, 0x08000420L, 0x08010020L, 0x08010400L, + 0x00000000L, 0x00010400L, 0x08000000L, 0x00010020L, 0x00000420L, + 0x08000400L, 0x00010420L, 0x00000000L, 0x08000020L, 0x00000020L, + 0x08000420L, 0x08010420L, 0x00010020L, 0x08010000L, 0x00000400L, + 0x00000420L, 0x08010400L, 0x08010400L, 0x08000420L, 0x00010020L, + 0x08010000L, 0x00010000L, 0x00000020L, 0x08000020L, 0x08000400L, + 0x08000000L, 0x00010400L, 0x08010420L, 0x00000000L, 0x00010420L, + 0x08000000L, 0x00000400L, 0x00010020L, 0x08000420L, 0x00000400L, + 0x00000000L, 0x08010420L, 0x08010020L, 0x08010400L, 0x00000420L, + 0x00010000L, 0x00010400L, 0x08010020L, 0x08000400L, 0x00000420L, + 0x00000020L, 0x00010420L, 0x08010000L, 0x08000020L, }, + {/* nibble 5 */ + 0x80000040L, 0x00200040L, 0x00000000L, 0x80202000L, 0x00200040L, + 0x00002000L, 0x80002040L, 0x00200000L, 0x00002040L, 0x80202040L, + 0x00202000L, 0x80000000L, 0x80002000L, 0x80000040L, 0x80200000L, + 0x00202040L, 0x00200000L, 0x80002040L, 0x80200040L, 0x00000000L, + 0x00002000L, 0x00000040L, 0x80202000L, 0x80200040L, 0x80202040L, + 0x80200000L, 0x80000000L, 0x00002040L, 0x00000040L, 0x00202000L, + 0x00202040L, 0x80002000L, 0x00002040L, 0x80000000L, 0x80002000L, + 0x00202040L, 0x80202000L, 0x00200040L, 0x00000000L, 0x80002000L, + 0x80000000L, 0x00002000L, 0x80200040L, 0x00200000L, 0x00200040L, + 0x80202040L, 0x00202000L, 0x00000040L, 0x80202040L, 0x00202000L, + 0x00200000L, 0x80002040L, 0x80000040L, 0x80200000L, 0x00202040L, + 0x00000000L, 0x00002000L, 0x80000040L, 0x80002040L, 0x80202000L, + 0x80200000L, 0x00002040L, 0x00000040L, 0x80200040L, }, + {/* nibble 6 */ + 0x00004000L, 0x00000200L, 0x01000200L, 0x01000004L, 0x01004204L, + 0x00004004L, 0x00004200L, 0x00000000L, 0x01000000L, 0x01000204L, + 0x00000204L, 0x01004000L, 0x00000004L, 0x01004200L, 0x01004000L, + 0x00000204L, 0x01000204L, 0x00004000L, 0x00004004L, 0x01004204L, + 0x00000000L, 0x01000200L, 0x01000004L, 0x00004200L, 0x01004004L, + 0x00004204L, 0x01004200L, 0x00000004L, 0x00004204L, 0x01004004L, + 0x00000200L, 0x01000000L, 0x00004204L, 0x01004000L, 0x01004004L, + 0x00000204L, 0x00004000L, 0x00000200L, 0x01000000L, 0x01004004L, + 0x01000204L, 0x00004204L, 0x00004200L, 0x00000000L, 0x00000200L, + 0x01000004L, 0x00000004L, 0x01000200L, 0x00000000L, 0x01000204L, + 0x01000200L, 0x00004200L, 0x00000204L, 0x00004000L, 0x01004204L, + 0x01000000L, 0x01004200L, 0x00000004L, 0x00004004L, 0x01004204L, + 0x01000004L, 0x01004200L, 0x01004000L, 0x00004004L, }, + {/* nibble 7 */ + 0x20800080L, 0x20820000L, 0x00020080L, 0x00000000L, 0x20020000L, + 0x00800080L, 0x20800000L, 0x20820080L, 0x00000080L, 0x20000000L, + 0x00820000L, 0x00020080L, 0x00820080L, 0x20020080L, 0x20000080L, + 0x20800000L, 0x00020000L, 0x00820080L, 0x00800080L, 0x20020000L, + 0x20820080L, 0x20000080L, 0x00000000L, 0x00820000L, 0x20000000L, + 0x00800000L, 0x20020080L, 0x20800080L, 0x00800000L, 0x00020000L, + 0x20820000L, 0x00000080L, 0x00800000L, 0x00020000L, 0x20000080L, + 0x20820080L, 0x00020080L, 0x20000000L, 0x00000000L, 0x00820000L, + 0x20800080L, 0x20020080L, 0x20020000L, 0x00800080L, 0x20820000L, + 0x00000080L, 0x00800080L, 0x20020000L, 0x20820080L, 0x00800000L, + 0x20800000L, 0x20000080L, 0x00820000L, 0x00020080L, 0x20020080L, + 0x20800000L, 0x00000080L, 0x20820000L, 0x00820080L, 0x00000000L, + 0x20000000L, 0x20800080L, 0x00020000L, 0x00820080L, }}; + +#define HPERM_OP(a, t, n, m) \ + ((t) = ((((a) << (16 - (n))) ^ (a)) & (m)), \ + (a) = (a) ^ (t) ^ (t >> (16 - (n)))) + +void DES_set_key(const DES_cblock *key, DES_key_schedule *schedule) { + static const int shifts2[16] = {0, 0, 1, 1, 1, 1, 1, 1, + 0, 1, 1, 1, 1, 1, 1, 0}; + uint32_t c, d, t, s, t2; + const uint8_t *in; + int i; + + in = key->bytes; + + c2l(in, c); + c2l(in, d); + + /* do PC1 in 47 simple operations :-) + * Thanks to John Fletcher (john_fletcher@lccmail.ocf.llnl.gov) + * for the inspiration. :-) */ + PERM_OP(d, c, t, 4, 0x0f0f0f0fL); + HPERM_OP(c, t, -2, 0xcccc0000L); + HPERM_OP(d, t, -2, 0xcccc0000L); + PERM_OP(d, c, t, 1, 0x55555555L); + PERM_OP(c, d, t, 8, 0x00ff00ffL); + PERM_OP(d, c, t, 1, 0x55555555L); + d = (((d & 0x000000ffL) << 16L) | (d & 0x0000ff00L) | + ((d & 0x00ff0000L) >> 16L) | ((c & 0xf0000000L) >> 4L)); + c &= 0x0fffffffL; + + for (i = 0; i < ITERATIONS; i++) { + if (shifts2[i]) { + c = ((c >> 2L) | (c << 26L)); + d = ((d >> 2L) | (d << 26L)); + } else { + c = ((c >> 1L) | (c << 27L)); + d = ((d >> 1L) | (d << 27L)); + } + c &= 0x0fffffffL; + d &= 0x0fffffffL; + /* could be a few less shifts but I am to lazy at this + * point in time to investigate */ + s = des_skb[0][(c) & 0x3f] | + des_skb[1][((c >> 6L) & 0x03) | ((c >> 7L) & 0x3c)] | + des_skb[2][((c >> 13L) & 0x0f) | ((c >> 14L) & 0x30)] | + des_skb[3][((c >> 20L) & 0x01) | ((c >> 21L) & 0x06) | + ((c >> 22L) & 0x38)]; + t = des_skb[4][(d) & 0x3f] | + des_skb[5][((d >> 7L) & 0x03) | ((d >> 8L) & 0x3c)] | + des_skb[6][(d >> 15L) & 0x3f] | + des_skb[7][((d >> 21L) & 0x0f) | ((d >> 22L) & 0x30)]; + + /* table contained 0213 4657 */ + t2 = ((t << 16L) | (s & 0x0000ffffL)) & 0xffffffffL; + schedule->subkeys[i][0] = ROTATE(t2, 30) & 0xffffffffL; + + t2 = ((s >> 16L) | (t & 0xffff0000L)); + schedule->subkeys[i][1] = ROTATE(t2, 26) & 0xffffffffL; + } +} + +static const uint8_t kOddParity[256] = { + 1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, + 14, 16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, + 31, 31, 32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, + 44, 47, 47, 49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, + 61, 61, 62, 62, 64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, + 74, 76, 76, 79, 79, 81, 81, 82, 82, 84, 84, 87, 87, 88, 88, + 91, 91, 93, 93, 94, 94, 97, 97, 98, 98, 100, 100, 103, 103, 104, + 104, 107, 107, 109, 109, 110, 110, 112, 112, 115, 115, 117, 117, 118, 118, + 121, 121, 122, 122, 124, 124, 127, 127, 128, 128, 131, 131, 133, 133, 134, + 134, 137, 137, 138, 138, 140, 140, 143, 143, 145, 145, 146, 146, 148, 148, + 151, 151, 152, 152, 155, 155, 157, 157, 158, 158, 161, 161, 162, 162, 164, + 164, 167, 167, 168, 168, 171, 171, 173, 173, 174, 174, 176, 176, 179, 179, + 181, 181, 182, 182, 185, 185, 186, 186, 188, 188, 191, 191, 193, 193, 194, + 194, 196, 196, 199, 199, 200, 200, 203, 203, 205, 205, 206, 206, 208, 208, + 211, 211, 213, 213, 214, 214, 217, 217, 218, 218, 220, 220, 223, 223, 224, + 224, 227, 227, 229, 229, 230, 230, 233, 233, 234, 234, 236, 236, 239, 239, + 241, 241, 242, 242, 244, 244, 247, 247, 248, 248, 251, 251, 253, 253, 254, + 254 +}; + +void DES_set_odd_parity(DES_cblock *key) { + unsigned i; + + for (i = 0; i < DES_KEY_SZ; i++) { + key->bytes[i] = kOddParity[key->bytes[i]]; + } +} + +static void DES_encrypt1(uint32_t *data, const DES_key_schedule *ks, int enc) { + uint32_t l, r, t, u; + + r = data[0]; + l = data[1]; + + IP(r, l); + /* Things have been modified so that the initial rotate is done outside + * the loop. This required the DES_SPtrans values in sp.h to be + * rotated 1 bit to the right. One perl script later and things have a + * 5% speed up on a sparc2. Thanks to Richard Outerbridge + * <71755.204@CompuServe.COM> for pointing this out. */ + /* clear the top bits on machines with 8byte longs */ + /* shift left by 2 */ + r = ROTATE(r, 29) & 0xffffffffL; + l = ROTATE(l, 29) & 0xffffffffL; + + /* I don't know if it is worth the effort of loop unrolling the + * inner loop */ + if (enc) { + D_ENCRYPT(ks, l, r, 0); + D_ENCRYPT(ks, r, l, 1); + D_ENCRYPT(ks, l, r, 2); + D_ENCRYPT(ks, r, l, 3); + D_ENCRYPT(ks, l, r, 4); + D_ENCRYPT(ks, r, l, 5); + D_ENCRYPT(ks, l, r, 6); + D_ENCRYPT(ks, r, l, 7); + D_ENCRYPT(ks, l, r, 8); + D_ENCRYPT(ks, r, l, 9); + D_ENCRYPT(ks, l, r, 10); + D_ENCRYPT(ks, r, l, 11); + D_ENCRYPT(ks, l, r, 12); + D_ENCRYPT(ks, r, l, 13); + D_ENCRYPT(ks, l, r, 14); + D_ENCRYPT(ks, r, l, 15); + } else { + D_ENCRYPT(ks, l, r, 15); + D_ENCRYPT(ks, r, l, 14); + D_ENCRYPT(ks, l, r, 13); + D_ENCRYPT(ks, r, l, 12); + D_ENCRYPT(ks, l, r, 11); + D_ENCRYPT(ks, r, l, 10); + D_ENCRYPT(ks, l, r, 9); + D_ENCRYPT(ks, r, l, 8); + D_ENCRYPT(ks, l, r, 7); + D_ENCRYPT(ks, r, l, 6); + D_ENCRYPT(ks, l, r, 5); + D_ENCRYPT(ks, r, l, 4); + D_ENCRYPT(ks, l, r, 3); + D_ENCRYPT(ks, r, l, 2); + D_ENCRYPT(ks, l, r, 1); + D_ENCRYPT(ks, r, l, 0); + } + + /* rotate and clear the top bits on machines with 8byte longs */ + l = ROTATE(l, 3) & 0xffffffffL; + r = ROTATE(r, 3) & 0xffffffffL; + + FP(r, l); + data[0] = l; + data[1] = r; +} + +static void DES_encrypt2(uint32_t *data, const DES_key_schedule *ks, int enc) { + uint32_t l, r, t, u; + + r = data[0]; + l = data[1]; + + /* Things have been modified so that the initial rotate is done outside the + * loop. This required the DES_SPtrans values in sp.h to be rotated 1 bit to + * the right. One perl script later and things have a 5% speed up on a + * sparc2. Thanks to Richard Outerbridge <71755.204@CompuServe.COM> for + * pointing this out. */ + /* clear the top bits on machines with 8byte longs */ + r = ROTATE(r, 29) & 0xffffffffL; + l = ROTATE(l, 29) & 0xffffffffL; + + /* I don't know if it is worth the effort of loop unrolling the + * inner loop */ + if (enc) { + D_ENCRYPT(ks, l, r, 0); + D_ENCRYPT(ks, r, l, 1); + D_ENCRYPT(ks, l, r, 2); + D_ENCRYPT(ks, r, l, 3); + D_ENCRYPT(ks, l, r, 4); + D_ENCRYPT(ks, r, l, 5); + D_ENCRYPT(ks, l, r, 6); + D_ENCRYPT(ks, r, l, 7); + D_ENCRYPT(ks, l, r, 8); + D_ENCRYPT(ks, r, l, 9); + D_ENCRYPT(ks, l, r, 10); + D_ENCRYPT(ks, r, l, 11); + D_ENCRYPT(ks, l, r, 12); + D_ENCRYPT(ks, r, l, 13); + D_ENCRYPT(ks, l, r, 14); + D_ENCRYPT(ks, r, l, 15); + } else { + D_ENCRYPT(ks, l, r, 15); + D_ENCRYPT(ks, r, l, 14); + D_ENCRYPT(ks, l, r, 13); + D_ENCRYPT(ks, r, l, 12); + D_ENCRYPT(ks, l, r, 11); + D_ENCRYPT(ks, r, l, 10); + D_ENCRYPT(ks, l, r, 9); + D_ENCRYPT(ks, r, l, 8); + D_ENCRYPT(ks, l, r, 7); + D_ENCRYPT(ks, r, l, 6); + D_ENCRYPT(ks, l, r, 5); + D_ENCRYPT(ks, r, l, 4); + D_ENCRYPT(ks, l, r, 3); + D_ENCRYPT(ks, r, l, 2); + D_ENCRYPT(ks, l, r, 1); + D_ENCRYPT(ks, r, l, 0); + } + /* rotate and clear the top bits on machines with 8byte longs */ + data[0] = ROTATE(l, 3) & 0xffffffffL; + data[1] = ROTATE(r, 3) & 0xffffffffL; +} + +/* DES_encrypt3 is not static because it's used in decrepit. */ +void DES_encrypt3(uint32_t *data, const DES_key_schedule *ks1, + const DES_key_schedule *ks2, const DES_key_schedule *ks3) { + uint32_t l, r; + + l = data[0]; + r = data[1]; + IP(l, r); + data[0] = l; + data[1] = r; + DES_encrypt2((uint32_t *)data, ks1, DES_ENCRYPT); + DES_encrypt2((uint32_t *)data, ks2, DES_DECRYPT); + DES_encrypt2((uint32_t *)data, ks3, DES_ENCRYPT); + l = data[0]; + r = data[1]; + FP(r, l); + data[0] = l; + data[1] = r; +} + +/* DES_decrypt3 is not static because it's used in decrepit. */ +void DES_decrypt3(uint32_t *data, const DES_key_schedule *ks1, + const DES_key_schedule *ks2, const DES_key_schedule *ks3) { + uint32_t l, r; + + l = data[0]; + r = data[1]; + IP(l, r); + data[0] = l; + data[1] = r; + DES_encrypt2((uint32_t *)data, ks3, DES_DECRYPT); + DES_encrypt2((uint32_t *)data, ks2, DES_ENCRYPT); + DES_encrypt2((uint32_t *)data, ks1, DES_DECRYPT); + l = data[0]; + r = data[1]; + FP(r, l); + data[0] = l; + data[1] = r; +} + +void DES_ecb_encrypt(const DES_cblock *in_block, DES_cblock *out_block, + const DES_key_schedule *schedule, int is_encrypt) { + uint32_t l; + uint32_t ll[2]; + const uint8_t *in = in_block->bytes; + uint8_t *out = out_block->bytes; + + c2l(in, l); + ll[0] = l; + c2l(in, l); + ll[1] = l; + DES_encrypt1(ll, schedule, is_encrypt); + l = ll[0]; + l2c(l, out); + l = ll[1]; + l2c(l, out); + ll[0] = ll[1] = 0; +} + +void DES_ncbc_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const DES_key_schedule *schedule, DES_cblock *ivec, + int enc) { + uint32_t tin0, tin1; + uint32_t tout0, tout1, xor0, xor1; + uint32_t tin[2]; + unsigned char *iv; + + iv = ivec->bytes; + + if (enc) { + c2l(iv, tout0); + c2l(iv, tout1); + for (; len >= 8; len -= 8) { + c2l(in, tin0); + c2l(in, tin1); + tin0 ^= tout0; + tin[0] = tin0; + tin1 ^= tout1; + tin[1] = tin1; + DES_encrypt1((uint32_t *)tin, schedule, DES_ENCRYPT); + tout0 = tin[0]; + l2c(tout0, out); + tout1 = tin[1]; + l2c(tout1, out); + } + if (len != 0) { + c2ln(in, tin0, tin1, len); + tin0 ^= tout0; + tin[0] = tin0; + tin1 ^= tout1; + tin[1] = tin1; + DES_encrypt1((uint32_t *)tin, schedule, DES_ENCRYPT); + tout0 = tin[0]; + l2c(tout0, out); + tout1 = tin[1]; + l2c(tout1, out); + } + iv = ivec->bytes; + l2c(tout0, iv); + l2c(tout1, iv); + } else { + c2l(iv, xor0); + c2l(iv, xor1); + for (; len >= 8; len -= 8) { + c2l(in, tin0); + tin[0] = tin0; + c2l(in, tin1); + tin[1] = tin1; + DES_encrypt1((uint32_t *)tin, schedule, DES_DECRYPT); + tout0 = tin[0] ^ xor0; + tout1 = tin[1] ^ xor1; + l2c(tout0, out); + l2c(tout1, out); + xor0 = tin0; + xor1 = tin1; + } + if (len != 0) { + c2l(in, tin0); + tin[0] = tin0; + c2l(in, tin1); + tin[1] = tin1; + DES_encrypt1((uint32_t *)tin, schedule, DES_DECRYPT); + tout0 = tin[0] ^ xor0; + tout1 = tin[1] ^ xor1; + l2cn(tout0, tout1, out, len); + xor0 = tin0; + xor1 = tin1; + } + iv = ivec->bytes; + l2c(xor0, iv); + l2c(xor1, iv); + } + tin[0] = tin[1] = 0; +} + +void DES_ecb3_encrypt(const DES_cblock *input, DES_cblock *output, + const DES_key_schedule *ks1, const DES_key_schedule *ks2, + const DES_key_schedule *ks3, int enc) { + uint32_t l0, l1; + uint32_t ll[2]; + const uint8_t *in = input->bytes; + uint8_t *out = output->bytes; + + c2l(in, l0); + c2l(in, l1); + ll[0] = l0; + ll[1] = l1; + if (enc) { + DES_encrypt3(ll, ks1, ks2, ks3); + } else { + DES_decrypt3(ll, ks1, ks2, ks3); + } + l0 = ll[0]; + l1 = ll[1]; + l2c(l0, out); + l2c(l1, out); +} + +void DES_ede3_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const DES_key_schedule *ks1, + const DES_key_schedule *ks2, + const DES_key_schedule *ks3, DES_cblock *ivec, + int enc) { + uint32_t tin0, tin1; + uint32_t tout0, tout1, xor0, xor1; + uint32_t tin[2]; + uint8_t *iv; + + iv = ivec->bytes; + + if (enc) { + c2l(iv, tout0); + c2l(iv, tout1); + for (; len >= 8; len -= 8) { + c2l(in, tin0); + c2l(in, tin1); + tin0 ^= tout0; + tin1 ^= tout1; + + tin[0] = tin0; + tin[1] = tin1; + DES_encrypt3((uint32_t *)tin, ks1, ks2, ks3); + tout0 = tin[0]; + tout1 = tin[1]; + + l2c(tout0, out); + l2c(tout1, out); + } + if (len != 0) { + c2ln(in, tin0, tin1, len); + tin0 ^= tout0; + tin1 ^= tout1; + + tin[0] = tin0; + tin[1] = tin1; + DES_encrypt3((uint32_t *)tin, ks1, ks2, ks3); + tout0 = tin[0]; + tout1 = tin[1]; + + l2c(tout0, out); + l2c(tout1, out); + } + iv = ivec->bytes; + l2c(tout0, iv); + l2c(tout1, iv); + } else { + uint32_t t0, t1; + + c2l(iv, xor0); + c2l(iv, xor1); + for (; len >= 8; len -= 8) { + c2l(in, tin0); + c2l(in, tin1); + + t0 = tin0; + t1 = tin1; + + tin[0] = tin0; + tin[1] = tin1; + DES_decrypt3((uint32_t *)tin, ks1, ks2, ks3); + tout0 = tin[0]; + tout1 = tin[1]; + + tout0 ^= xor0; + tout1 ^= xor1; + l2c(tout0, out); + l2c(tout1, out); + xor0 = t0; + xor1 = t1; + } + if (len != 0) { + c2l(in, tin0); + c2l(in, tin1); + + t0 = tin0; + t1 = tin1; + + tin[0] = tin0; + tin[1] = tin1; + DES_decrypt3((uint32_t *)tin, ks1, ks2, ks3); + tout0 = tin[0]; + tout1 = tin[1]; + + tout0 ^= xor0; + tout1 ^= xor1; + l2cn(tout0, tout1, out, len); + xor0 = t0; + xor1 = t1; + } + + iv = ivec->bytes; + l2c(xor0, iv); + l2c(xor1, iv); + } + + tin[0] = tin[1] = 0; +} + +void DES_ede2_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const DES_key_schedule *ks1, + const DES_key_schedule *ks2, + DES_cblock *ivec, + int enc) { + DES_ede3_cbc_encrypt(in, out, len, ks1, ks2, ks1, ivec, enc); +} + + +/* Deprecated functions. */ + +void DES_set_key_unchecked(const DES_cblock *key, DES_key_schedule *schedule) { + DES_set_key(key, schedule); +} diff --git a/TMessagesProj/jni/boringssl/crypto/des/internal.h b/TMessagesProj/jni/boringssl/crypto/des/internal.h new file mode 100644 index 00000000..91559ff4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/des/internal.h @@ -0,0 +1,229 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_DES_INTERNAL_H +#define OPENSSL_HEADER_DES_INTERNAL_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +#define c2l(c, l) \ + (l = ((uint32_t)(*((c)++))), l |= ((uint32_t)(*((c)++))) << 8L, \ + l |= ((uint32_t)(*((c)++))) << 16L, l |= ((uint32_t)(*((c)++))) << 24L) + +#define l2c(l, c) \ + (*((c)++) = (unsigned char)(((l)) & 0xff), \ + *((c)++) = (unsigned char)(((l) >> 8L) & 0xff), \ + *((c)++) = (unsigned char)(((l) >> 16L) & 0xff), \ + *((c)++) = (unsigned char)(((l) >> 24L) & 0xff)) + +/* NOTE - c is not incremented as per c2l */ +#define c2ln(c, l1, l2, n) \ + { \ + c += n; \ + l1 = l2 = 0; \ + switch (n) { \ + case 8: \ + l2 = ((uint32_t)(*(--(c)))) << 24L; \ + case 7: \ + l2 |= ((uint32_t)(*(--(c)))) << 16L; \ + case 6: \ + l2 |= ((uint32_t)(*(--(c)))) << 8L; \ + case 5: \ + l2 |= ((uint32_t)(*(--(c)))); \ + case 4: \ + l1 = ((uint32_t)(*(--(c)))) << 24L; \ + case 3: \ + l1 |= ((uint32_t)(*(--(c)))) << 16L; \ + case 2: \ + l1 |= ((uint32_t)(*(--(c)))) << 8L; \ + case 1: \ + l1 |= ((uint32_t)(*(--(c)))); \ + } \ + } + +/* NOTE - c is not incremented as per l2c */ +#define l2cn(l1, l2, c, n) \ + { \ + c += n; \ + switch (n) { \ + case 8: \ + *(--(c)) = (unsigned char)(((l2) >> 24L) & 0xff); \ + case 7: \ + *(--(c)) = (unsigned char)(((l2) >> 16L) & 0xff); \ + case 6: \ + *(--(c)) = (unsigned char)(((l2) >> 8L) & 0xff); \ + case 5: \ + *(--(c)) = (unsigned char)(((l2)) & 0xff); \ + case 4: \ + *(--(c)) = (unsigned char)(((l1) >> 24L) & 0xff); \ + case 3: \ + *(--(c)) = (unsigned char)(((l1) >> 16L) & 0xff); \ + case 2: \ + *(--(c)) = (unsigned char)(((l1) >> 8L) & 0xff); \ + case 1: \ + *(--(c)) = (unsigned char)(((l1)) & 0xff); \ + } \ + } + +/* IP and FP + * The problem is more of a geometric problem that random bit fiddling. + 0 1 2 3 4 5 6 7 62 54 46 38 30 22 14 6 + 8 9 10 11 12 13 14 15 60 52 44 36 28 20 12 4 +16 17 18 19 20 21 22 23 58 50 42 34 26 18 10 2 +24 25 26 27 28 29 30 31 to 56 48 40 32 24 16 8 0 + +32 33 34 35 36 37 38 39 63 55 47 39 31 23 15 7 +40 41 42 43 44 45 46 47 61 53 45 37 29 21 13 5 +48 49 50 51 52 53 54 55 59 51 43 35 27 19 11 3 +56 57 58 59 60 61 62 63 57 49 41 33 25 17 9 1 + +The output has been subject to swaps of the form +0 1 -> 3 1 but the odd and even bits have been put into +2 3 2 0 +different words. The main trick is to remember that +t=((l>>size)^r)&(mask); +r^=t; +l^=(t<> (n)) ^ (b)) & (m)), (b) ^= (t), (a) ^= ((t) << (n))) + +#define IP(l, r) \ + { \ + uint32_t tt; \ + PERM_OP(r, l, tt, 4, 0x0f0f0f0fL); \ + PERM_OP(l, r, tt, 16, 0x0000ffffL); \ + PERM_OP(r, l, tt, 2, 0x33333333L); \ + PERM_OP(l, r, tt, 8, 0x00ff00ffL); \ + PERM_OP(r, l, tt, 1, 0x55555555L); \ + } + +#define FP(l, r) \ + { \ + uint32_t tt; \ + PERM_OP(l, r, tt, 1, 0x55555555L); \ + PERM_OP(r, l, tt, 8, 0x00ff00ffL); \ + PERM_OP(l, r, tt, 2, 0x33333333L); \ + PERM_OP(r, l, tt, 16, 0x0000ffffL); \ + PERM_OP(l, r, tt, 4, 0x0f0f0f0fL); \ + } + +#define LOAD_DATA(ks, R, S, u, t, E0, E1) \ + u = R ^ ks->subkeys[S][0]; \ + t = R ^ ks->subkeys[S][1] + +#define D_ENCRYPT(ks, LL, R, S) \ + { \ + LOAD_DATA(ks, R, S, u, t, E0, E1); \ + t = ROTATE(t, 4); \ + LL ^= \ + DES_SPtrans[0][(u >> 2L) & 0x3f] ^ DES_SPtrans[2][(u >> 10L) & 0x3f] ^ \ + DES_SPtrans[4][(u >> 18L) & 0x3f] ^ \ + DES_SPtrans[6][(u >> 26L) & 0x3f] ^ DES_SPtrans[1][(t >> 2L) & 0x3f] ^ \ + DES_SPtrans[3][(t >> 10L) & 0x3f] ^ \ + DES_SPtrans[5][(t >> 18L) & 0x3f] ^ DES_SPtrans[7][(t >> 26L) & 0x3f]; \ + } + +#define ITERATIONS 16 +#define HALF_ITERATIONS 8 + +#if defined(_MSC_VER) +#define ROTATE(a, n) (_lrotr(a, n)) +#elif defined(__ICC) +#define ROTATE(a, n) (_rotr(a, n)) +#elif defined(__GNUC__) && __GNUC__ >= 2 && !defined(OPENSSL_NO_ASM) && \ + !defined(__STRICT_ANSI__) && \ + (defined(OPENSSL_X86) || defined(OPENSSL_X86_64)) +#define ROTATE(a, n) \ + ({ \ + unsigned int ret; \ + asm("rorl %1,%0" : "=r"(ret) : "I"(n), "0"(a) : "cc"); \ + ret; \ + }) +#endif + +#ifndef ROTATE +#define ROTATE(a, n) (((a) >> (n)) + ((a) << (32 - (n)))) +#endif + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_DES_INTERNAL_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/dh/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/dh/CMakeLists.txt new file mode 100644 index 00000000..5054628e --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/dh/CMakeLists.txt @@ -0,0 +1,13 @@ +include_directories(. .. ../../include) + +add_library( + dh + + OBJECT + + dh.c + dh_impl.c + params.c + check.c + dh_asn1.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/dh/check.c b/TMessagesProj/jni/boringssl/crypto/dh/check.c new file mode 100644 index 00000000..06af6f25 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/dh/check.c @@ -0,0 +1,180 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include "internal.h" + + +int DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, int *ret) { + int ok = 0; + BIGNUM q; + + *ret = 0; + BN_init(&q); + if (!BN_set_word(&q, 1)) { + goto err; + } + + if (BN_cmp(pub_key, &q) <= 0) { + *ret |= DH_CHECK_PUBKEY_TOO_SMALL; + } + if (!BN_copy(&q, dh->p) || + !BN_sub_word(&q, 1)) { + goto err; + } + if (BN_cmp(pub_key, &q) >= 0) { + *ret |= DH_CHECK_PUBKEY_TOO_LARGE; + } + + ok = 1; + +err: + BN_free(&q); + return ok; +} + + +int DH_check(const DH *dh, int *ret) { + /* Check that p is a safe prime and if g is 2, 3 or 5, check that it is a + * suitable generator where: + * for 2, p mod 24 == 11 + * for 3, p mod 12 == 5 + * for 5, p mod 10 == 3 or 7 + * should hold. + */ + int ok = 0; + BN_CTX *ctx = NULL; + BN_ULONG l; + BIGNUM *t1 = NULL, *t2 = NULL; + + *ret = 0; + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + BN_CTX_start(ctx); + t1 = BN_CTX_get(ctx); + if (t1 == NULL) { + goto err; + } + t2 = BN_CTX_get(ctx); + if (t2 == NULL) { + goto err; + } + + if (dh->q) { + if (BN_cmp(dh->g, BN_value_one()) <= 0) { + *ret |= DH_CHECK_NOT_SUITABLE_GENERATOR; + } else if (BN_cmp(dh->g, dh->p) >= 0) { + *ret |= DH_CHECK_NOT_SUITABLE_GENERATOR; + } else { + /* Check g^q == 1 mod p */ + if (!BN_mod_exp(t1, dh->g, dh->q, dh->p, ctx)) { + goto err; + } + if (!BN_is_one(t1)) { + *ret |= DH_CHECK_NOT_SUITABLE_GENERATOR; + } + } + if (!BN_is_prime_ex(dh->q, BN_prime_checks, ctx, NULL)) { + *ret |= DH_CHECK_Q_NOT_PRIME; + } + /* Check p == 1 mod q i.e. q divides p - 1 */ + if (!BN_div(t1, t2, dh->p, dh->q, ctx)) { + goto err; + } + if (!BN_is_one(t2)) { + *ret |= DH_CHECK_INVALID_Q_VALUE; + } + if (dh->j && BN_cmp(dh->j, t1)) { + *ret |= DH_CHECK_INVALID_J_VALUE; + } + } else if (BN_is_word(dh->g, DH_GENERATOR_2)) { + l = BN_mod_word(dh->p, 24); + if (l != 11) { + *ret |= DH_CHECK_NOT_SUITABLE_GENERATOR; + } + } else if (BN_is_word(dh->g, DH_GENERATOR_5)) { + l = BN_mod_word(dh->p, 10); + if (l != 3 && l != 7) { + *ret |= DH_CHECK_NOT_SUITABLE_GENERATOR; + } + } else { + *ret |= DH_CHECK_UNABLE_TO_CHECK_GENERATOR; + } + + if (!BN_is_prime_ex(dh->p, BN_prime_checks, ctx, NULL)) { + *ret |= DH_CHECK_P_NOT_PRIME; + } else if (!dh->q) { + if (!BN_rshift1(t1, dh->p)) { + goto err; + } + if (!BN_is_prime_ex(t1, BN_prime_checks, ctx, NULL)) { + *ret |= DH_CHECK_P_NOT_SAFE_PRIME; + } + } + ok = 1; + +err: + if (ctx != NULL) { + BN_CTX_end(ctx); + BN_CTX_free(ctx); + } + return ok; +} diff --git a/TMessagesProj/jni/boringssl/crypto/dh/dh.c b/TMessagesProj/jni/boringssl/crypto/dh/dh.c new file mode 100644 index 00000000..d25f3583 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/dh/dh.c @@ -0,0 +1,252 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "internal.h" +#include "../internal.h" + + +extern const DH_METHOD DH_default_method; + +static CRYPTO_EX_DATA_CLASS g_ex_data_class = CRYPTO_EX_DATA_CLASS_INIT; + +DH *DH_new(void) { return DH_new_method(NULL); } + +DH *DH_new_method(const ENGINE *engine) { + DH *dh = (DH *)OPENSSL_malloc(sizeof(DH)); + if (dh == NULL) { + OPENSSL_PUT_ERROR(DH, ERR_R_MALLOC_FAILURE); + return NULL; + } + + memset(dh, 0, sizeof(DH)); + + if (engine) { + dh->meth = ENGINE_get_DH_method(engine); + } + + if (dh->meth == NULL) { + dh->meth = (DH_METHOD*) &DH_default_method; + } + METHOD_ref(dh->meth); + + CRYPTO_MUTEX_init(&dh->method_mont_p_lock); + + dh->references = 1; + if (!CRYPTO_new_ex_data(&g_ex_data_class, dh, &dh->ex_data)) { + OPENSSL_free(dh); + return NULL; + } + + if (dh->meth->init && !dh->meth->init(dh)) { + CRYPTO_free_ex_data(&g_ex_data_class, dh, &dh->ex_data); + METHOD_unref(dh->meth); + OPENSSL_free(dh); + return NULL; + } + + return dh; +} + +void DH_free(DH *dh) { + if (dh == NULL) { + return; + } + + if (!CRYPTO_refcount_dec_and_test_zero(&dh->references)) { + return; + } + + if (dh->meth->finish) { + dh->meth->finish(dh); + } + METHOD_unref(dh->meth); + + CRYPTO_free_ex_data(&g_ex_data_class, dh, &dh->ex_data); + + if (dh->method_mont_p) BN_MONT_CTX_free(dh->method_mont_p); + if (dh->p != NULL) BN_clear_free(dh->p); + if (dh->g != NULL) BN_clear_free(dh->g); + if (dh->q != NULL) BN_clear_free(dh->q); + if (dh->j != NULL) BN_clear_free(dh->j); + if (dh->seed) OPENSSL_free(dh->seed); + if (dh->counter != NULL) BN_clear_free(dh->counter); + if (dh->pub_key != NULL) BN_clear_free(dh->pub_key); + if (dh->priv_key != NULL) BN_clear_free(dh->priv_key); + CRYPTO_MUTEX_cleanup(&dh->method_mont_p_lock); + + OPENSSL_free(dh); +} + +int DH_generate_parameters_ex(DH *dh, int prime_bits, int generator, BN_GENCB *cb) { + if (dh->meth->generate_parameters) { + return dh->meth->generate_parameters(dh, prime_bits, generator, cb); + } + return DH_default_method.generate_parameters(dh, prime_bits, generator, cb); +} + +int DH_generate_key(DH *dh) { + if (dh->meth->generate_key) { + return dh->meth->generate_key(dh); + } + return DH_default_method.generate_key(dh); +} + +int DH_compute_key(unsigned char *out, const BIGNUM *peers_key, DH *dh) { + if (dh->meth->compute_key) { + return dh->meth->compute_key(dh, out, peers_key); + } + return DH_default_method.compute_key(dh, out, peers_key); +} + +int DH_size(const DH *dh) { return BN_num_bytes(dh->p); } + +unsigned DH_num_bits(const DH *dh) { return BN_num_bits(dh->p); } + +int DH_up_ref(DH *dh) { + CRYPTO_refcount_inc(&dh->references); + return 1; +} + +static int int_dh_bn_cpy(BIGNUM **dst, const BIGNUM *src) { + BIGNUM *a = NULL; + + if (src) { + a = BN_dup(src); + if (!a) { + return 0; + } + } + + BN_free(*dst); + *dst = a; + return 1; +} + +static int int_dh_param_copy(DH *to, const DH *from, int is_x942) { + if (is_x942 == -1) { + is_x942 = !!from->q; + } + if (!int_dh_bn_cpy(&to->p, from->p) || + !int_dh_bn_cpy(&to->g, from->g)) { + return 0; + } + + if (!is_x942) { + return 1; + } + + if (!int_dh_bn_cpy(&to->q, from->q) || + !int_dh_bn_cpy(&to->j, from->j)) { + return 0; + } + + OPENSSL_free(to->seed); + to->seed = NULL; + to->seedlen = 0; + + if (from->seed) { + to->seed = BUF_memdup(from->seed, from->seedlen); + if (!to->seed) { + return 0; + } + to->seedlen = from->seedlen; + } + + return 1; +} + +DH *DHparams_dup(const DH *dh) { + DH *ret = DH_new(); + if (!ret) { + return NULL; + } + + if (!int_dh_param_copy(ret, dh, -1)) { + DH_free(ret); + return NULL; + } + + return ret; +} + +int DH_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func) { + int index; + if (!CRYPTO_get_ex_new_index(&g_ex_data_class, &index, argl, argp, new_func, + dup_func, free_func)) { + return -1; + } + return index; +} + +int DH_set_ex_data(DH *d, int idx, void *arg) { + return (CRYPTO_set_ex_data(&d->ex_data, idx, arg)); +} + +void *DH_get_ex_data(DH *d, int idx) { + return (CRYPTO_get_ex_data(&d->ex_data, idx)); +} diff --git a/TMessagesProj/jni/boringssl/crypto/dh/dh_asn1.c b/TMessagesProj/jni/boringssl/crypto/dh/dh_asn1.c new file mode 100644 index 00000000..73cd4df7 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/dh/dh_asn1.c @@ -0,0 +1,84 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2000. + */ +/* ==================================================================== + * Copyright (c) 2000-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include + +#include "internal.h" + +/* Override the default free and new methods */ +static int dh_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, + void *exarg) { + if (operation == ASN1_OP_NEW_PRE) { + *pval = (ASN1_VALUE *)DH_new(); + if (*pval) { + return 2; + } + return 0; + } else if (operation == ASN1_OP_FREE_PRE) { + DH_free((DH *)*pval); + *pval = NULL; + return 2; + } + return 1; +} + +ASN1_SEQUENCE_cb(DHparams, dh_cb) = { + ASN1_SIMPLE(DH, p, BIGNUM), ASN1_SIMPLE(DH, g, BIGNUM), + ASN1_OPT(DH, priv_length, ZLONG)} ASN1_SEQUENCE_END_cb(DH, DHparams); + +IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DH, DHparams, DHparams) diff --git a/TMessagesProj/jni/boringssl/crypto/dh/dh_impl.c b/TMessagesProj/jni/boringssl/crypto/dh/dh_impl.c new file mode 100644 index 00000000..6cf0abb6 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/dh/dh_impl.c @@ -0,0 +1,326 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include + +#include "internal.h" + + +#define OPENSSL_DH_MAX_MODULUS_BITS 10000 + +static int generate_parameters(DH *ret, int prime_bits, int generator, BN_GENCB *cb) { + /* We generate DH parameters as follows + * find a prime q which is prime_bits/2 bits long. + * p=(2*q)+1 or (p-1)/2 = q + * For this case, g is a generator if + * g^((p-1)/q) mod p != 1 for values of q which are the factors of p-1. + * Since the factors of p-1 are q and 2, we just need to check + * g^2 mod p != 1 and g^q mod p != 1. + * + * Having said all that, + * there is another special case method for the generators 2, 3 and 5. + * for 2, p mod 24 == 11 + * for 3, p mod 12 == 5 <<<<< does not work for safe primes. + * for 5, p mod 10 == 3 or 7 + * + * Thanks to Phil Karn for the pointers about the + * special generators and for answering some of my questions. + * + * I've implemented the second simple method :-). + * Since DH should be using a safe prime (both p and q are prime), + * this generator function can take a very very long time to run. + */ + + /* Actually there is no reason to insist that 'generator' be a generator. + * It's just as OK (and in some sense better) to use a generator of the + * order-q subgroup. + */ + + BIGNUM *t1, *t2; + int g, ok = 0; + BN_CTX *ctx = NULL; + + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + BN_CTX_start(ctx); + t1 = BN_CTX_get(ctx); + t2 = BN_CTX_get(ctx); + if (t1 == NULL || t2 == NULL) { + goto err; + } + + /* Make sure 'ret' has the necessary elements */ + if (!ret->p && ((ret->p = BN_new()) == NULL)) { + goto err; + } + if (!ret->g && ((ret->g = BN_new()) == NULL)) { + goto err; + } + + if (generator <= 1) { + OPENSSL_PUT_ERROR(DH, DH_R_BAD_GENERATOR); + goto err; + } + if (generator == DH_GENERATOR_2) { + if (!BN_set_word(t1, 24)) { + goto err; + } + if (!BN_set_word(t2, 11)) { + goto err; + } + g = 2; + } else if (generator == DH_GENERATOR_5) { + if (!BN_set_word(t1, 10)) { + goto err; + } + if (!BN_set_word(t2, 3)) { + goto err; + } + /* BN_set_word(t3,7); just have to miss + * out on these ones :-( */ + g = 5; + } else { + /* in the general case, don't worry if 'generator' is a + * generator or not: since we are using safe primes, + * it will generate either an order-q or an order-2q group, + * which both is OK */ + if (!BN_set_word(t1, 2)) { + goto err; + } + if (!BN_set_word(t2, 1)) { + goto err; + } + g = generator; + } + + if (!BN_generate_prime_ex(ret->p, prime_bits, 1, t1, t2, cb)) { + goto err; + } + if (!BN_GENCB_call(cb, 3, 0)) { + goto err; + } + if (!BN_set_word(ret->g, g)) { + goto err; + } + ok = 1; + +err: + if (!ok) { + OPENSSL_PUT_ERROR(DH, ERR_R_BN_LIB); + } + + if (ctx != NULL) { + BN_CTX_end(ctx); + BN_CTX_free(ctx); + } + return ok; +} + +static int generate_key(DH *dh) { + int ok = 0; + int generate_new_key = 0; + unsigned l; + BN_CTX *ctx; + BN_MONT_CTX *mont = NULL; + BIGNUM *pub_key = NULL, *priv_key = NULL; + BIGNUM local_priv; + + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + + if (dh->priv_key == NULL) { + priv_key = BN_new(); + if (priv_key == NULL) { + goto err; + } + generate_new_key = 1; + } else { + priv_key = dh->priv_key; + } + + if (dh->pub_key == NULL) { + pub_key = BN_new(); + if (pub_key == NULL) { + goto err; + } + } else { + pub_key = dh->pub_key; + } + + mont = BN_MONT_CTX_set_locked(&dh->method_mont_p, &dh->method_mont_p_lock, + dh->p, ctx); + if (!mont) { + goto err; + } + + if (generate_new_key) { + if (dh->q) { + do { + if (!BN_rand_range(priv_key, dh->q)) { + goto err; + } + } while (BN_is_zero(priv_key) || BN_is_one(priv_key)); + } else { + /* secret exponent length */ + DH_check_standard_parameters(dh); + l = dh->priv_length ? dh->priv_length : BN_num_bits(dh->p) - 1; + if (!BN_rand(priv_key, l, 0, 0)) { + goto err; + } + } + } + + BN_with_flags(&local_priv, priv_key, BN_FLG_CONSTTIME); + if (!BN_mod_exp_mont(pub_key, dh->g, &local_priv, dh->p, ctx, mont)) { + goto err; + } + + dh->pub_key = pub_key; + dh->priv_key = priv_key; + ok = 1; + +err: + if (ok != 1) { + OPENSSL_PUT_ERROR(DH, ERR_R_BN_LIB); + } + + if (dh->pub_key == NULL) { + BN_free(pub_key); + } + if (dh->priv_key == NULL) { + BN_free(priv_key); + } + BN_CTX_free(ctx); + return ok; +} + +static int compute_key(DH *dh, unsigned char *out, const BIGNUM *pub_key) { + BN_CTX *ctx = NULL; + BN_MONT_CTX *mont = NULL; + BIGNUM *shared_key; + int ret = -1; + int check_result; + BIGNUM local_priv; + + if (BN_num_bits(dh->p) > OPENSSL_DH_MAX_MODULUS_BITS) { + OPENSSL_PUT_ERROR(DH, DH_R_MODULUS_TOO_LARGE); + goto err; + } + + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + BN_CTX_start(ctx); + shared_key = BN_CTX_get(ctx); + if (shared_key == NULL) { + goto err; + } + + if (dh->priv_key == NULL) { + OPENSSL_PUT_ERROR(DH, DH_R_NO_PRIVATE_VALUE); + goto err; + } + + mont = BN_MONT_CTX_set_locked(&dh->method_mont_p, &dh->method_mont_p_lock, + dh->p, ctx); + if (!mont) { + goto err; + } + + if (!DH_check_pub_key(dh, pub_key, &check_result) || check_result) { + OPENSSL_PUT_ERROR(DH, DH_R_INVALID_PUBKEY); + goto err; + } + + BN_with_flags(&local_priv, dh->priv_key, BN_FLG_CONSTTIME); + if (!BN_mod_exp_mont(shared_key, pub_key, &local_priv, dh->p, ctx, + mont)) { + OPENSSL_PUT_ERROR(DH, ERR_R_BN_LIB); + goto err; + } + + ret = BN_bn2bin(shared_key, out); + +err: + if (ctx != NULL) { + BN_CTX_end(ctx); + BN_CTX_free(ctx); + } + + return ret; +} + +const struct dh_method DH_default_method = { + { + 0 /* references */, + 1 /* is_static */, + }, + NULL /* app_data */, + NULL /* init */, + NULL /* finish */, + generate_parameters, + generate_key, + compute_key, +}; diff --git a/TMessagesProj/jni/boringssl/crypto/dh/internal.h b/TMessagesProj/jni/boringssl/crypto/dh/internal.h new file mode 100644 index 00000000..81b9c902 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/dh/internal.h @@ -0,0 +1,80 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_DH_INTERNAL_H +#define OPENSSL_HEADER_DH_INTERNAL_H + +#include + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* DH_check_standard_parameters checks if the parameters in |dh| are well + * known and safe. If so, it sets |dh->priv_length| to an appropriately smaller + * value than the default. */ +void DH_check_standard_parameters(DH *dh); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_DH_INTERNAL_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/dh/params.c b/TMessagesProj/jni/boringssl/crypto/dh/params.c new file mode 100644 index 00000000..82d1d921 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/dh/params.c @@ -0,0 +1,316 @@ +/* ==================================================================== + * Copyright (c) 2011 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include + +#include "internal.h" + + +#if BN_BITS2 == 32 +#define TOBN(lo, hi) lo, hi +#elif BN_BITS2 == 64 +#define TOBN(lo, hi) ((BN_ULONG)hi << 32 | lo) +#else +#error "unsupported BN_BITS2" +#endif + +static const BN_ULONG dh1024_160_p[] = { + TOBN(0x2E4A4371, 0xDF1FB2BC), TOBN(0x6D4DA708, 0xE68CFDA7), + TOBN(0x365C1A65, 0x45BF37DF), TOBN(0x0DC8B4BD, 0xA151AF5F), + TOBN(0xF55BCCC0, 0xFAA31A4F), TOBN(0xE5644738, 0x4EFFD6FA), + TOBN(0x219A7372, 0x98488E9C), TOBN(0x90C4BD70, 0xACCBDD7D), + TOBN(0xD49B83BF, 0x24975C3C), TOBN(0xA9061123, 0x13ECB4AE), + TOBN(0x2EE652C0, 0x9838EF1E), TOBN(0x75A23D18, 0x6073E286), + TOBN(0x52D23B61, 0x9A6A9DCA), TOBN(0xFB06A3C6, 0x52C99FBC), + TOBN(0xAE5D54EC, 0xDE92DE5E), TOBN(0xA080E01D, 0xB10B8F96), +}; +static const BN_ULONG dh1024_160_g[] = { + TOBN(0x22B3B2E5, 0x855E6EEB), TOBN(0xF97C2A24, 0x858F4DCE), + TOBN(0x18D08BC8, 0x2D779D59), TOBN(0x8E73AFA3, 0xD662A4D1), + TOBN(0x69B6A28A, 0x1DBF0A01), TOBN(0x7A091F53, 0xA6A24C08), + TOBN(0x63F80A76, 0x909D0D22), TOBN(0xB9A92EE1, 0xD7FBD7D3), + TOBN(0x9E2749F4, 0x5E91547F), TOBN(0xB01B886A, 0x160217B4), + TOBN(0x5504F213, 0x777E690F), TOBN(0x5C41564B, 0x266FEA1E), + TOBN(0x14266D31, 0xD6406CFF), TOBN(0x58AC507F, 0xF8104DD2), + TOBN(0xEFB99905, 0x6765A442), TOBN(0xC3FD3412, 0xA4D1CBD5), +}; +static const BN_ULONG dh1024_160_q[] = { + TOBN(0x49462353, 0x64B7CB9D), TOBN(0x8ABA4E7D, 0x81A8DF27), 0xF518AA87, +}; + +static const BN_ULONG dh2048_224_p[] = { + TOBN(0x0C10E64F, 0x0AC4DFFE), TOBN(0x4E71B81C, 0xCF9DE538), + TOBN(0xFFA31F71, 0x7EF363E2), TOBN(0x6B8E75B9, 0xE3FB73C1), + TOBN(0x4BA80A29, 0xC9B53DCF), TOBN(0x16E79763, 0x23F10B0E), + TOBN(0x13042E9B, 0xC52172E4), TOBN(0xC928B2B9, 0xBE60E69C), + TOBN(0xB9E587E8, 0x80CD86A1), TOBN(0x98C641A4, 0x315D75E1), + TOBN(0x44328387, 0xCDF93ACC), TOBN(0xDC0A486D, 0x15987D9A), + TOBN(0x1FD5A074, 0x7310F712), TOBN(0xDE31EFDC, 0x278273C7), + TOBN(0x415D9330, 0x1602E714), TOBN(0xBC8985DB, 0x81286130), + TOBN(0x70918836, 0xB3BF8A31), TOBN(0xB9C49708, 0x6A00E0A0), + TOBN(0x8BBC27BE, 0xC6BA0B2C), TOBN(0xED34DBF6, 0xC9F98D11), + TOBN(0xB6C12207, 0x7AD5B7D0), TOBN(0x55B7394B, 0xD91E8FEF), + TOBN(0xEFDA4DF8, 0x9037C9ED), TOBN(0xAD6AC212, 0x6D3F8152), + TOBN(0x1274A0A6, 0x1DE6B85A), TOBN(0x309C180E, 0xEB3D688A), + TOBN(0x7BA1DF15, 0xAF9A3C40), TOBN(0xF95A56DB, 0xE6FA141D), + TOBN(0xB61D0A75, 0xB54B1597), TOBN(0x683B9FD1, 0xA20D64E5), + TOBN(0x9559C51F, 0xD660FAA7), TOBN(0x9123A9D0, 0xAD107E1E), +}; + +static const BN_ULONG dh2048_224_g[] = { + TOBN(0x191F2BFA, 0x84B890D3), TOBN(0x2A7065B3, 0x81BC087F), + TOBN(0xF6EC0179, 0x19C418E1), TOBN(0x71CFFF4C, 0x7B5A0F1C), + TOBN(0x9B6AA4BD, 0xEDFE72FE), TOBN(0x94B30269, 0x81E1BCFE), + TOBN(0x8D6C0191, 0x566AFBB4), TOBN(0x409D13CD, 0xB539CCE3), + TOBN(0x5F2FF381, 0x6AA21E7F), TOBN(0x770589EF, 0xD9E263E4), + TOBN(0xD19963DD, 0x10E183ED), TOBN(0x150B8EEB, 0xB70A8137), + TOBN(0x28C8F8AC, 0x051AE3D4), TOBN(0x0C1AB15B, 0xBB77A86F), + TOBN(0x16A330EF, 0x6E3025E3), TOBN(0xD6F83456, 0x19529A45), + TOBN(0x118E98D1, 0xF180EB34), TOBN(0x50717CBE, 0xB5F6C6B2), + TOBN(0xDA7460CD, 0x09939D54), TOBN(0x22EA1ED4, 0xE2471504), + TOBN(0x521BC98A, 0xB8A762D0), TOBN(0x5AC1348B, 0xF4D02727), + TOBN(0x1999024A, 0xC1766910), TOBN(0xA8D66AD7, 0xBE5E9001), + TOBN(0x620A8652, 0xC57DB17C), TOBN(0x00C29F52, 0xAB739D77), + TOBN(0xA70C4AFA, 0xDD921F01), TOBN(0x10B9A6F0, 0xA6824A4E), + TOBN(0xCFE4FFE3, 0x74866A08), TOBN(0x89998CAF, 0x6CDEBE7B), + TOBN(0x8FFDAC50, 0x9DF30B5C), TOBN(0x4F2D9AE3, 0xAC4032EF), +}; + +static const BN_ULONG dh2048_224_q[] = { + TOBN(0xB36371EB, 0xBF389A99), TOBN(0x4738CEBC, 0x1F80535A), + TOBN(0x99717710, 0xC58D93FE), 0x801C0D34, +}; + +static const BN_ULONG dh2048_256_p[] = { + TOBN(0x1E1A1597, 0xDB094AE9), TOBN(0xD7EF09CA, 0x693877FA), + TOBN(0x6E11715F, 0x6116D227), TOBN(0xC198AF12, 0xA4B54330), + TOBN(0xD7014103, 0x75F26375), TOBN(0x54E710C3, 0xC3A3960A), + TOBN(0xBD0BE621, 0xDED4010A), TOBN(0x89962856, 0xC0B857F6), + TOBN(0x71506026, 0xB3CA3F79), TOBN(0xE6B486F6, 0x1CCACB83), + TOBN(0x14056425, 0x67E144E5), TOBN(0xA41825D9, 0xF6A167B5), + TOBN(0x96524D8E, 0x3AD83477), TOBN(0x51BFA4AB, 0xF13C6D9A), + TOBN(0x35488A0E, 0x2D525267), TOBN(0xCAA6B790, 0xB63ACAE1), + TOBN(0x81B23F76, 0x4FDB70C5), TOBN(0x12307F5C, 0xBC39A0BF), + TOBN(0xB1E59BB8, 0xB941F54E), TOBN(0xD45F9088, 0x6C5BFC11), + TOBN(0x4275BF7B, 0x22E0B1EF), TOBN(0x5B4758C0, 0x91F9E672), + TOBN(0x6BCF67ED, 0x5A8A9D30), TOBN(0x97517ABD, 0x209E0C64), + TOBN(0x830E9A7C, 0x3BF4296D), TOBN(0x34096FAA, 0x16C3D911), + TOBN(0x61B2AA30, 0xFAF7DF45), TOBN(0xD61957D4, 0xE00DF8F1), + TOBN(0x435E3B00, 0x5D2CEED4), TOBN(0x660DD0F2, 0x8CEEF608), + TOBN(0x65195999, 0xFFBBD19C), TOBN(0xB4B6663C, 0x87A8E61D), +}; +static const BN_ULONG dh2048_256_g[] = { + TOBN(0x6CC41659, 0x664B4C0F), TOBN(0xEF98C582, 0x5E2327CF), + TOBN(0xD4795451, 0xD647D148), TOBN(0x90F00EF8, 0x2F630784), + TOBN(0x1DB246C3, 0x184B523D), TOBN(0xCDC67EB6, 0xC7891428), + TOBN(0x0DF92B52, 0x7FD02837), TOBN(0x64E0EC37, 0xB3353BBB), + TOBN(0x57CD0915, 0xECD06E15), TOBN(0xDF016199, 0xB7D2BBD2), + TOBN(0x052588B9, 0xC8484B1E), TOBN(0x13D3FE14, 0xDB2A3B73), + TOBN(0xD182EA0A, 0xD052B985), TOBN(0xE83B9C80, 0xA4BD1BFF), + TOBN(0xFB3F2E55, 0xDFC967C1), TOBN(0x767164E1, 0xB5045AF2), + TOBN(0x6F2F9193, 0x1D14348F), TOBN(0x428EBC83, 0x64E67982), + TOBN(0x82D6ED38, 0x8AC376D2), TOBN(0xAAB8A862, 0x777DE62A), + TOBN(0xE9EC144B, 0xDDF463E5), TOBN(0xC77A57F2, 0x0196F931), + TOBN(0x41000A65, 0xA55AE313), TOBN(0xC28CBB18, 0x901228F8), + TOBN(0x7E8C6F62, 0xBC3773BF), TOBN(0x0C6B47B1, 0xBE3A6C1B), + TOBN(0xAC0BB555, 0xFF4FED4A), TOBN(0x77BE463F, 0x10DBC150), + TOBN(0x1A0BA125, 0x07F4793A), TOBN(0x21EF2054, 0x4CA7B18F), + TOBN(0x60EDBD48, 0x2E775066), TOBN(0x73134D0B, 0x3FB32C9B), +}; +static const BN_ULONG dh2048_256_q[] = { + TOBN(0x64F5FBD3, 0xA308B0FE), TOBN(0x1EB3750B, 0x99B1A47D), + TOBN(0x40129DA2, 0xB4479976), TOBN(0xA709A097, 0x8CF83642), +}; + +/* dh1024_safe_prime_1 is hard-coded in Apache httpd 2.2, + * modules/ssl/ssl_engine_dh.c. */ +static const BN_ULONG dh1024_safe_prime_1[] = { + TOBN(0x24218EB3, 0xE7393E0F), TOBN(0xE2BD68B0, 0x7DE0F4D6), + TOBN(0x88AEAA74, 0x07DD62DB), TOBN(0x9DDD3305, 0x10EA9FCC), + TOBN(0x74087D15, 0xA7DBCA78), TOBN(0x78045B07, 0xDAE88600), + TOBN(0x1AAD3B72, 0x33168A46), TOBN(0x7BEDDCFD, 0xFF590137), + TOBN(0x7A635E81, 0xFE324A46), TOBN(0x420B2A29, 0x5AC179BA), + TOBN(0x177E16D5, 0x13B4B4D7), TOBN(0x639C72FB, 0x849F912E), + TOBN(0x98BCE951, 0xB88174CB), TOBN(0xA45F520B, 0x0C84D239), + TOBN(0x4AFD0AD5, 0x36D693D3), TOBN(0xCBBBDC19, 0xD67DE440), +}; + +/* dh1024_safe_prime_2 is hard-coded in nginx, + * src/event/ngx_event_openssl.c. */ +static const BN_ULONG dh1024_safe_prime_2[] = { + TOBN(0xCFE16B9B, 0x071DF045), TOBN(0x146757DA, 0x88D0F65D), + TOBN(0x58FAFD49, 0x4A63AB1E), TOBN(0xEF9EA027, 0x35D8CECE), + TOBN(0x70CC9A50, 0x25ECE662), TOBN(0x81DC2CA7, 0xF29BA5DF), + TOBN(0xF7D36CC8, 0x8F68B076), TOBN(0xA757E304, 0x60E91A92), + TOBN(0x9BE67780, 0x87A2BC04), TOBN(0xA5FDF1D2, 0xBEECA565), + TOBN(0x922614C5, 0x5CCBBAA8), TOBN(0xE710800C, 0x6C030276), + TOBN(0x0FB3504C, 0x08EED4EB), TOBN(0x68B42D4B, 0xD958A3F5), + TOBN(0x80E9CFDB, 0x7C43FCF5), TOBN(0xD8467490, 0xBBBC2DCA), +}; + +/* dh1024_safe_prime_3 is offered as a parameter by several high-traffic sites, + * including mozilla.org, as of Jan 2015. */ +static const BN_ULONG dh1024_safe_prime_3[] = { + TOBN(0x349E721B, 0x671746AE), TOBN(0xD75E93B2, 0x258A0655), + TOBN(0x25592EB6, 0xD425E6FB), TOBN(0xBF7CDD9A, 0x0C46AB04), + TOBN(0x28968680, 0x0AD0BC99), TOBN(0xD0B7EB49, 0xF53907FB), + TOBN(0xEBC85C1D, 0x202EABB3), TOBN(0x364D8C71, 0x3129C693), + TOBN(0x2D46F195, 0x53728351), TOBN(0x8C76CC85, 0xDF326DD6), + TOBN(0x9188E24E, 0xF898B3F9), TOBN(0x2855DFD2, 0x95EFB13C), + TOBN(0x7B2241FE, 0x1F5DAC48), TOBN(0x99A13D9F, 0x117B6BF7), + TOBN(0x3A3468C7, 0x0F97CDDA), TOBN(0x74A8297B, 0xC9BBF5F7)}; + +/* dh1024_safe_prime_4 is hard-coded in Apache httpd 2.0, + * modules/ssl/ssl_engine_dh.c. */ +static const BN_ULONG dh1024_safe_prime_4[] = { + TOBN(0x0DD5C86B, 0x5085E21F), TOBN(0xD823C650, 0x871538DF), + TOBN(0x262E56A8, 0x125136F7), TOBN(0x839EB5DB, 0x974E9EF1), + TOBN(0x1B13A63C, 0xEA9BAD99), TOBN(0x3D76E05E, 0x6044CF02), + TOBN(0x1BAC9B5C, 0x611EBBBE), TOBN(0x4E5327DF, 0x3E371D79), + TOBN(0x061CBC05, 0x000E6EDD), TOBN(0x20129B48, 0x2F971F3C), + TOBN(0x3048D5A2, 0xA6EF09C4), TOBN(0xCBD523A6, 0xFA15A259), + TOBN(0x4A79A770, 0x2A206490), TOBN(0x51BB055E, 0x91B78182), + TOBN(0xBDD4798E, 0x7CF180C3), TOBN(0x495BE32C, 0xE6969D3D)}; + +static const BN_ULONG bn_two_data[] = {2}; + +#define STATIC_BIGNUM(x) \ + { \ + (BN_ULONG *) x, sizeof(x) / sizeof(BN_ULONG), \ + sizeof(x) / sizeof(BN_ULONG), 0, BN_FLG_STATIC_DATA \ + } + +struct standard_parameters { + BIGNUM p, q, g; +}; + +static const struct standard_parameters dh1024_160 = { + STATIC_BIGNUM(dh1024_160_p), + STATIC_BIGNUM(dh1024_160_q), + STATIC_BIGNUM(dh1024_160_g), +}; + +static const struct standard_parameters dh2048_224 = { + STATIC_BIGNUM(dh2048_224_p), + STATIC_BIGNUM(dh2048_224_q), + STATIC_BIGNUM(dh2048_224_g), +}; + +static const struct standard_parameters dh2048_256 = { + STATIC_BIGNUM(dh2048_256_p), + STATIC_BIGNUM(dh2048_256_q), + STATIC_BIGNUM(dh2048_256_g), +}; + +static const BIGNUM dh1024_safe_prime[] = { + STATIC_BIGNUM(dh1024_safe_prime_1), + STATIC_BIGNUM(dh1024_safe_prime_2), + STATIC_BIGNUM(dh1024_safe_prime_3), + STATIC_BIGNUM(dh1024_safe_prime_4) +}; + +BIGNUM bn_two = STATIC_BIGNUM(bn_two_data); + +static DH *get_standard_parameters(const struct standard_parameters *params, + const ENGINE *engine) { + DH *dh; + + dh = DH_new_method(engine); + if (!dh) { + return NULL; + } + + dh->p = BN_dup(¶ms->p); + dh->q = BN_dup(¶ms->q); + dh->g = BN_dup(¶ms->g); + if (!dh->p || !dh->q || !dh->g) { + DH_free(dh); + return NULL; + } + + return dh; +} + +DH *DH_get_1024_160(const ENGINE *engine) { + return get_standard_parameters(&dh1024_160, engine); +} + +DH *DH_get_2048_224(const ENGINE *engine) { + return get_standard_parameters(&dh2048_224, engine); +} + +DH *DH_get_2048_256(const ENGINE *engine) { + return get_standard_parameters(&dh2048_256, engine); +} + +void DH_check_standard_parameters(DH *dh) { + int i; + + if (dh->p == NULL || + dh->g == NULL || + BN_num_bytes(dh->p) != (1024 / 8) || + BN_cmp(dh->g, &bn_two) != 0) { + return; + } + + for (i = 0; i < sizeof(dh1024_safe_prime) / sizeof(dh1024_safe_prime[0]); + i++) { + if (BN_cmp(dh->p, &dh1024_safe_prime[i]) == 0) { + /* The well-known DH groups are known to have safe primes. In this case + * we can safely reduce the size of the private key. */ + dh->priv_length = 161; + break; + } + } +} diff --git a/TMessagesProj/jni/boringssl/crypto/digest/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/digest/CMakeLists.txt new file mode 100644 index 00000000..8c933925 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/digest/CMakeLists.txt @@ -0,0 +1,10 @@ +include_directories(. .. ../../include) + +add_library( + digest + + OBJECT + + digest.c + digests.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/digest/digest.c b/TMessagesProj/jni/boringssl/crypto/digest/digest.c new file mode 100644 index 00000000..7082c484 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/digest/digest.c @@ -0,0 +1,247 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include +#include + +#include "internal.h" + + +int EVP_MD_type(const EVP_MD *md) { return md->type; } + +uint32_t EVP_MD_flags(const EVP_MD *md) { return md->flags; } + +size_t EVP_MD_size(const EVP_MD *md) { return md->md_size; } + +size_t EVP_MD_block_size(const EVP_MD *md) { return md->block_size; } + + +void EVP_MD_CTX_init(EVP_MD_CTX *ctx) { memset(ctx, 0, sizeof(EVP_MD_CTX)); } + +EVP_MD_CTX *EVP_MD_CTX_create(void) { + EVP_MD_CTX *ctx = OPENSSL_malloc(sizeof(EVP_MD_CTX)); + + if (ctx) { + EVP_MD_CTX_init(ctx); + } + + return ctx; +} + +int EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx) { + if (ctx->digest && ctx->digest->ctx_size && ctx->md_data) { + OPENSSL_cleanse(ctx->md_data, ctx->digest->ctx_size); + OPENSSL_free(ctx->md_data); + } + + assert(ctx->pctx == NULL || ctx->pctx_ops != NULL); + if (ctx->pctx_ops) { + ctx->pctx_ops->free(ctx->pctx); + } + + EVP_MD_CTX_init(ctx); + + return 1; +} + +void EVP_MD_CTX_destroy(EVP_MD_CTX *ctx) { + if (!ctx) { + return; + } + + EVP_MD_CTX_cleanup(ctx); + OPENSSL_free(ctx); +} + +int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in) { + uint8_t *tmp_buf = NULL; + + if (in == NULL || in->digest == NULL) { + OPENSSL_PUT_ERROR(DIGEST, DIGEST_R_INPUT_NOT_INITIALIZED); + return 0; + } + + if (out->digest == in->digest) { + /* |md_data| will be the correct size in this case so it's removed from + * |out| at this point so that |EVP_MD_CTX_cleanup| doesn't free it and + * then it's reused. */ + tmp_buf = out->md_data; + out->md_data = NULL; + } + + EVP_MD_CTX_cleanup(out); + memcpy(out, in, sizeof(EVP_MD_CTX)); + + if (in->md_data && in->digest->ctx_size) { + if (tmp_buf) { + out->md_data = tmp_buf; + } else { + out->md_data = OPENSSL_malloc(in->digest->ctx_size); + if (!out->md_data) { + OPENSSL_PUT_ERROR(DIGEST, ERR_R_MALLOC_FAILURE); + return 0; + } + } + memcpy(out->md_data, in->md_data, in->digest->ctx_size); + } + + assert(in->pctx == NULL || in->pctx_ops != NULL); + if (in->pctx && in->pctx_ops) { + out->pctx = in->pctx_ops->dup(in->pctx); + if (!out->pctx) { + EVP_MD_CTX_cleanup(out); + return 0; + } + } + + return 1; +} + +int EVP_MD_CTX_copy(EVP_MD_CTX *out, const EVP_MD_CTX *in) { + EVP_MD_CTX_init(out); + return EVP_MD_CTX_copy_ex(out, in); +} + +int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *engine) { + if (ctx->digest != type) { + if (ctx->digest && ctx->digest->ctx_size > 0) { + OPENSSL_free(ctx->md_data); + } + ctx->digest = type; + if (type->ctx_size > 0) { + ctx->md_data = OPENSSL_malloc(type->ctx_size); + if (ctx->md_data == NULL) { + OPENSSL_PUT_ERROR(DIGEST, ERR_R_MALLOC_FAILURE); + return 0; + } + } + } + + assert(ctx->pctx == NULL || ctx->pctx_ops != NULL); + + ctx->digest->init(ctx); + return 1; +} + +int EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type) { + EVP_MD_CTX_init(ctx); + return EVP_DigestInit_ex(ctx, type, NULL); +} + +int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *data, size_t len) { + ctx->digest->update(ctx, data, len); + return 1; +} + +int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, uint8_t *md_out, unsigned int *size) { + assert(ctx->digest->md_size <= EVP_MAX_MD_SIZE); + ctx->digest->final(ctx, md_out); + if (size != NULL) { + *size = ctx->digest->md_size; + } + OPENSSL_cleanse(ctx->md_data, ctx->digest->ctx_size); + return 1; +} + +int EVP_DigestFinal(EVP_MD_CTX *ctx, uint8_t *md, unsigned int *size) { + EVP_DigestFinal_ex(ctx, md, size); + EVP_MD_CTX_cleanup(ctx); + return 1; +} + +int EVP_Digest(const void *data, size_t count, uint8_t *out_md, + unsigned int *out_size, const EVP_MD *type, ENGINE *impl) { + EVP_MD_CTX ctx; + int ret; + + EVP_MD_CTX_init(&ctx); + ret = EVP_DigestInit_ex(&ctx, type, impl) && + EVP_DigestUpdate(&ctx, data, count) && + EVP_DigestFinal_ex(&ctx, out_md, out_size); + EVP_MD_CTX_cleanup(&ctx); + + return ret; +} + + +const EVP_MD *EVP_MD_CTX_md(const EVP_MD_CTX *ctx) { + if (ctx == NULL) { + return NULL; + } + return ctx->digest; +} + +unsigned EVP_MD_CTX_size(const EVP_MD_CTX *ctx) { + return EVP_MD_size(EVP_MD_CTX_md(ctx)); +} + +unsigned EVP_MD_CTX_block_size(const EVP_MD_CTX *ctx) { + return EVP_MD_block_size(EVP_MD_CTX_md(ctx)); +} + +int EVP_MD_CTX_type(const EVP_MD_CTX *ctx) { + return EVP_MD_type(EVP_MD_CTX_md(ctx)); +} + +int EVP_add_digest(const EVP_MD *digest) { + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/digest/digests.c b/TMessagesProj/jni/boringssl/crypto/digest/digests.c new file mode 100644 index 00000000..9c0e3e1e --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/digest/digests.c @@ -0,0 +1,298 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include +#include + +#include "internal.h" + +#if defined(NDEBUG) +#define CHECK(x) (void) (x) +#else +#define CHECK(x) assert(x) +#endif + +static void md5_init(EVP_MD_CTX *ctx) { + CHECK(MD5_Init(ctx->md_data)); +} + +static void md5_update(EVP_MD_CTX *ctx, const void *data, size_t count) { + CHECK(MD5_Update(ctx->md_data, data, count)); +} + +static void md5_final(EVP_MD_CTX *ctx, uint8_t *out) { + CHECK(MD5_Final(out, ctx->md_data)); +} + +static const EVP_MD md5_md = { + NID_md5, MD5_DIGEST_LENGTH, 0 /* flags */, md5_init, + md5_update, md5_final, 64 /* block size */, sizeof(MD5_CTX), +}; + +const EVP_MD *EVP_md5(void) { return &md5_md; } + + +static void sha1_init(EVP_MD_CTX *ctx) { + CHECK(SHA1_Init(ctx->md_data)); +} + +static void sha1_update(EVP_MD_CTX *ctx, const void *data, size_t count) { + CHECK(SHA1_Update(ctx->md_data, data, count)); +} + +static void sha1_final(EVP_MD_CTX *ctx, uint8_t *md) { + CHECK(SHA1_Final(md, ctx->md_data)); +} + +static const EVP_MD sha1_md = { + NID_sha1, SHA_DIGEST_LENGTH, 0 /* flags */, sha1_init, + sha1_update, sha1_final, 64 /* block size */, sizeof(SHA_CTX), +}; + +const EVP_MD *EVP_sha1(void) { return &sha1_md; } + + +static void sha224_init(EVP_MD_CTX *ctx) { + CHECK(SHA224_Init(ctx->md_data)); +} + +static void sha224_update(EVP_MD_CTX *ctx, const void *data, size_t count) { + CHECK(SHA224_Update(ctx->md_data, data, count)); +} + +static void sha224_final(EVP_MD_CTX *ctx, uint8_t *md) { + CHECK(SHA224_Final(md, ctx->md_data)); +} + +static const EVP_MD sha224_md = { + NID_sha224, SHA224_DIGEST_LENGTH, 0 /* flags */, + sha224_init, sha224_update, sha224_final, + 64 /* block size */, sizeof(SHA256_CTX), +}; + +const EVP_MD *EVP_sha224(void) { return &sha224_md; } + + +static void sha256_init(EVP_MD_CTX *ctx) { + CHECK(SHA256_Init(ctx->md_data)); +} + +static void sha256_update(EVP_MD_CTX *ctx, const void *data, size_t count) { + CHECK(SHA256_Update(ctx->md_data, data, count)); +} + +static void sha256_final(EVP_MD_CTX *ctx, uint8_t *md) { + CHECK(SHA256_Final(md, ctx->md_data)); +} + +static const EVP_MD sha256_md = { + NID_sha256, SHA256_DIGEST_LENGTH, 0 /* flags */, + sha256_init, sha256_update, sha256_final, + 64 /* block size */, sizeof(SHA256_CTX), +}; + +const EVP_MD *EVP_sha256(void) { return &sha256_md; } + + +static void sha384_init(EVP_MD_CTX *ctx) { + CHECK(SHA384_Init(ctx->md_data)); +} + +static void sha384_update(EVP_MD_CTX *ctx, const void *data, size_t count) { + CHECK(SHA384_Update(ctx->md_data, data, count)); +} + +static void sha384_final(EVP_MD_CTX *ctx, uint8_t *md) { + CHECK(SHA384_Final(md, ctx->md_data)); +} + +static const EVP_MD sha384_md = { + NID_sha384, SHA384_DIGEST_LENGTH, 0 /* flags */, + sha384_init, sha384_update, sha384_final, + 128 /* block size */, sizeof(SHA512_CTX), +}; + +const EVP_MD *EVP_sha384(void) { return &sha384_md; } + + +static void sha512_init(EVP_MD_CTX *ctx) { + CHECK(SHA512_Init(ctx->md_data)); +} + +static void sha512_update(EVP_MD_CTX *ctx, const void *data, size_t count) { + CHECK(SHA512_Update(ctx->md_data, data, count)); +} + +static void sha512_final(EVP_MD_CTX *ctx, uint8_t *md) { + CHECK(SHA512_Final(md, ctx->md_data)); +} + +static const EVP_MD sha512_md = { + NID_sha512, SHA512_DIGEST_LENGTH, 0 /* flags */, + sha512_init, sha512_update, sha512_final, + 128 /* block size */, sizeof(SHA512_CTX), +}; + +const EVP_MD *EVP_sha512(void) { return &sha512_md; } + + +typedef struct { + MD5_CTX md5; + SHA_CTX sha1; +} MD5_SHA1_CTX; + +static void md5_sha1_init(EVP_MD_CTX *md_ctx) { + MD5_SHA1_CTX *ctx = md_ctx->md_data; + CHECK(MD5_Init(&ctx->md5) && SHA1_Init(&ctx->sha1)); +} + +static void md5_sha1_update(EVP_MD_CTX *md_ctx, const void *data, + size_t count) { + MD5_SHA1_CTX *ctx = md_ctx->md_data; + CHECK(MD5_Update(&ctx->md5, data, count) && + SHA1_Update(&ctx->sha1, data, count)); +} + +static void md5_sha1_final(EVP_MD_CTX *md_ctx, uint8_t *out) { + MD5_SHA1_CTX *ctx = md_ctx->md_data; + CHECK(MD5_Final(out, &ctx->md5) && + SHA1_Final(out + MD5_DIGEST_LENGTH, &ctx->sha1)); +} + +static const EVP_MD md5_sha1_md = { + NID_md5_sha1, + MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH, + 0 /* flags */, + md5_sha1_init, + md5_sha1_update, + md5_sha1_final, + 64 /* block size */, + sizeof(MD5_SHA1_CTX), +}; + +const EVP_MD *EVP_md5_sha1(void) { return &md5_sha1_md; } + + +struct nid_to_digest { + int nid; + const EVP_MD* (*md_func)(void); + const char *short_name; + const char *long_name; +}; + +static const struct nid_to_digest nid_to_digest_mapping[] = { + { NID_md5, EVP_md5, SN_md5, LN_md5 }, + { NID_sha1, EVP_sha1, SN_sha1, LN_sha1 }, + { NID_sha224, EVP_sha224, SN_sha224, LN_sha224 }, + { NID_sha256, EVP_sha256, SN_sha256, LN_sha256 }, + { NID_sha384, EVP_sha384, SN_sha384, LN_sha384 }, + { NID_sha512, EVP_sha512, SN_sha512, LN_sha512 }, + { NID_md5_sha1, EVP_md5_sha1, SN_md5_sha1, LN_md5_sha1 }, + { NID_dsaWithSHA, EVP_sha1, SN_dsaWithSHA, LN_dsaWithSHA }, + { NID_dsaWithSHA1, EVP_sha1, SN_dsaWithSHA1, LN_dsaWithSHA1 }, + { NID_ecdsa_with_SHA1, EVP_sha1, SN_ecdsa_with_SHA1, NULL }, + { NID_md5WithRSAEncryption, EVP_md5, SN_md5WithRSAEncryption, + LN_md5WithRSAEncryption }, + { NID_sha1WithRSAEncryption, EVP_sha1, SN_sha1WithRSAEncryption, + LN_sha1WithRSAEncryption }, + { NID_sha224WithRSAEncryption, EVP_sha224, SN_sha224WithRSAEncryption, + LN_sha224WithRSAEncryption }, + { NID_sha256WithRSAEncryption, EVP_sha256, SN_sha256WithRSAEncryption, + LN_sha256WithRSAEncryption }, + { NID_sha384WithRSAEncryption, EVP_sha384, SN_sha384WithRSAEncryption, + LN_sha384WithRSAEncryption }, + { NID_sha512WithRSAEncryption, EVP_sha512, SN_sha512WithRSAEncryption, + LN_sha512WithRSAEncryption }, +}; + +const EVP_MD* EVP_get_digestbynid(int nid) { + unsigned i; + + for (i = 0; i < sizeof(nid_to_digest_mapping) / sizeof(struct nid_to_digest); + i++) { + if (nid_to_digest_mapping[i].nid == nid) { + return nid_to_digest_mapping[i].md_func(); + } + } + + return NULL; +} + +const EVP_MD* EVP_get_digestbyobj(const ASN1_OBJECT *obj) { + return EVP_get_digestbynid(OBJ_obj2nid(obj)); +} + +const EVP_MD *EVP_get_digestbyname(const char *name) { + unsigned i; + + for (i = 0; i < sizeof(nid_to_digest_mapping) / sizeof(struct nid_to_digest); + i++) { + const char *short_name = nid_to_digest_mapping[i].short_name; + const char *long_name = nid_to_digest_mapping[i].long_name; + if ((short_name && strcmp(short_name, name) == 0) || + (long_name && strcmp(long_name, name) == 0)) { + return nid_to_digest_mapping[i].md_func(); + } + } + + return NULL; +} diff --git a/TMessagesProj/jni/boringssl/crypto/digest/internal.h b/TMessagesProj/jni/boringssl/crypto/digest/internal.h new file mode 100644 index 00000000..e3d812ad --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/digest/internal.h @@ -0,0 +1,112 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_DIGEST_INTERNAL_H +#define OPENSSL_HEADER_DIGEST_INTERNAL_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +struct env_md_st { + /* type contains a NID identifing the digest function. (For example, + * NID_md5.) */ + int type; + + /* md_size contains the size, in bytes, of the resulting digest. */ + unsigned md_size; + + /* flags contains the OR of |EVP_MD_FLAG_*| values. */ + uint32_t flags; + + /* init initialises the state in |ctx->md_data|. */ + void (*init)(EVP_MD_CTX *ctx); + + /* update hashes |len| bytes of |data| into the state in |ctx->md_data|. */ + void (*update)(EVP_MD_CTX *ctx, const void *data, size_t count); + + /* final completes the hash and writes |md_size| bytes of digest to |out|. */ + void (*final)(EVP_MD_CTX *ctx, uint8_t *out); + + /* block_size contains the hash's native block size. */ + unsigned block_size; + + /* ctx_size contains the size, in bytes, of the state of the hash function. */ + unsigned ctx_size; +}; + +/* evp_md_pctx_ops contains function pointers to allow the |pctx| member of + * |EVP_MD_CTX| to be manipulated without breaking layering by calling EVP + * functions. */ +struct evp_md_pctx_ops { + /* free is called when an |EVP_MD_CTX| is being freed and the |pctx| also + * needs to be freed. */ + void (*free) (EVP_PKEY_CTX *pctx); + + /* dup is called when an |EVP_MD_CTX| is copied and so the |pctx| also needs + * to be copied. */ + EVP_PKEY_CTX* (*dup) (EVP_PKEY_CTX *pctx); +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_DIGEST_INTERNAL */ diff --git a/TMessagesProj/jni/boringssl/crypto/digest/md32_common.h b/TMessagesProj/jni/boringssl/crypto/digest/md32_common.h new file mode 100644 index 00000000..14607fba --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/digest/md32_common.h @@ -0,0 +1,350 @@ +/* ==================================================================== + * Copyright (c) 1999-2007 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== */ + +#ifndef OPENSSL_HEADER_MD32_COMMON_H +#define OPENSSL_HEADER_MD32_COMMON_H + +#include + + +#if defined(__cplusplus) +extern "C" { +#endif + +#define asm __asm__ + +/* This is a generic 32 bit "collector" for message digest algorithms. + * Whenever needed it collects input character stream into chunks of + * 32 bit values and invokes a block function that performs actual hash + * calculations. + * + * Porting guide. + * + * Obligatory macros: + * + * DATA_ORDER_IS_BIG_ENDIAN or DATA_ORDER_IS_LITTLE_ENDIAN + * this macro defines byte order of input stream. + * HASH_CBLOCK + * size of a unit chunk HASH_BLOCK operates on. + * HASH_LONG + * has to be at least 32 bit wide. + * HASH_CTX + * context structure that at least contains following + * members: + * typedef struct { + * ... + * HASH_LONG Nl,Nh; + * either { + * HASH_LONG data[HASH_LBLOCK]; + * unsigned char data[HASH_CBLOCK]; + * }; + * unsigned int num; + * ... + * } HASH_CTX; + * data[] vector is expected to be zeroed upon first call to + * HASH_UPDATE. + * HASH_UPDATE + * name of "Update" function, implemented here. + * HASH_TRANSFORM + * name of "Transform" function, implemented here. + * HASH_FINAL + * name of "Final" function, implemented here. + * HASH_BLOCK_DATA_ORDER + * name of "block" function capable of treating *unaligned* input + * message in original (data) byte order, implemented externally. + * HASH_MAKE_STRING + * macro convering context variables to an ASCII hash string. + * + * + */ + +#if !defined(DATA_ORDER_IS_BIG_ENDIAN) && !defined(DATA_ORDER_IS_LITTLE_ENDIAN) +#error "DATA_ORDER must be defined!" +#endif + +#ifndef HASH_CBLOCK +#error "HASH_CBLOCK must be defined!" +#endif +#ifndef HASH_LONG +#error "HASH_LONG must be defined!" +#endif +#ifndef HASH_CTX +#error "HASH_CTX must be defined!" +#endif + +#ifndef HASH_UPDATE +#error "HASH_UPDATE must be defined!" +#endif +#ifndef HASH_TRANSFORM +#error "HASH_TRANSFORM must be defined!" +#endif +#ifndef HASH_FINAL +#error "HASH_FINAL must be defined!" +#endif + +#ifndef HASH_BLOCK_DATA_ORDER +#error "HASH_BLOCK_DATA_ORDER must be defined!" +#endif + +/* + * Engage compiler specific rotate intrinsic function if available. + */ +#undef ROTATE +# if defined(_MSC_VER) +# define ROTATE(a,n) _lrotl(a,n) +# elif defined(__ICC) +# define ROTATE(a,n) _rotl(a,n) +# elif defined(__GNUC__) && __GNUC__>=2 && !defined(OPENSSL_NO_ASM) + /* + * Some GNU C inline assembler templates. Note that these are + * rotates by *constant* number of bits! But that's exactly + * what we need here... + * + */ +# if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) +# define ROTATE(a,n) ({ register uint32_t ret; \ + asm ( \ + "roll %1,%0" \ + : "=r"(ret) \ + : "I"(n), "0"((uint32_t)(a)) \ + : "cc"); \ + ret; \ + }) +# endif /* OPENSSL_X86 || OPENSSL_X86_64 */ +# endif /* COMPILER */ + +#ifndef ROTATE +#define ROTATE(a,n) (((a)<<(n))|(((a)&0xffffffff)>>(32-(n)))) +#endif + +#if defined(DATA_ORDER_IS_BIG_ENDIAN) + +#ifndef PEDANTIC +# if defined(__GNUC__) && __GNUC__>=2 && !defined(OPENSSL_NO_ASM) +# if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) + /* + * This gives ~30-40% performance improvement in SHA-256 compiled + * with gcc [on P4]. Well, first macro to be frank. We can pull + * this trick on x86* platforms only, because these CPUs can fetch + * unaligned data without raising an exception. + */ +# define HOST_c2l(c,l) ({ uint32_t r=*((const uint32_t *)(c)); \ + asm ("bswapl %0":"=r"(r):"0"(r)); \ + (c)+=4; (l)=r; }) +# define HOST_l2c(l,c) ({ uint32_t r=(l); \ + asm ("bswapl %0":"=r"(r):"0"(r)); \ + *((uint32_t *)(c))=r; (c)+=4; r; }) +# elif defined(__aarch64__) +# if defined(__BYTE_ORDER__) +# if defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__ +# define HOST_c2l(c,l) ({ uint32_t r; \ + asm ("rev %w0,%w1" \ + :"=r"(r) \ + :"r"(*((const uint32_t *)(c))));\ + (c)+=4; (l)=r; }) +# define HOST_l2c(l,c) ({ uint32_t r; \ + asm ("rev %w0,%w1" \ + :"=r"(r) \ + :"r"((uint32_t)(l))); \ + *((uint32_t *)(c))=r; (c)+=4; r; }) +# elif defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__==__ORDER_BIG_ENDIAN__ +# define HOST_c2l(c,l) (void)((l)=*((const uint32_t *)(c)), (c)+=4) +# define HOST_l2c(l,c) (*((uint32_t *)(c))=(l), (c)+=4, (l)) +# endif +# endif +# endif +# endif +#endif + +#ifndef HOST_c2l +#define HOST_c2l(c,l) (void)(l =(((uint32_t)(*((c)++)))<<24), \ + l|=(((uint32_t)(*((c)++)))<<16), \ + l|=(((uint32_t)(*((c)++)))<< 8), \ + l|=(((uint32_t)(*((c)++))) )) +#endif +#ifndef HOST_l2c +#define HOST_l2c(l,c) (*((c)++)=(uint8_t)(((l)>>24)&0xff), \ + *((c)++)=(uint8_t)(((l)>>16)&0xff), \ + *((c)++)=(uint8_t)(((l)>> 8)&0xff), \ + *((c)++)=(uint8_t)(((l) )&0xff), \ + l) +#endif + +#elif defined(DATA_ORDER_IS_LITTLE_ENDIAN) + +#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) + /* See comment in DATA_ORDER_IS_BIG_ENDIAN section. */ +# define HOST_c2l(c,l) (void)((l)=*((const uint32_t *)(c)), (c)+=4) +# define HOST_l2c(l,c) (*((uint32_t *)(c))=(l), (c)+=4, l) +#endif + +#ifndef HOST_c2l +#define HOST_c2l(c,l) (void)(l =(((uint32_t)(*((c)++))) ), \ + l|=(((uint32_t)(*((c)++)))<< 8), \ + l|=(((uint32_t)(*((c)++)))<<16), \ + l|=(((uint32_t)(*((c)++)))<<24)) +#endif +#ifndef HOST_l2c +#define HOST_l2c(l,c) (*((c)++)=(uint8_t)(((l) )&0xff), \ + *((c)++)=(uint8_t)(((l)>> 8)&0xff), \ + *((c)++)=(uint8_t)(((l)>>16)&0xff), \ + *((c)++)=(uint8_t)(((l)>>24)&0xff), \ + l) +#endif + +#endif + +int HASH_UPDATE (HASH_CTX *c, const void *data_, size_t len) + { + const uint8_t *data=data_; + uint8_t *p; + HASH_LONG l; + size_t n; + + if (len==0) return 1; + + l=(c->Nl+(((HASH_LONG)len)<<3))&0xffffffffUL; + /* 95-05-24 eay Fixed a bug with the overflow handling, thanks to + * Wei Dai for pointing it out. */ + if (l < c->Nl) /* overflow */ + c->Nh++; + c->Nh+=(HASH_LONG)(len>>29); /* might cause compiler warning on 16-bit */ + c->Nl=l; + + n = c->num; + if (n != 0) + { + p=(uint8_t *)c->data; + + if (len >= HASH_CBLOCK || len+n >= HASH_CBLOCK) + { + memcpy (p+n,data,HASH_CBLOCK-n); + HASH_BLOCK_DATA_ORDER (c,p,1); + n = HASH_CBLOCK-n; + data += n; + len -= n; + c->num = 0; + memset (p,0,HASH_CBLOCK); /* keep it zeroed */ + } + else + { + memcpy (p+n,data,len); + c->num += (unsigned int)len; + return 1; + } + } + + n = len/HASH_CBLOCK; + if (n > 0) + { + HASH_BLOCK_DATA_ORDER (c,data,n); + n *= HASH_CBLOCK; + data += n; + len -= n; + } + + if (len != 0) + { + p = (uint8_t *)c->data; + c->num = (unsigned int)len; + memcpy (p,data,len); + } + return 1; + } + + +void HASH_TRANSFORM (HASH_CTX *c, const uint8_t *data) + { + HASH_BLOCK_DATA_ORDER (c,data,1); + } + + +int HASH_FINAL (uint8_t *md, HASH_CTX *c) + { + uint8_t *p = (uint8_t *)c->data; + size_t n = c->num; + + p[n] = 0x80; /* there is always room for one */ + n++; + + if (n > (HASH_CBLOCK-8)) + { + memset (p+n,0,HASH_CBLOCK-n); + n=0; + HASH_BLOCK_DATA_ORDER (c,p,1); + } + memset (p+n,0,HASH_CBLOCK-8-n); + + p += HASH_CBLOCK-8; +#if defined(DATA_ORDER_IS_BIG_ENDIAN) + (void)HOST_l2c(c->Nh,p); + (void)HOST_l2c(c->Nl,p); +#elif defined(DATA_ORDER_IS_LITTLE_ENDIAN) + (void)HOST_l2c(c->Nl,p); + (void)HOST_l2c(c->Nh,p); +#endif + p -= HASH_CBLOCK; + HASH_BLOCK_DATA_ORDER (c,p,1); + c->num=0; + memset (p,0,HASH_CBLOCK); + +#ifndef HASH_MAKE_STRING +#error "HASH_MAKE_STRING must be defined!" +#else + HASH_MAKE_STRING(c,md); +#endif + + return 1; + } + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_MD32_COMMON_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/directory.h b/TMessagesProj/jni/boringssl/crypto/directory.h new file mode 100644 index 00000000..29123ea9 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/directory.h @@ -0,0 +1,66 @@ +/* Copied from Richard Levitte's (richard@levitte.org) LP library. All + * symbol names have been changed, with permission from the author. */ + +/* $LP: LPlib/source/LPdir.h,v 1.1 2004/06/14 08:56:04 _cvs_levitte Exp $ */ +/* + * Copyright (c) 2004, Richard Levitte + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef OPENSSL_HEADER_DIRECTORY_H +#define OPENSSL_HEADER_DIRECTORY_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Directory functions abstract the O/S specific operations for opening and + * reading directories in the filesystem. */ + + +/* OPENSSL_dir_context_st is an opaque structure that represents an open + * directory and a position in that directory. */ +typedef struct OPENSSL_dir_context_st OPENSSL_DIR_CTX; + +/* OPENSSL_DIR_read reads a single filename from |ctx|. On the first call, + * |directory| must be given and |*ctx| must be NULL. Subsequent calls with the + * same |*ctx| will return subsequent file names until it returns NULL to + * indicate EOF. The strings returned reference a buffer internal to the + * |OPENSSL_DIR_CTX| and will be overridden by subsequent calls. */ +OPENSSL_EXPORT const char *OPENSSL_DIR_read(OPENSSL_DIR_CTX **ctx, + const char *directory); + +/* OPENSSL_DIR_end closes |*ctx|. It returns one on success and zero on + * error. */ +OPENSSL_EXPORT int OPENSSL_DIR_end(OPENSSL_DIR_CTX **ctx); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_DIRECTORY_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/directory_posix.c b/TMessagesProj/jni/boringssl/crypto/directory_posix.c new file mode 100644 index 00000000..b944b692 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/directory_posix.c @@ -0,0 +1,108 @@ +/* $LP: LPlib/source/LPdir_unix.c,v 1.11 2004/09/23 22:07:22 _cvs_levitte Exp $ */ +/* + * Copyright (c) 2004, Richard Levitte + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +#if !defined(_POSIX_C_SOURCE) +#define _POSIX_C_SOURCE 201409 /* for readdir_r */ +#endif + +#include "directory.h" + + +#if !defined(OPENSSL_WINDOWS) + +#include +#include +#include +#include + +#if defined(OPENSSL_PNACL) +/* pnacl doesn't include readdir_r! So we do the best we can. */ +int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) { + errno = 0; + *result = readdir(dirp); + if (*result != NULL) { + return 0; + } + if (errno) { + return 1; + } + return 0; +} +#endif + +struct OPENSSL_dir_context_st { + DIR *dir; + struct dirent dirent; +}; + +const char *OPENSSL_DIR_read(OPENSSL_DIR_CTX **ctx, const char *directory) { + struct dirent *dirent; + + if (ctx == NULL || directory == NULL) { + errno = EINVAL; + return NULL; + } + + errno = 0; + if (*ctx == NULL) { + *ctx = malloc(sizeof(OPENSSL_DIR_CTX)); + if (*ctx == NULL) { + errno = ENOMEM; + return 0; + } + memset(*ctx, 0, sizeof(OPENSSL_DIR_CTX)); + + (*ctx)->dir = opendir(directory); + if ((*ctx)->dir == NULL) { + int save_errno = errno; /* Probably not needed, but I'm paranoid */ + free(*ctx); + *ctx = NULL; + errno = save_errno; + return 0; + } + } + + if (readdir_r((*ctx)->dir, &(*ctx)->dirent, &dirent) != 0 || + dirent == NULL) { + return 0; + } + + return (*ctx)->dirent.d_name; +} + +int OPENSSL_DIR_end(OPENSSL_DIR_CTX **ctx) { + if (ctx != NULL && *ctx != NULL) { + int r = closedir((*ctx)->dir); + free(*ctx); + *ctx = NULL; + return r == 0; + } + + errno = EINVAL; + return 0; +} + +#endif /* !OPENSSL_WINDOWS */ diff --git a/TMessagesProj/jni/boringssl/crypto/directory_win.c b/TMessagesProj/jni/boringssl/crypto/directory_win.c new file mode 100644 index 00000000..4ebacf21 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/directory_win.c @@ -0,0 +1,144 @@ +/* $LP: LPlib/source/LPdir_win.c,v 1.10 2004/08/26 13:36:05 _cvs_levitte Exp $ */ +/* + * Copyright (c) 2004, Richard Levitte + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "directory.h" + + +#if defined(OPENSSL_WINDOWS) + +#pragma warning(push, 3) +#include +#pragma warning(pop) +#include +#include +#include + +#ifndef NAME_MAX +#define NAME_MAX 255 +#endif + +#include + + +struct OPENSSL_dir_context_st { + WIN32_FIND_DATA ctx; + HANDLE handle; + char entry_name[NAME_MAX + 1]; +}; + +const char *OPENSSL_DIR_read(OPENSSL_DIR_CTX **ctx, const char *directory) { + if (ctx == NULL || directory == NULL) { + errno = EINVAL; + return 0; + } + + errno = 0; + if (*ctx == NULL) { + *ctx = malloc(sizeof(OPENSSL_DIR_CTX)); + if (*ctx == NULL) { + errno = ENOMEM; + return 0; + } + memset(*ctx, 0, sizeof(OPENSSL_DIR_CTX)); + + if (sizeof(TCHAR) != sizeof(char)) { + TCHAR *wdir = NULL; + /* len_0 denotes string length *with* trailing 0 */ + size_t index = 0, len_0 = strlen(directory) + 1; + + wdir = (TCHAR *)malloc(len_0 * sizeof(TCHAR)); + if (wdir == NULL) { + free(*ctx); + *ctx = NULL; + errno = ENOMEM; + return 0; + } + + if (!MultiByteToWideChar(CP_ACP, 0, directory, len_0, (WCHAR *)wdir, + len_0)) { + for (index = 0; index < len_0; index++) { + wdir[index] = (TCHAR)directory[index]; + } + } + + (*ctx)->handle = FindFirstFile(wdir, &(*ctx)->ctx); + + free(wdir); + } else { + (*ctx)->handle = FindFirstFile((TCHAR *)directory, &(*ctx)->ctx); + } + + if ((*ctx)->handle == INVALID_HANDLE_VALUE) { + free(*ctx); + *ctx = NULL; + errno = EINVAL; + return 0; + } + } else { + if (FindNextFile((*ctx)->handle, &(*ctx)->ctx) == FALSE) { + return 0; + } + } + + if (sizeof(TCHAR) != sizeof(char)) { + TCHAR *wdir = (*ctx)->ctx.cFileName; + size_t index, len_0 = 0; + + while (wdir[len_0] && len_0 < (sizeof((*ctx)->entry_name) - 1)) { + len_0++; + } + len_0++; + + if (!WideCharToMultiByte(CP_ACP, 0, (WCHAR *)wdir, len_0, + (*ctx)->entry_name, sizeof((*ctx)->entry_name), + NULL, 0)) { + for (index = 0; index < len_0; index++) { + (*ctx)->entry_name[index] = (char)wdir[index]; + } + } + } else { + strncpy((*ctx)->entry_name, (const char *)(*ctx)->ctx.cFileName, + sizeof((*ctx)->entry_name) - 1); + } + + (*ctx)->entry_name[sizeof((*ctx)->entry_name) - 1] = '\0'; + + return (*ctx)->entry_name; +} + +int OPENSSL_DIR_end(OPENSSL_DIR_CTX **ctx) { + if (ctx != NULL && *ctx != NULL) { + FindClose((*ctx)->handle); + free(*ctx); + *ctx = NULL; + return 1; + } + errno = EINVAL; + return 0; +} + +#endif /* OPENSSL_WINDOWS */ diff --git a/TMessagesProj/jni/boringssl/crypto/dsa/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/dsa/CMakeLists.txt new file mode 100644 index 00000000..6ef623a7 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/dsa/CMakeLists.txt @@ -0,0 +1,11 @@ +include_directories(. .. ../../include) + +add_library( + dsa + + OBJECT + + dsa.c + dsa_impl.c + dsa_asn1.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/dsa/dsa.c b/TMessagesProj/jni/boringssl/crypto/dsa/dsa.c new file mode 100644 index 00000000..3ff29c4f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/dsa/dsa.c @@ -0,0 +1,348 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * The DSS routines are based on patches supplied by + * Steven Schoch . */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" +#include "../internal.h" + + +extern const DSA_METHOD DSA_default_method; + +static CRYPTO_EX_DATA_CLASS g_ex_data_class = CRYPTO_EX_DATA_CLASS_INIT; + +DSA *DSA_new(void) { return DSA_new_method(NULL); } + +DSA *DSA_new_method(const ENGINE *engine) { + DSA *dsa = (DSA *)OPENSSL_malloc(sizeof(DSA)); + if (dsa == NULL) { + OPENSSL_PUT_ERROR(DSA, ERR_R_MALLOC_FAILURE); + return NULL; + } + + memset(dsa, 0, sizeof(DSA)); + + if (engine) { + dsa->meth = ENGINE_get_DSA_method(engine); + } + + if (dsa->meth == NULL) { + dsa->meth = (DSA_METHOD*) &DSA_default_method; + } + METHOD_ref(dsa->meth); + + dsa->write_params = 1; + dsa->references = 1; + + CRYPTO_MUTEX_init(&dsa->method_mont_p_lock); + + if (!CRYPTO_new_ex_data(&g_ex_data_class, dsa, &dsa->ex_data)) { + METHOD_unref(dsa->meth); + OPENSSL_free(dsa); + return NULL; + } + + if (dsa->meth->init && !dsa->meth->init(dsa)) { + CRYPTO_free_ex_data(&g_ex_data_class, dsa, &dsa->ex_data); + METHOD_unref(dsa->meth); + OPENSSL_free(dsa); + return NULL; + } + + return dsa; +} + +void DSA_free(DSA *dsa) { + if (dsa == NULL) { + return; + } + + if (!CRYPTO_refcount_dec_and_test_zero(&dsa->references)) { + return; + } + + if (dsa->meth->finish) { + dsa->meth->finish(dsa); + } + METHOD_unref(dsa->meth); + + CRYPTO_free_ex_data(&g_ex_data_class, dsa, &dsa->ex_data); + + BN_clear_free(dsa->p); + BN_clear_free(dsa->q); + BN_clear_free(dsa->g); + BN_clear_free(dsa->pub_key); + BN_clear_free(dsa->priv_key); + BN_clear_free(dsa->kinv); + BN_clear_free(dsa->r); + CRYPTO_MUTEX_cleanup(&dsa->method_mont_p_lock); + OPENSSL_free(dsa); +} + +int DSA_up_ref(DSA *dsa) { + CRYPTO_refcount_inc(&dsa->references); + return 1; +} + +int DSA_generate_parameters_ex(DSA *dsa, unsigned bits, const uint8_t *seed_in, + size_t seed_len, int *out_counter, + unsigned long *out_h, BN_GENCB *cb) { + if (dsa->meth->generate_parameters) { + return dsa->meth->generate_parameters(dsa, bits, seed_in, seed_len, + out_counter, out_h, cb); + } + return DSA_default_method.generate_parameters(dsa, bits, seed_in, seed_len, + out_counter, out_h, cb); +} + +int DSA_generate_key(DSA *dsa) { + if (dsa->meth->keygen) { + return dsa->meth->keygen(dsa); + } + return DSA_default_method.keygen(dsa); +} + +DSA_SIG *DSA_SIG_new(void) { + DSA_SIG *sig; + sig = OPENSSL_malloc(sizeof(DSA_SIG)); + if (!sig) { + return NULL; + } + sig->r = NULL; + sig->s = NULL; + return sig; +} + +void DSA_SIG_free(DSA_SIG *sig) { + if (!sig) { + return; + } + + BN_free(sig->r); + BN_free(sig->s); + OPENSSL_free(sig); +} + +DSA_SIG *DSA_do_sign(const uint8_t *digest, size_t digest_len, DSA *dsa) { + if (dsa->meth->sign) { + return dsa->meth->sign(digest, digest_len, dsa); + } + return DSA_default_method.sign(digest, digest_len, dsa); +} + +int DSA_do_verify(const uint8_t *digest, size_t digest_len, DSA_SIG *sig, + const DSA *dsa) { + int valid; + if (!DSA_do_check_signature(&valid, digest, digest_len, sig, dsa)) { + return -1; + } + return valid; +} + +int DSA_do_check_signature(int *out_valid, const uint8_t *digest, + size_t digest_len, DSA_SIG *sig, const DSA *dsa) { + if (dsa->meth->verify) { + return dsa->meth->verify(out_valid, digest, digest_len, sig, dsa); + } + + return DSA_default_method.verify(out_valid, digest, digest_len, sig, dsa); +} + +int DSA_sign(int type, const uint8_t *digest, size_t digest_len, + uint8_t *out_sig, unsigned int *out_siglen, DSA *dsa) { + DSA_SIG *s; + + s = DSA_do_sign(digest, digest_len, dsa); + if (s == NULL) { + *out_siglen = 0; + return 0; + } + + *out_siglen = i2d_DSA_SIG(s, &out_sig); + DSA_SIG_free(s); + return 1; +} + +int DSA_verify(int type, const uint8_t *digest, size_t digest_len, + const uint8_t *sig, size_t sig_len, const DSA *dsa) { + int valid; + if (!DSA_check_signature(&valid, digest, digest_len, sig, sig_len, dsa)) { + return -1; + } + return valid; +} + +int DSA_check_signature(int *out_valid, const uint8_t *digest, + size_t digest_len, const uint8_t *sig, size_t sig_len, + const DSA *dsa) { + DSA_SIG *s = NULL; + int ret = 0; + uint8_t *der = NULL; + + s = DSA_SIG_new(); + if (s == NULL) { + goto err; + } + + const uint8_t *sigp = sig; + if (d2i_DSA_SIG(&s, &sigp, sig_len) == NULL || sigp != sig + sig_len) { + goto err; + } + + /* Ensure that the signature uses DER and doesn't have trailing garbage. */ + int der_len = i2d_DSA_SIG(s, &der); + if (der_len < 0 || (size_t)der_len != sig_len || memcmp(sig, der, sig_len)) { + goto err; + } + + ret = DSA_do_check_signature(out_valid, digest, digest_len, s, dsa); + +err: + OPENSSL_free(der); + DSA_SIG_free(s); + return ret; +} + +int DSA_size(const DSA *dsa) { + int ret, i; + ASN1_INTEGER bs; + unsigned char buf[4]; /* 4 bytes looks really small. + However, i2d_ASN1_INTEGER() will not look + beyond the first byte, as long as the second + parameter is NULL. */ + + i = BN_num_bits(dsa->q); + bs.length = (i + 7) / 8; + bs.data = buf; + bs.type = V_ASN1_INTEGER; + /* If the top bit is set the asn1 encoding is 1 larger. */ + buf[0] = 0xff; + + i = i2d_ASN1_INTEGER(&bs, NULL); + i += i; /* r and s */ + ret = ASN1_object_size(1, i, V_ASN1_SEQUENCE); + return ret; +} + +int DSA_sign_setup(const DSA *dsa, BN_CTX *ctx, BIGNUM **out_kinv, + BIGNUM **out_r) { + if (dsa->meth->sign_setup) { + return dsa->meth->sign_setup(dsa, ctx, out_kinv, out_r, NULL, 0); + } + + return DSA_default_method.sign_setup(dsa, ctx, out_kinv, out_r, NULL, 0); +} + +int DSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func) { + int index; + if (!CRYPTO_get_ex_new_index(&g_ex_data_class, &index, argl, argp, new_func, + dup_func, free_func)) { + return -1; + } + return index; +} + +int DSA_set_ex_data(DSA *d, int idx, void *arg) { + return CRYPTO_set_ex_data(&d->ex_data, idx, arg); +} + +void *DSA_get_ex_data(const DSA *d, int idx) { + return CRYPTO_get_ex_data(&d->ex_data, idx); +} + +DH *DSA_dup_DH(const DSA *r) { + DH *ret = NULL; + + if (r == NULL) { + goto err; + } + ret = DH_new(); + if (ret == NULL) { + goto err; + } + if (r->q != NULL) { + ret->priv_length = BN_num_bits(r->q); + if ((ret->q = BN_dup(r->q)) == NULL) { + goto err; + } + } + if ((r->p != NULL && (ret->p = BN_dup(r->p)) == NULL) || + (r->g != NULL && (ret->g = BN_dup(r->g)) == NULL) || + (r->pub_key != NULL && (ret->pub_key = BN_dup(r->pub_key)) == NULL) || + (r->priv_key != NULL && (ret->priv_key = BN_dup(r->priv_key)) == NULL)) { + goto err; + } + + return ret; + +err: + DH_free(ret); + return NULL; +} diff --git a/TMessagesProj/jni/boringssl/crypto/dsa/dsa_asn1.c b/TMessagesProj/jni/boringssl/crypto/dsa/dsa_asn1.c new file mode 100644 index 00000000..b6b3fa4d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/dsa/dsa_asn1.c @@ -0,0 +1,150 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2000. */ +/* ==================================================================== + * Copyright (c) 2000-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include + +#include +#include +#include +#include + +#include "internal.h" + + +static int dsa_sig_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, + void *exarg) { + if (operation != ASN1_OP_NEW_PRE) { + return 1; + } + + DSA_SIG *sig; + sig = OPENSSL_malloc(sizeof(DSA_SIG)); + if (!sig) { + OPENSSL_PUT_ERROR(DSA, ERR_R_MALLOC_FAILURE); + return 0; + } + + memset(sig, 0, sizeof(DSA_SIG)); + *pval = (ASN1_VALUE *)sig; + return 2; +} + +ASN1_SEQUENCE_cb(DSA_SIG, dsa_sig_cb) = { + ASN1_SIMPLE(DSA_SIG, r, CBIGNUM), + ASN1_SIMPLE(DSA_SIG, s, CBIGNUM)} ASN1_SEQUENCE_END_cb(DSA_SIG, DSA_SIG); + +IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DSA_SIG, DSA_SIG, DSA_SIG); + + +static int dsa_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, + void *exarg) { + switch (operation) { + case ASN1_OP_NEW_PRE: + *pval = (ASN1_VALUE *)DSA_new(); + if (*pval) { + return 2; + } + return 0; + + case ASN1_OP_FREE_PRE: + DSA_free((DSA *)*pval); + *pval = NULL; + return 2; + + default: + return 1; + } +} + +ASN1_SEQUENCE_cb(DSAPrivateKey, dsa_cb) = { + ASN1_SIMPLE(DSA, version, LONG), + ASN1_SIMPLE(DSA, p, BIGNUM), + ASN1_SIMPLE(DSA, q, BIGNUM), + ASN1_SIMPLE(DSA, g, BIGNUM), + ASN1_SIMPLE(DSA, pub_key, BIGNUM), + ASN1_SIMPLE(DSA, priv_key, BIGNUM)} ASN1_SEQUENCE_END_cb(DSA, + DSAPrivateKey); + +IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DSA, DSAPrivateKey, DSAPrivateKey); + +ASN1_SEQUENCE_cb(DSAparams, dsa_cb) = { + ASN1_SIMPLE(DSA, p, BIGNUM), ASN1_SIMPLE(DSA, q, BIGNUM), + ASN1_SIMPLE(DSA, g, BIGNUM), } ASN1_SEQUENCE_END_cb(DSA, DSAparams); + +IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DSA, DSAparams, DSAparams); + + +/* DSA public key is a bit trickier... its effectively a CHOICE type decided by + * a field called write_params which can either write out just the public key + * as an INTEGER or the parameters and public key in a SEQUENCE. */ + +ASN1_SEQUENCE(dsa_pub_internal) = { + ASN1_SIMPLE(DSA, pub_key, BIGNUM), + ASN1_SIMPLE(DSA, p, BIGNUM), + ASN1_SIMPLE(DSA, q, BIGNUM), + ASN1_SIMPLE(DSA, g, BIGNUM) +} ASN1_SEQUENCE_END_name(DSA, dsa_pub_internal); + +ASN1_CHOICE_cb(DSAPublicKey, dsa_cb) = { + ASN1_SIMPLE(DSA, pub_key, BIGNUM), + ASN1_EX_COMBINE(0, 0, dsa_pub_internal) +} ASN1_CHOICE_END_cb(DSA, DSAPublicKey, write_params); + +IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DSA, DSAPublicKey, DSAPublicKey); + +DSA *DSAparams_dup(const DSA *dsa) { + return ASN1_item_dup(ASN1_ITEM_rptr(DSAparams), (DSA*) dsa); +} diff --git a/TMessagesProj/jni/boringssl/crypto/dsa/dsa_impl.c b/TMessagesProj/jni/boringssl/crypto/dsa/dsa_impl.c new file mode 100644 index 00000000..e4984b4f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/dsa/dsa_impl.c @@ -0,0 +1,750 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * The DSS routines are based on patches supplied by + * Steven Schoch . */ + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "internal.h" + +#define OPENSSL_DSA_MAX_MODULUS_BITS 10000 + +/* Primality test according to FIPS PUB 186[-1], Appendix 2.1: 50 rounds of + * Rabin-Miller */ +#define DSS_prime_checks 50 + +static int sign_setup(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **kinvp, + BIGNUM **rp, const uint8_t *digest, size_t digest_len) { + BN_CTX *ctx; + BIGNUM k, kq, *K, *kinv = NULL, *r = NULL; + int ret = 0; + + if (!dsa->p || !dsa->q || !dsa->g) { + OPENSSL_PUT_ERROR(DSA, DSA_R_MISSING_PARAMETERS); + return 0; + } + + BN_init(&k); + BN_init(&kq); + + ctx = ctx_in; + if (ctx == NULL) { + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + } + + r = BN_new(); + if (r == NULL) { + goto err; + } + + /* Get random k */ + do { + /* If possible, we'll include the private key and message digest in the k + * generation. The |digest| argument is only empty if |DSA_sign_setup| is + * being used. */ + int ok; + + if (digest_len > 0) { + ok = BN_generate_dsa_nonce(&k, dsa->q, dsa->priv_key, digest, digest_len, + ctx); + } else { + ok = BN_rand_range(&k, dsa->q); + } + if (!ok) { + goto err; + } + } while (BN_is_zero(&k)); + + BN_set_flags(&k, BN_FLG_CONSTTIME); + + if (BN_MONT_CTX_set_locked((BN_MONT_CTX **)&dsa->method_mont_p, + (CRYPTO_MUTEX *)&dsa->method_mont_p_lock, dsa->p, + ctx) == NULL) { + goto err; + } + + /* Compute r = (g^k mod p) mod q */ + if (!BN_copy(&kq, &k)) { + goto err; + } + + /* We do not want timing information to leak the length of k, + * so we compute g^k using an equivalent exponent of fixed length. + * + * (This is a kludge that we need because the BN_mod_exp_mont() + * does not let us specify the desired timing behaviour.) */ + + if (!BN_add(&kq, &kq, dsa->q)) { + goto err; + } + if (BN_num_bits(&kq) <= BN_num_bits(dsa->q) && !BN_add(&kq, &kq, dsa->q)) { + goto err; + } + + K = &kq; + + if (!BN_mod_exp_mont(r, dsa->g, K, dsa->p, ctx, dsa->method_mont_p)) { + goto err; + } + if (!BN_mod(r, r, dsa->q, ctx)) { + goto err; + } + + /* Compute part of 's = inv(k) (m + xr) mod q' */ + kinv = BN_mod_inverse(NULL, &k, dsa->q, ctx); + if (kinv == NULL) { + goto err; + } + + BN_clear_free(*kinvp); + *kinvp = kinv; + kinv = NULL; + BN_clear_free(*rp); + *rp = r; + ret = 1; + +err: + if (!ret) { + OPENSSL_PUT_ERROR(DSA, ERR_R_BN_LIB); + if (r != NULL) { + BN_clear_free(r); + } + } + + if (ctx_in == NULL) { + BN_CTX_free(ctx); + } + BN_clear_free(&k); + BN_clear_free(&kq); + return ret; +} + +static DSA_SIG *sign(const uint8_t *digest, size_t digest_len, DSA *dsa) { + BIGNUM *kinv = NULL, *r = NULL, *s = NULL; + BIGNUM m; + BIGNUM xr; + BN_CTX *ctx = NULL; + int reason = ERR_R_BN_LIB; + DSA_SIG *ret = NULL; + int noredo = 0; + + BN_init(&m); + BN_init(&xr); + + if (!dsa->p || !dsa->q || !dsa->g) { + reason = DSA_R_MISSING_PARAMETERS; + goto err; + } + + s = BN_new(); + if (s == NULL) { + goto err; + } + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + +redo: + if (dsa->kinv == NULL || dsa->r == NULL) { + if (!DSA_sign_setup(dsa, ctx, &kinv, &r)) { + goto err; + } + } else { + kinv = dsa->kinv; + dsa->kinv = NULL; + r = dsa->r; + dsa->r = NULL; + noredo = 1; + } + + if (digest_len > BN_num_bytes(dsa->q)) { + /* if the digest length is greater than the size of q use the + * BN_num_bits(dsa->q) leftmost bits of the digest, see + * fips 186-3, 4.2 */ + digest_len = BN_num_bytes(dsa->q); + } + + if (BN_bin2bn(digest, digest_len, &m) == NULL) { + goto err; + } + + /* Compute s = inv(k) (m + xr) mod q */ + if (!BN_mod_mul(&xr, dsa->priv_key, r, dsa->q, ctx)) { + goto err; /* s = xr */ + } + if (!BN_add(s, &xr, &m)) { + goto err; /* s = m + xr */ + } + if (BN_cmp(s, dsa->q) > 0) { + if (!BN_sub(s, s, dsa->q)) { + goto err; + } + } + if (!BN_mod_mul(s, s, kinv, dsa->q, ctx)) { + goto err; + } + + ret = DSA_SIG_new(); + if (ret == NULL) { + goto err; + } + /* Redo if r or s is zero as required by FIPS 186-3: this is + * very unlikely. */ + if (BN_is_zero(r) || BN_is_zero(s)) { + if (noredo) { + reason = DSA_R_NEED_NEW_SETUP_VALUES; + goto err; + } + goto redo; + } + ret->r = r; + ret->s = s; + +err: + if (!ret) { + OPENSSL_PUT_ERROR(DSA, reason); + BN_free(r); + BN_free(s); + } + BN_CTX_free(ctx); + BN_clear_free(&m); + BN_clear_free(&xr); + BN_clear_free(kinv); + + return ret; +} + +static int verify(int *out_valid, const uint8_t *dgst, size_t digest_len, + DSA_SIG *sig, const DSA *dsa) { + BN_CTX *ctx; + BIGNUM u1, u2, t1; + BN_MONT_CTX *mont = NULL; + int ret = 0; + unsigned i; + + *out_valid = 0; + + if (!dsa->p || !dsa->q || !dsa->g) { + OPENSSL_PUT_ERROR(DSA, DSA_R_MISSING_PARAMETERS); + return 0; + } + + i = BN_num_bits(dsa->q); + /* fips 186-3 allows only different sizes for q */ + if (i != 160 && i != 224 && i != 256) { + OPENSSL_PUT_ERROR(DSA, DSA_R_BAD_Q_VALUE); + return 0; + } + + if (BN_num_bits(dsa->p) > OPENSSL_DSA_MAX_MODULUS_BITS) { + OPENSSL_PUT_ERROR(DSA, DSA_R_MODULUS_TOO_LARGE); + return 0; + } + + BN_init(&u1); + BN_init(&u2); + BN_init(&t1); + + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + + if (BN_is_zero(sig->r) || BN_is_negative(sig->r) || + BN_ucmp(sig->r, dsa->q) >= 0) { + ret = 1; + goto err; + } + if (BN_is_zero(sig->s) || BN_is_negative(sig->s) || + BN_ucmp(sig->s, dsa->q) >= 0) { + ret = 1; + goto err; + } + + /* Calculate W = inv(S) mod Q + * save W in u2 */ + if (BN_mod_inverse(&u2, sig->s, dsa->q, ctx) == NULL) { + goto err; + } + + /* save M in u1 */ + if (digest_len > (i >> 3)) { + /* if the digest length is greater than the size of q use the + * BN_num_bits(dsa->q) leftmost bits of the digest, see + * fips 186-3, 4.2 */ + digest_len = (i >> 3); + } + + if (BN_bin2bn(dgst, digest_len, &u1) == NULL) { + goto err; + } + + /* u1 = M * w mod q */ + if (!BN_mod_mul(&u1, &u1, &u2, dsa->q, ctx)) { + goto err; + } + + /* u2 = r * w mod q */ + if (!BN_mod_mul(&u2, sig->r, &u2, dsa->q, ctx)) { + goto err; + } + + mont = BN_MONT_CTX_set_locked((BN_MONT_CTX **)&dsa->method_mont_p, + (CRYPTO_MUTEX *)&dsa->method_mont_p_lock, + dsa->p, ctx); + if (!mont) { + goto err; + } + + if (!BN_mod_exp2_mont(&t1, dsa->g, &u1, dsa->pub_key, &u2, dsa->p, ctx, + mont)) { + goto err; + } + + /* BN_copy(&u1,&t1); */ + /* let u1 = u1 mod q */ + if (!BN_mod(&u1, &t1, dsa->q, ctx)) { + goto err; + } + + /* V is now in u1. If the signature is correct, it will be + * equal to R. */ + *out_valid = BN_ucmp(&u1, sig->r) == 0; + ret = 1; + +err: + if (ret != 1) { + OPENSSL_PUT_ERROR(DSA, ERR_R_BN_LIB); + } + BN_CTX_free(ctx); + BN_free(&u1); + BN_free(&u2); + BN_free(&t1); + + return ret; +} + +static int keygen(DSA *dsa) { + int ok = 0; + BN_CTX *ctx = NULL; + BIGNUM *pub_key = NULL, *priv_key = NULL; + BIGNUM prk; + + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + + priv_key = dsa->priv_key; + if (priv_key == NULL) { + priv_key = BN_new(); + if (priv_key == NULL) { + goto err; + } + } + + do { + if (!BN_rand_range(priv_key, dsa->q)) { + goto err; + } + } while (BN_is_zero(priv_key)); + + pub_key = dsa->pub_key; + if (pub_key == NULL) { + pub_key = BN_new(); + if (pub_key == NULL) { + goto err; + } + } + + BN_init(&prk); + BN_with_flags(&prk, priv_key, BN_FLG_CONSTTIME); + + if (!BN_mod_exp(pub_key, dsa->g, &prk, dsa->p, ctx)) { + goto err; + } + + dsa->priv_key = priv_key; + dsa->pub_key = pub_key; + ok = 1; + +err: + if (dsa->pub_key == NULL) { + BN_free(pub_key); + } + if (dsa->priv_key == NULL) { + BN_free(priv_key); + } + BN_CTX_free(ctx); + + return ok; +} + +static int paramgen(DSA *ret, unsigned bits, const uint8_t *seed_in, + size_t seed_len, int *counter_ret, unsigned long *h_ret, + BN_GENCB *cb) { + int ok = 0; + unsigned char seed[SHA256_DIGEST_LENGTH]; + unsigned char md[SHA256_DIGEST_LENGTH]; + unsigned char buf[SHA256_DIGEST_LENGTH], buf2[SHA256_DIGEST_LENGTH]; + BIGNUM *r0, *W, *X, *c, *test; + BIGNUM *g = NULL, *q = NULL, *p = NULL; + BN_MONT_CTX *mont = NULL; + int k, n = 0, m = 0; + unsigned i; + int counter = 0; + int r = 0; + BN_CTX *ctx = NULL; + unsigned int h = 2; + unsigned qbits, qsize; + const EVP_MD *evpmd; + + if (bits >= 2048) { + qbits = 256; + evpmd = EVP_sha256(); + } else { + qbits = 160; + evpmd = EVP_sha1(); + } + qsize = qbits / 8; + + if (qsize != SHA_DIGEST_LENGTH && qsize != SHA224_DIGEST_LENGTH && + qsize != SHA256_DIGEST_LENGTH) { + /* invalid q size */ + return 0; + } + + if (bits < 512) { + bits = 512; + } + + bits = (bits + 63) / 64 * 64; + + /* NB: seed_len == 0 is special case: copy generated seed to + * seed_in if it is not NULL. */ + if (seed_len && (seed_len < (size_t)qsize)) { + seed_in = NULL; /* seed buffer too small -- ignore */ + } + if (seed_len > (size_t)qsize) { + seed_len = qsize; /* App. 2.2 of FIPS PUB 186 allows larger SEED, + * but our internal buffers are restricted to 160 bits*/ + } + if (seed_in != NULL) { + memcpy(seed, seed_in, seed_len); + } + + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + BN_CTX_start(ctx); + + mont = BN_MONT_CTX_new(); + if (mont == NULL) { + goto err; + } + + r0 = BN_CTX_get(ctx); + g = BN_CTX_get(ctx); + W = BN_CTX_get(ctx); + q = BN_CTX_get(ctx); + X = BN_CTX_get(ctx); + c = BN_CTX_get(ctx); + p = BN_CTX_get(ctx); + test = BN_CTX_get(ctx); + + if (test == NULL || !BN_lshift(test, BN_value_one(), bits - 1)) { + goto err; + } + + for (;;) { + /* Find q. */ + for (;;) { + int seed_is_random; + + /* step 1 */ + if (!BN_GENCB_call(cb, 0, m++)) { + goto err; + } + + if (!seed_len) { + if (!RAND_bytes(seed, qsize)) { + goto err; + } + seed_is_random = 1; + } else { + seed_is_random = 0; + seed_len = 0; /* use random seed if 'seed_in' turns out to be bad*/ + } + memcpy(buf, seed, qsize); + memcpy(buf2, seed, qsize); + /* precompute "SEED + 1" for step 7: */ + for (i = qsize - 1; i < qsize; i--) { + buf[i]++; + if (buf[i] != 0) { + break; + } + } + + /* step 2 */ + if (!EVP_Digest(seed, qsize, md, NULL, evpmd, NULL) || + !EVP_Digest(buf, qsize, buf2, NULL, evpmd, NULL)) { + goto err; + } + for (i = 0; i < qsize; i++) { + md[i] ^= buf2[i]; + } + + /* step 3 */ + md[0] |= 0x80; + md[qsize - 1] |= 0x01; + if (!BN_bin2bn(md, qsize, q)) { + goto err; + } + + /* step 4 */ + r = BN_is_prime_fasttest_ex(q, DSS_prime_checks, ctx, seed_is_random, cb); + if (r > 0) { + break; + } + if (r != 0) { + goto err; + } + + /* do a callback call */ + /* step 5 */ + } + + if (!BN_GENCB_call(cb, 2, 0) || !BN_GENCB_call(cb, 3, 0)) { + goto err; + } + + /* step 6 */ + counter = 0; + /* "offset = 2" */ + + n = (bits - 1) / 160; + + for (;;) { + if ((counter != 0) && !BN_GENCB_call(cb, 0, counter)) { + goto err; + } + + /* step 7 */ + BN_zero(W); + /* now 'buf' contains "SEED + offset - 1" */ + for (k = 0; k <= n; k++) { + /* obtain "SEED + offset + k" by incrementing: */ + for (i = qsize - 1; i < qsize; i--) { + buf[i]++; + if (buf[i] != 0) { + break; + } + } + + if (!EVP_Digest(buf, qsize, md, NULL, evpmd, NULL)) { + goto err; + } + + /* step 8 */ + if (!BN_bin2bn(md, qsize, r0) || + !BN_lshift(r0, r0, (qsize << 3) * k) || + !BN_add(W, W, r0)) { + goto err; + } + } + + /* more of step 8 */ + if (!BN_mask_bits(W, bits - 1) || + !BN_copy(X, W) || + !BN_add(X, X, test)) { + goto err; + } + + /* step 9 */ + if (!BN_lshift1(r0, q) || + !BN_mod(c, X, r0, ctx) || + !BN_sub(r0, c, BN_value_one()) || + !BN_sub(p, X, r0)) { + goto err; + } + + /* step 10 */ + if (BN_cmp(p, test) >= 0) { + /* step 11 */ + r = BN_is_prime_fasttest_ex(p, DSS_prime_checks, ctx, 1, cb); + if (r > 0) { + goto end; /* found it */ + } + if (r != 0) { + goto err; + } + } + + /* step 13 */ + counter++; + /* "offset = offset + n + 1" */ + + /* step 14 */ + if (counter >= 4096) { + break; + } + } + } +end: + if (!BN_GENCB_call(cb, 2, 1)) { + goto err; + } + + /* We now need to generate g */ + /* Set r0=(p-1)/q */ + if (!BN_sub(test, p, BN_value_one()) || + !BN_div(r0, NULL, test, q, ctx)) { + goto err; + } + + if (!BN_set_word(test, h) || + !BN_MONT_CTX_set(mont, p, ctx)) { + goto err; + } + + for (;;) { + /* g=test^r0%p */ + if (!BN_mod_exp_mont(g, test, r0, p, ctx, mont)) { + goto err; + } + if (!BN_is_one(g)) { + break; + } + if (!BN_add(test, test, BN_value_one())) { + goto err; + } + h++; + } + + if (!BN_GENCB_call(cb, 3, 1)) { + goto err; + } + + ok = 1; + +err: + if (ok) { + BN_free(ret->p); + BN_free(ret->q); + BN_free(ret->g); + ret->p = BN_dup(p); + ret->q = BN_dup(q); + ret->g = BN_dup(g); + if (ret->p == NULL || ret->q == NULL || ret->g == NULL) { + ok = 0; + goto err; + } + if (counter_ret != NULL) { + *counter_ret = counter; + } + if (h_ret != NULL) { + *h_ret = h; + } + } + + if (ctx) { + BN_CTX_end(ctx); + BN_CTX_free(ctx); + } + + BN_MONT_CTX_free(mont); + + return ok; +} + +static int finish(DSA *dsa) { + BN_MONT_CTX_free(dsa->method_mont_p); + dsa->method_mont_p = NULL; + return 1; +} + +const struct dsa_method DSA_default_method = { + { + 0 /* references */, + 1 /* is_static */, + }, + NULL /* app_data */, + + NULL /* init */, + finish /* finish */, + + sign, + sign_setup, + verify, + + paramgen, + keygen, +}; diff --git a/TMessagesProj/jni/boringssl/crypto/dsa/internal.h b/TMessagesProj/jni/boringssl/crypto/dsa/internal.h new file mode 100644 index 00000000..ef991585 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/dsa/internal.h @@ -0,0 +1,78 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * The DSS routines are based on patches supplied by + * Steven Schoch . */ + +#ifndef OPENSSL_HEADER_DSA_INTERNAL_H +#define OPENSSL_HEADER_DSA_INTERNAL_H + +#include + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_DSA_INTERNAL_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/ec/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/ec/CMakeLists.txt new file mode 100644 index 00000000..70c07f99 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ec/CMakeLists.txt @@ -0,0 +1,17 @@ +include_directories(. .. ../../include) + +add_library( + ec + + OBJECT + + ec.c + ec_asn1.c + ec_key.c + ec_montgomery.c + oct.c + p256-64.c + util-64.c + simple.c + wnaf.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/ec/ec.c b/TMessagesProj/jni/boringssl/crypto/ec/ec.c new file mode 100644 index 00000000..df0407c4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ec/ec.c @@ -0,0 +1,884 @@ +/* Originally written by Bodo Moeller for the OpenSSL project. + * ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * The elliptic curve binary polynomial software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems + * Laboratories. */ + +#include + +#include + +#include +#include +#include +#include + +#include "internal.h" + + +static const struct curve_data P224 = { + "NIST P-224", + 28, + 1, + {/* p */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, + /* a */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFE, + /* b */ + 0xB4, 0x05, 0x0A, 0x85, 0x0C, 0x04, 0xB3, 0xAB, 0xF5, 0x41, 0x32, 0x56, + 0x50, 0x44, 0xB0, 0xB7, 0xD7, 0xBF, 0xD8, 0xBA, 0x27, 0x0B, 0x39, 0x43, + 0x23, 0x55, 0xFF, 0xB4, + /* x */ + 0xB7, 0x0E, 0x0C, 0xBD, 0x6B, 0xB4, 0xBF, 0x7F, 0x32, 0x13, 0x90, 0xB9, + 0x4A, 0x03, 0xC1, 0xD3, 0x56, 0xC2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xD6, + 0x11, 0x5C, 0x1D, 0x21, + /* y */ + 0xbd, 0x37, 0x63, 0x88, 0xb5, 0xf7, 0x23, 0xfb, 0x4c, 0x22, 0xdf, 0xe6, + 0xcd, 0x43, 0x75, 0xa0, 0x5a, 0x07, 0x47, 0x64, 0x44, 0xd5, 0x81, 0x99, + 0x85, 0x00, 0x7e, 0x34, + /* order */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x16, 0xA2, 0xE0, 0xB8, 0xF0, 0x3E, 0x13, 0xDD, 0x29, 0x45, + 0x5C, 0x5C, 0x2A, 0x3D, + }}; + +static const struct curve_data P256 = { + "NIST P-256", + 32, + 1, + {/* p */ + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + /* a */ + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, + /* b */ + 0x5A, 0xC6, 0x35, 0xD8, 0xAA, 0x3A, 0x93, 0xE7, 0xB3, 0xEB, 0xBD, 0x55, + 0x76, 0x98, 0x86, 0xBC, 0x65, 0x1D, 0x06, 0xB0, 0xCC, 0x53, 0xB0, 0xF6, + 0x3B, 0xCE, 0x3C, 0x3E, 0x27, 0xD2, 0x60, 0x4B, + /* x */ + 0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47, 0xF8, 0xBC, 0xE6, 0xE5, + 0x63, 0xA4, 0x40, 0xF2, 0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, 0xA0, + 0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2, 0x96, + /* y */ + 0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, 0x8e, 0xe7, 0xeb, 0x4a, + 0x7c, 0x0f, 0x9e, 0x16, 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce, + 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5, + /* order */ + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84, + 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51}}; + +static const struct curve_data P384 = { + "NIST P-384", + 48, + 1, + {/* p */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + /* a */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFC, + /* b */ + 0xB3, 0x31, 0x2F, 0xA7, 0xE2, 0x3E, 0xE7, 0xE4, 0x98, 0x8E, 0x05, 0x6B, + 0xE3, 0xF8, 0x2D, 0x19, 0x18, 0x1D, 0x9C, 0x6E, 0xFE, 0x81, 0x41, 0x12, + 0x03, 0x14, 0x08, 0x8F, 0x50, 0x13, 0x87, 0x5A, 0xC6, 0x56, 0x39, 0x8D, + 0x8A, 0x2E, 0xD1, 0x9D, 0x2A, 0x85, 0xC8, 0xED, 0xD3, 0xEC, 0x2A, 0xEF, + /* x */ + 0xAA, 0x87, 0xCA, 0x22, 0xBE, 0x8B, 0x05, 0x37, 0x8E, 0xB1, 0xC7, 0x1E, + 0xF3, 0x20, 0xAD, 0x74, 0x6E, 0x1D, 0x3B, 0x62, 0x8B, 0xA7, 0x9B, 0x98, + 0x59, 0xF7, 0x41, 0xE0, 0x82, 0x54, 0x2A, 0x38, 0x55, 0x02, 0xF2, 0x5D, + 0xBF, 0x55, 0x29, 0x6C, 0x3A, 0x54, 0x5E, 0x38, 0x72, 0x76, 0x0A, 0xB7, + /* y */ + 0x36, 0x17, 0xde, 0x4a, 0x96, 0x26, 0x2c, 0x6f, 0x5d, 0x9e, 0x98, 0xbf, + 0x92, 0x92, 0xdc, 0x29, 0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a, 0x14, 0x7c, + 0xe9, 0xda, 0x31, 0x13, 0xb5, 0xf0, 0xb8, 0xc0, 0x0a, 0x60, 0xb1, 0xce, + 0x1d, 0x7e, 0x81, 0x9d, 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5f, + /* order */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC7, 0x63, 0x4D, 0x81, 0xF4, 0x37, 0x2D, 0xDF, 0x58, 0x1A, 0x0D, 0xB2, + 0x48, 0xB0, 0xA7, 0x7A, 0xEC, 0xEC, 0x19, 0x6A, 0xCC, 0xC5, 0x29, 0x73}}; + +static const struct curve_data P521 = { + "NIST P-521", + 66, + 1, + {/* p */ + 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + /* a */ + 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, + /* b */ + 0x00, 0x51, 0x95, 0x3E, 0xB9, 0x61, 0x8E, 0x1C, 0x9A, 0x1F, 0x92, 0x9A, + 0x21, 0xA0, 0xB6, 0x85, 0x40, 0xEE, 0xA2, 0xDA, 0x72, 0x5B, 0x99, 0xB3, + 0x15, 0xF3, 0xB8, 0xB4, 0x89, 0x91, 0x8E, 0xF1, 0x09, 0xE1, 0x56, 0x19, + 0x39, 0x51, 0xEC, 0x7E, 0x93, 0x7B, 0x16, 0x52, 0xC0, 0xBD, 0x3B, 0xB1, + 0xBF, 0x07, 0x35, 0x73, 0xDF, 0x88, 0x3D, 0x2C, 0x34, 0xF1, 0xEF, 0x45, + 0x1F, 0xD4, 0x6B, 0x50, 0x3F, 0x00, + /* x */ + 0x00, 0xC6, 0x85, 0x8E, 0x06, 0xB7, 0x04, 0x04, 0xE9, 0xCD, 0x9E, 0x3E, + 0xCB, 0x66, 0x23, 0x95, 0xB4, 0x42, 0x9C, 0x64, 0x81, 0x39, 0x05, 0x3F, + 0xB5, 0x21, 0xF8, 0x28, 0xAF, 0x60, 0x6B, 0x4D, 0x3D, 0xBA, 0xA1, 0x4B, + 0x5E, 0x77, 0xEF, 0xE7, 0x59, 0x28, 0xFE, 0x1D, 0xC1, 0x27, 0xA2, 0xFF, + 0xA8, 0xDE, 0x33, 0x48, 0xB3, 0xC1, 0x85, 0x6A, 0x42, 0x9B, 0xF9, 0x7E, + 0x7E, 0x31, 0xC2, 0xE5, 0xBD, 0x66, + /* y */ + 0x01, 0x18, 0x39, 0x29, 0x6a, 0x78, 0x9a, 0x3b, 0xc0, 0x04, 0x5c, 0x8a, + 0x5f, 0xb4, 0x2c, 0x7d, 0x1b, 0xd9, 0x98, 0xf5, 0x44, 0x49, 0x57, 0x9b, + 0x44, 0x68, 0x17, 0xaf, 0xbd, 0x17, 0x27, 0x3e, 0x66, 0x2c, 0x97, 0xee, + 0x72, 0x99, 0x5e, 0xf4, 0x26, 0x40, 0xc5, 0x50, 0xb9, 0x01, 0x3f, 0xad, + 0x07, 0x61, 0x35, 0x3c, 0x70, 0x86, 0xa2, 0x72, 0xc2, 0x40, 0x88, 0xbe, + 0x94, 0x76, 0x9f, 0xd1, 0x66, 0x50, + /* order */ + 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFA, 0x51, 0x86, + 0x87, 0x83, 0xBF, 0x2F, 0x96, 0x6B, 0x7F, 0xCC, 0x01, 0x48, 0xF7, 0x09, + 0xA5, 0xD0, 0x3B, 0xB5, 0xC9, 0xB8, 0x89, 0x9C, 0x47, 0xAE, 0xBB, 0x6F, + 0xB7, 0x1E, 0x91, 0x38, 0x64, 0x09}}; + +const struct built_in_curve OPENSSL_built_in_curves[] = { + {NID_secp224r1, &P224, 0}, + { + NID_X9_62_prime256v1, &P256, +#if defined(OPENSSL_64_BIT) && !defined(OPENSSL_WINDOWS) + EC_GFp_nistp256_method, +#else + 0, +#endif + }, + {NID_secp384r1, &P384, 0}, + {NID_secp521r1, &P521, 0}, + {NID_undef, 0, 0}, +}; + +EC_GROUP *ec_group_new(const EC_METHOD *meth) { + EC_GROUP *ret; + + if (meth == NULL) { + OPENSSL_PUT_ERROR(EC, EC_R_SLOT_FULL); + return NULL; + } + + if (meth->group_init == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return NULL; + } + + ret = OPENSSL_malloc(sizeof(EC_GROUP)); + if (ret == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + return NULL; + } + memset(ret, 0, sizeof(EC_GROUP)); + + ret->meth = meth; + BN_init(&ret->order); + BN_init(&ret->cofactor); + + if (!meth->group_init(ret)) { + OPENSSL_free(ret); + return NULL; + } + + return ret; +} + +EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a, + const BIGNUM *b, BN_CTX *ctx) { + const EC_METHOD *meth = EC_GFp_mont_method(); + EC_GROUP *ret; + + ret = ec_group_new(meth); + if (ret == NULL) { + return NULL; + } + + if (ret->meth->group_set_curve == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (!ret->meth->group_set_curve(ret, p, a, b, ctx)) { + EC_GROUP_free(ret); + return NULL; + } + return ret; +} + +int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator, + const BIGNUM *order, const BIGNUM *cofactor) { + if (group->curve_name != NID_undef) { + /* |EC_GROUP_set_generator| should only be used with |EC_GROUP|s returned + * by |EC_GROUP_new_curve_GFp|. */ + return 0; + } + + if (group->generator == NULL) { + group->generator = EC_POINT_new(group); + if (group->generator == NULL) { + return 0; + } + } + + if (!EC_POINT_copy(group->generator, generator)) { + return 0; + } + + if (order != NULL) { + if (!BN_copy(&group->order, order)) { + return 0; + } + } else { + BN_zero(&group->order); + } + + if (cofactor != NULL) { + if (!BN_copy(&group->cofactor, cofactor)) { + return 0; + } + } else { + BN_zero(&group->cofactor); + } + + return 1; +} + +static EC_GROUP *ec_group_new_from_data(const struct built_in_curve *curve) { + EC_GROUP *group = NULL; + EC_POINT *P = NULL; + BN_CTX *ctx = NULL; + BIGNUM *p = NULL, *a = NULL, *b = NULL, *x = NULL, *y = NULL; + int ok = 0; + unsigned param_len; + const EC_METHOD *meth; + const struct curve_data *data; + const uint8_t *params; + + if ((ctx = BN_CTX_new()) == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + goto err; + } + + data = curve->data; + param_len = data->param_len; + params = data->data; + + if (!(p = BN_bin2bn(params + 0 * param_len, param_len, NULL)) || + !(a = BN_bin2bn(params + 1 * param_len, param_len, NULL)) || + !(b = BN_bin2bn(params + 2 * param_len, param_len, NULL))) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + goto err; + } + + if (curve->method != 0) { + meth = curve->method(); + if (((group = ec_group_new(meth)) == NULL) || + (!(group->meth->group_set_curve(group, p, a, b, ctx)))) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + goto err; + } + } else { + if ((group = EC_GROUP_new_curve_GFp(p, a, b, ctx)) == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + goto err; + } + } + + if ((P = EC_POINT_new(group)) == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + goto err; + } + + if (!(x = BN_bin2bn(params + 3 * param_len, param_len, NULL)) || + !(y = BN_bin2bn(params + 4 * param_len, param_len, NULL))) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + goto err; + } + + if (!EC_POINT_set_affine_coordinates_GFp(group, P, x, y, ctx)) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + goto err; + } + if (!BN_bin2bn(params + 5 * param_len, param_len, &group->order) || + !BN_set_word(&group->cofactor, (BN_ULONG)data->cofactor)) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + goto err; + } + + group->generator = P; + P = NULL; + ok = 1; + +err: + if (!ok) { + EC_GROUP_free(group); + group = NULL; + } + EC_POINT_free(P); + BN_CTX_free(ctx); + BN_free(p); + BN_free(a); + BN_free(b); + BN_free(x); + BN_free(y); + return group; +} + +EC_GROUP *EC_GROUP_new_by_curve_name(int nid) { + unsigned i; + const struct built_in_curve *curve; + EC_GROUP *ret = NULL; + + for (i = 0; OPENSSL_built_in_curves[i].nid != NID_undef; i++) { + curve = &OPENSSL_built_in_curves[i]; + if (curve->nid == nid) { + ret = ec_group_new_from_data(curve); + break; + } + } + + if (ret == NULL) { + OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP); + return NULL; + } + + ret->curve_name = nid; + return ret; +} + +void EC_GROUP_free(EC_GROUP *group) { + if (!group) { + return; + } + + if (group->meth->group_finish != 0) { + group->meth->group_finish(group); + } + + ec_pre_comp_free(group->pre_comp); + + EC_POINT_free(group->generator); + BN_free(&group->order); + BN_free(&group->cofactor); + + OPENSSL_free(group); +} + +int ec_group_copy(EC_GROUP *dest, const EC_GROUP *src) { + if (dest->meth->group_copy == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (dest->meth != src->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + if (dest == src) { + return 1; + } + + ec_pre_comp_free(dest->pre_comp); + dest->pre_comp = ec_pre_comp_dup(src->pre_comp); + + if (src->generator != NULL) { + if (dest->generator == NULL) { + dest->generator = EC_POINT_new(dest); + if (dest->generator == NULL) { + return 0; + } + } + if (!EC_POINT_copy(dest->generator, src->generator)) { + return 0; + } + } else { + /* src->generator == NULL */ + if (dest->generator != NULL) { + EC_POINT_clear_free(dest->generator); + dest->generator = NULL; + } + } + + if (!BN_copy(&dest->order, &src->order) || + !BN_copy(&dest->cofactor, &src->cofactor)) { + return 0; + } + + dest->curve_name = src->curve_name; + + return dest->meth->group_copy(dest, src); +} + +EC_GROUP *EC_GROUP_dup(const EC_GROUP *a) { + EC_GROUP *t = NULL; + int ok = 0; + + if (a == NULL) { + return NULL; + } + + t = ec_group_new(a->meth); + if (t == NULL) { + return NULL; + } + if (!ec_group_copy(t, a)) { + goto err; + } + + ok = 1; + +err: + if (!ok) { + EC_GROUP_free(t); + return NULL; + } else { + return t; + } +} + +int EC_GROUP_cmp(const EC_GROUP *a, const EC_GROUP *b, BN_CTX *ignored) { + return a->curve_name == NID_undef || + b->curve_name == NID_undef || + a->curve_name != b->curve_name; +} + +const EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *group) { + return group->generator; +} + +int EC_GROUP_get_order(const EC_GROUP *group, BIGNUM *order, BN_CTX *ctx) { + if (!BN_copy(order, &group->order)) { + return 0; + } + + return !BN_is_zero(order); +} + +int EC_GROUP_get_cofactor(const EC_GROUP *group, BIGNUM *cofactor, + BN_CTX *ctx) { + if (!BN_copy(cofactor, &group->cofactor)) { + return 0; + } + + return !BN_is_zero(&group->cofactor); +} + +int EC_GROUP_get_curve_GFp(const EC_GROUP *group, BIGNUM *out_p, BIGNUM *out_a, + BIGNUM *out_b, BN_CTX *ctx) { + if (group->meth->group_get_curve == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + return group->meth->group_get_curve(group, out_p, out_a, out_b, ctx); +} + +int EC_GROUP_get_curve_name(const EC_GROUP *group) { return group->curve_name; } + +int EC_GROUP_get_degree(const EC_GROUP *group) { + if (group->meth->group_get_degree == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + return group->meth->group_get_degree(group); +} + +int EC_GROUP_precompute_mult(EC_GROUP *group, BN_CTX *ctx) { + if (group->meth->mul == 0) { + /* use default */ + return ec_wNAF_precompute_mult(group, ctx); + } + + if (group->meth->precompute_mult != 0) { + return group->meth->precompute_mult(group, ctx); + } + + return 1; /* nothing to do, so report success */ +} + +int EC_GROUP_have_precompute_mult(const EC_GROUP *group) { + if (group->meth->mul == 0) { + /* use default */ + return ec_wNAF_have_precompute_mult(group); + } + + if (group->meth->have_precompute_mult != 0) { + return group->meth->have_precompute_mult(group); + } + + return 0; /* cannot tell whether precomputation has been performed */ +} + +EC_POINT *EC_POINT_new(const EC_GROUP *group) { + EC_POINT *ret; + + if (group == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); + return NULL; + } + if (group->meth->point_init == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return NULL; + } + + ret = OPENSSL_malloc(sizeof *ret); + if (ret == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + return NULL; + } + + ret->meth = group->meth; + + if (!ret->meth->point_init(ret)) { + OPENSSL_free(ret); + return NULL; + } + + return ret; +} + +void EC_POINT_free(EC_POINT *point) { + if (!point) { + return; + } + + if (point->meth->point_finish != 0) { + point->meth->point_finish(point); + } + OPENSSL_free(point); +} + +void EC_POINT_clear_free(EC_POINT *point) { + if (!point) { + return; + } + + if (point->meth->point_clear_finish != 0) { + point->meth->point_clear_finish(point); + } else if (point->meth->point_finish != 0) { + point->meth->point_finish(point); + } + OPENSSL_cleanse(point, sizeof *point); + OPENSSL_free(point); +} + +int EC_POINT_copy(EC_POINT *dest, const EC_POINT *src) { + if (dest->meth->point_copy == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (dest->meth != src->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + if (dest == src) { + return 1; + } + return dest->meth->point_copy(dest, src); +} + +EC_POINT *EC_POINT_dup(const EC_POINT *a, const EC_GROUP *group) { + EC_POINT *t; + int r; + + if (a == NULL) { + return NULL; + } + + t = EC_POINT_new(group); + if (t == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + return NULL; + } + r = EC_POINT_copy(t, a); + if (!r) { + EC_POINT_free(t); + return NULL; + } else { + return t; + } +} + +int EC_POINT_set_to_infinity(const EC_GROUP *group, EC_POINT *point) { + if (group->meth->point_set_to_infinity == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != point->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->point_set_to_infinity(group, point); +} + +int EC_POINT_is_at_infinity(const EC_GROUP *group, const EC_POINT *point) { + if (group->meth->is_at_infinity == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != point->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->is_at_infinity(group, point); +} + +int EC_POINT_is_on_curve(const EC_GROUP *group, const EC_POINT *point, + BN_CTX *ctx) { + if (group->meth->is_on_curve == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != point->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->is_on_curve(group, point, ctx); +} + +int EC_POINT_cmp(const EC_GROUP *group, const EC_POINT *a, const EC_POINT *b, + BN_CTX *ctx) { + if (group->meth->point_cmp == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return -1; + } + if ((group->meth != a->meth) || (a->meth != b->meth)) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return -1; + } + return group->meth->point_cmp(group, a, b, ctx); +} + +int EC_POINT_make_affine(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx) { + if (group->meth->make_affine == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != point->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->make_affine(group, point, ctx); +} + +int EC_POINTs_make_affine(const EC_GROUP *group, size_t num, EC_POINT *points[], + BN_CTX *ctx) { + size_t i; + + if (group->meth->points_make_affine == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + for (i = 0; i < num; i++) { + if (group->meth != points[i]->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + } + return group->meth->points_make_affine(group, num, points, ctx); +} + +int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *group, + const EC_POINT *point, BIGNUM *x, + BIGNUM *y, BN_CTX *ctx) { + if (group->meth->point_get_affine_coordinates == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != point->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->point_get_affine_coordinates(group, point, x, y, ctx); +} + +int EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *group, EC_POINT *point, + const BIGNUM *x, const BIGNUM *y, + BN_CTX *ctx) { + if (group->meth->point_set_affine_coordinates == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != point->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->point_set_affine_coordinates(group, point, x, y, ctx); +} + +int EC_POINT_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, + const EC_POINT *b, BN_CTX *ctx) { + if (group->meth->add == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if ((group->meth != r->meth) || (r->meth != a->meth) || + (a->meth != b->meth)) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->add(group, r, a, b, ctx); +} + + +int EC_POINT_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, + BN_CTX *ctx) { + if (group->meth->dbl == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if ((group->meth != r->meth) || (r->meth != a->meth)) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->dbl(group, r, a, ctx); +} + + +int EC_POINT_invert(const EC_GROUP *group, EC_POINT *a, BN_CTX *ctx) { + if (group->meth->invert == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != a->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->invert(group, a, ctx); +} + +int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar, + const EC_POINT *point, const BIGNUM *p_scalar, BN_CTX *ctx) { + /* just a convenient interface to EC_POINTs_mul() */ + + const EC_POINT *points[1]; + const BIGNUM *scalars[1]; + + points[0] = point; + scalars[0] = p_scalar; + + return EC_POINTs_mul(group, r, g_scalar, (point != NULL && p_scalar != NULL), + points, scalars, ctx); +} + +int EC_POINTs_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, + size_t num, const EC_POINT *points[], const BIGNUM *scalars[], + BN_CTX *ctx) { + if (group->meth->mul == 0) { + /* use default. Warning, not constant-time. */ + return ec_wNAF_mul(group, r, scalar, num, points, scalars, ctx); + } + + return group->meth->mul(group, r, scalar, num, points, scalars, ctx); +} + +int ec_point_set_Jprojective_coordinates_GFp(const EC_GROUP *group, EC_POINT *point, + const BIGNUM *x, const BIGNUM *y, + const BIGNUM *z, BN_CTX *ctx) { + if (group->meth->point_set_Jprojective_coordinates_GFp == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != point->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->point_set_Jprojective_coordinates_GFp(group, point, x, y, + z, ctx); +} + +void EC_GROUP_set_asn1_flag(EC_GROUP *group, int flag) {} + +const EC_METHOD *EC_GROUP_method_of(const EC_GROUP *group) { + return NULL; +} + +int EC_METHOD_get_field_type(const EC_METHOD *meth) { + return NID_X9_62_prime_field; +} + +void EC_GROUP_set_point_conversion_form(EC_GROUP *group, + point_conversion_form_t form) { + if (form != POINT_CONVERSION_UNCOMPRESSED) { + abort(); + } +} diff --git a/TMessagesProj/jni/boringssl/crypto/ec/ec_asn1.c b/TMessagesProj/jni/boringssl/crypto/ec/ec_asn1.c new file mode 100644 index 00000000..31d89448 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ec/ec_asn1.c @@ -0,0 +1,577 @@ +/* Written by Nils Larsch for the OpenSSL project. */ +/* ==================================================================== + * Copyright (c) 2000-2003 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "internal.h" + + +typedef struct x9_62_fieldid_st { + ASN1_OBJECT *fieldType; + union { + char *ptr; + /* NID_X9_62_prime_field */ + ASN1_INTEGER *prime; + /* anything else */ + ASN1_TYPE *other; + } p; +} X9_62_FIELDID; + +ASN1_ADB_TEMPLATE(fieldID_def) = ASN1_SIMPLE(X9_62_FIELDID, p.other, ASN1_ANY); + +ASN1_ADB(X9_62_FIELDID) = { + ADB_ENTRY(NID_X9_62_prime_field, ASN1_SIMPLE(X9_62_FIELDID, p.prime, ASN1_INTEGER)), +} ASN1_ADB_END(X9_62_FIELDID, 0, fieldType, 0, &fieldID_def_tt, NULL); + +ASN1_SEQUENCE(X9_62_FIELDID) = { + ASN1_SIMPLE(X9_62_FIELDID, fieldType, ASN1_OBJECT), + ASN1_ADB_OBJECT(X9_62_FIELDID) +} ASN1_SEQUENCE_END(X9_62_FIELDID); + +typedef struct x9_62_curve_st { + ASN1_OCTET_STRING *a; + ASN1_OCTET_STRING *b; + ASN1_BIT_STRING *seed; +} X9_62_CURVE; + +ASN1_SEQUENCE(X9_62_CURVE) = { + ASN1_SIMPLE(X9_62_CURVE, a, ASN1_OCTET_STRING), + ASN1_SIMPLE(X9_62_CURVE, b, ASN1_OCTET_STRING), + ASN1_OPT(X9_62_CURVE, seed, ASN1_BIT_STRING) +} ASN1_SEQUENCE_END(X9_62_CURVE); + +typedef struct ec_parameters_st { + long version; + X9_62_FIELDID *fieldID; + X9_62_CURVE *curve; + ASN1_OCTET_STRING *base; + ASN1_INTEGER *order; + ASN1_INTEGER *cofactor; +} ECPARAMETERS; + +DECLARE_ASN1_ALLOC_FUNCTIONS(ECPARAMETERS); + +ASN1_SEQUENCE(ECPARAMETERS) = { + ASN1_SIMPLE(ECPARAMETERS, version, LONG), + ASN1_SIMPLE(ECPARAMETERS, fieldID, X9_62_FIELDID), + ASN1_SIMPLE(ECPARAMETERS, curve, X9_62_CURVE), + ASN1_SIMPLE(ECPARAMETERS, base, ASN1_OCTET_STRING), + ASN1_SIMPLE(ECPARAMETERS, order, ASN1_INTEGER), + ASN1_OPT(ECPARAMETERS, cofactor, ASN1_INTEGER) +} ASN1_SEQUENCE_END(ECPARAMETERS); + +IMPLEMENT_ASN1_ALLOC_FUNCTIONS(ECPARAMETERS); + +typedef struct ecpk_parameters_st { + int type; + union { + ASN1_OBJECT *named_curve; + ECPARAMETERS *parameters; + } value; +} ECPKPARAMETERS; + +/* SEC1 ECPrivateKey */ +typedef struct ec_privatekey_st { + long version; + ASN1_OCTET_STRING *privateKey; + ECPKPARAMETERS *parameters; + ASN1_BIT_STRING *publicKey; +} EC_PRIVATEKEY; + +DECLARE_ASN1_FUNCTIONS_const(ECPKPARAMETERS); +DECLARE_ASN1_ENCODE_FUNCTIONS_const(ECPKPARAMETERS, ECPKPARAMETERS); + +ASN1_CHOICE(ECPKPARAMETERS) = { + ASN1_SIMPLE(ECPKPARAMETERS, value.named_curve, ASN1_OBJECT), + ASN1_SIMPLE(ECPKPARAMETERS, value.parameters, ECPARAMETERS), +} ASN1_CHOICE_END(ECPKPARAMETERS); + +IMPLEMENT_ASN1_FUNCTIONS_const(ECPKPARAMETERS); + +DECLARE_ASN1_FUNCTIONS_const(EC_PRIVATEKEY); +DECLARE_ASN1_ENCODE_FUNCTIONS_const(EC_PRIVATEKEY, EC_PRIVATEKEY); + +ASN1_SEQUENCE(EC_PRIVATEKEY) = { + ASN1_SIMPLE(EC_PRIVATEKEY, version, LONG), + ASN1_SIMPLE(EC_PRIVATEKEY, privateKey, ASN1_OCTET_STRING), + ASN1_EXP_OPT(EC_PRIVATEKEY, parameters, ECPKPARAMETERS, 0), + ASN1_EXP_OPT(EC_PRIVATEKEY, publicKey, ASN1_BIT_STRING, 1), +} ASN1_SEQUENCE_END(EC_PRIVATEKEY); + +IMPLEMENT_ASN1_FUNCTIONS_const(EC_PRIVATEKEY); + + +ECPKPARAMETERS *ec_asn1_group2pkparameters(const EC_GROUP *group, + ECPKPARAMETERS *params) { + int ok = 0, nid; + ECPKPARAMETERS *ret = params; + + if (ret == NULL) { + ret = ECPKPARAMETERS_new(); + if (ret == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + return NULL; + } + } else { + ASN1_OBJECT_free(ret->value.named_curve); + } + + /* use the ASN.1 OID to describe the the elliptic curve parameters. */ + nid = EC_GROUP_get_curve_name(group); + if (nid) { + ret->type = 0; + ret->value.named_curve = (ASN1_OBJECT*) OBJ_nid2obj(nid); + ok = ret->value.named_curve != NULL; + } + + if (!ok) { + ECPKPARAMETERS_free(ret); + return NULL; + } + + return ret; +} + +EC_GROUP *ec_asn1_pkparameters2group(const ECPKPARAMETERS *params) { + EC_GROUP *ret = NULL; + int nid = NID_undef; + + if (params == NULL) { + OPENSSL_PUT_ERROR(EC, EC_R_MISSING_PARAMETERS); + return NULL; + } + + if (params->type == 0) { + nid = OBJ_obj2nid(params->value.named_curve); + } else if (params->type == 1) { + /* We don't support arbitary curves so we attempt to recognise it from the + * group order. */ + const ECPARAMETERS *ecparams = params->value.parameters; + unsigned i; + const struct built_in_curve *curve; + + for (i = 0; OPENSSL_built_in_curves[i].nid != NID_undef; i++) { + curve = &OPENSSL_built_in_curves[i]; + const unsigned param_len = curve->data->param_len; + if (ecparams->order->length == param_len && + memcmp(ecparams->order->data, &curve->data->data[param_len * 5], + param_len) == 0) { + nid = curve->nid; + break; + } + } + } + + if (nid == NID_undef) { + OPENSSL_PUT_ERROR(EC, EC_R_NON_NAMED_CURVE); + return NULL; + } + + ret = EC_GROUP_new_by_curve_name(nid); + if (ret == NULL) { + OPENSSL_PUT_ERROR(EC, EC_R_EC_GROUP_NEW_BY_NAME_FAILURE); + return NULL; + } + + return ret; +} + +static EC_GROUP *d2i_ECPKParameters(EC_GROUP **groupp, const uint8_t **inp, + long len) { + EC_GROUP *group = NULL; + ECPKPARAMETERS *params = NULL; + + params = d2i_ECPKPARAMETERS(NULL, inp, len); + if (params == NULL) { + OPENSSL_PUT_ERROR(EC, EC_R_D2I_ECPKPARAMETERS_FAILURE); + ECPKPARAMETERS_free(params); + return NULL; + } + + group = ec_asn1_pkparameters2group(params); + if (group == NULL) { + OPENSSL_PUT_ERROR(EC, EC_R_PKPARAMETERS2GROUP_FAILURE); + ECPKPARAMETERS_free(params); + return NULL; + } + + if (groupp) { + EC_GROUP_free(*groupp); + *groupp = group; + } + + ECPKPARAMETERS_free(params); + return group; +} + +static int i2d_ECPKParameters(const EC_GROUP *group, uint8_t **outp) { + int ret = 0; + ECPKPARAMETERS *tmp = ec_asn1_group2pkparameters(group, NULL); + if (tmp == NULL) { + OPENSSL_PUT_ERROR(EC, EC_R_GROUP2PKPARAMETERS_FAILURE); + return 0; + } + ret = i2d_ECPKPARAMETERS(tmp, outp); + if (ret == 0) { + OPENSSL_PUT_ERROR(EC, EC_R_I2D_ECPKPARAMETERS_FAILURE); + ECPKPARAMETERS_free(tmp); + return 0; + } + ECPKPARAMETERS_free(tmp); + return ret; +} + +EC_KEY *d2i_ECPrivateKey(EC_KEY **a, const uint8_t **in, long len) { + int ok = 0; + EC_KEY *ret = NULL; + EC_PRIVATEKEY *priv_key = NULL; + + priv_key = d2i_EC_PRIVATEKEY(NULL, in, len); + if (priv_key == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + return NULL; + } + + if (a == NULL || *a == NULL) { + ret = EC_KEY_new(); + if (ret == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + goto err; + } + } else { + ret = *a; + } + + if (priv_key->parameters) { + EC_GROUP_free(ret->group); + ret->group = ec_asn1_pkparameters2group(priv_key->parameters); + } + + if (ret->group == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + goto err; + } + + ret->version = priv_key->version; + + if (priv_key->privateKey) { + ret->priv_key = + BN_bin2bn(M_ASN1_STRING_data(priv_key->privateKey), + M_ASN1_STRING_length(priv_key->privateKey), ret->priv_key); + if (ret->priv_key == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + goto err; + } + } else { + OPENSSL_PUT_ERROR(EC, EC_R_MISSING_PRIVATE_KEY); + goto err; + } + + EC_POINT_free(ret->pub_key); + ret->pub_key = EC_POINT_new(ret->group); + if (ret->pub_key == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + goto err; + } + + if (priv_key->publicKey) { + const uint8_t *pub_oct; + int pub_oct_len; + + pub_oct = M_ASN1_STRING_data(priv_key->publicKey); + pub_oct_len = M_ASN1_STRING_length(priv_key->publicKey); + /* The first byte (the point conversion form) must be present. */ + if (pub_oct_len <= 0) { + OPENSSL_PUT_ERROR(EC, EC_R_BUFFER_TOO_SMALL); + goto err; + } + /* Save the point conversion form. */ + ret->conv_form = (point_conversion_form_t)(pub_oct[0] & ~0x01); + if (!EC_POINT_oct2point(ret->group, ret->pub_key, pub_oct, pub_oct_len, + NULL)) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + goto err; + } + } else { + if (!EC_POINT_mul(ret->group, ret->pub_key, ret->priv_key, NULL, NULL, + NULL)) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + goto err; + } + /* Remember the original private-key-only encoding. */ + ret->enc_flag |= EC_PKEY_NO_PUBKEY; + } + + if (a) { + *a = ret; + } + ok = 1; + +err: + if (!ok) { + if (a == NULL || *a != ret) { + EC_KEY_free(ret); + } + ret = NULL; + } + + EC_PRIVATEKEY_free(priv_key); + + return ret; +} + +int i2d_ECPrivateKey(const EC_KEY *key, uint8_t **outp) { + int ret = 0, ok = 0; + uint8_t *buffer = NULL; + size_t buf_len = 0, tmp_len; + EC_PRIVATEKEY *priv_key = NULL; + + if (key == NULL || key->group == NULL || key->priv_key == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); + goto err; + } + + priv_key = EC_PRIVATEKEY_new(); + if (priv_key == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + goto err; + } + + priv_key->version = key->version; + + buf_len = BN_num_bytes(&key->group->order); + buffer = OPENSSL_malloc(buf_len); + if (buffer == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!BN_bn2bin_padded(buffer, buf_len, key->priv_key)) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + goto err; + } + + if (!M_ASN1_OCTET_STRING_set(priv_key->privateKey, buffer, buf_len)) { + OPENSSL_PUT_ERROR(EC, ERR_R_ASN1_LIB); + goto err; + } + + /* TODO(fork): replace this flexibility with key sensible default? */ + if (!(key->enc_flag & EC_PKEY_NO_PARAMETERS)) { + if ((priv_key->parameters = ec_asn1_group2pkparameters( + key->group, priv_key->parameters)) == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + goto err; + } + } + + /* TODO(fork): replace this flexibility with key sensible default? */ + if (!(key->enc_flag & EC_PKEY_NO_PUBKEY) && key->pub_key != NULL) { + priv_key->publicKey = M_ASN1_BIT_STRING_new(); + if (priv_key->publicKey == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + goto err; + } + + tmp_len = EC_POINT_point2oct(key->group, key->pub_key, key->conv_form, NULL, + 0, NULL); + + if (tmp_len > buf_len) { + uint8_t *tmp_buffer = OPENSSL_realloc(buffer, tmp_len); + if (!tmp_buffer) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + goto err; + } + buffer = tmp_buffer; + buf_len = tmp_len; + } + + if (!EC_POINT_point2oct(key->group, key->pub_key, key->conv_form, buffer, + buf_len, NULL)) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + goto err; + } + + priv_key->publicKey->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07); + priv_key->publicKey->flags |= ASN1_STRING_FLAG_BITS_LEFT; + if (!M_ASN1_BIT_STRING_set(priv_key->publicKey, buffer, buf_len)) { + OPENSSL_PUT_ERROR(EC, ERR_R_ASN1_LIB); + goto err; + } + } + + ret = i2d_EC_PRIVATEKEY(priv_key, outp); + if (ret == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + goto err; + } + ok = 1; + +err: + OPENSSL_free(buffer); + EC_PRIVATEKEY_free(priv_key); + return (ok ? ret : 0); +} + +int i2d_ECParameters(const EC_KEY *key, uint8_t **outp) { + if (key == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + return i2d_ECPKParameters(key->group, outp); +} + +EC_KEY *d2i_ECParameters(EC_KEY **key, const uint8_t **inp, long len) { + EC_KEY *ret; + + if (inp == NULL || *inp == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); + return NULL; + } + + if (key == NULL || *key == NULL) { + ret = EC_KEY_new(); + if (ret == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + return NULL; + } + } else { + ret = *key; + } + + if (!d2i_ECPKParameters(&ret->group, inp, len)) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + if (key == NULL || *key == NULL) { + EC_KEY_free(ret); + } + return NULL; + } + + if (key) { + *key = ret; + } + return ret; +} + +EC_KEY *o2i_ECPublicKey(EC_KEY **keyp, const uint8_t **inp, long len) { + EC_KEY *ret = NULL; + + if (keyp == NULL || *keyp == NULL || (*keyp)->group == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + ret = *keyp; + if (ret->pub_key == NULL && + (ret->pub_key = EC_POINT_new(ret->group)) == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + return 0; + } + if (!EC_POINT_oct2point(ret->group, ret->pub_key, *inp, len, NULL)) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + return 0; + } + /* save the point conversion form */ + ret->conv_form = (point_conversion_form_t)(*inp[0] & ~0x01); + *inp += len; + return ret; +} + +int i2o_ECPublicKey(const EC_KEY *key, uint8_t **outp) { + size_t buf_len = 0; + int new_buffer = 0; + + if (key == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + buf_len = EC_POINT_point2oct(key->group, key->pub_key, key->conv_form, NULL, + 0, NULL); + + if (outp == NULL || buf_len == 0) { + /* out == NULL => just return the length of the octet string */ + return buf_len; + } + + if (*outp == NULL) { + *outp = OPENSSL_malloc(buf_len); + if (*outp == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + return 0; + } + new_buffer = 1; + } + if (!EC_POINT_point2oct(key->group, key->pub_key, key->conv_form, *outp, + buf_len, NULL)) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + if (new_buffer) { + OPENSSL_free(*outp); + *outp = NULL; + } + return 0; + } + + if (!new_buffer) { + *outp += buf_len; + } + return buf_len; +} diff --git a/TMessagesProj/jni/boringssl/crypto/ec/ec_key.c b/TMessagesProj/jni/boringssl/crypto/ec/ec_key.c new file mode 100644 index 00000000..0defa98a --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ec/ec_key.c @@ -0,0 +1,503 @@ +/* Originally written by Bodo Moeller for the OpenSSL project. + * ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * The elliptic curve binary polynomial software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems + * Laboratories. */ + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "internal.h" +#include "../internal.h" + + +static CRYPTO_EX_DATA_CLASS g_ex_data_class = CRYPTO_EX_DATA_CLASS_INIT; + +EC_KEY *EC_KEY_new(void) { return EC_KEY_new_method(NULL); } + +EC_KEY *EC_KEY_new_method(const ENGINE *engine) { + EC_KEY *ret = (EC_KEY *)OPENSSL_malloc(sizeof(EC_KEY)); + if (ret == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + return NULL; + } + + memset(ret, 0, sizeof(EC_KEY)); + + if (engine) { + ret->ecdsa_meth = ENGINE_get_ECDSA_method(engine); + } + if (ret->ecdsa_meth) { + METHOD_ref(ret->ecdsa_meth); + } + + ret->version = 1; + ret->conv_form = POINT_CONVERSION_UNCOMPRESSED; + ret->references = 1; + + if (!CRYPTO_new_ex_data(&g_ex_data_class, ret, &ret->ex_data)) { + goto err1; + } + + if (ret->ecdsa_meth && ret->ecdsa_meth->init && !ret->ecdsa_meth->init(ret)) { + goto err2; + } + + return ret; + +err2: + CRYPTO_free_ex_data(&g_ex_data_class, ret, &ret->ex_data); +err1: + if (ret->ecdsa_meth) { + METHOD_unref(ret->ecdsa_meth); + } + OPENSSL_free(ret); + return NULL; +} + +EC_KEY *EC_KEY_new_by_curve_name(int nid) { + EC_KEY *ret = EC_KEY_new(); + if (ret == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + return NULL; + } + ret->group = EC_GROUP_new_by_curve_name(nid); + if (ret->group == NULL) { + EC_KEY_free(ret); + return NULL; + } + return ret; +} + +void EC_KEY_free(EC_KEY *r) { + if (r == NULL) { + return; + } + + if (!CRYPTO_refcount_dec_and_test_zero(&r->references)) { + return; + } + + if (r->ecdsa_meth) { + if (r->ecdsa_meth->finish) { + r->ecdsa_meth->finish(r); + } + METHOD_unref(r->ecdsa_meth); + } + + EC_GROUP_free(r->group); + EC_POINT_free(r->pub_key); + BN_clear_free(r->priv_key); + + CRYPTO_free_ex_data(&g_ex_data_class, r, &r->ex_data); + + OPENSSL_cleanse((void *)r, sizeof(EC_KEY)); + OPENSSL_free(r); +} + +EC_KEY *EC_KEY_copy(EC_KEY *dest, const EC_KEY *src) { + if (dest == NULL || src == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); + return NULL; + } + /* Copy the parameters. */ + if (src->group) { + /* TODO(fork): duplicating the group seems wasteful. */ + EC_GROUP_free(dest->group); + dest->group = EC_GROUP_dup(src->group); + if (dest->group == NULL) { + return NULL; + } + } + + /* Copy the public key. */ + if (src->pub_key && src->group) { + EC_POINT_free(dest->pub_key); + dest->pub_key = EC_POINT_dup(src->pub_key, src->group); + if (dest->pub_key == NULL) { + return NULL; + } + } + + /* copy the private key */ + if (src->priv_key) { + if (dest->priv_key == NULL) { + dest->priv_key = BN_new(); + if (dest->priv_key == NULL) { + return NULL; + } + } + if (!BN_copy(dest->priv_key, src->priv_key)) { + return NULL; + } + } + /* copy method/extra data */ + if (src->ecdsa_meth) { + METHOD_unref(dest->ecdsa_meth); + dest->ecdsa_meth = src->ecdsa_meth; + METHOD_ref(dest->ecdsa_meth); + } + CRYPTO_free_ex_data(&g_ex_data_class, dest, &dest->ex_data); + if (!CRYPTO_dup_ex_data(&g_ex_data_class, &dest->ex_data, + &src->ex_data)) { + return NULL; + } + + /* copy the rest */ + dest->enc_flag = src->enc_flag; + dest->conv_form = src->conv_form; + dest->version = src->version; + dest->flags = src->flags; + + return dest; +} + +EC_KEY *EC_KEY_dup(const EC_KEY *ec_key) { + EC_KEY *ret = EC_KEY_new(); + if (ret == NULL) { + return NULL; + } + if (EC_KEY_copy(ret, ec_key) == NULL) { + EC_KEY_free(ret); + return NULL; + } + return ret; +} + +int EC_KEY_up_ref(EC_KEY *r) { + CRYPTO_refcount_inc(&r->references); + return 1; +} + +int EC_KEY_is_opaque(const EC_KEY *key) { + return key->ecdsa_meth && (key->ecdsa_meth->flags & ECDSA_FLAG_OPAQUE); +} + +const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key) { return key->group; } + +int EC_KEY_set_group(EC_KEY *key, const EC_GROUP *group) { + EC_GROUP_free(key->group); + /* TODO(fork): duplicating the group seems wasteful but see + * |EC_KEY_set_conv_form|. */ + key->group = EC_GROUP_dup(group); + return (key->group == NULL) ? 0 : 1; +} + +const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *key) { + return key->priv_key; +} + +int EC_KEY_set_private_key(EC_KEY *key, const BIGNUM *priv_key) { + BN_clear_free(key->priv_key); + key->priv_key = BN_dup(priv_key); + return (key->priv_key == NULL) ? 0 : 1; +} + +const EC_POINT *EC_KEY_get0_public_key(const EC_KEY *key) { + return key->pub_key; +} + +int EC_KEY_set_public_key(EC_KEY *key, const EC_POINT *pub_key) { + EC_POINT_free(key->pub_key); + key->pub_key = EC_POINT_dup(pub_key, key->group); + return (key->pub_key == NULL) ? 0 : 1; +} + +unsigned int EC_KEY_get_enc_flags(const EC_KEY *key) { return key->enc_flag; } + +void EC_KEY_set_enc_flags(EC_KEY *key, unsigned int flags) { + key->enc_flag = flags; +} + +point_conversion_form_t EC_KEY_get_conv_form(const EC_KEY *key) { + return key->conv_form; +} + +void EC_KEY_set_conv_form(EC_KEY *key, point_conversion_form_t cform) { + key->conv_form = cform; +} + +int EC_KEY_precompute_mult(EC_KEY *key, BN_CTX *ctx) { + if (key->group == NULL) { + return 0; + } + return EC_GROUP_precompute_mult(key->group, ctx); +} + +int EC_KEY_check_key(const EC_KEY *eckey) { + int ok = 0; + BN_CTX *ctx = NULL; + const BIGNUM *order = NULL; + EC_POINT *point = NULL; + + if (!eckey || !eckey->group || !eckey->pub_key) { + OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + if (EC_POINT_is_at_infinity(eckey->group, eckey->pub_key)) { + OPENSSL_PUT_ERROR(EC, EC_R_POINT_AT_INFINITY); + goto err; + } + + ctx = BN_CTX_new(); + point = EC_POINT_new(eckey->group); + + if (ctx == NULL || + point == NULL) { + goto err; + } + + /* testing whether the pub_key is on the elliptic curve */ + if (!EC_POINT_is_on_curve(eckey->group, eckey->pub_key, ctx)) { + OPENSSL_PUT_ERROR(EC, EC_R_POINT_IS_NOT_ON_CURVE); + goto err; + } + /* testing whether pub_key * order is the point at infinity */ + /* TODO(fork): can this be skipped if the cofactor is one or if we're about + * to check the private key, below? */ + order = &eckey->group->order; + if (BN_is_zero(order)) { + OPENSSL_PUT_ERROR(EC, EC_R_INVALID_GROUP_ORDER); + goto err; + } + if (!EC_POINT_mul(eckey->group, point, NULL, eckey->pub_key, order, ctx)) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + goto err; + } + if (!EC_POINT_is_at_infinity(eckey->group, point)) { + OPENSSL_PUT_ERROR(EC, EC_R_WRONG_ORDER); + goto err; + } + /* in case the priv_key is present : + * check if generator * priv_key == pub_key + */ + if (eckey->priv_key) { + if (BN_cmp(eckey->priv_key, order) >= 0) { + OPENSSL_PUT_ERROR(EC, EC_R_WRONG_ORDER); + goto err; + } + if (!EC_POINT_mul(eckey->group, point, eckey->priv_key, NULL, NULL, ctx)) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + goto err; + } + if (EC_POINT_cmp(eckey->group, point, eckey->pub_key, ctx) != 0) { + OPENSSL_PUT_ERROR(EC, EC_R_INVALID_PRIVATE_KEY); + goto err; + } + } + ok = 1; + +err: + BN_CTX_free(ctx); + EC_POINT_free(point); + return ok; +} + +int EC_KEY_set_public_key_affine_coordinates(EC_KEY *key, BIGNUM *x, + BIGNUM *y) { + BN_CTX *ctx = NULL; + BIGNUM *tx, *ty; + EC_POINT *point = NULL; + int ok = 0; + + if (!key || !key->group || !x || !y) { + OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + ctx = BN_CTX_new(); + point = EC_POINT_new(key->group); + + if (ctx == NULL || + point == NULL) { + goto err; + } + + tx = BN_CTX_get(ctx); + ty = BN_CTX_get(ctx); + + if (!EC_POINT_set_affine_coordinates_GFp(key->group, point, x, y, ctx) || + !EC_POINT_get_affine_coordinates_GFp(key->group, point, tx, ty, ctx)) { + goto err; + } + + /* Check if retrieved coordinates match originals: if not values + * are out of range. */ + if (BN_cmp(x, tx) || BN_cmp(y, ty)) { + OPENSSL_PUT_ERROR(EC, EC_R_COORDINATES_OUT_OF_RANGE); + goto err; + } + + if (!EC_KEY_set_public_key(key, point)) { + goto err; + } + + if (EC_KEY_check_key(key) == 0) { + goto err; + } + + ok = 1; + +err: + BN_CTX_free(ctx); + EC_POINT_free(point); + return ok; +} + +int EC_KEY_generate_key(EC_KEY *eckey) { + int ok = 0; + BN_CTX *ctx = NULL; + BIGNUM *priv_key = NULL, *order = NULL; + EC_POINT *pub_key = NULL; + + if (!eckey || !eckey->group) { + OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + order = BN_new(); + ctx = BN_CTX_new(); + + if (order == NULL || + ctx == NULL) { + goto err; + } + + if (eckey->priv_key == NULL) { + priv_key = BN_new(); + if (priv_key == NULL) { + goto err; + } + } else { + priv_key = eckey->priv_key; + } + + if (!EC_GROUP_get_order(eckey->group, order, ctx)) { + goto err; + } + + do { + if (!BN_rand_range(priv_key, order)) { + goto err; + } + } while (BN_is_zero(priv_key)); + + if (eckey->pub_key == NULL) { + pub_key = EC_POINT_new(eckey->group); + if (pub_key == NULL) { + goto err; + } + } else { + pub_key = eckey->pub_key; + } + + if (!EC_POINT_mul(eckey->group, pub_key, priv_key, NULL, NULL, ctx)) { + goto err; + } + + eckey->priv_key = priv_key; + eckey->pub_key = pub_key; + + ok = 1; + +err: + BN_free(order); + if (eckey->pub_key == NULL) { + EC_POINT_free(pub_key); + } + if (eckey->priv_key == NULL) { + BN_free(priv_key); + } + BN_CTX_free(ctx); + return ok; +} + +int EC_KEY_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func) { + int index; + if (!CRYPTO_get_ex_new_index(&g_ex_data_class, &index, argl, argp, new_func, + dup_func, free_func)) { + return -1; + } + return index; +} + +int EC_KEY_set_ex_data(EC_KEY *d, int idx, void *arg) { + return CRYPTO_set_ex_data(&d->ex_data, idx, arg); +} + +void *EC_KEY_get_ex_data(const EC_KEY *d, int idx) { + return CRYPTO_get_ex_data(&d->ex_data, idx); +} + +void EC_KEY_set_asn1_flag(EC_KEY *key, int flag) {} diff --git a/TMessagesProj/jni/boringssl/crypto/ec/ec_montgomery.c b/TMessagesProj/jni/boringssl/crypto/ec/ec_montgomery.c new file mode 100644 index 00000000..b897000b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ec/ec_montgomery.c @@ -0,0 +1,283 @@ +/* Originally written by Bodo Moeller and Nils Larsch for the OpenSSL project. + * ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * The elliptic curve binary polynomial software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems + * Laboratories. */ + +#include + +#include +#include +#include + +#include "internal.h" + + +const EC_METHOD *EC_GFp_mont_method(void) { + static const EC_METHOD ret = {EC_FLAGS_DEFAULT_OCT, + ec_GFp_mont_group_init, + ec_GFp_mont_group_finish, + ec_GFp_mont_group_clear_finish, + ec_GFp_mont_group_copy, + ec_GFp_mont_group_set_curve, + ec_GFp_simple_group_get_curve, + ec_GFp_simple_group_get_degree, + ec_GFp_simple_group_check_discriminant, + ec_GFp_simple_point_init, + ec_GFp_simple_point_finish, + ec_GFp_simple_point_clear_finish, + ec_GFp_simple_point_copy, + ec_GFp_simple_point_set_to_infinity, + ec_GFp_simple_set_Jprojective_coordinates_GFp, + ec_GFp_simple_get_Jprojective_coordinates_GFp, + ec_GFp_simple_point_set_affine_coordinates, + ec_GFp_simple_point_get_affine_coordinates, + 0, + 0, + 0, + ec_GFp_simple_add, + ec_GFp_simple_dbl, + ec_GFp_simple_invert, + ec_GFp_simple_is_at_infinity, + ec_GFp_simple_is_on_curve, + ec_GFp_simple_cmp, + ec_GFp_simple_make_affine, + ec_GFp_simple_points_make_affine, + 0 /* mul */, + 0 /* precompute_mult */, + 0 /* have_precompute_mult */, + ec_GFp_mont_field_mul, + ec_GFp_mont_field_sqr, + 0 /* field_div */, + ec_GFp_mont_field_encode, + ec_GFp_mont_field_decode, + ec_GFp_mont_field_set_to_one}; + + return &ret; +} + +int ec_GFp_mont_group_init(EC_GROUP *group) { + int ok; + + ok = ec_GFp_simple_group_init(group); + group->mont = NULL; + group->one = NULL; + return ok; +} + +void ec_GFp_mont_group_finish(EC_GROUP *group) { + BN_MONT_CTX_free(group->mont); + group->mont = NULL; + BN_free(group->one); + group->one = NULL; + ec_GFp_simple_group_finish(group); +} + +void ec_GFp_mont_group_clear_finish(EC_GROUP *group) { + BN_MONT_CTX_free(group->mont); + group->mont = NULL; + BN_clear_free(group->one); + group->one = NULL; + ec_GFp_simple_group_clear_finish(group); +} + +int ec_GFp_mont_group_copy(EC_GROUP *dest, const EC_GROUP *src) { + BN_MONT_CTX_free(dest->mont); + dest->mont = NULL; + BN_clear_free(dest->one); + dest->one = NULL; + + if (!ec_GFp_simple_group_copy(dest, src)) { + return 0; + } + + if (src->mont != NULL) { + dest->mont = BN_MONT_CTX_new(); + if (dest->mont == NULL) { + return 0; + } + if (!BN_MONT_CTX_copy(dest->mont, src->mont)) { + goto err; + } + } + if (src->one != NULL) { + dest->one = BN_dup(src->one); + if (dest->one == NULL) { + goto err; + } + } + + return 1; + +err: + BN_MONT_CTX_free(dest->mont); + dest->mont = NULL; + return 0; +} + +int ec_GFp_mont_group_set_curve(EC_GROUP *group, const BIGNUM *p, + const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) { + BN_CTX *new_ctx = NULL; + BN_MONT_CTX *mont = NULL; + BIGNUM *one = NULL; + int ret = 0; + + BN_MONT_CTX_free(group->mont); + group->mont = NULL; + BN_free(group->one); + group->one = NULL; + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } + } + + mont = BN_MONT_CTX_new(); + if (mont == NULL) { + goto err; + } + if (!BN_MONT_CTX_set(mont, p, ctx)) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + goto err; + } + one = BN_new(); + if (one == NULL || !BN_to_montgomery(one, BN_value_one(), mont, ctx)) { + goto err; + } + + group->mont = mont; + mont = NULL; + group->one = one; + one = NULL; + + ret = ec_GFp_simple_group_set_curve(group, p, a, b, ctx); + + if (!ret) { + BN_MONT_CTX_free(group->mont); + group->mont = NULL; + BN_free(group->one); + group->one = NULL; + } + +err: + BN_CTX_free(new_ctx); + BN_MONT_CTX_free(mont); + BN_free(one); + return ret; +} + +int ec_GFp_mont_field_mul(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, + const BIGNUM *b, BN_CTX *ctx) { + if (group->mont == NULL) { + OPENSSL_PUT_ERROR(EC, EC_R_NOT_INITIALIZED); + return 0; + } + + return BN_mod_mul_montgomery(r, a, b, group->mont, ctx); +} + +int ec_GFp_mont_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, + BN_CTX *ctx) { + if (group->mont == NULL) { + OPENSSL_PUT_ERROR(EC, EC_R_NOT_INITIALIZED); + return 0; + } + + return BN_mod_mul_montgomery(r, a, a, group->mont, ctx); +} + +int ec_GFp_mont_field_encode(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, + BN_CTX *ctx) { + if (group->mont == NULL) { + OPENSSL_PUT_ERROR(EC, EC_R_NOT_INITIALIZED); + return 0; + } + + return BN_to_montgomery(r, a, group->mont, ctx); +} + +int ec_GFp_mont_field_decode(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, + BN_CTX *ctx) { + if (group->mont == NULL) { + OPENSSL_PUT_ERROR(EC, EC_R_NOT_INITIALIZED); + return 0; + } + + return BN_from_montgomery(r, a, group->mont, ctx); +} + +int ec_GFp_mont_field_set_to_one(const EC_GROUP *group, BIGNUM *r, + BN_CTX *ctx) { + if (group->one == NULL) { + OPENSSL_PUT_ERROR(EC, EC_R_NOT_INITIALIZED); + return 0; + } + + if (!BN_copy(r, group->one)) { + return 0; + } + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/ec/example_mul.c b/TMessagesProj/jni/boringssl/crypto/ec/example_mul.c new file mode 100644 index 00000000..ebb724fa --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ec/example_mul.c @@ -0,0 +1,133 @@ +/* Originally written by Bodo Moeller for the OpenSSL project. + * ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * The elliptic curve binary polynomial software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems + * Laboratories. */ + +#include + +#include +#include +#include +#include + + +int example_EC_POINT_mul(void) { + /* This example ensures that 10×∞ + G = G, in P-256. */ + EC_GROUP *group = NULL; + EC_POINT *p = NULL, *result = NULL; + BIGNUM *n = NULL; + int ret = 0; + const EC_POINT *generator; + + group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); + p = EC_POINT_new(group); + result = EC_POINT_new(group); + n = BN_new(); + + if (p == NULL || + result == NULL || + group == NULL || + n == NULL || + !EC_POINT_set_to_infinity(group, p) || + !BN_set_word(n, 10)) { + goto err; + } + + /* First check that 10×∞ = ∞. */ + if (!EC_POINT_mul(group, result, NULL, p, n, NULL) || + !EC_POINT_is_at_infinity(group, result)) { + goto err; + } + + generator = EC_GROUP_get0_generator(group); + + /* Now check that 10×∞ + G = G. */ + if (!EC_POINT_mul(group, result, BN_value_one(), p, n, NULL) || + EC_POINT_cmp(group, result, generator, NULL) != 0) { + goto err; + } + + ret = 1; + +err: + BN_free(n); + EC_POINT_free(result); + EC_POINT_free(p); + EC_GROUP_free(group); + + return ret; +} + +int main(void) { + CRYPTO_library_init(); + + if (!example_EC_POINT_mul()) { + fprintf(stderr, "failed\n"); + return 1; + } + + printf("PASS\n"); + return 0; +} diff --git a/TMessagesProj/jni/boringssl/crypto/ec/internal.h b/TMessagesProj/jni/boringssl/crypto/ec/internal.h new file mode 100644 index 00000000..71062c16 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ec/internal.h @@ -0,0 +1,372 @@ +/* Originally written by Bodo Moeller for the OpenSSL project. + * ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * The elliptic curve binary polynomial software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems + * Laboratories. */ + +#ifndef OPENSSL_HEADER_EC_INTERNAL_H +#define OPENSSL_HEADER_EC_INTERNAL_H + +#include + +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Use default functions for poin2oct, oct2point and compressed coordinates */ +#define EC_FLAGS_DEFAULT_OCT 0x1 + +struct ec_method_st { + /* Various method flags */ + int flags; + + /* used by EC_GROUP_new, EC_GROUP_free, EC_GROUP_clear_free, EC_GROUP_copy: */ + int (*group_init)(EC_GROUP *); + void (*group_finish)(EC_GROUP *); + void (*group_clear_finish)(EC_GROUP *); + int (*group_copy)(EC_GROUP *, const EC_GROUP *); + + /* used by EC_GROUP_set_curve_GFp, EC_GROUP_get_curve_GFp, */ + /* EC_GROUP_set_curve_GF2m, and EC_GROUP_get_curve_GF2m: */ + int (*group_set_curve)(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, + const BIGNUM *b, BN_CTX *); + int (*group_get_curve)(const EC_GROUP *, BIGNUM *p, BIGNUM *a, BIGNUM *b, + BN_CTX *); + + /* used by EC_GROUP_get_degree: */ + int (*group_get_degree)(const EC_GROUP *); + + /* used by EC_GROUP_check: */ + int (*group_check_discriminant)(const EC_GROUP *, BN_CTX *); + + /* used by EC_POINT_new, EC_POINT_free, EC_POINT_clear_free, EC_POINT_copy: */ + int (*point_init)(EC_POINT *); + void (*point_finish)(EC_POINT *); + void (*point_clear_finish)(EC_POINT *); + int (*point_copy)(EC_POINT *, const EC_POINT *); + + /* used by EC_POINT_set_to_infinity, + * EC_POINT_set_Jprojective_coordinates_GFp, + * EC_POINT_get_Jprojective_coordinates_GFp, + * EC_POINT_set_affine_coordinates_GFp, ..._GF2m, + * EC_POINT_get_affine_coordinates_GFp, ..._GF2m, + * EC_POINT_set_compressed_coordinates_GFp, ..._GF2m: + */ + int (*point_set_to_infinity)(const EC_GROUP *, EC_POINT *); + int (*point_set_Jprojective_coordinates_GFp)(const EC_GROUP *, EC_POINT *, + const BIGNUM *x, const BIGNUM *y, + const BIGNUM *z, BN_CTX *); + int (*point_get_Jprojective_coordinates_GFp)(const EC_GROUP *, + const EC_POINT *, BIGNUM *x, + BIGNUM *y, BIGNUM *z, BN_CTX *); + int (*point_set_affine_coordinates)(const EC_GROUP *, EC_POINT *, + const BIGNUM *x, const BIGNUM *y, + BN_CTX *); + int (*point_get_affine_coordinates)(const EC_GROUP *, const EC_POINT *, + BIGNUM *x, BIGNUM *y, BN_CTX *); + int (*point_set_compressed_coordinates)(const EC_GROUP *, EC_POINT *, + const BIGNUM *x, int y_bit, BN_CTX *); + + /* used by EC_POINT_point2oct, EC_POINT_oct2point: */ + size_t (*point2oct)(const EC_GROUP *, const EC_POINT *, + point_conversion_form_t form, unsigned char *buf, + size_t len, BN_CTX *); + int (*oct2point)(const EC_GROUP *, EC_POINT *, const unsigned char *buf, + size_t len, BN_CTX *); + + /* used by EC_POINT_add, EC_POINT_dbl, ECP_POINT_invert: */ + int (*add)(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, + const EC_POINT *b, BN_CTX *); + int (*dbl)(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, BN_CTX *); + int (*invert)(const EC_GROUP *, EC_POINT *, BN_CTX *); + + /* used by EC_POINT_is_at_infinity, EC_POINT_is_on_curve, EC_POINT_cmp: */ + int (*is_at_infinity)(const EC_GROUP *, const EC_POINT *); + int (*is_on_curve)(const EC_GROUP *, const EC_POINT *, BN_CTX *); + int (*point_cmp)(const EC_GROUP *, const EC_POINT *a, const EC_POINT *b, + BN_CTX *); + + /* used by EC_POINT_make_affine, EC_POINTs_make_affine: */ + int (*make_affine)(const EC_GROUP *, EC_POINT *, BN_CTX *); + int (*points_make_affine)(const EC_GROUP *, size_t num, EC_POINT * [], + BN_CTX *); + + /* used by EC_POINTs_mul, EC_POINT_mul, EC_POINT_precompute_mult, + * EC_POINT_have_precompute_mult + * (default implementations are used if the 'mul' pointer is 0): */ + int (*mul)(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, + size_t num, const EC_POINT *points[], const BIGNUM *scalars[], + BN_CTX *); + int (*precompute_mult)(EC_GROUP *group, BN_CTX *); + int (*have_precompute_mult)(const EC_GROUP *group); + + + /* internal functions */ + + /* 'field_mul', 'field_sqr', and 'field_div' can be used by 'add' and 'dbl' + * so that the same implementations of point operations can be used with + * different optimized implementations of expensive field operations: */ + int (*field_mul)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, + const BIGNUM *b, BN_CTX *); + int (*field_sqr)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *); + int (*field_div)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, + const BIGNUM *b, BN_CTX *); + + int (*field_encode)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, + BN_CTX *); /* e.g. to Montgomery */ + int (*field_decode)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, + BN_CTX *); /* e.g. from Montgomery */ + int (*field_set_to_one)(const EC_GROUP *, BIGNUM *r, BN_CTX *); +} /* EC_METHOD */; + +const EC_METHOD* EC_GFp_mont_method(void); + +struct ec_pre_comp_st; +void ec_pre_comp_free(struct ec_pre_comp_st *pre_comp); +void *ec_pre_comp_dup(struct ec_pre_comp_st *pre_comp); + +struct ec_group_st { + const EC_METHOD *meth; + + EC_POINT *generator; /* optional */ + BIGNUM order, cofactor; + + int curve_name; /* optional NID for named curve */ + + struct ec_pre_comp_st *pre_comp; + + /* The following members are handled by the method functions, + * even if they appear generic */ + + BIGNUM field; /* For curves over GF(p), this is the modulus. */ + + BIGNUM a, b; /* Curve coefficients. */ + + int a_is_minus3; /* enable optimized point arithmetics for special case */ + + BN_MONT_CTX *mont; /* Montgomery structure. */ + BIGNUM *one; /* The value one */ +} /* EC_GROUP */; + +struct ec_point_st { + const EC_METHOD *meth; + + /* All members except 'meth' are handled by the method functions, + * even if they appear generic */ + + BIGNUM X; + BIGNUM Y; + BIGNUM Z; /* Jacobian projective coordinates: + * (X, Y, Z) represents (X/Z^2, Y/Z^3) if Z != 0 */ + int Z_is_one; /* enable optimized point arithmetics for special case */ +} /* EC_POINT */; + +EC_GROUP *ec_group_new(const EC_METHOD *meth); +int ec_group_copy(EC_GROUP *dest, const EC_GROUP *src); + +int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, + size_t num, const EC_POINT *points[], const BIGNUM *scalars[], + BN_CTX *); +int ec_wNAF_precompute_mult(EC_GROUP *group, BN_CTX *); +int ec_wNAF_have_precompute_mult(const EC_GROUP *group); + +/* method functions in simple.c */ +int ec_GFp_simple_group_init(EC_GROUP *); +void ec_GFp_simple_group_finish(EC_GROUP *); +void ec_GFp_simple_group_clear_finish(EC_GROUP *); +int ec_GFp_simple_group_copy(EC_GROUP *, const EC_GROUP *); +int ec_GFp_simple_group_set_curve(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, + const BIGNUM *b, BN_CTX *); +int ec_GFp_simple_group_get_curve(const EC_GROUP *, BIGNUM *p, BIGNUM *a, + BIGNUM *b, BN_CTX *); +int ec_GFp_simple_group_get_degree(const EC_GROUP *); +int ec_GFp_simple_group_check_discriminant(const EC_GROUP *, BN_CTX *); +int ec_GFp_simple_point_init(EC_POINT *); +void ec_GFp_simple_point_finish(EC_POINT *); +void ec_GFp_simple_point_clear_finish(EC_POINT *); +int ec_GFp_simple_point_copy(EC_POINT *, const EC_POINT *); +int ec_GFp_simple_point_set_to_infinity(const EC_GROUP *, EC_POINT *); +int ec_GFp_simple_set_Jprojective_coordinates_GFp(const EC_GROUP *, EC_POINT *, + const BIGNUM *x, + const BIGNUM *y, + const BIGNUM *z, BN_CTX *); +int ec_GFp_simple_get_Jprojective_coordinates_GFp(const EC_GROUP *, + const EC_POINT *, BIGNUM *x, + BIGNUM *y, BIGNUM *z, + BN_CTX *); +int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *, EC_POINT *, + const BIGNUM *x, const BIGNUM *y, + BN_CTX *); +int ec_GFp_simple_point_get_affine_coordinates(const EC_GROUP *, + const EC_POINT *, BIGNUM *x, + BIGNUM *y, BN_CTX *); +int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *, EC_POINT *, + const BIGNUM *x, int y_bit, + BN_CTX *); +int ec_GFp_simple_add(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, + const EC_POINT *b, BN_CTX *); +int ec_GFp_simple_dbl(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, + BN_CTX *); +int ec_GFp_simple_invert(const EC_GROUP *, EC_POINT *, BN_CTX *); +int ec_GFp_simple_is_at_infinity(const EC_GROUP *, const EC_POINT *); +int ec_GFp_simple_is_on_curve(const EC_GROUP *, const EC_POINT *, BN_CTX *); +int ec_GFp_simple_cmp(const EC_GROUP *, const EC_POINT *a, const EC_POINT *b, + BN_CTX *); +int ec_GFp_simple_make_affine(const EC_GROUP *, EC_POINT *, BN_CTX *); +int ec_GFp_simple_points_make_affine(const EC_GROUP *, size_t num, + EC_POINT * [], BN_CTX *); +int ec_GFp_simple_field_mul(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, + const BIGNUM *b, BN_CTX *); +int ec_GFp_simple_field_sqr(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, + BN_CTX *); + +/* method functions in montgomery.c */ +int ec_GFp_mont_group_init(EC_GROUP *); +int ec_GFp_mont_group_set_curve(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, + const BIGNUM *b, BN_CTX *); +void ec_GFp_mont_group_finish(EC_GROUP *); +void ec_GFp_mont_group_clear_finish(EC_GROUP *); +int ec_GFp_mont_group_copy(EC_GROUP *, const EC_GROUP *); +int ec_GFp_mont_field_mul(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, + const BIGNUM *b, BN_CTX *); +int ec_GFp_mont_field_sqr(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, + BN_CTX *); +int ec_GFp_mont_field_encode(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, + BN_CTX *); +int ec_GFp_mont_field_decode(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, + BN_CTX *); +int ec_GFp_mont_field_set_to_one(const EC_GROUP *, BIGNUM *r, BN_CTX *); + +int ec_point_set_Jprojective_coordinates_GFp(const EC_GROUP *group, + EC_POINT *point, const BIGNUM *x, + const BIGNUM *y, const BIGNUM *z, + BN_CTX *ctx); + +void ec_GFp_nistp_points_make_affine_internal( + size_t num, void *point_array, size_t felem_size, void *tmp_felems, + void (*felem_one)(void *out), int (*felem_is_zero)(const void *in), + void (*felem_assign)(void *out, const void *in), + void (*felem_square)(void *out, const void *in), + void (*felem_mul)(void *out, const void *in1, const void *in2), + void (*felem_inv)(void *out, const void *in), + void (*felem_contract)(void *out, const void *in)); + +void ec_GFp_nistp_recode_scalar_bits(uint8_t *sign, uint8_t *digit, uint8_t in); + +const EC_METHOD *EC_GFp_nistp256_method(void); + +struct ec_key_st { + int version; + + EC_GROUP *group; + + EC_POINT *pub_key; + BIGNUM *priv_key; + + unsigned int enc_flag; + point_conversion_form_t conv_form; + + CRYPTO_refcount_t references; + int flags; + + ECDSA_METHOD *ecdsa_meth; + + CRYPTO_EX_DATA ex_data; +} /* EC_KEY */; + +/* curve_data contains data about a built-in elliptic curve. */ +struct curve_data { + /* comment is a human-readable string describing the curve. */ + const char *comment; + /* param_len is the number of bytes needed to store a field element. */ + uint8_t param_len; + /* cofactor is the cofactor of the group (i.e. the number of elements in the + * group divided by the size of the main subgroup. */ + uint8_t cofactor; /* promoted to BN_ULONG */ + /* data points to an array of 6*|param_len| bytes which hold the field + * elements of the following (in big-endian order): prime, a, b, generator x, + * generator y, order. */ + const uint8_t data[]; +}; + +struct built_in_curve { + int nid; + const struct curve_data *data; + const EC_METHOD *(*method)(void); +}; + +/* OPENSSL_built_in_curves is terminated with an entry where |nid| is + * |NID_undef|. */ +extern const struct built_in_curve OPENSSL_built_in_curves[]; + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_EC_INTERNAL_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/ec/oct.c b/TMessagesProj/jni/boringssl/crypto/ec/oct.c new file mode 100644 index 00000000..cb50e172 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ec/oct.c @@ -0,0 +1,470 @@ +/* Originally written by Bodo Moeller for the OpenSSL project. + * ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * The elliptic curve binary polynomial software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems + * Laboratories. */ + +#include + +#include +#include + +#include "internal.h" + + +static size_t ec_GFp_simple_point2oct(const EC_GROUP *group, + const EC_POINT *point, + point_conversion_form_t form, + uint8_t *buf, size_t len, BN_CTX *ctx) { + size_t ret; + BN_CTX *new_ctx = NULL; + int used_ctx = 0; + BIGNUM *x, *y; + size_t field_len, i; + + if ((form != POINT_CONVERSION_COMPRESSED) && + (form != POINT_CONVERSION_UNCOMPRESSED)) { + OPENSSL_PUT_ERROR(EC, EC_R_INVALID_FORM); + goto err; + } + + if (EC_POINT_is_at_infinity(group, point)) { + /* encodes to a single 0 octet */ + if (buf != NULL) { + if (len < 1) { + OPENSSL_PUT_ERROR(EC, EC_R_BUFFER_TOO_SMALL); + return 0; + } + buf[0] = 0; + } + return 1; + } + + + /* ret := required output buffer length */ + field_len = BN_num_bytes(&group->field); + ret = + (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2 * field_len; + + /* if 'buf' is NULL, just return required length */ + if (buf != NULL) { + if (len < ret) { + OPENSSL_PUT_ERROR(EC, EC_R_BUFFER_TOO_SMALL); + goto err; + } + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } + } + + BN_CTX_start(ctx); + used_ctx = 1; + x = BN_CTX_get(ctx); + y = BN_CTX_get(ctx); + if (y == NULL) { + goto err; + } + + if (!EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx)) { + goto err; + } + + if ((form == POINT_CONVERSION_COMPRESSED) && + BN_is_odd(y)) { + buf[0] = form + 1; + } else { + buf[0] = form; + } + i = 1; + + if (!BN_bn2bin_padded(buf + i, field_len, x)) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + i += field_len; + + if (form == POINT_CONVERSION_UNCOMPRESSED) { + if (!BN_bn2bin_padded(buf + i, field_len, y)) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + i += field_len; + } + + if (i != ret) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + } + + if (used_ctx) { + BN_CTX_end(ctx); + } + BN_CTX_free(new_ctx); + return ret; + +err: + if (used_ctx) { + BN_CTX_end(ctx); + } + BN_CTX_free(new_ctx); + return 0; +} + + +static int ec_GFp_simple_oct2point(const EC_GROUP *group, EC_POINT *point, + const uint8_t *buf, size_t len, + BN_CTX *ctx) { + point_conversion_form_t form; + int y_bit; + BN_CTX *new_ctx = NULL; + BIGNUM *x, *y; + size_t field_len, enc_len; + int ret = 0; + + if (len == 0) { + OPENSSL_PUT_ERROR(EC, EC_R_BUFFER_TOO_SMALL); + return 0; + } + form = buf[0]; + y_bit = form & 1; + form = form & ~1U; + if ((form != 0) && (form != POINT_CONVERSION_COMPRESSED) && + (form != POINT_CONVERSION_UNCOMPRESSED)) { + OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING); + return 0; + } + if ((form == 0 || form == POINT_CONVERSION_UNCOMPRESSED) && y_bit) { + OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING); + return 0; + } + + if (form == 0) { + if (len != 1) { + OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING); + return 0; + } + + return EC_POINT_set_to_infinity(group, point); + } + + field_len = BN_num_bytes(&group->field); + enc_len = + (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2 * field_len; + + if (len != enc_len) { + OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING); + return 0; + } + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } + } + + BN_CTX_start(ctx); + x = BN_CTX_get(ctx); + y = BN_CTX_get(ctx); + if (x == NULL || y == NULL) { + goto err; + } + + if (!BN_bin2bn(buf + 1, field_len, x)) { + goto err; + } + if (BN_ucmp(x, &group->field) >= 0) { + OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING); + goto err; + } + + if (form == POINT_CONVERSION_COMPRESSED) { + if (!EC_POINT_set_compressed_coordinates_GFp(group, point, x, y_bit, ctx)) { + goto err; + } + } else { + if (!BN_bin2bn(buf + 1 + field_len, field_len, y)) { + goto err; + } + if (BN_ucmp(y, &group->field) >= 0) { + OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING); + goto err; + } + + if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) { + goto err; + } + } + + /* test required by X9.62 */ + if (!EC_POINT_is_on_curve(group, point, ctx)) { + OPENSSL_PUT_ERROR(EC, EC_R_POINT_IS_NOT_ON_CURVE); + goto err; + } + + ret = 1; + +err: + BN_CTX_end(ctx); + BN_CTX_free(new_ctx); + return ret; +} + +int EC_POINT_oct2point(const EC_GROUP *group, EC_POINT *point, + const uint8_t *buf, size_t len, BN_CTX *ctx) { + if (group->meth->oct2point == 0 && + !(group->meth->flags & EC_FLAGS_DEFAULT_OCT)) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != point->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + if (group->meth->flags & EC_FLAGS_DEFAULT_OCT) { + return ec_GFp_simple_oct2point(group, point, buf, len, ctx); + } + + return group->meth->oct2point(group, point, buf, len, ctx); +} + +size_t EC_POINT_point2oct(const EC_GROUP *group, const EC_POINT *point, + point_conversion_form_t form, uint8_t *buf, + size_t len, BN_CTX *ctx) { + if (group->meth->point2oct == 0 && + !(group->meth->flags & EC_FLAGS_DEFAULT_OCT)) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != point->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + if (group->meth->flags & EC_FLAGS_DEFAULT_OCT) { + return ec_GFp_simple_point2oct(group, point, form, buf, len, ctx); + } + + return group->meth->point2oct(group, point, form, buf, len, ctx); +} + +int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group, + EC_POINT *point, const BIGNUM *x_, + int y_bit, BN_CTX *ctx) { + BN_CTX *new_ctx = NULL; + BIGNUM *tmp1, *tmp2, *x, *y; + int ret = 0; + + ERR_clear_error(); + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } + } + + y_bit = (y_bit != 0); + + BN_CTX_start(ctx); + tmp1 = BN_CTX_get(ctx); + tmp2 = BN_CTX_get(ctx); + x = BN_CTX_get(ctx); + y = BN_CTX_get(ctx); + if (y == NULL) { + goto err; + } + + /* Recover y. We have a Weierstrass equation + * y^2 = x^3 + a*x + b, + * so y is one of the square roots of x^3 + a*x + b. */ + + /* tmp1 := x^3 */ + if (!BN_nnmod(x, x_, &group->field, ctx)) { + goto err; + } + + if (group->meth->field_decode == 0) { + /* field_{sqr,mul} work on standard representation */ + if (!group->meth->field_sqr(group, tmp2, x_, ctx) || + !group->meth->field_mul(group, tmp1, tmp2, x_, ctx)) { + goto err; + } + } else { + if (!BN_mod_sqr(tmp2, x_, &group->field, ctx) || + !BN_mod_mul(tmp1, tmp2, x_, &group->field, ctx)) { + goto err; + } + } + + /* tmp1 := tmp1 + a*x */ + if (group->a_is_minus3) { + if (!BN_mod_lshift1_quick(tmp2, x, &group->field) || + !BN_mod_add_quick(tmp2, tmp2, x, &group->field) || + !BN_mod_sub_quick(tmp1, tmp1, tmp2, &group->field)) { + goto err; + } + } else { + if (group->meth->field_decode) { + if (!group->meth->field_decode(group, tmp2, &group->a, ctx) || + !BN_mod_mul(tmp2, tmp2, x, &group->field, ctx)) { + goto err; + } + } else { + /* field_mul works on standard representation */ + if (!group->meth->field_mul(group, tmp2, &group->a, x, ctx)) { + goto err; + } + } + + if (!BN_mod_add_quick(tmp1, tmp1, tmp2, &group->field)) { + goto err; + } + } + + /* tmp1 := tmp1 + b */ + if (group->meth->field_decode) { + if (!group->meth->field_decode(group, tmp2, &group->b, ctx) || + !BN_mod_add_quick(tmp1, tmp1, tmp2, &group->field)) { + goto err; + } + } else { + if (!BN_mod_add_quick(tmp1, tmp1, &group->b, &group->field)) { + goto err; + } + } + + if (!BN_mod_sqrt(y, tmp1, &group->field, ctx)) { + unsigned long err = ERR_peek_last_error(); + + if (ERR_GET_LIB(err) == ERR_LIB_BN && + ERR_GET_REASON(err) == BN_R_NOT_A_SQUARE) { + ERR_clear_error(); + OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COMPRESSED_POINT); + } else { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + } + goto err; + } + + if (y_bit != BN_is_odd(y)) { + if (BN_is_zero(y)) { + int kron; + + kron = BN_kronecker(x, &group->field, ctx); + if (kron == -2) { + goto err; + } + + if (kron == 1) { + OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COMPRESSION_BIT); + } else { + /* BN_mod_sqrt() should have cought this error (not a square) */ + OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COMPRESSED_POINT); + } + goto err; + } + if (!BN_usub(y, &group->field, y)) { + goto err; + } + } + if (y_bit != BN_is_odd(y)) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + + if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) { + goto err; + } + + ret = 1; + +err: + BN_CTX_end(ctx); + BN_CTX_free(new_ctx); + return ret; +} + +int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group, + EC_POINT *point, const BIGNUM *x, + int y_bit, BN_CTX *ctx) { + if (group->meth->point_set_compressed_coordinates == 0 && + !(group->meth->flags & EC_FLAGS_DEFAULT_OCT)) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != point->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + if (group->meth->flags & EC_FLAGS_DEFAULT_OCT) { + return ec_GFp_simple_set_compressed_coordinates(group, point, x, y_bit, + ctx); + } + return group->meth->point_set_compressed_coordinates(group, point, x, y_bit, + ctx); +} diff --git a/TMessagesProj/jni/boringssl/crypto/ec/p256-64.c b/TMessagesProj/jni/boringssl/crypto/ec/p256-64.c new file mode 100644 index 00000000..3946b298 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ec/p256-64.c @@ -0,0 +1,1931 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* A 64-bit implementation of the NIST P-256 elliptic curve point + * multiplication + * + * OpenSSL integration was taken from Emilia Kasper's work in ecp_nistp224.c. + * Otherwise based on Emilia's P224 work, which was inspired by my curve25519 + * work which got its smarts from Daniel J. Bernstein's work on the same. */ + +#include + +#if defined(OPENSSL_64_BIT) && !defined(OPENSSL_WINDOWS) + +#include +#include +#include +#include +#include + +#include + +#include "internal.h" + + +typedef uint8_t u8; +typedef uint64_t u64; +typedef int64_t s64; +typedef __uint128_t uint128_t; +typedef __int128_t int128_t; + +/* The underlying field. P256 operates over GF(2^256-2^224+2^192+2^96-1). We + * can serialise an element of this field into 32 bytes. We call this an + * felem_bytearray. */ +typedef u8 felem_bytearray[32]; + +/* These are the parameters of P256, taken from FIPS 186-3, page 86. These + * values are big-endian. */ +static const felem_bytearray nistp256_curve_params[5] = { + {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, /* p */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, /* a = -3 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfc}, /* b */ + {0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a, 0x93, 0xe7, 0xb3, 0xeb, 0xbd, 0x55, + 0x76, 0x98, 0x86, 0xbc, 0x65, 0x1d, 0x06, 0xb0, 0xcc, 0x53, 0xb0, 0xf6, + 0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2, 0x60, 0x4b}, + {0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, /* x */ + 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, + 0x2d, 0xeb, 0x33, 0xa0, 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96}, + {0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, /* y */ + 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16, 0x2b, 0xce, 0x33, 0x57, + 0x6b, 0x31, 0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5}}; + +/* The representation of field elements. + * ------------------------------------ + * + * We represent field elements with either four 128-bit values, eight 128-bit + * values, or four 64-bit values. The field element represented is: + * v[0]*2^0 + v[1]*2^64 + v[2]*2^128 + v[3]*2^192 (mod p) + * or: + * v[0]*2^0 + v[1]*2^64 + v[2]*2^128 + ... + v[8]*2^512 (mod p) + * + * 128-bit values are called 'limbs'. Since the limbs are spaced only 64 bits + * apart, but are 128-bits wide, the most significant bits of each limb overlap + * with the least significant bits of the next. + * + * A field element with four limbs is an 'felem'. One with eight limbs is a + * 'longfelem' + * + * A field element with four, 64-bit values is called a 'smallfelem'. Small + * values are used as intermediate values before multiplication. */ + +#define NLIMBS 4 + +typedef uint128_t limb; +typedef limb felem[NLIMBS]; +typedef limb longfelem[NLIMBS * 2]; +typedef u64 smallfelem[NLIMBS]; + +/* This is the value of the prime as four 64-bit words, little-endian. */ +static const u64 kPrime[4] = {0xfffffffffffffffful, 0xffffffff, 0, + 0xffffffff00000001ul}; +static const u64 bottom63bits = 0x7ffffffffffffffful; + +/* bin32_to_felem takes a little-endian byte array and converts it into felem + * form. This assumes that the CPU is little-endian. */ +static void bin32_to_felem(felem out, const u8 in[32]) { + out[0] = *((u64 *)&in[0]); + out[1] = *((u64 *)&in[8]); + out[2] = *((u64 *)&in[16]); + out[3] = *((u64 *)&in[24]); +} + +/* smallfelem_to_bin32 takes a smallfelem and serialises into a little endian, + * 32 byte array. This assumes that the CPU is little-endian. */ +static void smallfelem_to_bin32(u8 out[32], const smallfelem in) { + *((u64 *)&out[0]) = in[0]; + *((u64 *)&out[8]) = in[1]; + *((u64 *)&out[16]) = in[2]; + *((u64 *)&out[24]) = in[3]; +} + +/* To preserve endianness when using BN_bn2bin and BN_bin2bn. */ +static void flip_endian(u8 *out, const u8 *in, unsigned len) { + unsigned i; + for (i = 0; i < len; ++i) { + out[i] = in[len - 1 - i]; + } +} + +/* BN_to_felem converts an OpenSSL BIGNUM into an felem. */ +static int BN_to_felem(felem out, const BIGNUM *bn) { + if (BN_is_negative(bn)) { + OPENSSL_PUT_ERROR(EC, EC_R_BIGNUM_OUT_OF_RANGE); + return 0; + } + + felem_bytearray b_out; + /* BN_bn2bin eats leading zeroes */ + memset(b_out, 0, sizeof(b_out)); + unsigned num_bytes = BN_num_bytes(bn); + if (num_bytes > sizeof(b_out)) { + OPENSSL_PUT_ERROR(EC, EC_R_BIGNUM_OUT_OF_RANGE); + return 0; + } + + felem_bytearray b_in; + num_bytes = BN_bn2bin(bn, b_in); + flip_endian(b_out, b_in, num_bytes); + bin32_to_felem(out, b_out); + return 1; +} + +/* felem_to_BN converts an felem into an OpenSSL BIGNUM. */ +static BIGNUM *smallfelem_to_BN(BIGNUM *out, const smallfelem in) { + felem_bytearray b_in, b_out; + smallfelem_to_bin32(b_in, in); + flip_endian(b_out, b_in, sizeof(b_out)); + return BN_bin2bn(b_out, sizeof(b_out), out); +} + +/* Field operations. */ + +static void smallfelem_one(smallfelem out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; +} + +static void smallfelem_assign(smallfelem out, const smallfelem in) { + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = in[3]; +} + +static void felem_assign(felem out, const felem in) { + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = in[3]; +} + +/* felem_sum sets out = out + in. */ +static void felem_sum(felem out, const felem in) { + out[0] += in[0]; + out[1] += in[1]; + out[2] += in[2]; + out[3] += in[3]; +} + +/* felem_small_sum sets out = out + in. */ +static void felem_small_sum(felem out, const smallfelem in) { + out[0] += in[0]; + out[1] += in[1]; + out[2] += in[2]; + out[3] += in[3]; +} + +/* felem_scalar sets out = out * scalar */ +static void felem_scalar(felem out, const u64 scalar) { + out[0] *= scalar; + out[1] *= scalar; + out[2] *= scalar; + out[3] *= scalar; +} + +/* longfelem_scalar sets out = out * scalar */ +static void longfelem_scalar(longfelem out, const u64 scalar) { + out[0] *= scalar; + out[1] *= scalar; + out[2] *= scalar; + out[3] *= scalar; + out[4] *= scalar; + out[5] *= scalar; + out[6] *= scalar; + out[7] *= scalar; +} + +#define two105m41m9 (((limb)1) << 105) - (((limb)1) << 41) - (((limb)1) << 9) +#define two105 (((limb)1) << 105) +#define two105m41p9 (((limb)1) << 105) - (((limb)1) << 41) + (((limb)1) << 9) + +/* zero105 is 0 mod p */ +static const felem zero105 = {two105m41m9, two105, two105m41p9, two105m41p9}; + +/* smallfelem_neg sets |out| to |-small| + * On exit: + * out[i] < out[i] + 2^105 */ +static void smallfelem_neg(felem out, const smallfelem small) { + /* In order to prevent underflow, we subtract from 0 mod p. */ + out[0] = zero105[0] - small[0]; + out[1] = zero105[1] - small[1]; + out[2] = zero105[2] - small[2]; + out[3] = zero105[3] - small[3]; +} + +/* felem_diff subtracts |in| from |out| + * On entry: + * in[i] < 2^104 + * On exit: + * out[i] < out[i] + 2^105. */ +static void felem_diff(felem out, const felem in) { + /* In order to prevent underflow, we add 0 mod p before subtracting. */ + out[0] += zero105[0]; + out[1] += zero105[1]; + out[2] += zero105[2]; + out[3] += zero105[3]; + + out[0] -= in[0]; + out[1] -= in[1]; + out[2] -= in[2]; + out[3] -= in[3]; +} + +#define two107m43m11 (((limb)1) << 107) - (((limb)1) << 43) - (((limb)1) << 11) +#define two107 (((limb)1) << 107) +#define two107m43p11 (((limb)1) << 107) - (((limb)1) << 43) + (((limb)1) << 11) + +/* zero107 is 0 mod p */ +static const felem zero107 = {two107m43m11, two107, two107m43p11, two107m43p11}; + +/* An alternative felem_diff for larger inputs |in| + * felem_diff_zero107 subtracts |in| from |out| + * On entry: + * in[i] < 2^106 + * On exit: + * out[i] < out[i] + 2^107. */ +static void felem_diff_zero107(felem out, const felem in) { + /* In order to prevent underflow, we add 0 mod p before subtracting. */ + out[0] += zero107[0]; + out[1] += zero107[1]; + out[2] += zero107[2]; + out[3] += zero107[3]; + + out[0] -= in[0]; + out[1] -= in[1]; + out[2] -= in[2]; + out[3] -= in[3]; +} + +/* longfelem_diff subtracts |in| from |out| + * On entry: + * in[i] < 7*2^67 + * On exit: + * out[i] < out[i] + 2^70 + 2^40. */ +static void longfelem_diff(longfelem out, const longfelem in) { + static const limb two70m8p6 = + (((limb)1) << 70) - (((limb)1) << 8) + (((limb)1) << 6); + static const limb two70p40 = (((limb)1) << 70) + (((limb)1) << 40); + static const limb two70 = (((limb)1) << 70); + static const limb two70m40m38p6 = (((limb)1) << 70) - (((limb)1) << 40) - + (((limb)1) << 38) + (((limb)1) << 6); + static const limb two70m6 = (((limb)1) << 70) - (((limb)1) << 6); + + /* add 0 mod p to avoid underflow */ + out[0] += two70m8p6; + out[1] += two70p40; + out[2] += two70; + out[3] += two70m40m38p6; + out[4] += two70m6; + out[5] += two70m6; + out[6] += two70m6; + out[7] += two70m6; + + /* in[i] < 7*2^67 < 2^70 - 2^40 - 2^38 + 2^6 */ + out[0] -= in[0]; + out[1] -= in[1]; + out[2] -= in[2]; + out[3] -= in[3]; + out[4] -= in[4]; + out[5] -= in[5]; + out[6] -= in[6]; + out[7] -= in[7]; +} + +#define two64m0 (((limb)1) << 64) - 1 +#define two110p32m0 (((limb)1) << 110) + (((limb)1) << 32) - 1 +#define two64m46 (((limb)1) << 64) - (((limb)1) << 46) +#define two64m32 (((limb)1) << 64) - (((limb)1) << 32) + +/* zero110 is 0 mod p. */ +static const felem zero110 = {two64m0, two110p32m0, two64m46, two64m32}; + +/* felem_shrink converts an felem into a smallfelem. The result isn't quite + * minimal as the value may be greater than p. + * + * On entry: + * in[i] < 2^109 + * On exit: + * out[i] < 2^64. */ +static void felem_shrink(smallfelem out, const felem in) { + felem tmp; + u64 a, b, mask; + s64 high, low; + static const u64 kPrime3Test = 0x7fffffff00000001ul; /* 2^63 - 2^32 + 1 */ + + /* Carry 2->3 */ + tmp[3] = zero110[3] + in[3] + ((u64)(in[2] >> 64)); + /* tmp[3] < 2^110 */ + + tmp[2] = zero110[2] + (u64)in[2]; + tmp[0] = zero110[0] + in[0]; + tmp[1] = zero110[1] + in[1]; + /* tmp[0] < 2**110, tmp[1] < 2^111, tmp[2] < 2**65 */ + + /* We perform two partial reductions where we eliminate the high-word of + * tmp[3]. We don't update the other words till the end. */ + a = tmp[3] >> 64; /* a < 2^46 */ + tmp[3] = (u64)tmp[3]; + tmp[3] -= a; + tmp[3] += ((limb)a) << 32; + /* tmp[3] < 2^79 */ + + b = a; + a = tmp[3] >> 64; /* a < 2^15 */ + b += a; /* b < 2^46 + 2^15 < 2^47 */ + tmp[3] = (u64)tmp[3]; + tmp[3] -= a; + tmp[3] += ((limb)a) << 32; + /* tmp[3] < 2^64 + 2^47 */ + + /* This adjusts the other two words to complete the two partial + * reductions. */ + tmp[0] += b; + tmp[1] -= (((limb)b) << 32); + + /* In order to make space in tmp[3] for the carry from 2 -> 3, we + * conditionally subtract kPrime if tmp[3] is large enough. */ + high = tmp[3] >> 64; + /* As tmp[3] < 2^65, high is either 1 or 0 */ + high <<= 63; + high >>= 63; + /* high is: + * all ones if the high word of tmp[3] is 1 + * all zeros if the high word of tmp[3] if 0 */ + low = tmp[3]; + mask = low >> 63; + /* mask is: + * all ones if the MSB of low is 1 + * all zeros if the MSB of low if 0 */ + low &= bottom63bits; + low -= kPrime3Test; + /* if low was greater than kPrime3Test then the MSB is zero */ + low = ~low; + low >>= 63; + /* low is: + * all ones if low was > kPrime3Test + * all zeros if low was <= kPrime3Test */ + mask = (mask & low) | high; + tmp[0] -= mask & kPrime[0]; + tmp[1] -= mask & kPrime[1]; + /* kPrime[2] is zero, so omitted */ + tmp[3] -= mask & kPrime[3]; + /* tmp[3] < 2**64 - 2**32 + 1 */ + + tmp[1] += ((u64)(tmp[0] >> 64)); + tmp[0] = (u64)tmp[0]; + tmp[2] += ((u64)(tmp[1] >> 64)); + tmp[1] = (u64)tmp[1]; + tmp[3] += ((u64)(tmp[2] >> 64)); + tmp[2] = (u64)tmp[2]; + /* tmp[i] < 2^64 */ + + out[0] = tmp[0]; + out[1] = tmp[1]; + out[2] = tmp[2]; + out[3] = tmp[3]; +} + +/* smallfelem_expand converts a smallfelem to an felem */ +static void smallfelem_expand(felem out, const smallfelem in) { + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = in[3]; +} + +/* smallfelem_square sets |out| = |small|^2 + * On entry: + * small[i] < 2^64 + * On exit: + * out[i] < 7 * 2^64 < 2^67 */ +static void smallfelem_square(longfelem out, const smallfelem small) { + limb a; + u64 high, low; + + a = ((uint128_t)small[0]) * small[0]; + low = a; + high = a >> 64; + out[0] = low; + out[1] = high; + + a = ((uint128_t)small[0]) * small[1]; + low = a; + high = a >> 64; + out[1] += low; + out[1] += low; + out[2] = high; + + a = ((uint128_t)small[0]) * small[2]; + low = a; + high = a >> 64; + out[2] += low; + out[2] *= 2; + out[3] = high; + + a = ((uint128_t)small[0]) * small[3]; + low = a; + high = a >> 64; + out[3] += low; + out[4] = high; + + a = ((uint128_t)small[1]) * small[2]; + low = a; + high = a >> 64; + out[3] += low; + out[3] *= 2; + out[4] += high; + + a = ((uint128_t)small[1]) * small[1]; + low = a; + high = a >> 64; + out[2] += low; + out[3] += high; + + a = ((uint128_t)small[1]) * small[3]; + low = a; + high = a >> 64; + out[4] += low; + out[4] *= 2; + out[5] = high; + + a = ((uint128_t)small[2]) * small[3]; + low = a; + high = a >> 64; + out[5] += low; + out[5] *= 2; + out[6] = high; + out[6] += high; + + a = ((uint128_t)small[2]) * small[2]; + low = a; + high = a >> 64; + out[4] += low; + out[5] += high; + + a = ((uint128_t)small[3]) * small[3]; + low = a; + high = a >> 64; + out[6] += low; + out[7] = high; +} + +/*felem_square sets |out| = |in|^2 + * On entry: + * in[i] < 2^109 + * On exit: + * out[i] < 7 * 2^64 < 2^67. */ +static void felem_square(longfelem out, const felem in) { + u64 small[4]; + felem_shrink(small, in); + smallfelem_square(out, small); +} + +/* smallfelem_mul sets |out| = |small1| * |small2| + * On entry: + * small1[i] < 2^64 + * small2[i] < 2^64 + * On exit: + * out[i] < 7 * 2^64 < 2^67. */ +static void smallfelem_mul(longfelem out, const smallfelem small1, + const smallfelem small2) { + limb a; + u64 high, low; + + a = ((uint128_t)small1[0]) * small2[0]; + low = a; + high = a >> 64; + out[0] = low; + out[1] = high; + + a = ((uint128_t)small1[0]) * small2[1]; + low = a; + high = a >> 64; + out[1] += low; + out[2] = high; + + a = ((uint128_t)small1[1]) * small2[0]; + low = a; + high = a >> 64; + out[1] += low; + out[2] += high; + + a = ((uint128_t)small1[0]) * small2[2]; + low = a; + high = a >> 64; + out[2] += low; + out[3] = high; + + a = ((uint128_t)small1[1]) * small2[1]; + low = a; + high = a >> 64; + out[2] += low; + out[3] += high; + + a = ((uint128_t)small1[2]) * small2[0]; + low = a; + high = a >> 64; + out[2] += low; + out[3] += high; + + a = ((uint128_t)small1[0]) * small2[3]; + low = a; + high = a >> 64; + out[3] += low; + out[4] = high; + + a = ((uint128_t)small1[1]) * small2[2]; + low = a; + high = a >> 64; + out[3] += low; + out[4] += high; + + a = ((uint128_t)small1[2]) * small2[1]; + low = a; + high = a >> 64; + out[3] += low; + out[4] += high; + + a = ((uint128_t)small1[3]) * small2[0]; + low = a; + high = a >> 64; + out[3] += low; + out[4] += high; + + a = ((uint128_t)small1[1]) * small2[3]; + low = a; + high = a >> 64; + out[4] += low; + out[5] = high; + + a = ((uint128_t)small1[2]) * small2[2]; + low = a; + high = a >> 64; + out[4] += low; + out[5] += high; + + a = ((uint128_t)small1[3]) * small2[1]; + low = a; + high = a >> 64; + out[4] += low; + out[5] += high; + + a = ((uint128_t)small1[2]) * small2[3]; + low = a; + high = a >> 64; + out[5] += low; + out[6] = high; + + a = ((uint128_t)small1[3]) * small2[2]; + low = a; + high = a >> 64; + out[5] += low; + out[6] += high; + + a = ((uint128_t)small1[3]) * small2[3]; + low = a; + high = a >> 64; + out[6] += low; + out[7] = high; +} + +/* felem_mul sets |out| = |in1| * |in2| + * On entry: + * in1[i] < 2^109 + * in2[i] < 2^109 + * On exit: + * out[i] < 7 * 2^64 < 2^67 */ +static void felem_mul(longfelem out, const felem in1, const felem in2) { + smallfelem small1, small2; + felem_shrink(small1, in1); + felem_shrink(small2, in2); + smallfelem_mul(out, small1, small2); +} + +/* felem_small_mul sets |out| = |small1| * |in2| + * On entry: + * small1[i] < 2^64 + * in2[i] < 2^109 + * On exit: + * out[i] < 7 * 2^64 < 2^67 */ +static void felem_small_mul(longfelem out, const smallfelem small1, + const felem in2) { + smallfelem small2; + felem_shrink(small2, in2); + smallfelem_mul(out, small1, small2); +} + +#define two100m36m4 (((limb)1) << 100) - (((limb)1) << 36) - (((limb)1) << 4) +#define two100 (((limb)1) << 100) +#define two100m36p4 (((limb)1) << 100) - (((limb)1) << 36) + (((limb)1) << 4) + +/* zero100 is 0 mod p */ +static const felem zero100 = {two100m36m4, two100, two100m36p4, two100m36p4}; + +/* Internal function for the different flavours of felem_reduce. + * felem_reduce_ reduces the higher coefficients in[4]-in[7]. + * On entry: + * out[0] >= in[6] + 2^32*in[6] + in[7] + 2^32*in[7] + * out[1] >= in[7] + 2^32*in[4] + * out[2] >= in[5] + 2^32*in[5] + * out[3] >= in[4] + 2^32*in[5] + 2^32*in[6] + * On exit: + * out[0] <= out[0] + in[4] + 2^32*in[5] + * out[1] <= out[1] + in[5] + 2^33*in[6] + * out[2] <= out[2] + in[7] + 2*in[6] + 2^33*in[7] + * out[3] <= out[3] + 2^32*in[4] + 3*in[7] */ +static void felem_reduce_(felem out, const longfelem in) { + int128_t c; + /* combine common terms from below */ + c = in[4] + (in[5] << 32); + out[0] += c; + out[3] -= c; + + c = in[5] - in[7]; + out[1] += c; + out[2] -= c; + + /* the remaining terms */ + /* 256: [(0,1),(96,-1),(192,-1),(224,1)] */ + out[1] -= (in[4] << 32); + out[3] += (in[4] << 32); + + /* 320: [(32,1),(64,1),(128,-1),(160,-1),(224,-1)] */ + out[2] -= (in[5] << 32); + + /* 384: [(0,-1),(32,-1),(96,2),(128,2),(224,-1)] */ + out[0] -= in[6]; + out[0] -= (in[6] << 32); + out[1] += (in[6] << 33); + out[2] += (in[6] * 2); + out[3] -= (in[6] << 32); + + /* 448: [(0,-1),(32,-1),(64,-1),(128,1),(160,2),(192,3)] */ + out[0] -= in[7]; + out[0] -= (in[7] << 32); + out[2] += (in[7] << 33); + out[3] += (in[7] * 3); +} + +/* felem_reduce converts a longfelem into an felem. + * To be called directly after felem_square or felem_mul. + * On entry: + * in[0] < 2^64, in[1] < 3*2^64, in[2] < 5*2^64, in[3] < 7*2^64 + * in[4] < 7*2^64, in[5] < 5*2^64, in[6] < 3*2^64, in[7] < 2*64 + * On exit: + * out[i] < 2^101 */ +static void felem_reduce(felem out, const longfelem in) { + out[0] = zero100[0] + in[0]; + out[1] = zero100[1] + in[1]; + out[2] = zero100[2] + in[2]; + out[3] = zero100[3] + in[3]; + + felem_reduce_(out, in); + + /* out[0] > 2^100 - 2^36 - 2^4 - 3*2^64 - 3*2^96 - 2^64 - 2^96 > 0 + * out[1] > 2^100 - 2^64 - 7*2^96 > 0 + * out[2] > 2^100 - 2^36 + 2^4 - 5*2^64 - 5*2^96 > 0 + * out[3] > 2^100 - 2^36 + 2^4 - 7*2^64 - 5*2^96 - 3*2^96 > 0 + * + * out[0] < 2^100 + 2^64 + 7*2^64 + 5*2^96 < 2^101 + * out[1] < 2^100 + 3*2^64 + 5*2^64 + 3*2^97 < 2^101 + * out[2] < 2^100 + 5*2^64 + 2^64 + 3*2^65 + 2^97 < 2^101 + * out[3] < 2^100 + 7*2^64 + 7*2^96 + 3*2^64 < 2^101 */ +} + +/* felem_reduce_zero105 converts a larger longfelem into an felem. + * On entry: + * in[0] < 2^71 + * On exit: + * out[i] < 2^106 */ +static void felem_reduce_zero105(felem out, const longfelem in) { + out[0] = zero105[0] + in[0]; + out[1] = zero105[1] + in[1]; + out[2] = zero105[2] + in[2]; + out[3] = zero105[3] + in[3]; + + felem_reduce_(out, in); + + /* out[0] > 2^105 - 2^41 - 2^9 - 2^71 - 2^103 - 2^71 - 2^103 > 0 + * out[1] > 2^105 - 2^71 - 2^103 > 0 + * out[2] > 2^105 - 2^41 + 2^9 - 2^71 - 2^103 > 0 + * out[3] > 2^105 - 2^41 + 2^9 - 2^71 - 2^103 - 2^103 > 0 + * + * out[0] < 2^105 + 2^71 + 2^71 + 2^103 < 2^106 + * out[1] < 2^105 + 2^71 + 2^71 + 2^103 < 2^106 + * out[2] < 2^105 + 2^71 + 2^71 + 2^71 + 2^103 < 2^106 + * out[3] < 2^105 + 2^71 + 2^103 + 2^71 < 2^106 */ +} + +/* subtract_u64 sets *result = *result - v and *carry to one if the + * subtraction underflowed. */ +static void subtract_u64(u64 *result, u64 *carry, u64 v) { + uint128_t r = *result; + r -= v; + *carry = (r >> 64) & 1; + *result = (u64)r; +} + +/* felem_contract converts |in| to its unique, minimal representation. On + * entry: in[i] < 2^109. */ +static void felem_contract(smallfelem out, const felem in) { + u64 all_equal_so_far = 0, result = 0; + + felem_shrink(out, in); + /* small is minimal except that the value might be > p */ + + all_equal_so_far--; + /* We are doing a constant time test if out >= kPrime. We need to compare + * each u64, from most-significant to least significant. For each one, if + * all words so far have been equal (m is all ones) then a non-equal + * result is the answer. Otherwise we continue. */ + unsigned i; + for (i = 3; i < 4; i--) { + u64 equal; + uint128_t a = ((uint128_t)kPrime[i]) - out[i]; + /* if out[i] > kPrime[i] then a will underflow and the high 64-bits + * will all be set. */ + result |= all_equal_so_far & ((u64)(a >> 64)); + + /* if kPrime[i] == out[i] then |equal| will be all zeros and the + * decrement will make it all ones. */ + equal = kPrime[i] ^ out[i]; + equal--; + equal &= equal << 32; + equal &= equal << 16; + equal &= equal << 8; + equal &= equal << 4; + equal &= equal << 2; + equal &= equal << 1; + equal = ((s64)equal) >> 63; + + all_equal_so_far &= equal; + } + + /* if all_equal_so_far is still all ones then the two values are equal + * and so out >= kPrime is true. */ + result |= all_equal_so_far; + + /* if out >= kPrime then we subtract kPrime. */ + u64 carry; + subtract_u64(&out[0], &carry, result & kPrime[0]); + subtract_u64(&out[1], &carry, carry); + subtract_u64(&out[2], &carry, carry); + subtract_u64(&out[3], &carry, carry); + + subtract_u64(&out[1], &carry, result & kPrime[1]); + subtract_u64(&out[2], &carry, carry); + subtract_u64(&out[3], &carry, carry); + + subtract_u64(&out[2], &carry, result & kPrime[2]); + subtract_u64(&out[3], &carry, carry); + + subtract_u64(&out[3], &carry, result & kPrime[3]); +} + +static void smallfelem_square_contract(smallfelem out, const smallfelem in) { + longfelem longtmp; + felem tmp; + + smallfelem_square(longtmp, in); + felem_reduce(tmp, longtmp); + felem_contract(out, tmp); +} + +static void smallfelem_mul_contract(smallfelem out, const smallfelem in1, + const smallfelem in2) { + longfelem longtmp; + felem tmp; + + smallfelem_mul(longtmp, in1, in2); + felem_reduce(tmp, longtmp); + felem_contract(out, tmp); +} + +/* felem_is_zero returns a limb with all bits set if |in| == 0 (mod p) and 0 + * otherwise. + * On entry: + * small[i] < 2^64 */ +static limb smallfelem_is_zero(const smallfelem small) { + limb result; + u64 is_p; + + u64 is_zero = small[0] | small[1] | small[2] | small[3]; + is_zero--; + is_zero &= is_zero << 32; + is_zero &= is_zero << 16; + is_zero &= is_zero << 8; + is_zero &= is_zero << 4; + is_zero &= is_zero << 2; + is_zero &= is_zero << 1; + is_zero = ((s64)is_zero) >> 63; + + is_p = (small[0] ^ kPrime[0]) | (small[1] ^ kPrime[1]) | + (small[2] ^ kPrime[2]) | (small[3] ^ kPrime[3]); + is_p--; + is_p &= is_p << 32; + is_p &= is_p << 16; + is_p &= is_p << 8; + is_p &= is_p << 4; + is_p &= is_p << 2; + is_p &= is_p << 1; + is_p = ((s64)is_p) >> 63; + + is_zero |= is_p; + + result = is_zero; + result |= ((limb)is_zero) << 64; + return result; +} + +static int smallfelem_is_zero_int(const smallfelem small) { + return (int)(smallfelem_is_zero(small) & ((limb)1)); +} + +/* felem_inv calculates |out| = |in|^{-1} + * + * Based on Fermat's Little Theorem: + * a^p = a (mod p) + * a^{p-1} = 1 (mod p) + * a^{p-2} = a^{-1} (mod p) */ +static void felem_inv(felem out, const felem in) { + felem ftmp, ftmp2; + /* each e_I will hold |in|^{2^I - 1} */ + felem e2, e4, e8, e16, e32, e64; + longfelem tmp; + unsigned i; + + felem_square(tmp, in); + felem_reduce(ftmp, tmp); /* 2^1 */ + felem_mul(tmp, in, ftmp); + felem_reduce(ftmp, tmp); /* 2^2 - 2^0 */ + felem_assign(e2, ftmp); + felem_square(tmp, ftmp); + felem_reduce(ftmp, tmp); /* 2^3 - 2^1 */ + felem_square(tmp, ftmp); + felem_reduce(ftmp, tmp); /* 2^4 - 2^2 */ + felem_mul(tmp, ftmp, e2); + felem_reduce(ftmp, tmp); /* 2^4 - 2^0 */ + felem_assign(e4, ftmp); + felem_square(tmp, ftmp); + felem_reduce(ftmp, tmp); /* 2^5 - 2^1 */ + felem_square(tmp, ftmp); + felem_reduce(ftmp, tmp); /* 2^6 - 2^2 */ + felem_square(tmp, ftmp); + felem_reduce(ftmp, tmp); /* 2^7 - 2^3 */ + felem_square(tmp, ftmp); + felem_reduce(ftmp, tmp); /* 2^8 - 2^4 */ + felem_mul(tmp, ftmp, e4); + felem_reduce(ftmp, tmp); /* 2^8 - 2^0 */ + felem_assign(e8, ftmp); + for (i = 0; i < 8; i++) { + felem_square(tmp, ftmp); + felem_reduce(ftmp, tmp); + } /* 2^16 - 2^8 */ + felem_mul(tmp, ftmp, e8); + felem_reduce(ftmp, tmp); /* 2^16 - 2^0 */ + felem_assign(e16, ftmp); + for (i = 0; i < 16; i++) { + felem_square(tmp, ftmp); + felem_reduce(ftmp, tmp); + } /* 2^32 - 2^16 */ + felem_mul(tmp, ftmp, e16); + felem_reduce(ftmp, tmp); /* 2^32 - 2^0 */ + felem_assign(e32, ftmp); + for (i = 0; i < 32; i++) { + felem_square(tmp, ftmp); + felem_reduce(ftmp, tmp); + } /* 2^64 - 2^32 */ + felem_assign(e64, ftmp); + felem_mul(tmp, ftmp, in); + felem_reduce(ftmp, tmp); /* 2^64 - 2^32 + 2^0 */ + for (i = 0; i < 192; i++) { + felem_square(tmp, ftmp); + felem_reduce(ftmp, tmp); + } /* 2^256 - 2^224 + 2^192 */ + + felem_mul(tmp, e64, e32); + felem_reduce(ftmp2, tmp); /* 2^64 - 2^0 */ + for (i = 0; i < 16; i++) { + felem_square(tmp, ftmp2); + felem_reduce(ftmp2, tmp); + } /* 2^80 - 2^16 */ + felem_mul(tmp, ftmp2, e16); + felem_reduce(ftmp2, tmp); /* 2^80 - 2^0 */ + for (i = 0; i < 8; i++) { + felem_square(tmp, ftmp2); + felem_reduce(ftmp2, tmp); + } /* 2^88 - 2^8 */ + felem_mul(tmp, ftmp2, e8); + felem_reduce(ftmp2, tmp); /* 2^88 - 2^0 */ + for (i = 0; i < 4; i++) { + felem_square(tmp, ftmp2); + felem_reduce(ftmp2, tmp); + } /* 2^92 - 2^4 */ + felem_mul(tmp, ftmp2, e4); + felem_reduce(ftmp2, tmp); /* 2^92 - 2^0 */ + felem_square(tmp, ftmp2); + felem_reduce(ftmp2, tmp); /* 2^93 - 2^1 */ + felem_square(tmp, ftmp2); + felem_reduce(ftmp2, tmp); /* 2^94 - 2^2 */ + felem_mul(tmp, ftmp2, e2); + felem_reduce(ftmp2, tmp); /* 2^94 - 2^0 */ + felem_square(tmp, ftmp2); + felem_reduce(ftmp2, tmp); /* 2^95 - 2^1 */ + felem_square(tmp, ftmp2); + felem_reduce(ftmp2, tmp); /* 2^96 - 2^2 */ + felem_mul(tmp, ftmp2, in); + felem_reduce(ftmp2, tmp); /* 2^96 - 3 */ + + felem_mul(tmp, ftmp2, ftmp); + felem_reduce(out, tmp); /* 2^256 - 2^224 + 2^192 + 2^96 - 3 */ +} + +static void smallfelem_inv_contract(smallfelem out, const smallfelem in) { + felem tmp; + + smallfelem_expand(tmp, in); + felem_inv(tmp, tmp); + felem_contract(out, tmp); +} + +/* Group operations + * ---------------- + * + * Building on top of the field operations we have the operations on the + * elliptic curve group itself. Points on the curve are represented in Jacobian + * coordinates. */ + +/* point_double calculates 2*(x_in, y_in, z_in) + * + * The method is taken from: + * http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b + * + * Outputs can equal corresponding inputs, i.e., x_out == x_in is allowed. + * while x_out == y_in is not (maybe this works, but it's not tested). */ +static void point_double(felem x_out, felem y_out, felem z_out, + const felem x_in, const felem y_in, const felem z_in) { + longfelem tmp, tmp2; + felem delta, gamma, beta, alpha, ftmp, ftmp2; + smallfelem small1, small2; + + felem_assign(ftmp, x_in); + /* ftmp[i] < 2^106 */ + felem_assign(ftmp2, x_in); + /* ftmp2[i] < 2^106 */ + + /* delta = z^2 */ + felem_square(tmp, z_in); + felem_reduce(delta, tmp); + /* delta[i] < 2^101 */ + + /* gamma = y^2 */ + felem_square(tmp, y_in); + felem_reduce(gamma, tmp); + /* gamma[i] < 2^101 */ + felem_shrink(small1, gamma); + + /* beta = x*gamma */ + felem_small_mul(tmp, small1, x_in); + felem_reduce(beta, tmp); + /* beta[i] < 2^101 */ + + /* alpha = 3*(x-delta)*(x+delta) */ + felem_diff(ftmp, delta); + /* ftmp[i] < 2^105 + 2^106 < 2^107 */ + felem_sum(ftmp2, delta); + /* ftmp2[i] < 2^105 + 2^106 < 2^107 */ + felem_scalar(ftmp2, 3); + /* ftmp2[i] < 3 * 2^107 < 2^109 */ + felem_mul(tmp, ftmp, ftmp2); + felem_reduce(alpha, tmp); + /* alpha[i] < 2^101 */ + felem_shrink(small2, alpha); + + /* x' = alpha^2 - 8*beta */ + smallfelem_square(tmp, small2); + felem_reduce(x_out, tmp); + felem_assign(ftmp, beta); + felem_scalar(ftmp, 8); + /* ftmp[i] < 8 * 2^101 = 2^104 */ + felem_diff(x_out, ftmp); + /* x_out[i] < 2^105 + 2^101 < 2^106 */ + + /* z' = (y + z)^2 - gamma - delta */ + felem_sum(delta, gamma); + /* delta[i] < 2^101 + 2^101 = 2^102 */ + felem_assign(ftmp, y_in); + felem_sum(ftmp, z_in); + /* ftmp[i] < 2^106 + 2^106 = 2^107 */ + felem_square(tmp, ftmp); + felem_reduce(z_out, tmp); + felem_diff(z_out, delta); + /* z_out[i] < 2^105 + 2^101 < 2^106 */ + + /* y' = alpha*(4*beta - x') - 8*gamma^2 */ + felem_scalar(beta, 4); + /* beta[i] < 4 * 2^101 = 2^103 */ + felem_diff_zero107(beta, x_out); + /* beta[i] < 2^107 + 2^103 < 2^108 */ + felem_small_mul(tmp, small2, beta); + /* tmp[i] < 7 * 2^64 < 2^67 */ + smallfelem_square(tmp2, small1); + /* tmp2[i] < 7 * 2^64 */ + longfelem_scalar(tmp2, 8); + /* tmp2[i] < 8 * 7 * 2^64 = 7 * 2^67 */ + longfelem_diff(tmp, tmp2); + /* tmp[i] < 2^67 + 2^70 + 2^40 < 2^71 */ + felem_reduce_zero105(y_out, tmp); + /* y_out[i] < 2^106 */ +} + +/* point_double_small is the same as point_double, except that it operates on + * smallfelems. */ +static void point_double_small(smallfelem x_out, smallfelem y_out, + smallfelem z_out, const smallfelem x_in, + const smallfelem y_in, const smallfelem z_in) { + felem felem_x_out, felem_y_out, felem_z_out; + felem felem_x_in, felem_y_in, felem_z_in; + + smallfelem_expand(felem_x_in, x_in); + smallfelem_expand(felem_y_in, y_in); + smallfelem_expand(felem_z_in, z_in); + point_double(felem_x_out, felem_y_out, felem_z_out, felem_x_in, felem_y_in, + felem_z_in); + felem_shrink(x_out, felem_x_out); + felem_shrink(y_out, felem_y_out); + felem_shrink(z_out, felem_z_out); +} + +/* copy_conditional copies in to out iff mask is all ones. */ +static void copy_conditional(felem out, const felem in, limb mask) { + unsigned i; + for (i = 0; i < NLIMBS; ++i) { + const limb tmp = mask & (in[i] ^ out[i]); + out[i] ^= tmp; + } +} + +/* copy_small_conditional copies in to out iff mask is all ones. */ +static void copy_small_conditional(felem out, const smallfelem in, limb mask) { + unsigned i; + const u64 mask64 = mask; + for (i = 0; i < NLIMBS; ++i) { + out[i] = ((limb)(in[i] & mask64)) | (out[i] & ~mask); + } +} + +/* point_add calcuates (x1, y1, z1) + (x2, y2, z2) + * + * The method is taken from: + * http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl, + * adapted for mixed addition (z2 = 1, or z2 = 0 for the point at infinity). + * + * This function includes a branch for checking whether the two input points + * are equal, (while not equal to the point at infinity). This case never + * happens during single point multiplication, so there is no timing leak for + * ECDH or ECDSA signing. */ +static void point_add(felem x3, felem y3, felem z3, const felem x1, + const felem y1, const felem z1, const int mixed, + const smallfelem x2, const smallfelem y2, + const smallfelem z2) { + felem ftmp, ftmp2, ftmp3, ftmp4, ftmp5, ftmp6, x_out, y_out, z_out; + longfelem tmp, tmp2; + smallfelem small1, small2, small3, small4, small5; + limb x_equal, y_equal, z1_is_zero, z2_is_zero; + + felem_shrink(small3, z1); + + z1_is_zero = smallfelem_is_zero(small3); + z2_is_zero = smallfelem_is_zero(z2); + + /* ftmp = z1z1 = z1**2 */ + smallfelem_square(tmp, small3); + felem_reduce(ftmp, tmp); + /* ftmp[i] < 2^101 */ + felem_shrink(small1, ftmp); + + if (!mixed) { + /* ftmp2 = z2z2 = z2**2 */ + smallfelem_square(tmp, z2); + felem_reduce(ftmp2, tmp); + /* ftmp2[i] < 2^101 */ + felem_shrink(small2, ftmp2); + + felem_shrink(small5, x1); + + /* u1 = ftmp3 = x1*z2z2 */ + smallfelem_mul(tmp, small5, small2); + felem_reduce(ftmp3, tmp); + /* ftmp3[i] < 2^101 */ + + /* ftmp5 = z1 + z2 */ + felem_assign(ftmp5, z1); + felem_small_sum(ftmp5, z2); + /* ftmp5[i] < 2^107 */ + + /* ftmp5 = (z1 + z2)**2 - (z1z1 + z2z2) = 2z1z2 */ + felem_square(tmp, ftmp5); + felem_reduce(ftmp5, tmp); + /* ftmp2 = z2z2 + z1z1 */ + felem_sum(ftmp2, ftmp); + /* ftmp2[i] < 2^101 + 2^101 = 2^102 */ + felem_diff(ftmp5, ftmp2); + /* ftmp5[i] < 2^105 + 2^101 < 2^106 */ + + /* ftmp2 = z2 * z2z2 */ + smallfelem_mul(tmp, small2, z2); + felem_reduce(ftmp2, tmp); + + /* s1 = ftmp2 = y1 * z2**3 */ + felem_mul(tmp, y1, ftmp2); + felem_reduce(ftmp6, tmp); + /* ftmp6[i] < 2^101 */ + } else { + /* We'll assume z2 = 1 (special case z2 = 0 is handled later). */ + + /* u1 = ftmp3 = x1*z2z2 */ + felem_assign(ftmp3, x1); + /* ftmp3[i] < 2^106 */ + + /* ftmp5 = 2z1z2 */ + felem_assign(ftmp5, z1); + felem_scalar(ftmp5, 2); + /* ftmp5[i] < 2*2^106 = 2^107 */ + + /* s1 = ftmp2 = y1 * z2**3 */ + felem_assign(ftmp6, y1); + /* ftmp6[i] < 2^106 */ + } + + /* u2 = x2*z1z1 */ + smallfelem_mul(tmp, x2, small1); + felem_reduce(ftmp4, tmp); + + /* h = ftmp4 = u2 - u1 */ + felem_diff_zero107(ftmp4, ftmp3); + /* ftmp4[i] < 2^107 + 2^101 < 2^108 */ + felem_shrink(small4, ftmp4); + + x_equal = smallfelem_is_zero(small4); + + /* z_out = ftmp5 * h */ + felem_small_mul(tmp, small4, ftmp5); + felem_reduce(z_out, tmp); + /* z_out[i] < 2^101 */ + + /* ftmp = z1 * z1z1 */ + smallfelem_mul(tmp, small1, small3); + felem_reduce(ftmp, tmp); + + /* s2 = tmp = y2 * z1**3 */ + felem_small_mul(tmp, y2, ftmp); + felem_reduce(ftmp5, tmp); + + /* r = ftmp5 = (s2 - s1)*2 */ + felem_diff_zero107(ftmp5, ftmp6); + /* ftmp5[i] < 2^107 + 2^107 = 2^108 */ + felem_scalar(ftmp5, 2); + /* ftmp5[i] < 2^109 */ + felem_shrink(small1, ftmp5); + y_equal = smallfelem_is_zero(small1); + + if (x_equal && y_equal && !z1_is_zero && !z2_is_zero) { + point_double(x3, y3, z3, x1, y1, z1); + return; + } + + /* I = ftmp = (2h)**2 */ + felem_assign(ftmp, ftmp4); + felem_scalar(ftmp, 2); + /* ftmp[i] < 2*2^108 = 2^109 */ + felem_square(tmp, ftmp); + felem_reduce(ftmp, tmp); + + /* J = ftmp2 = h * I */ + felem_mul(tmp, ftmp4, ftmp); + felem_reduce(ftmp2, tmp); + + /* V = ftmp4 = U1 * I */ + felem_mul(tmp, ftmp3, ftmp); + felem_reduce(ftmp4, tmp); + + /* x_out = r**2 - J - 2V */ + smallfelem_square(tmp, small1); + felem_reduce(x_out, tmp); + felem_assign(ftmp3, ftmp4); + felem_scalar(ftmp4, 2); + felem_sum(ftmp4, ftmp2); + /* ftmp4[i] < 2*2^101 + 2^101 < 2^103 */ + felem_diff(x_out, ftmp4); + /* x_out[i] < 2^105 + 2^101 */ + + /* y_out = r(V-x_out) - 2 * s1 * J */ + felem_diff_zero107(ftmp3, x_out); + /* ftmp3[i] < 2^107 + 2^101 < 2^108 */ + felem_small_mul(tmp, small1, ftmp3); + felem_mul(tmp2, ftmp6, ftmp2); + longfelem_scalar(tmp2, 2); + /* tmp2[i] < 2*2^67 = 2^68 */ + longfelem_diff(tmp, tmp2); + /* tmp[i] < 2^67 + 2^70 + 2^40 < 2^71 */ + felem_reduce_zero105(y_out, tmp); + /* y_out[i] < 2^106 */ + + copy_small_conditional(x_out, x2, z1_is_zero); + copy_conditional(x_out, x1, z2_is_zero); + copy_small_conditional(y_out, y2, z1_is_zero); + copy_conditional(y_out, y1, z2_is_zero); + copy_small_conditional(z_out, z2, z1_is_zero); + copy_conditional(z_out, z1, z2_is_zero); + felem_assign(x3, x_out); + felem_assign(y3, y_out); + felem_assign(z3, z_out); +} + +/* point_add_small is the same as point_add, except that it operates on + * smallfelems. */ +static void point_add_small(smallfelem x3, smallfelem y3, smallfelem z3, + smallfelem x1, smallfelem y1, smallfelem z1, + smallfelem x2, smallfelem y2, smallfelem z2) { + felem felem_x3, felem_y3, felem_z3; + felem felem_x1, felem_y1, felem_z1; + smallfelem_expand(felem_x1, x1); + smallfelem_expand(felem_y1, y1); + smallfelem_expand(felem_z1, z1); + point_add(felem_x3, felem_y3, felem_z3, felem_x1, felem_y1, felem_z1, 0, x2, + y2, z2); + felem_shrink(x3, felem_x3); + felem_shrink(y3, felem_y3); + felem_shrink(z3, felem_z3); +} + +/* Base point pre computation + * -------------------------- + * + * Two different sorts of precomputed tables are used in the following code. + * Each contain various points on the curve, where each point is three field + * elements (x, y, z). + * + * For the base point table, z is usually 1 (0 for the point at infinity). + * This table has 2 * 16 elements, starting with the following: + * index | bits | point + * ------+---------+------------------------------ + * 0 | 0 0 0 0 | 0G + * 1 | 0 0 0 1 | 1G + * 2 | 0 0 1 0 | 2^64G + * 3 | 0 0 1 1 | (2^64 + 1)G + * 4 | 0 1 0 0 | 2^128G + * 5 | 0 1 0 1 | (2^128 + 1)G + * 6 | 0 1 1 0 | (2^128 + 2^64)G + * 7 | 0 1 1 1 | (2^128 + 2^64 + 1)G + * 8 | 1 0 0 0 | 2^192G + * 9 | 1 0 0 1 | (2^192 + 1)G + * 10 | 1 0 1 0 | (2^192 + 2^64)G + * 11 | 1 0 1 1 | (2^192 + 2^64 + 1)G + * 12 | 1 1 0 0 | (2^192 + 2^128)G + * 13 | 1 1 0 1 | (2^192 + 2^128 + 1)G + * 14 | 1 1 1 0 | (2^192 + 2^128 + 2^64)G + * 15 | 1 1 1 1 | (2^192 + 2^128 + 2^64 + 1)G + * followed by a copy of this with each element multiplied by 2^32. + * + * The reason for this is so that we can clock bits into four different + * locations when doing simple scalar multiplies against the base point, + * and then another four locations using the second 16 elements. + * + * Tables for other points have table[i] = iG for i in 0 .. 16. */ + +/* gmul is the table of precomputed base points */ +static const smallfelem gmul[2][16][3] = { + {{{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, + {{0xf4a13945d898c296, 0x77037d812deb33a0, 0xf8bce6e563a440f2, + 0x6b17d1f2e12c4247}, + {0xcbb6406837bf51f5, 0x2bce33576b315ece, 0x8ee7eb4a7c0f9e16, + 0x4fe342e2fe1a7f9b}, + {1, 0, 0, 0}}, + {{0x90e75cb48e14db63, 0x29493baaad651f7e, 0x8492592e326e25de, + 0x0fa822bc2811aaa5}, + {0xe41124545f462ee7, 0x34b1a65050fe82f5, 0x6f4ad4bcb3df188b, + 0xbff44ae8f5dba80d}, + {1, 0, 0, 0}}, + {{0x93391ce2097992af, 0xe96c98fd0d35f1fa, 0xb257c0de95e02789, + 0x300a4bbc89d6726f}, + {0xaa54a291c08127a0, 0x5bb1eeada9d806a5, 0x7f1ddb25ff1e3c6f, + 0x72aac7e0d09b4644}, + {1, 0, 0, 0}}, + {{0x57c84fc9d789bd85, 0xfc35ff7dc297eac3, 0xfb982fd588c6766e, + 0x447d739beedb5e67}, + {0x0c7e33c972e25b32, 0x3d349b95a7fae500, 0xe12e9d953a4aaff7, + 0x2d4825ab834131ee}, + {1, 0, 0, 0}}, + {{0x13949c932a1d367f, 0xef7fbd2b1a0a11b7, 0xddc6068bb91dfc60, + 0xef9519328a9c72ff}, + {0x196035a77376d8a8, 0x23183b0895ca1740, 0xc1ee9807022c219c, + 0x611e9fc37dbb2c9b}, + {1, 0, 0, 0}}, + {{0xcae2b1920b57f4bc, 0x2936df5ec6c9bc36, 0x7dea6482e11238bf, + 0x550663797b51f5d8}, + {0x44ffe216348a964c, 0x9fb3d576dbdefbe1, 0x0afa40018d9d50e5, + 0x157164848aecb851}, + {1, 0, 0, 0}}, + {{0xe48ecafffc5cde01, 0x7ccd84e70d715f26, 0xa2e8f483f43e4391, + 0xeb5d7745b21141ea}, + {0xcac917e2731a3479, 0x85f22cfe2844b645, 0x0990e6a158006cee, + 0xeafd72ebdbecc17b}, + {1, 0, 0, 0}}, + {{0x6cf20ffb313728be, 0x96439591a3c6b94a, 0x2736ff8344315fc5, + 0xa6d39677a7849276}, + {0xf2bab833c357f5f4, 0x824a920c2284059b, 0x66b8babd2d27ecdf, + 0x674f84749b0b8816}, + {1, 0, 0, 0}}, + {{0x2df48c04677c8a3e, 0x74e02f080203a56b, 0x31855f7db8c7fedb, + 0x4e769e7672c9ddad}, + {0xa4c36165b824bbb0, 0xfb9ae16f3b9122a5, 0x1ec0057206947281, + 0x42b99082de830663}, + {1, 0, 0, 0}}, + {{0x6ef95150dda868b9, 0xd1f89e799c0ce131, 0x7fdc1ca008a1c478, + 0x78878ef61c6ce04d}, + {0x9c62b9121fe0d976, 0x6ace570ebde08d4f, 0xde53142c12309def, + 0xb6cb3f5d7b72c321}, + {1, 0, 0, 0}}, + {{0x7f991ed2c31a3573, 0x5b82dd5bd54fb496, 0x595c5220812ffcae, + 0x0c88bc4d716b1287}, + {0x3a57bf635f48aca8, 0x7c8181f4df2564f3, 0x18d1b5b39c04e6aa, + 0xdd5ddea3f3901dc6}, + {1, 0, 0, 0}}, + {{0xe96a79fb3e72ad0c, 0x43a0a28c42ba792f, 0xefe0a423083e49f3, + 0x68f344af6b317466}, + {0xcdfe17db3fb24d4a, 0x668bfc2271f5c626, 0x604ed93c24d67ff3, + 0x31b9c405f8540a20}, + {1, 0, 0, 0}}, + {{0xd36b4789a2582e7f, 0x0d1a10144ec39c28, 0x663c62c3edbad7a0, + 0x4052bf4b6f461db9}, + {0x235a27c3188d25eb, 0xe724f33999bfcc5b, 0x862be6bd71d70cc8, + 0xfecf4d5190b0fc61}, + {1, 0, 0, 0}}, + {{0x74346c10a1d4cfac, 0xafdf5cc08526a7a4, 0x123202a8f62bff7a, + 0x1eddbae2c802e41a}, + {0x8fa0af2dd603f844, 0x36e06b7e4c701917, 0x0c45f45273db33a0, + 0x43104d86560ebcfc}, + {1, 0, 0, 0}}, + {{0x9615b5110d1d78e5, 0x66b0de3225c4744b, 0x0a4a46fb6aaf363a, + 0xb48e26b484f7a21c}, + {0x06ebb0f621a01b2d, 0xc004e4048b7b0f98, 0x64131bcdfed6f668, + 0xfac015404d4d3dab}, + {1, 0, 0, 0}}}, + {{{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, + {{0x3a5a9e22185a5943, 0x1ab919365c65dfb6, 0x21656b32262c71da, + 0x7fe36b40af22af89}, + {0xd50d152c699ca101, 0x74b3d5867b8af212, 0x9f09f40407dca6f1, + 0xe697d45825b63624}, + {1, 0, 0, 0}}, + {{0xa84aa9397512218e, 0xe9a521b074ca0141, 0x57880b3a18a2e902, + 0x4a5b506612a677a6}, + {0x0beada7a4c4f3840, 0x626db15419e26d9d, 0xc42604fbe1627d40, + 0xeb13461ceac089f1}, + {1, 0, 0, 0}}, + {{0xf9faed0927a43281, 0x5e52c4144103ecbc, 0xc342967aa815c857, + 0x0781b8291c6a220a}, + {0x5a8343ceeac55f80, 0x88f80eeee54a05e3, 0x97b2a14f12916434, + 0x690cde8df0151593}, + {1, 0, 0, 0}}, + {{0xaee9c75df7f82f2a, 0x9e4c35874afdf43a, 0xf5622df437371326, + 0x8a535f566ec73617}, + {0xc5f9a0ac223094b7, 0xcde533864c8c7669, 0x37e02819085a92bf, + 0x0455c08468b08bd7}, + {1, 0, 0, 0}}, + {{0x0c0a6e2c9477b5d9, 0xf9a4bf62876dc444, 0x5050a949b6cdc279, + 0x06bada7ab77f8276}, + {0xc8b4aed1ea48dac9, 0xdebd8a4b7ea1070f, 0x427d49101366eb70, + 0x5b476dfd0e6cb18a}, + {1, 0, 0, 0}}, + {{0x7c5c3e44278c340a, 0x4d54606812d66f3b, 0x29a751b1ae23c5d8, + 0x3e29864e8a2ec908}, + {0x142d2a6626dbb850, 0xad1744c4765bd780, 0x1f150e68e322d1ed, + 0x239b90ea3dc31e7e}, + {1, 0, 0, 0}}, + {{0x78c416527a53322a, 0x305dde6709776f8e, 0xdbcab759f8862ed4, + 0x820f4dd949f72ff7}, + {0x6cc544a62b5debd4, 0x75be5d937b4e8cc4, 0x1b481b1b215c14d3, + 0x140406ec783a05ec}, + {1, 0, 0, 0}}, + {{0x6a703f10e895df07, 0xfd75f3fa01876bd8, 0xeb5b06e70ce08ffe, + 0x68f6b8542783dfee}, + {0x90c76f8a78712655, 0xcf5293d2f310bf7f, 0xfbc8044dfda45028, + 0xcbe1feba92e40ce6}, + {1, 0, 0, 0}}, + {{0xe998ceea4396e4c1, 0xfc82ef0b6acea274, 0x230f729f2250e927, + 0xd0b2f94d2f420109}, + {0x4305adddb38d4966, 0x10b838f8624c3b45, 0x7db2636658954e7a, + 0x971459828b0719e5}, + {1, 0, 0, 0}}, + {{0x4bd6b72623369fc9, 0x57f2929e53d0b876, 0xc2d5cba4f2340687, + 0x961610004a866aba}, + {0x49997bcd2e407a5e, 0x69ab197d92ddcb24, 0x2cf1f2438fe5131c, + 0x7acb9fadcee75e44}, + {1, 0, 0, 0}}, + {{0x254e839423d2d4c0, 0xf57f0c917aea685b, 0xa60d880f6f75aaea, + 0x24eb9acca333bf5b}, + {0xe3de4ccb1cda5dea, 0xfeef9341c51a6b4f, 0x743125f88bac4c4d, + 0x69f891c5acd079cc}, + {1, 0, 0, 0}}, + {{0xeee44b35702476b5, 0x7ed031a0e45c2258, 0xb422d1e7bd6f8514, + 0xe51f547c5972a107}, + {0xa25bcd6fc9cf343d, 0x8ca922ee097c184e, 0xa62f98b3a9fe9a06, + 0x1c309a2b25bb1387}, + {1, 0, 0, 0}}, + {{0x9295dbeb1967c459, 0xb00148833472c98e, 0xc504977708011828, + 0x20b87b8aa2c4e503}, + {0x3063175de057c277, 0x1bd539338fe582dd, 0x0d11adef5f69a044, + 0xf5c6fa49919776be}, + {1, 0, 0, 0}}, + {{0x8c944e760fd59e11, 0x3876cba1102fad5f, 0xa454c3fad83faa56, + 0x1ed7d1b9332010b9}, + {0xa1011a270024b889, 0x05e4d0dcac0cd344, 0x52b520f0eb6a2a24, + 0x3a2b03f03217257a}, + {1, 0, 0, 0}}, + {{0xf20fc2afdf1d043d, 0xf330240db58d5a62, 0xfc7d229ca0058c3b, + 0x15fee545c78dd9f6}, + {0x501e82885bc98cda, 0x41ef80e5d046ac04, 0x557d9f49461210fb, + 0x4ab5b6b2b8753f81}, + {1, 0, 0, 0}}}}; + +/* select_point selects the |idx|th point from a precomputation table and + * copies it to out. */ +static void select_point(const u64 idx, unsigned int size, + const smallfelem pre_comp[16][3], smallfelem out[3]) { + unsigned i, j; + u64 *outlimbs = &out[0][0]; + memset(outlimbs, 0, 3 * sizeof(smallfelem)); + + for (i = 0; i < size; i++) { + const u64 *inlimbs = (u64 *)&pre_comp[i][0][0]; + u64 mask = i ^ idx; + mask |= mask >> 4; + mask |= mask >> 2; + mask |= mask >> 1; + mask &= 1; + mask--; + for (j = 0; j < NLIMBS * 3; j++) { + outlimbs[j] |= inlimbs[j] & mask; + } + } +} + +/* get_bit returns the |i|th bit in |in| */ +static char get_bit(const felem_bytearray in, int i) { + if (i < 0 || i >= 256) { + return 0; + } + return (in[i >> 3] >> (i & 7)) & 1; +} + +/* Interleaved point multiplication using precomputed point multiples: The + * small point multiples 0*P, 1*P, ..., 17*P are in pre_comp[], the scalars + * in scalars[]. If g_scalar is non-NULL, we also add this multiple of the + * generator, using certain (large) precomputed multiples in g_pre_comp. + * Output point (X, Y, Z) is stored in x_out, y_out, z_out. */ +static void batch_mul(felem x_out, felem y_out, felem z_out, + const felem_bytearray scalars[], + const unsigned num_points, const u8 *g_scalar, + const int mixed, const smallfelem pre_comp[][17][3], + const smallfelem g_pre_comp[2][16][3]) { + int i, skip; + unsigned num, gen_mul = (g_scalar != NULL); + felem nq[3], ftmp; + smallfelem tmp[3]; + u64 bits; + u8 sign, digit; + + /* set nq to the point at infinity */ + memset(nq, 0, 3 * sizeof(felem)); + + /* Loop over all scalars msb-to-lsb, interleaving additions of multiples + * of the generator (two in each of the last 32 rounds) and additions of + * other points multiples (every 5th round). */ + + skip = 1; /* save two point operations in the first + * round */ + for (i = (num_points ? 255 : 31); i >= 0; --i) { + /* double */ + if (!skip) { + point_double(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2]); + } + + /* add multiples of the generator */ + if (gen_mul && i <= 31) { + /* first, look 32 bits upwards */ + bits = get_bit(g_scalar, i + 224) << 3; + bits |= get_bit(g_scalar, i + 160) << 2; + bits |= get_bit(g_scalar, i + 96) << 1; + bits |= get_bit(g_scalar, i + 32); + /* select the point to add, in constant time */ + select_point(bits, 16, g_pre_comp[1], tmp); + + if (!skip) { + /* Arg 1 below is for "mixed" */ + point_add(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2], 1, tmp[0], tmp[1], + tmp[2]); + } else { + smallfelem_expand(nq[0], tmp[0]); + smallfelem_expand(nq[1], tmp[1]); + smallfelem_expand(nq[2], tmp[2]); + skip = 0; + } + + /* second, look at the current position */ + bits = get_bit(g_scalar, i + 192) << 3; + bits |= get_bit(g_scalar, i + 128) << 2; + bits |= get_bit(g_scalar, i + 64) << 1; + bits |= get_bit(g_scalar, i); + /* select the point to add, in constant time */ + select_point(bits, 16, g_pre_comp[0], tmp); + /* Arg 1 below is for "mixed" */ + point_add(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2], 1, tmp[0], tmp[1], + tmp[2]); + } + + /* do other additions every 5 doublings */ + if (num_points && (i % 5 == 0)) { + /* loop over all scalars */ + for (num = 0; num < num_points; ++num) { + bits = get_bit(scalars[num], i + 4) << 5; + bits |= get_bit(scalars[num], i + 3) << 4; + bits |= get_bit(scalars[num], i + 2) << 3; + bits |= get_bit(scalars[num], i + 1) << 2; + bits |= get_bit(scalars[num], i) << 1; + bits |= get_bit(scalars[num], i - 1); + ec_GFp_nistp_recode_scalar_bits(&sign, &digit, bits); + + /* select the point to add or subtract, in constant time. */ + select_point(digit, 17, pre_comp[num], tmp); + smallfelem_neg(ftmp, tmp[1]); /* (X, -Y, Z) is the negative + * point */ + copy_small_conditional(ftmp, tmp[1], (((limb)sign) - 1)); + felem_contract(tmp[1], ftmp); + + if (!skip) { + point_add(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2], mixed, tmp[0], + tmp[1], tmp[2]); + } else { + smallfelem_expand(nq[0], tmp[0]); + smallfelem_expand(nq[1], tmp[1]); + smallfelem_expand(nq[2], tmp[2]); + skip = 0; + } + } + } + } + felem_assign(x_out, nq[0]); + felem_assign(y_out, nq[1]); + felem_assign(z_out, nq[2]); +} + +/* Precomputation for the group generator. */ +typedef struct { + smallfelem g_pre_comp[2][16][3]; +} NISTP256_PRE_COMP; + +/******************************************************************************/ +/* + * OPENSSL EC_METHOD FUNCTIONS + */ + +int ec_GFp_nistp256_group_init(EC_GROUP *group) { + int ret = ec_GFp_simple_group_init(group); + group->a_is_minus3 = 1; + return ret; +} + +int ec_GFp_nistp256_group_set_curve(EC_GROUP *group, const BIGNUM *p, + const BIGNUM *a, const BIGNUM *b, + BN_CTX *ctx) { + int ret = 0; + BN_CTX *new_ctx = NULL; + BIGNUM *curve_p, *curve_a, *curve_b; + + if (ctx == NULL) { + if ((ctx = new_ctx = BN_CTX_new()) == NULL) { + return 0; + } + } + BN_CTX_start(ctx); + if (((curve_p = BN_CTX_get(ctx)) == NULL) || + ((curve_a = BN_CTX_get(ctx)) == NULL) || + ((curve_b = BN_CTX_get(ctx)) == NULL)) { + goto err; + } + BN_bin2bn(nistp256_curve_params[0], sizeof(felem_bytearray), curve_p); + BN_bin2bn(nistp256_curve_params[1], sizeof(felem_bytearray), curve_a); + BN_bin2bn(nistp256_curve_params[2], sizeof(felem_bytearray), curve_b); + if (BN_cmp(curve_p, p) || + BN_cmp(curve_a, a) || + BN_cmp(curve_b, b)) { + OPENSSL_PUT_ERROR(EC, EC_R_WRONG_CURVE_PARAMETERS); + goto err; + } + ret = ec_GFp_simple_group_set_curve(group, p, a, b, ctx); + +err: + BN_CTX_end(ctx); + BN_CTX_free(new_ctx); + return ret; +} + +/* Takes the Jacobian coordinates (X, Y, Z) of a point and returns (X', Y') = + * (X/Z^2, Y/Z^3). */ +int ec_GFp_nistp256_point_get_affine_coordinates(const EC_GROUP *group, + const EC_POINT *point, + BIGNUM *x, BIGNUM *y, + BN_CTX *ctx) { + felem z1, z2, x_in, y_in; + smallfelem x_out, y_out; + longfelem tmp; + + if (EC_POINT_is_at_infinity(group, point)) { + OPENSSL_PUT_ERROR(EC, EC_R_POINT_AT_INFINITY); + return 0; + } + if (!BN_to_felem(x_in, &point->X) || + !BN_to_felem(y_in, &point->Y) || + !BN_to_felem(z1, &point->Z)) { + return 0; + } + felem_inv(z2, z1); + felem_square(tmp, z2); + felem_reduce(z1, tmp); + felem_mul(tmp, x_in, z1); + felem_reduce(x_in, tmp); + felem_contract(x_out, x_in); + if (x != NULL && !smallfelem_to_BN(x, x_out)) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + return 0; + } + felem_mul(tmp, z1, z2); + felem_reduce(z1, tmp); + felem_mul(tmp, y_in, z1); + felem_reduce(y_in, tmp); + felem_contract(y_out, y_in); + if (y != NULL && !smallfelem_to_BN(y, y_out)) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + return 0; + } + return 1; +} + +/* points below is of size |num|, and tmp_smallfelems is of size |num+1| */ +static void make_points_affine(size_t num, smallfelem points[][3], + smallfelem tmp_smallfelems[]) { + /* Runs in constant time, unless an input is the point at infinity (which + * normally shouldn't happen). */ + ec_GFp_nistp_points_make_affine_internal( + num, points, sizeof(smallfelem), tmp_smallfelems, + (void (*)(void *))smallfelem_one, + (int (*)(const void *))smallfelem_is_zero_int, + (void (*)(void *, const void *))smallfelem_assign, + (void (*)(void *, const void *))smallfelem_square_contract, + (void (*)(void *, const void *, const void *))smallfelem_mul_contract, + (void (*)(void *, const void *))smallfelem_inv_contract, + /* nothing to contract */ + (void (*)(void *, const void *))smallfelem_assign); +} + +/* Computes scalar*generator + \sum scalars[i]*points[i], ignoring NULL + * values Result is stored in r (r can equal one of the inputs). */ +int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r, + const BIGNUM *scalar, size_t num, + const EC_POINT *points[], + const BIGNUM *scalars[], BN_CTX *ctx) { + int ret = 0; + int j; + int mixed = 0; + BN_CTX *new_ctx = NULL; + BIGNUM *x, *y, *z, *tmp_scalar; + felem_bytearray g_secret; + felem_bytearray *secrets = NULL; + smallfelem(*pre_comp)[17][3] = NULL; + smallfelem *tmp_smallfelems = NULL; + felem_bytearray tmp; + unsigned i, num_bytes; + int have_pre_comp = 0; + size_t num_points = num; + smallfelem x_in, y_in, z_in; + felem x_out, y_out, z_out; + const smallfelem(*g_pre_comp)[16][3] = NULL; + EC_POINT *generator = NULL; + const EC_POINT *p = NULL; + const BIGNUM *p_scalar = NULL; + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } + } + + BN_CTX_start(ctx); + if ((x = BN_CTX_get(ctx)) == NULL || + (y = BN_CTX_get(ctx)) == NULL || + (z = BN_CTX_get(ctx)) == NULL || + (tmp_scalar = BN_CTX_get(ctx)) == NULL) { + goto err; + } + + if (scalar != NULL) { + /* try to use the standard precomputation */ + g_pre_comp = &gmul[0]; + generator = EC_POINT_new(group); + if (generator == NULL) { + goto err; + } + /* get the generator from precomputation */ + if (!smallfelem_to_BN(x, g_pre_comp[0][1][0]) || + !smallfelem_to_BN(y, g_pre_comp[0][1][1]) || + !smallfelem_to_BN(z, g_pre_comp[0][1][2])) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + goto err; + } + if (!ec_point_set_Jprojective_coordinates_GFp(group, generator, x, y, z, + ctx)) { + goto err; + } + if (0 == EC_POINT_cmp(group, generator, group->generator, ctx)) { + /* precomputation matches generator */ + have_pre_comp = 1; + } else { + /* we don't have valid precomputation: treat the generator as a + * random point. */ + num_points++; + } + } + + if (num_points > 0) { + if (num_points >= 3) { + /* unless we precompute multiples for just one or two points, + * converting those into affine form is time well spent */ + mixed = 1; + } + secrets = OPENSSL_malloc(num_points * sizeof(felem_bytearray)); + pre_comp = OPENSSL_malloc(num_points * 17 * 3 * sizeof(smallfelem)); + if (mixed) { + tmp_smallfelems = + OPENSSL_malloc((num_points * 17 + 1) * sizeof(smallfelem)); + } + if (secrets == NULL || pre_comp == NULL || + (mixed && tmp_smallfelems == NULL)) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* we treat NULL scalars as 0, and NULL points as points at infinity, + * i.e., they contribute nothing to the linear combination. */ + memset(secrets, 0, num_points * sizeof(felem_bytearray)); + memset(pre_comp, 0, num_points * 17 * 3 * sizeof(smallfelem)); + for (i = 0; i < num_points; ++i) { + if (i == num) { + /* we didn't have a valid precomputation, so we pick the generator. */ + p = EC_GROUP_get0_generator(group); + p_scalar = scalar; + } else { + /* the i^th point */ + p = points[i]; + p_scalar = scalars[i]; + } + if (p_scalar != NULL && p != NULL) { + /* reduce scalar to 0 <= scalar < 2^256 */ + if (BN_num_bits(p_scalar) > 256 || BN_is_negative(p_scalar)) { + /* this is an unusual input, and we don't guarantee + * constant-timeness. */ + if (!BN_nnmod(tmp_scalar, p_scalar, &group->order, ctx)) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + goto err; + } + num_bytes = BN_bn2bin(tmp_scalar, tmp); + } else { + num_bytes = BN_bn2bin(p_scalar, tmp); + } + flip_endian(secrets[i], tmp, num_bytes); + /* precompute multiples */ + if (!BN_to_felem(x_out, &p->X) || + !BN_to_felem(y_out, &p->Y) || + !BN_to_felem(z_out, &p->Z)) { + goto err; + } + felem_shrink(pre_comp[i][1][0], x_out); + felem_shrink(pre_comp[i][1][1], y_out); + felem_shrink(pre_comp[i][1][2], z_out); + for (j = 2; j <= 16; ++j) { + if (j & 1) { + point_add_small(pre_comp[i][j][0], pre_comp[i][j][1], + pre_comp[i][j][2], pre_comp[i][1][0], + pre_comp[i][1][1], pre_comp[i][1][2], + pre_comp[i][j - 1][0], pre_comp[i][j - 1][1], + pre_comp[i][j - 1][2]); + } else { + point_double_small(pre_comp[i][j][0], pre_comp[i][j][1], + pre_comp[i][j][2], pre_comp[i][j / 2][0], + pre_comp[i][j / 2][1], pre_comp[i][j / 2][2]); + } + } + } + } + if (mixed) { + make_points_affine(num_points * 17, pre_comp[0], tmp_smallfelems); + } + } + + /* the scalar for the generator */ + if (scalar != NULL && have_pre_comp) { + memset(g_secret, 0, sizeof(g_secret)); + /* reduce scalar to 0 <= scalar < 2^256 */ + if (BN_num_bits(scalar) > 256 || BN_is_negative(scalar)) { + /* this is an unusual input, and we don't guarantee + * constant-timeness. */ + if (!BN_nnmod(tmp_scalar, scalar, &group->order, ctx)) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + goto err; + } + num_bytes = BN_bn2bin(tmp_scalar, tmp); + } else { + num_bytes = BN_bn2bin(scalar, tmp); + } + flip_endian(g_secret, tmp, num_bytes); + /* do the multiplication with generator precomputation */ + batch_mul(x_out, y_out, z_out, (const felem_bytearray(*))secrets, + num_points, g_secret, mixed, (const smallfelem(*)[17][3])pre_comp, + g_pre_comp); + } else { + /* do the multiplication without generator precomputation */ + batch_mul(x_out, y_out, z_out, (const felem_bytearray(*))secrets, + num_points, NULL, mixed, (const smallfelem(*)[17][3])pre_comp, + NULL); + } + + /* reduce the output to its unique minimal representation */ + felem_contract(x_in, x_out); + felem_contract(y_in, y_out); + felem_contract(z_in, z_out); + if (!smallfelem_to_BN(x, x_in) || + !smallfelem_to_BN(y, y_in) || + !smallfelem_to_BN(z, z_in)) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + goto err; + } + ret = ec_point_set_Jprojective_coordinates_GFp(group, r, x, y, z, ctx); + +err: + BN_CTX_end(ctx); + EC_POINT_free(generator); + BN_CTX_free(new_ctx); + OPENSSL_free(secrets); + OPENSSL_free(pre_comp); + OPENSSL_free(tmp_smallfelems); + return ret; +} + +const EC_METHOD *EC_GFp_nistp256_method(void) { + static const EC_METHOD ret = { + EC_FLAGS_DEFAULT_OCT, + ec_GFp_nistp256_group_init, + ec_GFp_simple_group_finish, + ec_GFp_simple_group_clear_finish, + ec_GFp_simple_group_copy, ec_GFp_nistp256_group_set_curve, + ec_GFp_simple_group_get_curve, ec_GFp_simple_group_get_degree, + ec_GFp_simple_group_check_discriminant, ec_GFp_simple_point_init, + ec_GFp_simple_point_finish, ec_GFp_simple_point_clear_finish, + ec_GFp_simple_point_copy, ec_GFp_simple_point_set_to_infinity, + ec_GFp_simple_set_Jprojective_coordinates_GFp, + ec_GFp_simple_get_Jprojective_coordinates_GFp, + ec_GFp_simple_point_set_affine_coordinates, + ec_GFp_nistp256_point_get_affine_coordinates, + 0 /* point_set_compressed_coordinates */, 0 /* point2oct */, + 0 /* oct2point */, ec_GFp_simple_add, ec_GFp_simple_dbl, + ec_GFp_simple_invert, ec_GFp_simple_is_at_infinity, + ec_GFp_simple_is_on_curve, ec_GFp_simple_cmp, ec_GFp_simple_make_affine, + ec_GFp_simple_points_make_affine, ec_GFp_nistp256_points_mul, + 0 /* precompute_mult */, 0 /* have_precompute_mult */, + ec_GFp_simple_field_mul, ec_GFp_simple_field_sqr, 0 /* field_div */, + 0 /* field_encode */, 0 /* field_decode */, 0 /* field_set_to_one */ + }; + + return &ret; +} + +#endif /* 64_BIT && !WINDOWS */ diff --git a/TMessagesProj/jni/boringssl/crypto/ec/simple.c b/TMessagesProj/jni/boringssl/crypto/ec/simple.c new file mode 100644 index 00000000..c62199c1 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ec/simple.c @@ -0,0 +1,1357 @@ +/* Originally written by Bodo Moeller for the OpenSSL project. + * ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * The elliptic curve binary polynomial software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems + * Laboratories. */ + +#include + +#include + +#include +#include +#include + +#include "internal.h" + + +const EC_METHOD *EC_GFp_simple_method(void) { + static const EC_METHOD ret = {EC_FLAGS_DEFAULT_OCT, + ec_GFp_simple_group_init, + ec_GFp_simple_group_finish, + ec_GFp_simple_group_clear_finish, + ec_GFp_simple_group_copy, + ec_GFp_simple_group_set_curve, + ec_GFp_simple_group_get_curve, + ec_GFp_simple_group_get_degree, + ec_GFp_simple_group_check_discriminant, + ec_GFp_simple_point_init, + ec_GFp_simple_point_finish, + ec_GFp_simple_point_clear_finish, + ec_GFp_simple_point_copy, + ec_GFp_simple_point_set_to_infinity, + ec_GFp_simple_set_Jprojective_coordinates_GFp, + ec_GFp_simple_get_Jprojective_coordinates_GFp, + ec_GFp_simple_point_set_affine_coordinates, + ec_GFp_simple_point_get_affine_coordinates, + 0, + 0, + 0, + ec_GFp_simple_add, + ec_GFp_simple_dbl, + ec_GFp_simple_invert, + ec_GFp_simple_is_at_infinity, + ec_GFp_simple_is_on_curve, + ec_GFp_simple_cmp, + ec_GFp_simple_make_affine, + ec_GFp_simple_points_make_affine, + 0 /* mul */, + 0 /* precompute_mult */, + 0 /* have_precompute_mult */, + ec_GFp_simple_field_mul, + ec_GFp_simple_field_sqr, + 0 /* field_div */, + 0 /* field_encode */, + 0 /* field_decode */, + 0 /* field_set_to_one */}; + + return &ret; +} + + +/* Most method functions in this file are designed to work with non-trivial + * representations of field elements if necessary (see ecp_mont.c): while + * standard modular addition and subtraction are used, the field_mul and + * field_sqr methods will be used for multiplication, and field_encode and + * field_decode (if defined) will be used for converting between + * representations. + + * Functions ec_GFp_simple_points_make_affine() and + * ec_GFp_simple_point_get_affine_coordinates() specifically assume that if a + * non-trivial representation is used, it is a Montgomery representation (i.e. + * 'encoding' means multiplying by some factor R). */ + +int ec_GFp_simple_group_init(EC_GROUP *group) { + BN_init(&group->field); + BN_init(&group->a); + BN_init(&group->b); + group->a_is_minus3 = 0; + return 1; +} + +void ec_GFp_simple_group_finish(EC_GROUP *group) { + BN_free(&group->field); + BN_free(&group->a); + BN_free(&group->b); +} + +void ec_GFp_simple_group_clear_finish(EC_GROUP *group) { + BN_clear_free(&group->field); + BN_clear_free(&group->a); + BN_clear_free(&group->b); +} + +int ec_GFp_simple_group_copy(EC_GROUP *dest, const EC_GROUP *src) { + if (!BN_copy(&dest->field, &src->field) || + !BN_copy(&dest->a, &src->a) || + !BN_copy(&dest->b, &src->b)) { + return 0; + } + + dest->a_is_minus3 = src->a_is_minus3; + return 1; +} + +int ec_GFp_simple_group_set_curve(EC_GROUP *group, const BIGNUM *p, + const BIGNUM *a, const BIGNUM *b, + BN_CTX *ctx) { + int ret = 0; + BN_CTX *new_ctx = NULL; + BIGNUM *tmp_a; + + /* p must be a prime > 3 */ + if (BN_num_bits(p) <= 2 || !BN_is_odd(p)) { + OPENSSL_PUT_ERROR(EC, EC_R_INVALID_FIELD); + return 0; + } + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } + } + + BN_CTX_start(ctx); + tmp_a = BN_CTX_get(ctx); + if (tmp_a == NULL) { + goto err; + } + + /* group->field */ + if (!BN_copy(&group->field, p)) { + goto err; + } + BN_set_negative(&group->field, 0); + + /* group->a */ + if (!BN_nnmod(tmp_a, a, p, ctx)) { + goto err; + } + if (group->meth->field_encode) { + if (!group->meth->field_encode(group, &group->a, tmp_a, ctx)) { + goto err; + } + } else if (!BN_copy(&group->a, tmp_a)) { + goto err; + } + + /* group->b */ + if (!BN_nnmod(&group->b, b, p, ctx)) { + goto err; + } + if (group->meth->field_encode && + !group->meth->field_encode(group, &group->b, &group->b, ctx)) { + goto err; + } + + /* group->a_is_minus3 */ + if (!BN_add_word(tmp_a, 3)) { + goto err; + } + group->a_is_minus3 = (0 == BN_cmp(tmp_a, &group->field)); + + ret = 1; + +err: + BN_CTX_end(ctx); + BN_CTX_free(new_ctx); + return ret; +} + +int ec_GFp_simple_group_get_curve(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, + BIGNUM *b, BN_CTX *ctx) { + int ret = 0; + BN_CTX *new_ctx = NULL; + + if (p != NULL && !BN_copy(p, &group->field)) { + return 0; + } + + if (a != NULL || b != NULL) { + if (group->meth->field_decode) { + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } + } + if (a != NULL && !group->meth->field_decode(group, a, &group->a, ctx)) { + goto err; + } + if (b != NULL && !group->meth->field_decode(group, b, &group->b, ctx)) { + goto err; + } + } else { + if (a != NULL && !BN_copy(a, &group->a)) { + goto err; + } + if (b != NULL && !BN_copy(b, &group->b)) { + goto err; + } + } + } + + ret = 1; + +err: + BN_CTX_free(new_ctx); + return ret; +} + +int ec_GFp_simple_group_get_degree(const EC_GROUP *group) { + return BN_num_bits(&group->field); +} + +int ec_GFp_simple_group_check_discriminant(const EC_GROUP *group, BN_CTX *ctx) { + int ret = 0; + BIGNUM *a, *b, *order, *tmp_1, *tmp_2; + const BIGNUM *p = &group->field; + BN_CTX *new_ctx = NULL; + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + goto err; + } + } + BN_CTX_start(ctx); + a = BN_CTX_get(ctx); + b = BN_CTX_get(ctx); + tmp_1 = BN_CTX_get(ctx); + tmp_2 = BN_CTX_get(ctx); + order = BN_CTX_get(ctx); + if (order == NULL) { + goto err; + } + + if (group->meth->field_decode) { + if (!group->meth->field_decode(group, a, &group->a, ctx) || + !group->meth->field_decode(group, b, &group->b, ctx)) { + goto err; + } + } else { + if (!BN_copy(a, &group->a) || !BN_copy(b, &group->b)) { + goto err; + } + } + + /* check the discriminant: + * y^2 = x^3 + a*x + b is an elliptic curve <=> 4*a^3 + 27*b^2 != 0 (mod p) + * 0 =< a, b < p */ + if (BN_is_zero(a)) { + if (BN_is_zero(b)) { + goto err; + } + } else if (!BN_is_zero(b)) { + if (!BN_mod_sqr(tmp_1, a, p, ctx) || + !BN_mod_mul(tmp_2, tmp_1, a, p, ctx) || + !BN_lshift(tmp_1, tmp_2, 2)) { + goto err; + } + /* tmp_1 = 4*a^3 */ + + if (!BN_mod_sqr(tmp_2, b, p, ctx) || + !BN_mul_word(tmp_2, 27)) { + goto err; + } + /* tmp_2 = 27*b^2 */ + + if (!BN_mod_add(a, tmp_1, tmp_2, p, ctx) || + BN_is_zero(a)) { + goto err; + } + } + ret = 1; + +err: + if (ctx != NULL) { + BN_CTX_end(ctx); + } + BN_CTX_free(new_ctx); + return ret; +} + +int ec_GFp_simple_point_init(EC_POINT *point) { + BN_init(&point->X); + BN_init(&point->Y); + BN_init(&point->Z); + point->Z_is_one = 0; + + return 1; +} + +void ec_GFp_simple_point_finish(EC_POINT *point) { + BN_free(&point->X); + BN_free(&point->Y); + BN_free(&point->Z); +} + +void ec_GFp_simple_point_clear_finish(EC_POINT *point) { + BN_clear_free(&point->X); + BN_clear_free(&point->Y); + BN_clear_free(&point->Z); + point->Z_is_one = 0; +} + +int ec_GFp_simple_point_copy(EC_POINT *dest, const EC_POINT *src) { + if (!BN_copy(&dest->X, &src->X) || + !BN_copy(&dest->Y, &src->Y) || + !BN_copy(&dest->Z, &src->Z)) { + return 0; + } + dest->Z_is_one = src->Z_is_one; + + return 1; +} + +int ec_GFp_simple_point_set_to_infinity(const EC_GROUP *group, + EC_POINT *point) { + point->Z_is_one = 0; + BN_zero(&point->Z); + return 1; +} + +int ec_GFp_simple_set_Jprojective_coordinates_GFp( + const EC_GROUP *group, EC_POINT *point, const BIGNUM *x, const BIGNUM *y, + const BIGNUM *z, BN_CTX *ctx) { + BN_CTX *new_ctx = NULL; + int ret = 0; + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } + } + + if (x != NULL) { + if (!BN_nnmod(&point->X, x, &group->field, ctx)) { + goto err; + } + if (group->meth->field_encode && + !group->meth->field_encode(group, &point->X, &point->X, ctx)) { + goto err; + } + } + + if (y != NULL) { + if (!BN_nnmod(&point->Y, y, &group->field, ctx)) { + goto err; + } + if (group->meth->field_encode && + !group->meth->field_encode(group, &point->Y, &point->Y, ctx)) { + goto err; + } + } + + if (z != NULL) { + int Z_is_one; + + if (!BN_nnmod(&point->Z, z, &group->field, ctx)) { + goto err; + } + Z_is_one = BN_is_one(&point->Z); + if (group->meth->field_encode) { + if (Z_is_one && (group->meth->field_set_to_one != 0)) { + if (!group->meth->field_set_to_one(group, &point->Z, ctx)) { + goto err; + } + } else if (!group->meth->field_encode(group, &point->Z, &point->Z, ctx)) { + goto err; + } + } + point->Z_is_one = Z_is_one; + } + + ret = 1; + +err: + BN_CTX_free(new_ctx); + return ret; +} + +int ec_GFp_simple_get_Jprojective_coordinates_GFp(const EC_GROUP *group, + const EC_POINT *point, + BIGNUM *x, BIGNUM *y, + BIGNUM *z, BN_CTX *ctx) { + BN_CTX *new_ctx = NULL; + int ret = 0; + + if (group->meth->field_decode != 0) { + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } + } + + if (x != NULL && !group->meth->field_decode(group, x, &point->X, ctx)) { + goto err; + } + if (y != NULL && !group->meth->field_decode(group, y, &point->Y, ctx)) { + goto err; + } + if (z != NULL && !group->meth->field_decode(group, z, &point->Z, ctx)) { + goto err; + } + } else { + if (x != NULL && !BN_copy(x, &point->X)) { + goto err; + } + if (y != NULL && !BN_copy(y, &point->Y)) { + goto err; + } + if (z != NULL && !BN_copy(z, &point->Z)) { + goto err; + } + } + + ret = 1; + +err: + BN_CTX_free(new_ctx); + return ret; +} + +int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *group, + EC_POINT *point, const BIGNUM *x, + const BIGNUM *y, BN_CTX *ctx) { + if (x == NULL || y == NULL) { + /* unlike for projective coordinates, we do not tolerate this */ + OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + return ec_point_set_Jprojective_coordinates_GFp(group, point, x, y, + BN_value_one(), ctx); +} + +int ec_GFp_simple_point_get_affine_coordinates(const EC_GROUP *group, + const EC_POINT *point, BIGNUM *x, + BIGNUM *y, BN_CTX *ctx) { + BN_CTX *new_ctx = NULL; + BIGNUM *Z, *Z_1, *Z_2, *Z_3; + const BIGNUM *Z_; + int ret = 0; + + if (EC_POINT_is_at_infinity(group, point)) { + OPENSSL_PUT_ERROR(EC, EC_R_POINT_AT_INFINITY); + return 0; + } + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } + } + + BN_CTX_start(ctx); + Z = BN_CTX_get(ctx); + Z_1 = BN_CTX_get(ctx); + Z_2 = BN_CTX_get(ctx); + Z_3 = BN_CTX_get(ctx); + if (Z == NULL || Z_1 == NULL || Z_2 == NULL || Z_3 == NULL) { + goto err; + } + + /* transform (X, Y, Z) into (x, y) := (X/Z^2, Y/Z^3) */ + + if (group->meth->field_decode) { + if (!group->meth->field_decode(group, Z, &point->Z, ctx)) { + goto err; + } + Z_ = Z; + } else { + Z_ = &point->Z; + } + + if (BN_is_one(Z_)) { + if (group->meth->field_decode) { + if (x != NULL && !group->meth->field_decode(group, x, &point->X, ctx)) { + goto err; + } + if (y != NULL && !group->meth->field_decode(group, y, &point->Y, ctx)) { + goto err; + } + } else { + if (x != NULL && !BN_copy(x, &point->X)) { + goto err; + } + if (y != NULL && !BN_copy(y, &point->Y)) { + goto err; + } + } + } else { + if (!BN_mod_inverse(Z_1, Z_, &group->field, ctx)) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + goto err; + } + + if (group->meth->field_encode == 0) { + /* field_sqr works on standard representation */ + if (!group->meth->field_sqr(group, Z_2, Z_1, ctx)) { + goto err; + } + } else if (!BN_mod_sqr(Z_2, Z_1, &group->field, ctx)) { + goto err; + } + + /* in the Montgomery case, field_mul will cancel out Montgomery factor in + * X: */ + if (x != NULL && !group->meth->field_mul(group, x, &point->X, Z_2, ctx)) { + goto err; + } + + if (y != NULL) { + if (group->meth->field_encode == 0) { + /* field_mul works on standard representation */ + if (!group->meth->field_mul(group, Z_3, Z_2, Z_1, ctx)) { + goto err; + } + } else if (!BN_mod_mul(Z_3, Z_2, Z_1, &group->field, ctx)) { + goto err; + } + + /* in the Montgomery case, field_mul will cancel out Montgomery factor in + * Y: */ + if (!group->meth->field_mul(group, y, &point->Y, Z_3, ctx)) { + goto err; + } + } + } + + ret = 1; + +err: + BN_CTX_end(ctx); + BN_CTX_free(new_ctx); + return ret; +} + +int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, + const EC_POINT *b, BN_CTX *ctx) { + int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, + BN_CTX *); + int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); + const BIGNUM *p; + BN_CTX *new_ctx = NULL; + BIGNUM *n0, *n1, *n2, *n3, *n4, *n5, *n6; + int ret = 0; + + if (a == b) { + return EC_POINT_dbl(group, r, a, ctx); + } + if (EC_POINT_is_at_infinity(group, a)) { + return EC_POINT_copy(r, b); + } + if (EC_POINT_is_at_infinity(group, b)) { + return EC_POINT_copy(r, a); + } + + field_mul = group->meth->field_mul; + field_sqr = group->meth->field_sqr; + p = &group->field; + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } + } + + BN_CTX_start(ctx); + n0 = BN_CTX_get(ctx); + n1 = BN_CTX_get(ctx); + n2 = BN_CTX_get(ctx); + n3 = BN_CTX_get(ctx); + n4 = BN_CTX_get(ctx); + n5 = BN_CTX_get(ctx); + n6 = BN_CTX_get(ctx); + if (n6 == NULL) { + goto end; + } + + /* Note that in this function we must not read components of 'a' or 'b' + * once we have written the corresponding components of 'r'. + * ('r' might be one of 'a' or 'b'.) + */ + + /* n1, n2 */ + if (b->Z_is_one) { + if (!BN_copy(n1, &a->X) || !BN_copy(n2, &a->Y)) { + goto end; + } + /* n1 = X_a */ + /* n2 = Y_a */ + } else { + if (!field_sqr(group, n0, &b->Z, ctx) || + !field_mul(group, n1, &a->X, n0, ctx)) { + goto end; + } + /* n1 = X_a * Z_b^2 */ + + if (!field_mul(group, n0, n0, &b->Z, ctx) || + !field_mul(group, n2, &a->Y, n0, ctx)) { + goto end; + } + /* n2 = Y_a * Z_b^3 */ + } + + /* n3, n4 */ + if (a->Z_is_one) { + if (!BN_copy(n3, &b->X) || !BN_copy(n4, &b->Y)) { + goto end; + } + /* n3 = X_b */ + /* n4 = Y_b */ + } else { + if (!field_sqr(group, n0, &a->Z, ctx) || + !field_mul(group, n3, &b->X, n0, ctx)) { + goto end; + } + /* n3 = X_b * Z_a^2 */ + + if (!field_mul(group, n0, n0, &a->Z, ctx) || + !field_mul(group, n4, &b->Y, n0, ctx)) { + goto end; + } + /* n4 = Y_b * Z_a^3 */ + } + + /* n5, n6 */ + if (!BN_mod_sub_quick(n5, n1, n3, p) || + !BN_mod_sub_quick(n6, n2, n4, p)) { + goto end; + } + /* n5 = n1 - n3 */ + /* n6 = n2 - n4 */ + + if (BN_is_zero(n5)) { + if (BN_is_zero(n6)) { + /* a is the same point as b */ + BN_CTX_end(ctx); + ret = EC_POINT_dbl(group, r, a, ctx); + ctx = NULL; + goto end; + } else { + /* a is the inverse of b */ + BN_zero(&r->Z); + r->Z_is_one = 0; + ret = 1; + goto end; + } + } + + /* 'n7', 'n8' */ + if (!BN_mod_add_quick(n1, n1, n3, p) || + !BN_mod_add_quick(n2, n2, n4, p)) { + goto end; + } + /* 'n7' = n1 + n3 */ + /* 'n8' = n2 + n4 */ + + /* Z_r */ + if (a->Z_is_one && b->Z_is_one) { + if (!BN_copy(&r->Z, n5)) { + goto end; + } + } else { + if (a->Z_is_one) { + if (!BN_copy(n0, &b->Z)) { + goto end; + } + } else if (b->Z_is_one) { + if (!BN_copy(n0, &a->Z)) { + goto end; + } + } else if (!field_mul(group, n0, &a->Z, &b->Z, ctx)) { + goto end; + } + if (!field_mul(group, &r->Z, n0, n5, ctx)) { + goto end; + } + } + r->Z_is_one = 0; + /* Z_r = Z_a * Z_b * n5 */ + + /* X_r */ + if (!field_sqr(group, n0, n6, ctx) || + !field_sqr(group, n4, n5, ctx) || + !field_mul(group, n3, n1, n4, ctx) || + !BN_mod_sub_quick(&r->X, n0, n3, p)) { + goto end; + } + /* X_r = n6^2 - n5^2 * 'n7' */ + + /* 'n9' */ + if (!BN_mod_lshift1_quick(n0, &r->X, p) || + !BN_mod_sub_quick(n0, n3, n0, p)) { + goto end; + } + /* n9 = n5^2 * 'n7' - 2 * X_r */ + + /* Y_r */ + if (!field_mul(group, n0, n0, n6, ctx) || + !field_mul(group, n5, n4, n5, ctx)) { + goto end; /* now n5 is n5^3 */ + } + if (!field_mul(group, n1, n2, n5, ctx) || + !BN_mod_sub_quick(n0, n0, n1, p)) { + goto end; + } + if (BN_is_odd(n0) && !BN_add(n0, n0, p)) { + goto end; + } + /* now 0 <= n0 < 2*p, and n0 is even */ + if (!BN_rshift1(&r->Y, n0)) { + goto end; + } + /* Y_r = (n6 * 'n9' - 'n8' * 'n5^3') / 2 */ + + ret = 1; + +end: + if (ctx) { + /* otherwise we already called BN_CTX_end */ + BN_CTX_end(ctx); + } + BN_CTX_free(new_ctx); + return ret; +} + +int ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, + BN_CTX *ctx) { + int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, + BN_CTX *); + int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); + const BIGNUM *p; + BN_CTX *new_ctx = NULL; + BIGNUM *n0, *n1, *n2, *n3; + int ret = 0; + + if (EC_POINT_is_at_infinity(group, a)) { + BN_zero(&r->Z); + r->Z_is_one = 0; + return 1; + } + + field_mul = group->meth->field_mul; + field_sqr = group->meth->field_sqr; + p = &group->field; + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } + } + + BN_CTX_start(ctx); + n0 = BN_CTX_get(ctx); + n1 = BN_CTX_get(ctx); + n2 = BN_CTX_get(ctx); + n3 = BN_CTX_get(ctx); + if (n3 == NULL) { + goto err; + } + + /* Note that in this function we must not read components of 'a' + * once we have written the corresponding components of 'r'. + * ('r' might the same as 'a'.) + */ + + /* n1 */ + if (a->Z_is_one) { + if (!field_sqr(group, n0, &a->X, ctx) || + !BN_mod_lshift1_quick(n1, n0, p) || + !BN_mod_add_quick(n0, n0, n1, p) || + !BN_mod_add_quick(n1, n0, &group->a, p)) { + goto err; + } + /* n1 = 3 * X_a^2 + a_curve */ + } else if (group->a_is_minus3) { + if (!field_sqr(group, n1, &a->Z, ctx) || + !BN_mod_add_quick(n0, &a->X, n1, p) || + !BN_mod_sub_quick(n2, &a->X, n1, p) || + !field_mul(group, n1, n0, n2, ctx) || + !BN_mod_lshift1_quick(n0, n1, p) || + !BN_mod_add_quick(n1, n0, n1, p)) { + goto err; + } + /* n1 = 3 * (X_a + Z_a^2) * (X_a - Z_a^2) + * = 3 * X_a^2 - 3 * Z_a^4 */ + } else { + if (!field_sqr(group, n0, &a->X, ctx) || + !BN_mod_lshift1_quick(n1, n0, p) || + !BN_mod_add_quick(n0, n0, n1, p) || + !field_sqr(group, n1, &a->Z, ctx) || + !field_sqr(group, n1, n1, ctx) || + !field_mul(group, n1, n1, &group->a, ctx) || + !BN_mod_add_quick(n1, n1, n0, p)) { + goto err; + } + /* n1 = 3 * X_a^2 + a_curve * Z_a^4 */ + } + + /* Z_r */ + if (a->Z_is_one) { + if (!BN_copy(n0, &a->Y)) { + goto err; + } + } else if (!field_mul(group, n0, &a->Y, &a->Z, ctx)) { + goto err; + } + if (!BN_mod_lshift1_quick(&r->Z, n0, p)) { + goto err; + } + r->Z_is_one = 0; + /* Z_r = 2 * Y_a * Z_a */ + + /* n2 */ + if (!field_sqr(group, n3, &a->Y, ctx) || + !field_mul(group, n2, &a->X, n3, ctx) || + !BN_mod_lshift_quick(n2, n2, 2, p)) { + goto err; + } + /* n2 = 4 * X_a * Y_a^2 */ + + /* X_r */ + if (!BN_mod_lshift1_quick(n0, n2, p) || + !field_sqr(group, &r->X, n1, ctx) || + !BN_mod_sub_quick(&r->X, &r->X, n0, p)) { + goto err; + } + /* X_r = n1^2 - 2 * n2 */ + + /* n3 */ + if (!field_sqr(group, n0, n3, ctx) || + !BN_mod_lshift_quick(n3, n0, 3, p)) { + goto err; + } + /* n3 = 8 * Y_a^4 */ + + /* Y_r */ + if (!BN_mod_sub_quick(n0, n2, &r->X, p) || + !field_mul(group, n0, n1, n0, ctx) || + !BN_mod_sub_quick(&r->Y, n0, n3, p)) { + goto err; + } + /* Y_r = n1 * (n2 - X_r) - n3 */ + + ret = 1; + +err: + BN_CTX_end(ctx); + BN_CTX_free(new_ctx); + return ret; +} + +int ec_GFp_simple_invert(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx) { + if (EC_POINT_is_at_infinity(group, point) || BN_is_zero(&point->Y)) { + /* point is its own inverse */ + return 1; + } + + return BN_usub(&point->Y, &group->field, &point->Y); +} + +int ec_GFp_simple_is_at_infinity(const EC_GROUP *group, const EC_POINT *point) { + return !point->Z_is_one && BN_is_zero(&point->Z); +} + +int ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point, + BN_CTX *ctx) { + int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, + BN_CTX *); + int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); + const BIGNUM *p; + BN_CTX *new_ctx = NULL; + BIGNUM *rh, *tmp, *Z4, *Z6; + int ret = -1; + + if (EC_POINT_is_at_infinity(group, point)) { + return 1; + } + + field_mul = group->meth->field_mul; + field_sqr = group->meth->field_sqr; + p = &group->field; + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return -1; + } + } + + BN_CTX_start(ctx); + rh = BN_CTX_get(ctx); + tmp = BN_CTX_get(ctx); + Z4 = BN_CTX_get(ctx); + Z6 = BN_CTX_get(ctx); + if (Z6 == NULL) { + goto err; + } + + /* We have a curve defined by a Weierstrass equation + * y^2 = x^3 + a*x + b. + * The point to consider is given in Jacobian projective coordinates + * where (X, Y, Z) represents (x, y) = (X/Z^2, Y/Z^3). + * Substituting this and multiplying by Z^6 transforms the above equation + * into + * Y^2 = X^3 + a*X*Z^4 + b*Z^6. + * To test this, we add up the right-hand side in 'rh'. + */ + + /* rh := X^2 */ + if (!field_sqr(group, rh, &point->X, ctx)) { + goto err; + } + + if (!point->Z_is_one) { + if (!field_sqr(group, tmp, &point->Z, ctx) || + !field_sqr(group, Z4, tmp, ctx) || + !field_mul(group, Z6, Z4, tmp, ctx)) { + goto err; + } + + /* rh := (rh + a*Z^4)*X */ + if (group->a_is_minus3) { + if (!BN_mod_lshift1_quick(tmp, Z4, p) || + !BN_mod_add_quick(tmp, tmp, Z4, p) || + !BN_mod_sub_quick(rh, rh, tmp, p) || + !field_mul(group, rh, rh, &point->X, ctx)) { + goto err; + } + } else { + if (!field_mul(group, tmp, Z4, &group->a, ctx) || + !BN_mod_add_quick(rh, rh, tmp, p) || + !field_mul(group, rh, rh, &point->X, ctx)) { + goto err; + } + } + + /* rh := rh + b*Z^6 */ + if (!field_mul(group, tmp, &group->b, Z6, ctx) || + !BN_mod_add_quick(rh, rh, tmp, p)) { + goto err; + } + } else { + /* point->Z_is_one */ + + /* rh := (rh + a)*X */ + if (!BN_mod_add_quick(rh, rh, &group->a, p) || + !field_mul(group, rh, rh, &point->X, ctx)) { + goto err; + } + /* rh := rh + b */ + if (!BN_mod_add_quick(rh, rh, &group->b, p)) { + goto err; + } + } + + /* 'lh' := Y^2 */ + if (!field_sqr(group, tmp, &point->Y, ctx)) { + goto err; + } + + ret = (0 == BN_ucmp(tmp, rh)); + +err: + BN_CTX_end(ctx); + BN_CTX_free(new_ctx); + return ret; +} + +int ec_GFp_simple_cmp(const EC_GROUP *group, const EC_POINT *a, + const EC_POINT *b, BN_CTX *ctx) { + /* return values: + * -1 error + * 0 equal (in affine coordinates) + * 1 not equal + */ + + int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, + BN_CTX *); + int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); + BN_CTX *new_ctx = NULL; + BIGNUM *tmp1, *tmp2, *Za23, *Zb23; + const BIGNUM *tmp1_, *tmp2_; + int ret = -1; + + if (EC_POINT_is_at_infinity(group, a)) { + return EC_POINT_is_at_infinity(group, b) ? 0 : 1; + } + + if (EC_POINT_is_at_infinity(group, b)) { + return 1; + } + + if (a->Z_is_one && b->Z_is_one) { + return ((BN_cmp(&a->X, &b->X) == 0) && BN_cmp(&a->Y, &b->Y) == 0) ? 0 : 1; + } + + field_mul = group->meth->field_mul; + field_sqr = group->meth->field_sqr; + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return -1; + } + } + + BN_CTX_start(ctx); + tmp1 = BN_CTX_get(ctx); + tmp2 = BN_CTX_get(ctx); + Za23 = BN_CTX_get(ctx); + Zb23 = BN_CTX_get(ctx); + if (Zb23 == NULL) { + goto end; + } + + /* We have to decide whether + * (X_a/Z_a^2, Y_a/Z_a^3) = (X_b/Z_b^2, Y_b/Z_b^3), + * or equivalently, whether + * (X_a*Z_b^2, Y_a*Z_b^3) = (X_b*Z_a^2, Y_b*Z_a^3). + */ + + if (!b->Z_is_one) { + if (!field_sqr(group, Zb23, &b->Z, ctx) || + !field_mul(group, tmp1, &a->X, Zb23, ctx)) { + goto end; + } + tmp1_ = tmp1; + } else { + tmp1_ = &a->X; + } + if (!a->Z_is_one) { + if (!field_sqr(group, Za23, &a->Z, ctx) || + !field_mul(group, tmp2, &b->X, Za23, ctx)) { + goto end; + } + tmp2_ = tmp2; + } else { + tmp2_ = &b->X; + } + + /* compare X_a*Z_b^2 with X_b*Z_a^2 */ + if (BN_cmp(tmp1_, tmp2_) != 0) { + ret = 1; /* points differ */ + goto end; + } + + + if (!b->Z_is_one) { + if (!field_mul(group, Zb23, Zb23, &b->Z, ctx) || + !field_mul(group, tmp1, &a->Y, Zb23, ctx)) { + goto end; + } + /* tmp1_ = tmp1 */ + } else { + tmp1_ = &a->Y; + } + if (!a->Z_is_one) { + if (!field_mul(group, Za23, Za23, &a->Z, ctx) || + !field_mul(group, tmp2, &b->Y, Za23, ctx)) { + goto end; + } + /* tmp2_ = tmp2 */ + } else { + tmp2_ = &b->Y; + } + + /* compare Y_a*Z_b^3 with Y_b*Z_a^3 */ + if (BN_cmp(tmp1_, tmp2_) != 0) { + ret = 1; /* points differ */ + goto end; + } + + /* points are equal */ + ret = 0; + +end: + BN_CTX_end(ctx); + BN_CTX_free(new_ctx); + return ret; +} + +int ec_GFp_simple_make_affine(const EC_GROUP *group, EC_POINT *point, + BN_CTX *ctx) { + BN_CTX *new_ctx = NULL; + BIGNUM *x, *y; + int ret = 0; + + if (point->Z_is_one || EC_POINT_is_at_infinity(group, point)) { + return 1; + } + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } + } + + BN_CTX_start(ctx); + x = BN_CTX_get(ctx); + y = BN_CTX_get(ctx); + if (y == NULL) { + goto err; + } + + if (!EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx) || + !EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) { + goto err; + } + if (!point->Z_is_one) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + + ret = 1; + +err: + BN_CTX_end(ctx); + BN_CTX_free(new_ctx); + return ret; +} + +int ec_GFp_simple_points_make_affine(const EC_GROUP *group, size_t num, + EC_POINT *points[], BN_CTX *ctx) { + BN_CTX *new_ctx = NULL; + BIGNUM *tmp, *tmp_Z; + BIGNUM **prod_Z = NULL; + size_t i; + int ret = 0; + + if (num == 0) { + return 1; + } + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } + } + + BN_CTX_start(ctx); + tmp = BN_CTX_get(ctx); + tmp_Z = BN_CTX_get(ctx); + if (tmp == NULL || tmp_Z == NULL) { + goto err; + } + + prod_Z = OPENSSL_malloc(num * sizeof(prod_Z[0])); + if (prod_Z == NULL) { + goto err; + } + memset(prod_Z, 0, num * sizeof(prod_Z[0])); + for (i = 0; i < num; i++) { + prod_Z[i] = BN_new(); + if (prod_Z[i] == NULL) { + goto err; + } + } + + /* Set each prod_Z[i] to the product of points[0]->Z .. points[i]->Z, + * skipping any zero-valued inputs (pretend that they're 1). */ + + if (!BN_is_zero(&points[0]->Z)) { + if (!BN_copy(prod_Z[0], &points[0]->Z)) { + goto err; + } + } else { + if (group->meth->field_set_to_one != 0) { + if (!group->meth->field_set_to_one(group, prod_Z[0], ctx)) { + goto err; + } + } else { + if (!BN_one(prod_Z[0])) { + goto err; + } + } + } + + for (i = 1; i < num; i++) { + if (!BN_is_zero(&points[i]->Z)) { + if (!group->meth->field_mul(group, prod_Z[i], prod_Z[i - 1], + &points[i]->Z, ctx)) { + goto err; + } + } else { + if (!BN_copy(prod_Z[i], prod_Z[i - 1])) { + goto err; + } + } + } + + /* Now use a single explicit inversion to replace every + * non-zero points[i]->Z by its inverse. */ + + if (!BN_mod_inverse(tmp, prod_Z[num - 1], &group->field, ctx)) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + goto err; + } + + if (group->meth->field_encode != NULL) { + /* In the Montgomery case, we just turned R*H (representing H) + * into 1/(R*H), but we need R*(1/H) (representing 1/H); + * i.e. we need to multiply by the Montgomery factor twice. */ + if (!group->meth->field_encode(group, tmp, tmp, ctx) || + !group->meth->field_encode(group, tmp, tmp, ctx)) { + goto err; + } + } + + for (i = num - 1; i > 0; --i) { + /* Loop invariant: tmp is the product of the inverses of + * points[0]->Z .. points[i]->Z (zero-valued inputs skipped). */ + if (BN_is_zero(&points[i]->Z)) { + continue; + } + + /* Set tmp_Z to the inverse of points[i]->Z (as product + * of Z inverses 0 .. i, Z values 0 .. i - 1). */ + if (!group->meth->field_mul(group, tmp_Z, prod_Z[i - 1], tmp, ctx) || + /* Update tmp to satisfy the loop invariant for i - 1. */ + !group->meth->field_mul(group, tmp, tmp, &points[i]->Z, ctx) || + /* Replace points[i]->Z by its inverse. */ + !BN_copy(&points[i]->Z, tmp_Z)) { + goto err; + } + } + + /* Replace points[0]->Z by its inverse. */ + if (!BN_is_zero(&points[0]->Z) && !BN_copy(&points[0]->Z, tmp)) { + goto err; + } + + /* Finally, fix up the X and Y coordinates for all points. */ + for (i = 0; i < num; i++) { + EC_POINT *p = points[i]; + + if (!BN_is_zero(&p->Z)) { + /* turn (X, Y, 1/Z) into (X/Z^2, Y/Z^3, 1). */ + if (!group->meth->field_sqr(group, tmp, &p->Z, ctx) || + !group->meth->field_mul(group, &p->X, &p->X, tmp, ctx) || + !group->meth->field_mul(group, tmp, tmp, &p->Z, ctx) || + !group->meth->field_mul(group, &p->Y, &p->Y, tmp, ctx)) { + goto err; + } + + if (group->meth->field_set_to_one != NULL) { + if (!group->meth->field_set_to_one(group, &p->Z, ctx)) { + goto err; + } + } else { + if (!BN_one(&p->Z)) { + goto err; + } + } + p->Z_is_one = 1; + } + } + + ret = 1; + +err: + BN_CTX_end(ctx); + BN_CTX_free(new_ctx); + if (prod_Z != NULL) { + for (i = 0; i < num; i++) { + if (prod_Z[i] == NULL) { + break; + } + BN_clear_free(prod_Z[i]); + } + OPENSSL_free(prod_Z); + } + + return ret; +} + +int ec_GFp_simple_field_mul(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, + const BIGNUM *b, BN_CTX *ctx) { + return BN_mod_mul(r, a, b, &group->field, ctx); +} + +int ec_GFp_simple_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, + BN_CTX *ctx) { + return BN_mod_sqr(r, a, &group->field, ctx); +} diff --git a/TMessagesProj/jni/boringssl/crypto/ec/util-64.c b/TMessagesProj/jni/boringssl/crypto/ec/util-64.c new file mode 100644 index 00000000..171b0631 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ec/util-64.c @@ -0,0 +1,183 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + + +#if defined(OPENSSL_64_BIT) && !defined(OPENSSL_WINDOWS) + +#include + +#include "internal.h" + +/* Convert an array of points into affine coordinates. (If the point at + * infinity is found (Z = 0), it remains unchanged.) This function is + * essentially an equivalent to EC_POINTs_make_affine(), but works with the + * internal representation of points as used by ecp_nistp###.c rather than + * with (BIGNUM-based) EC_POINT data structures. point_array is the + * input/output buffer ('num' points in projective form, i.e. three + * coordinates each), based on an internal representation of field elements + * of size 'felem_size'. tmp_felems needs to point to a temporary array of + * 'num'+1 field elements for storage of intermediate values. */ +void ec_GFp_nistp_points_make_affine_internal( + size_t num, void *point_array, size_t felem_size, void *tmp_felems, + void (*felem_one)(void *out), int (*felem_is_zero)(const void *in), + void (*felem_assign)(void *out, const void *in), + void (*felem_square)(void *out, const void *in), + void (*felem_mul)(void *out, const void *in1, const void *in2), + void (*felem_inv)(void *out, const void *in), + void (*felem_contract)(void *out, const void *in)) { + int i = 0; + +#define tmp_felem(I) (&((char *)tmp_felems)[(I)*felem_size]) +#define X(I) (&((char *)point_array)[3 * (I)*felem_size]) +#define Y(I) (&((char *)point_array)[(3 * (I) + 1) * felem_size]) +#define Z(I) (&((char *)point_array)[(3 * (I) + 2) * felem_size]) + + if (!felem_is_zero(Z(0))) { + felem_assign(tmp_felem(0), Z(0)); + } else { + felem_one(tmp_felem(0)); + } + + for (i = 1; i < (int)num; i++) { + if (!felem_is_zero(Z(i))) { + felem_mul(tmp_felem(i), tmp_felem(i - 1), Z(i)); + } else { + felem_assign(tmp_felem(i), tmp_felem(i - 1)); + } + } + /* Now each tmp_felem(i) is the product of Z(0) .. Z(i), skipping any + * zero-valued factors: if Z(i) = 0, we essentially pretend that Z(i) = 1. */ + + felem_inv(tmp_felem(num - 1), tmp_felem(num - 1)); + for (i = num - 1; i >= 0; i--) { + if (i > 0) { + /* tmp_felem(i-1) is the product of Z(0) .. Z(i-1), tmp_felem(i) + * is the inverse of the product of Z(0) .. Z(i). */ + /* 1/Z(i) */ + felem_mul(tmp_felem(num), tmp_felem(i - 1), tmp_felem(i)); + } else { + felem_assign(tmp_felem(num), tmp_felem(0)); /* 1/Z(0) */ + } + + if (!felem_is_zero(Z(i))) { + if (i > 0) { + /* For next iteration, replace tmp_felem(i-1) by its inverse. */ + felem_mul(tmp_felem(i - 1), tmp_felem(i), Z(i)); + } + + /* Convert point (X, Y, Z) into affine form (X/(Z^2), Y/(Z^3), 1). */ + felem_square(Z(i), tmp_felem(num)); /* 1/(Z^2) */ + felem_mul(X(i), X(i), Z(i)); /* X/(Z^2) */ + felem_mul(Z(i), Z(i), tmp_felem(num)); /* 1/(Z^3) */ + felem_mul(Y(i), Y(i), Z(i)); /* Y/(Z^3) */ + felem_contract(X(i), X(i)); + felem_contract(Y(i), Y(i)); + felem_one(Z(i)); + } else { + if (i > 0) { + /* For next iteration, replace tmp_felem(i-1) by its inverse. */ + felem_assign(tmp_felem(i - 1), tmp_felem(i)); + } + } + } +} + +/* This function looks at 5+1 scalar bits (5 current, 1 adjacent less + * significant bit), and recodes them into a signed digit for use in fast point + * multiplication: the use of signed rather than unsigned digits means that + * fewer points need to be precomputed, given that point inversion is easy (a + * precomputed point dP makes -dP available as well). + * + * BACKGROUND: + * + * Signed digits for multiplication were introduced by Booth ("A signed binary + * multiplication technique", Quart. Journ. Mech. and Applied Math., vol. IV, + * pt. 2 (1951), pp. 236-240), in that case for multiplication of integers. + * Booth's original encoding did not generally improve the density of nonzero + * digits over the binary representation, and was merely meant to simplify the + * handling of signed factors given in two's complement; but it has since been + * shown to be the basis of various signed-digit representations that do have + * further advantages, including the wNAF, using the following general + * approach: + * + * (1) Given a binary representation + * + * b_k ... b_2 b_1 b_0, + * + * of a nonnegative integer (b_k in {0, 1}), rewrite it in digits 0, 1, -1 + * by using bit-wise subtraction as follows: + * + * b_k b_(k-1) ... b_2 b_1 b_0 + * - b_k ... b_3 b_2 b_1 b_0 + * ------------------------------------- + * s_k b_(k-1) ... s_3 s_2 s_1 s_0 + * + * A left-shift followed by subtraction of the original value yields a new + * representation of the same value, using signed bits s_i = b_(i+1) - b_i. + * This representation from Booth's paper has since appeared in the + * literature under a variety of different names including "reversed binary + * form", "alternating greedy expansion", "mutual opposite form", and + * "sign-alternating {+-1}-representation". + * + * An interesting property is that among the nonzero bits, values 1 and -1 + * strictly alternate. + * + * (2) Various window schemes can be applied to the Booth representation of + * integers: for example, right-to-left sliding windows yield the wNAF + * (a signed-digit encoding independently discovered by various researchers + * in the 1990s), and left-to-right sliding windows yield a left-to-right + * equivalent of the wNAF (independently discovered by various researchers + * around 2004). + * + * To prevent leaking information through side channels in point multiplication, + * we need to recode the given integer into a regular pattern: sliding windows + * as in wNAFs won't do, we need their fixed-window equivalent -- which is a few + * decades older: we'll be using the so-called "modified Booth encoding" due to + * MacSorley ("High-speed arithmetic in binary computers", Proc. IRE, vol. 49 + * (1961), pp. 67-91), in a radix-2^5 setting. That is, we always combine five + * signed bits into a signed digit: + * + * s_(4j + 4) s_(4j + 3) s_(4j + 2) s_(4j + 1) s_(4j) + * + * The sign-alternating property implies that the resulting digit values are + * integers from -16 to 16. + * + * Of course, we don't actually need to compute the signed digits s_i as an + * intermediate step (that's just a nice way to see how this scheme relates + * to the wNAF): a direct computation obtains the recoded digit from the + * six bits b_(4j + 4) ... b_(4j - 1). + * + * This function takes those five bits as an integer (0 .. 63), writing the + * recoded digit to *sign (0 for positive, 1 for negative) and *digit (absolute + * value, in the range 0 .. 8). Note that this integer essentially provides the + * input bits "shifted to the left" by one position: for example, the input to + * compute the least significant recoded digit, given that there's no bit b_-1, + * has to be b_4 b_3 b_2 b_1 b_0 0. */ +void ec_GFp_nistp_recode_scalar_bits(uint8_t *sign, uint8_t *digit, + uint8_t in) { + uint8_t s, d; + + s = ~((in >> 5) - 1); /* sets all bits to MSB(in), 'in' seen as + * 6-bit value */ + d = (1 << 6) - in - 1; + d = (d & s) | (in & ~s); + d = (d >> 1) + (d & 1); + + *sign = s & 1; + *digit = d; +} + +#endif /* 64_BIT && !WINDOWS */ diff --git a/TMessagesProj/jni/boringssl/crypto/ec/wnaf.c b/TMessagesProj/jni/boringssl/crypto/ec/wnaf.c new file mode 100644 index 00000000..7fa0e1bf --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ec/wnaf.c @@ -0,0 +1,853 @@ +/* Originally written by Bodo Moeller for the OpenSSL project. + * ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * The elliptic curve binary polynomial software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems + * Laboratories. */ + +#include + +#include + +#include +#include +#include +#include + +#include "internal.h" +#include "../internal.h" + + +/* This file implements the wNAF-based interleaving multi-exponentation method + * (); + * for multiplication with precomputation, we use wNAF splitting + * (). + * */ + +/* structure for precomputed multiples of the generator */ +typedef struct ec_pre_comp_st { + size_t blocksize; /* block size for wNAF splitting */ + size_t numblocks; /* max. number of blocks for which we have precomputation */ + size_t w; /* window size */ + EC_POINT **points; /* array with pre-calculated multiples of generator: + * 'num' pointers to EC_POINT objects followed by a NULL */ + size_t num; /* numblocks * 2^(w-1) */ + CRYPTO_refcount_t references; +} EC_PRE_COMP; + +static EC_PRE_COMP *ec_pre_comp_new(void) { + EC_PRE_COMP *ret = NULL; + + ret = (EC_PRE_COMP *)OPENSSL_malloc(sizeof(EC_PRE_COMP)); + if (!ret) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + return ret; + } + ret->blocksize = 8; /* default */ + ret->numblocks = 0; + ret->w = 4; /* default */ + ret->points = NULL; + ret->num = 0; + ret->references = 1; + return ret; +} + +void *ec_pre_comp_dup(EC_PRE_COMP *pre_comp) { + if (pre_comp == NULL) { + return NULL; + } + + CRYPTO_refcount_inc(&pre_comp->references); + return pre_comp; +} + +void ec_pre_comp_free(EC_PRE_COMP *pre_comp) { + if (pre_comp == NULL || + !CRYPTO_refcount_dec_and_test_zero(&pre_comp->references)) { + return; + } + + if (pre_comp->points) { + EC_POINT **p; + + for (p = pre_comp->points; *p != NULL; p++) { + EC_POINT_free(*p); + } + OPENSSL_free(pre_comp->points); + } + OPENSSL_free(pre_comp); +} + + +/* Determine the modified width-(w+1) Non-Adjacent Form (wNAF) of 'scalar'. + * This is an array r[] of values that are either zero or odd with an + * absolute value less than 2^w satisfying + * scalar = \sum_j r[j]*2^j + * where at most one of any w+1 consecutive digits is non-zero + * with the exception that the most significant digit may be only + * w-1 zeros away from that next non-zero digit. + */ +static signed char *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len) { + int window_val; + int ok = 0; + signed char *r = NULL; + int sign = 1; + int bit, next_bit, mask; + size_t len = 0, j; + + if (BN_is_zero(scalar)) { + r = OPENSSL_malloc(1); + if (!r) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + goto err; + } + r[0] = 0; + *ret_len = 1; + return r; + } + + if (w <= 0 || w > 7) /* 'signed char' can represent integers with absolute + values less than 2^7 */ + { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + bit = 1 << w; /* at most 128 */ + next_bit = bit << 1; /* at most 256 */ + mask = next_bit - 1; /* at most 255 */ + + if (BN_is_negative(scalar)) { + sign = -1; + } + + if (scalar->d == NULL || scalar->top == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + + len = BN_num_bits(scalar); + r = OPENSSL_malloc( + len + + 1); /* modified wNAF may be one digit longer than binary representation + * (*ret_len will be set to the actual length, i.e. at most + * BN_num_bits(scalar) + 1) */ + if (r == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + goto err; + } + window_val = scalar->d[0] & mask; + j = 0; + while ((window_val != 0) || + (j + w + 1 < len)) /* if j+w+1 >= len, window_val will not increase */ + { + int digit = 0; + + /* 0 <= window_val <= 2^(w+1) */ + + if (window_val & 1) { + /* 0 < window_val < 2^(w+1) */ + + if (window_val & bit) { + digit = window_val - next_bit; /* -2^w < digit < 0 */ + +#if 1 /* modified wNAF */ + if (j + w + 1 >= len) { + /* special case for generating modified wNAFs: + * no new bits will be added into window_val, + * so using a positive digit here will decrease + * the total length of the representation */ + + digit = window_val & (mask >> 1); /* 0 < digit < 2^w */ + } +#endif + } else { + digit = window_val; /* 0 < digit < 2^w */ + } + + if (digit <= -bit || digit >= bit || !(digit & 1)) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + + window_val -= digit; + + /* now window_val is 0 or 2^(w+1) in standard wNAF generation; + * for modified window NAFs, it may also be 2^w + */ + if (window_val != 0 && window_val != next_bit && window_val != bit) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + } + + r[j++] = sign * digit; + + window_val >>= 1; + window_val += bit * BN_is_bit_set(scalar, j + w); + + if (window_val > next_bit) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + } + + if (j > len + 1) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + len = j; + ok = 1; + +err: + if (!ok) { + OPENSSL_free(r); + r = NULL; + } + if (ok) { + *ret_len = len; + } + return r; +} + + +/* TODO: table should be optimised for the wNAF-based implementation, + * sometimes smaller windows will give better performance + * (thus the boundaries should be increased) + */ +#define EC_window_bits_for_scalar_size(b) \ + ((size_t)((b) >= 2000 ? 6 : (b) >= 800 ? 5 : (b) >= 300 \ + ? 4 \ + : (b) >= 70 ? 3 : (b) >= 20 \ + ? 2 \ + : 1)) + +/* Compute + * \sum scalars[i]*points[i], + * also including + * scalar*generator + * in the addition if scalar != NULL + */ +int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, + size_t num, const EC_POINT *points[], const BIGNUM *scalars[], + BN_CTX *ctx) { + BN_CTX *new_ctx = NULL; + const EC_POINT *generator = NULL; + EC_POINT *tmp = NULL; + size_t totalnum; + size_t blocksize = 0, numblocks = 0; /* for wNAF splitting */ + size_t pre_points_per_block = 0; + size_t i, j; + int k; + int r_is_inverted = 0; + int r_is_at_infinity = 1; + size_t *wsize = NULL; /* individual window sizes */ + signed char **wNAF = NULL; /* individual wNAFs */ + size_t *wNAF_len = NULL; + size_t max_len = 0; + size_t num_val; + EC_POINT **val = NULL; /* precomputation */ + EC_POINT **v; + EC_POINT ***val_sub = + NULL; /* pointers to sub-arrays of 'val' or 'pre_comp->points' */ + const EC_PRE_COMP *pre_comp = NULL; + int num_scalar = 0; /* flag: will be set to 1 if 'scalar' must be treated like + * other scalars, + * i.e. precomputation is not available */ + int ret = 0; + + if (group->meth != r->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + + if ((scalar == NULL) && (num == 0)) { + return EC_POINT_set_to_infinity(group, r); + } + + for (i = 0; i < num; i++) { + if (group->meth != points[i]->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + } + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + } + + if (scalar != NULL) { + generator = EC_GROUP_get0_generator(group); + if (generator == NULL) { + OPENSSL_PUT_ERROR(EC, EC_R_UNDEFINED_GENERATOR); + goto err; + } + + /* look if we can use precomputed multiples of generator */ + + pre_comp = group->pre_comp; + + if (pre_comp && pre_comp->numblocks && + (EC_POINT_cmp(group, generator, pre_comp->points[0], ctx) == 0)) { + blocksize = pre_comp->blocksize; + + /* determine maximum number of blocks that wNAF splitting may yield + * (NB: maximum wNAF length is bit length plus one) */ + numblocks = (BN_num_bits(scalar) / blocksize) + 1; + + /* we cannot use more blocks than we have precomputation for */ + if (numblocks > pre_comp->numblocks) { + numblocks = pre_comp->numblocks; + } + + pre_points_per_block = (size_t)1 << (pre_comp->w - 1); + + /* check that pre_comp looks sane */ + if (pre_comp->num != (pre_comp->numblocks * pre_points_per_block)) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + } else { + /* can't use precomputation */ + pre_comp = NULL; + numblocks = 1; + num_scalar = 1; /* treat 'scalar' like 'num'-th element of 'scalars' */ + } + } + + totalnum = num + numblocks; + + wsize = OPENSSL_malloc(totalnum * sizeof wsize[0]); + wNAF_len = OPENSSL_malloc(totalnum * sizeof wNAF_len[0]); + wNAF = OPENSSL_malloc((totalnum + 1) * + sizeof wNAF[0]); /* includes space for pivot */ + val_sub = OPENSSL_malloc(totalnum * sizeof val_sub[0]); + + /* Ensure wNAF is initialised in case we end up going to err. */ + if (wNAF) { + wNAF[0] = NULL; /* preliminary pivot */ + } + + if (!wsize || !wNAF_len || !wNAF || !val_sub) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* num_val will be the total number of temporarily precomputed points */ + num_val = 0; + + for (i = 0; i < num + num_scalar; i++) { + size_t bits; + + bits = i < num ? BN_num_bits(scalars[i]) : BN_num_bits(scalar); + wsize[i] = EC_window_bits_for_scalar_size(bits); + num_val += (size_t)1 << (wsize[i] - 1); + wNAF[i + 1] = NULL; /* make sure we always have a pivot */ + wNAF[i] = + compute_wNAF((i < num ? scalars[i] : scalar), wsize[i], &wNAF_len[i]); + if (wNAF[i] == NULL) { + goto err; + } + if (wNAF_len[i] > max_len) { + max_len = wNAF_len[i]; + } + } + + if (numblocks) { + /* we go here iff scalar != NULL */ + + if (pre_comp == NULL) { + if (num_scalar != 1) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + /* we have already generated a wNAF for 'scalar' */ + } else { + signed char *tmp_wNAF = NULL; + size_t tmp_len = 0; + + if (num_scalar != 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + + /* use the window size for which we have precomputation */ + wsize[num] = pre_comp->w; + tmp_wNAF = compute_wNAF(scalar, wsize[num], &tmp_len); + if (!tmp_wNAF) { + goto err; + } + + if (tmp_len <= max_len) { + /* One of the other wNAFs is at least as long + * as the wNAF belonging to the generator, + * so wNAF splitting will not buy us anything. */ + + numblocks = 1; /* don't use wNAF splitting */ + totalnum = num + numblocks; + wNAF[num] = tmp_wNAF; + wNAF[num + 1] = NULL; + wNAF_len[num] = tmp_len; + /* pre_comp->points starts with the points that we need here: */ + val_sub[num] = pre_comp->points; + } else { + /* don't include tmp_wNAF directly into wNAF array + * - use wNAF splitting and include the blocks */ + + signed char *pp; + EC_POINT **tmp_points; + + if (tmp_len < numblocks * blocksize) { + /* possibly we can do with fewer blocks than estimated */ + numblocks = (tmp_len + blocksize - 1) / blocksize; + if (numblocks > pre_comp->numblocks) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + OPENSSL_free(tmp_wNAF); + goto err; + } + totalnum = num + numblocks; + } + + /* split wNAF in 'numblocks' parts */ + pp = tmp_wNAF; + tmp_points = pre_comp->points; + + for (i = num; i < totalnum; i++) { + if (i < totalnum - 1) { + wNAF_len[i] = blocksize; + if (tmp_len < blocksize) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + OPENSSL_free(tmp_wNAF); + goto err; + } + tmp_len -= blocksize; + } else { + /* last block gets whatever is left + * (this could be more or less than 'blocksize'!) */ + wNAF_len[i] = tmp_len; + } + + wNAF[i + 1] = NULL; + wNAF[i] = OPENSSL_malloc(wNAF_len[i]); + if (wNAF[i] == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + OPENSSL_free(tmp_wNAF); + goto err; + } + memcpy(wNAF[i], pp, wNAF_len[i]); + if (wNAF_len[i] > max_len) { + max_len = wNAF_len[i]; + } + + if (*tmp_points == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + OPENSSL_free(tmp_wNAF); + goto err; + } + val_sub[i] = tmp_points; + tmp_points += pre_points_per_block; + pp += blocksize; + } + OPENSSL_free(tmp_wNAF); + } + } + } + + /* All points we precompute now go into a single array 'val'. + * 'val_sub[i]' is a pointer to the subarray for the i-th point, + * or to a subarray of 'pre_comp->points' if we already have precomputation. + */ + val = OPENSSL_malloc((num_val + 1) * sizeof val[0]); + if (val == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + goto err; + } + val[num_val] = NULL; /* pivot element */ + + /* allocate points for precomputation */ + v = val; + for (i = 0; i < num + num_scalar; i++) { + val_sub[i] = v; + for (j = 0; j < ((size_t)1 << (wsize[i] - 1)); j++) { + *v = EC_POINT_new(group); + if (*v == NULL) { + goto err; + } + v++; + } + } + if (!(v == val + num_val)) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + + if (!(tmp = EC_POINT_new(group))) { + goto err; + } + + /* prepare precomputed values: + * val_sub[i][0] := points[i] + * val_sub[i][1] := 3 * points[i] + * val_sub[i][2] := 5 * points[i] + * ... + */ + for (i = 0; i < num + num_scalar; i++) { + if (i < num) { + if (!EC_POINT_copy(val_sub[i][0], points[i])) { + goto err; + } + } else if (!EC_POINT_copy(val_sub[i][0], generator)) { + goto err; + } + + if (wsize[i] > 1) { + if (!EC_POINT_dbl(group, tmp, val_sub[i][0], ctx)) { + goto err; + } + for (j = 1; j < ((size_t)1 << (wsize[i] - 1)); j++) { + if (!EC_POINT_add(group, val_sub[i][j], val_sub[i][j - 1], tmp, ctx)) { + goto err; + } + } + } + } + +#if 1 /* optional; EC_window_bits_for_scalar_size assumes we do this step */ + if (!EC_POINTs_make_affine(group, num_val, val, ctx)) { + goto err; + } +#endif + + r_is_at_infinity = 1; + + for (k = max_len - 1; k >= 0; k--) { + if (!r_is_at_infinity && !EC_POINT_dbl(group, r, r, ctx)) { + goto err; + } + + for (i = 0; i < totalnum; i++) { + if (wNAF_len[i] > (size_t)k) { + int digit = wNAF[i][k]; + int is_neg; + + if (digit) { + is_neg = digit < 0; + + if (is_neg) { + digit = -digit; + } + + if (is_neg != r_is_inverted) { + if (!r_is_at_infinity && !EC_POINT_invert(group, r, ctx)) { + goto err; + } + r_is_inverted = !r_is_inverted; + } + + /* digit > 0 */ + + if (r_is_at_infinity) { + if (!EC_POINT_copy(r, val_sub[i][digit >> 1])) { + goto err; + } + r_is_at_infinity = 0; + } else { + if (!EC_POINT_add(group, r, r, val_sub[i][digit >> 1], ctx)) { + goto err; + } + } + } + } + } + } + + if (r_is_at_infinity) { + if (!EC_POINT_set_to_infinity(group, r)) { + goto err; + } + } else if (r_is_inverted && !EC_POINT_invert(group, r, ctx)) { + goto err; + } + + ret = 1; + +err: + BN_CTX_free(new_ctx); + EC_POINT_free(tmp); + OPENSSL_free(wsize); + OPENSSL_free(wNAF_len); + if (wNAF != NULL) { + signed char **w; + + for (w = wNAF; *w != NULL; w++) { + OPENSSL_free(*w); + } + + OPENSSL_free(wNAF); + } + if (val != NULL) { + for (v = val; *v != NULL; v++) { + EC_POINT_clear_free(*v); + } + + OPENSSL_free(val); + } + OPENSSL_free(val_sub); + return ret; +} + + +/* ec_wNAF_precompute_mult() + * creates an EC_PRE_COMP object with preprecomputed multiples of the generator + * for use with wNAF splitting as implemented in ec_wNAF_mul(). + * + * 'pre_comp->points' is an array of multiples of the generator + * of the following form: + * points[0] = generator; + * points[1] = 3 * generator; + * ... + * points[2^(w-1)-1] = (2^(w-1)-1) * generator; + * points[2^(w-1)] = 2^blocksize * generator; + * points[2^(w-1)+1] = 3 * 2^blocksize * generator; + * ... + * points[2^(w-1)*(numblocks-1)-1] = (2^(w-1)) * 2^(blocksize*(numblocks-2)) * + *generator + * points[2^(w-1)*(numblocks-1)] = 2^(blocksize*(numblocks-1)) * + *generator + * ... + * points[2^(w-1)*numblocks-1] = (2^(w-1)) * 2^(blocksize*(numblocks-1)) * + *generator + * points[2^(w-1)*numblocks] = NULL + */ +int ec_wNAF_precompute_mult(EC_GROUP *group, BN_CTX *ctx) { + const EC_POINT *generator; + EC_POINT *tmp_point = NULL, *base = NULL, **var; + BN_CTX *new_ctx = NULL; + BIGNUM *order; + size_t i, bits, w, pre_points_per_block, blocksize, numblocks, num; + EC_POINT **points = NULL; + EC_PRE_COMP *pre_comp; + int ret = 0; + + /* if there is an old EC_PRE_COMP object, throw it away */ + ec_pre_comp_free(group->pre_comp); + group->pre_comp = NULL; + + generator = EC_GROUP_get0_generator(group); + if (generator == NULL) { + OPENSSL_PUT_ERROR(EC, EC_R_UNDEFINED_GENERATOR); + return 0; + } + + pre_comp = ec_pre_comp_new(); + if (pre_comp == NULL) { + return 0; + } + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + } + + BN_CTX_start(ctx); + order = BN_CTX_get(ctx); + if (order == NULL) { + goto err; + } + + if (!EC_GROUP_get_order(group, order, ctx)) { + goto err; + } + if (BN_is_zero(order)) { + OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_ORDER); + goto err; + } + + bits = BN_num_bits(order); + /* The following parameters mean we precompute (approximately) + * one point per bit. + * + * TBD: The combination 8, 4 is perfect for 160 bits; for other + * bit lengths, other parameter combinations might provide better + * efficiency. + */ + blocksize = 8; + w = 4; + if (EC_window_bits_for_scalar_size(bits) > w) { + /* let's not make the window too small ... */ + w = EC_window_bits_for_scalar_size(bits); + } + + numblocks = (bits + blocksize - 1) / + blocksize; /* max. number of blocks to use for wNAF splitting */ + + pre_points_per_block = (size_t)1 << (w - 1); + num = pre_points_per_block * + numblocks; /* number of points to compute and store */ + + points = OPENSSL_malloc(sizeof(EC_POINT *) * (num + 1)); + if (!points) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + goto err; + } + + var = points; + var[num] = NULL; /* pivot */ + for (i = 0; i < num; i++) { + if ((var[i] = EC_POINT_new(group)) == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + goto err; + } + } + + if (!(tmp_point = EC_POINT_new(group)) || !(base = EC_POINT_new(group))) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!EC_POINT_copy(base, generator)) { + goto err; + } + + /* do the precomputation */ + for (i = 0; i < numblocks; i++) { + size_t j; + + if (!EC_POINT_dbl(group, tmp_point, base, ctx)) { + goto err; + } + + if (!EC_POINT_copy(*var++, base)) { + goto err; + } + + for (j = 1; j < pre_points_per_block; j++, var++) { + /* calculate odd multiples of the current base point */ + if (!EC_POINT_add(group, *var, tmp_point, *(var - 1), ctx)) { + goto err; + } + } + + if (i < numblocks - 1) { + /* get the next base (multiply current one by 2^blocksize) */ + size_t k; + + if (blocksize <= 2) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + + if (!EC_POINT_dbl(group, base, tmp_point, ctx)) { + goto err; + } + for (k = 2; k < blocksize; k++) { + if (!EC_POINT_dbl(group, base, base, ctx)) { + goto err; + } + } + } + } + + if (!EC_POINTs_make_affine(group, num, points, ctx)) { + goto err; + } + + pre_comp->blocksize = blocksize; + pre_comp->numblocks = numblocks; + pre_comp->w = w; + pre_comp->points = points; + points = NULL; + pre_comp->num = num; + + group->pre_comp = pre_comp; + pre_comp = NULL; + + ret = 1; + +err: + if (ctx != NULL) { + BN_CTX_end(ctx); + } + BN_CTX_free(new_ctx); + ec_pre_comp_free(pre_comp); + if (points) { + EC_POINT **p; + + for (p = points; *p != NULL; p++) { + EC_POINT_free(*p); + } + OPENSSL_free(points); + } + EC_POINT_free(tmp_point); + EC_POINT_free(base); + return ret; +} + + +int ec_wNAF_have_precompute_mult(const EC_GROUP *group) { + return group->pre_comp != NULL; +} diff --git a/TMessagesProj/jni/boringssl/crypto/ecdh/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/ecdh/CMakeLists.txt new file mode 100644 index 00000000..346e72d8 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ecdh/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories(. .. ../../include) + +add_library( + ecdh + + OBJECT + + ecdh.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/ecdh/ecdh.c b/TMessagesProj/jni/boringssl/crypto/ecdh/ecdh.c new file mode 100644 index 00000000..14856db0 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ecdh/ecdh.c @@ -0,0 +1,161 @@ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * The Elliptic Curve Public-Key Crypto Library (ECC Code) included + * herein is developed by SUN MICROSYSTEMS, INC., and is contributed + * to the OpenSSL project. + * + * The ECC Code is licensed pursuant to the OpenSSL open source + * license provided below. + * + * The ECDH software is originally written by Douglas Stebila of + * Sun Microsystems Laboratories. + * + */ +/* ==================================================================== + * Copyright (c) 2000-2002 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include + +#include +#include +#include +#include + + +int ECDH_compute_key(void *out, size_t outlen, const EC_POINT *pub_key, + EC_KEY *priv_key, void *(*KDF)(const void *in, size_t inlen, + void *out, size_t *outlen)) { + BN_CTX *ctx; + EC_POINT *tmp = NULL; + BIGNUM *x = NULL, *y = NULL; + const BIGNUM *priv; + const EC_GROUP *group; + int ret = -1; + size_t buflen; + uint8_t *buf = NULL; + + if ((ctx = BN_CTX_new()) == NULL) { + goto err; + } + BN_CTX_start(ctx); + x = BN_CTX_get(ctx); + y = BN_CTX_get(ctx); + + priv = EC_KEY_get0_private_key(priv_key); + if (priv == NULL) { + OPENSSL_PUT_ERROR(ECDH, ECDH_R_NO_PRIVATE_VALUE); + goto err; + } + + group = EC_KEY_get0_group(priv_key); + + tmp = EC_POINT_new(group); + if (tmp == NULL) { + OPENSSL_PUT_ERROR(ECDH, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!EC_POINT_mul(group, tmp, NULL, pub_key, priv, ctx)) { + OPENSSL_PUT_ERROR(ECDH, ECDH_R_POINT_ARITHMETIC_FAILURE); + goto err; + } + + if (!EC_POINT_get_affine_coordinates_GFp(group, tmp, x, y, ctx)) { + OPENSSL_PUT_ERROR(ECDH, ECDH_R_POINT_ARITHMETIC_FAILURE); + goto err; + } + + buflen = (EC_GROUP_get_degree(group) + 7) / 8; + buf = OPENSSL_malloc(buflen); + if (buf == NULL) { + OPENSSL_PUT_ERROR(ECDH, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!BN_bn2bin_padded(buf, buflen, x)) { + OPENSSL_PUT_ERROR(ECDH, ERR_R_INTERNAL_ERROR); + goto err; + } + + if (KDF != 0) { + if (KDF(buf, buflen, out, &outlen) == NULL) { + OPENSSL_PUT_ERROR(ECDH, ECDH_R_KDF_FAILED); + goto err; + } + ret = outlen; + } else { + /* no KDF, just copy as much as we can */ + if (outlen > buflen) { + outlen = buflen; + } + memcpy(out, buf, outlen); + ret = outlen; + } + +err: + if (tmp) { + EC_POINT_free(tmp); + } + if (ctx) { + BN_CTX_end(ctx); + } + if (ctx) { + BN_CTX_free(ctx); + } + if (buf) { + OPENSSL_free(buf); + } + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/ecdsa/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/ecdsa/CMakeLists.txt new file mode 100644 index 00000000..9ed50ddc --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ecdsa/CMakeLists.txt @@ -0,0 +1,10 @@ +include_directories(. .. ../../include) + +add_library( + ecdsa + + OBJECT + + ecdsa.c + ecdsa_asn1.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/ecdsa/ecdsa.c b/TMessagesProj/jni/boringssl/crypto/ecdsa/ecdsa.c new file mode 100644 index 00000000..8403d60e --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ecdsa/ecdsa.c @@ -0,0 +1,493 @@ +/* ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include + +#include +#include +#include +#include + +#include "../ec/internal.h" + + +int ECDSA_sign(int type, const uint8_t *digest, size_t digest_len, uint8_t *sig, + unsigned int *sig_len, EC_KEY *eckey) { + if (eckey->ecdsa_meth && eckey->ecdsa_meth->sign) { + return eckey->ecdsa_meth->sign(digest, digest_len, sig, sig_len, eckey); + } + + return ECDSA_sign_ex(type, digest, digest_len, sig, sig_len, NULL, NULL, + eckey); +} + +int ECDSA_verify(int type, const uint8_t *digest, size_t digest_len, + const uint8_t *sig, size_t sig_len, EC_KEY *eckey) { + ECDSA_SIG *s; + int ret = 0; + uint8_t *der = NULL; + + if (eckey->ecdsa_meth && eckey->ecdsa_meth->verify) { + return eckey->ecdsa_meth->verify(digest, digest_len, sig, sig_len, eckey); + } + + /* Decode the ECDSA signature. */ + s = ECDSA_SIG_from_bytes(sig, sig_len); + if (s == NULL) { + goto err; + } + + /* Defend against potential laxness in the DER parser. */ + size_t der_len; + if (!ECDSA_SIG_to_bytes(&der, &der_len, s) || + der_len != sig_len || memcmp(sig, der, sig_len) != 0) { + /* This should never happen. crypto/bytestring is strictly DER. */ + OPENSSL_PUT_ERROR(ECDSA, ERR_R_INTERNAL_ERROR); + goto err; + } + + ret = ECDSA_do_verify(digest, digest_len, s, eckey); + +err: + OPENSSL_free(der); + ECDSA_SIG_free(s); + return ret; +} + +/* digest_to_bn interprets |digest_len| bytes from |digest| as a big-endian + * number and sets |out| to that value. It then truncates |out| so that it's, + * at most, as long as |order|. It returns one on success and zero otherwise. */ +static int digest_to_bn(BIGNUM *out, const uint8_t *digest, size_t digest_len, + const BIGNUM *order) { + size_t num_bits; + + num_bits = BN_num_bits(order); + /* Need to truncate digest if it is too long: first truncate whole + * bytes. */ + if (8 * digest_len > num_bits) { + digest_len = (num_bits + 7) / 8; + } + if (!BN_bin2bn(digest, digest_len, out)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); + return 0; + } + + /* If still too long truncate remaining bits with a shift */ + if ((8 * digest_len > num_bits) && + !BN_rshift(out, out, 8 - (num_bits & 0x7))) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); + return 0; + } + + return 1; +} + +ECDSA_SIG *ECDSA_do_sign(const uint8_t *digest, size_t digest_len, + EC_KEY *key) { + return ECDSA_do_sign_ex(digest, digest_len, NULL, NULL, key); +} + +int ECDSA_do_verify(const uint8_t *digest, size_t digest_len, + const ECDSA_SIG *sig, EC_KEY *eckey) { + int ret = 0; + BN_CTX *ctx; + BIGNUM *order, *u1, *u2, *m, *X; + EC_POINT *point = NULL; + const EC_GROUP *group; + const EC_POINT *pub_key; + + if (eckey->ecdsa_meth && eckey->ecdsa_meth->verify) { + OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_NOT_IMPLEMENTED); + return 0; + } + + /* check input values */ + if ((group = EC_KEY_get0_group(eckey)) == NULL || + (pub_key = EC_KEY_get0_public_key(eckey)) == NULL || + sig == NULL) { + OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_MISSING_PARAMETERS); + return 0; + } + + ctx = BN_CTX_new(); + if (!ctx) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE); + return 0; + } + BN_CTX_start(ctx); + order = BN_CTX_get(ctx); + u1 = BN_CTX_get(ctx); + u2 = BN_CTX_get(ctx); + m = BN_CTX_get(ctx); + X = BN_CTX_get(ctx); + if (order == NULL || u1 == NULL || u2 == NULL || m == NULL || X == NULL) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); + goto err; + } + + if (!EC_GROUP_get_order(group, order, ctx)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB); + goto err; + } + + if (BN_is_zero(sig->r) || BN_is_negative(sig->r) || + BN_ucmp(sig->r, order) >= 0 || BN_is_zero(sig->s) || + BN_is_negative(sig->s) || BN_ucmp(sig->s, order) >= 0) { + OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_BAD_SIGNATURE); + ret = 0; /* signature is invalid */ + goto err; + } + /* calculate tmp1 = inv(S) mod order */ + if (!BN_mod_inverse(u2, sig->s, order, ctx)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); + goto err; + } + if (!digest_to_bn(m, digest, digest_len, order)) { + goto err; + } + /* u1 = m * tmp mod order */ + if (!BN_mod_mul(u1, m, u2, order, ctx)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); + goto err; + } + /* u2 = r * w mod q */ + if (!BN_mod_mul(u2, sig->r, u2, order, ctx)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); + goto err; + } + + point = EC_POINT_new(group); + if (point == NULL) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE); + goto err; + } + if (!EC_POINT_mul(group, point, u1, pub_key, u2, ctx)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB); + goto err; + } + if (!EC_POINT_get_affine_coordinates_GFp(group, point, X, NULL, ctx)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB); + goto err; + } + if (!BN_nnmod(u1, X, order, ctx)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); + goto err; + } + /* if the signature is correct u1 is equal to sig->r */ + ret = (BN_ucmp(u1, sig->r) == 0); + +err: + BN_CTX_end(ctx); + BN_CTX_free(ctx); + EC_POINT_free(point); + return ret; +} + +static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, + BIGNUM **rp, const uint8_t *digest, + size_t digest_len) { + BN_CTX *ctx = NULL; + BIGNUM *k = NULL, *r = NULL, *order = NULL, *X = NULL; + EC_POINT *tmp_point = NULL; + const EC_GROUP *group; + int ret = 0; + + if (eckey == NULL || (group = EC_KEY_get0_group(eckey)) == NULL) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + if (ctx_in == NULL) { + if ((ctx = BN_CTX_new()) == NULL) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE); + return 0; + } + } else { + ctx = ctx_in; + } + + k = BN_new(); /* this value is later returned in *kinvp */ + r = BN_new(); /* this value is later returned in *rp */ + order = BN_new(); + X = BN_new(); + if (!k || !r || !order || !X) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE); + goto err; + } + tmp_point = EC_POINT_new(group); + if (tmp_point == NULL) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB); + goto err; + } + if (!EC_GROUP_get_order(group, order, ctx)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB); + goto err; + } + + do { + /* If possible, we'll include the private key and message digest in the k + * generation. The |digest| argument is only empty if |ECDSA_sign_setup| is + * being used. */ + do { + int ok; + + if (digest_len > 0) { + ok = BN_generate_dsa_nonce(k, order, EC_KEY_get0_private_key(eckey), + digest, digest_len, ctx); + } else { + ok = BN_rand_range(k, order); + } + if (!ok) { + OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED); + goto err; + } + } while (BN_is_zero(k)); + + /* We do not want timing information to leak the length of k, + * so we compute G*k using an equivalent scalar of fixed + * bit-length. */ + + if (!BN_add(k, k, order)) { + goto err; + } + if (BN_num_bits(k) <= BN_num_bits(order)) { + if (!BN_add(k, k, order)) { + goto err; + } + } + + /* compute r the x-coordinate of generator * k */ + if (!EC_POINT_mul(group, tmp_point, k, NULL, NULL, ctx)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB); + goto err; + } + if (!EC_POINT_get_affine_coordinates_GFp(group, tmp_point, X, NULL, ctx)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB); + goto err; + } + + if (!BN_nnmod(r, X, order, ctx)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); + goto err; + } + } while (BN_is_zero(r)); + + /* compute the inverse of k */ + if (!BN_mod_inverse(k, k, order, ctx)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); + goto err; + } + /* clear old values if necessary */ + BN_clear_free(*rp); + BN_clear_free(*kinvp); + + /* save the pre-computed values */ + *rp = r; + *kinvp = k; + ret = 1; + +err: + if (!ret) { + BN_clear_free(k); + BN_clear_free(r); + } + if (ctx_in == NULL) { + BN_CTX_free(ctx); + } + BN_free(order); + EC_POINT_free(tmp_point); + BN_clear_free(X); + return ret; +} + +int ECDSA_sign_setup(EC_KEY *eckey, BN_CTX *ctx, BIGNUM **kinv, BIGNUM **rp) { + return ecdsa_sign_setup(eckey, ctx, kinv, rp, NULL, 0); +} + +ECDSA_SIG *ECDSA_do_sign_ex(const uint8_t *digest, size_t digest_len, + const BIGNUM *in_kinv, const BIGNUM *in_r, + EC_KEY *eckey) { + int ok = 0; + BIGNUM *kinv = NULL, *s, *m = NULL, *tmp = NULL, *order = NULL; + const BIGNUM *ckinv; + BN_CTX *ctx = NULL; + const EC_GROUP *group; + ECDSA_SIG *ret; + const BIGNUM *priv_key; + + if (eckey->ecdsa_meth && eckey->ecdsa_meth->sign) { + OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_NOT_IMPLEMENTED); + return NULL; + } + + group = EC_KEY_get0_group(eckey); + priv_key = EC_KEY_get0_private_key(eckey); + + if (group == NULL || priv_key == NULL) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_PASSED_NULL_PARAMETER); + return NULL; + } + + ret = ECDSA_SIG_new(); + if (!ret) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE); + return NULL; + } + s = ret->s; + + if ((ctx = BN_CTX_new()) == NULL || (order = BN_new()) == NULL || + (tmp = BN_new()) == NULL || (m = BN_new()) == NULL) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!EC_GROUP_get_order(group, order, ctx)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB); + goto err; + } + if (!digest_to_bn(m, digest, digest_len, order)) { + goto err; + } + for (;;) { + if (in_kinv == NULL || in_r == NULL) { + if (!ecdsa_sign_setup(eckey, ctx, &kinv, &ret->r, digest, digest_len)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_ECDSA_LIB); + goto err; + } + ckinv = kinv; + } else { + ckinv = in_kinv; + if (BN_copy(ret->r, in_r) == NULL) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE); + goto err; + } + } + + if (!BN_mod_mul(tmp, priv_key, ret->r, order, ctx)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); + goto err; + } + if (!BN_mod_add_quick(s, tmp, m, order)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); + goto err; + } + if (!BN_mod_mul(s, s, ckinv, order, ctx)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); + goto err; + } + if (BN_is_zero(s)) { + /* if kinv and r have been supplied by the caller + * don't to generate new kinv and r values */ + if (in_kinv != NULL && in_r != NULL) { + OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_NEED_NEW_SETUP_VALUES); + goto err; + } + } else { + /* s != 0 => we have a valid signature */ + break; + } + } + + ok = 1; + +err: + if (!ok) { + ECDSA_SIG_free(ret); + ret = NULL; + } + BN_CTX_free(ctx); + BN_clear_free(m); + BN_clear_free(tmp); + BN_free(order); + BN_clear_free(kinv); + return ret; +} + +int ECDSA_sign_ex(int type, const uint8_t *digest, size_t digest_len, + uint8_t *sig, unsigned int *sig_len, const BIGNUM *kinv, + const BIGNUM *r, EC_KEY *eckey) { + int ret = 0; + ECDSA_SIG *s = NULL; + + if (eckey->ecdsa_meth && eckey->ecdsa_meth->sign) { + OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_NOT_IMPLEMENTED); + *sig_len = 0; + goto err; + } + + s = ECDSA_do_sign_ex(digest, digest_len, kinv, r, eckey); + if (s == NULL) { + *sig_len = 0; + goto err; + } + + CBB cbb; + CBB_zero(&cbb); + size_t len; + if (!CBB_init_fixed(&cbb, sig, ECDSA_size(eckey)) || + !ECDSA_SIG_marshal(&cbb, s) || + !CBB_finish(&cbb, NULL, &len)) { + OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_ENCODE_ERROR); + CBB_cleanup(&cbb); + *sig_len = 0; + goto err; + } + *sig_len = (unsigned)len; + ret = 1; + +err: + ECDSA_SIG_free(s); + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/ecdsa/ecdsa_asn1.c b/TMessagesProj/jni/boringssl/crypto/ecdsa/ecdsa_asn1.c new file mode 100644 index 00000000..f2d7c363 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ecdsa/ecdsa_asn1.c @@ -0,0 +1,250 @@ +/* ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include "../ec/internal.h" + + +size_t ECDSA_size(const EC_KEY *key) { + if (key == NULL) { + return 0; + } + + size_t group_order_size; + if (key->ecdsa_meth && key->ecdsa_meth->group_order_size) { + group_order_size = key->ecdsa_meth->group_order_size(key); + } else { + const EC_GROUP *group = EC_KEY_get0_group(key); + if (group == NULL) { + return 0; + } + + BIGNUM *order = BN_new(); + if (order == NULL) { + return 0; + } + if (!EC_GROUP_get_order(group, order, NULL)) { + BN_clear_free(order); + return 0; + } + + group_order_size = BN_num_bytes(order); + BN_clear_free(order); + } + + return ECDSA_SIG_max_len(group_order_size); +} + +ECDSA_SIG *ECDSA_SIG_new(void) { + ECDSA_SIG *sig = OPENSSL_malloc(sizeof(ECDSA_SIG)); + if (sig == NULL) { + return NULL; + } + sig->r = BN_new(); + sig->s = BN_new(); + if (sig->r == NULL || sig->s == NULL) { + ECDSA_SIG_free(sig); + return NULL; + } + return sig; +} + +void ECDSA_SIG_free(ECDSA_SIG *sig) { + if (sig == NULL) { + return; + } + + BN_free(sig->r); + BN_free(sig->s); + OPENSSL_free(sig); +} + +ECDSA_SIG *ECDSA_SIG_parse(CBS *cbs) { + ECDSA_SIG *ret = ECDSA_SIG_new(); + if (ret == NULL) { + return NULL; + } + CBS child; + if (!CBS_get_asn1(cbs, &child, CBS_ASN1_SEQUENCE) || + !BN_cbs2unsigned(&child, ret->r) || + !BN_cbs2unsigned(&child, ret->s) || + CBS_len(&child) != 0) { + OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_BAD_SIGNATURE); + ECDSA_SIG_free(ret); + return NULL; + } + return ret; +} + +ECDSA_SIG *ECDSA_SIG_from_bytes(const uint8_t *in, size_t in_len) { + CBS cbs; + CBS_init(&cbs, in, in_len); + ECDSA_SIG *ret = ECDSA_SIG_parse(&cbs); + if (ret == NULL || CBS_len(&cbs) != 0) { + OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_BAD_SIGNATURE); + ECDSA_SIG_free(ret); + return NULL; + } + return ret; +} + +int ECDSA_SIG_marshal(CBB *cbb, const ECDSA_SIG *sig) { + CBB child; + if (!CBB_add_asn1(cbb, &child, CBS_ASN1_SEQUENCE) || + !BN_bn2cbb(&child, sig->r) || + !BN_bn2cbb(&child, sig->s) || + !CBB_flush(cbb)) { + OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_ENCODE_ERROR); + return 0; + } + return 1; +} + +int ECDSA_SIG_to_bytes(uint8_t **out_bytes, size_t *out_len, + const ECDSA_SIG *sig) { + CBB cbb; + CBB_zero(&cbb); + if (!CBB_init(&cbb, 0) || + !ECDSA_SIG_marshal(&cbb, sig) || + !CBB_finish(&cbb, out_bytes, out_len)) { + OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_ENCODE_ERROR); + CBB_cleanup(&cbb); + return 0; + } + return 1; +} + +/* der_len_len returns the number of bytes needed to represent a length of |len| + * in DER. */ +static size_t der_len_len(size_t len) { + if (len < 0x80) { + return 1; + } + size_t ret = 1; + while (len > 0) { + ret++; + len >>= 8; + } + return ret; +} + +size_t ECDSA_SIG_max_len(size_t order_len) { + /* Compute the maximum length of an |order_len| byte integer. Defensively + * assume that the leading 0x00 is included. */ + size_t integer_len = 1 /* tag */ + der_len_len(order_len + 1) + 1 + order_len; + if (integer_len < order_len) { + return 0; + } + /* An ECDSA signature is two INTEGERs. */ + size_t value_len = 2 * integer_len; + if (value_len < integer_len) { + return 0; + } + /* Add the header. */ + size_t ret = 1 /* tag */ + der_len_len(value_len) + value_len; + if (ret < value_len) { + return 0; + } + return ret; +} + +ECDSA_SIG *d2i_ECDSA_SIG(ECDSA_SIG **out, const uint8_t **inp, long len) { + if (len < 0) { + return NULL; + } + CBS cbs; + CBS_init(&cbs, *inp, (size_t)len); + ECDSA_SIG *ret = ECDSA_SIG_parse(&cbs); + if (ret == NULL) { + return NULL; + } + if (out != NULL) { + ECDSA_SIG_free(*out); + *out = ret; + } + *inp += (size_t)len - CBS_len(&cbs); + return ret; +} + +int i2d_ECDSA_SIG(const ECDSA_SIG *sig, uint8_t **outp) { + uint8_t *der; + size_t der_len; + if (!ECDSA_SIG_to_bytes(&der, &der_len, sig)) { + return -1; + } + if (der_len > INT_MAX) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_OVERFLOW); + OPENSSL_free(der); + return -1; + } + if (outp != NULL) { + if (*outp == NULL) { + *outp = der; + der = NULL; + } else { + memcpy(*outp, der, der_len); + *outp += der_len; + } + } + OPENSSL_free(der); + return (int)der_len; +} diff --git a/TMessagesProj/jni/boringssl/crypto/engine/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/engine/CMakeLists.txt new file mode 100644 index 00000000..e03650e3 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/engine/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories(. .. ../../include) + +add_library( + engine + + OBJECT + + engine.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/engine/engine.c b/TMessagesProj/jni/boringssl/crypto/engine/engine.c new file mode 100644 index 00000000..6c3300d3 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/engine/engine.c @@ -0,0 +1,120 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +struct engine_st { + DH_METHOD *dh_method; + DSA_METHOD *dsa_method; + RSA_METHOD *rsa_method; + ECDSA_METHOD *ecdsa_method; +}; + +ENGINE *ENGINE_new(void) { + ENGINE *engine = OPENSSL_malloc(sizeof(ENGINE)); + if (engine == NULL) { + return NULL; + } + + memset(engine, 0, sizeof(ENGINE)); + return engine; +} + +void ENGINE_free(ENGINE *engine) { + /* Methods are currently required to be static so are not unref'ed. */ + OPENSSL_free(engine); +} + +/* set_method takes a pointer to a method and its given size and sets + * |*out_member| to point to it. This function might want to be extended in the + * future to support making a copy of the method so that a stable ABI for + * ENGINEs can be supported. But, for the moment, all *_METHODS must be + * static. */ +static int set_method(void **out_member, const void *method, size_t method_size, + size_t compiled_size) { + const struct openssl_method_common_st *common = method; + if (method_size != compiled_size || !common->is_static) { + return 0; + } + + *out_member = (void*) method; + return 1; +} + +int ENGINE_set_DH_method(ENGINE *engine, const DH_METHOD *method, + size_t method_size) { + return set_method((void **)&engine->dh_method, method, method_size, + sizeof(DH_METHOD)); +} + +DH_METHOD *ENGINE_get_DH_method(const ENGINE *engine) { + return engine->dh_method; +} + +int ENGINE_set_DSA_method(ENGINE *engine, const DSA_METHOD *method, + size_t method_size) { + return set_method((void **)&engine->dsa_method, method, method_size, + sizeof(DSA_METHOD)); +} + +DSA_METHOD *ENGINE_get_DSA_method(const ENGINE *engine) { + return engine->dsa_method; +} + +int ENGINE_set_RSA_method(ENGINE *engine, const RSA_METHOD *method, + size_t method_size) { + return set_method((void **)&engine->rsa_method, method, method_size, + sizeof(RSA_METHOD)); +} + +RSA_METHOD *ENGINE_get_RSA_method(const ENGINE *engine) { + return engine->rsa_method; +} + +int ENGINE_set_ECDSA_method(ENGINE *engine, const ECDSA_METHOD *method, + size_t method_size) { + return set_method((void **)&engine->ecdsa_method, method, method_size, + sizeof(ECDSA_METHOD)); +} + +ECDSA_METHOD *ENGINE_get_ECDSA_method(const ENGINE *engine) { + return engine->ecdsa_method; +} + +void METHOD_ref(void *method_in) { + assert(((struct openssl_method_common_st*) method_in)->is_static); +} + +void METHOD_unref(void *method_in) { + struct openssl_method_common_st *method = method_in; + + if (method == NULL) { + return; + } + assert(method->is_static); +} + +OPENSSL_DECLARE_ERROR_REASON(ENGINE, OPERATION_NOT_SUPPORTED); diff --git a/TMessagesProj/jni/boringssl/crypto/err/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/err/CMakeLists.txt new file mode 100644 index 00000000..0a617b7b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/CMakeLists.txt @@ -0,0 +1,40 @@ +include_directories(. .. ../../include) + +add_custom_command( + OUTPUT err_data.c + COMMAND ${GO_EXECUTABLE} run err_data_generate.go > ${CMAKE_CURRENT_BINARY_DIR}/err_data.c + DEPENDS + err_data_generate.go + asn1.errordata + bio.errordata + bn.errordata + cipher.errordata + conf.errordata + dh.errordata + digest.errordata + dsa.errordata + ecdh.errordata + ecdsa.errordata + ec.errordata + engine.errordata + evp.errordata + hkdf.errordata + obj.errordata + pem.errordata + pkcs8.errordata + rsa.errordata + ssl.errordata + x509.errordata + x509v3.errordata + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +) + +add_library( + err + + OBJECT + + err.c + err_data.c +) + diff --git a/TMessagesProj/jni/boringssl/crypto/err/asn1.errordata b/TMessagesProj/jni/boringssl/crypto/err/asn1.errordata new file mode 100644 index 00000000..55342a09 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/asn1.errordata @@ -0,0 +1,88 @@ +ASN1,100,ASN1_LENGTH_MISMATCH +ASN1,101,AUX_ERROR +ASN1,102,BAD_GET_ASN1_OBJECT_CALL +ASN1,103,BAD_OBJECT_HEADER +ASN1,104,BMPSTRING_IS_WRONG_LENGTH +ASN1,105,BN_LIB +ASN1,106,BOOLEAN_IS_WRONG_LENGTH +ASN1,107,BUFFER_TOO_SMALL +ASN1,108,DECODE_ERROR +ASN1,109,DEPTH_EXCEEDED +ASN1,110,ENCODE_ERROR +ASN1,111,ERROR_GETTING_TIME +ASN1,112,EXPECTING_AN_ASN1_SEQUENCE +ASN1,113,EXPECTING_AN_INTEGER +ASN1,114,EXPECTING_AN_OBJECT +ASN1,115,EXPECTING_A_BOOLEAN +ASN1,116,EXPECTING_A_TIME +ASN1,117,EXPLICIT_LENGTH_MISMATCH +ASN1,118,EXPLICIT_TAG_NOT_CONSTRUCTED +ASN1,119,FIELD_MISSING +ASN1,120,FIRST_NUM_TOO_LARGE +ASN1,121,HEADER_TOO_LONG +ASN1,122,ILLEGAL_BITSTRING_FORMAT +ASN1,123,ILLEGAL_BOOLEAN +ASN1,124,ILLEGAL_CHARACTERS +ASN1,125,ILLEGAL_FORMAT +ASN1,126,ILLEGAL_HEX +ASN1,127,ILLEGAL_IMPLICIT_TAG +ASN1,128,ILLEGAL_INTEGER +ASN1,129,ILLEGAL_NESTED_TAGGING +ASN1,130,ILLEGAL_NULL +ASN1,131,ILLEGAL_NULL_VALUE +ASN1,132,ILLEGAL_OBJECT +ASN1,133,ILLEGAL_OPTIONAL_ANY +ASN1,134,ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE +ASN1,135,ILLEGAL_TAGGED_ANY +ASN1,136,ILLEGAL_TIME_VALUE +ASN1,137,INTEGER_NOT_ASCII_FORMAT +ASN1,138,INTEGER_TOO_LARGE_FOR_LONG +ASN1,139,INVALID_BIT_STRING_BITS_LEFT +ASN1,140,INVALID_BMPSTRING_LENGTH +ASN1,141,INVALID_DIGIT +ASN1,142,INVALID_MODIFIER +ASN1,143,INVALID_NUMBER +ASN1,144,INVALID_OBJECT_ENCODING +ASN1,145,INVALID_SEPARATOR +ASN1,146,INVALID_TIME_FORMAT +ASN1,147,INVALID_UNIVERSALSTRING_LENGTH +ASN1,148,INVALID_UTF8STRING +ASN1,149,LIST_ERROR +ASN1,150,MALLOC_FAILURE +ASN1,151,MISSING_ASN1_EOS +ASN1,152,MISSING_EOC +ASN1,153,MISSING_SECOND_NUMBER +ASN1,154,MISSING_VALUE +ASN1,155,MSTRING_NOT_UNIVERSAL +ASN1,156,MSTRING_WRONG_TAG +ASN1,157,NESTED_ASN1_ERROR +ASN1,158,NESTED_ASN1_STRING +ASN1,159,NON_HEX_CHARACTERS +ASN1,160,NOT_ASCII_FORMAT +ASN1,161,NOT_ENOUGH_DATA +ASN1,162,NO_MATCHING_CHOICE_TYPE +ASN1,163,NULL_IS_WRONG_LENGTH +ASN1,164,OBJECT_NOT_ASCII_FORMAT +ASN1,165,ODD_NUMBER_OF_CHARS +ASN1,166,SECOND_NUMBER_TOO_LARGE +ASN1,167,SEQUENCE_LENGTH_MISMATCH +ASN1,168,SEQUENCE_NOT_CONSTRUCTED +ASN1,169,SEQUENCE_OR_SET_NEEDS_CONFIG +ASN1,170,SHORT_LINE +ASN1,171,STREAMING_NOT_SUPPORTED +ASN1,172,STRING_TOO_LONG +ASN1,173,STRING_TOO_SHORT +ASN1,174,TAG_VALUE_TOO_HIGH +ASN1,175,TIME_NOT_ASCII_FORMAT +ASN1,176,TOO_LONG +ASN1,177,TYPE_NOT_CONSTRUCTED +ASN1,178,TYPE_NOT_PRIMITIVE +ASN1,179,UNEXPECTED_EOC +ASN1,180,UNIVERSALSTRING_IS_WRONG_LENGTH +ASN1,181,UNKNOWN_FORMAT +ASN1,182,UNKNOWN_TAG +ASN1,183,UNSUPPORTED_ANY_DEFINED_BY_TYPE +ASN1,184,UNSUPPORTED_PUBLIC_KEY_TYPE +ASN1,185,UNSUPPORTED_TYPE +ASN1,186,WRONG_TAG +ASN1,187,WRONG_TYPE diff --git a/TMessagesProj/jni/boringssl/crypto/err/bio.errordata b/TMessagesProj/jni/boringssl/crypto/err/bio.errordata new file mode 100644 index 00000000..94b3c971 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/bio.errordata @@ -0,0 +1,17 @@ +BIO,100,BAD_FOPEN_MODE +BIO,101,BROKEN_PIPE +BIO,102,CONNECT_ERROR +BIO,103,ERROR_SETTING_NBIO +BIO,104,INVALID_ARGUMENT +BIO,105,IN_USE +BIO,106,KEEPALIVE +BIO,107,NBIO_CONNECT_ERROR +BIO,108,NO_HOSTNAME_SPECIFIED +BIO,109,NO_PORT_SPECIFIED +BIO,110,NO_SUCH_FILE +BIO,111,NULL_PARAMETER +BIO,112,SYS_LIB +BIO,113,UNABLE_TO_CREATE_SOCKET +BIO,114,UNINITIALIZED +BIO,115,UNSUPPORTED_METHOD +BIO,116,WRITE_TO_READ_ONLY_BIO diff --git a/TMessagesProj/jni/boringssl/crypto/err/bn.errordata b/TMessagesProj/jni/boringssl/crypto/err/bn.errordata new file mode 100644 index 00000000..76b63925 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/bn.errordata @@ -0,0 +1,19 @@ +BN,100,ARG2_LT_ARG3 +BN,117,BAD_ENCODING +BN,101,BAD_RECIPROCAL +BN,102,BIGNUM_TOO_LONG +BN,103,BITS_TOO_SMALL +BN,104,CALLED_WITH_EVEN_MODULUS +BN,105,DIV_BY_ZERO +BN,118,ENCODE_ERROR +BN,106,EXPAND_ON_STATIC_BIGNUM_DATA +BN,107,INPUT_NOT_REDUCED +BN,108,INVALID_RANGE +BN,109,NEGATIVE_NUMBER +BN,110,NOT_A_SQUARE +BN,111,NOT_INITIALIZED +BN,112,NO_INVERSE +BN,113,PRIVATE_KEY_TOO_LARGE +BN,114,P_IS_NOT_PRIME +BN,115,TOO_MANY_ITERATIONS +BN,116,TOO_MANY_TEMPORARY_VARIABLES diff --git a/TMessagesProj/jni/boringssl/crypto/err/cipher.errordata b/TMessagesProj/jni/boringssl/crypto/err/cipher.errordata new file mode 100644 index 00000000..10375055 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/cipher.errordata @@ -0,0 +1,25 @@ +CIPHER,100,AES_KEY_SETUP_FAILED +CIPHER,101,BAD_DECRYPT +CIPHER,102,BAD_KEY_LENGTH +CIPHER,103,BUFFER_TOO_SMALL +CIPHER,104,CTRL_NOT_IMPLEMENTED +CIPHER,105,CTRL_OPERATION_NOT_IMPLEMENTED +CIPHER,106,DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH +CIPHER,107,INITIALIZATION_ERROR +CIPHER,108,INPUT_NOT_INITIALIZED +CIPHER,109,INVALID_AD_SIZE +CIPHER,110,INVALID_KEY_LENGTH +CIPHER,111,INVALID_NONCE_SIZE +CIPHER,112,INVALID_OPERATION +CIPHER,113,IV_TOO_LARGE +CIPHER,114,NO_CIPHER_SET +CIPHER,124,NO_DIRECTION_SET +CIPHER,115,OUTPUT_ALIASES_INPUT +CIPHER,116,TAG_TOO_LARGE +CIPHER,117,TOO_LARGE +CIPHER,118,UNSUPPORTED_AD_SIZE +CIPHER,119,UNSUPPORTED_INPUT_SIZE +CIPHER,120,UNSUPPORTED_KEY_SIZE +CIPHER,121,UNSUPPORTED_NONCE_SIZE +CIPHER,122,UNSUPPORTED_TAG_SIZE +CIPHER,123,WRONG_FINAL_BLOCK_LENGTH diff --git a/TMessagesProj/jni/boringssl/crypto/err/conf.errordata b/TMessagesProj/jni/boringssl/crypto/err/conf.errordata new file mode 100644 index 00000000..651fabe1 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/conf.errordata @@ -0,0 +1,6 @@ +CONF,100,LIST_CANNOT_BE_NULL +CONF,101,MISSING_CLOSE_SQUARE_BRACKET +CONF,102,MISSING_EQUAL_SIGN +CONF,103,NO_CLOSE_BRACE +CONF,104,UNABLE_TO_CREATE_NEW_SECTION +CONF,105,VARIABLE_HAS_NO_VALUE diff --git a/TMessagesProj/jni/boringssl/crypto/err/dh.errordata b/TMessagesProj/jni/boringssl/crypto/err/dh.errordata new file mode 100644 index 00000000..571e218a --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/dh.errordata @@ -0,0 +1,4 @@ +DH,100,BAD_GENERATOR +DH,101,INVALID_PUBKEY +DH,102,MODULUS_TOO_LARGE +DH,103,NO_PRIVATE_VALUE diff --git a/TMessagesProj/jni/boringssl/crypto/err/digest.errordata b/TMessagesProj/jni/boringssl/crypto/err/digest.errordata new file mode 100644 index 00000000..411e778b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/digest.errordata @@ -0,0 +1 @@ +DIGEST,100,INPUT_NOT_INITIALIZED diff --git a/TMessagesProj/jni/boringssl/crypto/err/dsa.errordata b/TMessagesProj/jni/boringssl/crypto/err/dsa.errordata new file mode 100644 index 00000000..3c5764a1 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/dsa.errordata @@ -0,0 +1,4 @@ +DSA,100,BAD_Q_VALUE +DSA,101,MISSING_PARAMETERS +DSA,102,MODULUS_TOO_LARGE +DSA,103,NEED_NEW_SETUP_VALUES diff --git a/TMessagesProj/jni/boringssl/crypto/err/ec.errordata b/TMessagesProj/jni/boringssl/crypto/err/ec.errordata new file mode 100644 index 00000000..e7b41756 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/ec.errordata @@ -0,0 +1,28 @@ +EC,126,BIGNUM_OUT_OF_RANGE +EC,100,BUFFER_TOO_SMALL +EC,101,COORDINATES_OUT_OF_RANGE +EC,102,D2I_ECPKPARAMETERS_FAILURE +EC,103,EC_GROUP_NEW_BY_NAME_FAILURE +EC,104,GROUP2PKPARAMETERS_FAILURE +EC,105,I2D_ECPKPARAMETERS_FAILURE +EC,106,INCOMPATIBLE_OBJECTS +EC,107,INVALID_COMPRESSED_POINT +EC,108,INVALID_COMPRESSION_BIT +EC,109,INVALID_ENCODING +EC,110,INVALID_FIELD +EC,111,INVALID_FORM +EC,112,INVALID_GROUP_ORDER +EC,113,INVALID_PRIVATE_KEY +EC,114,MISSING_PARAMETERS +EC,115,MISSING_PRIVATE_KEY +EC,116,NON_NAMED_CURVE +EC,117,NOT_INITIALIZED +EC,118,PKPARAMETERS2GROUP_FAILURE +EC,119,POINT_AT_INFINITY +EC,120,POINT_IS_NOT_ON_CURVE +EC,121,SLOT_FULL +EC,122,UNDEFINED_GENERATOR +EC,123,UNKNOWN_GROUP +EC,124,UNKNOWN_ORDER +EC,127,WRONG_CURVE_PARAMETERS +EC,125,WRONG_ORDER diff --git a/TMessagesProj/jni/boringssl/crypto/err/ecdh.errordata b/TMessagesProj/jni/boringssl/crypto/err/ecdh.errordata new file mode 100644 index 00000000..f714c304 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/ecdh.errordata @@ -0,0 +1,3 @@ +ECDH,100,KDF_FAILED +ECDH,101,NO_PRIVATE_VALUE +ECDH,102,POINT_ARITHMETIC_FAILURE diff --git a/TMessagesProj/jni/boringssl/crypto/err/ecdsa.errordata b/TMessagesProj/jni/boringssl/crypto/err/ecdsa.errordata new file mode 100644 index 00000000..58ba591f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/ecdsa.errordata @@ -0,0 +1,6 @@ +ECDSA,100,BAD_SIGNATURE +ECDSA,105,ENCODE_ERROR +ECDSA,101,MISSING_PARAMETERS +ECDSA,102,NEED_NEW_SETUP_VALUES +ECDSA,103,NOT_IMPLEMENTED +ECDSA,104,RANDOM_NUMBER_GENERATION_FAILED diff --git a/TMessagesProj/jni/boringssl/crypto/err/engine.errordata b/TMessagesProj/jni/boringssl/crypto/err/engine.errordata new file mode 100644 index 00000000..edbd7b97 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/engine.errordata @@ -0,0 +1 @@ +ENGINE,100,OPERATION_NOT_SUPPORTED diff --git a/TMessagesProj/jni/boringssl/crypto/err/err.c b/TMessagesProj/jni/boringssl/crypto/err/err.c new file mode 100644 index 00000000..24824e83 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/err.c @@ -0,0 +1,775 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include +#include + +#if defined(OPENSSL_WINDOWS) +#pragma warning(push, 3) +#include +#pragma warning(pop) +#endif + +#include +#include + +#include "../internal.h" + + +extern const uint32_t kOpenSSLReasonValues[]; +extern const size_t kOpenSSLReasonValuesLen; +extern const char kOpenSSLReasonStringData[]; + +/* err_clear_data frees the optional |data| member of the given error. */ +static void err_clear_data(struct err_error_st *error) { + if ((error->flags & ERR_FLAG_MALLOCED) != 0) { + OPENSSL_free(error->data); + } + error->data = NULL; + error->flags &= ~ERR_FLAG_MALLOCED; +} + +/* err_clear clears the given queued error. */ +static void err_clear(struct err_error_st *error) { + err_clear_data(error); + memset(error, 0, sizeof(struct err_error_st)); +} + +/* global_next_library contains the next custom library value to return. */ +static int global_next_library = ERR_NUM_LIBS; + +/* global_next_library_mutex protects |global_next_library| from concurrent + * updates. */ +static struct CRYPTO_STATIC_MUTEX global_next_library_mutex = + CRYPTO_STATIC_MUTEX_INIT; + +static void err_state_free(void *statep) { + ERR_STATE *state = statep; + + if (state == NULL) { + return; + } + + unsigned i; + for (i = 0; i < ERR_NUM_ERRORS; i++) { + err_clear(&state->errors[i]); + } + OPENSSL_free(state->to_free); + OPENSSL_free(state); +} + +/* err_get_state gets the ERR_STATE object for the current thread. */ +static ERR_STATE *err_get_state(void) { + ERR_STATE *state = CRYPTO_get_thread_local(OPENSSL_THREAD_LOCAL_ERR); + if (state == NULL) { + state = OPENSSL_malloc(sizeof(ERR_STATE)); + if (state == NULL) { + return NULL; + } + memset(state, 0, sizeof(ERR_STATE)); + if (!CRYPTO_set_thread_local(OPENSSL_THREAD_LOCAL_ERR, state, + err_state_free)) { + return NULL; + } + } + + return state; +} + +static uint32_t get_error_values(int inc, int top, const char **file, int *line, + const char **data, int *flags) { + unsigned i = 0; + ERR_STATE *state; + struct err_error_st *error; + uint32_t ret; + + state = err_get_state(); + if (state == NULL || state->bottom == state->top) { + return 0; + } + + if (top) { + assert(!inc); + /* last error */ + i = state->top; + } else { + i = (state->bottom + 1) % ERR_NUM_ERRORS; + } + + error = &state->errors[i]; + ret = error->packed; + + if (file != NULL && line != NULL) { + if (error->file == NULL) { + *file = "NA"; + *line = 0; + } else { + *file = error->file; + *line = error->line; + } + } + + if (data != NULL) { + if (error->data == NULL) { + *data = ""; + if (flags != NULL) { + *flags = 0; + } + } else { + *data = error->data; + if (flags != NULL) { + *flags = error->flags & ERR_FLAG_PUBLIC_MASK; + } + /* If this error is being removed, take ownership of data from + * the error. The semantics are such that the caller doesn't + * take ownership either. Instead the error system takes + * ownership and retains it until the next call that affects the + * error queue. */ + if (inc) { + if (error->flags & ERR_FLAG_MALLOCED) { + OPENSSL_free(state->to_free); + state->to_free = error->data; + } + error->data = NULL; + error->flags = 0; + } + } + } + + if (inc) { + assert(!top); + err_clear(error); + state->bottom = i; + } + + return ret; +} + +uint32_t ERR_get_error(void) { + return get_error_values(1 /* inc */, 0 /* bottom */, NULL, NULL, NULL, NULL); +} + +uint32_t ERR_get_error_line(const char **file, int *line) { + return get_error_values(1 /* inc */, 0 /* bottom */, file, line, NULL, NULL); +} + +uint32_t ERR_get_error_line_data(const char **file, int *line, + const char **data, int *flags) { + return get_error_values(1 /* inc */, 0 /* bottom */, file, line, data, flags); +} + +uint32_t ERR_peek_error(void) { + return get_error_values(0 /* peek */, 0 /* bottom */, NULL, NULL, NULL, NULL); +} + +uint32_t ERR_peek_error_line(const char **file, int *line) { + return get_error_values(0 /* peek */, 0 /* bottom */, file, line, NULL, NULL); +} + +uint32_t ERR_peek_error_line_data(const char **file, int *line, + const char **data, int *flags) { + return get_error_values(0 /* peek */, 0 /* bottom */, file, line, data, + flags); +} + +const char *ERR_peek_function(void) { + ERR_STATE *state = err_get_state(); + if (state == NULL || state->bottom == state->top) { + return NULL; + } + return state->errors[(state->bottom + 1) % ERR_NUM_ERRORS].function; +} + +uint32_t ERR_peek_last_error(void) { + return get_error_values(0 /* peek */, 1 /* top */, NULL, NULL, NULL, NULL); +} + +uint32_t ERR_peek_last_error_line(const char **file, int *line) { + return get_error_values(0 /* peek */, 1 /* top */, file, line, NULL, NULL); +} + +uint32_t ERR_peek_last_error_line_data(const char **file, int *line, + const char **data, int *flags) { + return get_error_values(0 /* peek */, 1 /* top */, file, line, data, flags); +} + +void ERR_clear_error(void) { + ERR_STATE *const state = err_get_state(); + unsigned i; + + if (state == NULL) { + return; + } + + for (i = 0; i < ERR_NUM_ERRORS; i++) { + err_clear(&state->errors[i]); + } + OPENSSL_free(state->to_free); + state->to_free = NULL; + + state->top = state->bottom = 0; +} + +void ERR_remove_thread_state(const CRYPTO_THREADID *tid) { + if (tid != NULL) { + assert(0); + return; + } + + ERR_clear_error(); +} + +int ERR_get_next_error_library(void) { + int ret; + + CRYPTO_STATIC_MUTEX_lock_write(&global_next_library_mutex); + ret = global_next_library++; + CRYPTO_STATIC_MUTEX_unlock(&global_next_library_mutex); + + return ret; +} + +void ERR_remove_state(unsigned long pid) { + ERR_clear_error(); +} + +void ERR_clear_system_error(void) { + errno = 0; +} + +static void err_error_string(uint32_t packed_error, const char *func_str, + char *buf, size_t len) { + char lib_buf[64], reason_buf[64]; + const char *lib_str, *reason_str; + unsigned lib, reason; + + if (len == 0) { + return; + } + + lib = ERR_GET_LIB(packed_error); + reason = ERR_GET_REASON(packed_error); + + lib_str = ERR_lib_error_string(packed_error); + reason_str = ERR_reason_error_string(packed_error); + + if (lib_str == NULL) { + BIO_snprintf(lib_buf, sizeof(lib_buf), "lib(%u)", lib); + lib_str = lib_buf; + } + + if (func_str == NULL) { + func_str = "OPENSSL_internal"; + } + + if (reason_str == NULL) { + BIO_snprintf(reason_buf, sizeof(reason_buf), "reason(%u)", reason); + reason_str = reason_buf; + } + + BIO_snprintf(buf, len, "error:%08" PRIx32 ":%s:%s:%s", + packed_error, lib_str, func_str, reason_str); + + if (strlen(buf) == len - 1) { + /* output may be truncated; make sure we always have 5 colon-separated + * fields, i.e. 4 colons. */ + static const unsigned num_colons = 4; + unsigned i; + char *s = buf; + + if (len <= num_colons) { + /* In this situation it's not possible to ensure that the correct number + * of colons are included in the output. */ + return; + } + + for (i = 0; i < num_colons; i++) { + char *colon = strchr(s, ':'); + char *last_pos = &buf[len - 1] - num_colons + i; + + if (colon == NULL || colon > last_pos) { + /* set colon |i| at last possible position (buf[len-1] is the + * terminating 0). If we're setting this colon, then all whole of the + * rest of the string must be colons in order to have the correct + * number. */ + memset(last_pos, ':', num_colons - i); + break; + } + + s = colon + 1; + } + } +} + +char *ERR_error_string(uint32_t packed_error, char *ret) { + static char buf[ERR_ERROR_STRING_BUF_LEN]; + + if (ret == NULL) { + /* TODO(fork): remove this. */ + ret = buf; + } + +#if !defined(NDEBUG) + /* This is aimed to help catch callers who don't provide + * |ERR_ERROR_STRING_BUF_LEN| bytes of space. */ + memset(ret, 0, ERR_ERROR_STRING_BUF_LEN); +#endif + + ERR_error_string_n(packed_error, ret, ERR_ERROR_STRING_BUF_LEN); + + return ret; +} + +void ERR_error_string_n(uint32_t packed_error, char *buf, size_t len) { + err_error_string(packed_error, NULL, buf, len); +} + +// err_string_cmp is a compare function for searching error values with +// |bsearch| in |err_string_lookup|. +static int err_string_cmp(const void *a, const void *b) { + const uint32_t a_key = *((const uint32_t*) a) >> 15; + const uint32_t b_key = *((const uint32_t*) b) >> 15; + + if (a_key < b_key) { + return -1; + } else if (a_key > b_key) { + return 1; + } else { + return 0; + } +} + +/* err_string_lookup looks up the string associated with |lib| and |key| in + * |values| and |string_data|. It returns the string or NULL if not found. */ +static const char *err_string_lookup(uint32_t lib, uint32_t key, + const uint32_t *values, + size_t num_values, + const char *string_data) { + /* |values| points to data in err_data.h, which is generated by + * err_data_generate.go. It's an array of uint32_t values. Each value has the + * following structure: + * | lib | key | offset | + * |6 bits| 11 bits | 15 bits | + * + * The |lib| value is a library identifier: one of the |ERR_LIB_*| values. + * The |key| is either a function or a reason code, depending on the context. + * The |offset| is the number of bytes from the start of |string_data| where + * the (NUL terminated) string for this value can be found. + * + * Values are sorted based on treating the |lib| and |key| part as an + * unsigned integer. */ + if (lib >= (1 << 6) || key >= (1 << 11)) { + return NULL; + } + uint32_t search_key = lib << 26 | key << 15; + const uint32_t *result = bsearch(&search_key, values, num_values, + sizeof(uint32_t), err_string_cmp); + if (result == NULL) { + return NULL; + } + + return &string_data[(*result) & 0x7fff]; +} + +static const char *const kLibraryNames[ERR_NUM_LIBS] = { + "invalid library (0)", + "unknown library", /* ERR_LIB_NONE */ + "system library", /* ERR_LIB_SYS */ + "bignum routines", /* ERR_LIB_BN */ + "RSA routines", /* ERR_LIB_RSA */ + "Diffie-Hellman routines", /* ERR_LIB_DH */ + "public key routines", /* ERR_LIB_EVP */ + "memory buffer routines", /* ERR_LIB_BUF */ + "object identifier routines", /* ERR_LIB_OBJ */ + "PEM routines", /* ERR_LIB_PEM */ + "DSA routines", /* ERR_LIB_DSA */ + "X.509 certificate routines", /* ERR_LIB_X509 */ + "ASN.1 encoding routines", /* ERR_LIB_ASN1 */ + "configuration file routines", /* ERR_LIB_CONF */ + "common libcrypto routines", /* ERR_LIB_CRYPTO */ + "elliptic curve routines", /* ERR_LIB_EC */ + "SSL routines", /* ERR_LIB_SSL */ + "BIO routines", /* ERR_LIB_BIO */ + "PKCS7 routines", /* ERR_LIB_PKCS7 */ + "PKCS8 routines", /* ERR_LIB_PKCS8 */ + "X509 V3 routines", /* ERR_LIB_X509V3 */ + "random number generator", /* ERR_LIB_RAND */ + "ENGINE routines", /* ERR_LIB_ENGINE */ + "OCSP routines", /* ERR_LIB_OCSP */ + "UI routines", /* ERR_LIB_UI */ + "COMP routines", /* ERR_LIB_COMP */ + "ECDSA routines", /* ERR_LIB_ECDSA */ + "ECDH routines", /* ERR_LIB_ECDH */ + "HMAC routines", /* ERR_LIB_HMAC */ + "Digest functions", /* ERR_LIB_DIGEST */ + "Cipher functions", /* ERR_LIB_CIPHER */ + "HKDF functions", /* ERR_LIB_HKDF */ + "User defined functions", /* ERR_LIB_USER */ +}; + +const char *ERR_lib_error_string(uint32_t packed_error) { + const uint32_t lib = ERR_GET_LIB(packed_error); + + if (lib >= ERR_NUM_LIBS) { + return NULL; + } + return kLibraryNames[lib]; +} + +const char *ERR_func_error_string(uint32_t packed_error) { + return "OPENSSL_internal"; +} + +const char *ERR_reason_error_string(uint32_t packed_error) { + const uint32_t lib = ERR_GET_LIB(packed_error); + const uint32_t reason = ERR_GET_REASON(packed_error); + + if (lib == ERR_LIB_SYS) { + if (reason < 127) { + return strerror(reason); + } + return NULL; + } + + if (reason < ERR_NUM_LIBS) { + return kLibraryNames[reason]; + } + + if (reason < 100) { + switch (reason) { + case ERR_R_MALLOC_FAILURE: + return "malloc failure"; + case ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED: + return "function should not have been called"; + case ERR_R_PASSED_NULL_PARAMETER: + return "passed a null parameter"; + case ERR_R_INTERNAL_ERROR: + return "internal error"; + case ERR_R_OVERFLOW: + return "overflow"; + default: + return NULL; + } + } + + return err_string_lookup(lib, reason, kOpenSSLReasonValues, + kOpenSSLReasonValuesLen, kOpenSSLReasonStringData); +} + +void ERR_print_errors_cb(ERR_print_errors_callback_t callback, void *ctx) { + char buf[ERR_ERROR_STRING_BUF_LEN]; + char buf2[1024]; + const char *file, *data; + int line, flags; + uint32_t packed_error; + + /* thread_hash is the least-significant bits of the |ERR_STATE| pointer value + * for this thread. */ + const unsigned long thread_hash = (uintptr_t) err_get_state(); + + for (;;) { + const char *function = ERR_peek_function(); + packed_error = ERR_get_error_line_data(&file, &line, &data, &flags); + if (packed_error == 0) { + break; + } + + err_error_string(packed_error, function, buf, sizeof(buf)); + BIO_snprintf(buf2, sizeof(buf2), "%lu:%s:%s:%d:%s\n", thread_hash, buf, + file, line, (flags & ERR_FLAG_STRING) ? data : ""); + if (callback(buf2, strlen(buf2), ctx) <= 0) { + break; + } + } +} + +static int print_errors_to_file(const char* msg, size_t msg_len, void* ctx) { + assert(msg[msg_len] == '\0'); + FILE* fp = ctx; + int res = fputs(msg, fp); + return res < 0 ? 0 : 1; +} + +void ERR_print_errors_fp(FILE *file) { + ERR_print_errors_cb(print_errors_to_file, file); +} + +/* err_set_error_data sets the data on the most recent error. The |flags| + * argument is a combination of the |ERR_FLAG_*| values. */ +static void err_set_error_data(char *data, int flags) { + ERR_STATE *const state = err_get_state(); + struct err_error_st *error; + + if (state == NULL || state->top == state->bottom) { + if (flags & ERR_FLAG_MALLOCED) { + OPENSSL_free(data); + } + return; + } + + error = &state->errors[state->top]; + + err_clear_data(error); + error->data = data; + error->flags = flags; +} + +void ERR_put_error(int library, int reason, const char *function, + const char *file, unsigned line) { + ERR_STATE *const state = err_get_state(); + struct err_error_st *error; + + if (state == NULL) { + return; + } + + if (library == ERR_LIB_SYS && reason == 0) { +#if defined(OPENSSL_WINDOWS) + reason = GetLastError(); +#else + reason = errno; +#endif + } + + state->top = (state->top + 1) % ERR_NUM_ERRORS; + if (state->top == state->bottom) { + state->bottom = (state->bottom + 1) % ERR_NUM_ERRORS; + } + + error = &state->errors[state->top]; + err_clear(error); + error->function = function; + error->file = file; + error->line = line; + error->packed = ERR_PACK(library, reason); +} + +/* ERR_add_error_data_vdata takes a variable number of const char* pointers, + * concatenates them and sets the result as the data on the most recent + * error. */ +static void err_add_error_vdata(unsigned num, va_list args) { + size_t alloced, new_len, len = 0, substr_len; + char *buf; + const char *substr; + unsigned i; + + alloced = 80; + buf = OPENSSL_malloc(alloced + 1); + if (buf == NULL) { + return; + } + + for (i = 0; i < num; i++) { + substr = va_arg(args, const char *); + if (substr == NULL) { + continue; + } + + substr_len = strlen(substr); + new_len = len + substr_len; + if (new_len > alloced) { + char *new_buf; + + if (alloced + 20 + 1 < alloced) { + /* overflow. */ + OPENSSL_free(buf); + return; + } + + alloced = new_len + 20; + new_buf = OPENSSL_realloc(buf, alloced + 1); + if (new_buf == NULL) { + OPENSSL_free(buf); + return; + } + buf = new_buf; + } + + memcpy(buf + len, substr, substr_len); + len = new_len; + } + + buf[len] = 0; + err_set_error_data(buf, ERR_FLAG_MALLOCED | ERR_FLAG_STRING); +} + +void ERR_add_error_data(unsigned count, ...) { + va_list args; + va_start(args, count); + err_add_error_vdata(count, args); + va_end(args); +} + +void ERR_add_error_dataf(const char *format, ...) { + va_list ap; + char *buf; + static const unsigned buf_len = 256; + + /* A fixed-size buffer is used because va_copy (which would be needed in + * order to call vsnprintf twice and measure the buffer) wasn't defined until + * C99. */ + buf = OPENSSL_malloc(buf_len + 1); + if (buf == NULL) { + return; + } + + va_start(ap, format); + BIO_vsnprintf(buf, buf_len, format, ap); + buf[buf_len] = 0; + va_end(ap); + + err_set_error_data(buf, ERR_FLAG_MALLOCED | ERR_FLAG_STRING); +} + +int ERR_set_mark(void) { + ERR_STATE *const state = err_get_state(); + + if (state == NULL || state->bottom == state->top) { + return 0; + } + state->errors[state->top].flags |= ERR_FLAG_MARK; + return 1; +} + +int ERR_pop_to_mark(void) { + ERR_STATE *const state = err_get_state(); + + if (state == NULL) { + return 0; + } + + while (state->bottom != state->top) { + struct err_error_st *error = &state->errors[state->top]; + + if ((error->flags & ERR_FLAG_MARK) != 0) { + error->flags &= ~ERR_FLAG_MARK; + return 1; + } + + err_clear(error); + if (state->top == 0) { + state->top = ERR_NUM_ERRORS - 1; + } else { + state->top--; + } + } + + return 0; +} + +void ERR_load_crypto_strings(void) {} + +void ERR_free_strings(void) {} + +void ERR_load_BIO_strings(void) {} + +void ERR_load_ERR_strings(void) {} diff --git a/TMessagesProj/jni/boringssl/crypto/err/err_data_generate.go b/TMessagesProj/jni/boringssl/crypto/err/err_data_generate.go new file mode 100644 index 00000000..24e0d66f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/err_data_generate.go @@ -0,0 +1,277 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +package main + +import ( + "bufio" + "bytes" + "errors" + "fmt" + "io" + "os" + "sort" + "strconv" + "strings" +) + +// libraryNames must be kept in sync with the enum in err.h. The generated code +// will contain static assertions to enforce this. +var libraryNames = []string{ + "NONE", + "SYS", + "BN", + "RSA", + "DH", + "EVP", + "BUF", + "OBJ", + "PEM", + "DSA", + "X509", + "ASN1", + "CONF", + "CRYPTO", + "EC", + "SSL", + "BIO", + "PKCS7", + "PKCS8", + "X509V3", + "RAND", + "ENGINE", + "OCSP", + "UI", + "COMP", + "ECDSA", + "ECDH", + "HMAC", + "DIGEST", + "CIPHER", + "HKDF", + "USER", +} + +// stringList is a map from uint32 -> string which can output data for a sorted +// list as C literals. +type stringList struct { + // entries is an array of keys and offsets into |stringData|. The + // offsets are in the bottom 15 bits of each uint32 and the key is the + // top 17 bits. + entries []uint32 + // internedStrings contains the same strings as are in |stringData|, + // but allows for easy deduplication. It maps a string to its offset in + // |stringData|. + internedStrings map[string]uint32 + stringData []byte +} + +func newStringList() *stringList { + return &stringList{ + internedStrings: make(map[string]uint32), + } +} + +// offsetMask is the bottom 15 bits. It's a mask that selects the offset from a +// uint32 in entries. +const offsetMask = 0x7fff + +func (st *stringList) Add(key uint32, value string) error { + if key&offsetMask != 0 { + return errors.New("need bottom 15 bits of the key for the offset") + } + offset, ok := st.internedStrings[value] + if !ok { + offset = uint32(len(st.stringData)) + if offset&offsetMask != offset { + return errors.New("stringList overflow") + } + st.stringData = append(st.stringData, []byte(value)...) + st.stringData = append(st.stringData, 0) + st.internedStrings[value] = offset + } + + for _, existing := range st.entries { + if existing>>15 == key>>15 { + panic("duplicate entry") + } + } + st.entries = append(st.entries, key|offset) + return nil +} + +// keySlice is a type that implements sorting of entries values. +type keySlice []uint32 + +func (ks keySlice) Len() int { + return len(ks) +} + +func (ks keySlice) Less(i, j int) bool { + return (ks[i] >> 15) < (ks[j] >> 15) +} + +func (ks keySlice) Swap(i, j int) { + ks[i], ks[j] = ks[j], ks[i] +} + +func (st *stringList) buildList() []uint32 { + sort.Sort(keySlice(st.entries)) + return st.entries +} + +type stringWriter interface { + io.Writer + WriteString(string) (int, error) +} + +func (st *stringList) WriteTo(out stringWriter, name string) { + list := st.buildList() + fmt.Fprintf(os.Stderr, "%s: %d bytes of list and %d bytes of string data.\n", name, 4*len(list), len(st.stringData)) + + values := "kOpenSSL" + name + "Values" + out.WriteString("const uint32_t " + values + "[] = {\n") + for _, v := range list { + fmt.Fprintf(out, " 0x%x,\n", v) + } + out.WriteString("};\n\n") + out.WriteString("const size_t " + values + "Len = sizeof(" + values + ") / sizeof(" + values + "[0]);\n\n") + + stringData := "kOpenSSL" + name + "StringData" + out.WriteString("const char " + stringData + "[] =\n \"") + for i, c := range st.stringData { + if c == 0 { + out.WriteString("\\0\"\n \"") + continue + } + out.Write(st.stringData[i : i+1]) + } + out.WriteString("\";\n\n") +} + +type errorData struct { + reasons *stringList + libraryMap map[string]uint32 +} + +func (e *errorData) readErrorDataFile(filename string) error { + inFile, err := os.Open(filename) + if err != nil { + return err + } + defer inFile.Close() + + scanner := bufio.NewScanner(inFile) + comma := []byte(",") + + lineNo := 0 + for scanner.Scan() { + lineNo++ + + line := scanner.Bytes() + if len(line) == 0 { + continue + } + parts := bytes.Split(line, comma) + if len(parts) != 3 { + return fmt.Errorf("bad line %d in %s: found %d values but want 3", lineNo, filename, len(parts)) + } + libNum, ok := e.libraryMap[string(parts[0])] + if !ok { + return fmt.Errorf("bad line %d in %s: unknown library", lineNo, filename) + } + if libNum >= 64 { + return fmt.Errorf("bad line %d in %s: library value too large", lineNo, filename) + } + key, err := strconv.ParseUint(string(parts[1]), 10 /* base */, 32 /* bit size */) + if err != nil { + return fmt.Errorf("bad line %d in %s: %s", lineNo, filename, err) + } + if key >= 2048 { + return fmt.Errorf("bad line %d in %s: key too large", lineNo, filename) + } + value := string(parts[2]) + + listKey := libNum<<26 | uint32(key)<<15 + + err = e.reasons.Add(listKey, value) + if err != nil { + return err + } + } + + return scanner.Err() +} + +func main() { + e := &errorData{ + reasons: newStringList(), + libraryMap: make(map[string]uint32), + } + for i, name := range libraryNames { + e.libraryMap[name] = uint32(i) + 1 + } + + cwd, err := os.Open(".") + if err != nil { + panic(err) + } + names, err := cwd.Readdirnames(-1) + if err != nil { + panic(err) + } + + sort.Strings(names) + for _, name := range names { + if !strings.HasSuffix(name, ".errordata") { + continue + } + if err := e.readErrorDataFile(name); err != nil { + panic(err) + } + } + + out := os.Stdout + + out.WriteString(`/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + + /* This file was generated by err_data_generate.go. */ + +#include +#include +#include + + +`) + + for i, name := range libraryNames { + fmt.Fprintf(out, "OPENSSL_COMPILE_ASSERT(ERR_LIB_%s == %d, library_values_changed_%d);\n", name, i+1, i+1) + } + fmt.Fprintf(out, "OPENSSL_COMPILE_ASSERT(ERR_NUM_LIBS == %d, library_values_changed_num);\n", len(libraryNames)+1) + out.WriteString("\n") + + e.reasons.WriteTo(out, "Reason") +} diff --git a/TMessagesProj/jni/boringssl/crypto/err/evp.errordata b/TMessagesProj/jni/boringssl/crypto/err/evp.errordata new file mode 100644 index 00000000..8f8dd483 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/evp.errordata @@ -0,0 +1,46 @@ +EVP,151,BN_DECODE_ERROR +EVP,100,BUFFER_TOO_SMALL +EVP,101,COMMAND_NOT_SUPPORTED +EVP,146,CONTEXT_NOT_INITIALISED +EVP,143,DECODE_ERROR +EVP,104,DIFFERENT_KEY_TYPES +EVP,105,DIFFERENT_PARAMETERS +EVP,147,DIGEST_AND_KEY_TYPE_NOT_SUPPORTED +EVP,107,EXPECTING_AN_EC_KEY_KEY +EVP,141,EXPECTING_AN_RSA_KEY +EVP,109,EXPECTING_A_DH_KEY +EVP,110,EXPECTING_A_DSA_KEY +EVP,111,ILLEGAL_OR_UNSUPPORTED_PADDING_MODE +EVP,112,INVALID_CURVE +EVP,113,INVALID_DIGEST_LENGTH +EVP,114,INVALID_DIGEST_TYPE +EVP,115,INVALID_KEYBITS +EVP,116,INVALID_MGF1_MD +EVP,142,INVALID_OPERATION +EVP,118,INVALID_PADDING_MODE +EVP,119,INVALID_PSS_PARAMETERS +EVP,144,INVALID_PSS_SALTLEN +EVP,121,INVALID_SALT_LENGTH +EVP,122,INVALID_TRAILER +EVP,123,KEYS_NOT_SET +EVP,124,MISSING_PARAMETERS +EVP,125,NO_DEFAULT_DIGEST +EVP,126,NO_KEY_SET +EVP,127,NO_MDC2_SUPPORT +EVP,128,NO_NID_FOR_CURVE +EVP,129,NO_OPERATION_SET +EVP,130,NO_PARAMETERS_SET +EVP,131,OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE +EVP,132,OPERATON_NOT_INITIALIZED +EVP,152,PARAMETER_ENCODING_ERROR +EVP,133,UNKNOWN_DIGEST +EVP,134,UNKNOWN_MASK_DIGEST +EVP,150,UNKNOWN_MESSAGE_DIGEST_ALGORITHM +EVP,145,UNKNOWN_PUBLIC_KEY_TYPE +EVP,149,UNKNOWN_SIGNATURE_ALGORITHM +EVP,138,UNSUPPORTED_ALGORITHM +EVP,139,UNSUPPORTED_MASK_ALGORITHM +EVP,140,UNSUPPORTED_MASK_PARAMETER +EVP,153,UNSUPPORTED_PUBLIC_KEY_TYPE +EVP,154,UNSUPPORTED_SIGNATURE_TYPE +EVP,148,WRONG_PUBLIC_KEY_TYPE diff --git a/TMessagesProj/jni/boringssl/crypto/err/hkdf.errordata b/TMessagesProj/jni/boringssl/crypto/err/hkdf.errordata new file mode 100644 index 00000000..84866dee --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/hkdf.errordata @@ -0,0 +1 @@ +HKDF,100,OUTPUT_TOO_LARGE diff --git a/TMessagesProj/jni/boringssl/crypto/err/obj.errordata b/TMessagesProj/jni/boringssl/crypto/err/obj.errordata new file mode 100644 index 00000000..c54435ea --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/obj.errordata @@ -0,0 +1 @@ +OBJ,100,UNKNOWN_NID diff --git a/TMessagesProj/jni/boringssl/crypto/err/pem.errordata b/TMessagesProj/jni/boringssl/crypto/err/pem.errordata new file mode 100644 index 00000000..2a4b73af --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/pem.errordata @@ -0,0 +1,15 @@ +PEM,100,BAD_BASE64_DECODE +PEM,101,BAD_DECRYPT +PEM,102,BAD_END_LINE +PEM,103,BAD_IV_CHARS +PEM,104,BAD_PASSWORD_READ +PEM,105,CIPHER_IS_NULL +PEM,106,ERROR_CONVERTING_PRIVATE_KEY +PEM,107,NOT_DEK_INFO +PEM,108,NOT_ENCRYPTED +PEM,109,NOT_PROC_TYPE +PEM,110,NO_START_LINE +PEM,111,READ_KEY +PEM,112,SHORT_HEADER +PEM,113,UNSUPPORTED_CIPHER +PEM,114,UNSUPPORTED_ENCRYPTION diff --git a/TMessagesProj/jni/boringssl/crypto/err/pkcs8.errordata b/TMessagesProj/jni/boringssl/crypto/err/pkcs8.errordata new file mode 100644 index 00000000..0eb5083b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/pkcs8.errordata @@ -0,0 +1,25 @@ +PKCS8,100,BAD_PKCS12_DATA +PKCS8,101,BAD_PKCS12_VERSION +PKCS8,102,CIPHER_HAS_NO_OBJECT_IDENTIFIER +PKCS8,103,CRYPT_ERROR +PKCS8,104,DECODE_ERROR +PKCS8,105,ENCODE_ERROR +PKCS8,106,ENCRYPT_ERROR +PKCS8,107,ERROR_SETTING_CIPHER_PARAMS +PKCS8,108,INCORRECT_PASSWORD +PKCS8,109,KEYGEN_FAILURE +PKCS8,110,KEY_GEN_ERROR +PKCS8,111,METHOD_NOT_SUPPORTED +PKCS8,112,MISSING_MAC +PKCS8,113,MULTIPLE_PRIVATE_KEYS_IN_PKCS12 +PKCS8,114,PKCS12_PUBLIC_KEY_INTEGRITY_NOT_SUPPORTED +PKCS8,115,PKCS12_TOO_DEEPLY_NESTED +PKCS8,116,PRIVATE_KEY_DECODE_ERROR +PKCS8,117,PRIVATE_KEY_ENCODE_ERROR +PKCS8,118,TOO_LONG +PKCS8,119,UNKNOWN_ALGORITHM +PKCS8,120,UNKNOWN_CIPHER +PKCS8,121,UNKNOWN_CIPHER_ALGORITHM +PKCS8,122,UNKNOWN_DIGEST +PKCS8,123,UNKNOWN_HASH +PKCS8,124,UNSUPPORTED_PRIVATE_KEY_ALGORITHM diff --git a/TMessagesProj/jni/boringssl/crypto/err/rsa.errordata b/TMessagesProj/jni/boringssl/crypto/err/rsa.errordata new file mode 100644 index 00000000..c19f73c7 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/rsa.errordata @@ -0,0 +1,46 @@ +RSA,143,BAD_ENCODING +RSA,100,BAD_E_VALUE +RSA,101,BAD_FIXED_HEADER_DECRYPT +RSA,102,BAD_PAD_BYTE_COUNT +RSA,103,BAD_RSA_PARAMETERS +RSA,104,BAD_SIGNATURE +RSA,145,BAD_VERSION +RSA,105,BLOCK_TYPE_IS_NOT_01 +RSA,106,BN_NOT_INITIALIZED +RSA,142,CANNOT_RECOVER_MULTI_PRIME_KEY +RSA,107,CRT_PARAMS_ALREADY_GIVEN +RSA,108,CRT_VALUES_INCORRECT +RSA,109,DATA_LEN_NOT_EQUAL_TO_MOD_LEN +RSA,110,DATA_TOO_LARGE +RSA,111,DATA_TOO_LARGE_FOR_KEY_SIZE +RSA,112,DATA_TOO_LARGE_FOR_MODULUS +RSA,113,DATA_TOO_SMALL +RSA,114,DATA_TOO_SMALL_FOR_KEY_SIZE +RSA,115,DIGEST_TOO_BIG_FOR_RSA_KEY +RSA,116,D_E_NOT_CONGRUENT_TO_1 +RSA,117,EMPTY_PUBLIC_KEY +RSA,144,ENCODE_ERROR +RSA,118,FIRST_OCTET_INVALID +RSA,119,INCONSISTENT_SET_OF_CRT_VALUES +RSA,120,INTERNAL_ERROR +RSA,121,INVALID_MESSAGE_LENGTH +RSA,122,KEY_SIZE_TOO_SMALL +RSA,123,LAST_OCTET_INVALID +RSA,124,MODULUS_TOO_LARGE +RSA,141,MUST_HAVE_AT_LEAST_TWO_PRIMES +RSA,125,NO_PUBLIC_EXPONENT +RSA,126,NULL_BEFORE_BLOCK_MISSING +RSA,127,N_NOT_EQUAL_P_Q +RSA,128,OAEP_DECODING_ERROR +RSA,129,ONLY_ONE_OF_P_Q_GIVEN +RSA,130,OUTPUT_BUFFER_TOO_SMALL +RSA,131,PADDING_CHECK_FAILED +RSA,132,PKCS_DECODING_ERROR +RSA,133,SLEN_CHECK_FAILED +RSA,134,SLEN_RECOVERY_FAILED +RSA,135,TOO_LONG +RSA,136,TOO_MANY_ITERATIONS +RSA,137,UNKNOWN_ALGORITHM_TYPE +RSA,138,UNKNOWN_PADDING_TYPE +RSA,139,VALUE_MISSING +RSA,140,WRONG_SIGNATURE_LENGTH diff --git a/TMessagesProj/jni/boringssl/crypto/err/ssl.errordata b/TMessagesProj/jni/boringssl/crypto/err/ssl.errordata new file mode 100644 index 00000000..7825cce1 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/ssl.errordata @@ -0,0 +1,216 @@ +SSL,100,APP_DATA_IN_HANDSHAKE +SSL,101,ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT +SSL,102,BAD_ALERT +SSL,103,BAD_CHANGE_CIPHER_SPEC +SSL,104,BAD_DATA_RETURNED_BY_CALLBACK +SSL,105,BAD_DH_P_LENGTH +SSL,106,BAD_DIGEST_LENGTH +SSL,107,BAD_ECC_CERT +SSL,108,BAD_ECPOINT +SSL,109,BAD_HANDSHAKE_LENGTH +SSL,110,BAD_HANDSHAKE_RECORD +SSL,111,BAD_HELLO_REQUEST +SSL,112,BAD_LENGTH +SSL,113,BAD_PACKET_LENGTH +SSL,114,BAD_RSA_ENCRYPT +SSL,115,BAD_SIGNATURE +SSL,116,BAD_SRTP_MKI_VALUE +SSL,117,BAD_SRTP_PROTECTION_PROFILE_LIST +SSL,118,BAD_SSL_FILETYPE +SSL,119,BAD_WRITE_RETRY +SSL,120,BIO_NOT_SET +SSL,121,BN_LIB +SSL,272,BUFFER_TOO_SMALL +SSL,122,CANNOT_SERIALIZE_PUBLIC_KEY +SSL,123,CA_DN_LENGTH_MISMATCH +SSL,124,CA_DN_TOO_LONG +SSL,125,CCS_RECEIVED_EARLY +SSL,126,CERTIFICATE_VERIFY_FAILED +SSL,127,CERT_CB_ERROR +SSL,128,CERT_LENGTH_MISMATCH +SSL,129,CHANNEL_ID_NOT_P256 +SSL,130,CHANNEL_ID_SIGNATURE_INVALID +SSL,131,CIPHER_CODE_WRONG_LENGTH +SSL,132,CIPHER_OR_HASH_UNAVAILABLE +SSL,133,CLIENTHELLO_PARSE_FAILED +SSL,134,CLIENTHELLO_TLSEXT +SSL,135,CONNECTION_REJECTED +SSL,136,CONNECTION_TYPE_NOT_SET +SSL,137,COOKIE_MISMATCH +SSL,284,CUSTOM_EXTENSION_CONTENTS_TOO_LARGE +SSL,285,CUSTOM_EXTENSION_ERROR +SSL,138,D2I_ECDSA_SIG +SSL,139,DATA_BETWEEN_CCS_AND_FINISHED +SSL,140,DATA_LENGTH_TOO_LONG +SSL,141,DECODE_ERROR +SSL,142,DECRYPTION_FAILED +SSL,143,DECRYPTION_FAILED_OR_BAD_RECORD_MAC +SSL,144,DH_PUBLIC_VALUE_LENGTH_IS_WRONG +SSL,145,DIGEST_CHECK_FAILED +SSL,146,DTLS_MESSAGE_TOO_BIG +SSL,147,ECC_CERT_NOT_FOR_SIGNING +SSL,148,EMPTY_SRTP_PROTECTION_PROFILE_LIST +SSL,276,EMS_STATE_INCONSISTENT +SSL,149,ENCRYPTED_LENGTH_TOO_LONG +SSL,281,ERROR_ADDING_EXTENSION +SSL,150,ERROR_IN_RECEIVED_CIPHER_LIST +SSL,282,ERROR_PARSING_EXTENSION +SSL,151,EVP_DIGESTSIGNFINAL_FAILED +SSL,152,EVP_DIGESTSIGNINIT_FAILED +SSL,153,EXCESSIVE_MESSAGE_SIZE +SSL,154,EXTRA_DATA_IN_MESSAGE +SSL,271,FRAGMENT_MISMATCH +SSL,155,GOT_A_FIN_BEFORE_A_CCS +SSL,156,GOT_CHANNEL_ID_BEFORE_A_CCS +SSL,157,GOT_NEXT_PROTO_BEFORE_A_CCS +SSL,158,GOT_NEXT_PROTO_WITHOUT_EXTENSION +SSL,159,HANDSHAKE_FAILURE_ON_CLIENT_HELLO +SSL,160,HANDSHAKE_RECORD_BEFORE_CCS +SSL,161,HTTPS_PROXY_REQUEST +SSL,162,HTTP_REQUEST +SSL,163,INAPPROPRIATE_FALLBACK +SSL,164,INVALID_COMMAND +SSL,165,INVALID_MESSAGE +SSL,166,INVALID_SSL_SESSION +SSL,167,INVALID_TICKET_KEYS_LENGTH +SSL,168,LENGTH_MISMATCH +SSL,169,LIBRARY_HAS_NO_CIPHERS +SSL,170,MISSING_DH_KEY +SSL,171,MISSING_ECDSA_SIGNING_CERT +SSL,283,MISSING_EXTENSION +SSL,172,MISSING_RSA_CERTIFICATE +SSL,173,MISSING_RSA_ENCRYPTING_CERT +SSL,174,MISSING_RSA_SIGNING_CERT +SSL,175,MISSING_TMP_DH_KEY +SSL,176,MISSING_TMP_ECDH_KEY +SSL,177,MIXED_SPECIAL_OPERATOR_WITH_GROUPS +SSL,178,MTU_TOO_SMALL +SSL,179,NESTED_GROUP +SSL,180,NO_CERTIFICATES_RETURNED +SSL,181,NO_CERTIFICATE_ASSIGNED +SSL,182,NO_CERTIFICATE_SET +SSL,183,NO_CIPHERS_AVAILABLE +SSL,184,NO_CIPHERS_PASSED +SSL,185,NO_CIPHERS_SPECIFIED +SSL,186,NO_CIPHER_MATCH +SSL,187,NO_COMPRESSION_SPECIFIED +SSL,188,NO_METHOD_SPECIFIED +SSL,189,NO_P256_SUPPORT +SSL,190,NO_PRIVATE_KEY_ASSIGNED +SSL,191,NO_RENEGOTIATION +SSL,192,NO_REQUIRED_DIGEST +SSL,193,NO_SHARED_CIPHER +SSL,194,NO_SHARED_SIGATURE_ALGORITHMS +SSL,195,NO_SRTP_PROFILES +SSL,196,NULL_SSL_CTX +SSL,197,NULL_SSL_METHOD_PASSED +SSL,198,OLD_SESSION_CIPHER_NOT_RETURNED +SSL,273,OLD_SESSION_VERSION_NOT_RETURNED +SSL,274,OUTPUT_ALIASES_INPUT +SSL,199,PACKET_LENGTH_TOO_LONG +SSL,200,PARSE_TLSEXT +SSL,201,PATH_TOO_LONG +SSL,202,PEER_DID_NOT_RETURN_A_CERTIFICATE +SSL,203,PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE +SSL,204,PROTOCOL_IS_SHUTDOWN +SSL,205,PSK_IDENTITY_NOT_FOUND +SSL,206,PSK_NO_CLIENT_CB +SSL,207,PSK_NO_SERVER_CB +SSL,208,READ_BIO_NOT_SET +SSL,209,READ_TIMEOUT_EXPIRED +SSL,210,RECORD_LENGTH_MISMATCH +SSL,211,RECORD_TOO_LARGE +SSL,212,RENEGOTIATE_EXT_TOO_LONG +SSL,213,RENEGOTIATION_ENCODING_ERR +SSL,214,RENEGOTIATION_MISMATCH +SSL,215,REQUIRED_CIPHER_MISSING +SSL,275,RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION +SSL,277,RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION +SSL,216,SCSV_RECEIVED_WHEN_RENEGOTIATING +SSL,217,SERVERHELLO_TLSEXT +SSL,218,SESSION_ID_CONTEXT_UNINITIALIZED +SSL,219,SESSION_MAY_NOT_BE_CREATED +SSL,220,SIGNATURE_ALGORITHMS_ERROR +SSL,280,SIGNATURE_ALGORITHMS_EXTENSION_SENT_BY_SERVER +SSL,221,SRTP_COULD_NOT_ALLOCATE_PROFILES +SSL,222,SRTP_PROTECTION_PROFILE_LIST_TOO_LONG +SSL,223,SRTP_UNKNOWN_PROTECTION_PROFILE +SSL,224,SSL3_EXT_INVALID_SERVERNAME +SSL,225,SSL3_EXT_INVALID_SERVERNAME_TYPE +SSL,1042,SSLV3_ALERT_BAD_CERTIFICATE +SSL,1020,SSLV3_ALERT_BAD_RECORD_MAC +SSL,1045,SSLV3_ALERT_CERTIFICATE_EXPIRED +SSL,1044,SSLV3_ALERT_CERTIFICATE_REVOKED +SSL,1046,SSLV3_ALERT_CERTIFICATE_UNKNOWN +SSL,1000,SSLV3_ALERT_CLOSE_NOTIFY +SSL,1030,SSLV3_ALERT_DECOMPRESSION_FAILURE +SSL,1040,SSLV3_ALERT_HANDSHAKE_FAILURE +SSL,1047,SSLV3_ALERT_ILLEGAL_PARAMETER +SSL,1041,SSLV3_ALERT_NO_CERTIFICATE +SSL,1010,SSLV3_ALERT_UNEXPECTED_MESSAGE +SSL,1043,SSLV3_ALERT_UNSUPPORTED_CERTIFICATE +SSL,226,SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION +SSL,227,SSL_HANDSHAKE_FAILURE +SSL,228,SSL_SESSION_ID_CALLBACK_FAILED +SSL,229,SSL_SESSION_ID_CONFLICT +SSL,230,SSL_SESSION_ID_CONTEXT_TOO_LONG +SSL,231,SSL_SESSION_ID_HAS_BAD_LENGTH +SSL,1049,TLSV1_ALERT_ACCESS_DENIED +SSL,1050,TLSV1_ALERT_DECODE_ERROR +SSL,1021,TLSV1_ALERT_DECRYPTION_FAILED +SSL,1051,TLSV1_ALERT_DECRYPT_ERROR +SSL,1060,TLSV1_ALERT_EXPORT_RESTRICTION +SSL,1086,TLSV1_ALERT_INAPPROPRIATE_FALLBACK +SSL,1071,TLSV1_ALERT_INSUFFICIENT_SECURITY +SSL,1080,TLSV1_ALERT_INTERNAL_ERROR +SSL,1100,TLSV1_ALERT_NO_RENEGOTIATION +SSL,1070,TLSV1_ALERT_PROTOCOL_VERSION +SSL,1022,TLSV1_ALERT_RECORD_OVERFLOW +SSL,1048,TLSV1_ALERT_UNKNOWN_CA +SSL,1090,TLSV1_ALERT_USER_CANCELLED +SSL,1114,TLSV1_BAD_CERTIFICATE_HASH_VALUE +SSL,1113,TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE +SSL,1111,TLSV1_CERTIFICATE_UNOBTAINABLE +SSL,1112,TLSV1_UNRECOGNIZED_NAME +SSL,1110,TLSV1_UNSUPPORTED_EXTENSION +SSL,232,TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER +SSL,233,TLS_ILLEGAL_EXPORTER_LABEL +SSL,234,TLS_INVALID_ECPOINTFORMAT_LIST +SSL,235,TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST +SSL,236,TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG +SSL,237,TOO_MANY_EMPTY_FRAGMENTS +SSL,278,TOO_MANY_WARNING_ALERTS +SSL,238,UNABLE_TO_FIND_ECDH_PARAMETERS +SSL,239,UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS +SSL,279,UNEXPECTED_EXTENSION +SSL,240,UNEXPECTED_GROUP_CLOSE +SSL,241,UNEXPECTED_MESSAGE +SSL,242,UNEXPECTED_OPERATOR_IN_GROUP +SSL,243,UNEXPECTED_RECORD +SSL,244,UNINITIALIZED +SSL,245,UNKNOWN_ALERT_TYPE +SSL,246,UNKNOWN_CERTIFICATE_TYPE +SSL,247,UNKNOWN_CIPHER_RETURNED +SSL,248,UNKNOWN_CIPHER_TYPE +SSL,249,UNKNOWN_DIGEST +SSL,250,UNKNOWN_KEY_EXCHANGE_TYPE +SSL,251,UNKNOWN_PROTOCOL +SSL,252,UNKNOWN_SSL_VERSION +SSL,253,UNKNOWN_STATE +SSL,254,UNPROCESSED_HANDSHAKE_DATA +SSL,255,UNSAFE_LEGACY_RENEGOTIATION_DISABLED +SSL,256,UNSUPPORTED_CIPHER +SSL,257,UNSUPPORTED_COMPRESSION_ALGORITHM +SSL,258,UNSUPPORTED_ELLIPTIC_CURVE +SSL,259,UNSUPPORTED_PROTOCOL +SSL,260,UNSUPPORTED_SSL_VERSION +SSL,261,USE_SRTP_NOT_NEGOTIATED +SSL,262,WRONG_CERTIFICATE_TYPE +SSL,263,WRONG_CIPHER_RETURNED +SSL,264,WRONG_CURVE +SSL,265,WRONG_MESSAGE_TYPE +SSL,266,WRONG_SIGNATURE_TYPE +SSL,267,WRONG_SSL_VERSION +SSL,268,WRONG_VERSION_NUMBER +SSL,269,X509_LIB +SSL,270,X509_VERIFICATION_SETUP_PROBLEMS diff --git a/TMessagesProj/jni/boringssl/crypto/err/x509.errordata b/TMessagesProj/jni/boringssl/crypto/err/x509.errordata new file mode 100644 index 00000000..f4828ce8 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/x509.errordata @@ -0,0 +1,37 @@ +X509,100,AKID_MISMATCH +X509,101,BAD_PKCS7_VERSION +X509,102,BAD_X509_FILETYPE +X509,103,BASE64_DECODE_ERROR +X509,104,CANT_CHECK_DH_KEY +X509,105,CERT_ALREADY_IN_HASH_TABLE +X509,106,CRL_ALREADY_DELTA +X509,107,CRL_VERIFY_FAILURE +X509,108,IDP_MISMATCH +X509,109,INVALID_BIT_STRING_BITS_LEFT +X509,110,INVALID_DIRECTORY +X509,111,INVALID_FIELD_NAME +X509,112,INVALID_TRUST +X509,113,ISSUER_MISMATCH +X509,114,KEY_TYPE_MISMATCH +X509,115,KEY_VALUES_MISMATCH +X509,116,LOADING_CERT_DIR +X509,117,LOADING_DEFAULTS +X509,118,METHOD_NOT_SUPPORTED +X509,119,NEWER_CRL_NOT_NEWER +X509,120,NOT_PKCS7_SIGNED_DATA +X509,121,NO_CERTIFICATES_INCLUDED +X509,122,NO_CERT_SET_FOR_US_TO_VERIFY +X509,136,NO_CRLS_INCLUDED +X509,123,NO_CRL_NUMBER +X509,124,PUBLIC_KEY_DECODE_ERROR +X509,125,PUBLIC_KEY_ENCODE_ERROR +X509,126,SHOULD_RETRY +X509,127,UNABLE_TO_FIND_PARAMETERS_IN_CHAIN +X509,128,UNABLE_TO_GET_CERTS_PUBLIC_KEY +X509,129,UNKNOWN_KEY_TYPE +X509,130,UNKNOWN_NID +X509,131,UNKNOWN_PURPOSE_ID +X509,132,UNKNOWN_TRUST_ID +X509,133,UNSUPPORTED_ALGORITHM +X509,134,WRONG_LOOKUP_TYPE +X509,135,WRONG_TYPE diff --git a/TMessagesProj/jni/boringssl/crypto/err/x509v3.errordata b/TMessagesProj/jni/boringssl/crypto/err/x509v3.errordata new file mode 100644 index 00000000..e53b7800 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/x509v3.errordata @@ -0,0 +1,63 @@ +X509V3,100,BAD_IP_ADDRESS +X509V3,101,BAD_OBJECT +X509V3,102,BN_DEC2BN_ERROR +X509V3,103,BN_TO_ASN1_INTEGER_ERROR +X509V3,104,CANNOT_FIND_FREE_FUNCTION +X509V3,105,DIRNAME_ERROR +X509V3,106,DISTPOINT_ALREADY_SET +X509V3,107,DUPLICATE_ZONE_ID +X509V3,108,ERROR_CONVERTING_ZONE +X509V3,109,ERROR_CREATING_EXTENSION +X509V3,110,ERROR_IN_EXTENSION +X509V3,111,EXPECTED_A_SECTION_NAME +X509V3,112,EXTENSION_EXISTS +X509V3,113,EXTENSION_NAME_ERROR +X509V3,114,EXTENSION_NOT_FOUND +X509V3,115,EXTENSION_SETTING_NOT_SUPPORTED +X509V3,116,EXTENSION_VALUE_ERROR +X509V3,117,ILLEGAL_EMPTY_EXTENSION +X509V3,118,ILLEGAL_HEX_DIGIT +X509V3,119,INCORRECT_POLICY_SYNTAX_TAG +X509V3,120,INVALID_BOOLEAN_STRING +X509V3,121,INVALID_EXTENSION_STRING +X509V3,122,INVALID_MULTIPLE_RDNS +X509V3,123,INVALID_NAME +X509V3,124,INVALID_NULL_ARGUMENT +X509V3,125,INVALID_NULL_NAME +X509V3,126,INVALID_NULL_VALUE +X509V3,127,INVALID_NUMBER +X509V3,128,INVALID_NUMBERS +X509V3,129,INVALID_OBJECT_IDENTIFIER +X509V3,130,INVALID_OPTION +X509V3,131,INVALID_POLICY_IDENTIFIER +X509V3,132,INVALID_PROXY_POLICY_SETTING +X509V3,133,INVALID_PURPOSE +X509V3,134,INVALID_SECTION +X509V3,135,INVALID_SYNTAX +X509V3,136,ISSUER_DECODE_ERROR +X509V3,137,MISSING_VALUE +X509V3,138,NEED_ORGANIZATION_AND_NUMBERS +X509V3,139,NO_CONFIG_DATABASE +X509V3,140,NO_ISSUER_CERTIFICATE +X509V3,141,NO_ISSUER_DETAILS +X509V3,142,NO_POLICY_IDENTIFIER +X509V3,143,NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED +X509V3,144,NO_PUBLIC_KEY +X509V3,145,NO_SUBJECT_DETAILS +X509V3,146,ODD_NUMBER_OF_DIGITS +X509V3,147,OPERATION_NOT_DEFINED +X509V3,148,OTHERNAME_ERROR +X509V3,149,POLICY_LANGUAGE_ALREADY_DEFINED +X509V3,150,POLICY_PATH_LENGTH +X509V3,151,POLICY_PATH_LENGTH_ALREADY_DEFINED +X509V3,152,POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY +X509V3,153,SECTION_NOT_FOUND +X509V3,154,UNABLE_TO_GET_ISSUER_DETAILS +X509V3,155,UNABLE_TO_GET_ISSUER_KEYID +X509V3,156,UNKNOWN_BIT_STRING_ARGUMENT +X509V3,157,UNKNOWN_EXTENSION +X509V3,158,UNKNOWN_EXTENSION_NAME +X509V3,159,UNKNOWN_OPTION +X509V3,160,UNSUPPORTED_OPTION +X509V3,161,UNSUPPORTED_TYPE +X509V3,162,USER_TOO_LONG diff --git a/TMessagesProj/jni/boringssl/crypto/evp/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/evp/CMakeLists.txt new file mode 100644 index 00000000..a81d9320 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/evp/CMakeLists.txt @@ -0,0 +1,20 @@ +include_directories(. .. ../../include) + +add_library( + evp + + OBJECT + + algorithm.c + digestsign.c + evp.c + evp_asn1.c + evp_ctx.c + p_dsa_asn1.c + p_ec.c + p_ec_asn1.c + p_rsa.c + p_rsa_asn1.c + pbkdf.c + sign.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/evp/algorithm.c b/TMessagesProj/jni/boringssl/crypto/evp/algorithm.c new file mode 100644 index 00000000..63bc77af --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/evp/algorithm.c @@ -0,0 +1,153 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include +#include + +#include "internal.h" + + +int EVP_DigestSignAlgorithm(EVP_MD_CTX *ctx, X509_ALGOR *algor) { + const EVP_MD *digest; + EVP_PKEY *pkey; + int sign_nid, paramtype; + + digest = EVP_MD_CTX_md(ctx); + pkey = EVP_PKEY_CTX_get0_pkey(ctx->pctx); + if (!digest || !pkey) { + OPENSSL_PUT_ERROR(EVP, EVP_R_CONTEXT_NOT_INITIALISED); + return 0; + } + + if (pkey->ameth->digest_sign_algorithm) { + switch (pkey->ameth->digest_sign_algorithm(ctx, algor)) { + case EVP_DIGEST_SIGN_ALGORITHM_ERROR: + return 0; + case EVP_DIGEST_SIGN_ALGORITHM_SUCCESS: + return 1; + case EVP_DIGEST_SIGN_ALGORITHM_DEFAULT: + /* Use default behavior. */ + break; + default: + assert(0); + } + } + + /* Default behavior: look up the OID for the algorithm/hash pair and encode + * that. */ + if (!OBJ_find_sigid_by_algs(&sign_nid, EVP_MD_type(digest), + pkey->ameth->pkey_id)) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED); + return 0; + } + + if (pkey->ameth->pkey_flags & ASN1_PKEY_SIGPARAM_NULL) { + paramtype = V_ASN1_NULL; + } else { + paramtype = V_ASN1_UNDEF; + } + + X509_ALGOR_set0(algor, OBJ_nid2obj(sign_nid), paramtype, NULL); + return 1; +} + +int EVP_DigestVerifyInitFromAlgorithm(EVP_MD_CTX *ctx, + X509_ALGOR *algor, + EVP_PKEY *pkey) { + int digest_nid, pkey_nid; + const EVP_PKEY_ASN1_METHOD *ameth; + const EVP_MD *digest; + + /* Convert signature OID into digest and public key OIDs */ + if (!OBJ_find_sigid_algs(OBJ_obj2nid(algor->algorithm), &digest_nid, + &pkey_nid)) { + OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_SIGNATURE_ALGORITHM); + return 0; + } + + /* Check public key OID matches public key type */ + ameth = EVP_PKEY_asn1_find(NULL, pkey_nid); + if (ameth == NULL || ameth->pkey_id != pkey->ameth->pkey_id) { + OPENSSL_PUT_ERROR(EVP, EVP_R_WRONG_PUBLIC_KEY_TYPE); + return 0; + } + + /* NID_undef signals that there are custom parameters to set. */ + if (digest_nid == NID_undef) { + if (!pkey->ameth || !pkey->ameth->digest_verify_init_from_algorithm) { + OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_SIGNATURE_ALGORITHM); + return 0; + } + + return pkey->ameth->digest_verify_init_from_algorithm(ctx, algor, pkey); + } + + /* Otherwise, initialize with the digest from the OID. */ + digest = EVP_get_digestbynid(digest_nid); + if (digest == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM); + return 0; + } + + return EVP_DigestVerifyInit(ctx, NULL, digest, NULL, pkey); +} + diff --git a/TMessagesProj/jni/boringssl/crypto/evp/digestsign.c b/TMessagesProj/jni/boringssl/crypto/evp/digestsign.c new file mode 100644 index 00000000..ccb4de4f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/evp/digestsign.c @@ -0,0 +1,164 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2006. + */ +/* ==================================================================== + * Copyright (c) 2006,2007 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include + +#include "internal.h" +#include "../digest/internal.h" + + +static const struct evp_md_pctx_ops md_pctx_ops = { + EVP_PKEY_CTX_free, + EVP_PKEY_CTX_dup, +}; + +static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, + const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey, + int is_verify) { + if (ctx->pctx == NULL) { + ctx->pctx = EVP_PKEY_CTX_new(pkey, e); + } + if (ctx->pctx == NULL) { + return 0; + } + ctx->pctx_ops = &md_pctx_ops; + + if (type == NULL) { + type = EVP_sha1(); + } + + if (type == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_DEFAULT_DIGEST); + return 0; + } + + if (is_verify) { + if (!EVP_PKEY_verify_init(ctx->pctx)) { + return 0; + } + } else { + if (!EVP_PKEY_sign_init(ctx->pctx)) { + return 0; + } + } + if (!EVP_PKEY_CTX_set_signature_md(ctx->pctx, type)) { + return 0; + } + if (pctx) { + *pctx = ctx->pctx; + } + if (!EVP_DigestInit_ex(ctx, type, e)) { + return 0; + } + return 1; +} + +int EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type, + ENGINE *e, EVP_PKEY *pkey) { + return do_sigver_init(ctx, pctx, type, e, pkey, 0); +} + +int EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, + const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey) { + return do_sigver_init(ctx, pctx, type, e, pkey, 1); +} + +int EVP_DigestSignUpdate(EVP_MD_CTX *ctx, const void *data, size_t len) { + return EVP_DigestUpdate(ctx, data, len); +} + +int EVP_DigestVerifyUpdate(EVP_MD_CTX *ctx, const void *data, size_t len) { + return EVP_DigestUpdate(ctx, data, len); +} + +int EVP_DigestSignFinal(EVP_MD_CTX *ctx, uint8_t *out_sig, + size_t *out_sig_len) { + if (out_sig) { + EVP_MD_CTX tmp_ctx; + int ret; + uint8_t md[EVP_MAX_MD_SIZE]; + unsigned int mdlen; + + EVP_MD_CTX_init(&tmp_ctx); + ret = EVP_MD_CTX_copy_ex(&tmp_ctx, ctx) && + EVP_DigestFinal_ex(&tmp_ctx, md, &mdlen) && + EVP_PKEY_sign(ctx->pctx, out_sig, out_sig_len, md, mdlen); + EVP_MD_CTX_cleanup(&tmp_ctx); + + return ret; + } else { + size_t s = EVP_MD_size(ctx->digest); + return EVP_PKEY_sign(ctx->pctx, out_sig, out_sig_len, NULL, s); + } +} + +int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig, + size_t sig_len) { + EVP_MD_CTX tmp_ctx; + int ret; + uint8_t md[EVP_MAX_MD_SIZE]; + unsigned int mdlen; + + EVP_MD_CTX_init(&tmp_ctx); + ret = EVP_MD_CTX_copy_ex(&tmp_ctx, ctx) && + EVP_DigestFinal_ex(&tmp_ctx, md, &mdlen) && + EVP_PKEY_verify(ctx->pctx, sig, sig_len, md, mdlen); + EVP_MD_CTX_cleanup(&tmp_ctx); + + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/evp/evp.c b/TMessagesProj/jni/boringssl/crypto/evp/evp.c new file mode 100644 index 00000000..a8116aad --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/evp/evp.c @@ -0,0 +1,414 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" +#include "../internal.h" + + +extern const EVP_PKEY_ASN1_METHOD dsa_asn1_meth; +extern const EVP_PKEY_ASN1_METHOD ec_asn1_meth; +extern const EVP_PKEY_ASN1_METHOD rsa_asn1_meth; + +EVP_PKEY *EVP_PKEY_new(void) { + EVP_PKEY *ret; + + ret = OPENSSL_malloc(sizeof(EVP_PKEY)); + if (ret == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + return NULL; + } + + memset(ret, 0, sizeof(EVP_PKEY)); + ret->type = EVP_PKEY_NONE; + ret->references = 1; + + return ret; +} + +static void free_it(EVP_PKEY *pkey) { + if (pkey->ameth && pkey->ameth->pkey_free) { + pkey->ameth->pkey_free(pkey); + pkey->pkey.ptr = NULL; + pkey->type = EVP_PKEY_NONE; + } +} + +void EVP_PKEY_free(EVP_PKEY *pkey) { + if (pkey == NULL) { + return; + } + + if (!CRYPTO_refcount_dec_and_test_zero(&pkey->references)) { + return; + } + + free_it(pkey); + OPENSSL_free(pkey); +} + +EVP_PKEY *EVP_PKEY_up_ref(EVP_PKEY *pkey) { + CRYPTO_refcount_inc(&pkey->references); + return pkey; +} + +int EVP_PKEY_is_opaque(const EVP_PKEY *pkey) { + if (pkey->ameth && pkey->ameth->pkey_opaque) { + return pkey->ameth->pkey_opaque(pkey); + } + return 0; +} + +int EVP_PKEY_supports_digest(const EVP_PKEY *pkey, const EVP_MD *md) { + if (pkey->ameth && pkey->ameth->pkey_supports_digest) { + return pkey->ameth->pkey_supports_digest(pkey, md); + } + return 1; +} + +int EVP_PKEY_cmp(const EVP_PKEY *a, const EVP_PKEY *b) { + if (a->type != b->type) { + return -1; + } + + if (a->ameth) { + int ret; + /* Compare parameters if the algorithm has them */ + if (a->ameth->param_cmp) { + ret = a->ameth->param_cmp(a, b); + if (ret <= 0) { + return ret; + } + } + + if (a->ameth->pub_cmp) { + return a->ameth->pub_cmp(a, b); + } + } + + return -2; +} + +int EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from) { + if (to->type != from->type) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DIFFERENT_KEY_TYPES); + goto err; + } + + if (EVP_PKEY_missing_parameters(from)) { + OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS); + goto err; + } + + if (from->ameth && from->ameth->param_copy) { + return from->ameth->param_copy(to, from); + } + +err: + return 0; +} + +int EVP_PKEY_missing_parameters(const EVP_PKEY *pkey) { + if (pkey->ameth && pkey->ameth->param_missing) { + return pkey->ameth->param_missing(pkey); + } + return 0; +} + +int EVP_PKEY_size(const EVP_PKEY *pkey) { + if (pkey && pkey->ameth && pkey->ameth->pkey_size) { + return pkey->ameth->pkey_size(pkey); + } + return 0; +} + +int EVP_PKEY_bits(EVP_PKEY *pkey) { + if (pkey && pkey->ameth && pkey->ameth->pkey_bits) { + return pkey->ameth->pkey_bits(pkey); + } + return 0; +} + +int EVP_PKEY_id(const EVP_PKEY *pkey) { + return pkey->type; +} + +/* TODO(fork): remove the first argument. */ +const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find(ENGINE **pengine, int nid) { + switch (nid) { + case EVP_PKEY_RSA: + case EVP_PKEY_RSA2: + return &rsa_asn1_meth; + case EVP_PKEY_EC: + return &ec_asn1_meth; + case EVP_PKEY_DSA: + return &dsa_asn1_meth; + default: + return NULL; + } +} + +int EVP_PKEY_type(int nid) { + const EVP_PKEY_ASN1_METHOD *meth = EVP_PKEY_asn1_find(NULL, nid); + if (meth == NULL) { + return NID_undef; + } + return meth->pkey_id; +} + +int EVP_PKEY_set1_RSA(EVP_PKEY *pkey, RSA *key) { + if (EVP_PKEY_assign_RSA(pkey, key)) { + RSA_up_ref(key); + return 1; + } + return 0; +} + +int EVP_PKEY_assign_RSA(EVP_PKEY *pkey, RSA *key) { + return EVP_PKEY_assign(pkey, EVP_PKEY_RSA, key); +} + +RSA *EVP_PKEY_get1_RSA(EVP_PKEY *pkey) { + if (pkey->type != EVP_PKEY_RSA) { + OPENSSL_PUT_ERROR(EVP, EVP_R_EXPECTING_AN_RSA_KEY); + return NULL; + } + RSA_up_ref(pkey->pkey.rsa); + return pkey->pkey.rsa; +} + +int EVP_PKEY_set1_DSA(EVP_PKEY *pkey, DSA *key) { + if (EVP_PKEY_assign_DSA(pkey, key)) { + DSA_up_ref(key); + return 1; + } + return 0; +} + +int EVP_PKEY_assign_DSA(EVP_PKEY *pkey, DSA *key) { + return EVP_PKEY_assign(pkey, EVP_PKEY_DSA, key); +} + +DSA *EVP_PKEY_get1_DSA(EVP_PKEY *pkey) { + if (pkey->type != EVP_PKEY_DSA) { + OPENSSL_PUT_ERROR(EVP, EVP_R_EXPECTING_A_DSA_KEY); + return NULL; + } + DSA_up_ref(pkey->pkey.dsa); + return pkey->pkey.dsa; +} + +int EVP_PKEY_set1_EC_KEY(EVP_PKEY *pkey, EC_KEY *key) { + if (EVP_PKEY_assign_EC_KEY(pkey, key)) { + EC_KEY_up_ref(key); + return 1; + } + return 0; +} + +int EVP_PKEY_assign_EC_KEY(EVP_PKEY *pkey, EC_KEY *key) { + return EVP_PKEY_assign(pkey, EVP_PKEY_EC, key); +} + +EC_KEY *EVP_PKEY_get1_EC_KEY(EVP_PKEY *pkey) { + if (pkey->type != EVP_PKEY_EC) { + OPENSSL_PUT_ERROR(EVP, EVP_R_EXPECTING_AN_EC_KEY_KEY); + return NULL; + } + EC_KEY_up_ref(pkey->pkey.ec); + return pkey->pkey.ec; +} + +int EVP_PKEY_set1_DH(EVP_PKEY *pkey, DH *key) { + if (EVP_PKEY_assign_DH(pkey, key)) { + DH_up_ref(key); + return 1; + } + return 0; +} + +int EVP_PKEY_assign_DH(EVP_PKEY *pkey, DH *key) { + return EVP_PKEY_assign(pkey, EVP_PKEY_DH, key); +} + +DH *EVP_PKEY_get1_DH(EVP_PKEY *pkey) { + if (pkey->type != EVP_PKEY_DH) { + OPENSSL_PUT_ERROR(EVP, EVP_R_EXPECTING_A_DH_KEY); + return NULL; + } + DH_up_ref(pkey->pkey.dh); + return pkey->pkey.dh; +} + +int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key) { + if (!EVP_PKEY_set_type(pkey, type)) { + return 0; + } + pkey->pkey.ptr = key; + return key != NULL; +} + +const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find_str(ENGINE **pengine, + const char *name, + size_t len) { + if (len == 3 && memcmp(name, "RSA", 3) == 0) { + return &rsa_asn1_meth; + } if (len == 2 && memcmp(name, "EC", 2) == 0) { + return &ec_asn1_meth; + } + return NULL; +} + +int EVP_PKEY_set_type(EVP_PKEY *pkey, int type) { + const EVP_PKEY_ASN1_METHOD *ameth; + + if (pkey && pkey->pkey.ptr) { + free_it(pkey); + } + + ameth = EVP_PKEY_asn1_find(NULL, type); + if (ameth == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); + ERR_add_error_dataf("algorithm %d (%s)", type, OBJ_nid2sn(type)); + return 0; + } + + if (pkey) { + pkey->ameth = ameth; + pkey->type = pkey->ameth->pkey_id; + } + + return 1; +} + + + +int EVP_PKEY_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) { + if (a->type != b->type) { + return -1; + } + if (a->ameth && a->ameth->param_cmp) { + return a->ameth->param_cmp(a, b); + } + return -2; +} + +static int print_unsupported(BIO *out, const EVP_PKEY *pkey, int indent, + const char *kstr) { + BIO_indent(out, indent, 128); + BIO_printf(out, "%s algorithm \"%s\" unsupported\n", kstr, + OBJ_nid2ln(pkey->type)); + return 1; +} + +int EVP_PKEY_print_public(BIO *out, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *pctx) { + if (pkey->ameth && pkey->ameth->pub_print) { + return pkey->ameth->pub_print(out, pkey, indent, pctx); + } + + return print_unsupported(out, pkey, indent, "Public Key"); +} + +int EVP_PKEY_print_private(BIO *out, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *pctx) { + if (pkey->ameth && pkey->ameth->priv_print) { + return pkey->ameth->priv_print(out, pkey, indent, pctx); + } + + return print_unsupported(out, pkey, indent, "Private Key"); +} + +int EVP_PKEY_print_params(BIO *out, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *pctx) { + if (pkey->ameth && pkey->ameth->param_print) { + return pkey->ameth->param_print(out, pkey, indent, pctx); + } + + return print_unsupported(out, pkey, indent, "Parameters"); +} + +int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) { + return EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG, EVP_PKEY_CTRL_MD, 0, + (void *)md); +} + +int EVP_PKEY_CTX_get_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD **out_md) { + return EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG, EVP_PKEY_CTRL_GET_MD, + 0, (void *)out_md); +} + +void OpenSSL_add_all_algorithms(void) {} + +void OpenSSL_add_all_ciphers(void) {} + +void OpenSSL_add_all_digests(void) {} + +void EVP_cleanup(void) {} diff --git a/TMessagesProj/jni/boringssl/crypto/evp/evp_asn1.c b/TMessagesProj/jni/boringssl/crypto/evp/evp_asn1.c new file mode 100644 index 00000000..356c62b8 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/evp/evp_asn1.c @@ -0,0 +1,166 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include +#include + +#include "internal.h" + + +EVP_PKEY *d2i_PrivateKey(int type, EVP_PKEY **out, const uint8_t **inp, + long len) { + EVP_PKEY *ret; + + if (out == NULL || *out == NULL) { + ret = EVP_PKEY_new(); + if (ret == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_EVP_LIB); + return NULL; + } + } else { + ret = *out; + } + + if (!EVP_PKEY_set_type(ret, type)) { + OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_PUBLIC_KEY_TYPE); + goto err; + } + + if (!ret->ameth->old_priv_decode || + !ret->ameth->old_priv_decode(ret, inp, len)) { + if (ret->ameth->priv_decode) { + PKCS8_PRIV_KEY_INFO *p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, inp, len); + if (!p8) { + goto err; + } + EVP_PKEY_free(ret); + ret = EVP_PKCS82PKEY(p8); + PKCS8_PRIV_KEY_INFO_free(p8); + } else { + OPENSSL_PUT_ERROR(EVP, ERR_R_ASN1_LIB); + goto err; + } + } + + if (out != NULL) { + *out = ret; + } + return ret; + +err: + if (out == NULL || *out != ret) { + EVP_PKEY_free(ret); + } + return NULL; +} + +EVP_PKEY *d2i_AutoPrivateKey(EVP_PKEY **out, const uint8_t **inp, long len) { + STACK_OF(ASN1_TYPE) *inkey; + const uint8_t *p; + int keytype; + p = *inp; + + /* Dirty trick: read in the ASN1 data into out STACK_OF(ASN1_TYPE): + * by analyzing it we can determine the passed structure: this + * assumes the input is surrounded by an ASN1 SEQUENCE. */ + inkey = d2i_ASN1_SEQUENCE_ANY(NULL, &p, len); + /* Since we only need to discern "traditional format" RSA and DSA + * keys we can just count the elements. */ + if (sk_ASN1_TYPE_num(inkey) == 6) { + keytype = EVP_PKEY_DSA; + } else if (sk_ASN1_TYPE_num(inkey) == 4) { + keytype = EVP_PKEY_EC; + } else if (sk_ASN1_TYPE_num(inkey) == 3) { + /* This seems to be PKCS8, not traditional format */ + PKCS8_PRIV_KEY_INFO *p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, inp, len); + EVP_PKEY *ret; + + sk_ASN1_TYPE_pop_free(inkey, ASN1_TYPE_free); + if (!p8) { + OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE); + return NULL; + } + ret = EVP_PKCS82PKEY(p8); + PKCS8_PRIV_KEY_INFO_free(p8); + if (out) { + *out = ret; + } + return ret; + } else { + keytype = EVP_PKEY_RSA; + } + + sk_ASN1_TYPE_pop_free(inkey, ASN1_TYPE_free); + return d2i_PrivateKey(keytype, out, inp, len); +} + +int i2d_PublicKey(EVP_PKEY *key, uint8_t **outp) { + switch (key->type) { + case EVP_PKEY_RSA: + return i2d_RSAPublicKey(key->pkey.rsa, outp); + case EVP_PKEY_DSA: + return i2d_DSAPublicKey(key->pkey.dsa, outp); + case EVP_PKEY_EC: + return i2o_ECPublicKey(key->pkey.ec, outp); + default: + OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE); + return -1; + } +} diff --git a/TMessagesProj/jni/boringssl/crypto/evp/evp_ctx.c b/TMessagesProj/jni/boringssl/crypto/evp/evp_ctx.c new file mode 100644 index 00000000..a8e71fea --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/evp/evp_ctx.c @@ -0,0 +1,480 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include +#include + +#include "internal.h" + + +extern const EVP_PKEY_METHOD rsa_pkey_meth; +extern const EVP_PKEY_METHOD ec_pkey_meth; + +static const EVP_PKEY_METHOD *const evp_methods[] = { + &rsa_pkey_meth, + &ec_pkey_meth, +}; + +static const EVP_PKEY_METHOD *evp_pkey_meth_find(int type) { + unsigned i; + + for (i = 0; i < sizeof(evp_methods)/sizeof(EVP_PKEY_METHOD*); i++) { + if (evp_methods[i]->pkey_id == type) { + return evp_methods[i]; + } + } + + return NULL; +} + +static EVP_PKEY_CTX *evp_pkey_ctx_new(EVP_PKEY *pkey, ENGINE *e, int id) { + EVP_PKEY_CTX *ret; + const EVP_PKEY_METHOD *pmeth; + + if (id == -1) { + if (!pkey || !pkey->ameth) { + return NULL; + } + id = pkey->ameth->pkey_id; + } + + pmeth = evp_pkey_meth_find(id); + + if (pmeth == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); + const char *name = OBJ_nid2sn(id); + ERR_add_error_dataf("algorithm %d (%s)", id, name); + return NULL; + } + + ret = OPENSSL_malloc(sizeof(EVP_PKEY_CTX)); + if (!ret) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + return NULL; + } + memset(ret, 0, sizeof(EVP_PKEY_CTX)); + + ret->engine = e; + ret->pmeth = pmeth; + ret->operation = EVP_PKEY_OP_UNDEFINED; + + if (pkey) { + ret->pkey = EVP_PKEY_up_ref(pkey); + } + + if (pmeth->init) { + if (pmeth->init(ret) <= 0) { + EVP_PKEY_free(ret->pkey); + OPENSSL_free(ret); + return NULL; + } + } + + return ret; +} + +EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *e) { + return evp_pkey_ctx_new(pkey, e, -1); +} + +EVP_PKEY_CTX *EVP_PKEY_CTX_new_id(int id, ENGINE *e) { + return evp_pkey_ctx_new(NULL, e, id); +} + +void EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx) { + if (ctx == NULL) { + return; + } + if (ctx->pmeth && ctx->pmeth->cleanup) { + ctx->pmeth->cleanup(ctx); + } + EVP_PKEY_free(ctx->pkey); + EVP_PKEY_free(ctx->peerkey); + OPENSSL_free(ctx); +} + +EVP_PKEY_CTX *EVP_PKEY_CTX_dup(EVP_PKEY_CTX *pctx) { + EVP_PKEY_CTX *rctx; + + if (!pctx->pmeth || !pctx->pmeth->copy) { + return NULL; + } + + rctx = OPENSSL_malloc(sizeof(EVP_PKEY_CTX)); + if (!rctx) { + return NULL; + } + + memset(rctx, 0, sizeof(EVP_PKEY_CTX)); + + rctx->pmeth = pctx->pmeth; + rctx->engine = pctx->engine; + rctx->operation = pctx->operation; + + if (pctx->pkey) { + rctx->pkey = EVP_PKEY_up_ref(pctx->pkey); + if (rctx->pkey == NULL) { + goto err; + } + } + + if (pctx->peerkey) { + rctx->peerkey = EVP_PKEY_up_ref(pctx->peerkey); + if (rctx->peerkey == NULL) { + goto err; + } + } + + if (pctx->pmeth->copy(rctx, pctx) > 0) { + return rctx; + } + +err: + EVP_PKEY_CTX_free(rctx); + OPENSSL_PUT_ERROR(EVP, ERR_LIB_EVP); + return NULL; +} + +EVP_PKEY *EVP_PKEY_CTX_get0_pkey(EVP_PKEY_CTX *ctx) { return ctx->pkey; } + +void EVP_PKEY_CTX_set_app_data(EVP_PKEY_CTX *ctx, void *data) { + ctx->app_data = data; +} + +void *EVP_PKEY_CTX_get_app_data(EVP_PKEY_CTX *ctx) { return ctx->app_data; } + +int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype, int cmd, + int p1, void *p2) { + if (!ctx || !ctx->pmeth || !ctx->pmeth->ctrl) { + OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED); + return 0; + } + if (keytype != -1 && ctx->pmeth->pkey_id != keytype) { + return 0; + } + + if (ctx->operation == EVP_PKEY_OP_UNDEFINED) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_OPERATION_SET); + return 0; + } + + if (optype != -1 && !(ctx->operation & optype)) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_OPERATION); + return 0; + } + + return ctx->pmeth->ctrl(ctx, cmd, p1, p2); +} + +int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx) { + if (!ctx || !ctx->pmeth || !ctx->pmeth->sign) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return 0; + } + + ctx->operation = EVP_PKEY_OP_SIGN; + if (!ctx->pmeth->sign_init) { + return 1; + } + + if (!ctx->pmeth->sign_init(ctx)) { + ctx->operation = EVP_PKEY_OP_UNDEFINED; + return 0; + } + + return 1; +} + +int EVP_PKEY_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *sig_len, + const uint8_t *data, size_t data_len) { + if (!ctx || !ctx->pmeth || !ctx->pmeth->sign) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return 0; + } + if (ctx->operation != EVP_PKEY_OP_SIGN) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); + return 0; + } + return ctx->pmeth->sign(ctx, sig, sig_len, data, data_len); +} + +int EVP_PKEY_verify_init(EVP_PKEY_CTX *ctx) { + if (!ctx || !ctx->pmeth || !ctx->pmeth->verify) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return 0; + } + ctx->operation = EVP_PKEY_OP_VERIFY; + if (!ctx->pmeth->verify_init) { + return 1; + } + if (!ctx->pmeth->verify_init(ctx)) { + ctx->operation = EVP_PKEY_OP_UNDEFINED; + return 0; + } + + return 1; +} + +int EVP_PKEY_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig, size_t sig_len, + const uint8_t *data, size_t data_len) { + if (!ctx || !ctx->pmeth || !ctx->pmeth->verify) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return 0; + } + if (ctx->operation != EVP_PKEY_OP_VERIFY) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); + return 0; + } + return ctx->pmeth->verify(ctx, sig, sig_len, data, data_len); +} + +int EVP_PKEY_encrypt_init(EVP_PKEY_CTX *ctx) { + if (!ctx || !ctx->pmeth || !ctx->pmeth->encrypt) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return 0; + } + ctx->operation = EVP_PKEY_OP_ENCRYPT; + if (!ctx->pmeth->encrypt_init) { + return 1; + } + if (!ctx->pmeth->encrypt_init(ctx)) { + ctx->operation = EVP_PKEY_OP_UNDEFINED; + return 0; + } + return 1; +} + +int EVP_PKEY_encrypt(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *outlen, + const uint8_t *in, size_t inlen) { + if (!ctx || !ctx->pmeth || !ctx->pmeth->encrypt) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return 0; + } + if (ctx->operation != EVP_PKEY_OP_ENCRYPT) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); + return 0; + } + return ctx->pmeth->encrypt(ctx, out, outlen, in, inlen); +} + +int EVP_PKEY_decrypt_init(EVP_PKEY_CTX *ctx) { + if (!ctx || !ctx->pmeth || !ctx->pmeth->decrypt) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return 0; + } + ctx->operation = EVP_PKEY_OP_DECRYPT; + if (!ctx->pmeth->decrypt_init) { + return 1; + } + if (!ctx->pmeth->decrypt_init(ctx)) { + ctx->operation = EVP_PKEY_OP_UNDEFINED; + return 0; + } + return 1; +} + +int EVP_PKEY_decrypt(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *outlen, + const uint8_t *in, size_t inlen) { + if (!ctx || !ctx->pmeth || !ctx->pmeth->decrypt) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return 0; + } + if (ctx->operation != EVP_PKEY_OP_DECRYPT) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); + return 0; + } + return ctx->pmeth->decrypt(ctx, out, outlen, in, inlen); +} + +int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx) { + if (!ctx || !ctx->pmeth || !ctx->pmeth->derive) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return 0; + } + ctx->operation = EVP_PKEY_OP_DERIVE; + if (!ctx->pmeth->derive_init) { + return 1; + } + if (!ctx->pmeth->derive_init(ctx)) { + ctx->operation = EVP_PKEY_OP_UNDEFINED; + return 0; + } + return 1; +} + +int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer) { + int ret; + if (!ctx || !ctx->pmeth || + !(ctx->pmeth->derive || ctx->pmeth->encrypt || ctx->pmeth->decrypt) || + !ctx->pmeth->ctrl) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return 0; + } + if (ctx->operation != EVP_PKEY_OP_DERIVE && + ctx->operation != EVP_PKEY_OP_ENCRYPT && + ctx->operation != EVP_PKEY_OP_DECRYPT) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); + return 0; + } + + ret = ctx->pmeth->ctrl(ctx, EVP_PKEY_CTRL_PEER_KEY, 0, peer); + + if (ret <= 0) { + return 0; + } + + if (ret == 2) { + return 1; + } + + if (!ctx->pkey) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET); + return 0; + } + + if (ctx->pkey->type != peer->type) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DIFFERENT_KEY_TYPES); + return 0; + } + + /* ran@cryptocom.ru: For clarity. The error is if parameters in peer are + * present (!missing) but don't match. EVP_PKEY_cmp_parameters may return + * 1 (match), 0 (don't match) and -2 (comparison is not defined). -1 + * (different key types) is impossible here because it is checked earlier. + * -2 is OK for us here, as well as 1, so we can check for 0 only. */ + if (!EVP_PKEY_missing_parameters(peer) && + !EVP_PKEY_cmp_parameters(ctx->pkey, peer)) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DIFFERENT_PARAMETERS); + return 0; + } + + EVP_PKEY_free(ctx->peerkey); + ctx->peerkey = peer; + + ret = ctx->pmeth->ctrl(ctx, EVP_PKEY_CTRL_PEER_KEY, 1, peer); + + if (ret <= 0) { + ctx->peerkey = NULL; + return 0; + } + + EVP_PKEY_up_ref(peer); + return 1; +} + +int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, uint8_t *key, size_t *out_key_len) { + if (!ctx || !ctx->pmeth || !ctx->pmeth->derive) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return 0; + } + if (ctx->operation != EVP_PKEY_OP_DERIVE) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); + return 0; + } + return ctx->pmeth->derive(ctx, key, out_key_len); +} + +int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx) { + if (!ctx || !ctx->pmeth || !ctx->pmeth->keygen) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return 0; + } + ctx->operation = EVP_PKEY_OP_KEYGEN; + if (!ctx->pmeth->keygen_init) { + return 1; + } + if (!ctx->pmeth->keygen_init(ctx)) { + ctx->operation = EVP_PKEY_OP_UNDEFINED; + return 0; + } + return 1; +} + +int EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey) { + if (!ctx || !ctx->pmeth || !ctx->pmeth->keygen) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return 0; + } + if (ctx->operation != EVP_PKEY_OP_KEYGEN) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); + return 0; + } + + if (!ppkey) { + return 0; + } + + if (!*ppkey) { + *ppkey = EVP_PKEY_new(); + if (!*ppkey) { + OPENSSL_PUT_ERROR(EVP, ERR_LIB_EVP); + return 0; + } + } + + if (!ctx->pmeth->keygen(ctx, *ppkey)) { + EVP_PKEY_free(*ppkey); + *ppkey = NULL; + return 0; + } + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/evp/internal.h b/TMessagesProj/jni/boringssl/crypto/evp/internal.h new file mode 100644 index 00000000..60881e3b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/evp/internal.h @@ -0,0 +1,271 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_EVP_INTERNAL_H +#define OPENSSL_HEADER_EVP_INTERNAL_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* These values are flags for EVP_PKEY_ASN1_METHOD.flags. */ + +/* ASN1_PKEY_SIGPARAM_NULL controls whether the default behavior of + * EVP_DigestSignAlgorithm writes an explicit NULL parameter in the + * AlgorithmIdentifier. */ +#define ASN1_PKEY_SIGPARAM_NULL 0x1 + +/* evp_digest_sign_algorithm_result_t is the return value of the + * digest_sign_algorithm function in EVP_PKEY_ASN1_METHOD. */ +typedef enum { + /* EVP_DIGEST_SIGN_ALGORITHM_ERROR signals an error. */ + EVP_DIGEST_SIGN_ALGORITHM_ERROR = 0, + /* EVP_DIGEST_SIGN_ALGORITHM_SUCCESS signals that the parameters were + * serialized in the AlgorithmIdentifier. */ + EVP_DIGEST_SIGN_ALGORITHM_SUCCESS = 1, + /* EVP_DIGEST_SIGN_ALGORITHM_DEFAULT signals that the parameters are + * serialized using the default behavior. */ + EVP_DIGEST_SIGN_ALGORITHM_DEFAULT = 2, +} evp_digest_sign_algorithm_result_t; + +struct evp_pkey_asn1_method_st { + int pkey_id; + int pkey_base_id; + unsigned long pkey_flags; + + const char *pem_str; + + int (*pub_decode)(EVP_PKEY *pk, X509_PUBKEY *pub); + int (*pub_encode)(X509_PUBKEY *pub, const EVP_PKEY *pk); + int (*pub_cmp)(const EVP_PKEY *a, const EVP_PKEY *b); + int (*pub_print)(BIO *out, const EVP_PKEY *pkey, int indent, ASN1_PCTX *pctx); + + int (*priv_decode)(EVP_PKEY *pk, PKCS8_PRIV_KEY_INFO *p8inf); + int (*priv_encode)(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pk); + int (*priv_print)(BIO *out, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *pctx); + + /* pkey_opaque returns 1 if the |pk| is opaque. Opaque keys are backed by + * custom implementations which do not expose key material and parameters.*/ + int (*pkey_opaque)(const EVP_PKEY *pk); + + /* pkey_supports_digest returns one if |pkey| supports digests of + * type |md|. This is intended for use with EVP_PKEYs backing custom + * implementations which can't sign all digests. If null, it is + * assumed that all digests are supported. */ + int (*pkey_supports_digest)(const EVP_PKEY *pkey, const EVP_MD *md); + + int (*pkey_size)(const EVP_PKEY *pk); + int (*pkey_bits)(const EVP_PKEY *pk); + + int (*param_decode)(EVP_PKEY *pkey, const uint8_t **pder, int derlen); + int (*param_encode)(const EVP_PKEY *pkey, uint8_t **pder); + int (*param_missing)(const EVP_PKEY *pk); + int (*param_copy)(EVP_PKEY *to, const EVP_PKEY *from); + int (*param_cmp)(const EVP_PKEY *a, const EVP_PKEY *b); + int (*param_print)(BIO *out, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *pctx); + int (*sig_print)(BIO *out, const X509_ALGOR *sigalg, const ASN1_STRING *sig, + int indent, ASN1_PCTX *pctx); + + + void (*pkey_free)(EVP_PKEY *pkey); + + /* Legacy functions for old PEM */ + + int (*old_priv_decode)(EVP_PKEY *pkey, const uint8_t **pder, + int derlen); + int (*old_priv_encode)(const EVP_PKEY *pkey, uint8_t **pder); + + /* Converting parameters to/from AlgorithmIdentifier (X509_ALGOR). */ + int (*digest_verify_init_from_algorithm)(EVP_MD_CTX *ctx, + X509_ALGOR *algor, + EVP_PKEY *pkey); + evp_digest_sign_algorithm_result_t (*digest_sign_algorithm)( + EVP_MD_CTX *ctx, + X509_ALGOR *algor); + +} /* EVP_PKEY_ASN1_METHOD */; + + +typedef int EVP_PKEY_gen_cb(EVP_PKEY_CTX *ctx); + +#define EVP_PKEY_OP_UNDEFINED 0 +#define EVP_PKEY_OP_PARAMGEN (1 << 1) +#define EVP_PKEY_OP_KEYGEN (1 << 2) +#define EVP_PKEY_OP_SIGN (1 << 3) +#define EVP_PKEY_OP_VERIFY (1 << 4) +#define EVP_PKEY_OP_VERIFYRECOVER (1 << 5) +#define EVP_PKEY_OP_ENCRYPT (1 << 6) +#define EVP_PKEY_OP_DECRYPT (1 << 7) +#define EVP_PKEY_OP_DERIVE (1 << 8) + +#define EVP_PKEY_OP_TYPE_SIG \ + (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY | EVP_PKEY_OP_VERIFYRECOVER) + +#define EVP_PKEY_OP_TYPE_CRYPT (EVP_PKEY_OP_ENCRYPT | EVP_PKEY_OP_DECRYPT) + +#define EVP_PKEY_OP_TYPE_NOGEN \ + (EVP_PKEY_OP_SIG | EVP_PKEY_OP_CRYPT | EVP_PKEY_OP_DERIVE) + +#define EVP_PKEY_OP_TYPE_GEN (EVP_PKEY_OP_PARAMGEN | EVP_PKEY_OP_KEYGEN) + +/* EVP_PKEY_CTX_ctrl performs |cmd| on |ctx|. The |keytype| and |optype| + * arguments can be -1 to specify that any type and operation are acceptable, + * otherwise |keytype| must match the type of |ctx| and the bits of |optype| + * must intersect the operation flags set on |ctx|. + * + * The |p1| and |p2| arguments depend on the value of |cmd|. + * + * It returns one on success and zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype, + int cmd, int p1, void *p2); + +#define EVP_PKEY_CTRL_MD 1 +#define EVP_PKEY_CTRL_GET_MD 2 + +/* EVP_PKEY_CTRL_PEER_KEY is called with different values of |p1|: + * 0: Is called from |EVP_PKEY_derive_set_peer| and |p2| contains a peer key. + * If the return value is <= 0, the key is rejected. + * 1: Is called at the end of |EVP_PKEY_derive_set_peer| and |p2| contains a + * peer key. If the return value is <= 0, the key is rejected. + * 2: Is called with |p2| == NULL to test whether the peer's key was used. + * (EC)DH always return one in this case. + * 3: Is called with |p2| == NULL to set whether the peer's key was used. + * (EC)DH always return one in this case. This was only used for GOST. */ +#define EVP_PKEY_CTRL_PEER_KEY 3 + +/* EVP_PKEY_ALG_CTRL is the base value from which key-type specific ctrl + * commands are numbered. */ +#define EVP_PKEY_ALG_CTRL 0x1000 + +#define EVP_PKEY_CTRL_RSA_PADDING (EVP_PKEY_ALG_CTRL + 1) +#define EVP_PKEY_CTRL_GET_RSA_PADDING (EVP_PKEY_ALG_CTRL + 2) +#define EVP_PKEY_CTRL_RSA_PSS_SALTLEN (EVP_PKEY_ALG_CTRL + 3) +#define EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN (EVP_PKEY_ALG_CTRL + 4) +#define EVP_PKEY_CTRL_RSA_KEYGEN_BITS (EVP_PKEY_ALG_CTRL + 5) +#define EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP (EVP_PKEY_ALG_CTRL + 6) +#define EVP_PKEY_CTRL_RSA_OAEP_MD (EVP_PKEY_ALG_CTRL + 7) +#define EVP_PKEY_CTRL_GET_RSA_OAEP_MD (EVP_PKEY_ALG_CTRL + 8) +#define EVP_PKEY_CTRL_RSA_MGF1_MD (EVP_PKEY_ALG_CTRL + 9) +#define EVP_PKEY_CTRL_GET_RSA_MGF1_MD (EVP_PKEY_ALG_CTRL + 10) +#define EVP_PKEY_CTRL_RSA_OAEP_LABEL (EVP_PKEY_ALG_CTRL + 11) +#define EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL (EVP_PKEY_ALG_CTRL + 12) + +#define EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID (EVP_PKEY_ALG_CTRL + 1) + +struct evp_pkey_ctx_st { + /* Method associated with this operation */ + const EVP_PKEY_METHOD *pmeth; + /* Engine that implements this method or NULL if builtin */ + ENGINE *engine; + /* Key: may be NULL */ + EVP_PKEY *pkey; + /* Peer key for key agreement, may be NULL */ + EVP_PKEY *peerkey; + /* operation contains one of the |EVP_PKEY_OP_*| values. */ + int operation; + /* Algorithm specific data */ + void *data; + /* Application specific data */ + void *app_data; +} /* EVP_PKEY_CTX */; + +struct evp_pkey_method_st { + int pkey_id; + int flags; + + int (*init)(EVP_PKEY_CTX *ctx); + int (*copy)(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src); + void (*cleanup)(EVP_PKEY_CTX *ctx); + + int (*paramgen_init)(EVP_PKEY_CTX *ctx); + int (*paramgen)(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey); + + int (*keygen_init)(EVP_PKEY_CTX *ctx); + int (*keygen)(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey); + + int (*sign_init)(EVP_PKEY_CTX *ctx); + int (*sign)(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *siglen, + const uint8_t *tbs, size_t tbslen); + + int (*verify_init)(EVP_PKEY_CTX *ctx); + int (*verify)(EVP_PKEY_CTX *ctx, const uint8_t *sig, size_t siglen, + const uint8_t *tbs, size_t tbslen); + + int (*encrypt_init)(EVP_PKEY_CTX *ctx); + int (*encrypt)(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *outlen, + const uint8_t *in, size_t inlen); + + int (*decrypt_init)(EVP_PKEY_CTX *ctx); + int (*decrypt)(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *outlen, + const uint8_t *in, size_t inlen); + + int (*derive_init)(EVP_PKEY_CTX *ctx); + int (*derive)(EVP_PKEY_CTX *ctx, uint8_t *key, size_t *keylen); + + int (*ctrl)(EVP_PKEY_CTX *ctx, int type, int p1, void *p2); +} /* EVP_PKEY_METHOD */; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_EVP_INTERNAL_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/evp/p_dsa_asn1.c b/TMessagesProj/jni/boringssl/crypto/evp/p_dsa_asn1.c new file mode 100644 index 00000000..4790cf62 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/evp/p_dsa_asn1.c @@ -0,0 +1,585 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project + * 2006. + */ +/* ==================================================================== + * Copyright (c) 2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../dsa/internal.h" +#include "internal.h" + + +static int dsa_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey) { + const uint8_t *p, *pm; + int pklen, pmlen; + int ptype; + void *pval; + ASN1_STRING *pstr; + X509_ALGOR *palg; + ASN1_INTEGER *public_key = NULL; + + DSA *dsa = NULL; + + if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, &palg, pubkey)) { + return 0; + } + X509_ALGOR_get0(NULL, &ptype, &pval, palg); + + if (ptype == V_ASN1_SEQUENCE) { + pstr = pval; + pm = pstr->data; + pmlen = pstr->length; + + dsa = d2i_DSAparams(NULL, &pm, pmlen); + if (dsa == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + goto err; + } + } else if (ptype == V_ASN1_NULL || ptype == V_ASN1_UNDEF) { + dsa = DSA_new(); + if (dsa == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + goto err; + } + } else { + OPENSSL_PUT_ERROR(EVP, EVP_R_PARAMETER_ENCODING_ERROR); + goto err; + } + + public_key = d2i_ASN1_INTEGER(NULL, &p, pklen); + if (public_key == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + goto err; + } + + dsa->pub_key = ASN1_INTEGER_to_BN(public_key, NULL); + if (dsa->pub_key == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_BN_DECODE_ERROR); + goto err; + } + + ASN1_INTEGER_free(public_key); + EVP_PKEY_assign_DSA(pkey, dsa); + return 1; + +err: + ASN1_INTEGER_free(public_key); + DSA_free(dsa); + return 0; +} + +static int dsa_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey) { + DSA *dsa; + ASN1_STRING *pval = NULL; + uint8_t *penc = NULL; + int penclen; + + dsa = pkey->pkey.dsa; + dsa->write_params = 0; + + int ptype; + if (dsa->p && dsa->q && dsa->g) { + pval = ASN1_STRING_new(); + if (!pval) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + goto err; + } + pval->length = i2d_DSAparams(dsa, &pval->data); + if (pval->length <= 0) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + goto err; + } + ptype = V_ASN1_SEQUENCE; + } else { + ptype = V_ASN1_UNDEF; + } + + penclen = i2d_DSAPublicKey(dsa, &penc); + if (penclen <= 0) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (X509_PUBKEY_set0_param(pk, OBJ_nid2obj(EVP_PKEY_DSA), ptype, pval, + penc, penclen)) { + return 1; + } + +err: + OPENSSL_free(penc); + ASN1_STRING_free(pval); + + return 0; +} + +static int dsa_priv_decode(EVP_PKEY *pkey, PKCS8_PRIV_KEY_INFO *p8) { + const uint8_t *p, *pm; + int pklen, pmlen; + int ptype; + void *pval; + ASN1_STRING *pstr; + X509_ALGOR *palg; + ASN1_INTEGER *privkey = NULL; + BN_CTX *ctx = NULL; + + /* In PKCS#8 DSA: you just get a private key integer and parameters in the + * AlgorithmIdentifier the pubkey must be recalculated. */ + + STACK_OF(ASN1_TYPE) *ndsa = NULL; + DSA *dsa = NULL; + + if (!PKCS8_pkey_get0(NULL, &p, &pklen, &palg, p8)) { + return 0; + } + X509_ALGOR_get0(NULL, &ptype, &pval, palg); + + /* Check for broken DSA PKCS#8, UGH! */ + if (*p == (V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED)) { + ASN1_TYPE *t1, *t2; + ndsa = d2i_ASN1_SEQUENCE_ANY(NULL, &p, pklen); + if (ndsa == NULL) { + goto decerr; + } + if (sk_ASN1_TYPE_num(ndsa) != 2) { + goto decerr; + } + + /* Handle Two broken types: + * SEQUENCE {parameters, priv_key} + * SEQUENCE {pub_key, priv_key}. */ + + t1 = sk_ASN1_TYPE_value(ndsa, 0); + t2 = sk_ASN1_TYPE_value(ndsa, 1); + if (t1->type == V_ASN1_SEQUENCE) { + p8->broken = PKCS8_EMBEDDED_PARAM; + pval = t1->value.ptr; + } else if (ptype == V_ASN1_SEQUENCE) { + p8->broken = PKCS8_NS_DB; + } else { + goto decerr; + } + + if (t2->type != V_ASN1_INTEGER) { + goto decerr; + } + + privkey = t2->value.integer; + } else { + const uint8_t *q = p; + privkey = d2i_ASN1_INTEGER(NULL, &p, pklen); + if (privkey == NULL) { + goto decerr; + } + if (privkey->type == V_ASN1_NEG_INTEGER) { + p8->broken = PKCS8_NEG_PRIVKEY; + ASN1_INTEGER_free(privkey); + privkey = d2i_ASN1_UINTEGER(NULL, &q, pklen); + if (privkey == NULL) { + goto decerr; + } + } + if (ptype != V_ASN1_SEQUENCE) { + goto decerr; + } + } + + pstr = pval; + pm = pstr->data; + pmlen = pstr->length; + dsa = d2i_DSAparams(NULL, &pm, pmlen); + if (dsa == NULL) { + goto decerr; + } + /* We have parameters. Now set private key */ + dsa->priv_key = ASN1_INTEGER_to_BN(privkey, NULL); + if (dsa->priv_key == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_LIB_BN); + goto dsaerr; + } + /* Calculate public key. */ + dsa->pub_key = BN_new(); + if (dsa->pub_key == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + goto dsaerr; + } + ctx = BN_CTX_new(); + if (ctx == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + goto dsaerr; + } + + if (!BN_mod_exp(dsa->pub_key, dsa->g, dsa->priv_key, dsa->p, ctx)) { + OPENSSL_PUT_ERROR(EVP, ERR_LIB_BN); + goto dsaerr; + } + + EVP_PKEY_assign_DSA(pkey, dsa); + BN_CTX_free(ctx); + sk_ASN1_TYPE_pop_free(ndsa, ASN1_TYPE_free); + ASN1_INTEGER_free(privkey); + + return 1; + +decerr: + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + +dsaerr: + BN_CTX_free(ctx); + ASN1_INTEGER_free(privkey); + sk_ASN1_TYPE_pop_free(ndsa, ASN1_TYPE_free); + DSA_free(dsa); + return 0; +} + +static int dsa_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey) { + ASN1_STRING *params = NULL; + ASN1_INTEGER *prkey = NULL; + uint8_t *dp = NULL; + int dplen; + + if (!pkey->pkey.dsa || !pkey->pkey.dsa->priv_key) { + OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS); + goto err; + } + + params = ASN1_STRING_new(); + if (!params) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + goto err; + } + + params->length = i2d_DSAparams(pkey->pkey.dsa, ¶ms->data); + if (params->length <= 0) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + goto err; + } + params->type = V_ASN1_SEQUENCE; + + /* Get private key into integer. */ + prkey = BN_to_ASN1_INTEGER(pkey->pkey.dsa->priv_key, NULL); + + if (!prkey) { + OPENSSL_PUT_ERROR(EVP, ERR_LIB_BN); + goto err; + } + + dplen = i2d_ASN1_INTEGER(prkey, &dp); + + ASN1_INTEGER_free(prkey); + prkey = NULL; + + if (!PKCS8_pkey_set0(p8, (ASN1_OBJECT *)OBJ_nid2obj(NID_dsa), 0, + V_ASN1_SEQUENCE, params, dp, dplen)) { + goto err; + } + + return 1; + +err: + OPENSSL_free(dp); + ASN1_STRING_free(params); + ASN1_INTEGER_free(prkey); + return 0; +} + +static int int_dsa_size(const EVP_PKEY *pkey) { + return DSA_size(pkey->pkey.dsa); +} + +static int dsa_bits(const EVP_PKEY *pkey) { + return BN_num_bits(pkey->pkey.dsa->p); +} + +static int dsa_missing_parameters(const EVP_PKEY *pkey) { + DSA *dsa; + dsa = pkey->pkey.dsa; + if (dsa->p == NULL || dsa->q == NULL || dsa->g == NULL) { + return 1; + } + return 0; +} + +static int dup_bn_into(BIGNUM **out, BIGNUM *src) { + BIGNUM *a; + + a = BN_dup(src); + if (a == NULL) { + return 0; + } + BN_free(*out); + *out = a; + + return 1; +} + +static int dsa_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from) { + if (!dup_bn_into(&to->pkey.dsa->p, from->pkey.dsa->p) || + !dup_bn_into(&to->pkey.dsa->q, from->pkey.dsa->q) || + !dup_bn_into(&to->pkey.dsa->g, from->pkey.dsa->g)) { + return 0; + } + + return 1; +} + +static int dsa_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) { + return BN_cmp(a->pkey.dsa->p, b->pkey.dsa->p) == 0 && + BN_cmp(a->pkey.dsa->q, b->pkey.dsa->q) == 0 && + BN_cmp(a->pkey.dsa->g, b->pkey.dsa->g) == 0; +} + +static int dsa_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) { + return BN_cmp(b->pkey.dsa->pub_key, a->pkey.dsa->pub_key) == 0; +} + +static void int_dsa_free(EVP_PKEY *pkey) { DSA_free(pkey->pkey.dsa); } + +static void update_buflen(const BIGNUM *b, size_t *pbuflen) { + size_t i; + + if (!b) { + return; + } + i = BN_num_bytes(b); + if (*pbuflen < i) { + *pbuflen = i; + } +} + +static int do_dsa_print(BIO *bp, const DSA *x, int off, int ptype) { + uint8_t *m = NULL; + int ret = 0; + size_t buf_len = 0; + const char *ktype = NULL; + + const BIGNUM *priv_key, *pub_key; + + priv_key = NULL; + if (ptype == 2) { + priv_key = x->priv_key; + } + + pub_key = NULL; + if (ptype > 0) { + pub_key = x->pub_key; + } + + ktype = "DSA-Parameters"; + if (ptype == 2) { + ktype = "Private-Key"; + } else if (ptype == 1) { + ktype = "Public-Key"; + } + + update_buflen(x->p, &buf_len); + update_buflen(x->q, &buf_len); + update_buflen(x->g, &buf_len); + update_buflen(priv_key, &buf_len); + update_buflen(pub_key, &buf_len); + + m = (uint8_t *)OPENSSL_malloc(buf_len + 10); + if (m == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (priv_key) { + if (!BIO_indent(bp, off, 128) || + BIO_printf(bp, "%s: (%d bit)\n", ktype, BN_num_bits(x->p)) <= 0) { + goto err; + } + } + + if (!ASN1_bn_print(bp, "priv:", priv_key, m, off) || + !ASN1_bn_print(bp, "pub: ", pub_key, m, off) || + !ASN1_bn_print(bp, "P: ", x->p, m, off) || + !ASN1_bn_print(bp, "Q: ", x->q, m, off) || + !ASN1_bn_print(bp, "G: ", x->g, m, off)) { + goto err; + } + ret = 1; + +err: + OPENSSL_free(m); + return ret; +} + +static int dsa_param_decode(EVP_PKEY *pkey, const uint8_t **pder, int derlen) { + DSA *dsa; + dsa = d2i_DSAparams(NULL, pder, derlen); + if (dsa == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_DSA_LIB); + return 0; + } + EVP_PKEY_assign_DSA(pkey, dsa); + return 1; +} + +static int dsa_param_encode(const EVP_PKEY *pkey, uint8_t **pder) { + return i2d_DSAparams(pkey->pkey.dsa, pder); +} + +static int dsa_param_print(BIO *bp, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *ctx) { + return do_dsa_print(bp, pkey->pkey.dsa, indent, 0); +} + +static int dsa_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *ctx) { + return do_dsa_print(bp, pkey->pkey.dsa, indent, 1); +} + +static int dsa_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *ctx) { + return do_dsa_print(bp, pkey->pkey.dsa, indent, 2); +} + +static int old_dsa_priv_decode(EVP_PKEY *pkey, const uint8_t **pder, + int derlen) { + DSA *dsa; + dsa = d2i_DSAPrivateKey(NULL, pder, derlen); + if (dsa == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_DSA_LIB); + return 0; + } + EVP_PKEY_assign_DSA(pkey, dsa); + return 1; +} + +static int old_dsa_priv_encode(const EVP_PKEY *pkey, uint8_t **pder) { + return i2d_DSAPrivateKey(pkey->pkey.dsa, pder); +} + +static int dsa_sig_print(BIO *bp, const X509_ALGOR *sigalg, + const ASN1_STRING *sig, int indent, ASN1_PCTX *pctx) { + DSA_SIG *dsa_sig; + const uint8_t *p; + + if (!sig) { + return BIO_puts(bp, "\n") > 0; + } + + p = sig->data; + dsa_sig = d2i_DSA_SIG(NULL, &p, sig->length); + if (dsa_sig == NULL) { + return X509_signature_dump(bp, sig, indent); + } + + int rv = 0; + size_t buf_len = 0; + uint8_t *m = NULL; + + update_buflen(dsa_sig->r, &buf_len); + update_buflen(dsa_sig->s, &buf_len); + m = OPENSSL_malloc(buf_len + 10); + if (m == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (BIO_write(bp, "\n", 1) != 1 || + !ASN1_bn_print(bp, "r: ", dsa_sig->r, m, indent) || + !ASN1_bn_print(bp, "s: ", dsa_sig->s, m, indent)) { + goto err; + } + rv = 1; + +err: + OPENSSL_free(m); + DSA_SIG_free(dsa_sig); + return rv; +} + +const EVP_PKEY_ASN1_METHOD dsa_asn1_meth = { + EVP_PKEY_DSA, + EVP_PKEY_DSA, + 0, + + "DSA", + + dsa_pub_decode, + dsa_pub_encode, + dsa_pub_cmp, + dsa_pub_print, + + dsa_priv_decode, + dsa_priv_encode, + dsa_priv_print, + + NULL /* pkey_opaque */, + NULL /* pkey_supports_digest */, + + int_dsa_size, + dsa_bits, + + dsa_param_decode, + dsa_param_encode, + dsa_missing_parameters, + dsa_copy_parameters, + dsa_cmp_parameters, + dsa_param_print, + dsa_sig_print, + + int_dsa_free, + old_dsa_priv_decode, + old_dsa_priv_encode, +}; diff --git a/TMessagesProj/jni/boringssl/crypto/evp/p_ec.c b/TMessagesProj/jni/boringssl/crypto/evp/p_ec.c new file mode 100644 index 00000000..f0249600 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/evp/p_ec.c @@ -0,0 +1,299 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2006. + */ +/* ==================================================================== + * Copyright (c) 2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" +#include "../ec/internal.h" + + +typedef struct { + /* Key and paramgen group */ + EC_GROUP *gen_group; + /* message digest */ + const EVP_MD *md; +} EC_PKEY_CTX; + + +static int pkey_ec_init(EVP_PKEY_CTX *ctx) { + EC_PKEY_CTX *dctx; + dctx = OPENSSL_malloc(sizeof(EC_PKEY_CTX)); + if (!dctx) { + return 0; + } + memset(dctx, 0, sizeof(EC_PKEY_CTX)); + + ctx->data = dctx; + + return 1; +} + +static int pkey_ec_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) { + EC_PKEY_CTX *dctx, *sctx; + if (!pkey_ec_init(dst)) { + return 0; + } + sctx = src->data; + dctx = dst->data; + + if (sctx->gen_group) { + dctx->gen_group = EC_GROUP_dup(sctx->gen_group); + if (!dctx->gen_group) { + return 0; + } + } + dctx->md = sctx->md; + + return 1; +} + +static void pkey_ec_cleanup(EVP_PKEY_CTX *ctx) { + EC_PKEY_CTX *dctx = ctx->data; + if (!dctx) { + return; + } + + EC_GROUP_free(dctx->gen_group); + OPENSSL_free(dctx); +} + +static int pkey_ec_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *siglen, + const uint8_t *tbs, size_t tbslen) { + int type; + unsigned int sltmp; + EC_PKEY_CTX *dctx = ctx->data; + EC_KEY *ec = ctx->pkey->pkey.ec; + + if (!sig) { + *siglen = ECDSA_size(ec); + return 1; + } else if (*siglen < (size_t)ECDSA_size(ec)) { + OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL); + return 0; + } + + type = NID_sha1; + if (dctx->md) { + type = EVP_MD_type(dctx->md); + } + + if (!ECDSA_sign(type, tbs, tbslen, sig, &sltmp, ec)) { + return 0; + } + *siglen = (size_t)sltmp; + return 1; +} + +static int pkey_ec_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig, size_t siglen, + const uint8_t *tbs, size_t tbslen) { + int type; + EC_PKEY_CTX *dctx = ctx->data; + EC_KEY *ec = ctx->pkey->pkey.ec; + + type = NID_sha1; + if (dctx->md) { + type = EVP_MD_type(dctx->md); + } + + return ECDSA_verify(type, tbs, tbslen, sig, siglen, ec); +} + +static int pkey_ec_derive(EVP_PKEY_CTX *ctx, uint8_t *key, + size_t *keylen) { + int ret; + size_t outlen; + const EC_POINT *pubkey = NULL; + EC_KEY *eckey; + + if (!ctx->pkey || !ctx->peerkey) { + OPENSSL_PUT_ERROR(EVP, EVP_R_KEYS_NOT_SET); + return 0; + } + + eckey = ctx->pkey->pkey.ec; + + if (!key) { + const EC_GROUP *group; + group = EC_KEY_get0_group(eckey); + *keylen = (EC_GROUP_get_degree(group) + 7) / 8; + return 1; + } + pubkey = EC_KEY_get0_public_key(ctx->peerkey->pkey.ec); + + /* NB: unlike PKCS#3 DH, if *outlen is less than maximum size this is + * not an error, the result is truncated. */ + + outlen = *keylen; + + ret = ECDH_compute_key(key, outlen, pubkey, eckey, 0); + if (ret < 0) { + return 0; + } + *keylen = ret; + return 1; +} + +static int pkey_ec_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) { + EC_PKEY_CTX *dctx = ctx->data; + EC_GROUP *group; + + switch (type) { + case EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID: + group = EC_GROUP_new_by_curve_name(p1); + if (group == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_CURVE); + return 0; + } + EC_GROUP_free(dctx->gen_group); + dctx->gen_group = group; + return 1; + + case EVP_PKEY_CTRL_MD: + if (EVP_MD_type((const EVP_MD *)p2) != NID_sha1 && + EVP_MD_type((const EVP_MD *)p2) != NID_ecdsa_with_SHA1 && + EVP_MD_type((const EVP_MD *)p2) != NID_sha224 && + EVP_MD_type((const EVP_MD *)p2) != NID_sha256 && + EVP_MD_type((const EVP_MD *)p2) != NID_sha384 && + EVP_MD_type((const EVP_MD *)p2) != NID_sha512) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_DIGEST_TYPE); + return 0; + } + dctx->md = p2; + return 1; + + case EVP_PKEY_CTRL_GET_MD: + *(const EVP_MD **)p2 = dctx->md; + return 1; + + case EVP_PKEY_CTRL_PEER_KEY: + /* Default behaviour is OK */ + return 1; + + default: + OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED); + return 0; + } +} + +static int pkey_ec_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { + EC_KEY *ec = NULL; + EC_PKEY_CTX *dctx = ctx->data; + int ret = 0; + + if (dctx->gen_group == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET); + return 0; + } + ec = EC_KEY_new(); + if (!ec) { + return 0; + } + ret = EC_KEY_set_group(ec, dctx->gen_group); + if (ret) { + EVP_PKEY_assign_EC_KEY(pkey, ec); + } else { + EC_KEY_free(ec); + } + return ret; +} + +static int pkey_ec_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { + EC_KEY *ec = NULL; + EC_PKEY_CTX *dctx = ctx->data; + if (ctx->pkey == NULL && dctx->gen_group == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET); + return 0; + } + ec = EC_KEY_new(); + if (!ec) { + return 0; + } + EVP_PKEY_assign_EC_KEY(pkey, ec); + if (ctx->pkey) { + /* Note: if error return, pkey is freed by parent routine */ + if (!EVP_PKEY_copy_parameters(pkey, ctx->pkey)) { + return 0; + } + } else { + if (!EC_KEY_set_group(ec, dctx->gen_group)) { + return 0; + } + } + return EC_KEY_generate_key(pkey->pkey.ec); +} + +const EVP_PKEY_METHOD ec_pkey_meth = { + EVP_PKEY_EC, 0 /* flags */, pkey_ec_init, + pkey_ec_copy, pkey_ec_cleanup, 0 /* paramgen_init */, + pkey_ec_paramgen, 0 /* keygen_init */, pkey_ec_keygen, + 0 /* sign_init */, pkey_ec_sign, 0 /* verify_init */, + pkey_ec_verify, 0 /* encrypt_init */, 0 /* encrypt */, + 0 /* decrypt_init */, 0 /* decrypt */, 0 /* derive_init */, + pkey_ec_derive, pkey_ec_ctrl, +}; diff --git a/TMessagesProj/jni/boringssl/crypto/evp/p_ec_asn1.c b/TMessagesProj/jni/boringssl/crypto/evp/p_ec_asn1.c new file mode 100644 index 00000000..98679479 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/evp/p_ec_asn1.c @@ -0,0 +1,573 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2006. + */ +/* ==================================================================== + * Copyright (c) 2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" + + +static int eckey_param2type(int *pptype, void **ppval, EC_KEY *ec_key) { + const EC_GROUP *group; + int nid; + + if (ec_key == NULL || (group = EC_KEY_get0_group(ec_key)) == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS); + return 0; + } + + nid = EC_GROUP_get_curve_name(group); + if (nid == NID_undef) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_NID_FOR_CURVE); + return 0; + } + + *ppval = (void*) OBJ_nid2obj(nid); + *pptype = V_ASN1_OBJECT; + return 1; +} + +static int eckey_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey) { + EC_KEY *ec_key = pkey->pkey.ec; + void *pval = NULL; + int ptype; + uint8_t *penc = NULL, *p; + int penclen; + + if (!eckey_param2type(&ptype, &pval, ec_key)) { + OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB); + return 0; + } + penclen = i2o_ECPublicKey(ec_key, NULL); + if (penclen <= 0) { + goto err; + } + penc = OPENSSL_malloc(penclen); + if (!penc) { + goto err; + } + p = penc; + penclen = i2o_ECPublicKey(ec_key, &p); + if (penclen <= 0) { + goto err; + } + if (X509_PUBKEY_set0_param(pk, OBJ_nid2obj(EVP_PKEY_EC), ptype, pval, penc, + penclen)) { + return 1; + } + +err: + if (ptype == V_ASN1_OBJECT) { + ASN1_OBJECT_free(pval); + } else { + ASN1_STRING_free(pval); + } + if (penc) { + OPENSSL_free(penc); + } + return 0; +} + +static EC_KEY *eckey_type2param(int ptype, void *pval) { + EC_KEY *eckey = NULL; + + if (ptype == V_ASN1_SEQUENCE) { + ASN1_STRING *pstr = pval; + const uint8_t *pm = pstr->data; + int pmlen = pstr->length; + + eckey = d2i_ECParameters(NULL, &pm, pmlen); + if (eckey == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + goto err; + } + } else if (ptype == V_ASN1_OBJECT) { + ASN1_OBJECT *poid = pval; + + /* type == V_ASN1_OBJECT => the parameters are given + * by an asn1 OID */ + eckey = EC_KEY_new_by_curve_name(OBJ_obj2nid(poid)); + if (eckey == NULL) { + goto err; + } + } else { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + goto err; + } + + return eckey; + +err: + if (eckey) { + EC_KEY_free(eckey); + } + return NULL; +} + +static int eckey_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey) { + const uint8_t *p = NULL; + void *pval; + int ptype, pklen; + EC_KEY *eckey = NULL; + X509_ALGOR *palg; + + if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, &palg, pubkey)) { + return 0; + } + X509_ALGOR_get0(NULL, &ptype, &pval, palg); + + eckey = eckey_type2param(ptype, pval); + if (!eckey) { + OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB); + return 0; + } + + /* We have parameters now set public key */ + if (!o2i_ECPublicKey(&eckey, &p, pklen)) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + goto err; + } + + EVP_PKEY_assign_EC_KEY(pkey, eckey); + return 1; + +err: + if (eckey) { + EC_KEY_free(eckey); + } + return 0; +} + +static int eckey_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) { + int r; + const EC_GROUP *group = EC_KEY_get0_group(b->pkey.ec); + const EC_POINT *pa = EC_KEY_get0_public_key(a->pkey.ec), + *pb = EC_KEY_get0_public_key(b->pkey.ec); + r = EC_POINT_cmp(group, pa, pb, NULL); + if (r == 0) { + return 1; + } else if (r == 1) { + return 0; + } else { + return -2; + } +} + +static int eckey_priv_decode(EVP_PKEY *pkey, PKCS8_PRIV_KEY_INFO *p8) { + const uint8_t *p = NULL; + void *pval; + int ptype, pklen; + EC_KEY *eckey = NULL; + X509_ALGOR *palg; + + if (!PKCS8_pkey_get0(NULL, &p, &pklen, &palg, p8)) { + return 0; + } + X509_ALGOR_get0(NULL, &ptype, &pval, palg); + + eckey = eckey_type2param(ptype, pval); + + if (!eckey) { + goto ecliberr; + } + + /* We have parameters now set private key */ + if (!d2i_ECPrivateKey(&eckey, &p, pklen)) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + goto ecerr; + } + + /* calculate public key (if necessary) */ + if (EC_KEY_get0_public_key(eckey) == NULL) { + const BIGNUM *priv_key; + const EC_GROUP *group; + EC_POINT *pub_key; + /* the public key was not included in the SEC1 private + * key => calculate the public key */ + group = EC_KEY_get0_group(eckey); + pub_key = EC_POINT_new(group); + if (pub_key == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB); + goto ecliberr; + } + if (!EC_POINT_copy(pub_key, EC_GROUP_get0_generator(group))) { + EC_POINT_free(pub_key); + OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB); + goto ecliberr; + } + priv_key = EC_KEY_get0_private_key(eckey); + if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, NULL)) { + EC_POINT_free(pub_key); + OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB); + goto ecliberr; + } + if (EC_KEY_set_public_key(eckey, pub_key) == 0) { + EC_POINT_free(pub_key); + OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB); + goto ecliberr; + } + EC_POINT_free(pub_key); + } + + EVP_PKEY_assign_EC_KEY(pkey, eckey); + return 1; + +ecliberr: + OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB); +ecerr: + if (eckey) { + EC_KEY_free(eckey); + } + return 0; +} + +static int eckey_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey) { + EC_KEY *ec_key; + uint8_t *ep, *p; + int eplen, ptype; + void *pval; + unsigned int tmp_flags, old_flags; + + ec_key = pkey->pkey.ec; + + if (!eckey_param2type(&ptype, &pval, ec_key)) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + return 0; + } + + /* set the private key */ + + /* do not include the parameters in the SEC1 private key + * see PKCS#11 12.11 */ + old_flags = EC_KEY_get_enc_flags(ec_key); + tmp_flags = old_flags | EC_PKEY_NO_PARAMETERS; + EC_KEY_set_enc_flags(ec_key, tmp_flags); + eplen = i2d_ECPrivateKey(ec_key, NULL); + if (!eplen) { + EC_KEY_set_enc_flags(ec_key, old_flags); + OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB); + return 0; + } + ep = (uint8_t *)OPENSSL_malloc(eplen); + if (!ep) { + EC_KEY_set_enc_flags(ec_key, old_flags); + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + return 0; + } + p = ep; + if (!i2d_ECPrivateKey(ec_key, &p)) { + EC_KEY_set_enc_flags(ec_key, old_flags); + OPENSSL_free(ep); + OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB); + return 0; + } + /* restore old encoding flags */ + EC_KEY_set_enc_flags(ec_key, old_flags); + + if (!PKCS8_pkey_set0(p8, (ASN1_OBJECT *)OBJ_nid2obj(NID_X9_62_id_ecPublicKey), + 0, ptype, pval, ep, eplen)) { + OPENSSL_free(ep); + return 0; + } + + return 1; +} + +static int int_ec_size(const EVP_PKEY *pkey) { + return ECDSA_size(pkey->pkey.ec); +} + +static int ec_bits(const EVP_PKEY *pkey) { + BIGNUM *order = BN_new(); + const EC_GROUP *group; + int ret; + + if (!order) { + ERR_clear_error(); + return 0; + } + group = EC_KEY_get0_group(pkey->pkey.ec); + if (!EC_GROUP_get_order(group, order, NULL)) { + ERR_clear_error(); + return 0; + } + + ret = BN_num_bits(order); + BN_free(order); + return ret; +} + +static int ec_missing_parameters(const EVP_PKEY *pkey) { + return EC_KEY_get0_group(pkey->pkey.ec) == NULL; +} + +static int ec_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from) { + EC_GROUP *group = EC_GROUP_dup(EC_KEY_get0_group(from->pkey.ec)); + if (group == NULL || + EC_KEY_set_group(to->pkey.ec, group) == 0) { + return 0; + } + EC_GROUP_free(group); + return 1; +} + +static int ec_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) { + const EC_GROUP *group_a = EC_KEY_get0_group(a->pkey.ec), + *group_b = EC_KEY_get0_group(b->pkey.ec); + if (EC_GROUP_cmp(group_a, group_b, NULL) != 0) { + /* mismatch */ + return 0; + } + return 1; +} + +static void int_ec_free(EVP_PKEY *pkey) { EC_KEY_free(pkey->pkey.ec); } + +static int do_EC_KEY_print(BIO *bp, const EC_KEY *x, int off, int ktype) { + uint8_t *buffer = NULL; + const char *ecstr; + size_t buf_len = 0, i; + int ret = 0, reason = ERR_R_BIO_LIB; + BIGNUM *order = NULL; + BN_CTX *ctx = NULL; + const EC_GROUP *group; + const EC_POINT *public_key; + const BIGNUM *priv_key; + uint8_t *pub_key_bytes = NULL; + size_t pub_key_bytes_len = 0; + + if (x == NULL || (group = EC_KEY_get0_group(x)) == NULL) { + reason = ERR_R_PASSED_NULL_PARAMETER; + goto err; + } + + ctx = BN_CTX_new(); + if (ctx == NULL) { + reason = ERR_R_MALLOC_FAILURE; + goto err; + } + + if (ktype > 0) { + public_key = EC_KEY_get0_public_key(x); + if (public_key != NULL) { + pub_key_bytes_len = EC_POINT_point2oct( + group, public_key, EC_KEY_get_conv_form(x), NULL, 0, ctx); + if (pub_key_bytes_len == 0) { + reason = ERR_R_MALLOC_FAILURE; + goto err; + } + pub_key_bytes = OPENSSL_malloc(pub_key_bytes_len); + if (pub_key_bytes == NULL) { + reason = ERR_R_MALLOC_FAILURE; + goto err; + } + pub_key_bytes_len = + EC_POINT_point2oct(group, public_key, EC_KEY_get_conv_form(x), + pub_key_bytes, pub_key_bytes_len, ctx); + if (pub_key_bytes_len == 0) { + reason = ERR_R_MALLOC_FAILURE; + goto err; + } + buf_len = pub_key_bytes_len; + } + } + + if (ktype == 2) { + priv_key = EC_KEY_get0_private_key(x); + if (priv_key && (i = (size_t)BN_num_bytes(priv_key)) > buf_len) { + buf_len = i; + } + } else { + priv_key = NULL; + } + + if (ktype > 0) { + buf_len += 10; + if ((buffer = OPENSSL_malloc(buf_len)) == NULL) { + reason = ERR_R_MALLOC_FAILURE; + goto err; + } + } + if (ktype == 2) { + ecstr = "Private-Key"; + } else if (ktype == 1) { + ecstr = "Public-Key"; + } else { + ecstr = "ECDSA-Parameters"; + } + + if (!BIO_indent(bp, off, 128)) { + goto err; + } + order = BN_new(); + if (order == NULL || !EC_GROUP_get_order(group, order, NULL) || + BIO_printf(bp, "%s: (%d bit)\n", ecstr, BN_num_bits(order)) <= 0) { + goto err; + } + + if ((priv_key != NULL) && + !ASN1_bn_print(bp, "priv:", priv_key, buffer, off)) { + goto err; + } + if (pub_key_bytes != NULL) { + BIO_hexdump(bp, pub_key_bytes, pub_key_bytes_len, off); + } + /* TODO(fork): implement */ + /* + if (!ECPKParameters_print(bp, group, off)) + goto err; */ + ret = 1; + +err: + if (!ret) { + OPENSSL_PUT_ERROR(EVP, reason); + } + OPENSSL_free(pub_key_bytes); + BN_free(order); + BN_CTX_free(ctx); + OPENSSL_free(buffer); + return ret; +} + +static int eckey_param_decode(EVP_PKEY *pkey, const uint8_t **pder, + int derlen) { + EC_KEY *eckey; + if (!(eckey = d2i_ECParameters(NULL, pder, derlen))) { + OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB); + return 0; + } + EVP_PKEY_assign_EC_KEY(pkey, eckey); + return 1; +} + +static int eckey_param_encode(const EVP_PKEY *pkey, uint8_t **pder) { + return i2d_ECParameters(pkey->pkey.ec, pder); +} + +static int eckey_param_print(BIO *bp, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *ctx) { + return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 0); +} + +static int eckey_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *ctx) { + return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 1); +} + + +static int eckey_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *ctx) { + return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 2); +} + +static int eckey_opaque(const EVP_PKEY *pkey) { + return EC_KEY_is_opaque(pkey->pkey.ec); +} + +static int old_ec_priv_decode(EVP_PKEY *pkey, const uint8_t **pder, + int derlen) { + EC_KEY *ec; + if (!(ec = d2i_ECPrivateKey(NULL, pder, derlen))) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + return 0; + } + EVP_PKEY_assign_EC_KEY(pkey, ec); + return 1; +} + +static int old_ec_priv_encode(const EVP_PKEY *pkey, uint8_t **pder) { + return i2d_ECPrivateKey(pkey->pkey.ec, pder); +} + +const EVP_PKEY_ASN1_METHOD ec_asn1_meth = { + EVP_PKEY_EC, + EVP_PKEY_EC, + 0, + "EC", + + eckey_pub_decode, + eckey_pub_encode, + eckey_pub_cmp, + eckey_pub_print, + + eckey_priv_decode, + eckey_priv_encode, + eckey_priv_print, + + eckey_opaque, + 0 /* pkey_supports_digest */, + + int_ec_size, + ec_bits, + + eckey_param_decode, + eckey_param_encode, + ec_missing_parameters, + ec_copy_parameters, + ec_cmp_parameters, + eckey_param_print, + 0, + + int_ec_free, + old_ec_priv_decode, + old_ec_priv_encode +}; diff --git a/TMessagesProj/jni/boringssl/crypto/evp/p_rsa.c b/TMessagesProj/jni/boringssl/crypto/evp/p_rsa.c new file mode 100644 index 00000000..cfecbfd0 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/evp/p_rsa.c @@ -0,0 +1,596 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2006. + */ +/* ==================================================================== + * Copyright (c) 2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../rsa/internal.h" +#include "internal.h" + + +typedef struct { + /* Key gen parameters */ + int nbits; + BIGNUM *pub_exp; + /* RSA padding mode */ + int pad_mode; + /* message digest */ + const EVP_MD *md; + /* message digest for MGF1 */ + const EVP_MD *mgf1md; + /* PSS salt length */ + int saltlen; + /* tbuf is a buffer which is either NULL, or is the size of the RSA modulus. + * It's used to store the output of RSA operations. */ + uint8_t *tbuf; + /* OAEP label */ + uint8_t *oaep_label; + size_t oaep_labellen; +} RSA_PKEY_CTX; + +static int pkey_rsa_init(EVP_PKEY_CTX *ctx) { + RSA_PKEY_CTX *rctx; + rctx = OPENSSL_malloc(sizeof(RSA_PKEY_CTX)); + if (!rctx) { + return 0; + } + memset(rctx, 0, sizeof(RSA_PKEY_CTX)); + + rctx->nbits = 2048; + rctx->pad_mode = RSA_PKCS1_PADDING; + rctx->saltlen = -2; + + ctx->data = rctx; + + return 1; +} + +static int pkey_rsa_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) { + RSA_PKEY_CTX *dctx, *sctx; + if (!pkey_rsa_init(dst)) { + return 0; + } + sctx = src->data; + dctx = dst->data; + dctx->nbits = sctx->nbits; + if (sctx->pub_exp) { + dctx->pub_exp = BN_dup(sctx->pub_exp); + if (!dctx->pub_exp) { + return 0; + } + } + + dctx->pad_mode = sctx->pad_mode; + dctx->md = sctx->md; + dctx->mgf1md = sctx->mgf1md; + if (sctx->oaep_label) { + OPENSSL_free(dctx->oaep_label); + dctx->oaep_label = BUF_memdup(sctx->oaep_label, sctx->oaep_labellen); + if (!dctx->oaep_label) { + return 0; + } + dctx->oaep_labellen = sctx->oaep_labellen; + } + + return 1; +} + +static void pkey_rsa_cleanup(EVP_PKEY_CTX *ctx) { + RSA_PKEY_CTX *rctx = ctx->data; + + if (rctx == NULL) { + return; + } + + BN_free(rctx->pub_exp); + OPENSSL_free(rctx->tbuf); + OPENSSL_free(rctx->oaep_label); + OPENSSL_free(rctx); +} + +static int setup_tbuf(RSA_PKEY_CTX *ctx, EVP_PKEY_CTX *pk) { + if (ctx->tbuf) { + return 1; + } + ctx->tbuf = OPENSSL_malloc(EVP_PKEY_size(pk->pkey)); + if (!ctx->tbuf) { + return 0; + } + return 1; +} + +static int pkey_rsa_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *siglen, + const uint8_t *tbs, size_t tbslen) { + RSA_PKEY_CTX *rctx = ctx->data; + RSA *rsa = ctx->pkey->pkey.rsa; + const size_t key_len = EVP_PKEY_size(ctx->pkey); + + if (!sig) { + *siglen = key_len; + return 1; + } + + if (*siglen < key_len) { + OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL); + return 0; + } + + if (rctx->md) { + unsigned int out_len; + + if (tbslen != EVP_MD_size(rctx->md)) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_DIGEST_LENGTH); + return 0; + } + + if (EVP_MD_type(rctx->md) == NID_mdc2) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_MDC2_SUPPORT); + return 0; + } + + switch (rctx->pad_mode) { + case RSA_PKCS1_PADDING: + if (!RSA_sign(EVP_MD_type(rctx->md), tbs, tbslen, sig, &out_len, rsa)) { + return 0; + } + *siglen = out_len; + return 1; + + case RSA_PKCS1_PSS_PADDING: + if (!setup_tbuf(rctx, ctx) || + !RSA_padding_add_PKCS1_PSS_mgf1(rsa, rctx->tbuf, tbs, rctx->md, + rctx->mgf1md, rctx->saltlen) || + !RSA_sign_raw(rsa, siglen, sig, *siglen, rctx->tbuf, key_len, + RSA_NO_PADDING)) { + return 0; + } + return 1; + + default: + return 0; + } + } + + return RSA_sign_raw(rsa, siglen, sig, *siglen, tbs, tbslen, rctx->pad_mode); +} + +static int pkey_rsa_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig, + size_t siglen, const uint8_t *tbs, + size_t tbslen) { + RSA_PKEY_CTX *rctx = ctx->data; + RSA *rsa = ctx->pkey->pkey.rsa; + size_t rslen; + const size_t key_len = EVP_PKEY_size(ctx->pkey); + + if (rctx->md) { + switch (rctx->pad_mode) { + case RSA_PKCS1_PADDING: + return RSA_verify(EVP_MD_type(rctx->md), tbs, tbslen, sig, siglen, rsa); + + case RSA_PKCS1_PSS_PADDING: + if (!setup_tbuf(rctx, ctx) || + !RSA_verify_raw(rsa, &rslen, rctx->tbuf, key_len, sig, siglen, + RSA_NO_PADDING) || + !RSA_verify_PKCS1_PSS_mgf1(rsa, tbs, rctx->md, rctx->mgf1md, + rctx->tbuf, rctx->saltlen)) { + return 0; + } + return 1; + + default: + return 0; + } + } + + if (!setup_tbuf(rctx, ctx) || + !RSA_verify_raw(rsa, &rslen, rctx->tbuf, key_len, sig, siglen, + rctx->pad_mode) || + rslen != tbslen || + CRYPTO_memcmp(tbs, rctx->tbuf, rslen) != 0) { + return 0; + } + + return 1; +} + +static int pkey_rsa_encrypt(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *outlen, + const uint8_t *in, size_t inlen) { + RSA_PKEY_CTX *rctx = ctx->data; + RSA *rsa = ctx->pkey->pkey.rsa; + const size_t key_len = EVP_PKEY_size(ctx->pkey); + + if (!out) { + *outlen = key_len; + return 1; + } + + if (*outlen < key_len) { + OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL); + return 0; + } + + if (rctx->pad_mode == RSA_PKCS1_OAEP_PADDING) { + if (!setup_tbuf(rctx, ctx) || + !RSA_padding_add_PKCS1_OAEP_mgf1(rctx->tbuf, key_len, in, inlen, + rctx->oaep_label, rctx->oaep_labellen, + rctx->md, rctx->mgf1md) || + !RSA_encrypt(rsa, outlen, out, *outlen, rctx->tbuf, key_len, + RSA_NO_PADDING)) { + return 0; + } + return 1; + } + + return RSA_encrypt(rsa, outlen, out, *outlen, in, inlen, rctx->pad_mode); +} + +static int pkey_rsa_decrypt(EVP_PKEY_CTX *ctx, uint8_t *out, + size_t *outlen, const uint8_t *in, + size_t inlen) { + RSA_PKEY_CTX *rctx = ctx->data; + RSA *rsa = ctx->pkey->pkey.rsa; + const size_t key_len = EVP_PKEY_size(ctx->pkey); + + if (!out) { + *outlen = key_len; + return 1; + } + + if (*outlen < key_len) { + OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL); + return 0; + } + + if (rctx->pad_mode == RSA_PKCS1_OAEP_PADDING) { + size_t plaintext_len; + int message_len; + + if (!setup_tbuf(rctx, ctx) || + !RSA_decrypt(rsa, &plaintext_len, rctx->tbuf, key_len, in, inlen, + RSA_NO_PADDING)) { + return 0; + } + + message_len = RSA_padding_check_PKCS1_OAEP_mgf1( + out, key_len, rctx->tbuf, plaintext_len, rctx->oaep_label, + rctx->oaep_labellen, rctx->md, rctx->mgf1md); + if (message_len < 0) { + return 0; + } + *outlen = message_len; + return 1; + } + + return RSA_decrypt(rsa, outlen, out, key_len, in, inlen, rctx->pad_mode); +} + +static int check_padding_md(const EVP_MD *md, int padding) { + if (!md) { + return 1; + } + + if (padding == RSA_NO_PADDING) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PADDING_MODE); + return 0; + } + + return 1; +} + +static int is_known_padding(int padding_mode) { + switch (padding_mode) { + case RSA_PKCS1_PADDING: + case RSA_NO_PADDING: + case RSA_PKCS1_OAEP_PADDING: + case RSA_PKCS1_PSS_PADDING: + return 1; + default: + return 0; + } +} + +static int pkey_rsa_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) { + RSA_PKEY_CTX *rctx = ctx->data; + switch (type) { + case EVP_PKEY_CTRL_RSA_PADDING: + if (!is_known_padding(p1) || !check_padding_md(rctx->md, p1) || + (p1 == RSA_PKCS1_PSS_PADDING && + 0 == (ctx->operation & (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY))) || + (p1 == RSA_PKCS1_OAEP_PADDING && + 0 == (ctx->operation & EVP_PKEY_OP_TYPE_CRYPT))) { + OPENSSL_PUT_ERROR(EVP, EVP_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE); + return 0; + } + if ((p1 == RSA_PKCS1_PSS_PADDING || p1 == RSA_PKCS1_OAEP_PADDING) && + rctx->md == NULL) { + rctx->md = EVP_sha1(); + } + rctx->pad_mode = p1; + return 1; + + case EVP_PKEY_CTRL_GET_RSA_PADDING: + *(int *)p2 = rctx->pad_mode; + return 1; + + case EVP_PKEY_CTRL_RSA_PSS_SALTLEN: + case EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN: + if (rctx->pad_mode != RSA_PKCS1_PSS_PADDING) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PSS_SALTLEN); + return 0; + } + if (type == EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN) { + *(int *)p2 = rctx->saltlen; + } else { + if (p1 < -2) { + return 0; + } + rctx->saltlen = p1; + } + return 1; + + case EVP_PKEY_CTRL_RSA_KEYGEN_BITS: + if (p1 < 256) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_KEYBITS); + return 0; + } + rctx->nbits = p1; + return 1; + + case EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP: + if (!p2) { + return 0; + } + BN_free(rctx->pub_exp); + rctx->pub_exp = p2; + return 1; + + case EVP_PKEY_CTRL_RSA_OAEP_MD: + case EVP_PKEY_CTRL_GET_RSA_OAEP_MD: + if (rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PADDING_MODE); + return 0; + } + if (type == EVP_PKEY_CTRL_GET_RSA_OAEP_MD) { + *(const EVP_MD **)p2 = rctx->md; + } else { + rctx->md = p2; + } + return 1; + + case EVP_PKEY_CTRL_MD: + if (!check_padding_md(p2, rctx->pad_mode)) { + return 0; + } + rctx->md = p2; + return 1; + + case EVP_PKEY_CTRL_GET_MD: + *(const EVP_MD **)p2 = rctx->md; + return 1; + + case EVP_PKEY_CTRL_RSA_MGF1_MD: + case EVP_PKEY_CTRL_GET_RSA_MGF1_MD: + if (rctx->pad_mode != RSA_PKCS1_PSS_PADDING && + rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_MGF1_MD); + return 0; + } + if (type == EVP_PKEY_CTRL_GET_RSA_MGF1_MD) { + if (rctx->mgf1md) { + *(const EVP_MD **)p2 = rctx->mgf1md; + } else { + *(const EVP_MD **)p2 = rctx->md; + } + } else { + rctx->mgf1md = p2; + } + return 1; + + case EVP_PKEY_CTRL_RSA_OAEP_LABEL: + if (rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PADDING_MODE); + return 0; + } + OPENSSL_free(rctx->oaep_label); + if (p2 && p1 > 0) { + /* TODO(fork): this seems wrong. Shouldn't it take a copy of the + * buffer? */ + rctx->oaep_label = p2; + rctx->oaep_labellen = p1; + } else { + rctx->oaep_label = NULL; + rctx->oaep_labellen = 0; + } + return 1; + + case EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL: + if (rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PADDING_MODE); + return 0; + } + CBS_init((CBS *)p2, rctx->oaep_label, rctx->oaep_labellen); + return 1; + + default: + OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED); + return 0; + } +} + +static int pkey_rsa_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { + RSA *rsa = NULL; + RSA_PKEY_CTX *rctx = ctx->data; + + if (!rctx->pub_exp) { + rctx->pub_exp = BN_new(); + if (!rctx->pub_exp || !BN_set_word(rctx->pub_exp, RSA_F4)) { + return 0; + } + } + rsa = RSA_new(); + if (!rsa) { + return 0; + } + + if (!RSA_generate_key_ex(rsa, rctx->nbits, rctx->pub_exp, NULL)) { + RSA_free(rsa); + return 0; + } + + EVP_PKEY_assign_RSA(pkey, rsa); + return 1; +} + +const EVP_PKEY_METHOD rsa_pkey_meth = { + EVP_PKEY_RSA, 0 /* flags */, pkey_rsa_init, + pkey_rsa_copy, pkey_rsa_cleanup, 0 /* paramgen_init */, + 0 /* paramgen */, 0 /* keygen_init */, pkey_rsa_keygen, + 0 /* sign_init */, pkey_rsa_sign, 0 /* verify_init */, + pkey_rsa_verify, 0 /* encrypt_init */, pkey_rsa_encrypt, + 0 /* decrypt_init */, pkey_rsa_decrypt, 0 /* derive_init */, + 0 /* derive */, pkey_rsa_ctrl, +}; + +int EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX *ctx, int padding) { + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, EVP_PKEY_CTRL_RSA_PADDING, + padding, NULL); +} + +int EVP_PKEY_CTX_get_rsa_padding(EVP_PKEY_CTX *ctx, int *out_padding) { + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, EVP_PKEY_CTRL_GET_RSA_PADDING, + 0, out_padding); +} + +int EVP_PKEY_CTX_set_rsa_pss_saltlen(EVP_PKEY_CTX *ctx, int salt_len) { + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, + (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY), + EVP_PKEY_CTRL_RSA_PSS_SALTLEN, salt_len, NULL); +} + +int EVP_PKEY_CTX_get_rsa_pss_saltlen(EVP_PKEY_CTX *ctx, int *out_salt_len) { + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, + (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY), + EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN, 0, out_salt_len); +} + +int EVP_PKEY_CTX_set_rsa_keygen_bits(EVP_PKEY_CTX *ctx, int bits) { + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_KEYGEN, + EVP_PKEY_CTRL_RSA_KEYGEN_BITS, bits, NULL); +} + +int EVP_PKEY_CTX_set_rsa_keygen_pubexp(EVP_PKEY_CTX *ctx, BIGNUM *e) { + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_KEYGEN, + EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP, 0, e); +} + +int EVP_PKEY_CTX_set_rsa_oaep_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) { + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT, + EVP_PKEY_CTRL_RSA_OAEP_MD, 0, (void *)md); +} + +int EVP_PKEY_CTX_get_rsa_oaep_md(EVP_PKEY_CTX *ctx, const EVP_MD **out_md) { + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT, + EVP_PKEY_CTRL_GET_RSA_OAEP_MD, 0, (void*) out_md); +} + +int EVP_PKEY_CTX_set_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) { + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, + EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT, + EVP_PKEY_CTRL_RSA_MGF1_MD, 0, (void*) md); +} + +int EVP_PKEY_CTX_get_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD **out_md) { + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, + EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT, + EVP_PKEY_CTRL_GET_RSA_MGF1_MD, 0, (void*) out_md); +} + +int EVP_PKEY_CTX_set0_rsa_oaep_label(EVP_PKEY_CTX *ctx, const uint8_t *label, + size_t label_len) { + int label_len_int = label_len; + if (((size_t) label_len_int) != label_len) { + return 0; + } + + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT, + EVP_PKEY_CTRL_RSA_OAEP_LABEL, label_len, + (void *)label); +} + +int EVP_PKEY_CTX_get0_rsa_oaep_label(EVP_PKEY_CTX *ctx, + const uint8_t **out_label) { + CBS label; + if (!EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT, + EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL, 0, &label)) { + return -1; + } + if (CBS_len(&label) > INT_MAX) { + OPENSSL_PUT_ERROR(EVP, ERR_R_OVERFLOW); + return -1; + } + *out_label = CBS_data(&label); + return (int)CBS_len(&label); +} diff --git a/TMessagesProj/jni/boringssl/crypto/evp/p_rsa_asn1.c b/TMessagesProj/jni/boringssl/crypto/evp/p_rsa_asn1.c new file mode 100644 index 00000000..544ff1b8 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/evp/p_rsa_asn1.c @@ -0,0 +1,727 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2006. + */ +/* ==================================================================== + * Copyright (c) 2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../rsa/internal.h" +#include "internal.h" + + +static int rsa_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey) { + uint8_t *encoded; + size_t encoded_len; + if (!RSA_public_key_to_bytes(&encoded, &encoded_len, pkey->pkey.rsa)) { + return 0; + } + + if (!X509_PUBKEY_set0_param(pk, OBJ_nid2obj(EVP_PKEY_RSA), V_ASN1_NULL, NULL, + encoded, encoded_len)) { + OPENSSL_free(encoded); + return 0; + } + + return 1; +} + +static int rsa_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey) { + const uint8_t *p; + int pklen; + RSA *rsa; + + if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, NULL, pubkey)) { + return 0; + } + rsa = RSA_public_key_from_bytes(p, pklen); + if (rsa == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_RSA_LIB); + return 0; + } + EVP_PKEY_assign_RSA(pkey, rsa); + return 1; +} + +static int rsa_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) { + return BN_cmp(b->pkey.rsa->n, a->pkey.rsa->n) == 0 && + BN_cmp(b->pkey.rsa->e, a->pkey.rsa->e) == 0; +} + +static int rsa_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey) { + uint8_t *encoded; + size_t encoded_len; + if (!RSA_private_key_to_bytes(&encoded, &encoded_len, pkey->pkey.rsa)) { + return 0; + } + + /* TODO(fork): const correctness in next line. */ + if (!PKCS8_pkey_set0(p8, (ASN1_OBJECT *)OBJ_nid2obj(NID_rsaEncryption), 0, + V_ASN1_NULL, NULL, encoded, encoded_len)) { + OPENSSL_free(encoded); + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + return 0; + } + + return 1; +} + +static int rsa_priv_decode(EVP_PKEY *pkey, PKCS8_PRIV_KEY_INFO *p8) { + const uint8_t *p; + int pklen; + if (!PKCS8_pkey_get0(NULL, &p, &pklen, NULL, p8)) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + return 0; + } + + RSA *rsa = RSA_private_key_from_bytes(p, pklen); + if (rsa == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_RSA_LIB); + return 0; + } + + EVP_PKEY_assign_RSA(pkey, rsa); + return 1; +} + +static int rsa_opaque(const EVP_PKEY *pkey) { + return RSA_is_opaque(pkey->pkey.rsa); +} + +static int rsa_supports_digest(const EVP_PKEY *pkey, const EVP_MD *md) { + return RSA_supports_digest(pkey->pkey.rsa, md); +} + +static int int_rsa_size(const EVP_PKEY *pkey) { + return RSA_size(pkey->pkey.rsa); +} + +static int rsa_bits(const EVP_PKEY *pkey) { + return BN_num_bits(pkey->pkey.rsa->n); +} + +static void int_rsa_free(EVP_PKEY *pkey) { RSA_free(pkey->pkey.rsa); } + +static void update_buflen(const BIGNUM *b, size_t *pbuflen) { + size_t i; + + if (!b) { + return; + } + + i = BN_num_bytes(b); + if (*pbuflen < i) { + *pbuflen = i; + } +} + +static int do_rsa_print(BIO *out, const RSA *rsa, int off, + int include_private) { + char *str; + const char *s; + uint8_t *m = NULL; + int ret = 0, mod_len = 0; + size_t buf_len = 0; + + update_buflen(rsa->n, &buf_len); + update_buflen(rsa->e, &buf_len); + + if (include_private) { + update_buflen(rsa->d, &buf_len); + update_buflen(rsa->p, &buf_len); + update_buflen(rsa->q, &buf_len); + update_buflen(rsa->dmp1, &buf_len); + update_buflen(rsa->dmq1, &buf_len); + update_buflen(rsa->iqmp, &buf_len); + + if (rsa->additional_primes != NULL) { + size_t i; + + for (i = 0; i < sk_RSA_additional_prime_num(rsa->additional_primes); + i++) { + const RSA_additional_prime *ap = + sk_RSA_additional_prime_value(rsa->additional_primes, i); + update_buflen(ap->prime, &buf_len); + update_buflen(ap->exp, &buf_len); + update_buflen(ap->coeff, &buf_len); + } + } + } + + m = (uint8_t *)OPENSSL_malloc(buf_len + 10); + if (m == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (rsa->n != NULL) { + mod_len = BN_num_bits(rsa->n); + } + + if (!BIO_indent(out, off, 128)) { + goto err; + } + + if (include_private && rsa->d) { + if (BIO_printf(out, "Private-Key: (%d bit)\n", mod_len) <= 0) { + goto err; + } + str = "modulus:"; + s = "publicExponent:"; + } else { + if (BIO_printf(out, "Public-Key: (%d bit)\n", mod_len) <= 0) { + goto err; + } + str = "Modulus:"; + s = "Exponent:"; + } + if (!ASN1_bn_print(out, str, rsa->n, m, off) || + !ASN1_bn_print(out, s, rsa->e, m, off)) { + goto err; + } + + if (include_private) { + if (!ASN1_bn_print(out, "privateExponent:", rsa->d, m, off) || + !ASN1_bn_print(out, "prime1:", rsa->p, m, off) || + !ASN1_bn_print(out, "prime2:", rsa->q, m, off) || + !ASN1_bn_print(out, "exponent1:", rsa->dmp1, m, off) || + !ASN1_bn_print(out, "exponent2:", rsa->dmq1, m, off) || + !ASN1_bn_print(out, "coefficient:", rsa->iqmp, m, off)) { + goto err; + } + + if (rsa->additional_primes != NULL && + sk_RSA_additional_prime_num(rsa->additional_primes) > 0) { + size_t i; + + if (BIO_printf(out, "otherPrimeInfos:\n") <= 0) { + goto err; + } + for (i = 0; i < sk_RSA_additional_prime_num(rsa->additional_primes); + i++) { + const RSA_additional_prime *ap = + sk_RSA_additional_prime_value(rsa->additional_primes, i); + + if (BIO_printf(out, "otherPrimeInfo (prime %u):\n", + (unsigned)(i + 3)) <= 0 || + !ASN1_bn_print(out, "prime:", ap->prime, m, off) || + !ASN1_bn_print(out, "exponent:", ap->exp, m, off) || + !ASN1_bn_print(out, "coeff:", ap->coeff, m, off)) { + goto err; + } + } + } + } + ret = 1; + +err: + OPENSSL_free(m); + return ret; +} + +static int rsa_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *ctx) { + return do_rsa_print(bp, pkey->pkey.rsa, indent, 0); +} + + +static int rsa_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *ctx) { + return do_rsa_print(bp, pkey->pkey.rsa, indent, 1); +} + +/* Given an MGF1 Algorithm ID decode to an Algorithm Identifier */ +static X509_ALGOR *rsa_mgf1_decode(X509_ALGOR *alg) { + const uint8_t *p; + int plen; + + if (alg == NULL || + OBJ_obj2nid(alg->algorithm) != NID_mgf1 || + alg->parameter->type != V_ASN1_SEQUENCE) { + return NULL; + } + + p = alg->parameter->value.sequence->data; + plen = alg->parameter->value.sequence->length; + return d2i_X509_ALGOR(NULL, &p, plen); +} + +static RSA_PSS_PARAMS *rsa_pss_decode(const X509_ALGOR *alg, + X509_ALGOR **pmaskHash) { + const uint8_t *p; + int plen; + RSA_PSS_PARAMS *pss; + + *pmaskHash = NULL; + + if (!alg->parameter || alg->parameter->type != V_ASN1_SEQUENCE) { + return NULL; + } + p = alg->parameter->value.sequence->data; + plen = alg->parameter->value.sequence->length; + pss = d2i_RSA_PSS_PARAMS(NULL, &p, plen); + + if (!pss) { + return NULL; + } + + *pmaskHash = rsa_mgf1_decode(pss->maskGenAlgorithm); + + return pss; +} + +static int rsa_pss_param_print(BIO *bp, RSA_PSS_PARAMS *pss, + X509_ALGOR *maskHash, int indent) { + int rv = 0; + + if (!pss) { + if (BIO_puts(bp, " (INVALID PSS PARAMETERS)\n") <= 0) { + return 0; + } + return 1; + } + + if (BIO_puts(bp, "\n") <= 0 || + !BIO_indent(bp, indent, 128) || + BIO_puts(bp, "Hash Algorithm: ") <= 0) { + goto err; + } + + if (pss->hashAlgorithm) { + if (i2a_ASN1_OBJECT(bp, pss->hashAlgorithm->algorithm) <= 0) { + goto err; + } + } else if (BIO_puts(bp, "sha1 (default)") <= 0) { + goto err; + } + + if (BIO_puts(bp, "\n") <= 0 || + !BIO_indent(bp, indent, 128) || + BIO_puts(bp, "Mask Algorithm: ") <= 0) { + goto err; + } + + if (pss->maskGenAlgorithm) { + if (i2a_ASN1_OBJECT(bp, pss->maskGenAlgorithm->algorithm) <= 0 || + BIO_puts(bp, " with ") <= 0) { + goto err; + } + + if (maskHash) { + if (i2a_ASN1_OBJECT(bp, maskHash->algorithm) <= 0) { + goto err; + } + } else if (BIO_puts(bp, "INVALID") <= 0) { + goto err; + } + } else if (BIO_puts(bp, "mgf1 with sha1 (default)") <= 0) { + goto err; + } + BIO_puts(bp, "\n"); + + if (!BIO_indent(bp, indent, 128) || + BIO_puts(bp, "Salt Length: 0x") <= 0) { + goto err; + } + + if (pss->saltLength) { + if (i2a_ASN1_INTEGER(bp, pss->saltLength) <= 0) { + goto err; + } + } else if (BIO_puts(bp, "14 (default)") <= 0) { + goto err; + } + BIO_puts(bp, "\n"); + + if (!BIO_indent(bp, indent, 128) || + BIO_puts(bp, "Trailer Field: 0x") <= 0) { + goto err; + } + + if (pss->trailerField) { + if (i2a_ASN1_INTEGER(bp, pss->trailerField) <= 0) { + goto err; + } + } else if (BIO_puts(bp, "BC (default)") <= 0) { + goto err; + } + BIO_puts(bp, "\n"); + + rv = 1; + +err: + return rv; +} + +static int rsa_sig_print(BIO *bp, const X509_ALGOR *sigalg, + const ASN1_STRING *sig, int indent, ASN1_PCTX *pctx) { + if (OBJ_obj2nid(sigalg->algorithm) == NID_rsassaPss) { + int rv; + RSA_PSS_PARAMS *pss; + X509_ALGOR *maskHash; + + pss = rsa_pss_decode(sigalg, &maskHash); + rv = rsa_pss_param_print(bp, pss, maskHash, indent); + RSA_PSS_PARAMS_free(pss); + X509_ALGOR_free(maskHash); + if (!rv) { + return 0; + } + } else if (!sig && BIO_puts(bp, "\n") <= 0) { + return 0; + } + + if (sig) { + return X509_signature_dump(bp, sig, indent); + } + return 1; +} + +static int old_rsa_priv_decode(EVP_PKEY *pkey, const uint8_t **pder, + int derlen) { + RSA *rsa = d2i_RSAPrivateKey(NULL, pder, derlen); + if (rsa == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_RSA_LIB); + return 0; + } + EVP_PKEY_assign_RSA(pkey, rsa); + return 1; +} + +static int old_rsa_priv_encode(const EVP_PKEY *pkey, uint8_t **pder) { + return i2d_RSAPrivateKey(pkey->pkey.rsa, pder); +} + +/* allocate and set algorithm ID from EVP_MD, default SHA1 */ +static int rsa_md_to_algor(X509_ALGOR **palg, const EVP_MD *md) { + if (EVP_MD_type(md) == NID_sha1) { + return 1; + } + *palg = X509_ALGOR_new(); + if (!*palg) { + return 0; + } + X509_ALGOR_set_md(*palg, md); + return 1; +} + +/* Allocate and set MGF1 algorithm ID from EVP_MD */ +static int rsa_md_to_mgf1(X509_ALGOR **palg, const EVP_MD *mgf1md) { + X509_ALGOR *algtmp = NULL; + ASN1_STRING *stmp = NULL; + *palg = NULL; + + if (EVP_MD_type(mgf1md) == NID_sha1) { + return 1; + } + /* need to embed algorithm ID inside another */ + if (!rsa_md_to_algor(&algtmp, mgf1md) || + !ASN1_item_pack(algtmp, ASN1_ITEM_rptr(X509_ALGOR), &stmp)) { + goto err; + } + *palg = X509_ALGOR_new(); + if (!*palg) { + goto err; + } + X509_ALGOR_set0(*palg, OBJ_nid2obj(NID_mgf1), V_ASN1_SEQUENCE, stmp); + stmp = NULL; + +err: + ASN1_STRING_free(stmp); + X509_ALGOR_free(algtmp); + if (*palg) { + return 1; + } + + return 0; +} + +/* convert algorithm ID to EVP_MD, default SHA1 */ +static const EVP_MD *rsa_algor_to_md(X509_ALGOR *alg) { + const EVP_MD *md; + if (!alg) { + return EVP_sha1(); + } + md = EVP_get_digestbyobj(alg->algorithm); + if (md == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_DIGEST); + } + return md; +} + +/* convert MGF1 algorithm ID to EVP_MD, default SHA1 */ +static const EVP_MD *rsa_mgf1_to_md(X509_ALGOR *alg, X509_ALGOR *maskHash) { + const EVP_MD *md; + if (!alg) { + return EVP_sha1(); + } + /* Check mask and lookup mask hash algorithm */ + if (OBJ_obj2nid(alg->algorithm) != NID_mgf1) { + OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_MASK_ALGORITHM); + return NULL; + } + if (!maskHash) { + OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_MASK_PARAMETER); + return NULL; + } + md = EVP_get_digestbyobj(maskHash->algorithm); + if (md == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_MASK_DIGEST); + return NULL; + } + return md; +} + +/* rsa_ctx_to_pss converts EVP_PKEY_CTX in PSS mode into corresponding + * algorithm parameter, suitable for setting as an AlgorithmIdentifier. */ +static ASN1_STRING *rsa_ctx_to_pss(EVP_PKEY_CTX *pkctx) { + const EVP_MD *sigmd, *mgf1md; + RSA_PSS_PARAMS *pss = NULL; + ASN1_STRING *os = NULL; + EVP_PKEY *pk = EVP_PKEY_CTX_get0_pkey(pkctx); + int saltlen, rv = 0; + + if (!EVP_PKEY_CTX_get_signature_md(pkctx, &sigmd) || + !EVP_PKEY_CTX_get_rsa_mgf1_md(pkctx, &mgf1md) || + !EVP_PKEY_CTX_get_rsa_pss_saltlen(pkctx, &saltlen)) { + goto err; + } + + if (saltlen == -1) { + saltlen = EVP_MD_size(sigmd); + } else if (saltlen == -2) { + saltlen = EVP_PKEY_size(pk) - EVP_MD_size(sigmd) - 2; + if (((EVP_PKEY_bits(pk) - 1) & 0x7) == 0) { + saltlen--; + } + } else { + goto err; + } + + pss = RSA_PSS_PARAMS_new(); + if (!pss) { + goto err; + } + + if (saltlen != 20) { + pss->saltLength = ASN1_INTEGER_new(); + if (!pss->saltLength || + !ASN1_INTEGER_set(pss->saltLength, saltlen)) { + goto err; + } + } + + if (!rsa_md_to_algor(&pss->hashAlgorithm, sigmd) || + !rsa_md_to_mgf1(&pss->maskGenAlgorithm, mgf1md)) { + goto err; + } + + /* Finally create string with pss parameter encoding. */ + if (!ASN1_item_pack(pss, ASN1_ITEM_rptr(RSA_PSS_PARAMS), &os)) { + goto err; + } + rv = 1; + +err: + if (pss) { + RSA_PSS_PARAMS_free(pss); + } + if (rv) { + return os; + } + if (os) { + ASN1_STRING_free(os); + } + return NULL; +} + +/* From PSS AlgorithmIdentifier set public key parameters. */ +static int rsa_pss_to_ctx(EVP_MD_CTX *ctx, X509_ALGOR *sigalg, EVP_PKEY *pkey) { + int ret = 0; + int saltlen; + const EVP_MD *mgf1md = NULL, *md = NULL; + RSA_PSS_PARAMS *pss; + X509_ALGOR *maskHash; + EVP_PKEY_CTX *pkctx; + + /* Sanity check: make sure it is PSS */ + if (OBJ_obj2nid(sigalg->algorithm) != NID_rsassaPss) { + OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_SIGNATURE_TYPE); + return 0; + } + /* Decode PSS parameters */ + pss = rsa_pss_decode(sigalg, &maskHash); + if (pss == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PSS_PARAMETERS); + goto err; + } + + mgf1md = rsa_mgf1_to_md(pss->maskGenAlgorithm, maskHash); + if (!mgf1md) { + goto err; + } + md = rsa_algor_to_md(pss->hashAlgorithm); + if (!md) { + goto err; + } + + saltlen = 20; + if (pss->saltLength) { + saltlen = ASN1_INTEGER_get(pss->saltLength); + + /* Could perform more salt length sanity checks but the main + * RSA routines will trap other invalid values anyway. */ + if (saltlen < 0) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_SALT_LENGTH); + goto err; + } + } + + /* low-level routines support only trailer field 0xbc (value 1) + * and PKCS#1 says we should reject any other value anyway. */ + if (pss->trailerField && ASN1_INTEGER_get(pss->trailerField) != 1) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_TRAILER); + goto err; + } + + if (!EVP_DigestVerifyInit(ctx, &pkctx, md, NULL, pkey) || + !EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_PSS_PADDING) || + !EVP_PKEY_CTX_set_rsa_pss_saltlen(pkctx, saltlen) || + !EVP_PKEY_CTX_set_rsa_mgf1_md(pkctx, mgf1md)) { + goto err; + } + + ret = 1; + +err: + RSA_PSS_PARAMS_free(pss); + if (maskHash) { + X509_ALGOR_free(maskHash); + } + return ret; +} + +/* Customised RSA AlgorithmIdentifier handling. This is called when a signature + * is encountered requiring special handling. We currently only handle PSS. */ +static int rsa_digest_verify_init_from_algorithm(EVP_MD_CTX *ctx, + X509_ALGOR *sigalg, + EVP_PKEY *pkey) { + /* Sanity check: make sure it is PSS */ + if (OBJ_obj2nid(sigalg->algorithm) != NID_rsassaPss) { + OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_SIGNATURE_TYPE); + return 0; + } + return rsa_pss_to_ctx(ctx, sigalg, pkey); +} + +static evp_digest_sign_algorithm_result_t rsa_digest_sign_algorithm( + EVP_MD_CTX *ctx, X509_ALGOR *sigalg) { + int pad_mode; + EVP_PKEY_CTX *pkctx = ctx->pctx; + if (!EVP_PKEY_CTX_get_rsa_padding(pkctx, &pad_mode)) { + return EVP_DIGEST_SIGN_ALGORITHM_ERROR; + } + if (pad_mode == RSA_PKCS1_PSS_PADDING) { + ASN1_STRING *os1 = rsa_ctx_to_pss(pkctx); + if (!os1) { + return EVP_DIGEST_SIGN_ALGORITHM_ERROR; + } + X509_ALGOR_set0(sigalg, OBJ_nid2obj(NID_rsassaPss), V_ASN1_SEQUENCE, os1); + return EVP_DIGEST_SIGN_ALGORITHM_SUCCESS; + } + + /* Other padding schemes use the default behavior. */ + return EVP_DIGEST_SIGN_ALGORITHM_DEFAULT; +} + +const EVP_PKEY_ASN1_METHOD rsa_asn1_meth = { + EVP_PKEY_RSA, + EVP_PKEY_RSA, + ASN1_PKEY_SIGPARAM_NULL, + + "RSA", + + rsa_pub_decode, + rsa_pub_encode, + rsa_pub_cmp, + rsa_pub_print, + + rsa_priv_decode, + rsa_priv_encode, + rsa_priv_print, + + rsa_opaque, + rsa_supports_digest, + + int_rsa_size, + rsa_bits, + + 0,0,0,0,0,0, + + rsa_sig_print, + int_rsa_free, + + old_rsa_priv_decode, + old_rsa_priv_encode, + + rsa_digest_verify_init_from_algorithm, + rsa_digest_sign_algorithm, +}; diff --git a/TMessagesProj/jni/boringssl/crypto/evp/pbkdf.c b/TMessagesProj/jni/boringssl/crypto/evp/pbkdf.c new file mode 100644 index 00000000..be6ed86a --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/evp/pbkdf.c @@ -0,0 +1,135 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include + +#include + + +int PKCS5_PBKDF2_HMAC(const char *password, size_t password_len, + const uint8_t *salt, size_t salt_len, unsigned iterations, + const EVP_MD *digest, size_t key_len, uint8_t *out_key) { + uint8_t digest_tmp[EVP_MAX_MD_SIZE], *p, itmp[4]; + size_t cplen, mdlen, tkeylen, k; + unsigned j; + uint32_t i = 1; + HMAC_CTX hctx_tpl, hctx; + + mdlen = EVP_MD_size(digest); + HMAC_CTX_init(&hctx_tpl); + p = out_key; + tkeylen = key_len; + if (!HMAC_Init_ex(&hctx_tpl, password, password_len, digest, NULL)) { + HMAC_CTX_cleanup(&hctx_tpl); + return 0; + } + while (tkeylen) { + if (tkeylen > mdlen) { + cplen = mdlen; + } else { + cplen = tkeylen; + } + /* We are unlikely to ever use more than 256 blocks (5120 bits!) + * but just in case... */ + itmp[0] = (uint8_t)((i >> 24) & 0xff); + itmp[1] = (uint8_t)((i >> 16) & 0xff); + itmp[2] = (uint8_t)((i >> 8) & 0xff); + itmp[3] = (uint8_t)(i & 0xff); + if (!HMAC_CTX_copy(&hctx, &hctx_tpl)) { + HMAC_CTX_cleanup(&hctx_tpl); + return 0; + } + if (!HMAC_Update(&hctx, salt, salt_len) || + !HMAC_Update(&hctx, itmp, 4) || + !HMAC_Final(&hctx, digest_tmp, NULL)) { + HMAC_CTX_cleanup(&hctx_tpl); + HMAC_CTX_cleanup(&hctx); + return 0; + } + HMAC_CTX_cleanup(&hctx); + memcpy(p, digest_tmp, cplen); + for (j = 1; j < iterations; j++) { + if (!HMAC_CTX_copy(&hctx, &hctx_tpl)) { + HMAC_CTX_cleanup(&hctx_tpl); + return 0; + } + if (!HMAC_Update(&hctx, digest_tmp, mdlen) || + !HMAC_Final(&hctx, digest_tmp, NULL)) { + HMAC_CTX_cleanup(&hctx_tpl); + HMAC_CTX_cleanup(&hctx); + return 0; + } + HMAC_CTX_cleanup(&hctx); + for (k = 0; k < cplen; k++) { + p[k] ^= digest_tmp[k]; + } + } + tkeylen -= cplen; + i++; + p += cplen; + } + HMAC_CTX_cleanup(&hctx_tpl); + return 1; +} + +int PKCS5_PBKDF2_HMAC_SHA1(const char *password, size_t password_len, + const uint8_t *salt, size_t salt_len, + unsigned iterations, size_t key_len, + uint8_t *out_key) { + return PKCS5_PBKDF2_HMAC(password, password_len, salt, salt_len, iterations, + EVP_sha1(), key_len, out_key); +} diff --git a/TMessagesProj/jni/boringssl/crypto/evp/sign.c b/TMessagesProj/jni/boringssl/crypto/evp/sign.c new file mode 100644 index 00000000..ced86bdf --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/evp/sign.c @@ -0,0 +1,151 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include "internal.h" + + +int EVP_SignInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl) { + return EVP_DigestInit_ex(ctx, type, impl); +} + +int EVP_SignInit(EVP_MD_CTX *ctx, const EVP_MD *type) { + return EVP_DigestInit(ctx, type); +} + +int EVP_SignUpdate(EVP_MD_CTX *ctx, const void *data, size_t len) { + return EVP_DigestUpdate(ctx, data, len); +} + +int EVP_SignFinal(const EVP_MD_CTX *ctx, uint8_t *sig, + unsigned int *out_sig_len, EVP_PKEY *pkey) { + uint8_t m[EVP_MAX_MD_SIZE]; + unsigned int m_len; + int ret = 0; + EVP_MD_CTX tmp_ctx; + EVP_PKEY_CTX *pkctx = NULL; + size_t sig_len = EVP_PKEY_size(pkey); + + *out_sig_len = 0; + EVP_MD_CTX_init(&tmp_ctx); + if (!EVP_MD_CTX_copy_ex(&tmp_ctx, ctx) || + !EVP_DigestFinal_ex(&tmp_ctx, m, &m_len)) { + goto out; + } + EVP_MD_CTX_cleanup(&tmp_ctx); + + pkctx = EVP_PKEY_CTX_new(pkey, NULL); + if (!pkctx || !EVP_PKEY_sign_init(pkctx) || + !EVP_PKEY_CTX_set_signature_md(pkctx, ctx->digest) || + !EVP_PKEY_sign(pkctx, sig, &sig_len, m, m_len)) { + goto out; + } + *out_sig_len = sig_len; + ret = 1; + +out: + if (pkctx) { + EVP_PKEY_CTX_free(pkctx); + } + + return ret; +} + +int EVP_VerifyInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl) { + return EVP_DigestInit_ex(ctx, type, impl); +} + +int EVP_VerifyInit(EVP_MD_CTX *ctx, const EVP_MD *type) { + return EVP_DigestInit(ctx, type); +} + +int EVP_VerifyUpdate(EVP_MD_CTX *ctx, const void *data, size_t len) { + return EVP_DigestUpdate(ctx, data, len); +} + +int EVP_VerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig, size_t sig_len, + EVP_PKEY *pkey) { + uint8_t m[EVP_MAX_MD_SIZE]; + unsigned int m_len; + int ret = 0; + EVP_MD_CTX tmp_ctx; + EVP_PKEY_CTX *pkctx = NULL; + + EVP_MD_CTX_init(&tmp_ctx); + if (!EVP_MD_CTX_copy_ex(&tmp_ctx, ctx) || + !EVP_DigestFinal_ex(&tmp_ctx, m, &m_len)) { + EVP_MD_CTX_cleanup(&tmp_ctx); + goto out; + } + EVP_MD_CTX_cleanup(&tmp_ctx); + + pkctx = EVP_PKEY_CTX_new(pkey, NULL); + if (!pkctx || + !EVP_PKEY_verify_init(pkctx) || + !EVP_PKEY_CTX_set_signature_md(pkctx, ctx->digest)) { + goto out; + } + ret = EVP_PKEY_verify(pkctx, sig, sig_len, m, m_len); + +out: + EVP_PKEY_CTX_free(pkctx); + return ret; +} + diff --git a/TMessagesProj/jni/boringssl/crypto/ex_data.c b/TMessagesProj/jni/boringssl/crypto/ex_data.c new file mode 100644 index 00000000..f562f17b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ex_data.c @@ -0,0 +1,314 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "internal.h" + + +struct crypto_ex_data_func_st { + long argl; /* Arbitary long */ + void *argp; /* Arbitary void pointer */ + CRYPTO_EX_new *new_func; + CRYPTO_EX_free *free_func; + CRYPTO_EX_dup *dup_func; +}; + +int CRYPTO_get_ex_new_index(CRYPTO_EX_DATA_CLASS *ex_data_class, int *out_index, + long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func) { + CRYPTO_EX_DATA_FUNCS *funcs; + int ret = 0; + + funcs = OPENSSL_malloc(sizeof(CRYPTO_EX_DATA_FUNCS)); + if (funcs == NULL) { + OPENSSL_PUT_ERROR(CRYPTO, ERR_R_MALLOC_FAILURE); + return 0; + } + + funcs->argl = argl; + funcs->argp = argp; + funcs->new_func = new_func; + funcs->dup_func = dup_func; + funcs->free_func = free_func; + + CRYPTO_STATIC_MUTEX_lock_write(&ex_data_class->lock); + + if (ex_data_class->meth == NULL) { + ex_data_class->meth = sk_CRYPTO_EX_DATA_FUNCS_new_null(); + } + + if (ex_data_class->meth == NULL || + !sk_CRYPTO_EX_DATA_FUNCS_push(ex_data_class->meth, funcs)) { + OPENSSL_PUT_ERROR(CRYPTO, ERR_R_MALLOC_FAILURE); + OPENSSL_free(funcs); + goto err; + } + + *out_index = sk_CRYPTO_EX_DATA_FUNCS_num(ex_data_class->meth) - 1 + + ex_data_class->num_reserved; + ret = 1; + +err: + CRYPTO_STATIC_MUTEX_unlock(&ex_data_class->lock); + return ret; +} + +int CRYPTO_set_ex_data(CRYPTO_EX_DATA *ad, int index, void *val) { + int n, i; + + if (ad->sk == NULL) { + ad->sk = sk_void_new_null(); + if (ad->sk == NULL) { + OPENSSL_PUT_ERROR(CRYPTO, ERR_R_MALLOC_FAILURE); + return 0; + } + } + + n = sk_void_num(ad->sk); + + /* Add NULL values until the stack is long enough. */ + for (i = n; i <= index; i++) { + if (!sk_void_push(ad->sk, NULL)) { + OPENSSL_PUT_ERROR(CRYPTO, ERR_R_MALLOC_FAILURE); + return 0; + } + } + + sk_void_set(ad->sk, index, val); + return 1; +} + +void *CRYPTO_get_ex_data(const CRYPTO_EX_DATA *ad, int idx) { + if (ad->sk == NULL || idx < 0 || (size_t)idx >= sk_void_num(ad->sk)) { + return NULL; + } + return sk_void_value(ad->sk, idx); +} + +/* get_func_pointers takes a copy of the CRYPTO_EX_DATA_FUNCS pointers, if any, + * for the given class. If there are some pointers, it sets |*out| to point to + * a fresh stack of them. Otherwise it sets |*out| to NULL. It returns one on + * success or zero on error. */ +static int get_func_pointers(STACK_OF(CRYPTO_EX_DATA_FUNCS) **out, + CRYPTO_EX_DATA_CLASS *ex_data_class) { + size_t n; + + *out = NULL; + + /* CRYPTO_EX_DATA_FUNCS structures are static once set, so we can take a + * shallow copy of the list under lock and then use the structures without + * the lock held. */ + CRYPTO_STATIC_MUTEX_lock_read(&ex_data_class->lock); + n = sk_CRYPTO_EX_DATA_FUNCS_num(ex_data_class->meth); + if (n > 0) { + *out = sk_CRYPTO_EX_DATA_FUNCS_dup(ex_data_class->meth); + } + CRYPTO_STATIC_MUTEX_unlock(&ex_data_class->lock); + + if (n > 0 && *out == NULL) { + OPENSSL_PUT_ERROR(CRYPTO, ERR_R_MALLOC_FAILURE); + return 0; + } + + return 1; +} + +int CRYPTO_new_ex_data(CRYPTO_EX_DATA_CLASS *ex_data_class, void *obj, + CRYPTO_EX_DATA *ad) { + STACK_OF(CRYPTO_EX_DATA_FUNCS) *func_pointers; + size_t i; + + ad->sk = NULL; + + if (!get_func_pointers(&func_pointers, ex_data_class)) { + return 0; + } + + for (i = 0; i < sk_CRYPTO_EX_DATA_FUNCS_num(func_pointers); i++) { + CRYPTO_EX_DATA_FUNCS *func_pointer = + sk_CRYPTO_EX_DATA_FUNCS_value(func_pointers, i); + if (func_pointer->new_func) { + func_pointer->new_func(obj, NULL, ad, i + ex_data_class->num_reserved, + func_pointer->argl, func_pointer->argp); + } + } + + sk_CRYPTO_EX_DATA_FUNCS_free(func_pointers); + + return 1; +} + +int CRYPTO_dup_ex_data(CRYPTO_EX_DATA_CLASS *ex_data_class, CRYPTO_EX_DATA *to, + const CRYPTO_EX_DATA *from) { + STACK_OF(CRYPTO_EX_DATA_FUNCS) *func_pointers; + size_t i; + + if (!from->sk) { + /* In this case, |from| is blank, which is also the initial state of |to|, + * so there's nothing to do. */ + return 1; + } + + if (!get_func_pointers(&func_pointers, ex_data_class)) { + return 0; + } + + for (i = 0; i < sk_CRYPTO_EX_DATA_FUNCS_num(func_pointers); i++) { + CRYPTO_EX_DATA_FUNCS *func_pointer = + sk_CRYPTO_EX_DATA_FUNCS_value(func_pointers, i); + void *ptr = CRYPTO_get_ex_data(from, i + ex_data_class->num_reserved); + if (func_pointer->dup_func) { + func_pointer->dup_func(to, from, &ptr, i + ex_data_class->num_reserved, + func_pointer->argl, func_pointer->argp); + } + CRYPTO_set_ex_data(to, i + ex_data_class->num_reserved, ptr); + } + + sk_CRYPTO_EX_DATA_FUNCS_free(func_pointers); + + return 1; +} + +void CRYPTO_free_ex_data(CRYPTO_EX_DATA_CLASS *ex_data_class, void *obj, + CRYPTO_EX_DATA *ad) { + STACK_OF(CRYPTO_EX_DATA_FUNCS) *func_pointers; + size_t i; + + if (!get_func_pointers(&func_pointers, ex_data_class)) { + return; + } + + for (i = 0; i < sk_CRYPTO_EX_DATA_FUNCS_num(func_pointers); i++) { + CRYPTO_EX_DATA_FUNCS *func_pointer = + sk_CRYPTO_EX_DATA_FUNCS_value(func_pointers, i); + if (func_pointer->free_func) { + void *ptr = CRYPTO_get_ex_data(ad, i + ex_data_class->num_reserved); + func_pointer->free_func(obj, ptr, ad, i + ex_data_class->num_reserved, + func_pointer->argl, func_pointer->argp); + } + } + + sk_CRYPTO_EX_DATA_FUNCS_free(func_pointers); + + sk_void_free(ad->sk); + ad->sk = NULL; +} + +void CRYPTO_cleanup_all_ex_data(void) {} diff --git a/TMessagesProj/jni/boringssl/crypto/header_removed.h b/TMessagesProj/jni/boringssl/crypto/header_removed.h new file mode 100644 index 00000000..49ee31a4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/header_removed.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is linked to under the names of several headers that have been + * removed. It's possible to put a #error in here in order to catch that an + * clean up older code. */ diff --git a/TMessagesProj/jni/boringssl/crypto/hkdf/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/hkdf/CMakeLists.txt new file mode 100644 index 00000000..39d64366 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/hkdf/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories(. .. ../../include) + +add_library( + hkdf + + OBJECT + + hkdf.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/hkdf/hkdf.c b/TMessagesProj/jni/boringssl/crypto/hkdf/hkdf.c new file mode 100644 index 00000000..f9cdcb0b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/hkdf/hkdf.c @@ -0,0 +1,89 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#include +#include + +#include +#include + + +int HKDF(uint8_t *out_key, size_t out_len, + const EVP_MD *digest, + const uint8_t *secret, size_t secret_len, + const uint8_t *salt, size_t salt_len, + const uint8_t *info, size_t info_len) { + /* https://tools.ietf.org/html/rfc5869#section-2.2 */ + const size_t digest_len = EVP_MD_size(digest); + uint8_t prk[EVP_MAX_MD_SIZE], previous[EVP_MAX_MD_SIZE]; + size_t n, done = 0; + unsigned i, prk_len; + int ret = 0; + HMAC_CTX hmac; + + /* If salt is not given, HashLength zeros are used. However, HMAC does that + * internally already so we can ignore it.*/ + + /* Expand key material to desired length. */ + n = (out_len + digest_len - 1) / digest_len; + if (out_len + digest_len < out_len || n > 255) { + OPENSSL_PUT_ERROR(HKDF, HKDF_R_OUTPUT_TOO_LARGE); + return 0; + } + + HMAC_CTX_init(&hmac); + + /* Extract input keying material into pseudorandom key |prk|. */ + if (HMAC(digest, salt, salt_len, secret, secret_len, prk, &prk_len) == NULL) { + goto out; + } + assert(prk_len == digest_len); + + if (!HMAC_Init_ex(&hmac, prk, prk_len, digest, NULL)) { + goto out; + } + + for (i = 0; i < n; i++) { + uint8_t ctr = i + 1; + size_t todo; + + if (i != 0 && (!HMAC_Init_ex(&hmac, NULL, 0, NULL, NULL) || + !HMAC_Update(&hmac, previous, digest_len))) { + goto out; + } + if (!HMAC_Update(&hmac, info, info_len) || + !HMAC_Update(&hmac, &ctr, 1) || + !HMAC_Final(&hmac, previous, NULL)) { + goto out; + } + + todo = digest_len; + if (done + todo > out_len) { + todo = out_len - done; + } + memcpy(out_key + done, previous, todo); + done += todo; + } + + ret = 1; + +out: + HMAC_CTX_cleanup(&hmac); + if (ret != 1) { + OPENSSL_PUT_ERROR(HKDF, ERR_R_HMAC_LIB); + } + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/hmac/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/hmac/CMakeLists.txt new file mode 100644 index 00000000..cd034ae4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/hmac/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories(. .. ../../include) + +add_library( + hmac + + OBJECT + + hmac.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/hmac/hmac.c b/TMessagesProj/jni/boringssl/crypto/hmac/hmac.c new file mode 100644 index 00000000..d37a249f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/hmac/hmac.c @@ -0,0 +1,213 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include + + +uint8_t *HMAC(const EVP_MD *evp_md, const void *key, size_t key_len, + const uint8_t *data, size_t data_len, uint8_t *out, + unsigned int *out_len) { + HMAC_CTX ctx; + static uint8_t static_out_buffer[EVP_MAX_MD_SIZE]; + + /* OpenSSL has traditionally supported using a static buffer if |out| is + * NULL. We maintain that but don't document it. This behaviour should be + * considered to be deprecated. */ + if (out == NULL) { + out = static_out_buffer; + } + + HMAC_CTX_init(&ctx); + if (!HMAC_Init_ex(&ctx, key, key_len, evp_md, NULL) || + !HMAC_Update(&ctx, data, data_len) || + !HMAC_Final(&ctx, out, out_len)) { + out = NULL; + } + + HMAC_CTX_cleanup(&ctx); + return out; +} + +void HMAC_CTX_init(HMAC_CTX *ctx) { + ctx->md = NULL; + EVP_MD_CTX_init(&ctx->i_ctx); + EVP_MD_CTX_init(&ctx->o_ctx); + EVP_MD_CTX_init(&ctx->md_ctx); +} + +void HMAC_CTX_cleanup(HMAC_CTX *ctx) { + EVP_MD_CTX_cleanup(&ctx->i_ctx); + EVP_MD_CTX_cleanup(&ctx->o_ctx); + EVP_MD_CTX_cleanup(&ctx->md_ctx); + OPENSSL_cleanse(ctx, sizeof(HMAC_CTX)); +} + +int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, size_t key_len, + const EVP_MD *md, ENGINE *impl) { + if (md == NULL) { + md = ctx->md; + } + + /* If either |key| is non-NULL or |md| has changed, initialize with a new key + * rather than rewinding the previous one. + * + * TODO(davidben,eroman): Passing the previous |md| with a NULL |key| is + * ambiguous between using the empty key and reusing the previous key. There + * exist callers which intend the latter, but the former is an awkward edge + * case. Fix to API to avoid this. */ + if (md != ctx->md || key != NULL) { + size_t i; + uint8_t pad[HMAC_MAX_MD_CBLOCK]; + uint8_t key_block[HMAC_MAX_MD_CBLOCK]; + unsigned key_block_len; + + size_t block_size = EVP_MD_block_size(md); + assert(block_size <= sizeof(key_block)); + if (block_size < key_len) { + /* Long keys are hashed. */ + if (!EVP_DigestInit_ex(&ctx->md_ctx, md, impl) || + !EVP_DigestUpdate(&ctx->md_ctx, key, key_len) || + !EVP_DigestFinal_ex(&ctx->md_ctx, key_block, &key_block_len)) { + return 0; + } + } else { + assert(key_len >= 0 && key_len <= sizeof(key_block)); + memcpy(key_block, key, key_len); + key_block_len = (unsigned)key_len; + } + /* Keys are then padded with zeros. */ + if (key_block_len != HMAC_MAX_MD_CBLOCK) { + memset(&key_block[key_block_len], 0, sizeof(key_block) - key_block_len); + } + + for (i = 0; i < HMAC_MAX_MD_CBLOCK; i++) { + pad[i] = 0x36 ^ key_block[i]; + } + if (!EVP_DigestInit_ex(&ctx->i_ctx, md, impl) || + !EVP_DigestUpdate(&ctx->i_ctx, pad, EVP_MD_block_size(md))) { + return 0; + } + + for (i = 0; i < HMAC_MAX_MD_CBLOCK; i++) { + pad[i] = 0x5c ^ key_block[i]; + } + if (!EVP_DigestInit_ex(&ctx->o_ctx, md, impl) || + !EVP_DigestUpdate(&ctx->o_ctx, pad, EVP_MD_block_size(md))) { + return 0; + } + + ctx->md = md; + } + + if (!EVP_MD_CTX_copy_ex(&ctx->md_ctx, &ctx->i_ctx)) { + return 0; + } + + return 1; +} + +int HMAC_Update(HMAC_CTX *ctx, const uint8_t *data, size_t data_len) { + return EVP_DigestUpdate(&ctx->md_ctx, data, data_len); +} + +int HMAC_Final(HMAC_CTX *ctx, uint8_t *out, unsigned int *out_len) { + unsigned int i; + uint8_t buf[EVP_MAX_MD_SIZE]; + + /* TODO(davidben): The only thing that can officially fail here is + * |EVP_MD_CTX_copy_ex|, but even that should be impossible in this case. */ + if (!EVP_DigestFinal_ex(&ctx->md_ctx, buf, &i) || + !EVP_MD_CTX_copy_ex(&ctx->md_ctx, &ctx->o_ctx) || + !EVP_DigestUpdate(&ctx->md_ctx, buf, i) || + !EVP_DigestFinal_ex(&ctx->md_ctx, out, out_len)) { + *out_len = 0; + return 0; + } + + return 1; +} + +size_t HMAC_size(const HMAC_CTX *ctx) { + return EVP_MD_size(ctx->md); +} + +int HMAC_CTX_copy_ex(HMAC_CTX *dest, const HMAC_CTX *src) { + if (!EVP_MD_CTX_copy_ex(&dest->i_ctx, &src->i_ctx) || + !EVP_MD_CTX_copy_ex(&dest->o_ctx, &src->o_ctx) || + !EVP_MD_CTX_copy_ex(&dest->md_ctx, &src->md_ctx)) { + return 0; + } + + dest->md = src->md; + return 1; +} + +int HMAC_Init(HMAC_CTX *ctx, const void *key, int key_len, const EVP_MD *md) { + if (key && md) { + HMAC_CTX_init(ctx); + } + return HMAC_Init_ex(ctx, key, key_len, md, NULL); +} + +int HMAC_CTX_copy(HMAC_CTX *dest, const HMAC_CTX *src) { + HMAC_CTX_init(dest); + return HMAC_CTX_copy_ex(dest, src); +} diff --git a/TMessagesProj/jni/boringssl/crypto/internal.h b/TMessagesProj/jni/boringssl/crypto/internal.h new file mode 100644 index 00000000..a502d20e --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/internal.h @@ -0,0 +1,547 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef OPENSSL_HEADER_CRYPTO_INTERNAL_H +#define OPENSSL_HEADER_CRYPTO_INTERNAL_H + +#include +#include + +#if defined(OPENSSL_NO_THREADS) +#elif defined(OPENSSL_WINDOWS) +#pragma warning(push, 3) +#include +#pragma warning(pop) +#else +#include +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* MSVC's C4701 warning about the use of *potentially*--as opposed to + * *definitely*--uninitialized values sometimes has false positives. Usually + * the false positives can and should be worked around by simplifying the + * control flow. When that is not practical, annotate the function containing + * the code that triggers the warning with + * OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS after its parameters: + * + * void f() OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS { + * ... + * } + * + * Note that MSVC's control flow analysis seems to operate on a whole-function + * basis, so the annotation must be placed on the entire function, not just a + * block within the function. */ +#if defined(_MSC_VER) +#define OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS \ + __pragma(warning(suppress:4701)) +#else +#define OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS +#endif + +/* MSVC will sometimes correctly detect unreachable code and issue a warning, + * which breaks the build since we treat errors as warnings, in some rare cases + * where we want to allow the dead code to continue to exist. In these + * situations, annotate the function containing the unreachable code with + * OPENSSL_SUPPRESS_UNREACHABLE_CODE_WARNINGS after its parameters: + * + * void f() OPENSSL_SUPPRESS_UNREACHABLE_CODE_WARNINGS { + * ... + * } + * + * Note that MSVC's reachability analysis seems to operate on a whole-function + * basis, so the annotation must be placed on the entire function, not just a + * block within the function. */ +#if defined(_MSC_VER) +#define OPENSSL_SUPPRESS_UNREACHABLE_CODE_WARNINGS \ + __pragma(warning(suppress:4702)) +#else +#define OPENSSL_SUPPRESS_UNREACHABLE_CODE_WARNINGS +#endif + + +#if defined(_MSC_VER) +#define OPENSSL_U64(x) x##UI64 +#else + +#if defined(OPENSSL_64_BIT) +#define OPENSSL_U64(x) x##UL +#else +#define OPENSSL_U64(x) x##ULL +#endif + +#endif /* defined(_MSC_VER) */ + +#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || defined(OPENSSL_ARM) || \ + defined(OPENSSL_AARCH64) +/* OPENSSL_cpuid_setup initializes OPENSSL_ia32cap_P. */ +void OPENSSL_cpuid_setup(void); +#endif + +#if !defined(inline) +#define inline __inline +#endif + + +/* Constant-time utility functions. + * + * The following methods return a bitmask of all ones (0xff...f) for true and 0 + * for false. This is useful for choosing a value based on the result of a + * conditional in constant time. For example, + * + * if (a < b) { + * c = a; + * } else { + * c = b; + * } + * + * can be written as + * + * unsigned int lt = constant_time_lt(a, b); + * c = constant_time_select(lt, a, b); */ + +/* constant_time_msb returns the given value with the MSB copied to all the + * other bits. */ +static inline unsigned int constant_time_msb(unsigned int a) { + return (unsigned int)((int)(a) >> (sizeof(int) * 8 - 1)); +} + +/* constant_time_lt returns 0xff..f if a < b and 0 otherwise. */ +static inline unsigned int constant_time_lt(unsigned int a, unsigned int b) { + /* Consider the two cases of the problem: + * msb(a) == msb(b): a < b iff the MSB of a - b is set. + * msb(a) != msb(b): a < b iff the MSB of b is set. + * + * If msb(a) == msb(b) then the following evaluates as: + * msb(a^((a^b)|((a-b)^a))) == + * msb(a^((a-b) ^ a)) == (because msb(a^b) == 0) + * msb(a^a^(a-b)) == (rearranging) + * msb(a-b) (because ∀x. x^x == 0) + * + * Else, if msb(a) != msb(b) then the following evaluates as: + * msb(a^((a^b)|((a-b)^a))) == + * msb(a^(𝟙 | ((a-b)^a))) == (because msb(a^b) == 1 and 𝟙 + * represents a value s.t. msb(𝟙) = 1) + * msb(a^𝟙) == (because ORing with 1 results in 1) + * msb(b) + * + * + * Here is an SMT-LIB verification of this formula: + * + * (define-fun lt ((a (_ BitVec 32)) (b (_ BitVec 32))) (_ BitVec 32) + * (bvxor a (bvor (bvxor a b) (bvxor (bvsub a b) a))) + * ) + * + * (declare-fun a () (_ BitVec 32)) + * (declare-fun b () (_ BitVec 32)) + * + * (assert (not (= (= #x00000001 (bvlshr (lt a b) #x0000001f)) (bvult a b)))) + * (check-sat) + * (get-model) + */ + return constant_time_msb(a^((a^b)|((a-b)^a))); +} + +/* constant_time_lt_8 acts like |constant_time_lt| but returns an 8-bit mask. */ +static inline uint8_t constant_time_lt_8(unsigned int a, unsigned int b) { + return (uint8_t)(constant_time_lt(a, b)); +} + +/* constant_time_gt returns 0xff..f if a >= b and 0 otherwise. */ +static inline unsigned int constant_time_ge(unsigned int a, unsigned int b) { + return ~constant_time_lt(a, b); +} + +/* constant_time_ge_8 acts like |constant_time_ge| but returns an 8-bit mask. */ +static inline uint8_t constant_time_ge_8(unsigned int a, unsigned int b) { + return (uint8_t)(constant_time_ge(a, b)); +} + +/* constant_time_is_zero returns 0xff..f if a == 0 and 0 otherwise. */ +static inline unsigned int constant_time_is_zero(unsigned int a) { + /* Here is an SMT-LIB verification of this formula: + * + * (define-fun is_zero ((a (_ BitVec 32))) (_ BitVec 32) + * (bvand (bvnot a) (bvsub a #x00000001)) + * ) + * + * (declare-fun a () (_ BitVec 32)) + * + * (assert (not (= (= #x00000001 (bvlshr (is_zero a) #x0000001f)) (= a #x00000000)))) + * (check-sat) + * (get-model) + */ + return constant_time_msb(~a & (a - 1)); +} + +/* constant_time_is_zero_8 acts like constant_time_is_zero but returns an 8-bit + * mask. */ +static inline uint8_t constant_time_is_zero_8(unsigned int a) { + return (uint8_t)(constant_time_is_zero(a)); +} + +/* constant_time_eq returns 0xff..f if a == b and 0 otherwise. */ +static inline unsigned int constant_time_eq(unsigned int a, unsigned int b) { + return constant_time_is_zero(a ^ b); +} + +/* constant_time_eq_8 acts like |constant_time_eq| but returns an 8-bit mask. */ +static inline uint8_t constant_time_eq_8(unsigned int a, unsigned int b) { + return (uint8_t)(constant_time_eq(a, b)); +} + +/* constant_time_eq_int acts like |constant_time_eq| but works on int values. */ +static inline unsigned int constant_time_eq_int(int a, int b) { + return constant_time_eq((unsigned)(a), (unsigned)(b)); +} + +/* constant_time_eq_int_8 acts like |constant_time_eq_int| but returns an 8-bit + * mask. */ +static inline uint8_t constant_time_eq_int_8(int a, int b) { + return constant_time_eq_8((unsigned)(a), (unsigned)(b)); +} + +/* constant_time_select returns (mask & a) | (~mask & b). When |mask| is all 1s + * or all 0s (as returned by the methods above), the select methods return + * either |a| (if |mask| is nonzero) or |b| (if |mask| is zero). */ +static inline unsigned int constant_time_select(unsigned int mask, + unsigned int a, unsigned int b) { + return (mask & a) | (~mask & b); +} + +/* constant_time_select_8 acts like |constant_time_select| but operates on + * 8-bit values. */ +static inline uint8_t constant_time_select_8(uint8_t mask, uint8_t a, + uint8_t b) { + return (uint8_t)(constant_time_select(mask, a, b)); +} + +/* constant_time_select_int acts like |constant_time_select| but operates on + * ints. */ +static inline int constant_time_select_int(unsigned int mask, int a, int b) { + return (int)(constant_time_select(mask, (unsigned)(a), (unsigned)(b))); +} + + +/* Thread-safe initialisation. */ + +#if defined(OPENSSL_NO_THREADS) +typedef uint32_t CRYPTO_once_t; +#define CRYPTO_ONCE_INIT 0 +#elif defined(OPENSSL_WINDOWS) +typedef LONG CRYPTO_once_t; +#define CRYPTO_ONCE_INIT 0 +#else +typedef pthread_once_t CRYPTO_once_t; +#define CRYPTO_ONCE_INIT PTHREAD_ONCE_INIT +#endif + +/* CRYPTO_once calls |init| exactly once per process. This is thread-safe: if + * concurrent threads call |CRYPTO_once| with the same |CRYPTO_once_t| argument + * then they will block until |init| completes, but |init| will have only been + * called once. + * + * The |once| argument must be a |CRYPTO_once_t| that has been initialised with + * the value |CRYPTO_ONCE_INIT|. */ +OPENSSL_EXPORT void CRYPTO_once(CRYPTO_once_t *once, void (*init)(void)); + + +/* Reference counting. */ + +/* CRYPTO_REFCOUNT_MAX is the value at which the reference count saturates. */ +#define CRYPTO_REFCOUNT_MAX 0xffffffff + +/* CRYPTO_refcount_inc atomically increments the value at |*count| unless the + * value would overflow. It's safe for multiple threads to concurrently call + * this or |CRYPTO_refcount_dec_and_test_zero| on the same + * |CRYPTO_refcount_t|. */ +OPENSSL_EXPORT void CRYPTO_refcount_inc(CRYPTO_refcount_t *count); + +/* CRYPTO_refcount_dec_and_test_zero tests the value at |*count|: + * if it's zero, it crashes the address space. + * if it's the maximum value, it returns zero. + * otherwise, it atomically decrements it and returns one iff the resulting + * value is zero. + * + * It's safe for multiple threads to concurrently call this or + * |CRYPTO_refcount_inc| on the same |CRYPTO_refcount_t|. */ +OPENSSL_EXPORT int CRYPTO_refcount_dec_and_test_zero(CRYPTO_refcount_t *count); + + +/* Locks. + * + * Two types of locks are defined: |CRYPTO_MUTEX|, which can be used in + * structures as normal, and |struct CRYPTO_STATIC_MUTEX|, which can be used as + * a global lock. A global lock must be initialised to the value + * |CRYPTO_STATIC_MUTEX_INIT|. + * + * |CRYPTO_MUTEX| can appear in public structures and so is defined in + * thread.h. + * + * The global lock is a different type because there's no static initialiser + * value on Windows for locks, so global locks have to be coupled with a + * |CRYPTO_once_t| to ensure that the lock is setup before use. This is done + * automatically by |CRYPTO_STATIC_MUTEX_lock_*|. */ + +#if defined(OPENSSL_NO_THREADS) +struct CRYPTO_STATIC_MUTEX {}; +#define CRYPTO_STATIC_MUTEX_INIT {} +#elif defined(OPENSSL_WINDOWS) +struct CRYPTO_STATIC_MUTEX { + CRYPTO_once_t once; + CRITICAL_SECTION lock; +}; +#define CRYPTO_STATIC_MUTEX_INIT { CRYPTO_ONCE_INIT, { 0 } } +#else +struct CRYPTO_STATIC_MUTEX { + pthread_rwlock_t lock; +}; +#define CRYPTO_STATIC_MUTEX_INIT { PTHREAD_RWLOCK_INITIALIZER } +#endif + +/* CRYPTO_MUTEX_init initialises |lock|. If |lock| is a static variable, use a + * |CRYPTO_STATIC_MUTEX|. */ +OPENSSL_EXPORT void CRYPTO_MUTEX_init(CRYPTO_MUTEX *lock); + +/* CRYPTO_MUTEX_lock_read locks |lock| such that other threads may also have a + * read lock, but none may have a write lock. (On Windows, read locks are + * actually fully exclusive.) */ +OPENSSL_EXPORT void CRYPTO_MUTEX_lock_read(CRYPTO_MUTEX *lock); + +/* CRYPTO_MUTEX_lock_write locks |lock| such that no other thread has any type + * of lock on it. */ +OPENSSL_EXPORT void CRYPTO_MUTEX_lock_write(CRYPTO_MUTEX *lock); + +/* CRYPTO_MUTEX_unlock unlocks |lock|. */ +OPENSSL_EXPORT void CRYPTO_MUTEX_unlock(CRYPTO_MUTEX *lock); + +/* CRYPTO_MUTEX_cleanup releases all resources held by |lock|. */ +OPENSSL_EXPORT void CRYPTO_MUTEX_cleanup(CRYPTO_MUTEX *lock); + +/* CRYPTO_STATIC_MUTEX_lock_read locks |lock| such that other threads may also + * have a read lock, but none may have a write lock. The |lock| variable does + * not need to be initialised by any function, but must have been statically + * initialised with |CRYPTO_STATIC_MUTEX_INIT|. */ +OPENSSL_EXPORT void CRYPTO_STATIC_MUTEX_lock_read( + struct CRYPTO_STATIC_MUTEX *lock); + +/* CRYPTO_STATIC_MUTEX_lock_write locks |lock| such that no other thread has + * any type of lock on it. The |lock| variable does not need to be initialised + * by any function, but must have been statically initialised with + * |CRYPTO_STATIC_MUTEX_INIT|. */ +OPENSSL_EXPORT void CRYPTO_STATIC_MUTEX_lock_write( + struct CRYPTO_STATIC_MUTEX *lock); + +/* CRYPTO_STATIC_MUTEX_unlock unlocks |lock|. */ +OPENSSL_EXPORT void CRYPTO_STATIC_MUTEX_unlock( + struct CRYPTO_STATIC_MUTEX *lock); + + +/* Thread local storage. */ + +/* thread_local_data_t enumerates the types of thread-local data that can be + * stored. */ +typedef enum { + OPENSSL_THREAD_LOCAL_ERR = 0, + OPENSSL_THREAD_LOCAL_RAND, + OPENSSL_THREAD_LOCAL_TEST, + NUM_OPENSSL_THREAD_LOCALS, +} thread_local_data_t; + +/* thread_local_destructor_t is the type of a destructor function that will be + * called when a thread exits and its thread-local storage needs to be freed. */ +typedef void (*thread_local_destructor_t)(void *); + +/* CRYPTO_get_thread_local gets the pointer value that is stored for the + * current thread for the given index, or NULL if none has been set. */ +OPENSSL_EXPORT void *CRYPTO_get_thread_local(thread_local_data_t value); + +/* CRYPTO_set_thread_local sets a pointer value for the current thread at the + * given index. This function should only be called once per thread for a given + * |index|: rather than update the pointer value itself, update the data that + * is pointed to. + * + * The destructor function will be called when a thread exits to free this + * thread-local data. All calls to |CRYPTO_set_thread_local| with the same + * |index| should have the same |destructor| argument. The destructor may be + * called with a NULL argument if a thread that never set a thread-local + * pointer for |index|, exits. The destructor may be called concurrently with + * different arguments. + * + * This function returns one on success or zero on error. If it returns zero + * then |destructor| has been called with |value| already. */ +OPENSSL_EXPORT int CRYPTO_set_thread_local( + thread_local_data_t index, void *value, + thread_local_destructor_t destructor); + + +/* ex_data */ + +typedef struct crypto_ex_data_func_st CRYPTO_EX_DATA_FUNCS; + +/* CRYPTO_EX_DATA_CLASS tracks the ex_indices registered for a type which + * supports ex_data. It should defined as a static global within the module + * which defines that type. */ +typedef struct { + struct CRYPTO_STATIC_MUTEX lock; + STACK_OF(CRYPTO_EX_DATA_FUNCS) *meth; + /* num_reserved is one if the ex_data index zero is reserved for legacy + * |TYPE_get_app_data| functions. */ + uint8_t num_reserved; +} CRYPTO_EX_DATA_CLASS; + +#define CRYPTO_EX_DATA_CLASS_INIT {CRYPTO_STATIC_MUTEX_INIT, NULL, 0} +#define CRYPTO_EX_DATA_CLASS_INIT_WITH_APP_DATA \ + {CRYPTO_STATIC_MUTEX_INIT, NULL, 1} + +/* CRYPTO_get_ex_new_index allocates a new index for |ex_data_class| and writes + * it to |*out_index|. Each class of object should provide a wrapper function + * that uses the correct |CRYPTO_EX_DATA_CLASS|. It returns one on success and + * zero otherwise. */ +OPENSSL_EXPORT int CRYPTO_get_ex_new_index(CRYPTO_EX_DATA_CLASS *ex_data_class, + int *out_index, long argl, + void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func); + +/* CRYPTO_set_ex_data sets an extra data pointer on a given object. Each class + * of object should provide a wrapper function. */ +OPENSSL_EXPORT int CRYPTO_set_ex_data(CRYPTO_EX_DATA *ad, int index, void *val); + +/* CRYPTO_get_ex_data returns an extra data pointer for a given object, or NULL + * if no such index exists. Each class of object should provide a wrapper + * function. */ +OPENSSL_EXPORT void *CRYPTO_get_ex_data(const CRYPTO_EX_DATA *ad, int index); + +/* CRYPTO_new_ex_data initialises a newly allocated |CRYPTO_EX_DATA| which is + * embedded inside of |obj| which is of class |ex_data_class|. Returns one on + * success and zero otherwise. */ +OPENSSL_EXPORT int CRYPTO_new_ex_data(CRYPTO_EX_DATA_CLASS *ex_data_class, + void *obj, CRYPTO_EX_DATA *ad); + +/* CRYPTO_dup_ex_data duplicates |from| into a freshly allocated + * |CRYPTO_EX_DATA|, |to|. Both of which are inside objects of the given + * class. It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int CRYPTO_dup_ex_data(CRYPTO_EX_DATA_CLASS *ex_data_class, + CRYPTO_EX_DATA *to, + const CRYPTO_EX_DATA *from); + +/* CRYPTO_free_ex_data frees |ad|, which is embedded inside |obj|, which is an + * object of the given class. */ +OPENSSL_EXPORT void CRYPTO_free_ex_data(CRYPTO_EX_DATA_CLASS *ex_data_class, + void *obj, CRYPTO_EX_DATA *ad); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_CRYPTO_INTERNAL_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/lhash/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/lhash/CMakeLists.txt new file mode 100644 index 00000000..593da769 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/lhash/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories(. .. ../../include) + +add_library( + lhash + + OBJECT + + lhash.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/lhash/lhash.c b/TMessagesProj/jni/boringssl/crypto/lhash/lhash.c new file mode 100644 index 00000000..257900ea --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/lhash/lhash.c @@ -0,0 +1,346 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include + +#include + +/* kMinNumBuckets is the minimum size of the buckets array in an |_LHASH|. */ +static const size_t kMinNumBuckets = 16; + +/* kMaxAverageChainLength contains the maximum, average chain length. When the + * average chain length exceeds this value, the hash table will be resized. */ +static const size_t kMaxAverageChainLength = 2; +static const size_t kMinAverageChainLength = 1; + +_LHASH *lh_new(lhash_hash_func hash, lhash_cmp_func comp) { + _LHASH *ret; + + ret = OPENSSL_malloc(sizeof(_LHASH)); + if (ret == NULL) { + return NULL; + } + memset(ret, 0, sizeof(_LHASH)); + + ret->num_buckets = kMinNumBuckets; + ret->buckets = OPENSSL_malloc(sizeof(LHASH_ITEM *) * ret->num_buckets); + if (ret->buckets == NULL) { + OPENSSL_free(ret); + return NULL; + } + memset(ret->buckets, 0, sizeof(LHASH_ITEM *) * ret->num_buckets); + + ret->comp = comp; + if (ret->comp == NULL) { + ret->comp = (lhash_cmp_func) strcmp; + } + ret->hash = hash; + if (ret->hash == NULL) { + ret->hash = (lhash_hash_func) lh_strhash; + } + + return ret; +} + +void lh_free(_LHASH *lh) { + size_t i; + LHASH_ITEM *n, *next; + + if (lh == NULL) { + return; + } + + for (i = 0; i < lh->num_buckets; i++) { + for (n = lh->buckets[i]; n != NULL; n = next) { + next = n->next; + OPENSSL_free(n); + } + } + + OPENSSL_free(lh->buckets); + OPENSSL_free(lh); +} + +size_t lh_num_items(const _LHASH *lh) { return lh->num_items; } + +/* get_next_ptr_and_hash returns a pointer to the pointer that points to the + * item equal to |data|. In other words, it searches for an item equal to |data| + * and, if it's at the start of a chain, then it returns a pointer to an + * element of |lh->buckets|, otherwise it returns a pointer to the |next| + * element of the previous item in the chain. If an element equal to |data| is + * not found, it returns a pointer that points to a NULL pointer. If |out_hash| + * is not NULL, then it also puts the hash value of |data| in |*out_hash|. */ +static LHASH_ITEM **get_next_ptr_and_hash(const _LHASH *lh, uint32_t *out_hash, + const void *data) { + const uint32_t hash = lh->hash(data); + LHASH_ITEM *cur, **ret; + + if (out_hash != NULL) { + *out_hash = hash; + } + + ret = &lh->buckets[hash % lh->num_buckets]; + for (cur = *ret; cur != NULL; cur = *ret) { + if (lh->comp(cur->data, data) == 0) { + break; + } + ret = &cur->next; + } + + return ret; +} + +void *lh_retrieve(const _LHASH *lh, const void *data) { + LHASH_ITEM **next_ptr; + + next_ptr = get_next_ptr_and_hash(lh, NULL, data); + + if (*next_ptr == NULL) { + return NULL; + } + + return (*next_ptr)->data; +} + +/* lh_rebucket allocates a new array of |new_num_buckets| pointers and + * redistributes the existing items into it before making it |lh->buckets| and + * freeing the old array. */ +static void lh_rebucket(_LHASH *lh, const size_t new_num_buckets) { + LHASH_ITEM **new_buckets, *cur, *next; + size_t i, alloc_size; + + alloc_size = sizeof(LHASH_ITEM *) * new_num_buckets; + if (alloc_size / sizeof(LHASH_ITEM*) != new_num_buckets) { + return; + } + + new_buckets = OPENSSL_malloc(alloc_size); + if (new_buckets == NULL) { + return; + } + memset(new_buckets, 0, alloc_size); + + for (i = 0; i < lh->num_buckets; i++) { + for (cur = lh->buckets[i]; cur != NULL; cur = next) { + const size_t new_bucket = cur->hash % new_num_buckets; + next = cur->next; + cur->next = new_buckets[new_bucket]; + new_buckets[new_bucket] = cur; + } + } + + OPENSSL_free(lh->buckets); + + lh->num_buckets = new_num_buckets; + lh->buckets = new_buckets; +} + +/* lh_maybe_resize resizes the |buckets| array if needed. */ +static void lh_maybe_resize(_LHASH *lh) { + size_t avg_chain_length; + + if (lh->callback_depth > 0) { + /* Don't resize the hash if we are currently iterating over it. */ + return; + } + + assert(lh->num_buckets >= kMinNumBuckets); + avg_chain_length = lh->num_items / lh->num_buckets; + + if (avg_chain_length > kMaxAverageChainLength) { + const size_t new_num_buckets = lh->num_buckets * 2; + + if (new_num_buckets > lh->num_buckets) { + lh_rebucket(lh, new_num_buckets); + } + } else if (avg_chain_length < kMinAverageChainLength && + lh->num_buckets > kMinNumBuckets) { + size_t new_num_buckets = lh->num_buckets / 2; + + if (new_num_buckets < kMinNumBuckets) { + new_num_buckets = kMinNumBuckets; + } + + lh_rebucket(lh, new_num_buckets); + } +} + +int lh_insert(_LHASH *lh, void **old_data, void *data) { + uint32_t hash; + LHASH_ITEM **next_ptr, *item; + + *old_data = NULL; + next_ptr = get_next_ptr_and_hash(lh, &hash, data); + + + if (*next_ptr != NULL) { + /* An element equal to |data| already exists in the hash table. It will be + * replaced. */ + *old_data = (*next_ptr)->data; + (*next_ptr)->data = data; + return 1; + } + + /* An element equal to |data| doesn't exist in the hash table yet. */ + item = OPENSSL_malloc(sizeof(LHASH_ITEM)); + if (item == NULL) { + return 0; + } + + item->data = data; + item->hash = hash; + item->next = NULL; + *next_ptr = item; + lh->num_items++; + lh_maybe_resize(lh); + + return 1; +} + +void *lh_delete(_LHASH *lh, const void *data) { + LHASH_ITEM **next_ptr, *item, *ret; + + next_ptr = get_next_ptr_and_hash(lh, NULL, data); + + if (*next_ptr == NULL) { + /* No such element. */ + return NULL; + } + + item = *next_ptr; + *next_ptr = item->next; + ret = item->data; + OPENSSL_free(item); + + lh->num_items--; + lh_maybe_resize(lh); + + return ret; +} + +static void lh_doall_internal(_LHASH *lh, void (*no_arg_func)(void *), + void (*arg_func)(void *, void *), void *arg) { + size_t i; + LHASH_ITEM *cur, *next; + + if (lh == NULL) { + return; + } + + if (lh->callback_depth < UINT_MAX) { + /* |callback_depth| is a saturating counter. */ + lh->callback_depth++; + } + + for (i = 0; i < lh->num_buckets; i++) { + for (cur = lh->buckets[i]; cur != NULL; cur = next) { + next = cur->next; + if (arg_func) { + arg_func(cur->data, arg); + } else { + no_arg_func(cur->data); + } + } + } + + if (lh->callback_depth < UINT_MAX) { + lh->callback_depth--; + } + + /* The callback may have added or removed elements and the non-zero value of + * |callback_depth| will have suppressed any resizing. Thus any needed + * resizing is done here. */ + lh_maybe_resize(lh); +} + +void lh_doall(_LHASH *lh, void (*func)(void *)) { + lh_doall_internal(lh, func, NULL, NULL); +} + +void lh_doall_arg(_LHASH *lh, void (*func)(void *, void *), void *arg) { + lh_doall_internal(lh, NULL, func, arg); +} + +uint32_t lh_strhash(const char *c) { + /* The following hash seems to work very well on normal text strings + * no collisions on /usr/dict/words and it distributes on %2^n quite + * well, not as good as MD5, but still good. */ + unsigned long ret = 0; + long n; + unsigned long v; + int r; + + if ((c == NULL) || (*c == '\0')) { + return (ret); + } + + n = 0x100; + while (*c) { + v = n | (*c); + n += 0x100; + r = (int)((v >> 2) ^ v) & 0x0f; + ret = (ret << r) | (ret >> (32 - r)); + ret &= 0xFFFFFFFFL; + ret ^= v * v; + c++; + } + + return ((ret >> 16) ^ ret); +} diff --git a/TMessagesProj/jni/boringssl/crypto/lhash/make_macros.sh b/TMessagesProj/jni/boringssl/crypto/lhash/make_macros.sh new file mode 100644 index 00000000..8a876af3 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/lhash/make_macros.sh @@ -0,0 +1,67 @@ +#!/bin/sh + +include_dir=../../include/openssl +out=${include_dir}/lhash_macros.h + +cat > $out << EOF +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#if !defined(IN_LHASH_H) +#error "Don't include this file directly. Include lhash.h" +#endif + +EOF + +output_lhash () { + type=$1 + + cat >> $out << EOF +/* ${type} */ +#define lh_${type}_new(hash, comp)\\ +((LHASH_OF(${type})*) lh_new(CHECKED_CAST(lhash_hash_func, uint32_t (*) (const ${type} *), hash), CHECKED_CAST(lhash_cmp_func, int (*) (const ${type} *a, const ${type} *b), comp))) + +#define lh_${type}_free(lh)\\ + lh_free(CHECKED_CAST(_LHASH*, LHASH_OF(${type})*, lh)); + +#define lh_${type}_num_items(lh)\\ + lh_num_items(CHECKED_CAST(_LHASH*, LHASH_OF(${type})*, lh)) + +#define lh_${type}_retrieve(lh, data)\\ + ((${type}*) lh_retrieve(CHECKED_CAST(_LHASH*, LHASH_OF(${type})*, lh), CHECKED_CAST(void*, ${type}*, data))) + +#define lh_${type}_insert(lh, old_data, data)\\ + lh_insert(CHECKED_CAST(_LHASH*, LHASH_OF(${type})*, lh), CHECKED_CAST(void**, ${type}**, old_data), CHECKED_CAST(void*, ${type}*, data)) + +#define lh_${type}_delete(lh, data)\\ + ((${type}*) lh_delete(CHECKED_CAST(_LHASH*, LHASH_OF(${type})*, lh), CHECKED_CAST(void*, ${type}*, data))) + +#define lh_${type}_doall(lh, func)\\ + lh_doall(CHECKED_CAST(_LHASH*, LHASH_OF(${type})*, lh), CHECKED_CAST(void (*)(void*), void (*) (${type}*), func)); + +#define lh_${type}_doall_arg(lh, func, arg)\\ + lh_doall_arg(CHECKED_CAST(_LHASH*, LHASH_OF(${type})*, lh), CHECKED_CAST(void (*)(void*, void*), void (*) (${type}*, void*), func), arg); + + +EOF +} + +lhash_types=$(cat ${include_dir}/lhash.h | grep '^ \* LHASH_OF:' | sed -e 's/.*LHASH_OF://' -e 's/ .*//') + +for type in $lhash_types; do + echo Hash of ${type} + output_lhash "${type}" +done + +clang-format -i $out diff --git a/TMessagesProj/jni/boringssl/crypto/md5/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/md5/CMakeLists.txt new file mode 100644 index 00000000..6c5e80f1 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/md5/CMakeLists.txt @@ -0,0 +1,30 @@ +include_directories(. .. ../../include) + +if (${ARCH} STREQUAL "x86_64") + set( + MD5_ARCH_SOURCES + + md5-x86_64.${ASM_EXT} + ) +endif() + +if (${ARCH} STREQUAL "x86") + set( + MD5_ARCH_SOURCES + + md5-586.${ASM_EXT} + ) +endif() + +add_library( + md5 + + OBJECT + + md5.c + + ${MD5_ARCH_SOURCES} +) + +perlasm(md5-x86_64.${ASM_EXT} asm/md5-x86_64.pl) +perlasm(md5-586.${ASM_EXT} asm/md5-586.pl) diff --git a/TMessagesProj/jni/boringssl/crypto/md5/asm/md5-586.pl b/TMessagesProj/jni/boringssl/crypto/md5/asm/md5-586.pl new file mode 100644 index 00000000..6cb66bb4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/md5/asm/md5-586.pl @@ -0,0 +1,307 @@ +#!/usr/local/bin/perl + +# Normal is the +# md5_block_x86(MD5_CTX *c, ULONG *X); +# version, non-normal is the +# md5_block_x86(MD5_CTX *c, ULONG *X,int blocks); + +$normal=0; + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +push(@INC,"${dir}","${dir}../../perlasm"); +require "x86asm.pl"; + +&asm_init($ARGV[0],$0); + +$A="eax"; +$B="ebx"; +$C="ecx"; +$D="edx"; +$tmp1="edi"; +$tmp2="ebp"; +$X="esi"; + +# What we need to load into $tmp for the next round +%Ltmp1=("R0",&Np($C), "R1",&Np($C), "R2",&Np($C), "R3",&Np($D)); +@xo=( + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, # R0 + 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, # R1 + 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, # R2 + 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9, # R3 + ); + +&md5_block("md5_block_asm_data_order"); +&asm_finish(); + +sub Np + { + local($p)=@_; + local(%n)=($A,$D,$B,$A,$C,$B,$D,$C); + return($n{$p}); + } + +sub R0 + { + local($pos,$a,$b,$c,$d,$K,$ki,$s,$t)=@_; + + &mov($tmp1,$C) if $pos < 0; + &mov($tmp2,&DWP($xo[$ki]*4,$K,"",0)) if $pos < 0; # very first one + + # body proper + + &comment("R0 $ki"); + &xor($tmp1,$d); # F function - part 2 + + &and($tmp1,$b); # F function - part 3 + &lea($a,&DWP($t,$a,$tmp2,1)); + + &xor($tmp1,$d); # F function - part 4 + + &add($a,$tmp1); + &mov($tmp1,&Np($c)) if $pos < 1; # next tmp1 for R0 + &mov($tmp1,&Np($c)) if $pos == 1; # next tmp1 for R1 + + &rotl($a,$s); + + &mov($tmp2,&DWP($xo[$ki+1]*4,$K,"",0)) if ($pos != 2); + + &add($a,$b); + } + +sub R1 + { + local($pos,$a,$b,$c,$d,$K,$ki,$s,$t)=@_; + + &comment("R1 $ki"); + + &lea($a,&DWP($t,$a,$tmp2,1)); + + &xor($tmp1,$b); # G function - part 2 + &and($tmp1,$d); # G function - part 3 + + &mov($tmp2,&DWP($xo[$ki+1]*4,$K,"",0)) if ($pos != 2); + &xor($tmp1,$c); # G function - part 4 + + &add($a,$tmp1); + &mov($tmp1,&Np($c)) if $pos < 1; # G function - part 1 + &mov($tmp1,&Np($c)) if $pos == 1; # G function - part 1 + + &rotl($a,$s); + + &add($a,$b); + } + +sub R2 + { + local($n,$pos,$a,$b,$c,$d,$K,$ki,$s,$t)=@_; + # This one is different, only 3 logical operations + +if (($n & 1) == 0) + { + &comment("R2 $ki"); + # make sure to do 'D' first, not 'B', else we clash with + # the last add from the previous round. + + &xor($tmp1,$d); # H function - part 2 + + &xor($tmp1,$b); # H function - part 3 + &lea($a,&DWP($t,$a,$tmp2,1)); + + &add($a,$tmp1); + + &rotl($a,$s); + + &mov($tmp2,&DWP($xo[$ki+1]*4,$K,"",0)); + &mov($tmp1,&Np($c)); + } +else + { + &comment("R2 $ki"); + # make sure to do 'D' first, not 'B', else we clash with + # the last add from the previous round. + + &lea($a,&DWP($t,$a,$tmp2,1)); + + &add($b,$c); # MOVED FORWARD + &xor($tmp1,$d); # H function - part 2 + + &xor($tmp1,$b); # H function - part 3 + &mov($tmp2,&DWP($xo[$ki+1]*4,$K,"",0)) if ($pos != 2); + + &add($a,$tmp1); + &mov($tmp1,&Np($c)) if $pos < 1; # H function - part 1 + &mov($tmp1,-1) if $pos == 1; # I function - part 1 + + &rotl($a,$s); + + &add($a,$b); + } + } + +sub R3 + { + local($pos,$a,$b,$c,$d,$K,$ki,$s,$t)=@_; + + &comment("R3 $ki"); + + # ¬($tmp1) + &xor($tmp1,$d) if $pos < 0; # I function - part 2 + + &or($tmp1,$b); # I function - part 3 + &lea($a,&DWP($t,$a,$tmp2,1)); + + &xor($tmp1,$c); # I function - part 4 + &mov($tmp2,&DWP($xo[$ki+1]*4,$K,"",0)) if $pos != 2; # load X/k value + &mov($tmp2,&wparam(0)) if $pos == 2; + + &add($a,$tmp1); + &mov($tmp1,-1) if $pos < 1; # H function - part 1 + &add($K,64) if $pos >=1 && !$normal; + + &rotl($a,$s); + + &xor($tmp1,&Np($d)) if $pos <= 0; # I function - part = first time + &mov($tmp1,&DWP( 0,$tmp2,"",0)) if $pos > 0; + &add($a,$b); + } + + +sub md5_block + { + local($name)=@_; + + &function_begin_B($name,"",3); + + # parameter 1 is the MD5_CTX structure. + # A 0 + # B 4 + # C 8 + # D 12 + + &push("esi"); + &push("edi"); + &mov($tmp1, &wparam(0)); # edi + &mov($X, &wparam(1)); # esi + &mov($C, &wparam(2)); + &push("ebp"); + &shl($C, 6); + &push("ebx"); + &add($C, $X); # offset we end at + &sub($C, 64); + &mov($A, &DWP( 0,$tmp1,"",0)); + &push($C); # Put on the TOS + &mov($B, &DWP( 4,$tmp1,"",0)); + &mov($C, &DWP( 8,$tmp1,"",0)); + &mov($D, &DWP(12,$tmp1,"",0)); + + &set_label("start") unless $normal; + &comment(""); + &comment("R0 section"); + + &R0(-2,$A,$B,$C,$D,$X, 0, 7,0xd76aa478); + &R0( 0,$D,$A,$B,$C,$X, 1,12,0xe8c7b756); + &R0( 0,$C,$D,$A,$B,$X, 2,17,0x242070db); + &R0( 0,$B,$C,$D,$A,$X, 3,22,0xc1bdceee); + &R0( 0,$A,$B,$C,$D,$X, 4, 7,0xf57c0faf); + &R0( 0,$D,$A,$B,$C,$X, 5,12,0x4787c62a); + &R0( 0,$C,$D,$A,$B,$X, 6,17,0xa8304613); + &R0( 0,$B,$C,$D,$A,$X, 7,22,0xfd469501); + &R0( 0,$A,$B,$C,$D,$X, 8, 7,0x698098d8); + &R0( 0,$D,$A,$B,$C,$X, 9,12,0x8b44f7af); + &R0( 0,$C,$D,$A,$B,$X,10,17,0xffff5bb1); + &R0( 0,$B,$C,$D,$A,$X,11,22,0x895cd7be); + &R0( 0,$A,$B,$C,$D,$X,12, 7,0x6b901122); + &R0( 0,$D,$A,$B,$C,$X,13,12,0xfd987193); + &R0( 0,$C,$D,$A,$B,$X,14,17,0xa679438e); + &R0( 1,$B,$C,$D,$A,$X,15,22,0x49b40821); + + &comment(""); + &comment("R1 section"); + &R1(-1,$A,$B,$C,$D,$X,16, 5,0xf61e2562); + &R1( 0,$D,$A,$B,$C,$X,17, 9,0xc040b340); + &R1( 0,$C,$D,$A,$B,$X,18,14,0x265e5a51); + &R1( 0,$B,$C,$D,$A,$X,19,20,0xe9b6c7aa); + &R1( 0,$A,$B,$C,$D,$X,20, 5,0xd62f105d); + &R1( 0,$D,$A,$B,$C,$X,21, 9,0x02441453); + &R1( 0,$C,$D,$A,$B,$X,22,14,0xd8a1e681); + &R1( 0,$B,$C,$D,$A,$X,23,20,0xe7d3fbc8); + &R1( 0,$A,$B,$C,$D,$X,24, 5,0x21e1cde6); + &R1( 0,$D,$A,$B,$C,$X,25, 9,0xc33707d6); + &R1( 0,$C,$D,$A,$B,$X,26,14,0xf4d50d87); + &R1( 0,$B,$C,$D,$A,$X,27,20,0x455a14ed); + &R1( 0,$A,$B,$C,$D,$X,28, 5,0xa9e3e905); + &R1( 0,$D,$A,$B,$C,$X,29, 9,0xfcefa3f8); + &R1( 0,$C,$D,$A,$B,$X,30,14,0x676f02d9); + &R1( 1,$B,$C,$D,$A,$X,31,20,0x8d2a4c8a); + + &comment(""); + &comment("R2 section"); + &R2( 0,-1,$A,$B,$C,$D,$X,32, 4,0xfffa3942); + &R2( 1, 0,$D,$A,$B,$C,$X,33,11,0x8771f681); + &R2( 2, 0,$C,$D,$A,$B,$X,34,16,0x6d9d6122); + &R2( 3, 0,$B,$C,$D,$A,$X,35,23,0xfde5380c); + &R2( 4, 0,$A,$B,$C,$D,$X,36, 4,0xa4beea44); + &R2( 5, 0,$D,$A,$B,$C,$X,37,11,0x4bdecfa9); + &R2( 6, 0,$C,$D,$A,$B,$X,38,16,0xf6bb4b60); + &R2( 7, 0,$B,$C,$D,$A,$X,39,23,0xbebfbc70); + &R2( 8, 0,$A,$B,$C,$D,$X,40, 4,0x289b7ec6); + &R2( 9, 0,$D,$A,$B,$C,$X,41,11,0xeaa127fa); + &R2(10, 0,$C,$D,$A,$B,$X,42,16,0xd4ef3085); + &R2(11, 0,$B,$C,$D,$A,$X,43,23,0x04881d05); + &R2(12, 0,$A,$B,$C,$D,$X,44, 4,0xd9d4d039); + &R2(13, 0,$D,$A,$B,$C,$X,45,11,0xe6db99e5); + &R2(14, 0,$C,$D,$A,$B,$X,46,16,0x1fa27cf8); + &R2(15, 1,$B,$C,$D,$A,$X,47,23,0xc4ac5665); + + &comment(""); + &comment("R3 section"); + &R3(-1,$A,$B,$C,$D,$X,48, 6,0xf4292244); + &R3( 0,$D,$A,$B,$C,$X,49,10,0x432aff97); + &R3( 0,$C,$D,$A,$B,$X,50,15,0xab9423a7); + &R3( 0,$B,$C,$D,$A,$X,51,21,0xfc93a039); + &R3( 0,$A,$B,$C,$D,$X,52, 6,0x655b59c3); + &R3( 0,$D,$A,$B,$C,$X,53,10,0x8f0ccc92); + &R3( 0,$C,$D,$A,$B,$X,54,15,0xffeff47d); + &R3( 0,$B,$C,$D,$A,$X,55,21,0x85845dd1); + &R3( 0,$A,$B,$C,$D,$X,56, 6,0x6fa87e4f); + &R3( 0,$D,$A,$B,$C,$X,57,10,0xfe2ce6e0); + &R3( 0,$C,$D,$A,$B,$X,58,15,0xa3014314); + &R3( 0,$B,$C,$D,$A,$X,59,21,0x4e0811a1); + &R3( 0,$A,$B,$C,$D,$X,60, 6,0xf7537e82); + &R3( 0,$D,$A,$B,$C,$X,61,10,0xbd3af235); + &R3( 0,$C,$D,$A,$B,$X,62,15,0x2ad7d2bb); + &R3( 2,$B,$C,$D,$A,$X,63,21,0xeb86d391); + + # &mov($tmp2,&wparam(0)); # done in the last R3 + # &mov($tmp1, &DWP( 0,$tmp2,"",0)); # done is the last R3 + + &add($A,$tmp1); + &mov($tmp1, &DWP( 4,$tmp2,"",0)); + + &add($B,$tmp1); + &mov($tmp1, &DWP( 8,$tmp2,"",0)); + + &add($C,$tmp1); + &mov($tmp1, &DWP(12,$tmp2,"",0)); + + &add($D,$tmp1); + &mov(&DWP( 0,$tmp2,"",0),$A); + + &mov(&DWP( 4,$tmp2,"",0),$B); + &mov($tmp1,&swtmp(0)) unless $normal; + + &mov(&DWP( 8,$tmp2,"",0),$C); + &mov(&DWP(12,$tmp2,"",0),$D); + + &cmp($tmp1,$X) unless $normal; # check count + &jae(&label("start")) unless $normal; + + &pop("eax"); # pop the temp variable off the stack + &pop("ebx"); + &pop("ebp"); + &pop("edi"); + &pop("esi"); + &ret(); + &function_end_B($name); + } + diff --git a/TMessagesProj/jni/boringssl/crypto/md5/asm/md5-x86_64.pl b/TMessagesProj/jni/boringssl/crypto/md5/asm/md5-x86_64.pl new file mode 100644 index 00000000..77a6e01d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/md5/asm/md5-x86_64.pl @@ -0,0 +1,370 @@ +#!/usr/bin/perl -w +# +# MD5 optimized for AMD64. +# +# Author: Marc Bevand +# Licence: I hereby disclaim the copyright on this code and place it +# in the public domain. +# + +use strict; + +my $code; + +# round1_step() does: +# dst = x + ((dst + F(x,y,z) + X[k] + T_i) <<< s) +# %r10d = X[k_next] +# %r11d = z' (copy of z for the next step) +# Each round1_step() takes about 5.3 clocks (9 instructions, 1.7 IPC) +sub round1_step +{ + my ($pos, $dst, $x, $y, $z, $k_next, $T_i, $s) = @_; + $code .= " mov 0*4(%rsi), %r10d /* (NEXT STEP) X[0] */\n" if ($pos == -1); + $code .= " mov %edx, %r11d /* (NEXT STEP) z' = %edx */\n" if ($pos == -1); + $code .= <A + mov 1*4(%rbp), %ebx # ebx = ctx->B + mov 2*4(%rbp), %ecx # ecx = ctx->C + mov 3*4(%rbp), %edx # edx = ctx->D + # end is 'rdi' + # ptr is 'rsi' + # A is 'eax' + # B is 'ebx' + # C is 'ecx' + # D is 'edx' + + cmp %rdi, %rsi # cmp end with ptr + je .Lend # jmp if ptr == end + + # BEGIN of loop over 16-word blocks +.Lloop: # save old values of A, B, C, D + mov %eax, %r8d + mov %ebx, %r9d + mov %ecx, %r14d + mov %edx, %r15d +EOF +round1_step(-1,'%eax','%ebx','%ecx','%edx', '1','0xd76aa478', '7'); +round1_step( 0,'%edx','%eax','%ebx','%ecx', '2','0xe8c7b756','12'); +round1_step( 0,'%ecx','%edx','%eax','%ebx', '3','0x242070db','17'); +round1_step( 0,'%ebx','%ecx','%edx','%eax', '4','0xc1bdceee','22'); +round1_step( 0,'%eax','%ebx','%ecx','%edx', '5','0xf57c0faf', '7'); +round1_step( 0,'%edx','%eax','%ebx','%ecx', '6','0x4787c62a','12'); +round1_step( 0,'%ecx','%edx','%eax','%ebx', '7','0xa8304613','17'); +round1_step( 0,'%ebx','%ecx','%edx','%eax', '8','0xfd469501','22'); +round1_step( 0,'%eax','%ebx','%ecx','%edx', '9','0x698098d8', '7'); +round1_step( 0,'%edx','%eax','%ebx','%ecx','10','0x8b44f7af','12'); +round1_step( 0,'%ecx','%edx','%eax','%ebx','11','0xffff5bb1','17'); +round1_step( 0,'%ebx','%ecx','%edx','%eax','12','0x895cd7be','22'); +round1_step( 0,'%eax','%ebx','%ecx','%edx','13','0x6b901122', '7'); +round1_step( 0,'%edx','%eax','%ebx','%ecx','14','0xfd987193','12'); +round1_step( 0,'%ecx','%edx','%eax','%ebx','15','0xa679438e','17'); +round1_step( 1,'%ebx','%ecx','%edx','%eax', '0','0x49b40821','22'); + +round2_step(-1,'%eax','%ebx','%ecx','%edx', '6','0xf61e2562', '5'); +round2_step( 0,'%edx','%eax','%ebx','%ecx','11','0xc040b340', '9'); +round2_step( 0,'%ecx','%edx','%eax','%ebx', '0','0x265e5a51','14'); +round2_step( 0,'%ebx','%ecx','%edx','%eax', '5','0xe9b6c7aa','20'); +round2_step( 0,'%eax','%ebx','%ecx','%edx','10','0xd62f105d', '5'); +round2_step( 0,'%edx','%eax','%ebx','%ecx','15', '0x2441453', '9'); +round2_step( 0,'%ecx','%edx','%eax','%ebx', '4','0xd8a1e681','14'); +round2_step( 0,'%ebx','%ecx','%edx','%eax', '9','0xe7d3fbc8','20'); +round2_step( 0,'%eax','%ebx','%ecx','%edx','14','0x21e1cde6', '5'); +round2_step( 0,'%edx','%eax','%ebx','%ecx', '3','0xc33707d6', '9'); +round2_step( 0,'%ecx','%edx','%eax','%ebx', '8','0xf4d50d87','14'); +round2_step( 0,'%ebx','%ecx','%edx','%eax','13','0x455a14ed','20'); +round2_step( 0,'%eax','%ebx','%ecx','%edx', '2','0xa9e3e905', '5'); +round2_step( 0,'%edx','%eax','%ebx','%ecx', '7','0xfcefa3f8', '9'); +round2_step( 0,'%ecx','%edx','%eax','%ebx','12','0x676f02d9','14'); +round2_step( 1,'%ebx','%ecx','%edx','%eax', '0','0x8d2a4c8a','20'); + +round3_step(-1,'%eax','%ebx','%ecx','%edx', '8','0xfffa3942', '4'); +round3_step( 0,'%edx','%eax','%ebx','%ecx','11','0x8771f681','11'); +round3_step( 0,'%ecx','%edx','%eax','%ebx','14','0x6d9d6122','16'); +round3_step( 0,'%ebx','%ecx','%edx','%eax', '1','0xfde5380c','23'); +round3_step( 0,'%eax','%ebx','%ecx','%edx', '4','0xa4beea44', '4'); +round3_step( 0,'%edx','%eax','%ebx','%ecx', '7','0x4bdecfa9','11'); +round3_step( 0,'%ecx','%edx','%eax','%ebx','10','0xf6bb4b60','16'); +round3_step( 0,'%ebx','%ecx','%edx','%eax','13','0xbebfbc70','23'); +round3_step( 0,'%eax','%ebx','%ecx','%edx', '0','0x289b7ec6', '4'); +round3_step( 0,'%edx','%eax','%ebx','%ecx', '3','0xeaa127fa','11'); +round3_step( 0,'%ecx','%edx','%eax','%ebx', '6','0xd4ef3085','16'); +round3_step( 0,'%ebx','%ecx','%edx','%eax', '9', '0x4881d05','23'); +round3_step( 0,'%eax','%ebx','%ecx','%edx','12','0xd9d4d039', '4'); +round3_step( 0,'%edx','%eax','%ebx','%ecx','15','0xe6db99e5','11'); +round3_step( 0,'%ecx','%edx','%eax','%ebx', '2','0x1fa27cf8','16'); +round3_step( 1,'%ebx','%ecx','%edx','%eax', '0','0xc4ac5665','23'); + +round4_step(-1,'%eax','%ebx','%ecx','%edx', '7','0xf4292244', '6'); +round4_step( 0,'%edx','%eax','%ebx','%ecx','14','0x432aff97','10'); +round4_step( 0,'%ecx','%edx','%eax','%ebx', '5','0xab9423a7','15'); +round4_step( 0,'%ebx','%ecx','%edx','%eax','12','0xfc93a039','21'); +round4_step( 0,'%eax','%ebx','%ecx','%edx', '3','0x655b59c3', '6'); +round4_step( 0,'%edx','%eax','%ebx','%ecx','10','0x8f0ccc92','10'); +round4_step( 0,'%ecx','%edx','%eax','%ebx', '1','0xffeff47d','15'); +round4_step( 0,'%ebx','%ecx','%edx','%eax', '8','0x85845dd1','21'); +round4_step( 0,'%eax','%ebx','%ecx','%edx','15','0x6fa87e4f', '6'); +round4_step( 0,'%edx','%eax','%ebx','%ecx', '6','0xfe2ce6e0','10'); +round4_step( 0,'%ecx','%edx','%eax','%ebx','13','0xa3014314','15'); +round4_step( 0,'%ebx','%ecx','%edx','%eax', '4','0x4e0811a1','21'); +round4_step( 0,'%eax','%ebx','%ecx','%edx','11','0xf7537e82', '6'); +round4_step( 0,'%edx','%eax','%ebx','%ecx', '2','0xbd3af235','10'); +round4_step( 0,'%ecx','%edx','%eax','%ebx', '9','0x2ad7d2bb','15'); +round4_step( 1,'%ebx','%ecx','%edx','%eax', '0','0xeb86d391','21'); +$code .= <A = A + mov %ebx, 1*4(%rbp) # ctx->B = B + mov %ecx, 2*4(%rbp) # ctx->C = C + mov %edx, 3*4(%rbp) # ctx->D = D + + mov (%rsp),%r15 + mov 8(%rsp),%r14 + mov 16(%rsp),%r12 + mov 24(%rsp),%rbx + mov 32(%rsp),%rbp + add \$40,%rsp +.Lepilogue: + ret +.size md5_block_asm_data_order,.-md5_block_asm_data_order +EOF + +# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame, +# CONTEXT *context,DISPATCHER_CONTEXT *disp) +if ($win64) { +my $rec="%rcx"; +my $frame="%rdx"; +my $context="%r8"; +my $disp="%r9"; + +$code.=<<___; +.extern __imp_RtlVirtualUnwind +.type se_handler,\@abi-omnipotent +.align 16 +se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + lea .Lprologue(%rip),%r10 + cmp %r10,%rbx # context->Rip<.Lprologue + jb .Lin_prologue + + mov 152($context),%rax # pull context->Rsp + + lea .Lepilogue(%rip),%r10 + cmp %r10,%rbx # context->Rip>=.Lepilogue + jae .Lin_prologue + + lea 40(%rax),%rax + + mov -8(%rax),%rbp + mov -16(%rax),%rbx + mov -24(%rax),%r12 + mov -32(%rax),%r14 + mov -40(%rax),%r15 + mov %rbx,144($context) # restore context->Rbx + mov %rbp,160($context) # restore context->Rbp + mov %r12,216($context) # restore context->R12 + mov %r14,232($context) # restore context->R14 + mov %r15,240($context) # restore context->R15 + +.Lin_prologue: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + + mov 40($disp),%rdi # disp->ContextRecord + mov $context,%rsi # context + mov \$154,%ecx # sizeof(CONTEXT) + .long 0xa548f3fc # cld; rep movsq + + mov $disp,%rsi + xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER + mov 8(%rsi),%rdx # arg2, disp->ImageBase + mov 0(%rsi),%r8 # arg3, disp->ControlPc + mov 16(%rsi),%r9 # arg4, disp->FunctionEntry + mov 40(%rsi),%r10 # disp->ContextRecord + lea 56(%rsi),%r11 # &disp->HandlerData + lea 24(%rsi),%r12 # &disp->EstablisherFrame + mov %r10,32(%rsp) # arg5 + mov %r11,40(%rsp) # arg6 + mov %r12,48(%rsp) # arg7 + mov %rcx,56(%rsp) # arg8, (NULL) + call *__imp_RtlVirtualUnwind(%rip) + + mov \$1,%eax # ExceptionContinueSearch + add \$64,%rsp + popfq + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + pop %rdi + pop %rsi + ret +.size se_handler,.-se_handler + +.section .pdata +.align 4 + .rva .LSEH_begin_md5_block_asm_data_order + .rva .LSEH_end_md5_block_asm_data_order + .rva .LSEH_info_md5_block_asm_data_order + +.section .xdata +.align 8 +.LSEH_info_md5_block_asm_data_order: + .byte 9,0,0,0 + .rva se_handler +___ +} + +print $code; + +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/md5/md5.c b/TMessagesProj/jni/boringssl/crypto/md5/md5.c new file mode 100644 index 00000000..6ad8d128 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/md5/md5.c @@ -0,0 +1,275 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include + + +uint8_t *MD5(const uint8_t *data, size_t len, uint8_t *out) { + MD5_CTX ctx; + static uint8_t digest[MD5_DIGEST_LENGTH]; + + /* TODO(fork): remove this static buffer. */ + if (out == NULL) { + out = digest; + } + + MD5_Init(&ctx); + MD5_Update(&ctx, data, len); + MD5_Final(out, &ctx); + + return out; +} + +int MD5_Init(MD5_CTX *md5) { + memset(md5, 0, sizeof(MD5_CTX)); + md5->A = 0x67452301UL; + md5->B = 0xefcdab89UL; + md5->C = 0x98badcfeUL; + md5->D = 0x10325476UL; + return 1; +} + +#if !defined(OPENSSL_NO_ASM) && \ + (defined(OPENSSL_X86_64) || defined(OPENSSL_X86)) +#define MD5_ASM +#define md5_block_data_order md5_block_asm_data_order +#endif + + +void md5_block_data_order(MD5_CTX *md5, const void *p, size_t num); + +#define DATA_ORDER_IS_LITTLE_ENDIAN + +#define HASH_LONG uint32_t +#define HASH_CTX MD5_CTX +#define HASH_CBLOCK 64 +#define HASH_UPDATE MD5_Update +#define HASH_TRANSFORM MD5_Transform +#define HASH_FINAL MD5_Final +#define HASH_MAKE_STRING(c, s) \ + do { \ + uint32_t ll; \ + ll = (c)->A; \ + (void) HOST_l2c(ll, (s)); \ + ll = (c)->B; \ + (void) HOST_l2c(ll, (s)); \ + ll = (c)->C; \ + (void) HOST_l2c(ll, (s)); \ + ll = (c)->D; \ + (void) HOST_l2c(ll, (s)); \ + } while (0) +#define HASH_BLOCK_DATA_ORDER md5_block_data_order + +#include "../digest/md32_common.h" + +/* As pointed out by Wei Dai , the above can be + * simplified to the code below. Wei attributes these optimizations + * to Peter Gutmann's SHS code, and he attributes it to Rich Schroeppel. + */ +#define F(b,c,d) ((((c) ^ (d)) & (b)) ^ (d)) +#define G(b,c,d) ((((b) ^ (c)) & (d)) ^ (c)) +#define H(b,c,d) ((b) ^ (c) ^ (d)) +#define I(b,c,d) (((~(d)) | (b)) ^ (c)) + +#define R0(a,b,c,d,k,s,t) { \ + a+=((k)+(t)+F((b),(c),(d))); \ + a=ROTATE(a,s); \ + a+=b; };\ + +#define R1(a,b,c,d,k,s,t) { \ + a+=((k)+(t)+G((b),(c),(d))); \ + a=ROTATE(a,s); \ + a+=b; }; + +#define R2(a,b,c,d,k,s,t) { \ + a+=((k)+(t)+H((b),(c),(d))); \ + a=ROTATE(a,s); \ + a+=b; }; + +#define R3(a,b,c,d,k,s,t) { \ + a+=((k)+(t)+I((b),(c),(d))); \ + a=ROTATE(a,s); \ + a+=b; }; + +#ifndef md5_block_data_order +#ifdef X +#undef X +#endif +void md5_block_data_order(MD5_CTX *md5, const void *in_data, size_t num) { + const uint8_t *data = in_data; + uint32_t A, B, C, D, l; + uint32_t XX0, XX1, XX2, XX3, XX4, XX5, XX6, XX7, XX8, XX9, XX10, XX11, XX12, + XX13, XX14, XX15; +#define X(i) XX##i + + A = md5->A; + B = md5->B; + C = md5->C; + D = md5->D; + + for (; num--;) { + HOST_c2l(data, l); + X(0) = l; + HOST_c2l(data, l); + X(1) = l; + /* Round 0 */ + R0(A, B, C, D, X(0), 7, 0xd76aa478L); + HOST_c2l(data, l); + X(2) = l; + R0(D, A, B, C, X(1), 12, 0xe8c7b756L); + HOST_c2l(data, l); + X(3) = l; + R0(C, D, A, B, X(2), 17, 0x242070dbL); + HOST_c2l(data, l); + X(4) = l; + R0(B, C, D, A, X(3), 22, 0xc1bdceeeL); + HOST_c2l(data, l); + X(5) = l; + R0(A, B, C, D, X(4), 7, 0xf57c0fafL); + HOST_c2l(data, l); + X(6) = l; + R0(D, A, B, C, X(5), 12, 0x4787c62aL); + HOST_c2l(data, l); + X(7) = l; + R0(C, D, A, B, X(6), 17, 0xa8304613L); + HOST_c2l(data, l); + X(8) = l; + R0(B, C, D, A, X(7), 22, 0xfd469501L); + HOST_c2l(data, l); + X(9) = l; + R0(A, B, C, D, X(8), 7, 0x698098d8L); + HOST_c2l(data, l); + X(10) = l; + R0(D, A, B, C, X(9), 12, 0x8b44f7afL); + HOST_c2l(data, l); + X(11) = l; + R0(C, D, A, B, X(10), 17, 0xffff5bb1L); + HOST_c2l(data, l); + X(12) = l; + R0(B, C, D, A, X(11), 22, 0x895cd7beL); + HOST_c2l(data, l); + X(13) = l; + R0(A, B, C, D, X(12), 7, 0x6b901122L); + HOST_c2l(data, l); + X(14) = l; + R0(D, A, B, C, X(13), 12, 0xfd987193L); + HOST_c2l(data, l); + X(15) = l; + R0(C, D, A, B, X(14), 17, 0xa679438eL); + R0(B, C, D, A, X(15), 22, 0x49b40821L); + /* Round 1 */ + R1(A, B, C, D, X(1), 5, 0xf61e2562L); + R1(D, A, B, C, X(6), 9, 0xc040b340L); + R1(C, D, A, B, X(11), 14, 0x265e5a51L); + R1(B, C, D, A, X(0), 20, 0xe9b6c7aaL); + R1(A, B, C, D, X(5), 5, 0xd62f105dL); + R1(D, A, B, C, X(10), 9, 0x02441453L); + R1(C, D, A, B, X(15), 14, 0xd8a1e681L); + R1(B, C, D, A, X(4), 20, 0xe7d3fbc8L); + R1(A, B, C, D, X(9), 5, 0x21e1cde6L); + R1(D, A, B, C, X(14), 9, 0xc33707d6L); + R1(C, D, A, B, X(3), 14, 0xf4d50d87L); + R1(B, C, D, A, X(8), 20, 0x455a14edL); + R1(A, B, C, D, X(13), 5, 0xa9e3e905L); + R1(D, A, B, C, X(2), 9, 0xfcefa3f8L); + R1(C, D, A, B, X(7), 14, 0x676f02d9L); + R1(B, C, D, A, X(12), 20, 0x8d2a4c8aL); + /* Round 2 */ + R2(A, B, C, D, X(5), 4, 0xfffa3942L); + R2(D, A, B, C, X(8), 11, 0x8771f681L); + R2(C, D, A, B, X(11), 16, 0x6d9d6122L); + R2(B, C, D, A, X(14), 23, 0xfde5380cL); + R2(A, B, C, D, X(1), 4, 0xa4beea44L); + R2(D, A, B, C, X(4), 11, 0x4bdecfa9L); + R2(C, D, A, B, X(7), 16, 0xf6bb4b60L); + R2(B, C, D, A, X(10), 23, 0xbebfbc70L); + R2(A, B, C, D, X(13), 4, 0x289b7ec6L); + R2(D, A, B, C, X(0), 11, 0xeaa127faL); + R2(C, D, A, B, X(3), 16, 0xd4ef3085L); + R2(B, C, D, A, X(6), 23, 0x04881d05L); + R2(A, B, C, D, X(9), 4, 0xd9d4d039L); + R2(D, A, B, C, X(12), 11, 0xe6db99e5L); + R2(C, D, A, B, X(15), 16, 0x1fa27cf8L); + R2(B, C, D, A, X(2), 23, 0xc4ac5665L); + /* Round 3 */ + R3(A, B, C, D, X(0), 6, 0xf4292244L); + R3(D, A, B, C, X(7), 10, 0x432aff97L); + R3(C, D, A, B, X(14), 15, 0xab9423a7L); + R3(B, C, D, A, X(5), 21, 0xfc93a039L); + R3(A, B, C, D, X(12), 6, 0x655b59c3L); + R3(D, A, B, C, X(3), 10, 0x8f0ccc92L); + R3(C, D, A, B, X(10), 15, 0xffeff47dL); + R3(B, C, D, A, X(1), 21, 0x85845dd1L); + R3(A, B, C, D, X(8), 6, 0x6fa87e4fL); + R3(D, A, B, C, X(15), 10, 0xfe2ce6e0L); + R3(C, D, A, B, X(6), 15, 0xa3014314L); + R3(B, C, D, A, X(13), 21, 0x4e0811a1L); + R3(A, B, C, D, X(4), 6, 0xf7537e82L); + R3(D, A, B, C, X(11), 10, 0xbd3af235L); + R3(C, D, A, B, X(2), 15, 0x2ad7d2bbL); + R3(B, C, D, A, X(9), 21, 0xeb86d391L); + + A = md5->A += A; + B = md5->B += B; + C = md5->C += C; + D = md5->D += D; + } +} +#endif diff --git a/TMessagesProj/jni/boringssl/crypto/mem.c b/TMessagesProj/jni/boringssl/crypto/mem.c new file mode 100644 index 00000000..edd14a81 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/mem.c @@ -0,0 +1,200 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#if !defined(_POSIX_C_SOURCE) +#define _POSIX_C_SOURCE 201410L /* needed for strdup, snprintf, vprintf etc */ +#endif + +#include + +#include +#include +#include +#include + +#if defined(OPENSSL_WINDOWS) +#pragma warning(push, 3) +#include +#pragma warning(pop) +#else +#include +#endif + + +void *OPENSSL_realloc_clean(void *ptr, size_t old_size, size_t new_size) { + void *ret = NULL; + + if (ptr == NULL) { + return OPENSSL_malloc(new_size); + } + + if (new_size == 0) { + return NULL; + } + + /* We don't support shrinking the buffer. Note the memcpy that copies + * |old_size| bytes to the new buffer, below. */ + if (new_size < old_size) { + return NULL; + } + + ret = OPENSSL_malloc(new_size); + if (ret == NULL) { + return NULL; + } + + memcpy(ret, ptr, old_size); + OPENSSL_cleanse(ptr, old_size); + OPENSSL_free(ptr); + return ret; +} + +void OPENSSL_cleanse(void *ptr, size_t len) { +#if defined(OPENSSL_WINDOWS) + SecureZeroMemory(ptr, len); +#else + memset(ptr, 0, len); + +#if !defined(OPENSSL_NO_ASM) + /* As best as we can tell, this is sufficient to break any optimisations that + might try to eliminate "superfluous" memsets. If there's an easy way to + detect memset_s, it would be better to use that. */ + __asm__ __volatile__("" : : "r"(ptr) : "memory"); +#endif +#endif /* !OPENSSL_NO_ASM */ +} + +int CRYPTO_memcmp(const void *in_a, const void *in_b, size_t len) { + size_t i; + const uint8_t *a = in_a; + const uint8_t *b = in_b; + uint8_t x = 0; + + for (i = 0; i < len; i++) { + x |= a[i] ^ b[i]; + } + + return x; +} + +uint32_t OPENSSL_hash32(const void *ptr, size_t len) { + /* These are the FNV-1a parameters for 32 bits. */ + static const uint32_t kPrime = 16777619u; + static const uint32_t kOffsetBasis = 2166136261u; + + const uint8_t *in = ptr; + size_t i; + uint32_t h = kOffsetBasis; + + for (i = 0; i < len; i++) { + h ^= in[i]; + h *= kPrime; + } + + return h; +} + +char *OPENSSL_strdup(const char *s) { return strdup(s); } + +size_t OPENSSL_strnlen(const char *s, size_t len) { + size_t i; + + for (i = 0; i < len; i++) { + if (s[i] == 0) { + return i; + } + } + + return len; +} + +#if defined(OPENSSL_WINDOWS) + +int OPENSSL_strcasecmp(const char *a, const char *b) { + return _stricmp(a, b); +} + +int OPENSSL_strncasecmp(const char *a, const char *b, size_t n) { + return _strnicmp(a, b, n); +} + +#else + +int OPENSSL_strcasecmp(const char *a, const char *b) { + return strcasecmp(a, b); +} + +int OPENSSL_strncasecmp(const char *a, const char *b, size_t n) { + return strncasecmp(a, b, n); +} + +#endif + +int BIO_snprintf(char *buf, size_t n, const char *format, ...) { + va_list args; + int ret; + + va_start(args, format); + + ret = BIO_vsnprintf(buf, n, format, args); + + va_end(args); + return ret; +} + +int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args) { + return vsnprintf(buf, n, format, args); +} diff --git a/TMessagesProj/jni/boringssl/crypto/modes/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/modes/CMakeLists.txt new file mode 100644 index 00000000..9145c5c0 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/modes/CMakeLists.txt @@ -0,0 +1,55 @@ +include_directories(. .. ../../include) + +if (${ARCH} STREQUAL "x86_64") + set( + MODES_ARCH_SOURCES + + aesni-gcm-x86_64.${ASM_EXT} + ghash-x86_64.${ASM_EXT} + ) +endif() + +if (${ARCH} STREQUAL "x86") + set( + MODES_ARCH_SOURCES + + ghash-x86.${ASM_EXT} + ) +endif() + +if (${ARCH} STREQUAL "arm") + set( + MODES_ARCH_SOURCES + + ghash-armv4.${ASM_EXT} + ghashv8-armx.${ASM_EXT} + ) +endif() + +if (${ARCH} STREQUAL "aarch64") + set( + MODES_ARCH_SOURCES + + ghashv8-armx.${ASM_EXT} + ) +endif() + +add_library( + modes + + OBJECT + + cbc.c + ctr.c + ofb.c + cfb.c + gcm.c + + ${MODES_ARCH_SOURCES} +) + +perlasm(aesni-gcm-x86_64.${ASM_EXT} asm/aesni-gcm-x86_64.pl) +perlasm(ghash-x86_64.${ASM_EXT} asm/ghash-x86_64.pl) +perlasm(ghash-x86.${ASM_EXT} asm/ghash-x86.pl) +perlasm(ghash-armv4.${ASM_EXT} asm/ghash-armv4.pl) +perlasm(ghashv8-armx.${ASM_EXT} asm/ghashv8-armx.pl) diff --git a/TMessagesProj/jni/boringssl/crypto/modes/asm/aesni-gcm-x86_64.pl b/TMessagesProj/jni/boringssl/crypto/modes/asm/aesni-gcm-x86_64.pl new file mode 100644 index 00000000..7e4e04ea --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/modes/asm/aesni-gcm-x86_64.pl @@ -0,0 +1,1057 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# +# AES-NI-CTR+GHASH stitch. +# +# February 2013 +# +# OpenSSL GCM implementation is organized in such way that its +# performance is rather close to the sum of its streamed components, +# in the context parallelized AES-NI CTR and modulo-scheduled +# PCLMULQDQ-enabled GHASH. Unfortunately, as no stitch implementation +# was observed to perform significantly better than the sum of the +# components on contemporary CPUs, the effort was deemed impossible to +# justify. This module is based on combination of Intel submissions, +# [1] and [2], with MOVBE twist suggested by Ilya Albrekht and Max +# Locktyukhin of Intel Corp. who verified that it reduces shuffles +# pressure with notable relative improvement, achieving 1.0 cycle per +# byte processed with 128-bit key on Haswell processor, and 0.74 - +# on Broadwell. [Mentioned results are raw profiled measurements for +# favourable packet size, one divisible by 96. Applications using the +# EVP interface will observe a few percent worse performance.] +# +# [1] http://rt.openssl.org/Ticket/Display.html?id=2900&user=guest&pass=guest +# [2] http://www.intel.com/content/dam/www/public/us/en/documents/software-support/enabling-high-performance-gcm.pdf + +$flavour = shift; +$output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or +die "can't locate x86_64-xlate.pl"; + +if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1` + =~ /GNU assembler version ([2-9]\.[0-9]+)/) { + $avx = ($1>=2.19) + ($1>=2.22); +} + +if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) && + `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) { + $avx = ($1>=2.09) + ($1>=2.10); +} + +if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) && + `ml64 2>&1` =~ /Version ([0-9]+)\./) { + $avx = ($1>=10) + ($1>=11); +} + +if (!$avx && `$ENV{CC} -v 2>&1` =~ /(^clang version|based on LLVM) ([3-9]\.[0-9]+)/) { + $avx = ($2>=3.0) + ($2>3.0); +} + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +if ($avx>1) {{{ + +($inp,$out,$len,$key,$ivp,$Xip)=("%rdi","%rsi","%rdx","%rcx","%r8","%r9"); + +($Ii,$T1,$T2,$Hkey, + $Z0,$Z1,$Z2,$Z3,$Xi) = map("%xmm$_",(0..8)); + +($inout0,$inout1,$inout2,$inout3,$inout4,$inout5,$rndkey) = map("%xmm$_",(9..15)); + +($counter,$rounds,$ret,$const,$in0,$end0)=("%ebx","%ebp","%r10","%r11","%r14","%r15"); + +$code=<<___; +.text + +.type _aesni_ctr32_ghash_6x,\@abi-omnipotent +.align 32 +_aesni_ctr32_ghash_6x: + vmovdqu 0x20($const),$T2 # borrow $T2, .Lone_msb + sub \$6,$len + vpxor $Z0,$Z0,$Z0 # $Z0 = 0 + vmovdqu 0x00-0x80($key),$rndkey + vpaddb $T2,$T1,$inout1 + vpaddb $T2,$inout1,$inout2 + vpaddb $T2,$inout2,$inout3 + vpaddb $T2,$inout3,$inout4 + vpaddb $T2,$inout4,$inout5 + vpxor $rndkey,$T1,$inout0 + vmovdqu $Z0,16+8(%rsp) # "$Z3" = 0 + jmp .Loop6x + +.align 32 +.Loop6x: + add \$`6<<24`,$counter + jc .Lhandle_ctr32 # discard $inout[1-5]? + vmovdqu 0x00-0x20($Xip),$Hkey # $Hkey^1 + vpaddb $T2,$inout5,$T1 # next counter value + vpxor $rndkey,$inout1,$inout1 + vpxor $rndkey,$inout2,$inout2 + +.Lresume_ctr32: + vmovdqu $T1,($ivp) # save next counter value + vpclmulqdq \$0x10,$Hkey,$Z3,$Z1 + vpxor $rndkey,$inout3,$inout3 + vmovups 0x10-0x80($key),$T2 # borrow $T2 for $rndkey + vpclmulqdq \$0x01,$Hkey,$Z3,$Z2 + xor %r12,%r12 + cmp $in0,$end0 + + vaesenc $T2,$inout0,$inout0 + vmovdqu 0x30+8(%rsp),$Ii # I[4] + vpxor $rndkey,$inout4,$inout4 + vpclmulqdq \$0x00,$Hkey,$Z3,$T1 + vaesenc $T2,$inout1,$inout1 + vpxor $rndkey,$inout5,$inout5 + setnc %r12b + vpclmulqdq \$0x11,$Hkey,$Z3,$Z3 + vaesenc $T2,$inout2,$inout2 + vmovdqu 0x10-0x20($Xip),$Hkey # $Hkey^2 + neg %r12 + vaesenc $T2,$inout3,$inout3 + vpxor $Z1,$Z2,$Z2 + vpclmulqdq \$0x00,$Hkey,$Ii,$Z1 + vpxor $Z0,$Xi,$Xi # modulo-scheduled + vaesenc $T2,$inout4,$inout4 + vpxor $Z1,$T1,$Z0 + and \$0x60,%r12 + vmovups 0x20-0x80($key),$rndkey + vpclmulqdq \$0x10,$Hkey,$Ii,$T1 + vaesenc $T2,$inout5,$inout5 + + vpclmulqdq \$0x01,$Hkey,$Ii,$T2 + lea ($in0,%r12),$in0 + vaesenc $rndkey,$inout0,$inout0 + vpxor 16+8(%rsp),$Xi,$Xi # modulo-scheduled [vpxor $Z3,$Xi,$Xi] + vpclmulqdq \$0x11,$Hkey,$Ii,$Hkey + vmovdqu 0x40+8(%rsp),$Ii # I[3] + vaesenc $rndkey,$inout1,$inout1 + movbe 0x58($in0),%r13 + vaesenc $rndkey,$inout2,$inout2 + movbe 0x50($in0),%r12 + vaesenc $rndkey,$inout3,$inout3 + mov %r13,0x20+8(%rsp) + vaesenc $rndkey,$inout4,$inout4 + mov %r12,0x28+8(%rsp) + vmovdqu 0x30-0x20($Xip),$Z1 # borrow $Z1 for $Hkey^3 + vaesenc $rndkey,$inout5,$inout5 + + vmovups 0x30-0x80($key),$rndkey + vpxor $T1,$Z2,$Z2 + vpclmulqdq \$0x00,$Z1,$Ii,$T1 + vaesenc $rndkey,$inout0,$inout0 + vpxor $T2,$Z2,$Z2 + vpclmulqdq \$0x10,$Z1,$Ii,$T2 + vaesenc $rndkey,$inout1,$inout1 + vpxor $Hkey,$Z3,$Z3 + vpclmulqdq \$0x01,$Z1,$Ii,$Hkey + vaesenc $rndkey,$inout2,$inout2 + vpclmulqdq \$0x11,$Z1,$Ii,$Z1 + vmovdqu 0x50+8(%rsp),$Ii # I[2] + vaesenc $rndkey,$inout3,$inout3 + vaesenc $rndkey,$inout4,$inout4 + vpxor $T1,$Z0,$Z0 + vmovdqu 0x40-0x20($Xip),$T1 # borrow $T1 for $Hkey^4 + vaesenc $rndkey,$inout5,$inout5 + + vmovups 0x40-0x80($key),$rndkey + vpxor $T2,$Z2,$Z2 + vpclmulqdq \$0x00,$T1,$Ii,$T2 + vaesenc $rndkey,$inout0,$inout0 + vpxor $Hkey,$Z2,$Z2 + vpclmulqdq \$0x10,$T1,$Ii,$Hkey + vaesenc $rndkey,$inout1,$inout1 + movbe 0x48($in0),%r13 + vpxor $Z1,$Z3,$Z3 + vpclmulqdq \$0x01,$T1,$Ii,$Z1 + vaesenc $rndkey,$inout2,$inout2 + movbe 0x40($in0),%r12 + vpclmulqdq \$0x11,$T1,$Ii,$T1 + vmovdqu 0x60+8(%rsp),$Ii # I[1] + vaesenc $rndkey,$inout3,$inout3 + mov %r13,0x30+8(%rsp) + vaesenc $rndkey,$inout4,$inout4 + mov %r12,0x38+8(%rsp) + vpxor $T2,$Z0,$Z0 + vmovdqu 0x60-0x20($Xip),$T2 # borrow $T2 for $Hkey^5 + vaesenc $rndkey,$inout5,$inout5 + + vmovups 0x50-0x80($key),$rndkey + vpxor $Hkey,$Z2,$Z2 + vpclmulqdq \$0x00,$T2,$Ii,$Hkey + vaesenc $rndkey,$inout0,$inout0 + vpxor $Z1,$Z2,$Z2 + vpclmulqdq \$0x10,$T2,$Ii,$Z1 + vaesenc $rndkey,$inout1,$inout1 + movbe 0x38($in0),%r13 + vpxor $T1,$Z3,$Z3 + vpclmulqdq \$0x01,$T2,$Ii,$T1 + vpxor 0x70+8(%rsp),$Xi,$Xi # accumulate I[0] + vaesenc $rndkey,$inout2,$inout2 + movbe 0x30($in0),%r12 + vpclmulqdq \$0x11,$T2,$Ii,$T2 + vaesenc $rndkey,$inout3,$inout3 + mov %r13,0x40+8(%rsp) + vaesenc $rndkey,$inout4,$inout4 + mov %r12,0x48+8(%rsp) + vpxor $Hkey,$Z0,$Z0 + vmovdqu 0x70-0x20($Xip),$Hkey # $Hkey^6 + vaesenc $rndkey,$inout5,$inout5 + + vmovups 0x60-0x80($key),$rndkey + vpxor $Z1,$Z2,$Z2 + vpclmulqdq \$0x10,$Hkey,$Xi,$Z1 + vaesenc $rndkey,$inout0,$inout0 + vpxor $T1,$Z2,$Z2 + vpclmulqdq \$0x01,$Hkey,$Xi,$T1 + vaesenc $rndkey,$inout1,$inout1 + movbe 0x28($in0),%r13 + vpxor $T2,$Z3,$Z3 + vpclmulqdq \$0x00,$Hkey,$Xi,$T2 + vaesenc $rndkey,$inout2,$inout2 + movbe 0x20($in0),%r12 + vpclmulqdq \$0x11,$Hkey,$Xi,$Xi + vaesenc $rndkey,$inout3,$inout3 + mov %r13,0x50+8(%rsp) + vaesenc $rndkey,$inout4,$inout4 + mov %r12,0x58+8(%rsp) + vpxor $Z1,$Z2,$Z2 + vaesenc $rndkey,$inout5,$inout5 + vpxor $T1,$Z2,$Z2 + + vmovups 0x70-0x80($key),$rndkey + vpslldq \$8,$Z2,$Z1 + vpxor $T2,$Z0,$Z0 + vmovdqu 0x10($const),$Hkey # .Lpoly + + vaesenc $rndkey,$inout0,$inout0 + vpxor $Xi,$Z3,$Z3 + vaesenc $rndkey,$inout1,$inout1 + vpxor $Z1,$Z0,$Z0 + movbe 0x18($in0),%r13 + vaesenc $rndkey,$inout2,$inout2 + movbe 0x10($in0),%r12 + vpalignr \$8,$Z0,$Z0,$Ii # 1st phase + vpclmulqdq \$0x10,$Hkey,$Z0,$Z0 + mov %r13,0x60+8(%rsp) + vaesenc $rndkey,$inout3,$inout3 + mov %r12,0x68+8(%rsp) + vaesenc $rndkey,$inout4,$inout4 + vmovups 0x80-0x80($key),$T1 # borrow $T1 for $rndkey + vaesenc $rndkey,$inout5,$inout5 + + vaesenc $T1,$inout0,$inout0 + vmovups 0x90-0x80($key),$rndkey + vaesenc $T1,$inout1,$inout1 + vpsrldq \$8,$Z2,$Z2 + vaesenc $T1,$inout2,$inout2 + vpxor $Z2,$Z3,$Z3 + vaesenc $T1,$inout3,$inout3 + vpxor $Ii,$Z0,$Z0 + movbe 0x08($in0),%r13 + vaesenc $T1,$inout4,$inout4 + movbe 0x00($in0),%r12 + vaesenc $T1,$inout5,$inout5 + vmovups 0xa0-0x80($key),$T1 + cmp \$11,$rounds + jb .Lenc_tail # 128-bit key + + vaesenc $rndkey,$inout0,$inout0 + vaesenc $rndkey,$inout1,$inout1 + vaesenc $rndkey,$inout2,$inout2 + vaesenc $rndkey,$inout3,$inout3 + vaesenc $rndkey,$inout4,$inout4 + vaesenc $rndkey,$inout5,$inout5 + + vaesenc $T1,$inout0,$inout0 + vaesenc $T1,$inout1,$inout1 + vaesenc $T1,$inout2,$inout2 + vaesenc $T1,$inout3,$inout3 + vaesenc $T1,$inout4,$inout4 + vmovups 0xb0-0x80($key),$rndkey + vaesenc $T1,$inout5,$inout5 + vmovups 0xc0-0x80($key),$T1 + je .Lenc_tail # 192-bit key + + vaesenc $rndkey,$inout0,$inout0 + vaesenc $rndkey,$inout1,$inout1 + vaesenc $rndkey,$inout2,$inout2 + vaesenc $rndkey,$inout3,$inout3 + vaesenc $rndkey,$inout4,$inout4 + vaesenc $rndkey,$inout5,$inout5 + + vaesenc $T1,$inout0,$inout0 + vaesenc $T1,$inout1,$inout1 + vaesenc $T1,$inout2,$inout2 + vaesenc $T1,$inout3,$inout3 + vaesenc $T1,$inout4,$inout4 + vmovups 0xd0-0x80($key),$rndkey + vaesenc $T1,$inout5,$inout5 + vmovups 0xe0-0x80($key),$T1 + jmp .Lenc_tail # 256-bit key + +.align 32 +.Lhandle_ctr32: + vmovdqu ($const),$Ii # borrow $Ii for .Lbswap_mask + vpshufb $Ii,$T1,$Z2 # byte-swap counter + vmovdqu 0x30($const),$Z1 # borrow $Z1, .Ltwo_lsb + vpaddd 0x40($const),$Z2,$inout1 # .Lone_lsb + vpaddd $Z1,$Z2,$inout2 + vmovdqu 0x00-0x20($Xip),$Hkey # $Hkey^1 + vpaddd $Z1,$inout1,$inout3 + vpshufb $Ii,$inout1,$inout1 + vpaddd $Z1,$inout2,$inout4 + vpshufb $Ii,$inout2,$inout2 + vpxor $rndkey,$inout1,$inout1 + vpaddd $Z1,$inout3,$inout5 + vpshufb $Ii,$inout3,$inout3 + vpxor $rndkey,$inout2,$inout2 + vpaddd $Z1,$inout4,$T1 # byte-swapped next counter value + vpshufb $Ii,$inout4,$inout4 + vpshufb $Ii,$inout5,$inout5 + vpshufb $Ii,$T1,$T1 # next counter value + jmp .Lresume_ctr32 + +.align 32 +.Lenc_tail: + vaesenc $rndkey,$inout0,$inout0 + vmovdqu $Z3,16+8(%rsp) # postpone vpxor $Z3,$Xi,$Xi + vpalignr \$8,$Z0,$Z0,$Xi # 2nd phase + vaesenc $rndkey,$inout1,$inout1 + vpclmulqdq \$0x10,$Hkey,$Z0,$Z0 + vpxor 0x00($inp),$T1,$T2 + vaesenc $rndkey,$inout2,$inout2 + vpxor 0x10($inp),$T1,$Ii + vaesenc $rndkey,$inout3,$inout3 + vpxor 0x20($inp),$T1,$Z1 + vaesenc $rndkey,$inout4,$inout4 + vpxor 0x30($inp),$T1,$Z2 + vaesenc $rndkey,$inout5,$inout5 + vpxor 0x40($inp),$T1,$Z3 + vpxor 0x50($inp),$T1,$Hkey + vmovdqu ($ivp),$T1 # load next counter value + + vaesenclast $T2,$inout0,$inout0 + vmovdqu 0x20($const),$T2 # borrow $T2, .Lone_msb + vaesenclast $Ii,$inout1,$inout1 + vpaddb $T2,$T1,$Ii + mov %r13,0x70+8(%rsp) + lea 0x60($inp),$inp + vaesenclast $Z1,$inout2,$inout2 + vpaddb $T2,$Ii,$Z1 + mov %r12,0x78+8(%rsp) + lea 0x60($out),$out + vmovdqu 0x00-0x80($key),$rndkey + vaesenclast $Z2,$inout3,$inout3 + vpaddb $T2,$Z1,$Z2 + vaesenclast $Z3, $inout4,$inout4 + vpaddb $T2,$Z2,$Z3 + vaesenclast $Hkey,$inout5,$inout5 + vpaddb $T2,$Z3,$Hkey + + add \$0x60,$ret + sub \$0x6,$len + jc .L6x_done + + vmovups $inout0,-0x60($out) # save output + vpxor $rndkey,$T1,$inout0 + vmovups $inout1,-0x50($out) + vmovdqa $Ii,$inout1 # 0 latency + vmovups $inout2,-0x40($out) + vmovdqa $Z1,$inout2 # 0 latency + vmovups $inout3,-0x30($out) + vmovdqa $Z2,$inout3 # 0 latency + vmovups $inout4,-0x20($out) + vmovdqa $Z3,$inout4 # 0 latency + vmovups $inout5,-0x10($out) + vmovdqa $Hkey,$inout5 # 0 latency + vmovdqu 0x20+8(%rsp),$Z3 # I[5] + jmp .Loop6x + +.L6x_done: + vpxor 16+8(%rsp),$Xi,$Xi # modulo-scheduled + vpxor $Z0,$Xi,$Xi # modulo-scheduled + + ret +.size _aesni_ctr32_ghash_6x,.-_aesni_ctr32_ghash_6x +___ +###################################################################### +# +# size_t aesni_gcm_[en|de]crypt(const void *inp, void *out, size_t len, +# const AES_KEY *key, unsigned char iv[16], +# struct { u128 Xi,H,Htbl[9]; } *Xip); +$code.=<<___; +.globl aesni_gcm_decrypt +.type aesni_gcm_decrypt,\@function,6 +.align 32 +aesni_gcm_decrypt: + xor $ret,$ret + cmp \$0x60,$len # minimal accepted length + jb .Lgcm_dec_abort + + lea (%rsp),%rax # save stack pointer + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 +___ +$code.=<<___ if ($win64); + lea -0xa8(%rsp),%rsp + movaps %xmm6,-0xd8(%rax) + movaps %xmm7,-0xc8(%rax) + movaps %xmm8,-0xb8(%rax) + movaps %xmm9,-0xa8(%rax) + movaps %xmm10,-0x98(%rax) + movaps %xmm11,-0x88(%rax) + movaps %xmm12,-0x78(%rax) + movaps %xmm13,-0x68(%rax) + movaps %xmm14,-0x58(%rax) + movaps %xmm15,-0x48(%rax) +.Lgcm_dec_body: +___ +$code.=<<___; + vzeroupper + + vmovdqu ($ivp),$T1 # input counter value + add \$-128,%rsp + mov 12($ivp),$counter + lea .Lbswap_mask(%rip),$const + lea -0x80($key),$in0 # borrow $in0 + mov \$0xf80,$end0 # borrow $end0 + vmovdqu ($Xip),$Xi # load Xi + and \$-128,%rsp # ensure stack alignment + vmovdqu ($const),$Ii # borrow $Ii for .Lbswap_mask + lea 0x80($key),$key # size optimization + lea 0x20+0x20($Xip),$Xip # size optimization + mov 0xf0-0x80($key),$rounds + vpshufb $Ii,$Xi,$Xi + + and $end0,$in0 + and %rsp,$end0 + sub $in0,$end0 + jc .Ldec_no_key_aliasing + cmp \$768,$end0 + jnc .Ldec_no_key_aliasing + sub $end0,%rsp # avoid aliasing with key +.Ldec_no_key_aliasing: + + vmovdqu 0x50($inp),$Z3 # I[5] + lea ($inp),$in0 + vmovdqu 0x40($inp),$Z0 + lea -0xc0($inp,$len),$end0 + vmovdqu 0x30($inp),$Z1 + shr \$4,$len + xor $ret,$ret + vmovdqu 0x20($inp),$Z2 + vpshufb $Ii,$Z3,$Z3 # passed to _aesni_ctr32_ghash_6x + vmovdqu 0x10($inp),$T2 + vpshufb $Ii,$Z0,$Z0 + vmovdqu ($inp),$Hkey + vpshufb $Ii,$Z1,$Z1 + vmovdqu $Z0,0x30(%rsp) + vpshufb $Ii,$Z2,$Z2 + vmovdqu $Z1,0x40(%rsp) + vpshufb $Ii,$T2,$T2 + vmovdqu $Z2,0x50(%rsp) + vpshufb $Ii,$Hkey,$Hkey + vmovdqu $T2,0x60(%rsp) + vmovdqu $Hkey,0x70(%rsp) + + call _aesni_ctr32_ghash_6x + + vmovups $inout0,-0x60($out) # save output + vmovups $inout1,-0x50($out) + vmovups $inout2,-0x40($out) + vmovups $inout3,-0x30($out) + vmovups $inout4,-0x20($out) + vmovups $inout5,-0x10($out) + + vpshufb ($const),$Xi,$Xi # .Lbswap_mask + vmovdqu $Xi,-0x40($Xip) # output Xi + + vzeroupper +___ +$code.=<<___ if ($win64); + movaps -0xd8(%rax),%xmm6 + movaps -0xd8(%rax),%xmm7 + movaps -0xb8(%rax),%xmm8 + movaps -0xa8(%rax),%xmm9 + movaps -0x98(%rax),%xmm10 + movaps -0x88(%rax),%xmm11 + movaps -0x78(%rax),%xmm12 + movaps -0x68(%rax),%xmm13 + movaps -0x58(%rax),%xmm14 + movaps -0x48(%rax),%xmm15 +___ +$code.=<<___; + mov -48(%rax),%r15 + mov -40(%rax),%r14 + mov -32(%rax),%r13 + mov -24(%rax),%r12 + mov -16(%rax),%rbp + mov -8(%rax),%rbx + lea (%rax),%rsp # restore %rsp +.Lgcm_dec_abort: + mov $ret,%rax # return value + ret +.size aesni_gcm_decrypt,.-aesni_gcm_decrypt +___ + +$code.=<<___; +.type _aesni_ctr32_6x,\@abi-omnipotent +.align 32 +_aesni_ctr32_6x: + vmovdqu 0x00-0x80($key),$Z0 # borrow $Z0 for $rndkey + vmovdqu 0x20($const),$T2 # borrow $T2, .Lone_msb + lea -1($rounds),%r13 + vmovups 0x10-0x80($key),$rndkey + lea 0x20-0x80($key),%r12 + vpxor $Z0,$T1,$inout0 + add \$`6<<24`,$counter + jc .Lhandle_ctr32_2 + vpaddb $T2,$T1,$inout1 + vpaddb $T2,$inout1,$inout2 + vpxor $Z0,$inout1,$inout1 + vpaddb $T2,$inout2,$inout3 + vpxor $Z0,$inout2,$inout2 + vpaddb $T2,$inout3,$inout4 + vpxor $Z0,$inout3,$inout3 + vpaddb $T2,$inout4,$inout5 + vpxor $Z0,$inout4,$inout4 + vpaddb $T2,$inout5,$T1 + vpxor $Z0,$inout5,$inout5 + jmp .Loop_ctr32 + +.align 16 +.Loop_ctr32: + vaesenc $rndkey,$inout0,$inout0 + vaesenc $rndkey,$inout1,$inout1 + vaesenc $rndkey,$inout2,$inout2 + vaesenc $rndkey,$inout3,$inout3 + vaesenc $rndkey,$inout4,$inout4 + vaesenc $rndkey,$inout5,$inout5 + vmovups (%r12),$rndkey + lea 0x10(%r12),%r12 + dec %r13d + jnz .Loop_ctr32 + + vmovdqu (%r12),$Hkey # last round key + vaesenc $rndkey,$inout0,$inout0 + vpxor 0x00($inp),$Hkey,$Z0 + vaesenc $rndkey,$inout1,$inout1 + vpxor 0x10($inp),$Hkey,$Z1 + vaesenc $rndkey,$inout2,$inout2 + vpxor 0x20($inp),$Hkey,$Z2 + vaesenc $rndkey,$inout3,$inout3 + vpxor 0x30($inp),$Hkey,$Xi + vaesenc $rndkey,$inout4,$inout4 + vpxor 0x40($inp),$Hkey,$T2 + vaesenc $rndkey,$inout5,$inout5 + vpxor 0x50($inp),$Hkey,$Hkey + lea 0x60($inp),$inp + + vaesenclast $Z0,$inout0,$inout0 + vaesenclast $Z1,$inout1,$inout1 + vaesenclast $Z2,$inout2,$inout2 + vaesenclast $Xi,$inout3,$inout3 + vaesenclast $T2,$inout4,$inout4 + vaesenclast $Hkey,$inout5,$inout5 + vmovups $inout0,0x00($out) + vmovups $inout1,0x10($out) + vmovups $inout2,0x20($out) + vmovups $inout3,0x30($out) + vmovups $inout4,0x40($out) + vmovups $inout5,0x50($out) + lea 0x60($out),$out + + ret +.align 32 +.Lhandle_ctr32_2: + vpshufb $Ii,$T1,$Z2 # byte-swap counter + vmovdqu 0x30($const),$Z1 # borrow $Z1, .Ltwo_lsb + vpaddd 0x40($const),$Z2,$inout1 # .Lone_lsb + vpaddd $Z1,$Z2,$inout2 + vpaddd $Z1,$inout1,$inout3 + vpshufb $Ii,$inout1,$inout1 + vpaddd $Z1,$inout2,$inout4 + vpshufb $Ii,$inout2,$inout2 + vpxor $Z0,$inout1,$inout1 + vpaddd $Z1,$inout3,$inout5 + vpshufb $Ii,$inout3,$inout3 + vpxor $Z0,$inout2,$inout2 + vpaddd $Z1,$inout4,$T1 # byte-swapped next counter value + vpshufb $Ii,$inout4,$inout4 + vpxor $Z0,$inout3,$inout3 + vpshufb $Ii,$inout5,$inout5 + vpxor $Z0,$inout4,$inout4 + vpshufb $Ii,$T1,$T1 # next counter value + vpxor $Z0,$inout5,$inout5 + jmp .Loop_ctr32 +.size _aesni_ctr32_6x,.-_aesni_ctr32_6x + +.globl aesni_gcm_encrypt +.type aesni_gcm_encrypt,\@function,6 +.align 32 +aesni_gcm_encrypt: + xor $ret,$ret + cmp \$0x60*3,$len # minimal accepted length + jb .Lgcm_enc_abort + + lea (%rsp),%rax # save stack pointer + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 +___ +$code.=<<___ if ($win64); + lea -0xa8(%rsp),%rsp + movaps %xmm6,-0xd8(%rax) + movaps %xmm7,-0xc8(%rax) + movaps %xmm8,-0xb8(%rax) + movaps %xmm9,-0xa8(%rax) + movaps %xmm10,-0x98(%rax) + movaps %xmm11,-0x88(%rax) + movaps %xmm12,-0x78(%rax) + movaps %xmm13,-0x68(%rax) + movaps %xmm14,-0x58(%rax) + movaps %xmm15,-0x48(%rax) +.Lgcm_enc_body: +___ +$code.=<<___; + vzeroupper + + vmovdqu ($ivp),$T1 # input counter value + add \$-128,%rsp + mov 12($ivp),$counter + lea .Lbswap_mask(%rip),$const + lea -0x80($key),$in0 # borrow $in0 + mov \$0xf80,$end0 # borrow $end0 + lea 0x80($key),$key # size optimization + vmovdqu ($const),$Ii # borrow $Ii for .Lbswap_mask + and \$-128,%rsp # ensure stack alignment + mov 0xf0-0x80($key),$rounds + + and $end0,$in0 + and %rsp,$end0 + sub $in0,$end0 + jc .Lenc_no_key_aliasing + cmp \$768,$end0 + jnc .Lenc_no_key_aliasing + sub $end0,%rsp # avoid aliasing with key +.Lenc_no_key_aliasing: + + lea ($out),$in0 + lea -0xc0($out,$len),$end0 + shr \$4,$len + + call _aesni_ctr32_6x + vpshufb $Ii,$inout0,$Xi # save bswapped output on stack + vpshufb $Ii,$inout1,$T2 + vmovdqu $Xi,0x70(%rsp) + vpshufb $Ii,$inout2,$Z0 + vmovdqu $T2,0x60(%rsp) + vpshufb $Ii,$inout3,$Z1 + vmovdqu $Z0,0x50(%rsp) + vpshufb $Ii,$inout4,$Z2 + vmovdqu $Z1,0x40(%rsp) + vpshufb $Ii,$inout5,$Z3 # passed to _aesni_ctr32_ghash_6x + vmovdqu $Z2,0x30(%rsp) + + call _aesni_ctr32_6x + + vmovdqu ($Xip),$Xi # load Xi + lea 0x20+0x20($Xip),$Xip # size optimization + sub \$12,$len + mov \$0x60*2,$ret + vpshufb $Ii,$Xi,$Xi + + call _aesni_ctr32_ghash_6x + vmovdqu 0x20(%rsp),$Z3 # I[5] + vmovdqu ($const),$Ii # borrow $Ii for .Lbswap_mask + vmovdqu 0x00-0x20($Xip),$Hkey # $Hkey^1 + vpunpckhqdq $Z3,$Z3,$T1 + vmovdqu 0x20-0x20($Xip),$rndkey # borrow $rndkey for $HK + vmovups $inout0,-0x60($out) # save output + vpshufb $Ii,$inout0,$inout0 # but keep bswapped copy + vpxor $Z3,$T1,$T1 + vmovups $inout1,-0x50($out) + vpshufb $Ii,$inout1,$inout1 + vmovups $inout2,-0x40($out) + vpshufb $Ii,$inout2,$inout2 + vmovups $inout3,-0x30($out) + vpshufb $Ii,$inout3,$inout3 + vmovups $inout4,-0x20($out) + vpshufb $Ii,$inout4,$inout4 + vmovups $inout5,-0x10($out) + vpshufb $Ii,$inout5,$inout5 + vmovdqu $inout0,0x10(%rsp) # free $inout0 +___ +{ my ($HK,$T3)=($rndkey,$inout0); + +$code.=<<___; + vmovdqu 0x30(%rsp),$Z2 # I[4] + vmovdqu 0x10-0x20($Xip),$Ii # borrow $Ii for $Hkey^2 + vpunpckhqdq $Z2,$Z2,$T2 + vpclmulqdq \$0x00,$Hkey,$Z3,$Z1 + vpxor $Z2,$T2,$T2 + vpclmulqdq \$0x11,$Hkey,$Z3,$Z3 + vpclmulqdq \$0x00,$HK,$T1,$T1 + + vmovdqu 0x40(%rsp),$T3 # I[3] + vpclmulqdq \$0x00,$Ii,$Z2,$Z0 + vmovdqu 0x30-0x20($Xip),$Hkey # $Hkey^3 + vpxor $Z1,$Z0,$Z0 + vpunpckhqdq $T3,$T3,$Z1 + vpclmulqdq \$0x11,$Ii,$Z2,$Z2 + vpxor $T3,$Z1,$Z1 + vpxor $Z3,$Z2,$Z2 + vpclmulqdq \$0x10,$HK,$T2,$T2 + vmovdqu 0x50-0x20($Xip),$HK + vpxor $T1,$T2,$T2 + + vmovdqu 0x50(%rsp),$T1 # I[2] + vpclmulqdq \$0x00,$Hkey,$T3,$Z3 + vmovdqu 0x40-0x20($Xip),$Ii # borrow $Ii for $Hkey^4 + vpxor $Z0,$Z3,$Z3 + vpunpckhqdq $T1,$T1,$Z0 + vpclmulqdq \$0x11,$Hkey,$T3,$T3 + vpxor $T1,$Z0,$Z0 + vpxor $Z2,$T3,$T3 + vpclmulqdq \$0x00,$HK,$Z1,$Z1 + vpxor $T2,$Z1,$Z1 + + vmovdqu 0x60(%rsp),$T2 # I[1] + vpclmulqdq \$0x00,$Ii,$T1,$Z2 + vmovdqu 0x60-0x20($Xip),$Hkey # $Hkey^5 + vpxor $Z3,$Z2,$Z2 + vpunpckhqdq $T2,$T2,$Z3 + vpclmulqdq \$0x11,$Ii,$T1,$T1 + vpxor $T2,$Z3,$Z3 + vpxor $T3,$T1,$T1 + vpclmulqdq \$0x10,$HK,$Z0,$Z0 + vmovdqu 0x80-0x20($Xip),$HK + vpxor $Z1,$Z0,$Z0 + + vpxor 0x70(%rsp),$Xi,$Xi # accumulate I[0] + vpclmulqdq \$0x00,$Hkey,$T2,$Z1 + vmovdqu 0x70-0x20($Xip),$Ii # borrow $Ii for $Hkey^6 + vpunpckhqdq $Xi,$Xi,$T3 + vpxor $Z2,$Z1,$Z1 + vpclmulqdq \$0x11,$Hkey,$T2,$T2 + vpxor $Xi,$T3,$T3 + vpxor $T1,$T2,$T2 + vpclmulqdq \$0x00,$HK,$Z3,$Z3 + vpxor $Z0,$Z3,$Z0 + + vpclmulqdq \$0x00,$Ii,$Xi,$Z2 + vmovdqu 0x00-0x20($Xip),$Hkey # $Hkey^1 + vpunpckhqdq $inout5,$inout5,$T1 + vpclmulqdq \$0x11,$Ii,$Xi,$Xi + vpxor $inout5,$T1,$T1 + vpxor $Z1,$Z2,$Z1 + vpclmulqdq \$0x10,$HK,$T3,$T3 + vmovdqu 0x20-0x20($Xip),$HK + vpxor $T2,$Xi,$Z3 + vpxor $Z0,$T3,$Z2 + + vmovdqu 0x10-0x20($Xip),$Ii # borrow $Ii for $Hkey^2 + vpxor $Z1,$Z3,$T3 # aggregated Karatsuba post-processing + vpclmulqdq \$0x00,$Hkey,$inout5,$Z0 + vpxor $T3,$Z2,$Z2 + vpunpckhqdq $inout4,$inout4,$T2 + vpclmulqdq \$0x11,$Hkey,$inout5,$inout5 + vpxor $inout4,$T2,$T2 + vpslldq \$8,$Z2,$T3 + vpclmulqdq \$0x00,$HK,$T1,$T1 + vpxor $T3,$Z1,$Xi + vpsrldq \$8,$Z2,$Z2 + vpxor $Z2,$Z3,$Z3 + + vpclmulqdq \$0x00,$Ii,$inout4,$Z1 + vmovdqu 0x30-0x20($Xip),$Hkey # $Hkey^3 + vpxor $Z0,$Z1,$Z1 + vpunpckhqdq $inout3,$inout3,$T3 + vpclmulqdq \$0x11,$Ii,$inout4,$inout4 + vpxor $inout3,$T3,$T3 + vpxor $inout5,$inout4,$inout4 + vpalignr \$8,$Xi,$Xi,$inout5 # 1st phase + vpclmulqdq \$0x10,$HK,$T2,$T2 + vmovdqu 0x50-0x20($Xip),$HK + vpxor $T1,$T2,$T2 + + vpclmulqdq \$0x00,$Hkey,$inout3,$Z0 + vmovdqu 0x40-0x20($Xip),$Ii # borrow $Ii for $Hkey^4 + vpxor $Z1,$Z0,$Z0 + vpunpckhqdq $inout2,$inout2,$T1 + vpclmulqdq \$0x11,$Hkey,$inout3,$inout3 + vpxor $inout2,$T1,$T1 + vpxor $inout4,$inout3,$inout3 + vxorps 0x10(%rsp),$Z3,$Z3 # accumulate $inout0 + vpclmulqdq \$0x00,$HK,$T3,$T3 + vpxor $T2,$T3,$T3 + + vpclmulqdq \$0x10,0x10($const),$Xi,$Xi + vxorps $inout5,$Xi,$Xi + + vpclmulqdq \$0x00,$Ii,$inout2,$Z1 + vmovdqu 0x60-0x20($Xip),$Hkey # $Hkey^5 + vpxor $Z0,$Z1,$Z1 + vpunpckhqdq $inout1,$inout1,$T2 + vpclmulqdq \$0x11,$Ii,$inout2,$inout2 + vpxor $inout1,$T2,$T2 + vpalignr \$8,$Xi,$Xi,$inout5 # 2nd phase + vpxor $inout3,$inout2,$inout2 + vpclmulqdq \$0x10,$HK,$T1,$T1 + vmovdqu 0x80-0x20($Xip),$HK + vpxor $T3,$T1,$T1 + + vxorps $Z3,$inout5,$inout5 + vpclmulqdq \$0x10,0x10($const),$Xi,$Xi + vxorps $inout5,$Xi,$Xi + + vpclmulqdq \$0x00,$Hkey,$inout1,$Z0 + vmovdqu 0x70-0x20($Xip),$Ii # borrow $Ii for $Hkey^6 + vpxor $Z1,$Z0,$Z0 + vpunpckhqdq $Xi,$Xi,$T3 + vpclmulqdq \$0x11,$Hkey,$inout1,$inout1 + vpxor $Xi,$T3,$T3 + vpxor $inout2,$inout1,$inout1 + vpclmulqdq \$0x00,$HK,$T2,$T2 + vpxor $T1,$T2,$T2 + + vpclmulqdq \$0x00,$Ii,$Xi,$Z1 + vpclmulqdq \$0x11,$Ii,$Xi,$Z3 + vpxor $Z0,$Z1,$Z1 + vpclmulqdq \$0x10,$HK,$T3,$Z2 + vpxor $inout1,$Z3,$Z3 + vpxor $T2,$Z2,$Z2 + + vpxor $Z1,$Z3,$Z0 # aggregated Karatsuba post-processing + vpxor $Z0,$Z2,$Z2 + vpslldq \$8,$Z2,$T1 + vmovdqu 0x10($const),$Hkey # .Lpoly + vpsrldq \$8,$Z2,$Z2 + vpxor $T1,$Z1,$Xi + vpxor $Z2,$Z3,$Z3 + + vpalignr \$8,$Xi,$Xi,$T2 # 1st phase + vpclmulqdq \$0x10,$Hkey,$Xi,$Xi + vpxor $T2,$Xi,$Xi + + vpalignr \$8,$Xi,$Xi,$T2 # 2nd phase + vpclmulqdq \$0x10,$Hkey,$Xi,$Xi + vpxor $Z3,$T2,$T2 + vpxor $T2,$Xi,$Xi +___ +} +$code.=<<___; + vpshufb ($const),$Xi,$Xi # .Lbswap_mask + vmovdqu $Xi,-0x40($Xip) # output Xi + + vzeroupper +___ +$code.=<<___ if ($win64); + movaps -0xd8(%rax),%xmm6 + movaps -0xc8(%rax),%xmm7 + movaps -0xb8(%rax),%xmm8 + movaps -0xa8(%rax),%xmm9 + movaps -0x98(%rax),%xmm10 + movaps -0x88(%rax),%xmm11 + movaps -0x78(%rax),%xmm12 + movaps -0x68(%rax),%xmm13 + movaps -0x58(%rax),%xmm14 + movaps -0x48(%rax),%xmm15 +___ +$code.=<<___; + mov -48(%rax),%r15 + mov -40(%rax),%r14 + mov -32(%rax),%r13 + mov -24(%rax),%r12 + mov -16(%rax),%rbp + mov -8(%rax),%rbx + lea (%rax),%rsp # restore %rsp +.Lgcm_enc_abort: + mov $ret,%rax # return value + ret +.size aesni_gcm_encrypt,.-aesni_gcm_encrypt +___ + +$code.=<<___; +.align 64 +.Lbswap_mask: + .byte 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 +.Lpoly: + .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xc2 +.Lone_msb: + .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 +.Ltwo_lsb: + .byte 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +.Lone_lsb: + .byte 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +.asciz "AES-NI GCM module for x86_64, CRYPTOGAMS by " +.align 64 +___ +if ($win64) { +$rec="%rcx"; +$frame="%rdx"; +$context="%r8"; +$disp="%r9"; + +$code.=<<___ +.extern __imp_RtlVirtualUnwind +.type gcm_se_handler,\@abi-omnipotent +.align 16 +gcm_se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + mov 8($disp),%rsi # disp->ImageBase + mov 56($disp),%r11 # disp->HandlerData + + mov 0(%r11),%r10d # HandlerData[0] + lea (%rsi,%r10),%r10 # prologue label + cmp %r10,%rbx # context->RipRsp + + mov 4(%r11),%r10d # HandlerData[1] + lea (%rsi,%r10),%r10 # epilogue label + cmp %r10,%rbx # context->Rip>=epilogue label + jae .Lcommon_seh_tail + + mov 120($context),%rax # pull context->Rax + + mov -48(%rax),%r15 + mov -40(%rax),%r14 + mov -32(%rax),%r13 + mov -24(%rax),%r12 + mov -16(%rax),%rbp + mov -8(%rax),%rbx + mov %r15,240($context) + mov %r14,232($context) + mov %r13,224($context) + mov %r12,216($context) + mov %rbp,160($context) + mov %rbx,144($context) + + lea -0xd8(%rax),%rsi # %xmm save area + lea 512($context),%rdi # & context.Xmm6 + mov \$20,%ecx # 10*sizeof(%xmm0)/sizeof(%rax) + .long 0xa548f3fc # cld; rep movsq + +.Lcommon_seh_tail: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + + mov 40($disp),%rdi # disp->ContextRecord + mov $context,%rsi # context + mov \$154,%ecx # sizeof(CONTEXT) + .long 0xa548f3fc # cld; rep movsq + + mov $disp,%rsi + xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER + mov 8(%rsi),%rdx # arg2, disp->ImageBase + mov 0(%rsi),%r8 # arg3, disp->ControlPc + mov 16(%rsi),%r9 # arg4, disp->FunctionEntry + mov 40(%rsi),%r10 # disp->ContextRecord + lea 56(%rsi),%r11 # &disp->HandlerData + lea 24(%rsi),%r12 # &disp->EstablisherFrame + mov %r10,32(%rsp) # arg5 + mov %r11,40(%rsp) # arg6 + mov %r12,48(%rsp) # arg7 + mov %rcx,56(%rsp) # arg8, (NULL) + call *__imp_RtlVirtualUnwind(%rip) + + mov \$1,%eax # ExceptionContinueSearch + add \$64,%rsp + popfq + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + pop %rdi + pop %rsi + ret +.size gcm_se_handler,.-gcm_se_handler + +.section .pdata +.align 4 + .rva .LSEH_begin_aesni_gcm_decrypt + .rva .LSEH_end_aesni_gcm_decrypt + .rva .LSEH_gcm_dec_info + + .rva .LSEH_begin_aesni_gcm_encrypt + .rva .LSEH_end_aesni_gcm_encrypt + .rva .LSEH_gcm_enc_info +.section .xdata +.align 8 +.LSEH_gcm_dec_info: + .byte 9,0,0,0 + .rva gcm_se_handler + .rva .Lgcm_dec_body,.Lgcm_dec_abort +.LSEH_gcm_enc_info: + .byte 9,0,0,0 + .rva gcm_se_handler + .rva .Lgcm_enc_body,.Lgcm_enc_abort +___ +} +}}} else {{{ +$code=<<___; # assembler is too old +.text + +.globl aesni_gcm_encrypt +.type aesni_gcm_encrypt,\@abi-omnipotent +aesni_gcm_encrypt: + xor %eax,%eax + ret +.size aesni_gcm_encrypt,.-aesni_gcm_encrypt + +.globl aesni_gcm_decrypt +.type aesni_gcm_decrypt,\@abi-omnipotent +aesni_gcm_decrypt: + xor %eax,%eax + ret +.size aesni_gcm_decrypt,.-aesni_gcm_decrypt +___ +}}} + +$code =~ s/\`([^\`]*)\`/eval($1)/gem; + +print $code; + +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/modes/asm/ghash-armv4.pl b/TMessagesProj/jni/boringssl/crypto/modes/asm/ghash-armv4.pl new file mode 100644 index 00000000..a0d04cec --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/modes/asm/ghash-armv4.pl @@ -0,0 +1,520 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# April 2010 +# +# The module implements "4-bit" GCM GHASH function and underlying +# single multiplication operation in GF(2^128). "4-bit" means that it +# uses 256 bytes per-key table [+32 bytes shared table]. There is no +# experimental performance data available yet. The only approximation +# that can be made at this point is based on code size. Inner loop is +# 32 instructions long and on single-issue core should execute in <40 +# cycles. Having verified that gcc 3.4 didn't unroll corresponding +# loop, this assembler loop body was found to be ~3x smaller than +# compiler-generated one... +# +# July 2010 +# +# Rescheduling for dual-issue pipeline resulted in 8.5% improvement on +# Cortex A8 core and ~25 cycles per processed byte (which was observed +# to be ~3 times faster than gcc-generated code:-) +# +# February 2011 +# +# Profiler-assisted and platform-specific optimization resulted in 7% +# improvement on Cortex A8 core and ~23.5 cycles per byte. +# +# March 2011 +# +# Add NEON implementation featuring polynomial multiplication, i.e. no +# lookup tables involved. On Cortex A8 it was measured to process one +# byte in 15 cycles or 55% faster than integer-only code. +# +# April 2014 +# +# Switch to multiplication algorithm suggested in paper referred +# below and combine it with reduction algorithm from x86 module. +# Performance improvement over previous version varies from 65% on +# Snapdragon S4 to 110% on Cortex A9. In absolute terms Cortex A8 +# processes one byte in 8.45 cycles, A9 - in 10.2, A15 - in 7.63, +# Snapdragon S4 - in 9.33. +# +# Câmara, D.; Gouvêa, C. P. L.; López, J. & Dahab, R.: Fast Software +# Polynomial Multiplication on ARM Processors using the NEON Engine. +# +# http://conradoplg.cryptoland.net/files/2010/12/mocrysen13.pdf + +# ==================================================================== +# Note about "528B" variant. In ARM case it makes lesser sense to +# implement it for following reasons: +# +# - performance improvement won't be anywhere near 50%, because 128- +# bit shift operation is neatly fused with 128-bit xor here, and +# "538B" variant would eliminate only 4-5 instructions out of 32 +# in the inner loop (meaning that estimated improvement is ~15%); +# - ARM-based systems are often embedded ones and extra memory +# consumption might be unappreciated (for so little improvement); +# +# Byte order [in]dependence. ========================================= +# +# Caller is expected to maintain specific *dword* order in Htable, +# namely with *least* significant dword of 128-bit value at *lower* +# address. This differs completely from C code and has everything to +# do with ldm instruction and order in which dwords are "consumed" by +# algorithm. *Byte* order within these dwords in turn is whatever +# *native* byte order on current platform. See gcm128.c for working +# example... + +$flavour = shift; +if ($flavour=~/^\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; } +else { while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {} } + +if ($flavour && $flavour ne "void") { + $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; + ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or + ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or + die "can't locate arm-xlate.pl"; + + open STDOUT,"| \"$^X\" $xlate $flavour $output"; +} else { + open STDOUT,">$output"; +} + +$Xi="r0"; # argument block +$Htbl="r1"; +$inp="r2"; +$len="r3"; + +$Zll="r4"; # variables +$Zlh="r5"; +$Zhl="r6"; +$Zhh="r7"; +$Tll="r8"; +$Tlh="r9"; +$Thl="r10"; +$Thh="r11"; +$nlo="r12"; +################# r13 is stack pointer +$nhi="r14"; +################# r15 is program counter + +$rem_4bit=$inp; # used in gcm_gmult_4bit +$cnt=$len; + +sub Zsmash() { + my $i=12; + my @args=@_; + for ($Zll,$Zlh,$Zhl,$Zhh) { + $code.=<<___; +#if __ARM_ARCH__>=7 && defined(__ARMEL__) + rev $_,$_ + str $_,[$Xi,#$i] +#elif defined(__ARMEB__) + str $_,[$Xi,#$i] +#else + mov $Tlh,$_,lsr#8 + strb $_,[$Xi,#$i+3] + mov $Thl,$_,lsr#16 + strb $Tlh,[$Xi,#$i+2] + mov $Thh,$_,lsr#24 + strb $Thl,[$Xi,#$i+1] + strb $Thh,[$Xi,#$i] +#endif +___ + $code.="\t".shift(@args)."\n"; + $i-=4; + } +} + +$code=<<___; +#if defined(__arm__) +#include "arm_arch.h" + +.syntax unified + +.text +.code 32 + +#ifdef __APPLE__ +#define ldrplb ldrbpl +#define ldrneb ldrbne +#endif + +.type rem_4bit,%object +.align 5 +rem_4bit: +.short 0x0000,0x1C20,0x3840,0x2460 +.short 0x7080,0x6CA0,0x48C0,0x54E0 +.short 0xE100,0xFD20,0xD940,0xC560 +.short 0x9180,0x8DA0,0xA9C0,0xB5E0 +.size rem_4bit,.-rem_4bit + +.type rem_4bit_get,%function +rem_4bit_get: + sub $rem_4bit,pc,#8 + sub $rem_4bit,$rem_4bit,#32 @ &rem_4bit + b .Lrem_4bit_got + nop +.size rem_4bit_get,.-rem_4bit_get + +.global gcm_ghash_4bit +.hidden gcm_ghash_4bit +.type gcm_ghash_4bit,%function +gcm_ghash_4bit: + sub r12,pc,#8 + add $len,$inp,$len @ $len to point at the end + stmdb sp!,{r3-r11,lr} @ save $len/end too + sub r12,r12,#48 @ &rem_4bit + + ldmia r12,{r4-r11} @ copy rem_4bit ... + stmdb sp!,{r4-r11} @ ... to stack + + ldrb $nlo,[$inp,#15] + ldrb $nhi,[$Xi,#15] +.Louter: + eor $nlo,$nlo,$nhi + and $nhi,$nlo,#0xf0 + and $nlo,$nlo,#0x0f + mov $cnt,#14 + + add $Zhh,$Htbl,$nlo,lsl#4 + ldmia $Zhh,{$Zll-$Zhh} @ load Htbl[nlo] + add $Thh,$Htbl,$nhi + ldrb $nlo,[$inp,#14] + + and $nhi,$Zll,#0xf @ rem + ldmia $Thh,{$Tll-$Thh} @ load Htbl[nhi] + add $nhi,$nhi,$nhi + eor $Zll,$Tll,$Zll,lsr#4 + ldrh $Tll,[sp,$nhi] @ rem_4bit[rem] + eor $Zll,$Zll,$Zlh,lsl#28 + ldrb $nhi,[$Xi,#14] + eor $Zlh,$Tlh,$Zlh,lsr#4 + eor $Zlh,$Zlh,$Zhl,lsl#28 + eor $Zhl,$Thl,$Zhl,lsr#4 + eor $Zhl,$Zhl,$Zhh,lsl#28 + eor $Zhh,$Thh,$Zhh,lsr#4 + eor $nlo,$nlo,$nhi + and $nhi,$nlo,#0xf0 + and $nlo,$nlo,#0x0f + eor $Zhh,$Zhh,$Tll,lsl#16 + +.Linner: + add $Thh,$Htbl,$nlo,lsl#4 + and $nlo,$Zll,#0xf @ rem + subs $cnt,$cnt,#1 + add $nlo,$nlo,$nlo + ldmia $Thh,{$Tll-$Thh} @ load Htbl[nlo] + eor $Zll,$Tll,$Zll,lsr#4 + eor $Zll,$Zll,$Zlh,lsl#28 + eor $Zlh,$Tlh,$Zlh,lsr#4 + eor $Zlh,$Zlh,$Zhl,lsl#28 + ldrh $Tll,[sp,$nlo] @ rem_4bit[rem] + eor $Zhl,$Thl,$Zhl,lsr#4 + ldrbpl $nlo,[$inp,$cnt] + eor $Zhl,$Zhl,$Zhh,lsl#28 + eor $Zhh,$Thh,$Zhh,lsr#4 + + add $Thh,$Htbl,$nhi + and $nhi,$Zll,#0xf @ rem + eor $Zhh,$Zhh,$Tll,lsl#16 @ ^= rem_4bit[rem] + add $nhi,$nhi,$nhi + ldmia $Thh,{$Tll-$Thh} @ load Htbl[nhi] + eor $Zll,$Tll,$Zll,lsr#4 + ldrbpl $Tll,[$Xi,$cnt] + eor $Zll,$Zll,$Zlh,lsl#28 + eor $Zlh,$Tlh,$Zlh,lsr#4 + ldrh $Tlh,[sp,$nhi] + eor $Zlh,$Zlh,$Zhl,lsl#28 + eor $Zhl,$Thl,$Zhl,lsr#4 + eor $Zhl,$Zhl,$Zhh,lsl#28 + eorpl $nlo,$nlo,$Tll + eor $Zhh,$Thh,$Zhh,lsr#4 + andpl $nhi,$nlo,#0xf0 + andpl $nlo,$nlo,#0x0f + eor $Zhh,$Zhh,$Tlh,lsl#16 @ ^= rem_4bit[rem] + bpl .Linner + + ldr $len,[sp,#32] @ re-load $len/end + add $inp,$inp,#16 + mov $nhi,$Zll +___ + &Zsmash("cmp\t$inp,$len","ldrbne\t$nlo,[$inp,#15]"); +$code.=<<___; + bne .Louter + + add sp,sp,#36 +#if __ARM_ARCH__>=5 + ldmia sp!,{r4-r11,pc} +#else + ldmia sp!,{r4-r11,lr} + tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet + bx lr @ interoperable with Thumb ISA:-) +#endif +.size gcm_ghash_4bit,.-gcm_ghash_4bit + +.global gcm_gmult_4bit +.hidden gcm_gmult_4bit +.type gcm_gmult_4bit,%function +gcm_gmult_4bit: + stmdb sp!,{r4-r11,lr} + ldrb $nlo,[$Xi,#15] + b rem_4bit_get +.Lrem_4bit_got: + and $nhi,$nlo,#0xf0 + and $nlo,$nlo,#0x0f + mov $cnt,#14 + + add $Zhh,$Htbl,$nlo,lsl#4 + ldmia $Zhh,{$Zll-$Zhh} @ load Htbl[nlo] + ldrb $nlo,[$Xi,#14] + + add $Thh,$Htbl,$nhi + and $nhi,$Zll,#0xf @ rem + ldmia $Thh,{$Tll-$Thh} @ load Htbl[nhi] + add $nhi,$nhi,$nhi + eor $Zll,$Tll,$Zll,lsr#4 + ldrh $Tll,[$rem_4bit,$nhi] @ rem_4bit[rem] + eor $Zll,$Zll,$Zlh,lsl#28 + eor $Zlh,$Tlh,$Zlh,lsr#4 + eor $Zlh,$Zlh,$Zhl,lsl#28 + eor $Zhl,$Thl,$Zhl,lsr#4 + eor $Zhl,$Zhl,$Zhh,lsl#28 + eor $Zhh,$Thh,$Zhh,lsr#4 + and $nhi,$nlo,#0xf0 + eor $Zhh,$Zhh,$Tll,lsl#16 + and $nlo,$nlo,#0x0f + +.Loop: + add $Thh,$Htbl,$nlo,lsl#4 + and $nlo,$Zll,#0xf @ rem + subs $cnt,$cnt,#1 + add $nlo,$nlo,$nlo + ldmia $Thh,{$Tll-$Thh} @ load Htbl[nlo] + eor $Zll,$Tll,$Zll,lsr#4 + eor $Zll,$Zll,$Zlh,lsl#28 + eor $Zlh,$Tlh,$Zlh,lsr#4 + eor $Zlh,$Zlh,$Zhl,lsl#28 + ldrh $Tll,[$rem_4bit,$nlo] @ rem_4bit[rem] + eor $Zhl,$Thl,$Zhl,lsr#4 + ldrbpl $nlo,[$Xi,$cnt] + eor $Zhl,$Zhl,$Zhh,lsl#28 + eor $Zhh,$Thh,$Zhh,lsr#4 + + add $Thh,$Htbl,$nhi + and $nhi,$Zll,#0xf @ rem + eor $Zhh,$Zhh,$Tll,lsl#16 @ ^= rem_4bit[rem] + add $nhi,$nhi,$nhi + ldmia $Thh,{$Tll-$Thh} @ load Htbl[nhi] + eor $Zll,$Tll,$Zll,lsr#4 + eor $Zll,$Zll,$Zlh,lsl#28 + eor $Zlh,$Tlh,$Zlh,lsr#4 + ldrh $Tll,[$rem_4bit,$nhi] @ rem_4bit[rem] + eor $Zlh,$Zlh,$Zhl,lsl#28 + eor $Zhl,$Thl,$Zhl,lsr#4 + eor $Zhl,$Zhl,$Zhh,lsl#28 + eor $Zhh,$Thh,$Zhh,lsr#4 + andpl $nhi,$nlo,#0xf0 + andpl $nlo,$nlo,#0x0f + eor $Zhh,$Zhh,$Tll,lsl#16 @ ^= rem_4bit[rem] + bpl .Loop +___ + &Zsmash(); +$code.=<<___; +#if __ARM_ARCH__>=5 + ldmia sp!,{r4-r11,pc} +#else + ldmia sp!,{r4-r11,lr} + tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet + bx lr @ interoperable with Thumb ISA:-) +#endif +.size gcm_gmult_4bit,.-gcm_gmult_4bit +___ +{ +my ($Xl,$Xm,$Xh,$IN)=map("q$_",(0..3)); +my ($t0,$t1,$t2,$t3)=map("q$_",(8..12)); +my ($Hlo,$Hhi,$Hhl,$k48,$k32,$k16)=map("d$_",(26..31)); + +sub clmul64x64 { +my ($r,$a,$b)=@_; +$code.=<<___; + vext.8 $t0#lo, $a, $a, #1 @ A1 + vmull.p8 $t0, $t0#lo, $b @ F = A1*B + vext.8 $r#lo, $b, $b, #1 @ B1 + vmull.p8 $r, $a, $r#lo @ E = A*B1 + vext.8 $t1#lo, $a, $a, #2 @ A2 + vmull.p8 $t1, $t1#lo, $b @ H = A2*B + vext.8 $t3#lo, $b, $b, #2 @ B2 + vmull.p8 $t3, $a, $t3#lo @ G = A*B2 + vext.8 $t2#lo, $a, $a, #3 @ A3 + veor $t0, $t0, $r @ L = E + F + vmull.p8 $t2, $t2#lo, $b @ J = A3*B + vext.8 $r#lo, $b, $b, #3 @ B3 + veor $t1, $t1, $t3 @ M = G + H + vmull.p8 $r, $a, $r#lo @ I = A*B3 + veor $t0#lo, $t0#lo, $t0#hi @ t0 = (L) (P0 + P1) << 8 + vand $t0#hi, $t0#hi, $k48 + vext.8 $t3#lo, $b, $b, #4 @ B4 + veor $t1#lo, $t1#lo, $t1#hi @ t1 = (M) (P2 + P3) << 16 + vand $t1#hi, $t1#hi, $k32 + vmull.p8 $t3, $a, $t3#lo @ K = A*B4 + veor $t2, $t2, $r @ N = I + J + veor $t0#lo, $t0#lo, $t0#hi + veor $t1#lo, $t1#lo, $t1#hi + veor $t2#lo, $t2#lo, $t2#hi @ t2 = (N) (P4 + P5) << 24 + vand $t2#hi, $t2#hi, $k16 + vext.8 $t0, $t0, $t0, #15 + veor $t3#lo, $t3#lo, $t3#hi @ t3 = (K) (P6 + P7) << 32 + vmov.i64 $t3#hi, #0 + vext.8 $t1, $t1, $t1, #14 + veor $t2#lo, $t2#lo, $t2#hi + vmull.p8 $r, $a, $b @ D = A*B + vext.8 $t3, $t3, $t3, #12 + vext.8 $t2, $t2, $t2, #13 + veor $t0, $t0, $t1 + veor $t2, $t2, $t3 + veor $r, $r, $t0 + veor $r, $r, $t2 +___ +} + +$code.=<<___; +#if __ARM_MAX_ARCH__>=7 +.arch armv7-a +.fpu neon + +.global gcm_init_neon +.hidden gcm_init_neon +.type gcm_init_neon,%function +.align 4 +gcm_init_neon: + vld1.64 $IN#hi,[r1]! @ load H + vmov.i8 $t0,#0xe1 + vld1.64 $IN#lo,[r1] + vshl.i64 $t0#hi,#57 + vshr.u64 $t0#lo,#63 @ t0=0xc2....01 + vdup.8 $t1,$IN#hi[7] + vshr.u64 $Hlo,$IN#lo,#63 + vshr.s8 $t1,#7 @ broadcast carry bit + vshl.i64 $IN,$IN,#1 + vand $t0,$t0,$t1 + vorr $IN#hi,$Hlo @ H<<<=1 + veor $IN,$IN,$t0 @ twisted H + vstmia r0,{$IN} + + ret @ bx lr +.size gcm_init_neon,.-gcm_init_neon + +.global gcm_gmult_neon +.hidden gcm_gmult_neon +.type gcm_gmult_neon,%function +.align 4 +gcm_gmult_neon: + vld1.64 $IN#hi,[$Xi]! @ load Xi + vld1.64 $IN#lo,[$Xi]! + vmov.i64 $k48,#0x0000ffffffffffff + vldmia $Htbl,{$Hlo-$Hhi} @ load twisted H + vmov.i64 $k32,#0x00000000ffffffff +#ifdef __ARMEL__ + vrev64.8 $IN,$IN +#endif + vmov.i64 $k16,#0x000000000000ffff + veor $Hhl,$Hlo,$Hhi @ Karatsuba pre-processing + mov $len,#16 + b .Lgmult_neon +.size gcm_gmult_neon,.-gcm_gmult_neon + +.global gcm_ghash_neon +.hidden gcm_ghash_neon +.type gcm_ghash_neon,%function +.align 4 +gcm_ghash_neon: + vld1.64 $Xl#hi,[$Xi]! @ load Xi + vld1.64 $Xl#lo,[$Xi]! + vmov.i64 $k48,#0x0000ffffffffffff + vldmia $Htbl,{$Hlo-$Hhi} @ load twisted H + vmov.i64 $k32,#0x00000000ffffffff +#ifdef __ARMEL__ + vrev64.8 $Xl,$Xl +#endif + vmov.i64 $k16,#0x000000000000ffff + veor $Hhl,$Hlo,$Hhi @ Karatsuba pre-processing + +.Loop_neon: + vld1.64 $IN#hi,[$inp]! @ load inp + vld1.64 $IN#lo,[$inp]! +#ifdef __ARMEL__ + vrev64.8 $IN,$IN +#endif + veor $IN,$Xl @ inp^=Xi +.Lgmult_neon: +___ + &clmul64x64 ($Xl,$Hlo,"$IN#lo"); # H.lo·Xi.lo +$code.=<<___; + veor $IN#lo,$IN#lo,$IN#hi @ Karatsuba pre-processing +___ + &clmul64x64 ($Xm,$Hhl,"$IN#lo"); # (H.lo+H.hi)·(Xi.lo+Xi.hi) + &clmul64x64 ($Xh,$Hhi,"$IN#hi"); # H.hi·Xi.hi +$code.=<<___; + veor $Xm,$Xm,$Xl @ Karatsuba post-processing + veor $Xm,$Xm,$Xh + veor $Xl#hi,$Xl#hi,$Xm#lo + veor $Xh#lo,$Xh#lo,$Xm#hi @ Xh|Xl - 256-bit result + + @ equivalent of reduction_avx from ghash-x86_64.pl + vshl.i64 $t1,$Xl,#57 @ 1st phase + vshl.i64 $t2,$Xl,#62 + veor $t2,$t2,$t1 @ + vshl.i64 $t1,$Xl,#63 + veor $t2, $t2, $t1 @ + veor $Xl#hi,$Xl#hi,$t2#lo @ + veor $Xh#lo,$Xh#lo,$t2#hi + + vshr.u64 $t2,$Xl,#1 @ 2nd phase + veor $Xh,$Xh,$Xl + veor $Xl,$Xl,$t2 @ + vshr.u64 $t2,$t2,#6 + vshr.u64 $Xl,$Xl,#1 @ + veor $Xl,$Xl,$Xh @ + veor $Xl,$Xl,$t2 @ + + subs $len,#16 + bne .Loop_neon + +#ifdef __ARMEL__ + vrev64.8 $Xl,$Xl +#endif + sub $Xi,#16 + vst1.64 $Xl#hi,[$Xi]! @ write out Xi + vst1.64 $Xl#lo,[$Xi] + + ret @ bx lr +.size gcm_ghash_neon,.-gcm_ghash_neon +#endif +___ +} +$code.=<<___; +.asciz "GHASH for ARMv4/NEON, CRYPTOGAMS by " +.align 2 + +#endif +___ + +foreach (split("\n",$code)) { + s/\`([^\`]*)\`/eval $1/geo; + + s/\bq([0-9]+)#(lo|hi)/sprintf "d%d",2*$1+($2 eq "hi")/geo or + s/\bret\b/bx lr/go or + s/\bbx\s+lr\b/.word\t0xe12fff1e/go; # make it possible to compile with -march=armv4 + + print $_,"\n"; +} +close STDOUT; # enforce flush diff --git a/TMessagesProj/jni/boringssl/crypto/modes/asm/ghash-x86.pl b/TMessagesProj/jni/boringssl/crypto/modes/asm/ghash-x86.pl new file mode 100644 index 00000000..0269169f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/modes/asm/ghash-x86.pl @@ -0,0 +1,1393 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# March, May, June 2010 +# +# The module implements "4-bit" GCM GHASH function and underlying +# single multiplication operation in GF(2^128). "4-bit" means that it +# uses 256 bytes per-key table [+64/128 bytes fixed table]. It has two +# code paths: vanilla x86 and vanilla SSE. Former will be executed on +# 486 and Pentium, latter on all others. SSE GHASH features so called +# "528B" variant of "4-bit" method utilizing additional 256+16 bytes +# of per-key storage [+512 bytes shared table]. Performance results +# are for streamed GHASH subroutine and are expressed in cycles per +# processed byte, less is better: +# +# gcc 2.95.3(*) SSE assembler x86 assembler +# +# Pentium 105/111(**) - 50 +# PIII 68 /75 12.2 24 +# P4 125/125 17.8 84(***) +# Opteron 66 /70 10.1 30 +# Core2 54 /67 8.4 18 +# Atom 105/105 16.8 53 +# VIA Nano 69 /71 13.0 27 +# +# (*) gcc 3.4.x was observed to generate few percent slower code, +# which is one of reasons why 2.95.3 results were chosen, +# another reason is lack of 3.4.x results for older CPUs; +# comparison with SSE results is not completely fair, because C +# results are for vanilla "256B" implementation, while +# assembler results are for "528B";-) +# (**) second number is result for code compiled with -fPIC flag, +# which is actually more relevant, because assembler code is +# position-independent; +# (***) see comment in non-MMX routine for further details; +# +# To summarize, it's >2-5 times faster than gcc-generated code. To +# anchor it to something else SHA1 assembler processes one byte in +# ~7 cycles on contemporary x86 cores. As for choice of MMX/SSE +# in particular, see comment at the end of the file... + +# May 2010 +# +# Add PCLMULQDQ version performing at 2.10 cycles per processed byte. +# The question is how close is it to theoretical limit? The pclmulqdq +# instruction latency appears to be 14 cycles and there can't be more +# than 2 of them executing at any given time. This means that single +# Karatsuba multiplication would take 28 cycles *plus* few cycles for +# pre- and post-processing. Then multiplication has to be followed by +# modulo-reduction. Given that aggregated reduction method [see +# "Carry-less Multiplication and Its Usage for Computing the GCM Mode" +# white paper by Intel] allows you to perform reduction only once in +# a while we can assume that asymptotic performance can be estimated +# as (28+Tmod/Naggr)/16, where Tmod is time to perform reduction +# and Naggr is the aggregation factor. +# +# Before we proceed to this implementation let's have closer look at +# the best-performing code suggested by Intel in their white paper. +# By tracing inter-register dependencies Tmod is estimated as ~19 +# cycles and Naggr chosen by Intel is 4, resulting in 2.05 cycles per +# processed byte. As implied, this is quite optimistic estimate, +# because it does not account for Karatsuba pre- and post-processing, +# which for a single multiplication is ~5 cycles. Unfortunately Intel +# does not provide performance data for GHASH alone. But benchmarking +# AES_GCM_encrypt ripped out of Fig. 15 of the white paper with aadt +# alone resulted in 2.46 cycles per byte of out 16KB buffer. Note that +# the result accounts even for pre-computing of degrees of the hash +# key H, but its portion is negligible at 16KB buffer size. +# +# Moving on to the implementation in question. Tmod is estimated as +# ~13 cycles and Naggr is 2, giving asymptotic performance of ... +# 2.16. How is it possible that measured performance is better than +# optimistic theoretical estimate? There is one thing Intel failed +# to recognize. By serializing GHASH with CTR in same subroutine +# former's performance is really limited to above (Tmul + Tmod/Naggr) +# equation. But if GHASH procedure is detached, the modulo-reduction +# can be interleaved with Naggr-1 multiplications at instruction level +# and under ideal conditions even disappear from the equation. So that +# optimistic theoretical estimate for this implementation is ... +# 28/16=1.75, and not 2.16. Well, it's probably way too optimistic, +# at least for such small Naggr. I'd argue that (28+Tproc/Naggr), +# where Tproc is time required for Karatsuba pre- and post-processing, +# is more realistic estimate. In this case it gives ... 1.91 cycles. +# Or in other words, depending on how well we can interleave reduction +# and one of the two multiplications the performance should be betwen +# 1.91 and 2.16. As already mentioned, this implementation processes +# one byte out of 8KB buffer in 2.10 cycles, while x86_64 counterpart +# - in 2.02. x86_64 performance is better, because larger register +# bank allows to interleave reduction and multiplication better. +# +# Does it make sense to increase Naggr? To start with it's virtually +# impossible in 32-bit mode, because of limited register bank +# capacity. Otherwise improvement has to be weighed agiainst slower +# setup, as well as code size and complexity increase. As even +# optimistic estimate doesn't promise 30% performance improvement, +# there are currently no plans to increase Naggr. +# +# Special thanks to David Woodhouse for +# providing access to a Westmere-based system on behalf of Intel +# Open Source Technology Centre. + +# January 2010 +# +# Tweaked to optimize transitions between integer and FP operations +# on same XMM register, PCLMULQDQ subroutine was measured to process +# one byte in 2.07 cycles on Sandy Bridge, and in 2.12 - on Westmere. +# The minor regression on Westmere is outweighed by ~15% improvement +# on Sandy Bridge. Strangely enough attempt to modify 64-bit code in +# similar manner resulted in almost 20% degradation on Sandy Bridge, +# where original 64-bit code processes one byte in 1.95 cycles. + +##################################################################### +# For reference, AMD Bulldozer processes one byte in 1.98 cycles in +# 32-bit mode and 1.89 in 64-bit. + +# February 2013 +# +# Overhaul: aggregate Karatsuba post-processing, improve ILP in +# reduction_alg9. Resulting performance is 1.96 cycles per byte on +# Westmere, 1.95 - on Sandy/Ivy Bridge, 1.76 - on Bulldozer. + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +push(@INC,"${dir}","${dir}../../perlasm"); +require "x86asm.pl"; + +&asm_init($ARGV[0],"ghash-x86.pl",$x86only = $ARGV[$#ARGV] eq "386"); + +$sse2=0; +for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); } + +($Zhh,$Zhl,$Zlh,$Zll) = ("ebp","edx","ecx","ebx"); +$inp = "edi"; +$Htbl = "esi"; + +$unroll = 0; # Affects x86 loop. Folded loop performs ~7% worse + # than unrolled, which has to be weighted against + # 2.5x x86-specific code size reduction. + +sub x86_loop { + my $off = shift; + my $rem = "eax"; + + &mov ($Zhh,&DWP(4,$Htbl,$Zll)); + &mov ($Zhl,&DWP(0,$Htbl,$Zll)); + &mov ($Zlh,&DWP(12,$Htbl,$Zll)); + &mov ($Zll,&DWP(8,$Htbl,$Zll)); + &xor ($rem,$rem); # avoid partial register stalls on PIII + + # shrd practically kills P4, 2.5x deterioration, but P4 has + # MMX code-path to execute. shrd runs tad faster [than twice + # the shifts, move's and or's] on pre-MMX Pentium (as well as + # PIII and Core2), *but* minimizes code size, spares register + # and thus allows to fold the loop... + if (!$unroll) { + my $cnt = $inp; + &mov ($cnt,15); + &jmp (&label("x86_loop")); + &set_label("x86_loop",16); + for($i=1;$i<=2;$i++) { + &mov (&LB($rem),&LB($Zll)); + &shrd ($Zll,$Zlh,4); + &and (&LB($rem),0xf); + &shrd ($Zlh,$Zhl,4); + &shrd ($Zhl,$Zhh,4); + &shr ($Zhh,4); + &xor ($Zhh,&DWP($off+16,"esp",$rem,4)); + + &mov (&LB($rem),&BP($off,"esp",$cnt)); + if ($i&1) { + &and (&LB($rem),0xf0); + } else { + &shl (&LB($rem),4); + } + + &xor ($Zll,&DWP(8,$Htbl,$rem)); + &xor ($Zlh,&DWP(12,$Htbl,$rem)); + &xor ($Zhl,&DWP(0,$Htbl,$rem)); + &xor ($Zhh,&DWP(4,$Htbl,$rem)); + + if ($i&1) { + &dec ($cnt); + &js (&label("x86_break")); + } else { + &jmp (&label("x86_loop")); + } + } + &set_label("x86_break",16); + } else { + for($i=1;$i<32;$i++) { + &comment($i); + &mov (&LB($rem),&LB($Zll)); + &shrd ($Zll,$Zlh,4); + &and (&LB($rem),0xf); + &shrd ($Zlh,$Zhl,4); + &shrd ($Zhl,$Zhh,4); + &shr ($Zhh,4); + &xor ($Zhh,&DWP($off+16,"esp",$rem,4)); + + if ($i&1) { + &mov (&LB($rem),&BP($off+15-($i>>1),"esp")); + &and (&LB($rem),0xf0); + } else { + &mov (&LB($rem),&BP($off+15-($i>>1),"esp")); + &shl (&LB($rem),4); + } + + &xor ($Zll,&DWP(8,$Htbl,$rem)); + &xor ($Zlh,&DWP(12,$Htbl,$rem)); + &xor ($Zhl,&DWP(0,$Htbl,$rem)); + &xor ($Zhh,&DWP(4,$Htbl,$rem)); + } + } + &bswap ($Zll); + &bswap ($Zlh); + &bswap ($Zhl); + if (!$x86only) { + &bswap ($Zhh); + } else { + &mov ("eax",$Zhh); + &bswap ("eax"); + &mov ($Zhh,"eax"); + } +} + +if ($unroll) { + &function_begin_B("_x86_gmult_4bit_inner"); + &x86_loop(4); + &ret (); + &function_end_B("_x86_gmult_4bit_inner"); +} + +sub deposit_rem_4bit { + my $bias = shift; + + &mov (&DWP($bias+0, "esp"),0x0000<<16); + &mov (&DWP($bias+4, "esp"),0x1C20<<16); + &mov (&DWP($bias+8, "esp"),0x3840<<16); + &mov (&DWP($bias+12,"esp"),0x2460<<16); + &mov (&DWP($bias+16,"esp"),0x7080<<16); + &mov (&DWP($bias+20,"esp"),0x6CA0<<16); + &mov (&DWP($bias+24,"esp"),0x48C0<<16); + &mov (&DWP($bias+28,"esp"),0x54E0<<16); + &mov (&DWP($bias+32,"esp"),0xE100<<16); + &mov (&DWP($bias+36,"esp"),0xFD20<<16); + &mov (&DWP($bias+40,"esp"),0xD940<<16); + &mov (&DWP($bias+44,"esp"),0xC560<<16); + &mov (&DWP($bias+48,"esp"),0x9180<<16); + &mov (&DWP($bias+52,"esp"),0x8DA0<<16); + &mov (&DWP($bias+56,"esp"),0xA9C0<<16); + &mov (&DWP($bias+60,"esp"),0xB5E0<<16); +} + +$suffix = $x86only ? "" : "_x86"; + +&function_begin("gcm_gmult_4bit".$suffix); + &stack_push(16+4+1); # +1 for stack alignment + &mov ($inp,&wparam(0)); # load Xi + &mov ($Htbl,&wparam(1)); # load Htable + + &mov ($Zhh,&DWP(0,$inp)); # load Xi[16] + &mov ($Zhl,&DWP(4,$inp)); + &mov ($Zlh,&DWP(8,$inp)); + &mov ($Zll,&DWP(12,$inp)); + + &deposit_rem_4bit(16); + + &mov (&DWP(0,"esp"),$Zhh); # copy Xi[16] on stack + &mov (&DWP(4,"esp"),$Zhl); + &mov (&DWP(8,"esp"),$Zlh); + &mov (&DWP(12,"esp"),$Zll); + &shr ($Zll,20); + &and ($Zll,0xf0); + + if ($unroll) { + &call ("_x86_gmult_4bit_inner"); + } else { + &x86_loop(0); + &mov ($inp,&wparam(0)); + } + + &mov (&DWP(12,$inp),$Zll); + &mov (&DWP(8,$inp),$Zlh); + &mov (&DWP(4,$inp),$Zhl); + &mov (&DWP(0,$inp),$Zhh); + &stack_pop(16+4+1); +&function_end("gcm_gmult_4bit".$suffix); + +&function_begin("gcm_ghash_4bit".$suffix); + &stack_push(16+4+1); # +1 for 64-bit alignment + &mov ($Zll,&wparam(0)); # load Xi + &mov ($Htbl,&wparam(1)); # load Htable + &mov ($inp,&wparam(2)); # load in + &mov ("ecx",&wparam(3)); # load len + &add ("ecx",$inp); + &mov (&wparam(3),"ecx"); + + &mov ($Zhh,&DWP(0,$Zll)); # load Xi[16] + &mov ($Zhl,&DWP(4,$Zll)); + &mov ($Zlh,&DWP(8,$Zll)); + &mov ($Zll,&DWP(12,$Zll)); + + &deposit_rem_4bit(16); + + &set_label("x86_outer_loop",16); + &xor ($Zll,&DWP(12,$inp)); # xor with input + &xor ($Zlh,&DWP(8,$inp)); + &xor ($Zhl,&DWP(4,$inp)); + &xor ($Zhh,&DWP(0,$inp)); + &mov (&DWP(12,"esp"),$Zll); # dump it on stack + &mov (&DWP(8,"esp"),$Zlh); + &mov (&DWP(4,"esp"),$Zhl); + &mov (&DWP(0,"esp"),$Zhh); + + &shr ($Zll,20); + &and ($Zll,0xf0); + + if ($unroll) { + &call ("_x86_gmult_4bit_inner"); + } else { + &x86_loop(0); + &mov ($inp,&wparam(2)); + } + &lea ($inp,&DWP(16,$inp)); + &cmp ($inp,&wparam(3)); + &mov (&wparam(2),$inp) if (!$unroll); + &jb (&label("x86_outer_loop")); + + &mov ($inp,&wparam(0)); # load Xi + &mov (&DWP(12,$inp),$Zll); + &mov (&DWP(8,$inp),$Zlh); + &mov (&DWP(4,$inp),$Zhl); + &mov (&DWP(0,$inp),$Zhh); + &stack_pop(16+4+1); +&function_end("gcm_ghash_4bit".$suffix); + +if (!$x86only) {{{ + +&static_label("rem_4bit"); + +if (!$sse2) {{ # pure-MMX "May" version... + +$S=12; # shift factor for rem_4bit + +&function_begin_B("_mmx_gmult_4bit_inner"); +# MMX version performs 3.5 times better on P4 (see comment in non-MMX +# routine for further details), 100% better on Opteron, ~70% better +# on Core2 and PIII... In other words effort is considered to be well +# spent... Since initial release the loop was unrolled in order to +# "liberate" register previously used as loop counter. Instead it's +# used to optimize critical path in 'Z.hi ^= rem_4bit[Z.lo&0xf]'. +# The path involves move of Z.lo from MMX to integer register, +# effective address calculation and finally merge of value to Z.hi. +# Reference to rem_4bit is scheduled so late that I had to >>4 +# rem_4bit elements. This resulted in 20-45% procent improvement +# on contemporary µ-archs. +{ + my $cnt; + my $rem_4bit = "eax"; + my @rem = ($Zhh,$Zll); + my $nhi = $Zhl; + my $nlo = $Zlh; + + my ($Zlo,$Zhi) = ("mm0","mm1"); + my $tmp = "mm2"; + + &xor ($nlo,$nlo); # avoid partial register stalls on PIII + &mov ($nhi,$Zll); + &mov (&LB($nlo),&LB($nhi)); + &shl (&LB($nlo),4); + &and ($nhi,0xf0); + &movq ($Zlo,&QWP(8,$Htbl,$nlo)); + &movq ($Zhi,&QWP(0,$Htbl,$nlo)); + &movd ($rem[0],$Zlo); + + for ($cnt=28;$cnt>=-2;$cnt--) { + my $odd = $cnt&1; + my $nix = $odd ? $nlo : $nhi; + + &shl (&LB($nlo),4) if ($odd); + &psrlq ($Zlo,4); + &movq ($tmp,$Zhi); + &psrlq ($Zhi,4); + &pxor ($Zlo,&QWP(8,$Htbl,$nix)); + &mov (&LB($nlo),&BP($cnt/2,$inp)) if (!$odd && $cnt>=0); + &psllq ($tmp,60); + &and ($nhi,0xf0) if ($odd); + &pxor ($Zhi,&QWP(0,$rem_4bit,$rem[1],8)) if ($cnt<28); + &and ($rem[0],0xf); + &pxor ($Zhi,&QWP(0,$Htbl,$nix)); + &mov ($nhi,$nlo) if (!$odd && $cnt>=0); + &movd ($rem[1],$Zlo); + &pxor ($Zlo,$tmp); + + push (@rem,shift(@rem)); # "rotate" registers + } + + &mov ($inp,&DWP(4,$rem_4bit,$rem[1],8)); # last rem_4bit[rem] + + &psrlq ($Zlo,32); # lower part of Zlo is already there + &movd ($Zhl,$Zhi); + &psrlq ($Zhi,32); + &movd ($Zlh,$Zlo); + &movd ($Zhh,$Zhi); + &shl ($inp,4); # compensate for rem_4bit[i] being >>4 + + &bswap ($Zll); + &bswap ($Zhl); + &bswap ($Zlh); + &xor ($Zhh,$inp); + &bswap ($Zhh); + + &ret (); +} +&function_end_B("_mmx_gmult_4bit_inner"); + +&function_begin("gcm_gmult_4bit_mmx"); + &mov ($inp,&wparam(0)); # load Xi + &mov ($Htbl,&wparam(1)); # load Htable + + &call (&label("pic_point")); + &set_label("pic_point"); + &blindpop("eax"); + &lea ("eax",&DWP(&label("rem_4bit")."-".&label("pic_point"),"eax")); + + &movz ($Zll,&BP(15,$inp)); + + &call ("_mmx_gmult_4bit_inner"); + + &mov ($inp,&wparam(0)); # load Xi + &emms (); + &mov (&DWP(12,$inp),$Zll); + &mov (&DWP(4,$inp),$Zhl); + &mov (&DWP(8,$inp),$Zlh); + &mov (&DWP(0,$inp),$Zhh); +&function_end("gcm_gmult_4bit_mmx"); + +# Streamed version performs 20% better on P4, 7% on Opteron, +# 10% on Core2 and PIII... +&function_begin("gcm_ghash_4bit_mmx"); + &mov ($Zhh,&wparam(0)); # load Xi + &mov ($Htbl,&wparam(1)); # load Htable + &mov ($inp,&wparam(2)); # load in + &mov ($Zlh,&wparam(3)); # load len + + &call (&label("pic_point")); + &set_label("pic_point"); + &blindpop("eax"); + &lea ("eax",&DWP(&label("rem_4bit")."-".&label("pic_point"),"eax")); + + &add ($Zlh,$inp); + &mov (&wparam(3),$Zlh); # len to point at the end of input + &stack_push(4+1); # +1 for stack alignment + + &mov ($Zll,&DWP(12,$Zhh)); # load Xi[16] + &mov ($Zhl,&DWP(4,$Zhh)); + &mov ($Zlh,&DWP(8,$Zhh)); + &mov ($Zhh,&DWP(0,$Zhh)); + &jmp (&label("mmx_outer_loop")); + + &set_label("mmx_outer_loop",16); + &xor ($Zll,&DWP(12,$inp)); + &xor ($Zhl,&DWP(4,$inp)); + &xor ($Zlh,&DWP(8,$inp)); + &xor ($Zhh,&DWP(0,$inp)); + &mov (&wparam(2),$inp); + &mov (&DWP(12,"esp"),$Zll); + &mov (&DWP(4,"esp"),$Zhl); + &mov (&DWP(8,"esp"),$Zlh); + &mov (&DWP(0,"esp"),$Zhh); + + &mov ($inp,"esp"); + &shr ($Zll,24); + + &call ("_mmx_gmult_4bit_inner"); + + &mov ($inp,&wparam(2)); + &lea ($inp,&DWP(16,$inp)); + &cmp ($inp,&wparam(3)); + &jb (&label("mmx_outer_loop")); + + &mov ($inp,&wparam(0)); # load Xi + &emms (); + &mov (&DWP(12,$inp),$Zll); + &mov (&DWP(4,$inp),$Zhl); + &mov (&DWP(8,$inp),$Zlh); + &mov (&DWP(0,$inp),$Zhh); + + &stack_pop(4+1); +&function_end("gcm_ghash_4bit_mmx"); + +}} else {{ # "June" MMX version... + # ... has slower "April" gcm_gmult_4bit_mmx with folded + # loop. This is done to conserve code size... +$S=16; # shift factor for rem_4bit + +sub mmx_loop() { +# MMX version performs 2.8 times better on P4 (see comment in non-MMX +# routine for further details), 40% better on Opteron and Core2, 50% +# better on PIII... In other words effort is considered to be well +# spent... + my $inp = shift; + my $rem_4bit = shift; + my $cnt = $Zhh; + my $nhi = $Zhl; + my $nlo = $Zlh; + my $rem = $Zll; + + my ($Zlo,$Zhi) = ("mm0","mm1"); + my $tmp = "mm2"; + + &xor ($nlo,$nlo); # avoid partial register stalls on PIII + &mov ($nhi,$Zll); + &mov (&LB($nlo),&LB($nhi)); + &mov ($cnt,14); + &shl (&LB($nlo),4); + &and ($nhi,0xf0); + &movq ($Zlo,&QWP(8,$Htbl,$nlo)); + &movq ($Zhi,&QWP(0,$Htbl,$nlo)); + &movd ($rem,$Zlo); + &jmp (&label("mmx_loop")); + + &set_label("mmx_loop",16); + &psrlq ($Zlo,4); + &and ($rem,0xf); + &movq ($tmp,$Zhi); + &psrlq ($Zhi,4); + &pxor ($Zlo,&QWP(8,$Htbl,$nhi)); + &mov (&LB($nlo),&BP(0,$inp,$cnt)); + &psllq ($tmp,60); + &pxor ($Zhi,&QWP(0,$rem_4bit,$rem,8)); + &dec ($cnt); + &movd ($rem,$Zlo); + &pxor ($Zhi,&QWP(0,$Htbl,$nhi)); + &mov ($nhi,$nlo); + &pxor ($Zlo,$tmp); + &js (&label("mmx_break")); + + &shl (&LB($nlo),4); + &and ($rem,0xf); + &psrlq ($Zlo,4); + &and ($nhi,0xf0); + &movq ($tmp,$Zhi); + &psrlq ($Zhi,4); + &pxor ($Zlo,&QWP(8,$Htbl,$nlo)); + &psllq ($tmp,60); + &pxor ($Zhi,&QWP(0,$rem_4bit,$rem,8)); + &movd ($rem,$Zlo); + &pxor ($Zhi,&QWP(0,$Htbl,$nlo)); + &pxor ($Zlo,$tmp); + &jmp (&label("mmx_loop")); + + &set_label("mmx_break",16); + &shl (&LB($nlo),4); + &and ($rem,0xf); + &psrlq ($Zlo,4); + &and ($nhi,0xf0); + &movq ($tmp,$Zhi); + &psrlq ($Zhi,4); + &pxor ($Zlo,&QWP(8,$Htbl,$nlo)); + &psllq ($tmp,60); + &pxor ($Zhi,&QWP(0,$rem_4bit,$rem,8)); + &movd ($rem,$Zlo); + &pxor ($Zhi,&QWP(0,$Htbl,$nlo)); + &pxor ($Zlo,$tmp); + + &psrlq ($Zlo,4); + &and ($rem,0xf); + &movq ($tmp,$Zhi); + &psrlq ($Zhi,4); + &pxor ($Zlo,&QWP(8,$Htbl,$nhi)); + &psllq ($tmp,60); + &pxor ($Zhi,&QWP(0,$rem_4bit,$rem,8)); + &movd ($rem,$Zlo); + &pxor ($Zhi,&QWP(0,$Htbl,$nhi)); + &pxor ($Zlo,$tmp); + + &psrlq ($Zlo,32); # lower part of Zlo is already there + &movd ($Zhl,$Zhi); + &psrlq ($Zhi,32); + &movd ($Zlh,$Zlo); + &movd ($Zhh,$Zhi); + + &bswap ($Zll); + &bswap ($Zhl); + &bswap ($Zlh); + &bswap ($Zhh); +} + +&function_begin("gcm_gmult_4bit_mmx"); + &mov ($inp,&wparam(0)); # load Xi + &mov ($Htbl,&wparam(1)); # load Htable + + &call (&label("pic_point")); + &set_label("pic_point"); + &blindpop("eax"); + &lea ("eax",&DWP(&label("rem_4bit")."-".&label("pic_point"),"eax")); + + &movz ($Zll,&BP(15,$inp)); + + &mmx_loop($inp,"eax"); + + &emms (); + &mov (&DWP(12,$inp),$Zll); + &mov (&DWP(4,$inp),$Zhl); + &mov (&DWP(8,$inp),$Zlh); + &mov (&DWP(0,$inp),$Zhh); +&function_end("gcm_gmult_4bit_mmx"); + +###################################################################### +# Below subroutine is "528B" variant of "4-bit" GCM GHASH function +# (see gcm128.c for details). It provides further 20-40% performance +# improvement over above mentioned "May" version. + +&static_label("rem_8bit"); + +&function_begin("gcm_ghash_4bit_mmx"); +{ my ($Zlo,$Zhi) = ("mm7","mm6"); + my $rem_8bit = "esi"; + my $Htbl = "ebx"; + + # parameter block + &mov ("eax",&wparam(0)); # Xi + &mov ("ebx",&wparam(1)); # Htable + &mov ("ecx",&wparam(2)); # inp + &mov ("edx",&wparam(3)); # len + &mov ("ebp","esp"); # original %esp + &call (&label("pic_point")); + &set_label ("pic_point"); + &blindpop ($rem_8bit); + &lea ($rem_8bit,&DWP(&label("rem_8bit")."-".&label("pic_point"),$rem_8bit)); + + &sub ("esp",512+16+16); # allocate stack frame... + &and ("esp",-64); # ...and align it + &sub ("esp",16); # place for (u8)(H[]<<4) + + &add ("edx","ecx"); # pointer to the end of input + &mov (&DWP(528+16+0,"esp"),"eax"); # save Xi + &mov (&DWP(528+16+8,"esp"),"edx"); # save inp+len + &mov (&DWP(528+16+12,"esp"),"ebp"); # save original %esp + + { my @lo = ("mm0","mm1","mm2"); + my @hi = ("mm3","mm4","mm5"); + my @tmp = ("mm6","mm7"); + my ($off1,$off2,$i) = (0,0,); + + &add ($Htbl,128); # optimize for size + &lea ("edi",&DWP(16+128,"esp")); + &lea ("ebp",&DWP(16+256+128,"esp")); + + # decompose Htable (low and high parts are kept separately), + # generate Htable[]>>4, (u8)(Htable[]<<4), save to stack... + for ($i=0;$i<18;$i++) { + + &mov ("edx",&DWP(16*$i+8-128,$Htbl)) if ($i<16); + &movq ($lo[0],&QWP(16*$i+8-128,$Htbl)) if ($i<16); + &psllq ($tmp[1],60) if ($i>1); + &movq ($hi[0],&QWP(16*$i+0-128,$Htbl)) if ($i<16); + &por ($lo[2],$tmp[1]) if ($i>1); + &movq (&QWP($off1-128,"edi"),$lo[1]) if ($i>0 && $i<17); + &psrlq ($lo[1],4) if ($i>0 && $i<17); + &movq (&QWP($off1,"edi"),$hi[1]) if ($i>0 && $i<17); + &movq ($tmp[0],$hi[1]) if ($i>0 && $i<17); + &movq (&QWP($off2-128,"ebp"),$lo[2]) if ($i>1); + &psrlq ($hi[1],4) if ($i>0 && $i<17); + &movq (&QWP($off2,"ebp"),$hi[2]) if ($i>1); + &shl ("edx",4) if ($i<16); + &mov (&BP($i,"esp"),&LB("edx")) if ($i<16); + + unshift (@lo,pop(@lo)); # "rotate" registers + unshift (@hi,pop(@hi)); + unshift (@tmp,pop(@tmp)); + $off1 += 8 if ($i>0); + $off2 += 8 if ($i>1); + } + } + + &movq ($Zhi,&QWP(0,"eax")); + &mov ("ebx",&DWP(8,"eax")); + &mov ("edx",&DWP(12,"eax")); # load Xi + +&set_label("outer",16); + { my $nlo = "eax"; + my $dat = "edx"; + my @nhi = ("edi","ebp"); + my @rem = ("ebx","ecx"); + my @red = ("mm0","mm1","mm2"); + my $tmp = "mm3"; + + &xor ($dat,&DWP(12,"ecx")); # merge input data + &xor ("ebx",&DWP(8,"ecx")); + &pxor ($Zhi,&QWP(0,"ecx")); + &lea ("ecx",&DWP(16,"ecx")); # inp+=16 + #&mov (&DWP(528+12,"esp"),$dat); # save inp^Xi + &mov (&DWP(528+8,"esp"),"ebx"); + &movq (&QWP(528+0,"esp"),$Zhi); + &mov (&DWP(528+16+4,"esp"),"ecx"); # save inp + + &xor ($nlo,$nlo); + &rol ($dat,8); + &mov (&LB($nlo),&LB($dat)); + &mov ($nhi[1],$nlo); + &and (&LB($nlo),0x0f); + &shr ($nhi[1],4); + &pxor ($red[0],$red[0]); + &rol ($dat,8); # next byte + &pxor ($red[1],$red[1]); + &pxor ($red[2],$red[2]); + + # Just like in "May" verson modulo-schedule for critical path in + # 'Z.hi ^= rem_8bit[Z.lo&0xff^((u8)H[nhi]<<4)]<<48'. Final 'pxor' + # is scheduled so late that rem_8bit[] has to be shifted *right* + # by 16, which is why last argument to pinsrw is 2, which + # corresponds to <<32=<<48>>16... + for ($j=11,$i=0;$i<15;$i++) { + + if ($i>0) { + &pxor ($Zlo,&QWP(16,"esp",$nlo,8)); # Z^=H[nlo] + &rol ($dat,8); # next byte + &pxor ($Zhi,&QWP(16+128,"esp",$nlo,8)); + + &pxor ($Zlo,$tmp); + &pxor ($Zhi,&QWP(16+256+128,"esp",$nhi[0],8)); + &xor (&LB($rem[1]),&BP(0,"esp",$nhi[0])); # rem^(H[nhi]<<4) + } else { + &movq ($Zlo,&QWP(16,"esp",$nlo,8)); + &movq ($Zhi,&QWP(16+128,"esp",$nlo,8)); + } + + &mov (&LB($nlo),&LB($dat)); + &mov ($dat,&DWP(528+$j,"esp")) if (--$j%4==0); + + &movd ($rem[0],$Zlo); + &movz ($rem[1],&LB($rem[1])) if ($i>0); + &psrlq ($Zlo,8); # Z>>=8 + + &movq ($tmp,$Zhi); + &mov ($nhi[0],$nlo); + &psrlq ($Zhi,8); + + &pxor ($Zlo,&QWP(16+256+0,"esp",$nhi[1],8)); # Z^=H[nhi]>>4 + &and (&LB($nlo),0x0f); + &psllq ($tmp,56); + + &pxor ($Zhi,$red[1]) if ($i>1); + &shr ($nhi[0],4); + &pinsrw ($red[0],&WP(0,$rem_8bit,$rem[1],2),2) if ($i>0); + + unshift (@red,pop(@red)); # "rotate" registers + unshift (@rem,pop(@rem)); + unshift (@nhi,pop(@nhi)); + } + + &pxor ($Zlo,&QWP(16,"esp",$nlo,8)); # Z^=H[nlo] + &pxor ($Zhi,&QWP(16+128,"esp",$nlo,8)); + &xor (&LB($rem[1]),&BP(0,"esp",$nhi[0])); # rem^(H[nhi]<<4) + + &pxor ($Zlo,$tmp); + &pxor ($Zhi,&QWP(16+256+128,"esp",$nhi[0],8)); + &movz ($rem[1],&LB($rem[1])); + + &pxor ($red[2],$red[2]); # clear 2nd word + &psllq ($red[1],4); + + &movd ($rem[0],$Zlo); + &psrlq ($Zlo,4); # Z>>=4 + + &movq ($tmp,$Zhi); + &psrlq ($Zhi,4); + &shl ($rem[0],4); # rem<<4 + + &pxor ($Zlo,&QWP(16,"esp",$nhi[1],8)); # Z^=H[nhi] + &psllq ($tmp,60); + &movz ($rem[0],&LB($rem[0])); + + &pxor ($Zlo,$tmp); + &pxor ($Zhi,&QWP(16+128,"esp",$nhi[1],8)); + + &pinsrw ($red[0],&WP(0,$rem_8bit,$rem[1],2),2); + &pxor ($Zhi,$red[1]); + + &movd ($dat,$Zlo); + &pinsrw ($red[2],&WP(0,$rem_8bit,$rem[0],2),3); # last is <<48 + + &psllq ($red[0],12); # correct by <<16>>4 + &pxor ($Zhi,$red[0]); + &psrlq ($Zlo,32); + &pxor ($Zhi,$red[2]); + + &mov ("ecx",&DWP(528+16+4,"esp")); # restore inp + &movd ("ebx",$Zlo); + &movq ($tmp,$Zhi); # 01234567 + &psllw ($Zhi,8); # 1.3.5.7. + &psrlw ($tmp,8); # .0.2.4.6 + &por ($Zhi,$tmp); # 10325476 + &bswap ($dat); + &pshufw ($Zhi,$Zhi,0b00011011); # 76543210 + &bswap ("ebx"); + + &cmp ("ecx",&DWP(528+16+8,"esp")); # are we done? + &jne (&label("outer")); + } + + &mov ("eax",&DWP(528+16+0,"esp")); # restore Xi + &mov (&DWP(12,"eax"),"edx"); + &mov (&DWP(8,"eax"),"ebx"); + &movq (&QWP(0,"eax"),$Zhi); + + &mov ("esp",&DWP(528+16+12,"esp")); # restore original %esp + &emms (); +} +&function_end("gcm_ghash_4bit_mmx"); +}} + +if ($sse2) {{ +###################################################################### +# PCLMULQDQ version. + +$Xip="eax"; +$Htbl="edx"; +$const="ecx"; +$inp="esi"; +$len="ebx"; + +($Xi,$Xhi)=("xmm0","xmm1"); $Hkey="xmm2"; +($T1,$T2,$T3)=("xmm3","xmm4","xmm5"); +($Xn,$Xhn)=("xmm6","xmm7"); + +&static_label("bswap"); + +sub clmul64x64_T2 { # minimal "register" pressure +my ($Xhi,$Xi,$Hkey,$HK)=@_; + + &movdqa ($Xhi,$Xi); # + &pshufd ($T1,$Xi,0b01001110); + &pshufd ($T2,$Hkey,0b01001110) if (!defined($HK)); + &pxor ($T1,$Xi); # + &pxor ($T2,$Hkey) if (!defined($HK)); + $HK=$T2 if (!defined($HK)); + + &pclmulqdq ($Xi,$Hkey,0x00); ####### + &pclmulqdq ($Xhi,$Hkey,0x11); ####### + &pclmulqdq ($T1,$HK,0x00); ####### + &xorps ($T1,$Xi); # + &xorps ($T1,$Xhi); # + + &movdqa ($T2,$T1); # + &psrldq ($T1,8); + &pslldq ($T2,8); # + &pxor ($Xhi,$T1); + &pxor ($Xi,$T2); # +} + +sub clmul64x64_T3 { +# Even though this subroutine offers visually better ILP, it +# was empirically found to be a tad slower than above version. +# At least in gcm_ghash_clmul context. But it's just as well, +# because loop modulo-scheduling is possible only thanks to +# minimized "register" pressure... +my ($Xhi,$Xi,$Hkey)=@_; + + &movdqa ($T1,$Xi); # + &movdqa ($Xhi,$Xi); + &pclmulqdq ($Xi,$Hkey,0x00); ####### + &pclmulqdq ($Xhi,$Hkey,0x11); ####### + &pshufd ($T2,$T1,0b01001110); # + &pshufd ($T3,$Hkey,0b01001110); + &pxor ($T2,$T1); # + &pxor ($T3,$Hkey); + &pclmulqdq ($T2,$T3,0x00); ####### + &pxor ($T2,$Xi); # + &pxor ($T2,$Xhi); # + + &movdqa ($T3,$T2); # + &psrldq ($T2,8); + &pslldq ($T3,8); # + &pxor ($Xhi,$T2); + &pxor ($Xi,$T3); # +} + +if (1) { # Algorithm 9 with <<1 twist. + # Reduction is shorter and uses only two + # temporary registers, which makes it better + # candidate for interleaving with 64x64 + # multiplication. Pre-modulo-scheduled loop + # was found to be ~20% faster than Algorithm 5 + # below. Algorithm 9 was therefore chosen for + # further optimization... + +sub reduction_alg9 { # 17/11 times faster than Intel version +my ($Xhi,$Xi) = @_; + + # 1st phase + &movdqa ($T2,$Xi); # + &movdqa ($T1,$Xi); + &psllq ($Xi,5); + &pxor ($T1,$Xi); # + &psllq ($Xi,1); + &pxor ($Xi,$T1); # + &psllq ($Xi,57); # + &movdqa ($T1,$Xi); # + &pslldq ($Xi,8); + &psrldq ($T1,8); # + &pxor ($Xi,$T2); + &pxor ($Xhi,$T1); # + + # 2nd phase + &movdqa ($T2,$Xi); + &psrlq ($Xi,1); + &pxor ($Xhi,$T2); # + &pxor ($T2,$Xi); + &psrlq ($Xi,5); + &pxor ($Xi,$T2); # + &psrlq ($Xi,1); # + &pxor ($Xi,$Xhi) # +} + +&function_begin_B("gcm_init_clmul"); + &mov ($Htbl,&wparam(0)); + &mov ($Xip,&wparam(1)); + + &call (&label("pic")); +&set_label("pic"); + &blindpop ($const); + &lea ($const,&DWP(&label("bswap")."-".&label("pic"),$const)); + + &movdqu ($Hkey,&QWP(0,$Xip)); + &pshufd ($Hkey,$Hkey,0b01001110);# dword swap + + # <<1 twist + &pshufd ($T2,$Hkey,0b11111111); # broadcast uppermost dword + &movdqa ($T1,$Hkey); + &psllq ($Hkey,1); + &pxor ($T3,$T3); # + &psrlq ($T1,63); + &pcmpgtd ($T3,$T2); # broadcast carry bit + &pslldq ($T1,8); + &por ($Hkey,$T1); # H<<=1 + + # magic reduction + &pand ($T3,&QWP(16,$const)); # 0x1c2_polynomial + &pxor ($Hkey,$T3); # if(carry) H^=0x1c2_polynomial + + # calculate H^2 + &movdqa ($Xi,$Hkey); + &clmul64x64_T2 ($Xhi,$Xi,$Hkey); + &reduction_alg9 ($Xhi,$Xi); + + &pshufd ($T1,$Hkey,0b01001110); + &pshufd ($T2,$Xi,0b01001110); + &pxor ($T1,$Hkey); # Karatsuba pre-processing + &movdqu (&QWP(0,$Htbl),$Hkey); # save H + &pxor ($T2,$Xi); # Karatsuba pre-processing + &movdqu (&QWP(16,$Htbl),$Xi); # save H^2 + &palignr ($T2,$T1,8); # low part is H.lo^H.hi + &movdqu (&QWP(32,$Htbl),$T2); # save Karatsuba "salt" + + &ret (); +&function_end_B("gcm_init_clmul"); + +&function_begin_B("gcm_gmult_clmul"); + &mov ($Xip,&wparam(0)); + &mov ($Htbl,&wparam(1)); + + &call (&label("pic")); +&set_label("pic"); + &blindpop ($const); + &lea ($const,&DWP(&label("bswap")."-".&label("pic"),$const)); + + &movdqu ($Xi,&QWP(0,$Xip)); + &movdqa ($T3,&QWP(0,$const)); + &movups ($Hkey,&QWP(0,$Htbl)); + &pshufb ($Xi,$T3); + &movups ($T2,&QWP(32,$Htbl)); + + &clmul64x64_T2 ($Xhi,$Xi,$Hkey,$T2); + &reduction_alg9 ($Xhi,$Xi); + + &pshufb ($Xi,$T3); + &movdqu (&QWP(0,$Xip),$Xi); + + &ret (); +&function_end_B("gcm_gmult_clmul"); + +&function_begin("gcm_ghash_clmul"); + &mov ($Xip,&wparam(0)); + &mov ($Htbl,&wparam(1)); + &mov ($inp,&wparam(2)); + &mov ($len,&wparam(3)); + + &call (&label("pic")); +&set_label("pic"); + &blindpop ($const); + &lea ($const,&DWP(&label("bswap")."-".&label("pic"),$const)); + + &movdqu ($Xi,&QWP(0,$Xip)); + &movdqa ($T3,&QWP(0,$const)); + &movdqu ($Hkey,&QWP(0,$Htbl)); + &pshufb ($Xi,$T3); + + &sub ($len,0x10); + &jz (&label("odd_tail")); + + ####### + # Xi+2 =[H*(Ii+1 + Xi+1)] mod P = + # [(H*Ii+1) + (H*Xi+1)] mod P = + # [(H*Ii+1) + H^2*(Ii+Xi)] mod P + # + &movdqu ($T1,&QWP(0,$inp)); # Ii + &movdqu ($Xn,&QWP(16,$inp)); # Ii+1 + &pshufb ($T1,$T3); + &pshufb ($Xn,$T3); + &movdqu ($T3,&QWP(32,$Htbl)); + &pxor ($Xi,$T1); # Ii+Xi + + &pshufd ($T1,$Xn,0b01001110); # H*Ii+1 + &movdqa ($Xhn,$Xn); + &pxor ($T1,$Xn); # + &lea ($inp,&DWP(32,$inp)); # i+=2 + + &pclmulqdq ($Xn,$Hkey,0x00); ####### + &pclmulqdq ($Xhn,$Hkey,0x11); ####### + &pclmulqdq ($T1,$T3,0x00); ####### + &movups ($Hkey,&QWP(16,$Htbl)); # load H^2 + &nop (); + + &sub ($len,0x20); + &jbe (&label("even_tail")); + &jmp (&label("mod_loop")); + +&set_label("mod_loop",32); + &pshufd ($T2,$Xi,0b01001110); # H^2*(Ii+Xi) + &movdqa ($Xhi,$Xi); + &pxor ($T2,$Xi); # + &nop (); + + &pclmulqdq ($Xi,$Hkey,0x00); ####### + &pclmulqdq ($Xhi,$Hkey,0x11); ####### + &pclmulqdq ($T2,$T3,0x10); ####### + &movups ($Hkey,&QWP(0,$Htbl)); # load H + + &xorps ($Xi,$Xn); # (H*Ii+1) + H^2*(Ii+Xi) + &movdqa ($T3,&QWP(0,$const)); + &xorps ($Xhi,$Xhn); + &movdqu ($Xhn,&QWP(0,$inp)); # Ii + &pxor ($T1,$Xi); # aggregated Karatsuba post-processing + &movdqu ($Xn,&QWP(16,$inp)); # Ii+1 + &pxor ($T1,$Xhi); # + + &pshufb ($Xhn,$T3); + &pxor ($T2,$T1); # + + &movdqa ($T1,$T2); # + &psrldq ($T2,8); + &pslldq ($T1,8); # + &pxor ($Xhi,$T2); + &pxor ($Xi,$T1); # + &pshufb ($Xn,$T3); + &pxor ($Xhi,$Xhn); # "Ii+Xi", consume early + + &movdqa ($Xhn,$Xn); #&clmul64x64_TX ($Xhn,$Xn,$Hkey); H*Ii+1 + &movdqa ($T2,$Xi); #&reduction_alg9($Xhi,$Xi); 1st phase + &movdqa ($T1,$Xi); + &psllq ($Xi,5); + &pxor ($T1,$Xi); # + &psllq ($Xi,1); + &pxor ($Xi,$T1); # + &pclmulqdq ($Xn,$Hkey,0x00); ####### + &movups ($T3,&QWP(32,$Htbl)); + &psllq ($Xi,57); # + &movdqa ($T1,$Xi); # + &pslldq ($Xi,8); + &psrldq ($T1,8); # + &pxor ($Xi,$T2); + &pxor ($Xhi,$T1); # + &pshufd ($T1,$Xhn,0b01001110); + &movdqa ($T2,$Xi); # 2nd phase + &psrlq ($Xi,1); + &pxor ($T1,$Xhn); + &pxor ($Xhi,$T2); # + &pclmulqdq ($Xhn,$Hkey,0x11); ####### + &movups ($Hkey,&QWP(16,$Htbl)); # load H^2 + &pxor ($T2,$Xi); + &psrlq ($Xi,5); + &pxor ($Xi,$T2); # + &psrlq ($Xi,1); # + &pxor ($Xi,$Xhi) # + &pclmulqdq ($T1,$T3,0x00); ####### + + &lea ($inp,&DWP(32,$inp)); + &sub ($len,0x20); + &ja (&label("mod_loop")); + +&set_label("even_tail"); + &pshufd ($T2,$Xi,0b01001110); # H^2*(Ii+Xi) + &movdqa ($Xhi,$Xi); + &pxor ($T2,$Xi); # + + &pclmulqdq ($Xi,$Hkey,0x00); ####### + &pclmulqdq ($Xhi,$Hkey,0x11); ####### + &pclmulqdq ($T2,$T3,0x10); ####### + &movdqa ($T3,&QWP(0,$const)); + + &xorps ($Xi,$Xn); # (H*Ii+1) + H^2*(Ii+Xi) + &xorps ($Xhi,$Xhn); + &pxor ($T1,$Xi); # aggregated Karatsuba post-processing + &pxor ($T1,$Xhi); # + + &pxor ($T2,$T1); # + + &movdqa ($T1,$T2); # + &psrldq ($T2,8); + &pslldq ($T1,8); # + &pxor ($Xhi,$T2); + &pxor ($Xi,$T1); # + + &reduction_alg9 ($Xhi,$Xi); + + &test ($len,$len); + &jnz (&label("done")); + + &movups ($Hkey,&QWP(0,$Htbl)); # load H +&set_label("odd_tail"); + &movdqu ($T1,&QWP(0,$inp)); # Ii + &pshufb ($T1,$T3); + &pxor ($Xi,$T1); # Ii+Xi + + &clmul64x64_T2 ($Xhi,$Xi,$Hkey); # H*(Ii+Xi) + &reduction_alg9 ($Xhi,$Xi); + +&set_label("done"); + &pshufb ($Xi,$T3); + &movdqu (&QWP(0,$Xip),$Xi); +&function_end("gcm_ghash_clmul"); + +} else { # Algorith 5. Kept for reference purposes. + +sub reduction_alg5 { # 19/16 times faster than Intel version +my ($Xhi,$Xi)=@_; + + # <<1 + &movdqa ($T1,$Xi); # + &movdqa ($T2,$Xhi); + &pslld ($Xi,1); + &pslld ($Xhi,1); # + &psrld ($T1,31); + &psrld ($T2,31); # + &movdqa ($T3,$T1); + &pslldq ($T1,4); + &psrldq ($T3,12); # + &pslldq ($T2,4); + &por ($Xhi,$T3); # + &por ($Xi,$T1); + &por ($Xhi,$T2); # + + # 1st phase + &movdqa ($T1,$Xi); + &movdqa ($T2,$Xi); + &movdqa ($T3,$Xi); # + &pslld ($T1,31); + &pslld ($T2,30); + &pslld ($Xi,25); # + &pxor ($T1,$T2); + &pxor ($T1,$Xi); # + &movdqa ($T2,$T1); # + &pslldq ($T1,12); + &psrldq ($T2,4); # + &pxor ($T3,$T1); + + # 2nd phase + &pxor ($Xhi,$T3); # + &movdqa ($Xi,$T3); + &movdqa ($T1,$T3); + &psrld ($Xi,1); # + &psrld ($T1,2); + &psrld ($T3,7); # + &pxor ($Xi,$T1); + &pxor ($Xhi,$T2); + &pxor ($Xi,$T3); # + &pxor ($Xi,$Xhi); # +} + +&function_begin_B("gcm_init_clmul"); + &mov ($Htbl,&wparam(0)); + &mov ($Xip,&wparam(1)); + + &call (&label("pic")); +&set_label("pic"); + &blindpop ($const); + &lea ($const,&DWP(&label("bswap")."-".&label("pic"),$const)); + + &movdqu ($Hkey,&QWP(0,$Xip)); + &pshufd ($Hkey,$Hkey,0b01001110);# dword swap + + # calculate H^2 + &movdqa ($Xi,$Hkey); + &clmul64x64_T3 ($Xhi,$Xi,$Hkey); + &reduction_alg5 ($Xhi,$Xi); + + &movdqu (&QWP(0,$Htbl),$Hkey); # save H + &movdqu (&QWP(16,$Htbl),$Xi); # save H^2 + + &ret (); +&function_end_B("gcm_init_clmul"); + +&function_begin_B("gcm_gmult_clmul"); + &mov ($Xip,&wparam(0)); + &mov ($Htbl,&wparam(1)); + + &call (&label("pic")); +&set_label("pic"); + &blindpop ($const); + &lea ($const,&DWP(&label("bswap")."-".&label("pic"),$const)); + + &movdqu ($Xi,&QWP(0,$Xip)); + &movdqa ($Xn,&QWP(0,$const)); + &movdqu ($Hkey,&QWP(0,$Htbl)); + &pshufb ($Xi,$Xn); + + &clmul64x64_T3 ($Xhi,$Xi,$Hkey); + &reduction_alg5 ($Xhi,$Xi); + + &pshufb ($Xi,$Xn); + &movdqu (&QWP(0,$Xip),$Xi); + + &ret (); +&function_end_B("gcm_gmult_clmul"); + +&function_begin("gcm_ghash_clmul"); + &mov ($Xip,&wparam(0)); + &mov ($Htbl,&wparam(1)); + &mov ($inp,&wparam(2)); + &mov ($len,&wparam(3)); + + &call (&label("pic")); +&set_label("pic"); + &blindpop ($const); + &lea ($const,&DWP(&label("bswap")."-".&label("pic"),$const)); + + &movdqu ($Xi,&QWP(0,$Xip)); + &movdqa ($T3,&QWP(0,$const)); + &movdqu ($Hkey,&QWP(0,$Htbl)); + &pshufb ($Xi,$T3); + + &sub ($len,0x10); + &jz (&label("odd_tail")); + + ####### + # Xi+2 =[H*(Ii+1 + Xi+1)] mod P = + # [(H*Ii+1) + (H*Xi+1)] mod P = + # [(H*Ii+1) + H^2*(Ii+Xi)] mod P + # + &movdqu ($T1,&QWP(0,$inp)); # Ii + &movdqu ($Xn,&QWP(16,$inp)); # Ii+1 + &pshufb ($T1,$T3); + &pshufb ($Xn,$T3); + &pxor ($Xi,$T1); # Ii+Xi + + &clmul64x64_T3 ($Xhn,$Xn,$Hkey); # H*Ii+1 + &movdqu ($Hkey,&QWP(16,$Htbl)); # load H^2 + + &sub ($len,0x20); + &lea ($inp,&DWP(32,$inp)); # i+=2 + &jbe (&label("even_tail")); + +&set_label("mod_loop"); + &clmul64x64_T3 ($Xhi,$Xi,$Hkey); # H^2*(Ii+Xi) + &movdqu ($Hkey,&QWP(0,$Htbl)); # load H + + &pxor ($Xi,$Xn); # (H*Ii+1) + H^2*(Ii+Xi) + &pxor ($Xhi,$Xhn); + + &reduction_alg5 ($Xhi,$Xi); + + ####### + &movdqa ($T3,&QWP(0,$const)); + &movdqu ($T1,&QWP(0,$inp)); # Ii + &movdqu ($Xn,&QWP(16,$inp)); # Ii+1 + &pshufb ($T1,$T3); + &pshufb ($Xn,$T3); + &pxor ($Xi,$T1); # Ii+Xi + + &clmul64x64_T3 ($Xhn,$Xn,$Hkey); # H*Ii+1 + &movdqu ($Hkey,&QWP(16,$Htbl)); # load H^2 + + &sub ($len,0x20); + &lea ($inp,&DWP(32,$inp)); + &ja (&label("mod_loop")); + +&set_label("even_tail"); + &clmul64x64_T3 ($Xhi,$Xi,$Hkey); # H^2*(Ii+Xi) + + &pxor ($Xi,$Xn); # (H*Ii+1) + H^2*(Ii+Xi) + &pxor ($Xhi,$Xhn); + + &reduction_alg5 ($Xhi,$Xi); + + &movdqa ($T3,&QWP(0,$const)); + &test ($len,$len); + &jnz (&label("done")); + + &movdqu ($Hkey,&QWP(0,$Htbl)); # load H +&set_label("odd_tail"); + &movdqu ($T1,&QWP(0,$inp)); # Ii + &pshufb ($T1,$T3); + &pxor ($Xi,$T1); # Ii+Xi + + &clmul64x64_T3 ($Xhi,$Xi,$Hkey); # H*(Ii+Xi) + &reduction_alg5 ($Xhi,$Xi); + + &movdqa ($T3,&QWP(0,$const)); +&set_label("done"); + &pshufb ($Xi,$T3); + &movdqu (&QWP(0,$Xip),$Xi); +&function_end("gcm_ghash_clmul"); + +} + +&set_label("bswap",64); + &data_byte(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0); + &data_byte(1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xc2); # 0x1c2_polynomial +&set_label("rem_8bit",64); + &data_short(0x0000,0x01C2,0x0384,0x0246,0x0708,0x06CA,0x048C,0x054E); + &data_short(0x0E10,0x0FD2,0x0D94,0x0C56,0x0918,0x08DA,0x0A9C,0x0B5E); + &data_short(0x1C20,0x1DE2,0x1FA4,0x1E66,0x1B28,0x1AEA,0x18AC,0x196E); + &data_short(0x1230,0x13F2,0x11B4,0x1076,0x1538,0x14FA,0x16BC,0x177E); + &data_short(0x3840,0x3982,0x3BC4,0x3A06,0x3F48,0x3E8A,0x3CCC,0x3D0E); + &data_short(0x3650,0x3792,0x35D4,0x3416,0x3158,0x309A,0x32DC,0x331E); + &data_short(0x2460,0x25A2,0x27E4,0x2626,0x2368,0x22AA,0x20EC,0x212E); + &data_short(0x2A70,0x2BB2,0x29F4,0x2836,0x2D78,0x2CBA,0x2EFC,0x2F3E); + &data_short(0x7080,0x7142,0x7304,0x72C6,0x7788,0x764A,0x740C,0x75CE); + &data_short(0x7E90,0x7F52,0x7D14,0x7CD6,0x7998,0x785A,0x7A1C,0x7BDE); + &data_short(0x6CA0,0x6D62,0x6F24,0x6EE6,0x6BA8,0x6A6A,0x682C,0x69EE); + &data_short(0x62B0,0x6372,0x6134,0x60F6,0x65B8,0x647A,0x663C,0x67FE); + &data_short(0x48C0,0x4902,0x4B44,0x4A86,0x4FC8,0x4E0A,0x4C4C,0x4D8E); + &data_short(0x46D0,0x4712,0x4554,0x4496,0x41D8,0x401A,0x425C,0x439E); + &data_short(0x54E0,0x5522,0x5764,0x56A6,0x53E8,0x522A,0x506C,0x51AE); + &data_short(0x5AF0,0x5B32,0x5974,0x58B6,0x5DF8,0x5C3A,0x5E7C,0x5FBE); + &data_short(0xE100,0xE0C2,0xE284,0xE346,0xE608,0xE7CA,0xE58C,0xE44E); + &data_short(0xEF10,0xEED2,0xEC94,0xED56,0xE818,0xE9DA,0xEB9C,0xEA5E); + &data_short(0xFD20,0xFCE2,0xFEA4,0xFF66,0xFA28,0xFBEA,0xF9AC,0xF86E); + &data_short(0xF330,0xF2F2,0xF0B4,0xF176,0xF438,0xF5FA,0xF7BC,0xF67E); + &data_short(0xD940,0xD882,0xDAC4,0xDB06,0xDE48,0xDF8A,0xDDCC,0xDC0E); + &data_short(0xD750,0xD692,0xD4D4,0xD516,0xD058,0xD19A,0xD3DC,0xD21E); + &data_short(0xC560,0xC4A2,0xC6E4,0xC726,0xC268,0xC3AA,0xC1EC,0xC02E); + &data_short(0xCB70,0xCAB2,0xC8F4,0xC936,0xCC78,0xCDBA,0xCFFC,0xCE3E); + &data_short(0x9180,0x9042,0x9204,0x93C6,0x9688,0x974A,0x950C,0x94CE); + &data_short(0x9F90,0x9E52,0x9C14,0x9DD6,0x9898,0x995A,0x9B1C,0x9ADE); + &data_short(0x8DA0,0x8C62,0x8E24,0x8FE6,0x8AA8,0x8B6A,0x892C,0x88EE); + &data_short(0x83B0,0x8272,0x8034,0x81F6,0x84B8,0x857A,0x873C,0x86FE); + &data_short(0xA9C0,0xA802,0xAA44,0xAB86,0xAEC8,0xAF0A,0xAD4C,0xAC8E); + &data_short(0xA7D0,0xA612,0xA454,0xA596,0xA0D8,0xA11A,0xA35C,0xA29E); + &data_short(0xB5E0,0xB422,0xB664,0xB7A6,0xB2E8,0xB32A,0xB16C,0xB0AE); + &data_short(0xBBF0,0xBA32,0xB874,0xB9B6,0xBCF8,0xBD3A,0xBF7C,0xBEBE); +}} # $sse2 + +&set_label("rem_4bit",64); + &data_word(0,0x0000<<$S,0,0x1C20<<$S,0,0x3840<<$S,0,0x2460<<$S); + &data_word(0,0x7080<<$S,0,0x6CA0<<$S,0,0x48C0<<$S,0,0x54E0<<$S); + &data_word(0,0xE100<<$S,0,0xFD20<<$S,0,0xD940<<$S,0,0xC560<<$S); + &data_word(0,0x9180<<$S,0,0x8DA0<<$S,0,0xA9C0<<$S,0,0xB5E0<<$S); +}}} # !$x86only + +&asciz("GHASH for x86, CRYPTOGAMS by "); +&asm_finish(); + +# A question was risen about choice of vanilla MMX. Or rather why wasn't +# SSE2 chosen instead? In addition to the fact that MMX runs on legacy +# CPUs such as PIII, "4-bit" MMX version was observed to provide better +# performance than *corresponding* SSE2 one even on contemporary CPUs. +# SSE2 results were provided by Peter-Michael Hager. He maintains SSE2 +# implementation featuring full range of lookup-table sizes, but with +# per-invocation lookup table setup. Latter means that table size is +# chosen depending on how much data is to be hashed in every given call, +# more data - larger table. Best reported result for Core2 is ~4 cycles +# per processed byte out of 64KB block. This number accounts even for +# 64KB table setup overhead. As discussed in gcm128.c we choose to be +# more conservative in respect to lookup table sizes, but how do the +# results compare? Minimalistic "256B" MMX version delivers ~11 cycles +# on same platform. As also discussed in gcm128.c, next in line "8-bit +# Shoup's" or "4KB" method should deliver twice the performance of +# "256B" one, in other words not worse than ~6 cycles per byte. It +# should be also be noted that in SSE2 case improvement can be "super- +# linear," i.e. more than twice, mostly because >>8 maps to single +# instruction on SSE2 register. This is unlike "4-bit" case when >>4 +# maps to same amount of instructions in both MMX and SSE2 cases. +# Bottom line is that switch to SSE2 is considered to be justifiable +# only in case we choose to implement "8-bit" method... diff --git a/TMessagesProj/jni/boringssl/crypto/modes/asm/ghash-x86_64.pl b/TMessagesProj/jni/boringssl/crypto/modes/asm/ghash-x86_64.pl new file mode 100644 index 00000000..5a7ce394 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/modes/asm/ghash-x86_64.pl @@ -0,0 +1,1753 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# March, June 2010 +# +# The module implements "4-bit" GCM GHASH function and underlying +# single multiplication operation in GF(2^128). "4-bit" means that +# it uses 256 bytes per-key table [+128 bytes shared table]. GHASH +# function features so called "528B" variant utilizing additional +# 256+16 bytes of per-key storage [+512 bytes shared table]. +# Performance results are for this streamed GHASH subroutine and are +# expressed in cycles per processed byte, less is better: +# +# gcc 3.4.x(*) assembler +# +# P4 28.6 14.0 +100% +# Opteron 19.3 7.7 +150% +# Core2 17.8 8.1(**) +120% +# Atom 31.6 16.8 +88% +# VIA Nano 21.8 10.1 +115% +# +# (*) comparison is not completely fair, because C results are +# for vanilla "256B" implementation, while assembler results +# are for "528B";-) +# (**) it's mystery [to me] why Core2 result is not same as for +# Opteron; + +# May 2010 +# +# Add PCLMULQDQ version performing at 2.02 cycles per processed byte. +# See ghash-x86.pl for background information and details about coding +# techniques. +# +# Special thanks to David Woodhouse for +# providing access to a Westmere-based system on behalf of Intel +# Open Source Technology Centre. + +# December 2012 +# +# Overhaul: aggregate Karatsuba post-processing, improve ILP in +# reduction_alg9, increase reduction aggregate factor to 4x. As for +# the latter. ghash-x86.pl discusses that it makes lesser sense to +# increase aggregate factor. Then why increase here? Critical path +# consists of 3 independent pclmulqdq instructions, Karatsuba post- +# processing and reduction. "On top" of this we lay down aggregated +# multiplication operations, triplets of independent pclmulqdq's. As +# issue rate for pclmulqdq is limited, it makes lesser sense to +# aggregate more multiplications than it takes to perform remaining +# non-multiplication operations. 2x is near-optimal coefficient for +# contemporary Intel CPUs (therefore modest improvement coefficient), +# but not for Bulldozer. Latter is because logical SIMD operations +# are twice as slow in comparison to Intel, so that critical path is +# longer. A CPU with higher pclmulqdq issue rate would also benefit +# from higher aggregate factor... +# +# Westmere 1.78(+13%) +# Sandy Bridge 1.80(+8%) +# Ivy Bridge 1.80(+7%) +# Haswell 0.55(+93%) (if system doesn't support AVX) +# Broadwell 0.45(+110%)(if system doesn't support AVX) +# Bulldozer 1.49(+27%) +# Silvermont 2.88(+13%) + +# March 2013 +# +# ... 8x aggregate factor AVX code path is using reduction algorithm +# suggested by Shay Gueron[1]. Even though contemporary AVX-capable +# CPUs such as Sandy and Ivy Bridge can execute it, the code performs +# sub-optimally in comparison to above mentioned version. But thanks +# to Ilya Albrekht and Max Locktyukhin of Intel Corp. we knew that +# it performs in 0.41 cycles per byte on Haswell processor, and in +# 0.29 on Broadwell. +# +# [1] http://rt.openssl.org/Ticket/Display.html?id=2900&user=guest&pass=guest + +$flavour = shift; +$output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or +die "can't locate x86_64-xlate.pl"; + +if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1` + =~ /GNU assembler version ([2-9]\.[0-9]+)/) { + $avx = ($1>=2.19) + ($1>=2.22); +} + +if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) && + `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) { + $avx = ($1>=2.09) + ($1>=2.10); +} + +if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) && + `ml64 2>&1` =~ /Version ([0-9]+)\./) { + $avx = ($1>=10) + ($1>=11); +} + +if (!$avx && `$ENV{CC} -v 2>&1` =~ /(^clang version|based on LLVM) ([3-9]\.[0-9]+)/) { + $avx = ($2>=3.0) + ($2>3.0); +} + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +$do4xaggr=1; + +# common register layout +$nlo="%rax"; +$nhi="%rbx"; +$Zlo="%r8"; +$Zhi="%r9"; +$tmp="%r10"; +$rem_4bit = "%r11"; + +$Xi="%rdi"; +$Htbl="%rsi"; + +# per-function register layout +$cnt="%rcx"; +$rem="%rdx"; + +sub LB() { my $r=shift; $r =~ s/%[er]([a-d])x/%\1l/ or + $r =~ s/%[er]([sd]i)/%\1l/ or + $r =~ s/%[er](bp)/%\1l/ or + $r =~ s/%(r[0-9]+)[d]?/%\1b/; $r; } + +sub AUTOLOAD() # thunk [simplified] 32-bit style perlasm +{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://; + my $arg = pop; + $arg = "\$$arg" if ($arg*1 eq $arg); + $code .= "\t$opcode\t".join(',',$arg,reverse @_)."\n"; +} + +{ my $N; + sub loop() { + my $inp = shift; + + $N++; +$code.=<<___; + xor $nlo,$nlo + xor $nhi,$nhi + mov `&LB("$Zlo")`,`&LB("$nlo")` + mov `&LB("$Zlo")`,`&LB("$nhi")` + shl \$4,`&LB("$nlo")` + mov \$14,$cnt + mov 8($Htbl,$nlo),$Zlo + mov ($Htbl,$nlo),$Zhi + and \$0xf0,`&LB("$nhi")` + mov $Zlo,$rem + jmp .Loop$N + +.align 16 +.Loop$N: + shr \$4,$Zlo + and \$0xf,$rem + mov $Zhi,$tmp + mov ($inp,$cnt),`&LB("$nlo")` + shr \$4,$Zhi + xor 8($Htbl,$nhi),$Zlo + shl \$60,$tmp + xor ($Htbl,$nhi),$Zhi + mov `&LB("$nlo")`,`&LB("$nhi")` + xor ($rem_4bit,$rem,8),$Zhi + mov $Zlo,$rem + shl \$4,`&LB("$nlo")` + xor $tmp,$Zlo + dec $cnt + js .Lbreak$N + + shr \$4,$Zlo + and \$0xf,$rem + mov $Zhi,$tmp + shr \$4,$Zhi + xor 8($Htbl,$nlo),$Zlo + shl \$60,$tmp + xor ($Htbl,$nlo),$Zhi + and \$0xf0,`&LB("$nhi")` + xor ($rem_4bit,$rem,8),$Zhi + mov $Zlo,$rem + xor $tmp,$Zlo + jmp .Loop$N + +.align 16 +.Lbreak$N: + shr \$4,$Zlo + and \$0xf,$rem + mov $Zhi,$tmp + shr \$4,$Zhi + xor 8($Htbl,$nlo),$Zlo + shl \$60,$tmp + xor ($Htbl,$nlo),$Zhi + and \$0xf0,`&LB("$nhi")` + xor ($rem_4bit,$rem,8),$Zhi + mov $Zlo,$rem + xor $tmp,$Zlo + + shr \$4,$Zlo + and \$0xf,$rem + mov $Zhi,$tmp + shr \$4,$Zhi + xor 8($Htbl,$nhi),$Zlo + shl \$60,$tmp + xor ($Htbl,$nhi),$Zhi + xor $tmp,$Zlo + xor ($rem_4bit,$rem,8),$Zhi + + bswap $Zlo + bswap $Zhi +___ +}} + +$code=<<___; +.text +.extern OPENSSL_ia32cap_P + +.globl gcm_gmult_4bit +.type gcm_gmult_4bit,\@function,2 +.align 16 +gcm_gmult_4bit: + push %rbx + push %rbp # %rbp and %r12 are pushed exclusively in + push %r12 # order to reuse Win64 exception handler... +.Lgmult_prologue: + + movzb 15($Xi),$Zlo + lea .Lrem_4bit(%rip),$rem_4bit +___ + &loop ($Xi); +$code.=<<___; + mov $Zlo,8($Xi) + mov $Zhi,($Xi) + + mov 16(%rsp),%rbx + lea 24(%rsp),%rsp +.Lgmult_epilogue: + ret +.size gcm_gmult_4bit,.-gcm_gmult_4bit +___ + +# per-function register layout +$inp="%rdx"; +$len="%rcx"; +$rem_8bit=$rem_4bit; + +$code.=<<___; +.globl gcm_ghash_4bit +.type gcm_ghash_4bit,\@function,4 +.align 16 +gcm_ghash_4bit: + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + sub \$280,%rsp +.Lghash_prologue: + mov $inp,%r14 # reassign couple of args + mov $len,%r15 +___ +{ my $inp="%r14"; + my $dat="%edx"; + my $len="%r15"; + my @nhi=("%ebx","%ecx"); + my @rem=("%r12","%r13"); + my $Hshr4="%rbp"; + + &sub ($Htbl,-128); # size optimization + &lea ($Hshr4,"16+128(%rsp)"); + { my @lo =($nlo,$nhi); + my @hi =($Zlo,$Zhi); + + &xor ($dat,$dat); + for ($i=0,$j=-2;$i<18;$i++,$j++) { + &mov ("$j(%rsp)",&LB($dat)) if ($i>1); + &or ($lo[0],$tmp) if ($i>1); + &mov (&LB($dat),&LB($lo[1])) if ($i>0 && $i<17); + &shr ($lo[1],4) if ($i>0 && $i<17); + &mov ($tmp,$hi[1]) if ($i>0 && $i<17); + &shr ($hi[1],4) if ($i>0 && $i<17); + &mov ("8*$j($Hshr4)",$hi[0]) if ($i>1); + &mov ($hi[0],"16*$i+0-128($Htbl)") if ($i<16); + &shl (&LB($dat),4) if ($i>0 && $i<17); + &mov ("8*$j-128($Hshr4)",$lo[0]) if ($i>1); + &mov ($lo[0],"16*$i+8-128($Htbl)") if ($i<16); + &shl ($tmp,60) if ($i>0 && $i<17); + + push (@lo,shift(@lo)); + push (@hi,shift(@hi)); + } + } + &add ($Htbl,-128); + &mov ($Zlo,"8($Xi)"); + &mov ($Zhi,"0($Xi)"); + &add ($len,$inp); # pointer to the end of data + &lea ($rem_8bit,".Lrem_8bit(%rip)"); + &jmp (".Louter_loop"); + +$code.=".align 16\n.Louter_loop:\n"; + &xor ($Zhi,"($inp)"); + &mov ("%rdx","8($inp)"); + &lea ($inp,"16($inp)"); + &xor ("%rdx",$Zlo); + &mov ("($Xi)",$Zhi); + &mov ("8($Xi)","%rdx"); + &shr ("%rdx",32); + + &xor ($nlo,$nlo); + &rol ($dat,8); + &mov (&LB($nlo),&LB($dat)); + &movz ($nhi[0],&LB($dat)); + &shl (&LB($nlo),4); + &shr ($nhi[0],4); + + for ($j=11,$i=0;$i<15;$i++) { + &rol ($dat,8); + &xor ($Zlo,"8($Htbl,$nlo)") if ($i>0); + &xor ($Zhi,"($Htbl,$nlo)") if ($i>0); + &mov ($Zlo,"8($Htbl,$nlo)") if ($i==0); + &mov ($Zhi,"($Htbl,$nlo)") if ($i==0); + + &mov (&LB($nlo),&LB($dat)); + &xor ($Zlo,$tmp) if ($i>0); + &movzw ($rem[1],"($rem_8bit,$rem[1],2)") if ($i>0); + + &movz ($nhi[1],&LB($dat)); + &shl (&LB($nlo),4); + &movzb ($rem[0],"(%rsp,$nhi[0])"); + + &shr ($nhi[1],4) if ($i<14); + &and ($nhi[1],0xf0) if ($i==14); + &shl ($rem[1],48) if ($i>0); + &xor ($rem[0],$Zlo); + + &mov ($tmp,$Zhi); + &xor ($Zhi,$rem[1]) if ($i>0); + &shr ($Zlo,8); + + &movz ($rem[0],&LB($rem[0])); + &mov ($dat,"$j($Xi)") if (--$j%4==0); + &shr ($Zhi,8); + + &xor ($Zlo,"-128($Hshr4,$nhi[0],8)"); + &shl ($tmp,56); + &xor ($Zhi,"($Hshr4,$nhi[0],8)"); + + unshift (@nhi,pop(@nhi)); # "rotate" registers + unshift (@rem,pop(@rem)); + } + &movzw ($rem[1],"($rem_8bit,$rem[1],2)"); + &xor ($Zlo,"8($Htbl,$nlo)"); + &xor ($Zhi,"($Htbl,$nlo)"); + + &shl ($rem[1],48); + &xor ($Zlo,$tmp); + + &xor ($Zhi,$rem[1]); + &movz ($rem[0],&LB($Zlo)); + &shr ($Zlo,4); + + &mov ($tmp,$Zhi); + &shl (&LB($rem[0]),4); + &shr ($Zhi,4); + + &xor ($Zlo,"8($Htbl,$nhi[0])"); + &movzw ($rem[0],"($rem_8bit,$rem[0],2)"); + &shl ($tmp,60); + + &xor ($Zhi,"($Htbl,$nhi[0])"); + &xor ($Zlo,$tmp); + &shl ($rem[0],48); + + &bswap ($Zlo); + &xor ($Zhi,$rem[0]); + + &bswap ($Zhi); + &cmp ($inp,$len); + &jb (".Louter_loop"); +} +$code.=<<___; + mov $Zlo,8($Xi) + mov $Zhi,($Xi) + + lea 280(%rsp),%rsi + mov 0(%rsi),%r15 + mov 8(%rsi),%r14 + mov 16(%rsi),%r13 + mov 24(%rsi),%r12 + mov 32(%rsi),%rbp + mov 40(%rsi),%rbx + lea 48(%rsi),%rsp +.Lghash_epilogue: + ret +.size gcm_ghash_4bit,.-gcm_ghash_4bit +___ + +###################################################################### +# PCLMULQDQ version. + +@_4args=$win64? ("%rcx","%rdx","%r8", "%r9") : # Win64 order + ("%rdi","%rsi","%rdx","%rcx"); # Unix order + +($Xi,$Xhi)=("%xmm0","%xmm1"); $Hkey="%xmm2"; +($T1,$T2,$T3)=("%xmm3","%xmm4","%xmm5"); + +sub clmul64x64_T2 { # minimal register pressure +my ($Xhi,$Xi,$Hkey,$HK)=@_; + +if (!defined($HK)) { $HK = $T2; +$code.=<<___; + movdqa $Xi,$Xhi # + pshufd \$0b01001110,$Xi,$T1 + pshufd \$0b01001110,$Hkey,$T2 + pxor $Xi,$T1 # + pxor $Hkey,$T2 +___ +} else { +$code.=<<___; + movdqa $Xi,$Xhi # + pshufd \$0b01001110,$Xi,$T1 + pxor $Xi,$T1 # +___ +} +$code.=<<___; + pclmulqdq \$0x00,$Hkey,$Xi ####### + pclmulqdq \$0x11,$Hkey,$Xhi ####### + pclmulqdq \$0x00,$HK,$T1 ####### + pxor $Xi,$T1 # + pxor $Xhi,$T1 # + + movdqa $T1,$T2 # + psrldq \$8,$T1 + pslldq \$8,$T2 # + pxor $T1,$Xhi + pxor $T2,$Xi # +___ +} + +sub reduction_alg9 { # 17/11 times faster than Intel version +my ($Xhi,$Xi) = @_; + +$code.=<<___; + # 1st phase + movdqa $Xi,$T2 # + movdqa $Xi,$T1 + psllq \$5,$Xi + pxor $Xi,$T1 # + psllq \$1,$Xi + pxor $T1,$Xi # + psllq \$57,$Xi # + movdqa $Xi,$T1 # + pslldq \$8,$Xi + psrldq \$8,$T1 # + pxor $T2,$Xi + pxor $T1,$Xhi # + + # 2nd phase + movdqa $Xi,$T2 + psrlq \$1,$Xi + pxor $T2,$Xhi # + pxor $Xi,$T2 + psrlq \$5,$Xi + pxor $T2,$Xi # + psrlq \$1,$Xi # + pxor $Xhi,$Xi # +___ +} + +{ my ($Htbl,$Xip)=@_4args; + my $HK="%xmm6"; + +$code.=<<___; +.globl gcm_init_clmul +.type gcm_init_clmul,\@abi-omnipotent +.align 16 +gcm_init_clmul: +.L_init_clmul: +___ +$code.=<<___ if ($win64); +.LSEH_begin_gcm_init_clmul: + # I can't trust assembler to use specific encoding:-( + .byte 0x48,0x83,0xec,0x18 #sub $0x18,%rsp + .byte 0x0f,0x29,0x34,0x24 #movaps %xmm6,(%rsp) +___ +$code.=<<___; + movdqu ($Xip),$Hkey + pshufd \$0b01001110,$Hkey,$Hkey # dword swap + + # <<1 twist + pshufd \$0b11111111,$Hkey,$T2 # broadcast uppermost dword + movdqa $Hkey,$T1 + psllq \$1,$Hkey + pxor $T3,$T3 # + psrlq \$63,$T1 + pcmpgtd $T2,$T3 # broadcast carry bit + pslldq \$8,$T1 + por $T1,$Hkey # H<<=1 + + # magic reduction + pand .L0x1c2_polynomial(%rip),$T3 + pxor $T3,$Hkey # if(carry) H^=0x1c2_polynomial + + # calculate H^2 + pshufd \$0b01001110,$Hkey,$HK + movdqa $Hkey,$Xi + pxor $Hkey,$HK +___ + &clmul64x64_T2 ($Xhi,$Xi,$Hkey,$HK); + &reduction_alg9 ($Xhi,$Xi); +$code.=<<___; + pshufd \$0b01001110,$Hkey,$T1 + pshufd \$0b01001110,$Xi,$T2 + pxor $Hkey,$T1 # Karatsuba pre-processing + movdqu $Hkey,0x00($Htbl) # save H + pxor $Xi,$T2 # Karatsuba pre-processing + movdqu $Xi,0x10($Htbl) # save H^2 + palignr \$8,$T1,$T2 # low part is H.lo^H.hi... + movdqu $T2,0x20($Htbl) # save Karatsuba "salt" +___ +if ($do4xaggr) { + &clmul64x64_T2 ($Xhi,$Xi,$Hkey,$HK); # H^3 + &reduction_alg9 ($Xhi,$Xi); +$code.=<<___; + movdqa $Xi,$T3 +___ + &clmul64x64_T2 ($Xhi,$Xi,$Hkey,$HK); # H^4 + &reduction_alg9 ($Xhi,$Xi); +$code.=<<___; + pshufd \$0b01001110,$T3,$T1 + pshufd \$0b01001110,$Xi,$T2 + pxor $T3,$T1 # Karatsuba pre-processing + movdqu $T3,0x30($Htbl) # save H^3 + pxor $Xi,$T2 # Karatsuba pre-processing + movdqu $Xi,0x40($Htbl) # save H^4 + palignr \$8,$T1,$T2 # low part is H^3.lo^H^3.hi... + movdqu $T2,0x50($Htbl) # save Karatsuba "salt" +___ +} +$code.=<<___ if ($win64); + movaps (%rsp),%xmm6 + lea 0x18(%rsp),%rsp +.LSEH_end_gcm_init_clmul: +___ +$code.=<<___; + ret +.size gcm_init_clmul,.-gcm_init_clmul +___ +} + +{ my ($Xip,$Htbl)=@_4args; + +$code.=<<___; +.globl gcm_gmult_clmul +.type gcm_gmult_clmul,\@abi-omnipotent +.align 16 +gcm_gmult_clmul: +.L_gmult_clmul: + movdqu ($Xip),$Xi + movdqa .Lbswap_mask(%rip),$T3 + movdqu ($Htbl),$Hkey + movdqu 0x20($Htbl),$T2 + pshufb $T3,$Xi +___ + &clmul64x64_T2 ($Xhi,$Xi,$Hkey,$T2); +$code.=<<___ if (0 || (&reduction_alg9($Xhi,$Xi)&&0)); + # experimental alternative. special thing about is that there + # no dependency between the two multiplications... + mov \$`0xE1<<1`,%eax + mov \$0xA040608020C0E000,%r10 # ((7..0)·0xE0)&0xff + mov \$0x07,%r11d + movq %rax,$T1 + movq %r10,$T2 + movq %r11,$T3 # borrow $T3 + pand $Xi,$T3 + pshufb $T3,$T2 # ($Xi&7)·0xE0 + movq %rax,$T3 + pclmulqdq \$0x00,$Xi,$T1 # ·(0xE1<<1) + pxor $Xi,$T2 + pslldq \$15,$T2 + paddd $T2,$T2 # <<(64+56+1) + pxor $T2,$Xi + pclmulqdq \$0x01,$T3,$Xi + movdqa .Lbswap_mask(%rip),$T3 # reload $T3 + psrldq \$1,$T1 + pxor $T1,$Xhi + pslldq \$7,$Xi + pxor $Xhi,$Xi +___ +$code.=<<___; + pshufb $T3,$Xi + movdqu $Xi,($Xip) + ret +.size gcm_gmult_clmul,.-gcm_gmult_clmul +___ +} + +{ my ($Xip,$Htbl,$inp,$len)=@_4args; + my ($Xln,$Xmn,$Xhn,$Hkey2,$HK) = map("%xmm$_",(3..7)); + my ($T1,$T2,$T3)=map("%xmm$_",(8..10)); + +$code.=<<___; +.globl gcm_ghash_clmul +.type gcm_ghash_clmul,\@abi-omnipotent +.align 32 +gcm_ghash_clmul: +.L_ghash_clmul: +___ +$code.=<<___ if ($win64); + lea -0x88(%rsp),%rax +.LSEH_begin_gcm_ghash_clmul: + # I can't trust assembler to use specific encoding:-( + .byte 0x48,0x8d,0x60,0xe0 #lea -0x20(%rax),%rsp + .byte 0x0f,0x29,0x70,0xe0 #movaps %xmm6,-0x20(%rax) + .byte 0x0f,0x29,0x78,0xf0 #movaps %xmm7,-0x10(%rax) + .byte 0x44,0x0f,0x29,0x00 #movaps %xmm8,0(%rax) + .byte 0x44,0x0f,0x29,0x48,0x10 #movaps %xmm9,0x10(%rax) + .byte 0x44,0x0f,0x29,0x50,0x20 #movaps %xmm10,0x20(%rax) + .byte 0x44,0x0f,0x29,0x58,0x30 #movaps %xmm11,0x30(%rax) + .byte 0x44,0x0f,0x29,0x60,0x40 #movaps %xmm12,0x40(%rax) + .byte 0x44,0x0f,0x29,0x68,0x50 #movaps %xmm13,0x50(%rax) + .byte 0x44,0x0f,0x29,0x70,0x60 #movaps %xmm14,0x60(%rax) + .byte 0x44,0x0f,0x29,0x78,0x70 #movaps %xmm15,0x70(%rax) +___ +$code.=<<___; + movdqa .Lbswap_mask(%rip),$T3 + + movdqu ($Xip),$Xi + movdqu ($Htbl),$Hkey + movdqu 0x20($Htbl),$HK + pshufb $T3,$Xi + + sub \$0x10,$len + jz .Lodd_tail + + movdqu 0x10($Htbl),$Hkey2 +___ +if ($do4xaggr) { +my ($Xl,$Xm,$Xh,$Hkey3,$Hkey4)=map("%xmm$_",(11..15)); + +$code.=<<___; + mov OPENSSL_ia32cap_P+4(%rip),%eax + cmp \$0x30,$len + jb .Lskip4x + + and \$`1<<26|1<<22`,%eax # isolate MOVBE+XSAVE + cmp \$`1<<22`,%eax # check for MOVBE without XSAVE + je .Lskip4x + + sub \$0x30,$len + mov \$0xA040608020C0E000,%rax # ((7..0)·0xE0)&0xff + movdqu 0x30($Htbl),$Hkey3 + movdqu 0x40($Htbl),$Hkey4 + + ####### + # Xi+4 =[(H*Ii+3) + (H^2*Ii+2) + (H^3*Ii+1) + H^4*(Ii+Xi)] mod P + # + movdqu 0x30($inp),$Xln + movdqu 0x20($inp),$Xl + pshufb $T3,$Xln + pshufb $T3,$Xl + movdqa $Xln,$Xhn + pshufd \$0b01001110,$Xln,$Xmn + pxor $Xln,$Xmn + pclmulqdq \$0x00,$Hkey,$Xln + pclmulqdq \$0x11,$Hkey,$Xhn + pclmulqdq \$0x00,$HK,$Xmn + + movdqa $Xl,$Xh + pshufd \$0b01001110,$Xl,$Xm + pxor $Xl,$Xm + pclmulqdq \$0x00,$Hkey2,$Xl + pclmulqdq \$0x11,$Hkey2,$Xh + pclmulqdq \$0x10,$HK,$Xm + xorps $Xl,$Xln + xorps $Xh,$Xhn + movups 0x50($Htbl),$HK + xorps $Xm,$Xmn + + movdqu 0x10($inp),$Xl + movdqu 0($inp),$T1 + pshufb $T3,$Xl + pshufb $T3,$T1 + movdqa $Xl,$Xh + pshufd \$0b01001110,$Xl,$Xm + pxor $T1,$Xi + pxor $Xl,$Xm + pclmulqdq \$0x00,$Hkey3,$Xl + movdqa $Xi,$Xhi + pshufd \$0b01001110,$Xi,$T1 + pxor $Xi,$T1 + pclmulqdq \$0x11,$Hkey3,$Xh + pclmulqdq \$0x00,$HK,$Xm + xorps $Xl,$Xln + xorps $Xh,$Xhn + + lea 0x40($inp),$inp + sub \$0x40,$len + jc .Ltail4x + + jmp .Lmod4_loop +.align 32 +.Lmod4_loop: + pclmulqdq \$0x00,$Hkey4,$Xi + xorps $Xm,$Xmn + movdqu 0x30($inp),$Xl + pshufb $T3,$Xl + pclmulqdq \$0x11,$Hkey4,$Xhi + xorps $Xln,$Xi + movdqu 0x20($inp),$Xln + movdqa $Xl,$Xh + pclmulqdq \$0x10,$HK,$T1 + pshufd \$0b01001110,$Xl,$Xm + xorps $Xhn,$Xhi + pxor $Xl,$Xm + pshufb $T3,$Xln + movups 0x20($Htbl),$HK + xorps $Xmn,$T1 + pclmulqdq \$0x00,$Hkey,$Xl + pshufd \$0b01001110,$Xln,$Xmn + + pxor $Xi,$T1 # aggregated Karatsuba post-processing + movdqa $Xln,$Xhn + pxor $Xhi,$T1 # + pxor $Xln,$Xmn + movdqa $T1,$T2 # + pclmulqdq \$0x11,$Hkey,$Xh + pslldq \$8,$T1 + psrldq \$8,$T2 # + pxor $T1,$Xi + movdqa .L7_mask(%rip),$T1 + pxor $T2,$Xhi # + movq %rax,$T2 + + pand $Xi,$T1 # 1st phase + pshufb $T1,$T2 # + pxor $Xi,$T2 # + pclmulqdq \$0x00,$HK,$Xm + psllq \$57,$T2 # + movdqa $T2,$T1 # + pslldq \$8,$T2 + pclmulqdq \$0x00,$Hkey2,$Xln + psrldq \$8,$T1 # + pxor $T2,$Xi + pxor $T1,$Xhi # + movdqu 0($inp),$T1 + + movdqa $Xi,$T2 # 2nd phase + psrlq \$1,$Xi + pclmulqdq \$0x11,$Hkey2,$Xhn + xorps $Xl,$Xln + movdqu 0x10($inp),$Xl + pshufb $T3,$Xl + pclmulqdq \$0x10,$HK,$Xmn + xorps $Xh,$Xhn + movups 0x50($Htbl),$HK + pshufb $T3,$T1 + pxor $T2,$Xhi # + pxor $Xi,$T2 + psrlq \$5,$Xi + + movdqa $Xl,$Xh + pxor $Xm,$Xmn + pshufd \$0b01001110,$Xl,$Xm + pxor $T2,$Xi # + pxor $T1,$Xhi + pxor $Xl,$Xm + pclmulqdq \$0x00,$Hkey3,$Xl + psrlq \$1,$Xi # + pxor $Xhi,$Xi # + movdqa $Xi,$Xhi + pclmulqdq \$0x11,$Hkey3,$Xh + xorps $Xl,$Xln + pshufd \$0b01001110,$Xi,$T1 + pxor $Xi,$T1 + + pclmulqdq \$0x00,$HK,$Xm + xorps $Xh,$Xhn + + lea 0x40($inp),$inp + sub \$0x40,$len + jnc .Lmod4_loop + +.Ltail4x: + pclmulqdq \$0x00,$Hkey4,$Xi + pclmulqdq \$0x11,$Hkey4,$Xhi + pclmulqdq \$0x10,$HK,$T1 + xorps $Xm,$Xmn + xorps $Xln,$Xi + xorps $Xhn,$Xhi + pxor $Xi,$Xhi # aggregated Karatsuba post-processing + pxor $Xmn,$T1 + + pxor $Xhi,$T1 # + pxor $Xi,$Xhi + + movdqa $T1,$T2 # + psrldq \$8,$T1 + pslldq \$8,$T2 # + pxor $T1,$Xhi + pxor $T2,$Xi # +___ + &reduction_alg9($Xhi,$Xi); +$code.=<<___; + add \$0x40,$len + jz .Ldone + movdqu 0x20($Htbl),$HK + sub \$0x10,$len + jz .Lodd_tail +.Lskip4x: +___ +} +$code.=<<___; + ####### + # Xi+2 =[H*(Ii+1 + Xi+1)] mod P = + # [(H*Ii+1) + (H*Xi+1)] mod P = + # [(H*Ii+1) + H^2*(Ii+Xi)] mod P + # + movdqu ($inp),$T1 # Ii + movdqu 16($inp),$Xln # Ii+1 + pshufb $T3,$T1 + pshufb $T3,$Xln + pxor $T1,$Xi # Ii+Xi + + movdqa $Xln,$Xhn + pshufd \$0b01001110,$Xln,$Xmn + pxor $Xln,$Xmn + pclmulqdq \$0x00,$Hkey,$Xln + pclmulqdq \$0x11,$Hkey,$Xhn + pclmulqdq \$0x00,$HK,$Xmn + + lea 32($inp),$inp # i+=2 + nop + sub \$0x20,$len + jbe .Leven_tail + nop + jmp .Lmod_loop + +.align 32 +.Lmod_loop: + movdqa $Xi,$Xhi + movdqa $Xmn,$T1 + pshufd \$0b01001110,$Xi,$Xmn # + pxor $Xi,$Xmn # + + pclmulqdq \$0x00,$Hkey2,$Xi + pclmulqdq \$0x11,$Hkey2,$Xhi + pclmulqdq \$0x10,$HK,$Xmn + + pxor $Xln,$Xi # (H*Ii+1) + H^2*(Ii+Xi) + pxor $Xhn,$Xhi + movdqu ($inp),$T2 # Ii + pxor $Xi,$T1 # aggregated Karatsuba post-processing + pshufb $T3,$T2 + movdqu 16($inp),$Xln # Ii+1 + + pxor $Xhi,$T1 + pxor $T2,$Xhi # "Ii+Xi", consume early + pxor $T1,$Xmn + pshufb $T3,$Xln + movdqa $Xmn,$T1 # + psrldq \$8,$T1 + pslldq \$8,$Xmn # + pxor $T1,$Xhi + pxor $Xmn,$Xi # + + movdqa $Xln,$Xhn # + + movdqa $Xi,$T2 # 1st phase + movdqa $Xi,$T1 + psllq \$5,$Xi + pxor $Xi,$T1 # + pclmulqdq \$0x00,$Hkey,$Xln ####### + psllq \$1,$Xi + pxor $T1,$Xi # + psllq \$57,$Xi # + movdqa $Xi,$T1 # + pslldq \$8,$Xi + psrldq \$8,$T1 # + pxor $T2,$Xi + pshufd \$0b01001110,$Xhn,$Xmn + pxor $T1,$Xhi # + pxor $Xhn,$Xmn # + + movdqa $Xi,$T2 # 2nd phase + psrlq \$1,$Xi + pclmulqdq \$0x11,$Hkey,$Xhn ####### + pxor $T2,$Xhi # + pxor $Xi,$T2 + psrlq \$5,$Xi + pxor $T2,$Xi # + lea 32($inp),$inp + psrlq \$1,$Xi # + pclmulqdq \$0x00,$HK,$Xmn ####### + pxor $Xhi,$Xi # + + sub \$0x20,$len + ja .Lmod_loop + +.Leven_tail: + movdqa $Xi,$Xhi + movdqa $Xmn,$T1 + pshufd \$0b01001110,$Xi,$Xmn # + pxor $Xi,$Xmn # + + pclmulqdq \$0x00,$Hkey2,$Xi + pclmulqdq \$0x11,$Hkey2,$Xhi + pclmulqdq \$0x10,$HK,$Xmn + + pxor $Xln,$Xi # (H*Ii+1) + H^2*(Ii+Xi) + pxor $Xhn,$Xhi + pxor $Xi,$T1 + pxor $Xhi,$T1 + pxor $T1,$Xmn + movdqa $Xmn,$T1 # + psrldq \$8,$T1 + pslldq \$8,$Xmn # + pxor $T1,$Xhi + pxor $Xmn,$Xi # +___ + &reduction_alg9 ($Xhi,$Xi); +$code.=<<___; + test $len,$len + jnz .Ldone + +.Lodd_tail: + movdqu ($inp),$T1 # Ii + pshufb $T3,$T1 + pxor $T1,$Xi # Ii+Xi +___ + &clmul64x64_T2 ($Xhi,$Xi,$Hkey,$HK); # H*(Ii+Xi) + &reduction_alg9 ($Xhi,$Xi); +$code.=<<___; +.Ldone: + pshufb $T3,$Xi + movdqu $Xi,($Xip) +___ +$code.=<<___ if ($win64); + movaps (%rsp),%xmm6 + movaps 0x10(%rsp),%xmm7 + movaps 0x20(%rsp),%xmm8 + movaps 0x30(%rsp),%xmm9 + movaps 0x40(%rsp),%xmm10 + movaps 0x50(%rsp),%xmm11 + movaps 0x60(%rsp),%xmm12 + movaps 0x70(%rsp),%xmm13 + movaps 0x80(%rsp),%xmm14 + movaps 0x90(%rsp),%xmm15 + lea 0xa8(%rsp),%rsp +.LSEH_end_gcm_ghash_clmul: +___ +$code.=<<___; + ret +.size gcm_ghash_clmul,.-gcm_ghash_clmul +___ +} + +$code.=<<___; +.globl gcm_init_avx +.type gcm_init_avx,\@abi-omnipotent +.align 32 +gcm_init_avx: +___ +if ($avx) { +my ($Htbl,$Xip)=@_4args; +my $HK="%xmm6"; + +$code.=<<___ if ($win64); +.LSEH_begin_gcm_init_avx: + # I can't trust assembler to use specific encoding:-( + .byte 0x48,0x83,0xec,0x18 #sub $0x18,%rsp + .byte 0x0f,0x29,0x34,0x24 #movaps %xmm6,(%rsp) +___ +$code.=<<___; + vzeroupper + + vmovdqu ($Xip),$Hkey + vpshufd \$0b01001110,$Hkey,$Hkey # dword swap + + # <<1 twist + vpshufd \$0b11111111,$Hkey,$T2 # broadcast uppermost dword + vpsrlq \$63,$Hkey,$T1 + vpsllq \$1,$Hkey,$Hkey + vpxor $T3,$T3,$T3 # + vpcmpgtd $T2,$T3,$T3 # broadcast carry bit + vpslldq \$8,$T1,$T1 + vpor $T1,$Hkey,$Hkey # H<<=1 + + # magic reduction + vpand .L0x1c2_polynomial(%rip),$T3,$T3 + vpxor $T3,$Hkey,$Hkey # if(carry) H^=0x1c2_polynomial + + vpunpckhqdq $Hkey,$Hkey,$HK + vmovdqa $Hkey,$Xi + vpxor $Hkey,$HK,$HK + mov \$4,%r10 # up to H^8 + jmp .Linit_start_avx +___ + +sub clmul64x64_avx { +my ($Xhi,$Xi,$Hkey,$HK)=@_; + +if (!defined($HK)) { $HK = $T2; +$code.=<<___; + vpunpckhqdq $Xi,$Xi,$T1 + vpunpckhqdq $Hkey,$Hkey,$T2 + vpxor $Xi,$T1,$T1 # + vpxor $Hkey,$T2,$T2 +___ +} else { +$code.=<<___; + vpunpckhqdq $Xi,$Xi,$T1 + vpxor $Xi,$T1,$T1 # +___ +} +$code.=<<___; + vpclmulqdq \$0x11,$Hkey,$Xi,$Xhi ####### + vpclmulqdq \$0x00,$Hkey,$Xi,$Xi ####### + vpclmulqdq \$0x00,$HK,$T1,$T1 ####### + vpxor $Xi,$Xhi,$T2 # + vpxor $T2,$T1,$T1 # + + vpslldq \$8,$T1,$T2 # + vpsrldq \$8,$T1,$T1 + vpxor $T2,$Xi,$Xi # + vpxor $T1,$Xhi,$Xhi +___ +} + +sub reduction_avx { +my ($Xhi,$Xi) = @_; + +$code.=<<___; + vpsllq \$57,$Xi,$T1 # 1st phase + vpsllq \$62,$Xi,$T2 + vpxor $T1,$T2,$T2 # + vpsllq \$63,$Xi,$T1 + vpxor $T1,$T2,$T2 # + vpslldq \$8,$T2,$T1 # + vpsrldq \$8,$T2,$T2 + vpxor $T1,$Xi,$Xi # + vpxor $T2,$Xhi,$Xhi + + vpsrlq \$1,$Xi,$T2 # 2nd phase + vpxor $Xi,$Xhi,$Xhi + vpxor $T2,$Xi,$Xi # + vpsrlq \$5,$T2,$T2 + vpxor $T2,$Xi,$Xi # + vpsrlq \$1,$Xi,$Xi # + vpxor $Xhi,$Xi,$Xi # +___ +} + +$code.=<<___; +.align 32 +.Linit_loop_avx: + vpalignr \$8,$T1,$T2,$T3 # low part is H.lo^H.hi... + vmovdqu $T3,-0x10($Htbl) # save Karatsuba "salt" +___ + &clmul64x64_avx ($Xhi,$Xi,$Hkey,$HK); # calculate H^3,5,7 + &reduction_avx ($Xhi,$Xi); +$code.=<<___; +.Linit_start_avx: + vmovdqa $Xi,$T3 +___ + &clmul64x64_avx ($Xhi,$Xi,$Hkey,$HK); # calculate H^2,4,6,8 + &reduction_avx ($Xhi,$Xi); +$code.=<<___; + vpshufd \$0b01001110,$T3,$T1 + vpshufd \$0b01001110,$Xi,$T2 + vpxor $T3,$T1,$T1 # Karatsuba pre-processing + vmovdqu $T3,0x00($Htbl) # save H^1,3,5,7 + vpxor $Xi,$T2,$T2 # Karatsuba pre-processing + vmovdqu $Xi,0x10($Htbl) # save H^2,4,6,8 + lea 0x30($Htbl),$Htbl + sub \$1,%r10 + jnz .Linit_loop_avx + + vpalignr \$8,$T2,$T1,$T3 # last "salt" is flipped + vmovdqu $T3,-0x10($Htbl) + + vzeroupper +___ +$code.=<<___ if ($win64); + movaps (%rsp),%xmm6 + lea 0x18(%rsp),%rsp +.LSEH_end_gcm_init_avx: +___ +$code.=<<___; + ret +.size gcm_init_avx,.-gcm_init_avx +___ +} else { +$code.=<<___; + jmp .L_init_clmul +.size gcm_init_avx,.-gcm_init_avx +___ +} + +$code.=<<___; +.globl gcm_gmult_avx +.type gcm_gmult_avx,\@abi-omnipotent +.align 32 +gcm_gmult_avx: + jmp .L_gmult_clmul +.size gcm_gmult_avx,.-gcm_gmult_avx +___ + +$code.=<<___; +.globl gcm_ghash_avx +.type gcm_ghash_avx,\@abi-omnipotent +.align 32 +gcm_ghash_avx: +___ +if ($avx) { +my ($Xip,$Htbl,$inp,$len)=@_4args; +my ($Xlo,$Xhi,$Xmi, + $Zlo,$Zhi,$Zmi, + $Hkey,$HK,$T1,$T2, + $Xi,$Xo,$Tred,$bswap,$Ii,$Ij) = map("%xmm$_",(0..15)); + +$code.=<<___ if ($win64); + lea -0x88(%rsp),%rax +.LSEH_begin_gcm_ghash_avx: + # I can't trust assembler to use specific encoding:-( + .byte 0x48,0x8d,0x60,0xe0 #lea -0x20(%rax),%rsp + .byte 0x0f,0x29,0x70,0xe0 #movaps %xmm6,-0x20(%rax) + .byte 0x0f,0x29,0x78,0xf0 #movaps %xmm7,-0x10(%rax) + .byte 0x44,0x0f,0x29,0x00 #movaps %xmm8,0(%rax) + .byte 0x44,0x0f,0x29,0x48,0x10 #movaps %xmm9,0x10(%rax) + .byte 0x44,0x0f,0x29,0x50,0x20 #movaps %xmm10,0x20(%rax) + .byte 0x44,0x0f,0x29,0x58,0x30 #movaps %xmm11,0x30(%rax) + .byte 0x44,0x0f,0x29,0x60,0x40 #movaps %xmm12,0x40(%rax) + .byte 0x44,0x0f,0x29,0x68,0x50 #movaps %xmm13,0x50(%rax) + .byte 0x44,0x0f,0x29,0x70,0x60 #movaps %xmm14,0x60(%rax) + .byte 0x44,0x0f,0x29,0x78,0x70 #movaps %xmm15,0x70(%rax) +___ +$code.=<<___; + vzeroupper + + vmovdqu ($Xip),$Xi # load $Xi + lea .L0x1c2_polynomial(%rip),%r10 + lea 0x40($Htbl),$Htbl # size optimization + vmovdqu .Lbswap_mask(%rip),$bswap + vpshufb $bswap,$Xi,$Xi + cmp \$0x80,$len + jb .Lshort_avx + sub \$0x80,$len + + vmovdqu 0x70($inp),$Ii # I[7] + vmovdqu 0x00-0x40($Htbl),$Hkey # $Hkey^1 + vpshufb $bswap,$Ii,$Ii + vmovdqu 0x20-0x40($Htbl),$HK + + vpunpckhqdq $Ii,$Ii,$T2 + vmovdqu 0x60($inp),$Ij # I[6] + vpclmulqdq \$0x00,$Hkey,$Ii,$Xlo + vpxor $Ii,$T2,$T2 + vpshufb $bswap,$Ij,$Ij + vpclmulqdq \$0x11,$Hkey,$Ii,$Xhi + vmovdqu 0x10-0x40($Htbl),$Hkey # $Hkey^2 + vpunpckhqdq $Ij,$Ij,$T1 + vmovdqu 0x50($inp),$Ii # I[5] + vpclmulqdq \$0x00,$HK,$T2,$Xmi + vpxor $Ij,$T1,$T1 + + vpshufb $bswap,$Ii,$Ii + vpclmulqdq \$0x00,$Hkey,$Ij,$Zlo + vpunpckhqdq $Ii,$Ii,$T2 + vpclmulqdq \$0x11,$Hkey,$Ij,$Zhi + vmovdqu 0x30-0x40($Htbl),$Hkey # $Hkey^3 + vpxor $Ii,$T2,$T2 + vmovdqu 0x40($inp),$Ij # I[4] + vpclmulqdq \$0x10,$HK,$T1,$Zmi + vmovdqu 0x50-0x40($Htbl),$HK + + vpshufb $bswap,$Ij,$Ij + vpxor $Xlo,$Zlo,$Zlo + vpclmulqdq \$0x00,$Hkey,$Ii,$Xlo + vpxor $Xhi,$Zhi,$Zhi + vpunpckhqdq $Ij,$Ij,$T1 + vpclmulqdq \$0x11,$Hkey,$Ii,$Xhi + vmovdqu 0x40-0x40($Htbl),$Hkey # $Hkey^4 + vpxor $Xmi,$Zmi,$Zmi + vpclmulqdq \$0x00,$HK,$T2,$Xmi + vpxor $Ij,$T1,$T1 + + vmovdqu 0x30($inp),$Ii # I[3] + vpxor $Zlo,$Xlo,$Xlo + vpclmulqdq \$0x00,$Hkey,$Ij,$Zlo + vpxor $Zhi,$Xhi,$Xhi + vpshufb $bswap,$Ii,$Ii + vpclmulqdq \$0x11,$Hkey,$Ij,$Zhi + vmovdqu 0x60-0x40($Htbl),$Hkey # $Hkey^5 + vpxor $Zmi,$Xmi,$Xmi + vpunpckhqdq $Ii,$Ii,$T2 + vpclmulqdq \$0x10,$HK,$T1,$Zmi + vmovdqu 0x80-0x40($Htbl),$HK + vpxor $Ii,$T2,$T2 + + vmovdqu 0x20($inp),$Ij # I[2] + vpxor $Xlo,$Zlo,$Zlo + vpclmulqdq \$0x00,$Hkey,$Ii,$Xlo + vpxor $Xhi,$Zhi,$Zhi + vpshufb $bswap,$Ij,$Ij + vpclmulqdq \$0x11,$Hkey,$Ii,$Xhi + vmovdqu 0x70-0x40($Htbl),$Hkey # $Hkey^6 + vpxor $Xmi,$Zmi,$Zmi + vpunpckhqdq $Ij,$Ij,$T1 + vpclmulqdq \$0x00,$HK,$T2,$Xmi + vpxor $Ij,$T1,$T1 + + vmovdqu 0x10($inp),$Ii # I[1] + vpxor $Zlo,$Xlo,$Xlo + vpclmulqdq \$0x00,$Hkey,$Ij,$Zlo + vpxor $Zhi,$Xhi,$Xhi + vpshufb $bswap,$Ii,$Ii + vpclmulqdq \$0x11,$Hkey,$Ij,$Zhi + vmovdqu 0x90-0x40($Htbl),$Hkey # $Hkey^7 + vpxor $Zmi,$Xmi,$Xmi + vpunpckhqdq $Ii,$Ii,$T2 + vpclmulqdq \$0x10,$HK,$T1,$Zmi + vmovdqu 0xb0-0x40($Htbl),$HK + vpxor $Ii,$T2,$T2 + + vmovdqu ($inp),$Ij # I[0] + vpxor $Xlo,$Zlo,$Zlo + vpclmulqdq \$0x00,$Hkey,$Ii,$Xlo + vpxor $Xhi,$Zhi,$Zhi + vpshufb $bswap,$Ij,$Ij + vpclmulqdq \$0x11,$Hkey,$Ii,$Xhi + vmovdqu 0xa0-0x40($Htbl),$Hkey # $Hkey^8 + vpxor $Xmi,$Zmi,$Zmi + vpclmulqdq \$0x10,$HK,$T2,$Xmi + + lea 0x80($inp),$inp + cmp \$0x80,$len + jb .Ltail_avx + + vpxor $Xi,$Ij,$Ij # accumulate $Xi + sub \$0x80,$len + jmp .Loop8x_avx + +.align 32 +.Loop8x_avx: + vpunpckhqdq $Ij,$Ij,$T1 + vmovdqu 0x70($inp),$Ii # I[7] + vpxor $Xlo,$Zlo,$Zlo + vpxor $Ij,$T1,$T1 + vpclmulqdq \$0x00,$Hkey,$Ij,$Xi + vpshufb $bswap,$Ii,$Ii + vpxor $Xhi,$Zhi,$Zhi + vpclmulqdq \$0x11,$Hkey,$Ij,$Xo + vmovdqu 0x00-0x40($Htbl),$Hkey # $Hkey^1 + vpunpckhqdq $Ii,$Ii,$T2 + vpxor $Xmi,$Zmi,$Zmi + vpclmulqdq \$0x00,$HK,$T1,$Tred + vmovdqu 0x20-0x40($Htbl),$HK + vpxor $Ii,$T2,$T2 + + vmovdqu 0x60($inp),$Ij # I[6] + vpclmulqdq \$0x00,$Hkey,$Ii,$Xlo + vpxor $Zlo,$Xi,$Xi # collect result + vpshufb $bswap,$Ij,$Ij + vpclmulqdq \$0x11,$Hkey,$Ii,$Xhi + vxorps $Zhi,$Xo,$Xo + vmovdqu 0x10-0x40($Htbl),$Hkey # $Hkey^2 + vpunpckhqdq $Ij,$Ij,$T1 + vpclmulqdq \$0x00,$HK, $T2,$Xmi + vpxor $Zmi,$Tred,$Tred + vxorps $Ij,$T1,$T1 + + vmovdqu 0x50($inp),$Ii # I[5] + vpxor $Xi,$Tred,$Tred # aggregated Karatsuba post-processing + vpclmulqdq \$0x00,$Hkey,$Ij,$Zlo + vpxor $Xo,$Tred,$Tred + vpslldq \$8,$Tred,$T2 + vpxor $Xlo,$Zlo,$Zlo + vpclmulqdq \$0x11,$Hkey,$Ij,$Zhi + vpsrldq \$8,$Tred,$Tred + vpxor $T2, $Xi, $Xi + vmovdqu 0x30-0x40($Htbl),$Hkey # $Hkey^3 + vpshufb $bswap,$Ii,$Ii + vxorps $Tred,$Xo, $Xo + vpxor $Xhi,$Zhi,$Zhi + vpunpckhqdq $Ii,$Ii,$T2 + vpclmulqdq \$0x10,$HK, $T1,$Zmi + vmovdqu 0x50-0x40($Htbl),$HK + vpxor $Ii,$T2,$T2 + vpxor $Xmi,$Zmi,$Zmi + + vmovdqu 0x40($inp),$Ij # I[4] + vpalignr \$8,$Xi,$Xi,$Tred # 1st phase + vpclmulqdq \$0x00,$Hkey,$Ii,$Xlo + vpshufb $bswap,$Ij,$Ij + vpxor $Zlo,$Xlo,$Xlo + vpclmulqdq \$0x11,$Hkey,$Ii,$Xhi + vmovdqu 0x40-0x40($Htbl),$Hkey # $Hkey^4 + vpunpckhqdq $Ij,$Ij,$T1 + vpxor $Zhi,$Xhi,$Xhi + vpclmulqdq \$0x00,$HK, $T2,$Xmi + vxorps $Ij,$T1,$T1 + vpxor $Zmi,$Xmi,$Xmi + + vmovdqu 0x30($inp),$Ii # I[3] + vpclmulqdq \$0x10,(%r10),$Xi,$Xi + vpclmulqdq \$0x00,$Hkey,$Ij,$Zlo + vpshufb $bswap,$Ii,$Ii + vpxor $Xlo,$Zlo,$Zlo + vpclmulqdq \$0x11,$Hkey,$Ij,$Zhi + vmovdqu 0x60-0x40($Htbl),$Hkey # $Hkey^5 + vpunpckhqdq $Ii,$Ii,$T2 + vpxor $Xhi,$Zhi,$Zhi + vpclmulqdq \$0x10,$HK, $T1,$Zmi + vmovdqu 0x80-0x40($Htbl),$HK + vpxor $Ii,$T2,$T2 + vpxor $Xmi,$Zmi,$Zmi + + vmovdqu 0x20($inp),$Ij # I[2] + vpclmulqdq \$0x00,$Hkey,$Ii,$Xlo + vpshufb $bswap,$Ij,$Ij + vpxor $Zlo,$Xlo,$Xlo + vpclmulqdq \$0x11,$Hkey,$Ii,$Xhi + vmovdqu 0x70-0x40($Htbl),$Hkey # $Hkey^6 + vpunpckhqdq $Ij,$Ij,$T1 + vpxor $Zhi,$Xhi,$Xhi + vpclmulqdq \$0x00,$HK, $T2,$Xmi + vpxor $Ij,$T1,$T1 + vpxor $Zmi,$Xmi,$Xmi + vxorps $Tred,$Xi,$Xi + + vmovdqu 0x10($inp),$Ii # I[1] + vpalignr \$8,$Xi,$Xi,$Tred # 2nd phase + vpclmulqdq \$0x00,$Hkey,$Ij,$Zlo + vpshufb $bswap,$Ii,$Ii + vpxor $Xlo,$Zlo,$Zlo + vpclmulqdq \$0x11,$Hkey,$Ij,$Zhi + vmovdqu 0x90-0x40($Htbl),$Hkey # $Hkey^7 + vpclmulqdq \$0x10,(%r10),$Xi,$Xi + vxorps $Xo,$Tred,$Tred + vpunpckhqdq $Ii,$Ii,$T2 + vpxor $Xhi,$Zhi,$Zhi + vpclmulqdq \$0x10,$HK, $T1,$Zmi + vmovdqu 0xb0-0x40($Htbl),$HK + vpxor $Ii,$T2,$T2 + vpxor $Xmi,$Zmi,$Zmi + + vmovdqu ($inp),$Ij # I[0] + vpclmulqdq \$0x00,$Hkey,$Ii,$Xlo + vpshufb $bswap,$Ij,$Ij + vpclmulqdq \$0x11,$Hkey,$Ii,$Xhi + vmovdqu 0xa0-0x40($Htbl),$Hkey # $Hkey^8 + vpxor $Tred,$Ij,$Ij + vpclmulqdq \$0x10,$HK, $T2,$Xmi + vpxor $Xi,$Ij,$Ij # accumulate $Xi + + lea 0x80($inp),$inp + sub \$0x80,$len + jnc .Loop8x_avx + + add \$0x80,$len + jmp .Ltail_no_xor_avx + +.align 32 +.Lshort_avx: + vmovdqu -0x10($inp,$len),$Ii # very last word + lea ($inp,$len),$inp + vmovdqu 0x00-0x40($Htbl),$Hkey # $Hkey^1 + vmovdqu 0x20-0x40($Htbl),$HK + vpshufb $bswap,$Ii,$Ij + + vmovdqa $Xlo,$Zlo # subtle way to zero $Zlo, + vmovdqa $Xhi,$Zhi # $Zhi and + vmovdqa $Xmi,$Zmi # $Zmi + sub \$0x10,$len + jz .Ltail_avx + + vpunpckhqdq $Ij,$Ij,$T1 + vpxor $Xlo,$Zlo,$Zlo + vpclmulqdq \$0x00,$Hkey,$Ij,$Xlo + vpxor $Ij,$T1,$T1 + vmovdqu -0x20($inp),$Ii + vpxor $Xhi,$Zhi,$Zhi + vpclmulqdq \$0x11,$Hkey,$Ij,$Xhi + vmovdqu 0x10-0x40($Htbl),$Hkey # $Hkey^2 + vpshufb $bswap,$Ii,$Ij + vpxor $Xmi,$Zmi,$Zmi + vpclmulqdq \$0x00,$HK,$T1,$Xmi + vpsrldq \$8,$HK,$HK + sub \$0x10,$len + jz .Ltail_avx + + vpunpckhqdq $Ij,$Ij,$T1 + vpxor $Xlo,$Zlo,$Zlo + vpclmulqdq \$0x00,$Hkey,$Ij,$Xlo + vpxor $Ij,$T1,$T1 + vmovdqu -0x30($inp),$Ii + vpxor $Xhi,$Zhi,$Zhi + vpclmulqdq \$0x11,$Hkey,$Ij,$Xhi + vmovdqu 0x30-0x40($Htbl),$Hkey # $Hkey^3 + vpshufb $bswap,$Ii,$Ij + vpxor $Xmi,$Zmi,$Zmi + vpclmulqdq \$0x00,$HK,$T1,$Xmi + vmovdqu 0x50-0x40($Htbl),$HK + sub \$0x10,$len + jz .Ltail_avx + + vpunpckhqdq $Ij,$Ij,$T1 + vpxor $Xlo,$Zlo,$Zlo + vpclmulqdq \$0x00,$Hkey,$Ij,$Xlo + vpxor $Ij,$T1,$T1 + vmovdqu -0x40($inp),$Ii + vpxor $Xhi,$Zhi,$Zhi + vpclmulqdq \$0x11,$Hkey,$Ij,$Xhi + vmovdqu 0x40-0x40($Htbl),$Hkey # $Hkey^4 + vpshufb $bswap,$Ii,$Ij + vpxor $Xmi,$Zmi,$Zmi + vpclmulqdq \$0x00,$HK,$T1,$Xmi + vpsrldq \$8,$HK,$HK + sub \$0x10,$len + jz .Ltail_avx + + vpunpckhqdq $Ij,$Ij,$T1 + vpxor $Xlo,$Zlo,$Zlo + vpclmulqdq \$0x00,$Hkey,$Ij,$Xlo + vpxor $Ij,$T1,$T1 + vmovdqu -0x50($inp),$Ii + vpxor $Xhi,$Zhi,$Zhi + vpclmulqdq \$0x11,$Hkey,$Ij,$Xhi + vmovdqu 0x60-0x40($Htbl),$Hkey # $Hkey^5 + vpshufb $bswap,$Ii,$Ij + vpxor $Xmi,$Zmi,$Zmi + vpclmulqdq \$0x00,$HK,$T1,$Xmi + vmovdqu 0x80-0x40($Htbl),$HK + sub \$0x10,$len + jz .Ltail_avx + + vpunpckhqdq $Ij,$Ij,$T1 + vpxor $Xlo,$Zlo,$Zlo + vpclmulqdq \$0x00,$Hkey,$Ij,$Xlo + vpxor $Ij,$T1,$T1 + vmovdqu -0x60($inp),$Ii + vpxor $Xhi,$Zhi,$Zhi + vpclmulqdq \$0x11,$Hkey,$Ij,$Xhi + vmovdqu 0x70-0x40($Htbl),$Hkey # $Hkey^6 + vpshufb $bswap,$Ii,$Ij + vpxor $Xmi,$Zmi,$Zmi + vpclmulqdq \$0x00,$HK,$T1,$Xmi + vpsrldq \$8,$HK,$HK + sub \$0x10,$len + jz .Ltail_avx + + vpunpckhqdq $Ij,$Ij,$T1 + vpxor $Xlo,$Zlo,$Zlo + vpclmulqdq \$0x00,$Hkey,$Ij,$Xlo + vpxor $Ij,$T1,$T1 + vmovdqu -0x70($inp),$Ii + vpxor $Xhi,$Zhi,$Zhi + vpclmulqdq \$0x11,$Hkey,$Ij,$Xhi + vmovdqu 0x90-0x40($Htbl),$Hkey # $Hkey^7 + vpshufb $bswap,$Ii,$Ij + vpxor $Xmi,$Zmi,$Zmi + vpclmulqdq \$0x00,$HK,$T1,$Xmi + vmovq 0xb8-0x40($Htbl),$HK + sub \$0x10,$len + jmp .Ltail_avx + +.align 32 +.Ltail_avx: + vpxor $Xi,$Ij,$Ij # accumulate $Xi +.Ltail_no_xor_avx: + vpunpckhqdq $Ij,$Ij,$T1 + vpxor $Xlo,$Zlo,$Zlo + vpclmulqdq \$0x00,$Hkey,$Ij,$Xlo + vpxor $Ij,$T1,$T1 + vpxor $Xhi,$Zhi,$Zhi + vpclmulqdq \$0x11,$Hkey,$Ij,$Xhi + vpxor $Xmi,$Zmi,$Zmi + vpclmulqdq \$0x00,$HK,$T1,$Xmi + + vmovdqu (%r10),$Tred + + vpxor $Xlo,$Zlo,$Xi + vpxor $Xhi,$Zhi,$Xo + vpxor $Xmi,$Zmi,$Zmi + + vpxor $Xi, $Zmi,$Zmi # aggregated Karatsuba post-processing + vpxor $Xo, $Zmi,$Zmi + vpslldq \$8, $Zmi,$T2 + vpsrldq \$8, $Zmi,$Zmi + vpxor $T2, $Xi, $Xi + vpxor $Zmi,$Xo, $Xo + + vpclmulqdq \$0x10,$Tred,$Xi,$T2 # 1st phase + vpalignr \$8,$Xi,$Xi,$Xi + vpxor $T2,$Xi,$Xi + + vpclmulqdq \$0x10,$Tred,$Xi,$T2 # 2nd phase + vpalignr \$8,$Xi,$Xi,$Xi + vpxor $Xo,$Xi,$Xi + vpxor $T2,$Xi,$Xi + + cmp \$0,$len + jne .Lshort_avx + + vpshufb $bswap,$Xi,$Xi + vmovdqu $Xi,($Xip) + vzeroupper +___ +$code.=<<___ if ($win64); + movaps (%rsp),%xmm6 + movaps 0x10(%rsp),%xmm7 + movaps 0x20(%rsp),%xmm8 + movaps 0x30(%rsp),%xmm9 + movaps 0x40(%rsp),%xmm10 + movaps 0x50(%rsp),%xmm11 + movaps 0x60(%rsp),%xmm12 + movaps 0x70(%rsp),%xmm13 + movaps 0x80(%rsp),%xmm14 + movaps 0x90(%rsp),%xmm15 + lea 0xa8(%rsp),%rsp +.LSEH_end_gcm_ghash_avx: +___ +$code.=<<___; + ret +.size gcm_ghash_avx,.-gcm_ghash_avx +___ +} else { +$code.=<<___; + jmp .L_ghash_clmul +.size gcm_ghash_avx,.-gcm_ghash_avx +___ +} + +$code.=<<___; +.align 64 +.Lbswap_mask: + .byte 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 +.L0x1c2_polynomial: + .byte 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xc2 +.L7_mask: + .long 7,0,7,0 +.L7_mask_poly: + .long 7,0,`0xE1<<1`,0 +.align 64 +.type .Lrem_4bit,\@object +.Lrem_4bit: + .long 0,`0x0000<<16`,0,`0x1C20<<16`,0,`0x3840<<16`,0,`0x2460<<16` + .long 0,`0x7080<<16`,0,`0x6CA0<<16`,0,`0x48C0<<16`,0,`0x54E0<<16` + .long 0,`0xE100<<16`,0,`0xFD20<<16`,0,`0xD940<<16`,0,`0xC560<<16` + .long 0,`0x9180<<16`,0,`0x8DA0<<16`,0,`0xA9C0<<16`,0,`0xB5E0<<16` +.type .Lrem_8bit,\@object +.Lrem_8bit: + .value 0x0000,0x01C2,0x0384,0x0246,0x0708,0x06CA,0x048C,0x054E + .value 0x0E10,0x0FD2,0x0D94,0x0C56,0x0918,0x08DA,0x0A9C,0x0B5E + .value 0x1C20,0x1DE2,0x1FA4,0x1E66,0x1B28,0x1AEA,0x18AC,0x196E + .value 0x1230,0x13F2,0x11B4,0x1076,0x1538,0x14FA,0x16BC,0x177E + .value 0x3840,0x3982,0x3BC4,0x3A06,0x3F48,0x3E8A,0x3CCC,0x3D0E + .value 0x3650,0x3792,0x35D4,0x3416,0x3158,0x309A,0x32DC,0x331E + .value 0x2460,0x25A2,0x27E4,0x2626,0x2368,0x22AA,0x20EC,0x212E + .value 0x2A70,0x2BB2,0x29F4,0x2836,0x2D78,0x2CBA,0x2EFC,0x2F3E + .value 0x7080,0x7142,0x7304,0x72C6,0x7788,0x764A,0x740C,0x75CE + .value 0x7E90,0x7F52,0x7D14,0x7CD6,0x7998,0x785A,0x7A1C,0x7BDE + .value 0x6CA0,0x6D62,0x6F24,0x6EE6,0x6BA8,0x6A6A,0x682C,0x69EE + .value 0x62B0,0x6372,0x6134,0x60F6,0x65B8,0x647A,0x663C,0x67FE + .value 0x48C0,0x4902,0x4B44,0x4A86,0x4FC8,0x4E0A,0x4C4C,0x4D8E + .value 0x46D0,0x4712,0x4554,0x4496,0x41D8,0x401A,0x425C,0x439E + .value 0x54E0,0x5522,0x5764,0x56A6,0x53E8,0x522A,0x506C,0x51AE + .value 0x5AF0,0x5B32,0x5974,0x58B6,0x5DF8,0x5C3A,0x5E7C,0x5FBE + .value 0xE100,0xE0C2,0xE284,0xE346,0xE608,0xE7CA,0xE58C,0xE44E + .value 0xEF10,0xEED2,0xEC94,0xED56,0xE818,0xE9DA,0xEB9C,0xEA5E + .value 0xFD20,0xFCE2,0xFEA4,0xFF66,0xFA28,0xFBEA,0xF9AC,0xF86E + .value 0xF330,0xF2F2,0xF0B4,0xF176,0xF438,0xF5FA,0xF7BC,0xF67E + .value 0xD940,0xD882,0xDAC4,0xDB06,0xDE48,0xDF8A,0xDDCC,0xDC0E + .value 0xD750,0xD692,0xD4D4,0xD516,0xD058,0xD19A,0xD3DC,0xD21E + .value 0xC560,0xC4A2,0xC6E4,0xC726,0xC268,0xC3AA,0xC1EC,0xC02E + .value 0xCB70,0xCAB2,0xC8F4,0xC936,0xCC78,0xCDBA,0xCFFC,0xCE3E + .value 0x9180,0x9042,0x9204,0x93C6,0x9688,0x974A,0x950C,0x94CE + .value 0x9F90,0x9E52,0x9C14,0x9DD6,0x9898,0x995A,0x9B1C,0x9ADE + .value 0x8DA0,0x8C62,0x8E24,0x8FE6,0x8AA8,0x8B6A,0x892C,0x88EE + .value 0x83B0,0x8272,0x8034,0x81F6,0x84B8,0x857A,0x873C,0x86FE + .value 0xA9C0,0xA802,0xAA44,0xAB86,0xAEC8,0xAF0A,0xAD4C,0xAC8E + .value 0xA7D0,0xA612,0xA454,0xA596,0xA0D8,0xA11A,0xA35C,0xA29E + .value 0xB5E0,0xB422,0xB664,0xB7A6,0xB2E8,0xB32A,0xB16C,0xB0AE + .value 0xBBF0,0xBA32,0xB874,0xB9B6,0xBCF8,0xBD3A,0xBF7C,0xBEBE + +.asciz "GHASH for x86_64, CRYPTOGAMS by " +.align 64 +___ + +# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame, +# CONTEXT *context,DISPATCHER_CONTEXT *disp) +if ($win64) { +$rec="%rcx"; +$frame="%rdx"; +$context="%r8"; +$disp="%r9"; + +$code.=<<___; +.extern __imp_RtlVirtualUnwind +.type se_handler,\@abi-omnipotent +.align 16 +se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + mov 8($disp),%rsi # disp->ImageBase + mov 56($disp),%r11 # disp->HandlerData + + mov 0(%r11),%r10d # HandlerData[0] + lea (%rsi,%r10),%r10 # prologue label + cmp %r10,%rbx # context->RipRsp + + mov 4(%r11),%r10d # HandlerData[1] + lea (%rsi,%r10),%r10 # epilogue label + cmp %r10,%rbx # context->Rip>=epilogue label + jae .Lin_prologue + + lea 24(%rax),%rax # adjust "rsp" + + mov -8(%rax),%rbx + mov -16(%rax),%rbp + mov -24(%rax),%r12 + mov %rbx,144($context) # restore context->Rbx + mov %rbp,160($context) # restore context->Rbp + mov %r12,216($context) # restore context->R12 + +.Lin_prologue: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + + mov 40($disp),%rdi # disp->ContextRecord + mov $context,%rsi # context + mov \$`1232/8`,%ecx # sizeof(CONTEXT) + .long 0xa548f3fc # cld; rep movsq + + mov $disp,%rsi + xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER + mov 8(%rsi),%rdx # arg2, disp->ImageBase + mov 0(%rsi),%r8 # arg3, disp->ControlPc + mov 16(%rsi),%r9 # arg4, disp->FunctionEntry + mov 40(%rsi),%r10 # disp->ContextRecord + lea 56(%rsi),%r11 # &disp->HandlerData + lea 24(%rsi),%r12 # &disp->EstablisherFrame + mov %r10,32(%rsp) # arg5 + mov %r11,40(%rsp) # arg6 + mov %r12,48(%rsp) # arg7 + mov %rcx,56(%rsp) # arg8, (NULL) + call *__imp_RtlVirtualUnwind(%rip) + + mov \$1,%eax # ExceptionContinueSearch + add \$64,%rsp + popfq + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + pop %rdi + pop %rsi + ret +.size se_handler,.-se_handler + +.section .pdata +.align 4 + .rva .LSEH_begin_gcm_gmult_4bit + .rva .LSEH_end_gcm_gmult_4bit + .rva .LSEH_info_gcm_gmult_4bit + + .rva .LSEH_begin_gcm_ghash_4bit + .rva .LSEH_end_gcm_ghash_4bit + .rva .LSEH_info_gcm_ghash_4bit + + .rva .LSEH_begin_gcm_init_clmul + .rva .LSEH_end_gcm_init_clmul + .rva .LSEH_info_gcm_init_clmul + + .rva .LSEH_begin_gcm_ghash_clmul + .rva .LSEH_end_gcm_ghash_clmul + .rva .LSEH_info_gcm_ghash_clmul +___ +$code.=<<___ if ($avx); + .rva .LSEH_begin_gcm_init_avx + .rva .LSEH_end_gcm_init_avx + .rva .LSEH_info_gcm_init_clmul + + .rva .LSEH_begin_gcm_ghash_avx + .rva .LSEH_end_gcm_ghash_avx + .rva .LSEH_info_gcm_ghash_clmul +___ +$code.=<<___; +.section .xdata +.align 8 +.LSEH_info_gcm_gmult_4bit: + .byte 9,0,0,0 + .rva se_handler + .rva .Lgmult_prologue,.Lgmult_epilogue # HandlerData +.LSEH_info_gcm_ghash_4bit: + .byte 9,0,0,0 + .rva se_handler + .rva .Lghash_prologue,.Lghash_epilogue # HandlerData +.LSEH_info_gcm_init_clmul: + .byte 0x01,0x08,0x03,0x00 + .byte 0x08,0x68,0x00,0x00 #movaps 0x00(rsp),xmm6 + .byte 0x04,0x22,0x00,0x00 #sub rsp,0x18 +.LSEH_info_gcm_ghash_clmul: + .byte 0x01,0x33,0x16,0x00 + .byte 0x33,0xf8,0x09,0x00 #movaps 0x90(rsp),xmm15 + .byte 0x2e,0xe8,0x08,0x00 #movaps 0x80(rsp),xmm14 + .byte 0x29,0xd8,0x07,0x00 #movaps 0x70(rsp),xmm13 + .byte 0x24,0xc8,0x06,0x00 #movaps 0x60(rsp),xmm12 + .byte 0x1f,0xb8,0x05,0x00 #movaps 0x50(rsp),xmm11 + .byte 0x1a,0xa8,0x04,0x00 #movaps 0x40(rsp),xmm10 + .byte 0x15,0x98,0x03,0x00 #movaps 0x30(rsp),xmm9 + .byte 0x10,0x88,0x02,0x00 #movaps 0x20(rsp),xmm8 + .byte 0x0c,0x78,0x01,0x00 #movaps 0x10(rsp),xmm7 + .byte 0x08,0x68,0x00,0x00 #movaps 0x00(rsp),xmm6 + .byte 0x04,0x01,0x15,0x00 #sub rsp,0xa8 +___ +} + +$code =~ s/\`([^\`]*)\`/eval($1)/gem; + +print $code; + +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/modes/asm/ghashv8-armx.pl b/TMessagesProj/jni/boringssl/crypto/modes/asm/ghashv8-armx.pl new file mode 100644 index 00000000..5856c94a --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/modes/asm/ghashv8-armx.pl @@ -0,0 +1,422 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# GHASH for ARMv8 Crypto Extension, 64-bit polynomial multiplication. +# +# June 2014 +# +# Initial version was developed in tight cooperation with Ard +# Biesheuvel from bits-n-pieces from +# other assembly modules. Just like aesv8-armx.pl this module +# supports both AArch32 and AArch64 execution modes. +# +# July 2014 +# +# Implement 2x aggregated reduction [see ghash-x86.pl for background +# information]. +# +# Current performance in cycles per processed byte: +# +# PMULL[2] 32-bit NEON(*) +# Apple A7 0.92 5.62 +# Cortex-A53 1.01 8.39 +# Cortex-A57 1.17 7.61 +# Denver 0.71 6.02 +# +# (*) presented for reference/comparison purposes; + +$flavour = shift; +$output = shift; + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or +die "can't locate arm-xlate.pl"; + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +$Xi="x0"; # argument block +$Htbl="x1"; +$inp="x2"; +$len="x3"; + +$inc="x12"; + +{ +my ($Xl,$Xm,$Xh,$IN)=map("q$_",(0..3)); +my ($t0,$t1,$t2,$xC2,$H,$Hhl,$H2)=map("q$_",(8..14)); + +$code=<<___; +#include "arm_arch.h" + +.text +___ +$code.=<<___ if ($flavour =~ /64/); +#if !defined(__clang__) +.arch armv8-a+crypto +#endif +___ +$code.=".fpu neon\n.code 32\n" if ($flavour !~ /64/); + +################################################################################ +# void gcm_init_v8(u128 Htable[16],const u64 H[2]); +# +# input: 128-bit H - secret parameter E(K,0^128) +# output: precomputed table filled with degrees of twisted H; +# H is twisted to handle reverse bitness of GHASH; +# only few of 16 slots of Htable[16] are used; +# data is opaque to outside world (which allows to +# optimize the code independently); +# +$code.=<<___; +.global gcm_init_v8 +.type gcm_init_v8,%function +.align 4 +gcm_init_v8: + vld1.64 {$t1},[x1] @ load input H + vmov.i8 $xC2,#0xe1 + vshl.i64 $xC2,$xC2,#57 @ 0xc2.0 + vext.8 $IN,$t1,$t1,#8 + vshr.u64 $t2,$xC2,#63 + vdup.32 $t1,${t1}[1] + vext.8 $t0,$t2,$xC2,#8 @ t0=0xc2....01 + vshr.u64 $t2,$IN,#63 + vshr.s32 $t1,$t1,#31 @ broadcast carry bit + vand $t2,$t2,$t0 + vshl.i64 $IN,$IN,#1 + vext.8 $t2,$t2,$t2,#8 + vand $t0,$t0,$t1 + vorr $IN,$IN,$t2 @ H<<<=1 + veor $H,$IN,$t0 @ twisted H + vst1.64 {$H},[x0],#16 @ store Htable[0] + + @ calculate H^2 + vext.8 $t0,$H,$H,#8 @ Karatsuba pre-processing + vpmull.p64 $Xl,$H,$H + veor $t0,$t0,$H + vpmull2.p64 $Xh,$H,$H + vpmull.p64 $Xm,$t0,$t0 + + vext.8 $t1,$Xl,$Xh,#8 @ Karatsuba post-processing + veor $t2,$Xl,$Xh + veor $Xm,$Xm,$t1 + veor $Xm,$Xm,$t2 + vpmull.p64 $t2,$Xl,$xC2 @ 1st phase + + vmov $Xh#lo,$Xm#hi @ Xh|Xm - 256-bit result + vmov $Xm#hi,$Xl#lo @ Xm is rotated Xl + veor $Xl,$Xm,$t2 + + vext.8 $t2,$Xl,$Xl,#8 @ 2nd phase + vpmull.p64 $Xl,$Xl,$xC2 + veor $t2,$t2,$Xh + veor $H2,$Xl,$t2 + + vext.8 $t1,$H2,$H2,#8 @ Karatsuba pre-processing + veor $t1,$t1,$H2 + vext.8 $Hhl,$t0,$t1,#8 @ pack Karatsuba pre-processed + vst1.64 {$Hhl-$H2},[x0] @ store Htable[1..2] + + ret +.size gcm_init_v8,.-gcm_init_v8 +___ +################################################################################ +# void gcm_gmult_v8(u64 Xi[2],const u128 Htable[16]); +# +# input: Xi - current hash value; +# Htable - table precomputed in gcm_init_v8; +# output: Xi - next hash value Xi; +# +$code.=<<___; +.global gcm_gmult_v8 +.type gcm_gmult_v8,%function +.align 4 +gcm_gmult_v8: + vld1.64 {$t1},[$Xi] @ load Xi + vmov.i8 $xC2,#0xe1 + vld1.64 {$H-$Hhl},[$Htbl] @ load twisted H, ... + vshl.u64 $xC2,$xC2,#57 +#ifndef __ARMEB__ + vrev64.8 $t1,$t1 +#endif + vext.8 $IN,$t1,$t1,#8 + + vpmull.p64 $Xl,$H,$IN @ H.lo·Xi.lo + veor $t1,$t1,$IN @ Karatsuba pre-processing + vpmull2.p64 $Xh,$H,$IN @ H.hi·Xi.hi + vpmull.p64 $Xm,$Hhl,$t1 @ (H.lo+H.hi)·(Xi.lo+Xi.hi) + + vext.8 $t1,$Xl,$Xh,#8 @ Karatsuba post-processing + veor $t2,$Xl,$Xh + veor $Xm,$Xm,$t1 + veor $Xm,$Xm,$t2 + vpmull.p64 $t2,$Xl,$xC2 @ 1st phase of reduction + + vmov $Xh#lo,$Xm#hi @ Xh|Xm - 256-bit result + vmov $Xm#hi,$Xl#lo @ Xm is rotated Xl + veor $Xl,$Xm,$t2 + + vext.8 $t2,$Xl,$Xl,#8 @ 2nd phase of reduction + vpmull.p64 $Xl,$Xl,$xC2 + veor $t2,$t2,$Xh + veor $Xl,$Xl,$t2 + +#ifndef __ARMEB__ + vrev64.8 $Xl,$Xl +#endif + vext.8 $Xl,$Xl,$Xl,#8 + vst1.64 {$Xl},[$Xi] @ write out Xi + + ret +.size gcm_gmult_v8,.-gcm_gmult_v8 +___ +################################################################################ +# void gcm_ghash_v8(u64 Xi[2],const u128 Htable[16],const u8 *inp,size_t len); +# +# input: table precomputed in gcm_init_v8; +# current hash value Xi; +# pointer to input data; +# length of input data in bytes, but divisible by block size; +# output: next hash value Xi; +# +$code.=<<___; +.global gcm_ghash_v8 +.type gcm_ghash_v8,%function +.align 4 +gcm_ghash_v8: +___ +$code.=<<___ if ($flavour !~ /64/); + vstmdb sp!,{d8-d15} @ 32-bit ABI says so +___ +$code.=<<___; + vld1.64 {$Xl},[$Xi] @ load [rotated] Xi + @ "[rotated]" means that + @ loaded value would have + @ to be rotated in order to + @ make it appear as in + @ alorithm specification + subs $len,$len,#32 @ see if $len is 32 or larger + mov $inc,#16 @ $inc is used as post- + @ increment for input pointer; + @ as loop is modulo-scheduled + @ $inc is zeroed just in time + @ to preclude oversteping + @ inp[len], which means that + @ last block[s] are actually + @ loaded twice, but last + @ copy is not processed + vld1.64 {$H-$Hhl},[$Htbl],#32 @ load twisted H, ..., H^2 + vmov.i8 $xC2,#0xe1 + vld1.64 {$H2},[$Htbl] + cclr $inc,eq @ is it time to zero $inc? + vext.8 $Xl,$Xl,$Xl,#8 @ rotate Xi + vld1.64 {$t0},[$inp],#16 @ load [rotated] I[0] + vshl.u64 $xC2,$xC2,#57 @ compose 0xc2.0 constant +#ifndef __ARMEB__ + vrev64.8 $t0,$t0 + vrev64.8 $Xl,$Xl +#endif + vext.8 $IN,$t0,$t0,#8 @ rotate I[0] + b.lo .Lodd_tail_v8 @ $len was less than 32 +___ +{ my ($Xln,$Xmn,$Xhn,$In) = map("q$_",(4..7)); + ####### + # Xi+2 =[H*(Ii+1 + Xi+1)] mod P = + # [(H*Ii+1) + (H*Xi+1)] mod P = + # [(H*Ii+1) + H^2*(Ii+Xi)] mod P + # +$code.=<<___; + vld1.64 {$t1},[$inp],$inc @ load [rotated] I[1] +#ifndef __ARMEB__ + vrev64.8 $t1,$t1 +#endif + vext.8 $In,$t1,$t1,#8 + veor $IN,$IN,$Xl @ I[i]^=Xi + vpmull.p64 $Xln,$H,$In @ H·Ii+1 + veor $t1,$t1,$In @ Karatsuba pre-processing + vpmull2.p64 $Xhn,$H,$In + b .Loop_mod2x_v8 + +.align 4 +.Loop_mod2x_v8: + vext.8 $t2,$IN,$IN,#8 + subs $len,$len,#32 @ is there more data? + vpmull.p64 $Xl,$H2,$IN @ H^2.lo·Xi.lo + cclr $inc,lo @ is it time to zero $inc? + + vpmull.p64 $Xmn,$Hhl,$t1 + veor $t2,$t2,$IN @ Karatsuba pre-processing + vpmull2.p64 $Xh,$H2,$IN @ H^2.hi·Xi.hi + veor $Xl,$Xl,$Xln @ accumulate + vpmull2.p64 $Xm,$Hhl,$t2 @ (H^2.lo+H^2.hi)·(Xi.lo+Xi.hi) + vld1.64 {$t0},[$inp],$inc @ load [rotated] I[i+2] + + veor $Xh,$Xh,$Xhn + cclr $inc,eq @ is it time to zero $inc? + veor $Xm,$Xm,$Xmn + + vext.8 $t1,$Xl,$Xh,#8 @ Karatsuba post-processing + veor $t2,$Xl,$Xh + veor $Xm,$Xm,$t1 + vld1.64 {$t1},[$inp],$inc @ load [rotated] I[i+3] +#ifndef __ARMEB__ + vrev64.8 $t0,$t0 +#endif + veor $Xm,$Xm,$t2 + vpmull.p64 $t2,$Xl,$xC2 @ 1st phase of reduction + +#ifndef __ARMEB__ + vrev64.8 $t1,$t1 +#endif + vmov $Xh#lo,$Xm#hi @ Xh|Xm - 256-bit result + vmov $Xm#hi,$Xl#lo @ Xm is rotated Xl + vext.8 $In,$t1,$t1,#8 + vext.8 $IN,$t0,$t0,#8 + veor $Xl,$Xm,$t2 + vpmull.p64 $Xln,$H,$In @ H·Ii+1 + veor $IN,$IN,$Xh @ accumulate $IN early + + vext.8 $t2,$Xl,$Xl,#8 @ 2nd phase of reduction + vpmull.p64 $Xl,$Xl,$xC2 + veor $IN,$IN,$t2 + veor $t1,$t1,$In @ Karatsuba pre-processing + veor $IN,$IN,$Xl + vpmull2.p64 $Xhn,$H,$In + b.hs .Loop_mod2x_v8 @ there was at least 32 more bytes + + veor $Xh,$Xh,$t2 + vext.8 $IN,$t0,$t0,#8 @ re-construct $IN + adds $len,$len,#32 @ re-construct $len + veor $Xl,$Xl,$Xh @ re-construct $Xl + b.eq .Ldone_v8 @ is $len zero? +___ +} +$code.=<<___; +.Lodd_tail_v8: + vext.8 $t2,$Xl,$Xl,#8 + veor $IN,$IN,$Xl @ inp^=Xi + veor $t1,$t0,$t2 @ $t1 is rotated inp^Xi + + vpmull.p64 $Xl,$H,$IN @ H.lo·Xi.lo + veor $t1,$t1,$IN @ Karatsuba pre-processing + vpmull2.p64 $Xh,$H,$IN @ H.hi·Xi.hi + vpmull.p64 $Xm,$Hhl,$t1 @ (H.lo+H.hi)·(Xi.lo+Xi.hi) + + vext.8 $t1,$Xl,$Xh,#8 @ Karatsuba post-processing + veor $t2,$Xl,$Xh + veor $Xm,$Xm,$t1 + veor $Xm,$Xm,$t2 + vpmull.p64 $t2,$Xl,$xC2 @ 1st phase of reduction + + vmov $Xh#lo,$Xm#hi @ Xh|Xm - 256-bit result + vmov $Xm#hi,$Xl#lo @ Xm is rotated Xl + veor $Xl,$Xm,$t2 + + vext.8 $t2,$Xl,$Xl,#8 @ 2nd phase of reduction + vpmull.p64 $Xl,$Xl,$xC2 + veor $t2,$t2,$Xh + veor $Xl,$Xl,$t2 + +.Ldone_v8: +#ifndef __ARMEB__ + vrev64.8 $Xl,$Xl +#endif + vext.8 $Xl,$Xl,$Xl,#8 + vst1.64 {$Xl},[$Xi] @ write out Xi + +___ +$code.=<<___ if ($flavour !~ /64/); + vldmia sp!,{d8-d15} @ 32-bit ABI says so +___ +$code.=<<___; + ret +.size gcm_ghash_v8,.-gcm_ghash_v8 +___ +} +$code.=<<___; +.asciz "GHASH for ARMv8, CRYPTOGAMS by " +.align 2 +___ + +if ($flavour =~ /64/) { ######## 64-bit code + sub unvmov { + my $arg=shift; + + $arg =~ m/q([0-9]+)#(lo|hi),\s*q([0-9]+)#(lo|hi)/o && + sprintf "ins v%d.d[%d],v%d.d[%d]",$1,($2 eq "lo")?0:1,$3,($4 eq "lo")?0:1; + } + foreach(split("\n",$code)) { + s/cclr\s+([wx])([^,]+),\s*([a-z]+)/csel $1$2,$1zr,$1$2,$3/o or + s/vmov\.i8/movi/o or # fix up legacy mnemonics + s/vmov\s+(.*)/unvmov($1)/geo or + s/vext\.8/ext/o or + s/vshr\.s/sshr\.s/o or + s/vshr/ushr/o or + s/^(\s+)v/$1/o or # strip off v prefix + s/\bbx\s+lr\b/ret/o; + + s/\bq([0-9]+)\b/"v".($1<8?$1:$1+8).".16b"/geo; # old->new registers + s/@\s/\/\//o; # old->new style commentary + + # fix up remainig legacy suffixes + s/\.[ui]?8(\s)/$1/o; + s/\.[uis]?32//o and s/\.16b/\.4s/go; + m/\.p64/o and s/\.16b/\.1q/o; # 1st pmull argument + m/l\.p64/o and s/\.16b/\.1d/go; # 2nd and 3rd pmull arguments + s/\.[uisp]?64//o and s/\.16b/\.2d/go; + s/\.[42]([sd])\[([0-3])\]/\.$1\[$2\]/o; + + print $_,"\n"; + } +} else { ######## 32-bit code + sub unvdup32 { + my $arg=shift; + + $arg =~ m/q([0-9]+),\s*q([0-9]+)\[([0-3])\]/o && + sprintf "vdup.32 q%d,d%d[%d]",$1,2*$2+($3>>1),$3&1; + } + sub unvpmullp64 { + my ($mnemonic,$arg)=@_; + + if ($arg =~ m/q([0-9]+),\s*q([0-9]+),\s*q([0-9]+)/o) { + my $word = 0xf2a00e00|(($1&7)<<13)|(($1&8)<<19) + |(($2&7)<<17)|(($2&8)<<4) + |(($3&7)<<1) |(($3&8)<<2); + $word |= 0x00010001 if ($mnemonic =~ "2"); + # since ARMv7 instructions are always encoded little-endian. + # correct solution is to use .inst directive, but older + # assemblers don't implement it:-( + sprintf ".byte\t0x%02x,0x%02x,0x%02x,0x%02x\t@ %s %s", + $word&0xff,($word>>8)&0xff, + ($word>>16)&0xff,($word>>24)&0xff, + $mnemonic,$arg; + } + } + + foreach(split("\n",$code)) { + s/\b[wx]([0-9]+)\b/r$1/go; # new->old registers + s/\bv([0-9])\.[12468]+[bsd]\b/q$1/go; # new->old registers + s/\/\/\s?/@ /o; # new->old style commentary + + # fix up remainig new-style suffixes + s/\],#[0-9]+/]!/o; + + s/cclr\s+([^,]+),\s*([a-z]+)/mov$2 $1,#0/o or + s/vdup\.32\s+(.*)/unvdup32($1)/geo or + s/v?(pmull2?)\.p64\s+(.*)/unvpmullp64($1,$2)/geo or + s/\bq([0-9]+)#(lo|hi)/sprintf "d%d",2*$1+($2 eq "hi")/geo or + s/^(\s+)b\./$1b/o or + s/^(\s+)ret/$1bx\tlr/o; + + print $_,"\n"; + } +} + +close STDOUT; # enforce flush diff --git a/TMessagesProj/jni/boringssl/crypto/modes/cbc.c b/TMessagesProj/jni/boringssl/crypto/modes/cbc.c new file mode 100644 index 00000000..931b718d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/modes/cbc.c @@ -0,0 +1,217 @@ +/* ==================================================================== + * Copyright (c) 2008 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== */ +#include + +#include +#include + +#include "internal.h" + + +#ifndef STRICT_ALIGNMENT +# define STRICT_ALIGNMENT 0 +#endif + +void CRYPTO_cbc128_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const void *key, uint8_t ivec[16], + block128_f block) { + size_t n; + const uint8_t *iv = ivec; + + assert(key != NULL && ivec != NULL); + assert(len == 0 || (in != NULL && out != NULL)); + + if (STRICT_ALIGNMENT && + ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) { + while (len >= 16) { + for (n = 0; n < 16; ++n) { + out[n] = in[n] ^ iv[n]; + } + (*block)(out, out, key); + iv = out; + len -= 16; + in += 16; + out += 16; + } + } else { + while (len >= 16) { + for (n = 0; n < 16; n += sizeof(size_t)) { + *(size_t *)(out + n) = *(size_t *)(in + n) ^ *(size_t *)(iv + n); + } + (*block)(out, out, key); + iv = out; + len -= 16; + in += 16; + out += 16; + } + } + + while (len) { + for (n = 0; n < 16 && n < len; ++n) { + out[n] = in[n] ^ iv[n]; + } + for (; n < 16; ++n) { + out[n] = iv[n]; + } + (*block)(out, out, key); + iv = out; + if (len <= 16) { + break; + } + len -= 16; + in += 16; + out += 16; + } + + memcpy(ivec, iv, 16); +} + +void CRYPTO_cbc128_decrypt(const uint8_t *in, uint8_t *out, size_t len, + const void *key, uint8_t ivec[16], + block128_f block) { + size_t n; + union { + size_t t[16 / sizeof(size_t)]; + uint8_t c[16]; + } tmp; + + assert(key != NULL && ivec != NULL); + assert(len == 0 || (in != NULL && out != NULL)); + + const uintptr_t inptr = (uintptr_t) in; + const uintptr_t outptr = (uintptr_t) out; + /* If |in| and |out| alias, |in| must be ahead. */ + assert(inptr >= outptr || inptr + len <= outptr); + + if ((inptr >= 32 && outptr <= inptr - 32) || inptr < outptr) { + /* If |out| is at least two blocks behind |in| or completely disjoint, there + * is no need to decrypt to a temporary block. */ + const uint8_t *iv = ivec; + + if (STRICT_ALIGNMENT && + ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) { + while (len >= 16) { + (*block)(in, out, key); + for (n = 0; n < 16; ++n) { + out[n] ^= iv[n]; + } + iv = in; + len -= 16; + in += 16; + out += 16; + } + } else if (16 % sizeof(size_t) == 0) { /* always true */ + while (len >= 16) { + size_t *out_t = (size_t *)out, *iv_t = (size_t *)iv; + + (*block)(in, out, key); + for (n = 0; n < 16 / sizeof(size_t); n++) { + out_t[n] ^= iv_t[n]; + } + iv = in; + len -= 16; + in += 16; + out += 16; + } + } + memcpy(ivec, iv, 16); + } else { + /* |out| is less than two blocks behind |in|. Decrypting an input block + * directly to |out| would overwrite a ciphertext block before it is used as + * the next block's IV. Decrypt to a temporary block instead. */ + if (STRICT_ALIGNMENT && + ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) { + uint8_t c; + while (len >= 16) { + (*block)(in, tmp.c, key); + for (n = 0; n < 16; ++n) { + c = in[n]; + out[n] = tmp.c[n] ^ ivec[n]; + ivec[n] = c; + } + len -= 16; + in += 16; + out += 16; + } + } else if (16 % sizeof(size_t) == 0) { /* always true */ + while (len >= 16) { + size_t c, *out_t = (size_t *)out, *ivec_t = (size_t *)ivec; + const size_t *in_t = (const size_t *)in; + + (*block)(in, tmp.c, key); + for (n = 0; n < 16 / sizeof(size_t); n++) { + c = in_t[n]; + out_t[n] = tmp.t[n] ^ ivec_t[n]; + ivec_t[n] = c; + } + len -= 16; + in += 16; + out += 16; + } + } + } + + while (len) { + uint8_t c; + (*block)(in, tmp.c, key); + for (n = 0; n < 16 && n < len; ++n) { + c = in[n]; + out[n] = tmp.c[n] ^ ivec[n]; + ivec[n] = c; + } + if (len <= 16) { + for (; n < 16; ++n) { + ivec[n] = in[n]; + } + break; + } + len -= 16; + in += 16; + out += 16; + } +} diff --git a/TMessagesProj/jni/boringssl/crypto/modes/cfb.c b/TMessagesProj/jni/boringssl/crypto/modes/cfb.c new file mode 100644 index 00000000..738a4380 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/modes/cfb.c @@ -0,0 +1,230 @@ +/* ==================================================================== + * Copyright (c) 2008 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== */ + +#include + +#include +#include + +#include "internal.h" + + +void CRYPTO_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const void *key, uint8_t ivec[16], int *num, int enc, + block128_f block) { + unsigned int n; + size_t l = 0; + + assert(in && out && key && ivec && num); + assert((16 % sizeof(size_t)) == 0); + + n = *num; + + if (enc) { + while (n && len) { + *(out++) = ivec[n] ^= *(in++); + --len; + n = (n + 1) % 16; + } +#if STRICT_ALIGNMENT + if (((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) { + while (l < len) { + if (n == 0) { + (*block)(ivec, ivec, key); + } + out[l] = ivec[n] ^= in[l]; + ++l; + n = (n + 1) % 16; + } + *num = n; + return; + } +#endif + while (len >= 16) { + (*block)(ivec, ivec, key); + for (; n < 16; n += sizeof(size_t)) { + *(size_t *)(out + n) = *(size_t *)(ivec + n) ^= *(size_t *)(in + n); + } + len -= 16; + out += 16; + in += 16; + n = 0; + } + if (len) { + (*block)(ivec, ivec, key); + while (len--) { + out[n] = ivec[n] ^= in[n]; + ++n; + } + } + *num = n; + return; + } else { + while (n && len) { + uint8_t c; + *(out++) = ivec[n] ^ (c = *(in++)); + ivec[n] = c; + --len; + n = (n + 1) % 16; + } + if (STRICT_ALIGNMENT && ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) { + while (l < len) { + unsigned char c; + if (n == 0) { + (*block)(ivec, ivec, key); + } + out[l] = ivec[n] ^ (c = in[l]); + ivec[n] = c; + ++l; + n = (n + 1) % 16; + } + *num = n; + return; + } + while (len >= 16) { + (*block)(ivec, ivec, key); + for (; n < 16; n += sizeof(size_t)) { + size_t t = *(size_t *)(in + n); + *(size_t *)(out + n) = *(size_t *)(ivec + n) ^ t; + *(size_t *)(ivec + n) = t; + } + len -= 16; + out += 16; + in += 16; + n = 0; + } + if (len) { + (*block)(ivec, ivec, key); + while (len--) { + uint8_t c; + out[n] = ivec[n] ^ (c = in[n]); + ivec[n] = c; + ++n; + } + } + *num = n; + return; + } +} + + +/* This expects a single block of size nbits for both in and out. Note that + it corrupts any extra bits in the last byte of out */ +static void cfbr_encrypt_block(const uint8_t *in, uint8_t *out, unsigned nbits, + const void *key, uint8_t ivec[16], int enc, + block128_f block) { + int n, rem, num; + uint8_t ovec[16 * 2 + 1]; /* +1 because we dererefence (but don't use) one + byte off the end */ + + if (nbits <= 0 || nbits > 128) { + return; + } + + /* fill in the first half of the new IV with the current IV */ + memcpy(ovec, ivec, 16); + /* construct the new IV */ + (*block)(ivec, ivec, key); + num = (nbits + 7) / 8; + if (enc) { + /* encrypt the input */ + for (n = 0; n < num; ++n) { + out[n] = (ovec[16 + n] = in[n] ^ ivec[n]); + } + } else { + /* decrypt the input */ + for (n = 0; n < num; ++n) { + out[n] = (ovec[16 + n] = in[n]) ^ ivec[n]; + } + } + /* shift ovec left... */ + rem = nbits % 8; + num = nbits / 8; + if (rem == 0) { + memcpy(ivec, ovec + num, 16); + } else { + for (n = 0; n < 16; ++n) { + ivec[n] = ovec[n + num] << rem | ovec[n + num + 1] >> (8 - rem); + } + } + + /* it is not necessary to cleanse ovec, since the IV is not secret */ +} + +/* N.B. This expects the input to be packed, MS bit first */ +void CRYPTO_cfb128_1_encrypt(const uint8_t *in, uint8_t *out, size_t bits, + const void *key, uint8_t ivec[16], int *num, + int enc, block128_f block) { + size_t n; + uint8_t c[1], d[1]; + + assert(in && out && key && ivec && num); + assert(*num == 0); + + for (n = 0; n < bits; ++n) { + c[0] = (in[n / 8] & (1 << (7 - n % 8))) ? 0x80 : 0; + cfbr_encrypt_block(c, d, 1, key, ivec, enc, block); + out[n / 8] = (out[n / 8] & ~(1 << (unsigned int)(7 - n % 8))) | + ((d[0] & 0x80) >> (unsigned int)(n % 8)); + } +} + +void CRYPTO_cfb128_8_encrypt(const unsigned char *in, unsigned char *out, + size_t length, const void *key, + unsigned char ivec[16], int *num, int enc, + block128_f block) { + size_t n; + + assert(in && out && key && ivec && num); + assert(*num == 0); + + for (n = 0; n < length; ++n) { + cfbr_encrypt_block(&in[n], &out[n], 8, key, ivec, enc, block); + } +} + diff --git a/TMessagesProj/jni/boringssl/crypto/modes/ctr.c b/TMessagesProj/jni/boringssl/crypto/modes/ctr.c new file mode 100644 index 00000000..64062b27 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/modes/ctr.c @@ -0,0 +1,224 @@ +/* ==================================================================== + * Copyright (c) 2008 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== */ +#include + +#include +#include + +#include "internal.h" + + +/* NOTE: the IV/counter CTR mode is big-endian. The code itself + * is endian-neutral. */ + +/* increment counter (128-bit int) by 1 */ +static void ctr128_inc(uint8_t *counter) { + uint32_t n = 16; + uint8_t c; + + do { + --n; + c = counter[n]; + ++c; + counter[n] = c; + if (c) { + return; + } + } while (n); +} + +/* The input encrypted as though 128bit counter mode is being used. The extra + * state information to record how much of the 128bit block we have used is + * contained in *num, and the encrypted counter is kept in ecount_buf. Both + * *num and ecount_buf must be initialised with zeros before the first call to + * CRYPTO_ctr128_encrypt(). + * + * This algorithm assumes that the counter is in the x lower bits of the IV + * (ivec), and that the application has full control over overflow and the rest + * of the IV. This implementation takes NO responsibility for checking that + * the counter doesn't overflow into the rest of the IV when incremented. */ +void CRYPTO_ctr128_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const void *key, uint8_t ivec[16], + uint8_t ecount_buf[16], unsigned int *num, + block128_f block) { + unsigned int n; + + assert(key && ecount_buf && num); + assert(len == 0 || (in && out)); + assert(*num < 16); + assert((16 % sizeof(size_t)) == 0); + + n = *num; + + while (n && len) { + *(out++) = *(in++) ^ ecount_buf[n]; + --len; + n = (n + 1) % 16; + } + +#if STRICT_ALIGNMENT + if (((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) { + size_t l = 0; + while (l < len) { + if (n == 0) { + (*block)(ivec, ecount_buf, key); + ctr128_inc(ivec); + } + out[l] = in[l] ^ ecount_buf[n]; + ++l; + n = (n + 1) % 16; + } + + *num = n; + return; + } +#endif + + while (len >= 16) { + (*block)(ivec, ecount_buf, key); + ctr128_inc(ivec); + for (; n < 16; n += sizeof(size_t)) { + *(size_t *)(out + n) = *(size_t *)(in + n) ^ *(size_t *)(ecount_buf + n); + } + len -= 16; + out += 16; + in += 16; + n = 0; + } + if (len) { + (*block)(ivec, ecount_buf, key); + ctr128_inc(ivec); + while (len--) { + out[n] = in[n] ^ ecount_buf[n]; + ++n; + } + } + *num = n; +} + +/* increment upper 96 bits of 128-bit counter by 1 */ +static void ctr96_inc(uint8_t *counter) { + uint32_t n = 12; + uint8_t c; + + do { + --n; + c = counter[n]; + ++c; + counter[n] = c; + if (c) { + return; + } + } while (n); +} + +void CRYPTO_ctr128_encrypt_ctr32(const uint8_t *in, uint8_t *out, + size_t len, const void *key, + uint8_t ivec[16], + uint8_t ecount_buf[16], + unsigned int *num, ctr128_f func) { + unsigned int n, ctr32; + + assert(key && ecount_buf && num); + assert(len == 0 || (in && out)); + assert(*num < 16); + + n = *num; + + while (n && len) { + *(out++) = *(in++) ^ ecount_buf[n]; + --len; + n = (n + 1) % 16; + } + + ctr32 = GETU32(ivec + 12); + while (len >= 16) { + size_t blocks = len / 16; + /* 1<<28 is just a not-so-small yet not-so-large number... + * Below condition is practically never met, but it has to + * be checked for code correctness. */ + if (sizeof(size_t) > sizeof(unsigned int) && blocks > (1U << 28)) { + blocks = (1U << 28); + } + /* As (*func) operates on 32-bit counter, caller + * has to handle overflow. 'if' below detects the + * overflow, which is then handled by limiting the + * amount of blocks to the exact overflow point... */ + ctr32 += (uint32_t)blocks; + if (ctr32 < blocks) { + blocks -= ctr32; + ctr32 = 0; + } + (*func)(in, out, blocks, key, ivec); + /* (*func) does not update ivec, caller does: */ + PUTU32(ivec + 12, ctr32); + /* ... overflow was detected, propogate carry. */ + if (ctr32 == 0) { + ctr96_inc(ivec); + } + blocks *= 16; + len -= blocks; + out += blocks; + in += blocks; + } + if (len) { + memset(ecount_buf, 0, 16); + (*func)(ecount_buf, ecount_buf, 1, key, ivec); + ++ctr32; + PUTU32(ivec + 12, ctr32); + if (ctr32 == 0) { + ctr96_inc(ivec); + } + while (len--) { + out[n] = in[n] ^ ecount_buf[n]; + ++n; + } + } + + *num = n; +} diff --git a/TMessagesProj/jni/boringssl/crypto/modes/gcm.c b/TMessagesProj/jni/boringssl/crypto/modes/gcm.c new file mode 100644 index 00000000..e7aa46e4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/modes/gcm.c @@ -0,0 +1,1250 @@ +/* ==================================================================== + * Copyright (c) 2008 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== */ + +#include + +#include +#include + +#include +#include + +#include "internal.h" +#include "../internal.h" + + +#if !defined(OPENSSL_NO_ASM) && \ + (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \ + defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) +#define GHASH_ASM +#endif + +#if defined(BSWAP4) && STRICT_ALIGNMENT == 1 +/* redefine, because alignment is ensured */ +#undef GETU32 +#define GETU32(p) BSWAP4(*(const uint32_t *)(p)) +#undef PUTU32 +#define PUTU32(p, v) *(uint32_t *)(p) = BSWAP4(v) +#endif + +#define PACK(s) ((size_t)(s) << (sizeof(size_t) * 8 - 16)) +#define REDUCE1BIT(V) \ + do { \ + if (sizeof(size_t) == 8) { \ + uint64_t T = OPENSSL_U64(0xe100000000000000) & (0 - (V.lo & 1)); \ + V.lo = (V.hi << 63) | (V.lo >> 1); \ + V.hi = (V.hi >> 1) ^ T; \ + } else { \ + uint32_t T = 0xe1000000U & (0 - (uint32_t)(V.lo & 1)); \ + V.lo = (V.hi << 63) | (V.lo >> 1); \ + V.hi = (V.hi >> 1) ^ ((uint64_t)T << 32); \ + } \ + } while (0) + + +static void gcm_init_4bit(u128 Htable[16], uint64_t H[2]) { + u128 V; + + Htable[0].hi = 0; + Htable[0].lo = 0; + V.hi = H[0]; + V.lo = H[1]; + + Htable[8] = V; + REDUCE1BIT(V); + Htable[4] = V; + REDUCE1BIT(V); + Htable[2] = V; + REDUCE1BIT(V); + Htable[1] = V; + Htable[3].hi = V.hi ^ Htable[2].hi, Htable[3].lo = V.lo ^ Htable[2].lo; + V = Htable[4]; + Htable[5].hi = V.hi ^ Htable[1].hi, Htable[5].lo = V.lo ^ Htable[1].lo; + Htable[6].hi = V.hi ^ Htable[2].hi, Htable[6].lo = V.lo ^ Htable[2].lo; + Htable[7].hi = V.hi ^ Htable[3].hi, Htable[7].lo = V.lo ^ Htable[3].lo; + V = Htable[8]; + Htable[9].hi = V.hi ^ Htable[1].hi, Htable[9].lo = V.lo ^ Htable[1].lo; + Htable[10].hi = V.hi ^ Htable[2].hi, Htable[10].lo = V.lo ^ Htable[2].lo; + Htable[11].hi = V.hi ^ Htable[3].hi, Htable[11].lo = V.lo ^ Htable[3].lo; + Htable[12].hi = V.hi ^ Htable[4].hi, Htable[12].lo = V.lo ^ Htable[4].lo; + Htable[13].hi = V.hi ^ Htable[5].hi, Htable[13].lo = V.lo ^ Htable[5].lo; + Htable[14].hi = V.hi ^ Htable[6].hi, Htable[14].lo = V.lo ^ Htable[6].lo; + Htable[15].hi = V.hi ^ Htable[7].hi, Htable[15].lo = V.lo ^ Htable[7].lo; + +#if defined(GHASH_ASM) && defined(OPENSSL_ARM) + /* ARM assembler expects specific dword order in Htable. */ + { + int j; + const union { + long one; + char little; + } is_endian = {1}; + + if (is_endian.little) { + for (j = 0; j < 16; ++j) { + V = Htable[j]; + Htable[j].hi = V.lo; + Htable[j].lo = V.hi; + } + } else { + for (j = 0; j < 16; ++j) { + V = Htable[j]; + Htable[j].hi = V.lo << 32 | V.lo >> 32; + Htable[j].lo = V.hi << 32 | V.hi >> 32; + } + } + } +#endif +} + +#if !defined(GHASH_ASM) || defined(OPENSSL_AARCH64) +static const size_t rem_4bit[16] = { + PACK(0x0000), PACK(0x1C20), PACK(0x3840), PACK(0x2460), + PACK(0x7080), PACK(0x6CA0), PACK(0x48C0), PACK(0x54E0), + PACK(0xE100), PACK(0xFD20), PACK(0xD940), PACK(0xC560), + PACK(0x9180), PACK(0x8DA0), PACK(0xA9C0), PACK(0xB5E0)}; + +static void gcm_gmult_4bit(uint64_t Xi[2], const u128 Htable[16]) { + u128 Z; + int cnt = 15; + size_t rem, nlo, nhi; + const union { + long one; + char little; + } is_endian = {1}; + + nlo = ((const uint8_t *)Xi)[15]; + nhi = nlo >> 4; + nlo &= 0xf; + + Z.hi = Htable[nlo].hi; + Z.lo = Htable[nlo].lo; + + while (1) { + rem = (size_t)Z.lo & 0xf; + Z.lo = (Z.hi << 60) | (Z.lo >> 4); + Z.hi = (Z.hi >> 4); + if (sizeof(size_t) == 8) { + Z.hi ^= rem_4bit[rem]; + } else { + Z.hi ^= (uint64_t)rem_4bit[rem] << 32; + } + + Z.hi ^= Htable[nhi].hi; + Z.lo ^= Htable[nhi].lo; + + if (--cnt < 0) { + break; + } + + nlo = ((const uint8_t *)Xi)[cnt]; + nhi = nlo >> 4; + nlo &= 0xf; + + rem = (size_t)Z.lo & 0xf; + Z.lo = (Z.hi << 60) | (Z.lo >> 4); + Z.hi = (Z.hi >> 4); + if (sizeof(size_t) == 8) { + Z.hi ^= rem_4bit[rem]; + } else { + Z.hi ^= (uint64_t)rem_4bit[rem] << 32; + } + + Z.hi ^= Htable[nlo].hi; + Z.lo ^= Htable[nlo].lo; + } + + if (is_endian.little) { +#ifdef BSWAP8 + Xi[0] = BSWAP8(Z.hi); + Xi[1] = BSWAP8(Z.lo); +#else + uint8_t *p = (uint8_t *)Xi; + uint32_t v; + v = (uint32_t)(Z.hi >> 32); + PUTU32(p, v); + v = (uint32_t)(Z.hi); + PUTU32(p + 4, v); + v = (uint32_t)(Z.lo >> 32); + PUTU32(p + 8, v); + v = (uint32_t)(Z.lo); + PUTU32(p + 12, v); +#endif + } else { + Xi[0] = Z.hi; + Xi[1] = Z.lo; + } +} + +/* Streamed gcm_mult_4bit, see CRYPTO_gcm128_[en|de]crypt for + * details... Compiler-generated code doesn't seem to give any + * performance improvement, at least not on x86[_64]. It's here + * mostly as reference and a placeholder for possible future + * non-trivial optimization[s]... */ +static void gcm_ghash_4bit(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, + size_t len) { + u128 Z; + int cnt; + size_t rem, nlo, nhi; + const union { + long one; + char little; + } is_endian = {1}; + + do { + cnt = 15; + nlo = ((const uint8_t *)Xi)[15]; + nlo ^= inp[15]; + nhi = nlo >> 4; + nlo &= 0xf; + + Z.hi = Htable[nlo].hi; + Z.lo = Htable[nlo].lo; + + while (1) { + rem = (size_t)Z.lo & 0xf; + Z.lo = (Z.hi << 60) | (Z.lo >> 4); + Z.hi = (Z.hi >> 4); + if (sizeof(size_t) == 8) { + Z.hi ^= rem_4bit[rem]; + } else { + Z.hi ^= (uint64_t)rem_4bit[rem] << 32; + } + + Z.hi ^= Htable[nhi].hi; + Z.lo ^= Htable[nhi].lo; + + if (--cnt < 0) { + break; + } + + nlo = ((const uint8_t *)Xi)[cnt]; + nlo ^= inp[cnt]; + nhi = nlo >> 4; + nlo &= 0xf; + + rem = (size_t)Z.lo & 0xf; + Z.lo = (Z.hi << 60) | (Z.lo >> 4); + Z.hi = (Z.hi >> 4); + if (sizeof(size_t) == 8) { + Z.hi ^= rem_4bit[rem]; + } else { + Z.hi ^= (uint64_t)rem_4bit[rem] << 32; + } + + Z.hi ^= Htable[nlo].hi; + Z.lo ^= Htable[nlo].lo; + } + + if (is_endian.little) { +#ifdef BSWAP8 + Xi[0] = BSWAP8(Z.hi); + Xi[1] = BSWAP8(Z.lo); +#else + uint8_t *p = (uint8_t *)Xi; + uint32_t v; + v = (uint32_t)(Z.hi >> 32); + PUTU32(p, v); + v = (uint32_t)(Z.hi); + PUTU32(p + 4, v); + v = (uint32_t)(Z.lo >> 32); + PUTU32(p + 8, v); + v = (uint32_t)(Z.lo); + PUTU32(p + 12, v); +#endif + } else { + Xi[0] = Z.hi; + Xi[1] = Z.lo; + } + } while (inp += 16, len -= 16); +} +#else /* GHASH_ASM */ +void gcm_gmult_4bit(uint64_t Xi[2], const u128 Htable[16]); +void gcm_ghash_4bit(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, + size_t len); +#endif + +#define GCM_MUL(ctx, Xi) gcm_gmult_4bit(ctx->Xi.u, ctx->Htable) +#if defined(GHASH_ASM) +#define GHASH(ctx, in, len) gcm_ghash_4bit((ctx)->Xi.u, (ctx)->Htable, in, len) +/* GHASH_CHUNK is "stride parameter" missioned to mitigate cache + * trashing effect. In other words idea is to hash data while it's + * still in L1 cache after encryption pass... */ +#define GHASH_CHUNK (3 * 1024) +#endif + + +#if defined(GHASH_ASM) +#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) +#define GHASH_ASM_X86_OR_64 +#define GCM_FUNCREF_4BIT +void gcm_init_clmul(u128 Htable[16], const uint64_t Xi[2]); +void gcm_gmult_clmul(uint64_t Xi[2], const u128 Htable[16]); +void gcm_ghash_clmul(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, + size_t len); + +#if defined(OPENSSL_X86) +#define gcm_init_avx gcm_init_clmul +#define gcm_gmult_avx gcm_gmult_clmul +#define gcm_ghash_avx gcm_ghash_clmul +#else +void gcm_init_avx(u128 Htable[16], const uint64_t Xi[2]); +void gcm_gmult_avx(uint64_t Xi[2], const u128 Htable[16]); +void gcm_ghash_avx(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, size_t len); +#endif + +#if defined(OPENSSL_X86) +#define GHASH_ASM_X86 +void gcm_gmult_4bit_mmx(uint64_t Xi[2], const u128 Htable[16]); +void gcm_ghash_4bit_mmx(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, + size_t len); + +void gcm_gmult_4bit_x86(uint64_t Xi[2], const u128 Htable[16]); +void gcm_ghash_4bit_x86(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, + size_t len); +#endif +#elif defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) +#include "../arm_arch.h" +#if __ARM_ARCH__ >= 7 +#define GHASH_ASM_ARM +#define GCM_FUNCREF_4BIT + +static int pmull_capable(void) { + return (OPENSSL_armcap_P & ARMV8_PMULL) != 0; +} + +void gcm_init_v8(u128 Htable[16], const uint64_t Xi[2]); +void gcm_gmult_v8(uint64_t Xi[2], const u128 Htable[16]); +void gcm_ghash_v8(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, + size_t len); + +#if defined(OPENSSL_ARM) +/* 32-bit ARM also has support for doing GCM with NEON instructions. */ +static int neon_capable(void) { + return CRYPTO_is_NEON_capable(); +} + +void gcm_init_neon(u128 Htable[16], const uint64_t Xi[2]); +void gcm_gmult_neon(uint64_t Xi[2], const u128 Htable[16]); +void gcm_ghash_neon(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, + size_t len); +#else +/* AArch64 only has the ARMv8 versions of functions. */ +static int neon_capable(void) { + return 0; +} +void gcm_init_neon(u128 Htable[16], const uint64_t Xi[2]) { + abort(); +} +void gcm_gmult_neon(uint64_t Xi[2], const u128 Htable[16]) { + abort(); +} +void gcm_ghash_neon(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, + size_t len) { + abort(); +} +#endif + +#endif +#endif +#endif + +#ifdef GCM_FUNCREF_4BIT +#undef GCM_MUL +#define GCM_MUL(ctx, Xi) (*gcm_gmult_p)(ctx->Xi.u, ctx->Htable) +#ifdef GHASH +#undef GHASH +#define GHASH(ctx, in, len) (*gcm_ghash_p)(ctx->Xi.u, ctx->Htable, in, len) +#endif +#endif + +GCM128_CONTEXT *CRYPTO_gcm128_new(void *key, block128_f block) { + GCM128_CONTEXT *ret; + + ret = (GCM128_CONTEXT *)OPENSSL_malloc(sizeof(GCM128_CONTEXT)); + if (ret != NULL) { + CRYPTO_gcm128_init(ret, key, block); + } + + return ret; +} + +void CRYPTO_gcm128_init(GCM128_CONTEXT *ctx, void *key, block128_f block) { + const union { + long one; + char little; + } is_endian = {1}; + + memset(ctx, 0, sizeof(*ctx)); + ctx->block = block; + ctx->key = key; + + (*block)(ctx->H.c, ctx->H.c, key); + + if (is_endian.little) { +/* H is stored in host byte order */ +#ifdef BSWAP8 + ctx->H.u[0] = BSWAP8(ctx->H.u[0]); + ctx->H.u[1] = BSWAP8(ctx->H.u[1]); +#else + uint8_t *p = ctx->H.c; + uint64_t hi, lo; + hi = (uint64_t)GETU32(p) << 32 | GETU32(p + 4); + lo = (uint64_t)GETU32(p + 8) << 32 | GETU32(p + 12); + ctx->H.u[0] = hi; + ctx->H.u[1] = lo; +#endif + } + +#if defined(GHASH_ASM_X86_OR_64) + if (crypto_gcm_clmul_enabled()) { + if (((OPENSSL_ia32cap_P[1] >> 22) & 0x41) == 0x41) { /* AVX+MOVBE */ + gcm_init_avx(ctx->Htable, ctx->H.u); + ctx->gmult = gcm_gmult_avx; + ctx->ghash = gcm_ghash_avx; + } else { + gcm_init_clmul(ctx->Htable, ctx->H.u); + ctx->gmult = gcm_gmult_clmul; + ctx->ghash = gcm_ghash_clmul; + } + return; + } + gcm_init_4bit(ctx->Htable, ctx->H.u); +#if defined(GHASH_ASM_X86) /* x86 only */ + if (OPENSSL_ia32cap_P[0] & (1 << 25)) { /* check SSE bit */ + ctx->gmult = gcm_gmult_4bit_mmx; + ctx->ghash = gcm_ghash_4bit_mmx; + } else { + ctx->gmult = gcm_gmult_4bit_x86; + ctx->ghash = gcm_ghash_4bit_x86; + } +#else + ctx->gmult = gcm_gmult_4bit; + ctx->ghash = gcm_ghash_4bit; +#endif +#elif defined(GHASH_ASM_ARM) + if (pmull_capable()) { + gcm_init_v8(ctx->Htable, ctx->H.u); + ctx->gmult = gcm_gmult_v8; + ctx->ghash = gcm_ghash_v8; + } else if (neon_capable()) { + gcm_init_neon(ctx->Htable,ctx->H.u); + ctx->gmult = gcm_gmult_neon; + ctx->ghash = gcm_ghash_neon; + } else { + gcm_init_4bit(ctx->Htable, ctx->H.u); + ctx->gmult = gcm_gmult_4bit; + ctx->ghash = gcm_ghash_4bit; + } +#else + gcm_init_4bit(ctx->Htable, ctx->H.u); + ctx->gmult = gcm_gmult_4bit; + ctx->ghash = gcm_ghash_4bit; +#endif +} + +void CRYPTO_gcm128_setiv(GCM128_CONTEXT *ctx, const uint8_t *iv, size_t len) { + const union { + long one; + char little; + } is_endian = {1}; + unsigned int ctr; +#ifdef GCM_FUNCREF_4BIT + void (*gcm_gmult_p)(uint64_t Xi[2], const u128 Htable[16]) = ctx->gmult; +#endif + + ctx->Yi.u[0] = 0; + ctx->Yi.u[1] = 0; + ctx->Xi.u[0] = 0; + ctx->Xi.u[1] = 0; + ctx->len.u[0] = 0; /* AAD length */ + ctx->len.u[1] = 0; /* message length */ + ctx->ares = 0; + ctx->mres = 0; + + if (len == 12) { + memcpy(ctx->Yi.c, iv, 12); + ctx->Yi.c[15] = 1; + ctr = 1; + } else { + size_t i; + uint64_t len0 = len; + + while (len >= 16) { + for (i = 0; i < 16; ++i) { + ctx->Yi.c[i] ^= iv[i]; + } + GCM_MUL(ctx, Yi); + iv += 16; + len -= 16; + } + if (len) { + for (i = 0; i < len; ++i) { + ctx->Yi.c[i] ^= iv[i]; + } + GCM_MUL(ctx, Yi); + } + len0 <<= 3; + if (is_endian.little) { +#ifdef BSWAP8 + ctx->Yi.u[1] ^= BSWAP8(len0); +#else + ctx->Yi.c[8] ^= (uint8_t)(len0 >> 56); + ctx->Yi.c[9] ^= (uint8_t)(len0 >> 48); + ctx->Yi.c[10] ^= (uint8_t)(len0 >> 40); + ctx->Yi.c[11] ^= (uint8_t)(len0 >> 32); + ctx->Yi.c[12] ^= (uint8_t)(len0 >> 24); + ctx->Yi.c[13] ^= (uint8_t)(len0 >> 16); + ctx->Yi.c[14] ^= (uint8_t)(len0 >> 8); + ctx->Yi.c[15] ^= (uint8_t)(len0); +#endif + } else { + ctx->Yi.u[1] ^= len0; + } + + GCM_MUL(ctx, Yi); + + if (is_endian.little) { + ctr = GETU32(ctx->Yi.c + 12); + } else { + ctr = ctx->Yi.d[3]; + } + } + + (*ctx->block)(ctx->Yi.c, ctx->EK0.c, ctx->key); + ++ctr; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } +} + +int CRYPTO_gcm128_aad(GCM128_CONTEXT *ctx, const uint8_t *aad, size_t len) { + size_t i; + unsigned int n; + uint64_t alen = ctx->len.u[0]; +#ifdef GCM_FUNCREF_4BIT + void (*gcm_gmult_p)(uint64_t Xi[2], const u128 Htable[16]) = ctx->gmult; +#ifdef GHASH + void (*gcm_ghash_p)(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, + size_t len) = ctx->ghash; +#endif +#endif + + if (ctx->len.u[1]) { + return 0; + } + + alen += len; + if (alen > (OPENSSL_U64(1) << 61) || (sizeof(len) == 8 && alen < len)) { + return 0; + } + ctx->len.u[0] = alen; + + n = ctx->ares; + if (n) { + while (n && len) { + ctx->Xi.c[n] ^= *(aad++); + --len; + n = (n + 1) % 16; + } + if (n == 0) { + GCM_MUL(ctx, Xi); + } else { + ctx->ares = n; + return 1; + } + } + +#ifdef GHASH + if ((i = (len & (size_t) - 16))) { + GHASH(ctx, aad, i); + aad += i; + len -= i; + } +#else + while (len >= 16) { + for (i = 0; i < 16; ++i) { + ctx->Xi.c[i] ^= aad[i]; + } + GCM_MUL(ctx, Xi); + aad += 16; + len -= 16; + } +#endif + if (len) { + n = (unsigned int)len; + for (i = 0; i < len; ++i) { + ctx->Xi.c[i] ^= aad[i]; + } + } + + ctx->ares = n; + return 1; +} + +int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const unsigned char *in, + unsigned char *out, size_t len) { + const union { + long one; + char little; + } is_endian = {1}; + unsigned int n, ctr; + size_t i; + uint64_t mlen = ctx->len.u[1]; + block128_f block = ctx->block; + void *key = ctx->key; +#ifdef GCM_FUNCREF_4BIT + void (*gcm_gmult_p)(uint64_t Xi[2], const u128 Htable[16]) = ctx->gmult; +#ifdef GHASH + void (*gcm_ghash_p)(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, + size_t len) = ctx->ghash; +#endif +#endif + + mlen += len; + if (mlen > ((OPENSSL_U64(1) << 36) - 32) || + (sizeof(len) == 8 && mlen < len)) { + return 0; + } + ctx->len.u[1] = mlen; + + if (ctx->ares) { + /* First call to encrypt finalizes GHASH(AAD) */ + GCM_MUL(ctx, Xi); + ctx->ares = 0; + } + + if (is_endian.little) { + ctr = GETU32(ctx->Yi.c + 12); + } else { + ctr = ctx->Yi.d[3]; + } + + n = ctx->mres; + if (n) { + while (n && len) { + ctx->Xi.c[n] ^= *(out++) = *(in++) ^ ctx->EKi.c[n]; + --len; + n = (n + 1) % 16; + } + if (n == 0) { + GCM_MUL(ctx, Xi); + } else { + ctx->mres = n; + return 1; + } + } + if (STRICT_ALIGNMENT && ((size_t)in | (size_t)out) % sizeof(size_t) != 0) { + for (i = 0; i < len; ++i) { + if (n == 0) { + (*block)(ctx->Yi.c, ctx->EKi.c, key); + ++ctr; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + } + ctx->Xi.c[n] ^= out[i] = in[i] ^ ctx->EKi.c[n]; + n = (n + 1) % 16; + if (n == 0) { + GCM_MUL(ctx, Xi); + } + } + + ctx->mres = n; + return 1; + } +#if defined(GHASH) && defined(GHASH_CHUNK) + while (len >= GHASH_CHUNK) { + size_t j = GHASH_CHUNK; + + while (j) { + size_t *out_t = (size_t *)out; + const size_t *in_t = (const size_t *)in; + + (*block)(ctx->Yi.c, ctx->EKi.c, key); + ++ctr; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + for (i = 0; i < 16 / sizeof(size_t); ++i) { + out_t[i] = in_t[i] ^ ctx->EKi.t[i]; + } + out += 16; + in += 16; + j -= 16; + } + GHASH(ctx, out - GHASH_CHUNK, GHASH_CHUNK); + len -= GHASH_CHUNK; + } + if ((i = (len & (size_t) - 16))) { + size_t j = i; + + while (len >= 16) { + size_t *out_t = (size_t *)out; + const size_t *in_t = (const size_t *)in; + + (*block)(ctx->Yi.c, ctx->EKi.c, key); + ++ctr; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + for (i = 0; i < 16 / sizeof(size_t); ++i) { + out_t[i] = in_t[i] ^ ctx->EKi.t[i]; + } + out += 16; + in += 16; + len -= 16; + } + GHASH(ctx, out - j, j); + } +#else + while (len >= 16) { + size_t *out_t = (size_t *)out; + const size_t *in_t = (const size_t *)in; + + (*block)(ctx->Yi.c, ctx->EKi.c, key); + ++ctr; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + for (i = 0; i < 16 / sizeof(size_t); ++i) { + ctx->Xi.t[i] ^= out_t[i] = in_t[i] ^ ctx->EKi.t[i]; + } + GCM_MUL(ctx, Xi); + out += 16; + in += 16; + len -= 16; + } +#endif + if (len) { + (*block)(ctx->Yi.c, ctx->EKi.c, key); + ++ctr; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + while (len--) { + ctx->Xi.c[n] ^= out[n] = in[n] ^ ctx->EKi.c[n]; + ++n; + } + } + + ctx->mres = n; + return 1; +} + +int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const unsigned char *in, + unsigned char *out, size_t len) { + const union { + long one; + char little; + } is_endian = {1}; + unsigned int n, ctr; + size_t i; + uint64_t mlen = ctx->len.u[1]; + block128_f block = ctx->block; + void *key = ctx->key; +#ifdef GCM_FUNCREF_4BIT + void (*gcm_gmult_p)(uint64_t Xi[2], const u128 Htable[16]) = ctx->gmult; +#ifdef GHASH + void (*gcm_ghash_p)(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, + size_t len) = ctx->ghash; +#endif +#endif + + mlen += len; + if (mlen > ((OPENSSL_U64(1) << 36) - 32) || + (sizeof(len) == 8 && mlen < len)) { + return 0; + } + ctx->len.u[1] = mlen; + + if (ctx->ares) { + /* First call to decrypt finalizes GHASH(AAD) */ + GCM_MUL(ctx, Xi); + ctx->ares = 0; + } + + if (is_endian.little) { + ctr = GETU32(ctx->Yi.c + 12); + } else { + ctr = ctx->Yi.d[3]; + } + + n = ctx->mres; + if (n) { + while (n && len) { + uint8_t c = *(in++); + *(out++) = c ^ ctx->EKi.c[n]; + ctx->Xi.c[n] ^= c; + --len; + n = (n + 1) % 16; + } + if (n == 0) { + GCM_MUL(ctx, Xi); + } else { + ctx->mres = n; + return 1; + } + } + if (STRICT_ALIGNMENT && ((size_t)in | (size_t)out) % sizeof(size_t) != 0) { + for (i = 0; i < len; ++i) { + uint8_t c; + if (n == 0) { + (*block)(ctx->Yi.c, ctx->EKi.c, key); + ++ctr; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + } + c = in[i]; + out[i] = c ^ ctx->EKi.c[n]; + ctx->Xi.c[n] ^= c; + n = (n + 1) % 16; + if (n == 0) { + GCM_MUL(ctx, Xi); + } + } + + ctx->mres = n; + return 1; + } +#if defined(GHASH) && defined(GHASH_CHUNK) + while (len >= GHASH_CHUNK) { + size_t j = GHASH_CHUNK; + + GHASH(ctx, in, GHASH_CHUNK); + while (j) { + size_t *out_t = (size_t *)out; + const size_t *in_t = (const size_t *)in; + + (*block)(ctx->Yi.c, ctx->EKi.c, key); + ++ctr; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + for (i = 0; i < 16 / sizeof(size_t); ++i) { + out_t[i] = in_t[i] ^ ctx->EKi.t[i]; + } + out += 16; + in += 16; + j -= 16; + } + len -= GHASH_CHUNK; + } + if ((i = (len & (size_t) - 16))) { + GHASH(ctx, in, i); + while (len >= 16) { + size_t *out_t = (size_t *)out; + const size_t *in_t = (const size_t *)in; + + (*block)(ctx->Yi.c, ctx->EKi.c, key); + ++ctr; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + for (i = 0; i < 16 / sizeof(size_t); ++i) { + out_t[i] = in_t[i] ^ ctx->EKi.t[i]; + } + out += 16; + in += 16; + len -= 16; + } + } +#else + while (len >= 16) { + size_t *out_t = (size_t *)out; + const size_t *in_t = (const size_t *)in; + + (*block)(ctx->Yi.c, ctx->EKi.c, key); + ++ctr; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + for (i = 0; i < 16 / sizeof(size_t); ++i) { + size_t c = in_t[i]; + out_t[i] = c ^ ctx->EKi.t[i]; + ctx->Xi.t[i] ^= c; + } + GCM_MUL(ctx, Xi); + out += 16; + in += 16; + len -= 16; + } +#endif + if (len) { + (*block)(ctx->Yi.c, ctx->EKi.c, key); + ++ctr; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + while (len--) { + uint8_t c = in[n]; + ctx->Xi.c[n] ^= c; + out[n] = c ^ ctx->EKi.c[n]; + ++n; + } + } + + ctx->mres = n; + return 1; +} + +int CRYPTO_gcm128_encrypt_ctr32(GCM128_CONTEXT *ctx, const uint8_t *in, + uint8_t *out, size_t len, ctr128_f stream) { + const union { + long one; + char little; + } is_endian = {1}; + unsigned int n, ctr; + size_t i; + uint64_t mlen = ctx->len.u[1]; + void *key = ctx->key; +#ifdef GCM_FUNCREF_4BIT + void (*gcm_gmult_p)(uint64_t Xi[2], const u128 Htable[16]) = ctx->gmult; +#ifdef GHASH + void (*gcm_ghash_p)(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, + size_t len) = ctx->ghash; +#endif +#endif + + mlen += len; + if (mlen > ((OPENSSL_U64(1) << 36) - 32) || + (sizeof(len) == 8 && mlen < len)) { + return 0; + } + ctx->len.u[1] = mlen; + + if (ctx->ares) { + /* First call to encrypt finalizes GHASH(AAD) */ + GCM_MUL(ctx, Xi); + ctx->ares = 0; + } + + if (is_endian.little) { + ctr = GETU32(ctx->Yi.c + 12); + } else { + ctr = ctx->Yi.d[3]; + } + + n = ctx->mres; + if (n) { + while (n && len) { + ctx->Xi.c[n] ^= *(out++) = *(in++) ^ ctx->EKi.c[n]; + --len; + n = (n + 1) % 16; + } + if (n == 0) { + GCM_MUL(ctx, Xi); + } else { + ctx->mres = n; + return 1; + } + } +#if defined(GHASH) + while (len >= GHASH_CHUNK) { + (*stream)(in, out, GHASH_CHUNK / 16, key, ctx->Yi.c); + ctr += GHASH_CHUNK / 16; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + GHASH(ctx, out, GHASH_CHUNK); + out += GHASH_CHUNK; + in += GHASH_CHUNK; + len -= GHASH_CHUNK; + } +#endif + if ((i = (len & (size_t) - 16))) { + size_t j = i / 16; + + (*stream)(in, out, j, key, ctx->Yi.c); + ctr += (unsigned int)j; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + in += i; + len -= i; +#if defined(GHASH) + GHASH(ctx, out, i); + out += i; +#else + while (j--) { + for (i = 0; i < 16; ++i) { + ctx->Xi.c[i] ^= out[i]; + } + GCM_MUL(ctx, Xi); + out += 16; + } +#endif + } + if (len) { + (*ctx->block)(ctx->Yi.c, ctx->EKi.c, key); + ++ctr; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + while (len--) { + ctx->Xi.c[n] ^= out[n] = in[n] ^ ctx->EKi.c[n]; + ++n; + } + } + + ctx->mres = n; + return 1; +} + +int CRYPTO_gcm128_decrypt_ctr32(GCM128_CONTEXT *ctx, const uint8_t *in, + uint8_t *out, size_t len, + ctr128_f stream) { + const union { + long one; + char little; + } is_endian = {1}; + unsigned int n, ctr; + size_t i; + uint64_t mlen = ctx->len.u[1]; + void *key = ctx->key; +#ifdef GCM_FUNCREF_4BIT + void (*gcm_gmult_p)(uint64_t Xi[2], const u128 Htable[16]) = ctx->gmult; +#ifdef GHASH + void (*gcm_ghash_p)(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, + size_t len) = ctx->ghash; +#endif +#endif + + mlen += len; + if (mlen > ((OPENSSL_U64(1) << 36) - 32) || + (sizeof(len) == 8 && mlen < len)) { + return 0; + } + ctx->len.u[1] = mlen; + + if (ctx->ares) { + /* First call to decrypt finalizes GHASH(AAD) */ + GCM_MUL(ctx, Xi); + ctx->ares = 0; + } + + if (is_endian.little) { + ctr = GETU32(ctx->Yi.c + 12); + } else { + ctr = ctx->Yi.d[3]; + } + + n = ctx->mres; + if (n) { + while (n && len) { + uint8_t c = *(in++); + *(out++) = c ^ ctx->EKi.c[n]; + ctx->Xi.c[n] ^= c; + --len; + n = (n + 1) % 16; + } + if (n == 0) { + GCM_MUL(ctx, Xi); + } else { + ctx->mres = n; + return 1; + } + } +#if defined(GHASH) + while (len >= GHASH_CHUNK) { + GHASH(ctx, in, GHASH_CHUNK); + (*stream)(in, out, GHASH_CHUNK / 16, key, ctx->Yi.c); + ctr += GHASH_CHUNK / 16; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + out += GHASH_CHUNK; + in += GHASH_CHUNK; + len -= GHASH_CHUNK; + } +#endif + if ((i = (len & (size_t) - 16))) { + size_t j = i / 16; + +#if defined(GHASH) + GHASH(ctx, in, i); +#else + while (j--) { + size_t k; + for (k = 0; k < 16; ++k) { + ctx->Xi.c[k] ^= in[k]; + } + GCM_MUL(ctx, Xi); + in += 16; + } + j = i / 16; + in -= i; +#endif + (*stream)(in, out, j, key, ctx->Yi.c); + ctr += (unsigned int)j; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + out += i; + in += i; + len -= i; + } + if (len) { + (*ctx->block)(ctx->Yi.c, ctx->EKi.c, key); + ++ctr; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + while (len--) { + uint8_t c = in[n]; + ctx->Xi.c[n] ^= c; + out[n] = c ^ ctx->EKi.c[n]; + ++n; + } + } + + ctx->mres = n; + return 1; +} + +int CRYPTO_gcm128_finish(GCM128_CONTEXT *ctx, const uint8_t *tag, size_t len) { + const union { + long one; + char little; + } is_endian = {1}; + uint64_t alen = ctx->len.u[0] << 3; + uint64_t clen = ctx->len.u[1] << 3; +#ifdef GCM_FUNCREF_4BIT + void (*gcm_gmult_p)(uint64_t Xi[2], const u128 Htable[16]) = ctx->gmult; +#endif + + if (ctx->mres || ctx->ares) { + GCM_MUL(ctx, Xi); + } + + if (is_endian.little) { +#ifdef BSWAP8 + alen = BSWAP8(alen); + clen = BSWAP8(clen); +#else + uint8_t *p = ctx->len.c; + + ctx->len.u[0] = alen; + ctx->len.u[1] = clen; + + alen = (uint64_t)GETU32(p) << 32 | GETU32(p + 4); + clen = (uint64_t)GETU32(p + 8) << 32 | GETU32(p + 12); +#endif + } + + ctx->Xi.u[0] ^= alen; + ctx->Xi.u[1] ^= clen; + GCM_MUL(ctx, Xi); + + ctx->Xi.u[0] ^= ctx->EK0.u[0]; + ctx->Xi.u[1] ^= ctx->EK0.u[1]; + + if (tag && len <= sizeof(ctx->Xi)) { + return CRYPTO_memcmp(ctx->Xi.c, tag, len) == 0; + } else { + return 0; + } +} + +void CRYPTO_gcm128_tag(GCM128_CONTEXT *ctx, unsigned char *tag, size_t len) { + CRYPTO_gcm128_finish(ctx, NULL, 0); + memcpy(tag, ctx->Xi.c, len <= sizeof(ctx->Xi.c) ? len : sizeof(ctx->Xi.c)); +} + +void CRYPTO_gcm128_release(GCM128_CONTEXT *ctx) { + if (ctx) { + OPENSSL_cleanse(ctx, sizeof(*ctx)); + OPENSSL_free(ctx); + } +} + +#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) +int crypto_gcm_clmul_enabled(void) { +#ifdef GHASH_ASM + return OPENSSL_ia32cap_P[0] & (1 << 24) && /* check FXSR bit */ + OPENSSL_ia32cap_P[1] & (1 << 1); /* check PCLMULQDQ bit */ +#else + return 0; +#endif +} +#endif diff --git a/TMessagesProj/jni/boringssl/crypto/modes/internal.h b/TMessagesProj/jni/boringssl/crypto/modes/internal.h new file mode 100644 index 00000000..d12405e6 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/modes/internal.h @@ -0,0 +1,202 @@ +/* ==================================================================== + * Copyright (c) 2008 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== */ + +#ifndef OPENSSL_HEADER_MODES_INTERNAL_H +#define OPENSSL_HEADER_MODES_INTERNAL_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +#define asm __asm__ + +#define STRICT_ALIGNMENT 1 +#if defined(OPENSSL_X86_64) || defined(OPENSSL_X86) || defined(OPENSSL_AARCH64) +#undef STRICT_ALIGNMENT +#define STRICT_ALIGNMENT 0 +#endif + +#if !defined(PEDANTIC) && !defined(OPENSSL_NO_ASM) +#if defined(__GNUC__) && __GNUC__ >= 2 +#if defined(OPENSSL_X86_64) +#define BSWAP8(x) \ + ({ \ + uint64_t ret = (x); \ + asm("bswapq %0" : "+r"(ret)); \ + ret; \ + }) +#define BSWAP4(x) \ + ({ \ + uint32_t ret = (x); \ + asm("bswapl %0" : "+r"(ret)); \ + ret; \ + }) +#elif defined(OPENSSL_X86) +#define BSWAP8(x) \ + ({ \ + uint32_t lo = (uint64_t)(x) >> 32, hi = (x); \ + asm("bswapl %0; bswapl %1" : "+r"(hi), "+r"(lo)); \ + (uint64_t) hi << 32 | lo; \ + }) +#define BSWAP4(x) \ + ({ \ + uint32_t ret = (x); \ + asm("bswapl %0" : "+r"(ret)); \ + ret; \ + }) +#elif defined(OPENSSL_AARCH64) +#define BSWAP8(x) \ + ({ \ + uint64_t ret; \ + asm("rev %0,%1" : "=r"(ret) : "r"(x)); \ + ret; \ + }) +#define BSWAP4(x) \ + ({ \ + uint32_t ret; \ + asm("rev %w0,%w1" : "=r"(ret) : "r"(x)); \ + ret; \ + }) +#elif defined(OPENSSL_ARM) && !defined(STRICT_ALIGNMENT) +#define BSWAP8(x) \ + ({ \ + uint32_t lo = (uint64_t)(x) >> 32, hi = (x); \ + asm("rev %0,%0; rev %1,%1" : "+r"(hi), "+r"(lo)); \ + (uint64_t) hi << 32 | lo; \ + }) +#define BSWAP4(x) \ + ({ \ + uint32_t ret; \ + asm("rev %0,%1" : "=r"(ret) : "r"((uint32_t)(x))); \ + ret; \ + }) +#endif +#elif defined(_MSC_VER) +#if _MSC_VER >= 1300 +#pragma warning(push, 3) +#include +#pragma warning(pop) +#pragma intrinsic(_byteswap_uint64, _byteswap_ulong) +#define BSWAP8(x) _byteswap_uint64((uint64_t)(x)) +#define BSWAP4(x) _byteswap_ulong((uint32_t)(x)) +#elif defined(OPENSSL_X86) +__inline uint32_t _bswap4(uint32_t val) { + _asm mov eax, val + _asm bswap eax +} +#define BSWAP4(x) _bswap4(x) +#endif +#endif +#endif + +#if defined(BSWAP4) && !defined(STRICT_ALIGNMENT) +#define GETU32(p) BSWAP4(*(const uint32_t *)(p)) +#define PUTU32(p, v) *(uint32_t *)(p) = BSWAP4(v) +#else +#define GETU32(p) \ + ((uint32_t)(p)[0] << 24 | (uint32_t)(p)[1] << 16 | (uint32_t)(p)[2] << 8 | (uint32_t)(p)[3]) +#define PUTU32(p, v) \ + ((p)[0] = (uint8_t)((v) >> 24), (p)[1] = (uint8_t)((v) >> 16), \ + (p)[2] = (uint8_t)((v) >> 8), (p)[3] = (uint8_t)(v)) +#endif + + +/* GCM definitions */ +typedef struct { uint64_t hi,lo; } u128; + +struct gcm128_context { + /* Following 6 names follow names in GCM specification */ + union { + uint64_t u[2]; + uint32_t d[4]; + uint8_t c[16]; + size_t t[16 / sizeof(size_t)]; + } Yi, EKi, EK0, len, Xi, H; + + /* Relative position of Xi, H and pre-computed Htable is used in some + * assembler modules, i.e. don't change the order! */ + u128 Htable[16]; + void (*gmult)(uint64_t Xi[2], const u128 Htable[16]); + void (*ghash)(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, + size_t len); + + unsigned int mres, ares; + block128_f block; + void *key; +}; + +struct xts128_context { + void *key1, *key2; + block128_f block1, block2; +}; + +struct ccm128_context { + union { + uint64_t u[2]; + uint8_t c[16]; + } nonce, cmac; + uint64_t blocks; + block128_f block; + void *key; +}; + +#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) +/* crypto_gcm_clmul_enabled returns one if the CLMUL implementation of GCM is + * used. */ +int crypto_gcm_clmul_enabled(void); +#endif + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_MODES_INTERNAL_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/modes/ofb.c b/TMessagesProj/jni/boringssl/crypto/modes/ofb.c new file mode 100644 index 00000000..5836a9f4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/modes/ofb.c @@ -0,0 +1,107 @@ +/* ==================================================================== + * Copyright (c) 2008 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== */ + +#include + +#include + +#include "internal.h" + + +void CRYPTO_ofb128_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const void *key, uint8_t ivec[16], int *num, + block128_f block) { + unsigned int n; + + assert(in && out && key && ivec && num); + assert((16 % sizeof(size_t)) == 0); + + n = *num; + + while (n && len) { + *(out++) = *(in++) ^ ivec[n]; + --len; + n = (n + 1) % 16; + } + +#if STRICT_ALIGNMENT + if (((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) { + size_t l = 0; + while (l < len) { + if (n == 0) { + (*block)(ivec, ivec, key); + } + out[l] = in[l] ^ ivec[n]; + ++l; + n = (n + 1) % 16; + } + + *num = n; + return; + } +#endif + + while (len >= 16) { + (*block)(ivec, ivec, key); + for (; n < 16; n += sizeof(size_t)) { + *(size_t *)(out + n) = *(size_t *)(in + n) ^ *(size_t *)(ivec + n); + } + len -= 16; + out += 16; + in += 16; + n = 0; + } + if (len) { + (*block)(ivec, ivec, key); + while (len--) { + out[n] = in[n] ^ ivec[n]; + ++n; + } + } + *num = n; +} diff --git a/TMessagesProj/jni/boringssl/crypto/pem/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/pem/CMakeLists.txt new file mode 100644 index 00000000..720ba2ff --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/pem/CMakeLists.txt @@ -0,0 +1,16 @@ +include_directories(. .. ../../include) + +add_library( + pem + + OBJECT + + pem_all.c + pem_info.c + pem_lib.c + pem_oth.c + pem_pk8.c + pem_pkey.c + pem_x509.c + pem_xaux.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/pem/pem_all.c b/TMessagesProj/jni/boringssl/crypto/pem/pem_all.c new file mode 100644 index 00000000..24ecc62a --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/pem/pem_all.c @@ -0,0 +1,281 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include +#include +#include +/*#include */ +#include +#include + + +static RSA *pkey_get_rsa(EVP_PKEY *key, RSA **rsa); +static DSA *pkey_get_dsa(EVP_PKEY *key, DSA **dsa); +static EC_KEY *pkey_get_eckey(EVP_PKEY *key, EC_KEY **eckey); + + +IMPLEMENT_PEM_rw(X509_REQ, X509_REQ, PEM_STRING_X509_REQ, X509_REQ) + +IMPLEMENT_PEM_write(X509_REQ_NEW, X509_REQ, PEM_STRING_X509_REQ_OLD, X509_REQ) + +IMPLEMENT_PEM_rw(X509_CRL, X509_CRL, PEM_STRING_X509_CRL, X509_CRL) + + + +/* We treat RSA or DSA private keys as a special case. + * + * For private keys we read in an EVP_PKEY structure with + * PEM_read_bio_PrivateKey() and extract the relevant private + * key: this means can handle "traditional" and PKCS#8 formats + * transparently. + */ + +static RSA *pkey_get_rsa(EVP_PKEY *key, RSA **rsa) +{ + RSA *rtmp; + if(!key) return NULL; + rtmp = EVP_PKEY_get1_RSA(key); + EVP_PKEY_free(key); + if(!rtmp) return NULL; + if(rsa) { + RSA_free(*rsa); + *rsa = rtmp; + } + return rtmp; +} + +RSA *PEM_read_bio_RSAPrivateKey(BIO *bp, RSA **rsa, pem_password_cb *cb, + void *u) +{ + EVP_PKEY *pktmp; + pktmp = PEM_read_bio_PrivateKey(bp, NULL, cb, u); + return pkey_get_rsa(pktmp, rsa); +} + +#ifndef OPENSSL_NO_FP_API + +RSA *PEM_read_RSAPrivateKey(FILE *fp, RSA **rsa, pem_password_cb *cb, + void *u) +{ + EVP_PKEY *pktmp; + pktmp = PEM_read_PrivateKey(fp, NULL, cb, u); + return pkey_get_rsa(pktmp, rsa); +} + +#endif + +IMPLEMENT_PEM_write_cb_const(RSAPrivateKey, RSA, PEM_STRING_RSA, RSAPrivateKey) + +IMPLEMENT_PEM_rw_const(RSAPublicKey, RSA, PEM_STRING_RSA_PUBLIC, RSAPublicKey) +IMPLEMENT_PEM_rw(RSA_PUBKEY, RSA, PEM_STRING_PUBLIC, RSA_PUBKEY) + +#ifndef OPENSSL_NO_DSA + +static DSA *pkey_get_dsa(EVP_PKEY *key, DSA **dsa) +{ + DSA *dtmp; + if(!key) return NULL; + dtmp = EVP_PKEY_get1_DSA(key); + EVP_PKEY_free(key); + if(!dtmp) return NULL; + if(dsa) { + DSA_free(*dsa); + *dsa = dtmp; + } + return dtmp; +} + +DSA *PEM_read_bio_DSAPrivateKey(BIO *bp, DSA **dsa, pem_password_cb *cb, + void *u) +{ + EVP_PKEY *pktmp; + pktmp = PEM_read_bio_PrivateKey(bp, NULL, cb, u); + return pkey_get_dsa(pktmp, dsa); /* will free pktmp */ +} + + +IMPLEMENT_PEM_write_cb_const(DSAPrivateKey, DSA, PEM_STRING_DSA, DSAPrivateKey) + +IMPLEMENT_PEM_rw(DSA_PUBKEY, DSA, PEM_STRING_PUBLIC, DSA_PUBKEY) + +#ifndef OPENSSL_NO_FP_API + +DSA *PEM_read_DSAPrivateKey(FILE *fp, DSA **dsa, pem_password_cb *cb, + void *u) +{ + EVP_PKEY *pktmp; + pktmp = PEM_read_PrivateKey(fp, NULL, cb, u); + return pkey_get_dsa(pktmp, dsa); /* will free pktmp */ +} + +#endif + +IMPLEMENT_PEM_rw_const(DSAparams, DSA, PEM_STRING_DSAPARAMS, DSAparams) + +#endif + + +static EC_KEY *pkey_get_eckey(EVP_PKEY *key, EC_KEY **eckey) +{ + EC_KEY *dtmp; + if(!key) return NULL; + dtmp = EVP_PKEY_get1_EC_KEY(key); + EVP_PKEY_free(key); + if(!dtmp) return NULL; + if(eckey) + { + EC_KEY_free(*eckey); + *eckey = dtmp; + } + return dtmp; +} + +EC_KEY *PEM_read_bio_ECPrivateKey(BIO *bp, EC_KEY **key, pem_password_cb *cb, + void *u) +{ + EVP_PKEY *pktmp; + pktmp = PEM_read_bio_PrivateKey(bp, NULL, cb, u); + return pkey_get_eckey(pktmp, key); /* will free pktmp */ +} + +/* TODO(fork): remove this code? */ +/* IMPLEMENT_PEM_rw_const(ECPKParameters, EC_GROUP, PEM_STRING_ECPARAMETERS, ECPKParameters) */ + + + + +IMPLEMENT_PEM_write_cb(ECPrivateKey, EC_KEY, PEM_STRING_ECPRIVATEKEY, ECPrivateKey) + + +IMPLEMENT_PEM_rw(EC_PUBKEY, EC_KEY, PEM_STRING_PUBLIC, EC_PUBKEY) + +#ifndef OPENSSL_NO_FP_API + +EC_KEY *PEM_read_ECPrivateKey(FILE *fp, EC_KEY **eckey, pem_password_cb *cb, + void *u) +{ + EVP_PKEY *pktmp; + pktmp = PEM_read_PrivateKey(fp, NULL, cb, u); + return pkey_get_eckey(pktmp, eckey); /* will free pktmp */ +} + +#endif + + + +IMPLEMENT_PEM_write_const(DHparams, DH, PEM_STRING_DHPARAMS, DHparams) + +/* TODO(fork): remove this code? */ +/* IMPLEMENT_PEM_write_const(DHxparams, DH, PEM_STRING_DHXPARAMS, DHxparams) */ + + +IMPLEMENT_PEM_rw(PUBKEY, EVP_PKEY, PEM_STRING_PUBLIC, PUBKEY) diff --git a/TMessagesProj/jni/boringssl/crypto/pem/pem_info.c b/TMessagesProj/jni/boringssl/crypto/pem/pem_info.c new file mode 100644 index 00000000..b4ae8054 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/pem/pem_info.c @@ -0,0 +1,404 @@ +/* crypto/pem/pem_info.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifndef OPENSSL_NO_FP_API +STACK_OF(X509_INFO) *PEM_X509_INFO_read(FILE *fp, STACK_OF(X509_INFO) *sk, pem_password_cb *cb, void *u) + { + BIO *b; + STACK_OF(X509_INFO) *ret; + + if ((b=BIO_new(BIO_s_file())) == NULL) + { + OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB); + return(0); + } + BIO_set_fp(b,fp,BIO_NOCLOSE); + ret=PEM_X509_INFO_read_bio(b,sk,cb,u); + BIO_free(b); + return(ret); + } +#endif + +STACK_OF(X509_INFO) *PEM_X509_INFO_read_bio(BIO *bp, STACK_OF(X509_INFO) *sk, pem_password_cb *cb, void *u) + { + X509_INFO *xi=NULL; + char *name=NULL,*header=NULL; + void *pp; + unsigned char *data=NULL; + const unsigned char *p; + long len,error=0; + int ok=0; + STACK_OF(X509_INFO) *ret=NULL; + unsigned int i,raw,ptype; + d2i_of_void *d2i = 0; + + if (sk == NULL) + { + if ((ret=sk_X509_INFO_new_null()) == NULL) + { + OPENSSL_PUT_ERROR(PEM, ERR_R_MALLOC_FAILURE); + goto err; + } + } + else + ret=sk; + + if ((xi=X509_INFO_new()) == NULL) goto err; + for (;;) + { + raw=0; + ptype = 0; + i=PEM_read_bio(bp,&name,&header,&data,&len); + if (i == 0) + { + error=ERR_GET_REASON(ERR_peek_last_error()); + if (error == PEM_R_NO_START_LINE) + { + ERR_clear_error(); + break; + } + goto err; + } +start: + if ( (strcmp(name,PEM_STRING_X509) == 0) || + (strcmp(name,PEM_STRING_X509_OLD) == 0)) + { + d2i=(D2I_OF(void))d2i_X509; + if (xi->x509 != NULL) + { + if (!sk_X509_INFO_push(ret,xi)) goto err; + if ((xi=X509_INFO_new()) == NULL) goto err; + goto start; + } + pp=&(xi->x509); + } + else if ((strcmp(name,PEM_STRING_X509_TRUSTED) == 0)) + { + d2i=(D2I_OF(void))d2i_X509_AUX; + if (xi->x509 != NULL) + { + if (!sk_X509_INFO_push(ret,xi)) goto err; + if ((xi=X509_INFO_new()) == NULL) goto err; + goto start; + } + pp=&(xi->x509); + } + else if (strcmp(name,PEM_STRING_X509_CRL) == 0) + { + d2i=(D2I_OF(void))d2i_X509_CRL; + if (xi->crl != NULL) + { + if (!sk_X509_INFO_push(ret,xi)) goto err; + if ((xi=X509_INFO_new()) == NULL) goto err; + goto start; + } + pp=&(xi->crl); + } + else + if (strcmp(name,PEM_STRING_RSA) == 0) + { + d2i=(D2I_OF(void))d2i_RSAPrivateKey; + if (xi->x_pkey != NULL) + { + if (!sk_X509_INFO_push(ret,xi)) goto err; + if ((xi=X509_INFO_new()) == NULL) goto err; + goto start; + } + + xi->enc_data=NULL; + xi->enc_len=0; + + xi->x_pkey=X509_PKEY_new(); + ptype=EVP_PKEY_RSA; + pp=&xi->x_pkey->dec_pkey; + if ((int)strlen(header) > 10) /* assume encrypted */ + raw=1; + } + else +#ifndef OPENSSL_NO_DSA + if (strcmp(name,PEM_STRING_DSA) == 0) + { + d2i=(D2I_OF(void))d2i_DSAPrivateKey; + if (xi->x_pkey != NULL) + { + if (!sk_X509_INFO_push(ret,xi)) goto err; + if ((xi=X509_INFO_new()) == NULL) goto err; + goto start; + } + + xi->enc_data=NULL; + xi->enc_len=0; + + xi->x_pkey=X509_PKEY_new(); + ptype = EVP_PKEY_DSA; + pp=&xi->x_pkey->dec_pkey; + if ((int)strlen(header) > 10) /* assume encrypted */ + raw=1; + } + else +#endif + if (strcmp(name,PEM_STRING_ECPRIVATEKEY) == 0) + { + d2i=(D2I_OF(void))d2i_ECPrivateKey; + if (xi->x_pkey != NULL) + { + if (!sk_X509_INFO_push(ret,xi)) goto err; + if ((xi=X509_INFO_new()) == NULL) goto err; + goto start; + } + + xi->enc_data=NULL; + xi->enc_len=0; + + xi->x_pkey=X509_PKEY_new(); + ptype = EVP_PKEY_EC; + pp=&xi->x_pkey->dec_pkey; + if ((int)strlen(header) > 10) /* assume encrypted */ + raw=1; + } + else + { + d2i=NULL; + pp=NULL; + } + + if (d2i != NULL) + { + if (!raw) + { + EVP_CIPHER_INFO cipher; + + if (!PEM_get_EVP_CIPHER_INFO(header,&cipher)) + goto err; + if (!PEM_do_header(&cipher,data,&len,cb,u)) + goto err; + p=data; + if (ptype) + { + if (!d2i_PrivateKey(ptype, pp, &p, len)) + { + OPENSSL_PUT_ERROR(PEM, ERR_R_ASN1_LIB); + goto err; + } + } + else if (d2i(pp,&p,len) == NULL) + { + OPENSSL_PUT_ERROR(PEM, ERR_R_ASN1_LIB); + goto err; + } + } + else + { /* encrypted RSA data */ + if (!PEM_get_EVP_CIPHER_INFO(header, + &xi->enc_cipher)) goto err; + xi->enc_data=(char *)data; + xi->enc_len=(int)len; + data=NULL; + } + } + else { + /* unknown */ + } + if (name != NULL) OPENSSL_free(name); + if (header != NULL) OPENSSL_free(header); + if (data != NULL) OPENSSL_free(data); + name=NULL; + header=NULL; + data=NULL; + } + + /* if the last one hasn't been pushed yet and there is anything + * in it then add it to the stack ... + */ + if ((xi->x509 != NULL) || (xi->crl != NULL) || + (xi->x_pkey != NULL) || (xi->enc_data != NULL)) + { + if (!sk_X509_INFO_push(ret,xi)) goto err; + xi=NULL; + } + ok=1; +err: + if (xi != NULL) X509_INFO_free(xi); + if (!ok) + { + for (i=0; ((int)i)x_pkey!=NULL) + { + if ( (xi->enc_data!=NULL) && (xi->enc_len>0) ) + { + if (enc == NULL) + { + OPENSSL_PUT_ERROR(PEM, PEM_R_CIPHER_IS_NULL); + goto err; + } + + /* copy from weirdo names into more normal things */ + iv=xi->enc_cipher.iv; + data=(unsigned char *)xi->enc_data; + i=xi->enc_len; + + /* we take the encryption data from the + * internal stuff rather than what the + * user has passed us ... as we have to + * match exactly for some strange reason + */ + objstr=OBJ_nid2sn( + EVP_CIPHER_nid(xi->enc_cipher.cipher)); + if (objstr == NULL) + { + OPENSSL_PUT_ERROR(PEM, PEM_R_UNSUPPORTED_CIPHER); + goto err; + } + + /* create the right magic header stuff */ + assert(strlen(objstr)+23+2*iv_len+13 <= sizeof buf); + buf[0]='\0'; + PEM_proc_type(buf,PEM_TYPE_ENCRYPTED); + PEM_dek_info(buf,objstr,iv_len,(char *)iv); + + /* use the normal code to write things out */ + i=PEM_write_bio(bp,PEM_STRING_RSA,buf,data,i); + if (i <= 0) goto err; + } + else + { + /* Add DSA/DH */ + /* normal optionally encrypted stuff */ + if (PEM_write_bio_RSAPrivateKey(bp, + xi->x_pkey->dec_pkey->pkey.rsa, + enc,kstr,klen,cb,u)<=0) + goto err; + } + } + + /* if we have a certificate then write it out now */ + if ((xi->x509 != NULL) && (PEM_write_bio_X509(bp,xi->x509) <= 0)) + goto err; + + /* we are ignoring anything else that is loaded into the X509_INFO + * structure for the moment ... as I don't need it so I'm not + * coding it here and Eric can do it when this makes it into the + * base library --tjh + */ + + ret=1; + +err: + OPENSSL_cleanse((char *)&ctx,sizeof(ctx)); + OPENSSL_cleanse(buf,PEM_BUFSIZE); + return(ret); + } diff --git a/TMessagesProj/jni/boringssl/crypto/pem/pem_lib.c b/TMessagesProj/jni/boringssl/crypto/pem/pem_lib.c new file mode 100644 index 00000000..59156969 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/pem/pem_lib.c @@ -0,0 +1,835 @@ +/* crypto/pem/pem_lib.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../evp/internal.h" + + +#define MIN_LENGTH 4 + +static int load_iv(char **fromp,unsigned char *to, int num); +static int check_pem(const char *nm, const char *name); +int pem_check_suffix(const char *pem_str, const char *suffix); + +void PEM_proc_type(char *buf, int type) + { + const char *str; + + if (type == PEM_TYPE_ENCRYPTED) + str="ENCRYPTED"; + else if (type == PEM_TYPE_MIC_CLEAR) + str="MIC-CLEAR"; + else if (type == PEM_TYPE_MIC_ONLY) + str="MIC-ONLY"; + else + str="BAD-TYPE"; + + BUF_strlcat(buf,"Proc-Type: 4,",PEM_BUFSIZE); + BUF_strlcat(buf,str,PEM_BUFSIZE); + BUF_strlcat(buf,"\n",PEM_BUFSIZE); + } + +void PEM_dek_info(char *buf, const char *type, int len, char *str) + { + static const unsigned char map[17]="0123456789ABCDEF"; + long i; + int j; + + BUF_strlcat(buf,"DEK-Info: ",PEM_BUFSIZE); + BUF_strlcat(buf,type,PEM_BUFSIZE); + BUF_strlcat(buf,",",PEM_BUFSIZE); + j=strlen(buf); + if (j + (len * 2) + 1 > PEM_BUFSIZE) + return; + for (i=0; i>4)&0x0f]; + buf[j+i*2+1]=map[(str[i] )&0x0f]; + } + buf[j+i*2]='\n'; + buf[j+i*2+1]='\0'; + } + +#ifndef OPENSSL_NO_FP_API +void *PEM_ASN1_read(d2i_of_void *d2i, const char *name, FILE *fp, void **x, + pem_password_cb *cb, void *u) + { + BIO *b; + void *ret; + + if ((b=BIO_new(BIO_s_file())) == NULL) + { + OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB); + return(0); + } + BIO_set_fp(b,fp,BIO_NOCLOSE); + ret=PEM_ASN1_read_bio(d2i,name,b,x,cb,u); + BIO_free(b); + return(ret); + } +#endif + +static int check_pem(const char *nm, const char *name) +{ + /* Normal matching nm and name */ + if (!strcmp(nm,name)) return 1; + + /* Make PEM_STRING_EVP_PKEY match any private key */ + + if(!strcmp(name,PEM_STRING_EVP_PKEY)) + { + int slen; + const EVP_PKEY_ASN1_METHOD *ameth; + if(!strcmp(nm,PEM_STRING_PKCS8)) + return 1; + if(!strcmp(nm,PEM_STRING_PKCS8INF)) + return 1; + slen = pem_check_suffix(nm, "PRIVATE KEY"); + if (slen > 0) + { + /* NB: ENGINE implementations wont contain + * a deprecated old private key decode function + * so don't look for them. + */ + ameth = EVP_PKEY_asn1_find_str(NULL, nm, slen); + if (ameth && ameth->old_priv_decode) + return 1; + } + return 0; + } + + if(!strcmp(name,PEM_STRING_PARAMETERS)) + { + int slen; + const EVP_PKEY_ASN1_METHOD *ameth; + slen = pem_check_suffix(nm, "PARAMETERS"); + if (slen > 0) + { + ENGINE *e; + ameth = EVP_PKEY_asn1_find_str(&e, nm, slen); + if (ameth) + { + int r; + if (ameth->param_decode) + r = 1; + else + r = 0; + return r; + } + } + return 0; + } + /* If reading DH parameters handle X9.42 DH format too */ + if(!strcmp(nm,PEM_STRING_DHXPARAMS) && + !strcmp(name,PEM_STRING_DHPARAMS)) return 1; + + /* Permit older strings */ + + if(!strcmp(nm,PEM_STRING_X509_OLD) && + !strcmp(name,PEM_STRING_X509)) return 1; + + if(!strcmp(nm,PEM_STRING_X509_REQ_OLD) && + !strcmp(name,PEM_STRING_X509_REQ)) return 1; + + /* Allow normal certs to be read as trusted certs */ + if(!strcmp(nm,PEM_STRING_X509) && + !strcmp(name,PEM_STRING_X509_TRUSTED)) return 1; + + if(!strcmp(nm,PEM_STRING_X509_OLD) && + !strcmp(name,PEM_STRING_X509_TRUSTED)) return 1; + + /* Some CAs use PKCS#7 with CERTIFICATE headers */ + if(!strcmp(nm, PEM_STRING_X509) && + !strcmp(name, PEM_STRING_PKCS7)) return 1; + + if(!strcmp(nm, PEM_STRING_PKCS7_SIGNED) && + !strcmp(name, PEM_STRING_PKCS7)) return 1; + +#ifndef OPENSSL_NO_CMS + if(!strcmp(nm, PEM_STRING_X509) && + !strcmp(name, PEM_STRING_CMS)) return 1; + /* Allow CMS to be read from PKCS#7 headers */ + if(!strcmp(nm, PEM_STRING_PKCS7) && + !strcmp(name, PEM_STRING_CMS)) return 1; +#endif + + return 0; +} + +int PEM_bytes_read_bio(unsigned char **pdata, long *plen, char **pnm, const char *name, BIO *bp, + pem_password_cb *cb, void *u) + { + EVP_CIPHER_INFO cipher; + char *nm=NULL,*header=NULL; + unsigned char *data=NULL; + long len; + int ret = 0; + + for (;;) + { + if (!PEM_read_bio(bp,&nm,&header,&data,&len)) { + if(ERR_GET_REASON(ERR_peek_error()) == + PEM_R_NO_START_LINE) + ERR_add_error_data(2, "Expecting: ", name); + return 0; + } + if(check_pem(nm, name)) break; + OPENSSL_free(nm); + OPENSSL_free(header); + OPENSSL_free(data); + } + if (!PEM_get_EVP_CIPHER_INFO(header,&cipher)) goto err; + if (!PEM_do_header(&cipher,data,&len,cb,u)) goto err; + + *pdata = data; + *plen = len; + + if (pnm) + *pnm = nm; + + ret = 1; + +err: + if (!ret || !pnm) OPENSSL_free(nm); + OPENSSL_free(header); + if (!ret) OPENSSL_free(data); + return ret; + } + +#ifndef OPENSSL_NO_FP_API +int PEM_ASN1_write(i2d_of_void *i2d, const char *name, FILE *fp, + void *x, const EVP_CIPHER *enc, unsigned char *kstr, + int klen, pem_password_cb *callback, void *u) + { + BIO *b; + int ret; + + if ((b=BIO_new(BIO_s_file())) == NULL) + { + OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB); + return(0); + } + BIO_set_fp(b,fp,BIO_NOCLOSE); + ret=PEM_ASN1_write_bio(i2d,name,b,x,enc,kstr,klen,callback,u); + BIO_free(b); + return(ret); + } +#endif + +int PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, BIO *bp, + void *x, const EVP_CIPHER *enc, unsigned char *kstr, + int klen, pem_password_cb *callback, void *u) + { + EVP_CIPHER_CTX ctx; + int dsize=0,i,j,ret=0; + unsigned char *p,*data=NULL; + const char *objstr=NULL; + char buf[PEM_BUFSIZE]; + unsigned char key[EVP_MAX_KEY_LENGTH]; + unsigned char iv[EVP_MAX_IV_LENGTH]; + + if (enc != NULL) + { + objstr=OBJ_nid2sn(EVP_CIPHER_nid(enc)); + if (objstr == NULL) + { + OPENSSL_PUT_ERROR(PEM, PEM_R_UNSUPPORTED_CIPHER); + goto err; + } + } + + if ((dsize=i2d(x,NULL)) < 0) + { + OPENSSL_PUT_ERROR(PEM, ERR_R_ASN1_LIB); + dsize=0; + goto err; + } + /* dzise + 8 bytes are needed */ + /* actually it needs the cipher block size extra... */ + data=(unsigned char *)OPENSSL_malloc((unsigned int)dsize+20); + if (data == NULL) + { + OPENSSL_PUT_ERROR(PEM, ERR_R_MALLOC_FAILURE); + goto err; + } + p=data; + i=i2d(x,&p); + + if (enc != NULL) + { + const unsigned iv_len = EVP_CIPHER_iv_length(enc); + + if (kstr == NULL) + { + klen = 0; + if (!callback) + callback = PEM_def_callback; + klen=(*callback)(buf,PEM_BUFSIZE,1,u); + if (klen <= 0) + { + OPENSSL_PUT_ERROR(PEM, PEM_R_READ_KEY); + goto err; + } + kstr=(unsigned char *)buf; + } + assert(iv_len <= (int)sizeof(iv)); + if (!RAND_bytes(iv, iv_len)) /* Generate a salt */ + goto err; + /* The 'iv' is used as the iv and as a salt. It is + * NOT taken from the BytesToKey function */ + if (!EVP_BytesToKey(enc,EVP_md5(),iv,kstr,klen,1,key,NULL)) + goto err; + + if (kstr == (unsigned char *)buf) OPENSSL_cleanse(buf,PEM_BUFSIZE); + + assert(strlen(objstr)+23+2*iv_len+13 <= sizeof buf); + + buf[0]='\0'; + PEM_proc_type(buf,PEM_TYPE_ENCRYPTED); + PEM_dek_info(buf,objstr,iv_len,(char *)iv); + /* k=strlen(buf); */ + + EVP_CIPHER_CTX_init(&ctx); + ret = 1; + if (!EVP_EncryptInit_ex(&ctx,enc,NULL,key,iv) + || !EVP_EncryptUpdate(&ctx,data,&j,data,i) + || !EVP_EncryptFinal_ex(&ctx,&(data[j]),&i)) + ret = 0; + else + i += j; + EVP_CIPHER_CTX_cleanup(&ctx); + if (ret == 0) + goto err; + } + else + { + ret=1; + buf[0]='\0'; + } + i=PEM_write_bio(bp,name,buf,data,i); + if (i <= 0) ret=0; +err: + OPENSSL_cleanse(key,sizeof(key)); + OPENSSL_cleanse(iv,sizeof(iv)); + OPENSSL_cleanse((char *)&ctx,sizeof(ctx)); + OPENSSL_cleanse(buf,PEM_BUFSIZE); + if (data != NULL) + { + OPENSSL_cleanse(data,(unsigned int)dsize); + OPENSSL_free(data); + } + return(ret); + } + +int PEM_do_header(EVP_CIPHER_INFO *cipher, unsigned char *data, long *plen, + pem_password_cb *callback,void *u) + { + int i=0,j,o,klen; + long len; + EVP_CIPHER_CTX ctx; + unsigned char key[EVP_MAX_KEY_LENGTH]; + char buf[PEM_BUFSIZE]; + + len= *plen; + + if (cipher->cipher == NULL) return(1); + + klen = 0; + if (!callback) callback = PEM_def_callback; + klen=callback(buf,PEM_BUFSIZE,0,u); + if (klen <= 0) + { + OPENSSL_PUT_ERROR(PEM, PEM_R_BAD_PASSWORD_READ); + return(0); + } + + if (!EVP_BytesToKey(cipher->cipher,EVP_md5(),&(cipher->iv[0]), + (unsigned char *)buf,klen,1,key,NULL)) + return 0; + + j=(int)len; + EVP_CIPHER_CTX_init(&ctx); + o = EVP_DecryptInit_ex(&ctx,cipher->cipher,NULL, key,&(cipher->iv[0])); + if (o) + o = EVP_DecryptUpdate(&ctx,data,&i,data,j); + if (o) + o = EVP_DecryptFinal_ex(&ctx,&(data[i]),&j); + EVP_CIPHER_CTX_cleanup(&ctx); + OPENSSL_cleanse((char *)buf,sizeof(buf)); + OPENSSL_cleanse((char *)key,sizeof(key)); + if (!o) + { + OPENSSL_PUT_ERROR(PEM, PEM_R_BAD_DECRYPT); + return(0); + } + j+=i; + *plen=j; + return(1); + } + +static const EVP_CIPHER* cipher_by_name(const char *name) { + /* This is similar to the (deprecated) function |EVP_get_cipherbyname|. */ + if (0 == strcmp(name, SN_rc4)) { + return EVP_rc4(); + } else if (0 == strcmp(name, SN_des_cbc)) { + return EVP_des_cbc(); + } else if (0 == strcmp(name, SN_des_ede3_cbc)) { + return EVP_des_ede3_cbc(); + } else if (0 == strcmp(name, SN_aes_128_cbc)) { + return EVP_aes_128_cbc(); + } else if (0 == strcmp(name, SN_aes_192_cbc)) { + return EVP_aes_192_cbc(); + } else if (0 == strcmp(name, SN_aes_256_cbc)) { + return EVP_aes_256_cbc(); + } else { + return NULL; + } +} + +int PEM_get_EVP_CIPHER_INFO(char *header, EVP_CIPHER_INFO *cipher) + { + const EVP_CIPHER *enc=NULL; + char *p,c; + char **header_pp = &header; + + cipher->cipher=NULL; + if ((header == NULL) || (*header == '\0') || (*header == '\n')) + return(1); + if (strncmp(header,"Proc-Type: ",11) != 0) + { OPENSSL_PUT_ERROR(PEM, PEM_R_NOT_PROC_TYPE); return(0); } + header+=11; + if (*header != '4') return(0); header++; + if (*header != ',') return(0); header++; + if (strncmp(header,"ENCRYPTED",9) != 0) + { OPENSSL_PUT_ERROR(PEM, PEM_R_NOT_ENCRYPTED); return(0); } + for (; (*header != '\n') && (*header != '\0'); header++) + ; + if (*header == '\0') + { OPENSSL_PUT_ERROR(PEM, PEM_R_SHORT_HEADER); return(0); } + header++; + if (strncmp(header,"DEK-Info: ",10) != 0) + { OPENSSL_PUT_ERROR(PEM, PEM_R_NOT_DEK_INFO); return(0); } + header+=10; + + p=header; + for (;;) + { + c= *header; + if (!( ((c >= 'A') && (c <= 'Z')) || (c == '-') || + ((c >= '0') && (c <= '9')))) + break; + header++; + } + *header='\0'; + cipher->cipher=enc=cipher_by_name(p); + *header=c; + header++; + + if (enc == NULL) + { + OPENSSL_PUT_ERROR(PEM, PEM_R_UNSUPPORTED_ENCRYPTION); + return(0); + } + if (!load_iv(header_pp,&(cipher->iv[0]),EVP_CIPHER_iv_length(enc))) + return(0); + + return(1); + } + +static int load_iv(char **fromp, unsigned char *to, int num) + { + int v,i; + char *from; + + from= *fromp; + for (i=0; i= '0') && (*from <= '9')) + v= *from-'0'; + else if ((*from >= 'A') && (*from <= 'F')) + v= *from-'A'+10; + else if ((*from >= 'a') && (*from <= 'f')) + v= *from-'a'+10; + else + { + OPENSSL_PUT_ERROR(PEM, PEM_R_BAD_IV_CHARS); + return(0); + } + from++; + to[i/2]|=v<<(long)((!(i&1))*4); + } + + *fromp=from; + return(1); + } + +#ifndef OPENSSL_NO_FP_API +int PEM_write(FILE *fp, const char *name, const char *header, + const unsigned char *data, long len) + { + BIO *b; + int ret; + + if ((b=BIO_new(BIO_s_file())) == NULL) + { + OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB); + return(0); + } + BIO_set_fp(b,fp,BIO_NOCLOSE); + ret=PEM_write_bio(b, name, header, data,len); + BIO_free(b); + return(ret); + } +#endif + +int PEM_write_bio(BIO *bp, const char *name, const char *header, + const unsigned char *data, long len) + { + int nlen,n,i,j,outl; + unsigned char *buf = NULL; + EVP_ENCODE_CTX ctx; + int reason=ERR_R_BUF_LIB; + + EVP_EncodeInit(&ctx); + nlen=strlen(name); + + if ( (BIO_write(bp,"-----BEGIN ",11) != 11) || + (BIO_write(bp,name,nlen) != nlen) || + (BIO_write(bp,"-----\n",6) != 6)) + goto err; + + i=strlen(header); + if (i > 0) + { + if ( (BIO_write(bp,header,i) != i) || + (BIO_write(bp,"\n",1) != 1)) + goto err; + } + + buf = OPENSSL_malloc(PEM_BUFSIZE*8); + if (buf == NULL) + { + reason=ERR_R_MALLOC_FAILURE; + goto err; + } + + i=j=0; + while (len > 0) + { + n=(int)((len>(PEM_BUFSIZE*5))?(PEM_BUFSIZE*5):len); + EVP_EncodeUpdate(&ctx,buf,&outl,&(data[j]),n); + if ((outl) && (BIO_write(bp,(char *)buf,outl) != outl)) + goto err; + i+=outl; + len-=n; + j+=n; + } + EVP_EncodeFinal(&ctx,buf,&outl); + if ((outl > 0) && (BIO_write(bp,(char *)buf,outl) != outl)) goto err; + OPENSSL_cleanse(buf, PEM_BUFSIZE*8); + OPENSSL_free(buf); + buf = NULL; + if ( (BIO_write(bp,"-----END ",9) != 9) || + (BIO_write(bp,name,nlen) != nlen) || + (BIO_write(bp,"-----\n",6) != 6)) + goto err; + return(i+outl); +err: + if (buf) { + OPENSSL_cleanse(buf, PEM_BUFSIZE*8); + OPENSSL_free(buf); + } + OPENSSL_PUT_ERROR(PEM, reason); + return(0); + } + +#ifndef OPENSSL_NO_FP_API +int PEM_read(FILE *fp, char **name, char **header, unsigned char **data, + long *len) + { + BIO *b; + int ret; + + if ((b=BIO_new(BIO_s_file())) == NULL) + { + OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB); + return(0); + } + BIO_set_fp(b,fp,BIO_NOCLOSE); + ret=PEM_read_bio(b, name, header, data,len); + BIO_free(b); + return(ret); + } +#endif + +int PEM_read_bio(BIO *bp, char **name, char **header, unsigned char **data, + long *len) + { + EVP_ENCODE_CTX ctx; + int end=0,i,k,bl=0,hl=0,nohead=0; + char buf[256]; + BUF_MEM *nameB; + BUF_MEM *headerB; + BUF_MEM *dataB,*tmpB; + + nameB=BUF_MEM_new(); + headerB=BUF_MEM_new(); + dataB=BUF_MEM_new(); + if ((nameB == NULL) || (headerB == NULL) || (dataB == NULL)) + { + BUF_MEM_free(nameB); + BUF_MEM_free(headerB); + BUF_MEM_free(dataB); + OPENSSL_PUT_ERROR(PEM, ERR_R_MALLOC_FAILURE); + return(0); + } + + buf[254]='\0'; + for (;;) + { + i=BIO_gets(bp,buf,254); + + if (i <= 0) + { + OPENSSL_PUT_ERROR(PEM, PEM_R_NO_START_LINE); + goto err; + } + + while ((i >= 0) && (buf[i] <= ' ')) i--; + buf[++i]='\n'; buf[++i]='\0'; + + if (strncmp(buf,"-----BEGIN ",11) == 0) + { + i=strlen(&(buf[11])); + + if (strncmp(&(buf[11+i-6]),"-----\n",6) != 0) + continue; + if (!BUF_MEM_grow(nameB,i+9)) + { + OPENSSL_PUT_ERROR(PEM, ERR_R_MALLOC_FAILURE); + goto err; + } + memcpy(nameB->data,&(buf[11]),i-6); + nameB->data[i-6]='\0'; + break; + } + } + hl=0; + if (!BUF_MEM_grow(headerB,256)) + { OPENSSL_PUT_ERROR(PEM, ERR_R_MALLOC_FAILURE); goto err; } + headerB->data[0]='\0'; + for (;;) + { + i=BIO_gets(bp,buf,254); + if (i <= 0) break; + + while ((i >= 0) && (buf[i] <= ' ')) i--; + buf[++i]='\n'; buf[++i]='\0'; + + if (buf[0] == '\n') break; + if (!BUF_MEM_grow(headerB,hl+i+9)) + { OPENSSL_PUT_ERROR(PEM, ERR_R_MALLOC_FAILURE); goto err; } + if (strncmp(buf,"-----END ",9) == 0) + { + nohead=1; + break; + } + memcpy(&(headerB->data[hl]),buf,i); + headerB->data[hl+i]='\0'; + hl+=i; + } + + bl=0; + if (!BUF_MEM_grow(dataB,1024)) + { OPENSSL_PUT_ERROR(PEM, ERR_R_MALLOC_FAILURE); goto err; } + dataB->data[0]='\0'; + if (!nohead) + { + for (;;) + { + i=BIO_gets(bp,buf,254); + if (i <= 0) break; + + while ((i >= 0) && (buf[i] <= ' ')) i--; + buf[++i]='\n'; buf[++i]='\0'; + + if (i != 65) end=1; + if (strncmp(buf,"-----END ",9) == 0) + break; + if (i > 65) break; + if (!BUF_MEM_grow_clean(dataB,i+bl+9)) + { + OPENSSL_PUT_ERROR(PEM, ERR_R_MALLOC_FAILURE); + goto err; + } + memcpy(&(dataB->data[bl]),buf,i); + dataB->data[bl+i]='\0'; + bl+=i; + if (end) + { + buf[0]='\0'; + i=BIO_gets(bp,buf,254); + if (i <= 0) break; + + while ((i >= 0) && (buf[i] <= ' ')) i--; + buf[++i]='\n'; buf[++i]='\0'; + + break; + } + } + } + else + { + tmpB=headerB; + headerB=dataB; + dataB=tmpB; + bl=hl; + } + i=strlen(nameB->data); + if ( (strncmp(buf,"-----END ",9) != 0) || + (strncmp(nameB->data,&(buf[9]),i) != 0) || + (strncmp(&(buf[9+i]),"-----\n",6) != 0)) + { + OPENSSL_PUT_ERROR(PEM, PEM_R_BAD_END_LINE); + goto err; + } + + EVP_DecodeInit(&ctx); + i=EVP_DecodeUpdate(&ctx, + (unsigned char *)dataB->data,&bl, + (unsigned char *)dataB->data,bl); + if (i < 0) + { + OPENSSL_PUT_ERROR(PEM, PEM_R_BAD_BASE64_DECODE); + goto err; + } + i=EVP_DecodeFinal(&ctx,(unsigned char *)&(dataB->data[bl]),&k); + if (i < 0) + { + OPENSSL_PUT_ERROR(PEM, PEM_R_BAD_BASE64_DECODE); + goto err; + } + bl+=k; + + if (bl == 0) goto err; + *name=nameB->data; + *header=headerB->data; + *data=(unsigned char *)dataB->data; + *len=bl; + OPENSSL_free(nameB); + OPENSSL_free(headerB); + OPENSSL_free(dataB); + return(1); +err: + BUF_MEM_free(nameB); + BUF_MEM_free(headerB); + BUF_MEM_free(dataB); + return(0); + } + +/* Check pem string and return prefix length. + * If for example the pem_str == "RSA PRIVATE KEY" and suffix = "PRIVATE KEY" + * the return value is 3 for the string "RSA". + */ + +int pem_check_suffix(const char *pem_str, const char *suffix) + { + int pem_len = strlen(pem_str); + int suffix_len = strlen(suffix); + const char *p; + if (suffix_len + 1 >= pem_len) + return 0; + p = pem_str + pem_len - suffix_len; + if (strcmp(p, suffix)) + return 0; + p--; + if (*p != ' ') + return 0; + return p - pem_str; + } + +int PEM_def_callback(char *buf, int size, int rwflag, void *userdata) + { + if (!buf || !userdata) + { + return 0; + } + size_t len = strlen((char *) userdata); + if (len >= (size_t) size) + { + return 0; + } + strcpy(buf, (char *) userdata); + return len; + } diff --git a/TMessagesProj/jni/boringssl/crypto/pem/pem_oth.c b/TMessagesProj/jni/boringssl/crypto/pem/pem_oth.c new file mode 100644 index 00000000..3e8f6bda --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/pem/pem_oth.c @@ -0,0 +1,89 @@ +/* crypto/pem/pem_oth.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + + +/* Handle 'other' PEMs: not private keys */ + +void *PEM_ASN1_read_bio(d2i_of_void *d2i, const char *name, BIO *bp, void **x, + pem_password_cb *cb, void *u) + { + const unsigned char *p=NULL; + unsigned char *data=NULL; + long len; + char *ret=NULL; + + if (!PEM_bytes_read_bio(&data, &len, NULL, name, bp, cb, u)) + return NULL; + p = data; + ret=d2i(x,&p,len); + if (ret == NULL) + OPENSSL_PUT_ERROR(PEM, ERR_R_ASN1_LIB); + OPENSSL_free(data); + return ret; + } diff --git a/TMessagesProj/jni/boringssl/crypto/pem/pem_pk8.c b/TMessagesProj/jni/boringssl/crypto/pem/pem_pk8.c new file mode 100644 index 00000000..08244772 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/pem/pem_pk8.c @@ -0,0 +1,244 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +static int do_pk8pkey(BIO *bp, EVP_PKEY *x, int isder, + int nid, const EVP_CIPHER *enc, + char *kstr, int klen, + pem_password_cb *cb, void *u); +static int do_pk8pkey_fp(FILE *bp, EVP_PKEY *x, int isder, + int nid, const EVP_CIPHER *enc, + char *kstr, int klen, + pem_password_cb *cb, void *u); + +/* These functions write a private key in PKCS#8 format: it is a "drop in" + * replacement for PEM_write_bio_PrivateKey() and friends. As usual if 'enc' + * is NULL then it uses the unencrypted private key form. The 'nid' versions + * uses PKCS#5 v1.5 PBE algorithms whereas the others use PKCS#5 v2.0. + */ + +int PEM_write_bio_PKCS8PrivateKey_nid(BIO *bp, EVP_PKEY *x, int nid, + char *kstr, int klen, + pem_password_cb *cb, void *u) +{ + return do_pk8pkey(bp, x, 0, nid, NULL, kstr, klen, cb, u); +} + +int PEM_write_bio_PKCS8PrivateKey(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc, + char *kstr, int klen, + pem_password_cb *cb, void *u) +{ + return do_pk8pkey(bp, x, 0, -1, enc, kstr, klen, cb, u); +} + +int i2d_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc, + char *kstr, int klen, + pem_password_cb *cb, void *u) +{ + return do_pk8pkey(bp, x, 1, -1, enc, kstr, klen, cb, u); +} + +int i2d_PKCS8PrivateKey_nid_bio(BIO *bp, EVP_PKEY *x, int nid, + char *kstr, int klen, + pem_password_cb *cb, void *u) +{ + return do_pk8pkey(bp, x, 1, nid, NULL, kstr, klen, cb, u); +} + +static int do_pk8pkey(BIO *bp, EVP_PKEY *x, int isder, int nid, const EVP_CIPHER *enc, + char *kstr, int klen, + pem_password_cb *cb, void *u) +{ + X509_SIG *p8; + PKCS8_PRIV_KEY_INFO *p8inf; + char buf[PEM_BUFSIZE]; + int ret; + if(!(p8inf = EVP_PKEY2PKCS8(x))) { + OPENSSL_PUT_ERROR(PEM, PEM_R_ERROR_CONVERTING_PRIVATE_KEY); + return 0; + } + if(enc || (nid != -1)) { + if(!kstr) { + klen = 0; + if (!cb) cb = PEM_def_callback; + klen = cb(buf, PEM_BUFSIZE, 1, u); + if(klen <= 0) { + OPENSSL_PUT_ERROR(PEM, PEM_R_READ_KEY); + PKCS8_PRIV_KEY_INFO_free(p8inf); + return 0; + } + + kstr = buf; + } + p8 = PKCS8_encrypt(nid, enc, kstr, klen, NULL, 0, 0, p8inf); + if(kstr == buf) OPENSSL_cleanse(buf, klen); + PKCS8_PRIV_KEY_INFO_free(p8inf); + if(isder) ret = i2d_PKCS8_bio(bp, p8); + else ret = PEM_write_bio_PKCS8(bp, p8); + X509_SIG_free(p8); + return ret; + } else { + if(isder) ret = i2d_PKCS8_PRIV_KEY_INFO_bio(bp, p8inf); + else ret = PEM_write_bio_PKCS8_PRIV_KEY_INFO(bp, p8inf); + PKCS8_PRIV_KEY_INFO_free(p8inf); + return ret; + } +} + +EVP_PKEY *d2i_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, void *u) +{ + PKCS8_PRIV_KEY_INFO *p8inf = NULL; + X509_SIG *p8 = NULL; + int klen; + EVP_PKEY *ret; + char psbuf[PEM_BUFSIZE]; + p8 = d2i_PKCS8_bio(bp, NULL); + if(!p8) return NULL; + + klen = 0; + if (!cb) cb = PEM_def_callback; + klen=cb(psbuf,PEM_BUFSIZE,0,u); + if (klen <= 0) { + OPENSSL_PUT_ERROR(PEM, PEM_R_BAD_PASSWORD_READ); + X509_SIG_free(p8); + return NULL; + } + p8inf = PKCS8_decrypt(p8, psbuf, klen); + X509_SIG_free(p8); + if(!p8inf) return NULL; + ret = EVP_PKCS82PKEY(p8inf); + PKCS8_PRIV_KEY_INFO_free(p8inf); + if(!ret) return NULL; + if(x) { + if(*x) EVP_PKEY_free(*x); + *x = ret; + } + return ret; +} + +#ifndef OPENSSL_NO_FP_API + +int i2d_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc, + char *kstr, int klen, + pem_password_cb *cb, void *u) +{ + return do_pk8pkey_fp(fp, x, 1, -1, enc, kstr, klen, cb, u); +} + +int i2d_PKCS8PrivateKey_nid_fp(FILE *fp, EVP_PKEY *x, int nid, + char *kstr, int klen, + pem_password_cb *cb, void *u) +{ + return do_pk8pkey_fp(fp, x, 1, nid, NULL, kstr, klen, cb, u); +} + +int PEM_write_PKCS8PrivateKey_nid(FILE *fp, EVP_PKEY *x, int nid, + char *kstr, int klen, + pem_password_cb *cb, void *u) +{ + return do_pk8pkey_fp(fp, x, 0, nid, NULL, kstr, klen, cb, u); +} + +int PEM_write_PKCS8PrivateKey(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc, + char *kstr, int klen, pem_password_cb *cb, void *u) +{ + return do_pk8pkey_fp(fp, x, 0, -1, enc, kstr, klen, cb, u); +} + +static int do_pk8pkey_fp(FILE *fp, EVP_PKEY *x, int isder, int nid, const EVP_CIPHER *enc, + char *kstr, int klen, + pem_password_cb *cb, void *u) +{ + BIO *bp; + int ret; + if(!(bp = BIO_new_fp(fp, BIO_NOCLOSE))) { + OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB); + return(0); + } + ret = do_pk8pkey(bp, x, isder, nid, enc, kstr, klen, cb, u); + BIO_free(bp); + return ret; +} + +EVP_PKEY *d2i_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY **x, pem_password_cb *cb, void *u) +{ + BIO *bp; + EVP_PKEY *ret; + if(!(bp = BIO_new_fp(fp, BIO_NOCLOSE))) { + OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB); + return NULL; + } + ret = d2i_PKCS8PrivateKey_bio(bp, x, cb, u); + BIO_free(bp); + return ret; +} + +#endif + +IMPLEMENT_PEM_rw(PKCS8, X509_SIG, PEM_STRING_PKCS8, X509_SIG) +IMPLEMENT_PEM_rw(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO, PEM_STRING_PKCS8INF, + PKCS8_PRIV_KEY_INFO) diff --git a/TMessagesProj/jni/boringssl/crypto/pem/pem_pkey.c b/TMessagesProj/jni/boringssl/crypto/pem/pem_pkey.c new file mode 100644 index 00000000..c4627275 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/pem/pem_pkey.c @@ -0,0 +1,312 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../evp/internal.h" + + +int pem_check_suffix(const char *pem_str, const char *suffix); + +EVP_PKEY *PEM_read_bio_PrivateKey(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, void *u) + { + char *nm=NULL; + const unsigned char *p=NULL; + unsigned char *data=NULL; + long len; + int slen; + EVP_PKEY *ret=NULL; + + if (!PEM_bytes_read_bio(&data, &len, &nm, PEM_STRING_EVP_PKEY, bp, cb, u)) + return NULL; + p = data; + + if (strcmp(nm,PEM_STRING_PKCS8INF) == 0) { + PKCS8_PRIV_KEY_INFO *p8inf; + p8inf=d2i_PKCS8_PRIV_KEY_INFO(NULL, &p, len); + if(!p8inf) goto p8err; + ret = EVP_PKCS82PKEY(p8inf); + if(x) { + if(*x) EVP_PKEY_free((EVP_PKEY *)*x); + *x = ret; + } + PKCS8_PRIV_KEY_INFO_free(p8inf); + } else if (strcmp(nm,PEM_STRING_PKCS8) == 0) { + PKCS8_PRIV_KEY_INFO *p8inf; + X509_SIG *p8; + int klen; + char psbuf[PEM_BUFSIZE]; + p8 = d2i_X509_SIG(NULL, &p, len); + if(!p8) goto p8err; + + klen = 0; + if (!cb) cb = PEM_def_callback; + klen=cb(psbuf,PEM_BUFSIZE,0,u); + if (klen <= 0) { + OPENSSL_PUT_ERROR(PEM, PEM_R_BAD_PASSWORD_READ); + X509_SIG_free(p8); + goto err; + } + p8inf = PKCS8_decrypt(p8, psbuf, klen); + X509_SIG_free(p8); + if(!p8inf) goto p8err; + ret = EVP_PKCS82PKEY(p8inf); + if(x) { + if(*x) EVP_PKEY_free((EVP_PKEY *)*x); + *x = ret; + } + PKCS8_PRIV_KEY_INFO_free(p8inf); + } else if ((slen = pem_check_suffix(nm, "PRIVATE KEY")) > 0) + { + const EVP_PKEY_ASN1_METHOD *ameth; + ameth = EVP_PKEY_asn1_find_str(NULL, nm, slen); + if (!ameth || !ameth->old_priv_decode) + goto p8err; + ret=d2i_PrivateKey(ameth->pkey_id,x,&p,len); + } +p8err: + if (ret == NULL) + OPENSSL_PUT_ERROR(PEM, ERR_R_ASN1_LIB); + +err: + OPENSSL_free(nm); + OPENSSL_cleanse(data, len); + OPENSSL_free(data); + return(ret); + } + +int PEM_write_bio_PrivateKey(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc, + unsigned char *kstr, int klen, + pem_password_cb *cb, void *u) + { + char pem_str[80]; + if (!x->ameth || x->ameth->priv_encode) + return PEM_write_bio_PKCS8PrivateKey(bp, x, enc, + (char *)kstr, klen, + cb, u); + + BIO_snprintf(pem_str, 80, "%s PRIVATE KEY", x->ameth->pem_str); + return PEM_ASN1_write_bio((i2d_of_void *)i2d_PrivateKey, + pem_str,bp,x,enc,kstr,klen,cb,u); + } + +static int public_key_type_from_str(const char *name, size_t len) { + if (len == 3 && memcmp(name, "RSA", 3) == 0) { + return EVP_PKEY_RSA; + } else if (len == 2 && memcmp(name, "DH", 2) == 0) { + return EVP_PKEY_DH; + } else if (len == 2 && memcmp(name, "EC", 2) == 0) { + return EVP_PKEY_EC; + } + return NID_undef; +} + +static int set_pkey_type_from_str(EVP_PKEY *pkey, const char *name, size_t len) { + int nid = public_key_type_from_str(name, len); + if (nid == NID_undef) { + return 0; + } + return EVP_PKEY_set_type(pkey, nid); +} + +EVP_PKEY *PEM_read_bio_Parameters(BIO *bp, EVP_PKEY **x) + { + char *nm=NULL; + const unsigned char *p=NULL; + unsigned char *data=NULL; + long len; + int slen; + EVP_PKEY *ret=NULL; + + if (!PEM_bytes_read_bio(&data, &len, &nm, PEM_STRING_PARAMETERS, + bp, 0, NULL)) + return NULL; + p = data; + + if ((slen = pem_check_suffix(nm, "PARAMETERS")) > 0) + { + ret = EVP_PKEY_new(); + if (!ret) + goto err; + if (!set_pkey_type_from_str(ret, nm, slen) + || !ret->ameth->param_decode + || !ret->ameth->param_decode(ret, &p, len)) + { + EVP_PKEY_free(ret); + ret = NULL; + goto err; + } + if(x) + { + if(*x) EVP_PKEY_free((EVP_PKEY *)*x); + *x = ret; + } + } +err: + if (ret == NULL) + OPENSSL_PUT_ERROR(PEM, ERR_R_ASN1_LIB); + OPENSSL_free(nm); + OPENSSL_free(data); + return(ret); + } + +int PEM_write_bio_Parameters(BIO *bp, EVP_PKEY *x) + { + char pem_str[80]; + if (!x->ameth || !x->ameth->param_encode) + return 0; + + BIO_snprintf(pem_str, 80, "%s PARAMETERS", x->ameth->pem_str); + return PEM_ASN1_write_bio( + (i2d_of_void *)x->ameth->param_encode, + pem_str,bp,x,NULL,NULL,0,0,NULL); + } + +#ifndef OPENSSL_NO_FP_API +EVP_PKEY *PEM_read_PrivateKey(FILE *fp, EVP_PKEY **x, pem_password_cb *cb, void *u) + { + BIO *b; + EVP_PKEY *ret; + + if ((b=BIO_new(BIO_s_file())) == NULL) + { + OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB); + return(0); + } + BIO_set_fp(b,fp,BIO_NOCLOSE); + ret=PEM_read_bio_PrivateKey(b,x,cb,u); + BIO_free(b); + return(ret); + } + +int PEM_write_PrivateKey(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc, + unsigned char *kstr, int klen, + pem_password_cb *cb, void *u) + { + BIO *b; + int ret; + + if ((b=BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) + { + OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB); + return 0; + } + ret=PEM_write_bio_PrivateKey(b, x, enc, kstr, klen, cb, u); + BIO_free(b); + return ret; + } + +#endif + + +/* Transparently read in PKCS#3 or X9.42 DH parameters */ + +DH *PEM_read_bio_DHparams(BIO *bp, DH **x, pem_password_cb *cb, void *u) + { + char *nm=NULL; + const unsigned char *p=NULL; + unsigned char *data=NULL; + long len; + DH *ret=NULL; + + if (!PEM_bytes_read_bio(&data, &len, &nm, PEM_STRING_DHPARAMS, + bp, cb, u)) + return NULL; + p = data; + + /* TODO(fork): remove? */ + /*if (!strcmp(nm, PEM_STRING_DHXPARAMS)) + ret = d2i_DHxparams(x, &p, len); + else */ + ret = d2i_DHparams(x, &p, len); + + if (ret == NULL) + OPENSSL_PUT_ERROR(PEM, ERR_R_ASN1_LIB); + OPENSSL_free(nm); + OPENSSL_free(data); + return ret; + } + +#ifndef OPENSSL_NO_FP_API +DH *PEM_read_DHparams(FILE *fp, DH **x, pem_password_cb *cb, void *u) + { + BIO *b; + DH *ret; + + if ((b=BIO_new(BIO_s_file())) == NULL) + { + OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB); + return(0); + } + BIO_set_fp(b,fp,BIO_NOCLOSE); + ret=PEM_read_bio_DHparams(b,x,cb,u); + BIO_free(b); + return(ret); + } +#endif diff --git a/TMessagesProj/jni/boringssl/crypto/pem/pem_x509.c b/TMessagesProj/jni/boringssl/crypto/pem/pem_x509.c new file mode 100644 index 00000000..f4630472 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/pem/pem_x509.c @@ -0,0 +1,65 @@ +/* pem_x509.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2001. + */ +/* ==================================================================== + * Copyright (c) 2001 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include +#include + + +IMPLEMENT_PEM_rw(X509, X509, PEM_STRING_X509, X509) diff --git a/TMessagesProj/jni/boringssl/crypto/pem/pem_xaux.c b/TMessagesProj/jni/boringssl/crypto/pem/pem_xaux.c new file mode 100644 index 00000000..8dabd41e --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/pem/pem_xaux.c @@ -0,0 +1,66 @@ +/* pem_xaux.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2001. + */ +/* ==================================================================== + * Copyright (c) 2001 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include +#include + + +IMPLEMENT_PEM_rw(X509_AUX, X509, PEM_STRING_X509_TRUSTED, X509_AUX) +IMPLEMENT_PEM_rw(X509_CERT_PAIR, X509_CERT_PAIR, PEM_STRING_X509_PAIR, X509_CERT_PAIR) diff --git a/TMessagesProj/jni/boringssl/crypto/perlasm/arm-xlate.pl b/TMessagesProj/jni/boringssl/crypto/perlasm/arm-xlate.pl new file mode 100644 index 00000000..706fa708 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/perlasm/arm-xlate.pl @@ -0,0 +1,170 @@ +#!/usr/bin/env perl + +# ARM assembler distiller by . + +my $flavour = shift; +my $output = shift; +open STDOUT,">$output" || die "can't open $output: $!"; + +$flavour = "linux32" if (!$flavour or $flavour eq "void"); + +my %GLOBALS; +my $dotinlocallabels=($flavour=~/linux/)?1:0; + +################################################################ +# directives which need special treatment on different platforms +################################################################ +my $arch = sub { + if ($flavour =~ /linux/) { ".arch\t".join(',',@_); } + else { ""; } +}; +my $fpu = sub { + if ($flavour =~ /linux/) { ".fpu\t".join(',',@_); } + else { ""; } +}; +my $hidden = sub { + if ($flavour =~ /ios/) { ".private_extern\t".join(',',@_); } + else { ".hidden\t".join(',',@_); } +}; +my $comm = sub { + my @args = split(/,\s*/,shift); + my $name = @args[0]; + my $global = \$GLOBALS{$name}; + my $ret; + + if ($flavour =~ /ios32/) { + $ret = ".comm\t_$name,@args[1]\n"; + $ret .= ".non_lazy_symbol_pointer\n"; + $ret .= "$name:\n"; + $ret .= ".indirect_symbol\t_$name\n"; + $ret .= ".long\t0"; + $name = "_$name"; + } else { $ret = ".comm\t".join(',',@args); } + + $$global = $name; + $ret; +}; +my $globl = sub { + my $name = shift; + my $global = \$GLOBALS{$name}; + my $ret; + + SWITCH: for ($flavour) { + /ios/ && do { $name = "_$name"; + last; + }; + } + + $ret = ".globl $name" if (!$ret); + $$global = $name; + $ret; +}; +my $global = $globl; +my $extern = sub { + &$globl(@_); + return; # return nothing +}; +my $type = sub { + if ($flavour =~ /linux/) { ".type\t".join(',',@_); } + else { ""; } +}; +my $size = sub { + if ($flavour =~ /linux/) { ".size\t".join(',',@_); } + else { ""; } +}; +my $inst = sub { + if ($flavour =~ /linux/) { ".inst\t".join(',',@_); } + else { ".long\t".join(',',@_); } +}; +my $asciz = sub { + my $line = join(",",@_); + if ($line =~ /^"(.*)"$/) + { ".byte " . join(",",unpack("C*",$1),0) . "\n.align 2"; } + else + { ""; } +}; + +sub range { + my ($r,$sfx,$start,$end) = @_; + + join(",",map("$r$_$sfx",($start..$end))); +} + +sub expand_line { + my $line = shift; + my @ret = (); + + pos($line)=0; + + while ($line =~ m/\G[^@\/\{\"]*/g) { + if ($line =~ m/\G(@|\/\/|$)/gc) { + last; + } + elsif ($line =~ m/\G\{/gc) { + my $saved_pos = pos($line); + $line =~ s/\G([rdqv])([0-9]+)([^\-]*)\-\1([0-9]+)\3/range($1,$3,$2,$4)/e; + pos($line) = $saved_pos; + $line =~ m/\G[^\}]*\}/g; + } + elsif ($line =~ m/\G\"/gc) { + $line =~ m/\G[^\"]*\"/g; + } + } + + $line =~ s/\b(\w+)/$GLOBALS{$1} or $1/ge; + + return $line; +} + +print "#if defined(__arm__)\n" if ($flavour eq "linux32"); +print "#if defined(__aarch64__)\n" if ($flavour eq "linux64"); + +while($line=<>) { + + if ($line =~ m/^\s*(#|@|\/\/)/) { print $line; next; } + + $line =~ s|/\*.*\*/||; # get rid of C-style comments... + $line =~ s|^\s+||; # ... and skip white spaces in beginning... + $line =~ s|\s+$||; # ... and at the end + + { + $line =~ s|[\b\.]L(\w{2,})|L$1|g; # common denominator for Locallabel + $line =~ s|\bL(\w{2,})|\.L$1|g if ($dotinlocallabels); + } + + { + $line =~ s|(^[\.\w]+)\:\s*||; + my $label = $1; + if ($label) { + printf "%s:",($GLOBALS{$label} or $label); + } + } + + if ($line !~ m/^[#@]/) { + $line =~ s|^\s*(\.?)(\S+)\s*||; + my $c = $1; $c = "\t" if ($c eq ""); + my $mnemonic = $2; + my $opcode; + if ($mnemonic =~ m/([^\.]+)\.([^\.]+)/) { + $opcode = eval("\$$1_$2"); + } else { + $opcode = eval("\$$mnemonic"); + } + + my $arg=expand_line($line); + + if (ref($opcode) eq 'CODE') { + $line = &$opcode($arg); + } elsif ($mnemonic) { + $line = $c.$mnemonic; + $line.= "\t$arg" if ($arg ne ""); + } + } + + print $line if ($line); + print "\n"; +} + +print "#endif" if ($flavour eq "linux32" || $flavour eq "linux64"); + +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/perlasm/cbc.pl b/TMessagesProj/jni/boringssl/crypto/perlasm/cbc.pl new file mode 100644 index 00000000..24561e75 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/perlasm/cbc.pl @@ -0,0 +1,349 @@ +#!/usr/local/bin/perl + +# void des_ncbc_encrypt(input, output, length, schedule, ivec, enc) +# des_cblock (*input); +# des_cblock (*output); +# long length; +# des_key_schedule schedule; +# des_cblock (*ivec); +# int enc; +# +# calls +# des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT); +# + +#&cbc("des_ncbc_encrypt","des_encrypt",0); +#&cbc("BF_cbc_encrypt","BF_encrypt","BF_encrypt", +# 1,4,5,3,5,-1); +#&cbc("des_ncbc_encrypt","des_encrypt","des_encrypt", +# 0,4,5,3,5,-1); +#&cbc("des_ede3_cbc_encrypt","des_encrypt3","des_decrypt3", +# 0,6,7,3,4,5); +# +# When doing a cipher that needs bigendian order, +# for encrypt, the iv is kept in bigendian form, +# while for decrypt, it is kept in little endian. +sub cbc + { + local($name,$enc_func,$dec_func,$swap,$iv_off,$enc_off,$p1,$p2,$p3)=@_; + # name is the function name + # enc_func and dec_func and the functions to call for encrypt/decrypt + # swap is true if byte order needs to be reversed + # iv_off is parameter number for the iv + # enc_off is parameter number for the encrypt/decrypt flag + # p1,p2,p3 are the offsets for parameters to be passed to the + # underlying calls. + + &function_begin_B($name,""); + &comment(""); + + $in="esi"; + $out="edi"; + $count="ebp"; + + &push("ebp"); + &push("ebx"); + &push("esi"); + &push("edi"); + + $data_off=4; + $data_off+=4 if ($p1 > 0); + $data_off+=4 if ($p2 > 0); + $data_off+=4 if ($p3 > 0); + + &mov($count, &wparam(2)); # length + + &comment("getting iv ptr from parameter $iv_off"); + &mov("ebx", &wparam($iv_off)); # Get iv ptr + + &mov($in, &DWP(0,"ebx","",0));# iv[0] + &mov($out, &DWP(4,"ebx","",0));# iv[1] + + &push($out); + &push($in); + &push($out); # used in decrypt for iv[1] + &push($in); # used in decrypt for iv[0] + + &mov("ebx", "esp"); # This is the address of tin[2] + + &mov($in, &wparam(0)); # in + &mov($out, &wparam(1)); # out + + # We have loaded them all, how lets push things + &comment("getting encrypt flag from parameter $enc_off"); + &mov("ecx", &wparam($enc_off)); # Get enc flag + if ($p3 > 0) + { + &comment("get and push parameter $p3"); + if ($enc_off != $p3) + { &mov("eax", &wparam($p3)); &push("eax"); } + else { &push("ecx"); } + } + if ($p2 > 0) + { + &comment("get and push parameter $p2"); + if ($enc_off != $p2) + { &mov("eax", &wparam($p2)); &push("eax"); } + else { &push("ecx"); } + } + if ($p1 > 0) + { + &comment("get and push parameter $p1"); + if ($enc_off != $p1) + { &mov("eax", &wparam($p1)); &push("eax"); } + else { &push("ecx"); } + } + &push("ebx"); # push data/iv + + &cmp("ecx",0); + &jz(&label("decrypt")); + + &and($count,0xfffffff8); + &mov("eax", &DWP($data_off,"esp","",0)); # load iv[0] + &mov("ebx", &DWP($data_off+4,"esp","",0)); # load iv[1] + + &jz(&label("encrypt_finish")); + + ############################################################# + + &set_label("encrypt_loop"); + # encrypt start + # "eax" and "ebx" hold iv (or the last cipher text) + + &mov("ecx", &DWP(0,$in,"",0)); # load first 4 bytes + &mov("edx", &DWP(4,$in,"",0)); # second 4 bytes + + &xor("eax", "ecx"); + &xor("ebx", "edx"); + + &bswap("eax") if $swap; + &bswap("ebx") if $swap; + + &mov(&DWP($data_off,"esp","",0), "eax"); # put in array for call + &mov(&DWP($data_off+4,"esp","",0), "ebx"); # + + &call($enc_func); + + &mov("eax", &DWP($data_off,"esp","",0)); + &mov("ebx", &DWP($data_off+4,"esp","",0)); + + &bswap("eax") if $swap; + &bswap("ebx") if $swap; + + &mov(&DWP(0,$out,"",0),"eax"); + &mov(&DWP(4,$out,"",0),"ebx"); + + # eax and ebx are the next iv. + + &add($in, 8); + &add($out, 8); + + &sub($count, 8); + &jnz(&label("encrypt_loop")); + +###################################################################3 + &set_label("encrypt_finish"); + &mov($count, &wparam(2)); # length + &and($count, 7); + &jz(&label("finish")); + &call(&label("PIC_point")); +&set_label("PIC_point"); + &blindpop("edx"); + &lea("ecx",&DWP(&label("cbc_enc_jmp_table")."-".&label("PIC_point"),"edx")); + &mov($count,&DWP(0,"ecx",$count,4)); + &add($count,"edx"); + &xor("ecx","ecx"); + &xor("edx","edx"); + #&mov($count,&DWP(&label("cbc_enc_jmp_table"),"",$count,4)); + &jmp_ptr($count); + +&set_label("ej7"); + &movb(&HB("edx"), &BP(6,$in,"",0)); + &shl("edx",8); +&set_label("ej6"); + &movb(&HB("edx"), &BP(5,$in,"",0)); +&set_label("ej5"); + &movb(&LB("edx"), &BP(4,$in,"",0)); +&set_label("ej4"); + &mov("ecx", &DWP(0,$in,"",0)); + &jmp(&label("ejend")); +&set_label("ej3"); + &movb(&HB("ecx"), &BP(2,$in,"",0)); + &shl("ecx",8); +&set_label("ej2"); + &movb(&HB("ecx"), &BP(1,$in,"",0)); +&set_label("ej1"); + &movb(&LB("ecx"), &BP(0,$in,"",0)); +&set_label("ejend"); + + &xor("eax", "ecx"); + &xor("ebx", "edx"); + + &bswap("eax") if $swap; + &bswap("ebx") if $swap; + + &mov(&DWP($data_off,"esp","",0), "eax"); # put in array for call + &mov(&DWP($data_off+4,"esp","",0), "ebx"); # + + &call($enc_func); + + &mov("eax", &DWP($data_off,"esp","",0)); + &mov("ebx", &DWP($data_off+4,"esp","",0)); + + &bswap("eax") if $swap; + &bswap("ebx") if $swap; + + &mov(&DWP(0,$out,"",0),"eax"); + &mov(&DWP(4,$out,"",0),"ebx"); + + &jmp(&label("finish")); + + ############################################################# + ############################################################# + &set_label("decrypt",1); + # decrypt start + &and($count,0xfffffff8); + # The next 2 instructions are only for if the jz is taken + &mov("eax", &DWP($data_off+8,"esp","",0)); # get iv[0] + &mov("ebx", &DWP($data_off+12,"esp","",0)); # get iv[1] + &jz(&label("decrypt_finish")); + + &set_label("decrypt_loop"); + &mov("eax", &DWP(0,$in,"",0)); # load first 4 bytes + &mov("ebx", &DWP(4,$in,"",0)); # second 4 bytes + + &bswap("eax") if $swap; + &bswap("ebx") if $swap; + + &mov(&DWP($data_off,"esp","",0), "eax"); # put back + &mov(&DWP($data_off+4,"esp","",0), "ebx"); # + + &call($dec_func); + + &mov("eax", &DWP($data_off,"esp","",0)); # get return + &mov("ebx", &DWP($data_off+4,"esp","",0)); # + + &bswap("eax") if $swap; + &bswap("ebx") if $swap; + + &mov("ecx", &DWP($data_off+8,"esp","",0)); # get iv[0] + &mov("edx", &DWP($data_off+12,"esp","",0)); # get iv[1] + + &xor("ecx", "eax"); + &xor("edx", "ebx"); + + &mov("eax", &DWP(0,$in,"",0)); # get old cipher text, + &mov("ebx", &DWP(4,$in,"",0)); # next iv actually + + &mov(&DWP(0,$out,"",0),"ecx"); + &mov(&DWP(4,$out,"",0),"edx"); + + &mov(&DWP($data_off+8,"esp","",0), "eax"); # save iv + &mov(&DWP($data_off+12,"esp","",0), "ebx"); # + + &add($in, 8); + &add($out, 8); + + &sub($count, 8); + &jnz(&label("decrypt_loop")); +############################ ENDIT #######################3 + &set_label("decrypt_finish"); + &mov($count, &wparam(2)); # length + &and($count, 7); + &jz(&label("finish")); + + &mov("eax", &DWP(0,$in,"",0)); # load first 4 bytes + &mov("ebx", &DWP(4,$in,"",0)); # second 4 bytes + + &bswap("eax") if $swap; + &bswap("ebx") if $swap; + + &mov(&DWP($data_off,"esp","",0), "eax"); # put back + &mov(&DWP($data_off+4,"esp","",0), "ebx"); # + + &call($dec_func); + + &mov("eax", &DWP($data_off,"esp","",0)); # get return + &mov("ebx", &DWP($data_off+4,"esp","",0)); # + + &bswap("eax") if $swap; + &bswap("ebx") if $swap; + + &mov("ecx", &DWP($data_off+8,"esp","",0)); # get iv[0] + &mov("edx", &DWP($data_off+12,"esp","",0)); # get iv[1] + + &xor("ecx", "eax"); + &xor("edx", "ebx"); + + # this is for when we exit + &mov("eax", &DWP(0,$in,"",0)); # get old cipher text, + &mov("ebx", &DWP(4,$in,"",0)); # next iv actually + +&set_label("dj7"); + &rotr("edx", 16); + &movb(&BP(6,$out,"",0), &LB("edx")); + &shr("edx",16); +&set_label("dj6"); + &movb(&BP(5,$out,"",0), &HB("edx")); +&set_label("dj5"); + &movb(&BP(4,$out,"",0), &LB("edx")); +&set_label("dj4"); + &mov(&DWP(0,$out,"",0), "ecx"); + &jmp(&label("djend")); +&set_label("dj3"); + &rotr("ecx", 16); + &movb(&BP(2,$out,"",0), &LB("ecx")); + &shl("ecx",16); +&set_label("dj2"); + &movb(&BP(1,$in,"",0), &HB("ecx")); +&set_label("dj1"); + &movb(&BP(0,$in,"",0), &LB("ecx")); +&set_label("djend"); + + # final iv is still in eax:ebx + &jmp(&label("finish")); + + +############################ FINISH #######################3 + &set_label("finish",1); + &mov("ecx", &wparam($iv_off)); # Get iv ptr + + ################################################# + $total=16+4; + $total+=4 if ($p1 > 0); + $total+=4 if ($p2 > 0); + $total+=4 if ($p3 > 0); + &add("esp",$total); + + &mov(&DWP(0,"ecx","",0), "eax"); # save iv + &mov(&DWP(4,"ecx","",0), "ebx"); # save iv + + &function_end_A($name); + + &align(64); + &set_label("cbc_enc_jmp_table"); + &data_word("0"); + &data_word(&label("ej1")."-".&label("PIC_point")); + &data_word(&label("ej2")."-".&label("PIC_point")); + &data_word(&label("ej3")."-".&label("PIC_point")); + &data_word(&label("ej4")."-".&label("PIC_point")); + &data_word(&label("ej5")."-".&label("PIC_point")); + &data_word(&label("ej6")."-".&label("PIC_point")); + &data_word(&label("ej7")."-".&label("PIC_point")); + # not used + #&set_label("cbc_dec_jmp_table",1); + #&data_word("0"); + #&data_word(&label("dj1")."-".&label("PIC_point")); + #&data_word(&label("dj2")."-".&label("PIC_point")); + #&data_word(&label("dj3")."-".&label("PIC_point")); + #&data_word(&label("dj4")."-".&label("PIC_point")); + #&data_word(&label("dj5")."-".&label("PIC_point")); + #&data_word(&label("dj6")."-".&label("PIC_point")); + #&data_word(&label("dj7")."-".&label("PIC_point")); + &align(64); + + &function_end_B($name); + + } + +1; diff --git a/TMessagesProj/jni/boringssl/crypto/perlasm/readme b/TMessagesProj/jni/boringssl/crypto/perlasm/readme new file mode 100644 index 00000000..f02bbee7 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/perlasm/readme @@ -0,0 +1,124 @@ +The perl scripts in this directory are my 'hack' to generate +multiple different assembler formats via the one origional script. + +The way to use this library is to start with adding the path to this directory +and then include it. + +push(@INC,"perlasm","../../perlasm"); +require "x86asm.pl"; + +The first thing we do is setup the file and type of assember + +&asm_init($ARGV[0],$0); + +The first argument is the 'type'. Currently +'cpp', 'sol', 'a.out', 'elf' or 'win32'. +Argument 2 is the file name. + +The reciprocal function is +&asm_finish() which should be called at the end. + +There are 2 main 'packages'. x86ms.pl, which is the microsoft assembler, +and x86unix.pl which is the unix (gas) version. + +Functions of interest are: +&external_label("des_SPtrans"); declare and external variable +&LB(reg); Low byte for a register +&HB(reg); High byte for a register +&BP(off,base,index,scale) Byte pointer addressing +&DWP(off,base,index,scale) Word pointer addressing +&stack_push(num) Basically a 'sub esp, num*4' with extra +&stack_pop(num) inverse of stack_push +&function_begin(name,extra) Start a function with pushing of + edi, esi, ebx and ebp. extra is extra win32 + external info that may be required. +&function_begin_B(name,extra) Same as norma function_begin but no pushing. +&function_end(name) Call at end of function. +&function_end_A(name) Standard pop and ret, for use inside functions +&function_end_B(name) Call at end but with poping or 'ret'. +&swtmp(num) Address on stack temp word. +&wparam(num) Parameter number num, that was push + in C convention. This all works over pushes + and pops. +&comment("hello there") Put in a comment. +&label("loop") Refer to a label, normally a jmp target. +&set_label("loop") Set a label at this point. +&data_word(word) Put in a word of data. + +So how does this all hold together? Given + +int calc(int len, int *data) + { + int i,j=0; + + for (i=0; i. +# +# Why AT&T to MASM and not vice versa? Several reasons. Because AT&T +# format is way easier to parse. Because it's simpler to "gear" from +# Unix ABI to Windows one [see cross-reference "card" at the end of +# file]. Because Linux targets were available first... +# +# In addition the script also "distills" code suitable for GNU +# assembler, so that it can be compiled with more rigid assemblers, +# such as Solaris /usr/ccs/bin/as. +# +# This translator is not designed to convert *arbitrary* assembler +# code from AT&T format to MASM one. It's designed to convert just +# enough to provide for dual-ABI OpenSSL modules development... +# There *are* limitations and you might have to modify your assembler +# code or this script to achieve the desired result... +# +# Currently recognized limitations: +# +# - can't use multiple ops per line; +# +# Dual-ABI styling rules. +# +# 1. Adhere to Unix register and stack layout [see cross-reference +# ABI "card" at the end for explanation]. +# 2. Forget about "red zone," stick to more traditional blended +# stack frame allocation. If volatile storage is actually required +# that is. If not, just leave the stack as is. +# 3. Functions tagged with ".type name,@function" get crafted with +# unified Win64 prologue and epilogue automatically. If you want +# to take care of ABI differences yourself, tag functions as +# ".type name,@abi-omnipotent" instead. +# 4. To optimize the Win64 prologue you can specify number of input +# arguments as ".type name,@function,N." Keep in mind that if N is +# larger than 6, then you *have to* write "abi-omnipotent" code, +# because >6 cases can't be addressed with unified prologue. +# 5. Name local labels as .L*, do *not* use dynamic labels such as 1: +# (sorry about latter). +# 6. Don't use [or hand-code with .byte] "rep ret." "ret" mnemonic is +# required to identify the spots, where to inject Win64 epilogue! +# But on the pros, it's then prefixed with rep automatically:-) +# 7. Stick to explicit ip-relative addressing. If you have to use +# GOTPCREL addressing, stick to mov symbol@GOTPCREL(%rip),%r??. +# Both are recognized and translated to proper Win64 addressing +# modes. To support legacy code a synthetic directive, .picmeup, +# is implemented. It puts address of the *next* instruction into +# target register, e.g.: +# +# .picmeup %rax +# lea .Label-.(%rax),%rax +# +# 8. In order to provide for structured exception handling unified +# Win64 prologue copies %rsp value to %rax. For further details +# see SEH paragraph at the end. +# 9. .init segment is allowed to contain calls to functions only. +# a. If function accepts more than 4 arguments *and* >4th argument +# is declared as non 64-bit value, do clear its upper part. + +my $flavour = shift; +my $output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +open STDOUT,">$output" || die "can't open $output: $!" + if (defined($output)); + +my $gas=1; $gas=0 if ($output =~ /\.asm$/); +my $elf=1; $elf=0 if (!$gas); +my $win64=0; +my $prefix=""; +my $decor=".L"; + +my $masmref=8 + 50727*2**-32; # 8.00.50727 shipped with VS2005 +my $masm=0; +my $PTR=" PTR"; + +my $nasmref=2.03; +my $nasm=0; + +if ($flavour eq "mingw64") { $gas=1; $elf=0; $win64=1; + $prefix=`echo __USER_LABEL_PREFIX__ | $ENV{CC} -E -P -`; + chomp($prefix); + } +elsif ($flavour eq "macosx") { $gas=1; $elf=0; $prefix="_"; $decor="L\$"; } +elsif ($flavour eq "masm") { $gas=0; $elf=0; $masm=$masmref; $win64=1; $decor="\$L\$"; } +elsif ($flavour eq "nasm") { $gas=0; $elf=0; $nasm=$nasmref; $win64=1; $decor="\$L\$"; $PTR=""; } +elsif (!$gas) +{ if ($ENV{ASM} =~ m/nasm/ && `nasm -v` =~ m/version ([0-9]+)\.([0-9]+)/i) + { $nasm = $1 + $2*0.01; $PTR=""; } + elsif (`ml64 2>&1` =~ m/Version ([0-9]+)\.([0-9]+)(\.([0-9]+))?/) + { $masm = $1 + $2*2**-16 + $4*2**-32; } + die "no assembler found on %PATH" if (!($nasm || $masm)); + $win64=1; + $elf=0; + $decor="\$L\$"; +} + +my $current_segment; +my $current_function; +my %globals; + +{ package opcode; # pick up opcodes + sub re { + my $self = shift; # single instance in enough... + local *line = shift; + undef $ret; + + if ($line =~ /^([a-z][a-z0-9]*)/i) { + $self->{op} = $1; + $ret = $self; + $line = substr($line,@+[0]); $line =~ s/^\s+//; + + undef $self->{sz}; + if ($self->{op} =~ /^(movz)x?([bw]).*/) { # movz is pain... + $self->{op} = $1; + $self->{sz} = $2; + } elsif ($self->{op} =~ /call|jmp/) { + $self->{sz} = ""; + } elsif ($self->{op} =~ /^p/ && $' !~ /^(ush|op|insrw)/) { # SSEn + $self->{sz} = ""; + } elsif ($self->{op} =~ /^v/) { # VEX + $self->{sz} = ""; + } elsif ($self->{op} =~ /mov[dq]/ && $line =~ /%xmm/) { + $self->{sz} = ""; + } elsif ($self->{op} =~ /([a-z]{3,})([qlwb])$/) { + $self->{op} = $1; + $self->{sz} = $2; + } + } + $ret; + } + sub size { + my $self = shift; + my $sz = shift; + $self->{sz} = $sz if (defined($sz) && !defined($self->{sz})); + $self->{sz}; + } + sub out { + my $self = shift; + if ($gas) { + if ($self->{op} eq "movz") { # movz is pain... + sprintf "%s%s%s",$self->{op},$self->{sz},shift; + } elsif ($self->{op} =~ /^set/) { + "$self->{op}"; + } elsif ($self->{op} eq "ret") { + my $epilogue = ""; + if ($win64 && $current_function->{abi} eq "svr4") { + $epilogue = "movq 8(%rsp),%rdi\n\t" . + "movq 16(%rsp),%rsi\n\t"; + } + $epilogue . ".byte 0xf3,0xc3"; + } elsif ($self->{op} eq "call" && !$elf && $current_segment eq ".init") { + ".p2align\t3\n\t.quad"; + } else { + "$self->{op}$self->{sz}"; + } + } else { + $self->{op} =~ s/^movz/movzx/; + if ($self->{op} eq "ret") { + $self->{op} = ""; + if ($win64 && $current_function->{abi} eq "svr4") { + $self->{op} = "mov rdi,QWORD${PTR}[8+rsp]\t;WIN64 epilogue\n\t". + "mov rsi,QWORD${PTR}[16+rsp]\n\t"; + } + $self->{op} .= "DB\t0F3h,0C3h\t\t;repret"; + } elsif ($self->{op} =~ /^(pop|push)f/) { + $self->{op} .= $self->{sz}; + } elsif ($self->{op} eq "call" && $current_segment eq ".CRT\$XCU") { + $self->{op} = "\tDQ"; + } + $self->{op}; + } + } + sub mnemonic { + my $self=shift; + my $op=shift; + $self->{op}=$op if (defined($op)); + $self->{op}; + } +} +{ package const; # pick up constants, which start with $ + sub re { + my $self = shift; # single instance in enough... + local *line = shift; + undef $ret; + + if ($line =~ /^\$([^,]+)/) { + $self->{value} = $1; + $ret = $self; + $line = substr($line,@+[0]); $line =~ s/^\s+//; + } + $ret; + } + sub out { + my $self = shift; + + if ($gas) { + # Solaris /usr/ccs/bin/as can't handle multiplications + # in $self->{value} + $self->{value} =~ s/(?{value} =~ s/([0-9]+\s*[\*\/\%]\s*[0-9]+)/eval($1)/eg; + sprintf "\$%s",$self->{value}; + } else { + $self->{value} =~ s/(0b[0-1]+)/oct($1)/eig; + $self->{value} =~ s/0x([0-9a-f]+)/0$1h/ig if ($masm); + sprintf "%s",$self->{value}; + } + } +} +{ package ea; # pick up effective addresses: expr(%reg,%reg,scale) + sub re { + my $self = shift; # single instance in enough... + local *line = shift; + undef $ret; + + # optional * ---vvv--- appears in indirect jmp/call + if ($line =~ /^(\*?)([^\(,]*)\(([%\w,]+)\)/) { + $self->{asterisk} = $1; + $self->{label} = $2; + ($self->{base},$self->{index},$self->{scale})=split(/,/,$3); + $self->{scale} = 1 if (!defined($self->{scale})); + $ret = $self; + $line = substr($line,@+[0]); $line =~ s/^\s+//; + + if ($win64 && $self->{label} =~ s/\@GOTPCREL//) { + die if (opcode->mnemonic() ne "mov"); + opcode->mnemonic("lea"); + } + $self->{base} =~ s/^%//; + $self->{index} =~ s/^%// if (defined($self->{index})); + } + $ret; + } + sub size {} + sub out { + my $self = shift; + my $sz = shift; + + $self->{label} =~ s/([_a-z][_a-z0-9]*)/$globals{$1} or $1/gei; + $self->{label} =~ s/\.L/$decor/g; + + # Silently convert all EAs to 64-bit. This is required for + # elder GNU assembler and results in more compact code, + # *but* most importantly AES module depends on this feature! + $self->{index} =~ s/^[er](.?[0-9xpi])[d]?$/r\1/; + $self->{base} =~ s/^[er](.?[0-9xpi])[d]?$/r\1/; + + # Solaris /usr/ccs/bin/as can't handle multiplications + # in $self->{label}, new gas requires sign extension... + use integer; + $self->{label} =~ s/(?{label} =~ s/\b([0-9]+\s*[\*\/\%]\s*[0-9]+)\b/eval($1)/eg; + $self->{label} =~ s/\b([0-9]+)\b/$1<<32>>32/eg; + + if (!$self->{label} && $self->{index} && $self->{scale}==1 && + $self->{base} =~ /(rbp|r13)/) { + $self->{base} = $self->{index}; $self->{index} = $1; + } + + if ($gas) { + $self->{label} =~ s/^___imp_/__imp__/ if ($flavour eq "mingw64"); + + if (defined($self->{index})) { + sprintf "%s%s(%s,%%%s,%d)",$self->{asterisk}, + $self->{label}, + $self->{base}?"%$self->{base}":"", + $self->{index},$self->{scale}; + } else { + sprintf "%s%s(%%%s)", $self->{asterisk},$self->{label},$self->{base}; + } + } else { + %szmap = ( b=>"BYTE$PTR", w=>"WORD$PTR", + l=>"DWORD$PTR", d=>"DWORD$PTR", + q=>"QWORD$PTR", o=>"OWORD$PTR", + x=>"XMMWORD$PTR", y=>"YMMWORD$PTR", z=>"ZMMWORD$PTR" ); + + $self->{label} =~ s/\./\$/g; + $self->{label} =~ s/(?{label} = "($self->{label})" if ($self->{label} =~ /[\*\+\-\/]/); + + ($self->{asterisk}) && ($sz="q") || + (opcode->mnemonic() =~ /^v?mov([qd])$/) && ($sz=$1) || + (opcode->mnemonic() =~ /^v?pinsr([qdwb])$/) && ($sz=$1) || + (opcode->mnemonic() =~ /^vpbroadcast([qdwb])$/) && ($sz=$1) || + (opcode->mnemonic() =~ /^vinsert[fi]128$/) && ($sz="x"); + + if (defined($self->{index})) { + sprintf "%s[%s%s*%d%s]",$szmap{$sz}, + $self->{label}?"$self->{label}+":"", + $self->{index},$self->{scale}, + $self->{base}?"+$self->{base}":""; + } elsif ($self->{base} eq "rip") { + sprintf "%s[%s]",$szmap{$sz},$self->{label}; + } else { + sprintf "%s[%s%s]",$szmap{$sz}, + $self->{label}?"$self->{label}+":"", + $self->{base}; + } + } + } +} +{ package register; # pick up registers, which start with %. + sub re { + my $class = shift; # muliple instances... + my $self = {}; + local *line = shift; + undef $ret; + + # optional * ---vvv--- appears in indirect jmp/call + if ($line =~ /^(\*?)%(\w+)/) { + bless $self,$class; + $self->{asterisk} = $1; + $self->{value} = $2; + $ret = $self; + $line = substr($line,@+[0]); $line =~ s/^\s+//; + } + $ret; + } + sub size { + my $self = shift; + undef $ret; + + if ($self->{value} =~ /^r[\d]+b$/i) { $ret="b"; } + elsif ($self->{value} =~ /^r[\d]+w$/i) { $ret="w"; } + elsif ($self->{value} =~ /^r[\d]+d$/i) { $ret="l"; } + elsif ($self->{value} =~ /^r[\w]+$/i) { $ret="q"; } + elsif ($self->{value} =~ /^[a-d][hl]$/i){ $ret="b"; } + elsif ($self->{value} =~ /^[\w]{2}l$/i) { $ret="b"; } + elsif ($self->{value} =~ /^[\w]{2}$/i) { $ret="w"; } + elsif ($self->{value} =~ /^e[a-z]{2}$/i){ $ret="l"; } + + $ret; + } + sub out { + my $self = shift; + if ($gas) { sprintf "%s%%%s",$self->{asterisk},$self->{value}; } + else { $self->{value}; } + } +} +{ package label; # pick up labels, which end with : + sub re { + my $self = shift; # single instance is enough... + local *line = shift; + undef $ret; + + if ($line =~ /(^[\.\w]+)\:/) { + $self->{value} = $1; + $ret = $self; + $line = substr($line,@+[0]); $line =~ s/^\s+//; + + $self->{value} =~ s/^\.L/$decor/; + } + $ret; + } + sub out { + my $self = shift; + + if ($gas) { + my $func = ($globals{$self->{value}} or $self->{value}) . ":"; + if ($win64 && + $current_function->{name} eq $self->{value} && + $current_function->{abi} eq "svr4") { + $func .= "\n"; + $func .= " movq %rdi,8(%rsp)\n"; + $func .= " movq %rsi,16(%rsp)\n"; + $func .= " movq %rsp,%rax\n"; + $func .= "${decor}SEH_begin_$current_function->{name}:\n"; + my $narg = $current_function->{narg}; + $narg=6 if (!defined($narg)); + $func .= " movq %rcx,%rdi\n" if ($narg>0); + $func .= " movq %rdx,%rsi\n" if ($narg>1); + $func .= " movq %r8,%rdx\n" if ($narg>2); + $func .= " movq %r9,%rcx\n" if ($narg>3); + $func .= " movq 40(%rsp),%r8\n" if ($narg>4); + $func .= " movq 48(%rsp),%r9\n" if ($narg>5); + } + $func; + } elsif ($self->{value} ne "$current_function->{name}") { + $self->{value} .= ":" if ($masm && $ret!~m/^\$/); + $self->{value} . ":"; + } elsif ($win64 && $current_function->{abi} eq "svr4") { + my $func = "$current_function->{name}" . + ($nasm ? ":" : "\tPROC $current_function->{scope}") . + "\n"; + $func .= " mov QWORD${PTR}[8+rsp],rdi\t;WIN64 prologue\n"; + $func .= " mov QWORD${PTR}[16+rsp],rsi\n"; + $func .= " mov rax,rsp\n"; + $func .= "${decor}SEH_begin_$current_function->{name}:"; + $func .= ":" if ($masm); + $func .= "\n"; + my $narg = $current_function->{narg}; + $narg=6 if (!defined($narg)); + $func .= " mov rdi,rcx\n" if ($narg>0); + $func .= " mov rsi,rdx\n" if ($narg>1); + $func .= " mov rdx,r8\n" if ($narg>2); + $func .= " mov rcx,r9\n" if ($narg>3); + $func .= " mov r8,QWORD${PTR}[40+rsp]\n" if ($narg>4); + $func .= " mov r9,QWORD${PTR}[48+rsp]\n" if ($narg>5); + $func .= "\n"; + } else { + "$current_function->{name}". + ($nasm ? ":" : "\tPROC $current_function->{scope}"); + } + } +} +{ package expr; # pick up expressioins + sub re { + my $self = shift; # single instance is enough... + local *line = shift; + undef $ret; + + if ($line =~ /(^[^,]+)/) { + $self->{value} = $1; + $ret = $self; + $line = substr($line,@+[0]); $line =~ s/^\s+//; + + $self->{value} =~ s/\@PLT// if (!$elf); + $self->{value} =~ s/([_a-z][_a-z0-9]*)/$globals{$1} or $1/gei; + $self->{value} =~ s/\.L/$decor/g; + } + $ret; + } + sub out { + my $self = shift; + if ($nasm && opcode->mnemonic()=~m/^j(?![re]cxz)/) { + "NEAR ".$self->{value}; + } else { + $self->{value}; + } + } +} +{ package directive; # pick up directives, which start with . + sub re { + my $self = shift; # single instance is enough... + local *line = shift; + undef $ret; + my $dir; + my %opcode = # lea 2f-1f(%rip),%dst; 1: nop; 2: + ( "%rax"=>0x01058d48, "%rcx"=>0x010d8d48, + "%rdx"=>0x01158d48, "%rbx"=>0x011d8d48, + "%rsp"=>0x01258d48, "%rbp"=>0x012d8d48, + "%rsi"=>0x01358d48, "%rdi"=>0x013d8d48, + "%r8" =>0x01058d4c, "%r9" =>0x010d8d4c, + "%r10"=>0x01158d4c, "%r11"=>0x011d8d4c, + "%r12"=>0x01258d4c, "%r13"=>0x012d8d4c, + "%r14"=>0x01358d4c, "%r15"=>0x013d8d4c ); + + if ($line =~ /^\s*(\.\w+)/) { + $dir = $1; + $ret = $self; + undef $self->{value}; + $line = substr($line,@+[0]); $line =~ s/^\s+//; + + SWITCH: for ($dir) { + /\.picmeup/ && do { if ($line =~ /(%r[\w]+)/i) { + $dir="\t.long"; + $line=sprintf "0x%x,0x90000000",$opcode{$1}; + } + last; + }; + /\.global|\.globl|\.extern/ + && do { $globals{$line} = $prefix . $line; + $line = $globals{$line} if ($prefix); + last; + }; + /\.type/ && do { ($sym,$type,$narg) = split(',',$line); + if ($type eq "\@function") { + undef $current_function; + $current_function->{name} = $sym; + $current_function->{abi} = "svr4"; + $current_function->{narg} = $narg; + $current_function->{scope} = defined($globals{$sym})?"PUBLIC":"PRIVATE"; + } elsif ($type eq "\@abi-omnipotent") { + undef $current_function; + $current_function->{name} = $sym; + $current_function->{scope} = defined($globals{$sym})?"PUBLIC":"PRIVATE"; + } + $line =~ s/\@abi\-omnipotent/\@function/; + $line =~ s/\@function.*/\@function/; + last; + }; + /\.asciz/ && do { if ($line =~ /^"(.*)"$/) { + $dir = ".byte"; + $line = join(",",unpack("C*",$1),0); + } + last; + }; + /\.rva|\.long|\.quad/ + && do { $line =~ s/([_a-z][_a-z0-9]*)/$globals{$1} or $1/gei; + $line =~ s/\.L/$decor/g; + last; + }; + } + + if ($gas) { + $self->{value} = $dir . "\t" . $line; + + if ($dir =~ /\.extern/) { + if ($flavour eq "elf") { + $self->{value} .= "\n.hidden $line"; + } else { + $self->{value} = ""; + } + } elsif (!$elf && $dir =~ /\.type/) { + $self->{value} = ""; + $self->{value} = ".def\t" . ($globals{$1} or $1) . ";\t" . + (defined($globals{$1})?".scl 2;":".scl 3;") . + "\t.type 32;\t.endef" + if ($win64 && $line =~ /([^,]+),\@function/); + } elsif (!$elf && $dir =~ /\.size/) { + $self->{value} = ""; + if (defined($current_function)) { + $self->{value} .= "${decor}SEH_end_$current_function->{name}:" + if ($win64 && $current_function->{abi} eq "svr4"); + undef $current_function; + } + } elsif (!$elf && $dir =~ /\.align/) { + $self->{value} = ".p2align\t" . (log($line)/log(2)); + } elsif ($dir eq ".section") { + $current_segment=$line; + if (!$elf && $current_segment eq ".init") { + if ($flavour eq "macosx") { $self->{value} = ".mod_init_func"; } + elsif ($flavour eq "mingw64") { $self->{value} = ".section\t.ctors"; } + } + } elsif ($dir =~ /\.(text|data)/) { + $current_segment=".$1"; + } elsif ($dir =~ /\.global|\.globl|\.extern/) { + if ($flavour eq "macosx") { + $self->{value} .= "\n.private_extern $line"; + } else { + $self->{value} .= "\n.hidden $line"; + } + } elsif ($dir =~ /\.hidden/) { + if ($flavour eq "macosx") { $self->{value} = ".private_extern\t$prefix$line"; } + elsif ($flavour eq "mingw64") { $self->{value} = ""; } + } elsif ($dir =~ /\.comm/) { + $self->{value} = "$dir\t$prefix$line"; + $self->{value} =~ s|,([0-9]+),([0-9]+)$|",$1,".log($2)/log(2)|e if ($flavour eq "macosx"); + } + $line = ""; + return $self; + } + + # non-gas case or nasm/masm + SWITCH: for ($dir) { + /\.text/ && do { my $v=undef; + if ($nasm) { + $v="section .text code align=64\n"; + } else { + $v="$current_segment\tENDS\n" if ($current_segment); + $current_segment = ".text\$"; + $v.="$current_segment\tSEGMENT "; + $v.=$masm>=$masmref ? "ALIGN(256)" : "PAGE"; + $v.=" 'CODE'"; + } + $self->{value} = $v; + last; + }; + /\.data/ && do { my $v=undef; + if ($nasm) { + $v="section .data data align=8\n"; + } else { + $v="$current_segment\tENDS\n" if ($current_segment); + $current_segment = "_DATA"; + $v.="$current_segment\tSEGMENT"; + } + $self->{value} = $v; + last; + }; + /\.section/ && do { my $v=undef; + $line =~ s/([^,]*).*/$1/; + $line = ".CRT\$XCU" if ($line eq ".init"); + if ($nasm) { + $v="section $line"; + if ($line=~/\.([px])data/) { + $v.=" rdata align="; + $v.=$1 eq "p"? 4 : 8; + } elsif ($line=~/\.CRT\$/i) { + $v.=" rdata align=8"; + } + } else { + $v="$current_segment\tENDS\n" if ($current_segment); + $v.="$line\tSEGMENT"; + if ($line=~/\.([px])data/) { + $v.=" READONLY"; + $v.=" ALIGN(".($1 eq "p" ? 4 : 8).")" if ($masm>=$masmref); + } elsif ($line=~/\.CRT\$/i) { + $v.=" READONLY "; + $v.=$masm>=$masmref ? "ALIGN(8)" : "DWORD"; + } + } + $current_segment = $line; + $self->{value} = $v; + last; + }; + /\.extern/ && do { $self->{value} = "EXTERN\t".$line; + $self->{value} .= ":NEAR" if ($masm); + last; + }; + /\.globl|.global/ + && do { $self->{value} = $masm?"PUBLIC":"global"; + $self->{value} .= "\t".$line; + last; + }; + /\.size/ && do { if (defined($current_function)) { + undef $self->{value}; + if ($current_function->{abi} eq "svr4") { + $self->{value}="${decor}SEH_end_$current_function->{name}:"; + $self->{value}.=":\n" if($masm); + } + $self->{value}.="$current_function->{name}\tENDP" if($masm && $current_function->{name}); + undef $current_function; + } + last; + }; + /\.align/ && do { $self->{value} = "ALIGN\t".$line; last; }; + /\.(value|long|rva|quad)/ + && do { my $sz = substr($1,0,1); + my @arr = split(/,\s*/,$line); + my $last = pop(@arr); + my $conv = sub { my $var=shift; + $var=~s/^(0b[0-1]+)/oct($1)/eig; + $var=~s/^0x([0-9a-f]+)/0$1h/ig if ($masm); + if ($sz eq "D" && ($current_segment=~/.[px]data/ || $dir eq ".rva")) + { $var=~s/([_a-z\$\@][_a-z0-9\$\@]*)/$nasm?"$1 wrt ..imagebase":"imagerel $1"/egi; } + $var; + }; + + $sz =~ tr/bvlrq/BWDDQ/; + $self->{value} = "\tD$sz\t"; + for (@arr) { $self->{value} .= &$conv($_).","; } + $self->{value} .= &$conv($last); + last; + }; + /\.byte/ && do { my @str=split(/,\s*/,$line); + map(s/(0b[0-1]+)/oct($1)/eig,@str); + map(s/0x([0-9a-f]+)/0$1h/ig,@str) if ($masm); + while ($#str>15) { + $self->{value}.="DB\t" + .join(",",@str[0..15])."\n"; + foreach (0..15) { shift @str; } + } + $self->{value}.="DB\t" + .join(",",@str) if (@str); + last; + }; + /\.comm/ && do { my @str=split(/,\s*/,$line); + my $v=undef; + if ($nasm) { + $v.="common $prefix@str[0] @str[1]"; + } else { + $v="$current_segment\tENDS\n" if ($current_segment); + $current_segment = "_DATA"; + $v.="$current_segment\tSEGMENT\n"; + $v.="COMM @str[0]:DWORD:".@str[1]/4; + } + $self->{value} = $v; + last; + }; + } + $line = ""; + } + + $ret; + } + sub out { + my $self = shift; + $self->{value}; + } +} + +sub rex { + local *opcode=shift; + my ($dst,$src,$rex)=@_; + + $rex|=0x04 if($dst>=8); + $rex|=0x01 if($src>=8); + push @opcode,($rex|0x40) if ($rex); +} + +# older gas and ml64 don't handle SSE>2 instructions +my %regrm = ( "%eax"=>0, "%ecx"=>1, "%edx"=>2, "%ebx"=>3, + "%esp"=>4, "%ebp"=>5, "%esi"=>6, "%edi"=>7 ); + +my $movq = sub { # elderly gas can't handle inter-register movq + my $arg = shift; + my @opcode=(0x66); + if ($arg =~ /%xmm([0-9]+),\s*%r(\w+)/) { + my ($src,$dst)=($1,$2); + if ($dst !~ /[0-9]+/) { $dst = $regrm{"%e$dst"}; } + rex(\@opcode,$src,$dst,0x8); + push @opcode,0x0f,0x7e; + push @opcode,0xc0|(($src&7)<<3)|($dst&7); # ModR/M + @opcode; + } elsif ($arg =~ /%r(\w+),\s*%xmm([0-9]+)/) { + my ($src,$dst)=($2,$1); + if ($dst !~ /[0-9]+/) { $dst = $regrm{"%e$dst"}; } + rex(\@opcode,$src,$dst,0x8); + push @opcode,0x0f,0x6e; + push @opcode,0xc0|(($src&7)<<3)|($dst&7); # ModR/M + @opcode; + } else { + (); + } +}; + +my $pextrd = sub { + if (shift =~ /\$([0-9]+),\s*%xmm([0-9]+),\s*(%\w+)/) { + my @opcode=(0x66); + $imm=$1; + $src=$2; + $dst=$3; + if ($dst =~ /%r([0-9]+)d/) { $dst = $1; } + elsif ($dst =~ /%e/) { $dst = $regrm{$dst}; } + rex(\@opcode,$src,$dst); + push @opcode,0x0f,0x3a,0x16; + push @opcode,0xc0|(($src&7)<<3)|($dst&7); # ModR/M + push @opcode,$imm; + @opcode; + } else { + (); + } +}; + +my $pinsrd = sub { + if (shift =~ /\$([0-9]+),\s*(%\w+),\s*%xmm([0-9]+)/) { + my @opcode=(0x66); + $imm=$1; + $src=$2; + $dst=$3; + if ($src =~ /%r([0-9]+)/) { $src = $1; } + elsif ($src =~ /%e/) { $src = $regrm{$src}; } + rex(\@opcode,$dst,$src); + push @opcode,0x0f,0x3a,0x22; + push @opcode,0xc0|(($dst&7)<<3)|($src&7); # ModR/M + push @opcode,$imm; + @opcode; + } else { + (); + } +}; + +my $pshufb = sub { + if (shift =~ /%xmm([0-9]+),\s*%xmm([0-9]+)/) { + my @opcode=(0x66); + rex(\@opcode,$2,$1); + push @opcode,0x0f,0x38,0x00; + push @opcode,0xc0|($1&7)|(($2&7)<<3); # ModR/M + @opcode; + } else { + (); + } +}; + +my $palignr = sub { + if (shift =~ /\$([0-9]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) { + my @opcode=(0x66); + rex(\@opcode,$3,$2); + push @opcode,0x0f,0x3a,0x0f; + push @opcode,0xc0|($2&7)|(($3&7)<<3); # ModR/M + push @opcode,$1; + @opcode; + } else { + (); + } +}; + +my $pclmulqdq = sub { + if (shift =~ /\$([x0-9a-f]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) { + my @opcode=(0x66); + rex(\@opcode,$3,$2); + push @opcode,0x0f,0x3a,0x44; + push @opcode,0xc0|($2&7)|(($3&7)<<3); # ModR/M + my $c=$1; + push @opcode,$c=~/^0/?oct($c):$c; + @opcode; + } else { + (); + } +}; + +my $rdrand = sub { + if (shift =~ /%[er](\w+)/) { + my @opcode=(); + my $dst=$1; + if ($dst !~ /[0-9]+/) { $dst = $regrm{"%e$dst"}; } + rex(\@opcode,0,$1,8); + push @opcode,0x0f,0xc7,0xf0|($dst&7); + @opcode; + } else { + (); + } +}; + +my $rdseed = sub { + if (shift =~ /%[er](\w+)/) { + my @opcode=(); + my $dst=$1; + if ($dst !~ /[0-9]+/) { $dst = $regrm{"%e$dst"}; } + rex(\@opcode,0,$1,8); + push @opcode,0x0f,0xc7,0xf8|($dst&7); + @opcode; + } else { + (); + } +}; + +sub rxb { + local *opcode=shift; + my ($dst,$src1,$src2,$rxb)=@_; + + $rxb|=0x7<<5; + $rxb&=~(0x04<<5) if($dst>=8); + $rxb&=~(0x01<<5) if($src1>=8); + $rxb&=~(0x02<<5) if($src2>=8); + push @opcode,$rxb; +} + +my $vprotd = sub { + if (shift =~ /\$([x0-9a-f]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) { + my @opcode=(0x8f); + rxb(\@opcode,$3,$2,-1,0x08); + push @opcode,0x78,0xc2; + push @opcode,0xc0|($2&7)|(($3&7)<<3); # ModR/M + my $c=$1; + push @opcode,$c=~/^0/?oct($c):$c; + @opcode; + } else { + (); + } +}; + +my $vprotq = sub { + if (shift =~ /\$([x0-9a-f]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) { + my @opcode=(0x8f); + rxb(\@opcode,$3,$2,-1,0x08); + push @opcode,0x78,0xc3; + push @opcode,0xc0|($2&7)|(($3&7)<<3); # ModR/M + my $c=$1; + push @opcode,$c=~/^0/?oct($c):$c; + @opcode; + } else { + (); + } +}; + +if ($nasm) { + print <<___; +default rel +%define XMMWORD +%define YMMWORD +%define ZMMWORD +___ +} elsif ($masm) { + print <<___; +OPTION DOTNAME +___ +} + +print STDOUT "#if defined(__x86_64__)\n" if ($gas); + +while($line=<>) { + + chomp($line); + + $line =~ s|[#!].*$||; # get rid of asm-style comments... + $line =~ s|/\*.*\*/||; # ... and C-style comments... + $line =~ s|^\s+||; # ... and skip white spaces in beginning + $line =~ s|\s+$||; # ... and at the end + + undef $label; + undef $opcode; + undef @args; + + if ($label=label->re(\$line)) { print $label->out(); } + + if (directive->re(\$line)) { + printf "%s",directive->out(); + } elsif ($opcode=opcode->re(\$line)) { + my $asm = eval("\$".$opcode->mnemonic()); + undef @bytes; + + if ((ref($asm) eq 'CODE') && scalar(@bytes=&$asm($line))) { + print $gas?".byte\t":"DB\t",join(',',@bytes),"\n"; + next; + } + + ARGUMENT: while (1) { + my $arg; + + if ($arg=register->re(\$line)) { opcode->size($arg->size()); } + elsif ($arg=const->re(\$line)) { } + elsif ($arg=ea->re(\$line)) { } + elsif ($arg=expr->re(\$line)) { } + else { last ARGUMENT; } + + push @args,$arg; + + last ARGUMENT if ($line !~ /^,/); + + $line =~ s/^,\s*//; + } # ARGUMENT: + + if ($#args>=0) { + my $insn; + my $sz=opcode->size(); + + if ($gas) { + $insn = $opcode->out($#args>=1?$args[$#args]->size():$sz); + @args = map($_->out($sz),@args); + printf "\t%s\t%s",$insn,join(",",@args); + } else { + $insn = $opcode->out(); + foreach (@args) { + my $arg = $_->out(); + # $insn.=$sz compensates for movq, pinsrw, ... + if ($arg =~ /^xmm[0-9]+$/) { $insn.=$sz; $sz="x" if(!$sz); last; } + if ($arg =~ /^ymm[0-9]+$/) { $insn.=$sz; $sz="y" if(!$sz); last; } + if ($arg =~ /^zmm[0-9]+$/) { $insn.=$sz; $sz="z" if(!$sz); last; } + if ($arg =~ /^mm[0-9]+$/) { $insn.=$sz; $sz="q" if(!$sz); last; } + } + @args = reverse(@args); + undef $sz if ($nasm && $opcode->mnemonic() eq "lea"); + + if ($insn eq "movq" && $#args == 1 && $args[0]->out($sz) eq "xmm0" && $args[1]->out($sz) eq "rax") { + # I have no clue why MASM can't parse this instruction. + printf "DB 66h, 48h, 0fh, 6eh, 0c0h"; + } else { + printf "\t%s\t%s",$insn,join(",",map($_->out($sz),@args)); + } + } + } else { + printf "\t%s",$opcode->out(); + } + } + + print $line,"\n"; +} + +print "\n$current_segment\tENDS\n" if ($current_segment && $masm); +print "END\n" if ($masm); +print "#endif\n" if ($gas); + + +close STDOUT; + + ################################################# +# Cross-reference x86_64 ABI "card" +# +# Unix Win64 +# %rax * * +# %rbx - - +# %rcx #4 #1 +# %rdx #3 #2 +# %rsi #2 - +# %rdi #1 - +# %rbp - - +# %rsp - - +# %r8 #5 #3 +# %r9 #6 #4 +# %r10 * * +# %r11 * * +# %r12 - - +# %r13 - - +# %r14 - - +# %r15 - - +# +# (*) volatile register +# (-) preserved by callee +# (#) Nth argument, volatile +# +# In Unix terms top of stack is argument transfer area for arguments +# which could not be accomodated in registers. Or in other words 7th +# [integer] argument resides at 8(%rsp) upon function entry point. +# 128 bytes above %rsp constitute a "red zone" which is not touched +# by signal handlers and can be used as temporal storage without +# allocating a frame. +# +# In Win64 terms N*8 bytes on top of stack is argument transfer area, +# which belongs to/can be overwritten by callee. N is the number of +# arguments passed to callee, *but* not less than 4! This means that +# upon function entry point 5th argument resides at 40(%rsp), as well +# as that 32 bytes from 8(%rsp) can always be used as temporal +# storage [without allocating a frame]. One can actually argue that +# one can assume a "red zone" above stack pointer under Win64 as well. +# Point is that at apparently no occasion Windows kernel would alter +# the area above user stack pointer in true asynchronous manner... +# +# All the above means that if assembler programmer adheres to Unix +# register and stack layout, but disregards the "red zone" existense, +# it's possible to use following prologue and epilogue to "gear" from +# Unix to Win64 ABI in leaf functions with not more than 6 arguments. +# +# omnipotent_function: +# ifdef WIN64 +# movq %rdi,8(%rsp) +# movq %rsi,16(%rsp) +# movq %rcx,%rdi ; if 1st argument is actually present +# movq %rdx,%rsi ; if 2nd argument is actually ... +# movq %r8,%rdx ; if 3rd argument is ... +# movq %r9,%rcx ; if 4th argument ... +# movq 40(%rsp),%r8 ; if 5th ... +# movq 48(%rsp),%r9 ; if 6th ... +# endif +# ... +# ifdef WIN64 +# movq 8(%rsp),%rdi +# movq 16(%rsp),%rsi +# endif +# ret +# + ################################################# +# Win64 SEH, Structured Exception Handling. +# +# Unlike on Unix systems(*) lack of Win64 stack unwinding information +# has undesired side-effect at run-time: if an exception is raised in +# assembler subroutine such as those in question (basically we're +# referring to segmentation violations caused by malformed input +# parameters), the application is briskly terminated without invoking +# any exception handlers, most notably without generating memory dump +# or any user notification whatsoever. This poses a problem. It's +# possible to address it by registering custom language-specific +# handler that would restore processor context to the state at +# subroutine entry point and return "exception is not handled, keep +# unwinding" code. Writing such handler can be a challenge... But it's +# doable, though requires certain coding convention. Consider following +# snippet: +# +# .type function,@function +# function: +# movq %rsp,%rax # copy rsp to volatile register +# pushq %r15 # save non-volatile registers +# pushq %rbx +# pushq %rbp +# movq %rsp,%r11 +# subq %rdi,%r11 # prepare [variable] stack frame +# andq $-64,%r11 +# movq %rax,0(%r11) # check for exceptions +# movq %r11,%rsp # allocate [variable] stack frame +# movq %rax,0(%rsp) # save original rsp value +# magic_point: +# ... +# movq 0(%rsp),%rcx # pull original rsp value +# movq -24(%rcx),%rbp # restore non-volatile registers +# movq -16(%rcx),%rbx +# movq -8(%rcx),%r15 +# movq %rcx,%rsp # restore original rsp +# ret +# .size function,.-function +# +# The key is that up to magic_point copy of original rsp value remains +# in chosen volatile register and no non-volatile register, except for +# rsp, is modified. While past magic_point rsp remains constant till +# the very end of the function. In this case custom language-specific +# exception handler would look like this: +# +# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame, +# CONTEXT *context,DISPATCHER_CONTEXT *disp) +# { ULONG64 *rsp = (ULONG64 *)context->Rax; +# if (context->Rip >= magic_point) +# { rsp = ((ULONG64 **)context->Rsp)[0]; +# context->Rbp = rsp[-3]; +# context->Rbx = rsp[-2]; +# context->R15 = rsp[-1]; +# } +# context->Rsp = (ULONG64)rsp; +# context->Rdi = rsp[1]; +# context->Rsi = rsp[2]; +# +# memcpy (disp->ContextRecord,context,sizeof(CONTEXT)); +# RtlVirtualUnwind(UNW_FLAG_NHANDLER,disp->ImageBase, +# dips->ControlPc,disp->FunctionEntry,disp->ContextRecord, +# &disp->HandlerData,&disp->EstablisherFrame,NULL); +# return ExceptionContinueSearch; +# } +# +# It's appropriate to implement this handler in assembler, directly in +# function's module. In order to do that one has to know members' +# offsets in CONTEXT and DISPATCHER_CONTEXT structures and some constant +# values. Here they are: +# +# CONTEXT.Rax 120 +# CONTEXT.Rcx 128 +# CONTEXT.Rdx 136 +# CONTEXT.Rbx 144 +# CONTEXT.Rsp 152 +# CONTEXT.Rbp 160 +# CONTEXT.Rsi 168 +# CONTEXT.Rdi 176 +# CONTEXT.R8 184 +# CONTEXT.R9 192 +# CONTEXT.R10 200 +# CONTEXT.R11 208 +# CONTEXT.R12 216 +# CONTEXT.R13 224 +# CONTEXT.R14 232 +# CONTEXT.R15 240 +# CONTEXT.Rip 248 +# CONTEXT.Xmm6 512 +# sizeof(CONTEXT) 1232 +# DISPATCHER_CONTEXT.ControlPc 0 +# DISPATCHER_CONTEXT.ImageBase 8 +# DISPATCHER_CONTEXT.FunctionEntry 16 +# DISPATCHER_CONTEXT.EstablisherFrame 24 +# DISPATCHER_CONTEXT.TargetIp 32 +# DISPATCHER_CONTEXT.ContextRecord 40 +# DISPATCHER_CONTEXT.LanguageHandler 48 +# DISPATCHER_CONTEXT.HandlerData 56 +# UNW_FLAG_NHANDLER 0 +# ExceptionContinueSearch 1 +# +# In order to tie the handler to the function one has to compose +# couple of structures: one for .xdata segment and one for .pdata. +# +# UNWIND_INFO structure for .xdata segment would be +# +# function_unwind_info: +# .byte 9,0,0,0 +# .rva handler +# +# This structure designates exception handler for a function with +# zero-length prologue, no stack frame or frame register. +# +# To facilitate composing of .pdata structures, auto-generated "gear" +# prologue copies rsp value to rax and denotes next instruction with +# .LSEH_begin_{function_name} label. This essentially defines the SEH +# styling rule mentioned in the beginning. Position of this label is +# chosen in such manner that possible exceptions raised in the "gear" +# prologue would be accounted to caller and unwound from latter's frame. +# End of function is marked with respective .LSEH_end_{function_name} +# label. To summarize, .pdata segment would contain +# +# .rva .LSEH_begin_function +# .rva .LSEH_end_function +# .rva function_unwind_info +# +# Reference to functon_unwind_info from .xdata segment is the anchor. +# In case you wonder why references are 32-bit .rvas and not 64-bit +# .quads. References put into these two segments are required to be +# *relative* to the base address of the current binary module, a.k.a. +# image base. No Win64 module, be it .exe or .dll, can be larger than +# 2GB and thus such relative references can be and are accommodated in +# 32 bits. +# +# Having reviewed the example function code, one can argue that "movq +# %rsp,%rax" above is redundant. It is not! Keep in mind that on Unix +# rax would contain an undefined value. If this "offends" you, use +# another register and refrain from modifying rax till magic_point is +# reached, i.e. as if it was a non-volatile register. If more registers +# are required prior [variable] frame setup is completed, note that +# nobody says that you can have only one "magic point." You can +# "liberate" non-volatile registers by denoting last stack off-load +# instruction and reflecting it in finer grade unwind logic in handler. +# After all, isn't it why it's called *language-specific* handler... +# +# Attentive reader can notice that exceptions would be mishandled in +# auto-generated "gear" epilogue. Well, exception effectively can't +# occur there, because if memory area used by it was subject to +# segmentation violation, then it would be raised upon call to the +# function (and as already mentioned be accounted to caller, which is +# not a problem). If you're still not comfortable, then define tail +# "magic point" just prior ret instruction and have handler treat it... +# +# (*) Note that we're talking about run-time, not debug-time. Lack of +# unwind information makes debugging hard on both Windows and +# Unix. "Unlike" referes to the fact that on Unix signal handler +# will always be invoked, core dumped and appropriate exit code +# returned to parent (for user notification). diff --git a/TMessagesProj/jni/boringssl/crypto/perlasm/x86asm.pl b/TMessagesProj/jni/boringssl/crypto/perlasm/x86asm.pl new file mode 100644 index 00000000..3c7be40c --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/perlasm/x86asm.pl @@ -0,0 +1,292 @@ +#!/usr/bin/env perl + +# require 'x86asm.pl'; +# &asm_init(,"des-586.pl"[,$i386only]); +# &function_begin("foo"); +# ... +# &function_end("foo"); +# &asm_finish + +$out=(); +$i386=0; + +# AUTOLOAD is this context has quite unpleasant side effect, namely +# that typos in function calls effectively go to assembler output, +# but on the pros side we don't have to implement one subroutine per +# each opcode... +sub ::AUTOLOAD +{ my $opcode = $AUTOLOAD; + + die "more than 4 arguments passed to $opcode" if ($#_>3); + + $opcode =~ s/.*:://; + if ($opcode =~ /^push/) { $stack+=4; } + elsif ($opcode =~ /^pop/) { $stack-=4; } + + &generic($opcode,@_) or die "undefined subroutine \&$AUTOLOAD"; +} + +sub ::emit +{ my $opcode=shift; + + if ($#_==-1) { push(@out,"\t$opcode\n"); } + else { push(@out,"\t$opcode\t".join(',',@_)."\n"); } +} + +sub ::LB +{ $_[0] =~ m/^e?([a-d])x$/o or die "$_[0] does not have a 'low byte'"; + $1."l"; +} +sub ::HB +{ $_[0] =~ m/^e?([a-d])x$/o or die "$_[0] does not have a 'high byte'"; + $1."h"; +} +sub ::stack_push{ my $num=$_[0]*4; $stack+=$num; &sub("esp",$num); } +sub ::stack_pop { my $num=$_[0]*4; $stack-=$num; &add("esp",$num); } +sub ::blindpop { &pop($_[0]); $stack+=4; } +sub ::wparam { &DWP($stack+4*$_[0],"esp"); } +sub ::swtmp { &DWP(4*$_[0],"esp"); } + +sub ::bswap +{ if ($i386) # emulate bswap for i386 + { &comment("bswap @_"); + &xchg(&HB(@_),&LB(@_)); + &ror (@_,16); + &xchg(&HB(@_),&LB(@_)); + } + else + { &generic("bswap",@_); } +} +# These are made-up opcodes introduced over the years essentially +# by ignorance, just alias them to real ones... +sub ::movb { &mov(@_); } +sub ::xorb { &xor(@_); } +sub ::rotl { &rol(@_); } +sub ::rotr { &ror(@_); } +sub ::exch { &xchg(@_); } +sub ::halt { &hlt; } +sub ::movz { &movzx(@_); } +sub ::pushf { &pushfd; } +sub ::popf { &popfd; } + +# 3 argument instructions +sub ::movq +{ my($p1,$p2,$optimize)=@_; + + if ($optimize && $p1=~/^mm[0-7]$/ && $p2=~/^mm[0-7]$/) + # movq between mmx registers can sink Intel CPUs + { &::pshufw($p1,$p2,0xe4); } + else + { &::generic("movq",@_); } +} + +# SSE>2 instructions +my %regrm = ( "eax"=>0, "ecx"=>1, "edx"=>2, "ebx"=>3, + "esp"=>4, "ebp"=>5, "esi"=>6, "edi"=>7 ); +sub ::pextrd +{ my($dst,$src,$imm)=@_; + if ("$dst:$src" =~ /(e[a-dsd][ixp]):xmm([0-7])/) + { &::data_byte(0x66,0x0f,0x3a,0x16,0xc0|($2<<3)|$regrm{$1},$imm); } + else + { &::generic("pextrd",@_); } +} + +sub ::pinsrd +{ my($dst,$src,$imm)=@_; + if ("$dst:$src" =~ /xmm([0-7]):(e[a-dsd][ixp])/) + { &::data_byte(0x66,0x0f,0x3a,0x22,0xc0|($1<<3)|$regrm{$2},$imm); } + else + { &::generic("pinsrd",@_); } +} + +sub ::pshufb +{ my($dst,$src)=@_; + if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/) + { &data_byte(0x66,0x0f,0x38,0x00,0xc0|($1<<3)|$2); } + else + { &::generic("pshufb",@_); } +} + +sub ::palignr +{ my($dst,$src,$imm)=@_; + if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/) + { &::data_byte(0x66,0x0f,0x3a,0x0f,0xc0|($1<<3)|$2,$imm); } + else + { &::generic("palignr",@_); } +} + +sub ::pclmulqdq +{ my($dst,$src,$imm)=@_; + if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/) + { &::data_byte(0x66,0x0f,0x3a,0x44,0xc0|($1<<3)|$2,$imm); } + else + { &::generic("pclmulqdq",@_); } +} + +sub ::rdrand +{ my ($dst)=@_; + if ($dst =~ /(e[a-dsd][ixp])/) + { &::data_byte(0x0f,0xc7,0xf0|$regrm{$dst}); } + else + { &::generic("rdrand",@_); } +} + +sub rxb { + local *opcode=shift; + my ($dst,$src1,$src2,$rxb)=@_; + + $rxb|=0x7<<5; + $rxb&=~(0x04<<5) if($dst>=8); + $rxb&=~(0x01<<5) if($src1>=8); + $rxb&=~(0x02<<5) if($src2>=8); + push @opcode,$rxb; +} + +sub ::vprotd +{ my $args=join(',',@_); + if ($args =~ /xmm([0-7]),xmm([0-7]),([x0-9a-f]+)/) + { my @opcode=(0x8f); + rxb(\@opcode,$1,$2,-1,0x08); + push @opcode,0x78,0xc2; + push @opcode,0xc0|($2&7)|(($1&7)<<3); # ModR/M + my $c=$3; + push @opcode,$c=~/^0/?oct($c):$c; + &::data_byte(@opcode); + } + else + { &::generic("vprotd",@_); } +} + +# label management +$lbdecor="L"; # local label decoration, set by package +$label="000"; + +sub ::islabel # see is argument is a known label +{ my $i; + foreach $i (values %label) { return $i if ($i eq $_[0]); } + $label{$_[0]}; # can be undef +} + +sub ::label # instantiate a function-scope label +{ if (!defined($label{$_[0]})) + { $label{$_[0]}="${lbdecor}${label}${_[0]}"; $label++; } + $label{$_[0]}; +} + +sub ::LABEL # instantiate a file-scope label +{ $label{$_[0]}=$_[1] if (!defined($label{$_[0]})); + $label{$_[0]}; +} + +sub ::static_label { &::LABEL($_[0],$lbdecor.$_[0]); } + +sub ::set_label_B { push(@out,"@_:\n"); } +sub ::set_label +{ my $label=&::label($_[0]); + &::align($_[1]) if ($_[1]>1); + &::set_label_B($label); + $label; +} + +sub ::wipe_labels # wipes function-scope labels +{ foreach $i (keys %label) + { delete $label{$i} if ($label{$i} =~ /^\Q${lbdecor}\E[0-9]{3}/); } +} + +# subroutine management +sub ::function_begin +{ &function_begin_B(@_); + $stack=4; + &push("ebp"); + &push("ebx"); + &push("esi"); + &push("edi"); +} + +sub ::function_end +{ &pop("edi"); + &pop("esi"); + &pop("ebx"); + &pop("ebp"); + &ret(); + &function_end_B(@_); + $stack=0; + &wipe_labels(); +} + +sub ::function_end_A +{ &pop("edi"); + &pop("esi"); + &pop("ebx"); + &pop("ebp"); + &ret(); + $stack+=16; # readjust esp as if we didn't pop anything +} + +sub ::asciz +{ my @str=unpack("C*",shift); + push @str,0; + while ($#str>15) { + &data_byte(@str[0..15]); + foreach (0..15) { shift @str; } + } + &data_byte(@str) if (@str); +} + +sub ::asm_finish +{ &file_end(); + print "#if defined(__i386__)\n" unless $win32; + print @out; + print "#endif\n" unless $win32; +} + +sub ::asm_init +{ my ($type,$fn,$cpu)=@_; + + $filename=$fn; + $i386=$cpu; + + $elf=$cpp=$coff=$aout=$macosx=$win32=$netware=$mwerks=$android=0; + if (($type eq "elf")) + { $elf=1; require "x86gas.pl"; } + elsif (($type eq "elf-1")) + { $elf=-1; require "x86gas.pl"; } + elsif (($type eq "a\.out")) + { $aout=1; require "x86gas.pl"; } + elsif (($type eq "coff" or $type eq "gaswin")) + { $coff=1; require "x86gas.pl"; } + elsif (($type eq "win32n")) + { $win32=1; require "x86nasm.pl"; } + elsif (($type eq "nw-nasm")) + { $netware=1; require "x86nasm.pl"; } + #elsif (($type eq "nw-mwasm")) + #{ $netware=1; $mwerks=1; require "x86nasm.pl"; } + elsif (($type eq "win32")) + { $win32=1; require "x86masm.pl"; } + elsif (($type eq "macosx")) + { $aout=1; $macosx=1; require "x86gas.pl"; } + elsif (($type eq "android")) + { $elf=1; $android=1; require "x86gas.pl"; } + else + { print STDERR <<"EOF"; +Pick one target type from + elf - Linux, FreeBSD, Solaris x86, etc. + a.out - DJGPP, elder OpenBSD, etc. + coff - GAS/COFF such as Win32 targets + win32n - Windows 95/Windows NT NASM format + nw-nasm - NetWare NASM format + macosx - Mac OS X +EOF + exit(1); + } + + $pic=0; + for (@ARGV) { $pic=1 if (/\-[fK]PIC/i); } + + $filename =~ s/\.pl$//; + &file($filename); +} + +sub ::hidden {} + +1; diff --git a/TMessagesProj/jni/boringssl/crypto/perlasm/x86gas.pl b/TMessagesProj/jni/boringssl/crypto/perlasm/x86gas.pl new file mode 100644 index 00000000..99d7c1bd --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/perlasm/x86gas.pl @@ -0,0 +1,263 @@ +#!/usr/bin/env perl + +package x86gas; + +*out=\@::out; + +$::lbdecor=$::aout?"L":".L"; # local label decoration +$nmdecor=($::aout or $::coff)?"_":""; # external name decoration + +$initseg=""; + +$align=16; +$align=log($align)/log(2) if ($::aout); +$com_start="#" if ($::aout or $::coff); + +sub opsize() +{ my $reg=shift; + if ($reg =~ m/^%e/o) { "l"; } + elsif ($reg =~ m/^%[a-d][hl]$/o) { "b"; } + elsif ($reg =~ m/^%[xm]/o) { undef; } + else { "w"; } +} + +# swap arguments; +# expand opcode with size suffix; +# prefix numeric constants with $; +sub ::generic +{ my($opcode,@arg)=@_; + my($suffix,$dst,$src); + + @arg=reverse(@arg); + + for (@arg) + { s/^(\*?)(e?[a-dsixphl]{2})$/$1%$2/o; # gp registers + s/^([xy]?mm[0-7])$/%$1/o; # xmm/mmx registers + s/^(\-?[0-9]+)$/\$$1/o; # constants + s/^(\-?0x[0-9a-f]+)$/\$$1/o; # constants + } + + $dst = $arg[$#arg] if ($#arg>=0); + $src = $arg[$#arg-1] if ($#arg>=1); + if ($dst =~ m/^%/o) { $suffix=&opsize($dst); } + elsif ($src =~ m/^%/o) { $suffix=&opsize($src); } + else { $suffix="l"; } + undef $suffix if ($dst =~ m/^%[xm]/o || $src =~ m/^%[xm]/o); + + if ($#_==0) { &::emit($opcode); } + elsif ($#_==1 && $opcode =~ m/^(call|clflush|j|loop|set)/o) + { &::emit($opcode,@arg); } + else { &::emit($opcode.$suffix,@arg);} + + 1; +} +# +# opcodes not covered by ::generic above, mostly inconsistent namings... +# +sub ::movzx { &::movzb(@_); } +sub ::pushfd { &::pushfl; } +sub ::popfd { &::popfl; } +sub ::cpuid { &::emit(".byte\t0x0f,0xa2"); } +sub ::rdtsc { &::emit(".byte\t0x0f,0x31"); } + +sub ::call { &::emit("call",(&::islabel($_[0]) or "$nmdecor$_[0]")); } +sub ::call_ptr { &::generic("call","*$_[0]"); } +sub ::jmp_ptr { &::generic("jmp","*$_[0]"); } + +*::bswap = sub { &::emit("bswap","%$_[0]"); } if (!$::i386); + +sub ::DWP +{ my($addr,$reg1,$reg2,$idx)=@_; + my $ret=""; + + if (!defined($idx) && 1*$reg2) { $idx=$reg2; $reg2=$reg1; undef $reg1; } + + $addr =~ s/^\s+//; + # prepend global references with optional underscore + $addr =~ s/^([^\+\-0-9][^\+\-]*)/&::islabel($1) or "$nmdecor$1"/ige; + + $reg1 = "%$reg1" if ($reg1); + $reg2 = "%$reg2" if ($reg2); + + $ret .= $addr if (($addr ne "") && ($addr ne 0)); + + if ($reg2) + { $idx!= 0 or $idx=1; + $ret .= "($reg1,$reg2,$idx)"; + } + elsif ($reg1) + { $ret .= "($reg1)"; } + + $ret; +} +sub ::QWP { &::DWP(@_); } +sub ::BP { &::DWP(@_); } +sub ::WP { &::DWP(@_); } +sub ::BC { @_; } +sub ::DWC { @_; } + +sub ::file +{ push(@out,".file\t\"$_[0].S\"\n.text\n"); } + +sub ::function_begin_B +{ my $func=shift; + my $global=($func !~ /^_/); + my $begin="${::lbdecor}_${func}_begin"; + + &::LABEL($func,$global?"$begin":"$nmdecor$func"); + $func=$nmdecor.$func; + + push(@out,".globl\t$func\n") if ($global); + if ($::macosx) { + push(@out,".private_extern\t$func\n"); + } else { + push(@out,".hidden\t$func\n"); + } + if ($::coff) + { push(@out,".def\t$func;\t.scl\t".(3-$global).";\t.type\t32;\t.endef\n"); } + elsif (($::aout and !$::pic) or $::macosx) + { } + else + { push(@out,".type $func,\@function\n"); } + push(@out,".align\t$align\n"); + push(@out,"$func:\n"); + push(@out,"$begin:\n") if ($global); + $::stack=4; +} + +sub ::function_end_B +{ my $func=shift; + push(@out,".size\t$nmdecor$func,.-".&::LABEL($func)."\n") if ($::elf); + $::stack=0; + &::wipe_labels(); +} + +sub ::comment + { + if (!defined($com_start) or $::elf) + { # Regarding $::elf above... + # GNU and SVR4 as'es use different comment delimiters, + push(@out,"\n"); # so we just skip ELF comments... + return; + } + foreach (@_) + { + if (/^\s*$/) + { push(@out,"\n"); } + else + { push(@out,"\t$com_start $_ $com_end\n"); } + } + } + +sub ::external_label +{ foreach(@_) { &::LABEL($_,$nmdecor.$_); } } + +sub ::public_label +{ push(@out,".globl\t".&::LABEL($_[0],$nmdecor.$_[0])."\n"); } + +sub ::file_end +{ if ($::macosx) + { if (%non_lazy_ptr) + { push(@out,".section __IMPORT,__pointers,non_lazy_symbol_pointers\n"); + foreach $i (keys %non_lazy_ptr) + { push(@out,"$non_lazy_ptr{$i}:\n.indirect_symbol\t$i\n.long\t0\n"); } + } + } + if (0 && grep {/\b${nmdecor}OPENSSL_ia32cap_P\b/i} @out) { + my $tmp=".comm\t${nmdecor}OPENSSL_ia32cap_P,16"; + if ($::macosx) { push (@out,"$tmp,2\n"); } + elsif ($::elf) { push (@out,"$tmp,4\n"); } + else { push (@out,"$tmp\n"); } + } + push(@out,$initseg) if ($initseg); +} + +sub ::data_byte { push(@out,".byte\t".join(',',@_)."\n"); } +sub ::data_short{ push(@out,".value\t".join(',',@_)."\n"); } +sub ::data_word { push(@out,".long\t".join(',',@_)."\n"); } + +sub ::align +{ my $val=$_[0]; + if ($::aout) + { $val=int(log($val)/log(2)); + $val.=",0x90"; + } + push(@out,".align\t$val\n"); +} + +sub ::picmeup +{ my($dst,$sym,$base,$reflabel)=@_; + + if (($::pic && ($::elf || $::aout)) || $::macosx) + { if (!defined($base)) + { &::call(&::label("PIC_me_up")); + &::set_label("PIC_me_up"); + &::blindpop($dst); + $base=$dst; + $reflabel=&::label("PIC_me_up"); + } + if ($::macosx) + { my $indirect=&::static_label("$nmdecor$sym\$non_lazy_ptr"); + &::mov($dst,&::DWP("$indirect-$reflabel",$base)); + $non_lazy_ptr{"$nmdecor$sym"}=$indirect; + } + elsif ($sym eq "OPENSSL_ia32cap_P" && $::elf>0) + { &::lea($dst,&::DWP("$sym-$reflabel",$base)); } + else + { &::lea($dst,&::DWP("_GLOBAL_OFFSET_TABLE_+[.-$reflabel]", + $base)); + &::mov($dst,&::DWP("$sym\@GOT",$dst)); + } + } + else + { &::lea($dst,&::DWP($sym)); } +} + +sub ::initseg +{ my $f=$nmdecor.shift; + + if ($::android) + { $initseg.=<<___; +.section .init_array +.align 4 +.long $f +___ + } + elsif ($::elf) + { $initseg.=<<___; +.section .init + call $f +___ + } + elsif ($::coff) + { $initseg.=<<___; # applies to both Cygwin and Mingw +.section .ctors +.long $f +___ + } + elsif ($::macosx) + { $initseg.=<<___; +.mod_init_func +.align 2 +.long $f +___ + } + elsif ($::aout) + { my $ctor="${nmdecor}_GLOBAL_\$I\$$f"; + $initseg.=".text\n"; + $initseg.=".type $ctor,\@function\n" if ($::pic); + $initseg.=<<___; # OpenBSD way... +.globl $ctor +.align 2 +$ctor: + jmp $f +___ + } +} + +sub ::dataseg +{ push(@out,".data\n"); } + +*::hidden = sub { push(@out,".hidden\t$nmdecor$_[0]\n"); } if ($::elf); + +1; diff --git a/TMessagesProj/jni/boringssl/crypto/perlasm/x86masm.pl b/TMessagesProj/jni/boringssl/crypto/perlasm/x86masm.pl new file mode 100644 index 00000000..b7f49d1c --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/perlasm/x86masm.pl @@ -0,0 +1,200 @@ +#!/usr/bin/env perl + +package x86masm; + +*out=\@::out; + +$::lbdecor="\$L"; # local label decoration +$nmdecor="_"; # external name decoration + +$initseg=""; +$segment=""; + +sub ::generic +{ my ($opcode,@arg)=@_; + + # fix hexadecimal constants + for (@arg) { s/(?= 0x02030000\n"); + push(@out,"safeseh ".&::LABEL($nm,$nmdecor.$nm)."\n"); + push(@out,"%endif\n"); +} + +1; diff --git a/TMessagesProj/jni/boringssl/crypto/pkcs8/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/pkcs8/CMakeLists.txt new file mode 100644 index 00000000..4bc2e9bd --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/pkcs8/CMakeLists.txt @@ -0,0 +1,12 @@ +include_directories(. .. ../../include) + +add_library( + pkcs8 + + OBJECT + + pkcs8.c + p8_pkey.c + p5_pbe.c + p5_pbev2.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/pkcs8/internal.h b/TMessagesProj/jni/boringssl/crypto/pkcs8/internal.h new file mode 100644 index 00000000..44ca4f7b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/pkcs8/internal.h @@ -0,0 +1,74 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef OPENSSL_HEADER_PKCS8_INTERNAL_H +#define OPENSSL_HEADER_PKCS8_INTERNAL_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +#define PKCS5_DEFAULT_ITERATIONS 2048 +#define PKCS5_SALT_LEN 8 + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_PKCS8_INTERNAL_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/pkcs8/p5_pbe.c b/TMessagesProj/jni/boringssl/crypto/pkcs8/p5_pbe.c new file mode 100644 index 00000000..653cabf3 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/pkcs8/p5_pbe.c @@ -0,0 +1,150 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include +#include +#include + +#include "internal.h" + + +/* PKCS#5 password based encryption structure */ + +ASN1_SEQUENCE(PBEPARAM) = { + ASN1_SIMPLE(PBEPARAM, salt, ASN1_OCTET_STRING), + ASN1_SIMPLE(PBEPARAM, iter, ASN1_INTEGER) +} ASN1_SEQUENCE_END(PBEPARAM) + +IMPLEMENT_ASN1_FUNCTIONS(PBEPARAM) + + +/* Set an algorithm identifier for a PKCS#5 PBE algorithm */ + +int PKCS5_pbe_set0_algor(X509_ALGOR *algor, int alg, int iter, + const unsigned char *salt, int saltlen) + { + PBEPARAM *pbe=NULL; + ASN1_STRING *pbe_str=NULL; + unsigned char *sstr; + + pbe = PBEPARAM_new(); + if (!pbe) + { + OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + goto err; + } + if(iter <= 0) + iter = PKCS5_DEFAULT_ITERATIONS; + if (!ASN1_INTEGER_set(pbe->iter, iter)) + { + OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + goto err; + } + if (!saltlen) + saltlen = PKCS5_SALT_LEN; + if (!ASN1_STRING_set(pbe->salt, NULL, saltlen)) + { + OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + goto err; + } + sstr = ASN1_STRING_data(pbe->salt); + if (salt) + memcpy(sstr, salt, saltlen); + else if (!RAND_bytes(sstr, saltlen)) + goto err; + + if(!ASN1_item_pack(pbe, ASN1_ITEM_rptr(PBEPARAM), &pbe_str)) + { + OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + goto err; + } + + PBEPARAM_free(pbe); + pbe = NULL; + + if (X509_ALGOR_set0(algor, OBJ_nid2obj(alg), V_ASN1_SEQUENCE, pbe_str)) + return 1; + +err: + if (pbe != NULL) + PBEPARAM_free(pbe); + if (pbe_str != NULL) + ASN1_STRING_free(pbe_str); + return 0; + } + +/* Return an algorithm identifier for a PKCS#5 PBE algorithm */ + +X509_ALGOR *PKCS5_pbe_set(int alg, int iter, + const unsigned char *salt, int saltlen) + { + X509_ALGOR *ret; + ret = X509_ALGOR_new(); + if (!ret) + { + OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + return NULL; + } + + if (PKCS5_pbe_set0_algor(ret, alg, iter, salt, saltlen)) + return ret; + + X509_ALGOR_free(ret); + return NULL; + } diff --git a/TMessagesProj/jni/boringssl/crypto/pkcs8/p5_pbev2.c b/TMessagesProj/jni/boringssl/crypto/pkcs8/p5_pbev2.c new file mode 100644 index 00000000..beeb3364 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/pkcs8/p5_pbev2.c @@ -0,0 +1,303 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999-2004. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" + + +/* PKCS#5 v2.0 password based encryption structures */ + +ASN1_SEQUENCE(PBE2PARAM) = { + ASN1_SIMPLE(PBE2PARAM, keyfunc, X509_ALGOR), + ASN1_SIMPLE(PBE2PARAM, encryption, X509_ALGOR) +} ASN1_SEQUENCE_END(PBE2PARAM) + +IMPLEMENT_ASN1_FUNCTIONS(PBE2PARAM) + +ASN1_SEQUENCE(PBKDF2PARAM) = { + ASN1_SIMPLE(PBKDF2PARAM, salt, ASN1_ANY), + ASN1_SIMPLE(PBKDF2PARAM, iter, ASN1_INTEGER), + ASN1_OPT(PBKDF2PARAM, keylength, ASN1_INTEGER), + ASN1_OPT(PBKDF2PARAM, prf, X509_ALGOR) +} ASN1_SEQUENCE_END(PBKDF2PARAM) + +IMPLEMENT_ASN1_FUNCTIONS(PBKDF2PARAM); + +static int ASN1_TYPE_set_octetstring(ASN1_TYPE *a, unsigned char *data, int len) + { + ASN1_STRING *os; + + if ((os=M_ASN1_OCTET_STRING_new()) == NULL) return(0); + if (!M_ASN1_OCTET_STRING_set(os,data,len)) + { + M_ASN1_OCTET_STRING_free(os); + return 0; + } + ASN1_TYPE_set(a,V_ASN1_OCTET_STRING,os); + return(1); + } + +static int param_to_asn1(EVP_CIPHER_CTX *c, ASN1_TYPE *type) + { + unsigned iv_len; + + iv_len = EVP_CIPHER_CTX_iv_length(c); + return ASN1_TYPE_set_octetstring(type, c->oiv, iv_len); + } + +/* Return an algorithm identifier for a PKCS#5 v2.0 PBE algorithm: + * yes I know this is horrible! + * + * Extended version to allow application supplied PRF NID and IV. */ + +X509_ALGOR *PKCS5_pbe2_set_iv(const EVP_CIPHER *cipher, int iter, + unsigned char *salt, int saltlen, + unsigned char *aiv, int prf_nid) +{ + X509_ALGOR *scheme = NULL, *kalg = NULL, *ret = NULL; + int alg_nid, keylen; + EVP_CIPHER_CTX ctx; + unsigned char iv[EVP_MAX_IV_LENGTH]; + PBE2PARAM *pbe2 = NULL; + const ASN1_OBJECT *obj; + + alg_nid = EVP_CIPHER_nid(cipher); + if(alg_nid == NID_undef) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER); + goto err; + } + obj = OBJ_nid2obj(alg_nid); + + if(!(pbe2 = PBE2PARAM_new())) goto merr; + + /* Setup the AlgorithmIdentifier for the encryption scheme */ + scheme = pbe2->encryption; + + scheme->algorithm = (ASN1_OBJECT*) obj; + if(!(scheme->parameter = ASN1_TYPE_new())) goto merr; + + /* Create random IV */ + if (EVP_CIPHER_iv_length(cipher)) + { + if (aiv) + memcpy(iv, aiv, EVP_CIPHER_iv_length(cipher)); + else if (!RAND_bytes(iv, EVP_CIPHER_iv_length(cipher))) + goto err; + } + + EVP_CIPHER_CTX_init(&ctx); + + /* Dummy cipherinit to just setup the IV, and PRF */ + if (!EVP_CipherInit_ex(&ctx, cipher, NULL, NULL, iv, 0)) + goto err; + if(param_to_asn1(&ctx, scheme->parameter) < 0) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ERROR_SETTING_CIPHER_PARAMS); + EVP_CIPHER_CTX_cleanup(&ctx); + goto err; + } + /* If prf NID unspecified see if cipher has a preference. + * An error is OK here: just means use default PRF. + */ + if ((prf_nid == -1) && + EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_PBE_PRF_NID, 0, &prf_nid) <= 0) + { + ERR_clear_error(); + prf_nid = NID_hmacWithSHA1; + } + EVP_CIPHER_CTX_cleanup(&ctx); + + /* If its RC2 then we'd better setup the key length */ + + if(alg_nid == NID_rc2_cbc) + keylen = EVP_CIPHER_key_length(cipher); + else + keylen = -1; + + /* Setup keyfunc */ + + X509_ALGOR_free(pbe2->keyfunc); + + pbe2->keyfunc = PKCS5_pbkdf2_set(iter, salt, saltlen, prf_nid, keylen); + + if (!pbe2->keyfunc) + goto merr; + + /* Now set up top level AlgorithmIdentifier */ + + if(!(ret = X509_ALGOR_new())) goto merr; + if(!(ret->parameter = ASN1_TYPE_new())) goto merr; + + ret->algorithm = (ASN1_OBJECT*) OBJ_nid2obj(NID_pbes2); + + /* Encode PBE2PARAM into parameter */ + + if(!ASN1_item_pack(pbe2, ASN1_ITEM_rptr(PBE2PARAM), + &ret->parameter->value.sequence)) goto merr; + ret->parameter->type = V_ASN1_SEQUENCE; + + PBE2PARAM_free(pbe2); + pbe2 = NULL; + + return ret; + + merr: + OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + + err: + PBE2PARAM_free(pbe2); + /* Note 'scheme' is freed as part of pbe2 */ + X509_ALGOR_free(kalg); + X509_ALGOR_free(ret); + + return NULL; + +} + +X509_ALGOR *PKCS5_pbe2_set(const EVP_CIPHER *cipher, int iter, + unsigned char *salt, int saltlen) + { + return PKCS5_pbe2_set_iv(cipher, iter, salt, saltlen, NULL, -1); + } + +X509_ALGOR *PKCS5_pbkdf2_set(int iter, unsigned char *salt, int saltlen, + int prf_nid, int keylen) + { + X509_ALGOR *keyfunc = NULL; + PBKDF2PARAM *kdf = NULL; + ASN1_OCTET_STRING *osalt = NULL; + + if(!(kdf = PBKDF2PARAM_new())) + goto merr; + if(!(osalt = M_ASN1_OCTET_STRING_new())) + goto merr; + + kdf->salt->value.octet_string = osalt; + kdf->salt->type = V_ASN1_OCTET_STRING; + + if (!saltlen) + saltlen = PKCS5_SALT_LEN; + if (!(osalt->data = OPENSSL_malloc (saltlen))) + goto merr; + + osalt->length = saltlen; + + if (salt) + memcpy (osalt->data, salt, saltlen); + else if (!RAND_bytes(osalt->data, saltlen)) + goto merr; + + if(iter <= 0) + iter = PKCS5_DEFAULT_ITERATIONS; + + if(!ASN1_INTEGER_set(kdf->iter, iter)) + goto merr; + + /* If have a key len set it up */ + + if(keylen > 0) + { + if(!(kdf->keylength = M_ASN1_INTEGER_new())) + goto merr; + if(!ASN1_INTEGER_set (kdf->keylength, keylen)) + goto merr; + } + + /* prf can stay NULL if we are using hmacWithSHA1 */ + if (prf_nid > 0 && prf_nid != NID_hmacWithSHA1) + { + kdf->prf = X509_ALGOR_new(); + if (!kdf->prf) + goto merr; + X509_ALGOR_set0(kdf->prf, OBJ_nid2obj(prf_nid), + V_ASN1_NULL, NULL); + } + + /* Finally setup the keyfunc structure */ + + keyfunc = X509_ALGOR_new(); + if (!keyfunc) + goto merr; + + keyfunc->algorithm = (ASN1_OBJECT*) OBJ_nid2obj(NID_id_pbkdf2); + + /* Encode PBKDF2PARAM into parameter of pbe2 */ + + if(!(keyfunc->parameter = ASN1_TYPE_new())) + goto merr; + + if(!ASN1_item_pack(kdf, ASN1_ITEM_rptr(PBKDF2PARAM), + &keyfunc->parameter->value.sequence)) + goto merr; + keyfunc->parameter->type = V_ASN1_SEQUENCE; + + PBKDF2PARAM_free(kdf); + return keyfunc; + + merr: + OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + PBKDF2PARAM_free(kdf); + X509_ALGOR_free(keyfunc); + return NULL; + } + diff --git a/TMessagesProj/jni/boringssl/crypto/pkcs8/p8_pkey.c b/TMessagesProj/jni/boringssl/crypto/pkcs8/p8_pkey.c new file mode 100644 index 00000000..bd9d30ca --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/pkcs8/p8_pkey.c @@ -0,0 +1,85 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + + +#include + +#include +#include +#include + +/* Minor tweak to operation: zero private key data */ +static int pkey_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, + void *exarg) { + /* Since the structure must still be valid use ASN1_OP_FREE_PRE */ + if (operation == ASN1_OP_FREE_PRE) { + PKCS8_PRIV_KEY_INFO *key = (PKCS8_PRIV_KEY_INFO *)*pval; + if (key->pkey && + key->pkey->value.octet_string) { + OPENSSL_cleanse(key->pkey->value.octet_string->data, + key->pkey->value.octet_string->length); + } + } + return 1; +} + +ASN1_SEQUENCE_cb(PKCS8_PRIV_KEY_INFO, pkey_cb) = { + ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, version, ASN1_INTEGER), + ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, pkeyalg, X509_ALGOR), + ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, pkey, ASN1_ANY), + ASN1_IMP_SET_OF_OPT(PKCS8_PRIV_KEY_INFO, attributes, X509_ATTRIBUTE, 0) +} ASN1_SEQUENCE_END_cb(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO); + +IMPLEMENT_ASN1_FUNCTIONS(PKCS8_PRIV_KEY_INFO); diff --git a/TMessagesProj/jni/boringssl/crypto/pkcs8/pkcs8.c b/TMessagesProj/jni/boringssl/crypto/pkcs8/pkcs8.c new file mode 100644 index 00000000..8ac203df --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/pkcs8/pkcs8.c @@ -0,0 +1,1141 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../bytestring/internal.h" +#include "../evp/internal.h" + + +#define PKCS12_KEY_ID 1 +#define PKCS12_IV_ID 2 +#define PKCS12_MAC_ID 3 + +static int ascii_to_ucs2(const char *ascii, size_t ascii_len, + uint8_t **out, size_t *out_len) { + uint8_t *unitmp; + size_t ulen, i; + + ulen = ascii_len * 2 + 2; + if (ulen < ascii_len) { + return 0; + } + unitmp = OPENSSL_malloc(ulen); + if (unitmp == NULL) { + return 0; + } + for (i = 0; i < ulen - 2; i += 2) { + unitmp[i] = 0; + unitmp[i + 1] = ascii[i >> 1]; + } + + /* Make result double null terminated */ + unitmp[ulen - 2] = 0; + unitmp[ulen - 1] = 0; + *out_len = ulen; + *out = unitmp; + return 1; +} + +static int pkcs12_key_gen_raw(const uint8_t *pass_raw, size_t pass_raw_len, + const uint8_t *salt, size_t salt_len, + int id, int iterations, + size_t out_len, uint8_t *out, + const EVP_MD *md_type) { + uint8_t *B, *D, *I, *p, *Ai; + int Slen, Plen, Ilen, Ijlen; + int i, j, v; + size_t u; + int ret = 0; + BIGNUM *Ij, *Bpl1; /* These hold Ij and B + 1 */ + EVP_MD_CTX ctx; + + EVP_MD_CTX_init(&ctx); + v = EVP_MD_block_size(md_type); + u = EVP_MD_size(md_type); + D = OPENSSL_malloc(v); + Ai = OPENSSL_malloc(u); + B = OPENSSL_malloc(v + 1); + Slen = v * ((salt_len + v - 1) / v); + if (pass_raw_len) { + Plen = v * ((pass_raw_len + v - 1) / v); + } else { + Plen = 0; + } + Ilen = Slen + Plen; + I = OPENSSL_malloc(Ilen); + Ij = BN_new(); + Bpl1 = BN_new(); + if (!D || !Ai || !B || !I || !Ij || !Bpl1) { + goto err; + } + for (i = 0; i < v; i++) { + D[i] = id; + } + p = I; + for (i = 0; i < Slen; i++) { + *p++ = salt[i % salt_len]; + } + for (i = 0; i < Plen; i++) { + *p++ = pass_raw[i % pass_raw_len]; + } + for (;;) { + if (!EVP_DigestInit_ex(&ctx, md_type, NULL) || + !EVP_DigestUpdate(&ctx, D, v) || + !EVP_DigestUpdate(&ctx, I, Ilen) || + !EVP_DigestFinal_ex(&ctx, Ai, NULL)) { + goto err; + } + for (j = 1; j < iterations; j++) { + if (!EVP_DigestInit_ex(&ctx, md_type, NULL) || + !EVP_DigestUpdate(&ctx, Ai, u) || + !EVP_DigestFinal_ex(&ctx, Ai, NULL)) { + goto err; + } + } + memcpy(out, Ai, out_len < u ? out_len : u); + if (u >= out_len) { + ret = 1; + goto end; + } + out_len -= u; + out += u; + for (j = 0; j < v; j++) { + B[j] = Ai[j % u]; + } + /* Work out B + 1 first then can use B as tmp space */ + if (!BN_bin2bn(B, v, Bpl1) || + !BN_add_word(Bpl1, 1)) { + goto err; + } + for (j = 0; j < Ilen; j += v) { + if (!BN_bin2bn(I + j, v, Ij) || + !BN_add(Ij, Ij, Bpl1) || + !BN_bn2bin(Ij, B)) { + goto err; + } + Ijlen = BN_num_bytes(Ij); + /* If more than 2^(v*8) - 1 cut off MSB */ + if (Ijlen > v) { + if (!BN_bn2bin(Ij, B)) { + goto err; + } + memcpy(I + j, B + 1, v); + /* If less than v bytes pad with zeroes */ + } else if (Ijlen < v) { + memset(I + j, 0, v - Ijlen); + if (!BN_bn2bin(Ij, I + j + v - Ijlen)) { + goto err; + } + } else if (!BN_bn2bin(Ij, I + j)) { + goto err; + } + } + } + +err: + OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + +end: + OPENSSL_free(Ai); + OPENSSL_free(B); + OPENSSL_free(D); + OPENSSL_free(I); + BN_free(Ij); + BN_free(Bpl1); + EVP_MD_CTX_cleanup(&ctx); + + return ret; +} + +static int pkcs12_pbe_keyivgen(EVP_CIPHER_CTX *ctx, const uint8_t *pass_raw, + size_t pass_raw_len, ASN1_TYPE *param, + const EVP_CIPHER *cipher, const EVP_MD *md, + int is_encrypt) { + PBEPARAM *pbe; + int salt_len, iterations, ret; + uint8_t *salt; + const uint8_t *pbuf; + uint8_t key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH]; + + /* Extract useful info from parameter */ + if (param == NULL || param->type != V_ASN1_SEQUENCE || + param->value.sequence == NULL) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); + return 0; + } + + pbuf = param->value.sequence->data; + pbe = d2i_PBEPARAM(NULL, &pbuf, param->value.sequence->length); + if (pbe == NULL) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); + return 0; + } + + if (!pbe->iter) { + iterations = 1; + } else { + iterations = ASN1_INTEGER_get(pbe->iter); + } + salt = pbe->salt->data; + salt_len = pbe->salt->length; + if (!pkcs12_key_gen_raw(pass_raw, pass_raw_len, salt, salt_len, PKCS12_KEY_ID, + iterations, EVP_CIPHER_key_length(cipher), key, md)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_KEY_GEN_ERROR); + PBEPARAM_free(pbe); + return 0; + } + if (!pkcs12_key_gen_raw(pass_raw, pass_raw_len, salt, salt_len, PKCS12_IV_ID, + iterations, EVP_CIPHER_iv_length(cipher), iv, md)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_KEY_GEN_ERROR); + PBEPARAM_free(pbe); + return 0; + } + PBEPARAM_free(pbe); + ret = EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, is_encrypt); + OPENSSL_cleanse(key, EVP_MAX_KEY_LENGTH); + OPENSSL_cleanse(iv, EVP_MAX_IV_LENGTH); + return ret; +} + +typedef int (*keygen_func)(EVP_CIPHER_CTX *ctx, const uint8_t *pass_raw, + size_t pass_raw_len, ASN1_TYPE *param, + const EVP_CIPHER *cipher, const EVP_MD *md, + int is_encrypt); + +struct pbe_suite { + int pbe_nid; + const EVP_CIPHER* (*cipher_func)(void); + const EVP_MD* (*md_func)(void); + keygen_func keygen; +}; + +static const struct pbe_suite kBuiltinPBE[] = { + { + NID_pbe_WithSHA1And40BitRC2_CBC, EVP_rc2_40_cbc, EVP_sha1, pkcs12_pbe_keyivgen, + }, + { + NID_pbe_WithSHA1And128BitRC4, EVP_rc4, EVP_sha1, pkcs12_pbe_keyivgen, + }, + { + NID_pbe_WithSHA1And3_Key_TripleDES_CBC, EVP_des_ede3_cbc, EVP_sha1, + pkcs12_pbe_keyivgen, + }, +}; + +static int pbe_cipher_init(ASN1_OBJECT *pbe_obj, + const uint8_t *pass_raw, size_t pass_raw_len, + ASN1_TYPE *param, + EVP_CIPHER_CTX *ctx, int is_encrypt) { + const EVP_CIPHER *cipher; + const EVP_MD *md; + unsigned i; + + const struct pbe_suite *suite = NULL; + const int pbe_nid = OBJ_obj2nid(pbe_obj); + + for (i = 0; i < sizeof(kBuiltinPBE) / sizeof(struct pbe_suite); i++) { + if (kBuiltinPBE[i].pbe_nid == pbe_nid) { + suite = &kBuiltinPBE[i]; + break; + } + } + + if (suite == NULL) { + char obj_str[80]; + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNKNOWN_ALGORITHM); + if (!pbe_obj) { + strncpy(obj_str, "NULL", sizeof(obj_str)); + } else { + i2t_ASN1_OBJECT(obj_str, sizeof(obj_str), pbe_obj); + } + ERR_add_error_data(2, "TYPE=", obj_str); + return 0; + } + + if (suite->cipher_func == NULL) { + cipher = NULL; + } else { + cipher = suite->cipher_func(); + if (!cipher) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNKNOWN_CIPHER); + return 0; + } + } + + if (suite->md_func == NULL) { + md = NULL; + } else { + md = suite->md_func(); + if (!md) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNKNOWN_DIGEST); + return 0; + } + } + + if (!suite->keygen(ctx, pass_raw, pass_raw_len, param, cipher, md, + is_encrypt)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_KEYGEN_FAILURE); + return 0; + } + + return 1; +} + +static int pbe_crypt(const X509_ALGOR *algor, + const uint8_t *pass_raw, size_t pass_raw_len, + const uint8_t *in, size_t in_len, + uint8_t **out, size_t *out_len, + int is_encrypt) { + uint8_t *buf; + int n, ret = 0; + EVP_CIPHER_CTX ctx; + unsigned block_size; + + EVP_CIPHER_CTX_init(&ctx); + + if (!pbe_cipher_init(algor->algorithm, pass_raw, pass_raw_len, + algor->parameter, &ctx, is_encrypt)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNKNOWN_CIPHER_ALGORITHM); + return 0; + } + block_size = EVP_CIPHER_CTX_block_size(&ctx); + + if (in_len + block_size < in_len) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_TOO_LONG); + goto err; + } + + buf = OPENSSL_malloc(in_len + block_size); + if (buf == NULL) { + OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!EVP_CipherUpdate(&ctx, buf, &n, in, in_len)) { + OPENSSL_free(buf); + OPENSSL_PUT_ERROR(PKCS8, ERR_R_EVP_LIB); + goto err; + } + *out_len = n; + + if (!EVP_CipherFinal_ex(&ctx, buf + n, &n)) { + OPENSSL_free(buf); + OPENSSL_PUT_ERROR(PKCS8, ERR_R_EVP_LIB); + goto err; + } + *out_len += n; + *out = buf; + ret = 1; + +err: + EVP_CIPHER_CTX_cleanup(&ctx); + return ret; +} + +static void *pkcs12_item_decrypt_d2i(X509_ALGOR *algor, const ASN1_ITEM *it, + const uint8_t *pass_raw, + size_t pass_raw_len, + ASN1_OCTET_STRING *oct) { + uint8_t *out; + const uint8_t *p; + void *ret; + size_t out_len; + + if (!pbe_crypt(algor, pass_raw, pass_raw_len, oct->data, oct->length, + &out, &out_len, 0 /* decrypt */)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_CRYPT_ERROR); + return NULL; + } + p = out; + ret = ASN1_item_d2i(NULL, &p, out_len, it); + OPENSSL_cleanse(out, out_len); + if (!ret) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); + } + OPENSSL_free(out); + return ret; +} + +PKCS8_PRIV_KEY_INFO *PKCS8_decrypt(X509_SIG *pkcs8, const char *pass, + int pass_len) { + uint8_t *pass_raw = NULL; + size_t pass_raw_len = 0; + PKCS8_PRIV_KEY_INFO *ret; + + if (pass) { + if (pass_len == -1) { + pass_len = strlen(pass); + } + if (!ascii_to_ucs2(pass, pass_len, &pass_raw, &pass_raw_len)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); + return NULL; + } + } + + ret = PKCS8_decrypt_pbe(pkcs8, pass_raw, pass_raw_len); + + if (pass_raw) { + OPENSSL_cleanse(pass_raw, pass_raw_len); + OPENSSL_free(pass_raw); + } + return ret; +} + +PKCS8_PRIV_KEY_INFO *PKCS8_decrypt_pbe(X509_SIG *pkcs8, const uint8_t *pass_raw, + size_t pass_raw_len) { + return pkcs12_item_decrypt_d2i(pkcs8->algor, + ASN1_ITEM_rptr(PKCS8_PRIV_KEY_INFO), pass_raw, + pass_raw_len, pkcs8->digest); +} + +static ASN1_OCTET_STRING *pkcs12_item_i2d_encrypt(X509_ALGOR *algor, + const ASN1_ITEM *it, + const uint8_t *pass_raw, + size_t pass_raw_len, void *obj) { + ASN1_OCTET_STRING *oct; + uint8_t *in = NULL; + int in_len; + size_t crypt_len; + + oct = M_ASN1_OCTET_STRING_new(); + if (oct == NULL) { + OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + return NULL; + } + in_len = ASN1_item_i2d(obj, &in, it); + if (!in) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ENCODE_ERROR); + return NULL; + } + if (!pbe_crypt(algor, pass_raw, pass_raw_len, in, in_len, &oct->data, &crypt_len, + 1 /* encrypt */)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ENCRYPT_ERROR); + OPENSSL_free(in); + return NULL; + } + oct->length = crypt_len; + OPENSSL_cleanse(in, in_len); + OPENSSL_free(in); + return oct; +} + +X509_SIG *PKCS8_encrypt(int pbe_nid, const EVP_CIPHER *cipher, const char *pass, + int pass_len, uint8_t *salt, size_t salt_len, + int iterations, PKCS8_PRIV_KEY_INFO *p8inf) { + uint8_t *pass_raw = NULL; + size_t pass_raw_len = 0; + X509_SIG *ret; + + if (pass) { + if (pass_len == -1) { + pass_len = strlen(pass); + } + if (!ascii_to_ucs2(pass, pass_len, &pass_raw, &pass_raw_len)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); + return NULL; + } + } + + ret = PKCS8_encrypt_pbe(pbe_nid, pass_raw, pass_raw_len, + salt, salt_len, iterations, p8inf); + + if (pass_raw) { + OPENSSL_cleanse(pass_raw, pass_raw_len); + OPENSSL_free(pass_raw); + } + return ret; +} + +X509_SIG *PKCS8_encrypt_pbe(int pbe_nid, + const uint8_t *pass_raw, size_t pass_raw_len, + uint8_t *salt, size_t salt_len, + int iterations, PKCS8_PRIV_KEY_INFO *p8inf) { + X509_SIG *pkcs8 = NULL; + X509_ALGOR *pbe; + + pkcs8 = X509_SIG_new(); + if (pkcs8 == NULL) { + OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + goto err; + } + + pbe = PKCS5_pbe_set(pbe_nid, iterations, salt, salt_len); + if (!pbe) { + OPENSSL_PUT_ERROR(PKCS8, ERR_R_ASN1_LIB); + goto err; + } + + X509_ALGOR_free(pkcs8->algor); + pkcs8->algor = pbe; + M_ASN1_OCTET_STRING_free(pkcs8->digest); + pkcs8->digest = pkcs12_item_i2d_encrypt( + pbe, ASN1_ITEM_rptr(PKCS8_PRIV_KEY_INFO), pass_raw, pass_raw_len, p8inf); + if (!pkcs8->digest) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ENCRYPT_ERROR); + goto err; + } + + return pkcs8; + +err: + X509_SIG_free(pkcs8); + return NULL; +} + +EVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *p8) { + EVP_PKEY *pkey = NULL; + ASN1_OBJECT *algoid; + char obj_tmp[80]; + + if (!PKCS8_pkey_get0(&algoid, NULL, NULL, NULL, p8)) { + return NULL; + } + + pkey = EVP_PKEY_new(); + if (pkey == NULL) { + OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + return NULL; + } + + if (!EVP_PKEY_set_type(pkey, OBJ_obj2nid(algoid))) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM); + i2t_ASN1_OBJECT(obj_tmp, 80, algoid); + ERR_add_error_data(2, "TYPE=", obj_tmp); + goto error; + } + + if (pkey->ameth->priv_decode) { + if (!pkey->ameth->priv_decode(pkey, p8)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_PRIVATE_KEY_DECODE_ERROR); + goto error; + } + } else { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_METHOD_NOT_SUPPORTED); + goto error; + } + + return pkey; + +error: + EVP_PKEY_free(pkey); + return NULL; +} + +PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(EVP_PKEY *pkey) { + PKCS8_PRIV_KEY_INFO *p8; + + p8 = PKCS8_PRIV_KEY_INFO_new(); + if (p8 == NULL) { + OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + return NULL; + } + p8->broken = PKCS8_OK; + + if (pkey->ameth) { + if (pkey->ameth->priv_encode) { + if (!pkey->ameth->priv_encode(p8, pkey)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_PRIVATE_KEY_ENCODE_ERROR); + goto error; + } + } else { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_METHOD_NOT_SUPPORTED); + goto error; + } + } else { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM); + goto error; + } + return p8; + +error: + PKCS8_PRIV_KEY_INFO_free(p8); + return NULL; +} + +struct pkcs12_context { + EVP_PKEY **out_key; + STACK_OF(X509) *out_certs; + uint8_t *password; + size_t password_len; +}; + +static int PKCS12_handle_content_info(CBS *content_info, unsigned depth, + struct pkcs12_context *ctx); + +/* PKCS12_handle_content_infos parses a series of PKCS#7 ContentInfos in a + * SEQUENCE. */ +static int PKCS12_handle_content_infos(CBS *content_infos, + unsigned depth, + struct pkcs12_context *ctx) { + uint8_t *der_bytes = NULL; + size_t der_len; + CBS in; + int ret = 0; + + /* Generally we only expect depths 0 (the top level, with a + * pkcs7-encryptedData and a pkcs7-data) and depth 1 (the various PKCS#12 + * bags). */ + if (depth > 3) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_PKCS12_TOO_DEEPLY_NESTED); + return 0; + } + + /* Although a BER->DER conversion is done at the beginning of |PKCS12_parse|, + * the ASN.1 data gets wrapped in OCTETSTRINGs and/or encrypted and the + * conversion cannot see through those wrappings. So each time we step + * through one we need to convert to DER again. */ + if (!CBS_asn1_ber_to_der(content_infos, &der_bytes, &der_len)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + return 0; + } + + if (der_bytes != NULL) { + CBS_init(&in, der_bytes, der_len); + } else { + CBS_init(&in, CBS_data(content_infos), CBS_len(content_infos)); + } + + if (!CBS_get_asn1(&in, &in, CBS_ASN1_SEQUENCE)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + + while (CBS_len(&in) > 0) { + CBS content_info; + if (!CBS_get_asn1(&in, &content_info, CBS_ASN1_SEQUENCE)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + + if (!PKCS12_handle_content_info(&content_info, depth + 1, ctx)) { + goto err; + } + } + + /* NSS includes additional data after the SEQUENCE, but it's an (unwrapped) + * copy of the same encrypted private key (with the same IV and + * ciphertext)! */ + + ret = 1; + +err: + OPENSSL_free(der_bytes); + return ret; +} + +/* PKCS12_handle_content_info parses a single PKCS#7 ContentInfo element in a + * PKCS#12 structure. */ +static int PKCS12_handle_content_info(CBS *content_info, unsigned depth, + struct pkcs12_context *ctx) { + CBS content_type, wrapped_contents, contents, content_infos; + int nid, ret = 0; + + if (!CBS_get_asn1(content_info, &content_type, CBS_ASN1_OBJECT) || + !CBS_get_asn1(content_info, &wrapped_contents, + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + + nid = OBJ_cbs2nid(&content_type); + if (nid == NID_pkcs7_encrypted) { + /* See https://tools.ietf.org/html/rfc2315#section-13. + * + * PKCS#7 encrypted data inside a PKCS#12 structure is generally an + * encrypted certificate bag and it's generally encrypted with 40-bit + * RC2-CBC. */ + CBS version_bytes, eci, contents_type, ai, encrypted_contents; + X509_ALGOR *algor = NULL; + const uint8_t *inp; + uint8_t *out; + size_t out_len; + + if (!CBS_get_asn1(&wrapped_contents, &contents, CBS_ASN1_SEQUENCE) || + !CBS_get_asn1(&contents, &version_bytes, CBS_ASN1_INTEGER) || + /* EncryptedContentInfo, see + * https://tools.ietf.org/html/rfc2315#section-10.1 */ + !CBS_get_asn1(&contents, &eci, CBS_ASN1_SEQUENCE) || + !CBS_get_asn1(&eci, &contents_type, CBS_ASN1_OBJECT) || + /* AlgorithmIdentifier, see + * https://tools.ietf.org/html/rfc5280#section-4.1.1.2 */ + !CBS_get_asn1_element(&eci, &ai, CBS_ASN1_SEQUENCE) || + !CBS_get_asn1(&eci, &encrypted_contents, + CBS_ASN1_CONTEXT_SPECIFIC | 0)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + + if (OBJ_cbs2nid(&contents_type) != NID_pkcs7_data) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + + inp = CBS_data(&ai); + algor = d2i_X509_ALGOR(NULL, &inp, CBS_len(&ai)); + if (algor == NULL) { + goto err; + } + if (inp != CBS_data(&ai) + CBS_len(&ai)) { + X509_ALGOR_free(algor); + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + + if (!pbe_crypt(algor, ctx->password, ctx->password_len, + CBS_data(&encrypted_contents), CBS_len(&encrypted_contents), + &out, &out_len, 0 /* decrypt */)) { + X509_ALGOR_free(algor); + goto err; + } + X509_ALGOR_free(algor); + + CBS_init(&content_infos, out, out_len); + ret = PKCS12_handle_content_infos(&content_infos, depth + 1, ctx); + OPENSSL_free(out); + } else if (nid == NID_pkcs7_data) { + CBS octet_string_contents; + + if (!CBS_get_asn1(&wrapped_contents, &octet_string_contents, + CBS_ASN1_OCTETSTRING)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + + ret = PKCS12_handle_content_infos(&octet_string_contents, depth + 1, ctx); + } else if (nid == NID_pkcs8ShroudedKeyBag) { + /* See ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1.pdf, section + * 4.2.2. */ + const uint8_t *inp = CBS_data(&wrapped_contents); + PKCS8_PRIV_KEY_INFO *pki = NULL; + X509_SIG *encrypted = NULL; + + if (*ctx->out_key) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_MULTIPLE_PRIVATE_KEYS_IN_PKCS12); + goto err; + } + + /* encrypted isn't actually an X.509 signature, but it has the same + * structure as one and so |X509_SIG| is reused to store it. */ + encrypted = d2i_X509_SIG(NULL, &inp, CBS_len(&wrapped_contents)); + if (encrypted == NULL) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + if (inp != CBS_data(&wrapped_contents) + CBS_len(&wrapped_contents)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + X509_SIG_free(encrypted); + goto err; + } + + pki = PKCS8_decrypt_pbe(encrypted, ctx->password, ctx->password_len); + X509_SIG_free(encrypted); + if (pki == NULL) { + goto err; + } + + *ctx->out_key = EVP_PKCS82PKEY(pki); + PKCS8_PRIV_KEY_INFO_free(pki); + + if (ctx->out_key == NULL) { + goto err; + } + ret = 1; + } else if (nid == NID_certBag) { + CBS cert_bag, cert_type, wrapped_cert, cert; + + if (!CBS_get_asn1(&wrapped_contents, &cert_bag, CBS_ASN1_SEQUENCE) || + !CBS_get_asn1(&cert_bag, &cert_type, CBS_ASN1_OBJECT) || + !CBS_get_asn1(&cert_bag, &wrapped_cert, + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) || + !CBS_get_asn1(&wrapped_cert, &cert, CBS_ASN1_OCTETSTRING)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + + if (OBJ_cbs2nid(&cert_type) == NID_x509Certificate) { + const uint8_t *inp = CBS_data(&cert); + X509 *x509 = d2i_X509(NULL, &inp, CBS_len(&cert)); + if (!x509) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + if (inp != CBS_data(&cert) + CBS_len(&cert)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + X509_free(x509); + goto err; + } + + if (0 == sk_X509_push(ctx->out_certs, x509)) { + X509_free(x509); + goto err; + } + } + ret = 1; + } else { + /* Unknown element type - ignore it. */ + ret = 1; + } + +err: + return ret; +} + +int PKCS12_get_key_and_certs(EVP_PKEY **out_key, STACK_OF(X509) *out_certs, + CBS *ber_in, const char *password) { + uint8_t *der_bytes = NULL; + size_t der_len; + CBS in, pfx, mac_data, authsafe, content_type, wrapped_authsafes, authsafes; + uint64_t version; + int ret = 0; + struct pkcs12_context ctx; + const size_t original_out_certs_len = sk_X509_num(out_certs); + + /* The input may be in BER format. */ + if (!CBS_asn1_ber_to_der(ber_in, &der_bytes, &der_len)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + return 0; + } + if (der_bytes != NULL) { + CBS_init(&in, der_bytes, der_len); + } else { + CBS_init(&in, CBS_data(ber_in), CBS_len(ber_in)); + } + + *out_key = NULL; + memset(&ctx, 0, sizeof(ctx)); + + /* See ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1.pdf, section + * four. */ + if (!CBS_get_asn1(&in, &pfx, CBS_ASN1_SEQUENCE) || + CBS_len(&in) != 0 || + !CBS_get_asn1_uint64(&pfx, &version)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + + if (version < 3) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_VERSION); + goto err; + } + + if (!CBS_get_asn1(&pfx, &authsafe, CBS_ASN1_SEQUENCE)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + + if (CBS_len(&pfx) == 0) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_MISSING_MAC); + goto err; + } + + if (!CBS_get_asn1(&pfx, &mac_data, CBS_ASN1_SEQUENCE)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + + /* authsafe is a PKCS#7 ContentInfo. See + * https://tools.ietf.org/html/rfc2315#section-7. */ + if (!CBS_get_asn1(&authsafe, &content_type, CBS_ASN1_OBJECT) || + !CBS_get_asn1(&authsafe, &wrapped_authsafes, + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + + /* The content type can either be |NID_pkcs7_data| or |NID_pkcs7_signed|. The + * latter indicates that it's signed by a public key, which isn't + * supported. */ + if (OBJ_cbs2nid(&content_type) != NID_pkcs7_data) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_PKCS12_PUBLIC_KEY_INTEGRITY_NOT_SUPPORTED); + goto err; + } + + if (!CBS_get_asn1(&wrapped_authsafes, &authsafes, CBS_ASN1_OCTETSTRING)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + + ctx.out_key = out_key; + ctx.out_certs = out_certs; + if (!ascii_to_ucs2(password, strlen(password), &ctx.password, + &ctx.password_len)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); + goto err; + } + + /* Verify the MAC. */ + { + CBS mac, hash_type_seq, hash_oid, salt, expected_mac; + uint64_t iterations; + int hash_nid; + const EVP_MD *md; + uint8_t hmac_key[EVP_MAX_MD_SIZE]; + uint8_t hmac[EVP_MAX_MD_SIZE]; + unsigned hmac_len; + + if (!CBS_get_asn1(&mac_data, &mac, CBS_ASN1_SEQUENCE) || + !CBS_get_asn1(&mac, &hash_type_seq, CBS_ASN1_SEQUENCE) || + !CBS_get_asn1(&hash_type_seq, &hash_oid, CBS_ASN1_OBJECT) || + !CBS_get_asn1(&mac, &expected_mac, CBS_ASN1_OCTETSTRING) || + !CBS_get_asn1(&mac_data, &salt, CBS_ASN1_OCTETSTRING)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + + /* The iteration count is optional and the default is one. */ + iterations = 1; + if (CBS_len(&mac_data) > 0) { + if (!CBS_get_asn1_uint64(&mac_data, &iterations) || + iterations > INT_MAX) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + } + + hash_nid = OBJ_cbs2nid(&hash_oid); + if (hash_nid == NID_undef || + (md = EVP_get_digestbynid(hash_nid)) == NULL) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNKNOWN_HASH); + goto err; + } + + if (!pkcs12_key_gen_raw(ctx.password, ctx.password_len, CBS_data(&salt), + CBS_len(&salt), PKCS12_MAC_ID, iterations, + EVP_MD_size(md), hmac_key, md)) { + goto err; + } + + if (NULL == HMAC(md, hmac_key, EVP_MD_size(md), CBS_data(&authsafes), + CBS_len(&authsafes), hmac, &hmac_len)) { + goto err; + } + + if (!CBS_mem_equal(&expected_mac, hmac, hmac_len)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_INCORRECT_PASSWORD); + goto err; + } + } + + /* authsafes contains a series of PKCS#7 ContentInfos. */ + if (!PKCS12_handle_content_infos(&authsafes, 0, &ctx)) { + goto err; + } + + ret = 1; + +err: + OPENSSL_free(ctx.password); + OPENSSL_free(der_bytes); + if (!ret) { + EVP_PKEY_free(*out_key); + *out_key = NULL; + while (sk_X509_num(out_certs) > original_out_certs_len) { + X509 *x509 = sk_X509_pop(out_certs); + X509_free(x509); + } + } + + return ret; +} + +void PKCS12_PBE_add(void) {} + +struct pkcs12_st { + uint8_t *ber_bytes; + size_t ber_len; +}; + +PKCS12* d2i_PKCS12(PKCS12 **out_p12, const uint8_t **ber_bytes, size_t ber_len) { + PKCS12 *p12; + + /* out_p12 must be NULL because we don't export the PKCS12 structure. */ + assert(out_p12 == NULL); + + p12 = OPENSSL_malloc(sizeof(PKCS12)); + if (!p12) { + return NULL; + } + + p12->ber_bytes = OPENSSL_malloc(ber_len); + if (!p12->ber_bytes) { + OPENSSL_free(p12); + return NULL; + } + + memcpy(p12->ber_bytes, *ber_bytes, ber_len); + p12->ber_len = ber_len; + *ber_bytes += ber_len; + + return p12; +} + +PKCS12* d2i_PKCS12_bio(BIO *bio, PKCS12 **out_p12) { + size_t used = 0; + BUF_MEM *buf; + const uint8_t *dummy; + static const size_t kMaxSize = 256 * 1024; + PKCS12 *ret = NULL; + + buf = BUF_MEM_new(); + if (buf == NULL) { + return NULL; + } + if (BUF_MEM_grow(buf, 8192) == 0) { + goto out; + } + + for (;;) { + int n = BIO_read(bio, &buf->data[used], buf->length - used); + if (n < 0) { + goto out; + } + + if (n == 0) { + break; + } + used += n; + + if (used < buf->length) { + continue; + } + + if (buf->length > kMaxSize || + BUF_MEM_grow(buf, buf->length * 2) == 0) { + goto out; + } + } + + dummy = (uint8_t*) buf->data; + ret = d2i_PKCS12(out_p12, &dummy, used); + +out: + BUF_MEM_free(buf); + return ret; +} + +PKCS12* d2i_PKCS12_fp(FILE *fp, PKCS12 **out_p12) { + BIO *bio; + PKCS12 *ret; + + bio = BIO_new_fp(fp, 0 /* don't take ownership */); + if (!bio) { + return NULL; + } + + ret = d2i_PKCS12_bio(bio, out_p12); + BIO_free(bio); + return ret; +} + +int PKCS12_parse(const PKCS12 *p12, const char *password, EVP_PKEY **out_pkey, + X509 **out_cert, STACK_OF(X509) **out_ca_certs) { + CBS ber_bytes; + STACK_OF(X509) *ca_certs = NULL; + char ca_certs_alloced = 0; + + if (out_ca_certs != NULL && *out_ca_certs != NULL) { + ca_certs = *out_ca_certs; + } + + if (!ca_certs) { + ca_certs = sk_X509_new_null(); + if (ca_certs == NULL) { + OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + return 0; + } + ca_certs_alloced = 1; + } + + CBS_init(&ber_bytes, p12->ber_bytes, p12->ber_len); + if (!PKCS12_get_key_and_certs(out_pkey, ca_certs, &ber_bytes, password)) { + if (ca_certs_alloced) { + sk_X509_free(ca_certs); + } + return 0; + } + + *out_cert = NULL; + if (sk_X509_num(ca_certs) > 0) { + *out_cert = sk_X509_shift(ca_certs); + } + + if (out_ca_certs) { + *out_ca_certs = ca_certs; + } else { + sk_X509_pop_free(ca_certs, X509_free); + } + + return 1; +} + +void PKCS12_free(PKCS12 *p12) { + OPENSSL_free(p12->ber_bytes); + OPENSSL_free(p12); +} diff --git a/TMessagesProj/jni/boringssl/crypto/poly1305/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/poly1305/CMakeLists.txt new file mode 100644 index 00000000..bb0c1e44 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/poly1305/CMakeLists.txt @@ -0,0 +1,21 @@ +include_directories(. .. ../../include) + +if (${ARCH} STREQUAL "arm") + set( + POLY1305_ARCH_SOURCES + + poly1305_arm_asm.S + ) +endif() + +add_library( + poly1305 + + OBJECT + + poly1305.c + poly1305_arm.c + poly1305_vec.c + + ${POLY1305_ARCH_SOURCES} +) diff --git a/TMessagesProj/jni/boringssl/crypto/poly1305/poly1305.c b/TMessagesProj/jni/boringssl/crypto/poly1305/poly1305.c new file mode 100644 index 00000000..5a49e2df --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/poly1305/poly1305.c @@ -0,0 +1,331 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This implementation of poly1305 is by Andrew Moon + * (https://github.com/floodyberry/poly1305-donna) and released as public + * domain. */ + +#include + +#include + +#include + + +#if defined(OPENSSL_WINDOWS) || !defined(OPENSSL_X86_64) + +#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || defined(OPENSSL_ARM) +/* We can assume little-endian. */ +static uint32_t U8TO32_LE(const uint8_t *m) { + uint32_t r; + memcpy(&r, m, sizeof(r)); + return r; +} + +static void U32TO8_LE(uint8_t *m, uint32_t v) { memcpy(m, &v, sizeof(v)); } +#else +static uint32_t U8TO32_LE(const uint8_t *m) { + return (uint32_t)m[0] | (uint32_t)m[1] << 8 | (uint32_t)m[2] << 16 | + (uint32_t)m[3] << 24; +} + +static void U32TO8_LE(uint8_t *m, uint32_t v) { + m[0] = v; + m[1] = v >> 8; + m[2] = v >> 16; + m[3] = v >> 24; +} +#endif + +#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM) +void CRYPTO_poly1305_init_neon(poly1305_state *state, const uint8_t key[32]); + +void CRYPTO_poly1305_update_neon(poly1305_state *state, const uint8_t *in, + size_t in_len); + +void CRYPTO_poly1305_finish_neon(poly1305_state *state, uint8_t mac[16]); +#endif + +static uint64_t mul32x32_64(uint32_t a, uint32_t b) { return (uint64_t)a * b; } + +struct poly1305_state_st { + uint32_t r0, r1, r2, r3, r4; + uint32_t s1, s2, s3, s4; + uint32_t h0, h1, h2, h3, h4; + uint8_t buf[16]; + unsigned int buf_used; + uint8_t key[16]; +}; + +/* poly1305_blocks updates |state| given some amount of input data. This + * function may only be called with a |len| that is not a multiple of 16 at the + * end of the data. Otherwise the input must be buffered into 16 byte blocks. */ +static void poly1305_update(struct poly1305_state_st *state, const uint8_t *in, + size_t len) { + uint32_t t0, t1, t2, t3; + uint64_t t[5]; + uint32_t b; + uint64_t c; + size_t j; + uint8_t mp[16]; + + if (len < 16) { + goto poly1305_donna_atmost15bytes; + } + +poly1305_donna_16bytes: + t0 = U8TO32_LE(in); + t1 = U8TO32_LE(in + 4); + t2 = U8TO32_LE(in + 8); + t3 = U8TO32_LE(in + 12); + + in += 16; + len -= 16; + + state->h0 += t0 & 0x3ffffff; + state->h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; + state->h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; + state->h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; + state->h4 += (t3 >> 8) | (1 << 24); + +poly1305_donna_mul: + t[0] = mul32x32_64(state->h0, state->r0) + mul32x32_64(state->h1, state->s4) + + mul32x32_64(state->h2, state->s3) + mul32x32_64(state->h3, state->s2) + + mul32x32_64(state->h4, state->s1); + t[1] = mul32x32_64(state->h0, state->r1) + mul32x32_64(state->h1, state->r0) + + mul32x32_64(state->h2, state->s4) + mul32x32_64(state->h3, state->s3) + + mul32x32_64(state->h4, state->s2); + t[2] = mul32x32_64(state->h0, state->r2) + mul32x32_64(state->h1, state->r1) + + mul32x32_64(state->h2, state->r0) + mul32x32_64(state->h3, state->s4) + + mul32x32_64(state->h4, state->s3); + t[3] = mul32x32_64(state->h0, state->r3) + mul32x32_64(state->h1, state->r2) + + mul32x32_64(state->h2, state->r1) + mul32x32_64(state->h3, state->r0) + + mul32x32_64(state->h4, state->s4); + t[4] = mul32x32_64(state->h0, state->r4) + mul32x32_64(state->h1, state->r3) + + mul32x32_64(state->h2, state->r2) + mul32x32_64(state->h3, state->r1) + + mul32x32_64(state->h4, state->r0); + + state->h0 = (uint32_t)t[0] & 0x3ffffff; + c = (t[0] >> 26); + t[1] += c; + state->h1 = (uint32_t)t[1] & 0x3ffffff; + b = (uint32_t)(t[1] >> 26); + t[2] += b; + state->h2 = (uint32_t)t[2] & 0x3ffffff; + b = (uint32_t)(t[2] >> 26); + t[3] += b; + state->h3 = (uint32_t)t[3] & 0x3ffffff; + b = (uint32_t)(t[3] >> 26); + t[4] += b; + state->h4 = (uint32_t)t[4] & 0x3ffffff; + b = (uint32_t)(t[4] >> 26); + state->h0 += b * 5; + + if (len >= 16) { + goto poly1305_donna_16bytes; + } + +/* final bytes */ +poly1305_donna_atmost15bytes: + if (!len) { + return; + } + + for (j = 0; j < len; j++) { + mp[j] = in[j]; + } + mp[j++] = 1; + for (; j < 16; j++) { + mp[j] = 0; + } + len = 0; + + t0 = U8TO32_LE(mp + 0); + t1 = U8TO32_LE(mp + 4); + t2 = U8TO32_LE(mp + 8); + t3 = U8TO32_LE(mp + 12); + + state->h0 += t0 & 0x3ffffff; + state->h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; + state->h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; + state->h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; + state->h4 += (t3 >> 8); + + goto poly1305_donna_mul; +} + +void CRYPTO_poly1305_init(poly1305_state *statep, const uint8_t key[32]) { + struct poly1305_state_st *state = (struct poly1305_state_st *)statep; + uint32_t t0, t1, t2, t3; + +#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM) + if (CRYPTO_is_NEON_functional()) { + CRYPTO_poly1305_init_neon(statep, key); + return; + } +#endif + + t0 = U8TO32_LE(key + 0); + t1 = U8TO32_LE(key + 4); + t2 = U8TO32_LE(key + 8); + t3 = U8TO32_LE(key + 12); + + /* precompute multipliers */ + state->r0 = t0 & 0x3ffffff; + t0 >>= 26; + t0 |= t1 << 6; + state->r1 = t0 & 0x3ffff03; + t1 >>= 20; + t1 |= t2 << 12; + state->r2 = t1 & 0x3ffc0ff; + t2 >>= 14; + t2 |= t3 << 18; + state->r3 = t2 & 0x3f03fff; + t3 >>= 8; + state->r4 = t3 & 0x00fffff; + + state->s1 = state->r1 * 5; + state->s2 = state->r2 * 5; + state->s3 = state->r3 * 5; + state->s4 = state->r4 * 5; + + /* init state */ + state->h0 = 0; + state->h1 = 0; + state->h2 = 0; + state->h3 = 0; + state->h4 = 0; + + state->buf_used = 0; + memcpy(state->key, key + 16, sizeof(state->key)); +} + +void CRYPTO_poly1305_update(poly1305_state *statep, const uint8_t *in, + size_t in_len) { + unsigned int i; + struct poly1305_state_st *state = (struct poly1305_state_st *)statep; + +#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM) + if (CRYPTO_is_NEON_functional()) { + CRYPTO_poly1305_update_neon(statep, in, in_len); + return; + } +#endif + + if (state->buf_used) { + unsigned int todo = 16 - state->buf_used; + if (todo > in_len) { + todo = in_len; + } + for (i = 0; i < todo; i++) { + state->buf[state->buf_used + i] = in[i]; + } + state->buf_used += todo; + in_len -= todo; + in += todo; + + if (state->buf_used == 16) { + poly1305_update(state, state->buf, 16); + state->buf_used = 0; + } + } + + if (in_len >= 16) { + size_t todo = in_len & ~0xf; + poly1305_update(state, in, todo); + in += todo; + in_len &= 0xf; + } + + if (in_len) { + for (i = 0; i < in_len; i++) { + state->buf[i] = in[i]; + } + state->buf_used = in_len; + } +} + +void CRYPTO_poly1305_finish(poly1305_state *statep, uint8_t mac[16]) { + struct poly1305_state_st *state = (struct poly1305_state_st *)statep; + uint64_t f0, f1, f2, f3; + uint32_t g0, g1, g2, g3, g4; + uint32_t b, nb; + +#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM) + if (CRYPTO_is_NEON_functional()) { + CRYPTO_poly1305_finish_neon(statep, mac); + return; + } +#endif + + if (state->buf_used) { + poly1305_update(state, state->buf, state->buf_used); + } + + b = state->h0 >> 26; + state->h0 = state->h0 & 0x3ffffff; + state->h1 += b; + b = state->h1 >> 26; + state->h1 = state->h1 & 0x3ffffff; + state->h2 += b; + b = state->h2 >> 26; + state->h2 = state->h2 & 0x3ffffff; + state->h3 += b; + b = state->h3 >> 26; + state->h3 = state->h3 & 0x3ffffff; + state->h4 += b; + b = state->h4 >> 26; + state->h4 = state->h4 & 0x3ffffff; + state->h0 += b * 5; + + g0 = state->h0 + 5; + b = g0 >> 26; + g0 &= 0x3ffffff; + g1 = state->h1 + b; + b = g1 >> 26; + g1 &= 0x3ffffff; + g2 = state->h2 + b; + b = g2 >> 26; + g2 &= 0x3ffffff; + g3 = state->h3 + b; + b = g3 >> 26; + g3 &= 0x3ffffff; + g4 = state->h4 + b - (1 << 26); + + b = (g4 >> 31) - 1; + nb = ~b; + state->h0 = (state->h0 & nb) | (g0 & b); + state->h1 = (state->h1 & nb) | (g1 & b); + state->h2 = (state->h2 & nb) | (g2 & b); + state->h3 = (state->h3 & nb) | (g3 & b); + state->h4 = (state->h4 & nb) | (g4 & b); + + f0 = ((state->h0) | (state->h1 << 26)) + (uint64_t)U8TO32_LE(&state->key[0]); + f1 = ((state->h1 >> 6) | (state->h2 << 20)) + + (uint64_t)U8TO32_LE(&state->key[4]); + f2 = ((state->h2 >> 12) | (state->h3 << 14)) + + (uint64_t)U8TO32_LE(&state->key[8]); + f3 = ((state->h3 >> 18) | (state->h4 << 8)) + + (uint64_t)U8TO32_LE(&state->key[12]); + + U32TO8_LE(&mac[0], f0); + f1 += (f0 >> 32); + U32TO8_LE(&mac[4], f1); + f2 += (f1 >> 32); + U32TO8_LE(&mac[8], f2); + f3 += (f2 >> 32); + U32TO8_LE(&mac[12], f3); +} + +#endif /* OPENSSL_WINDOWS || !OPENSSL_X86_64 */ diff --git a/TMessagesProj/jni/boringssl/crypto/poly1305/poly1305_arm.c b/TMessagesProj/jni/boringssl/crypto/poly1305/poly1305_arm.c new file mode 100644 index 00000000..c06ededd --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/poly1305/poly1305_arm.c @@ -0,0 +1,301 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This implementation was taken from the public domain, neon2 version in + * SUPERCOP by D. J. Bernstein and Peter Schwabe. */ + +#include + +#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM) + +#include + + +typedef struct { + uint32_t v[12]; /* for alignment; only using 10 */ +} fe1305x2; + +#define addmulmod openssl_poly1305_neon2_addmulmod +#define blocks openssl_poly1305_neon2_blocks + +extern void addmulmod(fe1305x2 *r, const fe1305x2 *x, const fe1305x2 *y, + const fe1305x2 *c); + +extern int blocks(fe1305x2 *h, const fe1305x2 *precomp, const uint8_t *in, + unsigned int inlen); + +static void freeze(fe1305x2 *r) { + int i; + + uint32_t x0 = r->v[0]; + uint32_t x1 = r->v[2]; + uint32_t x2 = r->v[4]; + uint32_t x3 = r->v[6]; + uint32_t x4 = r->v[8]; + uint32_t y0; + uint32_t y1; + uint32_t y2; + uint32_t y3; + uint32_t y4; + uint32_t swap; + + for (i = 0; i < 3; ++i) { + x1 += x0 >> 26; + x0 &= 0x3ffffff; + x2 += x1 >> 26; + x1 &= 0x3ffffff; + x3 += x2 >> 26; + x2 &= 0x3ffffff; + x4 += x3 >> 26; + x3 &= 0x3ffffff; + x0 += 5 * (x4 >> 26); + x4 &= 0x3ffffff; + } + + y0 = x0 + 5; + y1 = x1 + (y0 >> 26); + y0 &= 0x3ffffff; + y2 = x2 + (y1 >> 26); + y1 &= 0x3ffffff; + y3 = x3 + (y2 >> 26); + y2 &= 0x3ffffff; + y4 = x4 + (y3 >> 26); + y3 &= 0x3ffffff; + swap = -(y4 >> 26); + y4 &= 0x3ffffff; + + y0 ^= x0; + y1 ^= x1; + y2 ^= x2; + y3 ^= x3; + y4 ^= x4; + + y0 &= swap; + y1 &= swap; + y2 &= swap; + y3 &= swap; + y4 &= swap; + + y0 ^= x0; + y1 ^= x1; + y2 ^= x2; + y3 ^= x3; + y4 ^= x4; + + r->v[0] = y0; + r->v[2] = y1; + r->v[4] = y2; + r->v[6] = y3; + r->v[8] = y4; +} + +static void fe1305x2_tobytearray(uint8_t *r, fe1305x2 *x) { + uint32_t x0 = x->v[0]; + uint32_t x1 = x->v[2]; + uint32_t x2 = x->v[4]; + uint32_t x3 = x->v[6]; + uint32_t x4 = x->v[8]; + + x1 += x0 >> 26; + x0 &= 0x3ffffff; + x2 += x1 >> 26; + x1 &= 0x3ffffff; + x3 += x2 >> 26; + x2 &= 0x3ffffff; + x4 += x3 >> 26; + x3 &= 0x3ffffff; + + *(uint32_t *)r = x0 + (x1 << 26); + *(uint32_t *)(r + 4) = (x1 >> 6) + (x2 << 20); + *(uint32_t *)(r + 8) = (x2 >> 12) + (x3 << 14); + *(uint32_t *)(r + 12) = (x3 >> 18) + (x4 << 8); +} + +/* load32 exists to avoid breaking strict aliasing rules in + * fe1305x2_frombytearray. */ +static uint32_t load32(uint8_t *t) { + uint32_t tmp; + memcpy(&tmp, t, sizeof(tmp)); + return tmp; +} + +static void fe1305x2_frombytearray(fe1305x2 *r, const uint8_t *x, + unsigned long long xlen) { + int i; + uint8_t t[17]; + + for (i = 0; (i < 16) && (i < xlen); i++) { + t[i] = x[i]; + } + xlen -= i; + x += i; + t[i++] = 1; + for (; i < 17; i++) { + t[i] = 0; + } + + r->v[0] = 0x3ffffff & load32(t); + r->v[2] = 0x3ffffff & (load32(t + 3) >> 2); + r->v[4] = 0x3ffffff & (load32(t + 6) >> 4); + r->v[6] = 0x3ffffff & (load32(t + 9) >> 6); + r->v[8] = load32(t + 13); + + if (xlen) { + for (i = 0; (i < 16) && (i < xlen); i++) { + t[i] = x[i]; + } + t[i++] = 1; + for (; i < 17; i++) { + t[i] = 0; + } + + r->v[1] = 0x3ffffff & load32(t); + r->v[3] = 0x3ffffff & (load32(t + 3) >> 2); + r->v[5] = 0x3ffffff & (load32(t + 6) >> 4); + r->v[7] = 0x3ffffff & (load32(t + 9) >> 6); + r->v[9] = load32(t + 13); + } else { + r->v[1] = r->v[3] = r->v[5] = r->v[7] = r->v[9] = 0; + } +} + +static const fe1305x2 zero __attribute__((aligned(16))); + +struct poly1305_state_st { + uint8_t data[sizeof(fe1305x2[5]) + 128]; + uint8_t buf[32]; + unsigned int buf_used; + uint8_t key[16]; +}; + +void CRYPTO_poly1305_init_neon(poly1305_state *state, const uint8_t key[32]) { + struct poly1305_state_st *st = (struct poly1305_state_st *)(state); + fe1305x2 *const r = (fe1305x2 *)(st->data + (15 & (-(int)st->data))); + fe1305x2 *const h = r + 1; + fe1305x2 *const c = h + 1; + fe1305x2 *const precomp = c + 1; + unsigned int j; + + r->v[1] = r->v[0] = 0x3ffffff & *(uint32_t *)key; + r->v[3] = r->v[2] = 0x3ffff03 & ((*(uint32_t *)(key + 3)) >> 2); + r->v[5] = r->v[4] = 0x3ffc0ff & ((*(uint32_t *)(key + 6)) >> 4); + r->v[7] = r->v[6] = 0x3f03fff & ((*(uint32_t *)(key + 9)) >> 6); + r->v[9] = r->v[8] = 0x00fffff & ((*(uint32_t *)(key + 12)) >> 8); + + for (j = 0; j < 10; j++) { + h->v[j] = 0; /* XXX: should fast-forward a bit */ + } + + addmulmod(precomp, r, r, &zero); /* precompute r^2 */ + addmulmod(precomp + 1, precomp, precomp, &zero); /* precompute r^4 */ + + memcpy(st->key, key + 16, 16); + st->buf_used = 0; +} + +void CRYPTO_poly1305_update_neon(poly1305_state *state, const uint8_t *in, + size_t in_len) { + struct poly1305_state_st *st = (struct poly1305_state_st *)(state); + fe1305x2 *const r = (fe1305x2 *)(st->data + (15 & (-(int)st->data))); + fe1305x2 *const h = r + 1; + fe1305x2 *const c = h + 1; + fe1305x2 *const precomp = c + 1; + unsigned int i; + + if (st->buf_used) { + unsigned int todo = 32 - st->buf_used; + if (todo > in_len) { + todo = in_len; + } + for (i = 0; i < todo; i++) { + st->buf[st->buf_used + i] = in[i]; + } + st->buf_used += todo; + in_len -= todo; + in += todo; + + if (st->buf_used == sizeof(st->buf) && in_len) { + addmulmod(h, h, precomp, &zero); + fe1305x2_frombytearray(c, st->buf, sizeof(st->buf)); + for (i = 0; i < 10; i++) { + h->v[i] += c->v[i]; + } + st->buf_used = 0; + } + } + + while (in_len > 32) { + unsigned int tlen = 1048576; + if (in_len < tlen) { + tlen = in_len; + } + tlen -= blocks(h, precomp, in, tlen); + in_len -= tlen; + in += tlen; + } + + if (in_len) { + for (i = 0; i < in_len; i++) { + st->buf[i] = in[i]; + } + st->buf_used = in_len; + } +} + +void CRYPTO_poly1305_finish_neon(poly1305_state *state, uint8_t mac[16]) { + struct poly1305_state_st *st = (struct poly1305_state_st *)(state); + fe1305x2 *const r = (fe1305x2 *)(st->data + (15 & (-(int)st->data))); + fe1305x2 *const h = r + 1; + fe1305x2 *const c = h + 1; + fe1305x2 *const precomp = c + 1; + + addmulmod(h, h, precomp, &zero); + + if (st->buf_used > 16) { + fe1305x2_frombytearray(c, st->buf, st->buf_used); + precomp->v[1] = r->v[1]; + precomp->v[3] = r->v[3]; + precomp->v[5] = r->v[5]; + precomp->v[7] = r->v[7]; + precomp->v[9] = r->v[9]; + addmulmod(h, h, precomp, c); + } else if (st->buf_used > 0) { + fe1305x2_frombytearray(c, st->buf, st->buf_used); + r->v[1] = 1; + r->v[3] = 0; + r->v[5] = 0; + r->v[7] = 0; + r->v[9] = 0; + addmulmod(h, h, r, c); + } + + h->v[0] += h->v[1]; + h->v[2] += h->v[3]; + h->v[4] += h->v[5]; + h->v[6] += h->v[7]; + h->v[8] += h->v[9]; + freeze(h); + + fe1305x2_frombytearray(c, st->key, 16); + c->v[8] ^= (1 << 24); + + h->v[0] += c->v[0]; + h->v[2] += c->v[2]; + h->v[4] += c->v[4]; + h->v[6] += c->v[6]; + h->v[8] += c->v[8]; + fe1305x2_tobytearray(mac, h); +} + +#endif /* OPENSSL_ARM && !OPENSSL_NO_ASM */ diff --git a/TMessagesProj/jni/boringssl/crypto/poly1305/poly1305_arm_asm.S b/TMessagesProj/jni/boringssl/crypto/poly1305/poly1305_arm_asm.S new file mode 100644 index 00000000..e16f83bd --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/poly1305/poly1305_arm_asm.S @@ -0,0 +1,2015 @@ +#if defined(__arm__) && !defined(OPENSSL_NO_ASM) + +# This implementation was taken from the public domain, neon2 version in +# SUPERCOP by D. J. Bernstein and Peter Schwabe. + +# qhasm: int32 input_0 + +# qhasm: int32 input_1 + +# qhasm: int32 input_2 + +# qhasm: int32 input_3 + +# qhasm: stack32 input_4 + +# qhasm: stack32 input_5 + +# qhasm: stack32 input_6 + +# qhasm: stack32 input_7 + +# qhasm: int32 caller_r4 + +# qhasm: int32 caller_r5 + +# qhasm: int32 caller_r6 + +# qhasm: int32 caller_r7 + +# qhasm: int32 caller_r8 + +# qhasm: int32 caller_r9 + +# qhasm: int32 caller_r10 + +# qhasm: int32 caller_r11 + +# qhasm: int32 caller_r12 + +# qhasm: int32 caller_r14 + +# qhasm: reg128 caller_q4 + +# qhasm: reg128 caller_q5 + +# qhasm: reg128 caller_q6 + +# qhasm: reg128 caller_q7 + +# qhasm: startcode +.fpu neon +.text + +# qhasm: reg128 r0 + +# qhasm: reg128 r1 + +# qhasm: reg128 r2 + +# qhasm: reg128 r3 + +# qhasm: reg128 r4 + +# qhasm: reg128 x01 + +# qhasm: reg128 x23 + +# qhasm: reg128 x4 + +# qhasm: reg128 y0 + +# qhasm: reg128 y12 + +# qhasm: reg128 y34 + +# qhasm: reg128 5y12 + +# qhasm: reg128 5y34 + +# qhasm: stack128 y0_stack + +# qhasm: stack128 y12_stack + +# qhasm: stack128 y34_stack + +# qhasm: stack128 5y12_stack + +# qhasm: stack128 5y34_stack + +# qhasm: reg128 z0 + +# qhasm: reg128 z12 + +# qhasm: reg128 z34 + +# qhasm: reg128 5z12 + +# qhasm: reg128 5z34 + +# qhasm: stack128 z0_stack + +# qhasm: stack128 z12_stack + +# qhasm: stack128 z34_stack + +# qhasm: stack128 5z12_stack + +# qhasm: stack128 5z34_stack + +# qhasm: stack128 two24 + +# qhasm: int32 ptr + +# qhasm: reg128 c01 + +# qhasm: reg128 c23 + +# qhasm: reg128 d01 + +# qhasm: reg128 d23 + +# qhasm: reg128 t0 + +# qhasm: reg128 t1 + +# qhasm: reg128 t2 + +# qhasm: reg128 t3 + +# qhasm: reg128 t4 + +# qhasm: reg128 mask + +# qhasm: reg128 u0 + +# qhasm: reg128 u1 + +# qhasm: reg128 u2 + +# qhasm: reg128 u3 + +# qhasm: reg128 u4 + +# qhasm: reg128 v01 + +# qhasm: reg128 mid + +# qhasm: reg128 v23 + +# qhasm: reg128 v4 + +# qhasm: int32 len + +# qhasm: qpushenter crypto_onetimeauth_poly1305_neon2_blocks +.align 4 +.global openssl_poly1305_neon2_blocks +.hidden openssl_poly1305_neon2_blocks +.type openssl_poly1305_neon2_blocks STT_FUNC +openssl_poly1305_neon2_blocks: +vpush {q4,q5,q6,q7} +mov r12,sp +sub sp,sp,#192 +bic sp,sp,#31 + +# qhasm: len = input_3 +# asm 1: mov >len=int32#4,len=r3,y12=reg128#2%bot->y12=reg128#2%top},[y12=d2->y12=d3},[y34=reg128#3%bot->y34=reg128#3%top},[y34=d4->y34=d5},[input_1=int32#2,input_1=r1,z12=reg128#5%bot->z12=reg128#5%top},[z12=d8->z12=d9},[z34=reg128#6%bot->z34=reg128#6%top},[z34=d10->z34=d11},[mask=reg128#7,#0xffffffff +# asm 2: vmov.i64 >mask=q6,#0xffffffff +vmov.i64 q6,#0xffffffff + +# qhasm: 2x u4 = 0xff +# asm 1: vmov.i64 >u4=reg128#8,#0xff +# asm 2: vmov.i64 >u4=q7,#0xff +vmov.i64 q7,#0xff + +# qhasm: x01 aligned= mem128[input_0];input_0+=16 +# asm 1: vld1.8 {>x01=reg128#9%bot->x01=reg128#9%top},[x01=d16->x01=d17},[x23=reg128#10%bot->x23=reg128#10%top},[x23=d18->x23=d19},[input_0=int32#1,input_0=r0,>=6 +# asm 1: vshr.u64 >mask=reg128#7,mask=q6,>= 7 +# asm 1: vshr.u64 >u4=reg128#8,u4=q7,5y12=reg128#12,5y12=q11,5y34=reg128#13,5y34=q12,5y12=reg128#12,<5y12=reg128#12,5y12=q11,<5y12=q11,5y34=reg128#13,<5y34=reg128#13,5y34=q12,<5y34=q12,u4=reg128#8,u4=q7,5z12=reg128#14,5z12=q13,5z34=reg128#15,5z34=q14,5z12=reg128#14,<5z12=reg128#14,5z12=q13,<5z12=q13,5z34=reg128#15,<5z34=reg128#15,5z34=q14,<5z34=q14,ptr=int32#2,ptr=r1,r4=reg128#16,r4=q15,r0=reg128#8,r0=q7,ptr=int32#2,ptr=r1,ptr=int32#2,ptr=r1,ptr=int32#2,ptr=r1,ptr=int32#2,ptr=r1,ptr=int32#2,ptr=r1,ptr=int32#2,ptr=r1,ptr=int32#2,<5y12_stack=stack128#5 +# asm 2: lea >ptr=r1,<5y12_stack=[sp,#64] +add r1,sp,#64 + +# qhasm: mem128[ptr] aligned= 5y12 +# asm 1: vst1.8 {<5y12=reg128#12%bot-<5y12=reg128#12%top},[ptr=int32#2,<5y34_stack=stack128#6 +# asm 2: lea >ptr=r1,<5y34_stack=[sp,#80] +add r1,sp,#80 + +# qhasm: mem128[ptr] aligned= 5y34 +# asm 1: vst1.8 {<5y34=reg128#13%bot-<5y34=reg128#13%top},[ptr=int32#2,<5z12_stack=stack128#10 +# asm 2: lea >ptr=r1,<5z12_stack=[sp,#144] +add r1,sp,#144 + +# qhasm: mem128[ptr] aligned= 5z12 +# asm 1: vst1.8 {<5z12=reg128#14%bot-<5z12=reg128#14%top},[ptr=int32#2,<5z34_stack=stack128#11 +# asm 2: lea >ptr=r1,<5z34_stack=[sp,#160] +add r1,sp,#160 + +# qhasm: mem128[ptr] aligned= 5z34 +# asm 1: vst1.8 {<5z34=reg128#15%bot-<5z34=reg128#15%top},[? len - 64 +# asm 1: cmp +bls ._below64bytes + +# qhasm: input_2 += 32 +# asm 1: add >input_2=int32#2,input_2=r1,c01=reg128#1%bot->c01=reg128#1%top},[c01=d0->c01=d1},[c23=reg128#2%bot->c23=reg128#2%top},[c23=d2->c23=d3},[ptr=int32#3,ptr=r2,z12=reg128#3%bot->z12=reg128#3%top},[z12=d4->z12=d5},[ptr=int32#3,ptr=r2,z0=reg128#4%bot->z0=reg128#4%top},[z0=d6->z0=d7},[r3=reg128#5,r3=q4,input_2=int32#2,input_2=r1,ptr=int32#3,<5z34_stack=stack128#11 +# asm 2: lea >ptr=r2,<5z34_stack=[sp,#160] +add r2,sp,#160 + +# qhasm: 5z34 aligned= mem128[ptr] +# asm 1: vld1.8 {>5z34=reg128#6%bot->5z34=reg128#6%top},[5z34=d10->5z34=d11},[r0=reg128#8,r0=q7,r2=reg128#14,r2=q13,d01=reg128#12%bot->d01=reg128#12%top},[d01=d22->d01=d23},[r1=reg128#15,r1=q14,ptr=int32#3,<5z12_stack=stack128#10 +# asm 2: lea >ptr=r2,<5z12_stack=[sp,#144] +add r2,sp,#144 + +# qhasm: 5z12 aligned= mem128[ptr] +# asm 1: vld1.8 {>5z12=reg128#1%bot->5z12=reg128#1%top},[5z12=d0->5z12=d1},[d23=reg128#2%bot->d23=reg128#2%top},[d23=d2->d23=d3},[input_2=int32#2,input_2=r1,> 40 +# asm 1: vshr.u64 >v4=reg128#4,v4=q3,> 14; v23[3] = d23[2,3] unsigned>> 14 +# asm 1: vshrn.u64 > 26; v01[3] = d01[2,3] unsigned>> 26 +# asm 1: vshrn.u64 > 20; v23[1] = mid[2,3] unsigned>> 20 +# asm 1: vshrn.u64 ptr=int32#3,ptr=r2,y34=reg128#3%bot->y34=reg128#3%top},[y34=d4->y34=d5},[ptr=int32#3,ptr=r2,y12=reg128#2%bot->y12=reg128#2%top},[y12=d2->y12=d3},[ptr=int32#3,ptr=r2,y0=reg128#1%bot->y0=reg128#1%top},[y0=d0->y0=d1},[ptr=int32#3,<5y34_stack=stack128#6 +# asm 2: lea >ptr=r2,<5y34_stack=[sp,#80] +add r2,sp,#80 + +# qhasm: 5y34 aligned= mem128[ptr] +# asm 1: vld1.8 {>5y34=reg128#13%bot->5y34=reg128#13%top},[5y34=d24->5y34=d25},[ptr=int32#3,<5y12_stack=stack128#5 +# asm 2: lea >ptr=r2,<5y12_stack=[sp,#64] +add r2,sp,#64 + +# qhasm: 5y12 aligned= mem128[ptr] +# asm 1: vld1.8 {>5y12=reg128#12%bot->5y12=reg128#12%top},[5y12=d22->5y12=d23},[ptr=int32#3,ptr=r2,> 26 +# asm 1: vshr.u64 >t1=reg128#4,t1=q3,len=int32#4,len=r3,r0=reg128#6,r0=q5,r1=reg128#4,r1=q3,> 26 +# asm 1: vshr.u64 >t4=reg128#8,t4=q7,r3=reg128#5,r3=q4,x4=reg128#8,x4=q7,r4=reg128#16%bot->r4=reg128#16%top},[r4=d30->r4=d31},[> 26 +# asm 1: vshr.u64 >t2=reg128#9,t2=q8,r1=reg128#4,r1=q3,> 26 +# asm 1: vshr.u64 >t0=reg128#10,t0=q9,r2=reg128#9,r2=q8,x4=reg128#11,x4=q10,x01=reg128#6,x01=q5,r0=reg128#8%bot->r0=reg128#8%top},[r0=d14->r0=d15},[ptr=int32#3,ptr=r2,t0=reg128#10,t0=q9,> 26 +# asm 1: vshr.u64 >t3=reg128#14,t3=q13,x01=reg128#15,x01=q14,z34=reg128#6%bot->z34=reg128#6%top},[z34=d10->z34=d11},[x23=reg128#10,x23=q9,r3=reg128#5,r3=q4,input_2=int32#2,input_2=r1,> 26 +# asm 1: vshr.u64 >t1=reg128#14,t1=q13,x01=reg128#9,x01=q8,r1=reg128#4,r1=q3,> 26 +# asm 1: vshr.u64 >t4=reg128#14,t4=q13,r3=reg128#5,r3=q4,x4=reg128#11,x4=q10,? len - 64 +# asm 1: cmp +bhi ._mainloop2 + +# qhasm: input_2 -= 32 +# asm 1: sub >input_2=int32#3,input_2=r2,? len - 32 +# asm 1: cmp +bls ._end + +# qhasm: mainloop: +._mainloop: + +# qhasm: new r0 + +# qhasm: ptr = &two24 +# asm 1: lea >ptr=int32#2,ptr=r1,r4=reg128#5%bot->r4=reg128#5%top},[r4=d8->r4=d9},[u4=reg128#6%bot->u4=reg128#6%top},[u4=d10->u4=d11},[c01=reg128#8%bot->c01=reg128#8%top},[c01=d14->c01=d15},[c23=reg128#14%bot->c23=reg128#14%top},[c23=d26->c23=d27},[r0=reg128#4,r0=q3,r3=reg128#6,r3=q5,r1=reg128#14,r1=q13,r2=reg128#8,r2=q7,> 26 +# asm 1: vshr.u64 >t1=reg128#9,t1=q8,r0=reg128#4,r0=q3,r1=reg128#9,r1=q8,> 26 +# asm 1: vshr.u64 >t4=reg128#10,t4=q9,r3=reg128#6,r3=q5,r4=reg128#5,r4=q4,> 26 +# asm 1: vshr.u64 >t2=reg128#10,t2=q9,r1=reg128#11,r1=q10,> 26 +# asm 1: vshr.u64 >t0=reg128#9,t0=q8,r2=reg128#8,r2=q7,r4=reg128#5,r4=q4,r0=reg128#4,r0=q3,t0=reg128#9,t0=q8,> 26 +# asm 1: vshr.u64 >t3=reg128#14,t3=q13,r0=reg128#4,r0=q3,x23=reg128#10,x23=q9,r3=reg128#6,r3=q5,> 26 +# asm 1: vshr.u64 >t1=reg128#8,t1=q7,x01=reg128#9,x01=q8,r1=reg128#4,r1=q3,> 26 +# asm 1: vshr.u64 >t4=reg128#8,t4=q7,r3=reg128#6,r3=q5,x4=reg128#11,x4=q10,len=int32#4,len=r3,? len - 32 +# asm 1: cmp +bhi ._mainloop + +# qhasm: end: +._end: + +# qhasm: mem128[input_0] = x01;input_0+=16 +# asm 1: vst1.8 {len=int32#1,len=r0,mask=reg128#1,#0xffffffff +# asm 2: vmov.i64 >mask=q0,#0xffffffff +vmov.i64 q0,#0xffffffff + +# qhasm: y01 aligned= mem128[input_2];input_2+=16 +# asm 1: vld1.8 {>y01=reg128#2%bot->y01=reg128#2%top},[y01=d2->y01=d3},[_5y01=reg128#3,_5y01=q2,y23=reg128#4%bot->y23=reg128#4%top},[y23=d6->y23=d7},[_5y23=reg128#9,_5y23=q8,_5y4=reg128#11,_5y4=q10,x01=reg128#12%bot->x01=reg128#12%top},[x01=d22->x01=d23},[_5y01=reg128#3,<_5y01=reg128#3,_5y01=q2,<_5y01=q2,x23=reg128#13%bot->x23=reg128#13%top},[x23=d24->x23=d25},[_5y23=reg128#9,<_5y23=reg128#9,_5y23=q8,<_5y23=q8,_5y4=reg128#11,<_5y4=reg128#11,_5y4=q10,<_5y4=q10,c01=reg128#14%bot->c01=reg128#14%top},[c01=d26->c01=d27},[x01=reg128#12,x01=q11,c23=reg128#14%bot->c23=reg128#14%top},[c23=d26->c23=d27},[x23=reg128#13,x23=q12,>=6 +# asm 1: vshr.u64 >mask=reg128#1,mask=q0,x4=reg128#14,x4=q13,r0=reg128#15,r0=q14,r1=reg128#3,r1=q2,r2=reg128#16,r2=q15,r3=reg128#9,r3=q8,r4=reg128#10,r4=q9,> 26 +# asm 1: vshr.u64 >t1=reg128#2,t1=q1,r0=reg128#4,r0=q3,r1=reg128#2,r1=q1,> 26 +# asm 1: vshr.u64 >t4=reg128#3,t4=q2,r3=reg128#9,r3=q8,r4=reg128#3,r4=q2,> 26 +# asm 1: vshr.u64 >t2=reg128#10,t2=q9,r1=reg128#2,r1=q1,> 26 +# asm 1: vshr.u64 >t0=reg128#11,t0=q10,r2=reg128#10,r2=q9,r4=reg128#3,r4=q2,r0=reg128#4,r0=q3,t0=reg128#11,t0=q10,> 26 +# asm 1: vshr.u64 >t3=reg128#12,t3=q11,r0=reg128#4,r0=q3,x23=reg128#10,x23=q9,r3=reg128#9,r3=q8,> 26 +# asm 1: vshr.u64 >t1=reg128#11,t1=q10,x01=reg128#4,x01=q3,r1=reg128#2,r1=q1,> 26 +# asm 1: vshr.u64 >t4=reg128#11,t4=q10,r3=reg128#1,r3=q0,x4=reg128#3,x4=q2, + + +#if !defined(OPENSSL_WINDOWS) && defined(OPENSSL_X86_64) + +#include + +#define ALIGN(x) __attribute__((aligned(x))) +/* inline is not a keyword in C89. */ +#define INLINE +#define U8TO64_LE(m) (*(uint64_t *)(m)) +#define U8TO32_LE(m) (*(uint32_t *)(m)) +#define U64TO8_LE(m, v) (*(uint64_t *)(m)) = v + +typedef __m128i xmmi; +typedef unsigned __int128 uint128_t; + +static const uint32_t ALIGN(16) poly1305_x64_sse2_message_mask[4] = { + (1 << 26) - 1, 0, (1 << 26) - 1, 0}; +static const uint32_t ALIGN(16) poly1305_x64_sse2_5[4] = {5, 0, 5, 0}; +static const uint32_t ALIGN(16) poly1305_x64_sse2_1shl128[4] = {(1 << 24), 0, + (1 << 24), 0}; + +static uint128_t INLINE add128(uint128_t a, uint128_t b) { return a + b; } + +static uint128_t INLINE add128_64(uint128_t a, uint64_t b) { return a + b; } + +static uint128_t INLINE mul64x64_128(uint64_t a, uint64_t b) { + return (uint128_t)a * b; +} + +static uint64_t INLINE lo128(uint128_t a) { return (uint64_t)a; } + +static uint64_t INLINE shr128(uint128_t v, const int shift) { + return (uint64_t)(v >> shift); +} + +static uint64_t INLINE shr128_pair(uint64_t hi, uint64_t lo, const int shift) { + return (uint64_t)((((uint128_t)hi << 64) | lo) >> shift); +} + +typedef struct poly1305_power_t { + union { + xmmi v; + uint64_t u[2]; + uint32_t d[4]; + } R20, R21, R22, R23, R24, S21, S22, S23, S24; +} poly1305_power; + +typedef struct poly1305_state_internal_t { + poly1305_power P[2]; /* 288 bytes, top 32 bit halves unused = 144 + bytes of free storage */ + union { + xmmi H[5]; /* 80 bytes */ + uint64_t HH[10]; + }; + /* uint64_t r0,r1,r2; [24 bytes] */ + /* uint64_t pad0,pad1; [16 bytes] */ + uint64_t started; /* 8 bytes */ + uint64_t leftover; /* 8 bytes */ + uint8_t buffer[64]; /* 64 bytes */ +} poly1305_state_internal; /* 448 bytes total + 63 bytes for + alignment = 511 bytes raw */ + +static poly1305_state_internal INLINE *poly1305_aligned_state( + poly1305_state *state) { + return (poly1305_state_internal *)(((uint64_t)state + 63) & ~63); +} + +/* copy 0-63 bytes */ +static void INLINE +poly1305_block_copy(uint8_t *dst, const uint8_t *src, size_t bytes) { + size_t offset = src - dst; + if (bytes & 32) { + _mm_storeu_si128((xmmi *)(dst + 0), + _mm_loadu_si128((xmmi *)(dst + offset + 0))); + _mm_storeu_si128((xmmi *)(dst + 16), + _mm_loadu_si128((xmmi *)(dst + offset + 16))); + dst += 32; + } + if (bytes & 16) { + _mm_storeu_si128((xmmi *)dst, _mm_loadu_si128((xmmi *)(dst + offset))); + dst += 16; + } + if (bytes & 8) { + *(uint64_t *)dst = *(uint64_t *)(dst + offset); + dst += 8; + } + if (bytes & 4) { + *(uint32_t *)dst = *(uint32_t *)(dst + offset); + dst += 4; + } + if (bytes & 2) { + *(uint16_t *)dst = *(uint16_t *)(dst + offset); + dst += 2; + } + if (bytes & 1) { + *(uint8_t *)dst = *(uint8_t *)(dst + offset); + } +} + +/* zero 0-15 bytes */ +static void INLINE poly1305_block_zero(uint8_t *dst, size_t bytes) { + if (bytes & 8) { + *(uint64_t *)dst = 0; + dst += 8; + } + if (bytes & 4) { + *(uint32_t *)dst = 0; + dst += 4; + } + if (bytes & 2) { + *(uint16_t *)dst = 0; + dst += 2; + } + if (bytes & 1) { + *(uint8_t *)dst = 0; + } +} + +static size_t INLINE poly1305_min(size_t a, size_t b) { + return (a < b) ? a : b; +} + +void CRYPTO_poly1305_init(poly1305_state *state, const uint8_t key[32]) { + poly1305_state_internal *st = poly1305_aligned_state(state); + poly1305_power *p; + uint64_t r0, r1, r2; + uint64_t t0, t1; + + /* clamp key */ + t0 = U8TO64_LE(key + 0); + t1 = U8TO64_LE(key + 8); + r0 = t0 & 0xffc0fffffff; + t0 >>= 44; + t0 |= t1 << 20; + r1 = t0 & 0xfffffc0ffff; + t1 >>= 24; + r2 = t1 & 0x00ffffffc0f; + + /* store r in un-used space of st->P[1] */ + p = &st->P[1]; + p->R20.d[1] = (uint32_t)(r0); + p->R20.d[3] = (uint32_t)(r0 >> 32); + p->R21.d[1] = (uint32_t)(r1); + p->R21.d[3] = (uint32_t)(r1 >> 32); + p->R22.d[1] = (uint32_t)(r2); + p->R22.d[3] = (uint32_t)(r2 >> 32); + + /* store pad */ + p->R23.d[1] = U8TO32_LE(key + 16); + p->R23.d[3] = U8TO32_LE(key + 20); + p->R24.d[1] = U8TO32_LE(key + 24); + p->R24.d[3] = U8TO32_LE(key + 28); + + /* H = 0 */ + st->H[0] = _mm_setzero_si128(); + st->H[1] = _mm_setzero_si128(); + st->H[2] = _mm_setzero_si128(); + st->H[3] = _mm_setzero_si128(); + st->H[4] = _mm_setzero_si128(); + + st->started = 0; + st->leftover = 0; +} + +static void poly1305_first_block(poly1305_state_internal *st, + const uint8_t *m) { + const xmmi MMASK = _mm_load_si128((xmmi *)poly1305_x64_sse2_message_mask); + const xmmi FIVE = _mm_load_si128((xmmi *)poly1305_x64_sse2_5); + const xmmi HIBIT = _mm_load_si128((xmmi *)poly1305_x64_sse2_1shl128); + xmmi T5, T6; + poly1305_power *p; + uint128_t d[3]; + uint64_t r0, r1, r2; + uint64_t r20, r21, r22, s22; + uint64_t pad0, pad1; + uint64_t c; + uint64_t i; + + /* pull out stored info */ + p = &st->P[1]; + + r0 = ((uint64_t)p->R20.d[3] << 32) | (uint64_t)p->R20.d[1]; + r1 = ((uint64_t)p->R21.d[3] << 32) | (uint64_t)p->R21.d[1]; + r2 = ((uint64_t)p->R22.d[3] << 32) | (uint64_t)p->R22.d[1]; + pad0 = ((uint64_t)p->R23.d[3] << 32) | (uint64_t)p->R23.d[1]; + pad1 = ((uint64_t)p->R24.d[3] << 32) | (uint64_t)p->R24.d[1]; + + /* compute powers r^2,r^4 */ + r20 = r0; + r21 = r1; + r22 = r2; + for (i = 0; i < 2; i++) { + s22 = r22 * (5 << 2); + + d[0] = add128(mul64x64_128(r20, r20), mul64x64_128(r21 * 2, s22)); + d[1] = add128(mul64x64_128(r22, s22), mul64x64_128(r20 * 2, r21)); + d[2] = add128(mul64x64_128(r21, r21), mul64x64_128(r22 * 2, r20)); + + r20 = lo128(d[0]) & 0xfffffffffff; + c = shr128(d[0], 44); + d[1] = add128_64(d[1], c); + r21 = lo128(d[1]) & 0xfffffffffff; + c = shr128(d[1], 44); + d[2] = add128_64(d[2], c); + r22 = lo128(d[2]) & 0x3ffffffffff; + c = shr128(d[2], 42); + r20 += c * 5; + c = (r20 >> 44); + r20 = r20 & 0xfffffffffff; + r21 += c; + + p->R20.v = _mm_shuffle_epi32(_mm_cvtsi32_si128((uint32_t)(r20)&0x3ffffff), + _MM_SHUFFLE(1, 0, 1, 0)); + p->R21.v = _mm_shuffle_epi32( + _mm_cvtsi32_si128((uint32_t)((r20 >> 26) | (r21 << 18)) & 0x3ffffff), + _MM_SHUFFLE(1, 0, 1, 0)); + p->R22.v = + _mm_shuffle_epi32(_mm_cvtsi32_si128((uint32_t)((r21 >> 8)) & 0x3ffffff), + _MM_SHUFFLE(1, 0, 1, 0)); + p->R23.v = _mm_shuffle_epi32( + _mm_cvtsi32_si128((uint32_t)((r21 >> 34) | (r22 << 10)) & 0x3ffffff), + _MM_SHUFFLE(1, 0, 1, 0)); + p->R24.v = _mm_shuffle_epi32(_mm_cvtsi32_si128((uint32_t)((r22 >> 16))), + _MM_SHUFFLE(1, 0, 1, 0)); + p->S21.v = _mm_mul_epu32(p->R21.v, FIVE); + p->S22.v = _mm_mul_epu32(p->R22.v, FIVE); + p->S23.v = _mm_mul_epu32(p->R23.v, FIVE); + p->S24.v = _mm_mul_epu32(p->R24.v, FIVE); + p--; + } + + /* put saved info back */ + p = &st->P[1]; + p->R20.d[1] = (uint32_t)(r0); + p->R20.d[3] = (uint32_t)(r0 >> 32); + p->R21.d[1] = (uint32_t)(r1); + p->R21.d[3] = (uint32_t)(r1 >> 32); + p->R22.d[1] = (uint32_t)(r2); + p->R22.d[3] = (uint32_t)(r2 >> 32); + p->R23.d[1] = (uint32_t)(pad0); + p->R23.d[3] = (uint32_t)(pad0 >> 32); + p->R24.d[1] = (uint32_t)(pad1); + p->R24.d[3] = (uint32_t)(pad1 >> 32); + + /* H = [Mx,My] */ + T5 = _mm_unpacklo_epi64(_mm_loadl_epi64((xmmi *)(m + 0)), + _mm_loadl_epi64((xmmi *)(m + 16))); + T6 = _mm_unpacklo_epi64(_mm_loadl_epi64((xmmi *)(m + 8)), + _mm_loadl_epi64((xmmi *)(m + 24))); + st->H[0] = _mm_and_si128(MMASK, T5); + st->H[1] = _mm_and_si128(MMASK, _mm_srli_epi64(T5, 26)); + T5 = _mm_or_si128(_mm_srli_epi64(T5, 52), _mm_slli_epi64(T6, 12)); + st->H[2] = _mm_and_si128(MMASK, T5); + st->H[3] = _mm_and_si128(MMASK, _mm_srli_epi64(T5, 26)); + st->H[4] = _mm_or_si128(_mm_srli_epi64(T6, 40), HIBIT); +} + +static void poly1305_blocks(poly1305_state_internal *st, const uint8_t *m, + size_t bytes) { + const xmmi MMASK = _mm_load_si128((xmmi *)poly1305_x64_sse2_message_mask); + const xmmi FIVE = _mm_load_si128((xmmi *)poly1305_x64_sse2_5); + const xmmi HIBIT = _mm_load_si128((xmmi *)poly1305_x64_sse2_1shl128); + + poly1305_power *p; + xmmi H0, H1, H2, H3, H4; + xmmi T0, T1, T2, T3, T4, T5, T6; + xmmi M0, M1, M2, M3, M4; + xmmi C1, C2; + + H0 = st->H[0]; + H1 = st->H[1]; + H2 = st->H[2]; + H3 = st->H[3]; + H4 = st->H[4]; + + while (bytes >= 64) { + /* H *= [r^4,r^4] */ + p = &st->P[0]; + T0 = _mm_mul_epu32(H0, p->R20.v); + T1 = _mm_mul_epu32(H0, p->R21.v); + T2 = _mm_mul_epu32(H0, p->R22.v); + T3 = _mm_mul_epu32(H0, p->R23.v); + T4 = _mm_mul_epu32(H0, p->R24.v); + T5 = _mm_mul_epu32(H1, p->S24.v); + T6 = _mm_mul_epu32(H1, p->R20.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(H2, p->S23.v); + T6 = _mm_mul_epu32(H2, p->S24.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(H3, p->S22.v); + T6 = _mm_mul_epu32(H3, p->S23.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(H4, p->S21.v); + T6 = _mm_mul_epu32(H4, p->S22.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(H1, p->R21.v); + T6 = _mm_mul_epu32(H1, p->R22.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(H2, p->R20.v); + T6 = _mm_mul_epu32(H2, p->R21.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(H3, p->S24.v); + T6 = _mm_mul_epu32(H3, p->R20.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(H4, p->S23.v); + T6 = _mm_mul_epu32(H4, p->S24.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(H1, p->R23.v); + T4 = _mm_add_epi64(T4, T5); + T5 = _mm_mul_epu32(H2, p->R22.v); + T4 = _mm_add_epi64(T4, T5); + T5 = _mm_mul_epu32(H3, p->R21.v); + T4 = _mm_add_epi64(T4, T5); + T5 = _mm_mul_epu32(H4, p->R20.v); + T4 = _mm_add_epi64(T4, T5); + + /* H += [Mx,My]*[r^2,r^2] */ + T5 = _mm_unpacklo_epi64(_mm_loadl_epi64((xmmi *)(m + 0)), + _mm_loadl_epi64((xmmi *)(m + 16))); + T6 = _mm_unpacklo_epi64(_mm_loadl_epi64((xmmi *)(m + 8)), + _mm_loadl_epi64((xmmi *)(m + 24))); + M0 = _mm_and_si128(MMASK, T5); + M1 = _mm_and_si128(MMASK, _mm_srli_epi64(T5, 26)); + T5 = _mm_or_si128(_mm_srli_epi64(T5, 52), _mm_slli_epi64(T6, 12)); + M2 = _mm_and_si128(MMASK, T5); + M3 = _mm_and_si128(MMASK, _mm_srli_epi64(T5, 26)); + M4 = _mm_or_si128(_mm_srli_epi64(T6, 40), HIBIT); + + p = &st->P[1]; + T5 = _mm_mul_epu32(M0, p->R20.v); + T6 = _mm_mul_epu32(M0, p->R21.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(M1, p->S24.v); + T6 = _mm_mul_epu32(M1, p->R20.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(M2, p->S23.v); + T6 = _mm_mul_epu32(M2, p->S24.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(M3, p->S22.v); + T6 = _mm_mul_epu32(M3, p->S23.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(M4, p->S21.v); + T6 = _mm_mul_epu32(M4, p->S22.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(M0, p->R22.v); + T6 = _mm_mul_epu32(M0, p->R23.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(M1, p->R21.v); + T6 = _mm_mul_epu32(M1, p->R22.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(M2, p->R20.v); + T6 = _mm_mul_epu32(M2, p->R21.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(M3, p->S24.v); + T6 = _mm_mul_epu32(M3, p->R20.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(M4, p->S23.v); + T6 = _mm_mul_epu32(M4, p->S24.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(M0, p->R24.v); + T4 = _mm_add_epi64(T4, T5); + T5 = _mm_mul_epu32(M1, p->R23.v); + T4 = _mm_add_epi64(T4, T5); + T5 = _mm_mul_epu32(M2, p->R22.v); + T4 = _mm_add_epi64(T4, T5); + T5 = _mm_mul_epu32(M3, p->R21.v); + T4 = _mm_add_epi64(T4, T5); + T5 = _mm_mul_epu32(M4, p->R20.v); + T4 = _mm_add_epi64(T4, T5); + + /* H += [Mx,My] */ + T5 = _mm_unpacklo_epi64(_mm_loadl_epi64((xmmi *)(m + 32)), + _mm_loadl_epi64((xmmi *)(m + 48))); + T6 = _mm_unpacklo_epi64(_mm_loadl_epi64((xmmi *)(m + 40)), + _mm_loadl_epi64((xmmi *)(m + 56))); + M0 = _mm_and_si128(MMASK, T5); + M1 = _mm_and_si128(MMASK, _mm_srli_epi64(T5, 26)); + T5 = _mm_or_si128(_mm_srli_epi64(T5, 52), _mm_slli_epi64(T6, 12)); + M2 = _mm_and_si128(MMASK, T5); + M3 = _mm_and_si128(MMASK, _mm_srli_epi64(T5, 26)); + M4 = _mm_or_si128(_mm_srli_epi64(T6, 40), HIBIT); + + T0 = _mm_add_epi64(T0, M0); + T1 = _mm_add_epi64(T1, M1); + T2 = _mm_add_epi64(T2, M2); + T3 = _mm_add_epi64(T3, M3); + T4 = _mm_add_epi64(T4, M4); + + /* reduce */ + C1 = _mm_srli_epi64(T0, 26); + C2 = _mm_srli_epi64(T3, 26); + T0 = _mm_and_si128(T0, MMASK); + T3 = _mm_and_si128(T3, MMASK); + T1 = _mm_add_epi64(T1, C1); + T4 = _mm_add_epi64(T4, C2); + C1 = _mm_srli_epi64(T1, 26); + C2 = _mm_srli_epi64(T4, 26); + T1 = _mm_and_si128(T1, MMASK); + T4 = _mm_and_si128(T4, MMASK); + T2 = _mm_add_epi64(T2, C1); + T0 = _mm_add_epi64(T0, _mm_mul_epu32(C2, FIVE)); + C1 = _mm_srli_epi64(T2, 26); + C2 = _mm_srli_epi64(T0, 26); + T2 = _mm_and_si128(T2, MMASK); + T0 = _mm_and_si128(T0, MMASK); + T3 = _mm_add_epi64(T3, C1); + T1 = _mm_add_epi64(T1, C2); + C1 = _mm_srli_epi64(T3, 26); + T3 = _mm_and_si128(T3, MMASK); + T4 = _mm_add_epi64(T4, C1); + + /* H = (H*[r^4,r^4] + [Mx,My]*[r^2,r^2] + [Mx,My]) */ + H0 = T0; + H1 = T1; + H2 = T2; + H3 = T3; + H4 = T4; + + m += 64; + bytes -= 64; + } + + st->H[0] = H0; + st->H[1] = H1; + st->H[2] = H2; + st->H[3] = H3; + st->H[4] = H4; +} + +static size_t poly1305_combine(poly1305_state_internal *st, const uint8_t *m, + size_t bytes) { + const xmmi MMASK = _mm_load_si128((xmmi *)poly1305_x64_sse2_message_mask); + const xmmi HIBIT = _mm_load_si128((xmmi *)poly1305_x64_sse2_1shl128); + const xmmi FIVE = _mm_load_si128((xmmi *)poly1305_x64_sse2_5); + + poly1305_power *p; + xmmi H0, H1, H2, H3, H4; + xmmi M0, M1, M2, M3, M4; + xmmi T0, T1, T2, T3, T4, T5, T6; + xmmi C1, C2; + + uint64_t r0, r1, r2; + uint64_t t0, t1, t2, t3, t4; + uint64_t c; + size_t consumed = 0; + + H0 = st->H[0]; + H1 = st->H[1]; + H2 = st->H[2]; + H3 = st->H[3]; + H4 = st->H[4]; + + /* p = [r^2,r^2] */ + p = &st->P[1]; + + if (bytes >= 32) { + /* H *= [r^2,r^2] */ + T0 = _mm_mul_epu32(H0, p->R20.v); + T1 = _mm_mul_epu32(H0, p->R21.v); + T2 = _mm_mul_epu32(H0, p->R22.v); + T3 = _mm_mul_epu32(H0, p->R23.v); + T4 = _mm_mul_epu32(H0, p->R24.v); + T5 = _mm_mul_epu32(H1, p->S24.v); + T6 = _mm_mul_epu32(H1, p->R20.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(H2, p->S23.v); + T6 = _mm_mul_epu32(H2, p->S24.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(H3, p->S22.v); + T6 = _mm_mul_epu32(H3, p->S23.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(H4, p->S21.v); + T6 = _mm_mul_epu32(H4, p->S22.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(H1, p->R21.v); + T6 = _mm_mul_epu32(H1, p->R22.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(H2, p->R20.v); + T6 = _mm_mul_epu32(H2, p->R21.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(H3, p->S24.v); + T6 = _mm_mul_epu32(H3, p->R20.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(H4, p->S23.v); + T6 = _mm_mul_epu32(H4, p->S24.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(H1, p->R23.v); + T4 = _mm_add_epi64(T4, T5); + T5 = _mm_mul_epu32(H2, p->R22.v); + T4 = _mm_add_epi64(T4, T5); + T5 = _mm_mul_epu32(H3, p->R21.v); + T4 = _mm_add_epi64(T4, T5); + T5 = _mm_mul_epu32(H4, p->R20.v); + T4 = _mm_add_epi64(T4, T5); + + /* H += [Mx,My] */ + T5 = _mm_unpacklo_epi64(_mm_loadl_epi64((xmmi *)(m + 0)), + _mm_loadl_epi64((xmmi *)(m + 16))); + T6 = _mm_unpacklo_epi64(_mm_loadl_epi64((xmmi *)(m + 8)), + _mm_loadl_epi64((xmmi *)(m + 24))); + M0 = _mm_and_si128(MMASK, T5); + M1 = _mm_and_si128(MMASK, _mm_srli_epi64(T5, 26)); + T5 = _mm_or_si128(_mm_srli_epi64(T5, 52), _mm_slli_epi64(T6, 12)); + M2 = _mm_and_si128(MMASK, T5); + M3 = _mm_and_si128(MMASK, _mm_srli_epi64(T5, 26)); + M4 = _mm_or_si128(_mm_srli_epi64(T6, 40), HIBIT); + + T0 = _mm_add_epi64(T0, M0); + T1 = _mm_add_epi64(T1, M1); + T2 = _mm_add_epi64(T2, M2); + T3 = _mm_add_epi64(T3, M3); + T4 = _mm_add_epi64(T4, M4); + + /* reduce */ + C1 = _mm_srli_epi64(T0, 26); + C2 = _mm_srli_epi64(T3, 26); + T0 = _mm_and_si128(T0, MMASK); + T3 = _mm_and_si128(T3, MMASK); + T1 = _mm_add_epi64(T1, C1); + T4 = _mm_add_epi64(T4, C2); + C1 = _mm_srli_epi64(T1, 26); + C2 = _mm_srli_epi64(T4, 26); + T1 = _mm_and_si128(T1, MMASK); + T4 = _mm_and_si128(T4, MMASK); + T2 = _mm_add_epi64(T2, C1); + T0 = _mm_add_epi64(T0, _mm_mul_epu32(C2, FIVE)); + C1 = _mm_srli_epi64(T2, 26); + C2 = _mm_srli_epi64(T0, 26); + T2 = _mm_and_si128(T2, MMASK); + T0 = _mm_and_si128(T0, MMASK); + T3 = _mm_add_epi64(T3, C1); + T1 = _mm_add_epi64(T1, C2); + C1 = _mm_srli_epi64(T3, 26); + T3 = _mm_and_si128(T3, MMASK); + T4 = _mm_add_epi64(T4, C1); + + /* H = (H*[r^2,r^2] + [Mx,My]) */ + H0 = T0; + H1 = T1; + H2 = T2; + H3 = T3; + H4 = T4; + + consumed = 32; + } + + /* finalize, H *= [r^2,r] */ + r0 = ((uint64_t)p->R20.d[3] << 32) | (uint64_t)p->R20.d[1]; + r1 = ((uint64_t)p->R21.d[3] << 32) | (uint64_t)p->R21.d[1]; + r2 = ((uint64_t)p->R22.d[3] << 32) | (uint64_t)p->R22.d[1]; + + p->R20.d[2] = (uint32_t)(r0)&0x3ffffff; + p->R21.d[2] = (uint32_t)((r0 >> 26) | (r1 << 18)) & 0x3ffffff; + p->R22.d[2] = (uint32_t)((r1 >> 8)) & 0x3ffffff; + p->R23.d[2] = (uint32_t)((r1 >> 34) | (r2 << 10)) & 0x3ffffff; + p->R24.d[2] = (uint32_t)((r2 >> 16)); + p->S21.d[2] = p->R21.d[2] * 5; + p->S22.d[2] = p->R22.d[2] * 5; + p->S23.d[2] = p->R23.d[2] * 5; + p->S24.d[2] = p->R24.d[2] * 5; + + /* H *= [r^2,r] */ + T0 = _mm_mul_epu32(H0, p->R20.v); + T1 = _mm_mul_epu32(H0, p->R21.v); + T2 = _mm_mul_epu32(H0, p->R22.v); + T3 = _mm_mul_epu32(H0, p->R23.v); + T4 = _mm_mul_epu32(H0, p->R24.v); + T5 = _mm_mul_epu32(H1, p->S24.v); + T6 = _mm_mul_epu32(H1, p->R20.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(H2, p->S23.v); + T6 = _mm_mul_epu32(H2, p->S24.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(H3, p->S22.v); + T6 = _mm_mul_epu32(H3, p->S23.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(H4, p->S21.v); + T6 = _mm_mul_epu32(H4, p->S22.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(H1, p->R21.v); + T6 = _mm_mul_epu32(H1, p->R22.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(H2, p->R20.v); + T6 = _mm_mul_epu32(H2, p->R21.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(H3, p->S24.v); + T6 = _mm_mul_epu32(H3, p->R20.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(H4, p->S23.v); + T6 = _mm_mul_epu32(H4, p->S24.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(H1, p->R23.v); + T4 = _mm_add_epi64(T4, T5); + T5 = _mm_mul_epu32(H2, p->R22.v); + T4 = _mm_add_epi64(T4, T5); + T5 = _mm_mul_epu32(H3, p->R21.v); + T4 = _mm_add_epi64(T4, T5); + T5 = _mm_mul_epu32(H4, p->R20.v); + T4 = _mm_add_epi64(T4, T5); + + C1 = _mm_srli_epi64(T0, 26); + C2 = _mm_srli_epi64(T3, 26); + T0 = _mm_and_si128(T0, MMASK); + T3 = _mm_and_si128(T3, MMASK); + T1 = _mm_add_epi64(T1, C1); + T4 = _mm_add_epi64(T4, C2); + C1 = _mm_srli_epi64(T1, 26); + C2 = _mm_srli_epi64(T4, 26); + T1 = _mm_and_si128(T1, MMASK); + T4 = _mm_and_si128(T4, MMASK); + T2 = _mm_add_epi64(T2, C1); + T0 = _mm_add_epi64(T0, _mm_mul_epu32(C2, FIVE)); + C1 = _mm_srli_epi64(T2, 26); + C2 = _mm_srli_epi64(T0, 26); + T2 = _mm_and_si128(T2, MMASK); + T0 = _mm_and_si128(T0, MMASK); + T3 = _mm_add_epi64(T3, C1); + T1 = _mm_add_epi64(T1, C2); + C1 = _mm_srli_epi64(T3, 26); + T3 = _mm_and_si128(T3, MMASK); + T4 = _mm_add_epi64(T4, C1); + + /* H = H[0]+H[1] */ + H0 = _mm_add_epi64(T0, _mm_srli_si128(T0, 8)); + H1 = _mm_add_epi64(T1, _mm_srli_si128(T1, 8)); + H2 = _mm_add_epi64(T2, _mm_srli_si128(T2, 8)); + H3 = _mm_add_epi64(T3, _mm_srli_si128(T3, 8)); + H4 = _mm_add_epi64(T4, _mm_srli_si128(T4, 8)); + + t0 = _mm_cvtsi128_si32(H0); + c = (t0 >> 26); + t0 &= 0x3ffffff; + t1 = _mm_cvtsi128_si32(H1) + c; + c = (t1 >> 26); + t1 &= 0x3ffffff; + t2 = _mm_cvtsi128_si32(H2) + c; + c = (t2 >> 26); + t2 &= 0x3ffffff; + t3 = _mm_cvtsi128_si32(H3) + c; + c = (t3 >> 26); + t3 &= 0x3ffffff; + t4 = _mm_cvtsi128_si32(H4) + c; + c = (t4 >> 26); + t4 &= 0x3ffffff; + t0 = t0 + (c * 5); + c = (t0 >> 26); + t0 &= 0x3ffffff; + t1 = t1 + c; + + st->HH[0] = ((t0) | (t1 << 26)) & 0xfffffffffffull; + st->HH[1] = ((t1 >> 18) | (t2 << 8) | (t3 << 34)) & 0xfffffffffffull; + st->HH[2] = ((t3 >> 10) | (t4 << 16)) & 0x3ffffffffffull; + + return consumed; +} + +void CRYPTO_poly1305_update(poly1305_state *state, const uint8_t *m, + size_t bytes) { + poly1305_state_internal *st = poly1305_aligned_state(state); + size_t want; + + /* need at least 32 initial bytes to start the accelerated branch */ + if (!st->started) { + if ((st->leftover == 0) && (bytes > 32)) { + poly1305_first_block(st, m); + m += 32; + bytes -= 32; + } else { + want = poly1305_min(32 - st->leftover, bytes); + poly1305_block_copy(st->buffer + st->leftover, m, want); + bytes -= want; + m += want; + st->leftover += want; + if ((st->leftover < 32) || (bytes == 0)) { + return; + } + poly1305_first_block(st, st->buffer); + st->leftover = 0; + } + st->started = 1; + } + + /* handle leftover */ + if (st->leftover) { + want = poly1305_min(64 - st->leftover, bytes); + poly1305_block_copy(st->buffer + st->leftover, m, want); + bytes -= want; + m += want; + st->leftover += want; + if (st->leftover < 64) { + return; + } + poly1305_blocks(st, st->buffer, 64); + st->leftover = 0; + } + + /* process 64 byte blocks */ + if (bytes >= 64) { + want = (bytes & ~63); + poly1305_blocks(st, m, want); + m += want; + bytes -= want; + } + + if (bytes) { + poly1305_block_copy(st->buffer + st->leftover, m, bytes); + st->leftover += bytes; + } +} + +void CRYPTO_poly1305_finish(poly1305_state *state, uint8_t mac[16]) { + poly1305_state_internal *st = poly1305_aligned_state(state); + size_t leftover = st->leftover; + uint8_t *m = st->buffer; + uint128_t d[3]; + uint64_t h0, h1, h2; + uint64_t t0, t1; + uint64_t g0, g1, g2, c, nc; + uint64_t r0, r1, r2, s1, s2; + poly1305_power *p; + + if (st->started) { + size_t consumed = poly1305_combine(st, m, leftover); + leftover -= consumed; + m += consumed; + } + + /* st->HH will either be 0 or have the combined result */ + h0 = st->HH[0]; + h1 = st->HH[1]; + h2 = st->HH[2]; + + p = &st->P[1]; + r0 = ((uint64_t)p->R20.d[3] << 32) | (uint64_t)p->R20.d[1]; + r1 = ((uint64_t)p->R21.d[3] << 32) | (uint64_t)p->R21.d[1]; + r2 = ((uint64_t)p->R22.d[3] << 32) | (uint64_t)p->R22.d[1]; + s1 = r1 * (5 << 2); + s2 = r2 * (5 << 2); + + if (leftover < 16) { + goto poly1305_donna_atmost15bytes; + } + +poly1305_donna_atleast16bytes: + t0 = U8TO64_LE(m + 0); + t1 = U8TO64_LE(m + 8); + h0 += t0 & 0xfffffffffff; + t0 = shr128_pair(t1, t0, 44); + h1 += t0 & 0xfffffffffff; + h2 += (t1 >> 24) | ((uint64_t)1 << 40); + +poly1305_donna_mul: + d[0] = add128(add128(mul64x64_128(h0, r0), mul64x64_128(h1, s2)), + mul64x64_128(h2, s1)); + d[1] = add128(add128(mul64x64_128(h0, r1), mul64x64_128(h1, r0)), + mul64x64_128(h2, s2)); + d[2] = add128(add128(mul64x64_128(h0, r2), mul64x64_128(h1, r1)), + mul64x64_128(h2, r0)); + h0 = lo128(d[0]) & 0xfffffffffff; + c = shr128(d[0], 44); + d[1] = add128_64(d[1], c); + h1 = lo128(d[1]) & 0xfffffffffff; + c = shr128(d[1], 44); + d[2] = add128_64(d[2], c); + h2 = lo128(d[2]) & 0x3ffffffffff; + c = shr128(d[2], 42); + h0 += c * 5; + + m += 16; + leftover -= 16; + if (leftover >= 16) { + goto poly1305_donna_atleast16bytes; + } + +/* final bytes */ +poly1305_donna_atmost15bytes: + if (!leftover) { + goto poly1305_donna_finish; + } + + m[leftover++] = 1; + poly1305_block_zero(m + leftover, 16 - leftover); + leftover = 16; + + t0 = U8TO64_LE(m + 0); + t1 = U8TO64_LE(m + 8); + h0 += t0 & 0xfffffffffff; + t0 = shr128_pair(t1, t0, 44); + h1 += t0 & 0xfffffffffff; + h2 += (t1 >> 24); + + goto poly1305_donna_mul; + +poly1305_donna_finish: + c = (h0 >> 44); + h0 &= 0xfffffffffff; + h1 += c; + c = (h1 >> 44); + h1 &= 0xfffffffffff; + h2 += c; + c = (h2 >> 42); + h2 &= 0x3ffffffffff; + h0 += c * 5; + + g0 = h0 + 5; + c = (g0 >> 44); + g0 &= 0xfffffffffff; + g1 = h1 + c; + c = (g1 >> 44); + g1 &= 0xfffffffffff; + g2 = h2 + c - ((uint64_t)1 << 42); + + c = (g2 >> 63) - 1; + nc = ~c; + h0 = (h0 & nc) | (g0 & c); + h1 = (h1 & nc) | (g1 & c); + h2 = (h2 & nc) | (g2 & c); + + /* pad */ + t0 = ((uint64_t)p->R23.d[3] << 32) | (uint64_t)p->R23.d[1]; + t1 = ((uint64_t)p->R24.d[3] << 32) | (uint64_t)p->R24.d[1]; + h0 += (t0 & 0xfffffffffff); + c = (h0 >> 44); + h0 &= 0xfffffffffff; + t0 = shr128_pair(t1, t0, 44); + h1 += (t0 & 0xfffffffffff) + c; + c = (h1 >> 44); + h1 &= 0xfffffffffff; + t1 = (t1 >> 24); + h2 += (t1)+c; + + U64TO8_LE(mac + 0, ((h0) | (h1 << 44))); + U64TO8_LE(mac + 8, ((h1 >> 20) | (h2 << 24))); +} + +#endif /* !OPENSSL_WINDOWS && OPENSSL_X86_64 */ diff --git a/TMessagesProj/jni/boringssl/crypto/rand/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/rand/CMakeLists.txt new file mode 100644 index 00000000..374d8f17 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rand/CMakeLists.txt @@ -0,0 +1,24 @@ +include_directories(. .. ../../include) + +if (${ARCH} STREQUAL "x86_64") + set( + RAND_ARCH_SOURCES + + rdrand-x86_64.${ASM_EXT} + ) +endif() + +add_library( + rand + + OBJECT + + rand.c + urandom.c + windows.c + hwrand.c + + ${RAND_ARCH_SOURCES} +) + +perlasm(rdrand-x86_64.${ASM_EXT} asm/rdrand-x86_64.pl) diff --git a/TMessagesProj/jni/boringssl/crypto/rand/asm/rdrand-x86_64.pl b/TMessagesProj/jni/boringssl/crypto/rand/asm/rdrand-x86_64.pl new file mode 100644 index 00000000..c32a55c4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rand/asm/rdrand-x86_64.pl @@ -0,0 +1,75 @@ +#!/usr/bin/env perl + +# Copyright (c) 2015, Google Inc. +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +$flavour = shift; +$output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or +die "can't locate x86_64-xlate.pl"; + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +print<<___; +.text + +# CRYPTO_rdrand writes eight bytes of random data from the hardware RNG to +# |out|. It returns one on success or zero on hardware failure. +# int CRYPTO_rdrand(uint8_t out[8]); +.globl CRYPTO_rdrand +.type CRYPTO_rdrand,\@function,1 +.align 16 +CRYPTO_rdrand: + xorq %rax, %rax + # This is rdrand %rcx. It sets rcx to a random value and sets the carry + # flag on success. + .byte 0x48, 0x0f, 0xc7, 0xf1 + # An add-with-carry of zero effectively sets %rax to the carry flag. + adcq %rax, %rax + movq %rcx, 0(%rdi) + retq + +# CRYPTO_rdrand_multiple8_buf fills |len| bytes at |buf| with random data from +# the hardware RNG. The |len| argument must be a multiple of eight. It returns +# one on success and zero on hardware failure. +# int CRYPTO_rdrand_multiple8_buf(uint8_t *buf, size_t len); +.globl CRYPTO_rdrand_multiple8_buf +.type CRYPTO_rdrand_multiple8_buf,\@function,2 +.align 16 +CRYPTO_rdrand_multiple8_buf: + test %rsi, %rsi + jz .Lout + movq \$8, %rdx +.Lloop: + # This is rdrand %rcx. It sets rcx to a random value and sets the carry + # flag on success. + .byte 0x48, 0x0f, 0xc7, 0xf1 + jnc .Lerr + movq %rcx, 0(%rdi) + addq %rdx, %rdi + subq %rdx, %rsi + jnz .Lloop +.Lout: + movq \$1, %rax + retq +.Lerr: + xorq %rax, %rax + retq +___ + +close STDOUT; # flush diff --git a/TMessagesProj/jni/boringssl/crypto/rand/hwrand.c b/TMessagesProj/jni/boringssl/crypto/rand/hwrand.c new file mode 100644 index 00000000..f0bbccd2 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rand/hwrand.c @@ -0,0 +1,65 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#include +#include + +#include + +#include "internal.h" + + +#if defined(OPENSSL_X86_64) && !defined(OPENSSL_NO_ASM) + +/* These functions are defined in asm/rdrand-x86_64.pl */ +extern int CRYPTO_rdrand(uint8_t out[8]); +extern int CRYPTO_rdrand_multiple8_buf(uint8_t *buf, size_t len); + +static int have_rdrand(void) { + return (OPENSSL_ia32cap_P[1] & (1u << 30)) != 0; +} + +int CRYPTO_hwrand(uint8_t *buf, size_t len) { + if (!have_rdrand()) { + return 0; + } + + const size_t len_multiple8 = len & ~7; + if (!CRYPTO_rdrand_multiple8_buf(buf, len_multiple8)) { + return 0; + } + len -= len_multiple8; + + if (len != 0) { + assert(len < 8); + + uint8_t rand_buf[8]; + if (!CRYPTO_rdrand(rand_buf)) { + return 0; + } + memcpy(buf + len_multiple8, rand_buf, len); + } + + return 1; +} + +#else + +int CRYPTO_hwrand(uint8_t *buf, size_t len) { + return 0; +} + +#endif diff --git a/TMessagesProj/jni/boringssl/crypto/rand/internal.h b/TMessagesProj/jni/boringssl/crypto/rand/internal.h new file mode 100644 index 00000000..f35abbbe --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rand/internal.h @@ -0,0 +1,37 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_CRYPTO_RAND_INTERNAL_H +#define OPENSSL_HEADER_CRYPTO_RAND_INTERNAL_H + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* CRYPTO_sysrand fills |len| bytes at |buf| with entropy from the operating + * system. */ +void CRYPTO_sysrand(uint8_t *buf, size_t len); + +/* CRYPTO_hwrand fills |len| bytes at |buf| with entropy from the hardware. It + * returns one on success or zero on hardware failure or if hardware support is + * unavailable. */ +int CRYPTO_hwrand(uint8_t *buf, size_t len); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_CRYPTO_RAND_INTERNAL_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/rand/rand.c b/TMessagesProj/jni/boringssl/crypto/rand/rand.c new file mode 100644 index 00000000..e76a120d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rand/rand.c @@ -0,0 +1,186 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#include +#include + +#include +#include + +#include "internal.h" +#include "../internal.h" + + +/* It's assumed that the operating system always has an unfailing source of + * entropy which is accessed via |CRYPTO_sysrand|. (If the operating system + * entropy source fails, it's up to |CRYPTO_sysrand| to abort the process—we + * don't try to handle it.) + * + * In addition, the hardware may provide a low-latency RNG. Intel's rdrand + * instruction is the canonical example of this. When a hardware RNG is + * available we don't need to worry about an RNG failure arising from fork()ing + * the process or moving a VM, so we can keep thread-local RNG state and XOR + * the hardware entropy in. + * + * (We assume that the OS entropy is safe from fork()ing and VM duplication. + * This might be a bit of a leap of faith, esp on Windows, but there's nothing + * that we can do about it.) */ + +/* rand_thread_state contains the per-thread state for the RNG. This is only + * used if the system has support for a hardware RNG. */ +struct rand_thread_state { + uint8_t key[32]; + uint64_t calls_used; + size_t bytes_used; + uint8_t partial_block[64]; + unsigned partial_block_used; +}; + +/* kMaxCallsPerRefresh is the maximum number of |RAND_bytes| calls that we'll + * serve before reading a new key from the operating system. This only applies + * if we have a hardware RNG. */ +static const unsigned kMaxCallsPerRefresh = 1024; + +/* kMaxBytesPerRefresh is the maximum number of bytes that we'll return from + * |RAND_bytes| before reading a new key from the operating system. This only + * applies if we have a hardware RNG. */ +static const uint64_t kMaxBytesPerRefresh = 1024 * 1024; + +/* rand_thread_state_free frees a |rand_thread_state|. This is called when a + * thread exits. */ +static void rand_thread_state_free(void *state) { + if (state == NULL) { + return; + } + + OPENSSL_cleanse(state, sizeof(struct rand_thread_state)); + OPENSSL_free(state); +} + +int RAND_bytes(uint8_t *buf, size_t len) { + if (len == 0) { + return 1; + } + + if (!CRYPTO_hwrand(buf, len)) { + /* Without a hardware RNG to save us from address-space duplication, the OS + * entropy is used directly. */ + CRYPTO_sysrand(buf, len); + return 1; + } + + struct rand_thread_state *state = + CRYPTO_get_thread_local(OPENSSL_THREAD_LOCAL_RAND); + if (state == NULL) { + state = OPENSSL_malloc(sizeof(struct rand_thread_state)); + if (state == NULL || + !CRYPTO_set_thread_local(OPENSSL_THREAD_LOCAL_RAND, state, + rand_thread_state_free)) { + CRYPTO_sysrand(buf, len); + return 1; + } + + memset(state->partial_block, 0, sizeof(state->partial_block)); + state->calls_used = kMaxCallsPerRefresh; + } + + if (state->calls_used >= kMaxCallsPerRefresh || + state->bytes_used >= kMaxBytesPerRefresh) { + CRYPTO_sysrand(state->key, sizeof(state->key)); + state->calls_used = 0; + state->bytes_used = 0; + state->partial_block_used = sizeof(state->partial_block); + } + + if (len >= sizeof(state->partial_block)) { + size_t remaining = len; + while (remaining > 0) { + // kMaxBytesPerCall is only 2GB, while ChaCha can handle 256GB. But this + // is sufficient and easier on 32-bit. + static const size_t kMaxBytesPerCall = 0x80000000; + size_t todo = remaining; + if (todo > kMaxBytesPerCall) { + todo = kMaxBytesPerCall; + } + CRYPTO_chacha_20(buf, buf, todo, state->key, + (uint8_t *)&state->calls_used, 0); + buf += todo; + remaining -= todo; + state->calls_used++; + } + } else { + if (sizeof(state->partial_block) - state->partial_block_used < len) { + CRYPTO_chacha_20(state->partial_block, state->partial_block, + sizeof(state->partial_block), state->key, + (uint8_t *)&state->calls_used, 0); + state->partial_block_used = 0; + } + + unsigned i; + for (i = 0; i < len; i++) { + buf[i] ^= state->partial_block[state->partial_block_used++]; + } + state->calls_used++; + } + state->bytes_used += len; + + return 1; +} + +int RAND_pseudo_bytes(uint8_t *buf, size_t len) { + return RAND_bytes(buf, len); +} + +void RAND_seed(const void *buf, int num) {} + +int RAND_load_file(const char *path, long num) { + if (num < 0) { /* read the "whole file" */ + return 1; + } else if (num <= INT_MAX) { + return (int) num; + } else { + return INT_MAX; + } +} + +void RAND_add(const void *buf, int num, double entropy) {} + +int RAND_egd(const char *path) { + return 255; +} + +int RAND_poll(void) { + return 1; +} + +int RAND_status(void) { + return 1; +} + +static const struct rand_meth_st kSSLeayMethod = { + RAND_seed, + RAND_bytes, + RAND_cleanup, + RAND_add, + RAND_pseudo_bytes, + RAND_status, +}; + +RAND_METHOD *RAND_SSLeay(void) { + return (RAND_METHOD*) &kSSLeayMethod; +} + +void RAND_set_rand_method(const RAND_METHOD *method) {} diff --git a/TMessagesProj/jni/boringssl/crypto/rand/urandom.c b/TMessagesProj/jni/boringssl/crypto/rand/urandom.c new file mode 100644 index 00000000..d7ed5c62 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rand/urandom.c @@ -0,0 +1,264 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#if !defined(OPENSSL_WINDOWS) + +#include +#include +#include +#include +#include + +#include +#include + +#include "internal.h" +#include "../internal.h" + + +/* This file implements a PRNG by reading from /dev/urandom, optionally with a + * fork-safe buffer. + * + * If buffering is enabled then it maintains a global, linked list of buffers. + * Threads which need random bytes grab a buffer from the list under a lock and + * copy out the bytes that they need. In the rare case that the buffer is + * empty, it's refilled from /dev/urandom outside of the lock. + * + * Large requests are always serviced from /dev/urandom directly. + * + * Each buffer contains the PID of the process that created it and it's tested + * against the current PID each time. Thus processes that fork will discard all + * the buffers filled by the parent process. There are two problems with this: + * + * 1) glibc maintains a cache of the current PID+PPID and, if this cache isn't + * correctly invalidated, the getpid() will continue to believe that + * it's the old process. Glibc depends on the glibc wrappers for fork, + * vfork and clone being used in order to invalidate the getpid() cache. + * + * 2) If a process forks, dies and then its child forks, it's possible that + * the third process will end up with the same PID as the original process. + * If the second process never used any random values then this will mean + * that the third process has stale, cached values and won't notice. + */ + +/* BUF_SIZE is intended to be a 4K allocation with malloc overhead. struct + * rand_buffer also fits in this space and the remainder is entropy. */ +#define BUF_SIZE (4096 - 16) + +/* rand_buffer contains unused, random bytes. These structures form a linked + * list via the |next| pointer, which is NULL in the final element. */ +struct rand_buffer { + size_t used; /* used contains the number of bytes of |rand| that have + been consumed. */ + struct rand_buffer *next; + pid_t pid; /* pid contains the pid at the time that the buffer was + created so that data is not duplicated after a fork. */ + pid_t ppid; /* ppid contains the parent pid in order to try and reduce + the possibility of duplicated PID confusing the + detection of a fork. */ + uint8_t rand[]; +}; + +/* rand_bytes_per_buf is the number of actual entropy bytes in a buffer. */ +static const size_t rand_bytes_per_buf = BUF_SIZE - sizeof(struct rand_buffer); + +static struct CRYPTO_STATIC_MUTEX global_lock = CRYPTO_STATIC_MUTEX_INIT; + +/* list_head is the start of a global, linked-list of rand_buffer objects. It's + * protected by |global_lock|. */ +static struct rand_buffer *list_head; + +/* urandom_fd is a file descriptor to /dev/urandom. It's protected by + * |global_lock|. */ +static int urandom_fd = -2; + +/* urandom_buffering controls whether buffering is enabled (1) or not (0). This + * is protected by |global_lock|. */ +static int urandom_buffering = 0; + +/* urandom_get_fd_locked returns a file descriptor to /dev/urandom. The caller + * of this function must hold |global_lock|. */ +static int urandom_get_fd_locked(void) { + if (urandom_fd != -2) { + return urandom_fd; + } + + do { + urandom_fd = open("/dev/urandom", O_RDONLY); + } while (urandom_fd == -1 && errno == EINTR); + return urandom_fd; +} + +/* RAND_cleanup frees all buffers, closes any cached file descriptor + * and resets the global state. */ +void RAND_cleanup(void) { + struct rand_buffer *cur; + + CRYPTO_STATIC_MUTEX_lock_write(&global_lock); + while ((cur = list_head)) { + list_head = cur->next; + OPENSSL_free(cur); + } + if (urandom_fd >= 0) { + close(urandom_fd); + } + urandom_fd = -2; + list_head = NULL; + CRYPTO_STATIC_MUTEX_unlock(&global_lock); +} + +void RAND_set_urandom_fd(int fd) { + CRYPTO_STATIC_MUTEX_lock_write(&global_lock); + if (urandom_fd != -2) { + /* |RAND_set_urandom_fd| may not be called after the RNG is used. */ + abort(); + } + do { + urandom_fd = dup(fd); + } while (urandom_fd == -1 && errno == EINTR); + if (urandom_fd < 0) { + abort(); + } + CRYPTO_STATIC_MUTEX_unlock(&global_lock); +} + +/* read_full reads exactly |len| bytes from |fd| into |out| and returns 1. In + * the case of an error it returns 0. */ +static char read_full(int fd, uint8_t *out, size_t len) { + ssize_t r; + + while (len > 0) { + do { + r = read(fd, out, len); + } while (r == -1 && errno == EINTR); + + if (r <= 0) { + return 0; + } + out += r; + len -= r; + } + + return 1; +} + +/* CRYPTO_sysrand puts |num| random bytes into |out|. */ +void CRYPTO_sysrand(uint8_t *out, size_t requested) { + int fd; + struct rand_buffer *buf; + size_t todo; + pid_t pid, ppid; + + if (requested == 0) { + return; + } + + CRYPTO_STATIC_MUTEX_lock_write(&global_lock); + fd = urandom_get_fd_locked(); + + if (fd < 0) { + CRYPTO_STATIC_MUTEX_unlock(&global_lock); + abort(); + return; + } + + /* If buffering is not enabled, or if the request is large, then the + * result comes directly from urandom. */ + if (!urandom_buffering || requested > BUF_SIZE / 2) { + CRYPTO_STATIC_MUTEX_unlock(&global_lock); + if (!read_full(fd, out, requested)) { + abort(); + } + return; + } + + pid = getpid(); + ppid = getppid(); + + for (;;) { + buf = list_head; + if (buf && buf->pid == pid && buf->ppid == ppid && + rand_bytes_per_buf - buf->used >= requested) { + memcpy(out, &buf->rand[buf->used], requested); + buf->used += requested; + CRYPTO_STATIC_MUTEX_unlock(&global_lock); + return; + } + + /* If we don't immediately have enough entropy with the correct + * PID, remove the buffer from the list in order to gain + * exclusive access and unlock. */ + if (buf) { + list_head = buf->next; + } + CRYPTO_STATIC_MUTEX_unlock(&global_lock); + + if (!buf) { + buf = (struct rand_buffer *)OPENSSL_malloc(BUF_SIZE); + if (!buf) { + abort(); + return; + } + /* The buffer doesn't contain any random bytes yet + * so we mark it as fully used so that it will be + * filled below. */ + buf->used = rand_bytes_per_buf; + buf->next = NULL; + buf->pid = pid; + buf->ppid = ppid; + } + + if (buf->pid == pid && buf->ppid == ppid) { + break; + } + + /* We have forked and so cannot use these bytes as they + * may have been used in another process. */ + OPENSSL_free(buf); + CRYPTO_STATIC_MUTEX_lock_write(&global_lock); + } + + while (requested > 0) { + todo = rand_bytes_per_buf - buf->used; + if (todo > requested) { + todo = requested; + } + memcpy(out, &buf->rand[buf->used], todo); + requested -= todo; + out += todo; + buf->used += todo; + + if (buf->used < rand_bytes_per_buf) { + break; + } + + if (!read_full(fd, buf->rand, rand_bytes_per_buf)) { + OPENSSL_free(buf); + abort(); + return; + } + + buf->used = 0; + } + + CRYPTO_STATIC_MUTEX_lock_write(&global_lock); + assert(list_head != buf); + buf->next = list_head; + list_head = buf; + CRYPTO_STATIC_MUTEX_unlock(&global_lock); +} + +#endif /* !OPENSSL_WINDOWS */ diff --git a/TMessagesProj/jni/boringssl/crypto/rand/windows.c b/TMessagesProj/jni/boringssl/crypto/rand/windows.c new file mode 100644 index 00000000..1a0cb8b0 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rand/windows.c @@ -0,0 +1,56 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#if defined(OPENSSL_WINDOWS) + +#include +#include + +#pragma warning(push, 3) + +#include + +/* #define needed to link in RtlGenRandom(), a.k.a. SystemFunction036. See the + * "Community Additions" comment on MSDN here: + * http://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx */ +#define SystemFunction036 NTAPI SystemFunction036 +#include +#undef SystemFunction036 + +#pragma warning(pop) + +#include "internal.h" + + +void RAND_cleanup(void) { +} + +void CRYPTO_sysrand(uint8_t *out, size_t requested) { + while (requested > 0) { + ULONG output_bytes_this_pass = ULONG_MAX; + if (requested < output_bytes_this_pass) { + output_bytes_this_pass = requested; + } + if (RtlGenRandom(out, output_bytes_this_pass) == FALSE) { + abort(); + } + requested -= output_bytes_this_pass; + out += output_bytes_this_pass; + } + return; +} + +#endif /* OPENSSL_WINDOWS */ diff --git a/TMessagesProj/jni/boringssl/crypto/rc4/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/rc4/CMakeLists.txt new file mode 100644 index 00000000..fe2d0c65 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rc4/CMakeLists.txt @@ -0,0 +1,31 @@ +include_directories(. .. ../../include) + +if (${ARCH} STREQUAL "x86_64") + set( + RC4_ARCH_SOURCES + + rc4-x86_64.${ASM_EXT} + rc4-md5-x86_64.${ASM_EXT} + ) +endif() + +if (${ARCH} STREQUAL "x86") + set( + RC4_ARCH_SOURCES + + rc4-586.${ASM_EXT} + ) +endif() + +add_library( + rc4 + + OBJECT + + rc4.c + ${RC4_ARCH_SOURCES} +) + +perlasm(rc4-x86_64.${ASM_EXT} asm/rc4-x86_64.pl) +perlasm(rc4-md5-x86_64.${ASM_EXT} asm/rc4-md5-x86_64.pl) +perlasm(rc4-586.${ASM_EXT} asm/rc4-586.pl) diff --git a/TMessagesProj/jni/boringssl/crypto/rc4/asm/rc4-586.pl b/TMessagesProj/jni/boringssl/crypto/rc4/asm/rc4-586.pl new file mode 100644 index 00000000..fc860ae2 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rc4/asm/rc4-586.pl @@ -0,0 +1,414 @@ +#!/usr/bin/env perl + +# ==================================================================== +# [Re]written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== + +# At some point it became apparent that the original SSLeay RC4 +# assembler implementation performs suboptimally on latest IA-32 +# microarchitectures. After re-tuning performance has changed as +# following: +# +# Pentium -10% +# Pentium III +12% +# AMD +50%(*) +# P4 +250%(**) +# +# (*) This number is actually a trade-off:-) It's possible to +# achieve +72%, but at the cost of -48% off PIII performance. +# In other words code performing further 13% faster on AMD +# would perform almost 2 times slower on Intel PIII... +# For reference! This code delivers ~80% of rc4-amd64.pl +# performance on the same Opteron machine. +# (**) This number requires compressed key schedule set up by +# RC4_set_key [see commentary below for further details]. +# +# + +# May 2011 +# +# Optimize for Core2 and Westmere [and incidentally Opteron]. Current +# performance in cycles per processed byte (less is better) and +# improvement relative to previous version of this module is: +# +# Pentium 10.2 # original numbers +# Pentium III 7.8(*) +# Intel P4 7.5 +# +# Opteron 6.1/+20% # new MMX numbers +# Core2 5.3/+67%(**) +# Westmere 5.1/+94%(**) +# Sandy Bridge 5.0/+8% +# Atom 12.6/+6% +# +# (*) PIII can actually deliver 6.6 cycles per byte with MMX code, +# but this specific code performs poorly on Core2. And vice +# versa, below MMX/SSE code delivering 5.8/7.1 on Core2 performs +# poorly on PIII, at 8.0/14.5:-( As PIII is not a "hot" CPU +# [anymore], I chose to discard PIII-specific code path and opt +# for original IALU-only code, which is why MMX/SSE code path +# is guarded by SSE2 bit (see below), not MMX/SSE. +# (**) Performance vs. block size on Core2 and Westmere had a maximum +# at ... 64 bytes block size. And it was quite a maximum, 40-60% +# in comparison to largest 8KB block size. Above improvement +# coefficients are for the largest block size. + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +push(@INC,"${dir}","${dir}../../perlasm"); +require "x86asm.pl"; + +&asm_init($ARGV[0],"rc4-586.pl",$x86only = $ARGV[$#ARGV] eq "386"); + +$xx="eax"; +$yy="ebx"; +$tx="ecx"; +$ty="edx"; +$inp="esi"; +$out="ebp"; +$dat="edi"; + +sub RC4_loop { + my $i=shift; + my $func = ($i==0)?*mov:*or; + + &add (&LB($yy),&LB($tx)); + &mov ($ty,&DWP(0,$dat,$yy,4)); + &mov (&DWP(0,$dat,$yy,4),$tx); + &mov (&DWP(0,$dat,$xx,4),$ty); + &add ($ty,$tx); + &inc (&LB($xx)); + &and ($ty,0xff); + &ror ($out,8) if ($i!=0); + if ($i<3) { + &mov ($tx,&DWP(0,$dat,$xx,4)); + } else { + &mov ($tx,&wparam(3)); # reload [re-biased] out + } + &$func ($out,&DWP(0,$dat,$ty,4)); +} + +if ($alt=0) { + # >20% faster on Atom and Sandy Bridge[!], 8% faster on Opteron, + # but ~40% slower on Core2 and Westmere... Attempt to add movz + # brings down Opteron by 25%, Atom and Sandy Bridge by 15%, yet + # on Core2 with movz it's almost 20% slower than below alternative + # code... Yes, it's a total mess... + my @XX=($xx,$out); + $RC4_loop_mmx = sub { # SSE actually... + my $i=shift; + my $j=$i<=0?0:$i>>1; + my $mm=$i<=0?"mm0":"mm".($i&1); + + &add (&LB($yy),&LB($tx)); + &lea (@XX[1],&DWP(1,@XX[0])); + &pxor ("mm2","mm0") if ($i==0); + &psllq ("mm1",8) if ($i==0); + &and (@XX[1],0xff); + &pxor ("mm0","mm0") if ($i<=0); + &mov ($ty,&DWP(0,$dat,$yy,4)); + &mov (&DWP(0,$dat,$yy,4),$tx); + &pxor ("mm1","mm2") if ($i==0); + &mov (&DWP(0,$dat,$XX[0],4),$ty); + &add (&LB($ty),&LB($tx)); + &movd (@XX[0],"mm7") if ($i==0); + &mov ($tx,&DWP(0,$dat,@XX[1],4)); + &pxor ("mm1","mm1") if ($i==1); + &movq ("mm2",&QWP(0,$inp)) if ($i==1); + &movq (&QWP(-8,(@XX[0],$inp)),"mm1") if ($i==0); + &pinsrw ($mm,&DWP(0,$dat,$ty,4),$j); + + push (@XX,shift(@XX)) if ($i>=0); + } +} else { + # Using pinsrw here improves performane on Intel CPUs by 2-3%, but + # brings down AMD by 7%... + $RC4_loop_mmx = sub { + my $i=shift; + + &add (&LB($yy),&LB($tx)); + &psllq ("mm1",8*(($i-1)&7)) if (abs($i)!=1); + &mov ($ty,&DWP(0,$dat,$yy,4)); + &mov (&DWP(0,$dat,$yy,4),$tx); + &mov (&DWP(0,$dat,$xx,4),$ty); + &inc ($xx); + &add ($ty,$tx); + &movz ($xx,&LB($xx)); # (*) + &movz ($ty,&LB($ty)); # (*) + &pxor ("mm2",$i==1?"mm0":"mm1") if ($i>=0); + &movq ("mm0",&QWP(0,$inp)) if ($i<=0); + &movq (&QWP(-8,($out,$inp)),"mm2") if ($i==0); + &mov ($tx,&DWP(0,$dat,$xx,4)); + &movd ($i>0?"mm1":"mm2",&DWP(0,$dat,$ty,4)); + + # (*) This is the key to Core2 and Westmere performance. + # Whithout movz out-of-order execution logic confuses + # itself and fails to reorder loads and stores. Problem + # appears to be fixed in Sandy Bridge... + } +} + +&external_label("OPENSSL_ia32cap_P"); + +# void asm_RC4(RC4_KEY *key,size_t len,const unsigned char *inp,unsigned char *out); +&function_begin("asm_RC4"); + &mov ($dat,&wparam(0)); # load key schedule pointer + &mov ($ty, &wparam(1)); # load len + &mov ($inp,&wparam(2)); # load inp + &mov ($out,&wparam(3)); # load out + + &xor ($xx,$xx); # avoid partial register stalls + &xor ($yy,$yy); + + &cmp ($ty,0); # safety net + &je (&label("abort")); + + &mov (&LB($xx),&BP(0,$dat)); # load key->x + &mov (&LB($yy),&BP(4,$dat)); # load key->y + &add ($dat,8); + + &lea ($tx,&DWP(0,$inp,$ty)); + &sub ($out,$inp); # re-bias out + &mov (&wparam(1),$tx); # save input+len + + &inc (&LB($xx)); + + # detect compressed key schedule... + &cmp (&DWP(256,$dat),-1); + &je (&label("RC4_CHAR")); + + &mov ($tx,&DWP(0,$dat,$xx,4)); + + &and ($ty,-4); # how many 4-byte chunks? + &jz (&label("loop1")); + + &mov (&wparam(3),$out); # $out as accumulator in these loops + if ($x86only) { + &jmp (&label("go4loop4")); + } else { + &test ($ty,-8); + &jz (&label("go4loop4")); + + &picmeup($out,"OPENSSL_ia32cap_P"); + &bt (&DWP(0,$out),26); # check SSE2 bit [could have been MMX] + &jnc (&label("go4loop4")); + + &mov ($out,&wparam(3)) if (!$alt); + &movd ("mm7",&wparam(3)) if ($alt); + &and ($ty,-8); + &lea ($ty,&DWP(-8,$inp,$ty)); + &mov (&DWP(-4,$dat),$ty); # save input+(len/8)*8-8 + + &$RC4_loop_mmx(-1); + &jmp(&label("loop_mmx_enter")); + + &set_label("loop_mmx",16); + &$RC4_loop_mmx(0); + &set_label("loop_mmx_enter"); + for ($i=1;$i<8;$i++) { &$RC4_loop_mmx($i); } + &mov ($ty,$yy); + &xor ($yy,$yy); # this is second key to Core2 + &mov (&LB($yy),&LB($ty)); # and Westmere performance... + &cmp ($inp,&DWP(-4,$dat)); + &lea ($inp,&DWP(8,$inp)); + &jb (&label("loop_mmx")); + + if ($alt) { + &movd ($out,"mm7"); + &pxor ("mm2","mm0"); + &psllq ("mm1",8); + &pxor ("mm1","mm2"); + &movq (&QWP(-8,$out,$inp),"mm1"); + } else { + &psllq ("mm1",56); + &pxor ("mm2","mm1"); + &movq (&QWP(-8,$out,$inp),"mm2"); + } + &emms (); + + &cmp ($inp,&wparam(1)); # compare to input+len + &je (&label("done")); + &jmp (&label("loop1")); + } + +&set_label("go4loop4",16); + &lea ($ty,&DWP(-4,$inp,$ty)); + &mov (&wparam(2),$ty); # save input+(len/4)*4-4 + + &set_label("loop4"); + for ($i=0;$i<4;$i++) { RC4_loop($i); } + &ror ($out,8); + &xor ($out,&DWP(0,$inp)); + &cmp ($inp,&wparam(2)); # compare to input+(len/4)*4-4 + &mov (&DWP(0,$tx,$inp),$out);# $tx holds re-biased out here + &lea ($inp,&DWP(4,$inp)); + &mov ($tx,&DWP(0,$dat,$xx,4)); + &jb (&label("loop4")); + + &cmp ($inp,&wparam(1)); # compare to input+len + &je (&label("done")); + &mov ($out,&wparam(3)); # restore $out + + &set_label("loop1",16); + &add (&LB($yy),&LB($tx)); + &mov ($ty,&DWP(0,$dat,$yy,4)); + &mov (&DWP(0,$dat,$yy,4),$tx); + &mov (&DWP(0,$dat,$xx,4),$ty); + &add ($ty,$tx); + &inc (&LB($xx)); + &and ($ty,0xff); + &mov ($ty,&DWP(0,$dat,$ty,4)); + &xor (&LB($ty),&BP(0,$inp)); + &lea ($inp,&DWP(1,$inp)); + &mov ($tx,&DWP(0,$dat,$xx,4)); + &cmp ($inp,&wparam(1)); # compare to input+len + &mov (&BP(-1,$out,$inp),&LB($ty)); + &jb (&label("loop1")); + + &jmp (&label("done")); + +# this is essentially Intel P4 specific codepath... +&set_label("RC4_CHAR",16); + &movz ($tx,&BP(0,$dat,$xx)); + # strangely enough unrolled loop performs over 20% slower... + &set_label("cloop1"); + &add (&LB($yy),&LB($tx)); + &movz ($ty,&BP(0,$dat,$yy)); + &mov (&BP(0,$dat,$yy),&LB($tx)); + &mov (&BP(0,$dat,$xx),&LB($ty)); + &add (&LB($ty),&LB($tx)); + &movz ($ty,&BP(0,$dat,$ty)); + &add (&LB($xx),1); + &xor (&LB($ty),&BP(0,$inp)); + &lea ($inp,&DWP(1,$inp)); + &movz ($tx,&BP(0,$dat,$xx)); + &cmp ($inp,&wparam(1)); + &mov (&BP(-1,$out,$inp),&LB($ty)); + &jb (&label("cloop1")); + +&set_label("done"); + &dec (&LB($xx)); + &mov (&DWP(-4,$dat),$yy); # save key->y + &mov (&BP(-8,$dat),&LB($xx)); # save key->x +&set_label("abort"); +&function_end("asm_RC4"); + +######################################################################## + +$inp="esi"; +$out="edi"; +$idi="ebp"; +$ido="ecx"; +$idx="edx"; + +# void asm_RC4_set_key(RC4_KEY *key,int len,const unsigned char *data); +&function_begin("asm_RC4_set_key"); + &mov ($out,&wparam(0)); # load key + &mov ($idi,&wparam(1)); # load len + &mov ($inp,&wparam(2)); # load data + &picmeup($idx,"OPENSSL_ia32cap_P"); + + &lea ($out,&DWP(2*4,$out)); # &key->data + &lea ($inp,&DWP(0,$inp,$idi)); # $inp to point at the end + &neg ($idi); + &xor ("eax","eax"); + &mov (&DWP(-4,$out),$idi); # borrow key->y + + &bt (&DWP(0,$idx),20); # check for bit#20 + &jc (&label("c1stloop")); + +&set_label("w1stloop",16); + &mov (&DWP(0,$out,"eax",4),"eax"); # key->data[i]=i; + &add (&LB("eax"),1); # i++; + &jnc (&label("w1stloop")); + + &xor ($ido,$ido); + &xor ($idx,$idx); + +&set_label("w2ndloop",16); + &mov ("eax",&DWP(0,$out,$ido,4)); + &add (&LB($idx),&BP(0,$inp,$idi)); + &add (&LB($idx),&LB("eax")); + &add ($idi,1); + &mov ("ebx",&DWP(0,$out,$idx,4)); + &jnz (&label("wnowrap")); + &mov ($idi,&DWP(-4,$out)); + &set_label("wnowrap"); + &mov (&DWP(0,$out,$idx,4),"eax"); + &mov (&DWP(0,$out,$ido,4),"ebx"); + &add (&LB($ido),1); + &jnc (&label("w2ndloop")); +&jmp (&label("exit")); + +# Unlike all other x86 [and x86_64] implementations, Intel P4 core +# [including EM64T] was found to perform poorly with above "32-bit" key +# schedule, a.k.a. RC4_INT. Performance improvement for IA-32 hand-coded +# assembler turned out to be 3.5x if re-coded for compressed 8-bit one, +# a.k.a. RC4_CHAR! It's however inappropriate to just switch to 8-bit +# schedule for x86[_64], because non-P4 implementations suffer from +# significant performance losses then, e.g. PIII exhibits >2x +# deterioration, and so does Opteron. In order to assure optimal +# all-round performance, we detect P4 at run-time and set up compressed +# key schedule, which is recognized by RC4 procedure. + +&set_label("c1stloop",16); + &mov (&BP(0,$out,"eax"),&LB("eax")); # key->data[i]=i; + &add (&LB("eax"),1); # i++; + &jnc (&label("c1stloop")); + + &xor ($ido,$ido); + &xor ($idx,$idx); + &xor ("ebx","ebx"); + +&set_label("c2ndloop",16); + &mov (&LB("eax"),&BP(0,$out,$ido)); + &add (&LB($idx),&BP(0,$inp,$idi)); + &add (&LB($idx),&LB("eax")); + &add ($idi,1); + &mov (&LB("ebx"),&BP(0,$out,$idx)); + &jnz (&label("cnowrap")); + &mov ($idi,&DWP(-4,$out)); + &set_label("cnowrap"); + &mov (&BP(0,$out,$idx),&LB("eax")); + &mov (&BP(0,$out,$ido),&LB("ebx")); + &add (&LB($ido),1); + &jnc (&label("c2ndloop")); + + &mov (&DWP(256,$out),-1); # mark schedule as compressed + +&set_label("exit"); + &xor ("eax","eax"); + &mov (&DWP(-8,$out),"eax"); # key->x=0; + &mov (&DWP(-4,$out),"eax"); # key->y=0; +&function_end("asm_RC4_set_key"); + +# const char *RC4_options(void); +&function_begin_B("RC4_options"); + &call (&label("pic_point")); +&set_label("pic_point"); + &blindpop("eax"); + &lea ("eax",&DWP(&label("opts")."-".&label("pic_point"),"eax")); + &picmeup("edx","OPENSSL_ia32cap_P"); + &mov ("edx",&DWP(0,"edx")); + &bt ("edx",20); + &jc (&label("1xchar")); + &bt ("edx",26); + &jnc (&label("ret")); + &add ("eax",25); + &ret (); +&set_label("1xchar"); + &add ("eax",12); +&set_label("ret"); + &ret (); +&set_label("opts",64); +&asciz ("rc4(4x,int)"); +&asciz ("rc4(1x,char)"); +&asciz ("rc4(8x,mmx)"); +&asciz ("RC4 for x86, CRYPTOGAMS by "); +&align (64); +&function_end_B("RC4_options"); + +&asm_finish(); + diff --git a/TMessagesProj/jni/boringssl/crypto/rc4/asm/rc4-md5-x86_64.pl b/TMessagesProj/jni/boringssl/crypto/rc4/asm/rc4-md5-x86_64.pl new file mode 100644 index 00000000..272fa91e --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rc4/asm/rc4-md5-x86_64.pl @@ -0,0 +1,632 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== + +# June 2011 +# +# This is RC4+MD5 "stitch" implementation. The idea, as spelled in +# http://download.intel.com/design/intarch/papers/323686.pdf, is that +# since both algorithms exhibit instruction-level parallelism, ILP, +# below theoretical maximum, interleaving them would allow to utilize +# processor resources better and achieve better performance. RC4 +# instruction sequence is virtually identical to rc4-x86_64.pl, which +# is heavily based on submission by Maxim Perminov, Maxim Locktyukhin +# and Jim Guilford of Intel. MD5 is fresh implementation aiming to +# minimize register usage, which was used as "main thread" with RC4 +# weaved into it, one RC4 round per one MD5 round. In addition to the +# stiched subroutine the script can generate standalone replacement +# md5_block_asm_data_order and RC4. Below are performance numbers in +# cycles per processed byte, less is better, for these the standalone +# subroutines, sum of them, and stitched one: +# +# RC4 MD5 RC4+MD5 stitch gain +# Opteron 6.5(*) 5.4 11.9 7.0 +70%(*) +# Core2 6.5 5.8 12.3 7.7 +60% +# Westmere 4.3 5.2 9.5 7.0 +36% +# Sandy Bridge 4.2 5.5 9.7 6.8 +43% +# Atom 9.3 6.5 15.8 11.1 +42% +# +# (*) rc4-x86_64.pl delivers 5.3 on Opteron, so real improvement +# is +53%... + +my ($rc4,$md5)=(1,1); # what to generate? +my $D="#" if (!$md5); # if set to "#", MD5 is stitched into RC4(), + # but its result is discarded. Idea here is + # to be able to use 'openssl speed rc4' for + # benchmarking the stitched subroutine... + +my $flavour = shift; +my $output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +my $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; my $dir=$1; my $xlate; +( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or +die "can't locate x86_64-xlate.pl"; + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +my ($dat,$in0,$out,$ctx,$inp,$len, $func,$nargs); + +if ($rc4 && !$md5) { + ($dat,$len,$in0,$out) = ("%rdi","%rsi","%rdx","%rcx"); + $func="RC4"; $nargs=4; +} elsif ($md5 && !$rc4) { + ($ctx,$inp,$len) = ("%rdi","%rsi","%rdx"); + $func="md5_block_asm_data_order"; $nargs=3; +} else { + ($dat,$in0,$out,$ctx,$inp,$len) = ("%rdi","%rsi","%rdx","%rcx","%r8","%r9"); + $func="rc4_md5_enc"; $nargs=6; + # void rc4_md5_enc( + # RC4_KEY *key, # + # const void *in0, # RC4 input + # void *out, # RC4 output + # MD5_CTX *ctx, # + # const void *inp, # MD5 input + # size_t len); # number of 64-byte blocks +} + +my @K=( 0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee, + 0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501, + 0x698098d8,0x8b44f7af,0xffff5bb1,0x895cd7be, + 0x6b901122,0xfd987193,0xa679438e,0x49b40821, + + 0xf61e2562,0xc040b340,0x265e5a51,0xe9b6c7aa, + 0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8, + 0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed, + 0xa9e3e905,0xfcefa3f8,0x676f02d9,0x8d2a4c8a, + + 0xfffa3942,0x8771f681,0x6d9d6122,0xfde5380c, + 0xa4beea44,0x4bdecfa9,0xf6bb4b60,0xbebfbc70, + 0x289b7ec6,0xeaa127fa,0xd4ef3085,0x04881d05, + 0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665, + + 0xf4292244,0x432aff97,0xab9423a7,0xfc93a039, + 0x655b59c3,0x8f0ccc92,0xffeff47d,0x85845dd1, + 0x6fa87e4f,0xfe2ce6e0,0xa3014314,0x4e0811a1, + 0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391 ); + +my @V=("%r8d","%r9d","%r10d","%r11d"); # MD5 registers +my $tmp="%r12d"; + +my @XX=("%rbp","%rsi"); # RC4 registers +my @TX=("%rax","%rbx"); +my $YY="%rcx"; +my $TY="%rdx"; + +my $MOD=32; # 16, 32 or 64 + +$code.=<<___; +.text +.align 16 + +.globl $func +.type $func,\@function,$nargs +$func: + cmp \$0,$len + je .Labort + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + sub \$40,%rsp +.Lbody: +___ +if ($rc4) { +$code.=<<___; +$D#md5# mov $ctx,%r11 # reassign arguments + mov $len,%r12 + mov $in0,%r13 + mov $out,%r14 +$D#md5# mov $inp,%r15 +___ + $ctx="%r11" if ($md5); # reassign arguments + $len="%r12"; + $in0="%r13"; + $out="%r14"; + $inp="%r15" if ($md5); + $inp=$in0 if (!$md5); +$code.=<<___; + xor $XX[0],$XX[0] + xor $YY,$YY + + lea 8($dat),$dat + mov -8($dat),$XX[0]#b + mov -4($dat),$YY#b + + inc $XX[0]#b + sub $in0,$out + movl ($dat,$XX[0],4),$TX[0]#d +___ +$code.=<<___ if (!$md5); + xor $TX[1],$TX[1] + test \$-128,$len + jz .Loop1 + sub $XX[0],$TX[1] + and \$`$MOD-1`,$TX[1] + jz .Loop${MOD}_is_hot + sub $TX[1],$len +.Loop${MOD}_warmup: + add $TX[0]#b,$YY#b + movl ($dat,$YY,4),$TY#d + movl $TX[0]#d,($dat,$YY,4) + movl $TY#d,($dat,$XX[0],4) + add $TY#b,$TX[0]#b + inc $XX[0]#b + movl ($dat,$TX[0],4),$TY#d + movl ($dat,$XX[0],4),$TX[0]#d + xorb ($in0),$TY#b + movb $TY#b,($out,$in0) + lea 1($in0),$in0 + dec $TX[1] + jnz .Loop${MOD}_warmup + + mov $YY,$TX[1] + xor $YY,$YY + mov $TX[1]#b,$YY#b + +.Loop${MOD}_is_hot: + mov $len,32(%rsp) # save original $len + shr \$6,$len # number of 64-byte blocks +___ + if ($D && !$md5) { # stitch in dummy MD5 + $md5=1; + $ctx="%r11"; + $inp="%r15"; + $code.=<<___; + mov %rsp,$ctx + mov $in0,$inp +___ + } +} +$code.=<<___; +#rc4# add $TX[0]#b,$YY#b +#rc4# lea ($dat,$XX[0],4),$XX[1] + shl \$6,$len + add $inp,$len # pointer to the end of input + mov $len,16(%rsp) + +#md5# mov $ctx,24(%rsp) # save pointer to MD5_CTX +#md5# mov 0*4($ctx),$V[0] # load current hash value from MD5_CTX +#md5# mov 1*4($ctx),$V[1] +#md5# mov 2*4($ctx),$V[2] +#md5# mov 3*4($ctx),$V[3] + jmp .Loop + +.align 16 +.Loop: +#md5# mov $V[0],0*4(%rsp) # put aside current hash value +#md5# mov $V[1],1*4(%rsp) +#md5# mov $V[2],2*4(%rsp) +#md5# mov $V[3],$tmp # forward reference +#md5# mov $V[3],3*4(%rsp) +___ + +sub R0 { + my ($i,$a,$b,$c,$d)=@_; + my @rot0=(7,12,17,22); + my $j=$i%16; + my $k=$i%$MOD; + my $xmm="%xmm".($j&1); + $code.=" movdqu ($in0),%xmm2\n" if ($rc4 && $j==15); + $code.=" add \$$MOD,$XX[0]#b\n" if ($rc4 && $j==15 && $k==$MOD-1); + $code.=" pxor $xmm,$xmm\n" if ($rc4 && $j<=1); + $code.=<<___; +#rc4# movl ($dat,$YY,4),$TY#d +#md5# xor $c,$tmp +#rc4# movl $TX[0]#d,($dat,$YY,4) +#md5# and $b,$tmp +#md5# add 4*`$j`($inp),$a +#rc4# add $TY#b,$TX[0]#b +#rc4# movl `4*(($k+1)%$MOD)`(`$k==$MOD-1?"$dat,$XX[0],4":"$XX[1]"`),$TX[1]#d +#md5# add \$$K[$i],$a +#md5# xor $d,$tmp +#rc4# movz $TX[0]#b,$TX[0]#d +#rc4# movl $TY#d,4*$k($XX[1]) +#md5# add $tmp,$a +#rc4# add $TX[1]#b,$YY#b +#md5# rol \$$rot0[$j%4],$a +#md5# mov `$j==15?"$b":"$c"`,$tmp # forward reference +#rc4# pinsrw \$`($j>>1)&7`,($dat,$TX[0],4),$xmm\n +#md5# add $b,$a +___ + $code.=<<___ if ($rc4 && $j==15 && $k==$MOD-1); + mov $YY,$XX[1] + xor $YY,$YY # keyword to partial register + mov $XX[1]#b,$YY#b + lea ($dat,$XX[0],4),$XX[1] +___ + $code.=<<___ if ($rc4 && $j==15); + psllq \$8,%xmm1 + pxor %xmm0,%xmm2 + pxor %xmm1,%xmm2 +___ +} +sub R1 { + my ($i,$a,$b,$c,$d)=@_; + my @rot1=(5,9,14,20); + my $j=$i%16; + my $k=$i%$MOD; + my $xmm="%xmm".($j&1); + $code.=" movdqu 16($in0),%xmm3\n" if ($rc4 && $j==15); + $code.=" add \$$MOD,$XX[0]#b\n" if ($rc4 && $j==15 && $k==$MOD-1); + $code.=" pxor $xmm,$xmm\n" if ($rc4 && $j<=1); + $code.=<<___; +#rc4# movl ($dat,$YY,4),$TY#d +#md5# xor $b,$tmp +#rc4# movl $TX[0]#d,($dat,$YY,4) +#md5# and $d,$tmp +#md5# add 4*`((1+5*$j)%16)`($inp),$a +#rc4# add $TY#b,$TX[0]#b +#rc4# movl `4*(($k+1)%$MOD)`(`$k==$MOD-1?"$dat,$XX[0],4":"$XX[1]"`),$TX[1]#d +#md5# add \$$K[$i],$a +#md5# xor $c,$tmp +#rc4# movz $TX[0]#b,$TX[0]#d +#rc4# movl $TY#d,4*$k($XX[1]) +#md5# add $tmp,$a +#rc4# add $TX[1]#b,$YY#b +#md5# rol \$$rot1[$j%4],$a +#md5# mov `$j==15?"$c":"$b"`,$tmp # forward reference +#rc4# pinsrw \$`($j>>1)&7`,($dat,$TX[0],4),$xmm\n +#md5# add $b,$a +___ + $code.=<<___ if ($rc4 && $j==15 && $k==$MOD-1); + mov $YY,$XX[1] + xor $YY,$YY # keyword to partial register + mov $XX[1]#b,$YY#b + lea ($dat,$XX[0],4),$XX[1] +___ + $code.=<<___ if ($rc4 && $j==15); + psllq \$8,%xmm1 + pxor %xmm0,%xmm3 + pxor %xmm1,%xmm3 +___ +} +sub R2 { + my ($i,$a,$b,$c,$d)=@_; + my @rot2=(4,11,16,23); + my $j=$i%16; + my $k=$i%$MOD; + my $xmm="%xmm".($j&1); + $code.=" movdqu 32($in0),%xmm4\n" if ($rc4 && $j==15); + $code.=" add \$$MOD,$XX[0]#b\n" if ($rc4 && $j==15 && $k==$MOD-1); + $code.=" pxor $xmm,$xmm\n" if ($rc4 && $j<=1); + $code.=<<___; +#rc4# movl ($dat,$YY,4),$TY#d +#md5# xor $c,$tmp +#rc4# movl $TX[0]#d,($dat,$YY,4) +#md5# xor $b,$tmp +#md5# add 4*`((5+3*$j)%16)`($inp),$a +#rc4# add $TY#b,$TX[0]#b +#rc4# movl `4*(($k+1)%$MOD)`(`$k==$MOD-1?"$dat,$XX[0],4":"$XX[1]"`),$TX[1]#d +#md5# add \$$K[$i],$a +#rc4# movz $TX[0]#b,$TX[0]#d +#md5# add $tmp,$a +#rc4# movl $TY#d,4*$k($XX[1]) +#rc4# add $TX[1]#b,$YY#b +#md5# rol \$$rot2[$j%4],$a +#md5# mov `$j==15?"\\\$-1":"$c"`,$tmp # forward reference +#rc4# pinsrw \$`($j>>1)&7`,($dat,$TX[0],4),$xmm\n +#md5# add $b,$a +___ + $code.=<<___ if ($rc4 && $j==15 && $k==$MOD-1); + mov $YY,$XX[1] + xor $YY,$YY # keyword to partial register + mov $XX[1]#b,$YY#b + lea ($dat,$XX[0],4),$XX[1] +___ + $code.=<<___ if ($rc4 && $j==15); + psllq \$8,%xmm1 + pxor %xmm0,%xmm4 + pxor %xmm1,%xmm4 +___ +} +sub R3 { + my ($i,$a,$b,$c,$d)=@_; + my @rot3=(6,10,15,21); + my $j=$i%16; + my $k=$i%$MOD; + my $xmm="%xmm".($j&1); + $code.=" movdqu 48($in0),%xmm5\n" if ($rc4 && $j==15); + $code.=" add \$$MOD,$XX[0]#b\n" if ($rc4 && $j==15 && $k==$MOD-1); + $code.=" pxor $xmm,$xmm\n" if ($rc4 && $j<=1); + $code.=<<___; +#rc4# movl ($dat,$YY,4),$TY#d +#md5# xor $d,$tmp +#rc4# movl $TX[0]#d,($dat,$YY,4) +#md5# or $b,$tmp +#md5# add 4*`((7*$j)%16)`($inp),$a +#rc4# add $TY#b,$TX[0]#b +#rc4# movl `4*(($k+1)%$MOD)`(`$k==$MOD-1?"$dat,$XX[0],4":"$XX[1]"`),$TX[1]#d +#md5# add \$$K[$i],$a +#rc4# movz $TX[0]#b,$TX[0]#d +#md5# xor $c,$tmp +#rc4# movl $TY#d,4*$k($XX[1]) +#md5# add $tmp,$a +#rc4# add $TX[1]#b,$YY#b +#md5# rol \$$rot3[$j%4],$a +#md5# mov \$-1,$tmp # forward reference +#rc4# pinsrw \$`($j>>1)&7`,($dat,$TX[0],4),$xmm\n +#md5# add $b,$a +___ + $code.=<<___ if ($rc4 && $j==15); + mov $XX[0],$XX[1] + xor $XX[0],$XX[0] # keyword to partial register + mov $XX[1]#b,$XX[0]#b + mov $YY,$XX[1] + xor $YY,$YY # keyword to partial register + mov $XX[1]#b,$YY#b + lea ($dat,$XX[0],4),$XX[1] + psllq \$8,%xmm1 + pxor %xmm0,%xmm5 + pxor %xmm1,%xmm5 +___ +} + +my $i=0; +for(;$i<16;$i++) { R0($i,@V); unshift(@V,pop(@V)); push(@TX,shift(@TX)); } +for(;$i<32;$i++) { R1($i,@V); unshift(@V,pop(@V)); push(@TX,shift(@TX)); } +for(;$i<48;$i++) { R2($i,@V); unshift(@V,pop(@V)); push(@TX,shift(@TX)); } +for(;$i<64;$i++) { R3($i,@V); unshift(@V,pop(@V)); push(@TX,shift(@TX)); } + +$code.=<<___; +#md5# add 0*4(%rsp),$V[0] # accumulate hash value +#md5# add 1*4(%rsp),$V[1] +#md5# add 2*4(%rsp),$V[2] +#md5# add 3*4(%rsp),$V[3] + +#rc4# movdqu %xmm2,($out,$in0) # write RC4 output +#rc4# movdqu %xmm3,16($out,$in0) +#rc4# movdqu %xmm4,32($out,$in0) +#rc4# movdqu %xmm5,48($out,$in0) +#md5# lea 64($inp),$inp +#rc4# lea 64($in0),$in0 + cmp 16(%rsp),$inp # are we done? + jb .Loop + +#md5# mov 24(%rsp),$len # restore pointer to MD5_CTX +#rc4# sub $TX[0]#b,$YY#b # correct $YY +#md5# mov $V[0],0*4($len) # write MD5_CTX +#md5# mov $V[1],1*4($len) +#md5# mov $V[2],2*4($len) +#md5# mov $V[3],3*4($len) +___ +$code.=<<___ if ($rc4 && (!$md5 || $D)); + mov 32(%rsp),$len # restore original $len + and \$63,$len # remaining bytes + jnz .Loop1 + jmp .Ldone + +.align 16 +.Loop1: + add $TX[0]#b,$YY#b + movl ($dat,$YY,4),$TY#d + movl $TX[0]#d,($dat,$YY,4) + movl $TY#d,($dat,$XX[0],4) + add $TY#b,$TX[0]#b + inc $XX[0]#b + movl ($dat,$TX[0],4),$TY#d + movl ($dat,$XX[0],4),$TX[0]#d + xorb ($in0),$TY#b + movb $TY#b,($out,$in0) + lea 1($in0),$in0 + dec $len + jnz .Loop1 + +.Ldone: +___ +$code.=<<___; +#rc4# sub \$1,$XX[0]#b +#rc4# movl $XX[0]#d,-8($dat) +#rc4# movl $YY#d,-4($dat) + + mov 40(%rsp),%r15 + mov 48(%rsp),%r14 + mov 56(%rsp),%r13 + mov 64(%rsp),%r12 + mov 72(%rsp),%rbp + mov 80(%rsp),%rbx + lea 88(%rsp),%rsp +.Lepilogue: +.Labort: + ret +.size $func,.-$func +___ + +if ($rc4 && $D) { # sole purpose of this section is to provide + # option to use the generated module as drop-in + # replacement for rc4-x86_64.pl for debugging + # and testing purposes... +my ($idx,$ido)=("%r8","%r9"); +my ($dat,$len,$inp)=("%rdi","%rsi","%rdx"); + +$code.=<<___; +.globl RC4_set_key +.type RC4_set_key,\@function,3 +.align 16 +RC4_set_key: + lea 8($dat),$dat + lea ($inp,$len),$inp + neg $len + mov $len,%rcx + xor %eax,%eax + xor $ido,$ido + xor %r10,%r10 + xor %r11,%r11 + jmp .Lw1stloop + +.align 16 +.Lw1stloop: + mov %eax,($dat,%rax,4) + add \$1,%al + jnc .Lw1stloop + + xor $ido,$ido + xor $idx,$idx +.align 16 +.Lw2ndloop: + mov ($dat,$ido,4),%r10d + add ($inp,$len,1),$idx#b + add %r10b,$idx#b + add \$1,$len + mov ($dat,$idx,4),%r11d + cmovz %rcx,$len + mov %r10d,($dat,$idx,4) + mov %r11d,($dat,$ido,4) + add \$1,$ido#b + jnc .Lw2ndloop + + xor %eax,%eax + mov %eax,-8($dat) + mov %eax,-4($dat) + ret +.size RC4_set_key,.-RC4_set_key + +.globl RC4_options +.type RC4_options,\@abi-omnipotent +.align 16 +RC4_options: + lea .Lopts(%rip),%rax + ret +.align 64 +.Lopts: +.asciz "rc4(64x,int)" +.align 64 +.size RC4_options,.-RC4_options +___ +} +# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame, +# CONTEXT *context,DISPATCHER_CONTEXT *disp) +if ($win64) { +my $rec="%rcx"; +my $frame="%rdx"; +my $context="%r8"; +my $disp="%r9"; + +$code.=<<___; +.extern __imp_RtlVirtualUnwind +.type se_handler,\@abi-omnipotent +.align 16 +se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + lea .Lbody(%rip),%r10 + cmp %r10,%rbx # context->Rip<.Lbody + jb .Lin_prologue + + mov 152($context),%rax # pull context->Rsp + + lea .Lepilogue(%rip),%r10 + cmp %r10,%rbx # context->Rip>=.Lepilogue + jae .Lin_prologue + + mov 40(%rax),%r15 + mov 48(%rax),%r14 + mov 56(%rax),%r13 + mov 64(%rax),%r12 + mov 72(%rax),%rbp + mov 80(%rax),%rbx + lea 88(%rax),%rax + + mov %rbx,144($context) # restore context->Rbx + mov %rbp,160($context) # restore context->Rbp + mov %r12,216($context) # restore context->R12 + mov %r13,224($context) # restore context->R12 + mov %r14,232($context) # restore context->R14 + mov %r15,240($context) # restore context->R15 + +.Lin_prologue: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + + mov 40($disp),%rdi # disp->ContextRecord + mov $context,%rsi # context + mov \$154,%ecx # sizeof(CONTEXT) + .long 0xa548f3fc # cld; rep movsq + + mov $disp,%rsi + xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER + mov 8(%rsi),%rdx # arg2, disp->ImageBase + mov 0(%rsi),%r8 # arg3, disp->ControlPc + mov 16(%rsi),%r9 # arg4, disp->FunctionEntry + mov 40(%rsi),%r10 # disp->ContextRecord + lea 56(%rsi),%r11 # &disp->HandlerData + lea 24(%rsi),%r12 # &disp->EstablisherFrame + mov %r10,32(%rsp) # arg5 + mov %r11,40(%rsp) # arg6 + mov %r12,48(%rsp) # arg7 + mov %rcx,56(%rsp) # arg8, (NULL) + call *__imp_RtlVirtualUnwind(%rip) + + mov \$1,%eax # ExceptionContinueSearch + add \$64,%rsp + popfq + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + pop %rdi + pop %rsi + ret +.size se_handler,.-se_handler + +.section .pdata +.align 4 + .rva .LSEH_begin_$func + .rva .LSEH_end_$func + .rva .LSEH_info_$func + +.section .xdata +.align 8 +.LSEH_info_$func: + .byte 9,0,0,0 + .rva se_handler +___ +} + +sub reg_part { +my ($reg,$conv)=@_; + if ($reg =~ /%r[0-9]+/) { $reg .= $conv; } + elsif ($conv eq "b") { $reg =~ s/%[er]([^x]+)x?/%$1l/; } + elsif ($conv eq "w") { $reg =~ s/%[er](.+)/%$1/; } + elsif ($conv eq "d") { $reg =~ s/%[er](.+)/%e$1/; } + return $reg; +} + +$code =~ s/(%[a-z0-9]+)#([bwd])/reg_part($1,$2)/gem; +$code =~ s/\`([^\`]*)\`/eval $1/gem; +$code =~ s/pinsrw\s+\$0,/movd /gm; + +$code =~ s/#md5#//gm if ($md5); +$code =~ s/#rc4#//gm if ($rc4); + +print $code; + +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/rc4/asm/rc4-x86_64.pl b/TMessagesProj/jni/boringssl/crypto/rc4/asm/rc4-x86_64.pl new file mode 100644 index 00000000..cef62689 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rc4/asm/rc4-x86_64.pl @@ -0,0 +1,653 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# July 2004 +# +# 2.22x RC4 tune-up:-) It should be noted though that my hand [as in +# "hand-coded assembler"] doesn't stand for the whole improvement +# coefficient. It turned out that eliminating RC4_CHAR from config +# line results in ~40% improvement (yes, even for C implementation). +# Presumably it has everything to do with AMD cache architecture and +# RAW or whatever penalties. Once again! The module *requires* config +# line *without* RC4_CHAR! As for coding "secret," I bet on partial +# register arithmetics. For example instead of 'inc %r8; and $255,%r8' +# I simply 'inc %r8b'. Even though optimization manual discourages +# to operate on partial registers, it turned out to be the best bet. +# At least for AMD... How IA32E would perform remains to be seen... + +# November 2004 +# +# As was shown by Marc Bevand reordering of couple of load operations +# results in even higher performance gain of 3.3x:-) At least on +# Opteron... For reference, 1x in this case is RC4_CHAR C-code +# compiled with gcc 3.3.2, which performs at ~54MBps per 1GHz clock. +# Latter means that if you want to *estimate* what to expect from +# *your* Opteron, then multiply 54 by 3.3 and clock frequency in GHz. + +# November 2004 +# +# Intel P4 EM64T core was found to run the AMD64 code really slow... +# The only way to achieve comparable performance on P4 was to keep +# RC4_CHAR. Kind of ironic, huh? As it's apparently impossible to +# compose blended code, which would perform even within 30% marginal +# on either AMD and Intel platforms, I implement both cases. See +# rc4_skey.c for further details... + +# April 2005 +# +# P4 EM64T core appears to be "allergic" to 64-bit inc/dec. Replacing +# those with add/sub results in 50% performance improvement of folded +# loop... + +# May 2005 +# +# As was shown by Zou Nanhai loop unrolling can improve Intel EM64T +# performance by >30% [unlike P4 32-bit case that is]. But this is +# provided that loads are reordered even more aggressively! Both code +# pathes, AMD64 and EM64T, reorder loads in essentially same manner +# as my IA-64 implementation. On Opteron this resulted in modest 5% +# improvement [I had to test it], while final Intel P4 performance +# achieves respectful 432MBps on 2.8GHz processor now. For reference. +# If executed on Xeon, current RC4_CHAR code-path is 2.7x faster than +# RC4_INT code-path. While if executed on Opteron, it's only 25% +# slower than the RC4_INT one [meaning that if CPU µ-arch detection +# is not implemented, then this final RC4_CHAR code-path should be +# preferred, as it provides better *all-round* performance]. + +# March 2007 +# +# Intel Core2 was observed to perform poorly on both code paths:-( It +# apparently suffers from some kind of partial register stall, which +# occurs in 64-bit mode only [as virtually identical 32-bit loop was +# observed to outperform 64-bit one by almost 50%]. Adding two movzb to +# cloop1 boosts its performance by 80%! This loop appears to be optimal +# fit for Core2 and therefore the code was modified to skip cloop8 on +# this CPU. + +# May 2010 +# +# Intel Westmere was observed to perform suboptimally. Adding yet +# another movzb to cloop1 improved performance by almost 50%! Core2 +# performance is improved too, but nominally... + +# May 2011 +# +# The only code path that was not modified is P4-specific one. Non-P4 +# Intel code path optimization is heavily based on submission by Maxim +# Perminov, Maxim Locktyukhin and Jim Guilford of Intel. I've used +# some of the ideas even in attempt to optmize the original RC4_INT +# code path... Current performance in cycles per processed byte (less +# is better) and improvement coefficients relative to previous +# version of this module are: +# +# Opteron 5.3/+0%(*) +# P4 6.5 +# Core2 6.2/+15%(**) +# Westmere 4.2/+60% +# Sandy Bridge 4.2/+120% +# Atom 9.3/+80% +# +# (*) But corresponding loop has less instructions, which should have +# positive effect on upcoming Bulldozer, which has one less ALU. +# For reference, Intel code runs at 6.8 cpb rate on Opteron. +# (**) Note that Core2 result is ~15% lower than corresponding result +# for 32-bit code, meaning that it's possible to improve it, +# but more than likely at the cost of the others (see rc4-586.pl +# to get the idea)... + +$flavour = shift; +$output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or +die "can't locate x86_64-xlate.pl"; + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +$dat="%rdi"; # arg1 +$len="%rsi"; # arg2 +$inp="%rdx"; # arg3 +$out="%rcx"; # arg4 + +{ +$code=<<___; +.text +.extern OPENSSL_ia32cap_P + +.globl asm_RC4 +.type asm_RC4,\@function,4 +.align 16 +asm_RC4: + or $len,$len + jne .Lentry + ret +.Lentry: + push %rbx + push %r12 + push %r13 +.Lprologue: + mov $len,%r11 + mov $inp,%r12 + mov $out,%r13 +___ +my $len="%r11"; # reassign input arguments +my $inp="%r12"; +my $out="%r13"; + +my @XX=("%r10","%rsi"); +my @TX=("%rax","%rbx"); +my $YY="%rcx"; +my $TY="%rdx"; + +$code.=<<___; + xor $XX[0],$XX[0] + xor $YY,$YY + + lea 8($dat),$dat + mov -8($dat),$XX[0]#b + mov -4($dat),$YY#b + cmpl \$-1,256($dat) + je .LRC4_CHAR + mov OPENSSL_ia32cap_P(%rip),%r8d + xor $TX[1],$TX[1] + inc $XX[0]#b + sub $XX[0],$TX[1] + sub $inp,$out + movl ($dat,$XX[0],4),$TX[0]#d + test \$-16,$len + jz .Lloop1 + bt \$30,%r8d # Intel CPU? + jc .Lintel + and \$7,$TX[1] + lea 1($XX[0]),$XX[1] + jz .Loop8 + sub $TX[1],$len +.Loop8_warmup: + add $TX[0]#b,$YY#b + movl ($dat,$YY,4),$TY#d + movl $TX[0]#d,($dat,$YY,4) + movl $TY#d,($dat,$XX[0],4) + add $TY#b,$TX[0]#b + inc $XX[0]#b + movl ($dat,$TX[0],4),$TY#d + movl ($dat,$XX[0],4),$TX[0]#d + xorb ($inp),$TY#b + movb $TY#b,($out,$inp) + lea 1($inp),$inp + dec $TX[1] + jnz .Loop8_warmup + + lea 1($XX[0]),$XX[1] + jmp .Loop8 +.align 16 +.Loop8: +___ +for ($i=0;$i<8;$i++) { +$code.=<<___ if ($i==7); + add \$8,$XX[1]#b +___ +$code.=<<___; + add $TX[0]#b,$YY#b + movl ($dat,$YY,4),$TY#d + movl $TX[0]#d,($dat,$YY,4) + movl `4*($i==7?-1:$i)`($dat,$XX[1],4),$TX[1]#d + ror \$8,%r8 # ror is redundant when $i=0 + movl $TY#d,4*$i($dat,$XX[0],4) + add $TX[0]#b,$TY#b + movb ($dat,$TY,4),%r8b +___ +push(@TX,shift(@TX)); #push(@XX,shift(@XX)); # "rotate" registers +} +$code.=<<___; + add \$8,$XX[0]#b + ror \$8,%r8 + sub \$8,$len + + xor ($inp),%r8 + mov %r8,($out,$inp) + lea 8($inp),$inp + + test \$-8,$len + jnz .Loop8 + cmp \$0,$len + jne .Lloop1 + jmp .Lexit + +.align 16 +.Lintel: + test \$-32,$len + jz .Lloop1 + and \$15,$TX[1] + jz .Loop16_is_hot + sub $TX[1],$len +.Loop16_warmup: + add $TX[0]#b,$YY#b + movl ($dat,$YY,4),$TY#d + movl $TX[0]#d,($dat,$YY,4) + movl $TY#d,($dat,$XX[0],4) + add $TY#b,$TX[0]#b + inc $XX[0]#b + movl ($dat,$TX[0],4),$TY#d + movl ($dat,$XX[0],4),$TX[0]#d + xorb ($inp),$TY#b + movb $TY#b,($out,$inp) + lea 1($inp),$inp + dec $TX[1] + jnz .Loop16_warmup + + mov $YY,$TX[1] + xor $YY,$YY + mov $TX[1]#b,$YY#b + +.Loop16_is_hot: + lea ($dat,$XX[0],4),$XX[1] +___ +sub RC4_loop { + my $i=shift; + my $j=$i<0?0:$i; + my $xmm="%xmm".($j&1); + + $code.=" add \$16,$XX[0]#b\n" if ($i==15); + $code.=" movdqu ($inp),%xmm2\n" if ($i==15); + $code.=" add $TX[0]#b,$YY#b\n" if ($i<=0); + $code.=" movl ($dat,$YY,4),$TY#d\n"; + $code.=" pxor %xmm0,%xmm2\n" if ($i==0); + $code.=" psllq \$8,%xmm1\n" if ($i==0); + $code.=" pxor $xmm,$xmm\n" if ($i<=1); + $code.=" movl $TX[0]#d,($dat,$YY,4)\n"; + $code.=" add $TY#b,$TX[0]#b\n"; + $code.=" movl `4*($j+1)`($XX[1]),$TX[1]#d\n" if ($i<15); + $code.=" movz $TX[0]#b,$TX[0]#d\n"; + $code.=" movl $TY#d,4*$j($XX[1])\n"; + $code.=" pxor %xmm1,%xmm2\n" if ($i==0); + $code.=" lea ($dat,$XX[0],4),$XX[1]\n" if ($i==15); + $code.=" add $TX[1]#b,$YY#b\n" if ($i<15); + $code.=" pinsrw \$`($j>>1)&7`,($dat,$TX[0],4),$xmm\n"; + $code.=" movdqu %xmm2,($out,$inp)\n" if ($i==0); + $code.=" lea 16($inp),$inp\n" if ($i==0); + $code.=" movl ($XX[1]),$TX[1]#d\n" if ($i==15); +} + RC4_loop(-1); +$code.=<<___; + jmp .Loop16_enter +.align 16 +.Loop16: +___ + +for ($i=0;$i<16;$i++) { + $code.=".Loop16_enter:\n" if ($i==1); + RC4_loop($i); + push(@TX,shift(@TX)); # "rotate" registers +} +$code.=<<___; + mov $YY,$TX[1] + xor $YY,$YY # keyword to partial register + sub \$16,$len + mov $TX[1]#b,$YY#b + test \$-16,$len + jnz .Loop16 + + psllq \$8,%xmm1 + pxor %xmm0,%xmm2 + pxor %xmm1,%xmm2 + movdqu %xmm2,($out,$inp) + lea 16($inp),$inp + + cmp \$0,$len + jne .Lloop1 + jmp .Lexit + +.align 16 +.Lloop1: + add $TX[0]#b,$YY#b + movl ($dat,$YY,4),$TY#d + movl $TX[0]#d,($dat,$YY,4) + movl $TY#d,($dat,$XX[0],4) + add $TY#b,$TX[0]#b + inc $XX[0]#b + movl ($dat,$TX[0],4),$TY#d + movl ($dat,$XX[0],4),$TX[0]#d + xorb ($inp),$TY#b + movb $TY#b,($out,$inp) + lea 1($inp),$inp + dec $len + jnz .Lloop1 + jmp .Lexit + +.align 16 +.LRC4_CHAR: + add \$1,$XX[0]#b + movzb ($dat,$XX[0]),$TX[0]#d + test \$-8,$len + jz .Lcloop1 + jmp .Lcloop8 +.align 16 +.Lcloop8: + mov ($inp),%r8d + mov 4($inp),%r9d +___ +# unroll 2x4-wise, because 64-bit rotates kill Intel P4... +for ($i=0;$i<4;$i++) { +$code.=<<___; + add $TX[0]#b,$YY#b + lea 1($XX[0]),$XX[1] + movzb ($dat,$YY),$TY#d + movzb $XX[1]#b,$XX[1]#d + movzb ($dat,$XX[1]),$TX[1]#d + movb $TX[0]#b,($dat,$YY) + cmp $XX[1],$YY + movb $TY#b,($dat,$XX[0]) + jne .Lcmov$i # Intel cmov is sloooow... + mov $TX[0],$TX[1] +.Lcmov$i: + add $TX[0]#b,$TY#b + xor ($dat,$TY),%r8b + ror \$8,%r8d +___ +push(@TX,shift(@TX)); push(@XX,shift(@XX)); # "rotate" registers +} +for ($i=4;$i<8;$i++) { +$code.=<<___; + add $TX[0]#b,$YY#b + lea 1($XX[0]),$XX[1] + movzb ($dat,$YY),$TY#d + movzb $XX[1]#b,$XX[1]#d + movzb ($dat,$XX[1]),$TX[1]#d + movb $TX[0]#b,($dat,$YY) + cmp $XX[1],$YY + movb $TY#b,($dat,$XX[0]) + jne .Lcmov$i # Intel cmov is sloooow... + mov $TX[0],$TX[1] +.Lcmov$i: + add $TX[0]#b,$TY#b + xor ($dat,$TY),%r9b + ror \$8,%r9d +___ +push(@TX,shift(@TX)); push(@XX,shift(@XX)); # "rotate" registers +} +$code.=<<___; + lea -8($len),$len + mov %r8d,($out) + lea 8($inp),$inp + mov %r9d,4($out) + lea 8($out),$out + + test \$-8,$len + jnz .Lcloop8 + cmp \$0,$len + jne .Lcloop1 + jmp .Lexit +___ +$code.=<<___; +.align 16 +.Lcloop1: + add $TX[0]#b,$YY#b + movzb $YY#b,$YY#d + movzb ($dat,$YY),$TY#d + movb $TX[0]#b,($dat,$YY) + movb $TY#b,($dat,$XX[0]) + add $TX[0]#b,$TY#b + add \$1,$XX[0]#b + movzb $TY#b,$TY#d + movzb $XX[0]#b,$XX[0]#d + movzb ($dat,$TY),$TY#d + movzb ($dat,$XX[0]),$TX[0]#d + xorb ($inp),$TY#b + lea 1($inp),$inp + movb $TY#b,($out) + lea 1($out),$out + sub \$1,$len + jnz .Lcloop1 + jmp .Lexit + +.align 16 +.Lexit: + sub \$1,$XX[0]#b + movl $XX[0]#d,-8($dat) + movl $YY#d,-4($dat) + + mov (%rsp),%r13 + mov 8(%rsp),%r12 + mov 16(%rsp),%rbx + add \$24,%rsp +.Lepilogue: + ret +.size asm_RC4,.-asm_RC4 +___ +} + +$idx="%r8"; +$ido="%r9"; + +$code.=<<___; +.globl asm_RC4_set_key +.type asm_RC4_set_key,\@function,3 +.align 16 +asm_RC4_set_key: + lea 8($dat),$dat + lea ($inp,$len),$inp + neg $len + mov $len,%rcx + xor %eax,%eax + xor $ido,$ido + xor %r10,%r10 + xor %r11,%r11 + + mov OPENSSL_ia32cap_P(%rip),$idx#d + bt \$20,$idx#d # RC4_CHAR? + jc .Lc1stloop + jmp .Lw1stloop + +.align 16 +.Lw1stloop: + mov %eax,($dat,%rax,4) + add \$1,%al + jnc .Lw1stloop + + xor $ido,$ido + xor $idx,$idx +.align 16 +.Lw2ndloop: + mov ($dat,$ido,4),%r10d + add ($inp,$len,1),$idx#b + add %r10b,$idx#b + add \$1,$len + mov ($dat,$idx,4),%r11d + cmovz %rcx,$len + mov %r10d,($dat,$idx,4) + mov %r11d,($dat,$ido,4) + add \$1,$ido#b + jnc .Lw2ndloop + jmp .Lexit_key + +.align 16 +.Lc1stloop: + mov %al,($dat,%rax) + add \$1,%al + jnc .Lc1stloop + + xor $ido,$ido + xor $idx,$idx +.align 16 +.Lc2ndloop: + mov ($dat,$ido),%r10b + add ($inp,$len),$idx#b + add %r10b,$idx#b + add \$1,$len + mov ($dat,$idx),%r11b + jnz .Lcnowrap + mov %rcx,$len +.Lcnowrap: + mov %r10b,($dat,$idx) + mov %r11b,($dat,$ido) + add \$1,$ido#b + jnc .Lc2ndloop + movl \$-1,256($dat) + +.align 16 +.Lexit_key: + xor %eax,%eax + mov %eax,-8($dat) + mov %eax,-4($dat) + ret +.size asm_RC4_set_key,.-asm_RC4_set_key +___ + +# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame, +# CONTEXT *context,DISPATCHER_CONTEXT *disp) +if ($win64) { +$rec="%rcx"; +$frame="%rdx"; +$context="%r8"; +$disp="%r9"; + +$code.=<<___; +.extern __imp_RtlVirtualUnwind +.type stream_se_handler,\@abi-omnipotent +.align 16 +stream_se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + lea .Lprologue(%rip),%r10 + cmp %r10,%rbx # context->RipRsp + + lea .Lepilogue(%rip),%r10 + cmp %r10,%rbx # context->Rip>=epilogue label + jae .Lin_prologue + + lea 24(%rax),%rax + + mov -8(%rax),%rbx + mov -16(%rax),%r12 + mov -24(%rax),%r13 + mov %rbx,144($context) # restore context->Rbx + mov %r12,216($context) # restore context->R12 + mov %r13,224($context) # restore context->R13 + +.Lin_prologue: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + + jmp .Lcommon_seh_exit +.size stream_se_handler,.-stream_se_handler + +.type key_se_handler,\@abi-omnipotent +.align 16 +key_se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 152($context),%rax # pull context->Rsp + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + +.Lcommon_seh_exit: + + mov 40($disp),%rdi # disp->ContextRecord + mov $context,%rsi # context + mov \$154,%ecx # sizeof(CONTEXT) + .long 0xa548f3fc # cld; rep movsq + + mov $disp,%rsi + xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER + mov 8(%rsi),%rdx # arg2, disp->ImageBase + mov 0(%rsi),%r8 # arg3, disp->ControlPc + mov 16(%rsi),%r9 # arg4, disp->FunctionEntry + mov 40(%rsi),%r10 # disp->ContextRecord + lea 56(%rsi),%r11 # &disp->HandlerData + lea 24(%rsi),%r12 # &disp->EstablisherFrame + mov %r10,32(%rsp) # arg5 + mov %r11,40(%rsp) # arg6 + mov %r12,48(%rsp) # arg7 + mov %rcx,56(%rsp) # arg8, (NULL) + call *__imp_RtlVirtualUnwind(%rip) + + mov \$1,%eax # ExceptionContinueSearch + add \$64,%rsp + popfq + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + pop %rdi + pop %rsi + ret +.size key_se_handler,.-key_se_handler + +.section .pdata +.align 4 + .rva .LSEH_begin_asm_RC4 + .rva .LSEH_end_asm_RC4 + .rva .LSEH_info_asm_RC4 + + .rva .LSEH_begin_asm_RC4_set_key + .rva .LSEH_end_asm_RC4_set_key + .rva .LSEH_info_asm_RC4_set_key + +.section .xdata +.align 8 +.LSEH_info_asm_RC4: + .byte 9,0,0,0 + .rva stream_se_handler +.LSEH_info_asm_RC4_set_key: + .byte 9,0,0,0 + .rva key_se_handler +___ +} + +sub reg_part { +my ($reg,$conv)=@_; + if ($reg =~ /%r[0-9]+/) { $reg .= $conv; } + elsif ($conv eq "b") { $reg =~ s/%[er]([^x]+)x?/%$1l/; } + elsif ($conv eq "w") { $reg =~ s/%[er](.+)/%$1/; } + elsif ($conv eq "d") { $reg =~ s/%[er](.+)/%e$1/; } + return $reg; +} + +$code =~ s/(%[a-z0-9]+)#([bwd])/reg_part($1,$2)/gem; +$code =~ s/\`([^\`]*)\`/eval $1/gem; + +print $code; + +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/rc4/rc4.c b/TMessagesProj/jni/boringssl/crypto/rc4/rc4.c new file mode 100644 index 00000000..aa19dc28 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rc4/rc4.c @@ -0,0 +1,284 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#if defined(OPENSSL_NO_ASM) || \ + (!defined(OPENSSL_X86_64) && !defined(OPENSSL_X86)) + +#if defined(OPENSSL_64_BIT) +#define RC4_CHUNK uint64_t +#elif defined(OPENSSL_32_BIT) +#define RC4_CHUNK uint32_t +#else +#error "Unknown word size" +#endif + + +/* RC4 as implemented from a posting from + * Newsgroups: sci.crypt + * From: sterndark@netcom.com (David Sterndark) + * Subject: RC4 Algorithm revealed. + * Message-ID: + * Date: Wed, 14 Sep 1994 06:35:31 GMT */ + +void RC4(RC4_KEY *key, size_t len, const uint8_t *in, uint8_t *out) { + uint32_t *d; + uint32_t x, y, tx, ty; + size_t i; + + x = key->x; + y = key->y; + d = key->data; + +#define RC4_STEP \ + (x = (x + 1) & 0xff, tx = d[x], y = (tx + y) & 0xff, ty = d[y], d[y] = tx, \ + d[x] = ty, (RC4_CHUNK)d[(tx + ty) & 0xff]) + + if ((((size_t)in & (sizeof(RC4_CHUNK) - 1)) | + ((size_t)out & (sizeof(RC4_CHUNK) - 1))) == 0) { + RC4_CHUNK ichunk, otp; + const union { + long one; + char little; + } is_endian = {1}; + + /* I reckon we can afford to implement both endian + * cases and to decide which way to take at run-time + * because the machine code appears to be very compact + * and redundant 1-2KB is perfectly tolerable (i.e. + * in case the compiler fails to eliminate it:-). By + * suggestion from Terrel Larson + * who also stands for the is_endian union:-) + * + * Special notes. + * + * - is_endian is declared automatic as doing otherwise + * (declaring static) prevents gcc from eliminating + * the redundant code; + * - compilers (those I've tried) don't seem to have + * problems eliminating either the operators guarded + * by "if (sizeof(RC4_CHUNK)==8)" or the condition + * expressions themselves so I've got 'em to replace + * corresponding #ifdefs from the previous version; + * - I chose to let the redundant switch cases when + * sizeof(RC4_CHUNK)!=8 be (were also #ifdefed + * before); + * - in case you wonder "&(sizeof(RC4_CHUNK)*8-1)" in + * [LB]ESHFT guards against "shift is out of range" + * warnings when sizeof(RC4_CHUNK)!=8 + * + * */ + if (!is_endian.little) { /* BIG-ENDIAN CASE */ +#define BESHFT(c) \ + (((sizeof(RC4_CHUNK) - (c) - 1) * 8) & (sizeof(RC4_CHUNK) * 8 - 1)) + for (; len & (0 - sizeof(RC4_CHUNK)); len -= sizeof(RC4_CHUNK)) { + ichunk = *(RC4_CHUNK *)in; + otp = RC4_STEP << BESHFT(0); + otp |= RC4_STEP << BESHFT(1); + otp |= RC4_STEP << BESHFT(2); + otp |= RC4_STEP << BESHFT(3); +#if defined(OPENSSL_64_BIT) + otp |= RC4_STEP << BESHFT(4); + otp |= RC4_STEP << BESHFT(5); + otp |= RC4_STEP << BESHFT(6); + otp |= RC4_STEP << BESHFT(7); +#endif + *(RC4_CHUNK *)out = otp ^ ichunk; + in += sizeof(RC4_CHUNK); + out += sizeof(RC4_CHUNK); + } + } else { /* LITTLE-ENDIAN CASE */ +#define LESHFT(c) (((c) * 8) & (sizeof(RC4_CHUNK) * 8 - 1)) + for (; len & (0 - sizeof(RC4_CHUNK)); len -= sizeof(RC4_CHUNK)) { + ichunk = *(RC4_CHUNK *)in; + otp = RC4_STEP; + otp |= RC4_STEP << 8; + otp |= RC4_STEP << 16; + otp |= RC4_STEP << 24; +#if defined(OPENSSL_64_BIT) + otp |= RC4_STEP << LESHFT(4); + otp |= RC4_STEP << LESHFT(5); + otp |= RC4_STEP << LESHFT(6); + otp |= RC4_STEP << LESHFT(7); +#endif + *(RC4_CHUNK *)out = otp ^ ichunk; + in += sizeof(RC4_CHUNK); + out += sizeof(RC4_CHUNK); + } + } + } +#define LOOP(in, out) \ + x = ((x + 1) & 0xff); \ + tx = d[x]; \ + y = (tx + y) & 0xff; \ + d[x] = ty = d[y]; \ + d[y] = tx; \ + (out) = d[(tx + ty) & 0xff] ^ (in); + +#ifndef RC4_INDEX +#define RC4_LOOP(a, b, i) LOOP(*((a)++), *((b)++)) +#else +#define RC4_LOOP(a, b, i) LOOP(a[i], b[i]) +#endif + + i = len >> 3; + if (i) { + for (;;) { + RC4_LOOP(in, out, 0); + RC4_LOOP(in, out, 1); + RC4_LOOP(in, out, 2); + RC4_LOOP(in, out, 3); + RC4_LOOP(in, out, 4); + RC4_LOOP(in, out, 5); + RC4_LOOP(in, out, 6); + RC4_LOOP(in, out, 7); +#ifdef RC4_INDEX + in += 8; + out += 8; +#endif + if (--i == 0) { + break; + } + } + } + i = len & 0x07; + if (i) { + for (;;) { + RC4_LOOP(in, out, 0); + if (--i == 0) { + break; + } + RC4_LOOP(in, out, 1); + if (--i == 0) { + break; + } + RC4_LOOP(in, out, 2); + if (--i == 0) { + break; + } + RC4_LOOP(in, out, 3); + if (--i == 0) { + break; + } + RC4_LOOP(in, out, 4); + if (--i == 0) { + break; + } + RC4_LOOP(in, out, 5); + if (--i == 0) { + break; + } + RC4_LOOP(in, out, 6); + if (--i == 0) { + break; + } + } + } + key->x = x; + key->y = y; +} + +void RC4_set_key(RC4_KEY *rc4key, unsigned len, const uint8_t *key) { + uint32_t tmp; + int id1, id2; + uint32_t *d; + unsigned int i; + + d = &rc4key->data[0]; + rc4key->x = 0; + rc4key->y = 0; + id1 = id2 = 0; + +#define SK_LOOP(d, n) \ + { \ + tmp = d[(n)]; \ + id2 = (key[id1] + tmp + id2) & 0xff; \ + if (++id1 == len) \ + id1 = 0; \ + d[(n)] = d[id2]; \ + d[id2] = tmp; \ + } + + for (i = 0; i < 256; i++) { + d[i] = i; + } + for (i = 0; i < 256; i += 4) { + SK_LOOP(d, i + 0); + SK_LOOP(d, i + 1); + SK_LOOP(d, i + 2); + SK_LOOP(d, i + 3); + } +} + +#else + +/* In this case several functions are provided by asm code. However, one cannot + * control asm symbol visibility with command line flags and such so they are + * always hidden and wrapped by these C functions, which can be so + * controlled. */ + +void asm_RC4(RC4_KEY *key, size_t len, const uint8_t *in, uint8_t *out); +void RC4(RC4_KEY *key, size_t len, const uint8_t *in, uint8_t *out) { + asm_RC4(key, len, in, out); +} + +void asm_RC4_set_key(RC4_KEY *rc4key, unsigned len, const uint8_t *key); +void RC4_set_key(RC4_KEY *rc4key, unsigned len, const uint8_t *key) { + asm_RC4_set_key(rc4key, len, key); +} + +#endif /* OPENSSL_NO_ASM || (!OPENSSL_X86_64 && !OPENSSL_X86) */ diff --git a/TMessagesProj/jni/boringssl/crypto/refcount_c11.c b/TMessagesProj/jni/boringssl/crypto/refcount_c11.c new file mode 100644 index 00000000..fbc0343d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/refcount_c11.c @@ -0,0 +1,67 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include "internal.h" + + +#if defined(OPENSSL_C11_ATOMIC) + +#include +#include +#include +#include + +#include + + +/* See comment above the typedef of CRYPTO_refcount_t about these tests. */ +static_assert(alignof(CRYPTO_refcount_t) == alignof(_Atomic CRYPTO_refcount_t), + "_Atomic alters the needed alignment of a reference count"); +static_assert(sizeof(CRYPTO_refcount_t) == sizeof(_Atomic CRYPTO_refcount_t), + "_Atomic alters the size of a reference count"); + +static_assert((CRYPTO_refcount_t)-1 == CRYPTO_REFCOUNT_MAX, + "CRYPTO_REFCOUNT_MAX is incorrect"); + +void CRYPTO_refcount_inc(CRYPTO_refcount_t *in_count) { + _Atomic CRYPTO_refcount_t *count = (_Atomic CRYPTO_refcount_t *) in_count; + uint32_t expected = atomic_load(count); + + while (expected != CRYPTO_REFCOUNT_MAX) { + uint32_t new_value = expected + 1; + if (atomic_compare_exchange_weak(count, &expected, new_value)) { + break; + } + } +} + +int CRYPTO_refcount_dec_and_test_zero(CRYPTO_refcount_t *in_count) { + _Atomic CRYPTO_refcount_t *count = (_Atomic CRYPTO_refcount_t *)in_count; + uint32_t expected = atomic_load(count); + + for (;;) { + if (expected == 0) { + abort(); + } else if (expected == CRYPTO_REFCOUNT_MAX) { + return 0; + } else { + const uint32_t new_value = expected - 1; + if (atomic_compare_exchange_weak(count, &expected, new_value)) { + return new_value == 0; + } + } + } +} + +#endif /* OPENSSL_C11_ATOMIC */ diff --git a/TMessagesProj/jni/boringssl/crypto/refcount_lock.c b/TMessagesProj/jni/boringssl/crypto/refcount_lock.c new file mode 100644 index 00000000..bb8ef86b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/refcount_lock.c @@ -0,0 +1,53 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include "internal.h" + +#include + +#include + + +#if !defined(OPENSSL_C11_ATOMIC) + +OPENSSL_COMPILE_ASSERT((CRYPTO_refcount_t)-1 == CRYPTO_REFCOUNT_MAX, + CRYPTO_REFCOUNT_MAX_is_incorrect); + +static struct CRYPTO_STATIC_MUTEX g_refcount_lock = CRYPTO_STATIC_MUTEX_INIT; + +void CRYPTO_refcount_inc(CRYPTO_refcount_t *count) { + CRYPTO_STATIC_MUTEX_lock_write(&g_refcount_lock); + if (*count < CRYPTO_REFCOUNT_MAX) { + (*count)++; + } + CRYPTO_STATIC_MUTEX_unlock(&g_refcount_lock); +} + +int CRYPTO_refcount_dec_and_test_zero(CRYPTO_refcount_t *count) { + int ret; + + CRYPTO_STATIC_MUTEX_lock_write(&g_refcount_lock); + if (*count == 0) { + abort(); + } + if (*count < CRYPTO_REFCOUNT_MAX) { + (*count)--; + } + ret = (*count == 0); + CRYPTO_STATIC_MUTEX_unlock(&g_refcount_lock); + + return ret; +} + +#endif /* OPENSSL_C11_ATOMIC */ diff --git a/TMessagesProj/jni/boringssl/crypto/rsa/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/rsa/CMakeLists.txt new file mode 100644 index 00000000..bd18d2c4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rsa/CMakeLists.txt @@ -0,0 +1,13 @@ +include_directories(. .. ../../include) + +add_library( + rsa + + OBJECT + + rsa.c + rsa_impl.c + blinding.c + padding.c + rsa_asn1.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/rsa/blinding.c b/TMessagesProj/jni/boringssl/crypto/rsa/blinding.c new file mode 100644 index 00000000..75c34225 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rsa/blinding.c @@ -0,0 +1,460 @@ +/* ==================================================================== + * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + * Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include +#include + +#include "internal.h" + + +#define BN_BLINDING_COUNTER 32 + +struct bn_blinding_st { + BIGNUM *A; + BIGNUM *Ai; + BIGNUM *e; + BIGNUM *mod; /* just a reference */ + int counter; + unsigned long flags; + BN_MONT_CTX *m_ctx; + int (*bn_mod_exp)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx); +}; + +BN_BLINDING *BN_BLINDING_new(const BIGNUM *A, const BIGNUM *Ai, BIGNUM *mod) { + BN_BLINDING *ret = NULL; + + ret = (BN_BLINDING*) OPENSSL_malloc(sizeof(BN_BLINDING)); + if (ret == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + return NULL; + } + memset(ret, 0, sizeof(BN_BLINDING)); + if (A != NULL) { + ret->A = BN_dup(A); + if (ret->A == NULL) { + goto err; + } + } + if (Ai != NULL) { + ret->Ai = BN_dup(Ai); + if (ret->Ai == NULL) { + goto err; + } + } + + /* save a copy of mod in the BN_BLINDING structure */ + ret->mod = BN_dup(mod); + if (ret->mod == NULL) { + goto err; + } + if (BN_get_flags(mod, BN_FLG_CONSTTIME) != 0) { + BN_set_flags(ret->mod, BN_FLG_CONSTTIME); + } + + /* Set the counter to the special value -1 + * to indicate that this is never-used fresh blinding + * that does not need updating before first use. */ + ret->counter = -1; + return ret; + +err: + BN_BLINDING_free(ret); + return NULL; +} + +void BN_BLINDING_free(BN_BLINDING *r) { + if (r == NULL) { + return; + } + + BN_free(r->A); + BN_free(r->Ai); + BN_free(r->e); + BN_free(r->mod); + OPENSSL_free(r); +} + +int BN_BLINDING_update(BN_BLINDING *b, BN_CTX *ctx) { + int ret = 0; + + if (b->A == NULL || b->Ai == NULL) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BN_NOT_INITIALIZED); + goto err; + } + + if (b->counter == -1) { + b->counter = 0; + } + + if (++b->counter == BN_BLINDING_COUNTER && b->e != NULL && + !(b->flags & BN_BLINDING_NO_RECREATE)) { + /* re-create blinding parameters */ + if (!BN_BLINDING_create_param(b, NULL, NULL, ctx, NULL, NULL)) { + goto err; + } + } else if (!(b->flags & BN_BLINDING_NO_UPDATE)) { + if (!BN_mod_mul(b->A, b->A, b->A, b->mod, ctx)) { + goto err; + } + if (!BN_mod_mul(b->Ai, b->Ai, b->Ai, b->mod, ctx)) { + goto err; + } + } + + ret = 1; + +err: + if (b->counter == BN_BLINDING_COUNTER) { + b->counter = 0; + } + return ret; +} + +int BN_BLINDING_convert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx) { + return BN_BLINDING_convert_ex(n, NULL, b, ctx); +} + +int BN_BLINDING_convert_ex(BIGNUM *n, BIGNUM *r, BN_BLINDING *b, BN_CTX *ctx) { + int ret = 1; + + if (b->A == NULL || b->Ai == NULL) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BN_NOT_INITIALIZED); + return 0; + } + + if (b->counter == -1) { + /* Fresh blinding, doesn't need updating. */ + b->counter = 0; + } else if (!BN_BLINDING_update(b, ctx)) { + return 0; + } + + if (r != NULL) { + if (!BN_copy(r, b->Ai)) { + ret = 0; + } + } + + if (!BN_mod_mul(n, n, b->A, b->mod, ctx)) { + ret = 0; + } + + return ret; +} + +int BN_BLINDING_invert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx) { + return BN_BLINDING_invert_ex(n, NULL, b, ctx); +} + +int BN_BLINDING_invert_ex(BIGNUM *n, const BIGNUM *r, BN_BLINDING *b, + BN_CTX *ctx) { + int ret; + + if (r != NULL) { + ret = BN_mod_mul(n, n, r, b->mod, ctx); + } else { + if (b->Ai == NULL) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BN_NOT_INITIALIZED); + return 0; + } + ret = BN_mod_mul(n, n, b->Ai, b->mod, ctx); + } + + return ret; +} + +unsigned long BN_BLINDING_get_flags(const BN_BLINDING *b) { return b->flags; } + +void BN_BLINDING_set_flags(BN_BLINDING *b, unsigned long flags) { + b->flags = flags; +} + +BN_BLINDING *BN_BLINDING_create_param( + BN_BLINDING *b, const BIGNUM *e, BIGNUM *m, BN_CTX *ctx, + int (*bn_mod_exp)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx), + BN_MONT_CTX *m_ctx) { + int retry_counter = 32; + BN_BLINDING *ret = NULL; + + if (b == NULL) { + ret = BN_BLINDING_new(NULL, NULL, m); + } else { + ret = b; + } + + if (ret == NULL) { + goto err; + } + + if (ret->A == NULL && (ret->A = BN_new()) == NULL) { + goto err; + } + if (ret->Ai == NULL && (ret->Ai = BN_new()) == NULL) { + goto err; + } + + if (e != NULL) { + BN_free(ret->e); + ret->e = BN_dup(e); + } + if (ret->e == NULL) { + goto err; + } + + if (bn_mod_exp != NULL) { + ret->bn_mod_exp = bn_mod_exp; + } + if (m_ctx != NULL) { + ret->m_ctx = m_ctx; + } + + do { + if (!BN_rand_range(ret->A, ret->mod)) { + goto err; + } + if (BN_mod_inverse(ret->Ai, ret->A, ret->mod, ctx) == NULL) { + /* this should almost never happen for good RSA keys */ + uint32_t error = ERR_peek_last_error(); + if (ERR_GET_REASON(error) == BN_R_NO_INVERSE) { + if (retry_counter-- == 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_TOO_MANY_ITERATIONS); + goto err; + } + ERR_clear_error(); + } else { + goto err; + } + } else { + break; + } + } while (1); + + if (ret->bn_mod_exp != NULL && ret->m_ctx != NULL) { + if (!ret->bn_mod_exp(ret->A, ret->A, ret->e, ret->mod, ctx, ret->m_ctx)) { + goto err; + } + } else { + if (!BN_mod_exp(ret->A, ret->A, ret->e, ret->mod, ctx)) { + goto err; + } + } + + return ret; + +err: + if (b == NULL) { + BN_BLINDING_free(ret); + ret = NULL; + } + + return ret; +} + +static BIGNUM *rsa_get_public_exp(const BIGNUM *d, const BIGNUM *p, + const BIGNUM *q, BN_CTX *ctx) { + BIGNUM *ret = NULL, *r0, *r1, *r2; + + if (d == NULL || p == NULL || q == NULL) { + return NULL; + } + + BN_CTX_start(ctx); + r0 = BN_CTX_get(ctx); + r1 = BN_CTX_get(ctx); + r2 = BN_CTX_get(ctx); + if (r2 == NULL) { + goto err; + } + + if (!BN_sub(r1, p, BN_value_one())) { + goto err; + } + if (!BN_sub(r2, q, BN_value_one())) { + goto err; + } + if (!BN_mul(r0, r1, r2, ctx)) { + goto err; + } + + ret = BN_mod_inverse(NULL, d, r0, ctx); + +err: + BN_CTX_end(ctx); + return ret; +} + +BN_BLINDING *rsa_setup_blinding(RSA *rsa, BN_CTX *in_ctx) { + BIGNUM local_n; + BIGNUM *e, *n; + BN_CTX *ctx; + BN_BLINDING *ret = NULL; + BN_MONT_CTX *mont_ctx = NULL; + + if (in_ctx == NULL) { + ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } + } else { + ctx = in_ctx; + } + + BN_CTX_start(ctx); + e = BN_CTX_get(ctx); + if (e == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (rsa->e == NULL) { + e = rsa_get_public_exp(rsa->d, rsa->p, rsa->q, ctx); + if (e == NULL) { + OPENSSL_PUT_ERROR(RSA, RSA_R_NO_PUBLIC_EXPONENT); + goto err; + } + } else { + e = rsa->e; + } + + n = &local_n; + BN_with_flags(n, rsa->n, BN_FLG_CONSTTIME); + + if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) { + mont_ctx = + BN_MONT_CTX_set_locked(&rsa->_method_mod_n, &rsa->lock, rsa->n, ctx); + if (mont_ctx == NULL) { + goto err; + } + } + + ret = BN_BLINDING_create_param(NULL, e, n, ctx, rsa->meth->bn_mod_exp, + mont_ctx); + if (ret == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_BN_LIB); + goto err; + } + +err: + BN_CTX_end(ctx); + if (in_ctx == NULL) { + BN_CTX_free(ctx); + } + if (rsa->e == NULL) { + BN_free(e); + } + + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/rsa/internal.h b/TMessagesProj/jni/boringssl/crypto/rsa/internal.h new file mode 100644 index 00000000..c0044c3d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rsa/internal.h @@ -0,0 +1,142 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_RSA_INTERNAL_H +#define OPENSSL_HEADER_RSA_INTERNAL_H + +#include + + +#if defined(__cplusplus) +extern "C" { +#endif + + +#define RSA_PKCS1_PADDING_SIZE 11 + + +/* BN_BLINDING flags */ +#define BN_BLINDING_NO_UPDATE 0x00000001 +#define BN_BLINDING_NO_RECREATE 0x00000002 + +BN_BLINDING *BN_BLINDING_new(const BIGNUM *A, const BIGNUM *Ai, BIGNUM *mod); +void BN_BLINDING_free(BN_BLINDING *b); +int BN_BLINDING_update(BN_BLINDING *b, BN_CTX *ctx); +int BN_BLINDING_convert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx); +int BN_BLINDING_invert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx); +int BN_BLINDING_convert_ex(BIGNUM *n, BIGNUM *r, BN_BLINDING *b, BN_CTX *); +int BN_BLINDING_invert_ex(BIGNUM *n, const BIGNUM *r, BN_BLINDING *b, BN_CTX *); +unsigned long BN_BLINDING_get_flags(const BN_BLINDING *); +void BN_BLINDING_set_flags(BN_BLINDING *, unsigned long); +BN_BLINDING *BN_BLINDING_create_param( + BN_BLINDING *b, const BIGNUM *e, BIGNUM *m, BN_CTX *ctx, + int (*bn_mod_exp)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx), + BN_MONT_CTX *m_ctx); +BN_BLINDING *rsa_setup_blinding(RSA *rsa, BN_CTX *in_ctx); + + +int RSA_padding_add_PKCS1_type_1(uint8_t *to, unsigned to_len, + const uint8_t *from, unsigned from_len); +int RSA_padding_check_PKCS1_type_1(uint8_t *to, unsigned to_len, + const uint8_t *from, unsigned from_len); +int RSA_padding_add_PKCS1_type_2(uint8_t *to, unsigned to_len, + const uint8_t *from, unsigned from_len); +int RSA_padding_check_PKCS1_type_2(uint8_t *to, unsigned to_len, + const uint8_t *from, unsigned from_len); +int RSA_padding_add_PKCS1_OAEP_mgf1(uint8_t *to, unsigned to_len, + const uint8_t *from, unsigned from_len, + const uint8_t *param, unsigned plen, + const EVP_MD *md, const EVP_MD *mgf1md); +int RSA_padding_check_PKCS1_OAEP_mgf1(uint8_t *to, unsigned to_len, + const uint8_t *from, unsigned from_len, + const uint8_t *param, unsigned plen, + const EVP_MD *md, const EVP_MD *mgf1md); +int RSA_padding_add_none(uint8_t *to, unsigned to_len, const uint8_t *from, + unsigned from_len); + +/* RSA_private_transform calls either the method-specific |private_transform| + * function (if given) or the generic one. See the comment for + * |private_transform| in |rsa_meth_st|. */ +int RSA_private_transform(RSA *rsa, uint8_t *out, const uint8_t *in, + size_t len); + + +/* RSA_additional_prime contains information about the third, forth etc prime + * in a multi-prime RSA key. */ +typedef struct RSA_additional_prime_st { + BIGNUM *prime; + /* exp is d^{prime-1} mod prime */ + BIGNUM *exp; + /* coeff is such that r×coeff ≡ 1 mod prime. */ + BIGNUM *coeff; + + /* Values below here are not in the ASN.1 serialisation. */ + + /* r is the product of all primes (including p and q) prior to this one. */ + BIGNUM *r; + /* method_mod is managed by the |RSA_METHOD|. */ + BN_MONT_CTX *method_mod; +} RSA_additional_prime; + +void RSA_additional_prime_free(RSA_additional_prime *ap); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_RSA_INTERNAL_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/rsa/padding.c b/TMessagesProj/jni/boringssl/crypto/rsa/padding.c new file mode 100644 index 00000000..5a42e248 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rsa/padding.c @@ -0,0 +1,732 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2005. + */ +/* ==================================================================== + * Copyright (c) 2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include "internal.h" + +/* TODO(fork): don't the check functions have to be constant time? */ + +int RSA_padding_add_PKCS1_type_1(uint8_t *to, unsigned tlen, + const uint8_t *from, unsigned flen) { + unsigned j; + uint8_t *p; + + if (tlen < RSA_PKCS1_PADDING_SIZE) { + OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL); + return 0; + } + + if (flen > tlen - RSA_PKCS1_PADDING_SIZE) { + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE); + return 0; + } + + p = (uint8_t *)to; + + *(p++) = 0; + *(p++) = 1; /* Private Key BT (Block Type) */ + + /* pad out with 0xff data */ + j = tlen - 3 - flen; + memset(p, 0xff, j); + p += j; + *(p++) = 0; + memcpy(p, from, (unsigned int)flen); + return 1; +} + +int RSA_padding_check_PKCS1_type_1(uint8_t *to, unsigned tlen, + const uint8_t *from, unsigned flen) { + unsigned i, j; + const uint8_t *p; + + if (flen < 2) { + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_SMALL); + return -1; + } + + p = from; + if ((*(p++) != 0) || (*(p++) != 1)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BLOCK_TYPE_IS_NOT_01); + return -1; + } + + /* scan over padding data */ + j = flen - 2; /* one for leading 00, one for type. */ + for (i = 0; i < j; i++) { + /* should decrypt to 0xff */ + if (*p != 0xff) { + if (*p == 0) { + p++; + break; + } else { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_FIXED_HEADER_DECRYPT); + return -1; + } + } + p++; + } + + if (i == j) { + OPENSSL_PUT_ERROR(RSA, RSA_R_NULL_BEFORE_BLOCK_MISSING); + return -1; + } + + if (i < 8) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_PAD_BYTE_COUNT); + return -1; + } + i++; /* Skip over the '\0' */ + j -= i; + if (j > tlen) { + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE); + return -1; + } + memcpy(to, p, j); + + return j; +} + +int RSA_padding_add_PKCS1_type_2(uint8_t *to, unsigned tlen, + const uint8_t *from, unsigned flen) { + unsigned i, j; + uint8_t *p; + + if (tlen < RSA_PKCS1_PADDING_SIZE) { + OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL); + return 0; + } + + if (flen > tlen - RSA_PKCS1_PADDING_SIZE) { + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE); + return 0; + } + + p = (unsigned char *)to; + + *(p++) = 0; + *(p++) = 2; /* Public Key BT (Block Type) */ + + /* pad out with non-zero random data */ + j = tlen - 3 - flen; + + if (!RAND_bytes(p, j)) { + return 0; + } + + for (i = 0; i < j; i++) { + while (*p == 0) { + if (!RAND_bytes(p, 1)) { + return 0; + } + } + p++; + } + + *(p++) = 0; + + memcpy(p, from, (unsigned int)flen); + return 1; +} + +/* constant_time_byte_eq returns 1 if |x| == |y| and 0 otherwise. */ +static int constant_time_byte_eq(unsigned char a, unsigned char b) { + unsigned char z = ~(a ^ b); + z &= z >> 4; + z &= z >> 2; + z &= z >> 1; + + return z; +} + +/* constant_time_select returns |x| if |v| is 1 and |y| if |v| is 0. + * Its behavior is undefined if |v| takes any other value. */ +static int constant_time_select(int v, int x, int y) { + return ((~(v - 1)) & x) | ((v - 1) & y); +} + +/* constant_time_le returns 1 if |x| <= |y| and 0 otherwise. + * |x| and |y| must be positive. */ +static int constant_time_le(int x, int y) { + return ((x - y - 1) >> (sizeof(int) * 8 - 1)) & 1; +} + +int RSA_message_index_PKCS1_type_2(const uint8_t *from, size_t from_len, + size_t *out_index) { + size_t i; + int first_byte_is_zero, second_byte_is_two, looking_for_index; + int valid_index, zero_index = 0; + + /* PKCS#1 v1.5 decryption. See "PKCS #1 v2.2: RSA Cryptography + * Standard", section 7.2.2. */ + if (from_len < RSA_PKCS1_PADDING_SIZE) { + /* |from| is zero-padded to the size of the RSA modulus, a public value, so + * this can be rejected in non-constant time. */ + *out_index = 0; + return 0; + } + + first_byte_is_zero = constant_time_byte_eq(from[0], 0); + second_byte_is_two = constant_time_byte_eq(from[1], 2); + + looking_for_index = 1; + for (i = 2; i < from_len; i++) { + int equals0 = constant_time_byte_eq(from[i], 0); + zero_index = + constant_time_select(looking_for_index & equals0, i, zero_index); + looking_for_index = constant_time_select(equals0, 0, looking_for_index); + } + + /* The input must begin with 00 02. */ + valid_index = first_byte_is_zero; + valid_index &= second_byte_is_two; + + /* We must have found the end of PS. */ + valid_index &= ~looking_for_index; + + /* PS must be at least 8 bytes long, and it starts two bytes into |from|. */ + valid_index &= constant_time_le(2 + 8, zero_index); + + /* Skip the zero byte. */ + zero_index++; + + *out_index = constant_time_select(valid_index, zero_index, 0); + return valid_index; +} + +int RSA_padding_check_PKCS1_type_2(uint8_t *to, unsigned tlen, + const uint8_t *from, unsigned flen) { + size_t msg_index, msg_len; + + if (flen == 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_EMPTY_PUBLIC_KEY); + return -1; + } + + /* NOTE: Although |RSA_message_index_PKCS1_type_2| itself is constant time, + * the API contracts of this function and |RSA_decrypt| with + * |RSA_PKCS1_PADDING| make it impossible to completely avoid Bleichenbacher's + * attack. */ + if (!RSA_message_index_PKCS1_type_2(from, flen, &msg_index)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_PKCS_DECODING_ERROR); + return -1; + } + + msg_len = flen - msg_index; + if (msg_len > tlen) { + /* This shouldn't happen because this function is always called with |tlen| + * the key size and |flen| is bounded by the key size. */ + OPENSSL_PUT_ERROR(RSA, RSA_R_PKCS_DECODING_ERROR); + return -1; + } + memcpy(to, &from[msg_index], msg_len); + return msg_len; +} + +int RSA_padding_add_none(uint8_t *to, unsigned tlen, const uint8_t *from, unsigned flen) { + if (flen > tlen) { + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE); + return 0; + } + + if (flen < tlen) { + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE); + return 0; + } + + memcpy(to, from, (unsigned int)flen); + return 1; +} + +int PKCS1_MGF1(uint8_t *mask, unsigned len, const uint8_t *seed, + unsigned seedlen, const EVP_MD *dgst) { + unsigned outlen = 0; + uint32_t i; + uint8_t cnt[4]; + EVP_MD_CTX c; + uint8_t md[EVP_MAX_MD_SIZE]; + unsigned mdlen; + int ret = -1; + + EVP_MD_CTX_init(&c); + mdlen = EVP_MD_size(dgst); + + for (i = 0; outlen < len; i++) { + cnt[0] = (uint8_t)((i >> 24) & 255); + cnt[1] = (uint8_t)((i >> 16) & 255); + cnt[2] = (uint8_t)((i >> 8)) & 255; + cnt[3] = (uint8_t)(i & 255); + if (!EVP_DigestInit_ex(&c, dgst, NULL) || + !EVP_DigestUpdate(&c, seed, seedlen) || !EVP_DigestUpdate(&c, cnt, 4)) { + goto err; + } + + if (outlen + mdlen <= len) { + if (!EVP_DigestFinal_ex(&c, mask + outlen, NULL)) { + goto err; + } + outlen += mdlen; + } else { + if (!EVP_DigestFinal_ex(&c, md, NULL)) { + goto err; + } + memcpy(mask + outlen, md, len - outlen); + outlen = len; + } + } + ret = 0; + +err: + EVP_MD_CTX_cleanup(&c); + return ret; +} + +int RSA_padding_add_PKCS1_OAEP_mgf1(uint8_t *to, unsigned tlen, + const uint8_t *from, unsigned flen, + const uint8_t *param, unsigned plen, + const EVP_MD *md, const EVP_MD *mgf1md) { + unsigned i, emlen, mdlen; + uint8_t *db, *seed; + uint8_t *dbmask = NULL, seedmask[EVP_MAX_MD_SIZE]; + int ret = 0; + + if (md == NULL) { + md = EVP_sha1(); + } + if (mgf1md == NULL) { + mgf1md = md; + } + + mdlen = EVP_MD_size(md); + + if (tlen < 2 * mdlen + 2) { + OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL); + return 0; + } + + emlen = tlen - 1; + if (flen > emlen - 2 * mdlen - 1) { + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE); + return 0; + } + + if (emlen < 2 * mdlen + 1) { + OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL); + return 0; + } + + to[0] = 0; + seed = to + 1; + db = to + mdlen + 1; + + if (!EVP_Digest((void *)param, plen, db, NULL, md, NULL)) { + return 0; + } + memset(db + mdlen, 0, emlen - flen - 2 * mdlen - 1); + db[emlen - flen - mdlen - 1] = 0x01; + memcpy(db + emlen - flen - mdlen, from, flen); + if (!RAND_bytes(seed, mdlen)) { + return 0; + } + + dbmask = OPENSSL_malloc(emlen - mdlen); + if (dbmask == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + return 0; + } + + if (PKCS1_MGF1(dbmask, emlen - mdlen, seed, mdlen, mgf1md) < 0) { + goto out; + } + for (i = 0; i < emlen - mdlen; i++) { + db[i] ^= dbmask[i]; + } + + if (PKCS1_MGF1(seedmask, mdlen, db, emlen - mdlen, mgf1md) < 0) { + goto out; + } + for (i = 0; i < mdlen; i++) { + seed[i] ^= seedmask[i]; + } + ret = 1; + +out: + OPENSSL_free(dbmask); + return ret; +} + +int RSA_padding_check_PKCS1_OAEP_mgf1(uint8_t *to, unsigned tlen, + const uint8_t *from, unsigned flen, + const uint8_t *param, unsigned plen, + const EVP_MD *md, const EVP_MD *mgf1md) { + unsigned i, dblen, mlen = -1, mdlen; + const uint8_t *maskeddb, *maskedseed; + uint8_t *db = NULL, seed[EVP_MAX_MD_SIZE], phash[EVP_MAX_MD_SIZE]; + int bad, looking_for_one_byte, one_index = 0; + + if (md == NULL) { + md = EVP_sha1(); + } + if (mgf1md == NULL) { + mgf1md = md; + } + + mdlen = EVP_MD_size(md); + + /* The encoded message is one byte smaller than the modulus to ensure that it + * doesn't end up greater than the modulus. Thus there's an extra "+1" here + * compared to https://tools.ietf.org/html/rfc2437#section-9.1.1.2. */ + if (flen < 1 + 2*mdlen + 1) { + /* 'flen' is the length of the modulus, i.e. does not depend on the + * particular ciphertext. */ + goto decoding_err; + } + + dblen = flen - mdlen - 1; + db = OPENSSL_malloc(dblen); + if (db == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + + maskedseed = from + 1; + maskeddb = from + 1 + mdlen; + + if (PKCS1_MGF1(seed, mdlen, maskeddb, dblen, mgf1md)) { + goto err; + } + for (i = 0; i < mdlen; i++) { + seed[i] ^= maskedseed[i]; + } + + if (PKCS1_MGF1(db, dblen, seed, mdlen, mgf1md)) { + goto err; + } + for (i = 0; i < dblen; i++) { + db[i] ^= maskeddb[i]; + } + + if (!EVP_Digest((void *)param, plen, phash, NULL, md, NULL)) { + goto err; + } + + bad = CRYPTO_memcmp(db, phash, mdlen); + bad |= from[0]; + + looking_for_one_byte = 1; + for (i = mdlen; i < dblen; i++) { + int equals1 = constant_time_byte_eq(db[i], 1); + int equals0 = constant_time_byte_eq(db[i], 0); + one_index = + constant_time_select(looking_for_one_byte & equals1, i, one_index); + looking_for_one_byte = + constant_time_select(equals1, 0, looking_for_one_byte); + bad |= looking_for_one_byte & ~equals0; + } + + bad |= looking_for_one_byte; + + if (bad) { + goto decoding_err; + } + + one_index++; + mlen = dblen - one_index; + if (tlen < mlen) { + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE); + mlen = -1; + } else { + memcpy(to, db + one_index, mlen); + } + + OPENSSL_free(db); + return mlen; + +decoding_err: + /* to avoid chosen ciphertext attacks, the error message should not reveal + * which kind of decoding error happened */ + OPENSSL_PUT_ERROR(RSA, RSA_R_OAEP_DECODING_ERROR); + err: + OPENSSL_free(db); + return -1; +} + +static const unsigned char zeroes[] = {0,0,0,0,0,0,0,0}; + +int RSA_verify_PKCS1_PSS_mgf1(RSA *rsa, const uint8_t *mHash, + const EVP_MD *Hash, const EVP_MD *mgf1Hash, + const uint8_t *EM, int sLen) { + int i; + int ret = 0; + int maskedDBLen, MSBits, emLen; + size_t hLen; + const uint8_t *H; + uint8_t *DB = NULL; + EVP_MD_CTX ctx; + uint8_t H_[EVP_MAX_MD_SIZE]; + EVP_MD_CTX_init(&ctx); + + if (mgf1Hash == NULL) { + mgf1Hash = Hash; + } + + hLen = EVP_MD_size(Hash); + + /* Negative sLen has special meanings: + * -1 sLen == hLen + * -2 salt length is autorecovered from signature + * -N reserved */ + if (sLen == -1) { + sLen = hLen; + } else if (sLen == -2) { + sLen = -2; + } else if (sLen < -2) { + OPENSSL_PUT_ERROR(RSA, RSA_R_SLEN_CHECK_FAILED); + goto err; + } + + MSBits = (BN_num_bits(rsa->n) - 1) & 0x7; + emLen = RSA_size(rsa); + if (EM[0] & (0xFF << MSBits)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_FIRST_OCTET_INVALID); + goto err; + } + if (MSBits == 0) { + EM++; + emLen--; + } + if (emLen < ((int)hLen + sLen + 2)) { + /* sLen can be small negative */ + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE); + goto err; + } + if (EM[emLen - 1] != 0xbc) { + OPENSSL_PUT_ERROR(RSA, RSA_R_LAST_OCTET_INVALID); + goto err; + } + maskedDBLen = emLen - hLen - 1; + H = EM + maskedDBLen; + DB = OPENSSL_malloc(maskedDBLen); + if (!DB) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + if (PKCS1_MGF1(DB, maskedDBLen, H, hLen, mgf1Hash) < 0) { + goto err; + } + for (i = 0; i < maskedDBLen; i++) { + DB[i] ^= EM[i]; + } + if (MSBits) { + DB[0] &= 0xFF >> (8 - MSBits); + } + for (i = 0; DB[i] == 0 && i < (maskedDBLen - 1); i++) { + ; + } + if (DB[i++] != 0x1) { + OPENSSL_PUT_ERROR(RSA, RSA_R_SLEN_RECOVERY_FAILED); + goto err; + } + if (sLen >= 0 && (maskedDBLen - i) != sLen) { + OPENSSL_PUT_ERROR(RSA, RSA_R_SLEN_CHECK_FAILED); + goto err; + } + if (!EVP_DigestInit_ex(&ctx, Hash, NULL) || + !EVP_DigestUpdate(&ctx, zeroes, sizeof zeroes) || + !EVP_DigestUpdate(&ctx, mHash, hLen)) { + goto err; + } + if (maskedDBLen - i) { + if (!EVP_DigestUpdate(&ctx, DB + i, maskedDBLen - i)) { + goto err; + } + } + if (!EVP_DigestFinal_ex(&ctx, H_, NULL)) { + goto err; + } + if (memcmp(H_, H, hLen)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_SIGNATURE); + ret = 0; + } else { + ret = 1; + } + +err: + OPENSSL_free(DB); + EVP_MD_CTX_cleanup(&ctx); + + return ret; +} + +int RSA_padding_add_PKCS1_PSS_mgf1(RSA *rsa, unsigned char *EM, + const unsigned char *mHash, + const EVP_MD *Hash, const EVP_MD *mgf1Hash, + int sLen) { + int i; + int ret = 0; + size_t maskedDBLen, MSBits, emLen; + size_t hLen; + unsigned char *H, *salt = NULL, *p; + EVP_MD_CTX ctx; + + if (mgf1Hash == NULL) { + mgf1Hash = Hash; + } + + hLen = EVP_MD_size(Hash); + + /* Negative sLen has special meanings: + * -1 sLen == hLen + * -2 salt length is maximized + * -N reserved */ + if (sLen == -1) { + sLen = hLen; + } else if (sLen == -2) { + sLen = -2; + } else if (sLen < -2) { + OPENSSL_PUT_ERROR(RSA, RSA_R_SLEN_CHECK_FAILED); + goto err; + } + + if (BN_is_zero(rsa->n)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_EMPTY_PUBLIC_KEY); + goto err; + } + + MSBits = (BN_num_bits(rsa->n) - 1) & 0x7; + emLen = RSA_size(rsa); + if (MSBits == 0) { + assert(emLen >= 1); + *EM++ = 0; + emLen--; + } + if (sLen == -2) { + if (emLen < hLen + 2) { + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE); + goto err; + } + sLen = emLen - hLen - 2; + } else if (emLen < hLen + sLen + 2) { + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE); + goto err; + } + if (sLen > 0) { + salt = OPENSSL_malloc(sLen); + if (!salt) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + if (!RAND_bytes(salt, sLen)) { + goto err; + } + } + maskedDBLen = emLen - hLen - 1; + H = EM + maskedDBLen; + EVP_MD_CTX_init(&ctx); + if (!EVP_DigestInit_ex(&ctx, Hash, NULL) || + !EVP_DigestUpdate(&ctx, zeroes, sizeof zeroes) || + !EVP_DigestUpdate(&ctx, mHash, hLen)) { + goto err; + } + if (sLen && !EVP_DigestUpdate(&ctx, salt, sLen)) { + goto err; + } + if (!EVP_DigestFinal_ex(&ctx, H, NULL)) { + goto err; + } + EVP_MD_CTX_cleanup(&ctx); + + /* Generate dbMask in place then perform XOR on it */ + if (PKCS1_MGF1(EM, maskedDBLen, H, hLen, mgf1Hash)) { + goto err; + } + + p = EM; + + /* Initial PS XORs with all zeroes which is a NOP so just update + * pointer. Note from a test above this value is guaranteed to + * be non-negative. */ + p += emLen - sLen - hLen - 2; + *p++ ^= 0x1; + if (sLen > 0) { + for (i = 0; i < sLen; i++) { + *p++ ^= salt[i]; + } + } + if (MSBits) { + EM[0] &= 0xFF >> (8 - MSBits); + } + + /* H is already in place so just set final 0xbc */ + + EM[emLen - 1] = 0xbc; + + ret = 1; + +err: + OPENSSL_free(salt); + + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/rsa/rsa.c b/TMessagesProj/jni/boringssl/crypto/rsa/rsa.c new file mode 100644 index 00000000..2f23165c --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rsa/rsa.c @@ -0,0 +1,797 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" +#include "../internal.h" + + +extern const RSA_METHOD RSA_default_method; + +static CRYPTO_EX_DATA_CLASS g_ex_data_class = CRYPTO_EX_DATA_CLASS_INIT; + +RSA *RSA_new(void) { return RSA_new_method(NULL); } + +RSA *RSA_new_method(const ENGINE *engine) { + RSA *rsa = (RSA *)OPENSSL_malloc(sizeof(RSA)); + if (rsa == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + return NULL; + } + + memset(rsa, 0, sizeof(RSA)); + + if (engine) { + rsa->meth = ENGINE_get_RSA_method(engine); + } + + if (rsa->meth == NULL) { + rsa->meth = (RSA_METHOD*) &RSA_default_method; + } + METHOD_ref(rsa->meth); + + rsa->references = 1; + rsa->flags = rsa->meth->flags; + CRYPTO_MUTEX_init(&rsa->lock); + + if (!CRYPTO_new_ex_data(&g_ex_data_class, rsa, &rsa->ex_data)) { + METHOD_unref(rsa->meth); + OPENSSL_free(rsa); + return NULL; + } + + if (rsa->meth->init && !rsa->meth->init(rsa)) { + CRYPTO_free_ex_data(&g_ex_data_class, rsa, &rsa->ex_data); + METHOD_unref(rsa->meth); + OPENSSL_free(rsa); + return NULL; + } + + return rsa; +} + +void RSA_additional_prime_free(RSA_additional_prime *ap) { + if (ap == NULL) { + return; + } + + BN_clear_free(ap->prime); + BN_clear_free(ap->exp); + BN_clear_free(ap->coeff); + BN_clear_free(ap->r); + OPENSSL_free(ap); +} + +void RSA_free(RSA *rsa) { + unsigned u; + + if (rsa == NULL) { + return; + } + + if (!CRYPTO_refcount_dec_and_test_zero(&rsa->references)) { + return; + } + + if (rsa->meth->finish) { + rsa->meth->finish(rsa); + } + METHOD_unref(rsa->meth); + + CRYPTO_free_ex_data(&g_ex_data_class, rsa, &rsa->ex_data); + + BN_clear_free(rsa->n); + BN_clear_free(rsa->e); + BN_clear_free(rsa->d); + BN_clear_free(rsa->p); + BN_clear_free(rsa->q); + BN_clear_free(rsa->dmp1); + BN_clear_free(rsa->dmq1); + BN_clear_free(rsa->iqmp); + for (u = 0; u < rsa->num_blindings; u++) { + BN_BLINDING_free(rsa->blindings[u]); + } + OPENSSL_free(rsa->blindings); + OPENSSL_free(rsa->blindings_inuse); + if (rsa->additional_primes != NULL) { + sk_RSA_additional_prime_pop_free(rsa->additional_primes, + RSA_additional_prime_free); + } + CRYPTO_MUTEX_cleanup(&rsa->lock); + OPENSSL_free(rsa); +} + +int RSA_up_ref(RSA *rsa) { + CRYPTO_refcount_inc(&rsa->references); + return 1; +} + +int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb) { + if (rsa->meth->keygen) { + return rsa->meth->keygen(rsa, bits, e_value, cb); + } + + return RSA_default_method.keygen(rsa, bits, e_value, cb); +} + +int RSA_generate_multi_prime_key(RSA *rsa, int bits, int num_primes, + BIGNUM *e_value, BN_GENCB *cb) { + if (rsa->meth->multi_prime_keygen) { + return rsa->meth->multi_prime_keygen(rsa, bits, num_primes, e_value, cb); + } + + return RSA_default_method.multi_prime_keygen(rsa, bits, num_primes, e_value, + cb); +} + +int RSA_encrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, + const uint8_t *in, size_t in_len, int padding) { + if (rsa->meth->encrypt) { + return rsa->meth->encrypt(rsa, out_len, out, max_out, in, in_len, padding); + } + + return RSA_default_method.encrypt(rsa, out_len, out, max_out, in, in_len, + padding); +} + +int RSA_public_encrypt(int flen, const uint8_t *from, uint8_t *to, RSA *rsa, + int padding) { + size_t out_len; + + if (!RSA_encrypt(rsa, &out_len, to, RSA_size(rsa), from, flen, padding)) { + return -1; + } + + return out_len; +} + +int RSA_sign_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, + const uint8_t *in, size_t in_len, int padding) { + if (rsa->meth->sign_raw) { + return rsa->meth->sign_raw(rsa, out_len, out, max_out, in, in_len, padding); + } + + return RSA_default_method.sign_raw(rsa, out_len, out, max_out, in, in_len, + padding); +} + +int RSA_private_encrypt(int flen, const uint8_t *from, uint8_t *to, RSA *rsa, + int padding) { + size_t out_len; + + if (!RSA_sign_raw(rsa, &out_len, to, RSA_size(rsa), from, flen, padding)) { + return -1; + } + + return out_len; +} + +int RSA_decrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, + const uint8_t *in, size_t in_len, int padding) { + if (rsa->meth->decrypt) { + return rsa->meth->decrypt(rsa, out_len, out, max_out, in, in_len, padding); + } + + return RSA_default_method.decrypt(rsa, out_len, out, max_out, in, in_len, + padding); +} + +int RSA_private_decrypt(int flen, const uint8_t *from, uint8_t *to, RSA *rsa, + int padding) { + size_t out_len; + + if (!RSA_decrypt(rsa, &out_len, to, RSA_size(rsa), from, flen, padding)) { + return -1; + } + + return out_len; +} + +int RSA_verify_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, + const uint8_t *in, size_t in_len, int padding) { + if (rsa->meth->verify_raw) { + return rsa->meth->verify_raw(rsa, out_len, out, max_out, in, in_len, padding); + } + + return RSA_default_method.verify_raw(rsa, out_len, out, max_out, in, in_len, + padding); +} + +int RSA_public_decrypt(int flen, const uint8_t *from, uint8_t *to, RSA *rsa, + int padding) { + size_t out_len; + + if (!RSA_verify_raw(rsa, &out_len, to, RSA_size(rsa), from, flen, padding)) { + return -1; + } + + return out_len; +} + +unsigned RSA_size(const RSA *rsa) { + if (rsa->meth->size) { + return rsa->meth->size(rsa); + } + + return RSA_default_method.size(rsa); +} + +int RSA_is_opaque(const RSA *rsa) { + return rsa->meth && (rsa->meth->flags & RSA_FLAG_OPAQUE); +} + +int RSA_supports_digest(const RSA *rsa, const EVP_MD *md) { + if (rsa->meth && rsa->meth->supports_digest) { + return rsa->meth->supports_digest(rsa, md); + } + return 1; +} + +int RSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func) { + int index; + if (!CRYPTO_get_ex_new_index(&g_ex_data_class, &index, argl, argp, new_func, + dup_func, free_func)) { + return -1; + } + return index; +} + +int RSA_set_ex_data(RSA *d, int idx, void *arg) { + return CRYPTO_set_ex_data(&d->ex_data, idx, arg); +} + +void *RSA_get_ex_data(const RSA *d, int idx) { + return CRYPTO_get_ex_data(&d->ex_data, idx); +} + +/* SSL_SIG_LENGTH is the size of an SSL/TLS (prior to TLS 1.2) signature: it's + * the length of an MD5 and SHA1 hash. */ +static const unsigned SSL_SIG_LENGTH = 36; + +/* pkcs1_sig_prefix contains the ASN.1, DER encoded prefix for a hash that is + * to be signed with PKCS#1. */ +struct pkcs1_sig_prefix { + /* nid identifies the hash function. */ + int nid; + /* len is the number of bytes of |bytes| which are valid. */ + uint8_t len; + /* bytes contains the DER bytes. */ + uint8_t bytes[19]; +}; + +/* kPKCS1SigPrefixes contains the ASN.1 prefixes for PKCS#1 signatures with + * different hash functions. */ +static const struct pkcs1_sig_prefix kPKCS1SigPrefixes[] = { + { + NID_md5, + 18, + {0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x02, 0x05, 0x05, 0x00, 0x04, 0x10}, + }, + { + NID_sha1, + 15, + {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, + 0x00, 0x04, 0x14}, + }, + { + NID_sha224, + 19, + {0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, + 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1c}, + }, + { + NID_sha256, + 19, + {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, + 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20}, + }, + { + NID_sha384, + 19, + {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, + 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30}, + }, + { + NID_sha512, + 19, + {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, + 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40}, + }, + { + NID_undef, 0, {0}, + }, +}; + +int RSA_add_pkcs1_prefix(uint8_t **out_msg, size_t *out_msg_len, + int *is_alloced, int hash_nid, const uint8_t *msg, + size_t msg_len) { + unsigned i; + + if (hash_nid == NID_md5_sha1) { + /* Special case: SSL signature, just check the length. */ + if (msg_len != SSL_SIG_LENGTH) { + OPENSSL_PUT_ERROR(RSA, RSA_R_INVALID_MESSAGE_LENGTH); + return 0; + } + + *out_msg = (uint8_t*) msg; + *out_msg_len = SSL_SIG_LENGTH; + *is_alloced = 0; + return 1; + } + + for (i = 0; kPKCS1SigPrefixes[i].nid != NID_undef; i++) { + const struct pkcs1_sig_prefix *sig_prefix = &kPKCS1SigPrefixes[i]; + if (sig_prefix->nid != hash_nid) { + continue; + } + + const uint8_t* prefix = sig_prefix->bytes; + unsigned prefix_len = sig_prefix->len; + unsigned signed_msg_len; + uint8_t *signed_msg; + + signed_msg_len = prefix_len + msg_len; + if (signed_msg_len < prefix_len) { + OPENSSL_PUT_ERROR(RSA, RSA_R_TOO_LONG); + return 0; + } + + signed_msg = OPENSSL_malloc(signed_msg_len); + if (!signed_msg) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + return 0; + } + + memcpy(signed_msg, prefix, prefix_len); + memcpy(signed_msg + prefix_len, msg, msg_len); + + *out_msg = signed_msg; + *out_msg_len = signed_msg_len; + *is_alloced = 1; + + return 1; + } + + OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_ALGORITHM_TYPE); + return 0; +} + +int RSA_sign(int hash_nid, const uint8_t *in, unsigned in_len, uint8_t *out, + unsigned *out_len, RSA *rsa) { + const unsigned rsa_size = RSA_size(rsa); + int ret = 0; + uint8_t *signed_msg; + size_t signed_msg_len; + int signed_msg_is_alloced = 0; + size_t size_t_out_len; + + if (rsa->meth->sign) { + return rsa->meth->sign(hash_nid, in, in_len, out, out_len, rsa); + } + + if (!RSA_add_pkcs1_prefix(&signed_msg, &signed_msg_len, + &signed_msg_is_alloced, hash_nid, in, in_len)) { + return 0; + } + + if (rsa_size < RSA_PKCS1_PADDING_SIZE || + signed_msg_len > rsa_size - RSA_PKCS1_PADDING_SIZE) { + OPENSSL_PUT_ERROR(RSA, RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY); + goto finish; + } + + if (RSA_sign_raw(rsa, &size_t_out_len, out, rsa_size, signed_msg, + signed_msg_len, RSA_PKCS1_PADDING)) { + *out_len = size_t_out_len; + ret = 1; + } + +finish: + if (signed_msg_is_alloced) { + OPENSSL_free(signed_msg); + } + return ret; +} + +int RSA_verify(int hash_nid, const uint8_t *msg, size_t msg_len, + const uint8_t *sig, size_t sig_len, RSA *rsa) { + const size_t rsa_size = RSA_size(rsa); + uint8_t *buf = NULL; + int ret = 0; + uint8_t *signed_msg = NULL; + size_t signed_msg_len, len; + int signed_msg_is_alloced = 0; + + if (rsa->meth->verify) { + return rsa->meth->verify(hash_nid, msg, msg_len, sig, sig_len, rsa); + } + + if (sig_len != rsa_size) { + OPENSSL_PUT_ERROR(RSA, RSA_R_WRONG_SIGNATURE_LENGTH); + return 0; + } + + if (hash_nid == NID_md5_sha1 && msg_len != SSL_SIG_LENGTH) { + OPENSSL_PUT_ERROR(RSA, RSA_R_INVALID_MESSAGE_LENGTH); + return 0; + } + + buf = OPENSSL_malloc(rsa_size); + if (!buf) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + return 0; + } + + if (!RSA_verify_raw(rsa, &len, buf, rsa_size, sig, sig_len, + RSA_PKCS1_PADDING)) { + goto out; + } + + if (!RSA_add_pkcs1_prefix(&signed_msg, &signed_msg_len, + &signed_msg_is_alloced, hash_nid, msg, msg_len)) { + goto out; + } + + if (len != signed_msg_len || CRYPTO_memcmp(buf, signed_msg, len) != 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_SIGNATURE); + goto out; + } + + ret = 1; + +out: + OPENSSL_free(buf); + if (signed_msg_is_alloced) { + OPENSSL_free(signed_msg); + } + return ret; +} + +static void bn_free_and_null(BIGNUM **bn) { + BN_free(*bn); + *bn = NULL; +} + +int RSA_check_key(const RSA *key) { + BIGNUM n, pm1, qm1, lcm, gcd, de, dmp1, dmq1, iqmp; + BN_CTX *ctx; + int ok = 0, has_crt_values; + + if (RSA_is_opaque(key)) { + /* Opaque keys can't be checked. */ + return 1; + } + + if ((key->p != NULL) != (key->q != NULL)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_ONLY_ONE_OF_P_Q_GIVEN); + return 0; + } + + if (!key->n || !key->e) { + OPENSSL_PUT_ERROR(RSA, RSA_R_VALUE_MISSING); + return 0; + } + + if (!key->d || !key->p) { + /* For a public key, or without p and q, there's nothing that can be + * checked. */ + return 1; + } + + ctx = BN_CTX_new(); + if (ctx == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + return 0; + } + + BN_init(&n); + BN_init(&pm1); + BN_init(&qm1); + BN_init(&lcm); + BN_init(&gcd); + BN_init(&de); + BN_init(&dmp1); + BN_init(&dmq1); + BN_init(&iqmp); + + if (!BN_mul(&n, key->p, key->q, ctx) || + /* lcm = lcm(prime-1, for all primes) */ + !BN_sub(&pm1, key->p, BN_value_one()) || + !BN_sub(&qm1, key->q, BN_value_one()) || + !BN_mul(&lcm, &pm1, &qm1, ctx) || + !BN_gcd(&gcd, &pm1, &qm1, ctx)) { + OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN); + goto out; + } + + size_t num_additional_primes = 0; + if (key->additional_primes != NULL) { + num_additional_primes = sk_RSA_additional_prime_num(key->additional_primes); + } + + size_t i; + for (i = 0; i < num_additional_primes; i++) { + const RSA_additional_prime *ap = + sk_RSA_additional_prime_value(key->additional_primes, i); + if (!BN_mul(&n, &n, ap->prime, ctx) || + !BN_sub(&pm1, ap->prime, BN_value_one()) || + !BN_mul(&lcm, &lcm, &pm1, ctx) || + !BN_gcd(&gcd, &gcd, &pm1, ctx)) { + OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN); + goto out; + } + } + + if (!BN_div(&lcm, NULL, &lcm, &gcd, ctx) || + !BN_gcd(&gcd, &pm1, &qm1, ctx) || + /* de = d*e mod lcm(prime-1, for all primes). */ + !BN_mod_mul(&de, key->d, key->e, &lcm, ctx)) { + OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN); + goto out; + } + + if (BN_cmp(&n, key->n) != 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_N_NOT_EQUAL_P_Q); + goto out; + } + + if (!BN_is_one(&de)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_D_E_NOT_CONGRUENT_TO_1); + goto out; + } + + has_crt_values = key->dmp1 != NULL; + if (has_crt_values != (key->dmq1 != NULL) || + has_crt_values != (key->iqmp != NULL)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_INCONSISTENT_SET_OF_CRT_VALUES); + goto out; + } + + if (has_crt_values && num_additional_primes == 0) { + if (/* dmp1 = d mod (p-1) */ + !BN_mod(&dmp1, key->d, &pm1, ctx) || + /* dmq1 = d mod (q-1) */ + !BN_mod(&dmq1, key->d, &qm1, ctx) || + /* iqmp = q^-1 mod p */ + !BN_mod_inverse(&iqmp, key->q, key->p, ctx)) { + OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN); + goto out; + } + + if (BN_cmp(&dmp1, key->dmp1) != 0 || + BN_cmp(&dmq1, key->dmq1) != 0 || + BN_cmp(&iqmp, key->iqmp) != 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_CRT_VALUES_INCORRECT); + goto out; + } + } + + ok = 1; + +out: + BN_free(&n); + BN_free(&pm1); + BN_free(&qm1); + BN_free(&lcm); + BN_free(&gcd); + BN_free(&de); + BN_free(&dmp1); + BN_free(&dmq1); + BN_free(&iqmp); + BN_CTX_free(ctx); + + return ok; +} + +int RSA_recover_crt_params(RSA *rsa) { + BN_CTX *ctx; + BIGNUM *totient, *rem, *multiple, *p_plus_q, *p_minus_q; + int ok = 0; + + if (rsa->n == NULL || rsa->e == NULL || rsa->d == NULL) { + OPENSSL_PUT_ERROR(RSA, RSA_R_EMPTY_PUBLIC_KEY); + return 0; + } + + if (rsa->p || rsa->q || rsa->dmp1 || rsa->dmq1 || rsa->iqmp) { + OPENSSL_PUT_ERROR(RSA, RSA_R_CRT_PARAMS_ALREADY_GIVEN); + return 0; + } + + if (rsa->additional_primes != NULL) { + OPENSSL_PUT_ERROR(RSA, RSA_R_CANNOT_RECOVER_MULTI_PRIME_KEY); + return 0; + } + + /* This uses the algorithm from section 9B of the RSA paper: + * http://people.csail.mit.edu/rivest/Rsapaper.pdf */ + + ctx = BN_CTX_new(); + if (ctx == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + return 0; + } + + BN_CTX_start(ctx); + totient = BN_CTX_get(ctx); + rem = BN_CTX_get(ctx); + multiple = BN_CTX_get(ctx); + p_plus_q = BN_CTX_get(ctx); + p_minus_q = BN_CTX_get(ctx); + + if (totient == NULL || rem == NULL || multiple == NULL || p_plus_q == NULL || + p_minus_q == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* ed-1 is a small multiple of φ(n). */ + if (!BN_mul(totient, rsa->e, rsa->d, ctx) || + !BN_sub_word(totient, 1) || + /* φ(n) = + * pq - p - q + 1 = + * n - (p + q) + 1 + * + * Thus n is a reasonable estimate for φ(n). So, (ed-1)/n will be very + * close. But, when we calculate the quotient, we'll be truncating it + * because we discard the remainder. Thus (ed-1)/multiple will be >= n, + * which the totient cannot be. So we add one to the estimate. + * + * Consider ed-1 as: + * + * multiple * (n - (p+q) + 1) = + * multiple*n - multiple*(p+q) + multiple + * + * When we divide by n, the first term becomes multiple and, since + * multiple and p+q is tiny compared to n, the second and third terms can + * be ignored. Thus I claim that subtracting one from the estimate is + * sufficient. */ + !BN_div(multiple, NULL, totient, rsa->n, ctx) || + !BN_add_word(multiple, 1) || + !BN_div(totient, rem, totient, multiple, ctx)) { + OPENSSL_PUT_ERROR(RSA, ERR_R_BN_LIB); + goto err; + } + + if (!BN_is_zero(rem)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_RSA_PARAMETERS); + goto err; + } + + rsa->p = BN_new(); + rsa->q = BN_new(); + rsa->dmp1 = BN_new(); + rsa->dmq1 = BN_new(); + rsa->iqmp = BN_new(); + if (rsa->p == NULL || rsa->q == NULL || rsa->dmp1 == NULL || rsa->dmq1 == + NULL || rsa->iqmp == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* φ(n) = n - (p + q) + 1 => + * n - totient + 1 = p + q */ + if (!BN_sub(p_plus_q, rsa->n, totient) || + !BN_add_word(p_plus_q, 1) || + /* p - q = sqrt((p+q)^2 - 4n) */ + !BN_sqr(rem, p_plus_q, ctx) || + !BN_lshift(multiple, rsa->n, 2) || + !BN_sub(rem, rem, multiple) || + !BN_sqrt(p_minus_q, rem, ctx) || + /* q is 1/2 (p+q)-(p-q) */ + !BN_sub(rsa->q, p_plus_q, p_minus_q) || + !BN_rshift1(rsa->q, rsa->q) || + !BN_div(rsa->p, NULL, rsa->n, rsa->q, ctx) || + !BN_mul(multiple, rsa->p, rsa->q, ctx)) { + OPENSSL_PUT_ERROR(RSA, ERR_R_BN_LIB); + goto err; + } + + if (BN_cmp(multiple, rsa->n) != 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_INTERNAL_ERROR); + goto err; + } + + if (!BN_sub(rem, rsa->p, BN_value_one()) || + !BN_mod(rsa->dmp1, rsa->d, rem, ctx) || + !BN_sub(rem, rsa->q, BN_value_one()) || + !BN_mod(rsa->dmq1, rsa->d, rem, ctx) || + !BN_mod_inverse(rsa->iqmp, rsa->q, rsa->p, ctx)) { + OPENSSL_PUT_ERROR(RSA, ERR_R_BN_LIB); + goto err; + } + + ok = 1; + +err: + BN_CTX_end(ctx); + BN_CTX_free(ctx); + if (!ok) { + bn_free_and_null(&rsa->p); + bn_free_and_null(&rsa->q); + bn_free_and_null(&rsa->dmp1); + bn_free_and_null(&rsa->dmq1); + bn_free_and_null(&rsa->iqmp); + } + return ok; +} + +int RSA_private_transform(RSA *rsa, uint8_t *out, const uint8_t *in, + size_t len) { + if (rsa->meth->private_transform) { + return rsa->meth->private_transform(rsa, out, in, len); + } + + return RSA_default_method.private_transform(rsa, out, in, len); +} + +int RSA_blinding_on(RSA *rsa, BN_CTX *ctx) { + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/rsa/rsa_asn1.c b/TMessagesProj/jni/boringssl/crypto/rsa/rsa_asn1.c new file mode 100644 index 00000000..c62bcf08 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rsa/rsa_asn1.c @@ -0,0 +1,447 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2000. + */ +/* ==================================================================== + * Copyright (c) 2000-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "internal.h" + + +static int parse_integer(CBS *cbs, BIGNUM **out) { + assert(*out == NULL); + *out = BN_new(); + if (*out == NULL) { + return 0; + } + return BN_cbs2unsigned(cbs, *out); +} + +static int marshal_integer(CBB *cbb, BIGNUM *bn) { + if (bn == NULL) { + /* An RSA object may be missing some components. */ + OPENSSL_PUT_ERROR(RSA, RSA_R_VALUE_MISSING); + return 0; + } + return BN_bn2cbb(cbb, bn); +} + +RSA *RSA_parse_public_key(CBS *cbs) { + RSA *ret = RSA_new(); + if (ret == NULL) { + return NULL; + } + CBS child; + if (!CBS_get_asn1(cbs, &child, CBS_ASN1_SEQUENCE) || + !parse_integer(&child, &ret->n) || + !parse_integer(&child, &ret->e) || + CBS_len(&child) != 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_ENCODING); + RSA_free(ret); + return NULL; + } + return ret; +} + +RSA *RSA_public_key_from_bytes(const uint8_t *in, size_t in_len) { + CBS cbs; + CBS_init(&cbs, in, in_len); + RSA *ret = RSA_parse_public_key(&cbs); + if (ret == NULL || CBS_len(&cbs) != 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_ENCODING); + RSA_free(ret); + return NULL; + } + return ret; +} + +int RSA_marshal_public_key(CBB *cbb, const RSA *rsa) { + CBB child; + if (!CBB_add_asn1(cbb, &child, CBS_ASN1_SEQUENCE) || + !marshal_integer(&child, rsa->n) || + !marshal_integer(&child, rsa->e) || + !CBB_flush(cbb)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR); + return 0; + } + return 1; +} + +int RSA_public_key_to_bytes(uint8_t **out_bytes, size_t *out_len, + const RSA *rsa) { + CBB cbb; + CBB_zero(&cbb); + if (!CBB_init(&cbb, 0) || + !RSA_marshal_public_key(&cbb, rsa) || + !CBB_finish(&cbb, out_bytes, out_len)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR); + CBB_cleanup(&cbb); + return 0; + } + return 1; +} + +/* kVersionTwoPrime and kVersionMulti are the supported values of the version + * field of an RSAPrivateKey structure (RFC 3447). */ +static const uint64_t kVersionTwoPrime = 0; +static const uint64_t kVersionMulti = 1; + +/* rsa_parse_additional_prime parses a DER-encoded OtherPrimeInfo from |cbs| and + * advances |cbs|. It returns a newly-allocated |RSA_additional_prime| on + * success or NULL on error. The |r| and |method_mod| fields of the result are + * set to NULL. */ +static RSA_additional_prime *rsa_parse_additional_prime(CBS *cbs) { + RSA_additional_prime *ret = OPENSSL_malloc(sizeof(RSA_additional_prime)); + if (ret == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + return 0; + } + memset(ret, 0, sizeof(RSA_additional_prime)); + + CBS child; + if (!CBS_get_asn1(cbs, &child, CBS_ASN1_SEQUENCE) || + !parse_integer(&child, &ret->prime) || + !parse_integer(&child, &ret->exp) || + !parse_integer(&child, &ret->coeff) || + CBS_len(&child) != 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_ENCODING); + RSA_additional_prime_free(ret); + return NULL; + } + + return ret; +} + +RSA *RSA_parse_private_key(CBS *cbs) { + BN_CTX *ctx = NULL; + BIGNUM *product_of_primes_so_far = NULL; + RSA *ret = RSA_new(); + if (ret == NULL) { + return NULL; + } + + CBS child; + uint64_t version; + if (!CBS_get_asn1(cbs, &child, CBS_ASN1_SEQUENCE) || + !CBS_get_asn1_uint64(&child, &version) || + (version != kVersionTwoPrime && version != kVersionMulti) || + !parse_integer(&child, &ret->n) || + !parse_integer(&child, &ret->e) || + !parse_integer(&child, &ret->d) || + !parse_integer(&child, &ret->p) || + !parse_integer(&child, &ret->q) || + !parse_integer(&child, &ret->dmp1) || + !parse_integer(&child, &ret->dmq1) || + !parse_integer(&child, &ret->iqmp)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_VERSION); + goto err; + } + + /* Multi-prime RSA requires a newer version. */ + if (version == kVersionMulti && + CBS_peek_asn1_tag(&child, CBS_ASN1_SEQUENCE)) { + CBS other_prime_infos; + if (!CBS_get_asn1(&child, &other_prime_infos, CBS_ASN1_SEQUENCE) || + CBS_len(&other_prime_infos) == 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_ENCODING); + goto err; + } + ret->additional_primes = sk_RSA_additional_prime_new_null(); + if (ret->additional_primes == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + + ctx = BN_CTX_new(); + product_of_primes_so_far = BN_new(); + if (ctx == NULL || + product_of_primes_so_far == NULL || + !BN_mul(product_of_primes_so_far, ret->p, ret->q, ctx)) { + goto err; + } + + while (CBS_len(&other_prime_infos) > 0) { + RSA_additional_prime *ap = rsa_parse_additional_prime(&other_prime_infos); + if (ap == NULL) { + goto err; + } + if (!sk_RSA_additional_prime_push(ret->additional_primes, ap)) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + RSA_additional_prime_free(ap); + goto err; + } + ap->r = BN_dup(product_of_primes_so_far); + if (ap->r == NULL || + !BN_mul(product_of_primes_so_far, product_of_primes_so_far, + ap->prime, ctx)) { + goto err; + } + } + } + + if (CBS_len(&child) != 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_ENCODING); + goto err; + } + + BN_CTX_free(ctx); + BN_free(product_of_primes_so_far); + return ret; + +err: + BN_CTX_free(ctx); + BN_free(product_of_primes_so_far); + RSA_free(ret); + return NULL; +} + +RSA *RSA_private_key_from_bytes(const uint8_t *in, size_t in_len) { + CBS cbs; + CBS_init(&cbs, in, in_len); + RSA *ret = RSA_parse_private_key(&cbs); + if (ret == NULL || CBS_len(&cbs) != 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_ENCODING); + RSA_free(ret); + return NULL; + } + return ret; +} + +int RSA_marshal_private_key(CBB *cbb, const RSA *rsa) { + const int is_multiprime = + sk_RSA_additional_prime_num(rsa->additional_primes) > 0; + + CBB child; + if (!CBB_add_asn1(cbb, &child, CBS_ASN1_SEQUENCE) || + !CBB_add_asn1_uint64(&child, + is_multiprime ? kVersionMulti : kVersionTwoPrime) || + !marshal_integer(&child, rsa->n) || + !marshal_integer(&child, rsa->e) || + !marshal_integer(&child, rsa->d) || + !marshal_integer(&child, rsa->p) || + !marshal_integer(&child, rsa->q) || + !marshal_integer(&child, rsa->dmp1) || + !marshal_integer(&child, rsa->dmq1) || + !marshal_integer(&child, rsa->iqmp)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR); + return 0; + } + + if (is_multiprime) { + CBB other_prime_infos; + if (!CBB_add_asn1(&child, &other_prime_infos, CBS_ASN1_SEQUENCE)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR); + return 0; + } + size_t i; + for (i = 0; i < sk_RSA_additional_prime_num(rsa->additional_primes); i++) { + RSA_additional_prime *ap = + sk_RSA_additional_prime_value(rsa->additional_primes, i); + CBB other_prime_info; + if (!CBB_add_asn1(&other_prime_infos, &other_prime_info, + CBS_ASN1_SEQUENCE) || + !marshal_integer(&other_prime_info, ap->prime) || + !marshal_integer(&other_prime_info, ap->exp) || + !marshal_integer(&other_prime_info, ap->coeff)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR); + return 0; + } + } + } + + if (!CBB_flush(cbb)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR); + return 0; + } + return 1; +} + +int RSA_private_key_to_bytes(uint8_t **out_bytes, size_t *out_len, + const RSA *rsa) { + CBB cbb; + CBB_zero(&cbb); + if (!CBB_init(&cbb, 0) || + !RSA_marshal_private_key(&cbb, rsa) || + !CBB_finish(&cbb, out_bytes, out_len)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR); + CBB_cleanup(&cbb); + return 0; + } + return 1; +} + +RSA *d2i_RSAPublicKey(RSA **out, const uint8_t **inp, long len) { + if (len < 0) { + return NULL; + } + CBS cbs; + CBS_init(&cbs, *inp, (size_t)len); + RSA *ret = RSA_parse_public_key(&cbs); + if (ret == NULL) { + return NULL; + } + if (out != NULL) { + RSA_free(*out); + *out = ret; + } + *inp += (size_t)len - CBS_len(&cbs); + return ret; +} + +int i2d_RSAPublicKey(const RSA *in, uint8_t **outp) { + uint8_t *der; + size_t der_len; + if (!RSA_public_key_to_bytes(&der, &der_len, in)) { + return -1; + } + if (der_len > INT_MAX) { + OPENSSL_PUT_ERROR(RSA, ERR_R_OVERFLOW); + OPENSSL_free(der); + return -1; + } + if (outp != NULL) { + if (*outp == NULL) { + *outp = der; + der = NULL; + } else { + memcpy(*outp, der, der_len); + *outp += der_len; + } + } + OPENSSL_free(der); + return (int)der_len; +} + +RSA *d2i_RSAPrivateKey(RSA **out, const uint8_t **inp, long len) { + if (len < 0) { + return NULL; + } + CBS cbs; + CBS_init(&cbs, *inp, (size_t)len); + RSA *ret = RSA_parse_private_key(&cbs); + if (ret == NULL) { + return NULL; + } + if (out != NULL) { + RSA_free(*out); + *out = ret; + } + *inp += (size_t)len - CBS_len(&cbs); + return ret; +} + +int i2d_RSAPrivateKey(const RSA *in, uint8_t **outp) { + uint8_t *der; + size_t der_len; + if (!RSA_private_key_to_bytes(&der, &der_len, in)) { + return -1; + } + if (der_len > INT_MAX) { + OPENSSL_PUT_ERROR(RSA, ERR_R_OVERFLOW); + OPENSSL_free(der); + return -1; + } + if (outp != NULL) { + if (*outp == NULL) { + *outp = der; + der = NULL; + } else { + memcpy(*outp, der, der_len); + *outp += der_len; + } + } + OPENSSL_free(der); + return (int)der_len; +} + +ASN1_SEQUENCE(RSA_PSS_PARAMS) = { + ASN1_EXP_OPT(RSA_PSS_PARAMS, hashAlgorithm, X509_ALGOR,0), + ASN1_EXP_OPT(RSA_PSS_PARAMS, maskGenAlgorithm, X509_ALGOR,1), + ASN1_EXP_OPT(RSA_PSS_PARAMS, saltLength, ASN1_INTEGER,2), + ASN1_EXP_OPT(RSA_PSS_PARAMS, trailerField, ASN1_INTEGER,3), +} ASN1_SEQUENCE_END(RSA_PSS_PARAMS); + +IMPLEMENT_ASN1_FUNCTIONS(RSA_PSS_PARAMS); + +RSA *RSAPublicKey_dup(const RSA *rsa) { + uint8_t *der; + size_t der_len; + if (!RSA_public_key_to_bytes(&der, &der_len, rsa)) { + return NULL; + } + RSA *ret = RSA_public_key_from_bytes(der, der_len); + OPENSSL_free(der); + return ret; +} + +RSA *RSAPrivateKey_dup(const RSA *rsa) { + uint8_t *der; + size_t der_len; + if (!RSA_private_key_to_bytes(&der, &der_len, rsa)) { + return NULL; + } + RSA *ret = RSA_private_key_from_bytes(der, der_len); + OPENSSL_free(der); + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/rsa/rsa_impl.c b/TMessagesProj/jni/boringssl/crypto/rsa/rsa_impl.c new file mode 100644 index 00000000..aa1b70f0 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rsa/rsa_impl.c @@ -0,0 +1,1155 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include +#include + +#include "internal.h" +#include "../internal.h" + + +#define OPENSSL_RSA_MAX_MODULUS_BITS 16384 +#define OPENSSL_RSA_SMALL_MODULUS_BITS 3072 +#define OPENSSL_RSA_MAX_PUBEXP_BITS \ + 64 /* exponent limit enforced for "large" modulus only */ + + +static int finish(RSA *rsa) { + BN_MONT_CTX_free(rsa->_method_mod_n); + BN_MONT_CTX_free(rsa->_method_mod_p); + BN_MONT_CTX_free(rsa->_method_mod_q); + + if (rsa->additional_primes != NULL) { + size_t i; + for (i = 0; i < sk_RSA_additional_prime_num(rsa->additional_primes); i++) { + RSA_additional_prime *ap = + sk_RSA_additional_prime_value(rsa->additional_primes, i); + BN_MONT_CTX_free(ap->method_mod); + } + } + + return 1; +} + +static size_t size(const RSA *rsa) { + return BN_num_bytes(rsa->n); +} + +static int encrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, + const uint8_t *in, size_t in_len, int padding) { + const unsigned rsa_size = RSA_size(rsa); + BIGNUM *f, *result; + uint8_t *buf = NULL; + BN_CTX *ctx = NULL; + int i, ret = 0; + + if (rsa_size > OPENSSL_RSA_MAX_MODULUS_BITS) { + OPENSSL_PUT_ERROR(RSA, RSA_R_MODULUS_TOO_LARGE); + return 0; + } + + if (max_out < rsa_size) { + OPENSSL_PUT_ERROR(RSA, RSA_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + if (BN_ucmp(rsa->n, rsa->e) <= 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_E_VALUE); + return 0; + } + + /* for large moduli, enforce exponent limit */ + if (BN_num_bits(rsa->n) > OPENSSL_RSA_SMALL_MODULUS_BITS && + BN_num_bits(rsa->e) > OPENSSL_RSA_MAX_PUBEXP_BITS) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_E_VALUE); + return 0; + } + + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + + BN_CTX_start(ctx); + f = BN_CTX_get(ctx); + result = BN_CTX_get(ctx); + buf = OPENSSL_malloc(rsa_size); + if (!f || !result || !buf) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + + switch (padding) { + case RSA_PKCS1_PADDING: + i = RSA_padding_add_PKCS1_type_2(buf, rsa_size, in, in_len); + break; + case RSA_PKCS1_OAEP_PADDING: + /* Use the default parameters: SHA-1 for both hashes and no label. */ + i = RSA_padding_add_PKCS1_OAEP_mgf1(buf, rsa_size, in, in_len, + NULL, 0, NULL, NULL); + break; + case RSA_NO_PADDING: + i = RSA_padding_add_none(buf, rsa_size, in, in_len); + break; + default: + OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_PADDING_TYPE); + goto err; + } + + if (i <= 0) { + goto err; + } + + if (BN_bin2bn(buf, rsa_size, f) == NULL) { + goto err; + } + + if (BN_ucmp(f, rsa->n) >= 0) { + /* usually the padding functions would catch this */ + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_MODULUS); + goto err; + } + + if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) { + if (BN_MONT_CTX_set_locked(&rsa->_method_mod_n, &rsa->lock, rsa->n, ctx) == + NULL) { + goto err; + } + } + + if (!rsa->meth->bn_mod_exp(result, f, rsa->e, rsa->n, ctx, + rsa->_method_mod_n)) { + goto err; + } + + /* put in leading 0 bytes if the number is less than the length of the + * modulus */ + if (!BN_bn2bin_padded(out, rsa_size, result)) { + OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR); + goto err; + } + + *out_len = rsa_size; + ret = 1; + +err: + if (ctx != NULL) { + BN_CTX_end(ctx); + BN_CTX_free(ctx); + } + if (buf != NULL) { + OPENSSL_cleanse(buf, rsa_size); + OPENSSL_free(buf); + } + + return ret; +} + +/* MAX_BLINDINGS_PER_RSA defines the maximum number of cached BN_BLINDINGs per + * RSA*. Then this limit is exceeded, BN_BLINDING objects will be created and + * destroyed as needed. */ +#define MAX_BLINDINGS_PER_RSA 1024 + +/* rsa_blinding_get returns a BN_BLINDING to use with |rsa|. It does this by + * allocating one of the cached BN_BLINDING objects in |rsa->blindings|. If + * none are free, the cache will be extended by a extra element and the new + * BN_BLINDING is returned. + * + * On success, the index of the assigned BN_BLINDING is written to + * |*index_used| and must be passed to |rsa_blinding_release| when finished. */ +static BN_BLINDING *rsa_blinding_get(RSA *rsa, unsigned *index_used, + BN_CTX *ctx) { + BN_BLINDING *ret = NULL; + BN_BLINDING **new_blindings; + uint8_t *new_blindings_inuse; + char overflow = 0; + + CRYPTO_MUTEX_lock_write(&rsa->lock); + + unsigned i; + for (i = 0; i < rsa->num_blindings; i++) { + if (rsa->blindings_inuse[i] == 0) { + rsa->blindings_inuse[i] = 1; + ret = rsa->blindings[i]; + *index_used = i; + break; + } + } + + if (ret != NULL) { + CRYPTO_MUTEX_unlock(&rsa->lock); + return ret; + } + + overflow = rsa->num_blindings >= MAX_BLINDINGS_PER_RSA; + + /* We didn't find a free BN_BLINDING to use so increase the length of + * the arrays by one and use the newly created element. */ + + CRYPTO_MUTEX_unlock(&rsa->lock); + ret = rsa_setup_blinding(rsa, ctx); + if (ret == NULL) { + return NULL; + } + + if (overflow) { + /* We cannot add any more cached BN_BLINDINGs so we use |ret| + * and mark it for destruction in |rsa_blinding_release|. */ + *index_used = MAX_BLINDINGS_PER_RSA; + return ret; + } + + CRYPTO_MUTEX_lock_write(&rsa->lock); + + new_blindings = + OPENSSL_malloc(sizeof(BN_BLINDING *) * (rsa->num_blindings + 1)); + if (new_blindings == NULL) { + goto err1; + } + memcpy(new_blindings, rsa->blindings, + sizeof(BN_BLINDING *) * rsa->num_blindings); + new_blindings[rsa->num_blindings] = ret; + + new_blindings_inuse = OPENSSL_malloc(rsa->num_blindings + 1); + if (new_blindings_inuse == NULL) { + goto err2; + } + memcpy(new_blindings_inuse, rsa->blindings_inuse, rsa->num_blindings); + new_blindings_inuse[rsa->num_blindings] = 1; + *index_used = rsa->num_blindings; + + OPENSSL_free(rsa->blindings); + rsa->blindings = new_blindings; + OPENSSL_free(rsa->blindings_inuse); + rsa->blindings_inuse = new_blindings_inuse; + rsa->num_blindings++; + + CRYPTO_MUTEX_unlock(&rsa->lock); + return ret; + +err2: + OPENSSL_free(new_blindings); + +err1: + CRYPTO_MUTEX_unlock(&rsa->lock); + BN_BLINDING_free(ret); + return NULL; +} + +/* rsa_blinding_release marks the cached BN_BLINDING at the given index as free + * for other threads to use. */ +static void rsa_blinding_release(RSA *rsa, BN_BLINDING *blinding, + unsigned blinding_index) { + if (blinding_index == MAX_BLINDINGS_PER_RSA) { + /* This blinding wasn't cached. */ + BN_BLINDING_free(blinding); + return; + } + + CRYPTO_MUTEX_lock_write(&rsa->lock); + rsa->blindings_inuse[blinding_index] = 0; + CRYPTO_MUTEX_unlock(&rsa->lock); +} + +/* signing */ +static int sign_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, + const uint8_t *in, size_t in_len, int padding) { + const unsigned rsa_size = RSA_size(rsa); + uint8_t *buf = NULL; + int i, ret = 0; + + if (max_out < rsa_size) { + OPENSSL_PUT_ERROR(RSA, RSA_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + buf = OPENSSL_malloc(rsa_size); + if (buf == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + + switch (padding) { + case RSA_PKCS1_PADDING: + i = RSA_padding_add_PKCS1_type_1(buf, rsa_size, in, in_len); + break; + case RSA_NO_PADDING: + i = RSA_padding_add_none(buf, rsa_size, in, in_len); + break; + default: + OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_PADDING_TYPE); + goto err; + } + + if (i <= 0) { + goto err; + } + + if (!RSA_private_transform(rsa, out, buf, rsa_size)) { + goto err; + } + + *out_len = rsa_size; + ret = 1; + +err: + if (buf != NULL) { + OPENSSL_cleanse(buf, rsa_size); + OPENSSL_free(buf); + } + + return ret; +} + +static int decrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, + const uint8_t *in, size_t in_len, int padding) { + const unsigned rsa_size = RSA_size(rsa); + int r = -1; + uint8_t *buf = NULL; + int ret = 0; + + if (max_out < rsa_size) { + OPENSSL_PUT_ERROR(RSA, RSA_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + if (padding == RSA_NO_PADDING) { + buf = out; + } else { + /* Allocate a temporary buffer to hold the padded plaintext. */ + buf = OPENSSL_malloc(rsa_size); + if (buf == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + } + + if (in_len != rsa_size) { + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_LEN_NOT_EQUAL_TO_MOD_LEN); + goto err; + } + + if (!RSA_private_transform(rsa, buf, in, rsa_size)) { + goto err; + } + + switch (padding) { + case RSA_PKCS1_PADDING: + r = RSA_padding_check_PKCS1_type_2(out, rsa_size, buf, rsa_size); + break; + case RSA_PKCS1_OAEP_PADDING: + /* Use the default parameters: SHA-1 for both hashes and no label. */ + r = RSA_padding_check_PKCS1_OAEP_mgf1(out, rsa_size, buf, rsa_size, + NULL, 0, NULL, NULL); + break; + case RSA_NO_PADDING: + r = rsa_size; + break; + default: + OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_PADDING_TYPE); + goto err; + } + + if (r < 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_PADDING_CHECK_FAILED); + } else { + *out_len = r; + ret = 1; + } + +err: + if (padding != RSA_NO_PADDING && buf != NULL) { + OPENSSL_cleanse(buf, rsa_size); + OPENSSL_free(buf); + } + + return ret; +} + +static int verify_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, + const uint8_t *in, size_t in_len, int padding) { + const unsigned rsa_size = RSA_size(rsa); + BIGNUM *f, *result; + int ret = 0; + int r = -1; + uint8_t *buf = NULL; + BN_CTX *ctx = NULL; + + if (BN_num_bits(rsa->n) > OPENSSL_RSA_MAX_MODULUS_BITS) { + OPENSSL_PUT_ERROR(RSA, RSA_R_MODULUS_TOO_LARGE); + return 0; + } + + if (BN_ucmp(rsa->n, rsa->e) <= 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_E_VALUE); + return 0; + } + + if (max_out < rsa_size) { + OPENSSL_PUT_ERROR(RSA, RSA_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + /* for large moduli, enforce exponent limit */ + if (BN_num_bits(rsa->n) > OPENSSL_RSA_SMALL_MODULUS_BITS && + BN_num_bits(rsa->e) > OPENSSL_RSA_MAX_PUBEXP_BITS) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_E_VALUE); + return 0; + } + + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + + BN_CTX_start(ctx); + f = BN_CTX_get(ctx); + result = BN_CTX_get(ctx); + if (padding == RSA_NO_PADDING) { + buf = out; + } else { + /* Allocate a temporary buffer to hold the padded plaintext. */ + buf = OPENSSL_malloc(rsa_size); + if (buf == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + } + if (!f || !result) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (in_len != rsa_size) { + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_LEN_NOT_EQUAL_TO_MOD_LEN); + goto err; + } + + if (BN_bin2bn(in, in_len, f) == NULL) { + goto err; + } + + if (BN_ucmp(f, rsa->n) >= 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_MODULUS); + goto err; + } + + if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) { + if (BN_MONT_CTX_set_locked(&rsa->_method_mod_n, &rsa->lock, rsa->n, ctx) == + NULL) { + goto err; + } + } + + if (!rsa->meth->bn_mod_exp(result, f, rsa->e, rsa->n, ctx, + rsa->_method_mod_n)) { + goto err; + } + + if (!BN_bn2bin_padded(buf, rsa_size, result)) { + OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR); + goto err; + } + + switch (padding) { + case RSA_PKCS1_PADDING: + r = RSA_padding_check_PKCS1_type_1(out, rsa_size, buf, rsa_size); + break; + case RSA_NO_PADDING: + r = rsa_size; + break; + default: + OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_PADDING_TYPE); + goto err; + } + + if (r < 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_PADDING_CHECK_FAILED); + } else { + *out_len = r; + ret = 1; + } + +err: + if (ctx != NULL) { + BN_CTX_end(ctx); + BN_CTX_free(ctx); + } + if (padding != RSA_NO_PADDING && buf != NULL) { + OPENSSL_cleanse(buf, rsa_size); + OPENSSL_free(buf); + } + return ret; +} + +static int private_transform(RSA *rsa, uint8_t *out, const uint8_t *in, + size_t len) { + BIGNUM *f, *result; + BN_CTX *ctx = NULL; + unsigned blinding_index = 0; + BN_BLINDING *blinding = NULL; + int ret = 0; + + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + BN_CTX_start(ctx); + f = BN_CTX_get(ctx); + result = BN_CTX_get(ctx); + + if (f == NULL || result == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (BN_bin2bn(in, len, f) == NULL) { + goto err; + } + + if (BN_ucmp(f, rsa->n) >= 0) { + /* Usually the padding functions would catch this. */ + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_MODULUS); + goto err; + } + + if (!(rsa->flags & RSA_FLAG_NO_BLINDING)) { + blinding = rsa_blinding_get(rsa, &blinding_index, ctx); + if (blinding == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR); + goto err; + } + if (!BN_BLINDING_convert_ex(f, NULL, blinding, ctx)) { + goto err; + } + } + + if ((rsa->flags & RSA_FLAG_EXT_PKEY) || + ((rsa->p != NULL) && (rsa->q != NULL) && (rsa->dmp1 != NULL) && + (rsa->dmq1 != NULL) && (rsa->iqmp != NULL))) { + if (!rsa->meth->mod_exp(result, f, rsa, ctx)) { + goto err; + } + } else { + BIGNUM local_d; + BIGNUM *d = NULL; + + BN_init(&local_d); + d = &local_d; + BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME); + + if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) { + if (BN_MONT_CTX_set_locked(&rsa->_method_mod_n, &rsa->lock, rsa->n, + ctx) == NULL) { + goto err; + } + } + + if (!rsa->meth->bn_mod_exp(result, f, d, rsa->n, ctx, rsa->_method_mod_n)) { + goto err; + } + } + + if (blinding) { + if (!BN_BLINDING_invert_ex(result, NULL, blinding, ctx)) { + goto err; + } + } + + if (!BN_bn2bin_padded(out, len, result)) { + OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR); + goto err; + } + + ret = 1; + +err: + if (ctx != NULL) { + BN_CTX_end(ctx); + BN_CTX_free(ctx); + } + if (blinding != NULL) { + rsa_blinding_release(rsa, blinding, blinding_index); + } + + return ret; +} + +static int mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx) { + BIGNUM *r1, *m1, *vrfy; + BIGNUM local_dmp1, local_dmq1, local_c, local_r1; + BIGNUM *dmp1, *dmq1, *c, *pr1; + int ret = 0; + size_t i, num_additional_primes = 0; + + if (rsa->additional_primes != NULL) { + num_additional_primes = sk_RSA_additional_prime_num(rsa->additional_primes); + } + + BN_CTX_start(ctx); + r1 = BN_CTX_get(ctx); + m1 = BN_CTX_get(ctx); + vrfy = BN_CTX_get(ctx); + + { + BIGNUM local_p, local_q; + BIGNUM *p = NULL, *q = NULL; + + /* Make sure BN_mod_inverse in Montgomery intialization uses the + * BN_FLG_CONSTTIME flag (unless RSA_FLAG_NO_CONSTTIME is set) */ + BN_init(&local_p); + p = &local_p; + BN_with_flags(p, rsa->p, BN_FLG_CONSTTIME); + + BN_init(&local_q); + q = &local_q; + BN_with_flags(q, rsa->q, BN_FLG_CONSTTIME); + + if (rsa->flags & RSA_FLAG_CACHE_PRIVATE) { + if (BN_MONT_CTX_set_locked(&rsa->_method_mod_p, &rsa->lock, p, ctx) == + NULL) { + goto err; + } + if (BN_MONT_CTX_set_locked(&rsa->_method_mod_q, &rsa->lock, q, ctx) == + NULL) { + goto err; + } + } + } + + if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) { + if (BN_MONT_CTX_set_locked(&rsa->_method_mod_n, &rsa->lock, rsa->n, ctx) == + NULL) { + goto err; + } + } + + /* compute I mod q */ + c = &local_c; + BN_with_flags(c, I, BN_FLG_CONSTTIME); + if (!BN_mod(r1, c, rsa->q, ctx)) { + goto err; + } + + /* compute r1^dmq1 mod q */ + dmq1 = &local_dmq1; + BN_with_flags(dmq1, rsa->dmq1, BN_FLG_CONSTTIME); + if (!rsa->meth->bn_mod_exp(m1, r1, dmq1, rsa->q, ctx, rsa->_method_mod_q)) { + goto err; + } + + /* compute I mod p */ + c = &local_c; + BN_with_flags(c, I, BN_FLG_CONSTTIME); + if (!BN_mod(r1, c, rsa->p, ctx)) { + goto err; + } + + /* compute r1^dmp1 mod p */ + dmp1 = &local_dmp1; + BN_with_flags(dmp1, rsa->dmp1, BN_FLG_CONSTTIME); + if (!rsa->meth->bn_mod_exp(r0, r1, dmp1, rsa->p, ctx, rsa->_method_mod_p)) { + goto err; + } + + if (!BN_sub(r0, r0, m1)) { + goto err; + } + /* This will help stop the size of r0 increasing, which does + * affect the multiply if it optimised for a power of 2 size */ + if (BN_is_negative(r0)) { + if (!BN_add(r0, r0, rsa->p)) { + goto err; + } + } + + if (!BN_mul(r1, r0, rsa->iqmp, ctx)) { + goto err; + } + + /* Turn BN_FLG_CONSTTIME flag on before division operation */ + pr1 = &local_r1; + BN_with_flags(pr1, r1, BN_FLG_CONSTTIME); + + if (!BN_mod(r0, pr1, rsa->p, ctx)) { + goto err; + } + + /* If p < q it is occasionally possible for the correction of + * adding 'p' if r0 is negative above to leave the result still + * negative. This can break the private key operations: the following + * second correction should *always* correct this rare occurrence. + * This will *never* happen with OpenSSL generated keys because + * they ensure p > q [steve] */ + if (BN_is_negative(r0)) { + if (!BN_add(r0, r0, rsa->p)) { + goto err; + } + } + if (!BN_mul(r1, r0, rsa->q, ctx)) { + goto err; + } + if (!BN_add(r0, r1, m1)) { + goto err; + } + + for (i = 0; i < num_additional_primes; i++) { + /* multi-prime RSA. */ + BIGNUM local_exp, local_prime; + BIGNUM *exp = &local_exp, *prime = &local_prime; + RSA_additional_prime *ap = + sk_RSA_additional_prime_value(rsa->additional_primes, i); + + BN_with_flags(exp, ap->exp, BN_FLG_CONSTTIME); + BN_with_flags(prime, ap->prime, BN_FLG_CONSTTIME); + + /* c will already point to a BIGNUM with the correct flags. */ + if (!BN_mod(r1, c, prime, ctx)) { + goto err; + } + + if ((rsa->flags & RSA_FLAG_CACHE_PRIVATE) && + !BN_MONT_CTX_set_locked(&ap->method_mod, &rsa->lock, prime, ctx)) { + goto err; + } + + if (!rsa->meth->bn_mod_exp(m1, r1, exp, prime, ctx, ap->method_mod)) { + goto err; + } + + BN_set_flags(m1, BN_FLG_CONSTTIME); + + if (!BN_sub(m1, m1, r0) || + !BN_mul(m1, m1, ap->coeff, ctx) || + !BN_mod(m1, m1, prime, ctx) || + (BN_is_negative(m1) && !BN_add(m1, m1, prime)) || + !BN_mul(m1, m1, ap->r, ctx) || + !BN_add(r0, r0, m1)) { + goto err; + } + } + + if (rsa->e && rsa->n) { + if (!rsa->meth->bn_mod_exp(vrfy, r0, rsa->e, rsa->n, ctx, + rsa->_method_mod_n)) { + goto err; + } + /* If 'I' was greater than (or equal to) rsa->n, the operation + * will be equivalent to using 'I mod n'. However, the result of + * the verify will *always* be less than 'n' so we don't check + * for absolute equality, just congruency. */ + if (!BN_sub(vrfy, vrfy, I)) { + goto err; + } + if (!BN_mod(vrfy, vrfy, rsa->n, ctx)) { + goto err; + } + if (BN_is_negative(vrfy)) { + if (!BN_add(vrfy, vrfy, rsa->n)) { + goto err; + } + } + if (!BN_is_zero(vrfy)) { + /* 'I' and 'vrfy' aren't congruent mod n. Don't leak + * miscalculated CRT output, just do a raw (slower) + * mod_exp and return that instead. */ + + BIGNUM local_d; + BIGNUM *d = NULL; + + d = &local_d; + BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME); + if (!rsa->meth->bn_mod_exp(r0, I, d, rsa->n, ctx, rsa->_method_mod_n)) { + goto err; + } + } + } + ret = 1; + +err: + BN_CTX_end(ctx); + return ret; +} + +static int keygen_multiprime(RSA *rsa, int bits, int num_primes, + BIGNUM *e_value, BN_GENCB *cb) { + BIGNUM *r0 = NULL, *r1 = NULL, *r2 = NULL, *r3 = NULL, *tmp; + BIGNUM local_r0, local_d, local_p; + BIGNUM *pr0, *d, *p; + int prime_bits, ok = -1, n = 0, i, j; + BN_CTX *ctx = NULL; + STACK_OF(RSA_additional_prime) *additional_primes = NULL; + + if (num_primes < 2) { + ok = 0; /* we set our own err */ + OPENSSL_PUT_ERROR(RSA, RSA_R_MUST_HAVE_AT_LEAST_TWO_PRIMES); + goto err; + } + + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + BN_CTX_start(ctx); + r0 = BN_CTX_get(ctx); + r1 = BN_CTX_get(ctx); + r2 = BN_CTX_get(ctx); + r3 = BN_CTX_get(ctx); + if (r0 == NULL || r1 == NULL || r2 == NULL || r3 == NULL) { + goto err; + } + + if (num_primes > 2) { + additional_primes = sk_RSA_additional_prime_new_null(); + if (additional_primes == NULL) { + goto err; + } + } + + for (i = 2; i < num_primes; i++) { + RSA_additional_prime *ap = OPENSSL_malloc(sizeof(RSA_additional_prime)); + if (ap == NULL) { + goto err; + } + memset(ap, 0, sizeof(RSA_additional_prime)); + ap->prime = BN_new(); + ap->exp = BN_new(); + ap->coeff = BN_new(); + ap->r = BN_new(); + if (ap->prime == NULL || + ap->exp == NULL || + ap->coeff == NULL || + ap->r == NULL || + !sk_RSA_additional_prime_push(additional_primes, ap)) { + RSA_additional_prime_free(ap); + goto err; + } + } + + /* We need the RSA components non-NULL */ + if (!rsa->n && ((rsa->n = BN_new()) == NULL)) { + goto err; + } + if (!rsa->d && ((rsa->d = BN_new()) == NULL)) { + goto err; + } + if (!rsa->e && ((rsa->e = BN_new()) == NULL)) { + goto err; + } + if (!rsa->p && ((rsa->p = BN_new()) == NULL)) { + goto err; + } + if (!rsa->q && ((rsa->q = BN_new()) == NULL)) { + goto err; + } + if (!rsa->dmp1 && ((rsa->dmp1 = BN_new()) == NULL)) { + goto err; + } + if (!rsa->dmq1 && ((rsa->dmq1 = BN_new()) == NULL)) { + goto err; + } + if (!rsa->iqmp && ((rsa->iqmp = BN_new()) == NULL)) { + goto err; + } + + if (!BN_copy(rsa->e, e_value)) { + goto err; + } + + /* generate p and q */ + prime_bits = (bits + (num_primes - 1)) / num_primes; + for (;;) { + if (!BN_generate_prime_ex(rsa->p, prime_bits, 0, NULL, NULL, cb) || + !BN_sub(r2, rsa->p, BN_value_one()) || + !BN_gcd(r1, r2, rsa->e, ctx)) { + goto err; + } + if (BN_is_one(r1)) { + break; + } + if (!BN_GENCB_call(cb, 2, n++)) { + goto err; + } + } + if (!BN_GENCB_call(cb, 3, 0)) { + goto err; + } + prime_bits = ((bits - prime_bits) + (num_primes - 2)) / (num_primes - 1); + for (;;) { + /* When generating ridiculously small keys, we can get stuck + * continually regenerating the same prime values. Check for + * this and bail if it happens 3 times. */ + unsigned int degenerate = 0; + do { + if (!BN_generate_prime_ex(rsa->q, prime_bits, 0, NULL, NULL, cb)) { + goto err; + } + } while ((BN_cmp(rsa->p, rsa->q) == 0) && (++degenerate < 3)); + if (degenerate == 3) { + ok = 0; /* we set our own err */ + OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL); + goto err; + } + if (!BN_sub(r2, rsa->q, BN_value_one()) || + !BN_gcd(r1, r2, rsa->e, ctx)) { + goto err; + } + if (BN_is_one(r1)) { + break; + } + if (!BN_GENCB_call(cb, 2, n++)) { + goto err; + } + } + + if (!BN_GENCB_call(cb, 3, 1) || + !BN_mul(rsa->n, rsa->p, rsa->q, ctx)) { + goto err; + } + + for (i = 2; i < num_primes; i++) { + RSA_additional_prime *ap = + sk_RSA_additional_prime_value(additional_primes, i - 2); + prime_bits = ((bits - BN_num_bits(rsa->n)) + (num_primes - (i + 1))) / + (num_primes - i); + + for (;;) { + if (!BN_generate_prime_ex(ap->prime, prime_bits, 0, NULL, NULL, cb)) { + goto err; + } + if (BN_cmp(rsa->p, ap->prime) == 0 || + BN_cmp(rsa->q, ap->prime) == 0) { + continue; + } + + for (j = 0; j < i - 2; j++) { + if (BN_cmp(sk_RSA_additional_prime_value(additional_primes, j)->prime, + ap->prime) == 0) { + break; + } + } + if (j != i - 2) { + continue; + } + + if (!BN_sub(r2, ap->prime, BN_value_one()) || + !BN_gcd(r1, r2, rsa->e, ctx)) { + goto err; + } + + if (!BN_is_one(r1)) { + continue; + } + if (i != num_primes - 1) { + break; + } + + /* For the last prime we'll check that it makes n large enough. In the + * two prime case this isn't a problem because we generate primes with + * the top two bits set and so the product is always of the expected + * size. In the multi prime case, this doesn't follow. */ + if (!BN_mul(r1, rsa->n, ap->prime, ctx)) { + goto err; + } + if (BN_num_bits(r1) == bits) { + break; + } + + if (!BN_GENCB_call(cb, 2, n++)) { + goto err; + } + } + + /* ap->r is is the product of all the primes prior to the current one + * (including p and q). */ + if (!BN_copy(ap->r, rsa->n)) { + goto err; + } + if (i == num_primes - 1) { + /* In the case of the last prime, we calculated n as |r1| in the loop + * above. */ + if (!BN_copy(rsa->n, r1)) { + goto err; + } + } else if (!BN_mul(rsa->n, rsa->n, ap->prime, ctx)) { + goto err; + } + + if (!BN_GENCB_call(cb, 3, 1)) { + goto err; + } + } + + if (BN_cmp(rsa->p, rsa->q) < 0) { + tmp = rsa->p; + rsa->p = rsa->q; + rsa->q = tmp; + } + + /* calculate d */ + if (!BN_sub(r1, rsa->p, BN_value_one())) { + goto err; /* p-1 */ + } + if (!BN_sub(r2, rsa->q, BN_value_one())) { + goto err; /* q-1 */ + } + if (!BN_mul(r0, r1, r2, ctx)) { + goto err; /* (p-1)(q-1) */ + } + for (i = 2; i < num_primes; i++) { + RSA_additional_prime *ap = + sk_RSA_additional_prime_value(additional_primes, i - 2); + if (!BN_sub(r3, ap->prime, BN_value_one()) || + !BN_mul(r0, r0, r3, ctx)) { + goto err; + } + } + pr0 = &local_r0; + BN_with_flags(pr0, r0, BN_FLG_CONSTTIME); + if (!BN_mod_inverse(rsa->d, rsa->e, pr0, ctx)) { + goto err; /* d */ + } + + /* set up d for correct BN_FLG_CONSTTIME flag */ + d = &local_d; + BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME); + + /* calculate d mod (p-1) */ + if (!BN_mod(rsa->dmp1, d, r1, ctx)) { + goto err; + } + + /* calculate d mod (q-1) */ + if (!BN_mod(rsa->dmq1, d, r2, ctx)) { + goto err; + } + + /* calculate inverse of q mod p */ + p = &local_p; + BN_with_flags(p, rsa->p, BN_FLG_CONSTTIME); + + if (!BN_mod_inverse(rsa->iqmp, rsa->q, p, ctx)) { + goto err; + } + + for (i = 2; i < num_primes; i++) { + RSA_additional_prime *ap = + sk_RSA_additional_prime_value(additional_primes, i - 2); + if (!BN_sub(ap->exp, ap->prime, BN_value_one()) || + !BN_mod(ap->exp, rsa->d, ap->exp, ctx) || + !BN_mod_inverse(ap->coeff, ap->r, ap->prime, ctx)) { + goto err; + } + } + + ok = 1; + rsa->additional_primes = additional_primes; + additional_primes = NULL; + +err: + if (ok == -1) { + OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN); + ok = 0; + } + if (ctx != NULL) { + BN_CTX_end(ctx); + BN_CTX_free(ctx); + } + sk_RSA_additional_prime_pop_free(additional_primes, + RSA_additional_prime_free); + return ok; +} + +static int keygen(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb) { + return keygen_multiprime(rsa, bits, 2 /* num primes */, e_value, cb); +} + +const struct rsa_meth_st RSA_default_method = { + { + 0 /* references */, + 1 /* is_static */, + }, + NULL /* app_data */, + + NULL /* init */, + finish, + + size, + + NULL /* sign */, + NULL /* verify */, + + encrypt, + sign_raw, + decrypt, + verify_raw, + + private_transform, + + mod_exp /* mod_exp */, + BN_mod_exp_mont /* bn_mod_exp */, + + RSA_FLAG_CACHE_PUBLIC | RSA_FLAG_CACHE_PRIVATE, + + keygen, + keygen_multiprime, +}; diff --git a/TMessagesProj/jni/boringssl/crypto/sha/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/sha/CMakeLists.txt new file mode 100644 index 00000000..5a10c851 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/sha/CMakeLists.txt @@ -0,0 +1,66 @@ +include_directories(. .. ../../include) + +if (${ARCH} STREQUAL "x86_64") + set( + SHA_ARCH_SOURCES + + sha1-x86_64.${ASM_EXT} + sha256-x86_64.${ASM_EXT} + sha512-x86_64.${ASM_EXT} + ) +endif() + +if (${ARCH} STREQUAL "x86") + set( + SHA_ARCH_SOURCES + + sha1-586.${ASM_EXT} + sha256-586.${ASM_EXT} + sha512-586.${ASM_EXT} + ) +endif() + +if (${ARCH} STREQUAL "arm") + set( + SHA_ARCH_SOURCES + + sha1-armv4-large.${ASM_EXT} + sha256-armv4.${ASM_EXT} + sha512-armv4.${ASM_EXT} + ) +endif() + +if (${ARCH} STREQUAL "aarch64") + set( + SHA_ARCH_SOURCES + + sha1-armv8.${ASM_EXT} + sha256-armv8.${ASM_EXT} + sha512-armv8.${ASM_EXT} + ) +endif() + +add_library( + sha + + OBJECT + + sha1.c + sha256.c + sha512.c + + ${SHA_ARCH_SOURCES} +) + +perlasm(sha1-x86_64.${ASM_EXT} asm/sha1-x86_64.pl) +perlasm(sha256-x86_64.${ASM_EXT} asm/sha512-x86_64.pl sha256) +perlasm(sha512-x86_64.${ASM_EXT} asm/sha512-x86_64.pl sha512) +perlasm(sha1-586.${ASM_EXT} asm/sha1-586.pl) +perlasm(sha256-586.${ASM_EXT} asm/sha256-586.pl) +perlasm(sha512-586.${ASM_EXT} asm/sha512-586.pl) +perlasm(sha1-armv4-large.${ASM_EXT} asm/sha1-armv4-large.pl) +perlasm(sha256-armv4.${ASM_EXT} asm/sha256-armv4.pl) +perlasm(sha512-armv4.${ASM_EXT} asm/sha512-armv4.pl) +perlasm(sha1-armv8.${ASM_EXT} asm/sha1-armv8.pl) +perlasm(sha256-armv8.${ASM_EXT} asm/sha512-armv8.pl sha256) +perlasm(sha512-armv8.${ASM_EXT} asm/sha512-armv8.pl sha512) diff --git a/TMessagesProj/jni/boringssl/crypto/sha/asm/sha1-586.pl b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha1-586.pl new file mode 100644 index 00000000..e0b5d83b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha1-586.pl @@ -0,0 +1,1476 @@ +#!/usr/bin/env perl + +# ==================================================================== +# [Re]written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== + +# "[Re]written" was achieved in two major overhauls. In 2004 BODY_* +# functions were re-implemented to address P4 performance issue [see +# commentary below], and in 2006 the rest was rewritten in order to +# gain freedom to liberate licensing terms. + +# January, September 2004. +# +# It was noted that Intel IA-32 C compiler generates code which +# performs ~30% *faster* on P4 CPU than original *hand-coded* +# SHA1 assembler implementation. To address this problem (and +# prove that humans are still better than machines:-), the +# original code was overhauled, which resulted in following +# performance changes: +# +# compared with original compared with Intel cc +# assembler impl. generated code +# Pentium -16% +48% +# PIII/AMD +8% +16% +# P4 +85%(!) +45% +# +# As you can see Pentium came out as looser:-( Yet I reckoned that +# improvement on P4 outweights the loss and incorporate this +# re-tuned code to 0.9.7 and later. +# ---------------------------------------------------------------- +# + +# August 2009. +# +# George Spelvin has tipped that F_40_59(b,c,d) can be rewritten as +# '(c&d) + (b&(c^d))', which allows to accumulate partial results +# and lighten "pressure" on scratch registers. This resulted in +# >12% performance improvement on contemporary AMD cores (with no +# degradation on other CPUs:-). Also, the code was revised to maximize +# "distance" between instructions producing input to 'lea' instruction +# and the 'lea' instruction itself, which is essential for Intel Atom +# core and resulted in ~15% improvement. + +# October 2010. +# +# Add SSSE3, Supplemental[!] SSE3, implementation. The idea behind it +# is to offload message schedule denoted by Wt in NIST specification, +# or Xupdate in OpenSSL source, to SIMD unit. The idea is not novel, +# and in SSE2 context was first explored by Dean Gaudet in 2004, see +# http://arctic.org/~dean/crypto/sha1.html. Since then several things +# have changed that made it interesting again: +# +# a) XMM units became faster and wider; +# b) instruction set became more versatile; +# c) an important observation was made by Max Locktykhin, which made +# it possible to reduce amount of instructions required to perform +# the operation in question, for further details see +# http://software.intel.com/en-us/articles/improving-the-performance-of-the-secure-hash-algorithm-1/. + +# April 2011. +# +# Add AVX code path, probably most controversial... The thing is that +# switch to AVX alone improves performance by as little as 4% in +# comparison to SSSE3 code path. But below result doesn't look like +# 4% improvement... Trouble is that Sandy Bridge decodes 'ro[rl]' as +# pair of µ-ops, and it's the additional µ-ops, two per round, that +# make it run slower than Core2 and Westmere. But 'sh[rl]d' is decoded +# as single µ-op by Sandy Bridge and it's replacing 'ro[rl]' with +# equivalent 'sh[rl]d' that is responsible for the impressive 5.1 +# cycles per processed byte. But 'sh[rl]d' is not something that used +# to be fast, nor does it appear to be fast in upcoming Bulldozer +# [according to its optimization manual]. Which is why AVX code path +# is guarded by *both* AVX and synthetic bit denoting Intel CPUs. +# One can argue that it's unfair to AMD, but without 'sh[rl]d' it +# makes no sense to keep the AVX code path. If somebody feels that +# strongly, it's probably more appropriate to discuss possibility of +# using vector rotate XOP on AMD... + +# March 2014. +# +# Add support for Intel SHA Extensions. + +###################################################################### +# Current performance is summarized in following table. Numbers are +# CPU clock cycles spent to process single byte (less is better). +# +# x86 SSSE3 AVX +# Pentium 15.7 - +# PIII 11.5 - +# P4 10.6 - +# AMD K8 7.1 - +# Core2 7.3 6.0/+22% - +# Westmere 7.3 5.5/+33% - +# Sandy Bridge 8.8 6.2/+40% 5.1(**)/+73% +# Ivy Bridge 7.2 4.8/+51% 4.7(**)/+53% +# Haswell 6.5 4.3/+51% 4.1(**)/+58% +# Bulldozer 11.6 6.0/+92% +# VIA Nano 10.6 7.5/+41% +# Atom 12.5 9.3(*)/+35% +# Silvermont 14.5 9.9(*)/+46% +# +# (*) Loop is 1056 instructions long and expected result is ~8.25. +# The discrepancy is because of front-end limitations, so +# called MS-ROM penalties, and on Silvermont even rotate's +# limited parallelism. +# +# (**) As per above comment, the result is for AVX *plus* sh[rl]d. + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +push(@INC,"${dir}","${dir}../../perlasm"); +require "x86asm.pl"; + +&asm_init($ARGV[0],"sha1-586.pl",$ARGV[$#ARGV] eq "386"); + +$xmm=$ymm=0; +for (@ARGV) { $xmm=1 if (/-DOPENSSL_IA32_SSE2/); } + +$ymm=1 if ($xmm && + `$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1` + =~ /GNU assembler version ([2-9]\.[0-9]+)/ && + $1>=2.19); # first version supporting AVX + +$ymm=1 if ($xmm && !$ymm && $ARGV[0] eq "win32n" && + `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/ && + $1>=2.03); # first version supporting AVX + +$ymm=1 if ($xmm && !$ymm && $ARGV[0] eq "win32" && + `ml 2>&1` =~ /Version ([0-9]+)\./ && + $1>=10); # first version supporting AVX + +$ymm=1 if ($xmm && !$ymm && `$ENV{CC} -v 2>&1` =~ /(^clang version|based on LLVM) ([3-9]\.[0-9]+)/ && + $2>=3.0); # first version supporting AVX + +$shaext=$xmm; ### set to zero if compiling for 1.0.1 + +&external_label("OPENSSL_ia32cap_P") if ($xmm); + + +$A="eax"; +$B="ebx"; +$C="ecx"; +$D="edx"; +$E="edi"; +$T="esi"; +$tmp1="ebp"; + +@V=($A,$B,$C,$D,$E,$T); + +$alt=0; # 1 denotes alternative IALU implementation, which performs + # 8% *worse* on P4, same on Westmere and Atom, 2% better on + # Sandy Bridge... + +sub BODY_00_15 + { + local($n,$a,$b,$c,$d,$e,$f)=@_; + + &comment("00_15 $n"); + + &mov($f,$c); # f to hold F_00_19(b,c,d) + if ($n==0) { &mov($tmp1,$a); } + else { &mov($a,$tmp1); } + &rotl($tmp1,5); # tmp1=ROTATE(a,5) + &xor($f,$d); + &add($tmp1,$e); # tmp1+=e; + &mov($e,&swtmp($n%16)); # e becomes volatile and is loaded + # with xi, also note that e becomes + # f in next round... + &and($f,$b); + &rotr($b,2); # b=ROTATE(b,30) + &xor($f,$d); # f holds F_00_19(b,c,d) + &lea($tmp1,&DWP(0x5a827999,$tmp1,$e)); # tmp1+=K_00_19+xi + + if ($n==15) { &mov($e,&swtmp(($n+1)%16));# pre-fetch f for next round + &add($f,$tmp1); } # f+=tmp1 + else { &add($tmp1,$f); } # f becomes a in next round + &mov($tmp1,$a) if ($alt && $n==15); + } + +sub BODY_16_19 + { + local($n,$a,$b,$c,$d,$e,$f)=@_; + + &comment("16_19 $n"); + +if ($alt) { + &xor($c,$d); + &xor($f,&swtmp(($n+2)%16)); # f to hold Xupdate(xi,xa,xb,xc,xd) + &and($tmp1,$c); # tmp1 to hold F_00_19(b,c,d), b&=c^d + &xor($f,&swtmp(($n+8)%16)); + &xor($tmp1,$d); # tmp1=F_00_19(b,c,d) + &xor($f,&swtmp(($n+13)%16)); # f holds xa^xb^xc^xd + &rotl($f,1); # f=ROTATE(f,1) + &add($e,$tmp1); # e+=F_00_19(b,c,d) + &xor($c,$d); # restore $c + &mov($tmp1,$a); # b in next round + &rotr($b,$n==16?2:7); # b=ROTATE(b,30) + &mov(&swtmp($n%16),$f); # xi=f + &rotl($a,5); # ROTATE(a,5) + &lea($f,&DWP(0x5a827999,$f,$e));# f+=F_00_19(b,c,d)+e + &mov($e,&swtmp(($n+1)%16)); # pre-fetch f for next round + &add($f,$a); # f+=ROTATE(a,5) +} else { + &mov($tmp1,$c); # tmp1 to hold F_00_19(b,c,d) + &xor($f,&swtmp(($n+2)%16)); # f to hold Xupdate(xi,xa,xb,xc,xd) + &xor($tmp1,$d); + &xor($f,&swtmp(($n+8)%16)); + &and($tmp1,$b); + &xor($f,&swtmp(($n+13)%16)); # f holds xa^xb^xc^xd + &rotl($f,1); # f=ROTATE(f,1) + &xor($tmp1,$d); # tmp1=F_00_19(b,c,d) + &add($e,$tmp1); # e+=F_00_19(b,c,d) + &mov($tmp1,$a); + &rotr($b,2); # b=ROTATE(b,30) + &mov(&swtmp($n%16),$f); # xi=f + &rotl($tmp1,5); # ROTATE(a,5) + &lea($f,&DWP(0x5a827999,$f,$e));# f+=F_00_19(b,c,d)+e + &mov($e,&swtmp(($n+1)%16)); # pre-fetch f for next round + &add($f,$tmp1); # f+=ROTATE(a,5) +} + } + +sub BODY_20_39 + { + local($n,$a,$b,$c,$d,$e,$f)=@_; + local $K=($n<40)?0x6ed9eba1:0xca62c1d6; + + &comment("20_39 $n"); + +if ($alt) { + &xor($tmp1,$c); # tmp1 to hold F_20_39(b,c,d), b^=c + &xor($f,&swtmp(($n+2)%16)); # f to hold Xupdate(xi,xa,xb,xc,xd) + &xor($tmp1,$d); # tmp1 holds F_20_39(b,c,d) + &xor($f,&swtmp(($n+8)%16)); + &add($e,$tmp1); # e+=F_20_39(b,c,d) + &xor($f,&swtmp(($n+13)%16)); # f holds xa^xb^xc^xd + &rotl($f,1); # f=ROTATE(f,1) + &mov($tmp1,$a); # b in next round + &rotr($b,7); # b=ROTATE(b,30) + &mov(&swtmp($n%16),$f) if($n<77);# xi=f + &rotl($a,5); # ROTATE(a,5) + &xor($b,$c) if($n==39);# warm up for BODY_40_59 + &and($tmp1,$b) if($n==39); + &lea($f,&DWP($K,$f,$e)); # f+=e+K_XX_YY + &mov($e,&swtmp(($n+1)%16)) if($n<79);# pre-fetch f for next round + &add($f,$a); # f+=ROTATE(a,5) + &rotr($a,5) if ($n==79); +} else { + &mov($tmp1,$b); # tmp1 to hold F_20_39(b,c,d) + &xor($f,&swtmp(($n+2)%16)); # f to hold Xupdate(xi,xa,xb,xc,xd) + &xor($tmp1,$c); + &xor($f,&swtmp(($n+8)%16)); + &xor($tmp1,$d); # tmp1 holds F_20_39(b,c,d) + &xor($f,&swtmp(($n+13)%16)); # f holds xa^xb^xc^xd + &rotl($f,1); # f=ROTATE(f,1) + &add($e,$tmp1); # e+=F_20_39(b,c,d) + &rotr($b,2); # b=ROTATE(b,30) + &mov($tmp1,$a); + &rotl($tmp1,5); # ROTATE(a,5) + &mov(&swtmp($n%16),$f) if($n<77);# xi=f + &lea($f,&DWP($K,$f,$e)); # f+=e+K_XX_YY + &mov($e,&swtmp(($n+1)%16)) if($n<79);# pre-fetch f for next round + &add($f,$tmp1); # f+=ROTATE(a,5) +} + } + +sub BODY_40_59 + { + local($n,$a,$b,$c,$d,$e,$f)=@_; + + &comment("40_59 $n"); + +if ($alt) { + &add($e,$tmp1); # e+=b&(c^d) + &xor($f,&swtmp(($n+2)%16)); # f to hold Xupdate(xi,xa,xb,xc,xd) + &mov($tmp1,$d); + &xor($f,&swtmp(($n+8)%16)); + &xor($c,$d); # restore $c + &xor($f,&swtmp(($n+13)%16)); # f holds xa^xb^xc^xd + &rotl($f,1); # f=ROTATE(f,1) + &and($tmp1,$c); + &rotr($b,7); # b=ROTATE(b,30) + &add($e,$tmp1); # e+=c&d + &mov($tmp1,$a); # b in next round + &mov(&swtmp($n%16),$f); # xi=f + &rotl($a,5); # ROTATE(a,5) + &xor($b,$c) if ($n<59); + &and($tmp1,$b) if ($n<59);# tmp1 to hold F_40_59(b,c,d) + &lea($f,&DWP(0x8f1bbcdc,$f,$e));# f+=K_40_59+e+(b&(c^d)) + &mov($e,&swtmp(($n+1)%16)); # pre-fetch f for next round + &add($f,$a); # f+=ROTATE(a,5) +} else { + &mov($tmp1,$c); # tmp1 to hold F_40_59(b,c,d) + &xor($f,&swtmp(($n+2)%16)); # f to hold Xupdate(xi,xa,xb,xc,xd) + &xor($tmp1,$d); + &xor($f,&swtmp(($n+8)%16)); + &and($tmp1,$b); + &xor($f,&swtmp(($n+13)%16)); # f holds xa^xb^xc^xd + &rotl($f,1); # f=ROTATE(f,1) + &add($tmp1,$e); # b&(c^d)+=e + &rotr($b,2); # b=ROTATE(b,30) + &mov($e,$a); # e becomes volatile + &rotl($e,5); # ROTATE(a,5) + &mov(&swtmp($n%16),$f); # xi=f + &lea($f,&DWP(0x8f1bbcdc,$f,$tmp1));# f+=K_40_59+e+(b&(c^d)) + &mov($tmp1,$c); + &add($f,$e); # f+=ROTATE(a,5) + &and($tmp1,$d); + &mov($e,&swtmp(($n+1)%16)); # pre-fetch f for next round + &add($f,$tmp1); # f+=c&d +} + } + +&function_begin("sha1_block_data_order"); +if ($xmm) { + &static_label("shaext_shortcut") if ($shaext); + &static_label("ssse3_shortcut"); + &static_label("avx_shortcut") if ($ymm); + &static_label("K_XX_XX"); + + &call (&label("pic_point")); # make it PIC! + &set_label("pic_point"); + &blindpop($tmp1); + &picmeup($T,"OPENSSL_ia32cap_P",$tmp1,&label("pic_point")); + &lea ($tmp1,&DWP(&label("K_XX_XX")."-".&label("pic_point"),$tmp1)); + + &mov ($A,&DWP(0,$T)); + &mov ($D,&DWP(4,$T)); + &test ($D,1<<9); # check SSSE3 bit + &jz (&label("x86")); + &mov ($C,&DWP(8,$T)); + &test ($A,1<<24); # check FXSR bit + &jz (&label("x86")); + if ($shaext) { + &test ($C,1<<29); # check SHA bit + &jnz (&label("shaext_shortcut")); + } + if ($ymm) { + &and ($D,1<<28); # mask AVX bit + &and ($A,1<<30); # mask "Intel CPU" bit + &or ($A,$D); + &cmp ($A,1<<28|1<<30); + &je (&label("avx_shortcut")); + } + &jmp (&label("ssse3_shortcut")); + &set_label("x86",16); +} + &mov($tmp1,&wparam(0)); # SHA_CTX *c + &mov($T,&wparam(1)); # const void *input + &mov($A,&wparam(2)); # size_t num + &stack_push(16+3); # allocate X[16] + &shl($A,6); + &add($A,$T); + &mov(&wparam(2),$A); # pointer beyond the end of input + &mov($E,&DWP(16,$tmp1));# pre-load E + &jmp(&label("loop")); + +&set_label("loop",16); + + # copy input chunk to X, but reversing byte order! + for ($i=0; $i<16; $i+=4) + { + &mov($A,&DWP(4*($i+0),$T)); + &mov($B,&DWP(4*($i+1),$T)); + &mov($C,&DWP(4*($i+2),$T)); + &mov($D,&DWP(4*($i+3),$T)); + &bswap($A); + &bswap($B); + &bswap($C); + &bswap($D); + &mov(&swtmp($i+0),$A); + &mov(&swtmp($i+1),$B); + &mov(&swtmp($i+2),$C); + &mov(&swtmp($i+3),$D); + } + &mov(&wparam(1),$T); # redundant in 1st spin + + &mov($A,&DWP(0,$tmp1)); # load SHA_CTX + &mov($B,&DWP(4,$tmp1)); + &mov($C,&DWP(8,$tmp1)); + &mov($D,&DWP(12,$tmp1)); + # E is pre-loaded + + for($i=0;$i<16;$i++) { &BODY_00_15($i,@V); unshift(@V,pop(@V)); } + for(;$i<20;$i++) { &BODY_16_19($i,@V); unshift(@V,pop(@V)); } + for(;$i<40;$i++) { &BODY_20_39($i,@V); unshift(@V,pop(@V)); } + for(;$i<60;$i++) { &BODY_40_59($i,@V); unshift(@V,pop(@V)); } + for(;$i<80;$i++) { &BODY_20_39($i,@V); unshift(@V,pop(@V)); } + + (($V[5] eq $D) and ($V[0] eq $E)) or die; # double-check + + &mov($tmp1,&wparam(0)); # re-load SHA_CTX* + &mov($D,&wparam(1)); # D is last "T" and is discarded + + &add($E,&DWP(0,$tmp1)); # E is last "A"... + &add($T,&DWP(4,$tmp1)); + &add($A,&DWP(8,$tmp1)); + &add($B,&DWP(12,$tmp1)); + &add($C,&DWP(16,$tmp1)); + + &mov(&DWP(0,$tmp1),$E); # update SHA_CTX + &add($D,64); # advance input pointer + &mov(&DWP(4,$tmp1),$T); + &cmp($D,&wparam(2)); # have we reached the end yet? + &mov(&DWP(8,$tmp1),$A); + &mov($E,$C); # C is last "E" which needs to be "pre-loaded" + &mov(&DWP(12,$tmp1),$B); + &mov($T,$D); # input pointer + &mov(&DWP(16,$tmp1),$C); + &jb(&label("loop")); + + &stack_pop(16+3); +&function_end("sha1_block_data_order"); + +if ($xmm) { +if ($shaext) { +###################################################################### +# Intel SHA Extensions implementation of SHA1 update function. +# +my ($ctx,$inp,$num)=("edi","esi","ecx"); +my ($ABCD,$E,$E_,$BSWAP)=map("xmm$_",(0..3)); +my @MSG=map("xmm$_",(4..7)); + +sub sha1rnds4 { + my ($dst,$src,$imm)=@_; + if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/) + { &data_byte(0x0f,0x3a,0xcc,0xc0|($1<<3)|$2,$imm); } +} +sub sha1op38 { + my ($opcodelet,$dst,$src)=@_; + if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/) + { &data_byte(0x0f,0x38,$opcodelet,0xc0|($1<<3)|$2); } +} +sub sha1nexte { sha1op38(0xc8,@_); } +sub sha1msg1 { sha1op38(0xc9,@_); } +sub sha1msg2 { sha1op38(0xca,@_); } + +&function_begin("_sha1_block_data_order_shaext"); + &call (&label("pic_point")); # make it PIC! + &set_label("pic_point"); + &blindpop($tmp1); + &lea ($tmp1,&DWP(&label("K_XX_XX")."-".&label("pic_point"),$tmp1)); +&set_label("shaext_shortcut"); + &mov ($ctx,&wparam(0)); + &mov ("ebx","esp"); + &mov ($inp,&wparam(1)); + &mov ($num,&wparam(2)); + &sub ("esp",32); + + &movdqu ($ABCD,&QWP(0,$ctx)); + &movd ($E,&DWP(16,$ctx)); + &and ("esp",-32); + &movdqa ($BSWAP,&QWP(0x50,$tmp1)); # byte-n-word swap + + &movdqu (@MSG[0],&QWP(0,$inp)); + &pshufd ($ABCD,$ABCD,0b00011011); # flip word order + &movdqu (@MSG[1],&QWP(0x10,$inp)); + &pshufd ($E,$E,0b00011011); # flip word order + &movdqu (@MSG[2],&QWP(0x20,$inp)); + &pshufb (@MSG[0],$BSWAP); + &movdqu (@MSG[3],&QWP(0x30,$inp)); + &pshufb (@MSG[1],$BSWAP); + &pshufb (@MSG[2],$BSWAP); + &pshufb (@MSG[3],$BSWAP); + &jmp (&label("loop_shaext")); + +&set_label("loop_shaext",16); + &dec ($num); + &lea ("eax",&DWP(0x40,$inp)); + &movdqa (&QWP(0,"esp"),$E); # offload $E + &paddd ($E,@MSG[0]); + &cmovne ($inp,"eax"); + &movdqa (&QWP(16,"esp"),$ABCD); # offload $ABCD + +for($i=0;$i<20-4;$i+=2) { + &sha1msg1 (@MSG[0],@MSG[1]); + &movdqa ($E_,$ABCD); + &sha1rnds4 ($ABCD,$E,int($i/5)); # 0-3... + &sha1nexte ($E_,@MSG[1]); + &pxor (@MSG[0],@MSG[2]); + &sha1msg1 (@MSG[1],@MSG[2]); + &sha1msg2 (@MSG[0],@MSG[3]); + + &movdqa ($E,$ABCD); + &sha1rnds4 ($ABCD,$E_,int(($i+1)/5)); + &sha1nexte ($E,@MSG[2]); + &pxor (@MSG[1],@MSG[3]); + &sha1msg2 (@MSG[1],@MSG[0]); + + push(@MSG,shift(@MSG)); push(@MSG,shift(@MSG)); +} + &movdqu (@MSG[0],&QWP(0,$inp)); + &movdqa ($E_,$ABCD); + &sha1rnds4 ($ABCD,$E,3); # 64-67 + &sha1nexte ($E_,@MSG[1]); + &movdqu (@MSG[1],&QWP(0x10,$inp)); + &pshufb (@MSG[0],$BSWAP); + + &movdqa ($E,$ABCD); + &sha1rnds4 ($ABCD,$E_,3); # 68-71 + &sha1nexte ($E,@MSG[2]); + &movdqu (@MSG[2],&QWP(0x20,$inp)); + &pshufb (@MSG[1],$BSWAP); + + &movdqa ($E_,$ABCD); + &sha1rnds4 ($ABCD,$E,3); # 72-75 + &sha1nexte ($E_,@MSG[3]); + &movdqu (@MSG[3],&QWP(0x30,$inp)); + &pshufb (@MSG[2],$BSWAP); + + &movdqa ($E,$ABCD); + &sha1rnds4 ($ABCD,$E_,3); # 76-79 + &movdqa ($E_,&QWP(0,"esp")); + &pshufb (@MSG[3],$BSWAP); + &sha1nexte ($E,$E_); + &paddd ($ABCD,&QWP(16,"esp")); + + &jnz (&label("loop_shaext")); + + &pshufd ($ABCD,$ABCD,0b00011011); + &pshufd ($E,$E,0b00011011); + &movdqu (&QWP(0,$ctx),$ABCD) + &movd (&DWP(16,$ctx),$E); + &mov ("esp","ebx"); +&function_end("_sha1_block_data_order_shaext"); +} +###################################################################### +# The SSSE3 implementation. +# +# %xmm[0-7] are used as ring @X[] buffer containing quadruples of last +# 32 elements of the message schedule or Xupdate outputs. First 4 +# quadruples are simply byte-swapped input, next 4 are calculated +# according to method originally suggested by Dean Gaudet (modulo +# being implemented in SSSE3). Once 8 quadruples or 32 elements are +# collected, it switches to routine proposed by Max Locktyukhin. +# +# Calculations inevitably require temporary reqisters, and there are +# no %xmm registers left to spare. For this reason part of the ring +# buffer, X[2..4] to be specific, is offloaded to 3 quadriples ring +# buffer on the stack. Keep in mind that X[2] is alias X[-6], X[3] - +# X[-5], and X[4] - X[-4]... +# +# Another notable optimization is aggressive stack frame compression +# aiming to minimize amount of 9-byte instructions... +# +# Yet another notable optimization is "jumping" $B variable. It means +# that there is no register permanently allocated for $B value. This +# allowed to eliminate one instruction from body_20_39... +# +my $Xi=4; # 4xSIMD Xupdate round, start pre-seeded +my @X=map("xmm$_",(4..7,0..3)); # pre-seeded for $Xi=4 +my @V=($A,$B,$C,$D,$E); +my $j=0; # hash round +my $rx=0; +my @T=($T,$tmp1); +my $inp; + +my $_rol=sub { &rol(@_) }; +my $_ror=sub { &ror(@_) }; + +&function_begin("_sha1_block_data_order_ssse3"); + &call (&label("pic_point")); # make it PIC! + &set_label("pic_point"); + &blindpop($tmp1); + &lea ($tmp1,&DWP(&label("K_XX_XX")."-".&label("pic_point"),$tmp1)); +&set_label("ssse3_shortcut"); + + &movdqa (@X[3],&QWP(0,$tmp1)); # K_00_19 + &movdqa (@X[4],&QWP(16,$tmp1)); # K_20_39 + &movdqa (@X[5],&QWP(32,$tmp1)); # K_40_59 + &movdqa (@X[6],&QWP(48,$tmp1)); # K_60_79 + &movdqa (@X[2],&QWP(64,$tmp1)); # pbswap mask + + &mov ($E,&wparam(0)); # load argument block + &mov ($inp=@T[1],&wparam(1)); + &mov ($D,&wparam(2)); + &mov (@T[0],"esp"); + + # stack frame layout + # + # +0 X[0]+K X[1]+K X[2]+K X[3]+K # XMM->IALU xfer area + # X[4]+K X[5]+K X[6]+K X[7]+K + # X[8]+K X[9]+K X[10]+K X[11]+K + # X[12]+K X[13]+K X[14]+K X[15]+K + # + # +64 X[0] X[1] X[2] X[3] # XMM->XMM backtrace area + # X[4] X[5] X[6] X[7] + # X[8] X[9] X[10] X[11] # even borrowed for K_00_19 + # + # +112 K_20_39 K_20_39 K_20_39 K_20_39 # constants + # K_40_59 K_40_59 K_40_59 K_40_59 + # K_60_79 K_60_79 K_60_79 K_60_79 + # K_00_19 K_00_19 K_00_19 K_00_19 + # pbswap mask + # + # +192 ctx # argument block + # +196 inp + # +200 end + # +204 esp + &sub ("esp",208); + &and ("esp",-64); + + &movdqa (&QWP(112+0,"esp"),@X[4]); # copy constants + &movdqa (&QWP(112+16,"esp"),@X[5]); + &movdqa (&QWP(112+32,"esp"),@X[6]); + &shl ($D,6); # len*64 + &movdqa (&QWP(112+48,"esp"),@X[3]); + &add ($D,$inp); # end of input + &movdqa (&QWP(112+64,"esp"),@X[2]); + &add ($inp,64); + &mov (&DWP(192+0,"esp"),$E); # save argument block + &mov (&DWP(192+4,"esp"),$inp); + &mov (&DWP(192+8,"esp"),$D); + &mov (&DWP(192+12,"esp"),@T[0]); # save original %esp + + &mov ($A,&DWP(0,$E)); # load context + &mov ($B,&DWP(4,$E)); + &mov ($C,&DWP(8,$E)); + &mov ($D,&DWP(12,$E)); + &mov ($E,&DWP(16,$E)); + &mov (@T[0],$B); # magic seed + + &movdqu (@X[-4&7],&QWP(-64,$inp)); # load input to %xmm[0-3] + &movdqu (@X[-3&7],&QWP(-48,$inp)); + &movdqu (@X[-2&7],&QWP(-32,$inp)); + &movdqu (@X[-1&7],&QWP(-16,$inp)); + &pshufb (@X[-4&7],@X[2]); # byte swap + &pshufb (@X[-3&7],@X[2]); + &pshufb (@X[-2&7],@X[2]); + &movdqa (&QWP(112-16,"esp"),@X[3]); # borrow last backtrace slot + &pshufb (@X[-1&7],@X[2]); + &paddd (@X[-4&7],@X[3]); # add K_00_19 + &paddd (@X[-3&7],@X[3]); + &paddd (@X[-2&7],@X[3]); + &movdqa (&QWP(0,"esp"),@X[-4&7]); # X[]+K xfer to IALU + &psubd (@X[-4&7],@X[3]); # restore X[] + &movdqa (&QWP(0+16,"esp"),@X[-3&7]); + &psubd (@X[-3&7],@X[3]); + &movdqa (&QWP(0+32,"esp"),@X[-2&7]); + &mov (@T[1],$C); + &psubd (@X[-2&7],@X[3]); + &xor (@T[1],$D); + &pshufd (@X[0],@X[-4&7],0xee); # was &movdqa (@X[0],@X[-3&7]); + &and (@T[0],@T[1]); + &jmp (&label("loop")); + +###################################################################### +# SSE instruction sequence is first broken to groups of indepentent +# instructions, independent in respect to their inputs and shifter +# (not all architectures have more than one). Then IALU instructions +# are "knitted in" between the SSE groups. Distance is maintained for +# SSE latency of 2 in hope that it fits better upcoming AMD Bulldozer +# [which allegedly also implements SSSE3]... +# +# Temporary registers usage. X[2] is volatile at the entry and at the +# end is restored from backtrace ring buffer. X[3] is expected to +# contain current K_XX_XX constant and is used to caclulate X[-1]+K +# from previous round, it becomes volatile the moment the value is +# saved to stack for transfer to IALU. X[4] becomes volatile whenever +# X[-4] is accumulated and offloaded to backtrace ring buffer, at the +# end it is loaded with next K_XX_XX [which becomes X[3] in next +# round]... +# +sub Xupdate_ssse3_16_31() # recall that $Xi starts wtih 4 +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 40 instructions + my ($a,$b,$c,$d,$e); + + eval(shift(@insns)); # ror + eval(shift(@insns)); + eval(shift(@insns)); + &punpcklqdq(@X[0],@X[-3&7]); # compose "X[-14]" in "X[0]", was &palignr(@X[0],@X[-4&7],8); + &movdqa (@X[2],@X[-1&7]); + eval(shift(@insns)); + eval(shift(@insns)); + + &paddd (@X[3],@X[-1&7]); + &movdqa (&QWP(64+16*(($Xi-4)%3),"esp"),@X[-4&7]);# save X[] to backtrace buffer + eval(shift(@insns)); # rol + eval(shift(@insns)); + &psrldq (@X[2],4); # "X[-3]", 3 dwords + eval(shift(@insns)); + eval(shift(@insns)); + &pxor (@X[0],@X[-4&7]); # "X[0]"^="X[-16]" + eval(shift(@insns)); + eval(shift(@insns)); # ror + + &pxor (@X[2],@X[-2&7]); # "X[-3]"^"X[-8]" + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &pxor (@X[0],@X[2]); # "X[0]"^="X[-3]"^"X[-8]" + eval(shift(@insns)); + eval(shift(@insns)); # rol + &movdqa (&QWP(0+16*(($Xi-1)&3),"esp"),@X[3]); # X[]+K xfer to IALU + eval(shift(@insns)); + eval(shift(@insns)); + + &movdqa (@X[4],@X[0]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # ror + &movdqa (@X[2],@X[0]); + eval(shift(@insns)); + + &pslldq (@X[4],12); # "X[0]"<<96, extract one dword + &paddd (@X[0],@X[0]); + eval(shift(@insns)); + eval(shift(@insns)); + + &psrld (@X[2],31); + eval(shift(@insns)); + eval(shift(@insns)); # rol + &movdqa (@X[3],@X[4]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &psrld (@X[4],30); + eval(shift(@insns)); + eval(shift(@insns)); # ror + &por (@X[0],@X[2]); # "X[0]"<<<=1 + eval(shift(@insns)); + &movdqa (@X[2],&QWP(64+16*(($Xi-6)%3),"esp")) if ($Xi>5); # restore X[] from backtrace buffer + eval(shift(@insns)); + eval(shift(@insns)); + + &pslld (@X[3],2); + eval(shift(@insns)); + eval(shift(@insns)); # rol + &pxor (@X[0],@X[4]); + &movdqa (@X[4],&QWP(112-16+16*(($Xi)/5),"esp")); # K_XX_XX + eval(shift(@insns)); + eval(shift(@insns)); + + &pxor (@X[0],@X[3]); # "X[0]"^=("X[0]"<<96)<<<2 + &pshufd (@X[1],@X[-3&7],0xee) if ($Xi<7); # was &movdqa (@X[1],@X[-2&7]) + &pshufd (@X[3],@X[-1&7],0xee) if ($Xi==7); + eval(shift(@insns)); + eval(shift(@insns)); + + foreach (@insns) { eval; } # remaining instructions [if any] + + $Xi++; push(@X,shift(@X)); # "rotate" X[] +} + +sub Xupdate_ssse3_32_79() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 to 44 instructions + my ($a,$b,$c,$d,$e); + + eval(shift(@insns)); # body_20_39 + &pxor (@X[0],@X[-4&7]); # "X[0]"="X[-32]"^"X[-16]" + &punpcklqdq(@X[2],@X[-1&7]); # compose "X[-6]", was &palignr(@X[2],@X[-2&7],8) + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # rol + + &pxor (@X[0],@X[-7&7]); # "X[0]"^="X[-28]" + &movdqa (&QWP(64+16*(($Xi-4)%3),"esp"),@X[-4&7]); # save X[] to backtrace buffer + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)) if (@insns[0] =~ /_rol/); + if ($Xi%5) { + &movdqa (@X[4],@X[3]); # "perpetuate" K_XX_XX... + } else { # ... or load next one + &movdqa (@X[4],&QWP(112-16+16*($Xi/5),"esp")); + } + eval(shift(@insns)); # ror + &paddd (@X[3],@X[-1&7]); + eval(shift(@insns)); + + &pxor (@X[0],@X[2]); # "X[0]"^="X[-6]" + eval(shift(@insns)); # body_20_39 + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # rol + + &movdqa (@X[2],@X[0]); + &movdqa (&QWP(0+16*(($Xi-1)&3),"esp"),@X[3]); # X[]+K xfer to IALU + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # ror + eval(shift(@insns)); + eval(shift(@insns)) if (@insns[0] =~ /_rol/); + + &pslld (@X[0],2); + eval(shift(@insns)); # body_20_39 + eval(shift(@insns)); + &psrld (@X[2],30); + eval(shift(@insns)); + eval(shift(@insns)); # rol + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # ror + eval(shift(@insns)); + eval(shift(@insns)) if (@insns[1] =~ /_rol/); + eval(shift(@insns)) if (@insns[0] =~ /_rol/); + + &por (@X[0],@X[2]); # "X[0]"<<<=2 + eval(shift(@insns)); # body_20_39 + eval(shift(@insns)); + &movdqa (@X[2],&QWP(64+16*(($Xi-6)%3),"esp")) if($Xi<19); # restore X[] from backtrace buffer + eval(shift(@insns)); + eval(shift(@insns)); # rol + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # ror + &pshufd (@X[3],@X[-1],0xee) if ($Xi<19); # was &movdqa (@X[3],@X[0]) + eval(shift(@insns)); + + foreach (@insns) { eval; } # remaining instructions + + $Xi++; push(@X,shift(@X)); # "rotate" X[] +} + +sub Xuplast_ssse3_80() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 instructions + my ($a,$b,$c,$d,$e); + + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &paddd (@X[3],@X[-1&7]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &movdqa (&QWP(0+16*(($Xi-1)&3),"esp"),@X[3]); # X[]+K xfer IALU + + foreach (@insns) { eval; } # remaining instructions + + &mov ($inp=@T[1],&DWP(192+4,"esp")); + &cmp ($inp,&DWP(192+8,"esp")); + &je (&label("done")); + + &movdqa (@X[3],&QWP(112+48,"esp")); # K_00_19 + &movdqa (@X[2],&QWP(112+64,"esp")); # pbswap mask + &movdqu (@X[-4&7],&QWP(0,$inp)); # load input + &movdqu (@X[-3&7],&QWP(16,$inp)); + &movdqu (@X[-2&7],&QWP(32,$inp)); + &movdqu (@X[-1&7],&QWP(48,$inp)); + &add ($inp,64); + &pshufb (@X[-4&7],@X[2]); # byte swap + &mov (&DWP(192+4,"esp"),$inp); + &movdqa (&QWP(112-16,"esp"),@X[3]); # borrow last backtrace slot + + $Xi=0; +} + +sub Xloop_ssse3() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 instructions + my ($a,$b,$c,$d,$e); + + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &pshufb (@X[($Xi-3)&7],@X[2]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &paddd (@X[($Xi-4)&7],@X[3]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &movdqa (&QWP(0+16*$Xi,"esp"),@X[($Xi-4)&7]); # X[]+K xfer to IALU + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &psubd (@X[($Xi-4)&7],@X[3]); + + foreach (@insns) { eval; } + $Xi++; +} + +sub Xtail_ssse3() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 instructions + my ($a,$b,$c,$d,$e); + + foreach (@insns) { eval; } +} + +sub body_00_19 () { # ((c^d)&b)^d + # on start @T[0]=(c^d)&b + return &body_20_39() if ($rx==19); $rx++; + ( + '($a,$b,$c,$d,$e)=@V;'. + '&$_ror ($b,$j?7:2);', # $b>>>2 + '&xor (@T[0],$d);', + '&mov (@T[1],$a);', # $b in next round + + '&add ($e,&DWP(4*($j&15),"esp"));', # X[]+K xfer + '&xor ($b,$c);', # $c^$d for next round + + '&$_rol ($a,5);', + '&add ($e,@T[0]);', + '&and (@T[1],$b);', # ($b&($c^$d)) for next round + + '&xor ($b,$c);', # restore $b + '&add ($e,$a);' .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));' + ); +} + +sub body_20_39 () { # b^d^c + # on entry @T[0]=b^d + return &body_40_59() if ($rx==39); $rx++; + ( + '($a,$b,$c,$d,$e)=@V;'. + '&add ($e,&DWP(4*($j&15),"esp"));', # X[]+K xfer + '&xor (@T[0],$d) if($j==19);'. + '&xor (@T[0],$c) if($j> 19);', # ($b^$d^$c) + '&mov (@T[1],$a);', # $b in next round + + '&$_rol ($a,5);', + '&add ($e,@T[0]);', + '&xor (@T[1],$c) if ($j< 79);', # $b^$d for next round + + '&$_ror ($b,7);', # $b>>>2 + '&add ($e,$a);' .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));' + ); +} + +sub body_40_59 () { # ((b^c)&(c^d))^c + # on entry @T[0]=(b^c), (c^=d) + $rx++; + ( + '($a,$b,$c,$d,$e)=@V;'. + '&add ($e,&DWP(4*($j&15),"esp"));', # X[]+K xfer + '&and (@T[0],$c) if ($j>=40);', # (b^c)&(c^d) + '&xor ($c,$d) if ($j>=40);', # restore $c + + '&$_ror ($b,7);', # $b>>>2 + '&mov (@T[1],$a);', # $b for next round + '&xor (@T[0],$c);', + + '&$_rol ($a,5);', + '&add ($e,@T[0]);', + '&xor (@T[1],$c) if ($j==59);'. + '&xor (@T[1],$b) if ($j< 59);', # b^c for next round + + '&xor ($b,$c) if ($j< 59);', # c^d for next round + '&add ($e,$a);' .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));' + ); +} +###### +sub bodyx_00_19 () { # ((c^d)&b)^d + # on start @T[0]=(b&c)^(~b&d), $e+=X[]+K + return &bodyx_20_39() if ($rx==19); $rx++; + ( + '($a,$b,$c,$d,$e)=@V;'. + + '&rorx ($b,$b,2) if ($j==0);'. # $b>>>2 + '&rorx ($b,@T[1],7) if ($j!=0);', # $b>>>2 + '&lea ($e,&DWP(0,$e,@T[0]));', + '&rorx (@T[0],$a,5);', + + '&andn (@T[1],$a,$c);', + '&and ($a,$b)', + '&add ($d,&DWP(4*(($j+1)&15),"esp"));', # X[]+K xfer + + '&xor (@T[1],$a)', + '&add ($e,@T[0]);' .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));' + ); +} + +sub bodyx_20_39 () { # b^d^c + # on start $b=b^c^d + return &bodyx_40_59() if ($rx==39); $rx++; + ( + '($a,$b,$c,$d,$e)=@V;'. + + '&add ($e,($j==19?@T[0]:$b))', + '&rorx ($b,@T[1],7);', # $b>>>2 + '&rorx (@T[0],$a,5);', + + '&xor ($a,$b) if ($j<79);', + '&add ($d,&DWP(4*(($j+1)&15),"esp")) if ($j<79);', # X[]+K xfer + '&xor ($a,$c) if ($j<79);', + '&add ($e,@T[0]);' .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));' + ); +} + +sub bodyx_40_59 () { # ((b^c)&(c^d))^c + # on start $b=((b^c)&(c^d))^c + return &bodyx_20_39() if ($rx==59); $rx++; + ( + '($a,$b,$c,$d,$e)=@V;'. + + '&rorx (@T[0],$a,5)', + '&lea ($e,&DWP(0,$e,$b))', + '&rorx ($b,@T[1],7)', # $b>>>2 + '&add ($d,&DWP(4*(($j+1)&15),"esp"))', # X[]+K xfer + + '&mov (@T[1],$c)', + '&xor ($a,$b)', # b^c for next round + '&xor (@T[1],$b)', # c^d for next round + + '&and ($a,@T[1])', + '&add ($e,@T[0])', + '&xor ($a,$b)' .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));' + ); +} + +&set_label("loop",16); + &Xupdate_ssse3_16_31(\&body_00_19); + &Xupdate_ssse3_16_31(\&body_00_19); + &Xupdate_ssse3_16_31(\&body_00_19); + &Xupdate_ssse3_16_31(\&body_00_19); + &Xupdate_ssse3_32_79(\&body_00_19); + &Xupdate_ssse3_32_79(\&body_20_39); + &Xupdate_ssse3_32_79(\&body_20_39); + &Xupdate_ssse3_32_79(\&body_20_39); + &Xupdate_ssse3_32_79(\&body_20_39); + &Xupdate_ssse3_32_79(\&body_20_39); + &Xupdate_ssse3_32_79(\&body_40_59); + &Xupdate_ssse3_32_79(\&body_40_59); + &Xupdate_ssse3_32_79(\&body_40_59); + &Xupdate_ssse3_32_79(\&body_40_59); + &Xupdate_ssse3_32_79(\&body_40_59); + &Xupdate_ssse3_32_79(\&body_20_39); + &Xuplast_ssse3_80(\&body_20_39); # can jump to "done" + + $saved_j=$j; @saved_V=@V; + + &Xloop_ssse3(\&body_20_39); + &Xloop_ssse3(\&body_20_39); + &Xloop_ssse3(\&body_20_39); + + &mov (@T[1],&DWP(192,"esp")); # update context + &add ($A,&DWP(0,@T[1])); + &add (@T[0],&DWP(4,@T[1])); # $b + &add ($C,&DWP(8,@T[1])); + &mov (&DWP(0,@T[1]),$A); + &add ($D,&DWP(12,@T[1])); + &mov (&DWP(4,@T[1]),@T[0]); + &add ($E,&DWP(16,@T[1])); + &mov (&DWP(8,@T[1]),$C); + &mov ($B,$C); + &mov (&DWP(12,@T[1]),$D); + &xor ($B,$D); + &mov (&DWP(16,@T[1]),$E); + &mov (@T[1],@T[0]); + &pshufd (@X[0],@X[-4&7],0xee); # was &movdqa (@X[0],@X[-3&7]); + &and (@T[0],$B); + &mov ($B,$T[1]); + + &jmp (&label("loop")); + +&set_label("done",16); $j=$saved_j; @V=@saved_V; + + &Xtail_ssse3(\&body_20_39); + &Xtail_ssse3(\&body_20_39); + &Xtail_ssse3(\&body_20_39); + + &mov (@T[1],&DWP(192,"esp")); # update context + &add ($A,&DWP(0,@T[1])); + &mov ("esp",&DWP(192+12,"esp")); # restore %esp + &add (@T[0],&DWP(4,@T[1])); # $b + &add ($C,&DWP(8,@T[1])); + &mov (&DWP(0,@T[1]),$A); + &add ($D,&DWP(12,@T[1])); + &mov (&DWP(4,@T[1]),@T[0]); + &add ($E,&DWP(16,@T[1])); + &mov (&DWP(8,@T[1]),$C); + &mov (&DWP(12,@T[1]),$D); + &mov (&DWP(16,@T[1]),$E); + +&function_end("_sha1_block_data_order_ssse3"); + +$rx=0; # reset + +if ($ymm) { +my $Xi=4; # 4xSIMD Xupdate round, start pre-seeded +my @X=map("xmm$_",(4..7,0..3)); # pre-seeded for $Xi=4 +my @V=($A,$B,$C,$D,$E); +my $j=0; # hash round +my @T=($T,$tmp1); +my $inp; + +my $_rol=sub { &shld(@_[0],@_) }; +my $_ror=sub { &shrd(@_[0],@_) }; + +&function_begin("_sha1_block_data_order_avx"); + &call (&label("pic_point")); # make it PIC! + &set_label("pic_point"); + &blindpop($tmp1); + &lea ($tmp1,&DWP(&label("K_XX_XX")."-".&label("pic_point"),$tmp1)); +&set_label("avx_shortcut"); + &vzeroall(); + + &vmovdqa(@X[3],&QWP(0,$tmp1)); # K_00_19 + &vmovdqa(@X[4],&QWP(16,$tmp1)); # K_20_39 + &vmovdqa(@X[5],&QWP(32,$tmp1)); # K_40_59 + &vmovdqa(@X[6],&QWP(48,$tmp1)); # K_60_79 + &vmovdqa(@X[2],&QWP(64,$tmp1)); # pbswap mask + + &mov ($E,&wparam(0)); # load argument block + &mov ($inp=@T[1],&wparam(1)); + &mov ($D,&wparam(2)); + &mov (@T[0],"esp"); + + # stack frame layout + # + # +0 X[0]+K X[1]+K X[2]+K X[3]+K # XMM->IALU xfer area + # X[4]+K X[5]+K X[6]+K X[7]+K + # X[8]+K X[9]+K X[10]+K X[11]+K + # X[12]+K X[13]+K X[14]+K X[15]+K + # + # +64 X[0] X[1] X[2] X[3] # XMM->XMM backtrace area + # X[4] X[5] X[6] X[7] + # X[8] X[9] X[10] X[11] # even borrowed for K_00_19 + # + # +112 K_20_39 K_20_39 K_20_39 K_20_39 # constants + # K_40_59 K_40_59 K_40_59 K_40_59 + # K_60_79 K_60_79 K_60_79 K_60_79 + # K_00_19 K_00_19 K_00_19 K_00_19 + # pbswap mask + # + # +192 ctx # argument block + # +196 inp + # +200 end + # +204 esp + &sub ("esp",208); + &and ("esp",-64); + + &vmovdqa(&QWP(112+0,"esp"),@X[4]); # copy constants + &vmovdqa(&QWP(112+16,"esp"),@X[5]); + &vmovdqa(&QWP(112+32,"esp"),@X[6]); + &shl ($D,6); # len*64 + &vmovdqa(&QWP(112+48,"esp"),@X[3]); + &add ($D,$inp); # end of input + &vmovdqa(&QWP(112+64,"esp"),@X[2]); + &add ($inp,64); + &mov (&DWP(192+0,"esp"),$E); # save argument block + &mov (&DWP(192+4,"esp"),$inp); + &mov (&DWP(192+8,"esp"),$D); + &mov (&DWP(192+12,"esp"),@T[0]); # save original %esp + + &mov ($A,&DWP(0,$E)); # load context + &mov ($B,&DWP(4,$E)); + &mov ($C,&DWP(8,$E)); + &mov ($D,&DWP(12,$E)); + &mov ($E,&DWP(16,$E)); + &mov (@T[0],$B); # magic seed + + &vmovdqu(@X[-4&7],&QWP(-64,$inp)); # load input to %xmm[0-3] + &vmovdqu(@X[-3&7],&QWP(-48,$inp)); + &vmovdqu(@X[-2&7],&QWP(-32,$inp)); + &vmovdqu(@X[-1&7],&QWP(-16,$inp)); + &vpshufb(@X[-4&7],@X[-4&7],@X[2]); # byte swap + &vpshufb(@X[-3&7],@X[-3&7],@X[2]); + &vpshufb(@X[-2&7],@X[-2&7],@X[2]); + &vmovdqa(&QWP(112-16,"esp"),@X[3]); # borrow last backtrace slot + &vpshufb(@X[-1&7],@X[-1&7],@X[2]); + &vpaddd (@X[0],@X[-4&7],@X[3]); # add K_00_19 + &vpaddd (@X[1],@X[-3&7],@X[3]); + &vpaddd (@X[2],@X[-2&7],@X[3]); + &vmovdqa(&QWP(0,"esp"),@X[0]); # X[]+K xfer to IALU + &mov (@T[1],$C); + &vmovdqa(&QWP(0+16,"esp"),@X[1]); + &xor (@T[1],$D); + &vmovdqa(&QWP(0+32,"esp"),@X[2]); + &and (@T[0],@T[1]); + &jmp (&label("loop")); + +sub Xupdate_avx_16_31() # recall that $Xi starts wtih 4 +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 40 instructions + my ($a,$b,$c,$d,$e); + + eval(shift(@insns)); + eval(shift(@insns)); + &vpalignr(@X[0],@X[-3&7],@X[-4&7],8); # compose "X[-14]" in "X[0]" + eval(shift(@insns)); + eval(shift(@insns)); + + &vpaddd (@X[3],@X[3],@X[-1&7]); + &vmovdqa (&QWP(64+16*(($Xi-4)%3),"esp"),@X[-4&7]);# save X[] to backtrace buffer + eval(shift(@insns)); + eval(shift(@insns)); + &vpsrldq(@X[2],@X[-1&7],4); # "X[-3]", 3 dwords + eval(shift(@insns)); + eval(shift(@insns)); + &vpxor (@X[0],@X[0],@X[-4&7]); # "X[0]"^="X[-16]" + eval(shift(@insns)); + eval(shift(@insns)); + + &vpxor (@X[2],@X[2],@X[-2&7]); # "X[-3]"^"X[-8]" + eval(shift(@insns)); + eval(shift(@insns)); + &vmovdqa (&QWP(0+16*(($Xi-1)&3),"esp"),@X[3]); # X[]+K xfer to IALU + eval(shift(@insns)); + eval(shift(@insns)); + + &vpxor (@X[0],@X[0],@X[2]); # "X[0]"^="X[-3]"^"X[-8]" + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpsrld (@X[2],@X[0],31); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpslldq(@X[4],@X[0],12); # "X[0]"<<96, extract one dword + &vpaddd (@X[0],@X[0],@X[0]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpsrld (@X[3],@X[4],30); + &vpor (@X[0],@X[0],@X[2]); # "X[0]"<<<=1 + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpslld (@X[4],@X[4],2); + &vmovdqa (@X[2],&QWP(64+16*(($Xi-6)%3),"esp")) if ($Xi>5); # restore X[] from backtrace buffer + eval(shift(@insns)); + eval(shift(@insns)); + &vpxor (@X[0],@X[0],@X[3]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpxor (@X[0],@X[0],@X[4]); # "X[0]"^=("X[0]"<<96)<<<2 + eval(shift(@insns)); + eval(shift(@insns)); + &vmovdqa (@X[4],&QWP(112-16+16*(($Xi)/5),"esp")); # K_XX_XX + eval(shift(@insns)); + eval(shift(@insns)); + + foreach (@insns) { eval; } # remaining instructions [if any] + + $Xi++; push(@X,shift(@X)); # "rotate" X[] +} + +sub Xupdate_avx_32_79() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 to 44 instructions + my ($a,$b,$c,$d,$e); + + &vpalignr(@X[2],@X[-1&7],@X[-2&7],8); # compose "X[-6]" + &vpxor (@X[0],@X[0],@X[-4&7]); # "X[0]"="X[-32]"^"X[-16]" + eval(shift(@insns)); # body_20_39 + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # rol + + &vpxor (@X[0],@X[0],@X[-7&7]); # "X[0]"^="X[-28]" + &vmovdqa (&QWP(64+16*(($Xi-4)%3),"esp"),@X[-4&7]); # save X[] to backtrace buffer + eval(shift(@insns)); + eval(shift(@insns)); + if ($Xi%5) { + &vmovdqa (@X[4],@X[3]); # "perpetuate" K_XX_XX... + } else { # ... or load next one + &vmovdqa (@X[4],&QWP(112-16+16*($Xi/5),"esp")); + } + &vpaddd (@X[3],@X[3],@X[-1&7]); + eval(shift(@insns)); # ror + eval(shift(@insns)); + + &vpxor (@X[0],@X[0],@X[2]); # "X[0]"^="X[-6]" + eval(shift(@insns)); # body_20_39 + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # rol + + &vpsrld (@X[2],@X[0],30); + &vmovdqa (&QWP(0+16*(($Xi-1)&3),"esp"),@X[3]); # X[]+K xfer to IALU + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # ror + eval(shift(@insns)); + + &vpslld (@X[0],@X[0],2); + eval(shift(@insns)); # body_20_39 + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # rol + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # ror + eval(shift(@insns)); + + &vpor (@X[0],@X[0],@X[2]); # "X[0]"<<<=2 + eval(shift(@insns)); # body_20_39 + eval(shift(@insns)); + &vmovdqa (@X[2],&QWP(64+16*(($Xi-6)%3),"esp")) if($Xi<19); # restore X[] from backtrace buffer + eval(shift(@insns)); + eval(shift(@insns)); # rol + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # ror + eval(shift(@insns)); + + foreach (@insns) { eval; } # remaining instructions + + $Xi++; push(@X,shift(@X)); # "rotate" X[] +} + +sub Xuplast_avx_80() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 instructions + my ($a,$b,$c,$d,$e); + + eval(shift(@insns)); + &vpaddd (@X[3],@X[3],@X[-1&7]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vmovdqa (&QWP(0+16*(($Xi-1)&3),"esp"),@X[3]); # X[]+K xfer IALU + + foreach (@insns) { eval; } # remaining instructions + + &mov ($inp=@T[1],&DWP(192+4,"esp")); + &cmp ($inp,&DWP(192+8,"esp")); + &je (&label("done")); + + &vmovdqa(@X[3],&QWP(112+48,"esp")); # K_00_19 + &vmovdqa(@X[2],&QWP(112+64,"esp")); # pbswap mask + &vmovdqu(@X[-4&7],&QWP(0,$inp)); # load input + &vmovdqu(@X[-3&7],&QWP(16,$inp)); + &vmovdqu(@X[-2&7],&QWP(32,$inp)); + &vmovdqu(@X[-1&7],&QWP(48,$inp)); + &add ($inp,64); + &vpshufb(@X[-4&7],@X[-4&7],@X[2]); # byte swap + &mov (&DWP(192+4,"esp"),$inp); + &vmovdqa(&QWP(112-16,"esp"),@X[3]); # borrow last backtrace slot + + $Xi=0; +} + +sub Xloop_avx() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 instructions + my ($a,$b,$c,$d,$e); + + eval(shift(@insns)); + eval(shift(@insns)); + &vpshufb (@X[($Xi-3)&7],@X[($Xi-3)&7],@X[2]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpaddd (@X[$Xi&7],@X[($Xi-4)&7],@X[3]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vmovdqa (&QWP(0+16*$Xi,"esp"),@X[$Xi&7]); # X[]+K xfer to IALU + eval(shift(@insns)); + eval(shift(@insns)); + + foreach (@insns) { eval; } + $Xi++; +} + +sub Xtail_avx() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 instructions + my ($a,$b,$c,$d,$e); + + foreach (@insns) { eval; } +} + +&set_label("loop",16); + &Xupdate_avx_16_31(\&body_00_19); + &Xupdate_avx_16_31(\&body_00_19); + &Xupdate_avx_16_31(\&body_00_19); + &Xupdate_avx_16_31(\&body_00_19); + &Xupdate_avx_32_79(\&body_00_19); + &Xupdate_avx_32_79(\&body_20_39); + &Xupdate_avx_32_79(\&body_20_39); + &Xupdate_avx_32_79(\&body_20_39); + &Xupdate_avx_32_79(\&body_20_39); + &Xupdate_avx_32_79(\&body_20_39); + &Xupdate_avx_32_79(\&body_40_59); + &Xupdate_avx_32_79(\&body_40_59); + &Xupdate_avx_32_79(\&body_40_59); + &Xupdate_avx_32_79(\&body_40_59); + &Xupdate_avx_32_79(\&body_40_59); + &Xupdate_avx_32_79(\&body_20_39); + &Xuplast_avx_80(\&body_20_39); # can jump to "done" + + $saved_j=$j; @saved_V=@V; + + &Xloop_avx(\&body_20_39); + &Xloop_avx(\&body_20_39); + &Xloop_avx(\&body_20_39); + + &mov (@T[1],&DWP(192,"esp")); # update context + &add ($A,&DWP(0,@T[1])); + &add (@T[0],&DWP(4,@T[1])); # $b + &add ($C,&DWP(8,@T[1])); + &mov (&DWP(0,@T[1]),$A); + &add ($D,&DWP(12,@T[1])); + &mov (&DWP(4,@T[1]),@T[0]); + &add ($E,&DWP(16,@T[1])); + &mov ($B,$C); + &mov (&DWP(8,@T[1]),$C); + &xor ($B,$D); + &mov (&DWP(12,@T[1]),$D); + &mov (&DWP(16,@T[1]),$E); + &mov (@T[1],@T[0]); + &and (@T[0],$B); + &mov ($B,@T[1]); + + &jmp (&label("loop")); + +&set_label("done",16); $j=$saved_j; @V=@saved_V; + + &Xtail_avx(\&body_20_39); + &Xtail_avx(\&body_20_39); + &Xtail_avx(\&body_20_39); + + &vzeroall(); + + &mov (@T[1],&DWP(192,"esp")); # update context + &add ($A,&DWP(0,@T[1])); + &mov ("esp",&DWP(192+12,"esp")); # restore %esp + &add (@T[0],&DWP(4,@T[1])); # $b + &add ($C,&DWP(8,@T[1])); + &mov (&DWP(0,@T[1]),$A); + &add ($D,&DWP(12,@T[1])); + &mov (&DWP(4,@T[1]),@T[0]); + &add ($E,&DWP(16,@T[1])); + &mov (&DWP(8,@T[1]),$C); + &mov (&DWP(12,@T[1]),$D); + &mov (&DWP(16,@T[1]),$E); +&function_end("_sha1_block_data_order_avx"); +} +&set_label("K_XX_XX",64); +&data_word(0x5a827999,0x5a827999,0x5a827999,0x5a827999); # K_00_19 +&data_word(0x6ed9eba1,0x6ed9eba1,0x6ed9eba1,0x6ed9eba1); # K_20_39 +&data_word(0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc); # K_40_59 +&data_word(0xca62c1d6,0xca62c1d6,0xca62c1d6,0xca62c1d6); # K_60_79 +&data_word(0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f); # pbswap mask +&data_byte(0xf,0xe,0xd,0xc,0xb,0xa,0x9,0x8,0x7,0x6,0x5,0x4,0x3,0x2,0x1,0x0); +} +&asciz("SHA1 block transform for x86, CRYPTOGAMS by "); + +&asm_finish(); diff --git a/TMessagesProj/jni/boringssl/crypto/sha/asm/sha1-armv4-large.pl b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha1-armv4-large.pl new file mode 100644 index 00000000..a20d3368 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha1-armv4-large.pl @@ -0,0 +1,701 @@ +#!/usr/bin/env perl + +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== + +# sha1_block procedure for ARMv4. +# +# January 2007. + +# Size/performance trade-off +# ==================================================================== +# impl size in bytes comp cycles[*] measured performance +# ==================================================================== +# thumb 304 3212 4420 +# armv4-small 392/+29% 1958/+64% 2250/+96% +# armv4-compact 740/+89% 1552/+26% 1840/+22% +# armv4-large 1420/+92% 1307/+19% 1370/+34%[***] +# full unroll ~5100/+260% ~1260/+4% ~1300/+5% +# ==================================================================== +# thumb = same as 'small' but in Thumb instructions[**] and +# with recurring code in two private functions; +# small = detached Xload/update, loops are folded; +# compact = detached Xload/update, 5x unroll; +# large = interleaved Xload/update, 5x unroll; +# full unroll = interleaved Xload/update, full unroll, estimated[!]; +# +# [*] Manually counted instructions in "grand" loop body. Measured +# performance is affected by prologue and epilogue overhead, +# i-cache availability, branch penalties, etc. +# [**] While each Thumb instruction is twice smaller, they are not as +# diverse as ARM ones: e.g., there are only two arithmetic +# instructions with 3 arguments, no [fixed] rotate, addressing +# modes are limited. As result it takes more instructions to do +# the same job in Thumb, therefore the code is never twice as +# small and always slower. +# [***] which is also ~35% better than compiler generated code. Dual- +# issue Cortex A8 core was measured to process input block in +# ~990 cycles. + +# August 2010. +# +# Rescheduling for dual-issue pipeline resulted in 13% improvement on +# Cortex A8 core and in absolute terms ~870 cycles per input block +# [or 13.6 cycles per byte]. + +# February 2011. +# +# Profiler-assisted and platform-specific optimization resulted in 10% +# improvement on Cortex A8 core and 12.2 cycles per byte. + +# September 2013. +# +# Add NEON implementation (see sha1-586.pl for background info). On +# Cortex A8 it was measured to process one byte in 6.7 cycles or >80% +# faster than integer-only code. Because [fully unrolled] NEON code +# is ~2.5x larger and there are some redundant instructions executed +# when processing last block, improvement is not as big for smallest +# blocks, only ~30%. Snapdragon S4 is a tad faster, 6.4 cycles per +# byte, which is also >80% faster than integer-only code. Cortex-A15 +# is even faster spending 5.6 cycles per byte outperforming integer- +# only code by factor of 2. + +# May 2014. +# +# Add ARMv8 code path performing at 2.35 cpb on Apple A7. + +$flavour = shift; +if ($flavour=~/^\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; } +else { while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {} } + +if ($flavour && $flavour ne "void") { + $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; + ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or + ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or + die "can't locate arm-xlate.pl"; + + open STDOUT,"| \"$^X\" $xlate $flavour $output"; +} else { + open STDOUT,">$output"; +} + +$ctx="r0"; +$inp="r1"; +$len="r2"; +$a="r3"; +$b="r4"; +$c="r5"; +$d="r6"; +$e="r7"; +$K="r8"; +$t0="r9"; +$t1="r10"; +$t2="r11"; +$t3="r12"; +$Xi="r14"; +@V=($a,$b,$c,$d,$e); + +sub Xupdate { +my ($a,$b,$c,$d,$e,$opt1,$opt2)=@_; +$code.=<<___; + ldr $t0,[$Xi,#15*4] + ldr $t1,[$Xi,#13*4] + ldr $t2,[$Xi,#7*4] + add $e,$K,$e,ror#2 @ E+=K_xx_xx + ldr $t3,[$Xi,#2*4] + eor $t0,$t0,$t1 + eor $t2,$t2,$t3 @ 1 cycle stall + eor $t1,$c,$d @ F_xx_xx + mov $t0,$t0,ror#31 + add $e,$e,$a,ror#27 @ E+=ROR(A,27) + eor $t0,$t0,$t2,ror#31 + str $t0,[$Xi,#-4]! + $opt1 @ F_xx_xx + $opt2 @ F_xx_xx + add $e,$e,$t0 @ E+=X[i] +___ +} + +sub BODY_00_15 { +my ($a,$b,$c,$d,$e)=@_; +$code.=<<___; +#if __ARM_ARCH__<7 + ldrb $t1,[$inp,#2] + ldrb $t0,[$inp,#3] + ldrb $t2,[$inp,#1] + add $e,$K,$e,ror#2 @ E+=K_00_19 + ldrb $t3,[$inp],#4 + orr $t0,$t0,$t1,lsl#8 + eor $t1,$c,$d @ F_xx_xx + orr $t0,$t0,$t2,lsl#16 + add $e,$e,$a,ror#27 @ E+=ROR(A,27) + orr $t0,$t0,$t3,lsl#24 +#else + ldr $t0,[$inp],#4 @ handles unaligned + add $e,$K,$e,ror#2 @ E+=K_00_19 + eor $t1,$c,$d @ F_xx_xx + add $e,$e,$a,ror#27 @ E+=ROR(A,27) +#ifdef __ARMEL__ + rev $t0,$t0 @ byte swap +#endif +#endif + and $t1,$b,$t1,ror#2 + add $e,$e,$t0 @ E+=X[i] + eor $t1,$t1,$d,ror#2 @ F_00_19(B,C,D) + str $t0,[$Xi,#-4]! + add $e,$e,$t1 @ E+=F_00_19(B,C,D) +___ +} + +sub BODY_16_19 { +my ($a,$b,$c,$d,$e)=@_; + &Xupdate(@_,"and $t1,$b,$t1,ror#2"); +$code.=<<___; + eor $t1,$t1,$d,ror#2 @ F_00_19(B,C,D) + add $e,$e,$t1 @ E+=F_00_19(B,C,D) +___ +} + +sub BODY_20_39 { +my ($a,$b,$c,$d,$e)=@_; + &Xupdate(@_,"eor $t1,$b,$t1,ror#2"); +$code.=<<___; + add $e,$e,$t1 @ E+=F_20_39(B,C,D) +___ +} + +sub BODY_40_59 { +my ($a,$b,$c,$d,$e)=@_; + &Xupdate(@_,"and $t1,$b,$t1,ror#2","and $t2,$c,$d"); +$code.=<<___; + add $e,$e,$t1 @ E+=F_40_59(B,C,D) + add $e,$e,$t2,ror#2 +___ +} + +$code=<<___; +#include "arm_arch.h" + +.text +.code 32 + +.global sha1_block_data_order +.type sha1_block_data_order,%function + +.align 5 +sha1_block_data_order: +#if __ARM_MAX_ARCH__>=7 + sub r3,pc,#8 @ sha1_block_data_order + ldr r12,.LOPENSSL_armcap + ldr r12,[r3,r12] @ OPENSSL_armcap_P +#ifdef __APPLE__ + ldr r12,[r12] +#endif + tst r12,#ARMV8_SHA1 + bne .LARMv8 + tst r12,#ARMV7_NEON + bne .LNEON +#endif + stmdb sp!,{r4-r12,lr} + add $len,$inp,$len,lsl#6 @ $len to point at the end of $inp + ldmia $ctx,{$a,$b,$c,$d,$e} +.Lloop: + ldr $K,.LK_00_19 + mov $Xi,sp + sub sp,sp,#15*4 + mov $c,$c,ror#30 + mov $d,$d,ror#30 + mov $e,$e,ror#30 @ [6] +.L_00_15: +___ +for($i=0;$i<5;$i++) { + &BODY_00_15(@V); unshift(@V,pop(@V)); +} +$code.=<<___; + teq $Xi,sp + bne .L_00_15 @ [((11+4)*5+2)*3] + sub sp,sp,#25*4 +___ + &BODY_00_15(@V); unshift(@V,pop(@V)); + &BODY_16_19(@V); unshift(@V,pop(@V)); + &BODY_16_19(@V); unshift(@V,pop(@V)); + &BODY_16_19(@V); unshift(@V,pop(@V)); + &BODY_16_19(@V); unshift(@V,pop(@V)); +$code.=<<___; + + ldr $K,.LK_20_39 @ [+15+16*4] + cmn sp,#0 @ [+3], clear carry to denote 20_39 +.L_20_39_or_60_79: +___ +for($i=0;$i<5;$i++) { + &BODY_20_39(@V); unshift(@V,pop(@V)); +} +$code.=<<___; + teq $Xi,sp @ preserve carry + bne .L_20_39_or_60_79 @ [+((12+3)*5+2)*4] + bcs .L_done @ [+((12+3)*5+2)*4], spare 300 bytes + + ldr $K,.LK_40_59 + sub sp,sp,#20*4 @ [+2] +.L_40_59: +___ +for($i=0;$i<5;$i++) { + &BODY_40_59(@V); unshift(@V,pop(@V)); +} +$code.=<<___; + teq $Xi,sp + bne .L_40_59 @ [+((12+5)*5+2)*4] + + ldr $K,.LK_60_79 + sub sp,sp,#20*4 + cmp sp,#0 @ set carry to denote 60_79 + b .L_20_39_or_60_79 @ [+4], spare 300 bytes +.L_done: + add sp,sp,#80*4 @ "deallocate" stack frame + ldmia $ctx,{$K,$t0,$t1,$t2,$t3} + add $a,$K,$a + add $b,$t0,$b + add $c,$t1,$c,ror#2 + add $d,$t2,$d,ror#2 + add $e,$t3,$e,ror#2 + stmia $ctx,{$a,$b,$c,$d,$e} + teq $inp,$len + bne .Lloop @ [+18], total 1307 + +#if __ARM_ARCH__>=5 + ldmia sp!,{r4-r12,pc} +#else + ldmia sp!,{r4-r12,lr} + tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet + bx lr @ interoperable with Thumb ISA:-) +#endif +.size sha1_block_data_order,.-sha1_block_data_order + +.align 5 +.LK_00_19: .word 0x5a827999 +.LK_20_39: .word 0x6ed9eba1 +.LK_40_59: .word 0x8f1bbcdc +.LK_60_79: .word 0xca62c1d6 +#if __ARM_MAX_ARCH__>=7 +.LOPENSSL_armcap: +.word OPENSSL_armcap_P-sha1_block_data_order +#endif +.asciz "SHA1 block transform for ARMv4/NEON/ARMv8, CRYPTOGAMS by " +.align 5 +___ +##################################################################### +# NEON stuff +# +{{{ +my @V=($a,$b,$c,$d,$e); +my ($K_XX_XX,$Ki,$t0,$t1,$Xfer,$saved_sp)=map("r$_",(8..12,14)); +my $Xi=4; +my @X=map("q$_",(8..11,0..3)); +my @Tx=("q12","q13"); +my ($K,$zero)=("q14","q15"); +my $j=0; + +sub AUTOLOAD() # thunk [simplified] x86-style perlasm +{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://; $opcode =~ s/_/\./; + my $arg = pop; + $arg = "#$arg" if ($arg*1 eq $arg); + $code .= "\t$opcode\t".join(',',@_,$arg)."\n"; +} + +sub body_00_19 () { + ( + '($a,$b,$c,$d,$e)=@V;'. # '$code.="@ $j\n";'. + '&bic ($t0,$d,$b)', + '&add ($e,$e,$Ki)', # e+=X[i]+K + '&and ($t1,$c,$b)', + '&ldr ($Ki,sprintf "[sp,#%d]",4*(($j+1)&15))', + '&add ($e,$e,$a,"ror#27")', # e+=ROR(A,27) + '&eor ($t1,$t1,$t0)', # F_00_19 + '&mov ($b,$b,"ror#2")', # b=ROR(b,2) + '&add ($e,$e,$t1);'. # e+=F_00_19 + '$j++; unshift(@V,pop(@V));' + ) +} +sub body_20_39 () { + ( + '($a,$b,$c,$d,$e)=@V;'. # '$code.="@ $j\n";'. + '&eor ($t0,$b,$d)', + '&add ($e,$e,$Ki)', # e+=X[i]+K + '&ldr ($Ki,sprintf "[sp,#%d]",4*(($j+1)&15)) if ($j<79)', + '&eor ($t1,$t0,$c)', # F_20_39 + '&add ($e,$e,$a,"ror#27")', # e+=ROR(A,27) + '&mov ($b,$b,"ror#2")', # b=ROR(b,2) + '&add ($e,$e,$t1);'. # e+=F_20_39 + '$j++; unshift(@V,pop(@V));' + ) +} +sub body_40_59 () { + ( + '($a,$b,$c,$d,$e)=@V;'. # '$code.="@ $j\n";'. + '&add ($e,$e,$Ki)', # e+=X[i]+K + '&and ($t0,$c,$d)', + '&ldr ($Ki,sprintf "[sp,#%d]",4*(($j+1)&15))', + '&add ($e,$e,$a,"ror#27")', # e+=ROR(A,27) + '&eor ($t1,$c,$d)', + '&add ($e,$e,$t0)', + '&and ($t1,$t1,$b)', + '&mov ($b,$b,"ror#2")', # b=ROR(b,2) + '&add ($e,$e,$t1);'. # e+=F_40_59 + '$j++; unshift(@V,pop(@V));' + ) +} + +sub Xupdate_16_31 () +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); + my ($a,$b,$c,$d,$e); + + &vext_8 (@X[0],@X[-4&7],@X[-3&7],8); # compose "X[-14]" in "X[0]" + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vadd_i32 (@Tx[1],@X[-1&7],$K); + eval(shift(@insns)); + &vld1_32 ("{$K\[]}","[$K_XX_XX,:32]!") if ($Xi%5==0); + eval(shift(@insns)); + &vext_8 (@Tx[0],@X[-1&7],$zero,4); # "X[-3]", 3 words + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &veor (@X[0],@X[0],@X[-4&7]); # "X[0]"^="X[-16]" + eval(shift(@insns)); + eval(shift(@insns)); + &veor (@Tx[0],@Tx[0],@X[-2&7]); # "X[-3]"^"X[-8]" + eval(shift(@insns)); + eval(shift(@insns)); + &veor (@Tx[0],@Tx[0],@X[0]); # "X[0]"^="X[-3]"^"X[-8] + eval(shift(@insns)); + eval(shift(@insns)); + &vst1_32 ("{@Tx[1]}","[$Xfer,:128]!"); # X[]+K xfer + &sub ($Xfer,$Xfer,64) if ($Xi%4==0); + eval(shift(@insns)); + eval(shift(@insns)); + &vext_8 (@Tx[1],$zero,@Tx[0],4); # "X[0]"<<96, extract one dword + eval(shift(@insns)); + eval(shift(@insns)); + &vadd_i32 (@X[0],@Tx[0],@Tx[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &vsri_32 (@X[0],@Tx[0],31); # "X[0]"<<<=1 + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vshr_u32 (@Tx[0],@Tx[1],30); + eval(shift(@insns)); + eval(shift(@insns)); + &vshl_u32 (@Tx[1],@Tx[1],2); + eval(shift(@insns)); + eval(shift(@insns)); + &veor (@X[0],@X[0],@Tx[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &veor (@X[0],@X[0],@Tx[1]); # "X[0]"^=("X[0]">>96)<<<2 + + foreach (@insns) { eval; } # remaining instructions [if any] + + $Xi++; push(@X,shift(@X)); # "rotate" X[] +} + +sub Xupdate_32_79 () +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); + my ($a,$b,$c,$d,$e); + + &vext_8 (@Tx[0],@X[-2&7],@X[-1&7],8); # compose "X[-6]" + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &veor (@X[0],@X[0],@X[-4&7]); # "X[0]"="X[-32]"^"X[-16]" + eval(shift(@insns)); + eval(shift(@insns)); + &veor (@X[0],@X[0],@X[-7&7]); # "X[0]"^="X[-28]" + eval(shift(@insns)); + eval(shift(@insns)); + &vadd_i32 (@Tx[1],@X[-1&7],$K); + eval(shift(@insns)); + &vld1_32 ("{$K\[]}","[$K_XX_XX,:32]!") if ($Xi%5==0); + eval(shift(@insns)); + &veor (@Tx[0],@Tx[0],@X[0]); # "X[-6]"^="X[0]" + eval(shift(@insns)); + eval(shift(@insns)); + &vshr_u32 (@X[0],@Tx[0],30); + eval(shift(@insns)); + eval(shift(@insns)); + &vst1_32 ("{@Tx[1]}","[$Xfer,:128]!"); # X[]+K xfer + &sub ($Xfer,$Xfer,64) if ($Xi%4==0); + eval(shift(@insns)); + eval(shift(@insns)); + &vsli_32 (@X[0],@Tx[0],2); # "X[0]"="X[-6]"<<<2 + + foreach (@insns) { eval; } # remaining instructions [if any] + + $Xi++; push(@X,shift(@X)); # "rotate" X[] +} + +sub Xuplast_80 () +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); + my ($a,$b,$c,$d,$e); + + &vadd_i32 (@Tx[1],@X[-1&7],$K); + eval(shift(@insns)); + eval(shift(@insns)); + &vst1_32 ("{@Tx[1]}","[$Xfer,:128]!"); + &sub ($Xfer,$Xfer,64); + + &teq ($inp,$len); + &sub ($K_XX_XX,$K_XX_XX,16); # rewind $K_XX_XX + &subeq ($inp,$inp,64); # reload last block to avoid SEGV + &vld1_8 ("{@X[-4&7]-@X[-3&7]}","[$inp]!"); + eval(shift(@insns)); + eval(shift(@insns)); + &vld1_8 ("{@X[-2&7]-@X[-1&7]}","[$inp]!"); + eval(shift(@insns)); + eval(shift(@insns)); + &vld1_32 ("{$K\[]}","[$K_XX_XX,:32]!"); # load K_00_19 + eval(shift(@insns)); + eval(shift(@insns)); + &vrev32_8 (@X[-4&7],@X[-4&7]); + + foreach (@insns) { eval; } # remaining instructions + + $Xi=0; +} + +sub Xloop() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); + my ($a,$b,$c,$d,$e); + + &vrev32_8 (@X[($Xi-3)&7],@X[($Xi-3)&7]); + eval(shift(@insns)); + eval(shift(@insns)); + &vadd_i32 (@X[$Xi&7],@X[($Xi-4)&7],$K); + eval(shift(@insns)); + eval(shift(@insns)); + &vst1_32 ("{@X[$Xi&7]}","[$Xfer,:128]!");# X[]+K xfer to IALU + + foreach (@insns) { eval; } + + $Xi++; +} + +$code.=<<___; +#if __ARM_MAX_ARCH__>=7 +.arch armv7-a +.fpu neon + +.type sha1_block_data_order_neon,%function +.align 4 +sha1_block_data_order_neon: +.LNEON: + stmdb sp!,{r4-r12,lr} + add $len,$inp,$len,lsl#6 @ $len to point at the end of $inp + @ dmb @ errata #451034 on early Cortex A8 + @ vstmdb sp!,{d8-d15} @ ABI specification says so + mov $saved_sp,sp + sub sp,sp,#64 @ alloca + adr $K_XX_XX,.LK_00_19 + bic sp,sp,#15 @ align for 128-bit stores + + ldmia $ctx,{$a,$b,$c,$d,$e} @ load context + mov $Xfer,sp + + vld1.8 {@X[-4&7]-@X[-3&7]},[$inp]! @ handles unaligned + veor $zero,$zero,$zero + vld1.8 {@X[-2&7]-@X[-1&7]},[$inp]! + vld1.32 {${K}\[]},[$K_XX_XX,:32]! @ load K_00_19 + vrev32.8 @X[-4&7],@X[-4&7] @ yes, even on + vrev32.8 @X[-3&7],@X[-3&7] @ big-endian... + vrev32.8 @X[-2&7],@X[-2&7] + vadd.i32 @X[0],@X[-4&7],$K + vrev32.8 @X[-1&7],@X[-1&7] + vadd.i32 @X[1],@X[-3&7],$K + vst1.32 {@X[0]},[$Xfer,:128]! + vadd.i32 @X[2],@X[-2&7],$K + vst1.32 {@X[1]},[$Xfer,:128]! + vst1.32 {@X[2]},[$Xfer,:128]! + ldr $Ki,[sp] @ big RAW stall + +.Loop_neon: +___ + &Xupdate_16_31(\&body_00_19); + &Xupdate_16_31(\&body_00_19); + &Xupdate_16_31(\&body_00_19); + &Xupdate_16_31(\&body_00_19); + &Xupdate_32_79(\&body_00_19); + &Xupdate_32_79(\&body_20_39); + &Xupdate_32_79(\&body_20_39); + &Xupdate_32_79(\&body_20_39); + &Xupdate_32_79(\&body_20_39); + &Xupdate_32_79(\&body_20_39); + &Xupdate_32_79(\&body_40_59); + &Xupdate_32_79(\&body_40_59); + &Xupdate_32_79(\&body_40_59); + &Xupdate_32_79(\&body_40_59); + &Xupdate_32_79(\&body_40_59); + &Xupdate_32_79(\&body_20_39); + &Xuplast_80(\&body_20_39); + &Xloop(\&body_20_39); + &Xloop(\&body_20_39); + &Xloop(\&body_20_39); +$code.=<<___; + ldmia $ctx,{$Ki,$t0,$t1,$Xfer} @ accumulate context + add $a,$a,$Ki + ldr $Ki,[$ctx,#16] + add $b,$b,$t0 + add $c,$c,$t1 + add $d,$d,$Xfer + moveq sp,$saved_sp + add $e,$e,$Ki + ldrne $Ki,[sp] + stmia $ctx,{$a,$b,$c,$d,$e} + addne $Xfer,sp,#3*16 + bne .Loop_neon + + @ vldmia sp!,{d8-d15} + ldmia sp!,{r4-r12,pc} +.size sha1_block_data_order_neon,.-sha1_block_data_order_neon +#endif +___ +}}} +##################################################################### +# ARMv8 stuff +# +{{{ +my ($ABCD,$E,$E0,$E1)=map("q$_",(0..3)); +my @MSG=map("q$_",(4..7)); +my @Kxx=map("q$_",(8..11)); +my ($W0,$W1,$ABCD_SAVE)=map("q$_",(12..14)); + +$code.=<<___; +#if __ARM_MAX_ARCH__>=7 +.type sha1_block_data_order_armv8,%function +.align 5 +sha1_block_data_order_armv8: +.LARMv8: + vstmdb sp!,{d8-d15} @ ABI specification says so + + veor $E,$E,$E + adr r3,.LK_00_19 + vld1.32 {$ABCD},[$ctx]! + vld1.32 {$E\[0]},[$ctx] + sub $ctx,$ctx,#16 + vld1.32 {@Kxx[0]\[]},[r3,:32]! + vld1.32 {@Kxx[1]\[]},[r3,:32]! + vld1.32 {@Kxx[2]\[]},[r3,:32]! + vld1.32 {@Kxx[3]\[]},[r3,:32] + +.Loop_v8: + vld1.8 {@MSG[0]-@MSG[1]},[$inp]! + vld1.8 {@MSG[2]-@MSG[3]},[$inp]! + vrev32.8 @MSG[0],@MSG[0] + vrev32.8 @MSG[1],@MSG[1] + + vadd.i32 $W0,@Kxx[0],@MSG[0] + vrev32.8 @MSG[2],@MSG[2] + vmov $ABCD_SAVE,$ABCD @ offload + subs $len,$len,#1 + + vadd.i32 $W1,@Kxx[0],@MSG[1] + vrev32.8 @MSG[3],@MSG[3] + sha1h $E1,$ABCD @ 0 + sha1c $ABCD,$E,$W0 + vadd.i32 $W0,@Kxx[$j],@MSG[2] + sha1su0 @MSG[0],@MSG[1],@MSG[2] +___ +for ($j=0,$i=1;$i<20-3;$i++) { +my $f=("c","p","m","p")[$i/5]; +$code.=<<___; + sha1h $E0,$ABCD @ $i + sha1$f $ABCD,$E1,$W1 + vadd.i32 $W1,@Kxx[$j],@MSG[3] + sha1su1 @MSG[0],@MSG[3] +___ +$code.=<<___ if ($i<20-4); + sha1su0 @MSG[1],@MSG[2],@MSG[3] +___ + ($E0,$E1)=($E1,$E0); ($W0,$W1)=($W1,$W0); + push(@MSG,shift(@MSG)); $j++ if ((($i+3)%5)==0); +} +$code.=<<___; + sha1h $E0,$ABCD @ $i + sha1p $ABCD,$E1,$W1 + vadd.i32 $W1,@Kxx[$j],@MSG[3] + + sha1h $E1,$ABCD @ 18 + sha1p $ABCD,$E0,$W0 + + sha1h $E0,$ABCD @ 19 + sha1p $ABCD,$E1,$W1 + + vadd.i32 $E,$E,$E0 + vadd.i32 $ABCD,$ABCD,$ABCD_SAVE + bne .Loop_v8 + + vst1.32 {$ABCD},[$ctx]! + vst1.32 {$E\[0]},[$ctx] + + vldmia sp!,{d8-d15} + ret @ bx lr +.size sha1_block_data_order_armv8,.-sha1_block_data_order_armv8 +#endif +___ +}}} +$code.=<<___; +#if __ARM_MAX_ARCH__>=7 +.comm OPENSSL_armcap_P,4,4 +.hidden OPENSSL_armcap_P +#endif +___ + +{ my %opcode = ( + "sha1c" => 0xf2000c40, "sha1p" => 0xf2100c40, + "sha1m" => 0xf2200c40, "sha1su0" => 0xf2300c40, + "sha1h" => 0xf3b902c0, "sha1su1" => 0xf3ba0380 ); + + sub unsha1 { + my ($mnemonic,$arg)=@_; + + if ($arg =~ m/q([0-9]+)(?:,\s*q([0-9]+))?,\s*q([0-9]+)/o) { + my $word = $opcode{$mnemonic}|(($1&7)<<13)|(($1&8)<<19) + |(($2&7)<<17)|(($2&8)<<4) + |(($3&7)<<1) |(($3&8)<<2); + # since ARMv7 instructions are always encoded little-endian. + # correct solution is to use .inst directive, but older + # assemblers don't implement it:-( + sprintf ".byte\t0x%02x,0x%02x,0x%02x,0x%02x\t@ %s %s", + $word&0xff,($word>>8)&0xff, + ($word>>16)&0xff,($word>>24)&0xff, + $mnemonic,$arg; + } + } +} + +foreach (split($/,$code)) { + s/{q([0-9]+)\[\]}/sprintf "{d%d[],d%d[]}",2*$1,2*$1+1/eo or + s/{q([0-9]+)\[0\]}/sprintf "{d%d[0]}",2*$1/eo; + + s/\b(sha1\w+)\s+(q.*)/unsha1($1,$2)/geo; + + s/\bret\b/bx lr/o or + s/\bbx\s+lr\b/.word\t0xe12fff1e/o; # make it possible to compile with -march=armv4 + + print $_,$/; +} + +close STDOUT; # enforce flush diff --git a/TMessagesProj/jni/boringssl/crypto/sha/asm/sha1-armv8.pl b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha1-armv8.pl new file mode 100644 index 00000000..a8c08c27 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha1-armv8.pl @@ -0,0 +1,347 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# SHA1 for ARMv8. +# +# Performance in cycles per processed byte and improvement coefficient +# over code generated with "default" compiler: +# +# hardware-assisted software(*) +# Apple A7 2.31 4.13 (+14%) +# Cortex-A53 2.24 8.03 (+97%) +# Cortex-A57 2.35 7.88 (+74%) +# Denver 2.13 3.97 (+0%)(**) +# X-Gene 8.80 (+200%) +# +# (*) Software results are presented mostly for reference purposes. +# (**) Keep in mind that Denver relies on binary translation, which +# optimizes compiler output at run-time. + +$flavour = shift; +$output = shift; + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or +die "can't locate arm-xlate.pl"; + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +($ctx,$inp,$num)=("x0","x1","x2"); +@Xw=map("w$_",(3..17,19)); +@Xx=map("x$_",(3..17,19)); +@V=($A,$B,$C,$D,$E)=map("w$_",(20..24)); +($t0,$t1,$t2,$K)=map("w$_",(25..28)); + + +sub BODY_00_19 { +my ($i,$a,$b,$c,$d,$e)=@_; +my $j=($i+2)&15; + +$code.=<<___ if ($i<15 && !($i&1)); + lsr @Xx[$i+1],@Xx[$i],#32 +___ +$code.=<<___ if ($i<14 && !($i&1)); + ldr @Xx[$i+2],[$inp,#`($i+2)*4-64`] +___ +$code.=<<___ if ($i<14 && ($i&1)); +#ifdef __ARMEB__ + ror @Xx[$i+1],@Xx[$i+1],#32 +#else + rev32 @Xx[$i+1],@Xx[$i+1] +#endif +___ +$code.=<<___ if ($i<14); + bic $t0,$d,$b + and $t1,$c,$b + ror $t2,$a,#27 + add $d,$d,$K // future e+=K + orr $t0,$t0,$t1 + add $e,$e,$t2 // e+=rot(a,5) + ror $b,$b,#2 + add $d,$d,@Xw[($i+1)&15] // future e+=X[i] + add $e,$e,$t0 // e+=F(b,c,d) +___ +$code.=<<___ if ($i==19); + movz $K,#0xeba1 + movk $K,#0x6ed9,lsl#16 +___ +$code.=<<___ if ($i>=14); + eor @Xw[$j],@Xw[$j],@Xw[($j+2)&15] + bic $t0,$d,$b + and $t1,$c,$b + ror $t2,$a,#27 + eor @Xw[$j],@Xw[$j],@Xw[($j+8)&15] + add $d,$d,$K // future e+=K + orr $t0,$t0,$t1 + add $e,$e,$t2 // e+=rot(a,5) + eor @Xw[$j],@Xw[$j],@Xw[($j+13)&15] + ror $b,$b,#2 + add $d,$d,@Xw[($i+1)&15] // future e+=X[i] + add $e,$e,$t0 // e+=F(b,c,d) + ror @Xw[$j],@Xw[$j],#31 +___ +} + +sub BODY_40_59 { +my ($i,$a,$b,$c,$d,$e)=@_; +my $j=($i+2)&15; + +$code.=<<___ if ($i==59); + movz $K,#0xc1d6 + movk $K,#0xca62,lsl#16 +___ +$code.=<<___; + orr $t0,$b,$c + and $t1,$b,$c + eor @Xw[$j],@Xw[$j],@Xw[($j+2)&15] + ror $t2,$a,#27 + and $t0,$t0,$d + add $d,$d,$K // future e+=K + eor @Xw[$j],@Xw[$j],@Xw[($j+8)&15] + add $e,$e,$t2 // e+=rot(a,5) + orr $t0,$t0,$t1 + ror $b,$b,#2 + eor @Xw[$j],@Xw[$j],@Xw[($j+13)&15] + add $d,$d,@Xw[($i+1)&15] // future e+=X[i] + add $e,$e,$t0 // e+=F(b,c,d) + ror @Xw[$j],@Xw[$j],#31 +___ +} + +sub BODY_20_39 { +my ($i,$a,$b,$c,$d,$e)=@_; +my $j=($i+2)&15; + +$code.=<<___ if ($i==39); + movz $K,#0xbcdc + movk $K,#0x8f1b,lsl#16 +___ +$code.=<<___ if ($i<78); + eor @Xw[$j],@Xw[$j],@Xw[($j+2)&15] + eor $t0,$d,$b + ror $t2,$a,#27 + add $d,$d,$K // future e+=K + eor @Xw[$j],@Xw[$j],@Xw[($j+8)&15] + eor $t0,$t0,$c + add $e,$e,$t2 // e+=rot(a,5) + ror $b,$b,#2 + eor @Xw[$j],@Xw[$j],@Xw[($j+13)&15] + add $d,$d,@Xw[($i+1)&15] // future e+=X[i] + add $e,$e,$t0 // e+=F(b,c,d) + ror @Xw[$j],@Xw[$j],#31 +___ +$code.=<<___ if ($i==78); + ldp @Xw[1],@Xw[2],[$ctx] + eor $t0,$d,$b + ror $t2,$a,#27 + add $d,$d,$K // future e+=K + eor $t0,$t0,$c + add $e,$e,$t2 // e+=rot(a,5) + ror $b,$b,#2 + add $d,$d,@Xw[($i+1)&15] // future e+=X[i] + add $e,$e,$t0 // e+=F(b,c,d) +___ +$code.=<<___ if ($i==79); + ldp @Xw[3],@Xw[4],[$ctx,#8] + eor $t0,$d,$b + ror $t2,$a,#27 + eor $t0,$t0,$c + add $e,$e,$t2 // e+=rot(a,5) + ror $b,$b,#2 + ldr @Xw[5],[$ctx,#16] + add $e,$e,$t0 // e+=F(b,c,d) +___ +} + +$code.=<<___; +#include "arm_arch.h" + +.text + +.extern OPENSSL_armcap_P +.globl sha1_block_data_order +.type sha1_block_data_order,%function +.align 6 +sha1_block_data_order: + ldr x16,.LOPENSSL_armcap_P + adr x17,.LOPENSSL_armcap_P + add x16,x16,x17 + ldr w16,[x16] + tst w16,#ARMV8_SHA1 + b.ne .Lv8_entry + + stp x29,x30,[sp,#-96]! + add x29,sp,#0 + stp x19,x20,[sp,#16] + stp x21,x22,[sp,#32] + stp x23,x24,[sp,#48] + stp x25,x26,[sp,#64] + stp x27,x28,[sp,#80] + + ldp $A,$B,[$ctx] + ldp $C,$D,[$ctx,#8] + ldr $E,[$ctx,#16] + +.Loop: + ldr @Xx[0],[$inp],#64 + movz $K,#0x7999 + sub $num,$num,#1 + movk $K,#0x5a82,lsl#16 +#ifdef __ARMEB__ + ror $Xx[0],@Xx[0],#32 +#else + rev32 @Xx[0],@Xx[0] +#endif + add $E,$E,$K // warm it up + add $E,$E,@Xw[0] +___ +for($i=0;$i<20;$i++) { &BODY_00_19($i,@V); unshift(@V,pop(@V)); } +for(;$i<40;$i++) { &BODY_20_39($i,@V); unshift(@V,pop(@V)); } +for(;$i<60;$i++) { &BODY_40_59($i,@V); unshift(@V,pop(@V)); } +for(;$i<80;$i++) { &BODY_20_39($i,@V); unshift(@V,pop(@V)); } +$code.=<<___; + add $B,$B,@Xw[2] + add $C,$C,@Xw[3] + add $A,$A,@Xw[1] + add $D,$D,@Xw[4] + add $E,$E,@Xw[5] + stp $A,$B,[$ctx] + stp $C,$D,[$ctx,#8] + str $E,[$ctx,#16] + cbnz $num,.Loop + + ldp x19,x20,[sp,#16] + ldp x21,x22,[sp,#32] + ldp x23,x24,[sp,#48] + ldp x25,x26,[sp,#64] + ldp x27,x28,[sp,#80] + ldr x29,[sp],#96 + ret +.size sha1_block_data_order,.-sha1_block_data_order +___ +{{{ +my ($ABCD,$E,$E0,$E1)=map("v$_.16b",(0..3)); +my @MSG=map("v$_.16b",(4..7)); +my @Kxx=map("v$_.4s",(16..19)); +my ($W0,$W1)=("v20.4s","v21.4s"); +my $ABCD_SAVE="v22.16b"; + +$code.=<<___; +.type sha1_block_armv8,%function +.align 6 +sha1_block_armv8: +.Lv8_entry: + stp x29,x30,[sp,#-16]! + add x29,sp,#0 + + adr x4,.Lconst + eor $E,$E,$E + ld1.32 {$ABCD},[$ctx],#16 + ld1.32 {$E}[0],[$ctx] + sub $ctx,$ctx,#16 + ld1.32 {@Kxx[0]-@Kxx[3]},[x4] + +.Loop_hw: + ld1 {@MSG[0]-@MSG[3]},[$inp],#64 + sub $num,$num,#1 + rev32 @MSG[0],@MSG[0] + rev32 @MSG[1],@MSG[1] + + add.i32 $W0,@Kxx[0],@MSG[0] + rev32 @MSG[2],@MSG[2] + orr $ABCD_SAVE,$ABCD,$ABCD // offload + + add.i32 $W1,@Kxx[0],@MSG[1] + rev32 @MSG[3],@MSG[3] + sha1h $E1,$ABCD + sha1c $ABCD,$E,$W0 // 0 + add.i32 $W0,@Kxx[$j],@MSG[2] + sha1su0 @MSG[0],@MSG[1],@MSG[2] +___ +for ($j=0,$i=1;$i<20-3;$i++) { +my $f=("c","p","m","p")[$i/5]; +$code.=<<___; + sha1h $E0,$ABCD // $i + sha1$f $ABCD,$E1,$W1 + add.i32 $W1,@Kxx[$j],@MSG[3] + sha1su1 @MSG[0],@MSG[3] +___ +$code.=<<___ if ($i<20-4); + sha1su0 @MSG[1],@MSG[2],@MSG[3] +___ + ($E0,$E1)=($E1,$E0); ($W0,$W1)=($W1,$W0); + push(@MSG,shift(@MSG)); $j++ if ((($i+3)%5)==0); +} +$code.=<<___; + sha1h $E0,$ABCD // $i + sha1p $ABCD,$E1,$W1 + add.i32 $W1,@Kxx[$j],@MSG[3] + + sha1h $E1,$ABCD // 18 + sha1p $ABCD,$E0,$W0 + + sha1h $E0,$ABCD // 19 + sha1p $ABCD,$E1,$W1 + + add.i32 $E,$E,$E0 + add.i32 $ABCD,$ABCD,$ABCD_SAVE + + cbnz $num,.Loop_hw + + st1.32 {$ABCD},[$ctx],#16 + st1.32 {$E}[0],[$ctx] + + ldr x29,[sp],#16 + ret +.size sha1_block_armv8,.-sha1_block_armv8 +.align 6 +.Lconst: +.long 0x5a827999,0x5a827999,0x5a827999,0x5a827999 //K_00_19 +.long 0x6ed9eba1,0x6ed9eba1,0x6ed9eba1,0x6ed9eba1 //K_20_39 +.long 0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc //K_40_59 +.long 0xca62c1d6,0xca62c1d6,0xca62c1d6,0xca62c1d6 //K_60_79 +.LOPENSSL_armcap_P: +.quad OPENSSL_armcap_P-. +.asciz "SHA1 block transform for ARMv8, CRYPTOGAMS by " +.align 2 +.comm OPENSSL_armcap_P,4,4 +___ +}}} + +{ my %opcode = ( + "sha1c" => 0x5e000000, "sha1p" => 0x5e001000, + "sha1m" => 0x5e002000, "sha1su0" => 0x5e003000, + "sha1h" => 0x5e280800, "sha1su1" => 0x5e281800 ); + + sub unsha1 { + my ($mnemonic,$arg)=@_; + + $arg =~ m/[qv]([0-9]+)[^,]*,\s*[qv]([0-9]+)[^,]*(?:,\s*[qv]([0-9]+))?/o + && + sprintf ".inst\t0x%08x\t//%s %s", + $opcode{$mnemonic}|$1|($2<<5)|($3<<16), + $mnemonic,$arg; + } +} + +foreach(split("\n",$code)) { + + s/\`([^\`]*)\`/eval($1)/geo; + + s/\b(sha1\w+)\s+([qv].*)/unsha1($1,$2)/geo; + + s/\.\w?32\b//o and s/\.16b/\.4s/go; + m/(ld|st)1[^\[]+\[0\]/o and s/\.4s/\.s/go; + + print $_,"\n"; +} + +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/sha/asm/sha1-x86_64.pl b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha1-x86_64.pl new file mode 100644 index 00000000..124034dc --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha1-x86_64.pl @@ -0,0 +1,2067 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# sha1_block procedure for x86_64. +# +# It was brought to my attention that on EM64T compiler-generated code +# was far behind 32-bit assembler implementation. This is unlike on +# Opteron where compiler-generated code was only 15% behind 32-bit +# assembler, which originally made it hard to motivate the effort. +# There was suggestion to mechanically translate 32-bit code, but I +# dismissed it, reasoning that x86_64 offers enough register bank +# capacity to fully utilize SHA-1 parallelism. Therefore this fresh +# implementation:-) However! While 64-bit code does perform better +# on Opteron, I failed to beat 32-bit assembler on EM64T core. Well, +# x86_64 does offer larger *addressable* bank, but out-of-order core +# reaches for even more registers through dynamic aliasing, and EM64T +# core must have managed to run-time optimize even 32-bit code just as +# good as 64-bit one. Performance improvement is summarized in the +# following table: +# +# gcc 3.4 32-bit asm cycles/byte +# Opteron +45% +20% 6.8 +# Xeon P4 +65% +0% 9.9 +# Core2 +60% +10% 7.0 + +# August 2009. +# +# The code was revised to minimize code size and to maximize +# "distance" between instructions producing input to 'lea' +# instruction and the 'lea' instruction itself, which is essential +# for Intel Atom core. + +# October 2010. +# +# Add SSSE3, Supplemental[!] SSE3, implementation. The idea behind it +# is to offload message schedule denoted by Wt in NIST specification, +# or Xupdate in OpenSSL source, to SIMD unit. See sha1-586.pl module +# for background and implementation details. The only difference from +# 32-bit code is that 64-bit code doesn't have to spill @X[] elements +# to free temporary registers. + +# April 2011. +# +# Add AVX code path. See sha1-586.pl for further information. + +# May 2013. +# +# Add AVX2+BMI code path. Initial attempt (utilizing BMI instructions +# and loading pair of consecutive blocks to 256-bit %ymm registers) +# did not provide impressive performance improvement till a crucial +# hint regarding the number of Xupdate iterations to pre-compute in +# advance was provided by Ilya Albrekht of Intel Corp. + +# March 2014. +# +# Add support for Intel SHA Extensions. + +###################################################################### +# Current performance is summarized in following table. Numbers are +# CPU clock cycles spent to process single byte (less is better). +# +# x86_64 SSSE3 AVX[2] +# P4 9.05 - +# Opteron 6.26 - +# Core2 6.55 6.05/+8% - +# Westmere 6.73 5.30/+27% - +# Sandy Bridge 7.70 6.10/+26% 4.99/+54% +# Ivy Bridge 6.06 4.67/+30% 4.60/+32% +# Haswell 5.45 4.15/+31% 3.57/+53% +# Bulldozer 9.11 5.95/+53% +# VIA Nano 9.32 7.15/+30% +# Atom 10.3 9.17/+12% +# Silvermont 13.1(*) 9.37/+40% +# +# (*) obviously suboptimal result, nothing was done about it, +# because SSSE3 code is compiled unconditionally; + +$flavour = shift; +$output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or +die "can't locate x86_64-xlate.pl"; + +if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1` + =~ /GNU assembler version ([2-9]\.[0-9]+)/) { + $avx = ($1>=2.19) + ($1>=2.22); +} + +if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) && + `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) { + $avx = ($1>=2.09) + ($1>=2.10); +} + +if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) && + `ml64 2>&1` =~ /Version ([0-9]+)\./) { + $avx = ($1>=10) + ($1>=11); +} + +if (!$avx && `$ENV{CC} -v 2>&1` =~ /(^clang version|based on LLVM) ([2-9]\.[0-9]+)/) { + $avx = ($2>=3.0) + ($2>3.0); +} + +$shaext=0; ### set to zero if compiling for 1.0.1 +$avx=1 if (!$shaext && $avx); + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +$ctx="%rdi"; # 1st arg +$inp="%rsi"; # 2nd arg +$num="%rdx"; # 3rd arg + +# reassign arguments in order to produce more compact code +$ctx="%r8"; +$inp="%r9"; +$num="%r10"; + +$t0="%eax"; +$t1="%ebx"; +$t2="%ecx"; +@xi=("%edx","%ebp","%r14d"); +$A="%esi"; +$B="%edi"; +$C="%r11d"; +$D="%r12d"; +$E="%r13d"; + +@V=($A,$B,$C,$D,$E); + +sub BODY_00_19 { +my ($i,$a,$b,$c,$d,$e)=@_; +my $j=$i+1; +$code.=<<___ if ($i==0); + mov `4*$i`($inp),$xi[0] + bswap $xi[0] +___ +$code.=<<___ if ($i<15); + mov `4*$j`($inp),$xi[1] + mov $d,$t0 + mov $xi[0],`4*$i`(%rsp) + mov $a,$t2 + bswap $xi[1] + xor $c,$t0 + rol \$5,$t2 + and $b,$t0 + lea 0x5a827999($xi[0],$e),$e + add $t2,$e + xor $d,$t0 + rol \$30,$b + add $t0,$e +___ +$code.=<<___ if ($i>=15); + xor `4*($j%16)`(%rsp),$xi[1] + mov $d,$t0 + mov $xi[0],`4*($i%16)`(%rsp) + mov $a,$t2 + xor `4*(($j+2)%16)`(%rsp),$xi[1] + xor $c,$t0 + rol \$5,$t2 + xor `4*(($j+8)%16)`(%rsp),$xi[1] + and $b,$t0 + lea 0x5a827999($xi[0],$e),$e + rol \$30,$b + xor $d,$t0 + add $t2,$e + rol \$1,$xi[1] + add $t0,$e +___ +push(@xi,shift(@xi)); +} + +sub BODY_20_39 { +my ($i,$a,$b,$c,$d,$e)=@_; +my $j=$i+1; +my $K=($i<40)?0x6ed9eba1:0xca62c1d6; +$code.=<<___ if ($i<79); + xor `4*($j%16)`(%rsp),$xi[1] + mov $b,$t0 + `"mov $xi[0],".4*($i%16)."(%rsp)" if ($i<72)` + mov $a,$t2 + xor `4*(($j+2)%16)`(%rsp),$xi[1] + xor $d,$t0 + rol \$5,$t2 + xor `4*(($j+8)%16)`(%rsp),$xi[1] + lea $K($xi[0],$e),$e + xor $c,$t0 + add $t2,$e + rol \$30,$b + add $t0,$e + rol \$1,$xi[1] +___ +$code.=<<___ if ($i==79); + mov $b,$t0 + mov $a,$t2 + xor $d,$t0 + lea $K($xi[0],$e),$e + rol \$5,$t2 + xor $c,$t0 + add $t2,$e + rol \$30,$b + add $t0,$e +___ +push(@xi,shift(@xi)); +} + +sub BODY_40_59 { +my ($i,$a,$b,$c,$d,$e)=@_; +my $j=$i+1; +$code.=<<___; + xor `4*($j%16)`(%rsp),$xi[1] + mov $d,$t0 + mov $xi[0],`4*($i%16)`(%rsp) + mov $d,$t1 + xor `4*(($j+2)%16)`(%rsp),$xi[1] + and $c,$t0 + mov $a,$t2 + xor `4*(($j+8)%16)`(%rsp),$xi[1] + lea 0x8f1bbcdc($xi[0],$e),$e + xor $c,$t1 + rol \$5,$t2 + add $t0,$e + rol \$1,$xi[1] + and $b,$t1 + add $t2,$e + rol \$30,$b + add $t1,$e +___ +push(@xi,shift(@xi)); +} + +$code.=<<___; +.text +.extern OPENSSL_ia32cap_P + +.globl sha1_block_data_order +.type sha1_block_data_order,\@function,3 +.align 16 +sha1_block_data_order: + mov OPENSSL_ia32cap_P+0(%rip),%r9d + mov OPENSSL_ia32cap_P+4(%rip),%r8d + mov OPENSSL_ia32cap_P+8(%rip),%r10d + test \$`1<<9`,%r8d # check SSSE3 bit + jz .Lialu +___ +$code.=<<___ if ($shaext); + test \$`1<<29`,%r10d # check SHA bit + jnz _shaext_shortcut +___ +$code.=<<___ if ($avx>1); + and \$`1<<3|1<<5|1<<8`,%r10d # check AVX2+BMI1+BMI2 + cmp \$`1<<3|1<<5|1<<8`,%r10d + je _avx2_shortcut +___ +$code.=<<___ if ($avx); + and \$`1<<28`,%r8d # mask AVX bit + and \$`1<<30`,%r9d # mask "Intel CPU" bit + or %r9d,%r8d + cmp \$`1<<28|1<<30`,%r8d + je _avx_shortcut +___ +$code.=<<___; + jmp _ssse3_shortcut + +.align 16 +.Lialu: + mov %rsp,%rax + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + mov %rdi,$ctx # reassigned argument + sub \$`8+16*4`,%rsp + mov %rsi,$inp # reassigned argument + and \$-64,%rsp + mov %rdx,$num # reassigned argument + mov %rax,`16*4`(%rsp) +.Lprologue: + + mov 0($ctx),$A + mov 4($ctx),$B + mov 8($ctx),$C + mov 12($ctx),$D + mov 16($ctx),$E + jmp .Lloop + +.align 16 +.Lloop: +___ +for($i=0;$i<20;$i++) { &BODY_00_19($i,@V); unshift(@V,pop(@V)); } +for(;$i<40;$i++) { &BODY_20_39($i,@V); unshift(@V,pop(@V)); } +for(;$i<60;$i++) { &BODY_40_59($i,@V); unshift(@V,pop(@V)); } +for(;$i<80;$i++) { &BODY_20_39($i,@V); unshift(@V,pop(@V)); } +$code.=<<___; + add 0($ctx),$A + add 4($ctx),$B + add 8($ctx),$C + add 12($ctx),$D + add 16($ctx),$E + mov $A,0($ctx) + mov $B,4($ctx) + mov $C,8($ctx) + mov $D,12($ctx) + mov $E,16($ctx) + + sub \$1,$num + lea `16*4`($inp),$inp + jnz .Lloop + + mov `16*4`(%rsp),%rsi + mov -40(%rsi),%r14 + mov -32(%rsi),%r13 + mov -24(%rsi),%r12 + mov -16(%rsi),%rbp + mov -8(%rsi),%rbx + lea (%rsi),%rsp +.Lepilogue: + ret +.size sha1_block_data_order,.-sha1_block_data_order +___ +if ($shaext) {{{ +###################################################################### +# Intel SHA Extensions implementation of SHA1 update function. +# +my ($ctx,$inp,$num)=("%rdi","%rsi","%rdx"); +my ($ABCD,$E,$E_,$BSWAP,$ABCD_SAVE,$E_SAVE)=map("%xmm$_",(0..3,8,9)); +my @MSG=map("%xmm$_",(4..7)); + +$code.=<<___; +.type sha1_block_data_order_shaext,\@function,3 +.align 32 +sha1_block_data_order_shaext: +_shaext_shortcut: +___ +$code.=<<___ if ($win64); + lea `-8-4*16`(%rsp),%rsp + movaps %xmm6,-8-4*16(%rax) + movaps %xmm7,-8-3*16(%rax) + movaps %xmm8,-8-2*16(%rax) + movaps %xmm9,-8-1*16(%rax) +.Lprologue_shaext: +___ +$code.=<<___; + movdqu ($ctx),$ABCD + movd 16($ctx),$E + movdqa K_XX_XX+0xa0(%rip),$BSWAP # byte-n-word swap + + movdqu ($inp),@MSG[0] + pshufd \$0b00011011,$ABCD,$ABCD # flip word order + movdqu 0x10($inp),@MSG[1] + pshufd \$0b00011011,$E,$E # flip word order + movdqu 0x20($inp),@MSG[2] + pshufb $BSWAP,@MSG[0] + movdqu 0x30($inp),@MSG[3] + pshufb $BSWAP,@MSG[1] + pshufb $BSWAP,@MSG[2] + movdqa $E,$E_SAVE # offload $E + pshufb $BSWAP,@MSG[3] + jmp .Loop_shaext + +.align 16 +.Loop_shaext: + dec $num + lea 0x40($inp),%rax # next input block + paddd @MSG[0],$E + cmovne %rax,$inp + movdqa $ABCD,$ABCD_SAVE # offload $ABCD +___ +for($i=0;$i<20-4;$i+=2) { +$code.=<<___; + sha1msg1 @MSG[1],@MSG[0] + movdqa $ABCD,$E_ + sha1rnds4 \$`int($i/5)`,$E,$ABCD # 0-3... + sha1nexte @MSG[1],$E_ + pxor @MSG[2],@MSG[0] + sha1msg1 @MSG[2],@MSG[1] + sha1msg2 @MSG[3],@MSG[0] + + movdqa $ABCD,$E + sha1rnds4 \$`int(($i+1)/5)`,$E_,$ABCD + sha1nexte @MSG[2],$E + pxor @MSG[3],@MSG[1] + sha1msg2 @MSG[0],@MSG[1] +___ + push(@MSG,shift(@MSG)); push(@MSG,shift(@MSG)); +} +$code.=<<___; + movdqu ($inp),@MSG[0] + movdqa $ABCD,$E_ + sha1rnds4 \$3,$E,$ABCD # 64-67 + sha1nexte @MSG[1],$E_ + movdqu 0x10($inp),@MSG[1] + pshufb $BSWAP,@MSG[0] + + movdqa $ABCD,$E + sha1rnds4 \$3,$E_,$ABCD # 68-71 + sha1nexte @MSG[2],$E + movdqu 0x20($inp),@MSG[2] + pshufb $BSWAP,@MSG[1] + + movdqa $ABCD,$E_ + sha1rnds4 \$3,$E,$ABCD # 72-75 + sha1nexte @MSG[3],$E_ + movdqu 0x30($inp),@MSG[3] + pshufb $BSWAP,@MSG[2] + + movdqa $ABCD,$E + sha1rnds4 \$3,$E_,$ABCD # 76-79 + sha1nexte $E_SAVE,$E + pshufb $BSWAP,@MSG[3] + + paddd $ABCD_SAVE,$ABCD + movdqa $E,$E_SAVE # offload $E + + jnz .Loop_shaext + + pshufd \$0b00011011,$ABCD,$ABCD + pshufd \$0b00011011,$E,$E + movdqu $ABCD,($ctx) + movd $E,16($ctx) +___ +$code.=<<___ if ($win64); + movaps -8-4*16(%rax),%xmm6 + movaps -8-3*16(%rax),%xmm7 + movaps -8-2*16(%rax),%xmm8 + movaps -8-1*16(%rax),%xmm9 + mov %rax,%rsp +.Lepilogue_shaext: +___ +$code.=<<___; + ret +.size sha1_block_data_order_shaext,.-sha1_block_data_order_shaext +___ +}}} +{{{ +my $Xi=4; +my @X=map("%xmm$_",(4..7,0..3)); +my @Tx=map("%xmm$_",(8..10)); +my $Kx="%xmm11"; +my @V=($A,$B,$C,$D,$E)=("%eax","%ebx","%ecx","%edx","%ebp"); # size optimization +my @T=("%esi","%edi"); +my $j=0; +my $rx=0; +my $K_XX_XX="%r11"; + +my $_rol=sub { &rol(@_) }; +my $_ror=sub { &ror(@_) }; + +{ my $sn; +sub align32() { + ++$sn; +$code.=<<___; + jmp .Lalign32_$sn # see "Decoded ICache" in manual +.align 32 +.Lalign32_$sn: +___ +} +} + +$code.=<<___; +.type sha1_block_data_order_ssse3,\@function,3 +.align 16 +sha1_block_data_order_ssse3: +_ssse3_shortcut: + mov %rsp,%rax + push %rbx + push %rbp + push %r12 + push %r13 # redundant, done to share Win64 SE handler + push %r14 + lea `-64-($win64?6*16:0)`(%rsp),%rsp +___ +$code.=<<___ if ($win64); + movaps %xmm6,-40-6*16(%rax) + movaps %xmm7,-40-5*16(%rax) + movaps %xmm8,-40-4*16(%rax) + movaps %xmm9,-40-3*16(%rax) + movaps %xmm10,-40-2*16(%rax) + movaps %xmm11,-40-1*16(%rax) +.Lprologue_ssse3: +___ +$code.=<<___; + mov %rax,%r14 # original %rsp + and \$-64,%rsp + mov %rdi,$ctx # reassigned argument + mov %rsi,$inp # reassigned argument + mov %rdx,$num # reassigned argument + + shl \$6,$num + add $inp,$num + lea K_XX_XX+64(%rip),$K_XX_XX + + mov 0($ctx),$A # load context + mov 4($ctx),$B + mov 8($ctx),$C + mov 12($ctx),$D + mov $B,@T[0] # magic seed + mov 16($ctx),$E + mov $C,@T[1] + xor $D,@T[1] + and @T[1],@T[0] + + movdqa 64($K_XX_XX),@X[2] # pbswap mask + movdqa -64($K_XX_XX),@Tx[1] # K_00_19 + movdqu 0($inp),@X[-4&7] # load input to %xmm[0-3] + movdqu 16($inp),@X[-3&7] + movdqu 32($inp),@X[-2&7] + movdqu 48($inp),@X[-1&7] + pshufb @X[2],@X[-4&7] # byte swap + pshufb @X[2],@X[-3&7] + pshufb @X[2],@X[-2&7] + add \$64,$inp + paddd @Tx[1],@X[-4&7] # add K_00_19 + pshufb @X[2],@X[-1&7] + paddd @Tx[1],@X[-3&7] + paddd @Tx[1],@X[-2&7] + movdqa @X[-4&7],0(%rsp) # X[]+K xfer to IALU + psubd @Tx[1],@X[-4&7] # restore X[] + movdqa @X[-3&7],16(%rsp) + psubd @Tx[1],@X[-3&7] + movdqa @X[-2&7],32(%rsp) + psubd @Tx[1],@X[-2&7] + jmp .Loop_ssse3 +___ + +sub AUTOLOAD() # thunk [simplified] 32-bit style perlasm +{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://; + my $arg = pop; + $arg = "\$$arg" if ($arg*1 eq $arg); + $code .= "\t$opcode\t".join(',',$arg,reverse @_)."\n"; +} + +sub Xupdate_ssse3_16_31() # recall that $Xi starts wtih 4 +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 40 instructions + my ($a,$b,$c,$d,$e); + + eval(shift(@insns)); # ror + &pshufd (@X[0],@X[-4&7],0xee); # was &movdqa (@X[0],@X[-3&7]); + eval(shift(@insns)); + &movdqa (@Tx[0],@X[-1&7]); + &paddd (@Tx[1],@X[-1&7]); + eval(shift(@insns)); + eval(shift(@insns)); + + &punpcklqdq(@X[0],@X[-3&7]); # compose "X[-14]" in "X[0]", was &palignr(@X[0],@X[-4&7],8); + eval(shift(@insns)); + eval(shift(@insns)); # rol + eval(shift(@insns)); + &psrldq (@Tx[0],4); # "X[-3]", 3 dwords + eval(shift(@insns)); + eval(shift(@insns)); + + &pxor (@X[0],@X[-4&7]); # "X[0]"^="X[-16]" + eval(shift(@insns)); + eval(shift(@insns)); # ror + &pxor (@Tx[0],@X[-2&7]); # "X[-3]"^"X[-8]" + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &pxor (@X[0],@Tx[0]); # "X[0]"^="X[-3]"^"X[-8]" + eval(shift(@insns)); + eval(shift(@insns)); # rol + &movdqa (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer to IALU + eval(shift(@insns)); + eval(shift(@insns)); + + &movdqa (@Tx[2],@X[0]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # ror + &movdqa (@Tx[0],@X[0]); + eval(shift(@insns)); + + &pslldq (@Tx[2],12); # "X[0]"<<96, extract one dword + &paddd (@X[0],@X[0]); + eval(shift(@insns)); + eval(shift(@insns)); + + &psrld (@Tx[0],31); + eval(shift(@insns)); + eval(shift(@insns)); # rol + eval(shift(@insns)); + &movdqa (@Tx[1],@Tx[2]); + eval(shift(@insns)); + eval(shift(@insns)); + + &psrld (@Tx[2],30); + eval(shift(@insns)); + eval(shift(@insns)); # ror + &por (@X[0],@Tx[0]); # "X[0]"<<<=1 + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &pslld (@Tx[1],2); + &pxor (@X[0],@Tx[2]); + eval(shift(@insns)); + &movdqa (@Tx[2],eval(2*16*(($Xi)/5)-64)."($K_XX_XX)"); # K_XX_XX + eval(shift(@insns)); # rol + eval(shift(@insns)); + eval(shift(@insns)); + + &pxor (@X[0],@Tx[1]); # "X[0]"^=("X[0]">>96)<<<2 + &pshufd (@Tx[1],@X[-1&7],0xee) if ($Xi==7); # was &movdqa (@Tx[0],@X[-1&7]) in Xupdate_ssse3_32_79 + + foreach (@insns) { eval; } # remaining instructions [if any] + + $Xi++; push(@X,shift(@X)); # "rotate" X[] + push(@Tx,shift(@Tx)); +} + +sub Xupdate_ssse3_32_79() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 to 44 instructions + my ($a,$b,$c,$d,$e); + + eval(shift(@insns)) if ($Xi==8); + &pxor (@X[0],@X[-4&7]); # "X[0]"="X[-32]"^"X[-16]" + eval(shift(@insns)) if ($Xi==8); + eval(shift(@insns)); # body_20_39 + eval(shift(@insns)); + eval(shift(@insns)) if (@insns[1] =~ /_ror/); + eval(shift(@insns)) if (@insns[0] =~ /_ror/); + &punpcklqdq(@Tx[0],@X[-1&7]); # compose "X[-6]", was &palignr(@Tx[0],@X[-2&7],8); + eval(shift(@insns)); + eval(shift(@insns)); # rol + + &pxor (@X[0],@X[-7&7]); # "X[0]"^="X[-28]" + eval(shift(@insns)); + eval(shift(@insns)); + if ($Xi%5) { + &movdqa (@Tx[2],@Tx[1]);# "perpetuate" K_XX_XX... + } else { # ... or load next one + &movdqa (@Tx[2],eval(2*16*($Xi/5)-64)."($K_XX_XX)"); + } + eval(shift(@insns)); # ror + &paddd (@Tx[1],@X[-1&7]); + eval(shift(@insns)); + + &pxor (@X[0],@Tx[0]); # "X[0]"^="X[-6]" + eval(shift(@insns)); # body_20_39 + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # rol + eval(shift(@insns)) if (@insns[0] =~ /_ror/); + + &movdqa (@Tx[0],@X[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &movdqa (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer to IALU + eval(shift(@insns)); # ror + eval(shift(@insns)); + eval(shift(@insns)); # body_20_39 + + &pslld (@X[0],2); + eval(shift(@insns)); + eval(shift(@insns)); + &psrld (@Tx[0],30); + eval(shift(@insns)) if (@insns[0] =~ /_rol/);# rol + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # ror + + &por (@X[0],@Tx[0]); # "X[0]"<<<=2 + eval(shift(@insns)); + eval(shift(@insns)); # body_20_39 + eval(shift(@insns)) if (@insns[1] =~ /_rol/); + eval(shift(@insns)) if (@insns[0] =~ /_rol/); + &pshufd(@Tx[1],@X[-1&7],0xee) if ($Xi<19); # was &movdqa (@Tx[1],@X[0]) + eval(shift(@insns)); + eval(shift(@insns)); # rol + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # rol + eval(shift(@insns)); + + foreach (@insns) { eval; } # remaining instructions + + $Xi++; push(@X,shift(@X)); # "rotate" X[] + push(@Tx,shift(@Tx)); +} + +sub Xuplast_ssse3_80() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 instructions + my ($a,$b,$c,$d,$e); + + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &paddd (@Tx[1],@X[-1&7]); + eval(shift(@insns)); + eval(shift(@insns)); + + &movdqa (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer IALU + + foreach (@insns) { eval; } # remaining instructions + + &cmp ($inp,$num); + &je (".Ldone_ssse3"); + + unshift(@Tx,pop(@Tx)); + + &movdqa (@X[2],"64($K_XX_XX)"); # pbswap mask + &movdqa (@Tx[1],"-64($K_XX_XX)"); # K_00_19 + &movdqu (@X[-4&7],"0($inp)"); # load input + &movdqu (@X[-3&7],"16($inp)"); + &movdqu (@X[-2&7],"32($inp)"); + &movdqu (@X[-1&7],"48($inp)"); + &pshufb (@X[-4&7],@X[2]); # byte swap + &add ($inp,64); + + $Xi=0; +} + +sub Xloop_ssse3() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 instructions + my ($a,$b,$c,$d,$e); + + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &pshufb (@X[($Xi-3)&7],@X[2]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &paddd (@X[($Xi-4)&7],@Tx[1]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &movdqa (eval(16*$Xi)."(%rsp)",@X[($Xi-4)&7]); # X[]+K xfer to IALU + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &psubd (@X[($Xi-4)&7],@Tx[1]); + + foreach (@insns) { eval; } + $Xi++; +} + +sub Xtail_ssse3() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 instructions + my ($a,$b,$c,$d,$e); + + foreach (@insns) { eval; } +} + +sub body_00_19 () { # ((c^d)&b)^d + # on start @T[0]=(c^d)&b + return &body_20_39() if ($rx==19); $rx++; + ( + '($a,$b,$c,$d,$e)=@V;'. + '&$_ror ($b,$j?7:2)', # $b>>>2 + '&xor (@T[0],$d)', + '&mov (@T[1],$a)', # $b for next round + + '&add ($e,eval(4*($j&15))."(%rsp)")', # X[]+K xfer + '&xor ($b,$c)', # $c^$d for next round + + '&$_rol ($a,5)', + '&add ($e,@T[0])', + '&and (@T[1],$b)', # ($b&($c^$d)) for next round + + '&xor ($b,$c)', # restore $b + '&add ($e,$a);' .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));' + ); +} + +sub body_20_39 () { # b^d^c + # on entry @T[0]=b^d + return &body_40_59() if ($rx==39); $rx++; + ( + '($a,$b,$c,$d,$e)=@V;'. + '&add ($e,eval(4*($j&15))."(%rsp)")', # X[]+K xfer + '&xor (@T[0],$d) if($j==19);'. + '&xor (@T[0],$c) if($j> 19)', # ($b^$d^$c) + '&mov (@T[1],$a)', # $b for next round + + '&$_rol ($a,5)', + '&add ($e,@T[0])', + '&xor (@T[1],$c) if ($j< 79)', # $b^$d for next round + + '&$_ror ($b,7)', # $b>>>2 + '&add ($e,$a);' .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));' + ); +} + +sub body_40_59 () { # ((b^c)&(c^d))^c + # on entry @T[0]=(b^c), (c^=d) + $rx++; + ( + '($a,$b,$c,$d,$e)=@V;'. + '&add ($e,eval(4*($j&15))."(%rsp)")', # X[]+K xfer + '&and (@T[0],$c) if ($j>=40)', # (b^c)&(c^d) + '&xor ($c,$d) if ($j>=40)', # restore $c + + '&$_ror ($b,7)', # $b>>>2 + '&mov (@T[1],$a)', # $b for next round + '&xor (@T[0],$c)', + + '&$_rol ($a,5)', + '&add ($e,@T[0])', + '&xor (@T[1],$c) if ($j==59);'. + '&xor (@T[1],$b) if ($j< 59)', # b^c for next round + + '&xor ($b,$c) if ($j< 59)', # c^d for next round + '&add ($e,$a);' .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));' + ); +} +$code.=<<___; +.align 16 +.Loop_ssse3: +___ + &Xupdate_ssse3_16_31(\&body_00_19); + &Xupdate_ssse3_16_31(\&body_00_19); + &Xupdate_ssse3_16_31(\&body_00_19); + &Xupdate_ssse3_16_31(\&body_00_19); + &Xupdate_ssse3_32_79(\&body_00_19); + &Xupdate_ssse3_32_79(\&body_20_39); + &Xupdate_ssse3_32_79(\&body_20_39); + &Xupdate_ssse3_32_79(\&body_20_39); + &Xupdate_ssse3_32_79(\&body_20_39); + &Xupdate_ssse3_32_79(\&body_20_39); + &Xupdate_ssse3_32_79(\&body_40_59); + &Xupdate_ssse3_32_79(\&body_40_59); + &Xupdate_ssse3_32_79(\&body_40_59); + &Xupdate_ssse3_32_79(\&body_40_59); + &Xupdate_ssse3_32_79(\&body_40_59); + &Xupdate_ssse3_32_79(\&body_20_39); + &Xuplast_ssse3_80(\&body_20_39); # can jump to "done" + + $saved_j=$j; @saved_V=@V; + + &Xloop_ssse3(\&body_20_39); + &Xloop_ssse3(\&body_20_39); + &Xloop_ssse3(\&body_20_39); + +$code.=<<___; + add 0($ctx),$A # update context + add 4($ctx),@T[0] + add 8($ctx),$C + add 12($ctx),$D + mov $A,0($ctx) + add 16($ctx),$E + mov @T[0],4($ctx) + mov @T[0],$B # magic seed + mov $C,8($ctx) + mov $C,@T[1] + mov $D,12($ctx) + xor $D,@T[1] + mov $E,16($ctx) + and @T[1],@T[0] + jmp .Loop_ssse3 + +.align 16 +.Ldone_ssse3: +___ + $j=$saved_j; @V=@saved_V; + + &Xtail_ssse3(\&body_20_39); + &Xtail_ssse3(\&body_20_39); + &Xtail_ssse3(\&body_20_39); + +$code.=<<___; + add 0($ctx),$A # update context + add 4($ctx),@T[0] + add 8($ctx),$C + mov $A,0($ctx) + add 12($ctx),$D + mov @T[0],4($ctx) + add 16($ctx),$E + mov $C,8($ctx) + mov $D,12($ctx) + mov $E,16($ctx) +___ +$code.=<<___ if ($win64); + movaps -40-6*16(%r14),%xmm6 + movaps -40-5*16(%r14),%xmm7 + movaps -40-4*16(%r14),%xmm8 + movaps -40-3*16(%r14),%xmm9 + movaps -40-2*16(%r14),%xmm10 + movaps -40-1*16(%r14),%xmm11 +___ +$code.=<<___; + lea (%r14),%rsi + mov -40(%rsi),%r14 + mov -32(%rsi),%r13 + mov -24(%rsi),%r12 + mov -16(%rsi),%rbp + mov -8(%rsi),%rbx + lea (%rsi),%rsp +.Lepilogue_ssse3: + ret +.size sha1_block_data_order_ssse3,.-sha1_block_data_order_ssse3 +___ + +if ($avx) { +$Xi=4; # reset variables +@X=map("%xmm$_",(4..7,0..3)); +@Tx=map("%xmm$_",(8..10)); +$j=0; +$rx=0; + +my $done_avx_label=".Ldone_avx"; + +my $_rol=sub { &shld(@_[0],@_) }; +my $_ror=sub { &shrd(@_[0],@_) }; + +$code.=<<___; +.type sha1_block_data_order_avx,\@function,3 +.align 16 +sha1_block_data_order_avx: +_avx_shortcut: + mov %rsp,%rax + push %rbx + push %rbp + push %r12 + push %r13 # redundant, done to share Win64 SE handler + push %r14 + lea `-64-($win64?6*16:0)`(%rsp),%rsp + vzeroupper +___ +$code.=<<___ if ($win64); + vmovaps %xmm6,-40-6*16(%rax) + vmovaps %xmm7,-40-5*16(%rax) + vmovaps %xmm8,-40-4*16(%rax) + vmovaps %xmm9,-40-3*16(%rax) + vmovaps %xmm10,-40-2*16(%rax) + vmovaps %xmm11,-40-1*16(%rax) +.Lprologue_avx: +___ +$code.=<<___; + mov %rax,%r14 # original %rsp + and \$-64,%rsp + mov %rdi,$ctx # reassigned argument + mov %rsi,$inp # reassigned argument + mov %rdx,$num # reassigned argument + + shl \$6,$num + add $inp,$num + lea K_XX_XX+64(%rip),$K_XX_XX + + mov 0($ctx),$A # load context + mov 4($ctx),$B + mov 8($ctx),$C + mov 12($ctx),$D + mov $B,@T[0] # magic seed + mov 16($ctx),$E + mov $C,@T[1] + xor $D,@T[1] + and @T[1],@T[0] + + vmovdqa 64($K_XX_XX),@X[2] # pbswap mask + vmovdqa -64($K_XX_XX),$Kx # K_00_19 + vmovdqu 0($inp),@X[-4&7] # load input to %xmm[0-3] + vmovdqu 16($inp),@X[-3&7] + vmovdqu 32($inp),@X[-2&7] + vmovdqu 48($inp),@X[-1&7] + vpshufb @X[2],@X[-4&7],@X[-4&7] # byte swap + add \$64,$inp + vpshufb @X[2],@X[-3&7],@X[-3&7] + vpshufb @X[2],@X[-2&7],@X[-2&7] + vpshufb @X[2],@X[-1&7],@X[-1&7] + vpaddd $Kx,@X[-4&7],@X[0] # add K_00_19 + vpaddd $Kx,@X[-3&7],@X[1] + vpaddd $Kx,@X[-2&7],@X[2] + vmovdqa @X[0],0(%rsp) # X[]+K xfer to IALU + vmovdqa @X[1],16(%rsp) + vmovdqa @X[2],32(%rsp) + jmp .Loop_avx +___ + +sub Xupdate_avx_16_31() # recall that $Xi starts wtih 4 +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 40 instructions + my ($a,$b,$c,$d,$e); + + eval(shift(@insns)); + eval(shift(@insns)); + &vpalignr(@X[0],@X[-3&7],@X[-4&7],8); # compose "X[-14]" in "X[0]" + eval(shift(@insns)); + eval(shift(@insns)); + + &vpaddd (@Tx[1],$Kx,@X[-1&7]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpsrldq(@Tx[0],@X[-1&7],4); # "X[-3]", 3 dwords + eval(shift(@insns)); + eval(shift(@insns)); + &vpxor (@X[0],@X[0],@X[-4&7]); # "X[0]"^="X[-16]" + eval(shift(@insns)); + eval(shift(@insns)); + + &vpxor (@Tx[0],@Tx[0],@X[-2&7]); # "X[-3]"^"X[-8]" + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpxor (@X[0],@X[0],@Tx[0]); # "X[0]"^="X[-3]"^"X[-8]" + eval(shift(@insns)); + eval(shift(@insns)); + &vmovdqa (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer to IALU + eval(shift(@insns)); + eval(shift(@insns)); + + &vpsrld (@Tx[0],@X[0],31); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpslldq(@Tx[2],@X[0],12); # "X[0]"<<96, extract one dword + &vpaddd (@X[0],@X[0],@X[0]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpsrld (@Tx[1],@Tx[2],30); + &vpor (@X[0],@X[0],@Tx[0]); # "X[0]"<<<=1 + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpslld (@Tx[2],@Tx[2],2); + &vpxor (@X[0],@X[0],@Tx[1]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpxor (@X[0],@X[0],@Tx[2]); # "X[0]"^=("X[0]">>96)<<<2 + eval(shift(@insns)); + eval(shift(@insns)); + &vmovdqa ($Kx,eval(2*16*(($Xi)/5)-64)."($K_XX_XX)") if ($Xi%5==0); # K_XX_XX + eval(shift(@insns)); + eval(shift(@insns)); + + + foreach (@insns) { eval; } # remaining instructions [if any] + + $Xi++; push(@X,shift(@X)); # "rotate" X[] +} + +sub Xupdate_avx_32_79() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 to 44 instructions + my ($a,$b,$c,$d,$e); + + &vpalignr(@Tx[0],@X[-1&7],@X[-2&7],8); # compose "X[-6]" + &vpxor (@X[0],@X[0],@X[-4&7]); # "X[0]"="X[-32]"^"X[-16]" + eval(shift(@insns)); # body_20_39 + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # rol + + &vpxor (@X[0],@X[0],@X[-7&7]); # "X[0]"^="X[-28]" + eval(shift(@insns)); + eval(shift(@insns)) if (@insns[0] !~ /&ro[rl]/); + &vpaddd (@Tx[1],$Kx,@X[-1&7]); + &vmovdqa ($Kx,eval(2*16*($Xi/5)-64)."($K_XX_XX)") if ($Xi%5==0); + eval(shift(@insns)); # ror + eval(shift(@insns)); + + &vpxor (@X[0],@X[0],@Tx[0]); # "X[0]"^="X[-6]" + eval(shift(@insns)); # body_20_39 + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # rol + + &vpsrld (@Tx[0],@X[0],30); + &vmovdqa (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer to IALU + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # ror + eval(shift(@insns)); + + &vpslld (@X[0],@X[0],2); + eval(shift(@insns)); # body_20_39 + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # rol + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # ror + eval(shift(@insns)); + + &vpor (@X[0],@X[0],@Tx[0]); # "X[0]"<<<=2 + eval(shift(@insns)); # body_20_39 + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # rol + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # rol + eval(shift(@insns)); + + foreach (@insns) { eval; } # remaining instructions + + $Xi++; push(@X,shift(@X)); # "rotate" X[] +} + +sub Xuplast_avx_80() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 instructions + my ($a,$b,$c,$d,$e); + + eval(shift(@insns)); + &vpaddd (@Tx[1],$Kx,@X[-1&7]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vmovdqa (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer IALU + + foreach (@insns) { eval; } # remaining instructions + + &cmp ($inp,$num); + &je ($done_avx_label); + + &vmovdqa(@X[2],"64($K_XX_XX)"); # pbswap mask + &vmovdqa($Kx,"-64($K_XX_XX)"); # K_00_19 + &vmovdqu(@X[-4&7],"0($inp)"); # load input + &vmovdqu(@X[-3&7],"16($inp)"); + &vmovdqu(@X[-2&7],"32($inp)"); + &vmovdqu(@X[-1&7],"48($inp)"); + &vpshufb(@X[-4&7],@X[-4&7],@X[2]); # byte swap + &add ($inp,64); + + $Xi=0; +} + +sub Xloop_avx() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 instructions + my ($a,$b,$c,$d,$e); + + eval(shift(@insns)); + eval(shift(@insns)); + &vpshufb(@X[($Xi-3)&7],@X[($Xi-3)&7],@X[2]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpaddd (@X[$Xi&7],@X[($Xi-4)&7],$Kx); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vmovdqa(eval(16*$Xi)."(%rsp)",@X[$Xi&7]); # X[]+K xfer to IALU + eval(shift(@insns)); + eval(shift(@insns)); + + foreach (@insns) { eval; } + $Xi++; +} + +sub Xtail_avx() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 instructions + my ($a,$b,$c,$d,$e); + + foreach (@insns) { eval; } +} + +$code.=<<___; +.align 16 +.Loop_avx: +___ + &Xupdate_avx_16_31(\&body_00_19); + &Xupdate_avx_16_31(\&body_00_19); + &Xupdate_avx_16_31(\&body_00_19); + &Xupdate_avx_16_31(\&body_00_19); + &Xupdate_avx_32_79(\&body_00_19); + &Xupdate_avx_32_79(\&body_20_39); + &Xupdate_avx_32_79(\&body_20_39); + &Xupdate_avx_32_79(\&body_20_39); + &Xupdate_avx_32_79(\&body_20_39); + &Xupdate_avx_32_79(\&body_20_39); + &Xupdate_avx_32_79(\&body_40_59); + &Xupdate_avx_32_79(\&body_40_59); + &Xupdate_avx_32_79(\&body_40_59); + &Xupdate_avx_32_79(\&body_40_59); + &Xupdate_avx_32_79(\&body_40_59); + &Xupdate_avx_32_79(\&body_20_39); + &Xuplast_avx_80(\&body_20_39); # can jump to "done" + + $saved_j=$j; @saved_V=@V; + + &Xloop_avx(\&body_20_39); + &Xloop_avx(\&body_20_39); + &Xloop_avx(\&body_20_39); + +$code.=<<___; + add 0($ctx),$A # update context + add 4($ctx),@T[0] + add 8($ctx),$C + add 12($ctx),$D + mov $A,0($ctx) + add 16($ctx),$E + mov @T[0],4($ctx) + mov @T[0],$B # magic seed + mov $C,8($ctx) + mov $C,@T[1] + mov $D,12($ctx) + xor $D,@T[1] + mov $E,16($ctx) + and @T[1],@T[0] + jmp .Loop_avx + +.align 16 +$done_avx_label: +___ + $j=$saved_j; @V=@saved_V; + + &Xtail_avx(\&body_20_39); + &Xtail_avx(\&body_20_39); + &Xtail_avx(\&body_20_39); + +$code.=<<___; + vzeroupper + + add 0($ctx),$A # update context + add 4($ctx),@T[0] + add 8($ctx),$C + mov $A,0($ctx) + add 12($ctx),$D + mov @T[0],4($ctx) + add 16($ctx),$E + mov $C,8($ctx) + mov $D,12($ctx) + mov $E,16($ctx) +___ +$code.=<<___ if ($win64); + movaps -40-6*16(%r14),%xmm6 + movaps -40-5*16(%r14),%xmm7 + movaps -40-4*16(%r14),%xmm8 + movaps -40-3*16(%r14),%xmm9 + movaps -40-2*16(%r14),%xmm10 + movaps -40-1*16(%r14),%xmm11 +___ +$code.=<<___; + lea (%r14),%rsi + mov -40(%rsi),%r14 + mov -32(%rsi),%r13 + mov -24(%rsi),%r12 + mov -16(%rsi),%rbp + mov -8(%rsi),%rbx + lea (%rsi),%rsp +.Lepilogue_avx: + ret +.size sha1_block_data_order_avx,.-sha1_block_data_order_avx +___ + +if ($avx>1) { +use integer; +$Xi=4; # reset variables +@X=map("%ymm$_",(4..7,0..3)); +@Tx=map("%ymm$_",(8..10)); +$Kx="%ymm11"; +$j=0; + +my @ROTX=("%eax","%ebp","%ebx","%ecx","%edx","%esi"); +my ($a5,$t0)=("%r12d","%edi"); + +my ($A,$F,$B,$C,$D,$E)=@ROTX; +my $rx=0; +my $frame="%r13"; + +$code.=<<___; +.type sha1_block_data_order_avx2,\@function,3 +.align 16 +sha1_block_data_order_avx2: +_avx2_shortcut: + mov %rsp,%rax + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + vzeroupper +___ +$code.=<<___ if ($win64); + lea -6*16(%rsp),%rsp + vmovaps %xmm6,-40-6*16(%rax) + vmovaps %xmm7,-40-5*16(%rax) + vmovaps %xmm8,-40-4*16(%rax) + vmovaps %xmm9,-40-3*16(%rax) + vmovaps %xmm10,-40-2*16(%rax) + vmovaps %xmm11,-40-1*16(%rax) +.Lprologue_avx2: +___ +$code.=<<___; + mov %rax,%r14 # original %rsp + mov %rdi,$ctx # reassigned argument + mov %rsi,$inp # reassigned argument + mov %rdx,$num # reassigned argument + + lea -640(%rsp),%rsp + shl \$6,$num + lea 64($inp),$frame + and \$-128,%rsp + add $inp,$num + lea K_XX_XX+64(%rip),$K_XX_XX + + mov 0($ctx),$A # load context + cmp $num,$frame + cmovae $inp,$frame # next or same block + mov 4($ctx),$F + mov 8($ctx),$C + mov 12($ctx),$D + mov 16($ctx),$E + vmovdqu 64($K_XX_XX),@X[2] # pbswap mask + + vmovdqu ($inp),%xmm0 + vmovdqu 16($inp),%xmm1 + vmovdqu 32($inp),%xmm2 + vmovdqu 48($inp),%xmm3 + lea 64($inp),$inp + vinserti128 \$1,($frame),@X[-4&7],@X[-4&7] + vinserti128 \$1,16($frame),@X[-3&7],@X[-3&7] + vpshufb @X[2],@X[-4&7],@X[-4&7] + vinserti128 \$1,32($frame),@X[-2&7],@X[-2&7] + vpshufb @X[2],@X[-3&7],@X[-3&7] + vinserti128 \$1,48($frame),@X[-1&7],@X[-1&7] + vpshufb @X[2],@X[-2&7],@X[-2&7] + vmovdqu -64($K_XX_XX),$Kx # K_00_19 + vpshufb @X[2],@X[-1&7],@X[-1&7] + + vpaddd $Kx,@X[-4&7],@X[0] # add K_00_19 + vpaddd $Kx,@X[-3&7],@X[1] + vmovdqu @X[0],0(%rsp) # X[]+K xfer to IALU + vpaddd $Kx,@X[-2&7],@X[2] + vmovdqu @X[1],32(%rsp) + vpaddd $Kx,@X[-1&7],@X[3] + vmovdqu @X[2],64(%rsp) + vmovdqu @X[3],96(%rsp) +___ +for (;$Xi<8;$Xi++) { # Xupdate_avx2_16_31 + use integer; + + &vpalignr(@X[0],@X[-3&7],@X[-4&7],8); # compose "X[-14]" in "X[0]" + &vpsrldq(@Tx[0],@X[-1&7],4); # "X[-3]", 3 dwords + &vpxor (@X[0],@X[0],@X[-4&7]); # "X[0]"^="X[-16]" + &vpxor (@Tx[0],@Tx[0],@X[-2&7]); # "X[-3]"^"X[-8]" + &vpxor (@X[0],@X[0],@Tx[0]); # "X[0]"^="X[-3]"^"X[-8]" + &vpsrld (@Tx[0],@X[0],31); + &vmovdqu($Kx,eval(2*16*(($Xi)/5)-64)."($K_XX_XX)") if ($Xi%5==0); # K_XX_XX + &vpslldq(@Tx[2],@X[0],12); # "X[0]"<<96, extract one dword + &vpaddd (@X[0],@X[0],@X[0]); + &vpsrld (@Tx[1],@Tx[2],30); + &vpor (@X[0],@X[0],@Tx[0]); # "X[0]"<<<=1 + &vpslld (@Tx[2],@Tx[2],2); + &vpxor (@X[0],@X[0],@Tx[1]); + &vpxor (@X[0],@X[0],@Tx[2]); # "X[0]"^=("X[0]">>96)<<<2 + &vpaddd (@Tx[1],@X[0],$Kx); + &vmovdqu("32*$Xi(%rsp)",@Tx[1]); # X[]+K xfer to IALU + + push(@X,shift(@X)); # "rotate" X[] +} +$code.=<<___; + lea 128(%rsp),$frame + jmp .Loop_avx2 +.align 32 +.Loop_avx2: + rorx \$2,$F,$B + andn $D,$F,$t0 + and $C,$F + xor $t0,$F +___ +sub bodyx_00_19 () { # 8 instructions, 3 cycles critical path + # at start $f=(b&c)^(~b&d), $b>>>=2 + return &bodyx_20_39() if ($rx==19); $rx++; + ( + '($a,$f,$b,$c,$d,$e)=@ROTX;'. + + '&add ($e,((32*($j/4)+4*($j%4))%256-128)."($frame)");'. # e+=X[i]+K + '&lea ($frame,"256($frame)") if ($j%32==31);', + '&andn ($t0,$a,$c)', # ~b&d for next round + + '&add ($e,$f)', # e+=(b&c)^(~b&d) + '&rorx ($a5,$a,27)', # a<<<5 + '&rorx ($f,$a,2)', # b>>>2 for next round + '&and ($a,$b)', # b&c for next round + + '&add ($e,$a5)', # e+=a<<<5 + '&xor ($a,$t0);'. # f=(b&c)^(~b&d) for next round + + 'unshift(@ROTX,pop(@ROTX)); $j++;' + ) +} + +sub bodyx_20_39 () { # 7 instructions, 2 cycles critical path + # on entry $f=b^c^d, $b>>>=2 + return &bodyx_40_59() if ($rx==39); $rx++; + ( + '($a,$f,$b,$c,$d,$e)=@ROTX;'. + + '&add ($e,((32*($j/4)+4*($j%4))%256-128)."($frame)");'. # e+=X[i]+K + '&lea ($frame,"256($frame)") if ($j%32==31);', + + '&lea ($e,"($e,$f)")', # e+=b^c^d + '&rorx ($a5,$a,27)', # a<<<5 + '&rorx ($f,$a,2) if ($j<79)', # b>>>2 in next round + '&xor ($a,$b) if ($j<79)', # b^c for next round + + '&add ($e,$a5)', # e+=a<<<5 + '&xor ($a,$c) if ($j<79);'. # f=b^c^d for next round + + 'unshift(@ROTX,pop(@ROTX)); $j++;' + ) +} + +sub bodyx_40_59 () { # 10 instructions, 3 cycles critical path + # on entry $f=((b^c)&(c^d)), $b>>>=2 + $rx++; + ( + '($a,$f,$b,$c,$d,$e)=@ROTX;'. + + '&add ($e,((32*($j/4)+4*($j%4))%256-128)."($frame)");'. # e+=X[i]+K + '&lea ($frame,"256($frame)") if ($j%32==31);', + '&xor ($f,$c) if ($j>39)', # (b^c)&(c^d)^c + '&mov ($t0,$b) if ($j<59)', # count on zero latency + '&xor ($t0,$c) if ($j<59)', # c^d for next round + + '&lea ($e,"($e,$f)")', # e+=(b^c)&(c^d)^c + '&rorx ($a5,$a,27)', # a<<<5 + '&rorx ($f,$a,2)', # b>>>2 in next round + '&xor ($a,$b)', # b^c for next round + + '&add ($e,$a5)', # e+=a<<<5 + '&and ($a,$t0) if ($j< 59);'. # f=(b^c)&(c^d) for next round + '&xor ($a,$c) if ($j==59);'. # f=b^c^d for next round + + 'unshift(@ROTX,pop(@ROTX)); $j++;' + ) +} + +sub Xupdate_avx2_16_31() # recall that $Xi starts wtih 4 +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body,&$body); # 35 instructions + my ($a,$b,$c,$d,$e); + + &vpalignr(@X[0],@X[-3&7],@X[-4&7],8); # compose "X[-14]" in "X[0]" + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpsrldq(@Tx[0],@X[-1&7],4); # "X[-3]", 3 dwords + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpxor (@X[0],@X[0],@X[-4&7]); # "X[0]"^="X[-16]" + &vpxor (@Tx[0],@Tx[0],@X[-2&7]); # "X[-3]"^"X[-8]" + eval(shift(@insns)); + eval(shift(@insns)); + + &vpxor (@X[0],@X[0],@Tx[0]); # "X[0]"^="X[-3]"^"X[-8]" + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpsrld (@Tx[0],@X[0],31); + &vmovdqu($Kx,eval(2*16*(($Xi)/5)-64)."($K_XX_XX)") if ($Xi%5==0); # K_XX_XX + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpslldq(@Tx[2],@X[0],12); # "X[0]"<<96, extract one dword + &vpaddd (@X[0],@X[0],@X[0]); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpsrld (@Tx[1],@Tx[2],30); + &vpor (@X[0],@X[0],@Tx[0]); # "X[0]"<<<=1 + eval(shift(@insns)); + eval(shift(@insns)); + + &vpslld (@Tx[2],@Tx[2],2); + &vpxor (@X[0],@X[0],@Tx[1]); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpxor (@X[0],@X[0],@Tx[2]); # "X[0]"^=("X[0]">>96)<<<2 + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpaddd (@Tx[1],@X[0],$Kx); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vmovdqu(eval(32*($Xi))."(%rsp)",@Tx[1]); # X[]+K xfer to IALU + + foreach (@insns) { eval; } # remaining instructions [if any] + + $Xi++; + push(@X,shift(@X)); # "rotate" X[] +} + +sub Xupdate_avx2_32_79() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body,&$body); # 35 to 50 instructions + my ($a,$b,$c,$d,$e); + + &vpalignr(@Tx[0],@X[-1&7],@X[-2&7],8); # compose "X[-6]" + &vpxor (@X[0],@X[0],@X[-4&7]); # "X[0]"="X[-32]"^"X[-16]" + eval(shift(@insns)); + eval(shift(@insns)); + + &vpxor (@X[0],@X[0],@X[-7&7]); # "X[0]"^="X[-28]" + &vmovdqu($Kx,eval(2*16*($Xi/5)-64)."($K_XX_XX)") if ($Xi%5==0); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpxor (@X[0],@X[0],@Tx[0]); # "X[0]"^="X[-6]" + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpsrld (@Tx[0],@X[0],30); + &vpslld (@X[0],@X[0],2); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + #&vpslld (@X[0],@X[0],2); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpor (@X[0],@X[0],@Tx[0]); # "X[0]"<<<=2 + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpaddd (@Tx[1],@X[0],$Kx); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vmovdqu("32*$Xi(%rsp)",@Tx[1]); # X[]+K xfer to IALU + + foreach (@insns) { eval; } # remaining instructions + + $Xi++; + push(@X,shift(@X)); # "rotate" X[] +} + +sub Xloop_avx2() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body,&$body); # 32 instructions + my ($a,$b,$c,$d,$e); + + foreach (@insns) { eval; } +} + + &align32(); + &Xupdate_avx2_32_79(\&bodyx_00_19); + &Xupdate_avx2_32_79(\&bodyx_00_19); + &Xupdate_avx2_32_79(\&bodyx_00_19); + &Xupdate_avx2_32_79(\&bodyx_00_19); + + &Xupdate_avx2_32_79(\&bodyx_20_39); + &Xupdate_avx2_32_79(\&bodyx_20_39); + &Xupdate_avx2_32_79(\&bodyx_20_39); + &Xupdate_avx2_32_79(\&bodyx_20_39); + + &align32(); + &Xupdate_avx2_32_79(\&bodyx_40_59); + &Xupdate_avx2_32_79(\&bodyx_40_59); + &Xupdate_avx2_32_79(\&bodyx_40_59); + &Xupdate_avx2_32_79(\&bodyx_40_59); + + &Xloop_avx2(\&bodyx_20_39); + &Xloop_avx2(\&bodyx_20_39); + &Xloop_avx2(\&bodyx_20_39); + &Xloop_avx2(\&bodyx_20_39); + +$code.=<<___; + lea 128($inp),$frame + lea 128($inp),%rdi # borrow $t0 + cmp $num,$frame + cmovae $inp,$frame # next or previous block + + # output is d-e-[a]-f-b-c => A=d,F=e,C=f,D=b,E=c + add 0($ctx),@ROTX[0] # update context + add 4($ctx),@ROTX[1] + add 8($ctx),@ROTX[3] + mov @ROTX[0],0($ctx) + add 12($ctx),@ROTX[4] + mov @ROTX[1],4($ctx) + mov @ROTX[0],$A # A=d + add 16($ctx),@ROTX[5] + mov @ROTX[3],$a5 + mov @ROTX[3],8($ctx) + mov @ROTX[4],$D # D=b + #xchg @ROTX[5],$F # F=c, C=f + mov @ROTX[4],12($ctx) + mov @ROTX[1],$F # F=e + mov @ROTX[5],16($ctx) + #mov $F,16($ctx) + mov @ROTX[5],$E # E=c + mov $a5,$C # C=f + #xchg $F,$E # E=c, F=e + + cmp $num,$inp + je .Ldone_avx2 +___ + +$Xi=4; # reset variables +@X=map("%ymm$_",(4..7,0..3)); + +$code.=<<___; + vmovdqu 64($K_XX_XX),@X[2] # pbswap mask + cmp $num,%rdi # borrowed $t0 + ja .Last_avx2 + + vmovdqu -64(%rdi),%xmm0 # low part of @X[-4&7] + vmovdqu -48(%rdi),%xmm1 + vmovdqu -32(%rdi),%xmm2 + vmovdqu -16(%rdi),%xmm3 + vinserti128 \$1,0($frame),@X[-4&7],@X[-4&7] + vinserti128 \$1,16($frame),@X[-3&7],@X[-3&7] + vinserti128 \$1,32($frame),@X[-2&7],@X[-2&7] + vinserti128 \$1,48($frame),@X[-1&7],@X[-1&7] + jmp .Last_avx2 + +.align 32 +.Last_avx2: + lea 128+16(%rsp),$frame + rorx \$2,$F,$B + andn $D,$F,$t0 + and $C,$F + xor $t0,$F + sub \$-128,$inp +___ + $rx=$j=0; @ROTX=($A,$F,$B,$C,$D,$E); + + &Xloop_avx2 (\&bodyx_00_19); + &Xloop_avx2 (\&bodyx_00_19); + &Xloop_avx2 (\&bodyx_00_19); + &Xloop_avx2 (\&bodyx_00_19); + + &Xloop_avx2 (\&bodyx_20_39); + &vmovdqu ($Kx,"-64($K_XX_XX)"); # K_00_19 + &vpshufb (@X[-4&7],@X[-4&7],@X[2]); # byte swap + &Xloop_avx2 (\&bodyx_20_39); + &vpshufb (@X[-3&7],@X[-3&7],@X[2]); + &vpaddd (@Tx[0],@X[-4&7],$Kx); # add K_00_19 + &Xloop_avx2 (\&bodyx_20_39); + &vmovdqu ("0(%rsp)",@Tx[0]); + &vpshufb (@X[-2&7],@X[-2&7],@X[2]); + &vpaddd (@Tx[1],@X[-3&7],$Kx); + &Xloop_avx2 (\&bodyx_20_39); + &vmovdqu ("32(%rsp)",@Tx[1]); + &vpshufb (@X[-1&7],@X[-1&7],@X[2]); + &vpaddd (@X[2],@X[-2&7],$Kx); + + &Xloop_avx2 (\&bodyx_40_59); + &align32 (); + &vmovdqu ("64(%rsp)",@X[2]); + &vpaddd (@X[3],@X[-1&7],$Kx); + &Xloop_avx2 (\&bodyx_40_59); + &vmovdqu ("96(%rsp)",@X[3]); + &Xloop_avx2 (\&bodyx_40_59); + &Xupdate_avx2_16_31(\&bodyx_40_59); + + &Xupdate_avx2_16_31(\&bodyx_20_39); + &Xupdate_avx2_16_31(\&bodyx_20_39); + &Xupdate_avx2_16_31(\&bodyx_20_39); + &Xloop_avx2 (\&bodyx_20_39); + +$code.=<<___; + lea 128(%rsp),$frame + + # output is d-e-[a]-f-b-c => A=d,F=e,C=f,D=b,E=c + add 0($ctx),@ROTX[0] # update context + add 4($ctx),@ROTX[1] + add 8($ctx),@ROTX[3] + mov @ROTX[0],0($ctx) + add 12($ctx),@ROTX[4] + mov @ROTX[1],4($ctx) + mov @ROTX[0],$A # A=d + add 16($ctx),@ROTX[5] + mov @ROTX[3],$a5 + mov @ROTX[3],8($ctx) + mov @ROTX[4],$D # D=b + #xchg @ROTX[5],$F # F=c, C=f + mov @ROTX[4],12($ctx) + mov @ROTX[1],$F # F=e + mov @ROTX[5],16($ctx) + #mov $F,16($ctx) + mov @ROTX[5],$E # E=c + mov $a5,$C # C=f + #xchg $F,$E # E=c, F=e + + cmp $num,$inp + jbe .Loop_avx2 + +.Ldone_avx2: + vzeroupper +___ +$code.=<<___ if ($win64); + movaps -40-6*16(%r14),%xmm6 + movaps -40-5*16(%r14),%xmm7 + movaps -40-4*16(%r14),%xmm8 + movaps -40-3*16(%r14),%xmm9 + movaps -40-2*16(%r14),%xmm10 + movaps -40-1*16(%r14),%xmm11 +___ +$code.=<<___; + lea (%r14),%rsi + mov -40(%rsi),%r14 + mov -32(%rsi),%r13 + mov -24(%rsi),%r12 + mov -16(%rsi),%rbp + mov -8(%rsi),%rbx + lea (%rsi),%rsp +.Lepilogue_avx2: + ret +.size sha1_block_data_order_avx2,.-sha1_block_data_order_avx2 +___ +} +} +$code.=<<___; +.align 64 +K_XX_XX: +.long 0x5a827999,0x5a827999,0x5a827999,0x5a827999 # K_00_19 +.long 0x5a827999,0x5a827999,0x5a827999,0x5a827999 # K_00_19 +.long 0x6ed9eba1,0x6ed9eba1,0x6ed9eba1,0x6ed9eba1 # K_20_39 +.long 0x6ed9eba1,0x6ed9eba1,0x6ed9eba1,0x6ed9eba1 # K_20_39 +.long 0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc # K_40_59 +.long 0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc # K_40_59 +.long 0xca62c1d6,0xca62c1d6,0xca62c1d6,0xca62c1d6 # K_60_79 +.long 0xca62c1d6,0xca62c1d6,0xca62c1d6,0xca62c1d6 # K_60_79 +.long 0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f # pbswap mask +.long 0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f # pbswap mask +.byte 0xf,0xe,0xd,0xc,0xb,0xa,0x9,0x8,0x7,0x6,0x5,0x4,0x3,0x2,0x1,0x0 +___ +}}} +$code.=<<___; +.asciz "SHA1 block transform for x86_64, CRYPTOGAMS by " +.align 64 +___ + +# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame, +# CONTEXT *context,DISPATCHER_CONTEXT *disp) +if ($win64) { +$rec="%rcx"; +$frame="%rdx"; +$context="%r8"; +$disp="%r9"; + +$code.=<<___; +.extern __imp_RtlVirtualUnwind +.type se_handler,\@abi-omnipotent +.align 16 +se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + lea .Lprologue(%rip),%r10 + cmp %r10,%rbx # context->Rip<.Lprologue + jb .Lcommon_seh_tail + + mov 152($context),%rax # pull context->Rsp + + lea .Lepilogue(%rip),%r10 + cmp %r10,%rbx # context->Rip>=.Lepilogue + jae .Lcommon_seh_tail + + mov `16*4`(%rax),%rax # pull saved stack pointer + + mov -8(%rax),%rbx + mov -16(%rax),%rbp + mov -24(%rax),%r12 + mov -32(%rax),%r13 + mov -40(%rax),%r14 + mov %rbx,144($context) # restore context->Rbx + mov %rbp,160($context) # restore context->Rbp + mov %r12,216($context) # restore context->R12 + mov %r13,224($context) # restore context->R13 + mov %r14,232($context) # restore context->R14 + + jmp .Lcommon_seh_tail +.size se_handler,.-se_handler +___ + +$code.=<<___ if ($shaext); +.type shaext_handler,\@abi-omnipotent +.align 16 +shaext_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + lea .Lprologue_shaext(%rip),%r10 + cmp %r10,%rbx # context->Rip<.Lprologue + jb .Lcommon_seh_tail + + lea .Lepilogue_shaext(%rip),%r10 + cmp %r10,%rbx # context->Rip>=.Lepilogue + jae .Lcommon_seh_tail + + lea -8-4*16(%rax),%rsi + lea 512($context),%rdi # &context.Xmm6 + mov \$8,%ecx + .long 0xa548f3fc # cld; rep movsq + + jmp .Lcommon_seh_tail +.size shaext_handler,.-shaext_handler +___ + +$code.=<<___; +.type ssse3_handler,\@abi-omnipotent +.align 16 +ssse3_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + mov 8($disp),%rsi # disp->ImageBase + mov 56($disp),%r11 # disp->HandlerData + + mov 0(%r11),%r10d # HandlerData[0] + lea (%rsi,%r10),%r10 # prologue label + cmp %r10,%rbx # context->RipRsp + + mov 4(%r11),%r10d # HandlerData[1] + lea (%rsi,%r10),%r10 # epilogue label + cmp %r10,%rbx # context->Rip>=epilogue label + jae .Lcommon_seh_tail + + mov 232($context),%rax # pull context->R14 + + lea -40-6*16(%rax),%rsi + lea 512($context),%rdi # &context.Xmm6 + mov \$12,%ecx + .long 0xa548f3fc # cld; rep movsq + + mov -8(%rax),%rbx + mov -16(%rax),%rbp + mov -24(%rax),%r12 + mov -32(%rax),%r13 + mov -40(%rax),%r14 + mov %rbx,144($context) # restore context->Rbx + mov %rbp,160($context) # restore context->Rbp + mov %r12,216($context) # restore cotnext->R12 + mov %r13,224($context) # restore cotnext->R13 + mov %r14,232($context) # restore cotnext->R14 + +.Lcommon_seh_tail: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + + mov 40($disp),%rdi # disp->ContextRecord + mov $context,%rsi # context + mov \$154,%ecx # sizeof(CONTEXT) + .long 0xa548f3fc # cld; rep movsq + + mov $disp,%rsi + xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER + mov 8(%rsi),%rdx # arg2, disp->ImageBase + mov 0(%rsi),%r8 # arg3, disp->ControlPc + mov 16(%rsi),%r9 # arg4, disp->FunctionEntry + mov 40(%rsi),%r10 # disp->ContextRecord + lea 56(%rsi),%r11 # &disp->HandlerData + lea 24(%rsi),%r12 # &disp->EstablisherFrame + mov %r10,32(%rsp) # arg5 + mov %r11,40(%rsp) # arg6 + mov %r12,48(%rsp) # arg7 + mov %rcx,56(%rsp) # arg8, (NULL) + call *__imp_RtlVirtualUnwind(%rip) + + mov \$1,%eax # ExceptionContinueSearch + add \$64,%rsp + popfq + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + pop %rdi + pop %rsi + ret +.size ssse3_handler,.-ssse3_handler + +.section .pdata +.align 4 + .rva .LSEH_begin_sha1_block_data_order + .rva .LSEH_end_sha1_block_data_order + .rva .LSEH_info_sha1_block_data_order +___ +$code.=<<___ if ($shaext); + .rva .LSEH_begin_sha1_block_data_order_shaext + .rva .LSEH_end_sha1_block_data_order_shaext + .rva .LSEH_info_sha1_block_data_order_shaext +___ +$code.=<<___; + .rva .LSEH_begin_sha1_block_data_order_ssse3 + .rva .LSEH_end_sha1_block_data_order_ssse3 + .rva .LSEH_info_sha1_block_data_order_ssse3 +___ +$code.=<<___ if ($avx); + .rva .LSEH_begin_sha1_block_data_order_avx + .rva .LSEH_end_sha1_block_data_order_avx + .rva .LSEH_info_sha1_block_data_order_avx +___ +$code.=<<___ if ($avx>1); + .rva .LSEH_begin_sha1_block_data_order_avx2 + .rva .LSEH_end_sha1_block_data_order_avx2 + .rva .LSEH_info_sha1_block_data_order_avx2 +___ +$code.=<<___; +.section .xdata +.align 8 +.LSEH_info_sha1_block_data_order: + .byte 9,0,0,0 + .rva se_handler +___ +$code.=<<___ if ($shaext); +.LSEH_info_sha1_block_data_order_shaext: + .byte 9,0,0,0 + .rva shaext_handler +___ +$code.=<<___; +.LSEH_info_sha1_block_data_order_ssse3: + .byte 9,0,0,0 + .rva ssse3_handler + .rva .Lprologue_ssse3,.Lepilogue_ssse3 # HandlerData[] +___ +$code.=<<___ if ($avx); +.LSEH_info_sha1_block_data_order_avx: + .byte 9,0,0,0 + .rva ssse3_handler + .rva .Lprologue_avx,.Lepilogue_avx # HandlerData[] +___ +$code.=<<___ if ($avx>1); +.LSEH_info_sha1_block_data_order_avx2: + .byte 9,0,0,0 + .rva ssse3_handler + .rva .Lprologue_avx2,.Lepilogue_avx2 # HandlerData[] +___ +} + +#################################################################### + +sub sha1rnds4 { + if (@_[0] =~ /\$([x0-9a-f]+),\s*%xmm([0-7]),\s*%xmm([0-7])/) { + my @opcode=(0x0f,0x3a,0xcc); + push @opcode,0xc0|($2&7)|(($3&7)<<3); # ModR/M + my $c=$1; + push @opcode,$c=~/^0/?oct($c):$c; + return ".byte\t".join(',',@opcode); + } else { + return "sha1rnds4\t".@_[0]; + } +} + +sub sha1op38 { + my $instr = shift; + my %opcodelet = ( + "sha1nexte" => 0xc8, + "sha1msg1" => 0xc9, + "sha1msg2" => 0xca ); + + if (defined($opcodelet{$instr}) && @_[0] =~ /%xmm([0-9]+),\s*%xmm([0-9]+)/) { + my @opcode=(0x0f,0x38); + my $rex=0; + $rex|=0x04 if ($2>=8); + $rex|=0x01 if ($1>=8); + unshift @opcode,0x40|$rex if ($rex); + push @opcode,$opcodelet{$instr}; + push @opcode,0xc0|($1&7)|(($2&7)<<3); # ModR/M + return ".byte\t".join(',',@opcode); + } else { + return $instr."\t".@_[0]; + } +} + +foreach (split("\n",$code)) { + s/\`([^\`]*)\`/eval $1/geo; + + s/\b(sha1rnds4)\s+(.*)/sha1rnds4($2)/geo or + s/\b(sha1[^\s]*)\s+(.*)/sha1op38($1,$2)/geo; + + print $_,"\n"; +} +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/sha/asm/sha256-586.pl b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha256-586.pl new file mode 100644 index 00000000..e9077143 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha256-586.pl @@ -0,0 +1,1281 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# SHA256 block transform for x86. September 2007. +# +# Performance improvement over compiler generated code varies from +# 10% to 40% [see below]. Not very impressive on some µ-archs, but +# it's 5 times smaller and optimizies amount of writes. +# +# May 2012. +# +# Optimization including two of Pavel Semjanov's ideas, alternative +# Maj and full unroll, resulted in ~20-25% improvement on most CPUs, +# ~7% on Pentium, ~40% on Atom. As fully unrolled loop body is almost +# 15x larger, 8KB vs. 560B, it's fired only for longer inputs. But not +# on P4, where it kills performance, nor Sandy Bridge, where folded +# loop is approximately as fast... +# +# June 2012. +# +# Add AMD XOP-specific code path, >30% improvement on Bulldozer over +# May version, >60% over original. Add AVX+shrd code path, >25% +# improvement on Sandy Bridge over May version, 60% over original. +# +# May 2013. +# +# Replace AMD XOP code path with SSSE3 to cover more processors. +# (Biggest improvement coefficient is on upcoming Atom Silvermont, +# not shown.) Add AVX+BMI code path. +# +# March 2014. +# +# Add support for Intel SHA Extensions. +# +# Performance in clock cycles per processed byte (less is better): +# +# gcc icc x86 asm(*) SIMD x86_64 asm(**) +# Pentium 46 57 40/38 - - +# PIII 36 33 27/24 - - +# P4 41 38 28 - 17.3 +# AMD K8 27 25 19/15.5 - 14.9 +# Core2 26 23 18/15.6 14.3 13.8 +# Westmere 27 - 19/15.7 13.4 12.3 +# Sandy Bridge 25 - 15.9 12.4 11.6 +# Ivy Bridge 24 - 15.0 11.4 10.3 +# Haswell 22 - 13.9 9.46 7.80 +# Bulldozer 36 - 27/22 17.0 13.6 +# VIA Nano 36 - 25/22 16.8 16.5 +# Atom 50 - 30/25 21.9 18.9 +# Silvermont 40 - 34/31 22.9 20.6 +# +# (*) numbers after slash are for unrolled loop, where applicable; +# (**) x86_64 assembly performance is presented for reference +# purposes, results are best-available; + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +push(@INC,"${dir}","${dir}../../perlasm"); +require "x86asm.pl"; + +&asm_init($ARGV[0],"sha512-586.pl",$ARGV[$#ARGV] eq "386"); + +$xmm=$avx=0; +for (@ARGV) { $xmm=1 if (/-DOPENSSL_IA32_SSE2/); } + +if ($xmm && `$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1` + =~ /GNU assembler version ([2-9]\.[0-9]+)/) { + $avx = ($1>=2.19) + ($1>=2.22); +} + +if ($xmm && !$avx && $ARGV[0] eq "win32n" && + `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) { + $avx = ($1>=2.03) + ($1>=2.10); +} + +if ($xmm && !$avx && $ARGV[0] eq "win32" && + `ml 2>&1` =~ /Version ([0-9]+)\./) { + $avx = ($1>=10) + ($1>=11); +} + +if ($xmm && !$avx && `$ENV{CC} -v 2>&1` =~ /(^clang version|based on LLVM) ([3-9]\.[0-9]+)/) { + $avx = ($2>=3.0) + ($2>3.0); +} + +$shaext=$xmm; ### set to zero if compiling for 1.0.1 + +$unroll_after = 64*4; # If pre-evicted from L1P cache first spin of + # fully unrolled loop was measured to run about + # 3-4x slower. If slowdown coefficient is N and + # unrolled loop is m times faster, then you break + # even at (N-1)/(m-1) blocks. Then it needs to be + # adjusted for probability of code being evicted, + # code size/cache size=1/4. Typical m is 1.15... + +$A="eax"; +$E="edx"; +$T="ebx"; +$Aoff=&DWP(4,"esp"); +$Boff=&DWP(8,"esp"); +$Coff=&DWP(12,"esp"); +$Doff=&DWP(16,"esp"); +$Eoff=&DWP(20,"esp"); +$Foff=&DWP(24,"esp"); +$Goff=&DWP(28,"esp"); +$Hoff=&DWP(32,"esp"); +$Xoff=&DWP(36,"esp"); +$K256="ebp"; + +sub BODY_16_63() { + &mov ($T,"ecx"); # "ecx" is preloaded + &mov ("esi",&DWP(4*(9+15+16-14),"esp")); + &ror ("ecx",18-7); + &mov ("edi","esi"); + &ror ("esi",19-17); + &xor ("ecx",$T); + &shr ($T,3); + &ror ("ecx",7); + &xor ("esi","edi"); + &xor ($T,"ecx"); # T = sigma0(X[-15]) + &ror ("esi",17); + &add ($T,&DWP(4*(9+15+16),"esp")); # T += X[-16] + &shr ("edi",10); + &add ($T,&DWP(4*(9+15+16-9),"esp")); # T += X[-7] + #&xor ("edi","esi") # sigma1(X[-2]) + # &add ($T,"edi"); # T += sigma1(X[-2]) + # &mov (&DWP(4*(9+15),"esp"),$T); # save X[0] + + &BODY_00_15(1); +} +sub BODY_00_15() { + my $in_16_63=shift; + + &mov ("ecx",$E); + &xor ("edi","esi") if ($in_16_63); # sigma1(X[-2]) + &mov ("esi",$Foff); + &ror ("ecx",25-11); + &add ($T,"edi") if ($in_16_63); # T += sigma1(X[-2]) + &mov ("edi",$Goff); + &xor ("ecx",$E); + &xor ("esi","edi"); + &mov ($T,&DWP(4*(9+15),"esp")) if (!$in_16_63); + &mov (&DWP(4*(9+15),"esp"),$T) if ($in_16_63); # save X[0] + &ror ("ecx",11-6); + &and ("esi",$E); + &mov ($Eoff,$E); # modulo-scheduled + &xor ($E,"ecx"); + &add ($T,$Hoff); # T += h + &xor ("esi","edi"); # Ch(e,f,g) + &ror ($E,6); # Sigma1(e) + &mov ("ecx",$A); + &add ($T,"esi"); # T += Ch(e,f,g) + + &ror ("ecx",22-13); + &add ($T,$E); # T += Sigma1(e) + &mov ("edi",$Boff); + &xor ("ecx",$A); + &mov ($Aoff,$A); # modulo-scheduled + &lea ("esp",&DWP(-4,"esp")); + &ror ("ecx",13-2); + &mov ("esi",&DWP(0,$K256)); + &xor ("ecx",$A); + &mov ($E,$Eoff); # e in next iteration, d in this one + &xor ($A,"edi"); # a ^= b + &ror ("ecx",2); # Sigma0(a) + + &add ($T,"esi"); # T+= K[i] + &mov (&DWP(0,"esp"),$A); # (b^c) in next round + &add ($E,$T); # d += T + &and ($A,&DWP(4,"esp")); # a &= (b^c) + &add ($T,"ecx"); # T += Sigma0(a) + &xor ($A,"edi"); # h = Maj(a,b,c) = Ch(a^b,c,b) + &mov ("ecx",&DWP(4*(9+15+16-1),"esp")) if ($in_16_63); # preload T + &add ($K256,4); + &add ($A,$T); # h += T +} + +&external_label("OPENSSL_ia32cap_P") if (!$i386); + +&function_begin("sha256_block_data_order"); + &mov ("esi",wparam(0)); # ctx + &mov ("edi",wparam(1)); # inp + &mov ("eax",wparam(2)); # num + &mov ("ebx","esp"); # saved sp + + &call (&label("pic_point")); # make it PIC! +&set_label("pic_point"); + &blindpop($K256); + &lea ($K256,&DWP(&label("K256")."-".&label("pic_point"),$K256)); + + &sub ("esp",16); + &and ("esp",-64); + + &shl ("eax",6); + &add ("eax","edi"); + &mov (&DWP(0,"esp"),"esi"); # ctx + &mov (&DWP(4,"esp"),"edi"); # inp + &mov (&DWP(8,"esp"),"eax"); # inp+num*128 + &mov (&DWP(12,"esp"),"ebx"); # saved sp + if (!$i386 && $xmm) { + &picmeup("edx","OPENSSL_ia32cap_P",$K256,&label("K256")); + &mov ("ecx",&DWP(0,"edx")); + &mov ("ebx",&DWP(4,"edx")); + &test ("ecx",1<<20); # check for P4 + &jnz (&label("loop")); + &mov ("edx",&DWP(8,"edx")) if ($xmm); + &test ("ecx",1<<24); # check for FXSR + &jz ($unroll_after?&label("no_xmm"):&label("loop")); + &and ("ecx",1<<30); # mask "Intel CPU" bit + &and ("ebx",1<<28|1<<9); # mask AVX and SSSE3 bits + &test ("edx",1<<29) if ($shaext); # check for SHA + &jnz (&label("shaext")) if ($shaext); + &or ("ecx","ebx"); + &and ("ecx",1<<28|1<<30); + &cmp ("ecx",1<<28|1<<30); + if ($xmm) { + &je (&label("AVX")) if ($avx); + &test ("ebx",1<<9); # check for SSSE3 + &jnz (&label("SSSE3")); + } else { + &je (&label("loop_shrd")); + } + if ($unroll_after) { +&set_label("no_xmm"); + &sub ("eax","edi"); + &cmp ("eax",$unroll_after); + &jae (&label("unrolled")); + } } + &jmp (&label("loop")); + +sub COMPACT_LOOP() { +my $suffix=shift; + +&set_label("loop$suffix",$suffix?32:16); + # copy input block to stack reversing byte and dword order + for($i=0;$i<4;$i++) { + &mov ("eax",&DWP($i*16+0,"edi")); + &mov ("ebx",&DWP($i*16+4,"edi")); + &mov ("ecx",&DWP($i*16+8,"edi")); + &bswap ("eax"); + &mov ("edx",&DWP($i*16+12,"edi")); + &bswap ("ebx"); + &push ("eax"); + &bswap ("ecx"); + &push ("ebx"); + &bswap ("edx"); + &push ("ecx"); + &push ("edx"); + } + &add ("edi",64); + &lea ("esp",&DWP(-4*9,"esp"));# place for A,B,C,D,E,F,G,H + &mov (&DWP(4*(9+16)+4,"esp"),"edi"); + + # copy ctx->h[0-7] to A,B,C,D,E,F,G,H on stack + &mov ($A,&DWP(0,"esi")); + &mov ("ebx",&DWP(4,"esi")); + &mov ("ecx",&DWP(8,"esi")); + &mov ("edi",&DWP(12,"esi")); + # &mov ($Aoff,$A); + &mov ($Boff,"ebx"); + &xor ("ebx","ecx"); + &mov ($Coff,"ecx"); + &mov ($Doff,"edi"); + &mov (&DWP(0,"esp"),"ebx"); # magic + &mov ($E,&DWP(16,"esi")); + &mov ("ebx",&DWP(20,"esi")); + &mov ("ecx",&DWP(24,"esi")); + &mov ("edi",&DWP(28,"esi")); + # &mov ($Eoff,$E); + &mov ($Foff,"ebx"); + &mov ($Goff,"ecx"); + &mov ($Hoff,"edi"); + +&set_label("00_15$suffix",16); + + &BODY_00_15(); + + &cmp ("esi",0xc19bf174); + &jne (&label("00_15$suffix")); + + &mov ("ecx",&DWP(4*(9+15+16-1),"esp")); # preloaded in BODY_00_15(1) + &jmp (&label("16_63$suffix")); + +&set_label("16_63$suffix",16); + + &BODY_16_63(); + + &cmp ("esi",0xc67178f2); + &jne (&label("16_63$suffix")); + + &mov ("esi",&DWP(4*(9+16+64)+0,"esp"));#ctx + # &mov ($A,$Aoff); + &mov ("ebx",$Boff); + # &mov ("edi",$Coff); + &mov ("ecx",$Doff); + &add ($A,&DWP(0,"esi")); + &add ("ebx",&DWP(4,"esi")); + &add ("edi",&DWP(8,"esi")); + &add ("ecx",&DWP(12,"esi")); + &mov (&DWP(0,"esi"),$A); + &mov (&DWP(4,"esi"),"ebx"); + &mov (&DWP(8,"esi"),"edi"); + &mov (&DWP(12,"esi"),"ecx"); + # &mov ($E,$Eoff); + &mov ("eax",$Foff); + &mov ("ebx",$Goff); + &mov ("ecx",$Hoff); + &mov ("edi",&DWP(4*(9+16+64)+4,"esp"));#inp + &add ($E,&DWP(16,"esi")); + &add ("eax",&DWP(20,"esi")); + &add ("ebx",&DWP(24,"esi")); + &add ("ecx",&DWP(28,"esi")); + &mov (&DWP(16,"esi"),$E); + &mov (&DWP(20,"esi"),"eax"); + &mov (&DWP(24,"esi"),"ebx"); + &mov (&DWP(28,"esi"),"ecx"); + + &lea ("esp",&DWP(4*(9+16+64),"esp"));# destroy frame + &sub ($K256,4*64); # rewind K + + &cmp ("edi",&DWP(8,"esp")); # are we done yet? + &jb (&label("loop$suffix")); +} + &COMPACT_LOOP(); + &mov ("esp",&DWP(12,"esp")); # restore sp +&function_end_A(); + if (!$i386 && !$xmm) { + # ~20% improvement on Sandy Bridge + local *ror = sub { &shrd(@_[0],@_) }; + &COMPACT_LOOP("_shrd"); + &mov ("esp",&DWP(12,"esp")); # restore sp +&function_end_A(); + } + +&set_label("K256",64); # Yes! I keep it in the code segment! +@K256=( 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5, + 0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, + 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3, + 0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, + 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc, + 0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, + 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7, + 0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, + 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13, + 0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, + 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3, + 0xd192e819,0xd6990624,0xf40e3585,0x106aa070, + 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5, + 0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, + 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208, + 0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 ); +&data_word(@K256); +&data_word(0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f); # byte swap mask +&asciz("SHA256 block transform for x86, CRYPTOGAMS by "); + +($a,$b,$c,$d,$e,$f,$g,$h)=(0..7); # offsets +sub off { &DWP(4*(((shift)-$i)&7),"esp"); } + +if (!$i386 && $unroll_after) { +my @AH=($A,$K256); + +&set_label("unrolled",16); + &lea ("esp",&DWP(-96,"esp")); + # copy ctx->h[0-7] to A,B,C,D,E,F,G,H on stack + &mov ($AH[0],&DWP(0,"esi")); + &mov ($AH[1],&DWP(4,"esi")); + &mov ("ecx",&DWP(8,"esi")); + &mov ("ebx",&DWP(12,"esi")); + #&mov (&DWP(0,"esp"),$AH[0]); + &mov (&DWP(4,"esp"),$AH[1]); + &xor ($AH[1],"ecx"); # magic + &mov (&DWP(8,"esp"),"ecx"); + &mov (&DWP(12,"esp"),"ebx"); + &mov ($E,&DWP(16,"esi")); + &mov ("ebx",&DWP(20,"esi")); + &mov ("ecx",&DWP(24,"esi")); + &mov ("esi",&DWP(28,"esi")); + #&mov (&DWP(16,"esp"),$E); + &mov (&DWP(20,"esp"),"ebx"); + &mov (&DWP(24,"esp"),"ecx"); + &mov (&DWP(28,"esp"),"esi"); + &jmp (&label("grand_loop")); + +&set_label("grand_loop",16); + # copy input block to stack reversing byte order + for($i=0;$i<5;$i++) { + &mov ("ebx",&DWP(12*$i+0,"edi")); + &mov ("ecx",&DWP(12*$i+4,"edi")); + &bswap ("ebx"); + &mov ("esi",&DWP(12*$i+8,"edi")); + &bswap ("ecx"); + &mov (&DWP(32+12*$i+0,"esp"),"ebx"); + &bswap ("esi"); + &mov (&DWP(32+12*$i+4,"esp"),"ecx"); + &mov (&DWP(32+12*$i+8,"esp"),"esi"); + } + &mov ("ebx",&DWP($i*12,"edi")); + &add ("edi",64); + &bswap ("ebx"); + &mov (&DWP(96+4,"esp"),"edi"); + &mov (&DWP(32+12*$i,"esp"),"ebx"); + + my ($t1,$t2) = ("ecx","esi"); + + for ($i=0;$i<64;$i++) { + + if ($i>=16) { + &mov ($T,$t1); # $t1 is preloaded + # &mov ($t2,&DWP(32+4*(($i+14)&15),"esp")); + &ror ($t1,18-7); + &mov ("edi",$t2); + &ror ($t2,19-17); + &xor ($t1,$T); + &shr ($T,3); + &ror ($t1,7); + &xor ($t2,"edi"); + &xor ($T,$t1); # T = sigma0(X[-15]) + &ror ($t2,17); + &add ($T,&DWP(32+4*($i&15),"esp")); # T += X[-16] + &shr ("edi",10); + &add ($T,&DWP(32+4*(($i+9)&15),"esp")); # T += X[-7] + #&xor ("edi",$t2) # sigma1(X[-2]) + # &add ($T,"edi"); # T += sigma1(X[-2]) + # &mov (&DWP(4*(9+15),"esp"),$T); # save X[0] + } + &mov ($t1,$E); + &xor ("edi",$t2) if ($i>=16); # sigma1(X[-2]) + &mov ($t2,&off($f)); + &ror ($E,25-11); + &add ($T,"edi") if ($i>=16); # T += sigma1(X[-2]) + &mov ("edi",&off($g)); + &xor ($E,$t1); + &mov ($T,&DWP(32+4*($i&15),"esp")) if ($i<16); # X[i] + &mov (&DWP(32+4*($i&15),"esp"),$T) if ($i>=16 && $i<62); # save X[0] + &xor ($t2,"edi"); + &ror ($E,11-6); + &and ($t2,$t1); + &mov (&off($e),$t1); # save $E, modulo-scheduled + &xor ($E,$t1); + &add ($T,&off($h)); # T += h + &xor ("edi",$t2); # Ch(e,f,g) + &ror ($E,6); # Sigma1(e) + &mov ($t1,$AH[0]); + &add ($T,"edi"); # T += Ch(e,f,g) + + &ror ($t1,22-13); + &mov ($t2,$AH[0]); + &mov ("edi",&off($b)); + &xor ($t1,$AH[0]); + &mov (&off($a),$AH[0]); # save $A, modulo-scheduled + &xor ($AH[0],"edi"); # a ^= b, (b^c) in next round + &ror ($t1,13-2); + &and ($AH[1],$AH[0]); # (b^c) &= (a^b) + &lea ($E,&DWP(@K256[$i],$T,$E)); # T += Sigma1(1)+K[i] + &xor ($t1,$t2); + &xor ($AH[1],"edi"); # h = Maj(a,b,c) = Ch(a^b,c,b) + &mov ($t2,&DWP(32+4*(($i+2)&15),"esp")) if ($i>=15 && $i<63); + &ror ($t1,2); # Sigma0(a) + + &add ($AH[1],$E); # h += T + &add ($E,&off($d)); # d += T + &add ($AH[1],$t1); # h += Sigma0(a) + &mov ($t1,&DWP(32+4*(($i+15)&15),"esp")) if ($i>=15 && $i<63); + + @AH = reverse(@AH); # rotate(a,h) + ($t1,$t2) = ($t2,$t1); # rotate(t1,t2) + } + &mov ("esi",&DWP(96,"esp")); #ctx + #&mov ($AH[0],&DWP(0,"esp")); + &xor ($AH[1],"edi"); #&mov ($AH[1],&DWP(4,"esp")); + #&mov ("edi", &DWP(8,"esp")); + &mov ("ecx",&DWP(12,"esp")); + &add ($AH[0],&DWP(0,"esi")); + &add ($AH[1],&DWP(4,"esi")); + &add ("edi",&DWP(8,"esi")); + &add ("ecx",&DWP(12,"esi")); + &mov (&DWP(0,"esi"),$AH[0]); + &mov (&DWP(4,"esi"),$AH[1]); + &mov (&DWP(8,"esi"),"edi"); + &mov (&DWP(12,"esi"),"ecx"); + #&mov (&DWP(0,"esp"),$AH[0]); + &mov (&DWP(4,"esp"),$AH[1]); + &xor ($AH[1],"edi"); # magic + &mov (&DWP(8,"esp"),"edi"); + &mov (&DWP(12,"esp"),"ecx"); + #&mov ($E,&DWP(16,"esp")); + &mov ("edi",&DWP(20,"esp")); + &mov ("ebx",&DWP(24,"esp")); + &mov ("ecx",&DWP(28,"esp")); + &add ($E,&DWP(16,"esi")); + &add ("edi",&DWP(20,"esi")); + &add ("ebx",&DWP(24,"esi")); + &add ("ecx",&DWP(28,"esi")); + &mov (&DWP(16,"esi"),$E); + &mov (&DWP(20,"esi"),"edi"); + &mov (&DWP(24,"esi"),"ebx"); + &mov (&DWP(28,"esi"),"ecx"); + #&mov (&DWP(16,"esp"),$E); + &mov (&DWP(20,"esp"),"edi"); + &mov ("edi",&DWP(96+4,"esp")); # inp + &mov (&DWP(24,"esp"),"ebx"); + &mov (&DWP(28,"esp"),"ecx"); + + &cmp ("edi",&DWP(96+8,"esp")); # are we done yet? + &jb (&label("grand_loop")); + + &mov ("esp",&DWP(96+12,"esp")); # restore sp +&function_end_A(); +} + if (!$i386 && $xmm) {{{ +if ($shaext) { +###################################################################### +# Intel SHA Extensions implementation of SHA256 update function. +# +my ($ctx,$inp,$end)=("esi","edi","eax"); +my ($Wi,$ABEF,$CDGH,$TMP)=map("xmm$_",(0..2,7)); +my @MSG=map("xmm$_",(3..6)); + +sub sha256op38 { + my ($opcodelet,$dst,$src)=@_; + if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/) + { &data_byte(0x0f,0x38,$opcodelet,0xc0|($1<<3)|$2); } +} +sub sha256rnds2 { sha256op38(0xcb,@_); } +sub sha256msg1 { sha256op38(0xcc,@_); } +sub sha256msg2 { sha256op38(0xcd,@_); } + +&set_label("shaext",32); + &sub ("esp",32); + + &movdqu ($ABEF,&QWP(0,$ctx)); # DCBA + &lea ($K256,&DWP(0x80,$K256)); + &movdqu ($CDGH,&QWP(16,$ctx)); # HGFE + &movdqa ($TMP,&QWP(0x100-0x80,$K256)); # byte swap mask + + &pshufd ($Wi,$ABEF,0x1b); # ABCD + &pshufd ($ABEF,$ABEF,0xb1); # CDAB + &pshufd ($CDGH,$CDGH,0x1b); # EFGH + &palignr ($ABEF,$CDGH,8); # ABEF + &punpcklqdq ($CDGH,$Wi); # CDGH + &jmp (&label("loop_shaext")); + +&set_label("loop_shaext",16); + &movdqu (@MSG[0],&QWP(0,$inp)); + &movdqu (@MSG[1],&QWP(0x10,$inp)); + &movdqu (@MSG[2],&QWP(0x20,$inp)); + &pshufb (@MSG[0],$TMP); + &movdqu (@MSG[3],&QWP(0x30,$inp)); + &movdqa (&QWP(16,"esp"),$CDGH); # offload + + &movdqa ($Wi,&QWP(0*16-0x80,$K256)); + &paddd ($Wi,@MSG[0]); + &pshufb (@MSG[1],$TMP); + &sha256rnds2 ($CDGH,$ABEF); # 0-3 + &pshufd ($Wi,$Wi,0x0e); + &nop (); + &movdqa (&QWP(0,"esp"),$ABEF); # offload + &sha256rnds2 ($ABEF,$CDGH); + + &movdqa ($Wi,&QWP(1*16-0x80,$K256)); + &paddd ($Wi,@MSG[1]); + &pshufb (@MSG[2],$TMP); + &sha256rnds2 ($CDGH,$ABEF); # 4-7 + &pshufd ($Wi,$Wi,0x0e); + &lea ($inp,&DWP(0x40,$inp)); + &sha256msg1 (@MSG[0],@MSG[1]); + &sha256rnds2 ($ABEF,$CDGH); + + &movdqa ($Wi,&QWP(2*16-0x80,$K256)); + &paddd ($Wi,@MSG[2]); + &pshufb (@MSG[3],$TMP); + &sha256rnds2 ($CDGH,$ABEF); # 8-11 + &pshufd ($Wi,$Wi,0x0e); + &movdqa ($TMP,@MSG[3]); + &palignr ($TMP,@MSG[2],4); + &nop (); + &paddd (@MSG[0],$TMP); + &sha256msg1 (@MSG[1],@MSG[2]); + &sha256rnds2 ($ABEF,$CDGH); + + &movdqa ($Wi,&QWP(3*16-0x80,$K256)); + &paddd ($Wi,@MSG[3]); + &sha256msg2 (@MSG[0],@MSG[3]); + &sha256rnds2 ($CDGH,$ABEF); # 12-15 + &pshufd ($Wi,$Wi,0x0e); + &movdqa ($TMP,@MSG[0]); + &palignr ($TMP,@MSG[3],4); + &nop (); + &paddd (@MSG[1],$TMP); + &sha256msg1 (@MSG[2],@MSG[3]); + &sha256rnds2 ($ABEF,$CDGH); + +for($i=4;$i<16-3;$i++) { + &movdqa ($Wi,&QWP($i*16-0x80,$K256)); + &paddd ($Wi,@MSG[0]); + &sha256msg2 (@MSG[1],@MSG[0]); + &sha256rnds2 ($CDGH,$ABEF); # 16-19... + &pshufd ($Wi,$Wi,0x0e); + &movdqa ($TMP,@MSG[1]); + &palignr ($TMP,@MSG[0],4); + &nop (); + &paddd (@MSG[2],$TMP); + &sha256msg1 (@MSG[3],@MSG[0]); + &sha256rnds2 ($ABEF,$CDGH); + + push(@MSG,shift(@MSG)); +} + &movdqa ($Wi,&QWP(13*16-0x80,$K256)); + &paddd ($Wi,@MSG[0]); + &sha256msg2 (@MSG[1],@MSG[0]); + &sha256rnds2 ($CDGH,$ABEF); # 52-55 + &pshufd ($Wi,$Wi,0x0e); + &movdqa ($TMP,@MSG[1]) + &palignr ($TMP,@MSG[0],4); + &sha256rnds2 ($ABEF,$CDGH); + &paddd (@MSG[2],$TMP); + + &movdqa ($Wi,&QWP(14*16-0x80,$K256)); + &paddd ($Wi,@MSG[1]); + &sha256rnds2 ($CDGH,$ABEF); # 56-59 + &pshufd ($Wi,$Wi,0x0e); + &sha256msg2 (@MSG[2],@MSG[1]); + &movdqa ($TMP,&QWP(0x100-0x80,$K256)); # byte swap mask + &sha256rnds2 ($ABEF,$CDGH); + + &movdqa ($Wi,&QWP(15*16-0x80,$K256)); + &paddd ($Wi,@MSG[2]); + &nop (); + &sha256rnds2 ($CDGH,$ABEF); # 60-63 + &pshufd ($Wi,$Wi,0x0e); + &cmp ($end,$inp); + &nop (); + &sha256rnds2 ($ABEF,$CDGH); + + &paddd ($CDGH,&QWP(16,"esp")); + &paddd ($ABEF,&QWP(0,"esp")); + &jnz (&label("loop_shaext")); + + &pshufd ($CDGH,$CDGH,0xb1); # DCHG + &pshufd ($TMP,$ABEF,0x1b); # FEBA + &pshufd ($ABEF,$ABEF,0xb1); # BAFE + &punpckhqdq ($ABEF,$CDGH); # DCBA + &palignr ($CDGH,$TMP,8); # HGFE + + &mov ("esp",&DWP(32+12,"esp")); + &movdqu (&QWP(0,$ctx),$ABEF); + &movdqu (&QWP(16,$ctx),$CDGH); +&function_end_A(); +} + +my @X = map("xmm$_",(0..3)); +my ($t0,$t1,$t2,$t3) = map("xmm$_",(4..7)); +my @AH = ($A,$T); + +&set_label("SSSE3",32); + &lea ("esp",&DWP(-96,"esp")); + # copy ctx->h[0-7] to A,B,C,D,E,F,G,H on stack + &mov ($AH[0],&DWP(0,"esi")); + &mov ($AH[1],&DWP(4,"esi")); + &mov ("ecx",&DWP(8,"esi")); + &mov ("edi",&DWP(12,"esi")); + #&mov (&DWP(0,"esp"),$AH[0]); + &mov (&DWP(4,"esp"),$AH[1]); + &xor ($AH[1],"ecx"); # magic + &mov (&DWP(8,"esp"),"ecx"); + &mov (&DWP(12,"esp"),"edi"); + &mov ($E,&DWP(16,"esi")); + &mov ("edi",&DWP(20,"esi")); + &mov ("ecx",&DWP(24,"esi")); + &mov ("esi",&DWP(28,"esi")); + #&mov (&DWP(16,"esp"),$E); + &mov (&DWP(20,"esp"),"edi"); + &mov ("edi",&DWP(96+4,"esp")); # inp + &mov (&DWP(24,"esp"),"ecx"); + &mov (&DWP(28,"esp"),"esi"); + &movdqa ($t3,&QWP(256,$K256)); + &jmp (&label("grand_ssse3")); + +&set_label("grand_ssse3",16); + # load input, reverse byte order, add K256[0..15], save to stack + &movdqu (@X[0],&QWP(0,"edi")); + &movdqu (@X[1],&QWP(16,"edi")); + &movdqu (@X[2],&QWP(32,"edi")); + &movdqu (@X[3],&QWP(48,"edi")); + &add ("edi",64); + &pshufb (@X[0],$t3); + &mov (&DWP(96+4,"esp"),"edi"); + &pshufb (@X[1],$t3); + &movdqa ($t0,&QWP(0,$K256)); + &pshufb (@X[2],$t3); + &movdqa ($t1,&QWP(16,$K256)); + &paddd ($t0,@X[0]); + &pshufb (@X[3],$t3); + &movdqa ($t2,&QWP(32,$K256)); + &paddd ($t1,@X[1]); + &movdqa ($t3,&QWP(48,$K256)); + &movdqa (&QWP(32+0,"esp"),$t0); + &paddd ($t2,@X[2]); + &movdqa (&QWP(32+16,"esp"),$t1); + &paddd ($t3,@X[3]); + &movdqa (&QWP(32+32,"esp"),$t2); + &movdqa (&QWP(32+48,"esp"),$t3); + &jmp (&label("ssse3_00_47")); + +&set_label("ssse3_00_47",16); + &add ($K256,64); + +sub SSSE3_00_47 () { +my $j = shift; +my $body = shift; +my @X = @_; +my @insns = (&$body,&$body,&$body,&$body); # 120 instructions + + eval(shift(@insns)); + &movdqa ($t0,@X[1]); + eval(shift(@insns)); # @ + eval(shift(@insns)); + &movdqa ($t3,@X[3]); + eval(shift(@insns)); + eval(shift(@insns)); + &palignr ($t0,@X[0],4); # X[1..4] + eval(shift(@insns)); + eval(shift(@insns)); # @ + eval(shift(@insns)); + &palignr ($t3,@X[2],4); # X[9..12] + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &movdqa ($t1,$t0); + eval(shift(@insns)); # @ + eval(shift(@insns)); + &movdqa ($t2,$t0); + eval(shift(@insns)); + eval(shift(@insns)); + &psrld ($t0,3); + eval(shift(@insns)); + eval(shift(@insns)); # @ + &paddd (@X[0],$t3); # X[0..3] += X[9..12] + eval(shift(@insns)); + eval(shift(@insns)); + &psrld ($t2,7); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # @ + eval(shift(@insns)); + &pshufd ($t3,@X[3],0b11111010); # X[14..15] + eval(shift(@insns)); + eval(shift(@insns)); + &pslld ($t1,32-18); + eval(shift(@insns)); + eval(shift(@insns)); # @ + &pxor ($t0,$t2); + eval(shift(@insns)); + eval(shift(@insns)); + &psrld ($t2,18-7); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # @ + &pxor ($t0,$t1); + eval(shift(@insns)); + eval(shift(@insns)); + &pslld ($t1,18-7); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # @ + &pxor ($t0,$t2); + eval(shift(@insns)); + eval(shift(@insns)); + &movdqa ($t2,$t3); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # @ + &pxor ($t0,$t1); # sigma0(X[1..4]) + eval(shift(@insns)); + eval(shift(@insns)); + &psrld ($t3,10); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # @ + &paddd (@X[0],$t0); # X[0..3] += sigma0(X[1..4]) + eval(shift(@insns)); + eval(shift(@insns)); + &psrlq ($t2,17); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # @ + &pxor ($t3,$t2); + eval(shift(@insns)); + eval(shift(@insns)); + &psrlq ($t2,19-17); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # @ + &pxor ($t3,$t2); + eval(shift(@insns)); + eval(shift(@insns)); + &pshufd ($t3,$t3,0b10000000); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # @ + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # @ + eval(shift(@insns)); + &psrldq ($t3,8); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &paddd (@X[0],$t3); # X[0..1] += sigma1(X[14..15]) + eval(shift(@insns)); # @ + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # @ + eval(shift(@insns)); + &pshufd ($t3,@X[0],0b01010000); # X[16..17] + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &movdqa ($t2,$t3); + eval(shift(@insns)); # @ + &psrld ($t3,10); + eval(shift(@insns)); + &psrlq ($t2,17); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # @ + &pxor ($t3,$t2); + eval(shift(@insns)); + eval(shift(@insns)); + &psrlq ($t2,19-17); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # @ + &pxor ($t3,$t2); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &pshufd ($t3,$t3,0b00001000); + eval(shift(@insns)); + eval(shift(@insns)); # @ + &movdqa ($t2,&QWP(16*$j,$K256)); + eval(shift(@insns)); + eval(shift(@insns)); + &pslldq ($t3,8); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # @ + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # @ + &paddd (@X[0],$t3); # X[2..3] += sigma1(X[16..17]) + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &paddd ($t2,@X[0]); + eval(shift(@insns)); # @ + + foreach (@insns) { eval; } # remaining instructions + + &movdqa (&QWP(32+16*$j,"esp"),$t2); +} + +sub body_00_15 () { + ( + '&mov ("ecx",$E);', + '&ror ($E,25-11);', + '&mov ("esi",&off($f));', + '&xor ($E,"ecx");', + '&mov ("edi",&off($g));', + '&xor ("esi","edi");', + '&ror ($E,11-6);', + '&and ("esi","ecx");', + '&mov (&off($e),"ecx");', # save $E, modulo-scheduled + '&xor ($E,"ecx");', + '&xor ("edi","esi");', # Ch(e,f,g) + '&ror ($E,6);', # T = Sigma1(e) + '&mov ("ecx",$AH[0]);', + '&add ($E,"edi");', # T += Ch(e,f,g) + '&mov ("edi",&off($b));', + '&mov ("esi",$AH[0]);', + + '&ror ("ecx",22-13);', + '&mov (&off($a),$AH[0]);', # save $A, modulo-scheduled + '&xor ("ecx",$AH[0]);', + '&xor ($AH[0],"edi");', # a ^= b, (b^c) in next round + '&add ($E,&off($h));', # T += h + '&ror ("ecx",13-2);', + '&and ($AH[1],$AH[0]);', # (b^c) &= (a^b) + '&xor ("ecx","esi");', + '&add ($E,&DWP(32+4*($i&15),"esp"));', # T += K[i]+X[i] + '&xor ($AH[1],"edi");', # h = Maj(a,b,c) = Ch(a^b,c,b) + '&ror ("ecx",2);', # Sigma0(a) + + '&add ($AH[1],$E);', # h += T + '&add ($E,&off($d));', # d += T + '&add ($AH[1],"ecx");'. # h += Sigma0(a) + + '@AH = reverse(@AH); $i++;' # rotate(a,h) + ); +} + + for ($i=0,$j=0; $j<4; $j++) { + &SSSE3_00_47($j,\&body_00_15,@X); + push(@X,shift(@X)); # rotate(@X) + } + &cmp (&DWP(16*$j,$K256),0x00010203); + &jne (&label("ssse3_00_47")); + + for ($i=0; $i<16; ) { + foreach(body_00_15()) { eval; } + } + + &mov ("esi",&DWP(96,"esp")); #ctx + #&mov ($AH[0],&DWP(0,"esp")); + &xor ($AH[1],"edi"); #&mov ($AH[1],&DWP(4,"esp")); + #&mov ("edi", &DWP(8,"esp")); + &mov ("ecx",&DWP(12,"esp")); + &add ($AH[0],&DWP(0,"esi")); + &add ($AH[1],&DWP(4,"esi")); + &add ("edi",&DWP(8,"esi")); + &add ("ecx",&DWP(12,"esi")); + &mov (&DWP(0,"esi"),$AH[0]); + &mov (&DWP(4,"esi"),$AH[1]); + &mov (&DWP(8,"esi"),"edi"); + &mov (&DWP(12,"esi"),"ecx"); + #&mov (&DWP(0,"esp"),$AH[0]); + &mov (&DWP(4,"esp"),$AH[1]); + &xor ($AH[1],"edi"); # magic + &mov (&DWP(8,"esp"),"edi"); + &mov (&DWP(12,"esp"),"ecx"); + #&mov ($E,&DWP(16,"esp")); + &mov ("edi",&DWP(20,"esp")); + &mov ("ecx",&DWP(24,"esp")); + &add ($E,&DWP(16,"esi")); + &add ("edi",&DWP(20,"esi")); + &add ("ecx",&DWP(24,"esi")); + &mov (&DWP(16,"esi"),$E); + &mov (&DWP(20,"esi"),"edi"); + &mov (&DWP(20,"esp"),"edi"); + &mov ("edi",&DWP(28,"esp")); + &mov (&DWP(24,"esi"),"ecx"); + #&mov (&DWP(16,"esp"),$E); + &add ("edi",&DWP(28,"esi")); + &mov (&DWP(24,"esp"),"ecx"); + &mov (&DWP(28,"esi"),"edi"); + &mov (&DWP(28,"esp"),"edi"); + &mov ("edi",&DWP(96+4,"esp")); # inp + + &movdqa ($t3,&QWP(64,$K256)); + &sub ($K256,3*64); # rewind K + &cmp ("edi",&DWP(96+8,"esp")); # are we done yet? + &jb (&label("grand_ssse3")); + + &mov ("esp",&DWP(96+12,"esp")); # restore sp +&function_end_A(); + if ($avx) { +&set_label("AVX",32); + if ($avx>1) { + &and ("edx",1<<8|1<<3); # check for BMI2+BMI1 + &cmp ("edx",1<<8|1<<3); + &je (&label("AVX_BMI")); + } + &lea ("esp",&DWP(-96,"esp")); + &vzeroall (); + # copy ctx->h[0-7] to A,B,C,D,E,F,G,H on stack + &mov ($AH[0],&DWP(0,"esi")); + &mov ($AH[1],&DWP(4,"esi")); + &mov ("ecx",&DWP(8,"esi")); + &mov ("edi",&DWP(12,"esi")); + #&mov (&DWP(0,"esp"),$AH[0]); + &mov (&DWP(4,"esp"),$AH[1]); + &xor ($AH[1],"ecx"); # magic + &mov (&DWP(8,"esp"),"ecx"); + &mov (&DWP(12,"esp"),"edi"); + &mov ($E,&DWP(16,"esi")); + &mov ("edi",&DWP(20,"esi")); + &mov ("ecx",&DWP(24,"esi")); + &mov ("esi",&DWP(28,"esi")); + #&mov (&DWP(16,"esp"),$E); + &mov (&DWP(20,"esp"),"edi"); + &mov ("edi",&DWP(96+4,"esp")); # inp + &mov (&DWP(24,"esp"),"ecx"); + &mov (&DWP(28,"esp"),"esi"); + &vmovdqa ($t3,&QWP(256,$K256)); + &jmp (&label("grand_avx")); + +&set_label("grand_avx",32); + # load input, reverse byte order, add K256[0..15], save to stack + &vmovdqu (@X[0],&QWP(0,"edi")); + &vmovdqu (@X[1],&QWP(16,"edi")); + &vmovdqu (@X[2],&QWP(32,"edi")); + &vmovdqu (@X[3],&QWP(48,"edi")); + &add ("edi",64); + &vpshufb (@X[0],@X[0],$t3); + &mov (&DWP(96+4,"esp"),"edi"); + &vpshufb (@X[1],@X[1],$t3); + &vpshufb (@X[2],@X[2],$t3); + &vpaddd ($t0,@X[0],&QWP(0,$K256)); + &vpshufb (@X[3],@X[3],$t3); + &vpaddd ($t1,@X[1],&QWP(16,$K256)); + &vpaddd ($t2,@X[2],&QWP(32,$K256)); + &vpaddd ($t3,@X[3],&QWP(48,$K256)); + &vmovdqa (&QWP(32+0,"esp"),$t0); + &vmovdqa (&QWP(32+16,"esp"),$t1); + &vmovdqa (&QWP(32+32,"esp"),$t2); + &vmovdqa (&QWP(32+48,"esp"),$t3); + &jmp (&label("avx_00_47")); + +&set_label("avx_00_47",16); + &add ($K256,64); + +sub Xupdate_AVX () { + ( + '&vpalignr ($t0,@X[1],@X[0],4);', # X[1..4] + '&vpalignr ($t3,@X[3],@X[2],4);', # X[9..12] + '&vpsrld ($t2,$t0,7);', + '&vpaddd (@X[0],@X[0],$t3);', # X[0..3] += X[9..16] + '&vpsrld ($t3,$t0,3);', + '&vpslld ($t1,$t0,14);', + '&vpxor ($t0,$t3,$t2);', + '&vpshufd ($t3,@X[3],0b11111010)',# X[14..15] + '&vpsrld ($t2,$t2,18-7);', + '&vpxor ($t0,$t0,$t1);', + '&vpslld ($t1,$t1,25-14);', + '&vpxor ($t0,$t0,$t2);', + '&vpsrld ($t2,$t3,10);', + '&vpxor ($t0,$t0,$t1);', # sigma0(X[1..4]) + '&vpsrlq ($t1,$t3,17);', + '&vpaddd (@X[0],@X[0],$t0);', # X[0..3] += sigma0(X[1..4]) + '&vpxor ($t2,$t2,$t1);', + '&vpsrlq ($t3,$t3,19);', + '&vpxor ($t2,$t2,$t3);', # sigma1(X[14..15] + '&vpshufd ($t3,$t2,0b10000100);', + '&vpsrldq ($t3,$t3,8);', + '&vpaddd (@X[0],@X[0],$t3);', # X[0..1] += sigma1(X[14..15]) + '&vpshufd ($t3,@X[0],0b01010000)',# X[16..17] + '&vpsrld ($t2,$t3,10);', + '&vpsrlq ($t1,$t3,17);', + '&vpxor ($t2,$t2,$t1);', + '&vpsrlq ($t3,$t3,19);', + '&vpxor ($t2,$t2,$t3);', # sigma1(X[16..17] + '&vpshufd ($t3,$t2,0b11101000);', + '&vpslldq ($t3,$t3,8);', + '&vpaddd (@X[0],@X[0],$t3);' # X[2..3] += sigma1(X[16..17]) + ); +} + +local *ror = sub { &shrd(@_[0],@_) }; +sub AVX_00_47 () { +my $j = shift; +my $body = shift; +my @X = @_; +my @insns = (&$body,&$body,&$body,&$body); # 120 instructions +my $insn; + + foreach (Xupdate_AVX()) { # 31 instructions + eval; + eval(shift(@insns)); + eval(shift(@insns)); + eval($insn = shift(@insns)); + eval(shift(@insns)) if ($insn =~ /rorx/ && @insns[0] =~ /rorx/); + } + &vpaddd ($t2,@X[0],&QWP(16*$j,$K256)); + foreach (@insns) { eval; } # remaining instructions + &vmovdqa (&QWP(32+16*$j,"esp"),$t2); +} + + for ($i=0,$j=0; $j<4; $j++) { + &AVX_00_47($j,\&body_00_15,@X); + push(@X,shift(@X)); # rotate(@X) + } + &cmp (&DWP(16*$j,$K256),0x00010203); + &jne (&label("avx_00_47")); + + for ($i=0; $i<16; ) { + foreach(body_00_15()) { eval; } + } + + &mov ("esi",&DWP(96,"esp")); #ctx + #&mov ($AH[0],&DWP(0,"esp")); + &xor ($AH[1],"edi"); #&mov ($AH[1],&DWP(4,"esp")); + #&mov ("edi", &DWP(8,"esp")); + &mov ("ecx",&DWP(12,"esp")); + &add ($AH[0],&DWP(0,"esi")); + &add ($AH[1],&DWP(4,"esi")); + &add ("edi",&DWP(8,"esi")); + &add ("ecx",&DWP(12,"esi")); + &mov (&DWP(0,"esi"),$AH[0]); + &mov (&DWP(4,"esi"),$AH[1]); + &mov (&DWP(8,"esi"),"edi"); + &mov (&DWP(12,"esi"),"ecx"); + #&mov (&DWP(0,"esp"),$AH[0]); + &mov (&DWP(4,"esp"),$AH[1]); + &xor ($AH[1],"edi"); # magic + &mov (&DWP(8,"esp"),"edi"); + &mov (&DWP(12,"esp"),"ecx"); + #&mov ($E,&DWP(16,"esp")); + &mov ("edi",&DWP(20,"esp")); + &mov ("ecx",&DWP(24,"esp")); + &add ($E,&DWP(16,"esi")); + &add ("edi",&DWP(20,"esi")); + &add ("ecx",&DWP(24,"esi")); + &mov (&DWP(16,"esi"),$E); + &mov (&DWP(20,"esi"),"edi"); + &mov (&DWP(20,"esp"),"edi"); + &mov ("edi",&DWP(28,"esp")); + &mov (&DWP(24,"esi"),"ecx"); + #&mov (&DWP(16,"esp"),$E); + &add ("edi",&DWP(28,"esi")); + &mov (&DWP(24,"esp"),"ecx"); + &mov (&DWP(28,"esi"),"edi"); + &mov (&DWP(28,"esp"),"edi"); + &mov ("edi",&DWP(96+4,"esp")); # inp + + &vmovdqa ($t3,&QWP(64,$K256)); + &sub ($K256,3*64); # rewind K + &cmp ("edi",&DWP(96+8,"esp")); # are we done yet? + &jb (&label("grand_avx")); + + &mov ("esp",&DWP(96+12,"esp")); # restore sp + &vzeroall (); +&function_end_A(); + if ($avx>1) { +sub bodyx_00_15 () { # +10% + ( + '&rorx ("ecx",$E,6)', + '&rorx ("esi",$E,11)', + '&mov (&off($e),$E)', # save $E, modulo-scheduled + '&rorx ("edi",$E,25)', + '&xor ("ecx","esi")', + '&andn ("esi",$E,&off($g))', + '&xor ("ecx","edi")', # Sigma1(e) + '&and ($E,&off($f))', + '&mov (&off($a),$AH[0]);', # save $A, modulo-scheduled + '&or ($E,"esi")', # T = Ch(e,f,g) + + '&rorx ("edi",$AH[0],2)', + '&rorx ("esi",$AH[0],13)', + '&lea ($E,&DWP(0,$E,"ecx"))', # T += Sigma1(e) + '&rorx ("ecx",$AH[0],22)', + '&xor ("esi","edi")', + '&mov ("edi",&off($b))', + '&xor ("ecx","esi")', # Sigma0(a) + + '&xor ($AH[0],"edi")', # a ^= b, (b^c) in next round + '&add ($E,&off($h))', # T += h + '&and ($AH[1],$AH[0])', # (b^c) &= (a^b) + '&add ($E,&DWP(32+4*($i&15),"esp"))', # T += K[i]+X[i] + '&xor ($AH[1],"edi")', # h = Maj(a,b,c) = Ch(a^b,c,b) + + '&add ("ecx",$E)', # h += T + '&add ($E,&off($d))', # d += T + '&lea ($AH[1],&DWP(0,$AH[1],"ecx"));'. # h += Sigma0(a) + + '@AH = reverse(@AH); $i++;' # rotate(a,h) + ); +} + +&set_label("AVX_BMI",32); + &lea ("esp",&DWP(-96,"esp")); + &vzeroall (); + # copy ctx->h[0-7] to A,B,C,D,E,F,G,H on stack + &mov ($AH[0],&DWP(0,"esi")); + &mov ($AH[1],&DWP(4,"esi")); + &mov ("ecx",&DWP(8,"esi")); + &mov ("edi",&DWP(12,"esi")); + #&mov (&DWP(0,"esp"),$AH[0]); + &mov (&DWP(4,"esp"),$AH[1]); + &xor ($AH[1],"ecx"); # magic + &mov (&DWP(8,"esp"),"ecx"); + &mov (&DWP(12,"esp"),"edi"); + &mov ($E,&DWP(16,"esi")); + &mov ("edi",&DWP(20,"esi")); + &mov ("ecx",&DWP(24,"esi")); + &mov ("esi",&DWP(28,"esi")); + #&mov (&DWP(16,"esp"),$E); + &mov (&DWP(20,"esp"),"edi"); + &mov ("edi",&DWP(96+4,"esp")); # inp + &mov (&DWP(24,"esp"),"ecx"); + &mov (&DWP(28,"esp"),"esi"); + &vmovdqa ($t3,&QWP(256,$K256)); + &jmp (&label("grand_avx_bmi")); + +&set_label("grand_avx_bmi",32); + # load input, reverse byte order, add K256[0..15], save to stack + &vmovdqu (@X[0],&QWP(0,"edi")); + &vmovdqu (@X[1],&QWP(16,"edi")); + &vmovdqu (@X[2],&QWP(32,"edi")); + &vmovdqu (@X[3],&QWP(48,"edi")); + &add ("edi",64); + &vpshufb (@X[0],@X[0],$t3); + &mov (&DWP(96+4,"esp"),"edi"); + &vpshufb (@X[1],@X[1],$t3); + &vpshufb (@X[2],@X[2],$t3); + &vpaddd ($t0,@X[0],&QWP(0,$K256)); + &vpshufb (@X[3],@X[3],$t3); + &vpaddd ($t1,@X[1],&QWP(16,$K256)); + &vpaddd ($t2,@X[2],&QWP(32,$K256)); + &vpaddd ($t3,@X[3],&QWP(48,$K256)); + &vmovdqa (&QWP(32+0,"esp"),$t0); + &vmovdqa (&QWP(32+16,"esp"),$t1); + &vmovdqa (&QWP(32+32,"esp"),$t2); + &vmovdqa (&QWP(32+48,"esp"),$t3); + &jmp (&label("avx_bmi_00_47")); + +&set_label("avx_bmi_00_47",16); + &add ($K256,64); + + for ($i=0,$j=0; $j<4; $j++) { + &AVX_00_47($j,\&bodyx_00_15,@X); + push(@X,shift(@X)); # rotate(@X) + } + &cmp (&DWP(16*$j,$K256),0x00010203); + &jne (&label("avx_bmi_00_47")); + + for ($i=0; $i<16; ) { + foreach(bodyx_00_15()) { eval; } + } + + &mov ("esi",&DWP(96,"esp")); #ctx + #&mov ($AH[0],&DWP(0,"esp")); + &xor ($AH[1],"edi"); #&mov ($AH[1],&DWP(4,"esp")); + #&mov ("edi", &DWP(8,"esp")); + &mov ("ecx",&DWP(12,"esp")); + &add ($AH[0],&DWP(0,"esi")); + &add ($AH[1],&DWP(4,"esi")); + &add ("edi",&DWP(8,"esi")); + &add ("ecx",&DWP(12,"esi")); + &mov (&DWP(0,"esi"),$AH[0]); + &mov (&DWP(4,"esi"),$AH[1]); + &mov (&DWP(8,"esi"),"edi"); + &mov (&DWP(12,"esi"),"ecx"); + #&mov (&DWP(0,"esp"),$AH[0]); + &mov (&DWP(4,"esp"),$AH[1]); + &xor ($AH[1],"edi"); # magic + &mov (&DWP(8,"esp"),"edi"); + &mov (&DWP(12,"esp"),"ecx"); + #&mov ($E,&DWP(16,"esp")); + &mov ("edi",&DWP(20,"esp")); + &mov ("ecx",&DWP(24,"esp")); + &add ($E,&DWP(16,"esi")); + &add ("edi",&DWP(20,"esi")); + &add ("ecx",&DWP(24,"esi")); + &mov (&DWP(16,"esi"),$E); + &mov (&DWP(20,"esi"),"edi"); + &mov (&DWP(20,"esp"),"edi"); + &mov ("edi",&DWP(28,"esp")); + &mov (&DWP(24,"esi"),"ecx"); + #&mov (&DWP(16,"esp"),$E); + &add ("edi",&DWP(28,"esi")); + &mov (&DWP(24,"esp"),"ecx"); + &mov (&DWP(28,"esi"),"edi"); + &mov (&DWP(28,"esp"),"edi"); + &mov ("edi",&DWP(96+4,"esp")); # inp + + &vmovdqa ($t3,&QWP(64,$K256)); + &sub ($K256,3*64); # rewind K + &cmp ("edi",&DWP(96+8,"esp")); # are we done yet? + &jb (&label("grand_avx_bmi")); + + &mov ("esp",&DWP(96+12,"esp")); # restore sp + &vzeroall (); +&function_end_A(); + } + } + }}} +&function_end_B("sha256_block_data_order"); + +&asm_finish(); diff --git a/TMessagesProj/jni/boringssl/crypto/sha/asm/sha256-armv4.pl b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha256-armv4.pl new file mode 100644 index 00000000..df71676d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha256-armv4.pl @@ -0,0 +1,735 @@ +#!/usr/bin/env perl + +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# +# Permission to use under GPL terms is granted. +# ==================================================================== + +# SHA256 block procedure for ARMv4. May 2007. + +# Performance is ~2x better than gcc 3.4 generated code and in "abso- +# lute" terms is ~2250 cycles per 64-byte block or ~35 cycles per +# byte [on single-issue Xscale PXA250 core]. + +# July 2010. +# +# Rescheduling for dual-issue pipeline resulted in 22% improvement on +# Cortex A8 core and ~20 cycles per processed byte. + +# February 2011. +# +# Profiler-assisted and platform-specific optimization resulted in 16% +# improvement on Cortex A8 core and ~15.4 cycles per processed byte. + +# September 2013. +# +# Add NEON implementation. On Cortex A8 it was measured to process one +# byte in 12.5 cycles or 23% faster than integer-only code. Snapdragon +# S4 does it in 12.5 cycles too, but it's 50% faster than integer-only +# code (meaning that latter performs sub-optimally, nothing was done +# about it). + +# May 2014. +# +# Add ARMv8 code path performing at 2.0 cpb on Apple A7. + +$flavour = shift; +if ($flavour=~/^\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; } +else { while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {} } + +if ($flavour && $flavour ne "void") { + $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; + ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or + ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or + die "can't locate arm-xlate.pl"; + + open STDOUT,"| \"$^X\" $xlate $flavour $output"; +} else { + open STDOUT,">$output"; +} + +$ctx="r0"; $t0="r0"; +$inp="r1"; $t4="r1"; +$len="r2"; $t1="r2"; +$T1="r3"; $t3="r3"; +$A="r4"; +$B="r5"; +$C="r6"; +$D="r7"; +$E="r8"; +$F="r9"; +$G="r10"; +$H="r11"; +@V=($A,$B,$C,$D,$E,$F,$G,$H); +$t2="r12"; +$Ktbl="r14"; + +@Sigma0=( 2,13,22); +@Sigma1=( 6,11,25); +@sigma0=( 7,18, 3); +@sigma1=(17,19,10); + +sub BODY_00_15 { +my ($i,$a,$b,$c,$d,$e,$f,$g,$h) = @_; + +$code.=<<___ if ($i<16); +#if __ARM_ARCH__>=7 + @ ldr $t1,[$inp],#4 @ $i +# if $i==15 + str $inp,[sp,#17*4] @ make room for $t4 +# endif + eor $t0,$e,$e,ror#`$Sigma1[1]-$Sigma1[0]` + add $a,$a,$t2 @ h+=Maj(a,b,c) from the past + eor $t0,$t0,$e,ror#`$Sigma1[2]-$Sigma1[0]` @ Sigma1(e) +# ifndef __ARMEB__ + rev $t1,$t1 +# endif +#else + @ ldrb $t1,[$inp,#3] @ $i + add $a,$a,$t2 @ h+=Maj(a,b,c) from the past + ldrb $t2,[$inp,#2] + ldrb $t0,[$inp,#1] + orr $t1,$t1,$t2,lsl#8 + ldrb $t2,[$inp],#4 + orr $t1,$t1,$t0,lsl#16 +# if $i==15 + str $inp,[sp,#17*4] @ make room for $t4 +# endif + eor $t0,$e,$e,ror#`$Sigma1[1]-$Sigma1[0]` + orr $t1,$t1,$t2,lsl#24 + eor $t0,$t0,$e,ror#`$Sigma1[2]-$Sigma1[0]` @ Sigma1(e) +#endif +___ +$code.=<<___; + ldr $t2,[$Ktbl],#4 @ *K256++ + add $h,$h,$t1 @ h+=X[i] + str $t1,[sp,#`$i%16`*4] + eor $t1,$f,$g + add $h,$h,$t0,ror#$Sigma1[0] @ h+=Sigma1(e) + and $t1,$t1,$e + add $h,$h,$t2 @ h+=K256[i] + eor $t1,$t1,$g @ Ch(e,f,g) + eor $t0,$a,$a,ror#`$Sigma0[1]-$Sigma0[0]` + add $h,$h,$t1 @ h+=Ch(e,f,g) +#if $i==31 + and $t2,$t2,#0xff + cmp $t2,#0xf2 @ done? +#endif +#if $i<15 +# if __ARM_ARCH__>=7 + ldr $t1,[$inp],#4 @ prefetch +# else + ldrb $t1,[$inp,#3] +# endif + eor $t2,$a,$b @ a^b, b^c in next round +#else + ldr $t1,[sp,#`($i+2)%16`*4] @ from future BODY_16_xx + eor $t2,$a,$b @ a^b, b^c in next round + ldr $t4,[sp,#`($i+15)%16`*4] @ from future BODY_16_xx +#endif + eor $t0,$t0,$a,ror#`$Sigma0[2]-$Sigma0[0]` @ Sigma0(a) + and $t3,$t3,$t2 @ (b^c)&=(a^b) + add $d,$d,$h @ d+=h + eor $t3,$t3,$b @ Maj(a,b,c) + add $h,$h,$t0,ror#$Sigma0[0] @ h+=Sigma0(a) + @ add $h,$h,$t3 @ h+=Maj(a,b,c) +___ + ($t2,$t3)=($t3,$t2); +} + +sub BODY_16_XX { +my ($i,$a,$b,$c,$d,$e,$f,$g,$h) = @_; + +$code.=<<___; + @ ldr $t1,[sp,#`($i+1)%16`*4] @ $i + @ ldr $t4,[sp,#`($i+14)%16`*4] + mov $t0,$t1,ror#$sigma0[0] + add $a,$a,$t2 @ h+=Maj(a,b,c) from the past + mov $t2,$t4,ror#$sigma1[0] + eor $t0,$t0,$t1,ror#$sigma0[1] + eor $t2,$t2,$t4,ror#$sigma1[1] + eor $t0,$t0,$t1,lsr#$sigma0[2] @ sigma0(X[i+1]) + ldr $t1,[sp,#`($i+0)%16`*4] + eor $t2,$t2,$t4,lsr#$sigma1[2] @ sigma1(X[i+14]) + ldr $t4,[sp,#`($i+9)%16`*4] + + add $t2,$t2,$t0 + eor $t0,$e,$e,ror#`$Sigma1[1]-$Sigma1[0]` @ from BODY_00_15 + add $t1,$t1,$t2 + eor $t0,$t0,$e,ror#`$Sigma1[2]-$Sigma1[0]` @ Sigma1(e) + add $t1,$t1,$t4 @ X[i] +___ + &BODY_00_15(@_); +} + +$code=<<___; +#ifndef __KERNEL__ +# include "arm_arch.h" +#else +# define __ARM_ARCH__ __LINUX_ARM_ARCH__ +# define __ARM_MAX_ARCH__ 7 +#endif + +.text +#if __ARM_ARCH__<7 +.code 32 +#else +.syntax unified +# if defined(__thumb2__) && !defined(__APPLE__) +# define adrl adr +.thumb +# else +.code 32 +# endif +#endif + +.type K256,%object +.align 5 +K256: +.word 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5 +.word 0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5 +.word 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3 +.word 0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174 +.word 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc +.word 0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da +.word 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7 +.word 0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967 +.word 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13 +.word 0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85 +.word 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3 +.word 0xd192e819,0xd6990624,0xf40e3585,0x106aa070 +.word 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5 +.word 0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3 +.word 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208 +.word 0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 +.size K256,.-K256 +.word 0 @ terminator +#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) +.LOPENSSL_armcap: +.word OPENSSL_armcap_P-.Lsha256_block_data_order +#endif +.align 5 + +.global sha256_block_data_order +.type sha256_block_data_order,%function +sha256_block_data_order: +.Lsha256_block_data_order: +#if __ARM_ARCH__<7 + sub r3,pc,#8 @ sha256_block_data_order +#else + adr r3,sha256_block_data_order +#endif +#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) + ldr r12,.LOPENSSL_armcap + ldr r12,[r3,r12] @ OPENSSL_armcap_P +#ifdef __APPLE__ + ldr r12,[r12] +#endif + tst r12,#ARMV8_SHA256 + bne .LARMv8 + tst r12,#ARMV7_NEON + bne .LNEON +#endif + add $len,$inp,$len,lsl#6 @ len to point at the end of inp + stmdb sp!,{$ctx,$inp,$len,r4-r11,lr} + ldmia $ctx,{$A,$B,$C,$D,$E,$F,$G,$H} + sub $Ktbl,r3,#256+32 @ K256 + sub sp,sp,#16*4 @ alloca(X[16]) +.Loop: +# if __ARM_ARCH__>=7 + ldr $t1,[$inp],#4 +# else + ldrb $t1,[$inp,#3] +# endif + eor $t3,$B,$C @ magic + eor $t2,$t2,$t2 +___ +for($i=0;$i<16;$i++) { &BODY_00_15($i,@V); unshift(@V,pop(@V)); } +$code.=".Lrounds_16_xx:\n"; +for (;$i<32;$i++) { &BODY_16_XX($i,@V); unshift(@V,pop(@V)); } +$code.=<<___; +#if __ARM_ARCH__>=7 + ite eq @ Thumb2 thing, sanity check in ARM +#endif + ldreq $t3,[sp,#16*4] @ pull ctx + bne .Lrounds_16_xx + + add $A,$A,$t2 @ h+=Maj(a,b,c) from the past + ldr $t0,[$t3,#0] + ldr $t1,[$t3,#4] + ldr $t2,[$t3,#8] + add $A,$A,$t0 + ldr $t0,[$t3,#12] + add $B,$B,$t1 + ldr $t1,[$t3,#16] + add $C,$C,$t2 + ldr $t2,[$t3,#20] + add $D,$D,$t0 + ldr $t0,[$t3,#24] + add $E,$E,$t1 + ldr $t1,[$t3,#28] + add $F,$F,$t2 + ldr $inp,[sp,#17*4] @ pull inp + ldr $t2,[sp,#18*4] @ pull inp+len + add $G,$G,$t0 + add $H,$H,$t1 + stmia $t3,{$A,$B,$C,$D,$E,$F,$G,$H} + cmp $inp,$t2 + sub $Ktbl,$Ktbl,#256 @ rewind Ktbl + bne .Loop + + add sp,sp,#`16+3`*4 @ destroy frame +#if __ARM_ARCH__>=5 + ldmia sp!,{r4-r11,pc} +#else + ldmia sp!,{r4-r11,lr} + tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet + bx lr @ interoperable with Thumb ISA:-) +#endif +.size sha256_block_data_order,.-sha256_block_data_order +___ +###################################################################### +# NEON stuff +# +{{{ +my @X=map("q$_",(0..3)); +my ($T0,$T1,$T2,$T3,$T4,$T5)=("q8","q9","q10","q11","d24","d25"); +my $Xfer=$t4; +my $j=0; + +sub Dlo() { shift=~m|q([1]?[0-9])|?"d".($1*2):""; } +sub Dhi() { shift=~m|q([1]?[0-9])|?"d".($1*2+1):""; } + +sub AUTOLOAD() # thunk [simplified] x86-style perlasm +{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://; $opcode =~ s/_/\./; + my $arg = pop; + $arg = "#$arg" if ($arg*1 eq $arg); + $code .= "\t$opcode\t".join(',',@_,$arg)."\n"; +} + +sub Xupdate() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); + my ($a,$b,$c,$d,$e,$f,$g,$h); + + &vext_8 ($T0,@X[0],@X[1],4); # X[1..4] + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vext_8 ($T1,@X[2],@X[3],4); # X[9..12] + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vshr_u32 ($T2,$T0,$sigma0[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &vadd_i32 (@X[0],@X[0],$T1); # X[0..3] += X[9..12] + eval(shift(@insns)); + eval(shift(@insns)); + &vshr_u32 ($T1,$T0,$sigma0[2]); + eval(shift(@insns)); + eval(shift(@insns)); + &vsli_32 ($T2,$T0,32-$sigma0[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &vshr_u32 ($T3,$T0,$sigma0[1]); + eval(shift(@insns)); + eval(shift(@insns)); + &veor ($T1,$T1,$T2); + eval(shift(@insns)); + eval(shift(@insns)); + &vsli_32 ($T3,$T0,32-$sigma0[1]); + eval(shift(@insns)); + eval(shift(@insns)); + &vshr_u32 ($T4,&Dhi(@X[3]),$sigma1[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &veor ($T1,$T1,$T3); # sigma0(X[1..4]) + eval(shift(@insns)); + eval(shift(@insns)); + &vsli_32 ($T4,&Dhi(@X[3]),32-$sigma1[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &vshr_u32 ($T5,&Dhi(@X[3]),$sigma1[2]); + eval(shift(@insns)); + eval(shift(@insns)); + &vadd_i32 (@X[0],@X[0],$T1); # X[0..3] += sigma0(X[1..4]) + eval(shift(@insns)); + eval(shift(@insns)); + &veor ($T5,$T5,$T4); + eval(shift(@insns)); + eval(shift(@insns)); + &vshr_u32 ($T4,&Dhi(@X[3]),$sigma1[1]); + eval(shift(@insns)); + eval(shift(@insns)); + &vsli_32 ($T4,&Dhi(@X[3]),32-$sigma1[1]); + eval(shift(@insns)); + eval(shift(@insns)); + &veor ($T5,$T5,$T4); # sigma1(X[14..15]) + eval(shift(@insns)); + eval(shift(@insns)); + &vadd_i32 (&Dlo(@X[0]),&Dlo(@X[0]),$T5);# X[0..1] += sigma1(X[14..15]) + eval(shift(@insns)); + eval(shift(@insns)); + &vshr_u32 ($T4,&Dlo(@X[0]),$sigma1[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &vsli_32 ($T4,&Dlo(@X[0]),32-$sigma1[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &vshr_u32 ($T5,&Dlo(@X[0]),$sigma1[2]); + eval(shift(@insns)); + eval(shift(@insns)); + &veor ($T5,$T5,$T4); + eval(shift(@insns)); + eval(shift(@insns)); + &vshr_u32 ($T4,&Dlo(@X[0]),$sigma1[1]); + eval(shift(@insns)); + eval(shift(@insns)); + &vld1_32 ("{$T0}","[$Ktbl,:128]!"); + eval(shift(@insns)); + eval(shift(@insns)); + &vsli_32 ($T4,&Dlo(@X[0]),32-$sigma1[1]); + eval(shift(@insns)); + eval(shift(@insns)); + &veor ($T5,$T5,$T4); # sigma1(X[16..17]) + eval(shift(@insns)); + eval(shift(@insns)); + &vadd_i32 (&Dhi(@X[0]),&Dhi(@X[0]),$T5);# X[2..3] += sigma1(X[16..17]) + eval(shift(@insns)); + eval(shift(@insns)); + &vadd_i32 ($T0,$T0,@X[0]); + while($#insns>=2) { eval(shift(@insns)); } + &vst1_32 ("{$T0}","[$Xfer,:128]!"); + eval(shift(@insns)); + eval(shift(@insns)); + + push(@X,shift(@X)); # "rotate" X[] +} + +sub Xpreload() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); + my ($a,$b,$c,$d,$e,$f,$g,$h); + + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vld1_32 ("{$T0}","[$Ktbl,:128]!"); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vrev32_8 (@X[0],@X[0]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vadd_i32 ($T0,$T0,@X[0]); + foreach (@insns) { eval; } # remaining instructions + &vst1_32 ("{$T0}","[$Xfer,:128]!"); + + push(@X,shift(@X)); # "rotate" X[] +} + +sub body_00_15 () { + ( + '($a,$b,$c,$d,$e,$f,$g,$h)=@V;'. + '&add ($h,$h,$t1)', # h+=X[i]+K[i] + '&eor ($t1,$f,$g)', + '&eor ($t0,$e,$e,"ror#".($Sigma1[1]-$Sigma1[0]))', + '&add ($a,$a,$t2)', # h+=Maj(a,b,c) from the past + '&and ($t1,$t1,$e)', + '&eor ($t2,$t0,$e,"ror#".($Sigma1[2]-$Sigma1[0]))', # Sigma1(e) + '&eor ($t0,$a,$a,"ror#".($Sigma0[1]-$Sigma0[0]))', + '&eor ($t1,$t1,$g)', # Ch(e,f,g) + '&add ($h,$h,$t2,"ror#$Sigma1[0]")', # h+=Sigma1(e) + '&eor ($t2,$a,$b)', # a^b, b^c in next round + '&eor ($t0,$t0,$a,"ror#".($Sigma0[2]-$Sigma0[0]))', # Sigma0(a) + '&add ($h,$h,$t1)', # h+=Ch(e,f,g) + '&ldr ($t1,sprintf "[sp,#%d]",4*(($j+1)&15)) if (($j&15)!=15);'. + '&ldr ($t1,"[$Ktbl]") if ($j==15);'. + '&ldr ($t1,"[sp,#64]") if ($j==31)', + '&and ($t3,$t3,$t2)', # (b^c)&=(a^b) + '&add ($d,$d,$h)', # d+=h + '&add ($h,$h,$t0,"ror#$Sigma0[0]");'. # h+=Sigma0(a) + '&eor ($t3,$t3,$b)', # Maj(a,b,c) + '$j++; unshift(@V,pop(@V)); ($t2,$t3)=($t3,$t2);' + ) +} + +$code.=<<___; +#if __ARM_MAX_ARCH__>=7 +.arch armv7-a +.fpu neon + +.global sha256_block_data_order_neon +.type sha256_block_data_order_neon,%function +.align 4 +sha256_block_data_order_neon: +.LNEON: + stmdb sp!,{r4-r12,lr} + + sub $H,sp,#16*4+16 + adrl $Ktbl,K256 + bic $H,$H,#15 @ align for 128-bit stores + mov $t2,sp + mov sp,$H @ alloca + add $len,$inp,$len,lsl#6 @ len to point at the end of inp + + vld1.8 {@X[0]},[$inp]! + vld1.8 {@X[1]},[$inp]! + vld1.8 {@X[2]},[$inp]! + vld1.8 {@X[3]},[$inp]! + vld1.32 {$T0},[$Ktbl,:128]! + vld1.32 {$T1},[$Ktbl,:128]! + vld1.32 {$T2},[$Ktbl,:128]! + vld1.32 {$T3},[$Ktbl,:128]! + vrev32.8 @X[0],@X[0] @ yes, even on + str $ctx,[sp,#64] + vrev32.8 @X[1],@X[1] @ big-endian + str $inp,[sp,#68] + mov $Xfer,sp + vrev32.8 @X[2],@X[2] + str $len,[sp,#72] + vrev32.8 @X[3],@X[3] + str $t2,[sp,#76] @ save original sp + vadd.i32 $T0,$T0,@X[0] + vadd.i32 $T1,$T1,@X[1] + vst1.32 {$T0},[$Xfer,:128]! + vadd.i32 $T2,$T2,@X[2] + vst1.32 {$T1},[$Xfer,:128]! + vadd.i32 $T3,$T3,@X[3] + vst1.32 {$T2},[$Xfer,:128]! + vst1.32 {$T3},[$Xfer,:128]! + + ldmia $ctx,{$A-$H} + sub $Xfer,$Xfer,#64 + ldr $t1,[sp,#0] + eor $t2,$t2,$t2 + eor $t3,$B,$C + b .L_00_48 + +.align 4 +.L_00_48: +___ + &Xupdate(\&body_00_15); + &Xupdate(\&body_00_15); + &Xupdate(\&body_00_15); + &Xupdate(\&body_00_15); +$code.=<<___; + teq $t1,#0 @ check for K256 terminator + ldr $t1,[sp,#0] + sub $Xfer,$Xfer,#64 + bne .L_00_48 + + ldr $inp,[sp,#68] + ldr $t0,[sp,#72] + sub $Ktbl,$Ktbl,#256 @ rewind $Ktbl + teq $inp,$t0 + it eq + subeq $inp,$inp,#64 @ avoid SEGV + vld1.8 {@X[0]},[$inp]! @ load next input block + vld1.8 {@X[1]},[$inp]! + vld1.8 {@X[2]},[$inp]! + vld1.8 {@X[3]},[$inp]! + it ne + strne $inp,[sp,#68] + mov $Xfer,sp +___ + &Xpreload(\&body_00_15); + &Xpreload(\&body_00_15); + &Xpreload(\&body_00_15); + &Xpreload(\&body_00_15); +$code.=<<___; + ldr $t0,[$t1,#0] + add $A,$A,$t2 @ h+=Maj(a,b,c) from the past + ldr $t2,[$t1,#4] + ldr $t3,[$t1,#8] + ldr $t4,[$t1,#12] + add $A,$A,$t0 @ accumulate + ldr $t0,[$t1,#16] + add $B,$B,$t2 + ldr $t2,[$t1,#20] + add $C,$C,$t3 + ldr $t3,[$t1,#24] + add $D,$D,$t4 + ldr $t4,[$t1,#28] + add $E,$E,$t0 + str $A,[$t1],#4 + add $F,$F,$t2 + str $B,[$t1],#4 + add $G,$G,$t3 + str $C,[$t1],#4 + add $H,$H,$t4 + str $D,[$t1],#4 + stmia $t1,{$E-$H} + + ittte ne + movne $Xfer,sp + ldrne $t1,[sp,#0] + eorne $t2,$t2,$t2 + ldreq sp,[sp,#76] @ restore original sp + itt ne + eorne $t3,$B,$C + bne .L_00_48 + + ldmia sp!,{r4-r12,pc} +.size sha256_block_data_order_neon,.-sha256_block_data_order_neon +#endif +___ +}}} +###################################################################### +# ARMv8 stuff +# +{{{ +my ($ABCD,$EFGH,$abcd)=map("q$_",(0..2)); +my @MSG=map("q$_",(8..11)); +my ($W0,$W1,$ABCD_SAVE,$EFGH_SAVE)=map("q$_",(12..15)); +my $Ktbl="r3"; + +$code.=<<___; +#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) + +# if defined(__thumb2__) && !defined(__APPLE__) +# define INST(a,b,c,d) .byte c,d|0xc,a,b +# else +# define INST(a,b,c,d) .byte a,b,c,d +# endif + +.type sha256_block_data_order_armv8,%function +.align 5 +sha256_block_data_order_armv8: +.LARMv8: + vld1.32 {$ABCD,$EFGH},[$ctx] +# ifdef __APPLE__ + sub $Ktbl,$Ktbl,#256+32 +# elif defined(__thumb2__) + adr $Ktbl,.LARMv8 + sub $Ktbl,$Ktbl,#.LARMv8-K256 +# else + adrl $Ktbl,K256 +# endif + add $len,$inp,$len,lsl#6 @ len to point at the end of inp + +.Loop_v8: + vld1.8 {@MSG[0]-@MSG[1]},[$inp]! + vld1.8 {@MSG[2]-@MSG[3]},[$inp]! + vld1.32 {$W0},[$Ktbl]! + vrev32.8 @MSG[0],@MSG[0] + vrev32.8 @MSG[1],@MSG[1] + vrev32.8 @MSG[2],@MSG[2] + vrev32.8 @MSG[3],@MSG[3] + vmov $ABCD_SAVE,$ABCD @ offload + vmov $EFGH_SAVE,$EFGH + teq $inp,$len +___ +for($i=0;$i<12;$i++) { +$code.=<<___; + vld1.32 {$W1},[$Ktbl]! + vadd.i32 $W0,$W0,@MSG[0] + sha256su0 @MSG[0],@MSG[1] + vmov $abcd,$ABCD + sha256h $ABCD,$EFGH,$W0 + sha256h2 $EFGH,$abcd,$W0 + sha256su1 @MSG[0],@MSG[2],@MSG[3] +___ + ($W0,$W1)=($W1,$W0); push(@MSG,shift(@MSG)); +} +$code.=<<___; + vld1.32 {$W1},[$Ktbl]! + vadd.i32 $W0,$W0,@MSG[0] + vmov $abcd,$ABCD + sha256h $ABCD,$EFGH,$W0 + sha256h2 $EFGH,$abcd,$W0 + + vld1.32 {$W0},[$Ktbl]! + vadd.i32 $W1,$W1,@MSG[1] + vmov $abcd,$ABCD + sha256h $ABCD,$EFGH,$W1 + sha256h2 $EFGH,$abcd,$W1 + + vld1.32 {$W1},[$Ktbl] + vadd.i32 $W0,$W0,@MSG[2] + sub $Ktbl,$Ktbl,#256-16 @ rewind + vmov $abcd,$ABCD + sha256h $ABCD,$EFGH,$W0 + sha256h2 $EFGH,$abcd,$W0 + + vadd.i32 $W1,$W1,@MSG[3] + vmov $abcd,$ABCD + sha256h $ABCD,$EFGH,$W1 + sha256h2 $EFGH,$abcd,$W1 + + vadd.i32 $ABCD,$ABCD,$ABCD_SAVE + vadd.i32 $EFGH,$EFGH,$EFGH_SAVE + it ne + bne .Loop_v8 + + vst1.32 {$ABCD,$EFGH},[$ctx] + + ret @ bx lr +.size sha256_block_data_order_armv8,.-sha256_block_data_order_armv8 +#endif +___ +}}} +$code.=<<___; +.asciz "SHA256 block transform for ARMv4/NEON/ARMv8, CRYPTOGAMS by " +.align 2 +#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) +.comm OPENSSL_armcap_P,4,4 +.hidden OPENSSL_armcap_P +#endif +___ + +open SELF,$0; +while() { + next if (/^#!/); + last if (!s/^#/@/ and !/^$/); + print; +} +close SELF; + +{ my %opcode = ( + "sha256h" => 0xf3000c40, "sha256h2" => 0xf3100c40, + "sha256su0" => 0xf3ba03c0, "sha256su1" => 0xf3200c40 ); + + sub unsha256 { + my ($mnemonic,$arg)=@_; + + if ($arg =~ m/q([0-9]+)(?:,\s*q([0-9]+))?,\s*q([0-9]+)/o) { + my $word = $opcode{$mnemonic}|(($1&7)<<13)|(($1&8)<<19) + |(($2&7)<<17)|(($2&8)<<4) + |(($3&7)<<1) |(($3&8)<<2); + # since ARMv7 instructions are always encoded little-endian. + # correct solution is to use .inst directive, but older + # assemblers don't implement it:-( + sprintf "INST(0x%02x,0x%02x,0x%02x,0x%02x)\t@ %s %s", + $word&0xff,($word>>8)&0xff, + ($word>>16)&0xff,($word>>24)&0xff, + $mnemonic,$arg; + } + } +} + +foreach (split($/,$code)) { + + s/\`([^\`]*)\`/eval $1/geo; + + s/\b(sha256\w+)\s+(q.*)/unsha256($1,$2)/geo; + + s/\bret\b/bx lr/go or + s/\bbx\s+lr\b/.word\t0xe12fff1e/go; # make it possible to compile with -march=armv4 + + print $_,"\n"; +} + +close STDOUT; # enforce flush diff --git a/TMessagesProj/jni/boringssl/crypto/sha/asm/sha512-586.pl b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha512-586.pl new file mode 100644 index 00000000..2f6a202c --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha512-586.pl @@ -0,0 +1,911 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# SHA512 block transform for x86. September 2007. +# +# May 2013. +# +# Add SSSE3 code path, 20-25% improvement [over original SSE2 code]. +# +# Performance in clock cycles per processed byte (less is better): +# +# gcc icc x86 asm SIMD(*) x86_64(**) +# Pentium 100 97 61 - - +# PIII 75 77 56 - - +# P4 116 95 82 34.6 30.8 +# AMD K8 54 55 36 20.7 9.57 +# Core2 66 57 40 15.9 9.97 +# Westmere 70 - 38 12.2 9.58 +# Sandy Bridge 58 - 35 11.9 11.2 +# Ivy Bridge 50 - 33 11.5 8.17 +# Haswell 46 - 29 11.3 7.66 +# Bulldozer 121 - 50 14.0 13.5 +# VIA Nano 91 - 52 33 14.7 +# Atom 126 - 68 48(***) 14.7 +# Silvermont 97 - 58 42(***) 17.5 +# +# (*) whichever best applicable. +# (**) x86_64 assembler performance is presented for reference +# purposes, the results are for integer-only code. +# (***) paddq is increadibly slow on Atom. +# +# IALU code-path is optimized for elder Pentiums. On vanilla Pentium +# performance improvement over compiler generated code reaches ~60%, +# while on PIII - ~35%. On newer µ-archs improvement varies from 15% +# to 50%, but it's less important as they are expected to execute SSE2 +# code-path, which is commonly ~2-3x faster [than compiler generated +# code]. SSE2 code-path is as fast as original sha512-sse2.pl, even +# though it does not use 128-bit operations. The latter means that +# SSE2-aware kernel is no longer required to execute the code. Another +# difference is that new code optimizes amount of writes, but at the +# cost of increased data cache "footprint" by 1/2KB. + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +push(@INC,"${dir}","${dir}../../perlasm"); +require "x86asm.pl"; + +&asm_init($ARGV[0],"sha512-586.pl",$ARGV[$#ARGV] eq "386"); + +$sse2=0; +for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); } + +&external_label("OPENSSL_ia32cap_P") if ($sse2); + +$Tlo=&DWP(0,"esp"); $Thi=&DWP(4,"esp"); +$Alo=&DWP(8,"esp"); $Ahi=&DWP(8+4,"esp"); +$Blo=&DWP(16,"esp"); $Bhi=&DWP(16+4,"esp"); +$Clo=&DWP(24,"esp"); $Chi=&DWP(24+4,"esp"); +$Dlo=&DWP(32,"esp"); $Dhi=&DWP(32+4,"esp"); +$Elo=&DWP(40,"esp"); $Ehi=&DWP(40+4,"esp"); +$Flo=&DWP(48,"esp"); $Fhi=&DWP(48+4,"esp"); +$Glo=&DWP(56,"esp"); $Ghi=&DWP(56+4,"esp"); +$Hlo=&DWP(64,"esp"); $Hhi=&DWP(64+4,"esp"); +$K512="ebp"; + +$Asse2=&QWP(0,"esp"); +$Bsse2=&QWP(8,"esp"); +$Csse2=&QWP(16,"esp"); +$Dsse2=&QWP(24,"esp"); +$Esse2=&QWP(32,"esp"); +$Fsse2=&QWP(40,"esp"); +$Gsse2=&QWP(48,"esp"); +$Hsse2=&QWP(56,"esp"); + +$A="mm0"; # B-D and +$E="mm4"; # F-H are commonly loaded to respectively mm1-mm3 and + # mm5-mm7, but it's done on on-demand basis... +$BxC="mm2"; # ... except for B^C + +sub BODY_00_15_sse2 { + my $phase=shift; + + #&movq ("mm5",$Fsse2); # load f + #&movq ("mm6",$Gsse2); # load g + + &movq ("mm1",$E); # %mm1 is sliding right + &pxor ("mm5","mm6"); # f^=g + &psrlq ("mm1",14); + &movq ($Esse2,$E); # modulo-scheduled save e + &pand ("mm5",$E); # f&=e + &psllq ($E,23); # $E is sliding left + &movq ($A,"mm3") if ($phase<2); + &movq (&QWP(8*9,"esp"),"mm7") # save X[i] + &movq ("mm3","mm1"); # %mm3 is T1 + &psrlq ("mm1",4); + &pxor ("mm5","mm6"); # Ch(e,f,g) + &pxor ("mm3",$E); + &psllq ($E,23); + &pxor ("mm3","mm1"); + &movq ($Asse2,$A); # modulo-scheduled save a + &paddq ("mm7","mm5"); # X[i]+=Ch(e,f,g) + &pxor ("mm3",$E); + &psrlq ("mm1",23); + &paddq ("mm7",$Hsse2); # X[i]+=h + &pxor ("mm3","mm1"); + &psllq ($E,4); + &paddq ("mm7",QWP(0,$K512)); # X[i]+=K512[i] + &pxor ("mm3",$E); # T1=Sigma1_512(e) + + &movq ($E,$Dsse2); # e = load d, e in next round + &paddq ("mm3","mm7"); # T1+=X[i] + &movq ("mm5",$A); # %mm5 is sliding right + &psrlq ("mm5",28); + &paddq ($E,"mm3"); # d += T1 + &movq ("mm6",$A); # %mm6 is sliding left + &movq ("mm7","mm5"); + &psllq ("mm6",25); + &movq ("mm1",$Bsse2); # load b + &psrlq ("mm5",6); + &pxor ("mm7","mm6"); + &sub ("esp",8); + &psllq ("mm6",5); + &pxor ("mm7","mm5"); + &pxor ($A,"mm1"); # a^b, b^c in next round + &psrlq ("mm5",5); + &pxor ("mm7","mm6"); + &pand ($BxC,$A); # (b^c)&(a^b) + &psllq ("mm6",6); + &pxor ("mm7","mm5"); + &pxor ($BxC,"mm1"); # [h=]Maj(a,b,c) + &pxor ("mm6","mm7"); # Sigma0_512(a) + &movq ("mm7",&QWP(8*(9+16-1),"esp")) if ($phase!=0); # pre-fetch + &movq ("mm5",$Fsse2) if ($phase==0); # load f + + if ($phase>1) { + &paddq ($BxC,"mm6"); # h+=Sigma0(a) + &add ($K512,8); + #&paddq ($BxC,"mm3"); # h+=T1 + + ($A,$BxC) = ($BxC,$A); # rotate registers + } else { + &paddq ("mm3",$BxC); # T1+=Maj(a,b,c) + &movq ($BxC,$A); + &add ($K512,8); + &paddq ("mm3","mm6"); # T1+=Sigma0(a) + &movq ("mm6",$Gsse2) if ($phase==0); # load g + #&movq ($A,"mm3"); # h=T1 + } +} + +sub BODY_00_15_x86 { + #define Sigma1(x) (ROTR((x),14) ^ ROTR((x),18) ^ ROTR((x),41)) + # LO lo>>14^hi<<18 ^ lo>>18^hi<<14 ^ hi>>9^lo<<23 + # HI hi>>14^lo<<18 ^ hi>>18^lo<<14 ^ lo>>9^hi<<23 + &mov ("ecx",$Elo); + &mov ("edx",$Ehi); + &mov ("esi","ecx"); + + &shr ("ecx",9); # lo>>9 + &mov ("edi","edx"); + &shr ("edx",9); # hi>>9 + &mov ("ebx","ecx"); + &shl ("esi",14); # lo<<14 + &mov ("eax","edx"); + &shl ("edi",14); # hi<<14 + &xor ("ebx","esi"); + + &shr ("ecx",14-9); # lo>>14 + &xor ("eax","edi"); + &shr ("edx",14-9); # hi>>14 + &xor ("eax","ecx"); + &shl ("esi",18-14); # lo<<18 + &xor ("ebx","edx"); + &shl ("edi",18-14); # hi<<18 + &xor ("ebx","esi"); + + &shr ("ecx",18-14); # lo>>18 + &xor ("eax","edi"); + &shr ("edx",18-14); # hi>>18 + &xor ("eax","ecx"); + &shl ("esi",23-18); # lo<<23 + &xor ("ebx","edx"); + &shl ("edi",23-18); # hi<<23 + &xor ("eax","esi"); + &xor ("ebx","edi"); # T1 = Sigma1(e) + + &mov ("ecx",$Flo); + &mov ("edx",$Fhi); + &mov ("esi",$Glo); + &mov ("edi",$Ghi); + &add ("eax",$Hlo); + &adc ("ebx",$Hhi); # T1 += h + &xor ("ecx","esi"); + &xor ("edx","edi"); + &and ("ecx",$Elo); + &and ("edx",$Ehi); + &add ("eax",&DWP(8*(9+15)+0,"esp")); + &adc ("ebx",&DWP(8*(9+15)+4,"esp")); # T1 += X[0] + &xor ("ecx","esi"); + &xor ("edx","edi"); # Ch(e,f,g) = (f^g)&e)^g + + &mov ("esi",&DWP(0,$K512)); + &mov ("edi",&DWP(4,$K512)); # K[i] + &add ("eax","ecx"); + &adc ("ebx","edx"); # T1 += Ch(e,f,g) + &mov ("ecx",$Dlo); + &mov ("edx",$Dhi); + &add ("eax","esi"); + &adc ("ebx","edi"); # T1 += K[i] + &mov ($Tlo,"eax"); + &mov ($Thi,"ebx"); # put T1 away + &add ("eax","ecx"); + &adc ("ebx","edx"); # d += T1 + + #define Sigma0(x) (ROTR((x),28) ^ ROTR((x),34) ^ ROTR((x),39)) + # LO lo>>28^hi<<4 ^ hi>>2^lo<<30 ^ hi>>7^lo<<25 + # HI hi>>28^lo<<4 ^ lo>>2^hi<<30 ^ lo>>7^hi<<25 + &mov ("ecx",$Alo); + &mov ("edx",$Ahi); + &mov ($Dlo,"eax"); + &mov ($Dhi,"ebx"); + &mov ("esi","ecx"); + + &shr ("ecx",2); # lo>>2 + &mov ("edi","edx"); + &shr ("edx",2); # hi>>2 + &mov ("ebx","ecx"); + &shl ("esi",4); # lo<<4 + &mov ("eax","edx"); + &shl ("edi",4); # hi<<4 + &xor ("ebx","esi"); + + &shr ("ecx",7-2); # lo>>7 + &xor ("eax","edi"); + &shr ("edx",7-2); # hi>>7 + &xor ("ebx","ecx"); + &shl ("esi",25-4); # lo<<25 + &xor ("eax","edx"); + &shl ("edi",25-4); # hi<<25 + &xor ("eax","esi"); + + &shr ("ecx",28-7); # lo>>28 + &xor ("ebx","edi"); + &shr ("edx",28-7); # hi>>28 + &xor ("eax","ecx"); + &shl ("esi",30-25); # lo<<30 + &xor ("ebx","edx"); + &shl ("edi",30-25); # hi<<30 + &xor ("eax","esi"); + &xor ("ebx","edi"); # Sigma0(a) + + &mov ("ecx",$Alo); + &mov ("edx",$Ahi); + &mov ("esi",$Blo); + &mov ("edi",$Bhi); + &add ("eax",$Tlo); + &adc ("ebx",$Thi); # T1 = Sigma0(a)+T1 + &or ("ecx","esi"); + &or ("edx","edi"); + &and ("ecx",$Clo); + &and ("edx",$Chi); + &and ("esi",$Alo); + &and ("edi",$Ahi); + &or ("ecx","esi"); + &or ("edx","edi"); # Maj(a,b,c) = ((a|b)&c)|(a&b) + + &add ("eax","ecx"); + &adc ("ebx","edx"); # T1 += Maj(a,b,c) + &mov ($Tlo,"eax"); + &mov ($Thi,"ebx"); + + &mov (&LB("edx"),&BP(0,$K512)); # pre-fetch LSB of *K + &sub ("esp",8); + &lea ($K512,&DWP(8,$K512)); # K++ +} + + +&function_begin("sha512_block_data_order"); + &mov ("esi",wparam(0)); # ctx + &mov ("edi",wparam(1)); # inp + &mov ("eax",wparam(2)); # num + &mov ("ebx","esp"); # saved sp + + &call (&label("pic_point")); # make it PIC! +&set_label("pic_point"); + &blindpop($K512); + &lea ($K512,&DWP(&label("K512")."-".&label("pic_point"),$K512)); + + &sub ("esp",16); + &and ("esp",-64); + + &shl ("eax",7); + &add ("eax","edi"); + &mov (&DWP(0,"esp"),"esi"); # ctx + &mov (&DWP(4,"esp"),"edi"); # inp + &mov (&DWP(8,"esp"),"eax"); # inp+num*128 + &mov (&DWP(12,"esp"),"ebx"); # saved sp + +if ($sse2) { + &picmeup("edx","OPENSSL_ia32cap_P",$K512,&label("K512")); + &mov ("ecx",&DWP(0,"edx")); + &test ("ecx",1<<26); + &jz (&label("loop_x86")); + + &mov ("edx",&DWP(4,"edx")); + + # load ctx->h[0-7] + &movq ($A,&QWP(0,"esi")); + &and ("ecx",1<<24); # XMM registers availability + &movq ("mm1",&QWP(8,"esi")); + &and ("edx",1<<9); # SSSE3 bit + &movq ($BxC,&QWP(16,"esi")); + &or ("ecx","edx"); + &movq ("mm3",&QWP(24,"esi")); + &movq ($E,&QWP(32,"esi")); + &movq ("mm5",&QWP(40,"esi")); + &movq ("mm6",&QWP(48,"esi")); + &movq ("mm7",&QWP(56,"esi")); + &cmp ("ecx",1<<24|1<<9); + &je (&label("SSSE3")); + &sub ("esp",8*10); + &jmp (&label("loop_sse2")); + +&set_label("loop_sse2",16); + #&movq ($Asse2,$A); + &movq ($Bsse2,"mm1"); + &movq ($Csse2,$BxC); + &movq ($Dsse2,"mm3"); + #&movq ($Esse2,$E); + &movq ($Fsse2,"mm5"); + &movq ($Gsse2,"mm6"); + &pxor ($BxC,"mm1"); # magic + &movq ($Hsse2,"mm7"); + &movq ("mm3",$A); # magic + + &mov ("eax",&DWP(0,"edi")); + &mov ("ebx",&DWP(4,"edi")); + &add ("edi",8); + &mov ("edx",15); # counter + &bswap ("eax"); + &bswap ("ebx"); + &jmp (&label("00_14_sse2")); + +&set_label("00_14_sse2",16); + &movd ("mm1","eax"); + &mov ("eax",&DWP(0,"edi")); + &movd ("mm7","ebx"); + &mov ("ebx",&DWP(4,"edi")); + &add ("edi",8); + &bswap ("eax"); + &bswap ("ebx"); + &punpckldq("mm7","mm1"); + + &BODY_00_15_sse2(); + + &dec ("edx"); + &jnz (&label("00_14_sse2")); + + &movd ("mm1","eax"); + &movd ("mm7","ebx"); + &punpckldq("mm7","mm1"); + + &BODY_00_15_sse2(1); + + &pxor ($A,$A); # A is in %mm3 + &mov ("edx",32); # counter + &jmp (&label("16_79_sse2")); + +&set_label("16_79_sse2",16); + for ($j=0;$j<2;$j++) { # 2x unroll + #&movq ("mm7",&QWP(8*(9+16-1),"esp")); # prefetched in BODY_00_15 + &movq ("mm5",&QWP(8*(9+16-14),"esp")); + &movq ("mm1","mm7"); + &psrlq ("mm7",1); + &movq ("mm6","mm5"); + &psrlq ("mm5",6); + &psllq ("mm1",56); + &paddq ($A,"mm3"); # from BODY_00_15 + &movq ("mm3","mm7"); + &psrlq ("mm7",7-1); + &pxor ("mm3","mm1"); + &psllq ("mm1",63-56); + &pxor ("mm3","mm7"); + &psrlq ("mm7",8-7); + &pxor ("mm3","mm1"); + &movq ("mm1","mm5"); + &psrlq ("mm5",19-6); + &pxor ("mm7","mm3"); # sigma0 + + &psllq ("mm6",3); + &pxor ("mm1","mm5"); + &paddq ("mm7",&QWP(8*(9+16),"esp")); + &pxor ("mm1","mm6"); + &psrlq ("mm5",61-19); + &paddq ("mm7",&QWP(8*(9+16-9),"esp")); + &pxor ("mm1","mm5"); + &psllq ("mm6",45-3); + &movq ("mm5",$Fsse2); # load f + &pxor ("mm1","mm6"); # sigma1 + &movq ("mm6",$Gsse2); # load g + + &paddq ("mm7","mm1"); # X[i] + #&movq (&QWP(8*9,"esp"),"mm7"); # moved to BODY_00_15 + + &BODY_00_15_sse2(2); + } + &dec ("edx"); + &jnz (&label("16_79_sse2")); + + #&movq ($A,$Asse2); + &paddq ($A,"mm3"); # from BODY_00_15 + &movq ("mm1",$Bsse2); + #&movq ($BxC,$Csse2); + &movq ("mm3",$Dsse2); + #&movq ($E,$Esse2); + &movq ("mm5",$Fsse2); + &movq ("mm6",$Gsse2); + &movq ("mm7",$Hsse2); + + &pxor ($BxC,"mm1"); # de-magic + &paddq ($A,&QWP(0,"esi")); + &paddq ("mm1",&QWP(8,"esi")); + &paddq ($BxC,&QWP(16,"esi")); + &paddq ("mm3",&QWP(24,"esi")); + &paddq ($E,&QWP(32,"esi")); + &paddq ("mm5",&QWP(40,"esi")); + &paddq ("mm6",&QWP(48,"esi")); + &paddq ("mm7",&QWP(56,"esi")); + + &mov ("eax",8*80); + &movq (&QWP(0,"esi"),$A); + &movq (&QWP(8,"esi"),"mm1"); + &movq (&QWP(16,"esi"),$BxC); + &movq (&QWP(24,"esi"),"mm3"); + &movq (&QWP(32,"esi"),$E); + &movq (&QWP(40,"esi"),"mm5"); + &movq (&QWP(48,"esi"),"mm6"); + &movq (&QWP(56,"esi"),"mm7"); + + &lea ("esp",&DWP(0,"esp","eax")); # destroy frame + &sub ($K512,"eax"); # rewind K + + &cmp ("edi",&DWP(8*10+8,"esp")); # are we done yet? + &jb (&label("loop_sse2")); + + &mov ("esp",&DWP(8*10+12,"esp")); # restore sp + &emms (); +&function_end_A(); + +&set_label("SSSE3",32); +{ my ($cnt,$frame)=("ecx","edx"); + my @X=map("xmm$_",(0..7)); + my $j; + my $i=0; + + &lea ($frame,&DWP(-64,"esp")); + &sub ("esp",256); + + # fixed stack frame layout + # + # +0 A B C D E F G H # backing store + # +64 X[0]+K[i] .. X[15]+K[i] # XMM->MM xfer area + # +192 # XMM off-load ring buffer + # +256 # saved parameters + + &movdqa (@X[1],&QWP(80*8,$K512)); # byte swap mask + &movdqu (@X[0],&QWP(0,"edi")); + &pshufb (@X[0],@X[1]); + for ($j=0;$j<8;$j++) { + &movdqa (&QWP(16*(($j-1)%4),$frame),@X[3]) if ($j>4); # off-load + &movdqa (@X[3],&QWP(16*($j%8),$K512)); + &movdqa (@X[2],@X[1]) if ($j<7); # perpetuate byte swap mask + &movdqu (@X[1],&QWP(16*($j+1),"edi")) if ($j<7); # next input + &movdqa (@X[1],&QWP(16*(($j+1)%4),$frame)) if ($j==7);# restore @X[0] + &paddq (@X[3],@X[0]); + &pshufb (@X[1],@X[2]) if ($j<7); + &movdqa (&QWP(16*($j%8)-128,$frame),@X[3]); # xfer X[i]+K[i] + + push(@X,shift(@X)); # rotate(@X) + } + #&jmp (&label("loop_ssse3")); + &nop (); + +&set_label("loop_ssse3",32); + &movdqa (@X[2],&QWP(16*(($j+1)%4),$frame)); # pre-restore @X[1] + &movdqa (&QWP(16*(($j-1)%4),$frame),@X[3]); # off-load @X[3] + &lea ($K512,&DWP(16*8,$K512)); + + #&movq ($Asse2,$A); # off-load A-H + &movq ($Bsse2,"mm1"); + &mov ("ebx","edi"); + &movq ($Csse2,$BxC); + &lea ("edi",&DWP(128,"edi")); # advance input + &movq ($Dsse2,"mm3"); + &cmp ("edi","eax"); + #&movq ($Esse2,$E); + &movq ($Fsse2,"mm5"); + &cmovb ("ebx","edi"); + &movq ($Gsse2,"mm6"); + &mov ("ecx",4); # loop counter + &pxor ($BxC,"mm1"); # magic + &movq ($Hsse2,"mm7"); + &pxor ("mm3","mm3"); # magic + + &jmp (&label("00_47_ssse3")); + +sub BODY_00_15_ssse3 { # "phase-less" copy of BODY_00_15_sse2 + ( + '&movq ("mm1",$E)', # %mm1 is sliding right + '&movq ("mm7",&QWP(((-8*$i)%128)-128,$frame))',# X[i]+K[i] + '&pxor ("mm5","mm6")', # f^=g + '&psrlq ("mm1",14)', + '&movq (&QWP(8*($i+4)%64,"esp"),$E)', # modulo-scheduled save e + '&pand ("mm5",$E)', # f&=e + '&psllq ($E,23)', # $E is sliding left + '&paddq ($A,"mm3")', # [h+=Maj(a,b,c)] + '&movq ("mm3","mm1")', # %mm3 is T1 + '&psrlq("mm1",4)', + '&pxor ("mm5","mm6")', # Ch(e,f,g) + '&pxor ("mm3",$E)', + '&psllq($E,23)', + '&pxor ("mm3","mm1")', + '&movq (&QWP(8*$i%64,"esp"),$A)', # modulo-scheduled save a + '&paddq("mm7","mm5")', # X[i]+=Ch(e,f,g) + '&pxor ("mm3",$E)', + '&psrlq("mm1",23)', + '&paddq("mm7",&QWP(8*($i+7)%64,"esp"))', # X[i]+=h + '&pxor ("mm3","mm1")', + '&psllq($E,4)', + '&pxor ("mm3",$E)', # T1=Sigma1_512(e) + + '&movq ($E,&QWP(8*($i+3)%64,"esp"))', # e = load d, e in next round + '&paddq ("mm3","mm7")', # T1+=X[i] + '&movq ("mm5",$A)', # %mm5 is sliding right + '&psrlq("mm5",28)', + '&paddq ($E,"mm3")', # d += T1 + '&movq ("mm6",$A)', # %mm6 is sliding left + '&movq ("mm7","mm5")', + '&psllq("mm6",25)', + '&movq ("mm1",&QWP(8*($i+1)%64,"esp"))', # load b + '&psrlq("mm5",6)', + '&pxor ("mm7","mm6")', + '&psllq("mm6",5)', + '&pxor ("mm7","mm5")', + '&pxor ($A,"mm1")', # a^b, b^c in next round + '&psrlq("mm5",5)', + '&pxor ("mm7","mm6")', + '&pand ($BxC,$A)', # (b^c)&(a^b) + '&psllq("mm6",6)', + '&pxor ("mm7","mm5")', + '&pxor ($BxC,"mm1")', # [h=]Maj(a,b,c) + '&pxor ("mm6","mm7")', # Sigma0_512(a) + '&movq ("mm5",&QWP(8*($i+5-1)%64,"esp"))', # pre-load f + '&paddq ($BxC,"mm6")', # h+=Sigma0(a) + '&movq ("mm6",&QWP(8*($i+6-1)%64,"esp"))', # pre-load g + + '($A,$BxC) = ($BxC,$A); $i--;' + ); +} + +&set_label("00_47_ssse3",32); + + for(;$j<16;$j++) { + my ($t0,$t2,$t1)=@X[2..4]; + my @insns = (&BODY_00_15_ssse3(),&BODY_00_15_ssse3()); + + &movdqa ($t2,@X[5]); + &movdqa (@X[1],$t0); # restore @X[1] + &palignr ($t0,@X[0],8); # X[1..2] + &movdqa (&QWP(16*($j%4),$frame),@X[4]); # off-load @X[4] + &palignr ($t2,@X[4],8); # X[9..10] + + &movdqa ($t1,$t0); + &psrlq ($t0,7); + &paddq (@X[0],$t2); # X[0..1] += X[9..10] + &movdqa ($t2,$t1); + &psrlq ($t1,1); + &psllq ($t2,64-8); + &pxor ($t0,$t1); + &psrlq ($t1,8-1); + &pxor ($t0,$t2); + &psllq ($t2,8-1); + &pxor ($t0,$t1); + &movdqa ($t1,@X[7]); + &pxor ($t0,$t2); # sigma0(X[1..2]) + &movdqa ($t2,@X[7]); + &psrlq ($t1,6); + &paddq (@X[0],$t0); # X[0..1] += sigma0(X[1..2]) + + &movdqa ($t0,@X[7]); + &psrlq ($t2,19); + &psllq ($t0,64-61); + &pxor ($t1,$t2); + &psrlq ($t2,61-19); + &pxor ($t1,$t0); + &psllq ($t0,61-19); + &pxor ($t1,$t2); + &movdqa ($t2,&QWP(16*(($j+2)%4),$frame));# pre-restore @X[1] + &pxor ($t1,$t0); # sigma0(X[1..2]) + &movdqa ($t0,&QWP(16*($j%8),$K512)); + eval(shift(@insns)); + &paddq (@X[0],$t1); # X[0..1] += sigma0(X[14..15]) + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &paddq ($t0,@X[0]); + foreach(@insns) { eval; } + &movdqa (&QWP(16*($j%8)-128,$frame),$t0);# xfer X[i]+K[i] + + push(@X,shift(@X)); # rotate(@X) + } + &lea ($K512,&DWP(16*8,$K512)); + &dec ("ecx"); + &jnz (&label("00_47_ssse3")); + + &movdqa (@X[1],&QWP(0,$K512)); # byte swap mask + &lea ($K512,&DWP(-80*8,$K512)); # rewind + &movdqu (@X[0],&QWP(0,"ebx")); + &pshufb (@X[0],@X[1]); + + for ($j=0;$j<8;$j++) { # load next or same block + my @insns = (&BODY_00_15_ssse3(),&BODY_00_15_ssse3()); + + &movdqa (&QWP(16*(($j-1)%4),$frame),@X[3]) if ($j>4); # off-load + &movdqa (@X[3],&QWP(16*($j%8),$K512)); + &movdqa (@X[2],@X[1]) if ($j<7); # perpetuate byte swap mask + &movdqu (@X[1],&QWP(16*($j+1),"ebx")) if ($j<7); # next input + &movdqa (@X[1],&QWP(16*(($j+1)%4),$frame)) if ($j==7);# restore @X[0] + &paddq (@X[3],@X[0]); + &pshufb (@X[1],@X[2]) if ($j<7); + foreach(@insns) { eval; } + &movdqa (&QWP(16*($j%8)-128,$frame),@X[3]);# xfer X[i]+K[i] + + push(@X,shift(@X)); # rotate(@X) + } + + #&movq ($A,$Asse2); # load A-H + &movq ("mm1",$Bsse2); + &paddq ($A,"mm3"); # from BODY_00_15 + #&movq ($BxC,$Csse2); + &movq ("mm3",$Dsse2); + #&movq ($E,$Esse2); + #&movq ("mm5",$Fsse2); + #&movq ("mm6",$Gsse2); + &movq ("mm7",$Hsse2); + + &pxor ($BxC,"mm1"); # de-magic + &paddq ($A,&QWP(0,"esi")); + &paddq ("mm1",&QWP(8,"esi")); + &paddq ($BxC,&QWP(16,"esi")); + &paddq ("mm3",&QWP(24,"esi")); + &paddq ($E,&QWP(32,"esi")); + &paddq ("mm5",&QWP(40,"esi")); + &paddq ("mm6",&QWP(48,"esi")); + &paddq ("mm7",&QWP(56,"esi")); + + &movq (&QWP(0,"esi"),$A); + &movq (&QWP(8,"esi"),"mm1"); + &movq (&QWP(16,"esi"),$BxC); + &movq (&QWP(24,"esi"),"mm3"); + &movq (&QWP(32,"esi"),$E); + &movq (&QWP(40,"esi"),"mm5"); + &movq (&QWP(48,"esi"),"mm6"); + &movq (&QWP(56,"esi"),"mm7"); + + &cmp ("edi","eax") # are we done yet? + &jb (&label("loop_ssse3")); + + &mov ("esp",&DWP(64+12,$frame)); # restore sp + &emms (); +} +&function_end_A(); +} +&set_label("loop_x86",16); + # copy input block to stack reversing byte and qword order + for ($i=0;$i<8;$i++) { + &mov ("eax",&DWP($i*16+0,"edi")); + &mov ("ebx",&DWP($i*16+4,"edi")); + &mov ("ecx",&DWP($i*16+8,"edi")); + &mov ("edx",&DWP($i*16+12,"edi")); + &bswap ("eax"); + &bswap ("ebx"); + &bswap ("ecx"); + &bswap ("edx"); + &push ("eax"); + &push ("ebx"); + &push ("ecx"); + &push ("edx"); + } + &add ("edi",128); + &sub ("esp",9*8); # place for T,A,B,C,D,E,F,G,H + &mov (&DWP(8*(9+16)+4,"esp"),"edi"); + + # copy ctx->h[0-7] to A,B,C,D,E,F,G,H on stack + &lea ("edi",&DWP(8,"esp")); + &mov ("ecx",16); + &data_word(0xA5F3F689); # rep movsd + +&set_label("00_15_x86",16); + &BODY_00_15_x86(); + + &cmp (&LB("edx"),0x94); + &jne (&label("00_15_x86")); + +&set_label("16_79_x86",16); + #define sigma0(x) (ROTR((x),1) ^ ROTR((x),8) ^ ((x)>>7)) + # LO lo>>1^hi<<31 ^ lo>>8^hi<<24 ^ lo>>7^hi<<25 + # HI hi>>1^lo<<31 ^ hi>>8^lo<<24 ^ hi>>7 + &mov ("ecx",&DWP(8*(9+15+16-1)+0,"esp")); + &mov ("edx",&DWP(8*(9+15+16-1)+4,"esp")); + &mov ("esi","ecx"); + + &shr ("ecx",1); # lo>>1 + &mov ("edi","edx"); + &shr ("edx",1); # hi>>1 + &mov ("eax","ecx"); + &shl ("esi",24); # lo<<24 + &mov ("ebx","edx"); + &shl ("edi",24); # hi<<24 + &xor ("ebx","esi"); + + &shr ("ecx",7-1); # lo>>7 + &xor ("eax","edi"); + &shr ("edx",7-1); # hi>>7 + &xor ("eax","ecx"); + &shl ("esi",31-24); # lo<<31 + &xor ("ebx","edx"); + &shl ("edi",25-24); # hi<<25 + &xor ("ebx","esi"); + + &shr ("ecx",8-7); # lo>>8 + &xor ("eax","edi"); + &shr ("edx",8-7); # hi>>8 + &xor ("eax","ecx"); + &shl ("edi",31-25); # hi<<31 + &xor ("ebx","edx"); + &xor ("eax","edi"); # T1 = sigma0(X[-15]) + + &mov (&DWP(0,"esp"),"eax"); + &mov (&DWP(4,"esp"),"ebx"); # put T1 away + + #define sigma1(x) (ROTR((x),19) ^ ROTR((x),61) ^ ((x)>>6)) + # LO lo>>19^hi<<13 ^ hi>>29^lo<<3 ^ lo>>6^hi<<26 + # HI hi>>19^lo<<13 ^ lo>>29^hi<<3 ^ hi>>6 + &mov ("ecx",&DWP(8*(9+15+16-14)+0,"esp")); + &mov ("edx",&DWP(8*(9+15+16-14)+4,"esp")); + &mov ("esi","ecx"); + + &shr ("ecx",6); # lo>>6 + &mov ("edi","edx"); + &shr ("edx",6); # hi>>6 + &mov ("eax","ecx"); + &shl ("esi",3); # lo<<3 + &mov ("ebx","edx"); + &shl ("edi",3); # hi<<3 + &xor ("eax","esi"); + + &shr ("ecx",19-6); # lo>>19 + &xor ("ebx","edi"); + &shr ("edx",19-6); # hi>>19 + &xor ("eax","ecx"); + &shl ("esi",13-3); # lo<<13 + &xor ("ebx","edx"); + &shl ("edi",13-3); # hi<<13 + &xor ("ebx","esi"); + + &shr ("ecx",29-19); # lo>>29 + &xor ("eax","edi"); + &shr ("edx",29-19); # hi>>29 + &xor ("ebx","ecx"); + &shl ("edi",26-13); # hi<<26 + &xor ("eax","edx"); + &xor ("eax","edi"); # sigma1(X[-2]) + + &mov ("ecx",&DWP(8*(9+15+16)+0,"esp")); + &mov ("edx",&DWP(8*(9+15+16)+4,"esp")); + &add ("eax",&DWP(0,"esp")); + &adc ("ebx",&DWP(4,"esp")); # T1 = sigma1(X[-2])+T1 + &mov ("esi",&DWP(8*(9+15+16-9)+0,"esp")); + &mov ("edi",&DWP(8*(9+15+16-9)+4,"esp")); + &add ("eax","ecx"); + &adc ("ebx","edx"); # T1 += X[-16] + &add ("eax","esi"); + &adc ("ebx","edi"); # T1 += X[-7] + &mov (&DWP(8*(9+15)+0,"esp"),"eax"); + &mov (&DWP(8*(9+15)+4,"esp"),"ebx"); # save X[0] + + &BODY_00_15_x86(); + + &cmp (&LB("edx"),0x17); + &jne (&label("16_79_x86")); + + &mov ("esi",&DWP(8*(9+16+80)+0,"esp"));# ctx + &mov ("edi",&DWP(8*(9+16+80)+4,"esp"));# inp + for($i=0;$i<4;$i++) { + &mov ("eax",&DWP($i*16+0,"esi")); + &mov ("ebx",&DWP($i*16+4,"esi")); + &mov ("ecx",&DWP($i*16+8,"esi")); + &mov ("edx",&DWP($i*16+12,"esi")); + &add ("eax",&DWP(8+($i*16)+0,"esp")); + &adc ("ebx",&DWP(8+($i*16)+4,"esp")); + &mov (&DWP($i*16+0,"esi"),"eax"); + &mov (&DWP($i*16+4,"esi"),"ebx"); + &add ("ecx",&DWP(8+($i*16)+8,"esp")); + &adc ("edx",&DWP(8+($i*16)+12,"esp")); + &mov (&DWP($i*16+8,"esi"),"ecx"); + &mov (&DWP($i*16+12,"esi"),"edx"); + } + &add ("esp",8*(9+16+80)); # destroy frame + &sub ($K512,8*80); # rewind K + + &cmp ("edi",&DWP(8,"esp")); # are we done yet? + &jb (&label("loop_x86")); + + &mov ("esp",&DWP(12,"esp")); # restore sp +&function_end_A(); + +&set_label("K512",64); # Yes! I keep it in the code segment! + &data_word(0xd728ae22,0x428a2f98); # u64 + &data_word(0x23ef65cd,0x71374491); # u64 + &data_word(0xec4d3b2f,0xb5c0fbcf); # u64 + &data_word(0x8189dbbc,0xe9b5dba5); # u64 + &data_word(0xf348b538,0x3956c25b); # u64 + &data_word(0xb605d019,0x59f111f1); # u64 + &data_word(0xaf194f9b,0x923f82a4); # u64 + &data_word(0xda6d8118,0xab1c5ed5); # u64 + &data_word(0xa3030242,0xd807aa98); # u64 + &data_word(0x45706fbe,0x12835b01); # u64 + &data_word(0x4ee4b28c,0x243185be); # u64 + &data_word(0xd5ffb4e2,0x550c7dc3); # u64 + &data_word(0xf27b896f,0x72be5d74); # u64 + &data_word(0x3b1696b1,0x80deb1fe); # u64 + &data_word(0x25c71235,0x9bdc06a7); # u64 + &data_word(0xcf692694,0xc19bf174); # u64 + &data_word(0x9ef14ad2,0xe49b69c1); # u64 + &data_word(0x384f25e3,0xefbe4786); # u64 + &data_word(0x8b8cd5b5,0x0fc19dc6); # u64 + &data_word(0x77ac9c65,0x240ca1cc); # u64 + &data_word(0x592b0275,0x2de92c6f); # u64 + &data_word(0x6ea6e483,0x4a7484aa); # u64 + &data_word(0xbd41fbd4,0x5cb0a9dc); # u64 + &data_word(0x831153b5,0x76f988da); # u64 + &data_word(0xee66dfab,0x983e5152); # u64 + &data_word(0x2db43210,0xa831c66d); # u64 + &data_word(0x98fb213f,0xb00327c8); # u64 + &data_word(0xbeef0ee4,0xbf597fc7); # u64 + &data_word(0x3da88fc2,0xc6e00bf3); # u64 + &data_word(0x930aa725,0xd5a79147); # u64 + &data_word(0xe003826f,0x06ca6351); # u64 + &data_word(0x0a0e6e70,0x14292967); # u64 + &data_word(0x46d22ffc,0x27b70a85); # u64 + &data_word(0x5c26c926,0x2e1b2138); # u64 + &data_word(0x5ac42aed,0x4d2c6dfc); # u64 + &data_word(0x9d95b3df,0x53380d13); # u64 + &data_word(0x8baf63de,0x650a7354); # u64 + &data_word(0x3c77b2a8,0x766a0abb); # u64 + &data_word(0x47edaee6,0x81c2c92e); # u64 + &data_word(0x1482353b,0x92722c85); # u64 + &data_word(0x4cf10364,0xa2bfe8a1); # u64 + &data_word(0xbc423001,0xa81a664b); # u64 + &data_word(0xd0f89791,0xc24b8b70); # u64 + &data_word(0x0654be30,0xc76c51a3); # u64 + &data_word(0xd6ef5218,0xd192e819); # u64 + &data_word(0x5565a910,0xd6990624); # u64 + &data_word(0x5771202a,0xf40e3585); # u64 + &data_word(0x32bbd1b8,0x106aa070); # u64 + &data_word(0xb8d2d0c8,0x19a4c116); # u64 + &data_word(0x5141ab53,0x1e376c08); # u64 + &data_word(0xdf8eeb99,0x2748774c); # u64 + &data_word(0xe19b48a8,0x34b0bcb5); # u64 + &data_word(0xc5c95a63,0x391c0cb3); # u64 + &data_word(0xe3418acb,0x4ed8aa4a); # u64 + &data_word(0x7763e373,0x5b9cca4f); # u64 + &data_word(0xd6b2b8a3,0x682e6ff3); # u64 + &data_word(0x5defb2fc,0x748f82ee); # u64 + &data_word(0x43172f60,0x78a5636f); # u64 + &data_word(0xa1f0ab72,0x84c87814); # u64 + &data_word(0x1a6439ec,0x8cc70208); # u64 + &data_word(0x23631e28,0x90befffa); # u64 + &data_word(0xde82bde9,0xa4506ceb); # u64 + &data_word(0xb2c67915,0xbef9a3f7); # u64 + &data_word(0xe372532b,0xc67178f2); # u64 + &data_word(0xea26619c,0xca273ece); # u64 + &data_word(0x21c0c207,0xd186b8c7); # u64 + &data_word(0xcde0eb1e,0xeada7dd6); # u64 + &data_word(0xee6ed178,0xf57d4f7f); # u64 + &data_word(0x72176fba,0x06f067aa); # u64 + &data_word(0xa2c898a6,0x0a637dc5); # u64 + &data_word(0xbef90dae,0x113f9804); # u64 + &data_word(0x131c471b,0x1b710b35); # u64 + &data_word(0x23047d84,0x28db77f5); # u64 + &data_word(0x40c72493,0x32caab7b); # u64 + &data_word(0x15c9bebc,0x3c9ebe0a); # u64 + &data_word(0x9c100d4c,0x431d67c4); # u64 + &data_word(0xcb3e42b6,0x4cc5d4be); # u64 + &data_word(0xfc657e2a,0x597f299c); # u64 + &data_word(0x3ad6faec,0x5fcb6fab); # u64 + &data_word(0x4a475817,0x6c44198c); # u64 + + &data_word(0x04050607,0x00010203); # byte swap + &data_word(0x0c0d0e0f,0x08090a0b); # mask +&function_end_B("sha512_block_data_order"); +&asciz("SHA512 block transform for x86, CRYPTOGAMS by "); + +&asm_finish(); diff --git a/TMessagesProj/jni/boringssl/crypto/sha/asm/sha512-armv4.pl b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha512-armv4.pl new file mode 100644 index 00000000..2964a39c --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha512-armv4.pl @@ -0,0 +1,666 @@ +#!/usr/bin/env perl + +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# +# Permission to use under GPL terms is granted. +# ==================================================================== + +# SHA512 block procedure for ARMv4. September 2007. + +# This code is ~4.5 (four and a half) times faster than code generated +# by gcc 3.4 and it spends ~72 clock cycles per byte [on single-issue +# Xscale PXA250 core]. +# +# July 2010. +# +# Rescheduling for dual-issue pipeline resulted in 6% improvement on +# Cortex A8 core and ~40 cycles per processed byte. + +# February 2011. +# +# Profiler-assisted and platform-specific optimization resulted in 7% +# improvement on Coxtex A8 core and ~38 cycles per byte. + +# March 2011. +# +# Add NEON implementation. On Cortex A8 it was measured to process +# one byte in 23.3 cycles or ~60% faster than integer-only code. + +# August 2012. +# +# Improve NEON performance by 12% on Snapdragon S4. In absolute +# terms it's 22.6 cycles per byte, which is disappointing result. +# Technical writers asserted that 3-way S4 pipeline can sustain +# multiple NEON instructions per cycle, but dual NEON issue could +# not be observed, see http://www.openssl.org/~appro/Snapdragon-S4.html +# for further details. On side note Cortex-A15 processes one byte in +# 16 cycles. + +# Byte order [in]dependence. ========================================= +# +# Originally caller was expected to maintain specific *dword* order in +# h[0-7], namely with most significant dword at *lower* address, which +# was reflected in below two parameters as 0 and 4. Now caller is +# expected to maintain native byte order for whole 64-bit values. +$hi="HI"; +$lo="LO"; +# ==================================================================== + +$flavour = shift; +if ($flavour=~/^\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; } +else { while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {} } + +if ($flavour && $flavour ne "void") { + $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; + ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or + ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or + die "can't locate arm-xlate.pl"; + + open STDOUT,"| \"$^X\" $xlate $flavour $output"; +} else { + open STDOUT,">$output"; +} + +$ctx="r0"; # parameter block +$inp="r1"; +$len="r2"; + +$Tlo="r3"; +$Thi="r4"; +$Alo="r5"; +$Ahi="r6"; +$Elo="r7"; +$Ehi="r8"; +$t0="r9"; +$t1="r10"; +$t2="r11"; +$t3="r12"; +############ r13 is stack pointer +$Ktbl="r14"; +############ r15 is program counter + +$Aoff=8*0; +$Boff=8*1; +$Coff=8*2; +$Doff=8*3; +$Eoff=8*4; +$Foff=8*5; +$Goff=8*6; +$Hoff=8*7; +$Xoff=8*8; + +sub BODY_00_15() { +my $magic = shift; +$code.=<<___; + @ Sigma1(x) (ROTR((x),14) ^ ROTR((x),18) ^ ROTR((x),41)) + @ LO lo>>14^hi<<18 ^ lo>>18^hi<<14 ^ hi>>9^lo<<23 + @ HI hi>>14^lo<<18 ^ hi>>18^lo<<14 ^ lo>>9^hi<<23 + mov $t0,$Elo,lsr#14 + str $Tlo,[sp,#$Xoff+0] + mov $t1,$Ehi,lsr#14 + str $Thi,[sp,#$Xoff+4] + eor $t0,$t0,$Ehi,lsl#18 + ldr $t2,[sp,#$Hoff+0] @ h.lo + eor $t1,$t1,$Elo,lsl#18 + ldr $t3,[sp,#$Hoff+4] @ h.hi + eor $t0,$t0,$Elo,lsr#18 + eor $t1,$t1,$Ehi,lsr#18 + eor $t0,$t0,$Ehi,lsl#14 + eor $t1,$t1,$Elo,lsl#14 + eor $t0,$t0,$Ehi,lsr#9 + eor $t1,$t1,$Elo,lsr#9 + eor $t0,$t0,$Elo,lsl#23 + eor $t1,$t1,$Ehi,lsl#23 @ Sigma1(e) + adds $Tlo,$Tlo,$t0 + ldr $t0,[sp,#$Foff+0] @ f.lo + adc $Thi,$Thi,$t1 @ T += Sigma1(e) + ldr $t1,[sp,#$Foff+4] @ f.hi + adds $Tlo,$Tlo,$t2 + ldr $t2,[sp,#$Goff+0] @ g.lo + adc $Thi,$Thi,$t3 @ T += h + ldr $t3,[sp,#$Goff+4] @ g.hi + + eor $t0,$t0,$t2 + str $Elo,[sp,#$Eoff+0] + eor $t1,$t1,$t3 + str $Ehi,[sp,#$Eoff+4] + and $t0,$t0,$Elo + str $Alo,[sp,#$Aoff+0] + and $t1,$t1,$Ehi + str $Ahi,[sp,#$Aoff+4] + eor $t0,$t0,$t2 + ldr $t2,[$Ktbl,#$lo] @ K[i].lo + eor $t1,$t1,$t3 @ Ch(e,f,g) + ldr $t3,[$Ktbl,#$hi] @ K[i].hi + + adds $Tlo,$Tlo,$t0 + ldr $Elo,[sp,#$Doff+0] @ d.lo + adc $Thi,$Thi,$t1 @ T += Ch(e,f,g) + ldr $Ehi,[sp,#$Doff+4] @ d.hi + adds $Tlo,$Tlo,$t2 + and $t0,$t2,#0xff + adc $Thi,$Thi,$t3 @ T += K[i] + adds $Elo,$Elo,$Tlo + ldr $t2,[sp,#$Boff+0] @ b.lo + adc $Ehi,$Ehi,$Thi @ d += T + teq $t0,#$magic + + ldr $t3,[sp,#$Coff+0] @ c.lo +#if __ARM_ARCH__>=7 + it eq @ Thumb2 thing, sanity check in ARM +#endif + orreq $Ktbl,$Ktbl,#1 + @ Sigma0(x) (ROTR((x),28) ^ ROTR((x),34) ^ ROTR((x),39)) + @ LO lo>>28^hi<<4 ^ hi>>2^lo<<30 ^ hi>>7^lo<<25 + @ HI hi>>28^lo<<4 ^ lo>>2^hi<<30 ^ lo>>7^hi<<25 + mov $t0,$Alo,lsr#28 + mov $t1,$Ahi,lsr#28 + eor $t0,$t0,$Ahi,lsl#4 + eor $t1,$t1,$Alo,lsl#4 + eor $t0,$t0,$Ahi,lsr#2 + eor $t1,$t1,$Alo,lsr#2 + eor $t0,$t0,$Alo,lsl#30 + eor $t1,$t1,$Ahi,lsl#30 + eor $t0,$t0,$Ahi,lsr#7 + eor $t1,$t1,$Alo,lsr#7 + eor $t0,$t0,$Alo,lsl#25 + eor $t1,$t1,$Ahi,lsl#25 @ Sigma0(a) + adds $Tlo,$Tlo,$t0 + and $t0,$Alo,$t2 + adc $Thi,$Thi,$t1 @ T += Sigma0(a) + + ldr $t1,[sp,#$Boff+4] @ b.hi + orr $Alo,$Alo,$t2 + ldr $t2,[sp,#$Coff+4] @ c.hi + and $Alo,$Alo,$t3 + and $t3,$Ahi,$t1 + orr $Ahi,$Ahi,$t1 + orr $Alo,$Alo,$t0 @ Maj(a,b,c).lo + and $Ahi,$Ahi,$t2 + adds $Alo,$Alo,$Tlo + orr $Ahi,$Ahi,$t3 @ Maj(a,b,c).hi + sub sp,sp,#8 + adc $Ahi,$Ahi,$Thi @ h += T + tst $Ktbl,#1 + add $Ktbl,$Ktbl,#8 +___ +} +$code=<<___; +#ifndef __KERNEL__ +# include "arm_arch.h" +# define VFP_ABI_PUSH vstmdb sp!,{d8-d15} +# define VFP_ABI_POP vldmia sp!,{d8-d15} +#else +# define __ARM_ARCH__ __LINUX_ARM_ARCH__ +# define __ARM_MAX_ARCH__ 7 +# define VFP_ABI_PUSH +# define VFP_ABI_POP +#endif + +#ifdef __ARMEL__ +# define LO 0 +# define HI 4 +# define WORD64(hi0,lo0,hi1,lo1) .word lo0,hi0, lo1,hi1 +#else +# define HI 0 +# define LO 4 +# define WORD64(hi0,lo0,hi1,lo1) .word hi0,lo0, hi1,lo1 +#endif + +.text +#if __ARM_ARCH__<7 || defined(__APPLE__) +.code 32 +#else +.syntax unified +# ifdef __thumb2__ +# define adrl adr +.thumb +# else +.code 32 +# endif +#endif + +.type K512,%object +.align 5 +K512: +WORD64(0x428a2f98,0xd728ae22, 0x71374491,0x23ef65cd) +WORD64(0xb5c0fbcf,0xec4d3b2f, 0xe9b5dba5,0x8189dbbc) +WORD64(0x3956c25b,0xf348b538, 0x59f111f1,0xb605d019) +WORD64(0x923f82a4,0xaf194f9b, 0xab1c5ed5,0xda6d8118) +WORD64(0xd807aa98,0xa3030242, 0x12835b01,0x45706fbe) +WORD64(0x243185be,0x4ee4b28c, 0x550c7dc3,0xd5ffb4e2) +WORD64(0x72be5d74,0xf27b896f, 0x80deb1fe,0x3b1696b1) +WORD64(0x9bdc06a7,0x25c71235, 0xc19bf174,0xcf692694) +WORD64(0xe49b69c1,0x9ef14ad2, 0xefbe4786,0x384f25e3) +WORD64(0x0fc19dc6,0x8b8cd5b5, 0x240ca1cc,0x77ac9c65) +WORD64(0x2de92c6f,0x592b0275, 0x4a7484aa,0x6ea6e483) +WORD64(0x5cb0a9dc,0xbd41fbd4, 0x76f988da,0x831153b5) +WORD64(0x983e5152,0xee66dfab, 0xa831c66d,0x2db43210) +WORD64(0xb00327c8,0x98fb213f, 0xbf597fc7,0xbeef0ee4) +WORD64(0xc6e00bf3,0x3da88fc2, 0xd5a79147,0x930aa725) +WORD64(0x06ca6351,0xe003826f, 0x14292967,0x0a0e6e70) +WORD64(0x27b70a85,0x46d22ffc, 0x2e1b2138,0x5c26c926) +WORD64(0x4d2c6dfc,0x5ac42aed, 0x53380d13,0x9d95b3df) +WORD64(0x650a7354,0x8baf63de, 0x766a0abb,0x3c77b2a8) +WORD64(0x81c2c92e,0x47edaee6, 0x92722c85,0x1482353b) +WORD64(0xa2bfe8a1,0x4cf10364, 0xa81a664b,0xbc423001) +WORD64(0xc24b8b70,0xd0f89791, 0xc76c51a3,0x0654be30) +WORD64(0xd192e819,0xd6ef5218, 0xd6990624,0x5565a910) +WORD64(0xf40e3585,0x5771202a, 0x106aa070,0x32bbd1b8) +WORD64(0x19a4c116,0xb8d2d0c8, 0x1e376c08,0x5141ab53) +WORD64(0x2748774c,0xdf8eeb99, 0x34b0bcb5,0xe19b48a8) +WORD64(0x391c0cb3,0xc5c95a63, 0x4ed8aa4a,0xe3418acb) +WORD64(0x5b9cca4f,0x7763e373, 0x682e6ff3,0xd6b2b8a3) +WORD64(0x748f82ee,0x5defb2fc, 0x78a5636f,0x43172f60) +WORD64(0x84c87814,0xa1f0ab72, 0x8cc70208,0x1a6439ec) +WORD64(0x90befffa,0x23631e28, 0xa4506ceb,0xde82bde9) +WORD64(0xbef9a3f7,0xb2c67915, 0xc67178f2,0xe372532b) +WORD64(0xca273ece,0xea26619c, 0xd186b8c7,0x21c0c207) +WORD64(0xeada7dd6,0xcde0eb1e, 0xf57d4f7f,0xee6ed178) +WORD64(0x06f067aa,0x72176fba, 0x0a637dc5,0xa2c898a6) +WORD64(0x113f9804,0xbef90dae, 0x1b710b35,0x131c471b) +WORD64(0x28db77f5,0x23047d84, 0x32caab7b,0x40c72493) +WORD64(0x3c9ebe0a,0x15c9bebc, 0x431d67c4,0x9c100d4c) +WORD64(0x4cc5d4be,0xcb3e42b6, 0x597f299c,0xfc657e2a) +WORD64(0x5fcb6fab,0x3ad6faec, 0x6c44198c,0x4a475817) +.size K512,.-K512 +#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) +.LOPENSSL_armcap: +.word OPENSSL_armcap_P-.Lsha512_block_data_order +.skip 32-4 +#else +.skip 32 +#endif + +.global sha512_block_data_order +.type sha512_block_data_order,%function +sha512_block_data_order: +.Lsha512_block_data_order: +#if __ARM_ARCH__<7 + sub r3,pc,#8 @ sha512_block_data_order +#else + adr r3,sha512_block_data_order +#endif +#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) + ldr r12,.LOPENSSL_armcap + ldr r12,[r3,r12] @ OPENSSL_armcap_P +#ifdef __APPLE__ + ldr r12,[r12] +#endif + tst r12,#1 + bne .LNEON +#endif + add $len,$inp,$len,lsl#7 @ len to point at the end of inp + stmdb sp!,{r4-r12,lr} + sub $Ktbl,r3,#672 @ K512 + sub sp,sp,#9*8 + + ldr $Elo,[$ctx,#$Eoff+$lo] + ldr $Ehi,[$ctx,#$Eoff+$hi] + ldr $t0, [$ctx,#$Goff+$lo] + ldr $t1, [$ctx,#$Goff+$hi] + ldr $t2, [$ctx,#$Hoff+$lo] + ldr $t3, [$ctx,#$Hoff+$hi] +.Loop: + str $t0, [sp,#$Goff+0] + str $t1, [sp,#$Goff+4] + str $t2, [sp,#$Hoff+0] + str $t3, [sp,#$Hoff+4] + ldr $Alo,[$ctx,#$Aoff+$lo] + ldr $Ahi,[$ctx,#$Aoff+$hi] + ldr $Tlo,[$ctx,#$Boff+$lo] + ldr $Thi,[$ctx,#$Boff+$hi] + ldr $t0, [$ctx,#$Coff+$lo] + ldr $t1, [$ctx,#$Coff+$hi] + ldr $t2, [$ctx,#$Doff+$lo] + ldr $t3, [$ctx,#$Doff+$hi] + str $Tlo,[sp,#$Boff+0] + str $Thi,[sp,#$Boff+4] + str $t0, [sp,#$Coff+0] + str $t1, [sp,#$Coff+4] + str $t2, [sp,#$Doff+0] + str $t3, [sp,#$Doff+4] + ldr $Tlo,[$ctx,#$Foff+$lo] + ldr $Thi,[$ctx,#$Foff+$hi] + str $Tlo,[sp,#$Foff+0] + str $Thi,[sp,#$Foff+4] + +.L00_15: +#if __ARM_ARCH__<7 + ldrb $Tlo,[$inp,#7] + ldrb $t0, [$inp,#6] + ldrb $t1, [$inp,#5] + ldrb $t2, [$inp,#4] + ldrb $Thi,[$inp,#3] + ldrb $t3, [$inp,#2] + orr $Tlo,$Tlo,$t0,lsl#8 + ldrb $t0, [$inp,#1] + orr $Tlo,$Tlo,$t1,lsl#16 + ldrb $t1, [$inp],#8 + orr $Tlo,$Tlo,$t2,lsl#24 + orr $Thi,$Thi,$t3,lsl#8 + orr $Thi,$Thi,$t0,lsl#16 + orr $Thi,$Thi,$t1,lsl#24 +#else + ldr $Tlo,[$inp,#4] + ldr $Thi,[$inp],#8 +#ifdef __ARMEL__ + rev $Tlo,$Tlo + rev $Thi,$Thi +#endif +#endif +___ + &BODY_00_15(0x94); +$code.=<<___; + tst $Ktbl,#1 + beq .L00_15 + ldr $t0,[sp,#`$Xoff+8*(16-1)`+0] + ldr $t1,[sp,#`$Xoff+8*(16-1)`+4] + bic $Ktbl,$Ktbl,#1 +.L16_79: + @ sigma0(x) (ROTR((x),1) ^ ROTR((x),8) ^ ((x)>>7)) + @ LO lo>>1^hi<<31 ^ lo>>8^hi<<24 ^ lo>>7^hi<<25 + @ HI hi>>1^lo<<31 ^ hi>>8^lo<<24 ^ hi>>7 + mov $Tlo,$t0,lsr#1 + ldr $t2,[sp,#`$Xoff+8*(16-14)`+0] + mov $Thi,$t1,lsr#1 + ldr $t3,[sp,#`$Xoff+8*(16-14)`+4] + eor $Tlo,$Tlo,$t1,lsl#31 + eor $Thi,$Thi,$t0,lsl#31 + eor $Tlo,$Tlo,$t0,lsr#8 + eor $Thi,$Thi,$t1,lsr#8 + eor $Tlo,$Tlo,$t1,lsl#24 + eor $Thi,$Thi,$t0,lsl#24 + eor $Tlo,$Tlo,$t0,lsr#7 + eor $Thi,$Thi,$t1,lsr#7 + eor $Tlo,$Tlo,$t1,lsl#25 + + @ sigma1(x) (ROTR((x),19) ^ ROTR((x),61) ^ ((x)>>6)) + @ LO lo>>19^hi<<13 ^ hi>>29^lo<<3 ^ lo>>6^hi<<26 + @ HI hi>>19^lo<<13 ^ lo>>29^hi<<3 ^ hi>>6 + mov $t0,$t2,lsr#19 + mov $t1,$t3,lsr#19 + eor $t0,$t0,$t3,lsl#13 + eor $t1,$t1,$t2,lsl#13 + eor $t0,$t0,$t3,lsr#29 + eor $t1,$t1,$t2,lsr#29 + eor $t0,$t0,$t2,lsl#3 + eor $t1,$t1,$t3,lsl#3 + eor $t0,$t0,$t2,lsr#6 + eor $t1,$t1,$t3,lsr#6 + ldr $t2,[sp,#`$Xoff+8*(16-9)`+0] + eor $t0,$t0,$t3,lsl#26 + + ldr $t3,[sp,#`$Xoff+8*(16-9)`+4] + adds $Tlo,$Tlo,$t0 + ldr $t0,[sp,#`$Xoff+8*16`+0] + adc $Thi,$Thi,$t1 + + ldr $t1,[sp,#`$Xoff+8*16`+4] + adds $Tlo,$Tlo,$t2 + adc $Thi,$Thi,$t3 + adds $Tlo,$Tlo,$t0 + adc $Thi,$Thi,$t1 +___ + &BODY_00_15(0x17); +$code.=<<___; +#if __ARM_ARCH__>=7 + ittt eq @ Thumb2 thing, sanity check in ARM +#endif + ldreq $t0,[sp,#`$Xoff+8*(16-1)`+0] + ldreq $t1,[sp,#`$Xoff+8*(16-1)`+4] + beq .L16_79 + bic $Ktbl,$Ktbl,#1 + + ldr $Tlo,[sp,#$Boff+0] + ldr $Thi,[sp,#$Boff+4] + ldr $t0, [$ctx,#$Aoff+$lo] + ldr $t1, [$ctx,#$Aoff+$hi] + ldr $t2, [$ctx,#$Boff+$lo] + ldr $t3, [$ctx,#$Boff+$hi] + adds $t0,$Alo,$t0 + str $t0, [$ctx,#$Aoff+$lo] + adc $t1,$Ahi,$t1 + str $t1, [$ctx,#$Aoff+$hi] + adds $t2,$Tlo,$t2 + str $t2, [$ctx,#$Boff+$lo] + adc $t3,$Thi,$t3 + str $t3, [$ctx,#$Boff+$hi] + + ldr $Alo,[sp,#$Coff+0] + ldr $Ahi,[sp,#$Coff+4] + ldr $Tlo,[sp,#$Doff+0] + ldr $Thi,[sp,#$Doff+4] + ldr $t0, [$ctx,#$Coff+$lo] + ldr $t1, [$ctx,#$Coff+$hi] + ldr $t2, [$ctx,#$Doff+$lo] + ldr $t3, [$ctx,#$Doff+$hi] + adds $t0,$Alo,$t0 + str $t0, [$ctx,#$Coff+$lo] + adc $t1,$Ahi,$t1 + str $t1, [$ctx,#$Coff+$hi] + adds $t2,$Tlo,$t2 + str $t2, [$ctx,#$Doff+$lo] + adc $t3,$Thi,$t3 + str $t3, [$ctx,#$Doff+$hi] + + ldr $Tlo,[sp,#$Foff+0] + ldr $Thi,[sp,#$Foff+4] + ldr $t0, [$ctx,#$Eoff+$lo] + ldr $t1, [$ctx,#$Eoff+$hi] + ldr $t2, [$ctx,#$Foff+$lo] + ldr $t3, [$ctx,#$Foff+$hi] + adds $Elo,$Elo,$t0 + str $Elo,[$ctx,#$Eoff+$lo] + adc $Ehi,$Ehi,$t1 + str $Ehi,[$ctx,#$Eoff+$hi] + adds $t2,$Tlo,$t2 + str $t2, [$ctx,#$Foff+$lo] + adc $t3,$Thi,$t3 + str $t3, [$ctx,#$Foff+$hi] + + ldr $Alo,[sp,#$Goff+0] + ldr $Ahi,[sp,#$Goff+4] + ldr $Tlo,[sp,#$Hoff+0] + ldr $Thi,[sp,#$Hoff+4] + ldr $t0, [$ctx,#$Goff+$lo] + ldr $t1, [$ctx,#$Goff+$hi] + ldr $t2, [$ctx,#$Hoff+$lo] + ldr $t3, [$ctx,#$Hoff+$hi] + adds $t0,$Alo,$t0 + str $t0, [$ctx,#$Goff+$lo] + adc $t1,$Ahi,$t1 + str $t1, [$ctx,#$Goff+$hi] + adds $t2,$Tlo,$t2 + str $t2, [$ctx,#$Hoff+$lo] + adc $t3,$Thi,$t3 + str $t3, [$ctx,#$Hoff+$hi] + + add sp,sp,#640 + sub $Ktbl,$Ktbl,#640 + + teq $inp,$len + bne .Loop + + add sp,sp,#8*9 @ destroy frame +#if __ARM_ARCH__>=5 + ldmia sp!,{r4-r12,pc} +#else + ldmia sp!,{r4-r12,lr} + tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet + bx lr @ interoperable with Thumb ISA:-) +#endif +.size sha512_block_data_order,.-sha512_block_data_order +___ + +{ +my @Sigma0=(28,34,39); +my @Sigma1=(14,18,41); +my @sigma0=(1, 8, 7); +my @sigma1=(19,61,6); + +my $Ktbl="r3"; +my $cnt="r12"; # volatile register known as ip, intra-procedure-call scratch + +my @X=map("d$_",(0..15)); +my @V=($A,$B,$C,$D,$E,$F,$G,$H)=map("d$_",(16..23)); + +sub NEON_00_15() { +my $i=shift; +my ($a,$b,$c,$d,$e,$f,$g,$h)=@_; +my ($t0,$t1,$t2,$T1,$K,$Ch,$Maj)=map("d$_",(24..31)); # temps + +$code.=<<___ if ($i<16 || $i&1); + vshr.u64 $t0,$e,#@Sigma1[0] @ $i +#if $i<16 + vld1.64 {@X[$i%16]},[$inp]! @ handles unaligned +#endif + vshr.u64 $t1,$e,#@Sigma1[1] +#if $i>0 + vadd.i64 $a,$Maj @ h+=Maj from the past +#endif + vshr.u64 $t2,$e,#@Sigma1[2] +___ +$code.=<<___; + vld1.64 {$K},[$Ktbl,:64]! @ K[i++] + vsli.64 $t0,$e,#`64-@Sigma1[0]` + vsli.64 $t1,$e,#`64-@Sigma1[1]` + vmov $Ch,$e + vsli.64 $t2,$e,#`64-@Sigma1[2]` +#if $i<16 && defined(__ARMEL__) + vrev64.8 @X[$i],@X[$i] +#endif + veor $t1,$t0 + vbsl $Ch,$f,$g @ Ch(e,f,g) + vshr.u64 $t0,$a,#@Sigma0[0] + veor $t2,$t1 @ Sigma1(e) + vadd.i64 $T1,$Ch,$h + vshr.u64 $t1,$a,#@Sigma0[1] + vsli.64 $t0,$a,#`64-@Sigma0[0]` + vadd.i64 $T1,$t2 + vshr.u64 $t2,$a,#@Sigma0[2] + vadd.i64 $K,@X[$i%16] + vsli.64 $t1,$a,#`64-@Sigma0[1]` + veor $Maj,$a,$b + vsli.64 $t2,$a,#`64-@Sigma0[2]` + veor $h,$t0,$t1 + vadd.i64 $T1,$K + vbsl $Maj,$c,$b @ Maj(a,b,c) + veor $h,$t2 @ Sigma0(a) + vadd.i64 $d,$T1 + vadd.i64 $Maj,$T1 + @ vadd.i64 $h,$Maj +___ +} + +sub NEON_16_79() { +my $i=shift; + +if ($i&1) { &NEON_00_15($i,@_); return; } + +# 2x-vectorized, therefore runs every 2nd round +my @X=map("q$_",(0..7)); # view @X as 128-bit vector +my ($t0,$t1,$s0,$s1) = map("q$_",(12..15)); # temps +my ($d0,$d1,$d2) = map("d$_",(24..26)); # temps from NEON_00_15 +my $e=@_[4]; # $e from NEON_00_15 +$i /= 2; +$code.=<<___; + vshr.u64 $t0,@X[($i+7)%8],#@sigma1[0] + vshr.u64 $t1,@X[($i+7)%8],#@sigma1[1] + vadd.i64 @_[0],d30 @ h+=Maj from the past + vshr.u64 $s1,@X[($i+7)%8],#@sigma1[2] + vsli.64 $t0,@X[($i+7)%8],#`64-@sigma1[0]` + vext.8 $s0,@X[$i%8],@X[($i+1)%8],#8 @ X[i+1] + vsli.64 $t1,@X[($i+7)%8],#`64-@sigma1[1]` + veor $s1,$t0 + vshr.u64 $t0,$s0,#@sigma0[0] + veor $s1,$t1 @ sigma1(X[i+14]) + vshr.u64 $t1,$s0,#@sigma0[1] + vadd.i64 @X[$i%8],$s1 + vshr.u64 $s1,$s0,#@sigma0[2] + vsli.64 $t0,$s0,#`64-@sigma0[0]` + vsli.64 $t1,$s0,#`64-@sigma0[1]` + vext.8 $s0,@X[($i+4)%8],@X[($i+5)%8],#8 @ X[i+9] + veor $s1,$t0 + vshr.u64 $d0,$e,#@Sigma1[0] @ from NEON_00_15 + vadd.i64 @X[$i%8],$s0 + vshr.u64 $d1,$e,#@Sigma1[1] @ from NEON_00_15 + veor $s1,$t1 @ sigma0(X[i+1]) + vshr.u64 $d2,$e,#@Sigma1[2] @ from NEON_00_15 + vadd.i64 @X[$i%8],$s1 +___ + &NEON_00_15(2*$i,@_); +} + +$code.=<<___; +#if __ARM_MAX_ARCH__>=7 +.arch armv7-a +.fpu neon + +.global sha512_block_data_order_neon +.type sha512_block_data_order_neon,%function +.align 4 +sha512_block_data_order_neon: +.LNEON: + dmb @ errata #451034 on early Cortex A8 + add $len,$inp,$len,lsl#7 @ len to point at the end of inp + adr $Ktbl,K512 + VFP_ABI_PUSH + vldmia $ctx,{$A-$H} @ load context +.Loop_neon: +___ +for($i=0;$i<16;$i++) { &NEON_00_15($i,@V); unshift(@V,pop(@V)); } +$code.=<<___; + mov $cnt,#4 +.L16_79_neon: + subs $cnt,#1 +___ +for(;$i<32;$i++) { &NEON_16_79($i,@V); unshift(@V,pop(@V)); } +$code.=<<___; + bne .L16_79_neon + + vadd.i64 $A,d30 @ h+=Maj from the past + vldmia $ctx,{d24-d31} @ load context to temp + vadd.i64 q8,q12 @ vectorized accumulate + vadd.i64 q9,q13 + vadd.i64 q10,q14 + vadd.i64 q11,q15 + vstmia $ctx,{$A-$H} @ save context + teq $inp,$len + sub $Ktbl,#640 @ rewind K512 + bne .Loop_neon + + VFP_ABI_POP + ret @ bx lr +.size sha512_block_data_order_neon,.-sha512_block_data_order_neon +#endif +___ +} +$code.=<<___; +.asciz "SHA512 block transform for ARMv4/NEON, CRYPTOGAMS by " +.align 2 +#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) +.comm OPENSSL_armcap_P,4,4 +.hidden OPENSSL_armcap_P +#endif +___ + +$code =~ s/\`([^\`]*)\`/eval $1/gem; +$code =~ s/\bbx\s+lr\b/.word\t0xe12fff1e/gm; # make it possible to compile with -march=armv4 +$code =~ s/\bret\b/bx lr/gm; + +open SELF,$0; +while() { + next if (/^#!/); + last if (!s/^#/@/ and !/^$/); + print; +} +close SELF; + +print $code; +close STDOUT; # enforce flush diff --git a/TMessagesProj/jni/boringssl/crypto/sha/asm/sha512-armv8.pl b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha512-armv8.pl new file mode 100644 index 00000000..43e7293f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha512-armv8.pl @@ -0,0 +1,436 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# SHA256/512 for ARMv8. +# +# Performance in cycles per processed byte and improvement coefficient +# over code generated with "default" compiler: +# +# SHA256-hw SHA256(*) SHA512 +# Apple A7 1.97 10.5 (+33%) 6.73 (-1%(**)) +# Cortex-A53 2.38 15.5 (+115%) 10.0 (+150%(***)) +# Cortex-A57 2.31 11.6 (+86%) 7.51 (+260%(***)) +# Denver 2.01 10.5 (+26%) 6.70 (+8%) +# X-Gene 20.0 (+100%) 12.8 (+300%(***)) +# +# (*) Software SHA256 results are of lesser relevance, presented +# mostly for informational purposes. +# (**) The result is a trade-off: it's possible to improve it by +# 10% (or by 1 cycle per round), but at the cost of 20% loss +# on Cortex-A53 (or by 4 cycles per round). +# (***) Super-impressive coefficients over gcc-generated code are +# indication of some compiler "pathology", most notably code +# generated with -mgeneral-regs-only is significanty faster +# and the gap is only 40-90%. + +$flavour=shift; +# Unlike most perlasm files, sha512-armv8.pl takes an additional argument to +# determine which hash function to emit. This differs from upstream OpenSSL so +# that the script may continue to output to stdout. +$variant=shift; +$output=shift; + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or +die "can't locate arm-xlate.pl"; + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +if ($variant eq "sha512") { + $BITS=512; + $SZ=8; + @Sigma0=(28,34,39); + @Sigma1=(14,18,41); + @sigma0=(1, 8, 7); + @sigma1=(19,61, 6); + $rounds=80; + $reg_t="x"; +} elsif ($variant eq "sha256") { + $BITS=256; + $SZ=4; + @Sigma0=( 2,13,22); + @Sigma1=( 6,11,25); + @sigma0=( 7,18, 3); + @sigma1=(17,19,10); + $rounds=64; + $reg_t="w"; +} else { + die "Unknown variant: $variant"; +} + +$func="sha${BITS}_block_data_order"; + +($ctx,$inp,$num,$Ktbl)=map("x$_",(0..2,30)); + +@X=map("$reg_t$_",(3..15,0..2)); +@V=($A,$B,$C,$D,$E,$F,$G,$H)=map("$reg_t$_",(20..27)); +($t0,$t1,$t2,$t3)=map("$reg_t$_",(16,17,19,28)); + +sub BODY_00_xx { +my ($i,$a,$b,$c,$d,$e,$f,$g,$h)=@_; +my $j=($i+1)&15; +my ($T0,$T1,$T2)=(@X[($i-8)&15],@X[($i-9)&15],@X[($i-10)&15]); + $T0=@X[$i+3] if ($i<11); + +$code.=<<___ if ($i<16); +#ifndef __ARMEB__ + rev @X[$i],@X[$i] // $i +#endif +___ +$code.=<<___ if ($i<13 && ($i&1)); + ldp @X[$i+1],@X[$i+2],[$inp],#2*$SZ +___ +$code.=<<___ if ($i==13); + ldp @X[14],@X[15],[$inp] +___ +$code.=<<___ if ($i>=14); + ldr @X[($i-11)&15],[sp,#`$SZ*(($i-11)%4)`] +___ +$code.=<<___ if ($i>0 && $i<16); + add $a,$a,$t1 // h+=Sigma0(a) +___ +$code.=<<___ if ($i>=11); + str @X[($i-8)&15],[sp,#`$SZ*(($i-8)%4)`] +___ +# While ARMv8 specifies merged rotate-n-logical operation such as +# 'eor x,y,z,ror#n', it was found to negatively affect performance +# on Apple A7. The reason seems to be that it requires even 'y' to +# be available earlier. This means that such merged instruction is +# not necessarily best choice on critical path... On the other hand +# Cortex-A5x handles merged instructions much better than disjoint +# rotate and logical... See (**) footnote above. +$code.=<<___ if ($i<15); + ror $t0,$e,#$Sigma1[0] + add $h,$h,$t2 // h+=K[i] + eor $T0,$e,$e,ror#`$Sigma1[2]-$Sigma1[1]` + and $t1,$f,$e + bic $t2,$g,$e + add $h,$h,@X[$i&15] // h+=X[i] + orr $t1,$t1,$t2 // Ch(e,f,g) + eor $t2,$a,$b // a^b, b^c in next round + eor $t0,$t0,$T0,ror#$Sigma1[1] // Sigma1(e) + ror $T0,$a,#$Sigma0[0] + add $h,$h,$t1 // h+=Ch(e,f,g) + eor $t1,$a,$a,ror#`$Sigma0[2]-$Sigma0[1]` + add $h,$h,$t0 // h+=Sigma1(e) + and $t3,$t3,$t2 // (b^c)&=(a^b) + add $d,$d,$h // d+=h + eor $t3,$t3,$b // Maj(a,b,c) + eor $t1,$T0,$t1,ror#$Sigma0[1] // Sigma0(a) + add $h,$h,$t3 // h+=Maj(a,b,c) + ldr $t3,[$Ktbl],#$SZ // *K++, $t2 in next round + //add $h,$h,$t1 // h+=Sigma0(a) +___ +$code.=<<___ if ($i>=15); + ror $t0,$e,#$Sigma1[0] + add $h,$h,$t2 // h+=K[i] + ror $T1,@X[($j+1)&15],#$sigma0[0] + and $t1,$f,$e + ror $T2,@X[($j+14)&15],#$sigma1[0] + bic $t2,$g,$e + ror $T0,$a,#$Sigma0[0] + add $h,$h,@X[$i&15] // h+=X[i] + eor $t0,$t0,$e,ror#$Sigma1[1] + eor $T1,$T1,@X[($j+1)&15],ror#$sigma0[1] + orr $t1,$t1,$t2 // Ch(e,f,g) + eor $t2,$a,$b // a^b, b^c in next round + eor $t0,$t0,$e,ror#$Sigma1[2] // Sigma1(e) + eor $T0,$T0,$a,ror#$Sigma0[1] + add $h,$h,$t1 // h+=Ch(e,f,g) + and $t3,$t3,$t2 // (b^c)&=(a^b) + eor $T2,$T2,@X[($j+14)&15],ror#$sigma1[1] + eor $T1,$T1,@X[($j+1)&15],lsr#$sigma0[2] // sigma0(X[i+1]) + add $h,$h,$t0 // h+=Sigma1(e) + eor $t3,$t3,$b // Maj(a,b,c) + eor $t1,$T0,$a,ror#$Sigma0[2] // Sigma0(a) + eor $T2,$T2,@X[($j+14)&15],lsr#$sigma1[2] // sigma1(X[i+14]) + add @X[$j],@X[$j],@X[($j+9)&15] + add $d,$d,$h // d+=h + add $h,$h,$t3 // h+=Maj(a,b,c) + ldr $t3,[$Ktbl],#$SZ // *K++, $t2 in next round + add @X[$j],@X[$j],$T1 + add $h,$h,$t1 // h+=Sigma0(a) + add @X[$j],@X[$j],$T2 +___ + ($t2,$t3)=($t3,$t2); +} + +$code.=<<___; +#include "arm_arch.h" + +.text + +.extern OPENSSL_armcap_P +.globl $func +.type $func,%function +.align 6 +$func: +___ +$code.=<<___ if ($SZ==4); + ldr x16,.LOPENSSL_armcap_P + adr x17,.LOPENSSL_armcap_P + add x16,x16,x17 + ldr w16,[x16] + tst w16,#ARMV8_SHA256 + b.ne .Lv8_entry +___ +$code.=<<___; + stp x29,x30,[sp,#-128]! + add x29,sp,#0 + + stp x19,x20,[sp,#16] + stp x21,x22,[sp,#32] + stp x23,x24,[sp,#48] + stp x25,x26,[sp,#64] + stp x27,x28,[sp,#80] + sub sp,sp,#4*$SZ + + ldp $A,$B,[$ctx] // load context + ldp $C,$D,[$ctx,#2*$SZ] + ldp $E,$F,[$ctx,#4*$SZ] + add $num,$inp,$num,lsl#`log(16*$SZ)/log(2)` // end of input + ldp $G,$H,[$ctx,#6*$SZ] + adr $Ktbl,.LK$BITS + stp $ctx,$num,[x29,#96] + +.Loop: + ldp @X[0],@X[1],[$inp],#2*$SZ + ldr $t2,[$Ktbl],#$SZ // *K++ + eor $t3,$B,$C // magic seed + str $inp,[x29,#112] +___ +for ($i=0;$i<16;$i++) { &BODY_00_xx($i,@V); unshift(@V,pop(@V)); } +$code.=".Loop_16_xx:\n"; +for (;$i<32;$i++) { &BODY_00_xx($i,@V); unshift(@V,pop(@V)); } +$code.=<<___; + cbnz $t2,.Loop_16_xx + + ldp $ctx,$num,[x29,#96] + ldr $inp,[x29,#112] + sub $Ktbl,$Ktbl,#`$SZ*($rounds+1)` // rewind + + ldp @X[0],@X[1],[$ctx] + ldp @X[2],@X[3],[$ctx,#2*$SZ] + add $inp,$inp,#14*$SZ // advance input pointer + ldp @X[4],@X[5],[$ctx,#4*$SZ] + add $A,$A,@X[0] + ldp @X[6],@X[7],[$ctx,#6*$SZ] + add $B,$B,@X[1] + add $C,$C,@X[2] + add $D,$D,@X[3] + stp $A,$B,[$ctx] + add $E,$E,@X[4] + add $F,$F,@X[5] + stp $C,$D,[$ctx,#2*$SZ] + add $G,$G,@X[6] + add $H,$H,@X[7] + cmp $inp,$num + stp $E,$F,[$ctx,#4*$SZ] + stp $G,$H,[$ctx,#6*$SZ] + b.ne .Loop + + ldp x19,x20,[x29,#16] + add sp,sp,#4*$SZ + ldp x21,x22,[x29,#32] + ldp x23,x24,[x29,#48] + ldp x25,x26,[x29,#64] + ldp x27,x28,[x29,#80] + ldp x29,x30,[sp],#128 + ret +.size $func,.-$func + +.align 6 +.type .LK$BITS,%object +.LK$BITS: +___ +$code.=<<___ if ($SZ==8); + .quad 0x428a2f98d728ae22,0x7137449123ef65cd + .quad 0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc + .quad 0x3956c25bf348b538,0x59f111f1b605d019 + .quad 0x923f82a4af194f9b,0xab1c5ed5da6d8118 + .quad 0xd807aa98a3030242,0x12835b0145706fbe + .quad 0x243185be4ee4b28c,0x550c7dc3d5ffb4e2 + .quad 0x72be5d74f27b896f,0x80deb1fe3b1696b1 + .quad 0x9bdc06a725c71235,0xc19bf174cf692694 + .quad 0xe49b69c19ef14ad2,0xefbe4786384f25e3 + .quad 0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65 + .quad 0x2de92c6f592b0275,0x4a7484aa6ea6e483 + .quad 0x5cb0a9dcbd41fbd4,0x76f988da831153b5 + .quad 0x983e5152ee66dfab,0xa831c66d2db43210 + .quad 0xb00327c898fb213f,0xbf597fc7beef0ee4 + .quad 0xc6e00bf33da88fc2,0xd5a79147930aa725 + .quad 0x06ca6351e003826f,0x142929670a0e6e70 + .quad 0x27b70a8546d22ffc,0x2e1b21385c26c926 + .quad 0x4d2c6dfc5ac42aed,0x53380d139d95b3df + .quad 0x650a73548baf63de,0x766a0abb3c77b2a8 + .quad 0x81c2c92e47edaee6,0x92722c851482353b + .quad 0xa2bfe8a14cf10364,0xa81a664bbc423001 + .quad 0xc24b8b70d0f89791,0xc76c51a30654be30 + .quad 0xd192e819d6ef5218,0xd69906245565a910 + .quad 0xf40e35855771202a,0x106aa07032bbd1b8 + .quad 0x19a4c116b8d2d0c8,0x1e376c085141ab53 + .quad 0x2748774cdf8eeb99,0x34b0bcb5e19b48a8 + .quad 0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb + .quad 0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3 + .quad 0x748f82ee5defb2fc,0x78a5636f43172f60 + .quad 0x84c87814a1f0ab72,0x8cc702081a6439ec + .quad 0x90befffa23631e28,0xa4506cebde82bde9 + .quad 0xbef9a3f7b2c67915,0xc67178f2e372532b + .quad 0xca273eceea26619c,0xd186b8c721c0c207 + .quad 0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178 + .quad 0x06f067aa72176fba,0x0a637dc5a2c898a6 + .quad 0x113f9804bef90dae,0x1b710b35131c471b + .quad 0x28db77f523047d84,0x32caab7b40c72493 + .quad 0x3c9ebe0a15c9bebc,0x431d67c49c100d4c + .quad 0x4cc5d4becb3e42b6,0x597f299cfc657e2a + .quad 0x5fcb6fab3ad6faec,0x6c44198c4a475817 + .quad 0 // terminator +___ +$code.=<<___ if ($SZ==4); + .long 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5 + .long 0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5 + .long 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3 + .long 0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174 + .long 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc + .long 0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da + .long 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7 + .long 0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967 + .long 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13 + .long 0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85 + .long 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3 + .long 0xd192e819,0xd6990624,0xf40e3585,0x106aa070 + .long 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5 + .long 0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3 + .long 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208 + .long 0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 + .long 0 //terminator +___ +$code.=<<___; +.size .LK$BITS,.-.LK$BITS +.align 3 +.LOPENSSL_armcap_P: + .quad OPENSSL_armcap_P-. +.asciz "SHA$BITS block transform for ARMv8, CRYPTOGAMS by " +.align 2 +___ + +if ($SZ==4) { +my $Ktbl="x3"; + +my ($ABCD,$EFGH,$abcd)=map("v$_.16b",(0..2)); +my @MSG=map("v$_.16b",(4..7)); +my ($W0,$W1)=("v16.4s","v17.4s"); +my ($ABCD_SAVE,$EFGH_SAVE)=("v18.16b","v19.16b"); + +$code.=<<___; +.type sha256_block_armv8,%function +.align 6 +sha256_block_armv8: +.Lv8_entry: + stp x29,x30,[sp,#-16]! + add x29,sp,#0 + + ld1.32 {$ABCD,$EFGH},[$ctx] + adr $Ktbl,.LK256 + +.Loop_hw: + ld1 {@MSG[0]-@MSG[3]},[$inp],#64 + sub $num,$num,#1 + ld1.32 {$W0},[$Ktbl],#16 + rev32 @MSG[0],@MSG[0] + rev32 @MSG[1],@MSG[1] + rev32 @MSG[2],@MSG[2] + rev32 @MSG[3],@MSG[3] + orr $ABCD_SAVE,$ABCD,$ABCD // offload + orr $EFGH_SAVE,$EFGH,$EFGH +___ +for($i=0;$i<12;$i++) { +$code.=<<___; + ld1.32 {$W1},[$Ktbl],#16 + add.i32 $W0,$W0,@MSG[0] + sha256su0 @MSG[0],@MSG[1] + orr $abcd,$ABCD,$ABCD + sha256h $ABCD,$EFGH,$W0 + sha256h2 $EFGH,$abcd,$W0 + sha256su1 @MSG[0],@MSG[2],@MSG[3] +___ + ($W0,$W1)=($W1,$W0); push(@MSG,shift(@MSG)); +} +$code.=<<___; + ld1.32 {$W1},[$Ktbl],#16 + add.i32 $W0,$W0,@MSG[0] + orr $abcd,$ABCD,$ABCD + sha256h $ABCD,$EFGH,$W0 + sha256h2 $EFGH,$abcd,$W0 + + ld1.32 {$W0},[$Ktbl],#16 + add.i32 $W1,$W1,@MSG[1] + orr $abcd,$ABCD,$ABCD + sha256h $ABCD,$EFGH,$W1 + sha256h2 $EFGH,$abcd,$W1 + + ld1.32 {$W1},[$Ktbl] + add.i32 $W0,$W0,@MSG[2] + sub $Ktbl,$Ktbl,#$rounds*$SZ-16 // rewind + orr $abcd,$ABCD,$ABCD + sha256h $ABCD,$EFGH,$W0 + sha256h2 $EFGH,$abcd,$W0 + + add.i32 $W1,$W1,@MSG[3] + orr $abcd,$ABCD,$ABCD + sha256h $ABCD,$EFGH,$W1 + sha256h2 $EFGH,$abcd,$W1 + + add.i32 $ABCD,$ABCD,$ABCD_SAVE + add.i32 $EFGH,$EFGH,$EFGH_SAVE + + cbnz $num,.Loop_hw + + st1.32 {$ABCD,$EFGH},[$ctx] + + ldr x29,[sp],#16 + ret +.size sha256_block_armv8,.-sha256_block_armv8 +___ +} + +$code.=<<___; +.comm OPENSSL_armcap_P,4,4 +___ + +{ my %opcode = ( + "sha256h" => 0x5e004000, "sha256h2" => 0x5e005000, + "sha256su0" => 0x5e282800, "sha256su1" => 0x5e006000 ); + + sub unsha256 { + my ($mnemonic,$arg)=@_; + + $arg =~ m/[qv]([0-9]+)[^,]*,\s*[qv]([0-9]+)[^,]*(?:,\s*[qv]([0-9]+))?/o + && + sprintf ".inst\t0x%08x\t//%s %s", + $opcode{$mnemonic}|$1|($2<<5)|($3<<16), + $mnemonic,$arg; + } +} + +foreach(split("\n",$code)) { + + s/\`([^\`]*)\`/eval($1)/geo; + + s/\b(sha256\w+)\s+([qv].*)/unsha256($1,$2)/geo; + + s/\.\w?32\b//o and s/\.16b/\.4s/go; + m/(ld|st)1[^\[]+\[0\]/o and s/\.4s/\.s/go; + + print $_,"\n"; +} + +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/sha/asm/sha512-x86_64.pl b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha512-x86_64.pl new file mode 100644 index 00000000..6660a88b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha512-x86_64.pl @@ -0,0 +1,2396 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. Rights for redistribution and usage in source and binary +# forms are granted according to the OpenSSL license. +# ==================================================================== +# +# sha256/512_block procedure for x86_64. +# +# 40% improvement over compiler-generated code on Opteron. On EM64T +# sha256 was observed to run >80% faster and sha512 - >40%. No magical +# tricks, just straight implementation... I really wonder why gcc +# [being armed with inline assembler] fails to generate as fast code. +# The only thing which is cool about this module is that it's very +# same instruction sequence used for both SHA-256 and SHA-512. In +# former case the instructions operate on 32-bit operands, while in +# latter - on 64-bit ones. All I had to do is to get one flavor right, +# the other one passed the test right away:-) +# +# sha256_block runs in ~1005 cycles on Opteron, which gives you +# asymptotic performance of 64*1000/1005=63.7MBps times CPU clock +# frequency in GHz. sha512_block runs in ~1275 cycles, which results +# in 128*1000/1275=100MBps per GHz. Is there room for improvement? +# Well, if you compare it to IA-64 implementation, which maintains +# X[16] in register bank[!], tends to 4 instructions per CPU clock +# cycle and runs in 1003 cycles, 1275 is very good result for 3-way +# issue Opteron pipeline and X[16] maintained in memory. So that *if* +# there is a way to improve it, *then* the only way would be to try to +# offload X[16] updates to SSE unit, but that would require "deeper" +# loop unroll, which in turn would naturally cause size blow-up, not +# to mention increased complexity! And once again, only *if* it's +# actually possible to noticeably improve overall ILP, instruction +# level parallelism, on a given CPU implementation in this case. +# +# Special note on Intel EM64T. While Opteron CPU exhibits perfect +# perfromance ratio of 1.5 between 64- and 32-bit flavors [see above], +# [currently available] EM64T CPUs apparently are far from it. On the +# contrary, 64-bit version, sha512_block, is ~30% *slower* than 32-bit +# sha256_block:-( This is presumably because 64-bit shifts/rotates +# apparently are not atomic instructions, but implemented in microcode. +# +# May 2012. +# +# Optimization including one of Pavel Semjanov's ideas, alternative +# Maj, resulted in >=5% improvement on most CPUs, +20% SHA256 and +# unfortunately -2% SHA512 on P4 [which nobody should care about +# that much]. +# +# June 2012. +# +# Add SIMD code paths, see below for improvement coefficients. SSSE3 +# code path was not attempted for SHA512, because improvement is not +# estimated to be high enough, noticeably less than 9%, to justify +# the effort, not on pre-AVX processors. [Obviously with exclusion +# for VIA Nano, but it has SHA512 instruction that is faster and +# should be used instead.] For reference, corresponding estimated +# upper limit for improvement for SSSE3 SHA256 is 28%. The fact that +# higher coefficients are observed on VIA Nano and Bulldozer has more +# to do with specifics of their architecture [which is topic for +# separate discussion]. +# +# November 2012. +# +# Add AVX2 code path. Two consecutive input blocks are loaded to +# 256-bit %ymm registers, with data from first block to least +# significant 128-bit halves and data from second to most significant. +# The data is then processed with same SIMD instruction sequence as +# for AVX, but with %ymm as operands. Side effect is increased stack +# frame, 448 additional bytes in SHA256 and 1152 in SHA512, and 1.2KB +# code size increase. +# +# March 2014. +# +# Add support for Intel SHA Extensions. + +###################################################################### +# Current performance in cycles per processed byte (less is better): +# +# SHA256 SSSE3 AVX/XOP(*) SHA512 AVX/XOP(*) +# +# AMD K8 14.9 - - 9.57 - +# P4 17.3 - - 30.8 - +# Core 2 15.6 13.8(+13%) - 9.97 - +# Westmere 14.8 12.3(+19%) - 9.58 - +# Sandy Bridge 17.4 14.2(+23%) 11.6(+50%(**)) 11.2 8.10(+38%(**)) +# Ivy Bridge 12.6 10.5(+20%) 10.3(+22%) 8.17 7.22(+13%) +# Haswell 12.2 9.28(+31%) 7.80(+56%) 7.66 5.40(+42%) +# Bulldozer 21.1 13.6(+54%) 13.6(+54%(***)) 13.5 8.58(+57%) +# VIA Nano 23.0 16.5(+39%) - 14.7 - +# Atom 23.0 18.9(+22%) - 14.7 - +# Silvermont 27.4 20.6(+33%) - 17.5 - +# +# (*) whichever best applicable; +# (**) switch from ror to shrd stands for fair share of improvement; +# (***) execution time is fully determined by remaining integer-only +# part, body_00_15; reducing the amount of SIMD instructions +# below certain limit makes no difference/sense; to conserve +# space SHA256 XOP code path is therefore omitted; + +$flavour = shift; +$output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or +die "can't locate x86_64-xlate.pl"; + +if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1` + =~ /GNU assembler version ([2-9]\.[0-9]+)/) { + $avx = ($1>=2.19) + ($1>=2.22); +} + +if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) && + `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) { + $avx = ($1>=2.09) + ($1>=2.10); +} + +if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) && + `ml64 2>&1` =~ /Version ([0-9]+)\./) { + $avx = ($1>=10) + ($1>=11); +} + +if (!$avx && `$ENV{CC} -v 2>&1` =~ /(^clang version|based on LLVM) ([3-9]\.[0-9]+)/) { + $avx = ($2>=3.0) + ($2>3.0); +} + +$shaext=0; ### set to zero if compiling for 1.0.1 +$avx=1 if (!$shaext && $avx); + +open OUT,"| \"$^X\" $xlate $flavour"; +*STDOUT=*OUT; + +if ($output =~ /512/) { + $func="sha512_block_data_order"; + $TABLE="K512"; + $SZ=8; + @ROT=($A,$B,$C,$D,$E,$F,$G,$H)=("%rax","%rbx","%rcx","%rdx", + "%r8", "%r9", "%r10","%r11"); + ($T1,$a0,$a1,$a2,$a3)=("%r12","%r13","%r14","%r15","%rdi"); + @Sigma0=(28,34,39); + @Sigma1=(14,18,41); + @sigma0=(1, 8, 7); + @sigma1=(19,61, 6); + $rounds=80; +} else { + $func="sha256_block_data_order"; + $TABLE="K256"; + $SZ=4; + @ROT=($A,$B,$C,$D,$E,$F,$G,$H)=("%eax","%ebx","%ecx","%edx", + "%r8d","%r9d","%r10d","%r11d"); + ($T1,$a0,$a1,$a2,$a3)=("%r12d","%r13d","%r14d","%r15d","%edi"); + @Sigma0=( 2,13,22); + @Sigma1=( 6,11,25); + @sigma0=( 7,18, 3); + @sigma1=(17,19,10); + $rounds=64; +} + +$ctx="%rdi"; # 1st arg, zapped by $a3 +$inp="%rsi"; # 2nd arg +$Tbl="%rbp"; + +$_ctx="16*$SZ+0*8(%rsp)"; +$_inp="16*$SZ+1*8(%rsp)"; +$_end="16*$SZ+2*8(%rsp)"; +$_rsp="16*$SZ+3*8(%rsp)"; +$framesz="16*$SZ+4*8"; + + +sub ROUND_00_15() +{ my ($i,$a,$b,$c,$d,$e,$f,$g,$h) = @_; + my $STRIDE=$SZ; + $STRIDE += 16 if ($i%(16/$SZ)==(16/$SZ-1)); + +$code.=<<___; + ror \$`$Sigma1[2]-$Sigma1[1]`,$a0 + mov $f,$a2 + + xor $e,$a0 + ror \$`$Sigma0[2]-$Sigma0[1]`,$a1 + xor $g,$a2 # f^g + + mov $T1,`$SZ*($i&0xf)`(%rsp) + xor $a,$a1 + and $e,$a2 # (f^g)&e + + ror \$`$Sigma1[1]-$Sigma1[0]`,$a0 + add $h,$T1 # T1+=h + xor $g,$a2 # Ch(e,f,g)=((f^g)&e)^g + + ror \$`$Sigma0[1]-$Sigma0[0]`,$a1 + xor $e,$a0 + add $a2,$T1 # T1+=Ch(e,f,g) + + mov $a,$a2 + add ($Tbl),$T1 # T1+=K[round] + xor $a,$a1 + + xor $b,$a2 # a^b, b^c in next round + ror \$$Sigma1[0],$a0 # Sigma1(e) + mov $b,$h + + and $a2,$a3 + ror \$$Sigma0[0],$a1 # Sigma0(a) + add $a0,$T1 # T1+=Sigma1(e) + + xor $a3,$h # h=Maj(a,b,c)=Ch(a^b,c,b) + add $T1,$d # d+=T1 + add $T1,$h # h+=T1 + + lea $STRIDE($Tbl),$Tbl # round++ +___ +$code.=<<___ if ($i<15); + add $a1,$h # h+=Sigma0(a) +___ + ($a2,$a3) = ($a3,$a2); +} + +sub ROUND_16_XX() +{ my ($i,$a,$b,$c,$d,$e,$f,$g,$h) = @_; + +$code.=<<___; + mov `$SZ*(($i+1)&0xf)`(%rsp),$a0 + mov `$SZ*(($i+14)&0xf)`(%rsp),$a2 + + mov $a0,$T1 + ror \$`$sigma0[1]-$sigma0[0]`,$a0 + add $a1,$a # modulo-scheduled h+=Sigma0(a) + mov $a2,$a1 + ror \$`$sigma1[1]-$sigma1[0]`,$a2 + + xor $T1,$a0 + shr \$$sigma0[2],$T1 + ror \$$sigma0[0],$a0 + xor $a1,$a2 + shr \$$sigma1[2],$a1 + + ror \$$sigma1[0],$a2 + xor $a0,$T1 # sigma0(X[(i+1)&0xf]) + xor $a1,$a2 # sigma1(X[(i+14)&0xf]) + add `$SZ*(($i+9)&0xf)`(%rsp),$T1 + + add `$SZ*($i&0xf)`(%rsp),$T1 + mov $e,$a0 + add $a2,$T1 + mov $a,$a1 +___ + &ROUND_00_15(@_); +} + +$code=<<___; +.text + +.extern OPENSSL_ia32cap_P +.globl $func +.type $func,\@function,3 +.align 16 +$func: +___ +$code.=<<___ if ($SZ==4 || $avx); + lea OPENSSL_ia32cap_P(%rip),%r11 + mov 0(%r11),%r9d + mov 4(%r11),%r10d + mov 8(%r11),%r11d +___ +$code.=<<___ if ($SZ==4 && $shaext); + test \$`1<<29`,%r11d # check for SHA + jnz _shaext_shortcut +___ +$code.=<<___ if ($avx && $SZ==8); + test \$`1<<11`,%r10d # check for XOP + jnz .Lxop_shortcut +___ +$code.=<<___ if ($avx>1); + and \$`1<<8|1<<5|1<<3`,%r11d # check for BMI2+AVX2+BMI1 + cmp \$`1<<8|1<<5|1<<3`,%r11d + je .Lavx2_shortcut +___ +$code.=<<___ if ($avx); + and \$`1<<30`,%r9d # mask "Intel CPU" bit + and \$`1<<28|1<<9`,%r10d # mask AVX and SSSE3 bits + or %r9d,%r10d + cmp \$`1<<28|1<<9|1<<30`,%r10d + je .Lavx_shortcut +___ +$code.=<<___ if ($SZ==4); + test \$`1<<9`,%r10d + jnz .Lssse3_shortcut +___ +$code.=<<___; + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + mov %rsp,%r11 # copy %rsp + shl \$4,%rdx # num*16 + sub \$$framesz,%rsp + lea ($inp,%rdx,$SZ),%rdx # inp+num*16*$SZ + and \$-64,%rsp # align stack frame + mov $ctx,$_ctx # save ctx, 1st arg + mov $inp,$_inp # save inp, 2nd arh + mov %rdx,$_end # save end pointer, "3rd" arg + mov %r11,$_rsp # save copy of %rsp +.Lprologue: + + mov $SZ*0($ctx),$A + mov $SZ*1($ctx),$B + mov $SZ*2($ctx),$C + mov $SZ*3($ctx),$D + mov $SZ*4($ctx),$E + mov $SZ*5($ctx),$F + mov $SZ*6($ctx),$G + mov $SZ*7($ctx),$H + jmp .Lloop + +.align 16 +.Lloop: + mov $B,$a3 + lea $TABLE(%rip),$Tbl + xor $C,$a3 # magic +___ + for($i=0;$i<16;$i++) { + $code.=" mov $SZ*$i($inp),$T1\n"; + $code.=" mov @ROT[4],$a0\n"; + $code.=" mov @ROT[0],$a1\n"; + $code.=" bswap $T1\n"; + &ROUND_00_15($i,@ROT); + unshift(@ROT,pop(@ROT)); + } +$code.=<<___; + jmp .Lrounds_16_xx +.align 16 +.Lrounds_16_xx: +___ + for(;$i<32;$i++) { + &ROUND_16_XX($i,@ROT); + unshift(@ROT,pop(@ROT)); + } + +$code.=<<___; + cmpb \$0,`$SZ-1`($Tbl) + jnz .Lrounds_16_xx + + mov $_ctx,$ctx + add $a1,$A # modulo-scheduled h+=Sigma0(a) + lea 16*$SZ($inp),$inp + + add $SZ*0($ctx),$A + add $SZ*1($ctx),$B + add $SZ*2($ctx),$C + add $SZ*3($ctx),$D + add $SZ*4($ctx),$E + add $SZ*5($ctx),$F + add $SZ*6($ctx),$G + add $SZ*7($ctx),$H + + cmp $_end,$inp + + mov $A,$SZ*0($ctx) + mov $B,$SZ*1($ctx) + mov $C,$SZ*2($ctx) + mov $D,$SZ*3($ctx) + mov $E,$SZ*4($ctx) + mov $F,$SZ*5($ctx) + mov $G,$SZ*6($ctx) + mov $H,$SZ*7($ctx) + jb .Lloop + + mov $_rsp,%rsi + mov (%rsi),%r15 + mov 8(%rsi),%r14 + mov 16(%rsi),%r13 + mov 24(%rsi),%r12 + mov 32(%rsi),%rbp + mov 40(%rsi),%rbx + lea 48(%rsi),%rsp +.Lepilogue: + ret +.size $func,.-$func +___ + +if ($SZ==4) { +$code.=<<___; +.align 64 +.type $TABLE,\@object +$TABLE: + .long 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5 + .long 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5 + .long 0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5 + .long 0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5 + .long 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3 + .long 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3 + .long 0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174 + .long 0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174 + .long 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc + .long 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc + .long 0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da + .long 0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da + .long 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7 + .long 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7 + .long 0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967 + .long 0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967 + .long 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13 + .long 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13 + .long 0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85 + .long 0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85 + .long 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3 + .long 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3 + .long 0xd192e819,0xd6990624,0xf40e3585,0x106aa070 + .long 0xd192e819,0xd6990624,0xf40e3585,0x106aa070 + .long 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5 + .long 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5 + .long 0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3 + .long 0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3 + .long 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208 + .long 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208 + .long 0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 + .long 0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 + + .long 0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f + .long 0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f + .long 0x03020100,0x0b0a0908,0xffffffff,0xffffffff + .long 0x03020100,0x0b0a0908,0xffffffff,0xffffffff + .long 0xffffffff,0xffffffff,0x03020100,0x0b0a0908 + .long 0xffffffff,0xffffffff,0x03020100,0x0b0a0908 + .asciz "SHA256 block transform for x86_64, CRYPTOGAMS by " +___ +} else { +$code.=<<___; +.align 64 +.type $TABLE,\@object +$TABLE: + .quad 0x428a2f98d728ae22,0x7137449123ef65cd + .quad 0x428a2f98d728ae22,0x7137449123ef65cd + .quad 0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc + .quad 0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc + .quad 0x3956c25bf348b538,0x59f111f1b605d019 + .quad 0x3956c25bf348b538,0x59f111f1b605d019 + .quad 0x923f82a4af194f9b,0xab1c5ed5da6d8118 + .quad 0x923f82a4af194f9b,0xab1c5ed5da6d8118 + .quad 0xd807aa98a3030242,0x12835b0145706fbe + .quad 0xd807aa98a3030242,0x12835b0145706fbe + .quad 0x243185be4ee4b28c,0x550c7dc3d5ffb4e2 + .quad 0x243185be4ee4b28c,0x550c7dc3d5ffb4e2 + .quad 0x72be5d74f27b896f,0x80deb1fe3b1696b1 + .quad 0x72be5d74f27b896f,0x80deb1fe3b1696b1 + .quad 0x9bdc06a725c71235,0xc19bf174cf692694 + .quad 0x9bdc06a725c71235,0xc19bf174cf692694 + .quad 0xe49b69c19ef14ad2,0xefbe4786384f25e3 + .quad 0xe49b69c19ef14ad2,0xefbe4786384f25e3 + .quad 0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65 + .quad 0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65 + .quad 0x2de92c6f592b0275,0x4a7484aa6ea6e483 + .quad 0x2de92c6f592b0275,0x4a7484aa6ea6e483 + .quad 0x5cb0a9dcbd41fbd4,0x76f988da831153b5 + .quad 0x5cb0a9dcbd41fbd4,0x76f988da831153b5 + .quad 0x983e5152ee66dfab,0xa831c66d2db43210 + .quad 0x983e5152ee66dfab,0xa831c66d2db43210 + .quad 0xb00327c898fb213f,0xbf597fc7beef0ee4 + .quad 0xb00327c898fb213f,0xbf597fc7beef0ee4 + .quad 0xc6e00bf33da88fc2,0xd5a79147930aa725 + .quad 0xc6e00bf33da88fc2,0xd5a79147930aa725 + .quad 0x06ca6351e003826f,0x142929670a0e6e70 + .quad 0x06ca6351e003826f,0x142929670a0e6e70 + .quad 0x27b70a8546d22ffc,0x2e1b21385c26c926 + .quad 0x27b70a8546d22ffc,0x2e1b21385c26c926 + .quad 0x4d2c6dfc5ac42aed,0x53380d139d95b3df + .quad 0x4d2c6dfc5ac42aed,0x53380d139d95b3df + .quad 0x650a73548baf63de,0x766a0abb3c77b2a8 + .quad 0x650a73548baf63de,0x766a0abb3c77b2a8 + .quad 0x81c2c92e47edaee6,0x92722c851482353b + .quad 0x81c2c92e47edaee6,0x92722c851482353b + .quad 0xa2bfe8a14cf10364,0xa81a664bbc423001 + .quad 0xa2bfe8a14cf10364,0xa81a664bbc423001 + .quad 0xc24b8b70d0f89791,0xc76c51a30654be30 + .quad 0xc24b8b70d0f89791,0xc76c51a30654be30 + .quad 0xd192e819d6ef5218,0xd69906245565a910 + .quad 0xd192e819d6ef5218,0xd69906245565a910 + .quad 0xf40e35855771202a,0x106aa07032bbd1b8 + .quad 0xf40e35855771202a,0x106aa07032bbd1b8 + .quad 0x19a4c116b8d2d0c8,0x1e376c085141ab53 + .quad 0x19a4c116b8d2d0c8,0x1e376c085141ab53 + .quad 0x2748774cdf8eeb99,0x34b0bcb5e19b48a8 + .quad 0x2748774cdf8eeb99,0x34b0bcb5e19b48a8 + .quad 0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb + .quad 0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb + .quad 0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3 + .quad 0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3 + .quad 0x748f82ee5defb2fc,0x78a5636f43172f60 + .quad 0x748f82ee5defb2fc,0x78a5636f43172f60 + .quad 0x84c87814a1f0ab72,0x8cc702081a6439ec + .quad 0x84c87814a1f0ab72,0x8cc702081a6439ec + .quad 0x90befffa23631e28,0xa4506cebde82bde9 + .quad 0x90befffa23631e28,0xa4506cebde82bde9 + .quad 0xbef9a3f7b2c67915,0xc67178f2e372532b + .quad 0xbef9a3f7b2c67915,0xc67178f2e372532b + .quad 0xca273eceea26619c,0xd186b8c721c0c207 + .quad 0xca273eceea26619c,0xd186b8c721c0c207 + .quad 0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178 + .quad 0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178 + .quad 0x06f067aa72176fba,0x0a637dc5a2c898a6 + .quad 0x06f067aa72176fba,0x0a637dc5a2c898a6 + .quad 0x113f9804bef90dae,0x1b710b35131c471b + .quad 0x113f9804bef90dae,0x1b710b35131c471b + .quad 0x28db77f523047d84,0x32caab7b40c72493 + .quad 0x28db77f523047d84,0x32caab7b40c72493 + .quad 0x3c9ebe0a15c9bebc,0x431d67c49c100d4c + .quad 0x3c9ebe0a15c9bebc,0x431d67c49c100d4c + .quad 0x4cc5d4becb3e42b6,0x597f299cfc657e2a + .quad 0x4cc5d4becb3e42b6,0x597f299cfc657e2a + .quad 0x5fcb6fab3ad6faec,0x6c44198c4a475817 + .quad 0x5fcb6fab3ad6faec,0x6c44198c4a475817 + + .quad 0x0001020304050607,0x08090a0b0c0d0e0f + .quad 0x0001020304050607,0x08090a0b0c0d0e0f + .asciz "SHA512 block transform for x86_64, CRYPTOGAMS by " +___ +} + +###################################################################### +# SIMD code paths +# +if ($SZ==4 && $shaext) {{{ +###################################################################### +# Intel SHA Extensions implementation of SHA256 update function. +# +my ($ctx,$inp,$num,$Tbl)=("%rdi","%rsi","%rdx","%rcx"); + +my ($Wi,$ABEF,$CDGH,$TMP,$BSWAP,$ABEF_SAVE,$CDGH_SAVE)=map("%xmm$_",(0..2,7..10)); +my @MSG=map("%xmm$_",(3..6)); + +$code.=<<___; +.type sha256_block_data_order_shaext,\@function,3 +.align 64 +sha256_block_data_order_shaext: +_shaext_shortcut: +___ +$code.=<<___ if ($win64); + lea `-8-5*16`(%rsp),%rsp + movaps %xmm6,-8-5*16(%rax) + movaps %xmm7,-8-4*16(%rax) + movaps %xmm8,-8-3*16(%rax) + movaps %xmm9,-8-2*16(%rax) + movaps %xmm10,-8-1*16(%rax) +.Lprologue_shaext: +___ +$code.=<<___; + lea K256+0x80(%rip),$Tbl + movdqu ($ctx),$ABEF # DCBA + movdqu 16($ctx),$CDGH # HGFE + movdqa 0x200-0x80($Tbl),$TMP # byte swap mask + + pshufd \$0x1b,$ABEF,$Wi # ABCD + pshufd \$0xb1,$ABEF,$ABEF # CDAB + pshufd \$0x1b,$CDGH,$CDGH # EFGH + movdqa $TMP,$BSWAP # offload + palignr \$8,$CDGH,$ABEF # ABEF + punpcklqdq $Wi,$CDGH # CDGH + jmp .Loop_shaext + +.align 16 +.Loop_shaext: + movdqu ($inp),@MSG[0] + movdqu 0x10($inp),@MSG[1] + movdqu 0x20($inp),@MSG[2] + pshufb $TMP,@MSG[0] + movdqu 0x30($inp),@MSG[3] + + movdqa 0*32-0x80($Tbl),$Wi + paddd @MSG[0],$Wi + pshufb $TMP,@MSG[1] + movdqa $CDGH,$CDGH_SAVE # offload + sha256rnds2 $ABEF,$CDGH # 0-3 + pshufd \$0x0e,$Wi,$Wi + nop + movdqa $ABEF,$ABEF_SAVE # offload + sha256rnds2 $CDGH,$ABEF + + movdqa 1*32-0x80($Tbl),$Wi + paddd @MSG[1],$Wi + pshufb $TMP,@MSG[2] + sha256rnds2 $ABEF,$CDGH # 4-7 + pshufd \$0x0e,$Wi,$Wi + lea 0x40($inp),$inp + sha256msg1 @MSG[1],@MSG[0] + sha256rnds2 $CDGH,$ABEF + + movdqa 2*32-0x80($Tbl),$Wi + paddd @MSG[2],$Wi + pshufb $TMP,@MSG[3] + sha256rnds2 $ABEF,$CDGH # 8-11 + pshufd \$0x0e,$Wi,$Wi + movdqa @MSG[3],$TMP + palignr \$4,@MSG[2],$TMP + nop + paddd $TMP,@MSG[0] + sha256msg1 @MSG[2],@MSG[1] + sha256rnds2 $CDGH,$ABEF + + movdqa 3*32-0x80($Tbl),$Wi + paddd @MSG[3],$Wi + sha256msg2 @MSG[3],@MSG[0] + sha256rnds2 $ABEF,$CDGH # 12-15 + pshufd \$0x0e,$Wi,$Wi + movdqa @MSG[0],$TMP + palignr \$4,@MSG[3],$TMP + nop + paddd $TMP,@MSG[1] + sha256msg1 @MSG[3],@MSG[2] + sha256rnds2 $CDGH,$ABEF +___ +for($i=4;$i<16-3;$i++) { +$code.=<<___; + movdqa $i*32-0x80($Tbl),$Wi + paddd @MSG[0],$Wi + sha256msg2 @MSG[0],@MSG[1] + sha256rnds2 $ABEF,$CDGH # 16-19... + pshufd \$0x0e,$Wi,$Wi + movdqa @MSG[1],$TMP + palignr \$4,@MSG[0],$TMP + nop + paddd $TMP,@MSG[2] + sha256msg1 @MSG[0],@MSG[3] + sha256rnds2 $CDGH,$ABEF +___ + push(@MSG,shift(@MSG)); +} +$code.=<<___; + movdqa 13*32-0x80($Tbl),$Wi + paddd @MSG[0],$Wi + sha256msg2 @MSG[0],@MSG[1] + sha256rnds2 $ABEF,$CDGH # 52-55 + pshufd \$0x0e,$Wi,$Wi + movdqa @MSG[1],$TMP + palignr \$4,@MSG[0],$TMP + sha256rnds2 $CDGH,$ABEF + paddd $TMP,@MSG[2] + + movdqa 14*32-0x80($Tbl),$Wi + paddd @MSG[1],$Wi + sha256rnds2 $ABEF,$CDGH # 56-59 + pshufd \$0x0e,$Wi,$Wi + sha256msg2 @MSG[1],@MSG[2] + movdqa $BSWAP,$TMP + sha256rnds2 $CDGH,$ABEF + + movdqa 15*32-0x80($Tbl),$Wi + paddd @MSG[2],$Wi + nop + sha256rnds2 $ABEF,$CDGH # 60-63 + pshufd \$0x0e,$Wi,$Wi + dec $num + nop + sha256rnds2 $CDGH,$ABEF + + paddd $CDGH_SAVE,$CDGH + paddd $ABEF_SAVE,$ABEF + jnz .Loop_shaext + + pshufd \$0xb1,$CDGH,$CDGH # DCHG + pshufd \$0x1b,$ABEF,$TMP # FEBA + pshufd \$0xb1,$ABEF,$ABEF # BAFE + punpckhqdq $CDGH,$ABEF # DCBA + palignr \$8,$TMP,$CDGH # HGFE + + movdqu $ABEF,($ctx) + movdqu $CDGH,16($ctx) +___ +$code.=<<___ if ($win64); + movaps -8-5*16(%rax),%xmm6 + movaps -8-4*16(%rax),%xmm7 + movaps -8-3*16(%rax),%xmm8 + movaps -8-2*16(%rax),%xmm9 + movaps -8-1*16(%rax),%xmm10 + mov %rax,%rsp +.Lepilogue_shaext: +___ +$code.=<<___; + ret +.size sha256_block_data_order_shaext,.-sha256_block_data_order_shaext +___ +}}} +{{{ + +my $a4=$T1; +my ($a,$b,$c,$d,$e,$f,$g,$h); + +sub AUTOLOAD() # thunk [simplified] 32-bit style perlasm +{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://; + my $arg = pop; + $arg = "\$$arg" if ($arg*1 eq $arg); + $code .= "\t$opcode\t".join(',',$arg,reverse @_)."\n"; +} + +sub body_00_15 () { + ( + '($a,$b,$c,$d,$e,$f,$g,$h)=@ROT;'. + + '&ror ($a0,$Sigma1[2]-$Sigma1[1])', + '&mov ($a,$a1)', + '&mov ($a4,$f)', + + '&ror ($a1,$Sigma0[2]-$Sigma0[1])', + '&xor ($a0,$e)', + '&xor ($a4,$g)', # f^g + + '&ror ($a0,$Sigma1[1]-$Sigma1[0])', + '&xor ($a1,$a)', + '&and ($a4,$e)', # (f^g)&e + + '&xor ($a0,$e)', + '&add ($h,$SZ*($i&15)."(%rsp)")', # h+=X[i]+K[i] + '&mov ($a2,$a)', + + '&xor ($a4,$g)', # Ch(e,f,g)=((f^g)&e)^g + '&ror ($a1,$Sigma0[1]-$Sigma0[0])', + '&xor ($a2,$b)', # a^b, b^c in next round + + '&add ($h,$a4)', # h+=Ch(e,f,g) + '&ror ($a0,$Sigma1[0])', # Sigma1(e) + '&and ($a3,$a2)', # (b^c)&(a^b) + + '&xor ($a1,$a)', + '&add ($h,$a0)', # h+=Sigma1(e) + '&xor ($a3,$b)', # Maj(a,b,c)=Ch(a^b,c,b) + + '&ror ($a1,$Sigma0[0])', # Sigma0(a) + '&add ($d,$h)', # d+=h + '&add ($h,$a3)', # h+=Maj(a,b,c) + + '&mov ($a0,$d)', + '&add ($a1,$h);'. # h+=Sigma0(a) + '($a2,$a3) = ($a3,$a2); unshift(@ROT,pop(@ROT)); $i++;' + ); +} + +###################################################################### +# SSSE3 code path +# +if ($SZ==4) { # SHA256 only +my @X = map("%xmm$_",(0..3)); +my ($t0,$t1,$t2,$t3, $t4,$t5) = map("%xmm$_",(4..9)); + +$code.=<<___; +.type ${func}_ssse3,\@function,3 +.align 64 +${func}_ssse3: +.Lssse3_shortcut: + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + mov %rsp,%r11 # copy %rsp + shl \$4,%rdx # num*16 + sub \$`$framesz+$win64*16*4`,%rsp + lea ($inp,%rdx,$SZ),%rdx # inp+num*16*$SZ + and \$-64,%rsp # align stack frame + mov $ctx,$_ctx # save ctx, 1st arg + mov $inp,$_inp # save inp, 2nd arh + mov %rdx,$_end # save end pointer, "3rd" arg + mov %r11,$_rsp # save copy of %rsp +___ +$code.=<<___ if ($win64); + movaps %xmm6,16*$SZ+32(%rsp) + movaps %xmm7,16*$SZ+48(%rsp) + movaps %xmm8,16*$SZ+64(%rsp) + movaps %xmm9,16*$SZ+80(%rsp) +___ +$code.=<<___; +.Lprologue_ssse3: + + mov $SZ*0($ctx),$A + mov $SZ*1($ctx),$B + mov $SZ*2($ctx),$C + mov $SZ*3($ctx),$D + mov $SZ*4($ctx),$E + mov $SZ*5($ctx),$F + mov $SZ*6($ctx),$G + mov $SZ*7($ctx),$H +___ + +$code.=<<___; + #movdqa $TABLE+`$SZ*2*$rounds`+32(%rip),$t4 + #movdqa $TABLE+`$SZ*2*$rounds`+64(%rip),$t5 + jmp .Lloop_ssse3 +.align 16 +.Lloop_ssse3: + movdqa $TABLE+`$SZ*2*$rounds`(%rip),$t3 + movdqu 0x00($inp),@X[0] + movdqu 0x10($inp),@X[1] + movdqu 0x20($inp),@X[2] + pshufb $t3,@X[0] + movdqu 0x30($inp),@X[3] + lea $TABLE(%rip),$Tbl + pshufb $t3,@X[1] + movdqa 0x00($Tbl),$t0 + movdqa 0x20($Tbl),$t1 + pshufb $t3,@X[2] + paddd @X[0],$t0 + movdqa 0x40($Tbl),$t2 + pshufb $t3,@X[3] + movdqa 0x60($Tbl),$t3 + paddd @X[1],$t1 + paddd @X[2],$t2 + paddd @X[3],$t3 + movdqa $t0,0x00(%rsp) + mov $A,$a1 + movdqa $t1,0x10(%rsp) + mov $B,$a3 + movdqa $t2,0x20(%rsp) + xor $C,$a3 # magic + movdqa $t3,0x30(%rsp) + mov $E,$a0 + jmp .Lssse3_00_47 + +.align 16 +.Lssse3_00_47: + sub \$`-16*2*$SZ`,$Tbl # size optimization +___ +sub Xupdate_256_SSSE3 () { + ( + '&movdqa ($t0,@X[1]);', + '&movdqa ($t3,@X[3])', + '&palignr ($t0,@X[0],$SZ)', # X[1..4] + '&palignr ($t3,@X[2],$SZ);', # X[9..12] + '&movdqa ($t1,$t0)', + '&movdqa ($t2,$t0);', + '&psrld ($t0,$sigma0[2])', + '&paddd (@X[0],$t3);', # X[0..3] += X[9..12] + '&psrld ($t2,$sigma0[0])', + '&pshufd ($t3,@X[3],0b11111010)',# X[14..15] + '&pslld ($t1,8*$SZ-$sigma0[1]);'. + '&pxor ($t0,$t2)', + '&psrld ($t2,$sigma0[1]-$sigma0[0]);'. + '&pxor ($t0,$t1)', + '&pslld ($t1,$sigma0[1]-$sigma0[0]);'. + '&pxor ($t0,$t2);', + '&movdqa ($t2,$t3)', + '&pxor ($t0,$t1);', # sigma0(X[1..4]) + '&psrld ($t3,$sigma1[2])', + '&paddd (@X[0],$t0);', # X[0..3] += sigma0(X[1..4]) + '&psrlq ($t2,$sigma1[0])', + '&pxor ($t3,$t2);', + '&psrlq ($t2,$sigma1[1]-$sigma1[0])', + '&pxor ($t3,$t2)', + '&pshufb ($t3,$t4)', # sigma1(X[14..15]) + '&paddd (@X[0],$t3)', # X[0..1] += sigma1(X[14..15]) + '&pshufd ($t3,@X[0],0b01010000)',# X[16..17] + '&movdqa ($t2,$t3);', + '&psrld ($t3,$sigma1[2])', + '&psrlq ($t2,$sigma1[0])', + '&pxor ($t3,$t2);', + '&psrlq ($t2,$sigma1[1]-$sigma1[0])', + '&pxor ($t3,$t2);', + '&movdqa ($t2,16*2*$j."($Tbl)")', + '&pshufb ($t3,$t5)', + '&paddd (@X[0],$t3)' # X[2..3] += sigma1(X[16..17]) + ); +} + +sub SSSE3_256_00_47 () { +my $j = shift; +my $body = shift; +my @X = @_; +my @insns = (&$body,&$body,&$body,&$body); # 104 instructions + + if (0) { + foreach (Xupdate_256_SSSE3()) { # 36 instructions + eval; + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + } + } else { # squeeze extra 4% on Westmere and 19% on Atom + eval(shift(@insns)); #@ + &movdqa ($t0,@X[1]); + eval(shift(@insns)); + eval(shift(@insns)); + &movdqa ($t3,@X[3]); + eval(shift(@insns)); #@ + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); #@ + eval(shift(@insns)); + &palignr ($t0,@X[0],$SZ); # X[1..4] + eval(shift(@insns)); + eval(shift(@insns)); + &palignr ($t3,@X[2],$SZ); # X[9..12] + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); #@ + &movdqa ($t1,$t0); + eval(shift(@insns)); + eval(shift(@insns)); + &movdqa ($t2,$t0); + eval(shift(@insns)); #@ + eval(shift(@insns)); + &psrld ($t0,$sigma0[2]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &paddd (@X[0],$t3); # X[0..3] += X[9..12] + eval(shift(@insns)); #@ + eval(shift(@insns)); + &psrld ($t2,$sigma0[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &pshufd ($t3,@X[3],0b11111010); # X[4..15] + eval(shift(@insns)); + eval(shift(@insns)); #@ + &pslld ($t1,8*$SZ-$sigma0[1]); + eval(shift(@insns)); + eval(shift(@insns)); + &pxor ($t0,$t2); + eval(shift(@insns)); #@ + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); #@ + &psrld ($t2,$sigma0[1]-$sigma0[0]); + eval(shift(@insns)); + &pxor ($t0,$t1); + eval(shift(@insns)); + eval(shift(@insns)); + &pslld ($t1,$sigma0[1]-$sigma0[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &pxor ($t0,$t2); + eval(shift(@insns)); + eval(shift(@insns)); #@ + &movdqa ($t2,$t3); + eval(shift(@insns)); + eval(shift(@insns)); + &pxor ($t0,$t1); # sigma0(X[1..4]) + eval(shift(@insns)); #@ + eval(shift(@insns)); + eval(shift(@insns)); + &psrld ($t3,$sigma1[2]); + eval(shift(@insns)); + eval(shift(@insns)); + &paddd (@X[0],$t0); # X[0..3] += sigma0(X[1..4]) + eval(shift(@insns)); #@ + eval(shift(@insns)); + &psrlq ($t2,$sigma1[0]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &pxor ($t3,$t2); + eval(shift(@insns)); #@ + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); #@ + &psrlq ($t2,$sigma1[1]-$sigma1[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &pxor ($t3,$t2); + eval(shift(@insns)); #@ + eval(shift(@insns)); + eval(shift(@insns)); + #&pshufb ($t3,$t4); # sigma1(X[14..15]) + &pshufd ($t3,$t3,0b10000000); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &psrldq ($t3,8); + eval(shift(@insns)); + eval(shift(@insns)); #@ + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); #@ + &paddd (@X[0],$t3); # X[0..1] += sigma1(X[14..15]) + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &pshufd ($t3,@X[0],0b01010000); # X[16..17] + eval(shift(@insns)); + eval(shift(@insns)); #@ + eval(shift(@insns)); + &movdqa ($t2,$t3); + eval(shift(@insns)); + eval(shift(@insns)); + &psrld ($t3,$sigma1[2]); + eval(shift(@insns)); + eval(shift(@insns)); #@ + &psrlq ($t2,$sigma1[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &pxor ($t3,$t2); + eval(shift(@insns)); #@ + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); #@ + eval(shift(@insns)); + &psrlq ($t2,$sigma1[1]-$sigma1[0]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &pxor ($t3,$t2); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); #@ + #&pshufb ($t3,$t5); + &pshufd ($t3,$t3,0b00001000); + eval(shift(@insns)); + eval(shift(@insns)); + &movdqa ($t2,16*2*$j."($Tbl)"); + eval(shift(@insns)); #@ + eval(shift(@insns)); + &pslldq ($t3,8); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &paddd (@X[0],$t3); # X[2..3] += sigma1(X[16..17]) + eval(shift(@insns)); #@ + eval(shift(@insns)); + eval(shift(@insns)); + } + &paddd ($t2,@X[0]); + foreach (@insns) { eval; } # remaining instructions + &movdqa (16*$j."(%rsp)",$t2); +} + + for ($i=0,$j=0; $j<4; $j++) { + &SSSE3_256_00_47($j,\&body_00_15,@X); + push(@X,shift(@X)); # rotate(@X) + } + &cmpb ($SZ-1+16*2*$SZ."($Tbl)",0); + &jne (".Lssse3_00_47"); + + for ($i=0; $i<16; ) { + foreach(body_00_15()) { eval; } + } +$code.=<<___; + mov $_ctx,$ctx + mov $a1,$A + + add $SZ*0($ctx),$A + lea 16*$SZ($inp),$inp + add $SZ*1($ctx),$B + add $SZ*2($ctx),$C + add $SZ*3($ctx),$D + add $SZ*4($ctx),$E + add $SZ*5($ctx),$F + add $SZ*6($ctx),$G + add $SZ*7($ctx),$H + + cmp $_end,$inp + + mov $A,$SZ*0($ctx) + mov $B,$SZ*1($ctx) + mov $C,$SZ*2($ctx) + mov $D,$SZ*3($ctx) + mov $E,$SZ*4($ctx) + mov $F,$SZ*5($ctx) + mov $G,$SZ*6($ctx) + mov $H,$SZ*7($ctx) + jb .Lloop_ssse3 + + mov $_rsp,%rsi +___ +$code.=<<___ if ($win64); + movaps 16*$SZ+32(%rsp),%xmm6 + movaps 16*$SZ+48(%rsp),%xmm7 + movaps 16*$SZ+64(%rsp),%xmm8 + movaps 16*$SZ+80(%rsp),%xmm9 +___ +$code.=<<___; + mov (%rsi),%r15 + mov 8(%rsi),%r14 + mov 16(%rsi),%r13 + mov 24(%rsi),%r12 + mov 32(%rsi),%rbp + mov 40(%rsi),%rbx + lea 48(%rsi),%rsp +.Lepilogue_ssse3: + ret +.size ${func}_ssse3,.-${func}_ssse3 +___ +} + +if ($avx) {{ +###################################################################### +# XOP code path +# +if ($SZ==8) { # SHA512 only +$code.=<<___; +.type ${func}_xop,\@function,3 +.align 64 +${func}_xop: +.Lxop_shortcut: + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + mov %rsp,%r11 # copy %rsp + shl \$4,%rdx # num*16 + sub \$`$framesz+$win64*16*($SZ==4?4:6)`,%rsp + lea ($inp,%rdx,$SZ),%rdx # inp+num*16*$SZ + and \$-64,%rsp # align stack frame + mov $ctx,$_ctx # save ctx, 1st arg + mov $inp,$_inp # save inp, 2nd arh + mov %rdx,$_end # save end pointer, "3rd" arg + mov %r11,$_rsp # save copy of %rsp +___ +$code.=<<___ if ($win64); + movaps %xmm6,16*$SZ+32(%rsp) + movaps %xmm7,16*$SZ+48(%rsp) + movaps %xmm8,16*$SZ+64(%rsp) + movaps %xmm9,16*$SZ+80(%rsp) +___ +$code.=<<___ if ($win64 && $SZ>4); + movaps %xmm10,16*$SZ+96(%rsp) + movaps %xmm11,16*$SZ+112(%rsp) +___ +$code.=<<___; +.Lprologue_xop: + + vzeroupper + mov $SZ*0($ctx),$A + mov $SZ*1($ctx),$B + mov $SZ*2($ctx),$C + mov $SZ*3($ctx),$D + mov $SZ*4($ctx),$E + mov $SZ*5($ctx),$F + mov $SZ*6($ctx),$G + mov $SZ*7($ctx),$H + jmp .Lloop_xop +___ + if ($SZ==4) { # SHA256 + my @X = map("%xmm$_",(0..3)); + my ($t0,$t1,$t2,$t3) = map("%xmm$_",(4..7)); + +$code.=<<___; +.align 16 +.Lloop_xop: + vmovdqa $TABLE+`$SZ*2*$rounds`(%rip),$t3 + vmovdqu 0x00($inp),@X[0] + vmovdqu 0x10($inp),@X[1] + vmovdqu 0x20($inp),@X[2] + vmovdqu 0x30($inp),@X[3] + vpshufb $t3,@X[0],@X[0] + lea $TABLE(%rip),$Tbl + vpshufb $t3,@X[1],@X[1] + vpshufb $t3,@X[2],@X[2] + vpaddd 0x00($Tbl),@X[0],$t0 + vpshufb $t3,@X[3],@X[3] + vpaddd 0x20($Tbl),@X[1],$t1 + vpaddd 0x40($Tbl),@X[2],$t2 + vpaddd 0x60($Tbl),@X[3],$t3 + vmovdqa $t0,0x00(%rsp) + mov $A,$a1 + vmovdqa $t1,0x10(%rsp) + mov $B,$a3 + vmovdqa $t2,0x20(%rsp) + xor $C,$a3 # magic + vmovdqa $t3,0x30(%rsp) + mov $E,$a0 + jmp .Lxop_00_47 + +.align 16 +.Lxop_00_47: + sub \$`-16*2*$SZ`,$Tbl # size optimization +___ +sub XOP_256_00_47 () { +my $j = shift; +my $body = shift; +my @X = @_; +my @insns = (&$body,&$body,&$body,&$body); # 104 instructions + + &vpalignr ($t0,@X[1],@X[0],$SZ); # X[1..4] + eval(shift(@insns)); + eval(shift(@insns)); + &vpalignr ($t3,@X[3],@X[2],$SZ); # X[9..12] + eval(shift(@insns)); + eval(shift(@insns)); + &vprotd ($t1,$t0,8*$SZ-$sigma0[1]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpsrld ($t0,$t0,$sigma0[2]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpaddd (@X[0],@X[0],$t3); # X[0..3] += X[9..12] + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vprotd ($t2,$t1,$sigma0[1]-$sigma0[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpxor ($t0,$t0,$t1); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vprotd ($t3,@X[3],8*$SZ-$sigma1[1]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpxor ($t0,$t0,$t2); # sigma0(X[1..4]) + eval(shift(@insns)); + eval(shift(@insns)); + &vpsrld ($t2,@X[3],$sigma1[2]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpaddd (@X[0],@X[0],$t0); # X[0..3] += sigma0(X[1..4]) + eval(shift(@insns)); + eval(shift(@insns)); + &vprotd ($t1,$t3,$sigma1[1]-$sigma1[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpxor ($t3,$t3,$t2); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vpxor ($t3,$t3,$t1); # sigma1(X[14..15]) + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vpsrldq ($t3,$t3,8); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vpaddd (@X[0],@X[0],$t3); # X[0..1] += sigma1(X[14..15]) + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vprotd ($t3,@X[0],8*$SZ-$sigma1[1]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpsrld ($t2,@X[0],$sigma1[2]); + eval(shift(@insns)); + eval(shift(@insns)); + &vprotd ($t1,$t3,$sigma1[1]-$sigma1[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpxor ($t3,$t3,$t2); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vpxor ($t3,$t3,$t1); # sigma1(X[16..17]) + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vpslldq ($t3,$t3,8); # 22 instructions + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vpaddd (@X[0],@X[0],$t3); # X[2..3] += sigma1(X[16..17]) + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vpaddd ($t2,@X[0],16*2*$j."($Tbl)"); + foreach (@insns) { eval; } # remaining instructions + &vmovdqa (16*$j."(%rsp)",$t2); +} + + for ($i=0,$j=0; $j<4; $j++) { + &XOP_256_00_47($j,\&body_00_15,@X); + push(@X,shift(@X)); # rotate(@X) + } + &cmpb ($SZ-1+16*2*$SZ."($Tbl)",0); + &jne (".Lxop_00_47"); + + for ($i=0; $i<16; ) { + foreach(body_00_15()) { eval; } + } + + } else { # SHA512 + my @X = map("%xmm$_",(0..7)); + my ($t0,$t1,$t2,$t3) = map("%xmm$_",(8..11)); + +$code.=<<___; +.align 16 +.Lloop_xop: + vmovdqa $TABLE+`$SZ*2*$rounds`(%rip),$t3 + vmovdqu 0x00($inp),@X[0] + lea $TABLE+0x80(%rip),$Tbl # size optimization + vmovdqu 0x10($inp),@X[1] + vmovdqu 0x20($inp),@X[2] + vpshufb $t3,@X[0],@X[0] + vmovdqu 0x30($inp),@X[3] + vpshufb $t3,@X[1],@X[1] + vmovdqu 0x40($inp),@X[4] + vpshufb $t3,@X[2],@X[2] + vmovdqu 0x50($inp),@X[5] + vpshufb $t3,@X[3],@X[3] + vmovdqu 0x60($inp),@X[6] + vpshufb $t3,@X[4],@X[4] + vmovdqu 0x70($inp),@X[7] + vpshufb $t3,@X[5],@X[5] + vpaddq -0x80($Tbl),@X[0],$t0 + vpshufb $t3,@X[6],@X[6] + vpaddq -0x60($Tbl),@X[1],$t1 + vpshufb $t3,@X[7],@X[7] + vpaddq -0x40($Tbl),@X[2],$t2 + vpaddq -0x20($Tbl),@X[3],$t3 + vmovdqa $t0,0x00(%rsp) + vpaddq 0x00($Tbl),@X[4],$t0 + vmovdqa $t1,0x10(%rsp) + vpaddq 0x20($Tbl),@X[5],$t1 + vmovdqa $t2,0x20(%rsp) + vpaddq 0x40($Tbl),@X[6],$t2 + vmovdqa $t3,0x30(%rsp) + vpaddq 0x60($Tbl),@X[7],$t3 + vmovdqa $t0,0x40(%rsp) + mov $A,$a1 + vmovdqa $t1,0x50(%rsp) + mov $B,$a3 + vmovdqa $t2,0x60(%rsp) + xor $C,$a3 # magic + vmovdqa $t3,0x70(%rsp) + mov $E,$a0 + jmp .Lxop_00_47 + +.align 16 +.Lxop_00_47: + add \$`16*2*$SZ`,$Tbl +___ +sub XOP_512_00_47 () { +my $j = shift; +my $body = shift; +my @X = @_; +my @insns = (&$body,&$body); # 52 instructions + + &vpalignr ($t0,@X[1],@X[0],$SZ); # X[1..2] + eval(shift(@insns)); + eval(shift(@insns)); + &vpalignr ($t3,@X[5],@X[4],$SZ); # X[9..10] + eval(shift(@insns)); + eval(shift(@insns)); + &vprotq ($t1,$t0,8*$SZ-$sigma0[1]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpsrlq ($t0,$t0,$sigma0[2]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpaddq (@X[0],@X[0],$t3); # X[0..1] += X[9..10] + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vprotq ($t2,$t1,$sigma0[1]-$sigma0[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpxor ($t0,$t0,$t1); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vprotq ($t3,@X[7],8*$SZ-$sigma1[1]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpxor ($t0,$t0,$t2); # sigma0(X[1..2]) + eval(shift(@insns)); + eval(shift(@insns)); + &vpsrlq ($t2,@X[7],$sigma1[2]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpaddq (@X[0],@X[0],$t0); # X[0..1] += sigma0(X[1..2]) + eval(shift(@insns)); + eval(shift(@insns)); + &vprotq ($t1,$t3,$sigma1[1]-$sigma1[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpxor ($t3,$t3,$t2); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vpxor ($t3,$t3,$t1); # sigma1(X[14..15]) + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vpaddq (@X[0],@X[0],$t3); # X[0..1] += sigma1(X[14..15]) + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vpaddq ($t2,@X[0],16*2*$j-0x80."($Tbl)"); + foreach (@insns) { eval; } # remaining instructions + &vmovdqa (16*$j."(%rsp)",$t2); +} + + for ($i=0,$j=0; $j<8; $j++) { + &XOP_512_00_47($j,\&body_00_15,@X); + push(@X,shift(@X)); # rotate(@X) + } + &cmpb ($SZ-1+16*2*$SZ-0x80."($Tbl)",0); + &jne (".Lxop_00_47"); + + for ($i=0; $i<16; ) { + foreach(body_00_15()) { eval; } + } +} +$code.=<<___; + mov $_ctx,$ctx + mov $a1,$A + + add $SZ*0($ctx),$A + lea 16*$SZ($inp),$inp + add $SZ*1($ctx),$B + add $SZ*2($ctx),$C + add $SZ*3($ctx),$D + add $SZ*4($ctx),$E + add $SZ*5($ctx),$F + add $SZ*6($ctx),$G + add $SZ*7($ctx),$H + + cmp $_end,$inp + + mov $A,$SZ*0($ctx) + mov $B,$SZ*1($ctx) + mov $C,$SZ*2($ctx) + mov $D,$SZ*3($ctx) + mov $E,$SZ*4($ctx) + mov $F,$SZ*5($ctx) + mov $G,$SZ*6($ctx) + mov $H,$SZ*7($ctx) + jb .Lloop_xop + + mov $_rsp,%rsi + vzeroupper +___ +$code.=<<___ if ($win64); + movaps 16*$SZ+32(%rsp),%xmm6 + movaps 16*$SZ+48(%rsp),%xmm7 + movaps 16*$SZ+64(%rsp),%xmm8 + movaps 16*$SZ+80(%rsp),%xmm9 +___ +$code.=<<___ if ($win64 && $SZ>4); + movaps 16*$SZ+96(%rsp),%xmm10 + movaps 16*$SZ+112(%rsp),%xmm11 +___ +$code.=<<___; + mov (%rsi),%r15 + mov 8(%rsi),%r14 + mov 16(%rsi),%r13 + mov 24(%rsi),%r12 + mov 32(%rsi),%rbp + mov 40(%rsi),%rbx + lea 48(%rsi),%rsp +.Lepilogue_xop: + ret +.size ${func}_xop,.-${func}_xop +___ +} +###################################################################### +# AVX+shrd code path +# +local *ror = sub { &shrd(@_[0],@_) }; + +$code.=<<___; +.type ${func}_avx,\@function,3 +.align 64 +${func}_avx: +.Lavx_shortcut: + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + mov %rsp,%r11 # copy %rsp + shl \$4,%rdx # num*16 + sub \$`$framesz+$win64*16*($SZ==4?4:6)`,%rsp + lea ($inp,%rdx,$SZ),%rdx # inp+num*16*$SZ + and \$-64,%rsp # align stack frame + mov $ctx,$_ctx # save ctx, 1st arg + mov $inp,$_inp # save inp, 2nd arh + mov %rdx,$_end # save end pointer, "3rd" arg + mov %r11,$_rsp # save copy of %rsp +___ +$code.=<<___ if ($win64); + movaps %xmm6,16*$SZ+32(%rsp) + movaps %xmm7,16*$SZ+48(%rsp) + movaps %xmm8,16*$SZ+64(%rsp) + movaps %xmm9,16*$SZ+80(%rsp) +___ +$code.=<<___ if ($win64 && $SZ>4); + movaps %xmm10,16*$SZ+96(%rsp) + movaps %xmm11,16*$SZ+112(%rsp) +___ +$code.=<<___; +.Lprologue_avx: + + vzeroupper + mov $SZ*0($ctx),$A + mov $SZ*1($ctx),$B + mov $SZ*2($ctx),$C + mov $SZ*3($ctx),$D + mov $SZ*4($ctx),$E + mov $SZ*5($ctx),$F + mov $SZ*6($ctx),$G + mov $SZ*7($ctx),$H +___ + if ($SZ==4) { # SHA256 + my @X = map("%xmm$_",(0..3)); + my ($t0,$t1,$t2,$t3, $t4,$t5) = map("%xmm$_",(4..9)); + +$code.=<<___; + vmovdqa $TABLE+`$SZ*2*$rounds`+32(%rip),$t4 + vmovdqa $TABLE+`$SZ*2*$rounds`+64(%rip),$t5 + jmp .Lloop_avx +.align 16 +.Lloop_avx: + vmovdqa $TABLE+`$SZ*2*$rounds`(%rip),$t3 + vmovdqu 0x00($inp),@X[0] + vmovdqu 0x10($inp),@X[1] + vmovdqu 0x20($inp),@X[2] + vmovdqu 0x30($inp),@X[3] + vpshufb $t3,@X[0],@X[0] + lea $TABLE(%rip),$Tbl + vpshufb $t3,@X[1],@X[1] + vpshufb $t3,@X[2],@X[2] + vpaddd 0x00($Tbl),@X[0],$t0 + vpshufb $t3,@X[3],@X[3] + vpaddd 0x20($Tbl),@X[1],$t1 + vpaddd 0x40($Tbl),@X[2],$t2 + vpaddd 0x60($Tbl),@X[3],$t3 + vmovdqa $t0,0x00(%rsp) + mov $A,$a1 + vmovdqa $t1,0x10(%rsp) + mov $B,$a3 + vmovdqa $t2,0x20(%rsp) + xor $C,$a3 # magic + vmovdqa $t3,0x30(%rsp) + mov $E,$a0 + jmp .Lavx_00_47 + +.align 16 +.Lavx_00_47: + sub \$`-16*2*$SZ`,$Tbl # size optimization +___ +sub Xupdate_256_AVX () { + ( + '&vpalignr ($t0,@X[1],@X[0],$SZ)', # X[1..4] + '&vpalignr ($t3,@X[3],@X[2],$SZ)', # X[9..12] + '&vpsrld ($t2,$t0,$sigma0[0]);', + '&vpaddd (@X[0],@X[0],$t3)', # X[0..3] += X[9..12] + '&vpsrld ($t3,$t0,$sigma0[2])', + '&vpslld ($t1,$t0,8*$SZ-$sigma0[1]);', + '&vpxor ($t0,$t3,$t2)', + '&vpshufd ($t3,@X[3],0b11111010)',# X[14..15] + '&vpsrld ($t2,$t2,$sigma0[1]-$sigma0[0]);', + '&vpxor ($t0,$t0,$t1)', + '&vpslld ($t1,$t1,$sigma0[1]-$sigma0[0]);', + '&vpxor ($t0,$t0,$t2)', + '&vpsrld ($t2,$t3,$sigma1[2]);', + '&vpxor ($t0,$t0,$t1)', # sigma0(X[1..4]) + '&vpsrlq ($t3,$t3,$sigma1[0]);', + '&vpaddd (@X[0],@X[0],$t0)', # X[0..3] += sigma0(X[1..4]) + '&vpxor ($t2,$t2,$t3);', + '&vpsrlq ($t3,$t3,$sigma1[1]-$sigma1[0])', + '&vpxor ($t2,$t2,$t3)', + '&vpshufb ($t2,$t2,$t4)', # sigma1(X[14..15]) + '&vpaddd (@X[0],@X[0],$t2)', # X[0..1] += sigma1(X[14..15]) + '&vpshufd ($t3,@X[0],0b01010000)',# X[16..17] + '&vpsrld ($t2,$t3,$sigma1[2])', + '&vpsrlq ($t3,$t3,$sigma1[0])', + '&vpxor ($t2,$t2,$t3);', + '&vpsrlq ($t3,$t3,$sigma1[1]-$sigma1[0])', + '&vpxor ($t2,$t2,$t3)', + '&vpshufb ($t2,$t2,$t5)', + '&vpaddd (@X[0],@X[0],$t2)' # X[2..3] += sigma1(X[16..17]) + ); +} + +sub AVX_256_00_47 () { +my $j = shift; +my $body = shift; +my @X = @_; +my @insns = (&$body,&$body,&$body,&$body); # 104 instructions + + foreach (Xupdate_256_AVX()) { # 29 instructions + eval; + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + } + &vpaddd ($t2,@X[0],16*2*$j."($Tbl)"); + foreach (@insns) { eval; } # remaining instructions + &vmovdqa (16*$j."(%rsp)",$t2); +} + + for ($i=0,$j=0; $j<4; $j++) { + &AVX_256_00_47($j,\&body_00_15,@X); + push(@X,shift(@X)); # rotate(@X) + } + &cmpb ($SZ-1+16*2*$SZ."($Tbl)",0); + &jne (".Lavx_00_47"); + + for ($i=0; $i<16; ) { + foreach(body_00_15()) { eval; } + } + + } else { # SHA512 + my @X = map("%xmm$_",(0..7)); + my ($t0,$t1,$t2,$t3) = map("%xmm$_",(8..11)); + +$code.=<<___; + jmp .Lloop_avx +.align 16 +.Lloop_avx: + vmovdqa $TABLE+`$SZ*2*$rounds`(%rip),$t3 + vmovdqu 0x00($inp),@X[0] + lea $TABLE+0x80(%rip),$Tbl # size optimization + vmovdqu 0x10($inp),@X[1] + vmovdqu 0x20($inp),@X[2] + vpshufb $t3,@X[0],@X[0] + vmovdqu 0x30($inp),@X[3] + vpshufb $t3,@X[1],@X[1] + vmovdqu 0x40($inp),@X[4] + vpshufb $t3,@X[2],@X[2] + vmovdqu 0x50($inp),@X[5] + vpshufb $t3,@X[3],@X[3] + vmovdqu 0x60($inp),@X[6] + vpshufb $t3,@X[4],@X[4] + vmovdqu 0x70($inp),@X[7] + vpshufb $t3,@X[5],@X[5] + vpaddq -0x80($Tbl),@X[0],$t0 + vpshufb $t3,@X[6],@X[6] + vpaddq -0x60($Tbl),@X[1],$t1 + vpshufb $t3,@X[7],@X[7] + vpaddq -0x40($Tbl),@X[2],$t2 + vpaddq -0x20($Tbl),@X[3],$t3 + vmovdqa $t0,0x00(%rsp) + vpaddq 0x00($Tbl),@X[4],$t0 + vmovdqa $t1,0x10(%rsp) + vpaddq 0x20($Tbl),@X[5],$t1 + vmovdqa $t2,0x20(%rsp) + vpaddq 0x40($Tbl),@X[6],$t2 + vmovdqa $t3,0x30(%rsp) + vpaddq 0x60($Tbl),@X[7],$t3 + vmovdqa $t0,0x40(%rsp) + mov $A,$a1 + vmovdqa $t1,0x50(%rsp) + mov $B,$a3 + vmovdqa $t2,0x60(%rsp) + xor $C,$a3 # magic + vmovdqa $t3,0x70(%rsp) + mov $E,$a0 + jmp .Lavx_00_47 + +.align 16 +.Lavx_00_47: + add \$`16*2*$SZ`,$Tbl +___ +sub Xupdate_512_AVX () { + ( + '&vpalignr ($t0,@X[1],@X[0],$SZ)', # X[1..2] + '&vpalignr ($t3,@X[5],@X[4],$SZ)', # X[9..10] + '&vpsrlq ($t2,$t0,$sigma0[0])', + '&vpaddq (@X[0],@X[0],$t3);', # X[0..1] += X[9..10] + '&vpsrlq ($t3,$t0,$sigma0[2])', + '&vpsllq ($t1,$t0,8*$SZ-$sigma0[1]);', + '&vpxor ($t0,$t3,$t2)', + '&vpsrlq ($t2,$t2,$sigma0[1]-$sigma0[0]);', + '&vpxor ($t0,$t0,$t1)', + '&vpsllq ($t1,$t1,$sigma0[1]-$sigma0[0]);', + '&vpxor ($t0,$t0,$t2)', + '&vpsrlq ($t3,@X[7],$sigma1[2]);', + '&vpxor ($t0,$t0,$t1)', # sigma0(X[1..2]) + '&vpsllq ($t2,@X[7],8*$SZ-$sigma1[1]);', + '&vpaddq (@X[0],@X[0],$t0)', # X[0..1] += sigma0(X[1..2]) + '&vpsrlq ($t1,@X[7],$sigma1[0]);', + '&vpxor ($t3,$t3,$t2)', + '&vpsllq ($t2,$t2,$sigma1[1]-$sigma1[0]);', + '&vpxor ($t3,$t3,$t1)', + '&vpsrlq ($t1,$t1,$sigma1[1]-$sigma1[0]);', + '&vpxor ($t3,$t3,$t2)', + '&vpxor ($t3,$t3,$t1)', # sigma1(X[14..15]) + '&vpaddq (@X[0],@X[0],$t3)', # X[0..1] += sigma1(X[14..15]) + ); +} + +sub AVX_512_00_47 () { +my $j = shift; +my $body = shift; +my @X = @_; +my @insns = (&$body,&$body); # 52 instructions + + foreach (Xupdate_512_AVX()) { # 23 instructions + eval; + eval(shift(@insns)); + eval(shift(@insns)); + } + &vpaddq ($t2,@X[0],16*2*$j-0x80."($Tbl)"); + foreach (@insns) { eval; } # remaining instructions + &vmovdqa (16*$j."(%rsp)",$t2); +} + + for ($i=0,$j=0; $j<8; $j++) { + &AVX_512_00_47($j,\&body_00_15,@X); + push(@X,shift(@X)); # rotate(@X) + } + &cmpb ($SZ-1+16*2*$SZ-0x80."($Tbl)",0); + &jne (".Lavx_00_47"); + + for ($i=0; $i<16; ) { + foreach(body_00_15()) { eval; } + } +} +$code.=<<___; + mov $_ctx,$ctx + mov $a1,$A + + add $SZ*0($ctx),$A + lea 16*$SZ($inp),$inp + add $SZ*1($ctx),$B + add $SZ*2($ctx),$C + add $SZ*3($ctx),$D + add $SZ*4($ctx),$E + add $SZ*5($ctx),$F + add $SZ*6($ctx),$G + add $SZ*7($ctx),$H + + cmp $_end,$inp + + mov $A,$SZ*0($ctx) + mov $B,$SZ*1($ctx) + mov $C,$SZ*2($ctx) + mov $D,$SZ*3($ctx) + mov $E,$SZ*4($ctx) + mov $F,$SZ*5($ctx) + mov $G,$SZ*6($ctx) + mov $H,$SZ*7($ctx) + jb .Lloop_avx + + mov $_rsp,%rsi + vzeroupper +___ +$code.=<<___ if ($win64); + movaps 16*$SZ+32(%rsp),%xmm6 + movaps 16*$SZ+48(%rsp),%xmm7 + movaps 16*$SZ+64(%rsp),%xmm8 + movaps 16*$SZ+80(%rsp),%xmm9 +___ +$code.=<<___ if ($win64 && $SZ>4); + movaps 16*$SZ+96(%rsp),%xmm10 + movaps 16*$SZ+112(%rsp),%xmm11 +___ +$code.=<<___; + mov (%rsi),%r15 + mov 8(%rsi),%r14 + mov 16(%rsi),%r13 + mov 24(%rsi),%r12 + mov 32(%rsi),%rbp + mov 40(%rsi),%rbx + lea 48(%rsi),%rsp +.Lepilogue_avx: + ret +.size ${func}_avx,.-${func}_avx +___ + +if ($avx>1) {{ +###################################################################### +# AVX2+BMI code path +# +my $a5=$SZ==4?"%esi":"%rsi"; # zap $inp +my $PUSH8=8*2*$SZ; +use integer; + +sub bodyx_00_15 () { + # at start $a1 should be zero, $a3 - $b^$c and $a4 copy of $f + ( + '($a,$b,$c,$d,$e,$f,$g,$h)=@ROT;'. + + '&add ($h,(32*($i/(16/$SZ))+$SZ*($i%(16/$SZ)))%$PUSH8.$base)', # h+=X[i]+K[i] + '&and ($a4,$e)', # f&e + '&rorx ($a0,$e,$Sigma1[2])', + '&rorx ($a2,$e,$Sigma1[1])', + + '&lea ($a,"($a,$a1)")', # h+=Sigma0(a) from the past + '&lea ($h,"($h,$a4)")', + '&andn ($a4,$e,$g)', # ~e&g + '&xor ($a0,$a2)', + + '&rorx ($a1,$e,$Sigma1[0])', + '&lea ($h,"($h,$a4)")', # h+=Ch(e,f,g)=(e&f)+(~e&g) + '&xor ($a0,$a1)', # Sigma1(e) + '&mov ($a2,$a)', + + '&rorx ($a4,$a,$Sigma0[2])', + '&lea ($h,"($h,$a0)")', # h+=Sigma1(e) + '&xor ($a2,$b)', # a^b, b^c in next round + '&rorx ($a1,$a,$Sigma0[1])', + + '&rorx ($a0,$a,$Sigma0[0])', + '&lea ($d,"($d,$h)")', # d+=h + '&and ($a3,$a2)', # (b^c)&(a^b) + '&xor ($a1,$a4)', + + '&xor ($a3,$b)', # Maj(a,b,c)=Ch(a^b,c,b) + '&xor ($a1,$a0)', # Sigma0(a) + '&lea ($h,"($h,$a3)");'. # h+=Maj(a,b,c) + '&mov ($a4,$e)', # copy of f in future + + '($a2,$a3) = ($a3,$a2); unshift(@ROT,pop(@ROT)); $i++;' + ); + # and at the finish one has to $a+=$a1 +} + +$code.=<<___; +.type ${func}_avx2,\@function,3 +.align 64 +${func}_avx2: +.Lavx2_shortcut: + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + mov %rsp,%r11 # copy %rsp + sub \$`2*$SZ*$rounds+4*8+$win64*16*($SZ==4?4:6)`,%rsp + shl \$4,%rdx # num*16 + and \$-256*$SZ,%rsp # align stack frame + lea ($inp,%rdx,$SZ),%rdx # inp+num*16*$SZ + add \$`2*$SZ*($rounds-8)`,%rsp + mov $ctx,$_ctx # save ctx, 1st arg + mov $inp,$_inp # save inp, 2nd arh + mov %rdx,$_end # save end pointer, "3rd" arg + mov %r11,$_rsp # save copy of %rsp +___ +$code.=<<___ if ($win64); + movaps %xmm6,16*$SZ+32(%rsp) + movaps %xmm7,16*$SZ+48(%rsp) + movaps %xmm8,16*$SZ+64(%rsp) + movaps %xmm9,16*$SZ+80(%rsp) +___ +$code.=<<___ if ($win64 && $SZ>4); + movaps %xmm10,16*$SZ+96(%rsp) + movaps %xmm11,16*$SZ+112(%rsp) +___ +$code.=<<___; +.Lprologue_avx2: + + vzeroupper + sub \$-16*$SZ,$inp # inp++, size optimization + mov $SZ*0($ctx),$A + mov $inp,%r12 # borrow $T1 + mov $SZ*1($ctx),$B + cmp %rdx,$inp # $_end + mov $SZ*2($ctx),$C + cmove %rsp,%r12 # next block or random data + mov $SZ*3($ctx),$D + mov $SZ*4($ctx),$E + mov $SZ*5($ctx),$F + mov $SZ*6($ctx),$G + mov $SZ*7($ctx),$H +___ + if ($SZ==4) { # SHA256 + my @X = map("%ymm$_",(0..3)); + my ($t0,$t1,$t2,$t3, $t4,$t5) = map("%ymm$_",(4..9)); + +$code.=<<___; + vmovdqa $TABLE+`$SZ*2*$rounds`+32(%rip),$t4 + vmovdqa $TABLE+`$SZ*2*$rounds`+64(%rip),$t5 + jmp .Loop_avx2 +.align 16 +.Loop_avx2: + vmovdqa $TABLE+`$SZ*2*$rounds`(%rip),$t3 + vmovdqu -16*$SZ+0($inp),%xmm0 + vmovdqu -16*$SZ+16($inp),%xmm1 + vmovdqu -16*$SZ+32($inp),%xmm2 + vmovdqu -16*$SZ+48($inp),%xmm3 + #mov $inp,$_inp # offload $inp + vinserti128 \$1,(%r12),@X[0],@X[0] + vinserti128 \$1,16(%r12),@X[1],@X[1] + vpshufb $t3,@X[0],@X[0] + vinserti128 \$1,32(%r12),@X[2],@X[2] + vpshufb $t3,@X[1],@X[1] + vinserti128 \$1,48(%r12),@X[3],@X[3] + + lea $TABLE(%rip),$Tbl + vpshufb $t3,@X[2],@X[2] + vpaddd 0x00($Tbl),@X[0],$t0 + vpshufb $t3,@X[3],@X[3] + vpaddd 0x20($Tbl),@X[1],$t1 + vpaddd 0x40($Tbl),@X[2],$t2 + vpaddd 0x60($Tbl),@X[3],$t3 + vmovdqa $t0,0x00(%rsp) + xor $a1,$a1 + vmovdqa $t1,0x20(%rsp) + lea -$PUSH8(%rsp),%rsp + mov $B,$a3 + vmovdqa $t2,0x00(%rsp) + xor $C,$a3 # magic + vmovdqa $t3,0x20(%rsp) + mov $F,$a4 + sub \$-16*2*$SZ,$Tbl # size optimization + jmp .Lavx2_00_47 + +.align 16 +.Lavx2_00_47: +___ + +sub AVX2_256_00_47 () { +my $j = shift; +my $body = shift; +my @X = @_; +my @insns = (&$body,&$body,&$body,&$body); # 96 instructions +my $base = "+2*$PUSH8(%rsp)"; + + &lea ("%rsp","-$PUSH8(%rsp)") if (($j%2)==0); + foreach (Xupdate_256_AVX()) { # 29 instructions + eval; + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + } + &vpaddd ($t2,@X[0],16*2*$j."($Tbl)"); + foreach (@insns) { eval; } # remaining instructions + &vmovdqa ((32*$j)%$PUSH8."(%rsp)",$t2); +} + + for ($i=0,$j=0; $j<4; $j++) { + &AVX2_256_00_47($j,\&bodyx_00_15,@X); + push(@X,shift(@X)); # rotate(@X) + } + &lea ($Tbl,16*2*$SZ."($Tbl)"); + &cmpb (($SZ-1)."($Tbl)",0); + &jne (".Lavx2_00_47"); + + for ($i=0; $i<16; ) { + my $base=$i<8?"+$PUSH8(%rsp)":"(%rsp)"; + foreach(bodyx_00_15()) { eval; } + } + } else { # SHA512 + my @X = map("%ymm$_",(0..7)); + my ($t0,$t1,$t2,$t3) = map("%ymm$_",(8..11)); + +$code.=<<___; + jmp .Loop_avx2 +.align 16 +.Loop_avx2: + vmovdqu -16*$SZ($inp),%xmm0 + vmovdqu -16*$SZ+16($inp),%xmm1 + vmovdqu -16*$SZ+32($inp),%xmm2 + lea $TABLE+0x80(%rip),$Tbl # size optimization + vmovdqu -16*$SZ+48($inp),%xmm3 + vmovdqu -16*$SZ+64($inp),%xmm4 + vmovdqu -16*$SZ+80($inp),%xmm5 + vmovdqu -16*$SZ+96($inp),%xmm6 + vmovdqu -16*$SZ+112($inp),%xmm7 + #mov $inp,$_inp # offload $inp + vmovdqa `$SZ*2*$rounds-0x80`($Tbl),$t2 + vinserti128 \$1,(%r12),@X[0],@X[0] + vinserti128 \$1,16(%r12),@X[1],@X[1] + vpshufb $t2,@X[0],@X[0] + vinserti128 \$1,32(%r12),@X[2],@X[2] + vpshufb $t2,@X[1],@X[1] + vinserti128 \$1,48(%r12),@X[3],@X[3] + vpshufb $t2,@X[2],@X[2] + vinserti128 \$1,64(%r12),@X[4],@X[4] + vpshufb $t2,@X[3],@X[3] + vinserti128 \$1,80(%r12),@X[5],@X[5] + vpshufb $t2,@X[4],@X[4] + vinserti128 \$1,96(%r12),@X[6],@X[6] + vpshufb $t2,@X[5],@X[5] + vinserti128 \$1,112(%r12),@X[7],@X[7] + + vpaddq -0x80($Tbl),@X[0],$t0 + vpshufb $t2,@X[6],@X[6] + vpaddq -0x60($Tbl),@X[1],$t1 + vpshufb $t2,@X[7],@X[7] + vpaddq -0x40($Tbl),@X[2],$t2 + vpaddq -0x20($Tbl),@X[3],$t3 + vmovdqa $t0,0x00(%rsp) + vpaddq 0x00($Tbl),@X[4],$t0 + vmovdqa $t1,0x20(%rsp) + vpaddq 0x20($Tbl),@X[5],$t1 + vmovdqa $t2,0x40(%rsp) + vpaddq 0x40($Tbl),@X[6],$t2 + vmovdqa $t3,0x60(%rsp) + lea -$PUSH8(%rsp),%rsp + vpaddq 0x60($Tbl),@X[7],$t3 + vmovdqa $t0,0x00(%rsp) + xor $a1,$a1 + vmovdqa $t1,0x20(%rsp) + mov $B,$a3 + vmovdqa $t2,0x40(%rsp) + xor $C,$a3 # magic + vmovdqa $t3,0x60(%rsp) + mov $F,$a4 + add \$16*2*$SZ,$Tbl + jmp .Lavx2_00_47 + +.align 16 +.Lavx2_00_47: +___ + +sub AVX2_512_00_47 () { +my $j = shift; +my $body = shift; +my @X = @_; +my @insns = (&$body,&$body); # 48 instructions +my $base = "+2*$PUSH8(%rsp)"; + + &lea ("%rsp","-$PUSH8(%rsp)") if (($j%4)==0); + foreach (Xupdate_512_AVX()) { # 23 instructions + eval; + if ($_ !~ /\;$/) { + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + } + } + &vpaddq ($t2,@X[0],16*2*$j-0x80."($Tbl)"); + foreach (@insns) { eval; } # remaining instructions + &vmovdqa ((32*$j)%$PUSH8."(%rsp)",$t2); +} + + for ($i=0,$j=0; $j<8; $j++) { + &AVX2_512_00_47($j,\&bodyx_00_15,@X); + push(@X,shift(@X)); # rotate(@X) + } + &lea ($Tbl,16*2*$SZ."($Tbl)"); + &cmpb (($SZ-1-0x80)."($Tbl)",0); + &jne (".Lavx2_00_47"); + + for ($i=0; $i<16; ) { + my $base=$i<8?"+$PUSH8(%rsp)":"(%rsp)"; + foreach(bodyx_00_15()) { eval; } + } +} +$code.=<<___; + mov `2*$SZ*$rounds`(%rsp),$ctx # $_ctx + add $a1,$A + #mov `2*$SZ*$rounds+8`(%rsp),$inp # $_inp + lea `2*$SZ*($rounds-8)`(%rsp),$Tbl + + add $SZ*0($ctx),$A + add $SZ*1($ctx),$B + add $SZ*2($ctx),$C + add $SZ*3($ctx),$D + add $SZ*4($ctx),$E + add $SZ*5($ctx),$F + add $SZ*6($ctx),$G + add $SZ*7($ctx),$H + + mov $A,$SZ*0($ctx) + mov $B,$SZ*1($ctx) + mov $C,$SZ*2($ctx) + mov $D,$SZ*3($ctx) + mov $E,$SZ*4($ctx) + mov $F,$SZ*5($ctx) + mov $G,$SZ*6($ctx) + mov $H,$SZ*7($ctx) + + cmp `$PUSH8+2*8`($Tbl),$inp # $_end + je .Ldone_avx2 + + xor $a1,$a1 + mov $B,$a3 + xor $C,$a3 # magic + mov $F,$a4 + jmp .Lower_avx2 +.align 16 +.Lower_avx2: +___ + for ($i=0; $i<8; ) { + my $base="+16($Tbl)"; + foreach(bodyx_00_15()) { eval; } + } +$code.=<<___; + lea -$PUSH8($Tbl),$Tbl + cmp %rsp,$Tbl + jae .Lower_avx2 + + mov `2*$SZ*$rounds`(%rsp),$ctx # $_ctx + add $a1,$A + #mov `2*$SZ*$rounds+8`(%rsp),$inp # $_inp + lea `2*$SZ*($rounds-8)`(%rsp),%rsp + + add $SZ*0($ctx),$A + add $SZ*1($ctx),$B + add $SZ*2($ctx),$C + add $SZ*3($ctx),$D + add $SZ*4($ctx),$E + add $SZ*5($ctx),$F + lea `2*16*$SZ`($inp),$inp # inp+=2 + add $SZ*6($ctx),$G + mov $inp,%r12 + add $SZ*7($ctx),$H + cmp $_end,$inp + + mov $A,$SZ*0($ctx) + cmove %rsp,%r12 # next block or stale data + mov $B,$SZ*1($ctx) + mov $C,$SZ*2($ctx) + mov $D,$SZ*3($ctx) + mov $E,$SZ*4($ctx) + mov $F,$SZ*5($ctx) + mov $G,$SZ*6($ctx) + mov $H,$SZ*7($ctx) + + jbe .Loop_avx2 + lea (%rsp),$Tbl + +.Ldone_avx2: + lea ($Tbl),%rsp + mov $_rsp,%rsi + vzeroupper +___ +$code.=<<___ if ($win64); + movaps 16*$SZ+32(%rsp),%xmm6 + movaps 16*$SZ+48(%rsp),%xmm7 + movaps 16*$SZ+64(%rsp),%xmm8 + movaps 16*$SZ+80(%rsp),%xmm9 +___ +$code.=<<___ if ($win64 && $SZ>4); + movaps 16*$SZ+96(%rsp),%xmm10 + movaps 16*$SZ+112(%rsp),%xmm11 +___ +$code.=<<___; + mov (%rsi),%r15 + mov 8(%rsi),%r14 + mov 16(%rsi),%r13 + mov 24(%rsi),%r12 + mov 32(%rsi),%rbp + mov 40(%rsi),%rbx + lea 48(%rsi),%rsp +.Lepilogue_avx2: + ret +.size ${func}_avx2,.-${func}_avx2 +___ +}} +}}}}} + +# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame, +# CONTEXT *context,DISPATCHER_CONTEXT *disp) +if ($win64) { +$rec="%rcx"; +$frame="%rdx"; +$context="%r8"; +$disp="%r9"; + +$code.=<<___; +.extern __imp_RtlVirtualUnwind +.type se_handler,\@abi-omnipotent +.align 16 +se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + mov 8($disp),%rsi # disp->ImageBase + mov 56($disp),%r11 # disp->HanderlData + + mov 0(%r11),%r10d # HandlerData[0] + lea (%rsi,%r10),%r10 # prologue label + cmp %r10,%rbx # context->RipRsp + + mov 4(%r11),%r10d # HandlerData[1] + lea (%rsi,%r10),%r10 # epilogue label + cmp %r10,%rbx # context->Rip>=epilogue label + jae .Lin_prologue +___ +$code.=<<___ if ($avx>1); + lea .Lavx2_shortcut(%rip),%r10 + cmp %r10,%rbx # context->RipRbx + mov %rbp,160($context) # restore context->Rbp + mov %r12,216($context) # restore context->R12 + mov %r13,224($context) # restore context->R13 + mov %r14,232($context) # restore context->R14 + mov %r15,240($context) # restore context->R15 + + lea .Lepilogue(%rip),%r10 + cmp %r10,%rbx + jb .Lin_prologue # non-AVX code + + lea 16*$SZ+4*8(%rsi),%rsi # Xmm6- save area + lea 512($context),%rdi # &context.Xmm6 + mov \$`$SZ==4?8:12`,%ecx + .long 0xa548f3fc # cld; rep movsq + +.Lin_prologue: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + + mov 40($disp),%rdi # disp->ContextRecord + mov $context,%rsi # context + mov \$154,%ecx # sizeof(CONTEXT) + .long 0xa548f3fc # cld; rep movsq + + mov $disp,%rsi + xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER + mov 8(%rsi),%rdx # arg2, disp->ImageBase + mov 0(%rsi),%r8 # arg3, disp->ControlPc + mov 16(%rsi),%r9 # arg4, disp->FunctionEntry + mov 40(%rsi),%r10 # disp->ContextRecord + lea 56(%rsi),%r11 # &disp->HandlerData + lea 24(%rsi),%r12 # &disp->EstablisherFrame + mov %r10,32(%rsp) # arg5 + mov %r11,40(%rsp) # arg6 + mov %r12,48(%rsp) # arg7 + mov %rcx,56(%rsp) # arg8, (NULL) + call *__imp_RtlVirtualUnwind(%rip) + + mov \$1,%eax # ExceptionContinueSearch + add \$64,%rsp + popfq + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + pop %rdi + pop %rsi + ret +.size se_handler,.-se_handler +___ +$code.=<<___ if ($SZ == 4 && $shaext); +.type shaext_handler,\@abi-omnipotent +.align 16 +shaext_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + lea .Lprologue_shaext(%rip),%r10 + cmp %r10,%rbx # context->Rip<.Lprologue + jb .Lin_prologue + + lea .Lepilogue_shaext(%rip),%r10 + cmp %r10,%rbx # context->Rip>=.Lepilogue + jae .Lin_prologue + + lea -8-5*16(%rax),%rsi + lea 512($context),%rdi # &context.Xmm6 + mov \$10,%ecx + .long 0xa548f3fc # cld; rep movsq + + jmp .Lin_prologue +.size shaext_handler,.-shaext_handler +___ +$code.=<<___; +.section .pdata +.align 4 + .rva .LSEH_begin_$func + .rva .LSEH_end_$func + .rva .LSEH_info_$func +___ +$code.=<<___ if ($SZ==4 && $shext); + .rva .LSEH_begin_${func}_shaext + .rva .LSEH_end_${func}_shaext + .rva .LSEH_info_${func}_shaext +___ +$code.=<<___ if ($SZ==4); + .rva .LSEH_begin_${func}_ssse3 + .rva .LSEH_end_${func}_ssse3 + .rva .LSEH_info_${func}_ssse3 +___ +$code.=<<___ if ($avx && $SZ==8); + .rva .LSEH_begin_${func}_xop + .rva .LSEH_end_${func}_xop + .rva .LSEH_info_${func}_xop +___ +$code.=<<___ if ($avx); + .rva .LSEH_begin_${func}_avx + .rva .LSEH_end_${func}_avx + .rva .LSEH_info_${func}_avx +___ +$code.=<<___ if ($avx>1); + .rva .LSEH_begin_${func}_avx2 + .rva .LSEH_end_${func}_avx2 + .rva .LSEH_info_${func}_avx2 +___ +$code.=<<___; +.section .xdata +.align 8 +.LSEH_info_$func: + .byte 9,0,0,0 + .rva se_handler + .rva .Lprologue,.Lepilogue # HandlerData[] +___ +$code.=<<___ if ($SZ==4 && $shaext); +.LSEH_info_${func}_shaext: + .byte 9,0,0,0 + .rva shaext_handler +___ +$code.=<<___ if ($SZ==4); +.LSEH_info_${func}_ssse3: + .byte 9,0,0,0 + .rva se_handler + .rva .Lprologue_ssse3,.Lepilogue_ssse3 # HandlerData[] +___ +$code.=<<___ if ($avx && $SZ==8); +.LSEH_info_${func}_xop: + .byte 9,0,0,0 + .rva se_handler + .rva .Lprologue_xop,.Lepilogue_xop # HandlerData[] +___ +$code.=<<___ if ($avx); +.LSEH_info_${func}_avx: + .byte 9,0,0,0 + .rva se_handler + .rva .Lprologue_avx,.Lepilogue_avx # HandlerData[] +___ +$code.=<<___ if ($avx>1); +.LSEH_info_${func}_avx2: + .byte 9,0,0,0 + .rva se_handler + .rva .Lprologue_avx2,.Lepilogue_avx2 # HandlerData[] +___ +} + +sub sha256op38 { + my $instr = shift; + my %opcodelet = ( + "sha256rnds2" => 0xcb, + "sha256msg1" => 0xcc, + "sha256msg2" => 0xcd ); + + if (defined($opcodelet{$instr}) && @_[0] =~ /%xmm([0-7]),\s*%xmm([0-7])/) { + my @opcode=(0x0f,0x38); + push @opcode,$opcodelet{$instr}; + push @opcode,0xc0|($1&7)|(($2&7)<<3); # ModR/M + return ".byte\t".join(',',@opcode); + } else { + return $instr."\t".@_[0]; + } +} + +foreach (split("\n",$code)) { + s/\`([^\`]*)\`/eval $1/geo; + + s/\b(sha256[^\s]*)\s+(.*)/sha256op38($1,$2)/geo; + + print $_,"\n"; +} +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/sha/sha1.c b/TMessagesProj/jni/boringssl/crypto/sha/sha1.c new file mode 100644 index 00000000..c03e6081 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/sha/sha1.c @@ -0,0 +1,381 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include + + +#if !defined(OPENSSL_NO_ASM) && \ + (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \ + defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) +#define SHA1_ASM +#endif + +int SHA1_Init(SHA_CTX *sha) { + memset(sha, 0, sizeof(SHA_CTX)); + sha->h0 = 0x67452301UL; + sha->h1 = 0xefcdab89UL; + sha->h2 = 0x98badcfeUL; + sha->h3 = 0x10325476UL; + sha->h4 = 0xc3d2e1f0UL; + return 1; +} + +uint8_t *SHA1(const uint8_t *data, size_t len, uint8_t *out) { + SHA_CTX ctx; + static uint8_t buf[SHA_DIGEST_LENGTH]; + + /* TODO(fork): remove this static buffer. */ + if (out == NULL) { + out = buf; + } + if (!SHA1_Init(&ctx)) { + return NULL; + } + SHA1_Update(&ctx, data, len); + SHA1_Final(out, &ctx); + OPENSSL_cleanse(&ctx, sizeof(ctx)); + return out; +} + +#define DATA_ORDER_IS_BIG_ENDIAN + +#define HASH_LONG uint32_t +#define HASH_CTX SHA_CTX +#define HASH_CBLOCK 64 +#define HASH_MAKE_STRING(c, s) \ + do { \ + uint32_t ll; \ + ll = (c)->h0; \ + (void) HOST_l2c(ll, (s)); \ + ll = (c)->h1; \ + (void) HOST_l2c(ll, (s)); \ + ll = (c)->h2; \ + (void) HOST_l2c(ll, (s)); \ + ll = (c)->h3; \ + (void) HOST_l2c(ll, (s)); \ + ll = (c)->h4; \ + (void) HOST_l2c(ll, (s)); \ + } while (0) + +#define HASH_UPDATE SHA1_Update +#define HASH_TRANSFORM SHA1_Transform +#define HASH_FINAL SHA1_Final +#define HASH_BLOCK_DATA_ORDER sha1_block_data_order +#define Xupdate(a, ix, ia, ib, ic, id) \ + ((a) = (ia ^ ib ^ ic ^ id), ix = (a) = ROTATE((a), 1)) + +#ifndef SHA1_ASM +static +#endif +void sha1_block_data_order(SHA_CTX *c, const void *p, size_t num); + +#include "../digest/md32_common.h" + +#define K_00_19 0x5a827999UL +#define K_20_39 0x6ed9eba1UL +#define K_40_59 0x8f1bbcdcUL +#define K_60_79 0xca62c1d6UL + +/* As pointed out by Wei Dai , F() below can be simplified + * to the code in F_00_19. Wei attributes these optimisations to Peter + * Gutmann's SHS code, and he attributes it to Rich Schroeppel. #define + * F(x,y,z) (((x) & (y)) | ((~(x)) & (z))) I've just become aware of another + * tweak to be made, again from Wei Dai, in F_40_59, (x&a)|(y&a) -> (x|y)&a */ +#define F_00_19(b, c, d) ((((c) ^ (d)) & (b)) ^ (d)) +#define F_20_39(b, c, d) ((b) ^ (c) ^ (d)) +#define F_40_59(b, c, d) (((b) & (c)) | (((b) | (c)) & (d))) +#define F_60_79(b, c, d) F_20_39(b, c, d) + +#define BODY_00_15(i, a, b, c, d, e, f, xi) \ + (f) = xi + (e) + K_00_19 + ROTATE((a), 5) + F_00_19((b), (c), (d)); \ + (b) = ROTATE((b), 30); + +#define BODY_16_19(i, a, b, c, d, e, f, xi, xa, xb, xc, xd) \ + Xupdate(f, xi, xa, xb, xc, xd); \ + (f) += (e) + K_00_19 + ROTATE((a), 5) + F_00_19((b), (c), (d)); \ + (b) = ROTATE((b), 30); + +#define BODY_20_31(i, a, b, c, d, e, f, xi, xa, xb, xc, xd) \ + Xupdate(f, xi, xa, xb, xc, xd); \ + (f) += (e) + K_20_39 + ROTATE((a), 5) + F_20_39((b), (c), (d)); \ + (b) = ROTATE((b), 30); + +#define BODY_32_39(i, a, b, c, d, e, f, xa, xb, xc, xd) \ + Xupdate(f, xa, xa, xb, xc, xd); \ + (f) += (e) + K_20_39 + ROTATE((a), 5) + F_20_39((b), (c), (d)); \ + (b) = ROTATE((b), 30); + +#define BODY_40_59(i, a, b, c, d, e, f, xa, xb, xc, xd) \ + Xupdate(f, xa, xa, xb, xc, xd); \ + (f) += (e) + K_40_59 + ROTATE((a), 5) + F_40_59((b), (c), (d)); \ + (b) = ROTATE((b), 30); + +#define BODY_60_79(i, a, b, c, d, e, f, xa, xb, xc, xd) \ + Xupdate(f, xa, xa, xb, xc, xd); \ + (f) = xa + (e) + K_60_79 + ROTATE((a), 5) + F_60_79((b), (c), (d)); \ + (b) = ROTATE((b), 30); + +#ifdef X +#undef X +#endif + +/* Originally X was an array. As it's automatic it's natural +* to expect RISC compiler to accomodate at least part of it in +* the register bank, isn't it? Unfortunately not all compilers +* "find" this expectation reasonable:-( On order to make such +* compilers generate better code I replace X[] with a bunch of +* X0, X1, etc. See the function body below... +* */ +#define X(i) XX##i + +#if !defined(SHA1_ASM) +static void HASH_BLOCK_DATA_ORDER(SHA_CTX *c, const void *p, size_t num) { + const uint8_t *data = p; + register uint32_t A, B, C, D, E, T, l; + uint32_t XX0, XX1, XX2, XX3, XX4, XX5, XX6, XX7, XX8, XX9, XX10, + XX11, XX12, XX13, XX14, XX15; + + A = c->h0; + B = c->h1; + C = c->h2; + D = c->h3; + E = c->h4; + + for (;;) { + const union { + long one; + char little; + } is_endian = {1}; + + if (!is_endian.little && ((size_t)p % 4) == 0) { + const uint32_t *W = (const uint32_t *)data; + + X(0) = W[0]; + X(1) = W[1]; + BODY_00_15(0, A, B, C, D, E, T, X(0)); + X(2) = W[2]; + BODY_00_15(1, T, A, B, C, D, E, X(1)); + X(3) = W[3]; + BODY_00_15(2, E, T, A, B, C, D, X(2)); + X(4) = W[4]; + BODY_00_15(3, D, E, T, A, B, C, X(3)); + X(5) = W[5]; + BODY_00_15(4, C, D, E, T, A, B, X(4)); + X(6) = W[6]; + BODY_00_15(5, B, C, D, E, T, A, X(5)); + X(7) = W[7]; + BODY_00_15(6, A, B, C, D, E, T, X(6)); + X(8) = W[8]; + BODY_00_15(7, T, A, B, C, D, E, X(7)); + X(9) = W[9]; + BODY_00_15(8, E, T, A, B, C, D, X(8)); + X(10) = W[10]; + BODY_00_15(9, D, E, T, A, B, C, X(9)); + X(11) = W[11]; + BODY_00_15(10, C, D, E, T, A, B, X(10)); + X(12) = W[12]; + BODY_00_15(11, B, C, D, E, T, A, X(11)); + X(13) = W[13]; + BODY_00_15(12, A, B, C, D, E, T, X(12)); + X(14) = W[14]; + BODY_00_15(13, T, A, B, C, D, E, X(13)); + X(15) = W[15]; + BODY_00_15(14, E, T, A, B, C, D, X(14)); + BODY_00_15(15, D, E, T, A, B, C, X(15)); + + data += HASH_CBLOCK; + } else { + (void)HOST_c2l(data, l); + X(0) = l; + (void)HOST_c2l(data, l); + X(1) = l; + BODY_00_15(0, A, B, C, D, E, T, X(0)); + (void)HOST_c2l(data, l); + X(2) = l; + BODY_00_15(1, T, A, B, C, D, E, X(1)); + (void)HOST_c2l(data, l); + X(3) = l; + BODY_00_15(2, E, T, A, B, C, D, X(2)); + (void)HOST_c2l(data, l); + X(4) = l; + BODY_00_15(3, D, E, T, A, B, C, X(3)); + (void)HOST_c2l(data, l); + X(5) = l; + BODY_00_15(4, C, D, E, T, A, B, X(4)); + (void)HOST_c2l(data, l); + X(6) = l; + BODY_00_15(5, B, C, D, E, T, A, X(5)); + (void)HOST_c2l(data, l); + X(7) = l; + BODY_00_15(6, A, B, C, D, E, T, X(6)); + (void)HOST_c2l(data, l); + X(8) = l; + BODY_00_15(7, T, A, B, C, D, E, X(7)); + (void)HOST_c2l(data, l); + X(9) = l; + BODY_00_15(8, E, T, A, B, C, D, X(8)); + (void)HOST_c2l(data, l); + X(10) = l; + BODY_00_15(9, D, E, T, A, B, C, X(9)); + (void)HOST_c2l(data, l); + X(11) = l; + BODY_00_15(10, C, D, E, T, A, B, X(10)); + (void)HOST_c2l(data, l); + X(12) = l; + BODY_00_15(11, B, C, D, E, T, A, X(11)); + (void)HOST_c2l(data, l); + X(13) = l; + BODY_00_15(12, A, B, C, D, E, T, X(12)); + (void)HOST_c2l(data, l); + X(14) = l; + BODY_00_15(13, T, A, B, C, D, E, X(13)); + (void)HOST_c2l(data, l); + X(15) = l; + BODY_00_15(14, E, T, A, B, C, D, X(14)); + BODY_00_15(15, D, E, T, A, B, C, X(15)); + } + + BODY_16_19(16, C, D, E, T, A, B, X(0), X(0), X(2), X(8), X(13)); + BODY_16_19(17, B, C, D, E, T, A, X(1), X(1), X(3), X(9), X(14)); + BODY_16_19(18, A, B, C, D, E, T, X(2), X(2), X(4), X(10), X(15)); + BODY_16_19(19, T, A, B, C, D, E, X(3), X(3), X(5), X(11), X(0)); + + BODY_20_31(20, E, T, A, B, C, D, X(4), X(4), X(6), X(12), X(1)); + BODY_20_31(21, D, E, T, A, B, C, X(5), X(5), X(7), X(13), X(2)); + BODY_20_31(22, C, D, E, T, A, B, X(6), X(6), X(8), X(14), X(3)); + BODY_20_31(23, B, C, D, E, T, A, X(7), X(7), X(9), X(15), X(4)); + BODY_20_31(24, A, B, C, D, E, T, X(8), X(8), X(10), X(0), X(5)); + BODY_20_31(25, T, A, B, C, D, E, X(9), X(9), X(11), X(1), X(6)); + BODY_20_31(26, E, T, A, B, C, D, X(10), X(10), X(12), X(2), X(7)); + BODY_20_31(27, D, E, T, A, B, C, X(11), X(11), X(13), X(3), X(8)); + BODY_20_31(28, C, D, E, T, A, B, X(12), X(12), X(14), X(4), X(9)); + BODY_20_31(29, B, C, D, E, T, A, X(13), X(13), X(15), X(5), X(10)); + BODY_20_31(30, A, B, C, D, E, T, X(14), X(14), X(0), X(6), X(11)); + BODY_20_31(31, T, A, B, C, D, E, X(15), X(15), X(1), X(7), X(12)); + + BODY_32_39(32, E, T, A, B, C, D, X(0), X(2), X(8), X(13)); + BODY_32_39(33, D, E, T, A, B, C, X(1), X(3), X(9), X(14)); + BODY_32_39(34, C, D, E, T, A, B, X(2), X(4), X(10), X(15)); + BODY_32_39(35, B, C, D, E, T, A, X(3), X(5), X(11), X(0)); + BODY_32_39(36, A, B, C, D, E, T, X(4), X(6), X(12), X(1)); + BODY_32_39(37, T, A, B, C, D, E, X(5), X(7), X(13), X(2)); + BODY_32_39(38, E, T, A, B, C, D, X(6), X(8), X(14), X(3)); + BODY_32_39(39, D, E, T, A, B, C, X(7), X(9), X(15), X(4)); + + BODY_40_59(40, C, D, E, T, A, B, X(8), X(10), X(0), X(5)); + BODY_40_59(41, B, C, D, E, T, A, X(9), X(11), X(1), X(6)); + BODY_40_59(42, A, B, C, D, E, T, X(10), X(12), X(2), X(7)); + BODY_40_59(43, T, A, B, C, D, E, X(11), X(13), X(3), X(8)); + BODY_40_59(44, E, T, A, B, C, D, X(12), X(14), X(4), X(9)); + BODY_40_59(45, D, E, T, A, B, C, X(13), X(15), X(5), X(10)); + BODY_40_59(46, C, D, E, T, A, B, X(14), X(0), X(6), X(11)); + BODY_40_59(47, B, C, D, E, T, A, X(15), X(1), X(7), X(12)); + BODY_40_59(48, A, B, C, D, E, T, X(0), X(2), X(8), X(13)); + BODY_40_59(49, T, A, B, C, D, E, X(1), X(3), X(9), X(14)); + BODY_40_59(50, E, T, A, B, C, D, X(2), X(4), X(10), X(15)); + BODY_40_59(51, D, E, T, A, B, C, X(3), X(5), X(11), X(0)); + BODY_40_59(52, C, D, E, T, A, B, X(4), X(6), X(12), X(1)); + BODY_40_59(53, B, C, D, E, T, A, X(5), X(7), X(13), X(2)); + BODY_40_59(54, A, B, C, D, E, T, X(6), X(8), X(14), X(3)); + BODY_40_59(55, T, A, B, C, D, E, X(7), X(9), X(15), X(4)); + BODY_40_59(56, E, T, A, B, C, D, X(8), X(10), X(0), X(5)); + BODY_40_59(57, D, E, T, A, B, C, X(9), X(11), X(1), X(6)); + BODY_40_59(58, C, D, E, T, A, B, X(10), X(12), X(2), X(7)); + BODY_40_59(59, B, C, D, E, T, A, X(11), X(13), X(3), X(8)); + + BODY_60_79(60, A, B, C, D, E, T, X(12), X(14), X(4), X(9)); + BODY_60_79(61, T, A, B, C, D, E, X(13), X(15), X(5), X(10)); + BODY_60_79(62, E, T, A, B, C, D, X(14), X(0), X(6), X(11)); + BODY_60_79(63, D, E, T, A, B, C, X(15), X(1), X(7), X(12)); + BODY_60_79(64, C, D, E, T, A, B, X(0), X(2), X(8), X(13)); + BODY_60_79(65, B, C, D, E, T, A, X(1), X(3), X(9), X(14)); + BODY_60_79(66, A, B, C, D, E, T, X(2), X(4), X(10), X(15)); + BODY_60_79(67, T, A, B, C, D, E, X(3), X(5), X(11), X(0)); + BODY_60_79(68, E, T, A, B, C, D, X(4), X(6), X(12), X(1)); + BODY_60_79(69, D, E, T, A, B, C, X(5), X(7), X(13), X(2)); + BODY_60_79(70, C, D, E, T, A, B, X(6), X(8), X(14), X(3)); + BODY_60_79(71, B, C, D, E, T, A, X(7), X(9), X(15), X(4)); + BODY_60_79(72, A, B, C, D, E, T, X(8), X(10), X(0), X(5)); + BODY_60_79(73, T, A, B, C, D, E, X(9), X(11), X(1), X(6)); + BODY_60_79(74, E, T, A, B, C, D, X(10), X(12), X(2), X(7)); + BODY_60_79(75, D, E, T, A, B, C, X(11), X(13), X(3), X(8)); + BODY_60_79(76, C, D, E, T, A, B, X(12), X(14), X(4), X(9)); + BODY_60_79(77, B, C, D, E, T, A, X(13), X(15), X(5), X(10)); + BODY_60_79(78, A, B, C, D, E, T, X(14), X(0), X(6), X(11)); + BODY_60_79(79, T, A, B, C, D, E, X(15), X(1), X(7), X(12)); + + c->h0 = (c->h0 + E) & 0xffffffffL; + c->h1 = (c->h1 + T) & 0xffffffffL; + c->h2 = (c->h2 + A) & 0xffffffffL; + c->h3 = (c->h3 + B) & 0xffffffffL; + c->h4 = (c->h4 + C) & 0xffffffffL; + + if (--num == 0) { + break; + } + + A = c->h0; + B = c->h1; + C = c->h2; + D = c->h3; + E = c->h4; + } +} +#endif diff --git a/TMessagesProj/jni/boringssl/crypto/sha/sha256.c b/TMessagesProj/jni/boringssl/crypto/sha/sha256.c new file mode 100644 index 00000000..8276bbb5 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/sha/sha256.c @@ -0,0 +1,370 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include + + +#if !defined(OPENSSL_NO_ASM) && \ + (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \ + defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) +#define SHA256_ASM +#endif + +int SHA224_Init(SHA256_CTX *sha) { + memset(sha, 0, sizeof(SHA256_CTX)); + sha->h[0] = 0xc1059ed8UL; + sha->h[1] = 0x367cd507UL; + sha->h[2] = 0x3070dd17UL; + sha->h[3] = 0xf70e5939UL; + sha->h[4] = 0xffc00b31UL; + sha->h[5] = 0x68581511UL; + sha->h[6] = 0x64f98fa7UL; + sha->h[7] = 0xbefa4fa4UL; + sha->md_len = SHA224_DIGEST_LENGTH; + return 1; +} + +int SHA256_Init(SHA256_CTX *sha) { + memset(sha, 0, sizeof(SHA256_CTX)); + sha->h[0] = 0x6a09e667UL; + sha->h[1] = 0xbb67ae85UL; + sha->h[2] = 0x3c6ef372UL; + sha->h[3] = 0xa54ff53aUL; + sha->h[4] = 0x510e527fUL; + sha->h[5] = 0x9b05688cUL; + sha->h[6] = 0x1f83d9abUL; + sha->h[7] = 0x5be0cd19UL; + sha->md_len = SHA256_DIGEST_LENGTH; + return 1; +} + +uint8_t *SHA224(const uint8_t *data, size_t len, uint8_t *out) { + SHA256_CTX ctx; + static uint8_t buf[SHA224_DIGEST_LENGTH]; + + /* TODO(fork): remove this static buffer. */ + if (out == NULL) { + out = buf; + } + SHA224_Init(&ctx); + SHA256_Update(&ctx, data, len); + SHA256_Final(out, &ctx); + OPENSSL_cleanse(&ctx, sizeof(ctx)); + return out; +} + +uint8_t *SHA256(const uint8_t *data, size_t len, uint8_t *out) { + SHA256_CTX ctx; + static uint8_t buf[SHA256_DIGEST_LENGTH]; + + /* TODO(fork): remove this static buffer. */ + if (out == NULL) { + out = buf; + } + SHA256_Init(&ctx); + SHA256_Update(&ctx, data, len); + SHA256_Final(out, &ctx); + OPENSSL_cleanse(&ctx, sizeof(ctx)); + return out; +} + +int SHA224_Update(SHA256_CTX *ctx, const void *data, size_t len) { + return SHA256_Update(ctx, data, len); +} + +int SHA224_Final(uint8_t *md, SHA256_CTX *ctx) { + return SHA256_Final(md, ctx); +} + +#define DATA_ORDER_IS_BIG_ENDIAN + +#define HASH_LONG uint32_t +#define HASH_CTX SHA256_CTX +#define HASH_CBLOCK 64 + +/* Note that FIPS180-2 discusses "Truncation of the Hash Function Output." + * default: case below covers for it. It's not clear however if it's permitted + * to truncate to amount of bytes not divisible by 4. I bet not, but if it is, + * then default: case shall be extended. For reference. Idea behind separate + * cases for pre-defined lenghts is to let the compiler decide if it's + * appropriate to unroll small loops. + * + * TODO(davidben): The small |md_len| case is one of the few places a low-level + * hash 'final' function can fail. This should never happen. */ +#define HASH_MAKE_STRING(c, s) \ + do { \ + uint32_t ll; \ + unsigned int nn; \ + switch ((c)->md_len) { \ + case SHA224_DIGEST_LENGTH: \ + for (nn = 0; nn < SHA224_DIGEST_LENGTH / 4; nn++) { \ + ll = (c)->h[nn]; \ + (void) HOST_l2c(ll, (s)); \ + } \ + break; \ + case SHA256_DIGEST_LENGTH: \ + for (nn = 0; nn < SHA256_DIGEST_LENGTH / 4; nn++) { \ + ll = (c)->h[nn]; \ + (void) HOST_l2c(ll, (s)); \ + } \ + break; \ + default: \ + if ((c)->md_len > SHA256_DIGEST_LENGTH) { \ + return 0; \ + } \ + for (nn = 0; nn < (c)->md_len / 4; nn++) { \ + ll = (c)->h[nn]; \ + (void) HOST_l2c(ll, (s)); \ + } \ + break; \ + } \ + } while (0) + + +#define HASH_UPDATE SHA256_Update +#define HASH_TRANSFORM SHA256_Transform +#define HASH_FINAL SHA256_Final +#define HASH_BLOCK_DATA_ORDER sha256_block_data_order +#ifndef SHA256_ASM +static +#endif +void sha256_block_data_order(SHA256_CTX *ctx, const void *in, size_t num); + +#include "../digest/md32_common.h" + +#ifndef SHA256_ASM +static const HASH_LONG K256[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, + 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, + 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, + 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, + 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, + 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, + 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, + 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, + 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, + 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL}; + +/* FIPS specification refers to right rotations, while our ROTATE macro + * is left one. This is why you might notice that rotation coefficients + * differ from those observed in FIPS document by 32-N... */ +#define Sigma0(x) (ROTATE((x), 30) ^ ROTATE((x), 19) ^ ROTATE((x), 10)) +#define Sigma1(x) (ROTATE((x), 26) ^ ROTATE((x), 21) ^ ROTATE((x), 7)) +#define sigma0(x) (ROTATE((x), 25) ^ ROTATE((x), 14) ^ ((x) >> 3)) +#define sigma1(x) (ROTATE((x), 15) ^ ROTATE((x), 13) ^ ((x) >> 10)) + +#define Ch(x, y, z) (((x) & (y)) ^ ((~(x)) & (z))) +#define Maj(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + +#define ROUND_00_15(i, a, b, c, d, e, f, g, h) \ + do { \ + T1 += h + Sigma1(e) + Ch(e, f, g) + K256[i]; \ + h = Sigma0(a) + Maj(a, b, c); \ + d += T1; \ + h += T1; \ + } while (0) + +#define ROUND_16_63(i, a, b, c, d, e, f, g, h, X) \ + do { \ + s0 = X[(i + 1) & 0x0f]; \ + s0 = sigma0(s0); \ + s1 = X[(i + 14) & 0x0f]; \ + s1 = sigma1(s1); \ + T1 = X[(i) & 0x0f] += s0 + s1 + X[(i + 9) & 0x0f]; \ + ROUND_00_15(i, a, b, c, d, e, f, g, h); \ + } while (0) + +static void sha256_block_data_order(SHA256_CTX *ctx, const void *in, + size_t num) { + uint32_t a, b, c, d, e, f, g, h, s0, s1, T1; + HASH_LONG X[16]; + int i; + const uint8_t *data = in; + const union { + long one; + char little; + } is_endian = {1}; + + while (num--) { + a = ctx->h[0]; + b = ctx->h[1]; + c = ctx->h[2]; + d = ctx->h[3]; + e = ctx->h[4]; + f = ctx->h[5]; + g = ctx->h[6]; + h = ctx->h[7]; + + if (!is_endian.little && sizeof(HASH_LONG) == 4 && ((size_t)in % 4) == 0) { + const HASH_LONG *W = (const HASH_LONG *)data; + + T1 = X[0] = W[0]; + ROUND_00_15(0, a, b, c, d, e, f, g, h); + T1 = X[1] = W[1]; + ROUND_00_15(1, h, a, b, c, d, e, f, g); + T1 = X[2] = W[2]; + ROUND_00_15(2, g, h, a, b, c, d, e, f); + T1 = X[3] = W[3]; + ROUND_00_15(3, f, g, h, a, b, c, d, e); + T1 = X[4] = W[4]; + ROUND_00_15(4, e, f, g, h, a, b, c, d); + T1 = X[5] = W[5]; + ROUND_00_15(5, d, e, f, g, h, a, b, c); + T1 = X[6] = W[6]; + ROUND_00_15(6, c, d, e, f, g, h, a, b); + T1 = X[7] = W[7]; + ROUND_00_15(7, b, c, d, e, f, g, h, a); + T1 = X[8] = W[8]; + ROUND_00_15(8, a, b, c, d, e, f, g, h); + T1 = X[9] = W[9]; + ROUND_00_15(9, h, a, b, c, d, e, f, g); + T1 = X[10] = W[10]; + ROUND_00_15(10, g, h, a, b, c, d, e, f); + T1 = X[11] = W[11]; + ROUND_00_15(11, f, g, h, a, b, c, d, e); + T1 = X[12] = W[12]; + ROUND_00_15(12, e, f, g, h, a, b, c, d); + T1 = X[13] = W[13]; + ROUND_00_15(13, d, e, f, g, h, a, b, c); + T1 = X[14] = W[14]; + ROUND_00_15(14, c, d, e, f, g, h, a, b); + T1 = X[15] = W[15]; + ROUND_00_15(15, b, c, d, e, f, g, h, a); + + data += HASH_CBLOCK; + } else { + HASH_LONG l; + + HOST_c2l(data, l); + T1 = X[0] = l; + ROUND_00_15(0, a, b, c, d, e, f, g, h); + HOST_c2l(data, l); + T1 = X[1] = l; + ROUND_00_15(1, h, a, b, c, d, e, f, g); + HOST_c2l(data, l); + T1 = X[2] = l; + ROUND_00_15(2, g, h, a, b, c, d, e, f); + HOST_c2l(data, l); + T1 = X[3] = l; + ROUND_00_15(3, f, g, h, a, b, c, d, e); + HOST_c2l(data, l); + T1 = X[4] = l; + ROUND_00_15(4, e, f, g, h, a, b, c, d); + HOST_c2l(data, l); + T1 = X[5] = l; + ROUND_00_15(5, d, e, f, g, h, a, b, c); + HOST_c2l(data, l); + T1 = X[6] = l; + ROUND_00_15(6, c, d, e, f, g, h, a, b); + HOST_c2l(data, l); + T1 = X[7] = l; + ROUND_00_15(7, b, c, d, e, f, g, h, a); + HOST_c2l(data, l); + T1 = X[8] = l; + ROUND_00_15(8, a, b, c, d, e, f, g, h); + HOST_c2l(data, l); + T1 = X[9] = l; + ROUND_00_15(9, h, a, b, c, d, e, f, g); + HOST_c2l(data, l); + T1 = X[10] = l; + ROUND_00_15(10, g, h, a, b, c, d, e, f); + HOST_c2l(data, l); + T1 = X[11] = l; + ROUND_00_15(11, f, g, h, a, b, c, d, e); + HOST_c2l(data, l); + T1 = X[12] = l; + ROUND_00_15(12, e, f, g, h, a, b, c, d); + HOST_c2l(data, l); + T1 = X[13] = l; + ROUND_00_15(13, d, e, f, g, h, a, b, c); + HOST_c2l(data, l); + T1 = X[14] = l; + ROUND_00_15(14, c, d, e, f, g, h, a, b); + HOST_c2l(data, l); + T1 = X[15] = l; + ROUND_00_15(15, b, c, d, e, f, g, h, a); + } + + for (i = 16; i < 64; i += 8) { + ROUND_16_63(i + 0, a, b, c, d, e, f, g, h, X); + ROUND_16_63(i + 1, h, a, b, c, d, e, f, g, X); + ROUND_16_63(i + 2, g, h, a, b, c, d, e, f, X); + ROUND_16_63(i + 3, f, g, h, a, b, c, d, e, X); + ROUND_16_63(i + 4, e, f, g, h, a, b, c, d, X); + ROUND_16_63(i + 5, d, e, f, g, h, a, b, c, X); + ROUND_16_63(i + 6, c, d, e, f, g, h, a, b, X); + ROUND_16_63(i + 7, b, c, d, e, f, g, h, a, X); + } + + ctx->h[0] += a; + ctx->h[1] += b; + ctx->h[2] += c; + ctx->h[3] += d; + ctx->h[4] += e; + ctx->h[5] += f; + ctx->h[6] += g; + ctx->h[7] += h; + } +} + +#endif /* SHA256_ASM */ diff --git a/TMessagesProj/jni/boringssl/crypto/sha/sha512.c b/TMessagesProj/jni/boringssl/crypto/sha/sha512.c new file mode 100644 index 00000000..57c96ab9 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/sha/sha512.c @@ -0,0 +1,605 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include + +#include "../internal.h" + + +/* IMPLEMENTATION NOTES. + * + * As you might have noticed 32-bit hash algorithms: + * + * - permit SHA_LONG to be wider than 32-bit (case on CRAY); + * - optimized versions implement two transform functions: one operating + * on [aligned] data in host byte order and one - on data in input + * stream byte order; + * - share common byte-order neutral collector and padding function + * implementations, ../md32_common.h; + * + * Neither of the above applies to this SHA-512 implementations. Reasons + * [in reverse order] are: + * + * - it's the only 64-bit hash algorithm for the moment of this writing, + * there is no need for common collector/padding implementation [yet]; + * - by supporting only one transform function [which operates on + * *aligned* data in input stream byte order, big-endian in this case] + * we minimize burden of maintenance in two ways: a) collector/padding + * function is simpler; b) only one transform function to stare at; + * - SHA_LONG64 is required to be exactly 64-bit in order to be able to + * apply a number of optimizations to mitigate potential performance + * penalties caused by previous design decision; */ + +#if !defined(OPENSSL_NO_ASM) && \ + (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \ + defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) +#define SHA512_BLOCK_CAN_MANAGE_UNALIGNED_DATA +#define SHA512_ASM +#endif + +int SHA384_Init(SHA512_CTX *sha) { + sha->h[0] = OPENSSL_U64(0xcbbb9d5dc1059ed8); + sha->h[1] = OPENSSL_U64(0x629a292a367cd507); + sha->h[2] = OPENSSL_U64(0x9159015a3070dd17); + sha->h[3] = OPENSSL_U64(0x152fecd8f70e5939); + sha->h[4] = OPENSSL_U64(0x67332667ffc00b31); + sha->h[5] = OPENSSL_U64(0x8eb44a8768581511); + sha->h[6] = OPENSSL_U64(0xdb0c2e0d64f98fa7); + sha->h[7] = OPENSSL_U64(0x47b5481dbefa4fa4); + + sha->Nl = 0; + sha->Nh = 0; + sha->num = 0; + sha->md_len = SHA384_DIGEST_LENGTH; + return 1; +} + + +int SHA512_Init(SHA512_CTX *sha) { + sha->h[0] = OPENSSL_U64(0x6a09e667f3bcc908); + sha->h[1] = OPENSSL_U64(0xbb67ae8584caa73b); + sha->h[2] = OPENSSL_U64(0x3c6ef372fe94f82b); + sha->h[3] = OPENSSL_U64(0xa54ff53a5f1d36f1); + sha->h[4] = OPENSSL_U64(0x510e527fade682d1); + sha->h[5] = OPENSSL_U64(0x9b05688c2b3e6c1f); + sha->h[6] = OPENSSL_U64(0x1f83d9abfb41bd6b); + sha->h[7] = OPENSSL_U64(0x5be0cd19137e2179); + + sha->Nl = 0; + sha->Nh = 0; + sha->num = 0; + sha->md_len = SHA512_DIGEST_LENGTH; + return 1; +} + +uint8_t *SHA384(const uint8_t *data, size_t len, uint8_t *out) { + SHA512_CTX ctx; + static uint8_t buf[SHA384_DIGEST_LENGTH]; + + /* TODO(fork): remove this static buffer. */ + if (out == NULL) { + out = buf; + } + + SHA384_Init(&ctx); + SHA512_Update(&ctx, data, len); + SHA512_Final(out, &ctx); + OPENSSL_cleanse(&ctx, sizeof(ctx)); + return out; +} + +uint8_t *SHA512(const uint8_t *data, size_t len, uint8_t *out) { + SHA512_CTX ctx; + static uint8_t buf[SHA512_DIGEST_LENGTH]; + + /* TODO(fork): remove this static buffer. */ + if (out == NULL) { + out = buf; + } + SHA512_Init(&ctx); + SHA512_Update(&ctx, data, len); + SHA512_Final(out, &ctx); + OPENSSL_cleanse(&ctx, sizeof(ctx)); + return out; +} + +#if !defined(SHA512_ASM) +static +#endif +void sha512_block_data_order(SHA512_CTX *ctx, const void *in, size_t num); + + +int SHA384_Final(uint8_t *md, SHA512_CTX *sha) { + return SHA512_Final(md, sha); +} + +int SHA384_Update(SHA512_CTX *sha, const void *data, size_t len) { + return SHA512_Update(sha, data, len); +} + +void SHA512_Transform(SHA512_CTX *c, const uint8_t *data) { +#ifndef SHA512_BLOCK_CAN_MANAGE_UNALIGNED_DATA + if ((size_t)data % sizeof(c->u.d[0]) != 0) { + memcpy(c->u.p, data, sizeof(c->u.p)); + data = c->u.p; + } +#endif + sha512_block_data_order(c, data, 1); +} + +int SHA512_Update(SHA512_CTX *c, const void *in_data, size_t len) { + uint64_t l; + uint8_t *p = c->u.p; + const uint8_t *data = (const uint8_t *)in_data; + + if (len == 0) { + return 1; + } + + l = (c->Nl + (((uint64_t)len) << 3)) & OPENSSL_U64(0xffffffffffffffff); + if (l < c->Nl) { + c->Nh++; + } + if (sizeof(len) >= 8) { + c->Nh += (((uint64_t)len) >> 61); + } + c->Nl = l; + + if (c->num != 0) { + size_t n = sizeof(c->u) - c->num; + + if (len < n) { + memcpy(p + c->num, data, len); + c->num += (unsigned int)len; + return 1; + } else { + memcpy(p + c->num, data, n), c->num = 0; + len -= n; + data += n; + sha512_block_data_order(c, p, 1); + } + } + + if (len >= sizeof(c->u)) { +#ifndef SHA512_BLOCK_CAN_MANAGE_UNALIGNED_DATA + if ((size_t)data % sizeof(c->u.d[0]) != 0) { + while (len >= sizeof(c->u)) { + memcpy(p, data, sizeof(c->u)); + sha512_block_data_order(c, p, 1); + len -= sizeof(c->u); + data += sizeof(c->u); + } + } else +#endif + { + sha512_block_data_order(c, data, len / sizeof(c->u)); + data += len; + len %= sizeof(c->u); + data -= len; + } + } + + if (len != 0) { + memcpy(p, data, len); + c->num = (int)len; + } + + return 1; +} + +int SHA512_Final(uint8_t *md, SHA512_CTX *sha) { + uint8_t *p = (uint8_t *)sha->u.p; + size_t n = sha->num; + + p[n] = 0x80; /* There always is a room for one */ + n++; + if (n > (sizeof(sha->u) - 16)) { + memset(p + n, 0, sizeof(sha->u) - n); + n = 0; + sha512_block_data_order(sha, p, 1); + } + + memset(p + n, 0, sizeof(sha->u) - 16 - n); + p[sizeof(sha->u) - 1] = (uint8_t)(sha->Nl); + p[sizeof(sha->u) - 2] = (uint8_t)(sha->Nl >> 8); + p[sizeof(sha->u) - 3] = (uint8_t)(sha->Nl >> 16); + p[sizeof(sha->u) - 4] = (uint8_t)(sha->Nl >> 24); + p[sizeof(sha->u) - 5] = (uint8_t)(sha->Nl >> 32); + p[sizeof(sha->u) - 6] = (uint8_t)(sha->Nl >> 40); + p[sizeof(sha->u) - 7] = (uint8_t)(sha->Nl >> 48); + p[sizeof(sha->u) - 8] = (uint8_t)(sha->Nl >> 56); + p[sizeof(sha->u) - 9] = (uint8_t)(sha->Nh); + p[sizeof(sha->u) - 10] = (uint8_t)(sha->Nh >> 8); + p[sizeof(sha->u) - 11] = (uint8_t)(sha->Nh >> 16); + p[sizeof(sha->u) - 12] = (uint8_t)(sha->Nh >> 24); + p[sizeof(sha->u) - 13] = (uint8_t)(sha->Nh >> 32); + p[sizeof(sha->u) - 14] = (uint8_t)(sha->Nh >> 40); + p[sizeof(sha->u) - 15] = (uint8_t)(sha->Nh >> 48); + p[sizeof(sha->u) - 16] = (uint8_t)(sha->Nh >> 56); + + sha512_block_data_order(sha, p, 1); + + if (md == NULL) { + /* TODO(davidben): This NULL check is absent in other low-level hash 'final' + * functions and is one of the few places one can fail. */ + return 0; + } + + switch (sha->md_len) { + /* Let compiler decide if it's appropriate to unroll... */ + case SHA384_DIGEST_LENGTH: + for (n = 0; n < SHA384_DIGEST_LENGTH / 8; n++) { + uint64_t t = sha->h[n]; + + *(md++) = (uint8_t)(t >> 56); + *(md++) = (uint8_t)(t >> 48); + *(md++) = (uint8_t)(t >> 40); + *(md++) = (uint8_t)(t >> 32); + *(md++) = (uint8_t)(t >> 24); + *(md++) = (uint8_t)(t >> 16); + *(md++) = (uint8_t)(t >> 8); + *(md++) = (uint8_t)(t); + } + break; + case SHA512_DIGEST_LENGTH: + for (n = 0; n < SHA512_DIGEST_LENGTH / 8; n++) { + uint64_t t = sha->h[n]; + + *(md++) = (uint8_t)(t >> 56); + *(md++) = (uint8_t)(t >> 48); + *(md++) = (uint8_t)(t >> 40); + *(md++) = (uint8_t)(t >> 32); + *(md++) = (uint8_t)(t >> 24); + *(md++) = (uint8_t)(t >> 16); + *(md++) = (uint8_t)(t >> 8); + *(md++) = (uint8_t)(t); + } + break; + /* ... as well as make sure md_len is not abused. */ + default: + /* TODO(davidben): This bad |md_len| case is one of the few places a + * low-level hash 'final' function can fail. This should never happen. */ + return 0; + } + + return 1; +} + +#ifndef SHA512_ASM +static const uint64_t K512[80] = { + 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, + 0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019, + 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, + 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, + 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, + 0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, + 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, 0x2de92c6f592b0275, + 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, + 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, + 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725, + 0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, + 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, + 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, + 0x92722c851482353b, 0xa2bfe8a14cf10364, 0xa81a664bbc423001, + 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218, + 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, + 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, + 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, + 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, + 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, + 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, + 0xc67178f2e372532b, 0xca273eceea26619c, 0xd186b8c721c0c207, + 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, + 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, + 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, + 0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, + 0x5fcb6fab3ad6faec, 0x6c44198c4a475817}; + +#if defined(__GNUC__) && __GNUC__ >= 2 && !defined(OPENSSL_NO_ASM) +#if defined(__x86_64) || defined(__x86_64__) +#define ROTR(a, n) \ + ({ \ + uint64_t ret; \ + asm("rorq %1,%0" : "=r"(ret) : "J"(n), "0"(a) : "cc"); \ + ret; \ + }) +#define PULL64(x) \ + ({ \ + uint64_t ret = *((const uint64_t *)(&(x))); \ + asm("bswapq %0" : "=r"(ret) : "0"(ret)); \ + ret; \ + }) +#elif(defined(__i386) || defined(__i386__)) +#define PULL64(x) \ + ({ \ + const unsigned int *p = (const unsigned int *)(&(x)); \ + unsigned int hi = p[0], lo = p[1]; \ + asm("bswapl %0; bswapl %1;" : "=r"(lo), "=r"(hi) : "0"(lo), "1"(hi)); \ + ((uint64_t)hi) << 32 | lo; \ + }) +#elif(defined(_ARCH_PPC) && defined(__64BIT__)) || defined(_ARCH_PPC64) +#define ROTR(a, n) \ + ({ \ + uint64_t ret; \ + asm("rotrdi %0,%1,%2" : "=r"(ret) : "r"(a), "K"(n)); \ + ret; \ + }) +#elif defined(__aarch64__) +#define ROTR(a, n) \ + ({ \ + uint64_t ret; \ + asm("ror %0,%1,%2" : "=r"(ret) : "r"(a), "I"(n)); \ + ret; \ + }) +#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \ + __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define PULL64(x) \ + ({ \ + uint64_t ret; \ + asm("rev %0,%1" : "=r"(ret) : "r"(*((const uint64_t *)(&(x))))); \ + ret; \ + }) +#endif +#endif +#elif defined(_MSC_VER) +#if defined(_WIN64) /* applies to both IA-64 and AMD64 */ +#pragma intrinsic(_rotr64) +#define ROTR(a, n) _rotr64((a), n) +#endif +#if defined(_M_IX86) && !defined(OPENSSL_NO_ASM) +static uint64_t __fastcall __pull64be(const void *x) { + _asm mov edx, [ecx + 0] + _asm mov eax, [ecx + 4] + _asm bswap edx + _asm bswap eax +} +#define PULL64(x) __pull64be(&(x)) +#if _MSC_VER <= 1200 +#pragma inline_depth(0) +#endif +#endif +#endif + +#ifndef PULL64 +#define B(x, j) \ + (((uint64_t)(*(((const uint8_t *)(&x)) + j))) << ((7 - j) * 8)) +#define PULL64(x) \ + (B(x, 0) | B(x, 1) | B(x, 2) | B(x, 3) | B(x, 4) | B(x, 5) | B(x, 6) | \ + B(x, 7)) +#endif + +#ifndef ROTR +#define ROTR(x, s) (((x) >> s) | (x) << (64 - s)) +#endif + +#define Sigma0(x) (ROTR((x), 28) ^ ROTR((x), 34) ^ ROTR((x), 39)) +#define Sigma1(x) (ROTR((x), 14) ^ ROTR((x), 18) ^ ROTR((x), 41)) +#define sigma0(x) (ROTR((x), 1) ^ ROTR((x), 8) ^ ((x) >> 7)) +#define sigma1(x) (ROTR((x), 19) ^ ROTR((x), 61) ^ ((x) >> 6)) + +#define Ch(x, y, z) (((x) & (y)) ^ ((~(x)) & (z))) +#define Maj(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + + +#if defined(__i386) || defined(__i386__) || defined(_M_IX86) +/* + * This code should give better results on 32-bit CPU with less than + * ~24 registers, both size and performance wise... + */ +static void sha512_block_data_order(SHA512_CTX *ctx, const void *in, + size_t num) { + const uint64_t *W = in; + uint64_t A, E, T; + uint64_t X[9 + 80], *F; + int i; + + while (num--) { + F = X + 80; + A = ctx->h[0]; + F[1] = ctx->h[1]; + F[2] = ctx->h[2]; + F[3] = ctx->h[3]; + E = ctx->h[4]; + F[5] = ctx->h[5]; + F[6] = ctx->h[6]; + F[7] = ctx->h[7]; + + for (i = 0; i < 16; i++, F--) { + T = PULL64(W[i]); + F[0] = A; + F[4] = E; + F[8] = T; + T += F[7] + Sigma1(E) + Ch(E, F[5], F[6]) + K512[i]; + E = F[3] + T; + A = T + Sigma0(A) + Maj(A, F[1], F[2]); + } + + for (; i < 80; i++, F--) { + T = sigma0(F[8 + 16 - 1]); + T += sigma1(F[8 + 16 - 14]); + T += F[8 + 16] + F[8 + 16 - 9]; + + F[0] = A; + F[4] = E; + F[8] = T; + T += F[7] + Sigma1(E) + Ch(E, F[5], F[6]) + K512[i]; + E = F[3] + T; + A = T + Sigma0(A) + Maj(A, F[1], F[2]); + } + + ctx->h[0] += A; + ctx->h[1] += F[1]; + ctx->h[2] += F[2]; + ctx->h[3] += F[3]; + ctx->h[4] += E; + ctx->h[5] += F[5]; + ctx->h[6] += F[6]; + ctx->h[7] += F[7]; + + W += 16; + } +} + +#else + +#define ROUND_00_15(i, a, b, c, d, e, f, g, h) \ + do { \ + T1 += h + Sigma1(e) + Ch(e, f, g) + K512[i]; \ + h = Sigma0(a) + Maj(a, b, c); \ + d += T1; \ + h += T1; \ + } while (0) + +#define ROUND_16_80(i, j, a, b, c, d, e, f, g, h, X) \ + do { \ + s0 = X[(j + 1) & 0x0f]; \ + s0 = sigma0(s0); \ + s1 = X[(j + 14) & 0x0f]; \ + s1 = sigma1(s1); \ + T1 = X[(j) & 0x0f] += s0 + s1 + X[(j + 9) & 0x0f]; \ + ROUND_00_15(i + j, a, b, c, d, e, f, g, h); \ + } while (0) + +static void sha512_block_data_order(SHA512_CTX *ctx, const void *in, + size_t num) { + const uint64_t *W = in; + uint64_t a, b, c, d, e, f, g, h, s0, s1, T1; + uint64_t X[16]; + int i; + + while (num--) { + + a = ctx->h[0]; + b = ctx->h[1]; + c = ctx->h[2]; + d = ctx->h[3]; + e = ctx->h[4]; + f = ctx->h[5]; + g = ctx->h[6]; + h = ctx->h[7]; + + T1 = X[0] = PULL64(W[0]); + ROUND_00_15(0, a, b, c, d, e, f, g, h); + T1 = X[1] = PULL64(W[1]); + ROUND_00_15(1, h, a, b, c, d, e, f, g); + T1 = X[2] = PULL64(W[2]); + ROUND_00_15(2, g, h, a, b, c, d, e, f); + T1 = X[3] = PULL64(W[3]); + ROUND_00_15(3, f, g, h, a, b, c, d, e); + T1 = X[4] = PULL64(W[4]); + ROUND_00_15(4, e, f, g, h, a, b, c, d); + T1 = X[5] = PULL64(W[5]); + ROUND_00_15(5, d, e, f, g, h, a, b, c); + T1 = X[6] = PULL64(W[6]); + ROUND_00_15(6, c, d, e, f, g, h, a, b); + T1 = X[7] = PULL64(W[7]); + ROUND_00_15(7, b, c, d, e, f, g, h, a); + T1 = X[8] = PULL64(W[8]); + ROUND_00_15(8, a, b, c, d, e, f, g, h); + T1 = X[9] = PULL64(W[9]); + ROUND_00_15(9, h, a, b, c, d, e, f, g); + T1 = X[10] = PULL64(W[10]); + ROUND_00_15(10, g, h, a, b, c, d, e, f); + T1 = X[11] = PULL64(W[11]); + ROUND_00_15(11, f, g, h, a, b, c, d, e); + T1 = X[12] = PULL64(W[12]); + ROUND_00_15(12, e, f, g, h, a, b, c, d); + T1 = X[13] = PULL64(W[13]); + ROUND_00_15(13, d, e, f, g, h, a, b, c); + T1 = X[14] = PULL64(W[14]); + ROUND_00_15(14, c, d, e, f, g, h, a, b); + T1 = X[15] = PULL64(W[15]); + ROUND_00_15(15, b, c, d, e, f, g, h, a); + + for (i = 16; i < 80; i += 16) { + ROUND_16_80(i, 0, a, b, c, d, e, f, g, h, X); + ROUND_16_80(i, 1, h, a, b, c, d, e, f, g, X); + ROUND_16_80(i, 2, g, h, a, b, c, d, e, f, X); + ROUND_16_80(i, 3, f, g, h, a, b, c, d, e, X); + ROUND_16_80(i, 4, e, f, g, h, a, b, c, d, X); + ROUND_16_80(i, 5, d, e, f, g, h, a, b, c, X); + ROUND_16_80(i, 6, c, d, e, f, g, h, a, b, X); + ROUND_16_80(i, 7, b, c, d, e, f, g, h, a, X); + ROUND_16_80(i, 8, a, b, c, d, e, f, g, h, X); + ROUND_16_80(i, 9, h, a, b, c, d, e, f, g, X); + ROUND_16_80(i, 10, g, h, a, b, c, d, e, f, X); + ROUND_16_80(i, 11, f, g, h, a, b, c, d, e, X); + ROUND_16_80(i, 12, e, f, g, h, a, b, c, d, X); + ROUND_16_80(i, 13, d, e, f, g, h, a, b, c, X); + ROUND_16_80(i, 14, c, d, e, f, g, h, a, b, X); + ROUND_16_80(i, 15, b, c, d, e, f, g, h, a, X); + } + + ctx->h[0] += a; + ctx->h[1] += b; + ctx->h[2] += c; + ctx->h[3] += d; + ctx->h[4] += e; + ctx->h[5] += f; + ctx->h[6] += g; + ctx->h[7] += h; + + W += 16; + } +} + +#endif + +#endif /* SHA512_ASM */ diff --git a/TMessagesProj/jni/boringssl/crypto/stack/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/stack/CMakeLists.txt new file mode 100644 index 00000000..bdb05994 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/stack/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories(. .. ../../include) + +add_library( + stack + + OBJECT + + stack.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/stack/make_macros.sh b/TMessagesProj/jni/boringssl/crypto/stack/make_macros.sh new file mode 100644 index 00000000..4837e449 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/stack/make_macros.sh @@ -0,0 +1,115 @@ +#!/bin/sh + +include_dir=../../include/openssl + +cat > "${include_dir}/stack_macros.h" << EOF +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#if !defined(IN_STACK_H) +#error "Don't include this file directly. Include stack.h." +#endif + +EOF + +output_stack () { + type=$1 + ptrtype=$2 + + cat >> "${include_dir}/stack_macros.h" << EOF +/* ${type} */ +#define sk_${type}_new(comp)\\ + ((STACK_OF(${type})*) sk_new(CHECKED_CAST(stack_cmp_func, int (*) (const ${ptrtype} *a, const ${ptrtype} *b), comp))) + +#define sk_${type}_new_null()\\ + ((STACK_OF(${type})*) sk_new_null()) + +#define sk_${type}_num(sk)\\ + sk_num(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk)) + +#define sk_${type}_zero(sk)\\ + sk_zero(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk)); + +#define sk_${type}_value(sk, i)\\ + ((${ptrtype}) sk_value(CHECKED_CAST(_STACK*, const STACK_OF(${type})*, sk), (i))) + +#define sk_${type}_set(sk, i, p)\\ + ((${ptrtype}) sk_set(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk), (i), CHECKED_CAST(void*, ${ptrtype}, p))) + +#define sk_${type}_free(sk)\\ + sk_free(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk)) + +#define sk_${type}_pop_free(sk, free_func)\\ + sk_pop_free(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk), CHECKED_CAST(void (*) (void*), void (*) (${ptrtype}), free_func)) + +#define sk_${type}_insert(sk, p, where)\\ + sk_insert(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk), CHECKED_CAST(void*, ${ptrtype}, p), (where)) + +#define sk_${type}_delete(sk, where)\\ + ((${ptrtype}) sk_delete(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk), (where))) + +#define sk_${type}_delete_ptr(sk, p)\\ + ((${ptrtype}) sk_delete_ptr(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk), CHECKED_CAST(void*, ${ptrtype}, p))) + +#define sk_${type}_find(sk, out_index, p)\\ + sk_find(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk), (out_index), CHECKED_CAST(void*, ${ptrtype}, p)) + +#define sk_${type}_shift(sk)\\ + ((${ptrtype}) sk_shift(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk))) + +#define sk_${type}_push(sk, p)\\ + sk_push(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk), CHECKED_CAST(void*, ${ptrtype}, p)) + +#define sk_${type}_pop(sk)\\ + ((${ptrtype}) sk_pop(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk))) + +#define sk_${type}_dup(sk)\\ + ((STACK_OF(${type})*) sk_dup(CHECKED_CAST(_STACK*, const STACK_OF(${type})*, sk))) + +#define sk_${type}_sort(sk)\\ + sk_sort(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk)) + +#define sk_${type}_is_sorted(sk)\\ + sk_is_sorted(CHECKED_CAST(_STACK*, const STACK_OF(${type})*, sk)) + +#define sk_${type}_set_cmp_func(sk, comp)\\ + ((int (*) (const ${type} **a, const ${type} **b)) sk_set_cmp_func(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk), CHECKED_CAST(stack_cmp_func, int (*) (const ${type} **a, const ${type} **b), comp))) + +#define sk_${type}_deep_copy(sk, copy_func, free_func)\\ +((STACK_OF(${type})*) sk_deep_copy(CHECKED_CAST(const _STACK*, const STACK_OF(${type})*, sk), CHECKED_CAST(void* (*) (void*), ${ptrtype} (*) (${ptrtype}), copy_func), CHECKED_CAST(void (*) (void*), void (*) (${ptrtype}), free_func))) + + +EOF +} + +stack_types=$(cat "${include_dir}/stack.h" | grep '^ \* STACK_OF:' | sed -e 's/.*STACK_OF://' -e 's/ .*//') +const_stack_types=$(cat "${include_dir}/stack.h" | grep '^ \* CONST_STACK_OF:' | sed -e 's/.*CONST_STACK_OF://' -e 's/ .*//') +special_stack_types=$(cat "${include_dir}/stack.h" | grep '^ \* SPECIAL_STACK_OF:' | sed -e 's/.*SPECIAL_STACK_OF://' -e 's/ .*//') + +for type in $stack_types; do + echo Stack of ${type} + output_stack "${type}" "${type} *" +done + +for type in $const_stack_types; do + echo Stack of ${type} + output_stack "${type}" "const ${type} *" +done + +for type in $special_stack_types; do + echo Stack of ${type} + output_stack "${type}" "${type}" +done + +clang-format -i "${include_dir}/stack_macros.h" diff --git a/TMessagesProj/jni/boringssl/crypto/stack/stack.c b/TMessagesProj/jni/boringssl/crypto/stack/stack.c new file mode 100644 index 00000000..c5845159 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/stack/stack.c @@ -0,0 +1,386 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include + +/* kMinSize is the number of pointers that will be initially allocated in a new + * stack. */ +static const size_t kMinSize = 4; + +_STACK *sk_new(stack_cmp_func comp) { + _STACK *ret; + + ret = OPENSSL_malloc(sizeof(_STACK)); + if (ret == NULL) { + goto err; + } + memset(ret, 0, sizeof(_STACK)); + + ret->data = OPENSSL_malloc(sizeof(void *) * kMinSize); + if (ret->data == NULL) { + goto err; + } + + memset(ret->data, 0, sizeof(void *) * kMinSize); + + ret->comp = comp; + ret->num_alloc = kMinSize; + + return ret; + +err: + OPENSSL_free(ret); + return NULL; +} + +_STACK *sk_new_null(void) { return sk_new(NULL); } + +size_t sk_num(const _STACK *sk) { + if (sk == NULL) { + return 0; + } + return sk->num; +} + +void sk_zero(_STACK *sk) { + if (sk == NULL || sk->num == 0) { + return; + } + memset(sk->data, 0, sizeof(void*) * sk->num); + sk->num = 0; + sk->sorted = 0; +} + +void *sk_value(const _STACK *sk, size_t i) { + if (!sk || i >= sk->num) { + return NULL; + } + return sk->data[i]; +} + +void *sk_set(_STACK *sk, size_t i, void *value) { + if (!sk || i >= sk->num) { + return NULL; + } + return sk->data[i] = value; +} + +void sk_free(_STACK *sk) { + if (sk == NULL) { + return; + } + OPENSSL_free(sk->data); + OPENSSL_free(sk); +} + +void sk_pop_free(_STACK *sk, void (*func)(void *)) { + size_t i; + + if (sk == NULL) { + return; + } + + for (i = 0; i < sk->num; i++) { + if (sk->data[i] != NULL) { + func(sk->data[i]); + } + } + sk_free(sk); +} + +size_t sk_insert(_STACK *sk, void *p, size_t where) { + if (sk == NULL) { + return 0; + } + + if (sk->num_alloc <= sk->num + 1) { + /* Attempt to double the size of the array. */ + size_t new_alloc = sk->num_alloc << 1; + size_t alloc_size = new_alloc * sizeof(void *); + void **data; + + /* If the doubling overflowed, try to increment. */ + if (new_alloc < sk->num_alloc || alloc_size / sizeof(void *) != new_alloc) { + new_alloc = sk->num_alloc + 1; + alloc_size = new_alloc * sizeof(void *); + } + + /* If the increment also overflowed, fail. */ + if (new_alloc < sk->num_alloc || alloc_size / sizeof(void *) != new_alloc) { + return 0; + } + + data = OPENSSL_realloc(sk->data, alloc_size); + if (data == NULL) { + return 0; + } + + sk->data = data; + sk->num_alloc = new_alloc; + } + + if (where >= sk->num) { + sk->data[sk->num] = p; + } else { + memmove(&sk->data[where + 1], &sk->data[where], + sizeof(void *) * (sk->num - where)); + sk->data[where] = p; + } + + sk->num++; + sk->sorted = 0; + + return sk->num; +} + +void *sk_delete(_STACK *sk, size_t where) { + void *ret; + + if (!sk || where >= sk->num) { + return NULL; + } + + ret = sk->data[where]; + + if (where != sk->num - 1) { + memmove(&sk->data[where], &sk->data[where + 1], + sizeof(void *) * (sk->num - where - 1)); + } + + sk->num--; + return ret; +} + +void *sk_delete_ptr(_STACK *sk, void *p) { + size_t i; + + if (sk == NULL) { + return NULL; + } + + for (i = 0; i < sk->num; i++) { + if (sk->data[i] == p) { + return sk_delete(sk, i); + } + } + + return NULL; +} + +int sk_find(_STACK *sk, size_t *out_index, void *p) { + const void *const *r; + size_t i; + int (*comp_func)(const void *,const void *); + + if (sk == NULL) { + return 0; + } + + if (sk->comp == NULL) { + /* Use pointer equality when no comparison function has been set. */ + for (i = 0; i < sk->num; i++) { + if (sk->data[i] == p) { + if (out_index) { + *out_index = i; + } + return 1; + } + } + return 0; + } + + if (p == NULL) { + return 0; + } + + sk_sort(sk); + + /* sk->comp is a function that takes pointers to pointers to elements, but + * qsort and bsearch take a comparison function that just takes pointers to + * elements. However, since we're passing an array of pointers to + * qsort/bsearch, we can just cast the comparison function and everything + * works. */ + comp_func=(int (*)(const void *,const void *))(sk->comp); + r = bsearch(&p, sk->data, sk->num, sizeof(void *), comp_func); + if (r == NULL) { + return 0; + } + i = ((void **)r) - sk->data; + /* This function always returns the first result. */ + while (i > 0 && sk->comp((const void**) &p, (const void**) &sk->data[i-1]) == 0) { + i--; + } + if (out_index) { + *out_index = i; + } + return 1; +} + +void *sk_shift(_STACK *sk) { + if (sk == NULL) { + return NULL; + } + if (sk->num == 0) { + return NULL; + } + return sk_delete(sk, 0); +} + +size_t sk_push(_STACK *sk, void *p) { return (sk_insert(sk, p, sk->num)); } + +void *sk_pop(_STACK *sk) { + if (sk == NULL) { + return NULL; + } + if (sk->num == 0) { + return NULL; + } + return sk_delete(sk, sk->num - 1); +} + +_STACK *sk_dup(const _STACK *sk) { + _STACK *ret; + void **s; + + if (sk == NULL) { + return NULL; + } + + ret = sk_new(sk->comp); + if (ret == NULL) { + goto err; + } + + s = (void **)OPENSSL_realloc(ret->data, sizeof(void *) * sk->num_alloc); + if (s == NULL) { + goto err; + } + ret->data = s; + + ret->num = sk->num; + memcpy(ret->data, sk->data, sizeof(void *) * sk->num); + ret->sorted = sk->sorted; + ret->num_alloc = sk->num_alloc; + ret->comp = sk->comp; + return ret; + +err: + sk_free(ret); + return NULL; +} + +void sk_sort(_STACK *sk) { + int (*comp_func)(const void *,const void *); + + if (sk == NULL || sk->sorted) { + return; + } + + /* See the comment in sk_find about this cast. */ + comp_func = (int (*)(const void *, const void *))(sk->comp); + qsort(sk->data, sk->num, sizeof(void *), comp_func); + sk->sorted = 1; +} + +int sk_is_sorted(const _STACK *sk) { + if (!sk) { + return 1; + } + return sk->sorted; +} + +stack_cmp_func sk_set_cmp_func(_STACK *sk, stack_cmp_func comp) { + stack_cmp_func old = sk->comp; + + if (sk->comp != comp) { + sk->sorted = 0; + } + sk->comp = comp; + + return old; +} + +_STACK *sk_deep_copy(const _STACK *sk, void *(*copy_func)(void *), + void (*free_func)(void *)) { + _STACK *ret = sk_dup(sk); + if (ret == NULL) { + return NULL; + } + + size_t i; + for (i = 0; i < ret->num; i++) { + if (ret->data[i] == NULL) { + continue; + } + ret->data[i] = copy_func(ret->data[i]); + if (ret->data[i] == NULL) { + size_t j; + for (j = 0; j < i; j++) { + if (ret->data[j] != NULL) { + free_func(ret->data[j]); + } + } + sk_free(ret); + return NULL; + } + } + + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/thread.c b/TMessagesProj/jni/boringssl/crypto/thread.c new file mode 100644 index 00000000..88371159 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/thread.c @@ -0,0 +1,101 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#if !defined(OPENSSL_WINDOWS) +#include +#else +#pragma warning(push, 3) +#include +#pragma warning(pop) +#endif + +#include + + +int CRYPTO_num_locks(void) { return 1; } + +void CRYPTO_set_locking_callback(void (*func)(int mode, int lock_num, + const char *file, int line)) {} + +void CRYPTO_set_add_lock_callback(int (*func)(int *num, int mount, int lock_num, + const char *file, int line)) {} + +const char *CRYPTO_get_lock_name(int lock_num) { + return "No old-style OpenSSL locks anymore"; +} + +int CRYPTO_THREADID_set_callback(void (*func)(CRYPTO_THREADID *)) { return 1; } + +void CRYPTO_THREADID_set_numeric(CRYPTO_THREADID *id, unsigned long val) {} + +void CRYPTO_THREADID_set_pointer(CRYPTO_THREADID *id, void *ptr) {} + +void CRYPTO_THREADID_current(CRYPTO_THREADID *id) {} + +void CRYPTO_set_id_callback(unsigned long (*func)(void)) {} + +void CRYPTO_set_dynlock_create_callback(struct CRYPTO_dynlock_value *( + *dyn_create_function)(const char *file, int line)) {} + +void CRYPTO_set_dynlock_lock_callback(void (*dyn_lock_function)( + int mode, struct CRYPTO_dynlock_value *l, const char *file, int line)) {} + +void CRYPTO_set_dynlock_destroy_callback(void (*dyn_destroy_function)( + struct CRYPTO_dynlock_value *l, const char *file, int line)) {} diff --git a/TMessagesProj/jni/boringssl/crypto/thread_none.c b/TMessagesProj/jni/boringssl/crypto/thread_none.c new file mode 100644 index 00000000..cf4e85a7 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/thread_none.c @@ -0,0 +1,55 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include "internal.h" + +#if defined(OPENSSL_NO_THREADS) + +void CRYPTO_MUTEX_init(CRYPTO_MUTEX *lock) {} + +void CRYPTO_MUTEX_lock_read(CRYPTO_MUTEX *lock) {} + +void CRYPTO_MUTEX_lock_write(CRYPTO_MUTEX *lock) {} + +void CRYPTO_MUTEX_unlock(CRYPTO_MUTEX *lock) {} + +void CRYPTO_MUTEX_cleanup(CRYPTO_MUTEX *lock) {} + +void CRYPTO_STATIC_MUTEX_lock_read(struct CRYPTO_STATIC_MUTEX *lock) {} + +void CRYPTO_STATIC_MUTEX_lock_write(struct CRYPTO_STATIC_MUTEX *lock) {} + +void CRYPTO_STATIC_MUTEX_unlock(struct CRYPTO_STATIC_MUTEX *lock) {} + +void CRYPTO_once(CRYPTO_once_t *once, void (*init)(void)) { + if (*once) { + return; + } + *once = 1; + init(); +} + +static void *g_thread_locals[NUM_OPENSSL_THREAD_LOCALS]; + +void *CRYPTO_get_thread_local(thread_local_data_t index) { + return g_thread_locals[index]; +} + +int CRYPTO_set_thread_local(thread_local_data_t index, void *value, + thread_local_destructor_t destructor) { + g_thread_locals[index] = value; + return 1; +} + +#endif /* OPENSSL_NO_THREADS */ diff --git a/TMessagesProj/jni/boringssl/crypto/thread_pthread.c b/TMessagesProj/jni/boringssl/crypto/thread_pthread.c new file mode 100644 index 00000000..59c4b8d1 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/thread_pthread.c @@ -0,0 +1,162 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include "internal.h" + +#if !defined(OPENSSL_WINDOWS) && !defined(OPENSSL_NO_THREADS) + +#include +#include +#include + +#include +#include + + +OPENSSL_COMPILE_ASSERT(sizeof(CRYPTO_MUTEX) >= sizeof(pthread_rwlock_t), + CRYPTO_MUTEX_too_small); + +void CRYPTO_MUTEX_init(CRYPTO_MUTEX *lock) { + if (pthread_rwlock_init((pthread_rwlock_t *) lock, NULL) != 0) { + abort(); + } +} + +void CRYPTO_MUTEX_lock_read(CRYPTO_MUTEX *lock) { + if (pthread_rwlock_rdlock((pthread_rwlock_t *) lock) != 0) { + abort(); + } +} + +void CRYPTO_MUTEX_lock_write(CRYPTO_MUTEX *lock) { + if (pthread_rwlock_wrlock((pthread_rwlock_t *) lock) != 0) { + abort(); + } +} + +void CRYPTO_MUTEX_unlock(CRYPTO_MUTEX *lock) { + if (pthread_rwlock_unlock((pthread_rwlock_t *) lock) != 0) { + abort(); + } +} + +void CRYPTO_MUTEX_cleanup(CRYPTO_MUTEX *lock) { + pthread_rwlock_destroy((pthread_rwlock_t *) lock); +} + +void CRYPTO_STATIC_MUTEX_lock_read(struct CRYPTO_STATIC_MUTEX *lock) { + if (pthread_rwlock_rdlock(&lock->lock) != 0) { + abort(); + } +} + +void CRYPTO_STATIC_MUTEX_lock_write(struct CRYPTO_STATIC_MUTEX *lock) { + if (pthread_rwlock_wrlock(&lock->lock) != 0) { + abort(); + } +} + +void CRYPTO_STATIC_MUTEX_unlock(struct CRYPTO_STATIC_MUTEX *lock) { + if (pthread_rwlock_unlock(&lock->lock) != 0) { + abort(); + } +} + +void CRYPTO_once(CRYPTO_once_t *once, void (*init)(void)) { + pthread_once(once, init); +} + +static pthread_mutex_t g_destructors_lock = PTHREAD_MUTEX_INITIALIZER; +static thread_local_destructor_t g_destructors[NUM_OPENSSL_THREAD_LOCALS]; + +static void thread_local_destructor(void *arg) { + if (arg == NULL) { + return; + } + + thread_local_destructor_t destructors[NUM_OPENSSL_THREAD_LOCALS]; + if (pthread_mutex_lock(&g_destructors_lock) != 0) { + return; + } + memcpy(destructors, g_destructors, sizeof(destructors)); + pthread_mutex_unlock(&g_destructors_lock); + + unsigned i; + void **pointers = arg; + for (i = 0; i < NUM_OPENSSL_THREAD_LOCALS; i++) { + if (destructors[i] != NULL) { + destructors[i](pointers[i]); + } + } + + OPENSSL_free(pointers); +} + +static pthread_once_t g_thread_local_init_once = PTHREAD_ONCE_INIT; +static pthread_key_t g_thread_local_key; +static int g_thread_local_failed = 0; + +static void thread_local_init(void) { + g_thread_local_failed = + pthread_key_create(&g_thread_local_key, thread_local_destructor) != 0; +} + +void *CRYPTO_get_thread_local(thread_local_data_t index) { + CRYPTO_once(&g_thread_local_init_once, thread_local_init); + if (g_thread_local_failed) { + return NULL; + } + + void **pointers = pthread_getspecific(g_thread_local_key); + if (pointers == NULL) { + return NULL; + } + return pointers[index]; +} + +int CRYPTO_set_thread_local(thread_local_data_t index, void *value, + thread_local_destructor_t destructor) { + CRYPTO_once(&g_thread_local_init_once, thread_local_init); + if (g_thread_local_failed) { + destructor(value); + return 0; + } + + void **pointers = pthread_getspecific(g_thread_local_key); + if (pointers == NULL) { + pointers = OPENSSL_malloc(sizeof(void *) * NUM_OPENSSL_THREAD_LOCALS); + if (pointers == NULL) { + destructor(value); + return 0; + } + memset(pointers, 0, sizeof(void *) * NUM_OPENSSL_THREAD_LOCALS); + if (pthread_setspecific(g_thread_local_key, pointers) != 0) { + OPENSSL_free(pointers); + destructor(value); + return 0; + } + } + + if (pthread_mutex_lock(&g_destructors_lock) != 0) { + destructor(value); + return 0; + } + g_destructors[index] = destructor; + pthread_mutex_unlock(&g_destructors_lock); + + pointers[index] = value; + return 1; +} + +#endif /* !OPENSSL_WINDOWS && !OPENSSL_NO_THREADS */ diff --git a/TMessagesProj/jni/boringssl/crypto/thread_win.c b/TMessagesProj/jni/boringssl/crypto/thread_win.c new file mode 100644 index 00000000..5efd8be3 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/thread_win.c @@ -0,0 +1,282 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include "internal.h" + +#if defined(OPENSSL_WINDOWS) && !defined(OPENSSL_NO_THREADS) + +#pragma warning(push, 3) +#include +#pragma warning(pop) + +#include +#include +#include + +#include +#include + + +OPENSSL_COMPILE_ASSERT(sizeof(CRYPTO_MUTEX) >= sizeof(CRITICAL_SECTION), + CRYPTO_MUTEX_too_small); + +static void run_once(CRYPTO_once_t *in_once, void (*init)(void *), void *arg) { + volatile LONG *once = in_once; + + /* Values must be aligned. */ + assert((((uintptr_t) once) & 3) == 0); + + /* This assumes that reading *once has acquire semantics. This should be true + * on x86 and x86-64, where we expect Windows to run. */ +#if !defined(OPENSSL_X86) && !defined(OPENSSL_X86_64) +#error "Windows once code may not work on other platforms." \ + "You can use InitOnceBeginInitialize on >=Vista" +#endif + if (*once == 1) { + return; + } + + for (;;) { + switch (InterlockedCompareExchange(once, 2, 0)) { + case 0: + /* The value was zero so we are the first thread to call |CRYPTO_once| + * on it. */ + init(arg); + /* Write one to indicate that initialisation is complete. */ + InterlockedExchange(once, 1); + return; + + case 1: + /* Another thread completed initialisation between our fast-path check + * and |InterlockedCompareExchange|. */ + return; + + case 2: + /* Another thread is running the initialisation. Switch to it then try + * again. */ + SwitchToThread(); + break; + + default: + abort(); + } + } +} + +static void call_once_init(void *arg) { + void (*init_func)(void); + /* MSVC does not like casting between data and function pointers. */ + memcpy(&init_func, &arg, sizeof(void *)); + init_func(); +} + +void CRYPTO_once(CRYPTO_once_t *in_once, void (*init)(void)) { + void *arg; + /* MSVC does not like casting between data and function pointers. */ + memcpy(&arg, &init, sizeof(void *)); + run_once(in_once, call_once_init, arg); +} + +void CRYPTO_MUTEX_init(CRYPTO_MUTEX *lock) { + if (!InitializeCriticalSectionAndSpinCount((CRITICAL_SECTION *) lock, 0x400)) { + abort(); + } +} + +void CRYPTO_MUTEX_lock_read(CRYPTO_MUTEX *lock) { + /* Since we have to support Windows XP, read locks are actually exclusive. */ + EnterCriticalSection((CRITICAL_SECTION *) lock); +} + +void CRYPTO_MUTEX_lock_write(CRYPTO_MUTEX *lock) { + EnterCriticalSection((CRITICAL_SECTION *) lock); +} + +void CRYPTO_MUTEX_unlock(CRYPTO_MUTEX *lock) { + LeaveCriticalSection((CRITICAL_SECTION *) lock); +} + +void CRYPTO_MUTEX_cleanup(CRYPTO_MUTEX *lock) { + DeleteCriticalSection((CRITICAL_SECTION *) lock); +} + +static void static_lock_init(void *arg) { + struct CRYPTO_STATIC_MUTEX *lock = arg; + if (!InitializeCriticalSectionAndSpinCount(&lock->lock, 0x400)) { + abort(); + } +} + +void CRYPTO_STATIC_MUTEX_lock_read(struct CRYPTO_STATIC_MUTEX *lock) { + /* Since we have to support Windows XP, read locks are actually exclusive. */ + run_once(&lock->once, static_lock_init, lock); + EnterCriticalSection(&lock->lock); +} + +void CRYPTO_STATIC_MUTEX_lock_write(struct CRYPTO_STATIC_MUTEX *lock) { + CRYPTO_STATIC_MUTEX_lock_read(lock); +} + +void CRYPTO_STATIC_MUTEX_unlock(struct CRYPTO_STATIC_MUTEX *lock) { + LeaveCriticalSection(&lock->lock); +} + +static CRITICAL_SECTION g_destructors_lock; +static thread_local_destructor_t g_destructors[NUM_OPENSSL_THREAD_LOCALS]; + +static CRYPTO_once_t g_thread_local_init_once = CRYPTO_ONCE_INIT; +static DWORD g_thread_local_key; +static int g_thread_local_failed; + +static void thread_local_init(void) { + if (!InitializeCriticalSectionAndSpinCount(&g_destructors_lock, 0x400)) { + g_thread_local_failed = 1; + return; + } + g_thread_local_key = TlsAlloc(); + g_thread_local_failed = (g_thread_local_key == TLS_OUT_OF_INDEXES); +} + +static void NTAPI thread_local_destructor(PVOID module, + DWORD reason, PVOID reserved) { + if (DLL_THREAD_DETACH != reason && DLL_PROCESS_DETACH != reason) { + return; + } + + CRYPTO_once(&g_thread_local_init_once, thread_local_init); + if (g_thread_local_failed) { + return; + } + + void **pointers = (void**) TlsGetValue(g_thread_local_key); + if (pointers == NULL) { + return; + } + + thread_local_destructor_t destructors[NUM_OPENSSL_THREAD_LOCALS]; + + EnterCriticalSection(&g_destructors_lock); + memcpy(destructors, g_destructors, sizeof(destructors)); + LeaveCriticalSection(&g_destructors_lock); + + unsigned i; + for (i = 0; i < NUM_OPENSSL_THREAD_LOCALS; i++) { + if (destructors[i] != NULL) { + destructors[i](pointers[i]); + } + } + + OPENSSL_free(pointers); +} + +/* Thread Termination Callbacks. + * + * Windows doesn't support a per-thread destructor with its TLS primitives. + * So, we build it manually by inserting a function to be called on each + * thread's exit. This magic is from http://www.codeproject.com/threads/tls.asp + * and it works for VC++ 7.0 and later. + * + * Force a reference to _tls_used to make the linker create the TLS directory + * if it's not already there. (E.g. if __declspec(thread) is not used). Force + * a reference to p_thread_callback_boringssl to prevent whole program + * optimization from discarding the variable. */ +#ifdef _WIN64 +#pragma comment(linker, "/INCLUDE:_tls_used") +#pragma comment(linker, "/INCLUDE:p_thread_callback_boringssl") +#else +#pragma comment(linker, "/INCLUDE:__tls_used") +#pragma comment(linker, "/INCLUDE:_p_thread_callback_boringssl") +#endif + +/* .CRT$XLA to .CRT$XLZ is an array of PIMAGE_TLS_CALLBACK pointers that are + * called automatically by the OS loader code (not the CRT) when the module is + * loaded and on thread creation. They are NOT called if the module has been + * loaded by a LoadLibrary() call. It must have implicitly been loaded at + * process startup. + * + * By implicitly loaded, I mean that it is directly referenced by the main EXE + * or by one of its dependent DLLs. Delay-loaded DLL doesn't count as being + * implicitly loaded. + * + * See VC\crt\src\tlssup.c for reference. */ + +/* The linker must not discard p_thread_callback_boringssl. (We force a reference + * to this variable with a linker /INCLUDE:symbol pragma to ensure that.) If + * this variable is discarded, the OnThreadExit function will never be + * called. */ +#ifdef _WIN64 + +/* .CRT section is merged with .rdata on x64 so it must be constant data. */ +#pragma const_seg(".CRT$XLC") +/* When defining a const variable, it must have external linkage to be sure the + * linker doesn't discard it. */ +extern const PIMAGE_TLS_CALLBACK p_thread_callback_boringssl; +const PIMAGE_TLS_CALLBACK p_thread_callback_boringssl = thread_local_destructor; +/* Reset the default section. */ +#pragma const_seg() + +#else + +#pragma data_seg(".CRT$XLC") +PIMAGE_TLS_CALLBACK p_thread_callback_boringssl = thread_local_destructor; +/* Reset the default section. */ +#pragma data_seg() + +#endif /* _WIN64 */ + +void *CRYPTO_get_thread_local(thread_local_data_t index) { + CRYPTO_once(&g_thread_local_init_once, thread_local_init); + if (g_thread_local_failed) { + return NULL; + } + + void **pointers = TlsGetValue(g_thread_local_key); + if (pointers == NULL) { + return NULL; + } + return pointers[index]; +} + +int CRYPTO_set_thread_local(thread_local_data_t index, void *value, + thread_local_destructor_t destructor) { + CRYPTO_once(&g_thread_local_init_once, thread_local_init); + if (g_thread_local_failed) { + destructor(value); + return 0; + } + + void **pointers = TlsGetValue(g_thread_local_key); + if (pointers == NULL) { + pointers = OPENSSL_malloc(sizeof(void *) * NUM_OPENSSL_THREAD_LOCALS); + if (pointers == NULL) { + destructor(value); + return 0; + } + memset(pointers, 0, sizeof(void *) * NUM_OPENSSL_THREAD_LOCALS); + if (TlsSetValue(g_thread_local_key, pointers) == 0) { + OPENSSL_free(pointers); + destructor(value); + return 0; + } + } + + EnterCriticalSection(&g_destructors_lock); + g_destructors[index] = destructor; + LeaveCriticalSection(&g_destructors_lock); + + pointers[index] = value; + return 1; +} + +#endif /* OPENSSL_WINDOWS && !OPENSSL_NO_THREADS */ diff --git a/TMessagesProj/jni/boringssl/crypto/time_support.c b/TMessagesProj/jni/boringssl/crypto/time_support.c new file mode 100644 index 00000000..bf9daed1 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/time_support.c @@ -0,0 +1,212 @@ +/* Written by Richard Levitte (richard@levitte.org) for the OpenSSL + * project 2001. + * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2008. + */ +/* ==================================================================== + * Copyright (c) 2001 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#if !defined(_POSIX_C_SOURCE) +#define _POSIX_C_SOURCE 201410L /* for gmtime_r */ +#endif + +#if defined(__MINGW32__) +#define MINGW_HAS_SECURE_API 1 /* supplied by libmingwex */ +#include /* for correct definition of gmtime_s */ +#undef MINGW_HAS_SECURE_API +#endif + +#include + +#include + + +#define SECS_PER_DAY (24 * 60 * 60) + +struct tm *OPENSSL_gmtime(const time_t *time, struct tm *result) { +#if defined(OPENSSL_WINDOWS) + if (gmtime_s(result, time)) { + return NULL; + } + return result; +#else + return gmtime_r(time, result); +#endif +} + +/* Convert date to and from julian day Uses Fliegel & Van Flandern algorithm */ +static long date_to_julian(int y, int m, int d) { + return (1461 * (y + 4800 + (m - 14) / 12)) / 4 + + (367 * (m - 2 - 12 * ((m - 14) / 12))) / 12 - + (3 * ((y + 4900 + (m - 14) / 12) / 100)) / 4 + d - 32075; +} + +static void julian_to_date(long jd, int *y, int *m, int *d) { + long L = jd + 68569; + long n = (4 * L) / 146097; + long i, j; + + L = L - (146097 * n + 3) / 4; + i = (4000 * (L + 1)) / 1461001; + L = L - (1461 * i) / 4 + 31; + j = (80 * L) / 2447; + *d = L - (2447 * j) / 80; + L = j / 11; + *m = j + 2 - (12 * L); + *y = 100 * (n - 49) + i + L; +} + +/* Convert tm structure and offset into julian day and seconds */ +static int julian_adj(const struct tm *tm, int off_day, long offset_sec, + long *pday, int *psec) { + int offset_hms, offset_day; + long time_jd; + int time_year, time_month, time_day; + /* split offset into days and day seconds */ + offset_day = offset_sec / SECS_PER_DAY; + /* Avoid sign issues with % operator */ + offset_hms = offset_sec - (offset_day * SECS_PER_DAY); + offset_day += off_day; + /* Add current time seconds to offset */ + offset_hms += tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec; + /* Adjust day seconds if overflow */ + if (offset_hms >= SECS_PER_DAY) { + offset_day++; + offset_hms -= SECS_PER_DAY; + } else if (offset_hms < 0) { + offset_day--; + offset_hms += SECS_PER_DAY; + } + + /* Convert date of time structure into a Julian day number. */ + + time_year = tm->tm_year + 1900; + time_month = tm->tm_mon + 1; + time_day = tm->tm_mday; + + time_jd = date_to_julian(time_year, time_month, time_day); + + /* Work out Julian day of new date */ + time_jd += offset_day; + + if (time_jd < 0) { + return 0; + } + + *pday = time_jd; + *psec = offset_hms; + return 1; +} + +int OPENSSL_gmtime_adj(struct tm *tm, int off_day, long offset_sec) { + int time_sec, time_year, time_month, time_day; + long time_jd; + + /* Convert time and offset into julian day and seconds */ + if (!julian_adj(tm, off_day, offset_sec, &time_jd, &time_sec)) { + return 0; + } + + /* Convert Julian day back to date */ + + julian_to_date(time_jd, &time_year, &time_month, &time_day); + + if (time_year < 1900 || time_year > 9999) { + return 0; + } + + /* Update tm structure */ + + tm->tm_year = time_year - 1900; + tm->tm_mon = time_month - 1; + tm->tm_mday = time_day; + + tm->tm_hour = time_sec / 3600; + tm->tm_min = (time_sec / 60) % 60; + tm->tm_sec = time_sec % 60; + + return 1; +} + +int OPENSSL_gmtime_diff(int *pday, int *psec, const struct tm *from, + const struct tm *to) { + int from_sec, to_sec, diff_sec; + long from_jd, to_jd, diff_day; + + if (!julian_adj(from, 0, 0, &from_jd, &from_sec)) { + return 0; + } + if (!julian_adj(to, 0, 0, &to_jd, &to_sec)) { + return 0; + } + + diff_day = to_jd - from_jd; + diff_sec = to_sec - from_sec; + /* Adjust differences so both positive or both negative */ + if (diff_day > 0 && diff_sec < 0) { + diff_day--; + diff_sec += SECS_PER_DAY; + } + if (diff_day < 0 && diff_sec > 0) { + diff_day++; + diff_sec -= SECS_PER_DAY; + } + + if (pday) { + *pday = (int)diff_day; + } + if (psec) { + *psec = diff_sec; + } + + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/x509/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/x509/CMakeLists.txt new file mode 100644 index 00000000..456e3069 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/CMakeLists.txt @@ -0,0 +1,57 @@ +include_directories(. .. ../../include) + +add_library( + x509 + + OBJECT + + a_digest.c + a_sign.c + a_strex.c + a_verify.c + asn1_gen.c + by_dir.c + by_file.c + i2d_pr.c + pkcs7.c + t_crl.c + t_req.c + t_x509.c + t_x509a.c + x509.c + x509_att.c + x509_cmp.c + x509_d2.c + x509_def.c + x509_ext.c + x509_lu.c + x509_obj.c + x509_r2x.c + x509_req.c + x509_set.c + x509_trs.c + x509_txt.c + x509_v3.c + x509_vfy.c + x509_vpm.c + x509cset.c + x509name.c + x509rset.c + x509spki.c + x509type.c + x_algor.c + x_all.c + x_attrib.c + x_crl.c + x_exten.c + x_info.c + x_name.c + x_pkey.c + x_pubkey.c + x_req.c + x_sig.c + x_spki.c + x_val.c + x_x509.c + x_x509a.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/x509/a_digest.c b/TMessagesProj/jni/boringssl/crypto/x509/a_digest.c new file mode 100644 index 00000000..430e2e6c --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/a_digest.c @@ -0,0 +1,97 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include +#include + + +int ASN1_digest(i2d_of_void *i2d, const EVP_MD *type, char *data, + unsigned char *md, unsigned int *len) + { + int i, ret; + unsigned char *str,*p; + + i=i2d(data,NULL); + if ((str=(unsigned char *)OPENSSL_malloc(i)) == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return(0); + } + p=str; + i2d(data,&p); + + ret = EVP_Digest(str, i, md, len, type, NULL); + OPENSSL_free(str); + return ret; + } + +int ASN1_item_digest(const ASN1_ITEM *it, const EVP_MD *type, void *asn, + unsigned char *md, unsigned int *len) + { + int i, ret; + unsigned char *str = NULL; + + i=ASN1_item_i2d(asn,&str, it); + if (!str) return(0); + + ret = EVP_Digest(str, i, md, len, type, NULL); + OPENSSL_free(str); + return ret; + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/a_sign.c b/TMessagesProj/jni/boringssl/crypto/x509/a_sign.c new file mode 100644 index 00000000..4e9be8a4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/a_sign.c @@ -0,0 +1,136 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include +#include +#include +#include + +#include "../evp/internal.h" + + +int ASN1_item_sign(const ASN1_ITEM *it, X509_ALGOR *algor1, X509_ALGOR *algor2, + ASN1_BIT_STRING *signature, void *asn, EVP_PKEY *pkey, + const EVP_MD *type) + { + EVP_MD_CTX ctx; + EVP_MD_CTX_init(&ctx); + if (!EVP_DigestSignInit(&ctx, NULL, type, NULL, pkey)) + { + EVP_MD_CTX_cleanup(&ctx); + return 0; + } + return ASN1_item_sign_ctx(it, algor1, algor2, signature, asn, &ctx); + } + + +int ASN1_item_sign_ctx(const ASN1_ITEM *it, + X509_ALGOR *algor1, X509_ALGOR *algor2, + ASN1_BIT_STRING *signature, void *asn, EVP_MD_CTX *ctx) + { + EVP_PKEY *pkey; + unsigned char *buf_in=NULL,*buf_out=NULL; + size_t inl=0,outl=0,outll=0; + + pkey = EVP_PKEY_CTX_get0_pkey(ctx->pctx); + + /* Write out the requested copies of the AlgorithmIdentifier. */ + if (algor1 && !EVP_DigestSignAlgorithm(ctx, algor1)) + { + goto err; + } + if (algor2 && !EVP_DigestSignAlgorithm(ctx, algor2)) + { + goto err; + } + + inl=ASN1_item_i2d(asn,&buf_in, it); + outll=outl=EVP_PKEY_size(pkey); + buf_out=OPENSSL_malloc((unsigned int)outl); + if ((buf_in == NULL) || (buf_out == NULL)) + { + outl=0; + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!EVP_DigestSignUpdate(ctx, buf_in, inl) + || !EVP_DigestSignFinal(ctx, buf_out, &outl)) + { + outl=0; + OPENSSL_PUT_ERROR(X509, ERR_R_EVP_LIB); + goto err; + } + if (signature->data != NULL) OPENSSL_free(signature->data); + signature->data=buf_out; + buf_out=NULL; + signature->length=outl; + /* In the interests of compatibility, I'll make sure that + * the bit string has a 'not-used bits' value of 0 + */ + signature->flags&= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07); + signature->flags|=ASN1_STRING_FLAG_BITS_LEFT; +err: + EVP_MD_CTX_cleanup(ctx); + if (buf_in != NULL) + { OPENSSL_cleanse((char *)buf_in,(unsigned int)inl); OPENSSL_free(buf_in); } + if (buf_out != NULL) + { OPENSSL_cleanse((char *)buf_out,outll); OPENSSL_free(buf_out); } + return(outl); + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/a_strex.c b/TMessagesProj/jni/boringssl/crypto/x509/a_strex.c new file mode 100644 index 00000000..b194d180 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/a_strex.c @@ -0,0 +1,564 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include + +#include "charmap.h" + + +/* ASN1_STRING_print_ex() and X509_NAME_print_ex(). + * Enhanced string and name printing routines handling + * multibyte characters, RFC2253 and a host of other + * options. + */ + + +#define CHARTYPE_BS_ESC (ASN1_STRFLGS_ESC_2253 | CHARTYPE_FIRST_ESC_2253 | CHARTYPE_LAST_ESC_2253) + +#define ESC_FLAGS (ASN1_STRFLGS_ESC_2253 | \ + ASN1_STRFLGS_ESC_QUOTE | \ + ASN1_STRFLGS_ESC_CTRL | \ + ASN1_STRFLGS_ESC_MSB) + + +static int send_bio_chars(void *arg, const void *buf, int len) +{ + if(!arg) return 1; + if(BIO_write(arg, buf, len) != len) return 0; + return 1; +} + +static int send_fp_chars(void *arg, const void *buf, int len) +{ + if(!arg) return 1; + if(fwrite(buf, 1, len, arg) != (unsigned int)len) return 0; + return 1; +} + +typedef int char_io(void *arg, const void *buf, int len); + +/* This function handles display of + * strings, one character at a time. + * It is passed an unsigned long for each + * character because it could come from 2 or even + * 4 byte forms. + */ + +#define HEX_SIZE(type) (sizeof(type)*2) + +static int do_esc_char(unsigned long c, unsigned char flags, char *do_quotes, char_io *io_ch, void *arg) +{ + unsigned char chflgs, chtmp; + char tmphex[HEX_SIZE(long)+3]; + + if(c > 0xffffffffL) + return -1; + if(c > 0xffff) { + BIO_snprintf(tmphex, sizeof tmphex, "\\W%08lX", c); + if(!io_ch(arg, tmphex, 10)) return -1; + return 10; + } + if(c > 0xff) { + BIO_snprintf(tmphex, sizeof tmphex, "\\U%04lX", c); + if(!io_ch(arg, tmphex, 6)) return -1; + return 6; + } + chtmp = (unsigned char)c; + if(chtmp > 0x7f) chflgs = flags & ASN1_STRFLGS_ESC_MSB; + else chflgs = char_type[chtmp] & flags; + if(chflgs & CHARTYPE_BS_ESC) { + /* If we don't escape with quotes, signal we need quotes */ + if(chflgs & ASN1_STRFLGS_ESC_QUOTE) { + if(do_quotes) *do_quotes = 1; + if(!io_ch(arg, &chtmp, 1)) return -1; + return 1; + } + if(!io_ch(arg, "\\", 1)) return -1; + if(!io_ch(arg, &chtmp, 1)) return -1; + return 2; + } + if(chflgs & (ASN1_STRFLGS_ESC_CTRL|ASN1_STRFLGS_ESC_MSB)) { + BIO_snprintf(tmphex, 11, "\\%02X", chtmp); + if(!io_ch(arg, tmphex, 3)) return -1; + return 3; + } + /* If we get this far and do any escaping at all must escape + * the escape character itself: backslash. + */ + if (chtmp == '\\' && flags & ESC_FLAGS) { + if(!io_ch(arg, "\\\\", 2)) return -1; + return 2; + } + if(!io_ch(arg, &chtmp, 1)) return -1; + return 1; +} + +#define BUF_TYPE_WIDTH_MASK 0x7 +#define BUF_TYPE_CONVUTF8 0x8 + +/* This function sends each character in a buffer to + * do_esc_char(). It interprets the content formats + * and converts to or from UTF8 as appropriate. + */ + +static int do_buf(unsigned char *buf, int buflen, + int type, unsigned char flags, char *quotes, char_io *io_ch, void *arg) +{ + int i, outlen, len; + unsigned char orflags, *p, *q; + unsigned long c; + p = buf; + q = buf + buflen; + outlen = 0; + while(p != q) { + if(p == buf && flags & ASN1_STRFLGS_ESC_2253) orflags = CHARTYPE_FIRST_ESC_2253; + else orflags = 0; + switch(type & BUF_TYPE_WIDTH_MASK) { + case 4: + c = ((unsigned long)*p++) << 24; + c |= ((unsigned long)*p++) << 16; + c |= ((unsigned long)*p++) << 8; + c |= *p++; + break; + + case 2: + c = ((unsigned long)*p++) << 8; + c |= *p++; + break; + + case 1: + c = *p++; + break; + + case 0: + i = UTF8_getc(p, buflen, &c); + if(i < 0) return -1; /* Invalid UTF8String */ + p += i; + break; + default: + return -1; /* invalid width */ + } + if (p == q && flags & ASN1_STRFLGS_ESC_2253) orflags = CHARTYPE_LAST_ESC_2253; + if(type & BUF_TYPE_CONVUTF8) { + unsigned char utfbuf[6]; + int utflen; + utflen = UTF8_putc(utfbuf, sizeof utfbuf, c); + for(i = 0; i < utflen; i++) { + /* We don't need to worry about setting orflags correctly + * because if utflen==1 its value will be correct anyway + * otherwise each character will be > 0x7f and so the + * character will never be escaped on first and last. + */ + len = do_esc_char(utfbuf[i], (unsigned char)(flags | orflags), quotes, io_ch, arg); + if(len < 0) return -1; + outlen += len; + } + } else { + len = do_esc_char(c, (unsigned char)(flags | orflags), quotes, io_ch, arg); + if(len < 0) return -1; + outlen += len; + } + } + return outlen; +} + +/* This function hex dumps a buffer of characters */ + +static int do_hex_dump(char_io *io_ch, void *arg, unsigned char *buf, int buflen) +{ + static const char hexdig[] = "0123456789ABCDEF"; + unsigned char *p, *q; + char hextmp[2]; + if(arg) { + p = buf; + q = buf + buflen; + while(p != q) { + hextmp[0] = hexdig[*p >> 4]; + hextmp[1] = hexdig[*p & 0xf]; + if(!io_ch(arg, hextmp, 2)) return -1; + p++; + } + } + return buflen << 1; +} + +/* "dump" a string. This is done when the type is unknown, + * or the flags request it. We can either dump the content + * octets or the entire DER encoding. This uses the RFC2253 + * #01234 format. + */ + +static int do_dump(unsigned long lflags, char_io *io_ch, void *arg, ASN1_STRING *str) +{ + /* Placing the ASN1_STRING in a temp ASN1_TYPE allows + * the DER encoding to readily obtained + */ + ASN1_TYPE t; + unsigned char *der_buf, *p; + int outlen, der_len; + + if(!io_ch(arg, "#", 1)) return -1; + /* If we don't dump DER encoding just dump content octets */ + if(!(lflags & ASN1_STRFLGS_DUMP_DER)) { + outlen = do_hex_dump(io_ch, arg, str->data, str->length); + if(outlen < 0) return -1; + return outlen + 1; + } + t.type = str->type; + t.value.ptr = (char *)str; + der_len = i2d_ASN1_TYPE(&t, NULL); + der_buf = OPENSSL_malloc(der_len); + if(!der_buf) return -1; + p = der_buf; + i2d_ASN1_TYPE(&t, &p); + outlen = do_hex_dump(io_ch, arg, der_buf, der_len); + OPENSSL_free(der_buf); + if(outlen < 0) return -1; + return outlen + 1; +} + +/* Lookup table to convert tags to character widths, + * 0 = UTF8 encoded, -1 is used for non string types + * otherwise it is the number of bytes per character + */ + +static const signed char tag2nbyte[] = { + -1, -1, -1, -1, -1, /* 0-4 */ + -1, -1, -1, -1, -1, /* 5-9 */ + -1, -1, 0, -1, /* 10-13 */ + -1, -1, -1, -1, /* 15-17 */ + -1, 1, 1, /* 18-20 */ + -1, 1, 1, 1, /* 21-24 */ + -1, 1, -1, /* 25-27 */ + 4, -1, 2 /* 28-30 */ +}; + +/* This is the main function, print out an + * ASN1_STRING taking note of various escape + * and display options. Returns number of + * characters written or -1 if an error + * occurred. + */ + +static int do_print_ex(char_io *io_ch, void *arg, unsigned long lflags, ASN1_STRING *str) +{ + int outlen, len; + int type; + char quotes; + unsigned char flags; + quotes = 0; + /* Keep a copy of escape flags */ + flags = (unsigned char)(lflags & ESC_FLAGS); + + type = str->type; + + outlen = 0; + + + if(lflags & ASN1_STRFLGS_SHOW_TYPE) { + const char *tagname; + tagname = ASN1_tag2str(type); + outlen += strlen(tagname); + if(!io_ch(arg, tagname, outlen) || !io_ch(arg, ":", 1)) return -1; + outlen++; + } + + /* Decide what to do with type, either dump content or display it */ + + /* Dump everything */ + if(lflags & ASN1_STRFLGS_DUMP_ALL) type = -1; + /* Ignore the string type */ + else if(lflags & ASN1_STRFLGS_IGNORE_TYPE) type = 1; + else { + /* Else determine width based on type */ + if((type > 0) && (type < 31)) type = tag2nbyte[type]; + else type = -1; + if((type == -1) && !(lflags & ASN1_STRFLGS_DUMP_UNKNOWN)) type = 1; + } + + if(type == -1) { + len = do_dump(lflags, io_ch, arg, str); + if(len < 0) return -1; + outlen += len; + return outlen; + } + + if(lflags & ASN1_STRFLGS_UTF8_CONVERT) { + /* Note: if string is UTF8 and we want + * to convert to UTF8 then we just interpret + * it as 1 byte per character to avoid converting + * twice. + */ + if(!type) type = 1; + else type |= BUF_TYPE_CONVUTF8; + } + + len = do_buf(str->data, str->length, type, flags, "es, io_ch, NULL); + if(len < 0) return -1; + outlen += len; + if(quotes) outlen += 2; + if(!arg) return outlen; + if(quotes && !io_ch(arg, "\"", 1)) return -1; + if(do_buf(str->data, str->length, type, flags, NULL, io_ch, arg) < 0) + return -1; + if(quotes && !io_ch(arg, "\"", 1)) return -1; + return outlen; +} + +/* Used for line indenting: print 'indent' spaces */ + +static int do_indent(char_io *io_ch, void *arg, int indent) +{ + int i; + for(i = 0; i < indent; i++) + if(!io_ch(arg, " ", 1)) return 0; + return 1; +} + +#define FN_WIDTH_LN 25 +#define FN_WIDTH_SN 10 + +static int do_name_ex(char_io *io_ch, void *arg, X509_NAME *n, + int indent, unsigned long flags) +{ + int i, prev = -1, orflags, cnt; + int fn_opt, fn_nid; + ASN1_OBJECT *fn; + ASN1_STRING *val; + X509_NAME_ENTRY *ent; + char objtmp[80]; + const char *objbuf; + int outlen, len; + const char *sep_dn, *sep_mv, *sep_eq; + int sep_dn_len, sep_mv_len, sep_eq_len; + if(indent < 0) indent = 0; + outlen = indent; + if(!do_indent(io_ch, arg, indent)) return -1; + switch (flags & XN_FLAG_SEP_MASK) + { + case XN_FLAG_SEP_MULTILINE: + sep_dn = "\n"; + sep_dn_len = 1; + sep_mv = " + "; + sep_mv_len = 3; + break; + + case XN_FLAG_SEP_COMMA_PLUS: + sep_dn = ","; + sep_dn_len = 1; + sep_mv = "+"; + sep_mv_len = 1; + indent = 0; + break; + + case XN_FLAG_SEP_CPLUS_SPC: + sep_dn = ", "; + sep_dn_len = 2; + sep_mv = " + "; + sep_mv_len = 3; + indent = 0; + break; + + case XN_FLAG_SEP_SPLUS_SPC: + sep_dn = "; "; + sep_dn_len = 2; + sep_mv = " + "; + sep_mv_len = 3; + indent = 0; + break; + + default: + return -1; + } + + if(flags & XN_FLAG_SPC_EQ) { + sep_eq = " = "; + sep_eq_len = 3; + } else { + sep_eq = "="; + sep_eq_len = 1; + } + + fn_opt = flags & XN_FLAG_FN_MASK; + + cnt = X509_NAME_entry_count(n); + for(i = 0; i < cnt; i++) { + if(flags & XN_FLAG_DN_REV) + ent = X509_NAME_get_entry(n, cnt - i - 1); + else ent = X509_NAME_get_entry(n, i); + if(prev != -1) { + if(prev == ent->set) { + if(!io_ch(arg, sep_mv, sep_mv_len)) return -1; + outlen += sep_mv_len; + } else { + if(!io_ch(arg, sep_dn, sep_dn_len)) return -1; + outlen += sep_dn_len; + if(!do_indent(io_ch, arg, indent)) return -1; + outlen += indent; + } + } + prev = ent->set; + fn = X509_NAME_ENTRY_get_object(ent); + val = X509_NAME_ENTRY_get_data(ent); + fn_nid = OBJ_obj2nid(fn); + if(fn_opt != XN_FLAG_FN_NONE) { + int objlen, fld_len; + if((fn_opt == XN_FLAG_FN_OID) || (fn_nid==NID_undef) ) { + OBJ_obj2txt(objtmp, sizeof objtmp, fn, 1); + fld_len = 0; /* XXX: what should this be? */ + objbuf = objtmp; + } else { + if(fn_opt == XN_FLAG_FN_SN) { + fld_len = FN_WIDTH_SN; + objbuf = OBJ_nid2sn(fn_nid); + } else if(fn_opt == XN_FLAG_FN_LN) { + fld_len = FN_WIDTH_LN; + objbuf = OBJ_nid2ln(fn_nid); + } else { + fld_len = 0; /* XXX: what should this be? */ + objbuf = ""; + } + } + objlen = strlen(objbuf); + if(!io_ch(arg, objbuf, objlen)) return -1; + if ((objlen < fld_len) && (flags & XN_FLAG_FN_ALIGN)) { + if (!do_indent(io_ch, arg, fld_len - objlen)) return -1; + outlen += fld_len - objlen; + } + if(!io_ch(arg, sep_eq, sep_eq_len)) return -1; + outlen += objlen + sep_eq_len; + } + /* If the field name is unknown then fix up the DER dump + * flag. We might want to limit this further so it will + * DER dump on anything other than a few 'standard' fields. + */ + if((fn_nid == NID_undef) && (flags & XN_FLAG_DUMP_UNKNOWN_FIELDS)) + orflags = ASN1_STRFLGS_DUMP_ALL; + else orflags = 0; + + len = do_print_ex(io_ch, arg, flags | orflags, val); + if(len < 0) return -1; + outlen += len; + } + return outlen; +} + +/* Wrappers round the main functions */ + +int X509_NAME_print_ex(BIO *out, X509_NAME *nm, int indent, unsigned long flags) +{ + if(flags == XN_FLAG_COMPAT) + return X509_NAME_print(out, nm, indent); + return do_name_ex(send_bio_chars, out, nm, indent, flags); +} + +#ifndef OPENSSL_NO_FP_API +int X509_NAME_print_ex_fp(FILE *fp, X509_NAME *nm, int indent, unsigned long flags) +{ + if(flags == XN_FLAG_COMPAT) + { + BIO *btmp; + int ret; + btmp = BIO_new_fp(fp, BIO_NOCLOSE); + if(!btmp) return -1; + ret = X509_NAME_print(btmp, nm, indent); + BIO_free(btmp); + return ret; + } + return do_name_ex(send_fp_chars, fp, nm, indent, flags); +} +#endif + +int ASN1_STRING_print_ex(BIO *out, ASN1_STRING *str, unsigned long flags) +{ + return do_print_ex(send_bio_chars, out, flags, str); +} + +#ifndef OPENSSL_NO_FP_API +int ASN1_STRING_print_ex_fp(FILE *fp, ASN1_STRING *str, unsigned long flags) +{ + return do_print_ex(send_fp_chars, fp, flags, str); +} +#endif + +/* Utility function: convert any string type to UTF8, returns number of bytes + * in output string or a negative error code + */ + +int ASN1_STRING_to_UTF8(unsigned char **out, ASN1_STRING *in) +{ + ASN1_STRING stmp, *str = &stmp; + int mbflag, type, ret; + if(!in) return -1; + type = in->type; + if((type < 0) || (type > 30)) return -1; + mbflag = tag2nbyte[type]; + if(mbflag == -1) return -1; + mbflag |= MBSTRING_FLAG; + stmp.data = NULL; + stmp.length = 0; + stmp.flags = 0; + ret = ASN1_mbstring_copy(&str, in->data, in->length, mbflag, B_ASN1_UTF8STRING); + if(ret < 0) return ret; + *out = stmp.data; + return stmp.length; +} diff --git a/TMessagesProj/jni/boringssl/crypto/x509/a_verify.c b/TMessagesProj/jni/boringssl/crypto/x509/a_verify.c new file mode 100644 index 00000000..572a1392 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/a_verify.c @@ -0,0 +1,133 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../evp/internal.h" + + +int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a, + ASN1_BIT_STRING *signature, void *asn, EVP_PKEY *pkey) + { + EVP_MD_CTX ctx; + uint8_t *buf_in = NULL; + int ret = 0, inl; + + if (!pkey) + { + OPENSSL_PUT_ERROR(X509, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + if (signature->type == V_ASN1_BIT_STRING && signature->flags & 0x7) + { + OPENSSL_PUT_ERROR(X509, X509_R_INVALID_BIT_STRING_BITS_LEFT); + return 0; + } + + EVP_MD_CTX_init(&ctx); + + if (!EVP_DigestVerifyInitFromAlgorithm(&ctx, a, pkey)) + { + goto err; + } + + inl = ASN1_item_i2d(asn, &buf_in, it); + + if (buf_in == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!EVP_DigestVerifyUpdate(&ctx,buf_in,inl)) + { + OPENSSL_cleanse(buf_in,(unsigned int)inl); + OPENSSL_free(buf_in); + OPENSSL_PUT_ERROR(X509, ERR_R_EVP_LIB); + goto err; + } + + OPENSSL_cleanse(buf_in,(unsigned int)inl); + OPENSSL_free(buf_in); + + if (EVP_DigestVerifyFinal(&ctx,signature->data, + (size_t)signature->length) <= 0) + { + OPENSSL_PUT_ERROR(X509, ERR_R_EVP_LIB); + goto err; + } + /* we don't need to zero the 'ctx' because we just checked + * public information */ + /* memset(&ctx,0,sizeof(ctx)); */ + ret = 1; +err: + EVP_MD_CTX_cleanup(&ctx); + return ret; + } + diff --git a/TMessagesProj/jni/boringssl/crypto/x509/asn1_gen.c b/TMessagesProj/jni/boringssl/crypto/x509/asn1_gen.c new file mode 100644 index 00000000..850a8167 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/asn1_gen.c @@ -0,0 +1,873 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include +#include +#include + +#include "../internal.h" + + +/* Although this file is in crypto/x509 for layering purposes, it emits errors + * from the ASN.1 module for OpenSSL compatibility. */ + +#define ASN1_GEN_FLAG 0x10000 +#define ASN1_GEN_FLAG_IMP (ASN1_GEN_FLAG|1) +#define ASN1_GEN_FLAG_EXP (ASN1_GEN_FLAG|2) +#define ASN1_GEN_FLAG_TAG (ASN1_GEN_FLAG|3) +#define ASN1_GEN_FLAG_BITWRAP (ASN1_GEN_FLAG|4) +#define ASN1_GEN_FLAG_OCTWRAP (ASN1_GEN_FLAG|5) +#define ASN1_GEN_FLAG_SEQWRAP (ASN1_GEN_FLAG|6) +#define ASN1_GEN_FLAG_SETWRAP (ASN1_GEN_FLAG|7) +#define ASN1_GEN_FLAG_FORMAT (ASN1_GEN_FLAG|8) + +#define ASN1_GEN_STR(str,val) {str, sizeof(str) - 1, val} + +#define ASN1_FLAG_EXP_MAX 20 + +/* Input formats */ + +/* ASCII: default */ +#define ASN1_GEN_FORMAT_ASCII 1 +/* UTF8 */ +#define ASN1_GEN_FORMAT_UTF8 2 +/* Hex */ +#define ASN1_GEN_FORMAT_HEX 3 +/* List of bits */ +#define ASN1_GEN_FORMAT_BITLIST 4 + + +struct tag_name_st + { + const char *strnam; + int len; + int tag; + }; + +typedef struct + { + int exp_tag; + int exp_class; + int exp_constructed; + int exp_pad; + long exp_len; + } tag_exp_type; + +typedef struct + { + int imp_tag; + int imp_class; + int utype; + int format; + const char *str; + tag_exp_type exp_list[ASN1_FLAG_EXP_MAX]; + int exp_count; + } tag_exp_arg; + +static int bitstr_cb(const char *elem, int len, void *bitstr); +static int asn1_cb(const char *elem, int len, void *bitstr); +static int append_exp(tag_exp_arg *arg, int exp_tag, int exp_class, int exp_constructed, int exp_pad, int imp_ok); +static int parse_tagging(const char *vstart, int vlen, int *ptag, int *pclass); +static ASN1_TYPE *asn1_multi(int utype, const char *section, X509V3_CTX *cnf); +static ASN1_TYPE *asn1_str2type(const char *str, int format, int utype); +static int asn1_str2tag(const char *tagstr, int len); + +ASN1_TYPE *ASN1_generate_nconf(char *str, CONF *nconf) + { + X509V3_CTX cnf; + + if (!nconf) + return ASN1_generate_v3(str, NULL); + + X509V3_set_nconf(&cnf, nconf); + return ASN1_generate_v3(str, &cnf); + } + +ASN1_TYPE *ASN1_generate_v3(char *str, X509V3_CTX *cnf) + OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS + { + ASN1_TYPE *ret; + tag_exp_arg asn1_tags; + tag_exp_type *etmp; + + int i, len; + + unsigned char *orig_der = NULL, *new_der = NULL; + const unsigned char *cpy_start; + unsigned char *p; + const unsigned char *cp; + int cpy_len; + long hdr_len; + int hdr_constructed = 0, hdr_tag, hdr_class; + int r; + + asn1_tags.imp_tag = -1; + asn1_tags.imp_class = -1; + asn1_tags.format = ASN1_GEN_FORMAT_ASCII; + asn1_tags.exp_count = 0; + if (CONF_parse_list(str, ',', 1, asn1_cb, &asn1_tags) != 0) + return NULL; + + if ((asn1_tags.utype == V_ASN1_SEQUENCE) || (asn1_tags.utype == V_ASN1_SET)) + { + if (!cnf) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG); + return NULL; + } + ret = asn1_multi(asn1_tags.utype, asn1_tags.str, cnf); + } + else + ret = asn1_str2type(asn1_tags.str, asn1_tags.format, asn1_tags.utype); + + if (!ret) + return NULL; + + /* If no tagging return base type */ + if ((asn1_tags.imp_tag == -1) && (asn1_tags.exp_count == 0)) + return ret; + + /* Generate the encoding */ + cpy_len = i2d_ASN1_TYPE(ret, &orig_der); + ASN1_TYPE_free(ret); + ret = NULL; + /* Set point to start copying for modified encoding */ + cpy_start = orig_der; + + /* Do we need IMPLICIT tagging? */ + if (asn1_tags.imp_tag != -1) + { + /* If IMPLICIT we will replace the underlying tag */ + /* Skip existing tag+len */ + r = ASN1_get_object(&cpy_start, &hdr_len, &hdr_tag, &hdr_class, cpy_len); + if (r & 0x80) + goto err; + /* Update copy length */ + cpy_len -= cpy_start - orig_der; + /* For IMPLICIT tagging the length should match the + * original length and constructed flag should be + * consistent. + */ + if (r & 0x1) + { + /* Indefinite length constructed */ + hdr_constructed = 2; + hdr_len = 0; + } + else + /* Just retain constructed flag */ + hdr_constructed = r & V_ASN1_CONSTRUCTED; + /* Work out new length with IMPLICIT tag: ignore constructed + * because it will mess up if indefinite length + */ + len = ASN1_object_size(0, hdr_len, asn1_tags.imp_tag); + } + else + len = cpy_len; + + /* Work out length in any EXPLICIT, starting from end */ + + for(i = 0, etmp = asn1_tags.exp_list + asn1_tags.exp_count - 1; i < asn1_tags.exp_count; i++, etmp--) + { + /* Content length: number of content octets + any padding */ + len += etmp->exp_pad; + etmp->exp_len = len; + /* Total object length: length including new header */ + len = ASN1_object_size(0, len, etmp->exp_tag); + } + + /* Allocate buffer for new encoding */ + + new_der = OPENSSL_malloc(len); + if (!new_der) + goto err; + + /* Generate tagged encoding */ + + p = new_der; + + /* Output explicit tags first */ + + for (i = 0, etmp = asn1_tags.exp_list; i < asn1_tags.exp_count; i++, etmp++) + { + ASN1_put_object(&p, etmp->exp_constructed, etmp->exp_len, + etmp->exp_tag, etmp->exp_class); + if (etmp->exp_pad) + *p++ = 0; + } + + /* If IMPLICIT, output tag */ + + if (asn1_tags.imp_tag != -1) + { + if (asn1_tags.imp_class == V_ASN1_UNIVERSAL + && (asn1_tags.imp_tag == V_ASN1_SEQUENCE + || asn1_tags.imp_tag == V_ASN1_SET) ) + hdr_constructed = V_ASN1_CONSTRUCTED; + ASN1_put_object(&p, hdr_constructed, hdr_len, + asn1_tags.imp_tag, asn1_tags.imp_class); + } + + /* Copy across original encoding */ + memcpy(p, cpy_start, cpy_len); + + cp = new_der; + + /* Obtain new ASN1_TYPE structure */ + ret = d2i_ASN1_TYPE(NULL, &cp, len); + + err: + if (orig_der) + OPENSSL_free(orig_der); + if (new_der) + OPENSSL_free(new_der); + + return ret; + + } + +static int asn1_cb(const char *elem, int len, void *bitstr) + { + tag_exp_arg *arg = bitstr; + int i; + int utype; + int vlen = 0; + const char *p, *vstart = NULL; + + int tmp_tag, tmp_class; + + if (elem == NULL) + return 0; + + for(i = 0, p = elem; i < len; p++, i++) + { + /* Look for the ':' in name value pairs */ + if (*p == ':') + { + vstart = p + 1; + vlen = len - (vstart - elem); + len = p - elem; + break; + } + } + + utype = asn1_str2tag(elem, len); + + if (utype == -1) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNKNOWN_TAG); + ERR_add_error_data(2, "tag=", elem); + return -1; + } + + /* If this is not a modifier mark end of string and exit */ + if (!(utype & ASN1_GEN_FLAG)) + { + arg->utype = utype; + arg->str = vstart; + /* If no value and not end of string, error */ + if (!vstart && elem[len]) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_VALUE); + return -1; + } + return 0; + } + + switch(utype) + { + + case ASN1_GEN_FLAG_IMP: + /* Check for illegal multiple IMPLICIT tagging */ + if (arg->imp_tag != -1) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_NESTED_TAGGING); + return -1; + } + if (!parse_tagging(vstart, vlen, &arg->imp_tag, &arg->imp_class)) + return -1; + break; + + case ASN1_GEN_FLAG_EXP: + + if (!parse_tagging(vstart, vlen, &tmp_tag, &tmp_class)) + return -1; + if (!append_exp(arg, tmp_tag, tmp_class, 1, 0, 0)) + return -1; + break; + + case ASN1_GEN_FLAG_SEQWRAP: + if (!append_exp(arg, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL, 1, 0, 1)) + return -1; + break; + + case ASN1_GEN_FLAG_SETWRAP: + if (!append_exp(arg, V_ASN1_SET, V_ASN1_UNIVERSAL, 1, 0, 1)) + return -1; + break; + + case ASN1_GEN_FLAG_BITWRAP: + if (!append_exp(arg, V_ASN1_BIT_STRING, V_ASN1_UNIVERSAL, 0, 1, 1)) + return -1; + break; + + case ASN1_GEN_FLAG_OCTWRAP: + if (!append_exp(arg, V_ASN1_OCTET_STRING, V_ASN1_UNIVERSAL, 0, 0, 1)) + return -1; + break; + + case ASN1_GEN_FLAG_FORMAT: + if (!vstart) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNKNOWN_FORMAT); + return -1; + } + if (!strncmp(vstart, "ASCII", 5)) + arg->format = ASN1_GEN_FORMAT_ASCII; + else if (!strncmp(vstart, "UTF8", 4)) + arg->format = ASN1_GEN_FORMAT_UTF8; + else if (!strncmp(vstart, "HEX", 3)) + arg->format = ASN1_GEN_FORMAT_HEX; + else if (!strncmp(vstart, "BITLIST", 7)) + arg->format = ASN1_GEN_FORMAT_BITLIST; + else + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNKNOWN_FORMAT); + return -1; + } + break; + + } + + return 1; + + } + +static int parse_tagging(const char *vstart, int vlen, int *ptag, int *pclass) + { + char erch[2]; + long tag_num; + char *eptr; + if (!vstart) + return 0; + tag_num = strtoul(vstart, &eptr, 10); + /* Check we haven't gone past max length: should be impossible */ + if (eptr && *eptr && (eptr > vstart + vlen)) + return 0; + if (tag_num < 0) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_NUMBER); + return 0; + } + *ptag = tag_num; + /* If we have non numeric characters, parse them */ + if (eptr) + vlen -= eptr - vstart; + else + vlen = 0; + if (vlen) + { + switch (*eptr) + { + + case 'U': + *pclass = V_ASN1_UNIVERSAL; + break; + + case 'A': + *pclass = V_ASN1_APPLICATION; + break; + + case 'P': + *pclass = V_ASN1_PRIVATE; + break; + + case 'C': + *pclass = V_ASN1_CONTEXT_SPECIFIC; + break; + + default: + erch[0] = *eptr; + erch[1] = 0; + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_MODIFIER); + ERR_add_error_data(2, "Char=", erch); + return 0; + break; + + } + } + else + *pclass = V_ASN1_CONTEXT_SPECIFIC; + + return 1; + + } + +/* Handle multiple types: SET and SEQUENCE */ + +static ASN1_TYPE *asn1_multi(int utype, const char *section, X509V3_CTX *cnf) + { + ASN1_TYPE *ret = NULL; + STACK_OF(ASN1_TYPE) *sk = NULL; + STACK_OF(CONF_VALUE) *sect = NULL; + unsigned char *der = NULL; + int derlen; + size_t i; + sk = sk_ASN1_TYPE_new_null(); + if (!sk) + goto bad; + if (section) + { + if (!cnf) + goto bad; + sect = X509V3_get_section(cnf, (char *)section); + if (!sect) + goto bad; + for (i = 0; i < sk_CONF_VALUE_num(sect); i++) + { + ASN1_TYPE *typ = ASN1_generate_v3(sk_CONF_VALUE_value(sect, i)->value, cnf); + if (!typ) + goto bad; + if (!sk_ASN1_TYPE_push(sk, typ)) + goto bad; + } + } + + /* Now we has a STACK of the components, convert to the correct form */ + + if (utype == V_ASN1_SET) + derlen = i2d_ASN1_SET_ANY(sk, &der); + else + derlen = i2d_ASN1_SEQUENCE_ANY(sk, &der); + + if (derlen < 0) + goto bad; + + if (!(ret = ASN1_TYPE_new())) + goto bad; + + if (!(ret->value.asn1_string = ASN1_STRING_type_new(utype))) + goto bad; + + ret->type = utype; + + ret->value.asn1_string->data = der; + ret->value.asn1_string->length = derlen; + + der = NULL; + + bad: + + if (der) + OPENSSL_free(der); + + if (sk) + sk_ASN1_TYPE_pop_free(sk, ASN1_TYPE_free); + if (sect) + X509V3_section_free(cnf, sect); + + return ret; + } + +static int append_exp(tag_exp_arg *arg, int exp_tag, int exp_class, int exp_constructed, int exp_pad, int imp_ok) + { + tag_exp_type *exp_tmp; + /* Can only have IMPLICIT if permitted */ + if ((arg->imp_tag != -1) && !imp_ok) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_IMPLICIT_TAG); + return 0; + } + + if (arg->exp_count == ASN1_FLAG_EXP_MAX) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_DEPTH_EXCEEDED); + return 0; + } + + exp_tmp = &arg->exp_list[arg->exp_count++]; + + /* If IMPLICIT set tag to implicit value then + * reset implicit tag since it has been used. + */ + if (arg->imp_tag != -1) + { + exp_tmp->exp_tag = arg->imp_tag; + exp_tmp->exp_class = arg->imp_class; + arg->imp_tag = -1; + arg->imp_class = -1; + } + else + { + exp_tmp->exp_tag = exp_tag; + exp_tmp->exp_class = exp_class; + } + exp_tmp->exp_constructed = exp_constructed; + exp_tmp->exp_pad = exp_pad; + + return 1; + } + + +static int asn1_str2tag(const char *tagstr, int len) + { + unsigned int i; + static const struct tag_name_st *tntmp, tnst [] = { + ASN1_GEN_STR("BOOL", V_ASN1_BOOLEAN), + ASN1_GEN_STR("BOOLEAN", V_ASN1_BOOLEAN), + ASN1_GEN_STR("NULL", V_ASN1_NULL), + ASN1_GEN_STR("INT", V_ASN1_INTEGER), + ASN1_GEN_STR("INTEGER", V_ASN1_INTEGER), + ASN1_GEN_STR("ENUM", V_ASN1_ENUMERATED), + ASN1_GEN_STR("ENUMERATED", V_ASN1_ENUMERATED), + ASN1_GEN_STR("OID", V_ASN1_OBJECT), + ASN1_GEN_STR("OBJECT", V_ASN1_OBJECT), + ASN1_GEN_STR("UTCTIME", V_ASN1_UTCTIME), + ASN1_GEN_STR("UTC", V_ASN1_UTCTIME), + ASN1_GEN_STR("GENERALIZEDTIME", V_ASN1_GENERALIZEDTIME), + ASN1_GEN_STR("GENTIME", V_ASN1_GENERALIZEDTIME), + ASN1_GEN_STR("OCT", V_ASN1_OCTET_STRING), + ASN1_GEN_STR("OCTETSTRING", V_ASN1_OCTET_STRING), + ASN1_GEN_STR("BITSTR", V_ASN1_BIT_STRING), + ASN1_GEN_STR("BITSTRING", V_ASN1_BIT_STRING), + ASN1_GEN_STR("UNIVERSALSTRING", V_ASN1_UNIVERSALSTRING), + ASN1_GEN_STR("UNIV", V_ASN1_UNIVERSALSTRING), + ASN1_GEN_STR("IA5", V_ASN1_IA5STRING), + ASN1_GEN_STR("IA5STRING", V_ASN1_IA5STRING), + ASN1_GEN_STR("UTF8", V_ASN1_UTF8STRING), + ASN1_GEN_STR("UTF8String", V_ASN1_UTF8STRING), + ASN1_GEN_STR("BMP", V_ASN1_BMPSTRING), + ASN1_GEN_STR("BMPSTRING", V_ASN1_BMPSTRING), + ASN1_GEN_STR("VISIBLESTRING", V_ASN1_VISIBLESTRING), + ASN1_GEN_STR("VISIBLE", V_ASN1_VISIBLESTRING), + ASN1_GEN_STR("PRINTABLESTRING", V_ASN1_PRINTABLESTRING), + ASN1_GEN_STR("PRINTABLE", V_ASN1_PRINTABLESTRING), + ASN1_GEN_STR("T61", V_ASN1_T61STRING), + ASN1_GEN_STR("T61STRING", V_ASN1_T61STRING), + ASN1_GEN_STR("TELETEXSTRING", V_ASN1_T61STRING), + ASN1_GEN_STR("GeneralString", V_ASN1_GENERALSTRING), + ASN1_GEN_STR("GENSTR", V_ASN1_GENERALSTRING), + ASN1_GEN_STR("NUMERIC", V_ASN1_NUMERICSTRING), + ASN1_GEN_STR("NUMERICSTRING", V_ASN1_NUMERICSTRING), + + /* Special cases */ + ASN1_GEN_STR("SEQUENCE", V_ASN1_SEQUENCE), + ASN1_GEN_STR("SEQ", V_ASN1_SEQUENCE), + ASN1_GEN_STR("SET", V_ASN1_SET), + /* type modifiers */ + /* Explicit tag */ + ASN1_GEN_STR("EXP", ASN1_GEN_FLAG_EXP), + ASN1_GEN_STR("EXPLICIT", ASN1_GEN_FLAG_EXP), + /* Implicit tag */ + ASN1_GEN_STR("IMP", ASN1_GEN_FLAG_IMP), + ASN1_GEN_STR("IMPLICIT", ASN1_GEN_FLAG_IMP), + /* OCTET STRING wrapper */ + ASN1_GEN_STR("OCTWRAP", ASN1_GEN_FLAG_OCTWRAP), + /* SEQUENCE wrapper */ + ASN1_GEN_STR("SEQWRAP", ASN1_GEN_FLAG_SEQWRAP), + /* SET wrapper */ + ASN1_GEN_STR("SETWRAP", ASN1_GEN_FLAG_SETWRAP), + /* BIT STRING wrapper */ + ASN1_GEN_STR("BITWRAP", ASN1_GEN_FLAG_BITWRAP), + ASN1_GEN_STR("FORM", ASN1_GEN_FLAG_FORMAT), + ASN1_GEN_STR("FORMAT", ASN1_GEN_FLAG_FORMAT), + }; + + if (len == -1) + len = strlen(tagstr); + + tntmp = tnst; + for (i = 0; i < sizeof(tnst) / sizeof(struct tag_name_st); i++, tntmp++) + { + if ((len == tntmp->len) && !strncmp(tntmp->strnam, tagstr, len)) + return tntmp->tag; + } + + return -1; + } + +static ASN1_TYPE *asn1_str2type(const char *str, int format, int utype) + { + ASN1_TYPE *atmp = NULL; + + CONF_VALUE vtmp; + + unsigned char *rdata; + long rdlen; + + int no_unused = 1; + + if (!(atmp = ASN1_TYPE_new())) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return NULL; + } + + if (!str) + str = ""; + + switch(utype) + { + + case V_ASN1_NULL: + if (str && *str) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_NULL_VALUE); + goto bad_form; + } + break; + + case V_ASN1_BOOLEAN: + if (format != ASN1_GEN_FORMAT_ASCII) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NOT_ASCII_FORMAT); + goto bad_form; + } + vtmp.name = NULL; + vtmp.section = NULL; + vtmp.value = (char *)str; + if (!X509V3_get_value_bool(&vtmp, &atmp->value.boolean)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_BOOLEAN); + goto bad_str; + } + break; + + case V_ASN1_INTEGER: + case V_ASN1_ENUMERATED: + if (format != ASN1_GEN_FORMAT_ASCII) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INTEGER_NOT_ASCII_FORMAT); + goto bad_form; + } + if (!(atmp->value.integer = s2i_ASN1_INTEGER(NULL, (char *)str))) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_INTEGER); + goto bad_str; + } + break; + + case V_ASN1_OBJECT: + if (format != ASN1_GEN_FORMAT_ASCII) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_OBJECT_NOT_ASCII_FORMAT); + goto bad_form; + } + if (!(atmp->value.object = OBJ_txt2obj(str, 0))) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_OBJECT); + goto bad_str; + } + break; + + case V_ASN1_UTCTIME: + case V_ASN1_GENERALIZEDTIME: + if (format != ASN1_GEN_FORMAT_ASCII) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_TIME_NOT_ASCII_FORMAT); + goto bad_form; + } + if (!(atmp->value.asn1_string = ASN1_STRING_new())) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto bad_str; + } + if (!ASN1_STRING_set(atmp->value.asn1_string, str, -1)) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto bad_str; + } + atmp->value.asn1_string->type = utype; + if (!ASN1_TIME_check(atmp->value.asn1_string)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_TIME_VALUE); + goto bad_str; + } + + break; + + case V_ASN1_BMPSTRING: + case V_ASN1_PRINTABLESTRING: + case V_ASN1_IA5STRING: + case V_ASN1_T61STRING: + case V_ASN1_UTF8STRING: + case V_ASN1_VISIBLESTRING: + case V_ASN1_UNIVERSALSTRING: + case V_ASN1_GENERALSTRING: + case V_ASN1_NUMERICSTRING: + + if (format == ASN1_GEN_FORMAT_ASCII) + format = MBSTRING_ASC; + else if (format == ASN1_GEN_FORMAT_UTF8) + format = MBSTRING_UTF8; + else + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_FORMAT); + goto bad_form; + } + + + if (ASN1_mbstring_copy(&atmp->value.asn1_string, (unsigned char *)str, + -1, format, ASN1_tag2bit(utype)) <= 0) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto bad_str; + } + + + break; + + case V_ASN1_BIT_STRING: + + case V_ASN1_OCTET_STRING: + + if (!(atmp->value.asn1_string = ASN1_STRING_new())) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto bad_form; + } + + if (format == ASN1_GEN_FORMAT_HEX) + { + + if (!(rdata = string_to_hex((char *)str, &rdlen))) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_HEX); + goto bad_str; + } + + atmp->value.asn1_string->data = rdata; + atmp->value.asn1_string->length = rdlen; + atmp->value.asn1_string->type = utype; + + } + else if (format == ASN1_GEN_FORMAT_ASCII) + ASN1_STRING_set(atmp->value.asn1_string, str, -1); + else if ((format == ASN1_GEN_FORMAT_BITLIST) && (utype == V_ASN1_BIT_STRING)) + { + if (!CONF_parse_list(str, ',', 1, bitstr_cb, atmp->value.bit_string)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_LIST_ERROR); + goto bad_str; + } + no_unused = 0; + + } + else + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_BITSTRING_FORMAT); + goto bad_form; + } + + if ((utype == V_ASN1_BIT_STRING) && no_unused) + { + atmp->value.asn1_string->flags + &= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07); + atmp->value.asn1_string->flags + |= ASN1_STRING_FLAG_BITS_LEFT; + } + + + break; + + default: + OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNSUPPORTED_TYPE); + goto bad_str; + break; + } + + + atmp->type = utype; + return atmp; + + + bad_str: + ERR_add_error_data(2, "string=", str); + bad_form: + + ASN1_TYPE_free(atmp); + return NULL; + + } + +static int bitstr_cb(const char *elem, int len, void *bitstr) + { + long bitnum; + char *eptr; + if (!elem) + return 0; + bitnum = strtoul(elem, &eptr, 10); + if (eptr && *eptr && (eptr != elem + len)) + return 0; + if (bitnum < 0) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_NUMBER); + return 0; + } + if (!ASN1_BIT_STRING_set_bit(bitstr, bitnum, 1)) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return 0; + } + return 1; + } + diff --git a/TMessagesProj/jni/boringssl/crypto/x509/by_dir.c b/TMessagesProj/jni/boringssl/crypto/x509/by_dir.c new file mode 100644 index 00000000..3393dfa4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/by_dir.c @@ -0,0 +1,491 @@ +/* crypto/x509/by_dir.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../internal.h" + + +typedef struct lookup_dir_hashes_st + { + unsigned long hash; + int suffix; + } BY_DIR_HASH; + +typedef struct lookup_dir_entry_st + { + char *dir; + int dir_type; + STACK_OF(BY_DIR_HASH) *hashes; + } BY_DIR_ENTRY; + +typedef struct lookup_dir_st + { + BUF_MEM *buffer; + STACK_OF(BY_DIR_ENTRY) *dirs; + } BY_DIR; + +DECLARE_STACK_OF(BY_DIR_HASH) +DECLARE_STACK_OF(BY_DIR_ENTRY) + +static int dir_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, long argl, + char **ret); +static int new_dir(X509_LOOKUP *lu); +static void free_dir(X509_LOOKUP *lu); +static int add_cert_dir(BY_DIR *ctx,const char *dir,int type); +static int get_cert_by_subject(X509_LOOKUP *xl,int type,X509_NAME *name, + X509_OBJECT *ret); +X509_LOOKUP_METHOD x509_dir_lookup= + { + "Load certs from files in a directory", + new_dir, /* new */ + free_dir, /* free */ + NULL, /* init */ + NULL, /* shutdown */ + dir_ctrl, /* ctrl */ + get_cert_by_subject, /* get_by_subject */ + NULL, /* get_by_issuer_serial */ + NULL, /* get_by_fingerprint */ + NULL, /* get_by_alias */ + }; + +X509_LOOKUP_METHOD *X509_LOOKUP_hash_dir(void) + { + return(&x509_dir_lookup); + } + +static int dir_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, long argl, + char **retp) + { + int ret=0; + BY_DIR *ld; + char *dir = NULL; + + ld=(BY_DIR *)ctx->method_data; + + switch (cmd) + { + case X509_L_ADD_DIR: + if (argl == X509_FILETYPE_DEFAULT) + { + dir=(char *)getenv(X509_get_default_cert_dir_env()); + if (dir) + ret=add_cert_dir(ld,dir,X509_FILETYPE_PEM); + else + ret=add_cert_dir(ld,X509_get_default_cert_dir(), + X509_FILETYPE_PEM); + if (!ret) + { + OPENSSL_PUT_ERROR(X509, X509_R_LOADING_CERT_DIR); + } + } + else + ret=add_cert_dir(ld,argp,(int)argl); + break; + } + return(ret); + } + +static int new_dir(X509_LOOKUP *lu) + { + BY_DIR *a; + + if ((a=(BY_DIR *)OPENSSL_malloc(sizeof(BY_DIR))) == NULL) + return(0); + if ((a->buffer=BUF_MEM_new()) == NULL) + { + OPENSSL_free(a); + return(0); + } + a->dirs=NULL; + lu->method_data=(char *)a; + return(1); + } + +static void by_dir_hash_free(BY_DIR_HASH *hash) + { + OPENSSL_free(hash); + } + +static int by_dir_hash_cmp(const BY_DIR_HASH **a, + const BY_DIR_HASH **b) + { + if ((*a)->hash > (*b)->hash) + return 1; + if ((*a)->hash < (*b)->hash) + return -1; + return 0; + } + +static void by_dir_entry_free(BY_DIR_ENTRY *ent) + { + if (ent->dir) + OPENSSL_free(ent->dir); + if (ent->hashes) + sk_BY_DIR_HASH_pop_free(ent->hashes, by_dir_hash_free); + OPENSSL_free(ent); + } + +static void free_dir(X509_LOOKUP *lu) + { + BY_DIR *a; + + a=(BY_DIR *)lu->method_data; + if (a->dirs != NULL) + sk_BY_DIR_ENTRY_pop_free(a->dirs, by_dir_entry_free); + if (a->buffer != NULL) + BUF_MEM_free(a->buffer); + OPENSSL_free(a); + } + +static int add_cert_dir(BY_DIR *ctx, const char *dir, int type) + { + size_t j,len; + const char *s,*ss,*p; + + if (dir == NULL || !*dir) + { + OPENSSL_PUT_ERROR(X509, X509_R_INVALID_DIRECTORY); + return 0; + } + + s=dir; + p=s; + do + { + if ((*p == ':') || (*p == '\0')) + { + BY_DIR_ENTRY *ent; + ss=s; + s=p+1; + len=p-ss; + if (len == 0) continue; + for (j=0; j < sk_BY_DIR_ENTRY_num(ctx->dirs); j++) + { + ent = sk_BY_DIR_ENTRY_value(ctx->dirs, j); + if (strlen(ent->dir) == len && + strncmp(ent->dir,ss,len) == 0) + break; + } + if (j < sk_BY_DIR_ENTRY_num(ctx->dirs)) + continue; + if (ctx->dirs == NULL) + { + ctx->dirs = sk_BY_DIR_ENTRY_new_null(); + if (!ctx->dirs) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return 0; + } + } + ent = OPENSSL_malloc(sizeof(BY_DIR_ENTRY)); + if (!ent) + return 0; + ent->dir_type = type; + ent->hashes = sk_BY_DIR_HASH_new(by_dir_hash_cmp); + ent->dir = OPENSSL_malloc(len+1); + if (!ent->dir || !ent->hashes) + { + by_dir_entry_free(ent); + return 0; + } + strncpy(ent->dir,ss,len); + ent->dir[len] = '\0'; + if (!sk_BY_DIR_ENTRY_push(ctx->dirs, ent)) + { + by_dir_entry_free(ent); + return 0; + } + } + } while (*p++ != '\0'); + return 1; + } + +/* g_ent_hashes_lock protects the |hashes| member of all |BY_DIR_ENTRY| + * objects. */ +static struct CRYPTO_STATIC_MUTEX g_ent_hashes_lock = CRYPTO_STATIC_MUTEX_INIT; + +static int get_cert_by_subject(X509_LOOKUP *xl, int type, X509_NAME *name, + X509_OBJECT *ret) + { + BY_DIR *ctx; + union { + struct { + X509 st_x509; + X509_CINF st_x509_cinf; + } x509; + struct { + X509_CRL st_crl; + X509_CRL_INFO st_crl_info; + } crl; + } data; + int ok=0; + size_t i; + int j,k; + unsigned long h; + unsigned long hash_array[2]; + int hash_index; + BUF_MEM *b=NULL; + X509_OBJECT stmp,*tmp; + const char *postfix=""; + + if (name == NULL) return(0); + + stmp.type=type; + if (type == X509_LU_X509) + { + data.x509.st_x509.cert_info= &data.x509.st_x509_cinf; + data.x509.st_x509_cinf.subject=name; + stmp.data.x509= &data.x509.st_x509; + postfix=""; + } + else if (type == X509_LU_CRL) + { + data.crl.st_crl.crl= &data.crl.st_crl_info; + data.crl.st_crl_info.issuer=name; + stmp.data.crl= &data.crl.st_crl; + postfix="r"; + } + else + { + OPENSSL_PUT_ERROR(X509, X509_R_WRONG_LOOKUP_TYPE); + goto finish; + } + + if ((b=BUF_MEM_new()) == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_BUF_LIB); + goto finish; + } + + ctx=(BY_DIR *)xl->method_data; + + hash_array[0]=X509_NAME_hash(name); + hash_array[1]=X509_NAME_hash_old(name); + for (hash_index=0; hash_index < 2; ++hash_index) + { + h=hash_array[hash_index]; + for (i=0; i < sk_BY_DIR_ENTRY_num(ctx->dirs); i++) + { + BY_DIR_ENTRY *ent; + size_t idx; + BY_DIR_HASH htmp, *hent; + ent = sk_BY_DIR_ENTRY_value(ctx->dirs, i); + j=strlen(ent->dir)+1+8+6+1+1; + if (!BUF_MEM_grow(b,j)) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + goto finish; + } + if (type == X509_LU_CRL && ent->hashes) + { + htmp.hash = h; + CRYPTO_STATIC_MUTEX_lock_read(&g_ent_hashes_lock); + if (sk_BY_DIR_HASH_find(ent->hashes, &idx, &htmp)) + { + hent = sk_BY_DIR_HASH_value(ent->hashes, idx); + k = hent->suffix; + } + else + { + hent = NULL; + k=0; + } + CRYPTO_STATIC_MUTEX_unlock(&g_ent_hashes_lock); + } + else + { + k = 0; + hent = NULL; + } + for (;;) + { + char c = '/'; +#ifdef OPENSSL_SYS_VMS + c = ent->dir[strlen(ent->dir)-1]; + if (c != ':' && c != '>' && c != ']') + { + /* If no separator is present, we assume the + directory specifier is a logical name, and + add a colon. We really should use better + VMS routines for merging things like this, + but this will do for now... + -- Richard Levitte */ + c = ':'; + } + else + { + c = '\0'; + } +#endif + if (c == '\0') + { + /* This is special. When c == '\0', no + directory separator should be added. */ + BIO_snprintf(b->data,b->max, + "%s%08lx.%s%d",ent->dir,h, + postfix,k); + } + else + { + BIO_snprintf(b->data,b->max, + "%s%c%08lx.%s%d",ent->dir,c,h, + postfix,k); + } +#ifndef OPENSSL_NO_POSIX_IO +#ifdef _WIN32 +#define stat _stat +#endif + { + struct stat st; + if (stat(b->data,&st) < 0) + break; + } +#endif + /* found one. */ + if (type == X509_LU_X509) + { + if ((X509_load_cert_file(xl,b->data, + ent->dir_type)) == 0) + break; + } + else if (type == X509_LU_CRL) + { + if ((X509_load_crl_file(xl,b->data, + ent->dir_type)) == 0) + break; + } + /* else case will caught higher up */ + k++; + } + + /* we have added it to the cache so now pull + * it out again */ + CRYPTO_MUTEX_lock_write(&xl->store_ctx->objs_lock); + tmp = NULL; + if (sk_X509_OBJECT_find(xl->store_ctx->objs, &idx, &stmp)) { + tmp=sk_X509_OBJECT_value(xl->store_ctx->objs,idx); + } + CRYPTO_MUTEX_unlock(&xl->store_ctx->objs_lock); + + + /* If a CRL, update the last file suffix added for this */ + + if (type == X509_LU_CRL) + { + CRYPTO_STATIC_MUTEX_lock_write(&g_ent_hashes_lock); + /* Look for entry again in case another thread added + * an entry first. + */ + if (!hent) + { + htmp.hash = h; + if (sk_BY_DIR_HASH_find(ent->hashes, &idx, &htmp)) + hent = sk_BY_DIR_HASH_value(ent->hashes, idx); + } + if (!hent) + { + hent = OPENSSL_malloc(sizeof(BY_DIR_HASH)); + if (hent == NULL) + { + CRYPTO_STATIC_MUTEX_unlock(&g_ent_hashes_lock); + ok = 0; + goto finish; + } + hent->hash = h; + hent->suffix = k; + if (!sk_BY_DIR_HASH_push(ent->hashes, hent)) + { + CRYPTO_STATIC_MUTEX_unlock(&g_ent_hashes_lock); + OPENSSL_free(hent); + ok = 0; + goto finish; + } + } + else if (hent->suffix < k) + hent->suffix = k; + + CRYPTO_STATIC_MUTEX_unlock(&g_ent_hashes_lock); + } + + if (tmp != NULL) + { + ok=1; + ret->type=tmp->type; + memcpy(&ret->data,&tmp->data,sizeof(ret->data)); + /* If we were going to up the reference count, + * we would need to do it on a perl 'type' + * basis */ + /* CRYPTO_add(&tmp->data.x509->references,1, + CRYPTO_LOCK_X509);*/ + goto finish; + } + } + } +finish: + if (b != NULL) BUF_MEM_free(b); + return(ok); + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/by_file.c b/TMessagesProj/jni/boringssl/crypto/x509/by_file.c new file mode 100644 index 00000000..f1d6194c --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/by_file.c @@ -0,0 +1,295 @@ +/* crypto/x509/by_file.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include +#include +#include + + +#ifndef OPENSSL_NO_STDIO + +static int by_file_ctrl(X509_LOOKUP *ctx, int cmd, const char *argc, + long argl, char **ret); +X509_LOOKUP_METHOD x509_file_lookup= + { + "Load file into cache", + NULL, /* new */ + NULL, /* free */ + NULL, /* init */ + NULL, /* shutdown */ + by_file_ctrl, /* ctrl */ + NULL, /* get_by_subject */ + NULL, /* get_by_issuer_serial */ + NULL, /* get_by_fingerprint */ + NULL, /* get_by_alias */ + }; + +X509_LOOKUP_METHOD *X509_LOOKUP_file(void) + { + return(&x509_file_lookup); + } + +static int by_file_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, long argl, + char **ret) + { + int ok=0; + char *file; + + switch (cmd) + { + case X509_L_FILE_LOAD: + if (argl == X509_FILETYPE_DEFAULT) + { + file = (char *)getenv(X509_get_default_cert_file_env()); + if (file) + ok = (X509_load_cert_crl_file(ctx,file, + X509_FILETYPE_PEM) != 0); + + else + ok = (X509_load_cert_crl_file(ctx,X509_get_default_cert_file(), + X509_FILETYPE_PEM) != 0); + + if (!ok) + { + OPENSSL_PUT_ERROR(X509, X509_R_LOADING_DEFAULTS); + } + } + else + { + if(argl == X509_FILETYPE_PEM) + ok = (X509_load_cert_crl_file(ctx,argp, + X509_FILETYPE_PEM) != 0); + else + ok = (X509_load_cert_file(ctx,argp,(int)argl) != 0); + } + break; + } + return(ok); + } + +int X509_load_cert_file(X509_LOOKUP *ctx, const char *file, int type) + { + int ret=0; + BIO *in=NULL; + int i,count=0; + X509 *x=NULL; + + if (file == NULL) return(1); + in=BIO_new(BIO_s_file()); + + if ((in == NULL) || (BIO_read_filename(in,file) <= 0)) + { + OPENSSL_PUT_ERROR(X509, ERR_R_SYS_LIB); + goto err; + } + + if (type == X509_FILETYPE_PEM) + { + for (;;) + { + x=PEM_read_bio_X509_AUX(in,NULL,NULL,NULL); + if (x == NULL) + { + if ((ERR_GET_REASON(ERR_peek_last_error()) == + PEM_R_NO_START_LINE) && (count > 0)) + { + ERR_clear_error(); + break; + } + else + { + OPENSSL_PUT_ERROR(X509, ERR_R_PEM_LIB); + goto err; + } + } + i=X509_STORE_add_cert(ctx->store_ctx,x); + if (!i) goto err; + count++; + X509_free(x); + x=NULL; + } + ret=count; + } + else if (type == X509_FILETYPE_ASN1) + { + x=d2i_X509_bio(in,NULL); + if (x == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_ASN1_LIB); + goto err; + } + i=X509_STORE_add_cert(ctx->store_ctx,x); + if (!i) goto err; + ret=i; + } + else + { + OPENSSL_PUT_ERROR(X509, X509_R_BAD_X509_FILETYPE); + goto err; + } +err: + if (x != NULL) X509_free(x); + if (in != NULL) BIO_free(in); + return(ret); + } + +int X509_load_crl_file(X509_LOOKUP *ctx, const char *file, int type) + { + int ret=0; + BIO *in=NULL; + int i,count=0; + X509_CRL *x=NULL; + + if (file == NULL) return(1); + in=BIO_new(BIO_s_file()); + + if ((in == NULL) || (BIO_read_filename(in,file) <= 0)) + { + OPENSSL_PUT_ERROR(X509, ERR_R_SYS_LIB); + goto err; + } + + if (type == X509_FILETYPE_PEM) + { + for (;;) + { + x=PEM_read_bio_X509_CRL(in,NULL,NULL,NULL); + if (x == NULL) + { + if ((ERR_GET_REASON(ERR_peek_last_error()) == + PEM_R_NO_START_LINE) && (count > 0)) + { + ERR_clear_error(); + break; + } + else + { + OPENSSL_PUT_ERROR(X509, ERR_R_PEM_LIB); + goto err; + } + } + i=X509_STORE_add_crl(ctx->store_ctx,x); + if (!i) goto err; + count++; + X509_CRL_free(x); + x=NULL; + } + ret=count; + } + else if (type == X509_FILETYPE_ASN1) + { + x=d2i_X509_CRL_bio(in,NULL); + if (x == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_ASN1_LIB); + goto err; + } + i=X509_STORE_add_crl(ctx->store_ctx,x); + if (!i) goto err; + ret=i; + } + else + { + OPENSSL_PUT_ERROR(X509, X509_R_BAD_X509_FILETYPE); + goto err; + } +err: + if (x != NULL) X509_CRL_free(x); + if (in != NULL) BIO_free(in); + return(ret); + } + +int X509_load_cert_crl_file(X509_LOOKUP *ctx, const char *file, int type) +{ + STACK_OF(X509_INFO) *inf; + X509_INFO *itmp; + BIO *in; + size_t i; + int count = 0; + if(type != X509_FILETYPE_PEM) + return X509_load_cert_file(ctx, file, type); + in = BIO_new_file(file, "r"); + if(!in) { + OPENSSL_PUT_ERROR(X509, ERR_R_SYS_LIB); + return 0; + } + inf = PEM_X509_INFO_read_bio(in, NULL, NULL, NULL); + BIO_free(in); + if(!inf) { + OPENSSL_PUT_ERROR(X509, ERR_R_PEM_LIB); + return 0; + } + for(i = 0; i < sk_X509_INFO_num(inf); i++) { + itmp = sk_X509_INFO_value(inf, i); + if(itmp->x509) { + X509_STORE_add_cert(ctx->store_ctx, itmp->x509); + count++; + } + if(itmp->crl) { + X509_STORE_add_crl(ctx->store_ctx, itmp->crl); + count++; + } + } + sk_X509_INFO_pop_free(inf, X509_INFO_free); + return count; +} + +#endif /* OPENSSL_NO_STDIO */ diff --git a/TMessagesProj/jni/boringssl/crypto/x509/charmap.h b/TMessagesProj/jni/boringssl/crypto/x509/charmap.h new file mode 100644 index 00000000..b55e6387 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/charmap.h @@ -0,0 +1,15 @@ +/* Auto generated with chartype.pl script. + * Mask of various character properties + */ + +static const unsigned char char_type[] = { + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +120, 0, 1,40, 0, 0, 0,16,16,16, 0,25,25,16,16,16, +16,16,16,16,16,16,16,16,16,16,16, 9, 9,16, 9,16, + 0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16, 0, 1, 0, 0, 0, + 0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16, 0, 0, 0, 0, 2 +}; + diff --git a/TMessagesProj/jni/boringssl/crypto/x509/i2d_pr.c b/TMessagesProj/jni/boringssl/crypto/x509/i2d_pr.c new file mode 100644 index 00000000..e7f4269d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/i2d_pr.c @@ -0,0 +1,84 @@ +/* crypto/asn1/i2d_pr.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include + +#include "../evp/internal.h" + + +int i2d_PrivateKey(const EVP_PKEY *a, unsigned char **pp) + { + if (a->ameth && a->ameth->old_priv_encode) + { + return a->ameth->old_priv_encode(a, pp); + } + if (a->ameth && a->ameth->priv_encode) { + PKCS8_PRIV_KEY_INFO *p8 = EVP_PKEY2PKCS8((EVP_PKEY*)a); + int ret = i2d_PKCS8_PRIV_KEY_INFO(p8,pp); + PKCS8_PRIV_KEY_INFO_free(p8); + return ret; + } + /* Although this file is in crypto/x509 for layering reasons, it emits + * an error code from ASN1 for OpenSSL compatibility. */ + OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE); + return -1; + } + diff --git a/TMessagesProj/jni/boringssl/crypto/x509/pkcs7.c b/TMessagesProj/jni/boringssl/crypto/x509/pkcs7.c new file mode 100644 index 00000000..2087f948 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/pkcs7.c @@ -0,0 +1,346 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "../bytestring/internal.h" + + +/* pkcs7_parse_header reads the non-certificate/non-CRL prefix of a PKCS#7 + * SignedData blob from |cbs| and sets |*out| to point to the rest of the + * input. If the input is in BER format, then |*der_bytes| will be set to a + * pointer that needs to be freed by the caller once they have finished + * processing |*out| (which will be pointing into |*der_bytes|). + * + * It returns one on success or zero on error. On error, |*der_bytes| is + * NULL. */ +static int pkcs7_parse_header(uint8_t **der_bytes, CBS *out, CBS *cbs) { + size_t der_len; + CBS in, content_info, content_type, wrapped_signed_data, signed_data; + uint64_t version; + + /* The input may be in BER format. */ + *der_bytes = NULL; + if (!CBS_asn1_ber_to_der(cbs, der_bytes, &der_len)) { + return 0; + } + if (*der_bytes != NULL) { + CBS_init(&in, *der_bytes, der_len); + } else { + CBS_init(&in, CBS_data(cbs), CBS_len(cbs)); + } + + /* See https://tools.ietf.org/html/rfc2315#section-7 */ + if (!CBS_get_asn1(&in, &content_info, CBS_ASN1_SEQUENCE) || + !CBS_get_asn1(&content_info, &content_type, CBS_ASN1_OBJECT)) { + goto err; + } + + if (OBJ_cbs2nid(&content_type) != NID_pkcs7_signed) { + OPENSSL_PUT_ERROR(X509, X509_R_NOT_PKCS7_SIGNED_DATA); + goto err; + } + + /* See https://tools.ietf.org/html/rfc2315#section-9.1 */ + if (!CBS_get_asn1(&content_info, &wrapped_signed_data, + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) || + !CBS_get_asn1(&wrapped_signed_data, &signed_data, CBS_ASN1_SEQUENCE) || + !CBS_get_asn1_uint64(&signed_data, &version) || + !CBS_get_asn1(&signed_data, NULL /* digests */, CBS_ASN1_SET) || + !CBS_get_asn1(&signed_data, NULL /* content */, CBS_ASN1_SEQUENCE)) { + goto err; + } + + if (version < 1) { + OPENSSL_PUT_ERROR(X509, X509_R_BAD_PKCS7_VERSION); + goto err; + } + + CBS_init(out, CBS_data(&signed_data), CBS_len(&signed_data)); + return 1; + +err: + if (*der_bytes) { + OPENSSL_free(*der_bytes); + *der_bytes = NULL; + } + + return 0; +} + +int PKCS7_get_certificates(STACK_OF(X509) *out_certs, CBS *cbs) { + CBS signed_data, certificates; + uint8_t *der_bytes = NULL; + int ret = 0; + const size_t initial_certs_len = sk_X509_num(out_certs); + + if (!pkcs7_parse_header(&der_bytes, &signed_data, cbs)) { + return 0; + } + + /* See https://tools.ietf.org/html/rfc2315#section-9.1 */ + if (!CBS_get_asn1(&signed_data, &certificates, + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) { + OPENSSL_PUT_ERROR(X509, X509_R_NO_CERTIFICATES_INCLUDED); + goto err; + } + + while (CBS_len(&certificates) > 0) { + CBS cert; + X509 *x509; + const uint8_t *inp; + + if (!CBS_get_asn1_element(&certificates, &cert, CBS_ASN1_SEQUENCE)) { + goto err; + } + + inp = CBS_data(&cert); + x509 = d2i_X509(NULL, &inp, CBS_len(&cert)); + if (!x509) { + goto err; + } + + assert(inp == CBS_data(&cert) + CBS_len(&cert)); + + if (sk_X509_push(out_certs, x509) == 0) { + X509_free(x509); + goto err; + } + } + + ret = 1; + +err: + if (der_bytes) { + OPENSSL_free(der_bytes); + } + + if (!ret) { + while (sk_X509_num(out_certs) != initial_certs_len) { + X509 *x509 = sk_X509_pop(out_certs); + X509_free(x509); + } + } + + return ret; +} + +int PKCS7_get_CRLs(STACK_OF(X509_CRL) *out_crls, CBS *cbs) { + CBS signed_data, crls; + uint8_t *der_bytes = NULL; + int ret = 0; + const size_t initial_crls_len = sk_X509_CRL_num(out_crls); + + if (!pkcs7_parse_header(&der_bytes, &signed_data, cbs)) { + return 0; + } + + /* See https://tools.ietf.org/html/rfc2315#section-9.1 */ + + /* Even if only CRLs are included, there may be an empty certificates block. + * OpenSSL does this, for example. */ + if (CBS_peek_asn1_tag(&signed_data, + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) && + !CBS_get_asn1(&signed_data, NULL /* certificates */, + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) { + goto err; + } + + if (!CBS_get_asn1(&signed_data, &crls, + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1)) { + OPENSSL_PUT_ERROR(X509, X509_R_NO_CRLS_INCLUDED); + goto err; + } + + while (CBS_len(&crls) > 0) { + CBS crl_data; + X509_CRL *crl; + const uint8_t *inp; + + if (!CBS_get_asn1_element(&crls, &crl_data, CBS_ASN1_SEQUENCE)) { + goto err; + } + + inp = CBS_data(&crl_data); + crl = d2i_X509_CRL(NULL, &inp, CBS_len(&crl_data)); + if (!crl) { + goto err; + } + + assert(inp == CBS_data(&crl_data) + CBS_len(&crl_data)); + + if (sk_X509_CRL_push(out_crls, crl) == 0) { + X509_CRL_free(crl); + goto err; + } + } + + ret = 1; + +err: + if (der_bytes) { + OPENSSL_free(der_bytes); + } + + if (!ret) { + while (sk_X509_CRL_num(out_crls) != initial_crls_len) { + X509_CRL_free(sk_X509_CRL_pop(out_crls)); + } + } + + return ret; +} + +int PKCS7_get_PEM_certificates(STACK_OF(X509) *out_certs, BIO *pem_bio) { + uint8_t *data; + long len; + int ret; + + /* Even though we pass PEM_STRING_PKCS7 as the expected PEM type here, PEM + * internally will actually allow several other values too, including + * "CERTIFICATE". */ + if (!PEM_bytes_read_bio(&data, &len, NULL /* PEM type output */, + PEM_STRING_PKCS7, pem_bio, + NULL /* password callback */, + NULL /* password callback argument */)) { + return 0; + } + + CBS cbs; + CBS_init(&cbs, data, len); + ret = PKCS7_get_certificates(out_certs, &cbs); + OPENSSL_free(data); + return ret; +} + +int PKCS7_get_PEM_CRLs(STACK_OF(X509_CRL) *out_crls, BIO *pem_bio) { + uint8_t *data; + long len; + int ret; + + /* Even though we pass PEM_STRING_PKCS7 as the expected PEM type here, PEM + * internally will actually allow several other values too, including + * "CERTIFICATE". */ + if (!PEM_bytes_read_bio(&data, &len, NULL /* PEM type output */, + PEM_STRING_PKCS7, pem_bio, + NULL /* password callback */, + NULL /* password callback argument */)) { + return 0; + } + + CBS cbs; + CBS_init(&cbs, data, len); + ret = PKCS7_get_CRLs(out_crls, &cbs); + OPENSSL_free(data); + return ret; +} + +/* pkcs7_bundle writes a PKCS#7, SignedData structure to |out| and then calls + * |cb| with a CBB to which certificate or CRL data can be written, and the + * opaque context pointer, |arg|. The callback can return zero to indicate an + * error. + * + * pkcs7_bundle returns one on success or zero on error. */ +static int pkcs7_bundle(CBB *out, int (*cb)(CBB *out, const void *arg), + const void *arg) { + CBB outer_seq, wrapped_seq, seq, version_bytes, digest_algos_set, + content_info; + + /* See https://tools.ietf.org/html/rfc2315#section-7 */ + if (!CBB_add_asn1(out, &outer_seq, CBS_ASN1_SEQUENCE) || + !OBJ_nid2cbb(&outer_seq, NID_pkcs7_signed) || + !CBB_add_asn1(&outer_seq, &wrapped_seq, + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) || + /* See https://tools.ietf.org/html/rfc2315#section-9.1 */ + !CBB_add_asn1(&wrapped_seq, &seq, CBS_ASN1_SEQUENCE) || + !CBB_add_asn1(&seq, &version_bytes, CBS_ASN1_INTEGER) || + !CBB_add_u8(&version_bytes, 1) || + !CBB_add_asn1(&seq, &digest_algos_set, CBS_ASN1_SET) || + !CBB_add_asn1(&seq, &content_info, CBS_ASN1_SEQUENCE) || + !OBJ_nid2cbb(&content_info, NID_pkcs7_data) || + !cb(&seq, arg)) { + return 0; + } + + return CBB_flush(out); +} + +static int pkcs7_bundle_certificates_cb(CBB *out, const void *arg) { + const STACK_OF(X509) *certs = arg; + size_t i; + CBB certificates; + + /* See https://tools.ietf.org/html/rfc2315#section-9.1 */ + if (!CBB_add_asn1(out, &certificates, + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) { + return 0; + } + + for (i = 0; i < sk_X509_num(certs); i++) { + X509 *x509 = sk_X509_value(certs, i); + uint8_t *buf; + int len = i2d_X509(x509, NULL); + + if (len < 0 || + !CBB_add_space(&certificates, &buf, len) || + i2d_X509(x509, &buf) < 0) { + return 0; + } + } + + return CBB_flush(out); +} + +int PKCS7_bundle_certificates(CBB *out, const STACK_OF(X509) *certs) { + return pkcs7_bundle(out, pkcs7_bundle_certificates_cb, certs); +} + +static int pkcs7_bundle_crls_cb(CBB *out, const void *arg) { + const STACK_OF(X509_CRL) *crls = arg; + size_t i; + CBB crl_data; + + /* See https://tools.ietf.org/html/rfc2315#section-9.1 */ + if (!CBB_add_asn1(out, &crl_data, + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1)) { + return 0; + } + + for (i = 0; i < sk_X509_CRL_num(crls); i++) { + X509_CRL *crl = sk_X509_CRL_value(crls, i); + uint8_t *buf; + int len = i2d_X509_CRL(crl, NULL); + + if (len < 0 || + !CBB_add_space(&crl_data, &buf, len) || + i2d_X509_CRL(crl, &buf) < 0) { + return 0; + } + } + + return CBB_flush(out); +} + +int PKCS7_bundle_CRLs(CBB *out, const STACK_OF(X509_CRL) *crls) { + return pkcs7_bundle(out, pkcs7_bundle_crls_cb, crls); +} diff --git a/TMessagesProj/jni/boringssl/crypto/x509/t_crl.c b/TMessagesProj/jni/boringssl/crypto/x509/t_crl.c new file mode 100644 index 00000000..a2d8bc74 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/t_crl.c @@ -0,0 +1,129 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include +#include +#include + + +#ifndef OPENSSL_NO_FP_API +int X509_CRL_print_fp(FILE *fp, X509_CRL *x) + { + BIO *b; + int ret; + + if ((b=BIO_new(BIO_s_file())) == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_BUF_LIB); + return(0); + } + BIO_set_fp(b,fp,BIO_NOCLOSE); + ret=X509_CRL_print(b, x); + BIO_free(b); + return(ret); + } +#endif + +int X509_CRL_print(BIO *out, X509_CRL *x) +{ + STACK_OF(X509_REVOKED) *rev; + X509_REVOKED *r; + long l; + size_t i; + char *p; + + BIO_printf(out, "Certificate Revocation List (CRL):\n"); + l = X509_CRL_get_version(x); + BIO_printf(out, "%8sVersion %lu (0x%lx)\n", "", l+1, l); + X509_signature_print(out, x->sig_alg, NULL); + p=X509_NAME_oneline(X509_CRL_get_issuer(x),NULL,0); + BIO_printf(out,"%8sIssuer: %s\n","",p); + OPENSSL_free(p); + BIO_printf(out,"%8sLast Update: ",""); + ASN1_TIME_print(out,X509_CRL_get_lastUpdate(x)); + BIO_printf(out,"\n%8sNext Update: ",""); + if (X509_CRL_get_nextUpdate(x)) + ASN1_TIME_print(out,X509_CRL_get_nextUpdate(x)); + else BIO_printf(out,"NONE"); + BIO_printf(out,"\n"); + + X509V3_extensions_print(out, "CRL extensions", + x->crl->extensions, 0, 8); + + rev = X509_CRL_get_REVOKED(x); + + if(sk_X509_REVOKED_num(rev) > 0) + BIO_printf(out, "Revoked Certificates:\n"); + else BIO_printf(out, "No Revoked Certificates.\n"); + + for(i = 0; i < sk_X509_REVOKED_num(rev); i++) { + r = sk_X509_REVOKED_value(rev, i); + BIO_printf(out," Serial Number: "); + i2a_ASN1_INTEGER(out,r->serialNumber); + BIO_printf(out,"\n Revocation Date: "); + ASN1_TIME_print(out,r->revocationDate); + BIO_printf(out,"\n"); + X509V3_extensions_print(out, "CRL entry extensions", + r->extensions, 0, 8); + } + X509_signature_print(out, x->sig_alg, x->signature); + + return 1; + +} diff --git a/TMessagesProj/jni/boringssl/crypto/x509/t_req.c b/TMessagesProj/jni/boringssl/crypto/x509/t_req.c new file mode 100644 index 00000000..39c836cc --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/t_req.c @@ -0,0 +1,246 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include +#include +#include +#include + + +int X509_REQ_print_fp(FILE *fp, X509_REQ *x) { + BIO *bio = BIO_new(BIO_s_file()); + if (bio == NULL) { + OPENSSL_PUT_ERROR(X509, ERR_R_BUF_LIB); + return 0; + } + + BIO_set_fp(bio, fp, BIO_NOCLOSE); + int ret = X509_REQ_print(bio, x); + BIO_free(bio); + return ret; +} + +int X509_REQ_print_ex(BIO *bio, X509_REQ *x, unsigned long nmflags, + unsigned long cflag) { + long l; + EVP_PKEY *pkey; + STACK_OF(X509_ATTRIBUTE) * sk; + char mlch = ' '; + + int nmindent = 0; + + if ((nmflags & XN_FLAG_SEP_MASK) == XN_FLAG_SEP_MULTILINE) { + mlch = '\n'; + nmindent = 12; + } + + if (nmflags == X509_FLAG_COMPAT) { + nmindent = 16; + } + + X509_REQ_INFO *ri = x->req_info; + if (!(cflag & X509_FLAG_NO_HEADER)) { + if (BIO_write(bio, "Certificate Request:\n", 21) <= 0 || + BIO_write(bio, " Data:\n", 10) <= 0) { + goto err; + } + } + if (!(cflag & X509_FLAG_NO_VERSION)) { + l = X509_REQ_get_version(x); + if (BIO_printf(bio, "%8sVersion: %ld (0x%lx)\n", "", l + 1, l) <= 0) { + goto err; + } + } + if (!(cflag & X509_FLAG_NO_SUBJECT)) { + if (BIO_printf(bio, " Subject:%c", mlch) <= 0 || + X509_NAME_print_ex(bio, ri->subject, nmindent, nmflags) < 0 || + BIO_write(bio, "\n", 1) <= 0) { + goto err; + } + } + if (!(cflag & X509_FLAG_NO_PUBKEY)) { + if (BIO_write(bio, " Subject Public Key Info:\n", 33) <= 0 || + BIO_printf(bio, "%12sPublic Key Algorithm: ", "") <= 0 || + i2a_ASN1_OBJECT(bio, ri->pubkey->algor->algorithm) <= 0 || + BIO_puts(bio, "\n") <= 0) { + goto err; + } + + pkey = X509_REQ_get_pubkey(x); + if (pkey == NULL) { + BIO_printf(bio, "%12sUnable to load Public Key\n", ""); + ERR_print_errors(bio); + } else { + EVP_PKEY_print_public(bio, pkey, 16, NULL); + EVP_PKEY_free(pkey); + } + } + + if (!(cflag & X509_FLAG_NO_ATTRIBUTES)) { + if (BIO_printf(bio, "%8sAttributes:\n", "") <= 0) { + goto err; + } + + sk = x->req_info->attributes; + if (sk_X509_ATTRIBUTE_num(sk) == 0) { + if (BIO_printf(bio, "%12sa0:00\n", "") <= 0) { + goto err; + } + } else { + size_t i; + for (i = 0; i < sk_X509_ATTRIBUTE_num(sk); i++) { + X509_ATTRIBUTE *a = sk_X509_ATTRIBUTE_value(sk, i); + ASN1_OBJECT *aobj = X509_ATTRIBUTE_get0_object(a); + + if (X509_REQ_extension_nid(OBJ_obj2nid(aobj))) { + continue; + } + + if (BIO_printf(bio, "%12s", "") <= 0) { + goto err; + } + + const int num_attrs = X509_ATTRIBUTE_count(a); + const int obj_str_len = i2a_ASN1_OBJECT(bio, aobj); + if (obj_str_len <= 0) { + if (BIO_puts(bio, "(Unable to print attribute ID.)\n") < 0) { + goto err; + } else { + continue; + } + } + + int j; + for (j = 0; j < num_attrs; j++) { + const ASN1_TYPE *at = X509_ATTRIBUTE_get0_type(a, j); + const int type = at->type; + ASN1_BIT_STRING *bs = at->value.asn1_string; + + int k; + for (k = 25 - obj_str_len; k > 0; k--) { + if (BIO_write(bio, " ", 1) != 1) { + goto err; + } + } + + if (BIO_puts(bio, ":") <= 0) { + goto err; + } + + if (type == V_ASN1_PRINTABLESTRING || + type == V_ASN1_UTF8STRING || + type == V_ASN1_IA5STRING || + type == V_ASN1_T61STRING) { + if (BIO_write(bio, (char *)bs->data, bs->length) != bs->length) { + goto err; + } + BIO_puts(bio, "\n"); + } else { + BIO_puts(bio, "unable to print attribute\n"); + } + } + } + } + } + + if (!(cflag & X509_FLAG_NO_EXTENSIONS)) { + STACK_OF(X509_EXTENSION) *exts = X509_REQ_get_extensions(x); + if (exts) { + BIO_printf(bio, "%8sRequested Extensions:\n", ""); + + size_t i; + for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) { + X509_EXTENSION *ex = sk_X509_EXTENSION_value(exts, i); + if (BIO_printf(bio, "%12s", "") <= 0) { + goto err; + } + ASN1_OBJECT *obj = X509_EXTENSION_get_object(ex); + i2a_ASN1_OBJECT(bio, obj); + const int is_critical = X509_EXTENSION_get_critical(ex); + if (BIO_printf(bio, ": %s\n", is_critical ? "critical" : "") <= 0) { + goto err; + } + if (!X509V3_EXT_print(bio, ex, cflag, 16)) { + BIO_printf(bio, "%16s", ""); + ASN1_STRING_print(bio, X509_EXTENSION_get_data(ex)); + } + if (BIO_write(bio, "\n", 1) <= 0) { + goto err; + } + } + sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); + } + } + + if (!(cflag & X509_FLAG_NO_SIGDUMP) && + !X509_signature_print(bio, x->sig_alg, x->signature)) { + goto err; + } + + return 1; + +err: + OPENSSL_PUT_ERROR(X509, ERR_R_BUF_LIB); + return 0; +} + +int X509_REQ_print(BIO *bio, X509_REQ *req) { + return X509_REQ_print_ex(bio, req, XN_FLAG_COMPAT, X509_FLAG_COMPAT); +} diff --git a/TMessagesProj/jni/boringssl/crypto/x509/t_x509.c b/TMessagesProj/jni/boringssl/crypto/x509/t_x509.c new file mode 100644 index 00000000..7785ebff --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/t_x509.c @@ -0,0 +1,500 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../evp/internal.h" + +#ifndef OPENSSL_NO_FP_API +int X509_print_ex_fp(FILE *fp, X509 *x, unsigned long nmflag, unsigned long cflag) + { + BIO *b; + int ret; + + if ((b=BIO_new(BIO_s_file())) == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_BUF_LIB); + return(0); + } + BIO_set_fp(b,fp,BIO_NOCLOSE); + ret=X509_print_ex(b, x, nmflag, cflag); + BIO_free(b); + return(ret); + } + +int X509_print_fp(FILE *fp, X509 *x) + { + return X509_print_ex_fp(fp, x, XN_FLAG_COMPAT, X509_FLAG_COMPAT); + } +#endif + +int X509_print(BIO *bp, X509 *x) +{ + return X509_print_ex(bp, x, XN_FLAG_COMPAT, X509_FLAG_COMPAT); +} + +int X509_print_ex(BIO *bp, X509 *x, unsigned long nmflags, unsigned long cflag) + { + long l; + int ret=0,i; + char *m=NULL,mlch = ' '; + int nmindent = 0; + X509_CINF *ci; + ASN1_INTEGER *bs; + EVP_PKEY *pkey=NULL; + const char *neg; + + if((nmflags & XN_FLAG_SEP_MASK) == XN_FLAG_SEP_MULTILINE) { + mlch = '\n'; + nmindent = 12; + } + + if(nmflags == X509_FLAG_COMPAT) + nmindent = 16; + + ci=x->cert_info; + if(!(cflag & X509_FLAG_NO_HEADER)) + { + if (BIO_write(bp,"Certificate:\n",13) <= 0) goto err; + if (BIO_write(bp," Data:\n",10) <= 0) goto err; + } + if(!(cflag & X509_FLAG_NO_VERSION)) + { + l=X509_get_version(x); + if (BIO_printf(bp,"%8sVersion: %lu (0x%lx)\n","",l+1,l) <= 0) goto err; + } + if(!(cflag & X509_FLAG_NO_SERIAL)) + { + + if (BIO_write(bp," Serial Number:",22) <= 0) goto err; + + bs=X509_get_serialNumber(x); + if (bs->length <= (int)sizeof(long)) + { + l=ASN1_INTEGER_get(bs); + if (bs->type == V_ASN1_NEG_INTEGER) + { + l= -l; + neg="-"; + } + else + neg=""; + if (BIO_printf(bp," %s%lu (%s0x%lx)\n",neg,l,neg,l) <= 0) + goto err; + } + else + { + neg=(bs->type == V_ASN1_NEG_INTEGER)?" (Negative)":""; + if (BIO_printf(bp,"\n%12s%s","",neg) <= 0) goto err; + + for (i=0; ilength; i++) + { + if (BIO_printf(bp,"%02x%c",bs->data[i], + ((i+1 == bs->length)?'\n':':')) <= 0) + goto err; + } + } + + } + + if(!(cflag & X509_FLAG_NO_SIGNAME)) + { + if (X509_signature_print(bp, ci->signature, NULL) <= 0) + goto err; + } + + if(!(cflag & X509_FLAG_NO_ISSUER)) + { + if (BIO_printf(bp," Issuer:%c",mlch) <= 0) goto err; + if (X509_NAME_print_ex(bp,X509_get_issuer_name(x),nmindent, nmflags) < 0) goto err; + if (BIO_write(bp,"\n",1) <= 0) goto err; + } + if(!(cflag & X509_FLAG_NO_VALIDITY)) + { + if (BIO_write(bp," Validity\n",17) <= 0) goto err; + if (BIO_write(bp," Not Before: ",24) <= 0) goto err; + if (!ASN1_TIME_print(bp,X509_get_notBefore(x))) goto err; + if (BIO_write(bp,"\n Not After : ",25) <= 0) goto err; + if (!ASN1_TIME_print(bp,X509_get_notAfter(x))) goto err; + if (BIO_write(bp,"\n",1) <= 0) goto err; + } + if(!(cflag & X509_FLAG_NO_SUBJECT)) + { + if (BIO_printf(bp," Subject:%c",mlch) <= 0) goto err; + if (X509_NAME_print_ex(bp,X509_get_subject_name(x),nmindent, nmflags) < 0) goto err; + if (BIO_write(bp,"\n",1) <= 0) goto err; + } + if(!(cflag & X509_FLAG_NO_PUBKEY)) + { + if (BIO_write(bp," Subject Public Key Info:\n",33) <= 0) + goto err; + if (BIO_printf(bp,"%12sPublic Key Algorithm: ","") <= 0) + goto err; + if (i2a_ASN1_OBJECT(bp, ci->key->algor->algorithm) <= 0) + goto err; + if (BIO_puts(bp, "\n") <= 0) + goto err; + + pkey=X509_get_pubkey(x); + if (pkey == NULL) + { + BIO_printf(bp,"%12sUnable to load Public Key\n",""); + BIO_print_errors(bp); + } + else + { + EVP_PKEY_print_public(bp, pkey, 16, NULL); + EVP_PKEY_free(pkey); + } + } + + if(!(cflag & X509_FLAG_NO_IDS)) + { + if (ci->issuerUID) + { + if (BIO_printf(bp,"%8sIssuer Unique ID: ","") <= 0) + goto err; + if (!X509_signature_dump(bp, ci->issuerUID, 12)) + goto err; + } + if (ci->subjectUID) + { + if (BIO_printf(bp,"%8sSubject Unique ID: ","") <= 0) + goto err; + if (!X509_signature_dump(bp, ci->subjectUID, 12)) + goto err; + } + } + + if (!(cflag & X509_FLAG_NO_EXTENSIONS)) + X509V3_extensions_print(bp, "X509v3 extensions", + ci->extensions, cflag, 8); + + if(!(cflag & X509_FLAG_NO_SIGDUMP)) + { + if(X509_signature_print(bp, x->sig_alg, x->signature) <= 0) goto err; + } + if(!(cflag & X509_FLAG_NO_AUX)) + { + if (!X509_CERT_AUX_print(bp, x->aux, 0)) goto err; + } + ret=1; +err: + if (m != NULL) OPENSSL_free(m); + return(ret); + } + +int X509_ocspid_print (BIO *bp, X509 *x) + { + unsigned char *der=NULL ; + unsigned char *dertmp; + int derlen; + int i; + unsigned char SHA1md[SHA_DIGEST_LENGTH]; + + /* display the hash of the subject as it would appear + in OCSP requests */ + if (BIO_printf(bp," Subject OCSP hash: ") <= 0) + goto err; + derlen = i2d_X509_NAME(x->cert_info->subject, NULL); + if ((der = dertmp = (unsigned char *)OPENSSL_malloc (derlen)) == NULL) + goto err; + i2d_X509_NAME(x->cert_info->subject, &dertmp); + + if (!EVP_Digest(der, derlen, SHA1md, NULL, EVP_sha1(), NULL)) + goto err; + for (i=0; i < SHA_DIGEST_LENGTH; i++) + { + if (BIO_printf(bp,"%02X",SHA1md[i]) <= 0) goto err; + } + OPENSSL_free (der); + der=NULL; + + /* display the hash of the public key as it would appear + in OCSP requests */ + if (BIO_printf(bp,"\n Public key OCSP hash: ") <= 0) + goto err; + + if (!EVP_Digest(x->cert_info->key->public_key->data, + x->cert_info->key->public_key->length, + SHA1md, NULL, EVP_sha1(), NULL)) + goto err; + for (i=0; i < SHA_DIGEST_LENGTH; i++) + { + if (BIO_printf(bp,"%02X",SHA1md[i]) <= 0) + goto err; + } + BIO_printf(bp,"\n"); + + return (1); +err: + if (der != NULL) OPENSSL_free(der); + return(0); + } + +int X509_signature_print(BIO *bp, X509_ALGOR *sigalg, ASN1_STRING *sig) +{ + int sig_nid; + if (BIO_puts(bp," Signature Algorithm: ") <= 0) return 0; + if (i2a_ASN1_OBJECT(bp, sigalg->algorithm) <= 0) return 0; + + sig_nid = OBJ_obj2nid(sigalg->algorithm); + if (sig_nid != NID_undef) + { + int pkey_nid, dig_nid; + const EVP_PKEY_ASN1_METHOD *ameth; + if (OBJ_find_sigid_algs(sig_nid, &dig_nid, &pkey_nid)) + { + ameth = EVP_PKEY_asn1_find(NULL, pkey_nid); + if (ameth && ameth->sig_print) + return ameth->sig_print(bp, sigalg, sig, 9, 0); + } + } + if (sig) + return X509_signature_dump(bp, sig, 9); + else if (BIO_puts(bp, "\n") <= 0) + return 0; + return 1; +} + +int ASN1_STRING_print(BIO *bp, const ASN1_STRING *v) + { + int i,n; + char buf[80]; + const char *p; + + if (v == NULL) return(0); + n=0; + p=(const char *)v->data; + for (i=0; ilength; i++) + { + if ((p[i] > '~') || ((p[i] < ' ') && + (p[i] != '\n') && (p[i] != '\r'))) + buf[n]='.'; + else + buf[n]=p[i]; + n++; + if (n >= 80) + { + if (BIO_write(bp,buf,n) <= 0) + return(0); + n=0; + } + } + if (n > 0) + if (BIO_write(bp,buf,n) <= 0) + return(0); + return(1); + } + +int ASN1_TIME_print(BIO *bp, const ASN1_TIME *tm) +{ + if(tm->type == V_ASN1_UTCTIME) return ASN1_UTCTIME_print(bp, tm); + if(tm->type == V_ASN1_GENERALIZEDTIME) + return ASN1_GENERALIZEDTIME_print(bp, tm); + BIO_write(bp,"Bad time value",14); + return(0); +} + +static const char *const mon[12]= + { + "Jan","Feb","Mar","Apr","May","Jun", + "Jul","Aug","Sep","Oct","Nov","Dec" + }; + +int ASN1_GENERALIZEDTIME_print(BIO *bp, const ASN1_GENERALIZEDTIME *tm) + { + char *v; + int gmt=0; + int i; + int y=0,M=0,d=0,h=0,m=0,s=0; + char *f = NULL; + int f_len = 0; + + i=tm->length; + v=(char *)tm->data; + + if (i < 12) goto err; + if (v[i-1] == 'Z') gmt=1; + for (i=0; i<12; i++) + if ((v[i] > '9') || (v[i] < '0')) goto err; + y= (v[0]-'0')*1000+(v[1]-'0')*100 + (v[2]-'0')*10+(v[3]-'0'); + M= (v[4]-'0')*10+(v[5]-'0'); + if ((M > 12) || (M < 1)) goto err; + d= (v[6]-'0')*10+(v[7]-'0'); + h= (v[8]-'0')*10+(v[9]-'0'); + m= (v[10]-'0')*10+(v[11]-'0'); + if (tm->length >= 14 && + (v[12] >= '0') && (v[12] <= '9') && + (v[13] >= '0') && (v[13] <= '9')) + { + s= (v[12]-'0')*10+(v[13]-'0'); + /* Check for fractions of seconds. */ + if (tm->length >= 15 && v[14] == '.') + { + int l = tm->length; + f = &v[14]; /* The decimal point. */ + f_len = 1; + while (14 + f_len < l && f[f_len] >= '0' && f[f_len] <= '9') + ++f_len; + } + } + + if (BIO_printf(bp,"%s %2d %02d:%02d:%02d%.*s %d%s", + mon[M-1],d,h,m,s,f_len,f,y,(gmt)?" GMT":"") <= 0) + return(0); + else + return(1); +err: + BIO_write(bp,"Bad time value",14); + return(0); + } + +int ASN1_UTCTIME_print(BIO *bp, const ASN1_UTCTIME *tm) + { + const char *v; + int gmt=0; + int i; + int y=0,M=0,d=0,h=0,m=0,s=0; + + i=tm->length; + v=(const char *)tm->data; + + if (i < 10) goto err; + if (v[i-1] == 'Z') gmt=1; + for (i=0; i<10; i++) + if ((v[i] > '9') || (v[i] < '0')) goto err; + y= (v[0]-'0')*10+(v[1]-'0'); + if (y < 50) y+=100; + M= (v[2]-'0')*10+(v[3]-'0'); + if ((M > 12) || (M < 1)) goto err; + d= (v[4]-'0')*10+(v[5]-'0'); + h= (v[6]-'0')*10+(v[7]-'0'); + m= (v[8]-'0')*10+(v[9]-'0'); + if (tm->length >=12 && + (v[10] >= '0') && (v[10] <= '9') && + (v[11] >= '0') && (v[11] <= '9')) + s= (v[10]-'0')*10+(v[11]-'0'); + + if (BIO_printf(bp,"%s %2d %02d:%02d:%02d %d%s", + mon[M-1],d,h,m,s,y+1900,(gmt)?" GMT":"") <= 0) + return(0); + else + return(1); +err: + BIO_write(bp,"Bad time value",14); + return(0); + } + +int X509_NAME_print(BIO *bp, X509_NAME *name, int obase) + { + char *s,*c,*b; + int ret=0,l,i; + + l=80-2-obase; + + b=X509_NAME_oneline(name,NULL,0); + if (!b) + return 0; + if (!*b) + { + OPENSSL_free(b); + return 1; + } + s=b+1; /* skip the first slash */ + + c=s; + for (;;) + { + if ( ((*s == '/') && + ((s[1] >= 'A') && (s[1] <= 'Z') && ( + (s[2] == '=') || + ((s[2] >= 'A') && (s[2] <= 'Z') && + (s[3] == '=')) + ))) || + (*s == '\0')) + { + i=s-c; + if (BIO_write(bp,c,i) != i) goto err; + c=s+1; /* skip following slash */ + if (*s != '\0') + { + if (BIO_write(bp,", ",2) != 2) goto err; + } + l--; + } + if (*s == '\0') break; + s++; + l--; + } + + ret=1; + if (0) + { +err: + OPENSSL_PUT_ERROR(X509, ERR_R_BUF_LIB); + } + OPENSSL_free(b); + return(ret); + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/t_x509a.c b/TMessagesProj/jni/boringssl/crypto/x509/t_x509a.c new file mode 100644 index 00000000..76672688 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/t_x509a.c @@ -0,0 +1,109 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include +#include + + +/* X509_CERT_AUX and string set routines */ + +int X509_CERT_AUX_print(BIO *out, X509_CERT_AUX *aux, int indent) +{ + char oidstr[80], first; + size_t i; + int j; + if(!aux) return 1; + if(aux->trust) { + first = 1; + BIO_printf(out, "%*sTrusted Uses:\n%*s", + indent, "", indent + 2, ""); + for(i = 0; i < sk_ASN1_OBJECT_num(aux->trust); i++) { + if(!first) BIO_puts(out, ", "); + else first = 0; + OBJ_obj2txt(oidstr, sizeof oidstr, + sk_ASN1_OBJECT_value(aux->trust, i), 0); + BIO_puts(out, oidstr); + } + BIO_puts(out, "\n"); + } else BIO_printf(out, "%*sNo Trusted Uses.\n", indent, ""); + if(aux->reject) { + first = 1; + BIO_printf(out, "%*sRejected Uses:\n%*s", + indent, "", indent + 2, ""); + for(i = 0; i < sk_ASN1_OBJECT_num(aux->reject); i++) { + if(!first) BIO_puts(out, ", "); + else first = 0; + OBJ_obj2txt(oidstr, sizeof oidstr, + sk_ASN1_OBJECT_value(aux->reject, i), 0); + BIO_puts(out, oidstr); + } + BIO_puts(out, "\n"); + } else BIO_printf(out, "%*sNo Rejected Uses.\n", indent, ""); + if(aux->alias) BIO_printf(out, "%*sAlias: %s\n", indent, "", + aux->alias->data); + if(aux->keyid) { + BIO_printf(out, "%*sKey Id: ", indent, ""); + for(j = 0; j < aux->keyid->length; j++) + BIO_printf(out, "%s%02X", + j ? ":" : "", + aux->keyid->data[j]); + BIO_write(out,"\n",1); + } + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/x509/vpm_int.h b/TMessagesProj/jni/boringssl/crypto/x509/vpm_int.h new file mode 100644 index 00000000..9edbd5ad --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/vpm_int.h @@ -0,0 +1,70 @@ +/* vpm_int.h */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2013. + */ +/* ==================================================================== + * Copyright (c) 2013 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +/* internal only structure to hold additional X509_VERIFY_PARAM data */ + +struct X509_VERIFY_PARAM_ID_st + { + STACK_OF(OPENSSL_STRING) *hosts; /* Set of acceptable names */ + unsigned int hostflags; /* Flags to control matching features */ + char *peername; /* Matching hostname in peer certificate */ + char *email; /* If not NULL email address to match */ + size_t emaillen; + unsigned char *ip; /* If not NULL IP address to match */ + size_t iplen; /* Length of IP address */ + }; diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509.c b/TMessagesProj/jni/boringssl/crypto/x509/x509.c new file mode 100644 index 00000000..31f9e1eb --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509.c @@ -0,0 +1,152 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + +int PKCS8_pkey_set0(PKCS8_PRIV_KEY_INFO *priv, ASN1_OBJECT *aobj, int version, + int ptype, void *pval, uint8_t *penc, int penclen) { + uint8_t **ppenc = NULL; + if (version >= 0) { + if (!ASN1_INTEGER_set(priv->version, version)) { + return 0; + } + } + + if (penc) { + int pmtype; + ASN1_OCTET_STRING *oct; + + oct = ASN1_OCTET_STRING_new(); + if (!oct) { + return 0; + } + oct->data = penc; + ppenc = &oct->data; + oct->length = penclen; + if (priv->broken == PKCS8_NO_OCTET) { + pmtype = V_ASN1_SEQUENCE; + } else { + pmtype = V_ASN1_OCTET_STRING; + } + ASN1_TYPE_set(priv->pkey, pmtype, oct); + } + + if (!X509_ALGOR_set0(priv->pkeyalg, aobj, ptype, pval)) { + /* If call fails do not swallow 'enc' */ + if (ppenc) { + *ppenc = NULL; + } + return 0; + } + + return 1; +} + +int PKCS8_pkey_get0(ASN1_OBJECT **ppkalg, const uint8_t **pk, int *ppklen, + X509_ALGOR **pa, PKCS8_PRIV_KEY_INFO *p8) { + if (ppkalg) { + *ppkalg = p8->pkeyalg->algorithm; + } + + if (p8->pkey->type == V_ASN1_OCTET_STRING) { + p8->broken = PKCS8_OK; + if (pk) { + *pk = p8->pkey->value.octet_string->data; + *ppklen = p8->pkey->value.octet_string->length; + } + } else if (p8->pkey->type == V_ASN1_SEQUENCE) { + p8->broken = PKCS8_NO_OCTET; + if (pk) { + *pk = p8->pkey->value.sequence->data; + *ppklen = p8->pkey->value.sequence->length; + } + } else { + return 0; + } + + if (pa) { + *pa = p8->pkeyalg; + } + return 1; +} + +int X509_signature_dump(BIO *bp, const ASN1_STRING *sig, int indent) { + const uint8_t *s; + int i, n; + + n = sig->length; + s = sig->data; + for (i = 0; i < n; i++) { + if ((i % 18) == 0) { + if (BIO_write(bp, "\n", 1) <= 0 || + BIO_indent(bp, indent, indent) <= 0) { + return 0; + } + } + if (BIO_printf(bp, "%02x%s", s[i], ((i + 1) == n) ? "" : ":") <= 0) { + return 0; + } + } + if (BIO_write(bp, "\n", 1) != 1) { + return 0; + } + + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509_att.c b/TMessagesProj/jni/boringssl/crypto/x509/x509_att.c new file mode 100644 index 00000000..14914849 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509_att.c @@ -0,0 +1,353 @@ +/* crypto/x509/x509_att.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include +#include +#include + + +int X509at_get_attr_count(const STACK_OF(X509_ATTRIBUTE) *x) +{ + return sk_X509_ATTRIBUTE_num(x); +} + +int X509at_get_attr_by_NID(const STACK_OF(X509_ATTRIBUTE) *x, int nid, + int lastpos) +{ + const ASN1_OBJECT *obj; + + obj=OBJ_nid2obj(nid); + if (obj == NULL) return(-2); + return(X509at_get_attr_by_OBJ(x,obj,lastpos)); +} + +int X509at_get_attr_by_OBJ(const STACK_OF(X509_ATTRIBUTE) *sk, const ASN1_OBJECT *obj, + int lastpos) +{ + int n; + X509_ATTRIBUTE *ex; + + if (sk == NULL) return(-1); + lastpos++; + if (lastpos < 0) + lastpos=0; + n=sk_X509_ATTRIBUTE_num(sk); + for ( ; lastpos < n; lastpos++) + { + ex=sk_X509_ATTRIBUTE_value(sk,lastpos); + if (OBJ_cmp(ex->object,obj) == 0) + return(lastpos); + } + return(-1); +} + +X509_ATTRIBUTE *X509at_get_attr(const STACK_OF(X509_ATTRIBUTE) *x, int loc) +{ + if (x == NULL || loc < 0 || sk_X509_ATTRIBUTE_num(x) <= (size_t) loc) + return NULL; + else + return sk_X509_ATTRIBUTE_value(x,loc); +} + +X509_ATTRIBUTE *X509at_delete_attr(STACK_OF(X509_ATTRIBUTE) *x, int loc) +{ + X509_ATTRIBUTE *ret; + + if (x == NULL || loc < 0 || sk_X509_ATTRIBUTE_num(x) <= (size_t) loc) + return(NULL); + ret=sk_X509_ATTRIBUTE_delete(x,loc); + return(ret); +} + +STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x, + X509_ATTRIBUTE *attr) +{ + X509_ATTRIBUTE *new_attr=NULL; + STACK_OF(X509_ATTRIBUTE) *sk=NULL; + + if (x == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_PASSED_NULL_PARAMETER); + goto err2; + } + + if (*x == NULL) + { + if ((sk=sk_X509_ATTRIBUTE_new_null()) == NULL) + goto err; + } + else + sk= *x; + + if ((new_attr=X509_ATTRIBUTE_dup(attr)) == NULL) + goto err2; + if (!sk_X509_ATTRIBUTE_push(sk,new_attr)) + goto err; + if (*x == NULL) + *x=sk; + return(sk); +err: + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); +err2: + if (new_attr != NULL) X509_ATTRIBUTE_free(new_attr); + if (sk != NULL) sk_X509_ATTRIBUTE_free(sk); + return(NULL); +} + +STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_OBJ(STACK_OF(X509_ATTRIBUTE) **x, + const ASN1_OBJECT *obj, int type, + const unsigned char *bytes, int len) +{ + X509_ATTRIBUTE *attr; + STACK_OF(X509_ATTRIBUTE) *ret; + attr = X509_ATTRIBUTE_create_by_OBJ(NULL, obj, type, bytes, len); + if(!attr) return 0; + ret = X509at_add1_attr(x, attr); + X509_ATTRIBUTE_free(attr); + return ret; +} + +STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_NID(STACK_OF(X509_ATTRIBUTE) **x, + int nid, int type, + const unsigned char *bytes, int len) +{ + X509_ATTRIBUTE *attr; + STACK_OF(X509_ATTRIBUTE) *ret; + attr = X509_ATTRIBUTE_create_by_NID(NULL, nid, type, bytes, len); + if(!attr) return 0; + ret = X509at_add1_attr(x, attr); + X509_ATTRIBUTE_free(attr); + return ret; +} + +STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_txt(STACK_OF(X509_ATTRIBUTE) **x, + const char *attrname, int type, + const unsigned char *bytes, int len) +{ + X509_ATTRIBUTE *attr; + STACK_OF(X509_ATTRIBUTE) *ret; + attr = X509_ATTRIBUTE_create_by_txt(NULL, attrname, type, bytes, len); + if(!attr) return 0; + ret = X509at_add1_attr(x, attr); + X509_ATTRIBUTE_free(attr); + return ret; +} + +void *X509at_get0_data_by_OBJ(STACK_OF(X509_ATTRIBUTE) *x, + ASN1_OBJECT *obj, int lastpos, int type) +{ + int i; + X509_ATTRIBUTE *at; + i = X509at_get_attr_by_OBJ(x, obj, lastpos); + if (i == -1) + return NULL; + if ((lastpos <= -2) && (X509at_get_attr_by_OBJ(x, obj, i) != -1)) + return NULL; + at = X509at_get_attr(x, i); + if (lastpos <= -3 && (X509_ATTRIBUTE_count(at) != 1)) + return NULL; + return X509_ATTRIBUTE_get0_data(at, 0, type, NULL); +} + +X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_NID(X509_ATTRIBUTE **attr, int nid, + int atrtype, const void *data, int len) +{ + const ASN1_OBJECT *obj; + + obj=OBJ_nid2obj(nid); + if (obj == NULL) + { + OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_NID); + return(NULL); + } + return X509_ATTRIBUTE_create_by_OBJ(attr,obj,atrtype,data,len); +} + +X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_OBJ(X509_ATTRIBUTE **attr, + const ASN1_OBJECT *obj, int atrtype, const void *data, int len) +{ + X509_ATTRIBUTE *ret; + + if ((attr == NULL) || (*attr == NULL)) + { + if ((ret=X509_ATTRIBUTE_new()) == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return(NULL); + } + } + else + ret= *attr; + + if (!X509_ATTRIBUTE_set1_object(ret,obj)) + goto err; + if (!X509_ATTRIBUTE_set1_data(ret,atrtype,data,len)) + goto err; + + if ((attr != NULL) && (*attr == NULL)) *attr=ret; + return(ret); +err: + if ((attr == NULL) || (ret != *attr)) + X509_ATTRIBUTE_free(ret); + return(NULL); +} + +X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_txt(X509_ATTRIBUTE **attr, + const char *atrname, int type, const unsigned char *bytes, int len) + { + ASN1_OBJECT *obj; + X509_ATTRIBUTE *nattr; + + obj=OBJ_txt2obj(atrname, 0); + if (obj == NULL) + { + OPENSSL_PUT_ERROR(X509, X509_R_INVALID_FIELD_NAME); + ERR_add_error_data(2, "name=", atrname); + return(NULL); + } + nattr = X509_ATTRIBUTE_create_by_OBJ(attr,obj,type,bytes,len); + ASN1_OBJECT_free(obj); + return nattr; + } + +int X509_ATTRIBUTE_set1_object(X509_ATTRIBUTE *attr, const ASN1_OBJECT *obj) +{ + if ((attr == NULL) || (obj == NULL)) + return(0); + ASN1_OBJECT_free(attr->object); + attr->object=OBJ_dup(obj); + return attr->object != NULL; +} + +int X509_ATTRIBUTE_set1_data(X509_ATTRIBUTE *attr, int attrtype, const void *data, int len) +{ + ASN1_TYPE *ttmp; + ASN1_STRING *stmp = NULL; + int atype = 0; + if (!attr) return 0; + if(attrtype & MBSTRING_FLAG) { + stmp = ASN1_STRING_set_by_NID(NULL, data, len, attrtype, + OBJ_obj2nid(attr->object)); + if(!stmp) { + OPENSSL_PUT_ERROR(X509, ERR_R_ASN1_LIB); + return 0; + } + atype = stmp->type; + } else if (len != -1){ + if(!(stmp = ASN1_STRING_type_new(attrtype))) goto err; + if(!ASN1_STRING_set(stmp, data, len)) goto err; + atype = attrtype; + } + if(!(attr->value.set = sk_ASN1_TYPE_new_null())) goto err; + attr->single = 0; + /* This is a bit naughty because the attribute should really have + * at least one value but some types use and zero length SET and + * require this. + */ + if (attrtype == 0) + return 1; + if(!(ttmp = ASN1_TYPE_new())) goto err; + if ((len == -1) && !(attrtype & MBSTRING_FLAG)) + { + if (!ASN1_TYPE_set1(ttmp, attrtype, data)) + goto err; + } + else + ASN1_TYPE_set(ttmp, atype, stmp); + if(!sk_ASN1_TYPE_push(attr->value.set, ttmp)) goto err; + return 1; + err: + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return 0; +} + +int X509_ATTRIBUTE_count(X509_ATTRIBUTE *attr) +{ + if(!attr->single) return sk_ASN1_TYPE_num(attr->value.set); + if(attr->value.single) return 1; + return 0; +} + +ASN1_OBJECT *X509_ATTRIBUTE_get0_object(X509_ATTRIBUTE *attr) +{ + if (attr == NULL) return(NULL); + return(attr->object); +} + +void *X509_ATTRIBUTE_get0_data(X509_ATTRIBUTE *attr, int idx, + int atrtype, void *data) +{ + ASN1_TYPE *ttmp; + ttmp = X509_ATTRIBUTE_get0_type(attr, idx); + if(!ttmp) return NULL; + if(atrtype != ASN1_TYPE_get(ttmp)){ + OPENSSL_PUT_ERROR(X509, X509_R_WRONG_TYPE); + return NULL; + } + return ttmp->value.ptr; +} + +ASN1_TYPE *X509_ATTRIBUTE_get0_type(X509_ATTRIBUTE *attr, int idx) +{ + if (attr == NULL) return(NULL); + if(idx >= X509_ATTRIBUTE_count(attr)) return NULL; + if(!attr->single) return sk_ASN1_TYPE_value(attr->value.set, idx); + else return attr->value.single; +} diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509_cmp.c b/TMessagesProj/jni/boringssl/crypto/x509/x509_cmp.c new file mode 100644 index 00000000..0e35f3ea --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509_cmp.c @@ -0,0 +1,490 @@ +/* crypto/x509/x509_cmp.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +int X509_issuer_and_serial_cmp(const X509 *a, const X509 *b) + { + int i; + X509_CINF *ai,*bi; + + ai=a->cert_info; + bi=b->cert_info; + i=M_ASN1_INTEGER_cmp(ai->serialNumber,bi->serialNumber); + if (i) return(i); + return(X509_NAME_cmp(ai->issuer,bi->issuer)); + } + +unsigned long X509_issuer_and_serial_hash(X509 *a) + { + unsigned long ret=0; + EVP_MD_CTX ctx; + unsigned char md[16]; + char *f; + + EVP_MD_CTX_init(&ctx); + f=X509_NAME_oneline(a->cert_info->issuer,NULL,0); + if (!EVP_DigestInit_ex(&ctx, EVP_md5(), NULL)) + goto err; + if (!EVP_DigestUpdate(&ctx,(unsigned char *)f,strlen(f))) + goto err; + OPENSSL_free(f); + if(!EVP_DigestUpdate(&ctx,(unsigned char *)a->cert_info->serialNumber->data, + (unsigned long)a->cert_info->serialNumber->length)) + goto err; + if (!EVP_DigestFinal_ex(&ctx,&(md[0]),NULL)) + goto err; + ret=( ((unsigned long)md[0] )|((unsigned long)md[1]<<8L)| + ((unsigned long)md[2]<<16L)|((unsigned long)md[3]<<24L) + )&0xffffffffL; + err: + EVP_MD_CTX_cleanup(&ctx); + return(ret); + } + +int X509_issuer_name_cmp(const X509 *a, const X509 *b) + { + return(X509_NAME_cmp(a->cert_info->issuer,b->cert_info->issuer)); + } + +int X509_subject_name_cmp(const X509 *a, const X509 *b) + { + return(X509_NAME_cmp(a->cert_info->subject,b->cert_info->subject)); + } + +int X509_CRL_cmp(const X509_CRL *a, const X509_CRL *b) + { + return(X509_NAME_cmp(a->crl->issuer,b->crl->issuer)); + } + +int X509_CRL_match(const X509_CRL *a, const X509_CRL *b) + { + return memcmp(a->sha1_hash, b->sha1_hash, 20); + } + +X509_NAME *X509_get_issuer_name(X509 *a) + { + return(a->cert_info->issuer); + } + +unsigned long X509_issuer_name_hash(X509 *x) + { + return(X509_NAME_hash(x->cert_info->issuer)); + } + +unsigned long X509_issuer_name_hash_old(X509 *x) + { + return(X509_NAME_hash_old(x->cert_info->issuer)); + } + +X509_NAME *X509_get_subject_name(X509 *a) + { + return(a->cert_info->subject); + } + +ASN1_INTEGER *X509_get_serialNumber(X509 *a) + { + return(a->cert_info->serialNumber); + } + +unsigned long X509_subject_name_hash(X509 *x) + { + return(X509_NAME_hash(x->cert_info->subject)); + } + +unsigned long X509_subject_name_hash_old(X509 *x) + { + return(X509_NAME_hash_old(x->cert_info->subject)); + } + +/* Compare two certificates: they must be identical for + * this to work. NB: Although "cmp" operations are generally + * prototyped to take "const" arguments (eg. for use in + * STACKs), the way X509 handling is - these operations may + * involve ensuring the hashes are up-to-date and ensuring + * certain cert information is cached. So this is the point + * where the "depth-first" constification tree has to halt + * with an evil cast. + */ +int X509_cmp(const X509 *a, const X509 *b) +{ + int rv; + /* ensure hash is valid */ + X509_check_purpose((X509 *)a, -1, 0); + X509_check_purpose((X509 *)b, -1, 0); + + rv = memcmp(a->sha1_hash, b->sha1_hash, SHA_DIGEST_LENGTH); + if (rv) + return rv; + /* Check for match against stored encoding too */ + if (!a->cert_info->enc.modified && !b->cert_info->enc.modified) + { + rv = (int)(a->cert_info->enc.len - b->cert_info->enc.len); + if (rv) + return rv; + return memcmp(a->cert_info->enc.enc, b->cert_info->enc.enc, + a->cert_info->enc.len); + } + return rv; +} + + +int X509_NAME_cmp(const X509_NAME *a, const X509_NAME *b) + { + int ret; + + /* Ensure canonical encoding is present and up to date */ + + if (!a->canon_enc || a->modified) + { + ret = i2d_X509_NAME((X509_NAME *)a, NULL); + if (ret < 0) + return -2; + } + + if (!b->canon_enc || b->modified) + { + ret = i2d_X509_NAME((X509_NAME *)b, NULL); + if (ret < 0) + return -2; + } + + ret = a->canon_enclen - b->canon_enclen; + + if (ret) + return ret; + + return memcmp(a->canon_enc, b->canon_enc, a->canon_enclen); + + } + +unsigned long X509_NAME_hash(X509_NAME *x) + { + unsigned long ret=0; + unsigned char md[SHA_DIGEST_LENGTH]; + + /* Make sure X509_NAME structure contains valid cached encoding */ + i2d_X509_NAME(x,NULL); + if (!EVP_Digest(x->canon_enc, x->canon_enclen, md, NULL, EVP_sha1(), + NULL)) + return 0; + + ret=( ((unsigned long)md[0] )|((unsigned long)md[1]<<8L)| + ((unsigned long)md[2]<<16L)|((unsigned long)md[3]<<24L) + )&0xffffffffL; + return(ret); + } + + +/* I now DER encode the name and hash it. Since I cache the DER encoding, + * this is reasonably efficient. */ + +unsigned long X509_NAME_hash_old(X509_NAME *x) + { + EVP_MD_CTX md_ctx; + unsigned long ret=0; + unsigned char md[16]; + + /* Make sure X509_NAME structure contains valid cached encoding */ + i2d_X509_NAME(x,NULL); + EVP_MD_CTX_init(&md_ctx); + /* EVP_MD_CTX_set_flags(&md_ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); */ + if (EVP_DigestInit_ex(&md_ctx, EVP_md5(), NULL) + && EVP_DigestUpdate(&md_ctx, x->bytes->data, x->bytes->length) + && EVP_DigestFinal_ex(&md_ctx,md,NULL)) + ret=(((unsigned long)md[0] )|((unsigned long)md[1]<<8L)| + ((unsigned long)md[2]<<16L)|((unsigned long)md[3]<<24L) + )&0xffffffffL; + EVP_MD_CTX_cleanup(&md_ctx); + + return(ret); + } + +/* Search a stack of X509 for a match */ +X509 *X509_find_by_issuer_and_serial(STACK_OF(X509) *sk, X509_NAME *name, + ASN1_INTEGER *serial) + { + size_t i; + X509_CINF cinf; + X509 x,*x509=NULL; + + if(!sk) return NULL; + + x.cert_info= &cinf; + cinf.serialNumber=serial; + cinf.issuer=name; + + for (i=0; icert_info == NULL)) + return(NULL); + return(X509_PUBKEY_get(x->cert_info->key)); + } + +ASN1_BIT_STRING *X509_get0_pubkey_bitstr(const X509 *x) + { + if(!x) return NULL; + return x->cert_info->key->public_key; + } + + +int X509_check_private_key(X509 *x, EVP_PKEY *k) + { + EVP_PKEY *xk; + int ret; + + xk=X509_get_pubkey(x); + + if (xk) + ret = EVP_PKEY_cmp(xk, k); + else + ret = -2; + + switch (ret) + { + case 1: + break; + case 0: + OPENSSL_PUT_ERROR(X509, X509_R_KEY_VALUES_MISMATCH); + break; + case -1: + OPENSSL_PUT_ERROR(X509, X509_R_KEY_TYPE_MISMATCH); + break; + case -2: + OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_KEY_TYPE); + } + if (xk) + EVP_PKEY_free(xk); + if (ret > 0) + return 1; + return 0; + } + +/* Check a suite B algorithm is permitted: pass in a public key and + * the NID of its signature (or 0 if no signature). The pflags is + * a pointer to a flags field which must contain the suite B verification + * flags. + */ + + +static int check_suite_b(EVP_PKEY *pkey, int sign_nid, unsigned long *pflags) + { + const EC_GROUP *grp = NULL; + int curve_nid; + if (pkey && pkey->type == EVP_PKEY_EC) + grp = EC_KEY_get0_group(pkey->pkey.ec); + if (!grp) + return X509_V_ERR_SUITE_B_INVALID_ALGORITHM; + curve_nid = EC_GROUP_get_curve_name(grp); + /* Check curve is consistent with LOS */ + if (curve_nid == NID_secp384r1) /* P-384 */ + { + /* Check signature algorithm is consistent with + * curve. + */ + if (sign_nid != -1 && sign_nid != NID_ecdsa_with_SHA384) + return X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM; + if (!(*pflags & X509_V_FLAG_SUITEB_192_LOS)) + return X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED; + /* If we encounter P-384 we cannot use P-256 later */ + *pflags &= ~X509_V_FLAG_SUITEB_128_LOS_ONLY; + } + else if (curve_nid == NID_X9_62_prime256v1) /* P-256 */ + { + if (sign_nid != -1 && sign_nid != NID_ecdsa_with_SHA256) + return X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM; + if (!(*pflags & X509_V_FLAG_SUITEB_128_LOS_ONLY)) + return X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED; + } + else + return X509_V_ERR_SUITE_B_INVALID_CURVE; + + return X509_V_OK; + } + +int X509_chain_check_suiteb(int *perror_depth, X509 *x, STACK_OF(X509) *chain, + unsigned long flags) + { + int rv, sign_nid; + size_t i; + EVP_PKEY *pk = NULL; + unsigned long tflags; + if (!(flags & X509_V_FLAG_SUITEB_128_LOS)) + return X509_V_OK; + tflags = flags; + /* If no EE certificate passed in must be first in chain */ + if (x == NULL) + { + x = sk_X509_value(chain, 0); + i = 1; + } + else + i = 0; + + if (X509_get_version(x) != 2) + { + rv = X509_V_ERR_SUITE_B_INVALID_VERSION; + /* Correct error depth */ + i = 0; + goto end; + } + + pk = X509_get_pubkey(x); + /* Check EE key only */ + rv = check_suite_b(pk, -1, &tflags); + if (rv != X509_V_OK) + { + /* Correct error depth */ + i = 0; + goto end; + } + for(; i < sk_X509_num(chain); i++) + { + sign_nid = X509_get_signature_nid(x); + x = sk_X509_value(chain, i); + if (X509_get_version(x) != 2) + { + rv = X509_V_ERR_SUITE_B_INVALID_VERSION; + goto end; + } + EVP_PKEY_free(pk); + pk = X509_get_pubkey(x); + rv = check_suite_b(pk, sign_nid, &tflags); + if (rv != X509_V_OK) + goto end; + } + + /* Final check: root CA signature */ + rv = check_suite_b(pk, X509_get_signature_nid(x), &tflags); + end: + if (pk) + EVP_PKEY_free(pk); + if (rv != X509_V_OK) + { + /* Invalid signature or LOS errors are for previous cert */ + if ((rv == X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM + || rv == X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED) && i) + i--; + /* If we have LOS error and flags changed then we are signing + * P-384 with P-256. Use more meaninggul error. + */ + if (rv == X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED && flags != tflags) + rv = X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256; + if (perror_depth) + *perror_depth = i; + } + return rv; + } + +int X509_CRL_check_suiteb(X509_CRL *crl, EVP_PKEY *pk, unsigned long flags) + { + int sign_nid; + if (!(flags & X509_V_FLAG_SUITEB_128_LOS)) + return X509_V_OK; + sign_nid = OBJ_obj2nid(crl->crl->sig_alg->algorithm); + return check_suite_b(pk, sign_nid, &flags); + } + +/* Not strictly speaking an "up_ref" as a STACK doesn't have a reference + * count but it has the same effect by duping the STACK and upping the ref + * of each X509 structure. + */ +STACK_OF(X509) *X509_chain_up_ref(STACK_OF(X509) *chain) + { + STACK_OF(X509) *ret; + size_t i; + ret = sk_X509_dup(chain); + for (i = 0; i < sk_X509_num(ret); i++) + { + X509_up_ref(sk_X509_value(ret, i)); + } + return ret; + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509_d2.c b/TMessagesProj/jni/boringssl/crypto/x509/x509_d2.c new file mode 100644 index 00000000..2161d851 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509_d2.c @@ -0,0 +1,105 @@ +/* crypto/x509/x509_d2.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include + + +#ifndef OPENSSL_NO_STDIO +int X509_STORE_set_default_paths(X509_STORE *ctx) + { + X509_LOOKUP *lookup; + + lookup=X509_STORE_add_lookup(ctx,X509_LOOKUP_file()); + if (lookup == NULL) return(0); + X509_LOOKUP_load_file(lookup,NULL,X509_FILETYPE_DEFAULT); + + lookup=X509_STORE_add_lookup(ctx,X509_LOOKUP_hash_dir()); + if (lookup == NULL) return(0); + X509_LOOKUP_add_dir(lookup,NULL,X509_FILETYPE_DEFAULT); + + /* clear any errors */ + ERR_clear_error(); + + return(1); + } + +int X509_STORE_load_locations(X509_STORE *ctx, const char *file, + const char *path) + { + X509_LOOKUP *lookup; + + if (file != NULL) + { + lookup=X509_STORE_add_lookup(ctx,X509_LOOKUP_file()); + if (lookup == NULL) return(0); + if (X509_LOOKUP_load_file(lookup,file,X509_FILETYPE_PEM) != 1) + return(0); + } + if (path != NULL) + { + lookup=X509_STORE_add_lookup(ctx,X509_LOOKUP_hash_dir()); + if (lookup == NULL) return(0); + if (X509_LOOKUP_add_dir(lookup,path,X509_FILETYPE_PEM) != 1) + return(0); + } + if ((path == NULL) && (file == NULL)) + return(0); + return(1); + } + +#endif diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509_def.c b/TMessagesProj/jni/boringssl/crypto/x509/x509_def.c new file mode 100644 index 00000000..dbae289f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509_def.c @@ -0,0 +1,88 @@ +/* crypto/x509/x509_def.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + + +/* TODO(fork): cleanup */ + +#define OPENSSLDIR "/etc/ssl" +#define X509_CERT_AREA OPENSSLDIR +#define X509_CERT_DIR OPENSSLDIR "/certs" +#define X509_CERT_FILE OPENSSLDIR "/cert.pem" +#define X509_PRIVATE_DIR OPENSSLDIR "/private" +#define X509_CERT_DIR_EVP "SSL_CERT_DIR" +#define X509_CERT_FILE_EVP "SSL_CERT_FILE" + +const char *X509_get_default_private_dir(void) + { return(X509_PRIVATE_DIR); } + +const char *X509_get_default_cert_area(void) + { return(X509_CERT_AREA); } + +const char *X509_get_default_cert_dir(void) + { return(X509_CERT_DIR); } + +const char *X509_get_default_cert_file(void) + { return(X509_CERT_FILE); } + +const char *X509_get_default_cert_dir_env(void) + { return(X509_CERT_DIR_EVP); } + +const char *X509_get_default_cert_file_env(void) + { return(X509_CERT_FILE_EVP); } + diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509_ext.c b/TMessagesProj/jni/boringssl/crypto/x509/x509_ext.c new file mode 100644 index 00000000..2f1e0c5a --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509_ext.c @@ -0,0 +1,206 @@ +/* crypto/x509/x509_ext.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include +#include +#include + + +int X509_CRL_get_ext_count(X509_CRL *x) + { + return(X509v3_get_ext_count(x->crl->extensions)); + } + +int X509_CRL_get_ext_by_NID(X509_CRL *x, int nid, int lastpos) + { + return(X509v3_get_ext_by_NID(x->crl->extensions,nid,lastpos)); + } + +int X509_CRL_get_ext_by_OBJ(X509_CRL *x, ASN1_OBJECT *obj, int lastpos) + { + return(X509v3_get_ext_by_OBJ(x->crl->extensions,obj,lastpos)); + } + +int X509_CRL_get_ext_by_critical(X509_CRL *x, int crit, int lastpos) + { + return(X509v3_get_ext_by_critical(x->crl->extensions,crit,lastpos)); + } + +X509_EXTENSION *X509_CRL_get_ext(X509_CRL *x, int loc) + { + return(X509v3_get_ext(x->crl->extensions,loc)); + } + +X509_EXTENSION *X509_CRL_delete_ext(X509_CRL *x, int loc) + { + return(X509v3_delete_ext(x->crl->extensions,loc)); + } + +void *X509_CRL_get_ext_d2i(X509_CRL *x, int nid, int *crit, int *idx) +{ + return X509V3_get_d2i(x->crl->extensions, nid, crit, idx); +} + +int X509_CRL_add1_ext_i2d(X509_CRL *x, int nid, void *value, int crit, + unsigned long flags) +{ + return X509V3_add1_i2d(&x->crl->extensions, nid, value, crit, flags); +} + +int X509_CRL_add_ext(X509_CRL *x, X509_EXTENSION *ex, int loc) + { + return(X509v3_add_ext(&(x->crl->extensions),ex,loc) != NULL); + } + +int X509_get_ext_count(X509 *x) + { + return(X509v3_get_ext_count(x->cert_info->extensions)); + } + +int X509_get_ext_by_NID(X509 *x, int nid, int lastpos) + { + return(X509v3_get_ext_by_NID(x->cert_info->extensions,nid,lastpos)); + } + +int X509_get_ext_by_OBJ(X509 *x, ASN1_OBJECT *obj, int lastpos) + { + return(X509v3_get_ext_by_OBJ(x->cert_info->extensions,obj,lastpos)); + } + +int X509_get_ext_by_critical(X509 *x, int crit, int lastpos) + { + return(X509v3_get_ext_by_critical(x->cert_info->extensions,crit,lastpos)); + } + +X509_EXTENSION *X509_get_ext(X509 *x, int loc) + { + return(X509v3_get_ext(x->cert_info->extensions,loc)); + } + +X509_EXTENSION *X509_delete_ext(X509 *x, int loc) + { + return(X509v3_delete_ext(x->cert_info->extensions,loc)); + } + +int X509_add_ext(X509 *x, X509_EXTENSION *ex, int loc) + { + return(X509v3_add_ext(&(x->cert_info->extensions),ex,loc) != NULL); + } + +void *X509_get_ext_d2i(X509 *x, int nid, int *crit, int *idx) +{ + return X509V3_get_d2i(x->cert_info->extensions, nid, crit, idx); +} + +int X509_add1_ext_i2d(X509 *x, int nid, void *value, int crit, + unsigned long flags) +{ + return X509V3_add1_i2d(&x->cert_info->extensions, nid, value, crit, + flags); +} + +int X509_REVOKED_get_ext_count(X509_REVOKED *x) + { + return(X509v3_get_ext_count(x->extensions)); + } + +int X509_REVOKED_get_ext_by_NID(X509_REVOKED *x, int nid, int lastpos) + { + return(X509v3_get_ext_by_NID(x->extensions,nid,lastpos)); + } + +int X509_REVOKED_get_ext_by_OBJ(X509_REVOKED *x, ASN1_OBJECT *obj, + int lastpos) + { + return(X509v3_get_ext_by_OBJ(x->extensions,obj,lastpos)); + } + +int X509_REVOKED_get_ext_by_critical(X509_REVOKED *x, int crit, int lastpos) + { + return(X509v3_get_ext_by_critical(x->extensions,crit,lastpos)); + } + +X509_EXTENSION *X509_REVOKED_get_ext(X509_REVOKED *x, int loc) + { + return(X509v3_get_ext(x->extensions,loc)); + } + +X509_EXTENSION *X509_REVOKED_delete_ext(X509_REVOKED *x, int loc) + { + return(X509v3_delete_ext(x->extensions,loc)); + } + +int X509_REVOKED_add_ext(X509_REVOKED *x, X509_EXTENSION *ex, int loc) + { + return(X509v3_add_ext(&(x->extensions),ex,loc) != NULL); + } + +void *X509_REVOKED_get_ext_d2i(X509_REVOKED *x, int nid, int *crit, int *idx) +{ + return X509V3_get_d2i(x->extensions, nid, crit, idx); +} + +int X509_REVOKED_add1_ext_i2d(X509_REVOKED *x, int nid, void *value, int crit, + unsigned long flags) +{ + return X509V3_add1_i2d(&x->extensions, nid, value, crit, flags); +} + +IMPLEMENT_ASN1_SET_OF(X509_EXTENSION) diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509_lu.c b/TMessagesProj/jni/boringssl/crypto/x509/x509_lu.c new file mode 100644 index 00000000..aa2f5e54 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509_lu.c @@ -0,0 +1,732 @@ +/* crypto/x509/x509_lu.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "../internal.h" + + +X509_LOOKUP *X509_LOOKUP_new(X509_LOOKUP_METHOD *method) + { + X509_LOOKUP *ret; + + ret=(X509_LOOKUP *)OPENSSL_malloc(sizeof(X509_LOOKUP)); + if (ret == NULL) return NULL; + + ret->init=0; + ret->skip=0; + ret->method=method; + ret->method_data=NULL; + ret->store_ctx=NULL; + if ((method->new_item != NULL) && !method->new_item(ret)) + { + OPENSSL_free(ret); + return NULL; + } + return ret; + } + +void X509_LOOKUP_free(X509_LOOKUP *ctx) + { + if (ctx == NULL) return; + if ( (ctx->method != NULL) && + (ctx->method->free != NULL)) + (*ctx->method->free)(ctx); + OPENSSL_free(ctx); + } + +int X509_LOOKUP_init(X509_LOOKUP *ctx) + { + if (ctx->method == NULL) return 0; + if (ctx->method->init != NULL) + return ctx->method->init(ctx); + else + return 1; + } + +int X509_LOOKUP_shutdown(X509_LOOKUP *ctx) + { + if (ctx->method == NULL) return 0; + if (ctx->method->shutdown != NULL) + return ctx->method->shutdown(ctx); + else + return 1; + } + +int X509_LOOKUP_ctrl(X509_LOOKUP *ctx, int cmd, const char *argc, long argl, + char **ret) + { + if (ctx->method == NULL) return -1; + if (ctx->method->ctrl != NULL) + return ctx->method->ctrl(ctx,cmd,argc,argl,ret); + else + return 1; + } + +int X509_LOOKUP_by_subject(X509_LOOKUP *ctx, int type, X509_NAME *name, + X509_OBJECT *ret) + { + if ((ctx->method == NULL) || (ctx->method->get_by_subject == NULL)) + return X509_LU_FAIL; + if (ctx->skip) return 0; + return ctx->method->get_by_subject(ctx,type,name,ret); + } + +int X509_LOOKUP_by_issuer_serial(X509_LOOKUP *ctx, int type, X509_NAME *name, + ASN1_INTEGER *serial, X509_OBJECT *ret) + { + if ((ctx->method == NULL) || + (ctx->method->get_by_issuer_serial == NULL)) + return X509_LU_FAIL; + return ctx->method->get_by_issuer_serial(ctx,type,name,serial,ret); + } + +int X509_LOOKUP_by_fingerprint(X509_LOOKUP *ctx, int type, + unsigned char *bytes, int len, X509_OBJECT *ret) + { + if ((ctx->method == NULL) || (ctx->method->get_by_fingerprint == NULL)) + return X509_LU_FAIL; + return ctx->method->get_by_fingerprint(ctx,type,bytes,len,ret); + } + +int X509_LOOKUP_by_alias(X509_LOOKUP *ctx, int type, char *str, int len, + X509_OBJECT *ret) + { + if ((ctx->method == NULL) || (ctx->method->get_by_alias == NULL)) + return X509_LU_FAIL; + return ctx->method->get_by_alias(ctx,type,str,len,ret); + } + + +static int x509_object_cmp(const X509_OBJECT **a, const X509_OBJECT **b) + { + int ret; + + ret=((*a)->type - (*b)->type); + if (ret) return ret; + switch ((*a)->type) + { + case X509_LU_X509: + ret=X509_subject_name_cmp((*a)->data.x509,(*b)->data.x509); + break; + case X509_LU_CRL: + ret=X509_CRL_cmp((*a)->data.crl,(*b)->data.crl); + break; + default: + /* abort(); */ + return 0; + } + return ret; + } + +X509_STORE *X509_STORE_new(void) + { + X509_STORE *ret; + + if ((ret=(X509_STORE *)OPENSSL_malloc(sizeof(X509_STORE))) == NULL) + return NULL; + memset(ret, 0, sizeof(*ret)); + ret->objs = sk_X509_OBJECT_new(x509_object_cmp); + CRYPTO_MUTEX_init(&ret->objs_lock); + ret->cache = 1; + ret->get_cert_methods = sk_X509_LOOKUP_new_null(); + + if ((ret->param = X509_VERIFY_PARAM_new()) == NULL) + goto err; + + ret->references = 1; + return ret; +err: + if (ret) + { + if (ret->param) + X509_VERIFY_PARAM_free(ret->param); + if (ret->get_cert_methods) + sk_X509_LOOKUP_free(ret->get_cert_methods); + if (ret->objs) + sk_X509_OBJECT_free(ret->objs); + OPENSSL_free(ret); + } + return NULL; + } + +static void cleanup(X509_OBJECT *a) + { + if (a->type == X509_LU_X509) + { + X509_free(a->data.x509); + } + else if (a->type == X509_LU_CRL) + { + X509_CRL_free(a->data.crl); + } + else + { + /* abort(); */ + } + + OPENSSL_free(a); + } + +void X509_STORE_free(X509_STORE *vfy) + { + size_t j; + STACK_OF(X509_LOOKUP) *sk; + X509_LOOKUP *lu; + + if (vfy == NULL) + return; + + if (!CRYPTO_refcount_dec_and_test_zero(&vfy->references)) { + return; + } + + CRYPTO_MUTEX_cleanup(&vfy->objs_lock); + + sk=vfy->get_cert_methods; + for (j=0; jobjs, cleanup); + + if (vfy->param) + X509_VERIFY_PARAM_free(vfy->param); + OPENSSL_free(vfy); + } + +X509_LOOKUP *X509_STORE_add_lookup(X509_STORE *v, X509_LOOKUP_METHOD *m) + { + size_t i; + STACK_OF(X509_LOOKUP) *sk; + X509_LOOKUP *lu; + + sk=v->get_cert_methods; + for (i=0; imethod) + { + return lu; + } + } + /* a new one */ + lu=X509_LOOKUP_new(m); + if (lu == NULL) + return NULL; + else + { + lu->store_ctx=v; + if (sk_X509_LOOKUP_push(v->get_cert_methods,lu)) + return lu; + else + { + X509_LOOKUP_free(lu); + return NULL; + } + } + } + +int X509_STORE_get_by_subject(X509_STORE_CTX *vs, int type, X509_NAME *name, + X509_OBJECT *ret) + { + X509_STORE *ctx=vs->ctx; + X509_LOOKUP *lu; + X509_OBJECT stmp,*tmp; + int i,j; + + CRYPTO_MUTEX_lock_write(&ctx->objs_lock); + tmp=X509_OBJECT_retrieve_by_subject(ctx->objs,type,name); + CRYPTO_MUTEX_unlock(&ctx->objs_lock); + + if (tmp == NULL || type == X509_LU_CRL) + { + for (i=vs->current_method; i<(int)sk_X509_LOOKUP_num(ctx->get_cert_methods); i++) + { + lu=sk_X509_LOOKUP_value(ctx->get_cert_methods,i); + j=X509_LOOKUP_by_subject(lu,type,name,&stmp); + if (j < 0) + { + vs->current_method=j; + return j; + } + else if (j) + { + tmp= &stmp; + break; + } + } + vs->current_method=0; + if (tmp == NULL) + return 0; + } + +/* if (ret->data.ptr != NULL) + X509_OBJECT_free_contents(ret); */ + + ret->type=tmp->type; + ret->data.ptr=tmp->data.ptr; + + X509_OBJECT_up_ref_count(ret); + + return 1; + } + +int X509_STORE_add_cert(X509_STORE *ctx, X509 *x) + { + X509_OBJECT *obj; + int ret=1; + + if (x == NULL) return 0; + obj=(X509_OBJECT *)OPENSSL_malloc(sizeof(X509_OBJECT)); + if (obj == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return 0; + } + obj->type=X509_LU_X509; + obj->data.x509=x; + + CRYPTO_MUTEX_lock_write(&ctx->objs_lock); + + X509_OBJECT_up_ref_count(obj); + + if (X509_OBJECT_retrieve_match(ctx->objs, obj)) + { + X509_OBJECT_free_contents(obj); + OPENSSL_free(obj); + OPENSSL_PUT_ERROR(X509, X509_R_CERT_ALREADY_IN_HASH_TABLE); + ret=0; + } + else sk_X509_OBJECT_push(ctx->objs, obj); + + CRYPTO_MUTEX_unlock(&ctx->objs_lock); + + return ret; + } + +int X509_STORE_add_crl(X509_STORE *ctx, X509_CRL *x) + { + X509_OBJECT *obj; + int ret=1; + + if (x == NULL) return 0; + obj=(X509_OBJECT *)OPENSSL_malloc(sizeof(X509_OBJECT)); + if (obj == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return 0; + } + obj->type=X509_LU_CRL; + obj->data.crl=x; + + CRYPTO_MUTEX_lock_write(&ctx->objs_lock); + + X509_OBJECT_up_ref_count(obj); + + if (X509_OBJECT_retrieve_match(ctx->objs, obj)) + { + X509_OBJECT_free_contents(obj); + OPENSSL_free(obj); + OPENSSL_PUT_ERROR(X509, X509_R_CERT_ALREADY_IN_HASH_TABLE); + ret=0; + } + else sk_X509_OBJECT_push(ctx->objs, obj); + + CRYPTO_MUTEX_unlock(&ctx->objs_lock); + + return ret; + } + +void X509_OBJECT_up_ref_count(X509_OBJECT *a) + { + switch (a->type) + { + case X509_LU_X509: + X509_up_ref(a->data.x509); + break; + case X509_LU_CRL: + CRYPTO_refcount_inc(&a->data.crl->references); + break; + } + } + +void X509_OBJECT_free_contents(X509_OBJECT *a) + { + switch (a->type) + { + case X509_LU_X509: + X509_free(a->data.x509); + break; + case X509_LU_CRL: + X509_CRL_free(a->data.crl); + break; + } + } + +static int x509_object_idx_cnt(STACK_OF(X509_OBJECT) *h, int type, + X509_NAME *name, int *pnmatch) + { + X509_OBJECT stmp; + X509 x509_s; + X509_CINF cinf_s; + X509_CRL crl_s; + X509_CRL_INFO crl_info_s; + size_t idx; + + stmp.type=type; + switch (type) + { + case X509_LU_X509: + stmp.data.x509= &x509_s; + x509_s.cert_info= &cinf_s; + cinf_s.subject=name; + break; + case X509_LU_CRL: + stmp.data.crl= &crl_s; + crl_s.crl= &crl_info_s; + crl_info_s.issuer=name; + break; + default: + /* abort(); */ + return -1; + } + + idx = -1; + if (sk_X509_OBJECT_find(h, &idx, &stmp) && pnmatch) + { + int tidx; + const X509_OBJECT *tobj, *pstmp; + *pnmatch = 1; + pstmp = &stmp; + for (tidx = idx + 1; tidx < (int)sk_X509_OBJECT_num(h); tidx++) + { + tobj = sk_X509_OBJECT_value(h, tidx); + if (x509_object_cmp(&tobj, &pstmp)) + break; + (*pnmatch)++; + } + } + + return idx; + } + + +int X509_OBJECT_idx_by_subject(STACK_OF(X509_OBJECT) *h, int type, + X509_NAME *name) + { + return x509_object_idx_cnt(h, type, name, NULL); + } + +X509_OBJECT *X509_OBJECT_retrieve_by_subject(STACK_OF(X509_OBJECT) *h, int type, + X509_NAME *name) + { + int idx; + idx = X509_OBJECT_idx_by_subject(h, type, name); + if (idx==-1) return NULL; + return sk_X509_OBJECT_value(h, idx); + } + +STACK_OF(X509)* X509_STORE_get1_certs(X509_STORE_CTX *ctx, X509_NAME *nm) + { + int i, idx, cnt; + STACK_OF(X509) *sk; + X509 *x; + X509_OBJECT *obj; + sk = sk_X509_new_null(); + CRYPTO_MUTEX_lock_write(&ctx->ctx->objs_lock); + idx = x509_object_idx_cnt(ctx->ctx->objs, X509_LU_X509, nm, &cnt); + if (idx < 0) + { + /* Nothing found in cache: do lookup to possibly add new + * objects to cache + */ + X509_OBJECT xobj; + CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock); + if (!X509_STORE_get_by_subject(ctx, X509_LU_X509, nm, &xobj)) + { + sk_X509_free(sk); + return NULL; + } + X509_OBJECT_free_contents(&xobj); + CRYPTO_MUTEX_lock_write(&ctx->ctx->objs_lock); + idx = x509_object_idx_cnt(ctx->ctx->objs,X509_LU_X509,nm, &cnt); + if (idx < 0) + { + CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock); + sk_X509_free(sk); + return NULL; + } + } + for (i = 0; i < cnt; i++, idx++) + { + obj = sk_X509_OBJECT_value(ctx->ctx->objs, idx); + x = obj->data.x509; + if (!sk_X509_push(sk, X509_up_ref(x))) + { + CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock); + X509_free(x); + sk_X509_pop_free(sk, X509_free); + return NULL; + } + } + CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock); + return sk; + + } + +STACK_OF(X509_CRL)* X509_STORE_get1_crls(X509_STORE_CTX *ctx, X509_NAME *nm) + { + int i, idx, cnt; + STACK_OF(X509_CRL) *sk; + X509_CRL *x; + X509_OBJECT *obj, xobj; + sk = sk_X509_CRL_new_null(); + CRYPTO_MUTEX_lock_write(&ctx->ctx->objs_lock); + /* Check cache first */ + idx = x509_object_idx_cnt(ctx->ctx->objs, X509_LU_CRL, nm, &cnt); + + /* Always do lookup to possibly add new CRLs to cache + */ + CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock); + if (!X509_STORE_get_by_subject(ctx, X509_LU_CRL, nm, &xobj)) + { + sk_X509_CRL_free(sk); + return NULL; + } + X509_OBJECT_free_contents(&xobj); + CRYPTO_MUTEX_lock_write(&ctx->ctx->objs_lock); + idx = x509_object_idx_cnt(ctx->ctx->objs,X509_LU_CRL, nm, &cnt); + if (idx < 0) + { + CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock); + sk_X509_CRL_free(sk); + return NULL; + } + + for (i = 0; i < cnt; i++, idx++) + { + obj = sk_X509_OBJECT_value(ctx->ctx->objs, idx); + x = obj->data.crl; + CRYPTO_refcount_inc(&x->references); + if (!sk_X509_CRL_push(sk, x)) + { + CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock); + X509_CRL_free(x); + sk_X509_CRL_pop_free(sk, X509_CRL_free); + return NULL; + } + } + CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock); + return sk; + } + +X509_OBJECT *X509_OBJECT_retrieve_match(STACK_OF(X509_OBJECT) *h, X509_OBJECT *x) + { + size_t idx, i; + X509_OBJECT *obj; + + if (!sk_X509_OBJECT_find(h, &idx, x)) { + return NULL; + } + if ((x->type != X509_LU_X509) && (x->type != X509_LU_CRL)) + return sk_X509_OBJECT_value(h, idx); + for (i = idx; i < sk_X509_OBJECT_num(h); i++) + { + obj = sk_X509_OBJECT_value(h, i); + if (x509_object_cmp((const X509_OBJECT **)&obj, (const X509_OBJECT **)&x)) + return NULL; + if (x->type == X509_LU_X509) + { + if (!X509_cmp(obj->data.x509, x->data.x509)) + return obj; + } + else if (x->type == X509_LU_CRL) + { + if (!X509_CRL_match(obj->data.crl, x->data.crl)) + return obj; + } + else + return obj; + } + return NULL; + } + + +/* Try to get issuer certificate from store. Due to limitations + * of the API this can only retrieve a single certificate matching + * a given subject name. However it will fill the cache with all + * matching certificates, so we can examine the cache for all + * matches. + * + * Return values are: + * 1 lookup successful. + * 0 certificate not found. + * -1 some other error. + */ +int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x) + { + X509_NAME *xn; + X509_OBJECT obj, *pobj; + int ok, idx, ret; + size_t i; + xn=X509_get_issuer_name(x); + ok=X509_STORE_get_by_subject(ctx,X509_LU_X509,xn,&obj); + if (ok != X509_LU_X509) + { + if (ok == X509_LU_RETRY) + { + X509_OBJECT_free_contents(&obj); + OPENSSL_PUT_ERROR(X509, X509_R_SHOULD_RETRY); + return -1; + } + else if (ok != X509_LU_FAIL) + { + X509_OBJECT_free_contents(&obj); + /* not good :-(, break anyway */ + return -1; + } + return 0; + } + /* If certificate matches all OK */ + if (ctx->check_issued(ctx, x, obj.data.x509)) + { + *issuer = obj.data.x509; + return 1; + } + X509_OBJECT_free_contents(&obj); + + /* Else find index of first cert accepted by 'check_issued' */ + ret = 0; + CRYPTO_MUTEX_lock_write(&ctx->ctx->objs_lock); + idx = X509_OBJECT_idx_by_subject(ctx->ctx->objs, X509_LU_X509, xn); + if (idx != -1) /* should be true as we've had at least one match */ + { + /* Look through all matching certs for suitable issuer */ + for (i = idx; i < sk_X509_OBJECT_num(ctx->ctx->objs); i++) + { + pobj = sk_X509_OBJECT_value(ctx->ctx->objs, i); + /* See if we've run past the matches */ + if (pobj->type != X509_LU_X509) + break; + if (X509_NAME_cmp(xn, X509_get_subject_name(pobj->data.x509))) + break; + if (ctx->check_issued(ctx, x, pobj->data.x509)) + { + *issuer = pobj->data.x509; + X509_OBJECT_up_ref_count(pobj); + ret = 1; + break; + } + } + } + CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock); + return ret; + } + +int X509_STORE_set_flags(X509_STORE *ctx, unsigned long flags) + { + return X509_VERIFY_PARAM_set_flags(ctx->param, flags); + } + +int X509_STORE_set_depth(X509_STORE *ctx, int depth) + { + X509_VERIFY_PARAM_set_depth(ctx->param, depth); + return 1; + } + +int X509_STORE_set_purpose(X509_STORE *ctx, int purpose) + { + return X509_VERIFY_PARAM_set_purpose(ctx->param, purpose); + } + +int X509_STORE_set_trust(X509_STORE *ctx, int trust) + { + return X509_VERIFY_PARAM_set_trust(ctx->param, trust); + } + +int X509_STORE_set1_param(X509_STORE *ctx, X509_VERIFY_PARAM *param) + { + return X509_VERIFY_PARAM_set1(ctx->param, param); + } + +void X509_STORE_set_verify_cb(X509_STORE *ctx, + int (*verify_cb)(int, X509_STORE_CTX *)) + { + ctx->verify_cb = verify_cb; + } + +void X509_STORE_set_lookup_crls_cb(X509_STORE *ctx, + STACK_OF(X509_CRL)* (*cb)(X509_STORE_CTX *ctx, X509_NAME *nm)) + { + ctx->lookup_crls = cb; + } + +X509_STORE *X509_STORE_CTX_get0_store(X509_STORE_CTX *ctx) + { + return ctx->ctx; + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509_obj.c b/TMessagesProj/jni/boringssl/crypto/x509/x509_obj.c new file mode 100644 index 00000000..b6f08164 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509_obj.c @@ -0,0 +1,191 @@ +/* crypto/x509/x509_obj.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include +#include +#include +#include + + +char *X509_NAME_oneline(X509_NAME *a, char *buf, int len) + { + X509_NAME_ENTRY *ne; + size_t i; + int n,lold,l,l1,l2,num,j,type; + const char *s; + char *p; + unsigned char *q; + BUF_MEM *b=NULL; + static const char hex[17]="0123456789ABCDEF"; + int gs_doit[4]; + char tmp_buf[80]; + + if (buf == NULL) + { + if ((b=BUF_MEM_new()) == NULL) goto err; + if (!BUF_MEM_grow(b,200)) goto err; + b->data[0]='\0'; + len=200; + } + if (a == NULL) + { + if(b) + { + buf=b->data; + OPENSSL_free(b); + } + strncpy(buf,"NO X509_NAME",len); + buf[len-1]='\0'; + return buf; + } + + len--; /* space for '\0' */ + l=0; + for (i=0; ientries); i++) + { + ne=sk_X509_NAME_ENTRY_value(a->entries,i); + n=OBJ_obj2nid(ne->object); + if ((n == NID_undef) || ((s=OBJ_nid2sn(n)) == NULL)) + { + i2t_ASN1_OBJECT(tmp_buf,sizeof(tmp_buf),ne->object); + s=tmp_buf; + } + l1=strlen(s); + + type=ne->value->type; + num=ne->value->length; + q=ne->value->data; + + if ((type == V_ASN1_GENERALSTRING) && ((num%4) == 0)) + { + gs_doit[0]=gs_doit[1]=gs_doit[2]=gs_doit[3]=0; + for (j=0; j '~')) l2+=3; + } + + lold=l; + l+=1+l1+1+l2; + if (b != NULL) + { + if (!BUF_MEM_grow(b,l+1)) goto err; + p= &(b->data[lold]); + } + else if (l > len) + { + break; + } + else + p= &(buf[lold]); + *(p++)='/'; + memcpy(p,s,(unsigned int)l1); p+=l1; + *(p++)='='; + + q=ne->value->data; + + for (j=0; j '~')) + { + *(p++)='\\'; + *(p++)='x'; + *(p++)=hex[(n>>4)&0x0f]; + *(p++)=hex[n&0x0f]; + } + else + *(p++)=n; + } + *p='\0'; + } + if (b != NULL) + { + p=b->data; + OPENSSL_free(b); + } + else + p=buf; + if (i == 0) + *p = '\0'; + return(p); +err: + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + if (b != NULL) BUF_MEM_free(b); + return(NULL); + } + diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509_r2x.c b/TMessagesProj/jni/boringssl/crypto/x509/x509_r2x.c new file mode 100644 index 00000000..85979ac0 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509_r2x.c @@ -0,0 +1,113 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +X509 *X509_REQ_to_X509(X509_REQ *r, int days, EVP_PKEY *pkey) + { + X509 *ret=NULL; + X509_CINF *xi=NULL; + X509_NAME *xn; + + if ((ret=X509_new()) == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* duplicate the request */ + xi=ret->cert_info; + + if (sk_X509_ATTRIBUTE_num(r->req_info->attributes) != 0) + { + if ((xi->version=M_ASN1_INTEGER_new()) == NULL) goto err; + if (!ASN1_INTEGER_set(xi->version,2)) goto err; +/* xi->extensions=ri->attributes; <- bad, should not ever be done + ri->attributes=NULL; */ + } + + xn=X509_REQ_get_subject_name(r); + if (X509_set_subject_name(ret,X509_NAME_dup(xn)) == 0) + goto err; + if (X509_set_issuer_name(ret,X509_NAME_dup(xn)) == 0) + goto err; + + if (X509_gmtime_adj(xi->validity->notBefore,0) == NULL) + goto err; + if (X509_gmtime_adj(xi->validity->notAfter,(long)60*60*24*days) == NULL) + goto err; + + X509_set_pubkey(ret,X509_REQ_get_pubkey(r)); + + if (!X509_sign(ret,pkey,EVP_md5())) + goto err; + if (0) + { +err: + X509_free(ret); + ret=NULL; + } + return(ret); + } + diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509_req.c b/TMessagesProj/jni/boringssl/crypto/x509/x509_req.c new file mode 100644 index 00000000..01c5113e --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509_req.c @@ -0,0 +1,315 @@ +/* crypto/x509/x509_req.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +X509_REQ *X509_to_X509_REQ(X509 *x, EVP_PKEY *pkey, const EVP_MD *md) + { + X509_REQ *ret; + X509_REQ_INFO *ri; + int i; + EVP_PKEY *pktmp; + + ret=X509_REQ_new(); + if (ret == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + goto err; + } + + ri=ret->req_info; + + ri->version->length=1; + ri->version->data=(unsigned char *)OPENSSL_malloc(1); + if (ri->version->data == NULL) goto err; + ri->version->data[0]=0; /* version == 0 */ + + if (!X509_REQ_set_subject_name(ret,X509_get_subject_name(x))) + goto err; + + pktmp = X509_get_pubkey(x); + if (pktmp == NULL) + goto err; + i=X509_REQ_set_pubkey(ret,pktmp); + EVP_PKEY_free(pktmp); + if (!i) goto err; + + if (pkey != NULL) + { + if (!X509_REQ_sign(ret,pkey,md)) + goto err; + } + return(ret); +err: + X509_REQ_free(ret); + return(NULL); + } + +EVP_PKEY *X509_REQ_get_pubkey(X509_REQ *req) + { + if ((req == NULL) || (req->req_info == NULL)) + return(NULL); + return(X509_PUBKEY_get(req->req_info->pubkey)); + } + +int X509_REQ_check_private_key(X509_REQ *x, EVP_PKEY *k) + { + EVP_PKEY *xk=NULL; + int ok=0; + + xk=X509_REQ_get_pubkey(x); + switch (EVP_PKEY_cmp(xk, k)) + { + case 1: + ok=1; + break; + case 0: + OPENSSL_PUT_ERROR(X509, X509_R_KEY_VALUES_MISMATCH); + break; + case -1: + OPENSSL_PUT_ERROR(X509, X509_R_KEY_TYPE_MISMATCH); + break; + case -2: + if (k->type == EVP_PKEY_EC) + { + OPENSSL_PUT_ERROR(X509, ERR_R_EC_LIB); + break; + } + if (k->type == EVP_PKEY_DH) + { + /* No idea */ + OPENSSL_PUT_ERROR(X509, X509_R_CANT_CHECK_DH_KEY); + break; + } + OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_KEY_TYPE); + } + + EVP_PKEY_free(xk); + return(ok); + } + +/* It seems several organisations had the same idea of including a list of + * extensions in a certificate request. There are at least two OIDs that are + * used and there may be more: so the list is configurable. + */ + +static const int ext_nid_list[] = { NID_ext_req, NID_ms_ext_req, NID_undef}; + +static const int *ext_nids = ext_nid_list; + +int X509_REQ_extension_nid(int req_nid) +{ + int i, nid; + for(i = 0; ; i++) { + nid = ext_nids[i]; + if(nid == NID_undef) return 0; + else if (req_nid == nid) return 1; + } +} + +const int *X509_REQ_get_extension_nids(void) +{ + return ext_nids; +} + +void X509_REQ_set_extension_nids(const int *nids) +{ + ext_nids = nids; +} + +STACK_OF(X509_EXTENSION) *X509_REQ_get_extensions(X509_REQ *req) + { + X509_ATTRIBUTE *attr; + ASN1_TYPE *ext = NULL; + int idx; + const int *pnid; + const unsigned char *p; + + if ((req == NULL) || (req->req_info == NULL) || !ext_nids) + return(NULL); + for (pnid = ext_nids; *pnid != NID_undef; pnid++) + { + idx = X509_REQ_get_attr_by_NID(req, *pnid, -1); + if (idx == -1) + continue; + attr = X509_REQ_get_attr(req, idx); + if(attr->single) ext = attr->value.single; + else if(sk_ASN1_TYPE_num(attr->value.set)) + ext = sk_ASN1_TYPE_value(attr->value.set, 0); + break; + } + if(!ext || (ext->type != V_ASN1_SEQUENCE)) + return NULL; + p = ext->value.sequence->data; + return (STACK_OF(X509_EXTENSION) *) + ASN1_item_d2i(NULL, &p, ext->value.sequence->length, + ASN1_ITEM_rptr(X509_EXTENSIONS)); +} + +/* Add a STACK_OF extensions to a certificate request: allow alternative OIDs + * in case we want to create a non standard one. + */ + +int X509_REQ_add_extensions_nid(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts, + int nid) +{ + ASN1_TYPE *at = NULL; + X509_ATTRIBUTE *attr = NULL; + if(!(at = ASN1_TYPE_new()) || + !(at->value.sequence = ASN1_STRING_new())) goto err; + + at->type = V_ASN1_SEQUENCE; + /* Generate encoding of extensions */ + at->value.sequence->length = + ASN1_item_i2d((ASN1_VALUE *)exts, + &at->value.sequence->data, + ASN1_ITEM_rptr(X509_EXTENSIONS)); + if(!(attr = X509_ATTRIBUTE_new())) goto err; + if(!(attr->value.set = sk_ASN1_TYPE_new_null())) goto err; + if(!sk_ASN1_TYPE_push(attr->value.set, at)) goto err; + at = NULL; + attr->single = 0; + attr->object = (ASN1_OBJECT*) OBJ_nid2obj(nid); + if (!req->req_info->attributes) + { + if (!(req->req_info->attributes = sk_X509_ATTRIBUTE_new_null())) + goto err; + } + if(!sk_X509_ATTRIBUTE_push(req->req_info->attributes, attr)) goto err; + return 1; + err: + X509_ATTRIBUTE_free(attr); + ASN1_TYPE_free(at); + return 0; +} +/* This is the normal usage: use the "official" OID */ +int X509_REQ_add_extensions(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts) +{ + return X509_REQ_add_extensions_nid(req, exts, NID_ext_req); +} + +/* Request attribute functions */ + +int X509_REQ_get_attr_count(const X509_REQ *req) +{ + return X509at_get_attr_count(req->req_info->attributes); +} + +int X509_REQ_get_attr_by_NID(const X509_REQ *req, int nid, + int lastpos) +{ + return X509at_get_attr_by_NID(req->req_info->attributes, nid, lastpos); +} + +int X509_REQ_get_attr_by_OBJ(const X509_REQ *req, ASN1_OBJECT *obj, + int lastpos) +{ + return X509at_get_attr_by_OBJ(req->req_info->attributes, obj, lastpos); +} + +X509_ATTRIBUTE *X509_REQ_get_attr(const X509_REQ *req, int loc) +{ + return X509at_get_attr(req->req_info->attributes, loc); +} + +X509_ATTRIBUTE *X509_REQ_delete_attr(X509_REQ *req, int loc) +{ + return X509at_delete_attr(req->req_info->attributes, loc); +} + +int X509_REQ_add1_attr(X509_REQ *req, X509_ATTRIBUTE *attr) +{ + if(X509at_add1_attr(&req->req_info->attributes, attr)) return 1; + return 0; +} + +int X509_REQ_add1_attr_by_OBJ(X509_REQ *req, + const ASN1_OBJECT *obj, int type, + const unsigned char *bytes, int len) +{ + if(X509at_add1_attr_by_OBJ(&req->req_info->attributes, obj, + type, bytes, len)) return 1; + return 0; +} + +int X509_REQ_add1_attr_by_NID(X509_REQ *req, + int nid, int type, + const unsigned char *bytes, int len) +{ + if(X509at_add1_attr_by_NID(&req->req_info->attributes, nid, + type, bytes, len)) return 1; + return 0; +} + +int X509_REQ_add1_attr_by_txt(X509_REQ *req, + const char *attrname, int type, + const unsigned char *bytes, int len) +{ + if(X509at_add1_attr_by_txt(&req->req_info->attributes, attrname, + type, bytes, len)) return 1; + return 0; +} diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509_set.c b/TMessagesProj/jni/boringssl/crypto/x509/x509_set.c new file mode 100644 index 00000000..06658b07 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509_set.c @@ -0,0 +1,154 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include +#include + + +int X509_set_version(X509 *x, long version) + { + if (x == NULL) return(0); + if (version == 0) + { + M_ASN1_INTEGER_free(x->cert_info->version); + x->cert_info->version = NULL; + return(1); + } + if (x->cert_info->version == NULL) + { + if ((x->cert_info->version=M_ASN1_INTEGER_new()) == NULL) + return(0); + } + return(ASN1_INTEGER_set(x->cert_info->version,version)); + } + +int X509_set_serialNumber(X509 *x, ASN1_INTEGER *serial) + { + ASN1_INTEGER *in; + + if (x == NULL) return(0); + in=x->cert_info->serialNumber; + if (in != serial) + { + in=M_ASN1_INTEGER_dup(serial); + if (in != NULL) + { + M_ASN1_INTEGER_free(x->cert_info->serialNumber); + x->cert_info->serialNumber=in; + } + } + return(in != NULL); + } + +int X509_set_issuer_name(X509 *x, X509_NAME *name) + { + if ((x == NULL) || (x->cert_info == NULL)) return(0); + return(X509_NAME_set(&x->cert_info->issuer,name)); + } + +int X509_set_subject_name(X509 *x, X509_NAME *name) + { + if ((x == NULL) || (x->cert_info == NULL)) return(0); + return(X509_NAME_set(&x->cert_info->subject,name)); + } + +int X509_set_notBefore(X509 *x, const ASN1_TIME *tm) + { + ASN1_TIME *in; + + if ((x == NULL) || (x->cert_info->validity == NULL)) return(0); + in=x->cert_info->validity->notBefore; + if (in != tm) + { + in=M_ASN1_TIME_dup(tm); + if (in != NULL) + { + M_ASN1_TIME_free(x->cert_info->validity->notBefore); + x->cert_info->validity->notBefore=in; + } + } + return(in != NULL); + } + +int X509_set_notAfter(X509 *x, const ASN1_TIME *tm) + { + ASN1_TIME *in; + + if ((x == NULL) || (x->cert_info->validity == NULL)) return(0); + in=x->cert_info->validity->notAfter; + if (in != tm) + { + in=M_ASN1_TIME_dup(tm); + if (in != NULL) + { + M_ASN1_TIME_free(x->cert_info->validity->notAfter); + x->cert_info->validity->notAfter=in; + } + } + return(in != NULL); + } + +int X509_set_pubkey(X509 *x, EVP_PKEY *pkey) + { + if ((x == NULL) || (x->cert_info == NULL)) return(0); + return(X509_PUBKEY_set(&(x->cert_info->key),pkey)); + } + + + diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509_trs.c b/TMessagesProj/jni/boringssl/crypto/x509/x509_trs.c new file mode 100644 index 00000000..820e6052 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509_trs.c @@ -0,0 +1,304 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include +#include +#include +#include +#include + + +static int tr_cmp(const X509_TRUST **a, + const X509_TRUST **b); +static void trtable_free(X509_TRUST *p); + +static int trust_1oidany(X509_TRUST *trust, X509 *x, int flags); +static int trust_1oid(X509_TRUST *trust, X509 *x, int flags); +static int trust_compat(X509_TRUST *trust, X509 *x, int flags); + +static int obj_trust(int id, X509 *x, int flags); +static int (*default_trust)(int id, X509 *x, int flags) = obj_trust; + +/* WARNING: the following table should be kept in order of trust + * and without any gaps so we can just subtract the minimum trust + * value to get an index into the table + */ + +static X509_TRUST trstandard[] = { +{X509_TRUST_COMPAT, 0, trust_compat, (char *) "compatible", 0, NULL}, +{X509_TRUST_SSL_CLIENT, 0, trust_1oidany, (char *) "SSL Client", NID_client_auth, NULL}, +{X509_TRUST_SSL_SERVER, 0, trust_1oidany, (char *) "SSL Server", NID_server_auth, NULL}, +{X509_TRUST_EMAIL, 0, trust_1oidany, (char *) "S/MIME email", NID_email_protect, NULL}, +{X509_TRUST_OBJECT_SIGN, 0, trust_1oidany, (char *) "Object Signer", NID_code_sign, NULL}, +{X509_TRUST_OCSP_SIGN, 0, trust_1oid, (char *) "OCSP responder", NID_OCSP_sign, NULL}, +{X509_TRUST_OCSP_REQUEST, 0, trust_1oid, (char *) "OCSP request", NID_ad_OCSP, NULL}, +{X509_TRUST_TSA, 0, trust_1oidany, (char *) "TSA server", NID_time_stamp, NULL} +}; + +#define X509_TRUST_COUNT (sizeof(trstandard)/sizeof(X509_TRUST)) + +static STACK_OF(X509_TRUST) *trtable = NULL; + +static int tr_cmp(const X509_TRUST **a, + const X509_TRUST **b) +{ + return (*a)->trust - (*b)->trust; +} + +int (*X509_TRUST_set_default(int (*trust)(int , X509 *, int)))(int, X509 *, int) +{ + int (*oldtrust)(int , X509 *, int); + oldtrust = default_trust; + default_trust = trust; + return oldtrust; +} + + +int X509_check_trust(X509 *x, int id, int flags) +{ + X509_TRUST *pt; + int idx; + if(id == -1) return 1; + /* We get this as a default value */ + if (id == 0) + { + int rv; + rv = obj_trust(NID_anyExtendedKeyUsage, x, 0); + if (rv != X509_TRUST_UNTRUSTED) + return rv; + return trust_compat(NULL, x, 0); + } + idx = X509_TRUST_get_by_id(id); + if(idx == -1) return default_trust(id, x, flags); + pt = X509_TRUST_get0(idx); + return pt->check_trust(pt, x, flags); +} + +int X509_TRUST_get_count(void) +{ + if(!trtable) return X509_TRUST_COUNT; + return sk_X509_TRUST_num(trtable) + X509_TRUST_COUNT; +} + +X509_TRUST * X509_TRUST_get0(int idx) +{ + if(idx < 0) return NULL; + if(idx < (int)X509_TRUST_COUNT) return trstandard + idx; + return sk_X509_TRUST_value(trtable, idx - X509_TRUST_COUNT); +} + +int X509_TRUST_get_by_id(int id) +{ + X509_TRUST tmp; + size_t idx; + + if((id >= X509_TRUST_MIN) && (id <= X509_TRUST_MAX)) + return id - X509_TRUST_MIN; + tmp.trust = id; + if(!trtable) return -1; + if (!sk_X509_TRUST_find(trtable, &idx, &tmp)) { + return -1; + } + return idx + X509_TRUST_COUNT; +} + +int X509_TRUST_set(int *t, int trust) +{ + if(X509_TRUST_get_by_id(trust) == -1) { + OPENSSL_PUT_ERROR(X509, X509_R_INVALID_TRUST); + return 0; + } + *t = trust; + return 1; +} + +int X509_TRUST_add(int id, int flags, int (*ck)(X509_TRUST *, X509 *, int), + char *name, int arg1, void *arg2) +{ + int idx; + X509_TRUST *trtmp; + char *name_dup; + + /* This is set according to what we change: application can't set it */ + flags &= ~X509_TRUST_DYNAMIC; + /* This will always be set for application modified trust entries */ + flags |= X509_TRUST_DYNAMIC_NAME; + /* Get existing entry if any */ + idx = X509_TRUST_get_by_id(id); + /* Need a new entry */ + if(idx == -1) { + if(!(trtmp = OPENSSL_malloc(sizeof(X509_TRUST)))) { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return 0; + } + trtmp->flags = X509_TRUST_DYNAMIC; + } else trtmp = X509_TRUST_get0(idx); + + /* Duplicate the supplied name. */ + name_dup = BUF_strdup(name); + if (name_dup == NULL) { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + if (idx == -1) + OPENSSL_free(trtmp); + return 0; + } + + /* OPENSSL_free existing name if dynamic */ + if (trtmp->flags & X509_TRUST_DYNAMIC_NAME) OPENSSL_free(trtmp->name); + trtmp->name = name_dup; + /* Keep the dynamic flag of existing entry */ + trtmp->flags &= X509_TRUST_DYNAMIC; + /* Set all other flags */ + trtmp->flags |= flags; + + trtmp->trust = id; + trtmp->check_trust = ck; + trtmp->arg1 = arg1; + trtmp->arg2 = arg2; + + /* If its a new entry manage the dynamic table */ + if(idx == -1) { + if(!trtable && !(trtable = sk_X509_TRUST_new(tr_cmp))) { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + trtable_free(trtmp); + return 0; + } + if (!sk_X509_TRUST_push(trtable, trtmp)) { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + trtable_free(trtmp); + return 0; + } + } + return 1; +} + +static void trtable_free(X509_TRUST *p) + { + if(!p) return; + if (p->flags & X509_TRUST_DYNAMIC) + { + if (p->flags & X509_TRUST_DYNAMIC_NAME) + OPENSSL_free(p->name); + OPENSSL_free(p); + } + } + +void X509_TRUST_cleanup(void) +{ + unsigned int i; + for(i = 0; i < X509_TRUST_COUNT; i++) trtable_free(trstandard + i); + sk_X509_TRUST_pop_free(trtable, trtable_free); + trtable = NULL; +} + +int X509_TRUST_get_flags(X509_TRUST *xp) +{ + return xp->flags; +} + +char *X509_TRUST_get0_name(X509_TRUST *xp) +{ + return xp->name; +} + +int X509_TRUST_get_trust(X509_TRUST *xp) +{ + return xp->trust; +} + +static int trust_1oidany(X509_TRUST *trust, X509 *x, int flags) +{ + if(x->aux && (x->aux->trust || x->aux->reject)) + return obj_trust(trust->arg1, x, flags); + /* we don't have any trust settings: for compatibility + * we return trusted if it is self signed + */ + return trust_compat(trust, x, flags); +} + +static int trust_1oid(X509_TRUST *trust, X509 *x, int flags) +{ + if(x->aux) return obj_trust(trust->arg1, x, flags); + return X509_TRUST_UNTRUSTED; +} + +static int trust_compat(X509_TRUST *trust, X509 *x, int flags) +{ + X509_check_purpose(x, -1, 0); + if(x->ex_flags & EXFLAG_SS) return X509_TRUST_TRUSTED; + else return X509_TRUST_UNTRUSTED; +} + +static int obj_trust(int id, X509 *x, int flags) +{ + ASN1_OBJECT *obj; + size_t i; + X509_CERT_AUX *ax; + ax = x->aux; + if(!ax) return X509_TRUST_UNTRUSTED; + if(ax->reject) { + for(i = 0; i < sk_ASN1_OBJECT_num(ax->reject); i++) { + obj = sk_ASN1_OBJECT_value(ax->reject, i); + if(OBJ_obj2nid(obj) == id) return X509_TRUST_REJECTED; + } + } + if(ax->trust) { + for(i = 0; i < sk_ASN1_OBJECT_num(ax->trust); i++) { + obj = sk_ASN1_OBJECT_value(ax->trust, i); + if(OBJ_obj2nid(obj) == id) return X509_TRUST_TRUSTED; + } + } + return X509_TRUST_UNTRUSTED; +} + diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509_txt.c b/TMessagesProj/jni/boringssl/crypto/x509/x509_txt.c new file mode 100644 index 00000000..c2867102 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509_txt.c @@ -0,0 +1,209 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +const char *X509_verify_cert_error_string(long n) + { + static char buf[100]; + + switch ((int)n) + { + case X509_V_OK: + return("ok"); + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: + return("unable to get issuer certificate"); + case X509_V_ERR_UNABLE_TO_GET_CRL: + return("unable to get certificate CRL"); + case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: + return("unable to decrypt certificate's signature"); + case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: + return("unable to decrypt CRL's signature"); + case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: + return("unable to decode issuer public key"); + case X509_V_ERR_CERT_SIGNATURE_FAILURE: + return("certificate signature failure"); + case X509_V_ERR_CRL_SIGNATURE_FAILURE: + return("CRL signature failure"); + case X509_V_ERR_CERT_NOT_YET_VALID: + return("certificate is not yet valid"); + case X509_V_ERR_CRL_NOT_YET_VALID: + return("CRL is not yet valid"); + case X509_V_ERR_CERT_HAS_EXPIRED: + return("certificate has expired"); + case X509_V_ERR_CRL_HAS_EXPIRED: + return("CRL has expired"); + case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: + return("format error in certificate's notBefore field"); + case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: + return("format error in certificate's notAfter field"); + case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: + return("format error in CRL's lastUpdate field"); + case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: + return("format error in CRL's nextUpdate field"); + case X509_V_ERR_OUT_OF_MEM: + return("out of memory"); + case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: + return("self signed certificate"); + case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: + return("self signed certificate in certificate chain"); + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: + return("unable to get local issuer certificate"); + case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: + return("unable to verify the first certificate"); + case X509_V_ERR_CERT_CHAIN_TOO_LONG: + return("certificate chain too long"); + case X509_V_ERR_CERT_REVOKED: + return("certificate revoked"); + case X509_V_ERR_INVALID_CA: + return ("invalid CA certificate"); + case X509_V_ERR_INVALID_NON_CA: + return ("invalid non-CA certificate (has CA markings)"); + case X509_V_ERR_PATH_LENGTH_EXCEEDED: + return ("path length constraint exceeded"); + case X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED: + return("proxy path length constraint exceeded"); + case X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED: + return("proxy certificates not allowed, please set the appropriate flag"); + case X509_V_ERR_INVALID_PURPOSE: + return ("unsupported certificate purpose"); + case X509_V_ERR_CERT_UNTRUSTED: + return ("certificate not trusted"); + case X509_V_ERR_CERT_REJECTED: + return ("certificate rejected"); + case X509_V_ERR_APPLICATION_VERIFICATION: + return("application verification failure"); + case X509_V_ERR_SUBJECT_ISSUER_MISMATCH: + return("subject issuer mismatch"); + case X509_V_ERR_AKID_SKID_MISMATCH: + return("authority and subject key identifier mismatch"); + case X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH: + return("authority and issuer serial number mismatch"); + case X509_V_ERR_KEYUSAGE_NO_CERTSIGN: + return("key usage does not include certificate signing"); + case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: + return("unable to get CRL issuer certificate"); + case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION: + return("unhandled critical extension"); + case X509_V_ERR_KEYUSAGE_NO_CRL_SIGN: + return("key usage does not include CRL signing"); + case X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE: + return("key usage does not include digital signature"); + case X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION: + return("unhandled critical CRL extension"); + case X509_V_ERR_INVALID_EXTENSION: + return("invalid or inconsistent certificate extension"); + case X509_V_ERR_INVALID_POLICY_EXTENSION: + return("invalid or inconsistent certificate policy extension"); + case X509_V_ERR_NO_EXPLICIT_POLICY: + return("no explicit policy"); + case X509_V_ERR_DIFFERENT_CRL_SCOPE: + return("Different CRL scope"); + case X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE: + return("Unsupported extension feature"); + case X509_V_ERR_UNNESTED_RESOURCE: + return("RFC 3779 resource not subset of parent's resources"); + + case X509_V_ERR_PERMITTED_VIOLATION: + return("permitted subtree violation"); + case X509_V_ERR_EXCLUDED_VIOLATION: + return("excluded subtree violation"); + case X509_V_ERR_SUBTREE_MINMAX: + return("name constraints minimum and maximum not supported"); + case X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE: + return("unsupported name constraint type"); + case X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX: + return("unsupported or invalid name constraint syntax"); + case X509_V_ERR_UNSUPPORTED_NAME_SYNTAX: + return("unsupported or invalid name syntax"); + case X509_V_ERR_CRL_PATH_VALIDATION_ERROR: + return("CRL path validation error"); + + case X509_V_ERR_SUITE_B_INVALID_VERSION: + return("Suite B: certificate version invalid"); + case X509_V_ERR_SUITE_B_INVALID_ALGORITHM: + return("Suite B: invalid public key algorithm"); + case X509_V_ERR_SUITE_B_INVALID_CURVE: + return("Suite B: invalid ECC curve"); + case X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM: + return("Suite B: invalid signature algorithm"); + case X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED: + return("Suite B: curve not allowed for this LOS"); + case X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256: + return("Suite B: cannot sign P-384 with P-256"); + + case X509_V_ERR_HOSTNAME_MISMATCH: + return("Hostname mismatch"); + case X509_V_ERR_EMAIL_MISMATCH: + return("Email address mismatch"); + case X509_V_ERR_IP_ADDRESS_MISMATCH: + return("IP address mismatch"); + + default: + BIO_snprintf(buf,sizeof buf,"error number %ld",n); + return(buf); + } + } + + diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509_v3.c b/TMessagesProj/jni/boringssl/crypto/x509/x509_v3.c new file mode 100644 index 00000000..b0429851 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509_v3.c @@ -0,0 +1,271 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include +#include +#include +#include + + +int X509v3_get_ext_count(const STACK_OF(X509_EXTENSION) *x) + { + if (x == NULL) return(0); + return(sk_X509_EXTENSION_num(x)); + } + +int X509v3_get_ext_by_NID(const STACK_OF(X509_EXTENSION) *x, int nid, + int lastpos) + { + const ASN1_OBJECT *obj; + + obj=OBJ_nid2obj(nid); + if (obj == NULL) return(-2); + return(X509v3_get_ext_by_OBJ(x,obj,lastpos)); + } + +int X509v3_get_ext_by_OBJ(const STACK_OF(X509_EXTENSION) *sk, const ASN1_OBJECT *obj, + int lastpos) + { + int n; + X509_EXTENSION *ex; + + if (sk == NULL) return(-1); + lastpos++; + if (lastpos < 0) + lastpos=0; + n=sk_X509_EXTENSION_num(sk); + for ( ; lastpos < n; lastpos++) + { + ex=sk_X509_EXTENSION_value(sk,lastpos); + if (OBJ_cmp(ex->object,obj) == 0) + return(lastpos); + } + return(-1); + } + +int X509v3_get_ext_by_critical(const STACK_OF(X509_EXTENSION) *sk, int crit, + int lastpos) + { + int n; + X509_EXTENSION *ex; + + if (sk == NULL) return(-1); + lastpos++; + if (lastpos < 0) + lastpos=0; + n=sk_X509_EXTENSION_num(sk); + for ( ; lastpos < n; lastpos++) + { + ex=sk_X509_EXTENSION_value(sk,lastpos); + if ( ((ex->critical > 0) && crit) || + ((ex->critical <= 0) && !crit)) + return(lastpos); + } + return(-1); + } + +X509_EXTENSION *X509v3_get_ext(const STACK_OF(X509_EXTENSION) *x, int loc) + { + if (x == NULL || loc < 0 || sk_X509_EXTENSION_num(x) <= (size_t) loc) + return NULL; + else + return sk_X509_EXTENSION_value(x,loc); + } + +X509_EXTENSION *X509v3_delete_ext(STACK_OF(X509_EXTENSION) *x, int loc) + { + X509_EXTENSION *ret; + + if (x == NULL || loc < 0 || sk_X509_EXTENSION_num(x) <= (size_t) loc) + return(NULL); + ret=sk_X509_EXTENSION_delete(x,loc); + return(ret); + } + +STACK_OF(X509_EXTENSION) *X509v3_add_ext(STACK_OF(X509_EXTENSION) **x, + X509_EXTENSION *ex, int loc) + { + X509_EXTENSION *new_ex=NULL; + int n; + STACK_OF(X509_EXTENSION) *sk=NULL; + + if (x == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_PASSED_NULL_PARAMETER); + goto err2; + } + + if (*x == NULL) + { + if ((sk=sk_X509_EXTENSION_new_null()) == NULL) + goto err; + } + else + sk= *x; + + n=sk_X509_EXTENSION_num(sk); + if (loc > n) loc=n; + else if (loc < 0) loc=n; + + if ((new_ex=X509_EXTENSION_dup(ex)) == NULL) + goto err2; + if (!sk_X509_EXTENSION_insert(sk,new_ex,loc)) + goto err; + if (*x == NULL) + *x=sk; + return(sk); +err: + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); +err2: + if (new_ex != NULL) X509_EXTENSION_free(new_ex); + if (sk != NULL) sk_X509_EXTENSION_free(sk); + return(NULL); + } + +X509_EXTENSION *X509_EXTENSION_create_by_NID(X509_EXTENSION **ex, int nid, + int crit, ASN1_OCTET_STRING *data) + { + const ASN1_OBJECT *obj; + X509_EXTENSION *ret; + + obj=OBJ_nid2obj(nid); + if (obj == NULL) + { + OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_NID); + return(NULL); + } + ret=X509_EXTENSION_create_by_OBJ(ex,obj,crit,data); + return(ret); + } + +X509_EXTENSION *X509_EXTENSION_create_by_OBJ(X509_EXTENSION **ex, + const ASN1_OBJECT *obj, int crit, ASN1_OCTET_STRING *data) + { + X509_EXTENSION *ret; + + if ((ex == NULL) || (*ex == NULL)) + { + if ((ret=X509_EXTENSION_new()) == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return(NULL); + } + } + else + ret= *ex; + + if (!X509_EXTENSION_set_object(ret,obj)) + goto err; + if (!X509_EXTENSION_set_critical(ret,crit)) + goto err; + if (!X509_EXTENSION_set_data(ret,data)) + goto err; + + if ((ex != NULL) && (*ex == NULL)) *ex=ret; + return(ret); +err: + if ((ex == NULL) || (ret != *ex)) + X509_EXTENSION_free(ret); + return(NULL); + } + +int X509_EXTENSION_set_object(X509_EXTENSION *ex, const ASN1_OBJECT *obj) + { + if ((ex == NULL) || (obj == NULL)) + return(0); + ASN1_OBJECT_free(ex->object); + ex->object=OBJ_dup(obj); + return ex->object != NULL; + } + +int X509_EXTENSION_set_critical(X509_EXTENSION *ex, int crit) + { + if (ex == NULL) return(0); + ex->critical=(crit)?0xFF:-1; + return(1); + } + +int X509_EXTENSION_set_data(X509_EXTENSION *ex, ASN1_OCTET_STRING *data) + { + int i; + + if (ex == NULL) return(0); + i=M_ASN1_OCTET_STRING_set(ex->value,data->data,data->length); + if (!i) return(0); + return(1); + } + +ASN1_OBJECT *X509_EXTENSION_get_object(X509_EXTENSION *ex) + { + if (ex == NULL) return(NULL); + return(ex->object); + } + +ASN1_OCTET_STRING *X509_EXTENSION_get_data(X509_EXTENSION *ex) + { + if (ex == NULL) return(NULL); + return(ex->value); + } + +int X509_EXTENSION_get_critical(X509_EXTENSION *ex) + { + if (ex == NULL) return(0); + if(ex->critical > 0) return 1; + return 0; + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509_vfy.c b/TMessagesProj/jni/boringssl/crypto/x509/x509_vfy.c new file mode 100644 index 00000000..288ddd8c --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509_vfy.c @@ -0,0 +1,2465 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vpm_int.h" +#include "../internal.h" + + +static CRYPTO_EX_DATA_CLASS g_ex_data_class = + CRYPTO_EX_DATA_CLASS_INIT_WITH_APP_DATA; + +/* CRL score values */ + +/* No unhandled critical extensions */ + +#define CRL_SCORE_NOCRITICAL 0x100 + +/* certificate is within CRL scope */ + +#define CRL_SCORE_SCOPE 0x080 + +/* CRL times valid */ + +#define CRL_SCORE_TIME 0x040 + +/* Issuer name matches certificate */ + +#define CRL_SCORE_ISSUER_NAME 0x020 + +/* If this score or above CRL is probably valid */ + +#define CRL_SCORE_VALID (CRL_SCORE_NOCRITICAL|CRL_SCORE_TIME|CRL_SCORE_SCOPE) + +/* CRL issuer is certificate issuer */ + +#define CRL_SCORE_ISSUER_CERT 0x018 + +/* CRL issuer is on certificate path */ + +#define CRL_SCORE_SAME_PATH 0x008 + +/* CRL issuer matches CRL AKID */ + +#define CRL_SCORE_AKID 0x004 + +/* Have a delta CRL with valid times */ + +#define CRL_SCORE_TIME_DELTA 0x002 + +static int null_callback(int ok,X509_STORE_CTX *e); +static int check_issued(X509_STORE_CTX *ctx, X509 *x, X509 *issuer); +static X509 *find_issuer(X509_STORE_CTX *ctx, STACK_OF(X509) *sk, X509 *x); +static int check_chain_extensions(X509_STORE_CTX *ctx); +static int check_name_constraints(X509_STORE_CTX *ctx); +static int check_id(X509_STORE_CTX *ctx); +static int check_trust(X509_STORE_CTX *ctx); +static int check_revocation(X509_STORE_CTX *ctx); +static int check_cert(X509_STORE_CTX *ctx); +static int check_policy(X509_STORE_CTX *ctx); + +static int get_crl_score(X509_STORE_CTX *ctx, X509 **pissuer, + unsigned int *preasons, + X509_CRL *crl, X509 *x); +static int get_crl_delta(X509_STORE_CTX *ctx, + X509_CRL **pcrl, X509_CRL **pdcrl, X509 *x); +static void get_delta_sk(X509_STORE_CTX *ctx, X509_CRL **dcrl, int *pcrl_score, + X509_CRL *base, STACK_OF(X509_CRL) *crls); +static void crl_akid_check(X509_STORE_CTX *ctx, X509_CRL *crl, + X509 **pissuer, int *pcrl_score); +static int crl_crldp_check(X509 *x, X509_CRL *crl, int crl_score, + unsigned int *preasons); +static int check_crl_path(X509_STORE_CTX *ctx, X509 *x); +static int check_crl_chain(X509_STORE_CTX *ctx, + STACK_OF(X509) *cert_path, + STACK_OF(X509) *crl_path); + +static int internal_verify(X509_STORE_CTX *ctx); +const char X509_version[]="X.509"; + + +static int null_callback(int ok, X509_STORE_CTX *e) + { + return ok; + } + +#if 0 +static int x509_subject_cmp(X509 **a, X509 **b) + { + return X509_subject_name_cmp(*a,*b); + } +#endif +/* Return 1 is a certificate is self signed */ +static int cert_self_signed(X509 *x) + { + X509_check_purpose(x, -1, 0); + if (x->ex_flags & EXFLAG_SS) + return 1; + else + return 0; + } + +/* Given a certificate try and find an exact match in the store */ + +static X509 *lookup_cert_match(X509_STORE_CTX *ctx, X509 *x) + { + STACK_OF(X509) *certs; + X509 *xtmp = NULL; + size_t i; + /* Lookup all certs with matching subject name */ + certs = ctx->lookup_certs(ctx, X509_get_subject_name(x)); + if (certs == NULL) + return NULL; + /* Look for exact match */ + for (i = 0; i < sk_X509_num(certs); i++) + { + xtmp = sk_X509_value(certs, i); + if (!X509_cmp(xtmp, x)) + break; + } + if (i < sk_X509_num(certs)) + X509_up_ref(xtmp); + else + xtmp = NULL; + sk_X509_pop_free(certs, X509_free); + return xtmp; + } + +int X509_verify_cert(X509_STORE_CTX *ctx) + { + X509 *x,*xtmp,*chain_ss=NULL; + int bad_chain = 0; + X509_VERIFY_PARAM *param = ctx->param; + int depth,i,ok=0; + int num; + int (*cb)(int xok,X509_STORE_CTX *xctx); + STACK_OF(X509) *sktmp=NULL; + if (ctx->cert == NULL) + { + OPENSSL_PUT_ERROR(X509, X509_R_NO_CERT_SET_FOR_US_TO_VERIFY); + return -1; + } + + cb=ctx->verify_cb; + + /* first we make sure the chain we are going to build is + * present and that the first entry is in place */ + if (ctx->chain == NULL) + { + if ( ((ctx->chain=sk_X509_new_null()) == NULL) || + (!sk_X509_push(ctx->chain,ctx->cert))) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + goto end; + } + X509_up_ref(ctx->cert); + ctx->last_untrusted=1; + } + + /* We use a temporary STACK so we can chop and hack at it */ + if (ctx->untrusted != NULL + && (sktmp=sk_X509_dup(ctx->untrusted)) == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + goto end; + } + + num=sk_X509_num(ctx->chain); + x=sk_X509_value(ctx->chain,num-1); + depth=param->depth; + + + for (;;) + { + /* If we have enough, we break */ + if (depth < num) break; /* FIXME: If this happens, we should take + * note of it and, if appropriate, use the + * X509_V_ERR_CERT_CHAIN_TOO_LONG error + * code later. + */ + + /* If we are self signed, we break */ + if (cert_self_signed(x)) + break; + /* If asked see if we can find issuer in trusted store first */ + if (ctx->param->flags & X509_V_FLAG_TRUSTED_FIRST) + { + ok = ctx->get_issuer(&xtmp, ctx, x); + if (ok < 0) + return ok; + /* If successful for now free up cert so it + * will be picked up again later. + */ + if (ok > 0) + { + X509_free(xtmp); + break; + } + } + + /* If we were passed a cert chain, use it first */ + if (ctx->untrusted != NULL) + { + xtmp=find_issuer(ctx, sktmp,x); + if (xtmp != NULL) + { + if (!sk_X509_push(ctx->chain,xtmp)) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + goto end; + } + CRYPTO_refcount_inc(&xtmp->references); + (void)sk_X509_delete_ptr(sktmp,xtmp); + ctx->last_untrusted++; + x=xtmp; + num++; + /* reparse the full chain for + * the next one */ + continue; + } + } + break; + } + + /* at this point, chain should contain a list of untrusted + * certificates. We now need to add at least one trusted one, + * if possible, otherwise we complain. */ + + /* Examine last certificate in chain and see if it + * is self signed. + */ + + i=sk_X509_num(ctx->chain); + x=sk_X509_value(ctx->chain,i-1); + if (cert_self_signed(x)) + { + /* we have a self signed certificate */ + if (sk_X509_num(ctx->chain) == 1) + { + /* We have a single self signed certificate: see if + * we can find it in the store. We must have an exact + * match to avoid possible impersonation. + */ + ok = ctx->get_issuer(&xtmp, ctx, x); + if ((ok <= 0) || X509_cmp(x, xtmp)) + { + ctx->error=X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT; + ctx->current_cert=x; + ctx->error_depth=i-1; + if (ok == 1) X509_free(xtmp); + bad_chain = 1; + ok=cb(0,ctx); + if (!ok) goto end; + } + else + { + /* We have a match: replace certificate with store version + * so we get any trust settings. + */ + X509_free(x); + x = xtmp; + (void)sk_X509_set(ctx->chain, i - 1, x); + ctx->last_untrusted=0; + } + } + else + { + /* extract and save self signed certificate for later use */ + chain_ss=sk_X509_pop(ctx->chain); + ctx->last_untrusted--; + num--; + x=sk_X509_value(ctx->chain,num-1); + } + } + + /* We now lookup certs from the certificate store */ + for (;;) + { + /* If we have enough, we break */ + if (depth < num) break; + + /* If we are self signed, we break */ + if (cert_self_signed(x)) + break; + + ok = ctx->get_issuer(&xtmp, ctx, x); + + if (ok < 0) return ok; + if (ok == 0) break; + + x = xtmp; + if (!sk_X509_push(ctx->chain,x)) + { + X509_free(xtmp); + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return 0; + } + num++; + } + + /* we now have our chain, lets check it... */ + + i = check_trust(ctx); + + /* If explicitly rejected error */ + if (i == X509_TRUST_REJECTED) + goto end; + /* If not explicitly trusted then indicate error unless it's + * a single self signed certificate in which case we've indicated + * an error already and set bad_chain == 1 + */ + if (i != X509_TRUST_TRUSTED && !bad_chain) + { + if ((chain_ss == NULL) || !ctx->check_issued(ctx, x, chain_ss)) + { + if (ctx->last_untrusted >= num) + ctx->error=X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY; + else + ctx->error=X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT; + ctx->current_cert=x; + } + else + { + + sk_X509_push(ctx->chain,chain_ss); + num++; + ctx->last_untrusted=num; + ctx->current_cert=chain_ss; + ctx->error=X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN; + chain_ss=NULL; + } + + ctx->error_depth=num-1; + bad_chain = 1; + ok=cb(0,ctx); + if (!ok) goto end; + } + + /* We have the chain complete: now we need to check its purpose */ + ok = check_chain_extensions(ctx); + + if (!ok) goto end; + + /* Check name constraints */ + + ok = check_name_constraints(ctx); + + if (!ok) goto end; + + ok = check_id(ctx); + + if (!ok) goto end; + + /* Check revocation status: we do this after copying parameters + * because they may be needed for CRL signature verification. + */ + + ok = ctx->check_revocation(ctx); + if(!ok) goto end; + + i = X509_chain_check_suiteb(&ctx->error_depth, NULL, ctx->chain, + ctx->param->flags); + if (i != X509_V_OK) + { + ctx->error = i; + ctx->current_cert = sk_X509_value(ctx->chain, ctx->error_depth); + ok = cb(0, ctx); + if (!ok) + goto end; + } + + /* At this point, we have a chain and need to verify it */ + if (ctx->verify != NULL) + ok=ctx->verify(ctx); + else + ok=internal_verify(ctx); + if(!ok) goto end; + + /* If we get this far evaluate policies */ + if (!bad_chain && (ctx->param->flags & X509_V_FLAG_POLICY_CHECK)) + ok = ctx->check_policy(ctx); + +end: + if (sktmp != NULL) sk_X509_free(sktmp); + if (chain_ss != NULL) X509_free(chain_ss); + return ok; + } + + +/* Given a STACK_OF(X509) find the issuer of cert (if any) + */ + +static X509 *find_issuer(X509_STORE_CTX *ctx, STACK_OF(X509) *sk, X509 *x) +{ + size_t i; + X509 *issuer; + for (i = 0; i < sk_X509_num(sk); i++) + { + issuer = sk_X509_value(sk, i); + if (ctx->check_issued(ctx, x, issuer)) + return issuer; + } + return NULL; +} + +/* Given a possible certificate and issuer check them */ + +static int check_issued(X509_STORE_CTX *ctx, X509 *x, X509 *issuer) +{ + int ret; + ret = X509_check_issued(issuer, x); + if (ret == X509_V_OK) + return 1; + /* If we haven't asked for issuer errors don't set ctx */ + if (!(ctx->param->flags & X509_V_FLAG_CB_ISSUER_CHECK)) + return 0; + + ctx->error = ret; + ctx->current_cert = x; + ctx->current_issuer = issuer; + return ctx->verify_cb(0, ctx); +} + +/* Alternative lookup method: look from a STACK stored in other_ctx */ + +static int get_issuer_sk(X509 **issuer, X509_STORE_CTX *ctx, X509 *x) +{ + *issuer = find_issuer(ctx, ctx->other_ctx, x); + if (*issuer) + { + X509_up_ref(*issuer); + return 1; + } + else + return 0; +} + + +/* Check a certificate chains extensions for consistency + * with the supplied purpose + */ + +static int check_chain_extensions(X509_STORE_CTX *ctx) +{ + int i, ok=0, must_be_ca, plen = 0; + X509 *x; + int (*cb)(int xok,X509_STORE_CTX *xctx); + int proxy_path_length = 0; + int purpose; + int allow_proxy_certs; + cb=ctx->verify_cb; + + /* must_be_ca can have 1 of 3 values: + -1: we accept both CA and non-CA certificates, to allow direct + use of self-signed certificates (which are marked as CA). + 0: we only accept non-CA certificates. This is currently not + used, but the possibility is present for future extensions. + 1: we only accept CA certificates. This is currently used for + all certificates in the chain except the leaf certificate. + */ + must_be_ca = -1; + + /* CRL path validation */ + if (ctx->parent) + { + allow_proxy_certs = 0; + purpose = X509_PURPOSE_CRL_SIGN; + } + else + { + allow_proxy_certs = + !!(ctx->param->flags & X509_V_FLAG_ALLOW_PROXY_CERTS); + /* A hack to keep people who don't want to modify their + software happy */ + if (getenv("OPENSSL_ALLOW_PROXY_CERTS")) + allow_proxy_certs = 1; + purpose = ctx->param->purpose; + } + + /* Check all untrusted certificates */ + for (i = 0; i < ctx->last_untrusted; i++) + { + int ret; + x = sk_X509_value(ctx->chain, i); + if (!(ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL) + && (x->ex_flags & EXFLAG_CRITICAL)) + { + ctx->error = X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION; + ctx->error_depth = i; + ctx->current_cert = x; + ok=cb(0,ctx); + if (!ok) goto end; + } + if (!allow_proxy_certs && (x->ex_flags & EXFLAG_PROXY)) + { + ctx->error = X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED; + ctx->error_depth = i; + ctx->current_cert = x; + ok=cb(0,ctx); + if (!ok) goto end; + } + ret = X509_check_ca(x); + switch(must_be_ca) + { + case -1: + if ((ctx->param->flags & X509_V_FLAG_X509_STRICT) + && (ret != 1) && (ret != 0)) + { + ret = 0; + ctx->error = X509_V_ERR_INVALID_CA; + } + else + ret = 1; + break; + case 0: + if (ret != 0) + { + ret = 0; + ctx->error = X509_V_ERR_INVALID_NON_CA; + } + else + ret = 1; + break; + default: + if ((ret == 0) + || ((ctx->param->flags & X509_V_FLAG_X509_STRICT) + && (ret != 1))) + { + ret = 0; + ctx->error = X509_V_ERR_INVALID_CA; + } + else + ret = 1; + break; + } + if (ret == 0) + { + ctx->error_depth = i; + ctx->current_cert = x; + ok=cb(0,ctx); + if (!ok) goto end; + } + if (ctx->param->purpose > 0) + { + ret = X509_check_purpose(x, purpose, must_be_ca > 0); + if ((ret == 0) + || ((ctx->param->flags & X509_V_FLAG_X509_STRICT) + && (ret != 1))) + { + ctx->error = X509_V_ERR_INVALID_PURPOSE; + ctx->error_depth = i; + ctx->current_cert = x; + ok=cb(0,ctx); + if (!ok) goto end; + } + } + /* Check pathlen if not self issued */ + if ((i > 1) && !(x->ex_flags & EXFLAG_SI) + && (x->ex_pathlen != -1) + && (plen > (x->ex_pathlen + proxy_path_length + 1))) + { + ctx->error = X509_V_ERR_PATH_LENGTH_EXCEEDED; + ctx->error_depth = i; + ctx->current_cert = x; + ok=cb(0,ctx); + if (!ok) goto end; + } + /* Increment path length if not self issued */ + if (!(x->ex_flags & EXFLAG_SI)) + plen++; + /* If this certificate is a proxy certificate, the next + certificate must be another proxy certificate or a EE + certificate. If not, the next certificate must be a + CA certificate. */ + if (x->ex_flags & EXFLAG_PROXY) + { + if (x->ex_pcpathlen != -1 && i > x->ex_pcpathlen) + { + ctx->error = + X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED; + ctx->error_depth = i; + ctx->current_cert = x; + ok=cb(0,ctx); + if (!ok) goto end; + } + proxy_path_length++; + must_be_ca = 0; + } + else + must_be_ca = 1; + } + ok = 1; + end: + return ok; +} + +static int check_name_constraints(X509_STORE_CTX *ctx) + { + X509 *x; + int i, j, rv; + /* Check name constraints for all certificates */ + for (i = sk_X509_num(ctx->chain) - 1; i >= 0; i--) + { + x = sk_X509_value(ctx->chain, i); + /* Ignore self issued certs unless last in chain */ + if (i && (x->ex_flags & EXFLAG_SI)) + continue; + /* Check against constraints for all certificates higher in + * chain including trust anchor. Trust anchor not strictly + * speaking needed but if it includes constraints it is to be + * assumed it expects them to be obeyed. + */ + for (j = sk_X509_num(ctx->chain) - 1; j > i; j--) + { + NAME_CONSTRAINTS *nc = sk_X509_value(ctx->chain, j)->nc; + if (nc) + { + rv = NAME_CONSTRAINTS_check(x, nc); + if (rv != X509_V_OK) + { + ctx->error = rv; + ctx->error_depth = i; + ctx->current_cert = x; + if (!ctx->verify_cb(0,ctx)) + return 0; + } + } + } + } + return 1; + } + +static int check_id_error(X509_STORE_CTX *ctx, int errcode) + { + ctx->error = errcode; + ctx->current_cert = ctx->cert; + ctx->error_depth = 0; + return ctx->verify_cb(0, ctx); + } + +static int check_hosts(X509 *x, X509_VERIFY_PARAM_ID *id) + { + size_t i; + size_t n = sk_OPENSSL_STRING_num(id->hosts); + char *name; + + for (i = 0; i < n; ++i) + { + name = sk_OPENSSL_STRING_value(id->hosts, i); + if (X509_check_host(x, name, strlen(name), id->hostflags, + &id->peername) > 0) + return 1; + } + return n == 0; + } + +static int check_id(X509_STORE_CTX *ctx) + { + X509_VERIFY_PARAM *vpm = ctx->param; + X509_VERIFY_PARAM_ID *id = vpm->id; + X509 *x = ctx->cert; + if (id->hosts && check_hosts(x, id) <= 0) + { + if (!check_id_error(ctx, X509_V_ERR_HOSTNAME_MISMATCH)) + return 0; + } + if (id->email && X509_check_email(x, id->email, id->emaillen, 0) <= 0) + { + if (!check_id_error(ctx, X509_V_ERR_EMAIL_MISMATCH)) + return 0; + } + if (id->ip && X509_check_ip(x, id->ip, id->iplen, 0) <= 0) + { + if (!check_id_error(ctx, X509_V_ERR_IP_ADDRESS_MISMATCH)) + return 0; + } + return 1; + } + +static int check_trust(X509_STORE_CTX *ctx) +{ + size_t i; + int ok; + X509 *x = NULL; + int (*cb)(int xok,X509_STORE_CTX *xctx); + cb=ctx->verify_cb; + /* Check all trusted certificates in chain */ + for (i = ctx->last_untrusted; i < sk_X509_num(ctx->chain); i++) + { + x = sk_X509_value(ctx->chain, i); + ok = X509_check_trust(x, ctx->param->trust, 0); + /* If explicitly trusted return trusted */ + if (ok == X509_TRUST_TRUSTED) + return X509_TRUST_TRUSTED; + /* If explicitly rejected notify callback and reject if + * not overridden. + */ + if (ok == X509_TRUST_REJECTED) + { + ctx->error_depth = i; + ctx->current_cert = x; + ctx->error = X509_V_ERR_CERT_REJECTED; + ok = cb(0, ctx); + if (!ok) + return X509_TRUST_REJECTED; + } + } + /* If we accept partial chains and have at least one trusted + * certificate return success. + */ + if (ctx->param->flags & X509_V_FLAG_PARTIAL_CHAIN) + { + X509 *mx; + if (ctx->last_untrusted < (int) sk_X509_num(ctx->chain)) + return X509_TRUST_TRUSTED; + x = sk_X509_value(ctx->chain, 0); + mx = lookup_cert_match(ctx, x); + if (mx) + { + (void)sk_X509_set(ctx->chain, 0, mx); + X509_free(x); + ctx->last_untrusted = 0; + return X509_TRUST_TRUSTED; + } + } + + /* If no trusted certs in chain at all return untrusted and + * allow standard (no issuer cert) etc errors to be indicated. + */ + return X509_TRUST_UNTRUSTED; +} + +static int check_revocation(X509_STORE_CTX *ctx) + { + int i, last, ok; + if (!(ctx->param->flags & X509_V_FLAG_CRL_CHECK)) + return 1; + if (ctx->param->flags & X509_V_FLAG_CRL_CHECK_ALL) + last = sk_X509_num(ctx->chain) - 1; + else + { + /* If checking CRL paths this isn't the EE certificate */ + if (ctx->parent) + return 1; + last = 0; + } + for(i = 0; i <= last; i++) + { + ctx->error_depth = i; + ok = check_cert(ctx); + if (!ok) return ok; + } + return 1; + } + +static int check_cert(X509_STORE_CTX *ctx) + OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS + { + X509_CRL *crl = NULL, *dcrl = NULL; + X509 *x; + int ok, cnum; + unsigned int last_reasons; + cnum = ctx->error_depth; + x = sk_X509_value(ctx->chain, cnum); + ctx->current_cert = x; + ctx->current_issuer = NULL; + ctx->current_crl_score = 0; + ctx->current_reasons = 0; + while (ctx->current_reasons != CRLDP_ALL_REASONS) + { + last_reasons = ctx->current_reasons; + /* Try to retrieve relevant CRL */ + if (ctx->get_crl) + ok = ctx->get_crl(ctx, &crl, x); + else + ok = get_crl_delta(ctx, &crl, &dcrl, x); + /* If error looking up CRL, nothing we can do except + * notify callback + */ + if(!ok) + { + ctx->error = X509_V_ERR_UNABLE_TO_GET_CRL; + ok = ctx->verify_cb(0, ctx); + goto err; + } + ctx->current_crl = crl; + ok = ctx->check_crl(ctx, crl); + if (!ok) + goto err; + + if (dcrl) + { + ok = ctx->check_crl(ctx, dcrl); + if (!ok) + goto err; + ok = ctx->cert_crl(ctx, dcrl, x); + if (!ok) + goto err; + } + else + ok = 1; + + /* Don't look in full CRL if delta reason is removefromCRL */ + if (ok != 2) + { + ok = ctx->cert_crl(ctx, crl, x); + if (!ok) + goto err; + } + + X509_CRL_free(crl); + X509_CRL_free(dcrl); + crl = NULL; + dcrl = NULL; + /* If reasons not updated we wont get anywhere by + * another iteration, so exit loop. + */ + if (last_reasons == ctx->current_reasons) + { + ctx->error = X509_V_ERR_UNABLE_TO_GET_CRL; + ok = ctx->verify_cb(0, ctx); + goto err; + } + } + err: + X509_CRL_free(crl); + X509_CRL_free(dcrl); + + ctx->current_crl = NULL; + return ok; + + } + +/* Check CRL times against values in X509_STORE_CTX */ + +static int check_crl_time(X509_STORE_CTX *ctx, X509_CRL *crl, int notify) + { + time_t *ptime; + int i; + if (notify) + ctx->current_crl = crl; + if (ctx->param->flags & X509_V_FLAG_USE_CHECK_TIME) + ptime = &ctx->param->check_time; + else + ptime = NULL; + + i=X509_cmp_time(X509_CRL_get_lastUpdate(crl), ptime); + if (i == 0) + { + if (!notify) + return 0; + ctx->error=X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD; + if (!ctx->verify_cb(0, ctx)) + return 0; + } + + if (i > 0) + { + if (!notify) + return 0; + ctx->error=X509_V_ERR_CRL_NOT_YET_VALID; + if (!ctx->verify_cb(0, ctx)) + return 0; + } + + if(X509_CRL_get_nextUpdate(crl)) + { + i=X509_cmp_time(X509_CRL_get_nextUpdate(crl), ptime); + + if (i == 0) + { + if (!notify) + return 0; + ctx->error=X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD; + if (!ctx->verify_cb(0, ctx)) + return 0; + } + /* Ignore expiry of base CRL is delta is valid */ + if ((i < 0) && !(ctx->current_crl_score & CRL_SCORE_TIME_DELTA)) + { + if (!notify) + return 0; + ctx->error=X509_V_ERR_CRL_HAS_EXPIRED; + if (!ctx->verify_cb(0, ctx)) + return 0; + } + } + + if (notify) + ctx->current_crl = NULL; + + return 1; + } + +static int get_crl_sk(X509_STORE_CTX *ctx, X509_CRL **pcrl, X509_CRL **pdcrl, + X509 **pissuer, int *pscore, unsigned int *preasons, + STACK_OF(X509_CRL) *crls) + { + int crl_score, best_score = *pscore; + size_t i; + unsigned int reasons, best_reasons = 0; + X509 *x = ctx->current_cert; + X509_CRL *crl, *best_crl = NULL; + X509 *crl_issuer = NULL, *best_crl_issuer = NULL; + + for (i = 0; i < sk_X509_CRL_num(crls); i++) + { + crl = sk_X509_CRL_value(crls, i); + reasons = *preasons; + crl_score = get_crl_score(ctx, &crl_issuer, &reasons, crl, x); + + if (crl_score > best_score) + { + best_crl = crl; + best_crl_issuer = crl_issuer; + best_score = crl_score; + best_reasons = reasons; + } + } + + if (best_crl) + { + if (*pcrl) + X509_CRL_free(*pcrl); + *pcrl = best_crl; + *pissuer = best_crl_issuer; + *pscore = best_score; + *preasons = best_reasons; + CRYPTO_refcount_inc(&best_crl->references); + if (*pdcrl) + { + X509_CRL_free(*pdcrl); + *pdcrl = NULL; + } + get_delta_sk(ctx, pdcrl, pscore, best_crl, crls); + } + + if (best_score >= CRL_SCORE_VALID) + return 1; + + return 0; + } + +/* Compare two CRL extensions for delta checking purposes. They should be + * both present or both absent. If both present all fields must be identical. + */ + +static int crl_extension_match(X509_CRL *a, X509_CRL *b, int nid) + { + ASN1_OCTET_STRING *exta, *extb; + int i; + i = X509_CRL_get_ext_by_NID(a, nid, -1); + if (i >= 0) + { + /* Can't have multiple occurrences */ + if (X509_CRL_get_ext_by_NID(a, nid, i) != -1) + return 0; + exta = X509_EXTENSION_get_data(X509_CRL_get_ext(a, i)); + } + else + exta = NULL; + + i = X509_CRL_get_ext_by_NID(b, nid, -1); + + if (i >= 0) + { + + if (X509_CRL_get_ext_by_NID(b, nid, i) != -1) + return 0; + extb = X509_EXTENSION_get_data(X509_CRL_get_ext(b, i)); + } + else + extb = NULL; + + if (!exta && !extb) + return 1; + + if (!exta || !extb) + return 0; + + + if (ASN1_OCTET_STRING_cmp(exta, extb)) + return 0; + + return 1; + } + +/* See if a base and delta are compatible */ + +static int check_delta_base(X509_CRL *delta, X509_CRL *base) + { + /* Delta CRL must be a delta */ + if (!delta->base_crl_number) + return 0; + /* Base must have a CRL number */ + if (!base->crl_number) + return 0; + /* Issuer names must match */ + if (X509_NAME_cmp(X509_CRL_get_issuer(base), + X509_CRL_get_issuer(delta))) + return 0; + /* AKID and IDP must match */ + if (!crl_extension_match(delta, base, NID_authority_key_identifier)) + return 0; + if (!crl_extension_match(delta, base, NID_issuing_distribution_point)) + return 0; + /* Delta CRL base number must not exceed Full CRL number. */ + if (ASN1_INTEGER_cmp(delta->base_crl_number, base->crl_number) > 0) + return 0; + /* Delta CRL number must exceed full CRL number */ + if (ASN1_INTEGER_cmp(delta->crl_number, base->crl_number) > 0) + return 1; + return 0; + } + +/* For a given base CRL find a delta... maybe extend to delta scoring + * or retrieve a chain of deltas... + */ + +static void get_delta_sk(X509_STORE_CTX *ctx, X509_CRL **dcrl, int *pscore, + X509_CRL *base, STACK_OF(X509_CRL) *crls) + { + X509_CRL *delta; + size_t i; + if (!(ctx->param->flags & X509_V_FLAG_USE_DELTAS)) + return; + if (!((ctx->current_cert->ex_flags | base->flags) & EXFLAG_FRESHEST)) + return; + for (i = 0; i < sk_X509_CRL_num(crls); i++) + { + delta = sk_X509_CRL_value(crls, i); + if (check_delta_base(delta, base)) + { + if (check_crl_time(ctx, delta, 0)) + *pscore |= CRL_SCORE_TIME_DELTA; + CRYPTO_refcount_inc(&delta->references); + *dcrl = delta; + return; + } + } + *dcrl = NULL; + } + +/* For a given CRL return how suitable it is for the supplied certificate 'x'. + * The return value is a mask of several criteria. + * If the issuer is not the certificate issuer this is returned in *pissuer. + * The reasons mask is also used to determine if the CRL is suitable: if + * no new reasons the CRL is rejected, otherwise reasons is updated. + */ + +static int get_crl_score(X509_STORE_CTX *ctx, X509 **pissuer, + unsigned int *preasons, + X509_CRL *crl, X509 *x) + { + + int crl_score = 0; + unsigned int tmp_reasons = *preasons, crl_reasons; + + /* First see if we can reject CRL straight away */ + + /* Invalid IDP cannot be processed */ + if (crl->idp_flags & IDP_INVALID) + return 0; + /* Reason codes or indirect CRLs need extended CRL support */ + if (!(ctx->param->flags & X509_V_FLAG_EXTENDED_CRL_SUPPORT)) + { + if (crl->idp_flags & (IDP_INDIRECT | IDP_REASONS)) + return 0; + } + else if (crl->idp_flags & IDP_REASONS) + { + /* If no new reasons reject */ + if (!(crl->idp_reasons & ~tmp_reasons)) + return 0; + } + /* Don't process deltas at this stage */ + else if (crl->base_crl_number) + return 0; + /* If issuer name doesn't match certificate need indirect CRL */ + if (X509_NAME_cmp(X509_get_issuer_name(x), X509_CRL_get_issuer(crl))) + { + if (!(crl->idp_flags & IDP_INDIRECT)) + return 0; + } + else + crl_score |= CRL_SCORE_ISSUER_NAME; + + if (!(crl->flags & EXFLAG_CRITICAL)) + crl_score |= CRL_SCORE_NOCRITICAL; + + /* Check expiry */ + if (check_crl_time(ctx, crl, 0)) + crl_score |= CRL_SCORE_TIME; + + /* Check authority key ID and locate certificate issuer */ + crl_akid_check(ctx, crl, pissuer, &crl_score); + + /* If we can't locate certificate issuer at this point forget it */ + + if (!(crl_score & CRL_SCORE_AKID)) + return 0; + + /* Check cert for matching CRL distribution points */ + + if (crl_crldp_check(x, crl, crl_score, &crl_reasons)) + { + /* If no new reasons reject */ + if (!(crl_reasons & ~tmp_reasons)) + return 0; + tmp_reasons |= crl_reasons; + crl_score |= CRL_SCORE_SCOPE; + } + + *preasons = tmp_reasons; + + return crl_score; + + } + +static void crl_akid_check(X509_STORE_CTX *ctx, X509_CRL *crl, + X509 **pissuer, int *pcrl_score) + { + X509 *crl_issuer = NULL; + X509_NAME *cnm = X509_CRL_get_issuer(crl); + int cidx = ctx->error_depth; + size_t i; + + if (cidx != sk_X509_num(ctx->chain) - 1) + cidx++; + + crl_issuer = sk_X509_value(ctx->chain, cidx); + + if (X509_check_akid(crl_issuer, crl->akid) == X509_V_OK) + { + if (*pcrl_score & CRL_SCORE_ISSUER_NAME) + { + *pcrl_score |= CRL_SCORE_AKID|CRL_SCORE_ISSUER_CERT; + *pissuer = crl_issuer; + return; + } + } + + for (cidx++; cidx < (int) sk_X509_num(ctx->chain); cidx++) + { + crl_issuer = sk_X509_value(ctx->chain, cidx); + if (X509_NAME_cmp(X509_get_subject_name(crl_issuer), cnm)) + continue; + if (X509_check_akid(crl_issuer, crl->akid) == X509_V_OK) + { + *pcrl_score |= CRL_SCORE_AKID|CRL_SCORE_SAME_PATH; + *pissuer = crl_issuer; + return; + } + } + + /* Anything else needs extended CRL support */ + + if (!(ctx->param->flags & X509_V_FLAG_EXTENDED_CRL_SUPPORT)) + return; + + /* Otherwise the CRL issuer is not on the path. Look for it in the + * set of untrusted certificates. + */ + for (i = 0; i < sk_X509_num(ctx->untrusted); i++) + { + crl_issuer = sk_X509_value(ctx->untrusted, i); + if (X509_NAME_cmp(X509_get_subject_name(crl_issuer), cnm)) + continue; + if (X509_check_akid(crl_issuer, crl->akid) == X509_V_OK) + { + *pissuer = crl_issuer; + *pcrl_score |= CRL_SCORE_AKID; + return; + } + } + } + +/* Check the path of a CRL issuer certificate. This creates a new + * X509_STORE_CTX and populates it with most of the parameters from the + * parent. This could be optimised somewhat since a lot of path checking + * will be duplicated by the parent, but this will rarely be used in + * practice. + */ + +static int check_crl_path(X509_STORE_CTX *ctx, X509 *x) + { + X509_STORE_CTX crl_ctx; + int ret; + /* Don't allow recursive CRL path validation */ + if (ctx->parent) + return 0; + if (!X509_STORE_CTX_init(&crl_ctx, ctx->ctx, x, ctx->untrusted)) + return -1; + + crl_ctx.crls = ctx->crls; + /* Copy verify params across */ + X509_STORE_CTX_set0_param(&crl_ctx, ctx->param); + + crl_ctx.parent = ctx; + crl_ctx.verify_cb = ctx->verify_cb; + + /* Verify CRL issuer */ + ret = X509_verify_cert(&crl_ctx); + + if (ret <= 0) + goto err; + + /* Check chain is acceptable */ + + ret = check_crl_chain(ctx, ctx->chain, crl_ctx.chain); + err: + X509_STORE_CTX_cleanup(&crl_ctx); + return ret; + } + +/* RFC3280 says nothing about the relationship between CRL path + * and certificate path, which could lead to situations where a + * certificate could be revoked or validated by a CA not authorised + * to do so. RFC5280 is more strict and states that the two paths must + * end in the same trust anchor, though some discussions remain... + * until this is resolved we use the RFC5280 version + */ + +static int check_crl_chain(X509_STORE_CTX *ctx, + STACK_OF(X509) *cert_path, + STACK_OF(X509) *crl_path) + { + X509 *cert_ta, *crl_ta; + cert_ta = sk_X509_value(cert_path, sk_X509_num(cert_path) - 1); + crl_ta = sk_X509_value(crl_path, sk_X509_num(crl_path) - 1); + if (!X509_cmp(cert_ta, crl_ta)) + return 1; + return 0; + } + +/* Check for match between two dist point names: three separate cases. + * 1. Both are relative names and compare X509_NAME types. + * 2. One full, one relative. Compare X509_NAME to GENERAL_NAMES. + * 3. Both are full names and compare two GENERAL_NAMES. + * 4. One is NULL: automatic match. + */ + + +static int idp_check_dp(DIST_POINT_NAME *a, DIST_POINT_NAME *b) + { + X509_NAME *nm = NULL; + GENERAL_NAMES *gens = NULL; + GENERAL_NAME *gena, *genb; + size_t i, j; + if (!a || !b) + return 1; + if (a->type == 1) + { + if (!a->dpname) + return 0; + /* Case 1: two X509_NAME */ + if (b->type == 1) + { + if (!b->dpname) + return 0; + if (!X509_NAME_cmp(a->dpname, b->dpname)) + return 1; + else + return 0; + } + /* Case 2: set name and GENERAL_NAMES appropriately */ + nm = a->dpname; + gens = b->name.fullname; + } + else if (b->type == 1) + { + if (!b->dpname) + return 0; + /* Case 2: set name and GENERAL_NAMES appropriately */ + gens = a->name.fullname; + nm = b->dpname; + } + + /* Handle case 2 with one GENERAL_NAMES and one X509_NAME */ + if (nm) + { + for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) + { + gena = sk_GENERAL_NAME_value(gens, i); + if (gena->type != GEN_DIRNAME) + continue; + if (!X509_NAME_cmp(nm, gena->d.directoryName)) + return 1; + } + return 0; + } + + /* Else case 3: two GENERAL_NAMES */ + + for (i = 0; i < sk_GENERAL_NAME_num(a->name.fullname); i++) + { + gena = sk_GENERAL_NAME_value(a->name.fullname, i); + for (j = 0; j < sk_GENERAL_NAME_num(b->name.fullname); j++) + { + genb = sk_GENERAL_NAME_value(b->name.fullname, j); + if (!GENERAL_NAME_cmp(gena, genb)) + return 1; + } + } + + return 0; + + } + +static int crldp_check_crlissuer(DIST_POINT *dp, X509_CRL *crl, int crl_score) + { + size_t i; + X509_NAME *nm = X509_CRL_get_issuer(crl); + /* If no CRLissuer return is successful iff don't need a match */ + if (!dp->CRLissuer) + return !!(crl_score & CRL_SCORE_ISSUER_NAME); + for (i = 0; i < sk_GENERAL_NAME_num(dp->CRLissuer); i++) + { + GENERAL_NAME *gen = sk_GENERAL_NAME_value(dp->CRLissuer, i); + if (gen->type != GEN_DIRNAME) + continue; + if (!X509_NAME_cmp(gen->d.directoryName, nm)) + return 1; + } + return 0; + } + +/* Check CRLDP and IDP */ + +static int crl_crldp_check(X509 *x, X509_CRL *crl, int crl_score, + unsigned int *preasons) + { + size_t i; + if (crl->idp_flags & IDP_ONLYATTR) + return 0; + if (x->ex_flags & EXFLAG_CA) + { + if (crl->idp_flags & IDP_ONLYUSER) + return 0; + } + else + { + if (crl->idp_flags & IDP_ONLYCA) + return 0; + } + *preasons = crl->idp_reasons; + for (i = 0; i < sk_DIST_POINT_num(x->crldp); i++) + { + DIST_POINT *dp = sk_DIST_POINT_value(x->crldp, i); + if (crldp_check_crlissuer(dp, crl, crl_score)) + { + if (!crl->idp || + idp_check_dp(dp->distpoint, crl->idp->distpoint)) + { + *preasons &= dp->dp_reasons; + return 1; + } + } + } + if ((!crl->idp || !crl->idp->distpoint) && (crl_score & CRL_SCORE_ISSUER_NAME)) + return 1; + return 0; + } + +/* Retrieve CRL corresponding to current certificate. + * If deltas enabled try to find a delta CRL too + */ + +static int get_crl_delta(X509_STORE_CTX *ctx, + X509_CRL **pcrl, X509_CRL **pdcrl, X509 *x) + { + int ok; + X509 *issuer = NULL; + int crl_score = 0; + unsigned int reasons; + X509_CRL *crl = NULL, *dcrl = NULL; + STACK_OF(X509_CRL) *skcrl; + X509_NAME *nm = X509_get_issuer_name(x); + reasons = ctx->current_reasons; + ok = get_crl_sk(ctx, &crl, &dcrl, + &issuer, &crl_score, &reasons, ctx->crls); + + if (ok) + goto done; + + /* Lookup CRLs from store */ + + skcrl = ctx->lookup_crls(ctx, nm); + + /* If no CRLs found and a near match from get_crl_sk use that */ + if (!skcrl && crl) + goto done; + + get_crl_sk(ctx, &crl, &dcrl, &issuer, &crl_score, &reasons, skcrl); + + sk_X509_CRL_pop_free(skcrl, X509_CRL_free); + + done: + + /* If we got any kind of CRL use it and return success */ + if (crl) + { + ctx->current_issuer = issuer; + ctx->current_crl_score = crl_score; + ctx->current_reasons = reasons; + *pcrl = crl; + *pdcrl = dcrl; + return 1; + } + + return 0; + } + +/* Check CRL validity */ +static int check_crl(X509_STORE_CTX *ctx, X509_CRL *crl) + { + X509 *issuer = NULL; + EVP_PKEY *ikey = NULL; + int ok = 0, chnum, cnum; + cnum = ctx->error_depth; + chnum = sk_X509_num(ctx->chain) - 1; + /* if we have an alternative CRL issuer cert use that */ + if (ctx->current_issuer) + issuer = ctx->current_issuer; + + /* Else find CRL issuer: if not last certificate then issuer + * is next certificate in chain. + */ + else if (cnum < chnum) + issuer = sk_X509_value(ctx->chain, cnum + 1); + else + { + issuer = sk_X509_value(ctx->chain, chnum); + /* If not self signed, can't check signature */ + if(!ctx->check_issued(ctx, issuer, issuer)) + { + ctx->error = X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER; + ok = ctx->verify_cb(0, ctx); + if(!ok) goto err; + } + } + + if(issuer) + { + /* Skip most tests for deltas because they have already + * been done + */ + if (!crl->base_crl_number) + { + /* Check for cRLSign bit if keyUsage present */ + if ((issuer->ex_flags & EXFLAG_KUSAGE) && + !(issuer->ex_kusage & KU_CRL_SIGN)) + { + ctx->error = X509_V_ERR_KEYUSAGE_NO_CRL_SIGN; + ok = ctx->verify_cb(0, ctx); + if(!ok) goto err; + } + + if (!(ctx->current_crl_score & CRL_SCORE_SCOPE)) + { + ctx->error = X509_V_ERR_DIFFERENT_CRL_SCOPE; + ok = ctx->verify_cb(0, ctx); + if(!ok) goto err; + } + + if (!(ctx->current_crl_score & CRL_SCORE_SAME_PATH)) + { + if (check_crl_path(ctx, ctx->current_issuer) <= 0) + { + ctx->error = X509_V_ERR_CRL_PATH_VALIDATION_ERROR; + ok = ctx->verify_cb(0, ctx); + if(!ok) goto err; + } + } + + if (crl->idp_flags & IDP_INVALID) + { + ctx->error = X509_V_ERR_INVALID_EXTENSION; + ok = ctx->verify_cb(0, ctx); + if(!ok) goto err; + } + + + } + + if (!(ctx->current_crl_score & CRL_SCORE_TIME)) + { + ok = check_crl_time(ctx, crl, 1); + if (!ok) + goto err; + } + + /* Attempt to get issuer certificate public key */ + ikey = X509_get_pubkey(issuer); + + if(!ikey) + { + ctx->error=X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY; + ok = ctx->verify_cb(0, ctx); + if (!ok) goto err; + } + else + { + int rv; + rv = X509_CRL_check_suiteb(crl, ikey, ctx->param->flags); + if (rv != X509_V_OK) + { + ctx->error=rv; + ok = ctx->verify_cb(0, ctx); + if (!ok) + goto err; + } + /* Verify CRL signature */ + if(X509_CRL_verify(crl, ikey) <= 0) + { + ctx->error=X509_V_ERR_CRL_SIGNATURE_FAILURE; + ok = ctx->verify_cb(0, ctx); + if (!ok) goto err; + } + } + } + + ok = 1; + + err: + EVP_PKEY_free(ikey); + return ok; + } + +/* Check certificate against CRL */ +static int cert_crl(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x) + { + int ok; + X509_REVOKED *rev; + /* The rules changed for this... previously if a CRL contained + * unhandled critical extensions it could still be used to indicate + * a certificate was revoked. This has since been changed since + * critical extension can change the meaning of CRL entries. + */ + if (!(ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL) + && (crl->flags & EXFLAG_CRITICAL)) + { + ctx->error = X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION; + ok = ctx->verify_cb(0, ctx); + if(!ok) + return 0; + } + /* Look for serial number of certificate in CRL + * If found make sure reason is not removeFromCRL. + */ + if (X509_CRL_get0_by_cert(crl, &rev, x)) + { + if (rev->reason == CRL_REASON_REMOVE_FROM_CRL) + return 2; + ctx->error = X509_V_ERR_CERT_REVOKED; + ok = ctx->verify_cb(0, ctx); + if (!ok) + return 0; + } + + return 1; + } + +static int check_policy(X509_STORE_CTX *ctx) + { + int ret; + if (ctx->parent) + return 1; + ret = X509_policy_check(&ctx->tree, &ctx->explicit_policy, ctx->chain, + ctx->param->policies, ctx->param->flags); + if (ret == 0) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return 0; + } + /* Invalid or inconsistent extensions */ + if (ret == -1) + { + /* Locate certificates with bad extensions and notify + * callback. + */ + X509 *x; + size_t i; + for (i = 1; i < sk_X509_num(ctx->chain); i++) + { + x = sk_X509_value(ctx->chain, i); + if (!(x->ex_flags & EXFLAG_INVALID_POLICY)) + continue; + ctx->current_cert = x; + ctx->error = X509_V_ERR_INVALID_POLICY_EXTENSION; + if(!ctx->verify_cb(0, ctx)) + return 0; + } + return 1; + } + if (ret == -2) + { + ctx->current_cert = NULL; + ctx->error = X509_V_ERR_NO_EXPLICIT_POLICY; + return ctx->verify_cb(0, ctx); + } + + if (ctx->param->flags & X509_V_FLAG_NOTIFY_POLICY) + { + ctx->current_cert = NULL; + ctx->error = X509_V_OK; + if (!ctx->verify_cb(2, ctx)) + return 0; + } + + return 1; + } + +static int check_cert_time(X509_STORE_CTX *ctx, X509 *x) + { + time_t *ptime; + int i; + + if (ctx->param->flags & X509_V_FLAG_USE_CHECK_TIME) + ptime = &ctx->param->check_time; + else + ptime = NULL; + + i=X509_cmp_time(X509_get_notBefore(x), ptime); + if (i == 0) + { + ctx->error=X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD; + ctx->current_cert=x; + if (!ctx->verify_cb(0, ctx)) + return 0; + } + + if (i > 0) + { + ctx->error=X509_V_ERR_CERT_NOT_YET_VALID; + ctx->current_cert=x; + if (!ctx->verify_cb(0, ctx)) + return 0; + } + + i=X509_cmp_time(X509_get_notAfter(x), ptime); + if (i == 0) + { + ctx->error=X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD; + ctx->current_cert=x; + if (!ctx->verify_cb(0, ctx)) + return 0; + } + + if (i < 0) + { + ctx->error=X509_V_ERR_CERT_HAS_EXPIRED; + ctx->current_cert=x; + if (!ctx->verify_cb(0, ctx)) + return 0; + } + + return 1; + } + +static int internal_verify(X509_STORE_CTX *ctx) + { + int ok=0,n; + X509 *xs,*xi; + EVP_PKEY *pkey=NULL; + int (*cb)(int xok,X509_STORE_CTX *xctx); + + cb=ctx->verify_cb; + + n=sk_X509_num(ctx->chain); + ctx->error_depth=n-1; + n--; + xi=sk_X509_value(ctx->chain,n); + + if (ctx->check_issued(ctx, xi, xi)) + xs=xi; + else + { + if (ctx->param->flags & X509_V_FLAG_PARTIAL_CHAIN) + { + xs = xi; + goto check_cert; + } + if (n <= 0) + { + ctx->error=X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE; + ctx->current_cert=xi; + ok=cb(0,ctx); + goto end; + } + else + { + n--; + ctx->error_depth=n; + xs=sk_X509_value(ctx->chain,n); + } + } + +/* ctx->error=0; not needed */ + while (n >= 0) + { + ctx->error_depth=n; + + /* Skip signature check for self signed certificates unless + * explicitly asked for. It doesn't add any security and + * just wastes time. + */ + if (!xs->valid && (xs != xi || (ctx->param->flags & X509_V_FLAG_CHECK_SS_SIGNATURE))) + { + if ((pkey=X509_get_pubkey(xi)) == NULL) + { + ctx->error=X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY; + ctx->current_cert=xi; + ok=(*cb)(0,ctx); + if (!ok) goto end; + } + else if (X509_verify(xs,pkey) <= 0) + { + ctx->error=X509_V_ERR_CERT_SIGNATURE_FAILURE; + ctx->current_cert=xs; + ok=(*cb)(0,ctx); + if (!ok) + { + EVP_PKEY_free(pkey); + goto end; + } + } + EVP_PKEY_free(pkey); + pkey=NULL; + } + + xs->valid = 1; + + check_cert: + ok = check_cert_time(ctx, xs); + if (!ok) + goto end; + + /* The last error (if any) is still in the error value */ + ctx->current_issuer=xi; + ctx->current_cert=xs; + ok=(*cb)(1,ctx); + if (!ok) goto end; + + n--; + if (n >= 0) + { + xi=xs; + xs=sk_X509_value(ctx->chain,n); + } + } + ok=1; +end: + return ok; + } + +int X509_cmp_current_time(const ASN1_TIME *ctm) +{ + return X509_cmp_time(ctm, NULL); +} + +int X509_cmp_time(const ASN1_TIME *ctm, time_t *cmp_time) + { + char *str; + ASN1_TIME atm; + long offset; + char buff1[24],buff2[24],*p; + int i, j, remaining; + + p=buff1; + remaining = ctm->length; + str=(char *)ctm->data; + /* Note that the following (historical) code allows much more slack in + * the time format than RFC5280. In RFC5280, the representation is + * fixed: + * UTCTime: YYMMDDHHMMSSZ + * GeneralizedTime: YYYYMMDDHHMMSSZ */ + if (ctm->type == V_ASN1_UTCTIME) + { + /* YYMMDDHHMM[SS]Z or YYMMDDHHMM[SS](+-)hhmm */ + int min_length = sizeof("YYMMDDHHMMZ") - 1; + int max_length = sizeof("YYMMDDHHMMSS+hhmm") - 1; + if (remaining < min_length || remaining > max_length) + return 0; + memcpy(p,str,10); + p+=10; + str+=10; + remaining -= 10; + } + else + { + /* YYYYMMDDHHMM[SS[.fff]]Z or YYYYMMDDHHMM[SS[.f[f[f]]]](+-)hhmm */ + int min_length = sizeof("YYYYMMDDHHMMZ") - 1; + int max_length = sizeof("YYYYMMDDHHMMSS.fff+hhmm") - 1; + if (remaining < min_length || remaining > max_length) + return 0; + memcpy(p,str,12); + p+=12; + str+=12; + remaining -= 12; + } + + if ((*str == 'Z') || (*str == '-') || (*str == '+')) + { *(p++)='0'; *(p++)='0'; } + else + { + /* SS (seconds) */ + if (remaining < 2) + return 0; + *(p++)= *(str++); + *(p++)= *(str++); + remaining -= 2; + /* Skip any (up to three) fractional seconds... + * TODO(emilia): in RFC5280, fractional seconds are forbidden. + * Can we just kill them altogether? */ + if (remaining && *str == '.') + { + str++; + remaining--; + for (i = 0; i < 3 && remaining; i++, str++, remaining--) + { + if (*str < '0' || *str > '9') + break; + } + } + + } + *(p++)='Z'; + *(p++)='\0'; + + /* We now need either a terminating 'Z' or an offset. */ + if (!remaining) + return 0; + if (*str == 'Z') + { + if (remaining != 1) + return 0; + offset=0; + } + else + { + /* (+-)HHMM */ + if ((*str != '+') && (*str != '-')) + return 0; + /* Historical behaviour: the (+-)hhmm offset is forbidden in RFC5280. */ + if (remaining != 5) + return 0; + if (str[1] < '0' || str[1] > '9' || str[2] < '0' || str[2] > '9' || + str[3] < '0' || str[3] > '9' || str[4] < '0' || str[4] > '9') + return 0; + offset=((str[1]-'0')*10+(str[2]-'0'))*60; + offset+=(str[3]-'0')*10+(str[4]-'0'); + if (*str == '-') + offset= -offset; + } + atm.type=ctm->type; + atm.flags = 0; + atm.length=sizeof(buff2); + atm.data=(unsigned char *)buff2; + + if (X509_time_adj(&atm, offset*60, cmp_time) == NULL) + return 0; + + if (ctm->type == V_ASN1_UTCTIME) + { + i=(buff1[0]-'0')*10+(buff1[1]-'0'); + if (i < 50) i+=100; /* cf. RFC 2459 */ + j=(buff2[0]-'0')*10+(buff2[1]-'0'); + if (j < 50) j+=100; + + if (i < j) return -1; + if (i > j) return 1; + } + i=strcmp(buff1,buff2); + if (i == 0) /* wait a second then return younger :-) */ + return -1; + else + return i; + } + +ASN1_TIME *X509_gmtime_adj(ASN1_TIME *s, long adj) +{ + return X509_time_adj(s, adj, NULL); +} + +ASN1_TIME *X509_time_adj(ASN1_TIME *s, long offset_sec, time_t *in_tm) + { + return X509_time_adj_ex(s, 0, offset_sec, in_tm); + } + +ASN1_TIME *X509_time_adj_ex(ASN1_TIME *s, + int offset_day, long offset_sec, time_t *in_tm) + { + time_t t = 0; + + if (in_tm) t = *in_tm; + else time(&t); + + if (s && !(s->flags & ASN1_STRING_FLAG_MSTRING)) + { + if (s->type == V_ASN1_UTCTIME) + return ASN1_UTCTIME_adj(s,t, offset_day, offset_sec); + if (s->type == V_ASN1_GENERALIZEDTIME) + return ASN1_GENERALIZEDTIME_adj(s, t, offset_day, + offset_sec); + } + return ASN1_TIME_adj(s, t, offset_day, offset_sec); + } + +/* Make a delta CRL as the diff between two full CRLs */ + +X509_CRL *X509_CRL_diff(X509_CRL *base, X509_CRL *newer, + EVP_PKEY *skey, const EVP_MD *md, unsigned int flags) + { + X509_CRL *crl = NULL; + int i; + size_t j; + STACK_OF(X509_REVOKED) *revs = NULL; + /* CRLs can't be delta already */ + if (base->base_crl_number || newer->base_crl_number) + { + OPENSSL_PUT_ERROR(X509, X509_R_CRL_ALREADY_DELTA); + return NULL; + } + /* Base and new CRL must have a CRL number */ + if (!base->crl_number || !newer->crl_number) + { + OPENSSL_PUT_ERROR(X509, X509_R_NO_CRL_NUMBER); + return NULL; + } + /* Issuer names must match */ + if (X509_NAME_cmp(X509_CRL_get_issuer(base), + X509_CRL_get_issuer(newer))) + { + OPENSSL_PUT_ERROR(X509, X509_R_ISSUER_MISMATCH); + return NULL; + } + /* AKID and IDP must match */ + if (!crl_extension_match(base, newer, NID_authority_key_identifier)) + { + OPENSSL_PUT_ERROR(X509, X509_R_AKID_MISMATCH); + return NULL; + } + if (!crl_extension_match(base, newer, NID_issuing_distribution_point)) + { + OPENSSL_PUT_ERROR(X509, X509_R_IDP_MISMATCH); + return NULL; + } + /* Newer CRL number must exceed full CRL number */ + if (ASN1_INTEGER_cmp(newer->crl_number, base->crl_number) <= 0) + { + OPENSSL_PUT_ERROR(X509, X509_R_NEWER_CRL_NOT_NEWER); + return NULL; + } + /* CRLs must verify */ + if (skey && (X509_CRL_verify(base, skey) <= 0 || + X509_CRL_verify(newer, skey) <= 0)) + { + OPENSSL_PUT_ERROR(X509, X509_R_CRL_VERIFY_FAILURE); + return NULL; + } + /* Create new CRL */ + crl = X509_CRL_new(); + if (!crl || !X509_CRL_set_version(crl, 1)) + goto memerr; + /* Set issuer name */ + if (!X509_CRL_set_issuer_name(crl, X509_CRL_get_issuer(newer))) + goto memerr; + + if (!X509_CRL_set_lastUpdate(crl, X509_CRL_get_lastUpdate(newer))) + goto memerr; + if (!X509_CRL_set_nextUpdate(crl, X509_CRL_get_nextUpdate(newer))) + goto memerr; + + /* Set base CRL number: must be critical */ + + if (!X509_CRL_add1_ext_i2d(crl, NID_delta_crl, base->crl_number, 1, 0)) + goto memerr; + + /* Copy extensions across from newest CRL to delta: this will set + * CRL number to correct value too. + */ + + for (i = 0; i < X509_CRL_get_ext_count(newer); i++) + { + X509_EXTENSION *ext; + ext = X509_CRL_get_ext(newer, i); + if (!X509_CRL_add_ext(crl, ext, -1)) + goto memerr; + } + + /* Go through revoked entries, copying as needed */ + + revs = X509_CRL_get_REVOKED(newer); + + for (j = 0; j < sk_X509_REVOKED_num(revs); j++) + { + X509_REVOKED *rvn, *rvtmp; + rvn = sk_X509_REVOKED_value(revs, j); + /* Add only if not also in base. + * TODO: need something cleverer here for some more complex + * CRLs covering multiple CAs. + */ + if (!X509_CRL_get0_by_serial(base, &rvtmp, rvn->serialNumber)) + { + rvtmp = X509_REVOKED_dup(rvn); + if (!rvtmp) + goto memerr; + if (!X509_CRL_add0_revoked(crl, rvtmp)) + { + X509_REVOKED_free(rvtmp); + goto memerr; + } + } + } + /* TODO: optionally prune deleted entries */ + + if (skey && md && !X509_CRL_sign(crl, skey, md)) + goto memerr; + + return crl; + + memerr: + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + if (crl) + X509_CRL_free(crl); + return NULL; + } + +int X509_STORE_CTX_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func) + { + /* This function is (usually) called only once, by + * SSL_get_ex_data_X509_STORE_CTX_idx (ssl/ssl_cert.c). */ + int index; + if (!CRYPTO_get_ex_new_index(&g_ex_data_class, &index, argl, argp, + new_func, dup_func, free_func)) + { + return -1; + } + return index; + } + +int X509_STORE_CTX_set_ex_data(X509_STORE_CTX *ctx, int idx, void *data) + { + return CRYPTO_set_ex_data(&ctx->ex_data,idx,data); + } + +void *X509_STORE_CTX_get_ex_data(X509_STORE_CTX *ctx, int idx) + { + return CRYPTO_get_ex_data(&ctx->ex_data,idx); + } + +int X509_STORE_CTX_get_error(X509_STORE_CTX *ctx) + { + return ctx->error; + } + +void X509_STORE_CTX_set_error(X509_STORE_CTX *ctx, int err) + { + ctx->error=err; + } + +int X509_STORE_CTX_get_error_depth(X509_STORE_CTX *ctx) + { + return ctx->error_depth; + } + +X509 *X509_STORE_CTX_get_current_cert(X509_STORE_CTX *ctx) + { + return ctx->current_cert; + } + +STACK_OF(X509) *X509_STORE_CTX_get_chain(X509_STORE_CTX *ctx) + { + return ctx->chain; + } + +STACK_OF(X509) *X509_STORE_CTX_get1_chain(X509_STORE_CTX *ctx) + { + if (!ctx->chain) + return NULL; + return X509_chain_up_ref(ctx->chain); + } + +X509 *X509_STORE_CTX_get0_current_issuer(X509_STORE_CTX *ctx) + { + return ctx->current_issuer; + } + +X509_CRL *X509_STORE_CTX_get0_current_crl(X509_STORE_CTX *ctx) + { + return ctx->current_crl; + } + +X509_STORE_CTX *X509_STORE_CTX_get0_parent_ctx(X509_STORE_CTX *ctx) + { + return ctx->parent; + } + +void X509_STORE_CTX_set_cert(X509_STORE_CTX *ctx, X509 *x) + { + ctx->cert=x; + } + +void X509_STORE_CTX_set_chain(X509_STORE_CTX *ctx, STACK_OF(X509) *sk) + { + ctx->untrusted=sk; + } + +void X509_STORE_CTX_set0_crls(X509_STORE_CTX *ctx, STACK_OF(X509_CRL) *sk) + { + ctx->crls=sk; + } + +int X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose) + { + return X509_STORE_CTX_purpose_inherit(ctx, 0, purpose, 0); + } + +int X509_STORE_CTX_set_trust(X509_STORE_CTX *ctx, int trust) + { + return X509_STORE_CTX_purpose_inherit(ctx, 0, 0, trust); + } + +/* This function is used to set the X509_STORE_CTX purpose and trust + * values. This is intended to be used when another structure has its + * own trust and purpose values which (if set) will be inherited by + * the ctx. If they aren't set then we will usually have a default + * purpose in mind which should then be used to set the trust value. + * An example of this is SSL use: an SSL structure will have its own + * purpose and trust settings which the application can set: if they + * aren't set then we use the default of SSL client/server. + */ + +int X509_STORE_CTX_purpose_inherit(X509_STORE_CTX *ctx, int def_purpose, + int purpose, int trust) +{ + int idx; + /* If purpose not set use default */ + if (!purpose) purpose = def_purpose; + /* If we have a purpose then check it is valid */ + if (purpose) + { + X509_PURPOSE *ptmp; + idx = X509_PURPOSE_get_by_id(purpose); + if (idx == -1) + { + OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_PURPOSE_ID); + return 0; + } + ptmp = X509_PURPOSE_get0(idx); + if (ptmp->trust == X509_TRUST_DEFAULT) + { + idx = X509_PURPOSE_get_by_id(def_purpose); + if (idx == -1) + { + OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_PURPOSE_ID); + return 0; + } + ptmp = X509_PURPOSE_get0(idx); + } + /* If trust not set then get from purpose default */ + if (!trust) trust = ptmp->trust; + } + if (trust) + { + idx = X509_TRUST_get_by_id(trust); + if (idx == -1) + { + OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_TRUST_ID); + return 0; + } + } + + if (purpose && !ctx->param->purpose) ctx->param->purpose = purpose; + if (trust && !ctx->param->trust) ctx->param->trust = trust; + return 1; +} + +X509_STORE_CTX *X509_STORE_CTX_new(void) +{ + X509_STORE_CTX *ctx; + ctx = (X509_STORE_CTX *)OPENSSL_malloc(sizeof(X509_STORE_CTX)); + if (!ctx) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return NULL; + } + memset(ctx, 0, sizeof(X509_STORE_CTX)); + return ctx; +} + +void X509_STORE_CTX_free(X509_STORE_CTX *ctx) +{ + X509_STORE_CTX_cleanup(ctx); + OPENSSL_free(ctx); +} + +int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509, + STACK_OF(X509) *chain) + { + int ret = 1; + int ex_data_allocated = 0; + + memset(ctx, 0, sizeof(X509_STORE_CTX)); + ctx->ctx=store; + ctx->cert=x509; + ctx->untrusted=chain; + + if(!CRYPTO_new_ex_data(&g_ex_data_class, ctx, + &ctx->ex_data)) + { + goto err; + } + ex_data_allocated = 1; + + ctx->param = X509_VERIFY_PARAM_new(); + if (!ctx->param) + goto err; + + /* Inherit callbacks and flags from X509_STORE if not set + * use defaults. */ + + if (store) + ret = X509_VERIFY_PARAM_inherit(ctx->param, store->param); + else + ctx->param->inh_flags |= X509_VP_FLAG_DEFAULT|X509_VP_FLAG_ONCE; + + if (store) + { + ctx->verify_cb = store->verify_cb; + ctx->cleanup = store->cleanup; + } + else + ctx->cleanup = 0; + + if (ret) + ret = X509_VERIFY_PARAM_inherit(ctx->param, + X509_VERIFY_PARAM_lookup("default")); + + if (ret == 0) + goto err; + + if (store && store->check_issued) + ctx->check_issued = store->check_issued; + else + ctx->check_issued = check_issued; + + if (store && store->get_issuer) + ctx->get_issuer = store->get_issuer; + else + ctx->get_issuer = X509_STORE_CTX_get1_issuer; + + if (store && store->verify_cb) + ctx->verify_cb = store->verify_cb; + else + ctx->verify_cb = null_callback; + + if (store && store->verify) + ctx->verify = store->verify; + else + ctx->verify = internal_verify; + + if (store && store->check_revocation) + ctx->check_revocation = store->check_revocation; + else + ctx->check_revocation = check_revocation; + + if (store && store->get_crl) + ctx->get_crl = store->get_crl; + else + ctx->get_crl = NULL; + + if (store && store->check_crl) + ctx->check_crl = store->check_crl; + else + ctx->check_crl = check_crl; + + if (store && store->cert_crl) + ctx->cert_crl = store->cert_crl; + else + ctx->cert_crl = cert_crl; + + if (store && store->lookup_certs) + ctx->lookup_certs = store->lookup_certs; + else + ctx->lookup_certs = X509_STORE_get1_certs; + + if (store && store->lookup_crls) + ctx->lookup_crls = store->lookup_crls; + else + ctx->lookup_crls = X509_STORE_get1_crls; + + ctx->check_policy = check_policy; + + return 1; + +err: + if (ex_data_allocated) + { + CRYPTO_free_ex_data(&g_ex_data_class, ctx, &ctx->ex_data); + } + if (ctx->param != NULL) + { + X509_VERIFY_PARAM_free(ctx->param); + } + + memset(ctx, 0, sizeof(X509_STORE_CTX)); + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return 0; + } + +/* Set alternative lookup method: just a STACK of trusted certificates. + * This avoids X509_STORE nastiness where it isn't needed. + */ + +void X509_STORE_CTX_trusted_stack(X509_STORE_CTX *ctx, STACK_OF(X509) *sk) +{ + ctx->other_ctx = sk; + ctx->get_issuer = get_issuer_sk; +} + +void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx) + { + if (ctx->cleanup) ctx->cleanup(ctx); + if (ctx->param != NULL) + { + if (ctx->parent == NULL) + X509_VERIFY_PARAM_free(ctx->param); + ctx->param=NULL; + } + if (ctx->tree != NULL) + { + X509_policy_tree_free(ctx->tree); + ctx->tree=NULL; + } + if (ctx->chain != NULL) + { + sk_X509_pop_free(ctx->chain,X509_free); + ctx->chain=NULL; + } + CRYPTO_free_ex_data(&g_ex_data_class, ctx, &(ctx->ex_data)); + memset(&ctx->ex_data,0,sizeof(CRYPTO_EX_DATA)); + } + +void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth) + { + X509_VERIFY_PARAM_set_depth(ctx->param, depth); + } + +void X509_STORE_CTX_set_flags(X509_STORE_CTX *ctx, unsigned long flags) + { + X509_VERIFY_PARAM_set_flags(ctx->param, flags); + } + +void X509_STORE_CTX_set_time(X509_STORE_CTX *ctx, unsigned long flags, time_t t) + { + X509_VERIFY_PARAM_set_time(ctx->param, t); + } + +void X509_STORE_CTX_set_verify_cb(X509_STORE_CTX *ctx, + int (*verify_cb)(int, X509_STORE_CTX *)) + { + ctx->verify_cb=verify_cb; + } + +X509_POLICY_TREE *X509_STORE_CTX_get0_policy_tree(X509_STORE_CTX *ctx) + { + return ctx->tree; + } + +int X509_STORE_CTX_get_explicit_policy(X509_STORE_CTX *ctx) + { + return ctx->explicit_policy; + } + +int X509_STORE_CTX_set_default(X509_STORE_CTX *ctx, const char *name) + { + const X509_VERIFY_PARAM *param; + param = X509_VERIFY_PARAM_lookup(name); + if (!param) + return 0; + return X509_VERIFY_PARAM_inherit(ctx->param, param); + } + +X509_VERIFY_PARAM *X509_STORE_CTX_get0_param(X509_STORE_CTX *ctx) + { + return ctx->param; + } + +void X509_STORE_CTX_set0_param(X509_STORE_CTX *ctx, X509_VERIFY_PARAM *param) + { + if (ctx->param) + X509_VERIFY_PARAM_free(ctx->param); + ctx->param = param; + } + +IMPLEMENT_ASN1_SET_OF(X509) +IMPLEMENT_ASN1_SET_OF(X509_ATTRIBUTE) diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509_vpm.c b/TMessagesProj/jni/boringssl/crypto/x509/x509_vpm.c new file mode 100644 index 00000000..8c8f98ea --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509_vpm.c @@ -0,0 +1,672 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2004. */ +/* ==================================================================== + * Copyright (c) 2004 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "vpm_int.h" + + +/* X509_VERIFY_PARAM functions */ + +#define SET_HOST 0 +#define ADD_HOST 1 + +static char *str_copy(char *s) { return OPENSSL_strdup(s); } +static void str_free(char *s) { OPENSSL_free(s); } + +#define string_stack_free(sk) sk_OPENSSL_STRING_pop_free(sk, str_free) + +static int int_x509_param_set_hosts(X509_VERIFY_PARAM_ID *id, int mode, + const char *name, size_t namelen) + { + char *copy; + + /* + * Refuse names with embedded NUL bytes. + * XXX: Do we need to push an error onto the error stack? + */ + if (name && memchr(name, '\0', namelen)) + return 0; + + if (mode == SET_HOST && id->hosts) + { + string_stack_free(id->hosts); + id->hosts = NULL; + } + if (name == NULL || namelen == 0) + return 1; + + copy = BUF_strndup(name, namelen); + if (copy == NULL) + return 0; + + if (id->hosts == NULL && + (id->hosts = sk_OPENSSL_STRING_new_null()) == NULL) + { + OPENSSL_free(copy); + return 0; + } + + if (!sk_OPENSSL_STRING_push(id->hosts, copy)) + { + OPENSSL_free(copy); + if (sk_OPENSSL_STRING_num(id->hosts) == 0) + { + sk_OPENSSL_STRING_free(id->hosts); + id->hosts = NULL; + } + return 0; + } + + return 1; + } + +static void x509_verify_param_zero(X509_VERIFY_PARAM *param) + { + X509_VERIFY_PARAM_ID *paramid; + if (!param) + return; + param->name = NULL; + param->purpose = 0; + param->trust = 0; + /*param->inh_flags = X509_VP_FLAG_DEFAULT;*/ + param->inh_flags = 0; + param->flags = 0; + param->depth = -1; + if (param->policies) + { + sk_ASN1_OBJECT_pop_free(param->policies, ASN1_OBJECT_free); + param->policies = NULL; + } + paramid = param->id; + if (paramid->hosts) + { + string_stack_free(paramid->hosts); + paramid->hosts = NULL; + } + if (paramid->peername) + { + OPENSSL_free(paramid->peername); + paramid->peername = NULL; + } + if (paramid->email) + { + OPENSSL_free(paramid->email); + paramid->email = NULL; + paramid->emaillen = 0; + } + if (paramid->ip) + { + OPENSSL_free(paramid->ip); + paramid->ip = NULL; + paramid->iplen = 0; + } + + } + +X509_VERIFY_PARAM *X509_VERIFY_PARAM_new(void) + { + X509_VERIFY_PARAM *param; + X509_VERIFY_PARAM_ID *paramid; + param = OPENSSL_malloc(sizeof(X509_VERIFY_PARAM)); + if (!param) + return NULL; + paramid = OPENSSL_malloc(sizeof(X509_VERIFY_PARAM_ID)); + if (!paramid) + { + OPENSSL_free(param); + return NULL; + } + memset(param, 0, sizeof(X509_VERIFY_PARAM)); + memset(paramid, 0, sizeof(X509_VERIFY_PARAM_ID)); + param->id = paramid; + x509_verify_param_zero(param); + return param; + } + +void X509_VERIFY_PARAM_free(X509_VERIFY_PARAM *param) + { + if (param == NULL) + return; + x509_verify_param_zero(param); + OPENSSL_free(param->id); + OPENSSL_free(param); + } + +/* This function determines how parameters are "inherited" from one structure + * to another. There are several different ways this can happen. + * + * 1. If a child structure needs to have its values initialized from a parent + * they are simply copied across. For example SSL_CTX copied to SSL. + * 2. If the structure should take on values only if they are currently unset. + * For example the values in an SSL structure will take appropriate value + * for SSL servers or clients but only if the application has not set new + * ones. + * + * The "inh_flags" field determines how this function behaves. + * + * Normally any values which are set in the default are not copied from the + * destination and verify flags are ORed together. + * + * If X509_VP_FLAG_DEFAULT is set then anything set in the source is copied + * to the destination. Effectively the values in "to" become default values + * which will be used only if nothing new is set in "from". + * + * If X509_VP_FLAG_OVERWRITE is set then all value are copied across whether + * they are set or not. Flags is still Ored though. + * + * If X509_VP_FLAG_RESET_FLAGS is set then the flags value is copied instead + * of ORed. + * + * If X509_VP_FLAG_LOCKED is set then no values are copied. + * + * If X509_VP_FLAG_ONCE is set then the current inh_flags setting is zeroed + * after the next call. + */ + +/* Macro to test if a field should be copied from src to dest */ + +#define test_x509_verify_param_copy(field, def) \ + (to_overwrite || \ + ((src->field != def) && (to_default || (dest->field == def)))) + +/* As above but for ID fields */ + +#define test_x509_verify_param_copy_id(idf, def) \ + test_x509_verify_param_copy(id->idf, def) + +/* Macro to test and copy a field if necessary */ + +#define x509_verify_param_copy(field, def) \ + if (test_x509_verify_param_copy(field, def)) \ + dest->field = src->field + + +int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *dest, + const X509_VERIFY_PARAM *src) + { + unsigned long inh_flags; + int to_default, to_overwrite; + X509_VERIFY_PARAM_ID *id; + if (!src) + return 1; + id = src->id; + inh_flags = dest->inh_flags | src->inh_flags; + + if (inh_flags & X509_VP_FLAG_ONCE) + dest->inh_flags = 0; + + if (inh_flags & X509_VP_FLAG_LOCKED) + return 1; + + if (inh_flags & X509_VP_FLAG_DEFAULT) + to_default = 1; + else + to_default = 0; + + if (inh_flags & X509_VP_FLAG_OVERWRITE) + to_overwrite = 1; + else + to_overwrite = 0; + + x509_verify_param_copy(purpose, 0); + x509_verify_param_copy(trust, 0); + x509_verify_param_copy(depth, -1); + + /* If overwrite or check time not set, copy across */ + + if (to_overwrite || !(dest->flags & X509_V_FLAG_USE_CHECK_TIME)) + { + dest->check_time = src->check_time; + dest->flags &= ~X509_V_FLAG_USE_CHECK_TIME; + /* Don't need to copy flag: that is done below */ + } + + if (inh_flags & X509_VP_FLAG_RESET_FLAGS) + dest->flags = 0; + + dest->flags |= src->flags; + + if (test_x509_verify_param_copy(policies, NULL)) + { + if (!X509_VERIFY_PARAM_set1_policies(dest, src->policies)) + return 0; + } + + /* Copy the host flags if and only if we're copying the host list */ + if (test_x509_verify_param_copy_id(hosts, NULL)) + { + if (dest->id->hosts) + { + string_stack_free(dest->id->hosts); + dest->id->hosts = NULL; + } + if (id->hosts) + { + dest->id->hosts = + sk_OPENSSL_STRING_deep_copy(id->hosts, + str_copy, str_free); + if (dest->id->hosts == NULL) + return 0; + dest->id->hostflags = id->hostflags; + } + } + + if (test_x509_verify_param_copy_id(email, NULL)) + { + if (!X509_VERIFY_PARAM_set1_email(dest, id->email, id->emaillen)) + return 0; + } + + if (test_x509_verify_param_copy_id(ip, NULL)) + { + if (!X509_VERIFY_PARAM_set1_ip(dest, id->ip, id->iplen)) + return 0; + } + + return 1; + } + +int X509_VERIFY_PARAM_set1(X509_VERIFY_PARAM *to, + const X509_VERIFY_PARAM *from) + { + unsigned long save_flags = to->inh_flags; + int ret; + to->inh_flags |= X509_VP_FLAG_DEFAULT; + ret = X509_VERIFY_PARAM_inherit(to, from); + to->inh_flags = save_flags; + return ret; + } + +static int int_x509_param_set1(char **pdest, size_t *pdestlen, + const char *src, size_t srclen) + { + void *tmp; + if (src) + { + if (srclen == 0) + { + tmp = BUF_strdup(src); + srclen = strlen(src); + } + else + tmp = BUF_memdup(src, srclen); + if (!tmp) + return 0; + } + else + { + tmp = NULL; + srclen = 0; + } + if (*pdest) + OPENSSL_free(*pdest); + *pdest = tmp; + if (pdestlen) + *pdestlen = srclen; + return 1; + } + +int X509_VERIFY_PARAM_set1_name(X509_VERIFY_PARAM *param, const char *name) + { + if (param->name) + OPENSSL_free(param->name); + param->name = BUF_strdup(name); + if (param->name) + return 1; + return 0; + } + +int X509_VERIFY_PARAM_set_flags(X509_VERIFY_PARAM *param, unsigned long flags) + { + param->flags |= flags; + if (flags & X509_V_FLAG_POLICY_MASK) + param->flags |= X509_V_FLAG_POLICY_CHECK; + return 1; + } + +int X509_VERIFY_PARAM_clear_flags(X509_VERIFY_PARAM *param, unsigned long flags) + { + param->flags &= ~flags; + return 1; + } + +unsigned long X509_VERIFY_PARAM_get_flags(X509_VERIFY_PARAM *param) + { + return param->flags; + } + +int X509_VERIFY_PARAM_set_purpose(X509_VERIFY_PARAM *param, int purpose) + { + return X509_PURPOSE_set(¶m->purpose, purpose); + } + +int X509_VERIFY_PARAM_set_trust(X509_VERIFY_PARAM *param, int trust) + { + return X509_TRUST_set(¶m->trust, trust); + } + +void X509_VERIFY_PARAM_set_depth(X509_VERIFY_PARAM *param, int depth) + { + param->depth = depth; + } + +void X509_VERIFY_PARAM_set_time(X509_VERIFY_PARAM *param, time_t t) + { + param->check_time = t; + param->flags |= X509_V_FLAG_USE_CHECK_TIME; + } + +int X509_VERIFY_PARAM_add0_policy(X509_VERIFY_PARAM *param, ASN1_OBJECT *policy) + { + if (!param->policies) + { + param->policies = sk_ASN1_OBJECT_new_null(); + if (!param->policies) + return 0; + } + if (!sk_ASN1_OBJECT_push(param->policies, policy)) + return 0; + return 1; + } + +int X509_VERIFY_PARAM_set1_policies(X509_VERIFY_PARAM *param, + STACK_OF(ASN1_OBJECT) *policies) + { + size_t i; + ASN1_OBJECT *oid, *doid; + if (!param) + return 0; + if (param->policies) + sk_ASN1_OBJECT_pop_free(param->policies, ASN1_OBJECT_free); + + if (!policies) + { + param->policies = NULL; + return 1; + } + + param->policies = sk_ASN1_OBJECT_new_null(); + if (!param->policies) + return 0; + + for (i = 0; i < sk_ASN1_OBJECT_num(policies); i++) + { + oid = sk_ASN1_OBJECT_value(policies, i); + doid = OBJ_dup(oid); + if (!doid) + return 0; + if (!sk_ASN1_OBJECT_push(param->policies, doid)) + { + ASN1_OBJECT_free(doid); + return 0; + } + } + param->flags |= X509_V_FLAG_POLICY_CHECK; + return 1; + } + +int X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *param, + const char *name, size_t namelen) + { + return int_x509_param_set_hosts(param->id, SET_HOST, name, namelen); + } + +int X509_VERIFY_PARAM_add1_host(X509_VERIFY_PARAM *param, + const char *name, size_t namelen) + { + return int_x509_param_set_hosts(param->id, ADD_HOST, name, namelen); + } + +void X509_VERIFY_PARAM_set_hostflags(X509_VERIFY_PARAM *param, + unsigned int flags) + { + param->id->hostflags = flags; + } + +char *X509_VERIFY_PARAM_get0_peername(X509_VERIFY_PARAM *param) + { + return param->id->peername; + } + +int X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *param, + const char *email, size_t emaillen) + { + return int_x509_param_set1(¶m->id->email, ¶m->id->emaillen, + email, emaillen); + } + +int X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *param, + const unsigned char *ip, size_t iplen) + { + if (iplen != 0 && iplen != 4 && iplen != 16) + return 0; + return int_x509_param_set1((char **)¶m->id->ip, ¶m->id->iplen, + (char *)ip, iplen); + } + +int X509_VERIFY_PARAM_set1_ip_asc(X509_VERIFY_PARAM *param, const char *ipasc) + { + unsigned char ipout[16]; + size_t iplen; + + iplen = (size_t) a2i_ipadd(ipout, ipasc); + if (iplen == 0) + return 0; + return X509_VERIFY_PARAM_set1_ip(param, ipout, iplen); + } + +int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *param) + { + return param->depth; + } + +const char *X509_VERIFY_PARAM_get0_name(const X509_VERIFY_PARAM *param) + { + return param->name; + } + +static const X509_VERIFY_PARAM_ID _empty_id = {NULL, 0U, NULL, NULL, 0, NULL, 0}; + +#define vpm_empty_id (X509_VERIFY_PARAM_ID *)&_empty_id + +/* Default verify parameters: these are used for various + * applications and can be overridden by the user specified table. + * NB: the 'name' field *must* be in alphabetical order because it + * will be searched using OBJ_search. + */ + +static const X509_VERIFY_PARAM default_table[] = { + { + (char *) "default", /* X509 default parameters */ + 0, /* Check time */ + 0, /* internal flags */ + 0, /* flags */ + 0, /* purpose */ + 0, /* trust */ + 100, /* depth */ + NULL, /* policies */ + vpm_empty_id + }, + { + (char *) "pkcs7", /* S/MIME sign parameters */ + 0, /* Check time */ + 0, /* internal flags */ + 0, /* flags */ + X509_PURPOSE_SMIME_SIGN, /* purpose */ + X509_TRUST_EMAIL, /* trust */ + -1, /* depth */ + NULL, /* policies */ + vpm_empty_id + }, + { + (char *) "smime_sign", /* S/MIME sign parameters */ + 0, /* Check time */ + 0, /* internal flags */ + 0, /* flags */ + X509_PURPOSE_SMIME_SIGN, /* purpose */ + X509_TRUST_EMAIL, /* trust */ + -1, /* depth */ + NULL, /* policies */ + vpm_empty_id + }, + { + (char *) "ssl_client", /* SSL/TLS client parameters */ + 0, /* Check time */ + 0, /* internal flags */ + 0, /* flags */ + X509_PURPOSE_SSL_CLIENT, /* purpose */ + X509_TRUST_SSL_CLIENT, /* trust */ + -1, /* depth */ + NULL, /* policies */ + vpm_empty_id + }, + { + (char *) "ssl_server", /* SSL/TLS server parameters */ + 0, /* Check time */ + 0, /* internal flags */ + 0, /* flags */ + X509_PURPOSE_SSL_SERVER, /* purpose */ + X509_TRUST_SSL_SERVER, /* trust */ + -1, /* depth */ + NULL, /* policies */ + vpm_empty_id + }}; + +static STACK_OF(X509_VERIFY_PARAM) *param_table = NULL; + +static int param_cmp(const X509_VERIFY_PARAM **a, + const X509_VERIFY_PARAM **b) + { + return strcmp((*a)->name, (*b)->name); + } + +int X509_VERIFY_PARAM_add0_table(X509_VERIFY_PARAM *param) + { + X509_VERIFY_PARAM *ptmp; + if (!param_table) + { + param_table = sk_X509_VERIFY_PARAM_new(param_cmp); + if (!param_table) + return 0; + } + else + { + size_t idx; + + if (sk_X509_VERIFY_PARAM_find(param_table, &idx, param)) + { + ptmp = sk_X509_VERIFY_PARAM_value(param_table, idx); + X509_VERIFY_PARAM_free(ptmp); + (void)sk_X509_VERIFY_PARAM_delete(param_table, idx); + } + } + if (!sk_X509_VERIFY_PARAM_push(param_table, param)) + return 0; + return 1; + } + +int X509_VERIFY_PARAM_get_count(void) + { + int num = sizeof(default_table)/sizeof(X509_VERIFY_PARAM); + if (param_table) + num += sk_X509_VERIFY_PARAM_num(param_table); + return num; + } + +const X509_VERIFY_PARAM *X509_VERIFY_PARAM_get0(int id) + { + int num = sizeof(default_table)/sizeof(X509_VERIFY_PARAM); + if (id < num) + return default_table + id; + return sk_X509_VERIFY_PARAM_value(param_table, id - num); + } + +const X509_VERIFY_PARAM *X509_VERIFY_PARAM_lookup(const char *name) + { + X509_VERIFY_PARAM pm; + unsigned i, limit; + + pm.name = (char *)name; + if (param_table) + { + size_t idx; + if (sk_X509_VERIFY_PARAM_find(param_table, &idx, &pm)) + return sk_X509_VERIFY_PARAM_value(param_table, idx); + } + + limit = sizeof(default_table)/sizeof(X509_VERIFY_PARAM); + for (i = 0; i < limit; i++) { + if (strcmp(default_table[i].name, name) == 0) { + return &default_table[i]; + } + } + return NULL; + } + +void X509_VERIFY_PARAM_table_cleanup(void) + { + if (param_table) + sk_X509_VERIFY_PARAM_pop_free(param_table, + X509_VERIFY_PARAM_free); + param_table = NULL; + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509cset.c b/TMessagesProj/jni/boringssl/crypto/x509/x509cset.c new file mode 100644 index 00000000..b526c69d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509cset.c @@ -0,0 +1,165 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2001. */ +/* ==================================================================== + * Copyright (c) 2001 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include +#include +#include +#include + + +int X509_CRL_set_version(X509_CRL *x, long version) + { + if (x == NULL) return(0); + if (x->crl->version == NULL) + { + if ((x->crl->version=M_ASN1_INTEGER_new()) == NULL) + return(0); + } + return(ASN1_INTEGER_set(x->crl->version,version)); + } + +int X509_CRL_set_issuer_name(X509_CRL *x, X509_NAME *name) + { + if ((x == NULL) || (x->crl == NULL)) return(0); + return(X509_NAME_set(&x->crl->issuer,name)); + } + + +int X509_CRL_set_lastUpdate(X509_CRL *x, const ASN1_TIME *tm) + { + ASN1_TIME *in; + + if (x == NULL) return(0); + in=x->crl->lastUpdate; + if (in != tm) + { + in=M_ASN1_TIME_dup(tm); + if (in != NULL) + { + M_ASN1_TIME_free(x->crl->lastUpdate); + x->crl->lastUpdate=in; + } + } + return(in != NULL); + } + +int X509_CRL_set_nextUpdate(X509_CRL *x, const ASN1_TIME *tm) + { + ASN1_TIME *in; + + if (x == NULL) return(0); + in=x->crl->nextUpdate; + if (in != tm) + { + in=M_ASN1_TIME_dup(tm); + if (in != NULL) + { + M_ASN1_TIME_free(x->crl->nextUpdate); + x->crl->nextUpdate=in; + } + } + return(in != NULL); + } + +int X509_CRL_sort(X509_CRL *c) + { + size_t i; + X509_REVOKED *r; + /* sort the data so it will be written in serial + * number order */ + sk_X509_REVOKED_sort(c->crl->revoked); + for (i=0; icrl->revoked); i++) + { + r=sk_X509_REVOKED_value(c->crl->revoked,i); + r->sequence=i; + } + c->crl->enc.modified = 1; + return 1; + } + +int X509_REVOKED_set_revocationDate(X509_REVOKED *x, ASN1_TIME *tm) + { + ASN1_TIME *in; + + if (x == NULL) return(0); + in=x->revocationDate; + if (in != tm) + { + in=M_ASN1_TIME_dup(tm); + if (in != NULL) + { + M_ASN1_TIME_free(x->revocationDate); + x->revocationDate=in; + } + } + return(in != NULL); + } + +int X509_REVOKED_set_serialNumber(X509_REVOKED *x, ASN1_INTEGER *serial) + { + ASN1_INTEGER *in; + + if (x == NULL) return(0); + in=x->serialNumber; + if (in != serial) + { + in=M_ASN1_INTEGER_dup(serial); + if (in != NULL) + { + M_ASN1_INTEGER_free(x->serialNumber); + x->serialNumber=in; + } + } + return(in != NULL); + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509name.c b/TMessagesProj/jni/boringssl/crypto/x509/x509name.c new file mode 100644 index 00000000..7bb3aa15 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509name.c @@ -0,0 +1,381 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include +#include +#include +#include + + +int X509_NAME_get_text_by_NID(X509_NAME *name, int nid, char *buf, int len) + { + const ASN1_OBJECT *obj; + + obj=OBJ_nid2obj(nid); + if (obj == NULL) return(-1); + return(X509_NAME_get_text_by_OBJ(name,obj,buf,len)); + } + +int X509_NAME_get_text_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj, char *buf, + int len) + { + int i; + ASN1_STRING *data; + + i=X509_NAME_get_index_by_OBJ(name,obj,-1); + if (i < 0) return(-1); + data=X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name,i)); + i=(data->length > (len-1))?(len-1):data->length; + if (buf == NULL) return(data->length); + memcpy(buf,data->data,i); + buf[i]='\0'; + return(i); + } + +int X509_NAME_entry_count(X509_NAME *name) + { + if (name == NULL) return(0); + return(sk_X509_NAME_ENTRY_num(name->entries)); + } + +int X509_NAME_get_index_by_NID(X509_NAME *name, int nid, int lastpos) + { + const ASN1_OBJECT *obj; + + obj=OBJ_nid2obj(nid); + if (obj == NULL) return(-2); + return(X509_NAME_get_index_by_OBJ(name,obj,lastpos)); + } + +/* NOTE: you should be passsing -1, not 0 as lastpos */ +int X509_NAME_get_index_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj, + int lastpos) + { + int n; + X509_NAME_ENTRY *ne; + STACK_OF(X509_NAME_ENTRY) *sk; + + if (name == NULL) return(-1); + if (lastpos < 0) + lastpos= -1; + sk=name->entries; + n=sk_X509_NAME_ENTRY_num(sk); + for (lastpos++; lastpos < n; lastpos++) + { + ne=sk_X509_NAME_ENTRY_value(sk,lastpos); + if (OBJ_cmp(ne->object,obj) == 0) + return(lastpos); + } + return(-1); + } + +X509_NAME_ENTRY *X509_NAME_get_entry(X509_NAME *name, int loc) + { + if(name == NULL || loc < 0 || sk_X509_NAME_ENTRY_num(name->entries) <= (size_t) loc) + return(NULL); + else + return(sk_X509_NAME_ENTRY_value(name->entries,loc)); + } + +X509_NAME_ENTRY *X509_NAME_delete_entry(X509_NAME *name, int loc) + { + X509_NAME_ENTRY *ret; + int i,n,set_prev,set_next; + STACK_OF(X509_NAME_ENTRY) *sk; + + if (name == NULL || loc < 0 || sk_X509_NAME_ENTRY_num(name->entries) <= (size_t) loc) + return(NULL); + sk=name->entries; + ret=sk_X509_NAME_ENTRY_delete(sk,loc); + n=sk_X509_NAME_ENTRY_num(sk); + name->modified=1; + if (loc == n) return(ret); + + /* else we need to fixup the set field */ + if (loc != 0) + set_prev=(sk_X509_NAME_ENTRY_value(sk,loc-1))->set; + else + set_prev=ret->set-1; + set_next=sk_X509_NAME_ENTRY_value(sk,loc)->set; + + /* set_prev is the previous set + * set is the current set + * set_next is the following + * prev 1 1 1 1 1 1 1 1 + * set 1 1 2 2 + * next 1 1 2 2 2 2 3 2 + * so basically only if prev and next differ by 2, then + * re-number down by 1 */ + if (set_prev+1 < set_next) + for (i=loc; iset--; + return(ret); + } + +int X509_NAME_add_entry_by_OBJ(X509_NAME *name, ASN1_OBJECT *obj, int type, + unsigned char *bytes, int len, int loc, int set) +{ + X509_NAME_ENTRY *ne; + int ret; + ne = X509_NAME_ENTRY_create_by_OBJ(NULL, obj, type, bytes, len); + if(!ne) return 0; + ret = X509_NAME_add_entry(name, ne, loc, set); + X509_NAME_ENTRY_free(ne); + return ret; +} + +int X509_NAME_add_entry_by_NID(X509_NAME *name, int nid, int type, + unsigned char *bytes, int len, int loc, int set) +{ + X509_NAME_ENTRY *ne; + int ret; + ne = X509_NAME_ENTRY_create_by_NID(NULL, nid, type, bytes, len); + if(!ne) return 0; + ret = X509_NAME_add_entry(name, ne, loc, set); + X509_NAME_ENTRY_free(ne); + return ret; +} + +int X509_NAME_add_entry_by_txt(X509_NAME *name, const char *field, int type, + const unsigned char *bytes, int len, int loc, int set) +{ + X509_NAME_ENTRY *ne; + int ret; + ne = X509_NAME_ENTRY_create_by_txt(NULL, field, type, bytes, len); + if(!ne) return 0; + ret = X509_NAME_add_entry(name, ne, loc, set); + X509_NAME_ENTRY_free(ne); + return ret; +} + +/* if set is -1, append to previous set, 0 'a new one', and 1, + * prepend to the guy we are about to stomp on. */ +int X509_NAME_add_entry(X509_NAME *name, X509_NAME_ENTRY *ne, int loc, + int set) + { + X509_NAME_ENTRY *new_name=NULL; + int n,i,inc; + STACK_OF(X509_NAME_ENTRY) *sk; + + if (name == NULL) return(0); + sk=name->entries; + n=sk_X509_NAME_ENTRY_num(sk); + if (loc > n) loc=n; + else if (loc < 0) loc=n; + + name->modified=1; + + if (set == -1) + { + if (loc == 0) + { + set=0; + inc=1; + } + else + { + set=sk_X509_NAME_ENTRY_value(sk,loc-1)->set; + inc=0; + } + } + else /* if (set >= 0) */ + { + if (loc >= n) + { + if (loc != 0) + set=sk_X509_NAME_ENTRY_value(sk,loc-1)->set+1; + else + set=0; + } + else + set=sk_X509_NAME_ENTRY_value(sk,loc)->set; + inc=(set == 0)?1:0; + } + + if ((new_name=X509_NAME_ENTRY_dup(ne)) == NULL) + goto err; + new_name->set=set; + if (!sk_X509_NAME_ENTRY_insert(sk,new_name,loc)) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + goto err; + } + if (inc) + { + n=sk_X509_NAME_ENTRY_num(sk); + for (i=loc+1; iset+=1; + } + return(1); +err: + if (new_name != NULL) + X509_NAME_ENTRY_free(new_name); + return(0); + } + +X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_txt(X509_NAME_ENTRY **ne, + const char *field, int type, const unsigned char *bytes, int len) + { + ASN1_OBJECT *obj; + X509_NAME_ENTRY *nentry; + + obj=OBJ_txt2obj(field, 0); + if (obj == NULL) + { + OPENSSL_PUT_ERROR(X509, X509_R_INVALID_FIELD_NAME); + ERR_add_error_data(2, "name=", field); + return(NULL); + } + nentry = X509_NAME_ENTRY_create_by_OBJ(ne,obj,type,bytes,len); + ASN1_OBJECT_free(obj); + return nentry; + } + +X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_NID(X509_NAME_ENTRY **ne, int nid, + int type, unsigned char *bytes, int len) + { + const ASN1_OBJECT *obj; + X509_NAME_ENTRY *nentry; + + obj=OBJ_nid2obj(nid); + if (obj == NULL) + { + OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_NID); + return(NULL); + } + nentry = X509_NAME_ENTRY_create_by_OBJ(ne,obj,type,bytes,len); + /* TODO(fork): remove this? */ + /* ASN1_OBJECT_free(obj); */ + return nentry; + } + +X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_OBJ(X509_NAME_ENTRY **ne, + const ASN1_OBJECT *obj, int type, const unsigned char *bytes, int len) + { + X509_NAME_ENTRY *ret; + + if ((ne == NULL) || (*ne == NULL)) + { + if ((ret=X509_NAME_ENTRY_new()) == NULL) + return(NULL); + } + else + ret= *ne; + + if (!X509_NAME_ENTRY_set_object(ret,obj)) + goto err; + if (!X509_NAME_ENTRY_set_data(ret,type,bytes,len)) + goto err; + + if ((ne != NULL) && (*ne == NULL)) *ne=ret; + return(ret); +err: + if ((ne == NULL) || (ret != *ne)) + X509_NAME_ENTRY_free(ret); + return(NULL); + } + +int X509_NAME_ENTRY_set_object(X509_NAME_ENTRY *ne, const ASN1_OBJECT *obj) + { + if ((ne == NULL) || (obj == NULL)) + { + OPENSSL_PUT_ERROR(X509, ERR_R_PASSED_NULL_PARAMETER); + return(0); + } + ASN1_OBJECT_free(ne->object); + ne->object=OBJ_dup(obj); + return((ne->object == NULL)?0:1); + } + +int X509_NAME_ENTRY_set_data(X509_NAME_ENTRY *ne, int type, + const unsigned char *bytes, int len) + { + int i; + + if ((ne == NULL) || ((bytes == NULL) && (len != 0))) return(0); + if((type > 0) && (type & MBSTRING_FLAG)) + return ASN1_STRING_set_by_NID(&ne->value, bytes, + len, type, + OBJ_obj2nid(ne->object)) ? 1 : 0; + if (len < 0) len=strlen((const char *)bytes); + i=ASN1_STRING_set(ne->value,bytes,len); + if (!i) return(0); + if (type != V_ASN1_UNDEF) + { + if (type == V_ASN1_APP_CHOOSE) + ne->value->type=ASN1_PRINTABLE_type(bytes,len); + else + ne->value->type=type; + } + return(1); + } + +ASN1_OBJECT *X509_NAME_ENTRY_get_object(X509_NAME_ENTRY *ne) + { + if (ne == NULL) return(NULL); + return(ne->object); + } + +ASN1_STRING *X509_NAME_ENTRY_get_data(X509_NAME_ENTRY *ne) + { + if (ne == NULL) return(NULL); + return(ne->value); + } + diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509rset.c b/TMessagesProj/jni/boringssl/crypto/x509/x509rset.c new file mode 100644 index 00000000..dbab555d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509rset.c @@ -0,0 +1,80 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include + + +int X509_REQ_set_version(X509_REQ *x, long version) + { + if (x == NULL) return(0); + return(ASN1_INTEGER_set(x->req_info->version,version)); + } + +int X509_REQ_set_subject_name(X509_REQ *x, X509_NAME *name) + { + if ((x == NULL) || (x->req_info == NULL)) return(0); + return(X509_NAME_set(&x->req_info->subject,name)); + } + +int X509_REQ_set_pubkey(X509_REQ *x, EVP_PKEY *pkey) + { + if ((x == NULL) || (x->req_info == NULL)) return(0); + return(X509_PUBKEY_set(&x->req_info->pubkey,pkey)); + } + diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509spki.c b/TMessagesProj/jni/boringssl/crypto/x509/x509spki.c new file mode 100644 index 00000000..ccf93e06 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509spki.c @@ -0,0 +1,135 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include +#include + + +int NETSCAPE_SPKI_set_pubkey(NETSCAPE_SPKI *x, EVP_PKEY *pkey) +{ + if ((x == NULL) || (x->spkac == NULL)) return(0); + return(X509_PUBKEY_set(&(x->spkac->pubkey),pkey)); +} + +EVP_PKEY *NETSCAPE_SPKI_get_pubkey(NETSCAPE_SPKI *x) +{ + if ((x == NULL) || (x->spkac == NULL)) + return(NULL); + return(X509_PUBKEY_get(x->spkac->pubkey)); +} + +/* Load a Netscape SPKI from a base64 encoded string */ + +NETSCAPE_SPKI * NETSCAPE_SPKI_b64_decode(const char *str, int len) +{ + unsigned char *spki_der; + const unsigned char *p; + size_t spki_len; + NETSCAPE_SPKI *spki; + if (len <= 0) + len = strlen(str); + if (!EVP_DecodedLength(&spki_len, len)) { + OPENSSL_PUT_ERROR(X509, X509_R_BASE64_DECODE_ERROR); + return NULL; + } + if (!(spki_der = OPENSSL_malloc(spki_len))) { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return NULL; + } + if (!EVP_DecodeBase64(spki_der, &spki_len, spki_len, (const uint8_t *)str, len)) { + OPENSSL_PUT_ERROR(X509, X509_R_BASE64_DECODE_ERROR); + OPENSSL_free(spki_der); + return NULL; + } + p = spki_der; + spki = d2i_NETSCAPE_SPKI(NULL, &p, spki_len); + OPENSSL_free(spki_der); + return spki; +} + +/* Generate a base64 encoded string from an SPKI */ + +char * NETSCAPE_SPKI_b64_encode(NETSCAPE_SPKI *spki) +{ + unsigned char *der_spki, *p; + char *b64_str; + size_t b64_len; + int der_len; + der_len = i2d_NETSCAPE_SPKI(spki, NULL); + if (!EVP_EncodedLength(&b64_len, der_len)) + { + OPENSSL_PUT_ERROR(X509, ERR_R_OVERFLOW); + return NULL; + } + der_spki = OPENSSL_malloc(der_len); + if (der_spki == NULL) { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return NULL; + } + b64_str = OPENSSL_malloc(b64_len); + if (b64_str == NULL) { + OPENSSL_free(der_spki); + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return NULL; + } + p = der_spki; + i2d_NETSCAPE_SPKI(spki, &p); + EVP_EncodeBlock((unsigned char *)b64_str, der_spki, der_len); + OPENSSL_free(der_spki); + return b64_str; +} diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509type.c b/TMessagesProj/jni/boringssl/crypto/x509/x509type.c new file mode 100644 index 00000000..e7c79354 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509type.c @@ -0,0 +1,128 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include + + +int X509_certificate_type(X509 *x, EVP_PKEY *pkey) + { + EVP_PKEY *pk; + int ret=0,i; + + if (x == NULL) return(0); + + if (pkey == NULL) + pk=X509_get_pubkey(x); + else + pk=pkey; + + if (pk == NULL) return(0); + + switch (pk->type) + { + case EVP_PKEY_RSA: + ret=EVP_PK_RSA|EVP_PKT_SIGN; +/* if (!sign only extension) */ + ret|=EVP_PKT_ENC; + break; + case EVP_PKEY_DSA: + ret=EVP_PK_DSA|EVP_PKT_SIGN; + break; + case EVP_PKEY_EC: + ret=EVP_PK_EC|EVP_PKT_SIGN|EVP_PKT_EXCH; + break; + case EVP_PKEY_DH: + ret=EVP_PK_DH|EVP_PKT_EXCH; + break; + case NID_id_GostR3410_94: + case NID_id_GostR3410_2001: + ret=EVP_PKT_EXCH|EVP_PKT_SIGN; + break; + default: + break; + } + + i=OBJ_obj2nid(x->sig_alg->algorithm); + if (i && OBJ_find_sigid_algs(i, NULL, &i)) + { + + switch (i) + { + case NID_rsaEncryption: + case NID_rsa: + ret|=EVP_PKS_RSA; + break; + case NID_dsa: + case NID_dsa_2: + ret|=EVP_PKS_DSA; + break; + case NID_X9_62_id_ecPublicKey: + ret|=EVP_PKS_EC; + break; + default: + break; + } + } + + if (EVP_PKEY_size(pk) <= 1024/8)/* /8 because it's 1024 bits we look + for, not bytes */ + ret|=EVP_PKT_EXP; + if(pkey==NULL) EVP_PKEY_free(pk); + return(ret); + } + diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x_algor.c b/TMessagesProj/jni/boringssl/crypto/x509/x_algor.c new file mode 100644 index 00000000..ae694e3d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x_algor.c @@ -0,0 +1,154 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2000. */ +/* ==================================================================== + * Copyright (c) 2000 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include +#include + + +ASN1_SEQUENCE(X509_ALGOR) = { + ASN1_SIMPLE(X509_ALGOR, algorithm, ASN1_OBJECT), + ASN1_OPT(X509_ALGOR, parameter, ASN1_ANY) +} ASN1_SEQUENCE_END(X509_ALGOR) + +ASN1_ITEM_TEMPLATE(X509_ALGORS) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, algorithms, X509_ALGOR) +ASN1_ITEM_TEMPLATE_END(X509_ALGORS) + +IMPLEMENT_ASN1_FUNCTIONS(X509_ALGOR) +IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(X509_ALGORS, X509_ALGORS, X509_ALGORS) +IMPLEMENT_ASN1_DUP_FUNCTION(X509_ALGOR) + +IMPLEMENT_ASN1_SET_OF(X509_ALGOR) + +int X509_ALGOR_set0(X509_ALGOR *alg, const ASN1_OBJECT *aobj, int ptype, void *pval) + { + if (!alg) + return 0; + if (ptype != V_ASN1_UNDEF) + { + if (alg->parameter == NULL) + alg->parameter = ASN1_TYPE_new(); + if (alg->parameter == NULL) + return 0; + } + if (alg) + { + if (alg->algorithm) + ASN1_OBJECT_free(alg->algorithm); + alg->algorithm = (ASN1_OBJECT*) aobj; + } + if (ptype == 0) + return 1; + if (ptype == V_ASN1_UNDEF) + { + if (alg->parameter) + { + ASN1_TYPE_free(alg->parameter); + alg->parameter = NULL; + } + } + else + ASN1_TYPE_set(alg->parameter, ptype, pval); + return 1; + } + +void X509_ALGOR_get0(ASN1_OBJECT **paobj, int *pptype, void **ppval, + X509_ALGOR *algor) + { + if (paobj) + *paobj = algor->algorithm; + if (pptype) + { + if (algor->parameter == NULL) + { + *pptype = V_ASN1_UNDEF; + return; + } + else + *pptype = algor->parameter->type; + if (ppval) + *ppval = algor->parameter->value.ptr; + } + } + +/* Set up an X509_ALGOR DigestAlgorithmIdentifier from an EVP_MD */ + +void X509_ALGOR_set_md(X509_ALGOR *alg, const EVP_MD *md) + { + int param_type; + + if (EVP_MD_flags(md) & EVP_MD_FLAG_DIGALGID_ABSENT) + param_type = V_ASN1_UNDEF; + else + param_type = V_ASN1_NULL; + + X509_ALGOR_set0(alg, OBJ_nid2obj(EVP_MD_type(md)), param_type, NULL); + + } + +/* X509_ALGOR_cmp returns 0 if |a| and |b| are equal and non-zero otherwise. */ +int X509_ALGOR_cmp(const X509_ALGOR *a, const X509_ALGOR *b) + { + int rv; + rv = OBJ_cmp(a->algorithm, b->algorithm); + if (rv) + return rv; + if (!a->parameter && !b->parameter) + return 0; + return ASN1_TYPE_cmp(a->parameter, b->parameter); + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x_all.c b/TMessagesProj/jni/boringssl/crypto/x509/x_all.c new file mode 100644 index 00000000..d7f2d295 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x_all.c @@ -0,0 +1,547 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +int X509_verify(X509 *a, EVP_PKEY *r) + { + if (X509_ALGOR_cmp(a->sig_alg, a->cert_info->signature)) + return 0; + return(ASN1_item_verify(ASN1_ITEM_rptr(X509_CINF),a->sig_alg, + a->signature,a->cert_info,r)); + } + +int X509_REQ_verify(X509_REQ *a, EVP_PKEY *r) + { + return( ASN1_item_verify(ASN1_ITEM_rptr(X509_REQ_INFO), + a->sig_alg,a->signature,a->req_info,r)); + } + +int X509_sign(X509 *x, EVP_PKEY *pkey, const EVP_MD *md) + { + x->cert_info->enc.modified = 1; + return(ASN1_item_sign(ASN1_ITEM_rptr(X509_CINF), x->cert_info->signature, + x->sig_alg, x->signature, x->cert_info,pkey,md)); + } + +int X509_sign_ctx(X509 *x, EVP_MD_CTX *ctx) + { + x->cert_info->enc.modified = 1; + return ASN1_item_sign_ctx(ASN1_ITEM_rptr(X509_CINF), + x->cert_info->signature, + x->sig_alg, x->signature, x->cert_info, ctx); + } + +/* TODO(fork) +int X509_http_nbio(OCSP_REQ_CTX *rctx, X509 **pcert) + { + return OCSP_REQ_CTX_nbio_d2i(rctx, + (ASN1_VALUE **)pcert, ASN1_ITEM_rptr(X509)); + } +*/ + +int X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, const EVP_MD *md) + { + return(ASN1_item_sign(ASN1_ITEM_rptr(X509_REQ_INFO),x->sig_alg, NULL, + x->signature, x->req_info,pkey,md)); + } + +int X509_REQ_sign_ctx(X509_REQ *x, EVP_MD_CTX *ctx) + { + return ASN1_item_sign_ctx(ASN1_ITEM_rptr(X509_REQ_INFO), + x->sig_alg, NULL, x->signature, x->req_info, ctx); + } + +int X509_CRL_sign(X509_CRL *x, EVP_PKEY *pkey, const EVP_MD *md) + { + x->crl->enc.modified = 1; + return(ASN1_item_sign(ASN1_ITEM_rptr(X509_CRL_INFO),x->crl->sig_alg, + x->sig_alg, x->signature, x->crl,pkey,md)); + } + +int X509_CRL_sign_ctx(X509_CRL *x, EVP_MD_CTX *ctx) + { + x->crl->enc.modified = 1; + return ASN1_item_sign_ctx(ASN1_ITEM_rptr(X509_CRL_INFO), + x->crl->sig_alg, x->sig_alg, x->signature, x->crl, ctx); + } + +/* TODO(fork) +int X509_CRL_http_nbio(OCSP_REQ_CTX *rctx, X509_CRL **pcrl) + { + return OCSP_REQ_CTX_nbio_d2i(rctx, + (ASN1_VALUE **)pcrl, ASN1_ITEM_rptr(X509_CRL)); + } +*/ + +int NETSCAPE_SPKI_sign(NETSCAPE_SPKI *x, EVP_PKEY *pkey, const EVP_MD *md) + { + return(ASN1_item_sign(ASN1_ITEM_rptr(NETSCAPE_SPKAC), x->sig_algor,NULL, + x->signature, x->spkac,pkey,md)); + } + +int NETSCAPE_SPKI_verify(NETSCAPE_SPKI *x, EVP_PKEY *pkey) + { + return (ASN1_item_verify(ASN1_ITEM_rptr(NETSCAPE_SPKAC), x->sig_algor, + x->signature, x->spkac, pkey)); + } + +#ifndef OPENSSL_NO_FP_API +X509 *d2i_X509_fp(FILE *fp, X509 **x509) + { + return ASN1_item_d2i_fp(ASN1_ITEM_rptr(X509), fp, x509); + } + +int i2d_X509_fp(FILE *fp, X509 *x509) + { + return ASN1_item_i2d_fp(ASN1_ITEM_rptr(X509), fp, x509); + } +#endif + +X509 *d2i_X509_bio(BIO *bp, X509 **x509) + { + return ASN1_item_d2i_bio(ASN1_ITEM_rptr(X509), bp, x509); + } + +int i2d_X509_bio(BIO *bp, X509 *x509) + { + return ASN1_item_i2d_bio(ASN1_ITEM_rptr(X509), bp, x509); + } + +#ifndef OPENSSL_NO_FP_API +X509_CRL *d2i_X509_CRL_fp(FILE *fp, X509_CRL **crl) + { + return ASN1_item_d2i_fp(ASN1_ITEM_rptr(X509_CRL), fp, crl); + } + +int i2d_X509_CRL_fp(FILE *fp, X509_CRL *crl) + { + return ASN1_item_i2d_fp(ASN1_ITEM_rptr(X509_CRL), fp, crl); + } +#endif + +X509_CRL *d2i_X509_CRL_bio(BIO *bp, X509_CRL **crl) + { + return ASN1_item_d2i_bio(ASN1_ITEM_rptr(X509_CRL), bp, crl); + } + +int i2d_X509_CRL_bio(BIO *bp, X509_CRL *crl) + { + return ASN1_item_i2d_bio(ASN1_ITEM_rptr(X509_CRL), bp, crl); + } + +/* TODO(fork) */ +#if 0 +#ifndef OPENSSL_NO_FP_API +PKCS7 *d2i_PKCS7_fp(FILE *fp, PKCS7 **p7) + { + return ASN1_item_d2i_fp(ASN1_ITEM_rptr(PKCS7), fp, p7); + } + +int i2d_PKCS7_fp(FILE *fp, PKCS7 *p7) + { + return ASN1_item_i2d_fp(ASN1_ITEM_rptr(PKCS7), fp, p7); + } +#endif + +PKCS7 *d2i_PKCS7_bio(BIO *bp, PKCS7 **p7) + { + return ASN1_item_d2i_bio(ASN1_ITEM_rptr(PKCS7), bp, p7); + } + +int i2d_PKCS7_bio(BIO *bp, PKCS7 *p7) + { + return ASN1_item_i2d_bio(ASN1_ITEM_rptr(PKCS7), bp, p7); + } +#endif + +#ifndef OPENSSL_NO_FP_API +X509_REQ *d2i_X509_REQ_fp(FILE *fp, X509_REQ **req) + { + return ASN1_item_d2i_fp(ASN1_ITEM_rptr(X509_REQ), fp, req); + } + +int i2d_X509_REQ_fp(FILE *fp, X509_REQ *req) + { + return ASN1_item_i2d_fp(ASN1_ITEM_rptr(X509_REQ), fp, req); + } +#endif + +X509_REQ *d2i_X509_REQ_bio(BIO *bp, X509_REQ **req) + { + return ASN1_item_d2i_bio(ASN1_ITEM_rptr(X509_REQ), bp, req); + } + +int i2d_X509_REQ_bio(BIO *bp, X509_REQ *req) + { + return ASN1_item_i2d_bio(ASN1_ITEM_rptr(X509_REQ), bp, req); + } + + +#ifndef OPENSSL_NO_FP_API +RSA *d2i_RSAPrivateKey_fp(FILE *fp, RSA **rsa) + { + return ASN1_d2i_fp_of(RSA, RSA_new, d2i_RSAPrivateKey, fp, rsa); + } + +int i2d_RSAPrivateKey_fp(FILE *fp, RSA *rsa) + { + return ASN1_i2d_fp_of_const(RSA, i2d_RSAPrivateKey, fp, rsa); + } + +RSA *d2i_RSAPublicKey_fp(FILE *fp, RSA **rsa) + { + return ASN1_d2i_fp_of(RSA, RSA_new, d2i_RSAPublicKey, fp, rsa); + } + +RSA *d2i_RSA_PUBKEY_fp(FILE *fp, RSA **rsa) + { + return ASN1_d2i_fp((void *(*)(void)) + RSA_new,(D2I_OF(void))d2i_RSA_PUBKEY, fp, + (void **)rsa); + } + +int i2d_RSAPublicKey_fp(FILE *fp, RSA *rsa) + { + return ASN1_i2d_fp_of_const(RSA, i2d_RSAPublicKey, fp, rsa); + } + +int i2d_RSA_PUBKEY_fp(FILE *fp, RSA *rsa) + { + return ASN1_i2d_fp((I2D_OF_const(void))i2d_RSA_PUBKEY,fp,rsa); + } +#endif + +RSA *d2i_RSAPrivateKey_bio(BIO *bp, RSA **rsa) + { + return ASN1_d2i_bio_of(RSA, RSA_new, d2i_RSAPrivateKey, bp, rsa); + } + +int i2d_RSAPrivateKey_bio(BIO *bp, RSA *rsa) + { + return ASN1_i2d_bio_of_const(RSA, i2d_RSAPrivateKey, bp, rsa); + } + +RSA *d2i_RSAPublicKey_bio(BIO *bp, RSA **rsa) + { + return ASN1_d2i_bio_of(RSA, RSA_new, d2i_RSAPublicKey, bp, rsa); + } + + +RSA *d2i_RSA_PUBKEY_bio(BIO *bp, RSA **rsa) + { + return ASN1_d2i_bio_of(RSA,RSA_new,d2i_RSA_PUBKEY,bp,rsa); + } + +int i2d_RSAPublicKey_bio(BIO *bp, RSA *rsa) + { + return ASN1_i2d_bio_of_const(RSA, i2d_RSAPublicKey, bp, rsa); + } + +int i2d_RSA_PUBKEY_bio(BIO *bp, RSA *rsa) + { + return ASN1_i2d_bio_of_const(RSA,i2d_RSA_PUBKEY,bp,rsa); + } + +#ifndef OPENSSL_NO_DSA +#ifndef OPENSSL_NO_FP_API +DSA *d2i_DSAPrivateKey_fp(FILE *fp, DSA **dsa) + { + return ASN1_d2i_fp_of(DSA,DSA_new,d2i_DSAPrivateKey,fp,dsa); + } + +int i2d_DSAPrivateKey_fp(FILE *fp, DSA *dsa) + { + return ASN1_i2d_fp_of_const(DSA,i2d_DSAPrivateKey,fp,dsa); + } + +DSA *d2i_DSA_PUBKEY_fp(FILE *fp, DSA **dsa) + { + return ASN1_d2i_fp_of(DSA,DSA_new,d2i_DSA_PUBKEY,fp,dsa); + } + +int i2d_DSA_PUBKEY_fp(FILE *fp, DSA *dsa) + { + return ASN1_i2d_fp_of_const(DSA,i2d_DSA_PUBKEY,fp,dsa); + } +#endif + +DSA *d2i_DSAPrivateKey_bio(BIO *bp, DSA **dsa) + { + return ASN1_d2i_bio_of(DSA,DSA_new,d2i_DSAPrivateKey,bp,dsa +); + } + +int i2d_DSAPrivateKey_bio(BIO *bp, DSA *dsa) + { + return ASN1_i2d_bio_of_const(DSA,i2d_DSAPrivateKey,bp,dsa); + } + +DSA *d2i_DSA_PUBKEY_bio(BIO *bp, DSA **dsa) + { + return ASN1_d2i_bio_of(DSA,DSA_new,d2i_DSA_PUBKEY,bp,dsa); + } + +int i2d_DSA_PUBKEY_bio(BIO *bp, DSA *dsa) + { + return ASN1_i2d_bio_of_const(DSA,i2d_DSA_PUBKEY,bp,dsa); + } + +#endif + +#ifndef OPENSSL_NO_FP_API +EC_KEY *d2i_EC_PUBKEY_fp(FILE *fp, EC_KEY **eckey) + { + return ASN1_d2i_fp_of(EC_KEY,EC_KEY_new,d2i_EC_PUBKEY,fp,eckey); + } + +int i2d_EC_PUBKEY_fp(FILE *fp, EC_KEY *eckey) + { + return ASN1_i2d_fp_of_const(EC_KEY,i2d_EC_PUBKEY,fp,eckey); + } + +EC_KEY *d2i_ECPrivateKey_fp(FILE *fp, EC_KEY **eckey) + { + return ASN1_d2i_fp_of(EC_KEY,EC_KEY_new,d2i_ECPrivateKey,fp,eckey); + } + +int i2d_ECPrivateKey_fp(FILE *fp, EC_KEY *eckey) + { + return ASN1_i2d_fp_of_const(EC_KEY,i2d_ECPrivateKey,fp,eckey); + } +#endif +EC_KEY *d2i_EC_PUBKEY_bio(BIO *bp, EC_KEY **eckey) + { + return ASN1_d2i_bio_of(EC_KEY,EC_KEY_new,d2i_EC_PUBKEY,bp,eckey); + } + +int i2d_EC_PUBKEY_bio(BIO *bp, EC_KEY *ecdsa) + { + return ASN1_i2d_bio_of_const(EC_KEY,i2d_EC_PUBKEY,bp,ecdsa); + } + +EC_KEY *d2i_ECPrivateKey_bio(BIO *bp, EC_KEY **eckey) + { + return ASN1_d2i_bio_of(EC_KEY,EC_KEY_new,d2i_ECPrivateKey,bp,eckey); + } + +int i2d_ECPrivateKey_bio(BIO *bp, EC_KEY *eckey) + { + return ASN1_i2d_bio_of_const(EC_KEY,i2d_ECPrivateKey,bp,eckey); + } + + +int X509_pubkey_digest(const X509 *data, const EVP_MD *type, unsigned char *md, + unsigned int *len) + { + ASN1_BIT_STRING *key; + key = X509_get0_pubkey_bitstr(data); + if(!key) return 0; + return EVP_Digest(key->data, key->length, md, len, type, NULL); + } + +int X509_digest(const X509 *data, const EVP_MD *type, unsigned char *md, + unsigned int *len) + { + return(ASN1_item_digest(ASN1_ITEM_rptr(X509),type,(char *)data,md,len)); + } + +int X509_CRL_digest(const X509_CRL *data, const EVP_MD *type, unsigned char *md, + unsigned int *len) + { + return(ASN1_item_digest(ASN1_ITEM_rptr(X509_CRL),type,(char *)data,md,len)); + } + +int X509_REQ_digest(const X509_REQ *data, const EVP_MD *type, unsigned char *md, + unsigned int *len) + { + return(ASN1_item_digest(ASN1_ITEM_rptr(X509_REQ),type,(char *)data,md,len)); + } + +int X509_NAME_digest(const X509_NAME *data, const EVP_MD *type, unsigned char *md, + unsigned int *len) + { + return(ASN1_item_digest(ASN1_ITEM_rptr(X509_NAME),type,(char *)data,md,len)); + } + +#if 0 /* TODO(fork): remove */ +int PKCS7_ISSUER_AND_SERIAL_digest(PKCS7_ISSUER_AND_SERIAL *data, const EVP_MD *type, + unsigned char *md, unsigned int *len) + { + return(ASN1_item_digest(ASN1_ITEM_rptr(PKCS7_ISSUER_AND_SERIAL),type, + (char *)data,md,len)); + } +#endif + +#ifndef OPENSSL_NO_FP_API +X509_SIG *d2i_PKCS8_fp(FILE *fp, X509_SIG **p8) + { + return ASN1_d2i_fp_of(X509_SIG,X509_SIG_new,d2i_X509_SIG,fp,p8); + } + +int i2d_PKCS8_fp(FILE *fp, X509_SIG *p8) + { + return ASN1_i2d_fp_of(X509_SIG,i2d_X509_SIG,fp,p8); + } +#endif + +X509_SIG *d2i_PKCS8_bio(BIO *bp, X509_SIG **p8) + { + return ASN1_d2i_bio_of(X509_SIG,X509_SIG_new,d2i_X509_SIG,bp,p8); + } + +int i2d_PKCS8_bio(BIO *bp, X509_SIG *p8) + { + return ASN1_i2d_bio_of(X509_SIG,i2d_X509_SIG,bp,p8); + } + +#ifndef OPENSSL_NO_FP_API +PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_fp(FILE *fp, + PKCS8_PRIV_KEY_INFO **p8inf) + { + return ASN1_d2i_fp_of(PKCS8_PRIV_KEY_INFO,PKCS8_PRIV_KEY_INFO_new, + d2i_PKCS8_PRIV_KEY_INFO,fp,p8inf); + } + +int i2d_PKCS8_PRIV_KEY_INFO_fp(FILE *fp, PKCS8_PRIV_KEY_INFO *p8inf) + { + return ASN1_i2d_fp_of(PKCS8_PRIV_KEY_INFO,i2d_PKCS8_PRIV_KEY_INFO,fp, + p8inf); + } + +int i2d_PKCS8PrivateKeyInfo_fp(FILE *fp, EVP_PKEY *key) + { + PKCS8_PRIV_KEY_INFO *p8inf; + int ret; + p8inf = EVP_PKEY2PKCS8(key); + if(!p8inf) return 0; + ret = i2d_PKCS8_PRIV_KEY_INFO_fp(fp, p8inf); + PKCS8_PRIV_KEY_INFO_free(p8inf); + return ret; + } + +int i2d_PrivateKey_fp(FILE *fp, EVP_PKEY *pkey) + { + return ASN1_i2d_fp_of_const(EVP_PKEY,i2d_PrivateKey,fp,pkey); + } + +EVP_PKEY *d2i_PrivateKey_fp(FILE *fp, EVP_PKEY **a) +{ + return ASN1_d2i_fp_of(EVP_PKEY,EVP_PKEY_new,d2i_AutoPrivateKey,fp,a); +} + +int i2d_PUBKEY_fp(FILE *fp, EVP_PKEY *pkey) + { + return ASN1_i2d_fp_of_const(EVP_PKEY,i2d_PUBKEY,fp,pkey); + } + +EVP_PKEY *d2i_PUBKEY_fp(FILE *fp, EVP_PKEY **a) +{ + return ASN1_d2i_fp_of(EVP_PKEY,EVP_PKEY_new,d2i_PUBKEY,fp,a); +} + +PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_bio(BIO *bp, + PKCS8_PRIV_KEY_INFO **p8inf) + { + return ASN1_d2i_bio_of(PKCS8_PRIV_KEY_INFO,PKCS8_PRIV_KEY_INFO_new, + d2i_PKCS8_PRIV_KEY_INFO,bp,p8inf); + } + +int i2d_PKCS8_PRIV_KEY_INFO_bio(BIO *bp, PKCS8_PRIV_KEY_INFO *p8inf) + { + return ASN1_i2d_bio_of(PKCS8_PRIV_KEY_INFO,i2d_PKCS8_PRIV_KEY_INFO,bp, + p8inf); + } + +int i2d_PKCS8PrivateKeyInfo_bio(BIO *bp, EVP_PKEY *key) + { + PKCS8_PRIV_KEY_INFO *p8inf; + int ret; + p8inf = EVP_PKEY2PKCS8(key); + if(!p8inf) return 0; + ret = i2d_PKCS8_PRIV_KEY_INFO_bio(bp, p8inf); + PKCS8_PRIV_KEY_INFO_free(p8inf); + return ret; + } +#endif + +int i2d_PrivateKey_bio(BIO *bp, EVP_PKEY *pkey) + { + return ASN1_i2d_bio_of_const(EVP_PKEY,i2d_PrivateKey,bp,pkey); + } + +EVP_PKEY *d2i_PrivateKey_bio(BIO *bp, EVP_PKEY **a) + { + return ASN1_d2i_bio_of(EVP_PKEY,EVP_PKEY_new,d2i_AutoPrivateKey,bp,a); + } + +int i2d_PUBKEY_bio(BIO *bp, EVP_PKEY *pkey) + { + return ASN1_i2d_bio_of_const(EVP_PKEY,i2d_PUBKEY,bp,pkey); + } + +EVP_PKEY *d2i_PUBKEY_bio(BIO *bp, EVP_PKEY **a) + { + return ASN1_d2i_bio_of(EVP_PKEY,EVP_PKEY_new,d2i_PUBKEY,bp,a); + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x_attrib.c b/TMessagesProj/jni/boringssl/crypto/x509/x_attrib.c new file mode 100644 index 00000000..c460a702 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x_attrib.c @@ -0,0 +1,117 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include + + +/* X509_ATTRIBUTE: this has the following form: + * + * typedef struct x509_attributes_st + * { + * ASN1_OBJECT *object; + * int single; + * union { + * char *ptr; + * STACK_OF(ASN1_TYPE) *set; + * ASN1_TYPE *single; + * } value; + * } X509_ATTRIBUTE; + * + * this needs some extra thought because the CHOICE type is + * merged with the main structure and because the value can + * be anything at all we *must* try the SET OF first because + * the ASN1_ANY type will swallow anything including the whole + * SET OF structure. + */ + +ASN1_CHOICE(X509_ATTRIBUTE_SET) = { + ASN1_SET_OF(X509_ATTRIBUTE, value.set, ASN1_ANY), + ASN1_SIMPLE(X509_ATTRIBUTE, value.single, ASN1_ANY) +} ASN1_CHOICE_END_selector(X509_ATTRIBUTE, X509_ATTRIBUTE_SET, single) + +ASN1_SEQUENCE(X509_ATTRIBUTE) = { + ASN1_SIMPLE(X509_ATTRIBUTE, object, ASN1_OBJECT), + /* CHOICE type merged with parent */ + ASN1_EX_COMBINE(0, 0, X509_ATTRIBUTE_SET) +} ASN1_SEQUENCE_END(X509_ATTRIBUTE) + +IMPLEMENT_ASN1_FUNCTIONS(X509_ATTRIBUTE) +IMPLEMENT_ASN1_DUP_FUNCTION(X509_ATTRIBUTE) + +X509_ATTRIBUTE *X509_ATTRIBUTE_create(int nid, int atrtype, void *value) + { + X509_ATTRIBUTE *ret=NULL; + ASN1_TYPE *val=NULL; + + if ((ret=X509_ATTRIBUTE_new()) == NULL) + return(NULL); + /* TODO(fork): const correctness. */ + ret->object=(ASN1_OBJECT*) OBJ_nid2obj(nid); + ret->single=0; + if ((ret->value.set=sk_ASN1_TYPE_new_null()) == NULL) goto err; + if ((val=ASN1_TYPE_new()) == NULL) goto err; + if (!sk_ASN1_TYPE_push(ret->value.set,val)) goto err; + + ASN1_TYPE_set(val,atrtype,value); + return(ret); +err: + if (ret != NULL) X509_ATTRIBUTE_free(ret); + if (val != NULL) ASN1_TYPE_free(val); + return(NULL); + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x_crl.c b/TMessagesProj/jni/boringssl/crypto/x509/x_crl.c new file mode 100644 index 00000000..d5168727 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x_crl.c @@ -0,0 +1,560 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../internal.h" + + +/* Method to handle CRL access. + * In general a CRL could be very large (several Mb) and can consume large + * amounts of resources if stored in memory by multiple processes. + * This method allows general CRL operations to be redirected to more + * efficient callbacks: for example a CRL entry database. + */ + +#define X509_CRL_METHOD_DYNAMIC 1 + +struct x509_crl_method_st + { + int flags; + int (*crl_init)(X509_CRL *crl); + int (*crl_free)(X509_CRL *crl); + int (*crl_lookup)(X509_CRL *crl, X509_REVOKED **ret, + ASN1_INTEGER *ser, X509_NAME *issuer); + int (*crl_verify)(X509_CRL *crl, EVP_PKEY *pk); + }; + +static int X509_REVOKED_cmp(const X509_REVOKED **a, + const X509_REVOKED **b); +static void setup_idp(X509_CRL *crl, ISSUING_DIST_POINT *idp); + +ASN1_SEQUENCE(X509_REVOKED) = { + ASN1_SIMPLE(X509_REVOKED,serialNumber, ASN1_INTEGER), + ASN1_SIMPLE(X509_REVOKED,revocationDate, ASN1_TIME), + ASN1_SEQUENCE_OF_OPT(X509_REVOKED,extensions, X509_EXTENSION) +} ASN1_SEQUENCE_END(X509_REVOKED) + +static int def_crl_verify(X509_CRL *crl, EVP_PKEY *r); +static int def_crl_lookup(X509_CRL *crl, + X509_REVOKED **ret, ASN1_INTEGER *serial, X509_NAME *issuer); + +static const X509_CRL_METHOD int_crl_meth = + { + 0, + 0,0, + def_crl_lookup, + def_crl_verify + }; + +static const X509_CRL_METHOD *default_crl_method = &int_crl_meth; + +/* The X509_CRL_INFO structure needs a bit of customisation. + * Since we cache the original encoding the signature wont be affected by + * reordering of the revoked field. + */ +static int crl_inf_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, + void *exarg) +{ + X509_CRL_INFO *a = (X509_CRL_INFO *)*pval; + + if(!a || !a->revoked) return 1; + switch(operation) { + /* Just set cmp function here. We don't sort because that + * would affect the output of X509_CRL_print(). + */ + case ASN1_OP_D2I_POST: + (void)sk_X509_REVOKED_set_cmp_func(a->revoked,X509_REVOKED_cmp); + break; + } + return 1; +} + + +ASN1_SEQUENCE_enc(X509_CRL_INFO, enc, crl_inf_cb) = { + ASN1_OPT(X509_CRL_INFO, version, ASN1_INTEGER), + ASN1_SIMPLE(X509_CRL_INFO, sig_alg, X509_ALGOR), + ASN1_SIMPLE(X509_CRL_INFO, issuer, X509_NAME), + ASN1_SIMPLE(X509_CRL_INFO, lastUpdate, ASN1_TIME), + ASN1_OPT(X509_CRL_INFO, nextUpdate, ASN1_TIME), + ASN1_SEQUENCE_OF_OPT(X509_CRL_INFO, revoked, X509_REVOKED), + ASN1_EXP_SEQUENCE_OF_OPT(X509_CRL_INFO, extensions, X509_EXTENSION, 0) +} ASN1_SEQUENCE_END_enc(X509_CRL_INFO, X509_CRL_INFO) + +/* Set CRL entry issuer according to CRL certificate issuer extension. + * Check for unhandled critical CRL entry extensions. + */ + +static int crl_set_issuers(X509_CRL *crl) + { + + size_t i, k; + int j; + GENERAL_NAMES *gens, *gtmp; + STACK_OF(X509_REVOKED) *revoked; + + revoked = X509_CRL_get_REVOKED(crl); + + gens = NULL; + for (i = 0; i < sk_X509_REVOKED_num(revoked); i++) + { + X509_REVOKED *rev = sk_X509_REVOKED_value(revoked, i); + STACK_OF(X509_EXTENSION) *exts; + ASN1_ENUMERATED *reason; + X509_EXTENSION *ext; + gtmp = X509_REVOKED_get_ext_d2i(rev, + NID_certificate_issuer, + &j, NULL); + if (!gtmp && (j != -1)) + { + crl->flags |= EXFLAG_INVALID; + return 1; + } + + if (gtmp) + { + gens = gtmp; + if (!crl->issuers) + { + crl->issuers = sk_GENERAL_NAMES_new_null(); + if (!crl->issuers) + return 0; + } + if (!sk_GENERAL_NAMES_push(crl->issuers, gtmp)) + return 0; + } + rev->issuer = gens; + + reason = X509_REVOKED_get_ext_d2i(rev, NID_crl_reason, + &j, NULL); + if (!reason && (j != -1)) + { + crl->flags |= EXFLAG_INVALID; + return 1; + } + + if (reason) + { + rev->reason = ASN1_ENUMERATED_get(reason); + ASN1_ENUMERATED_free(reason); + } + else + rev->reason = CRL_REASON_NONE; + + /* Check for critical CRL entry extensions */ + + exts = rev->extensions; + + for (k = 0; k < sk_X509_EXTENSION_num(exts); k++) + { + ext = sk_X509_EXTENSION_value(exts, k); + if (ext->critical > 0) + { + if (OBJ_obj2nid(ext->object) == + NID_certificate_issuer) + continue; + crl->flags |= EXFLAG_CRITICAL; + break; + } + } + + + } + + return 1; + + } + +/* The X509_CRL structure needs a bit of customisation. Cache some extensions + * and hash of the whole CRL. + */ +static int crl_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, + void *exarg) + { + X509_CRL *crl = (X509_CRL *)*pval; + STACK_OF(X509_EXTENSION) *exts; + X509_EXTENSION *ext; + size_t idx; + + switch(operation) + { + case ASN1_OP_NEW_POST: + crl->idp = NULL; + crl->akid = NULL; + crl->flags = 0; + crl->idp_flags = 0; + crl->idp_reasons = CRLDP_ALL_REASONS; + crl->meth = default_crl_method; + crl->meth_data = NULL; + crl->issuers = NULL; + crl->crl_number = NULL; + crl->base_crl_number = NULL; + break; + + case ASN1_OP_D2I_POST: + X509_CRL_digest(crl, EVP_sha1(), crl->sha1_hash, NULL); + crl->idp = X509_CRL_get_ext_d2i(crl, + NID_issuing_distribution_point, NULL, NULL); + if (crl->idp) + setup_idp(crl, crl->idp); + + crl->akid = X509_CRL_get_ext_d2i(crl, + NID_authority_key_identifier, NULL, NULL); + + crl->crl_number = X509_CRL_get_ext_d2i(crl, + NID_crl_number, NULL, NULL); + + crl->base_crl_number = X509_CRL_get_ext_d2i(crl, + NID_delta_crl, NULL, NULL); + /* Delta CRLs must have CRL number */ + if (crl->base_crl_number && !crl->crl_number) + crl->flags |= EXFLAG_INVALID; + + /* See if we have any unhandled critical CRL extensions and + * indicate this in a flag. We only currently handle IDP so + * anything else critical sets the flag. + * + * This code accesses the X509_CRL structure directly: + * applications shouldn't do this. + */ + + exts = crl->crl->extensions; + + for (idx = 0; idx < sk_X509_EXTENSION_num(exts); idx++) + { + int nid; + ext = sk_X509_EXTENSION_value(exts, idx); + nid = OBJ_obj2nid(ext->object); + if (nid == NID_freshest_crl) + crl->flags |= EXFLAG_FRESHEST; + if (ext->critical > 0) + { + /* We handle IDP and deltas */ + if ((nid == NID_issuing_distribution_point) + || (nid == NID_authority_key_identifier) + || (nid == NID_delta_crl)) + break;; + crl->flags |= EXFLAG_CRITICAL; + break; + } + } + + + if (!crl_set_issuers(crl)) + return 0; + + if (crl->meth->crl_init) + { + if (crl->meth->crl_init(crl) == 0) + return 0; + } + break; + + case ASN1_OP_FREE_POST: + if (crl->meth->crl_free) + { + if (!crl->meth->crl_free(crl)) + return 0; + } + if (crl->akid) + AUTHORITY_KEYID_free(crl->akid); + if (crl->idp) + ISSUING_DIST_POINT_free(crl->idp); + ASN1_INTEGER_free(crl->crl_number); + ASN1_INTEGER_free(crl->base_crl_number); + sk_GENERAL_NAMES_pop_free(crl->issuers, GENERAL_NAMES_free); + break; + } + return 1; + } + +/* Convert IDP into a more convenient form */ + +static void setup_idp(X509_CRL *crl, ISSUING_DIST_POINT *idp) + { + int idp_only = 0; + /* Set various flags according to IDP */ + crl->idp_flags |= IDP_PRESENT; + if (idp->onlyuser > 0) + { + idp_only++; + crl->idp_flags |= IDP_ONLYUSER; + } + if (idp->onlyCA > 0) + { + idp_only++; + crl->idp_flags |= IDP_ONLYCA; + } + if (idp->onlyattr > 0) + { + idp_only++; + crl->idp_flags |= IDP_ONLYATTR; + } + + if (idp_only > 1) + crl->idp_flags |= IDP_INVALID; + + if (idp->indirectCRL > 0) + crl->idp_flags |= IDP_INDIRECT; + + if (idp->onlysomereasons) + { + crl->idp_flags |= IDP_REASONS; + if (idp->onlysomereasons->length > 0) + crl->idp_reasons = idp->onlysomereasons->data[0]; + if (idp->onlysomereasons->length > 1) + crl->idp_reasons |= + (idp->onlysomereasons->data[1] << 8); + crl->idp_reasons &= CRLDP_ALL_REASONS; + } + + DIST_POINT_set_dpname(idp->distpoint, X509_CRL_get_issuer(crl)); + } + +ASN1_SEQUENCE_ref(X509_CRL, crl_cb) = { + ASN1_SIMPLE(X509_CRL, crl, X509_CRL_INFO), + ASN1_SIMPLE(X509_CRL, sig_alg, X509_ALGOR), + ASN1_SIMPLE(X509_CRL, signature, ASN1_BIT_STRING) +} ASN1_SEQUENCE_END_ref(X509_CRL, X509_CRL) + +IMPLEMENT_ASN1_FUNCTIONS(X509_REVOKED) +IMPLEMENT_ASN1_DUP_FUNCTION(X509_REVOKED) +IMPLEMENT_ASN1_FUNCTIONS(X509_CRL_INFO) +IMPLEMENT_ASN1_FUNCTIONS(X509_CRL) +IMPLEMENT_ASN1_DUP_FUNCTION(X509_CRL) + +static int X509_REVOKED_cmp(const X509_REVOKED **a, + const X509_REVOKED **b) + { + return(ASN1_STRING_cmp( + (ASN1_STRING *)(*a)->serialNumber, + (ASN1_STRING *)(*b)->serialNumber)); + } + +int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev) +{ + X509_CRL_INFO *inf; + inf = crl->crl; + if(!inf->revoked) + inf->revoked = sk_X509_REVOKED_new(X509_REVOKED_cmp); + if(!inf->revoked || !sk_X509_REVOKED_push(inf->revoked, rev)) { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return 0; + } + inf->enc.modified = 1; + return 1; +} + +int X509_CRL_verify(X509_CRL *crl, EVP_PKEY *r) + { + if (crl->meth->crl_verify) + return crl->meth->crl_verify(crl, r); + return 0; + } + +int X509_CRL_get0_by_serial(X509_CRL *crl, + X509_REVOKED **ret, ASN1_INTEGER *serial) + { + if (crl->meth->crl_lookup) + return crl->meth->crl_lookup(crl, ret, serial, NULL); + return 0; + } + +int X509_CRL_get0_by_cert(X509_CRL *crl, X509_REVOKED **ret, X509 *x) + { + if (crl->meth->crl_lookup) + return crl->meth->crl_lookup(crl, ret, + X509_get_serialNumber(x), + X509_get_issuer_name(x)); + return 0; + } + +static int def_crl_verify(X509_CRL *crl, EVP_PKEY *r) + { + return(ASN1_item_verify(ASN1_ITEM_rptr(X509_CRL_INFO), + crl->sig_alg, crl->signature,crl->crl,r)); + } + +static int crl_revoked_issuer_match(X509_CRL *crl, X509_NAME *nm, + X509_REVOKED *rev) + { + size_t i; + + if (!rev->issuer) + { + if (!nm) + return 1; + if (!X509_NAME_cmp(nm, X509_CRL_get_issuer(crl))) + return 1; + return 0; + } + + if (!nm) + nm = X509_CRL_get_issuer(crl); + + for (i = 0; i < sk_GENERAL_NAME_num(rev->issuer); i++) + { + GENERAL_NAME *gen = sk_GENERAL_NAME_value(rev->issuer, i); + if (gen->type != GEN_DIRNAME) + continue; + if (!X509_NAME_cmp(nm, gen->d.directoryName)) + return 1; + } + return 0; + + } + +static struct CRYPTO_STATIC_MUTEX g_crl_sort_lock = CRYPTO_STATIC_MUTEX_INIT; + +static int def_crl_lookup(X509_CRL *crl, + X509_REVOKED **ret, ASN1_INTEGER *serial, X509_NAME *issuer) + { + X509_REVOKED rtmp, *rev; + size_t idx; + rtmp.serialNumber = serial; + /* Sort revoked into serial number order if not already sorted. + * Do this under a lock to avoid race condition. + */ + + CRYPTO_STATIC_MUTEX_lock_read(&g_crl_sort_lock); + const int is_sorted = sk_X509_REVOKED_is_sorted(crl->crl->revoked); + CRYPTO_STATIC_MUTEX_unlock(&g_crl_sort_lock); + + if (!is_sorted) + { + CRYPTO_STATIC_MUTEX_lock_write(&g_crl_sort_lock); + if (!sk_X509_REVOKED_is_sorted(crl->crl->revoked)) + { + sk_X509_REVOKED_sort(crl->crl->revoked); + } + CRYPTO_STATIC_MUTEX_unlock(&g_crl_sort_lock); + } + + if (!sk_X509_REVOKED_find(crl->crl->revoked, &idx, &rtmp)) + return 0; + /* Need to look for matching name */ + for(;idx < sk_X509_REVOKED_num(crl->crl->revoked); idx++) + { + rev = sk_X509_REVOKED_value(crl->crl->revoked, idx); + if (ASN1_INTEGER_cmp(rev->serialNumber, serial)) + return 0; + if (crl_revoked_issuer_match(crl, issuer, rev)) + { + if (ret) + *ret = rev; + if (rev->reason == CRL_REASON_REMOVE_FROM_CRL) + return 2; + return 1; + } + } + return 0; + } + +void X509_CRL_set_default_method(const X509_CRL_METHOD *meth) + { + if (meth == NULL) + default_crl_method = &int_crl_meth; + else + default_crl_method = meth; + } + +X509_CRL_METHOD *X509_CRL_METHOD_new( + int (*crl_init)(X509_CRL *crl), + int (*crl_free)(X509_CRL *crl), + int (*crl_lookup)(X509_CRL *crl, X509_REVOKED **ret, + ASN1_INTEGER *ser, X509_NAME *issuer), + int (*crl_verify)(X509_CRL *crl, EVP_PKEY *pk)) + { + X509_CRL_METHOD *m; + m = OPENSSL_malloc(sizeof(X509_CRL_METHOD)); + if (!m) + return NULL; + m->crl_init = crl_init; + m->crl_free = crl_free; + m->crl_lookup = crl_lookup; + m->crl_verify = crl_verify; + m->flags = X509_CRL_METHOD_DYNAMIC; + return m; + } + +void X509_CRL_METHOD_free(X509_CRL_METHOD *m) + { + if (!(m->flags & X509_CRL_METHOD_DYNAMIC)) + return; + OPENSSL_free(m); + } + +void X509_CRL_set_meth_data(X509_CRL *crl, void *dat) + { + crl->meth_data = dat; + } + +void *X509_CRL_get_meth_data(X509_CRL *crl) + { + return crl->meth_data; + } + +IMPLEMENT_ASN1_SET_OF(X509_REVOKED) +IMPLEMENT_ASN1_SET_OF(X509_CRL) diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x_exten.c b/TMessagesProj/jni/boringssl/crypto/x509/x_exten.c new file mode 100644 index 00000000..cf64c844 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x_exten.c @@ -0,0 +1,75 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include + + +ASN1_SEQUENCE(X509_EXTENSION) = { + ASN1_SIMPLE(X509_EXTENSION, object, ASN1_OBJECT), + ASN1_OPT(X509_EXTENSION, critical, ASN1_BOOLEAN), + ASN1_SIMPLE(X509_EXTENSION, value, ASN1_OCTET_STRING) +} ASN1_SEQUENCE_END(X509_EXTENSION) + +ASN1_ITEM_TEMPLATE(X509_EXTENSIONS) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, Extension, X509_EXTENSION) +ASN1_ITEM_TEMPLATE_END(X509_EXTENSIONS) + +IMPLEMENT_ASN1_FUNCTIONS(X509_EXTENSION) +IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(X509_EXTENSIONS, X509_EXTENSIONS, X509_EXTENSIONS) +IMPLEMENT_ASN1_DUP_FUNCTION(X509_EXTENSION) diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x_info.c b/TMessagesProj/jni/boringssl/crypto/x509/x_info.c new file mode 100644 index 00000000..be579d79 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x_info.c @@ -0,0 +1,95 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include +#include + + +X509_INFO *X509_INFO_new(void) + { + X509_INFO *ret=NULL; + + ret=(X509_INFO *)OPENSSL_malloc(sizeof(X509_INFO)); + if (ret == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return(NULL); + } + + ret->enc_cipher.cipher=NULL; + ret->enc_len=0; + ret->enc_data=NULL; + + ret->x509=NULL; + ret->crl=NULL; + ret->x_pkey=NULL; + return(ret); + } + +void X509_INFO_free(X509_INFO *x) + { + if (x == NULL) return; + + if (x->x509 != NULL) X509_free(x->x509); + if (x->crl != NULL) X509_CRL_free(x->crl); + if (x->x_pkey != NULL) X509_PKEY_free(x->x_pkey); + if (x->enc_data != NULL) OPENSSL_free(x->enc_data); + OPENSSL_free(x); + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x_name.c b/TMessagesProj/jni/boringssl/crypto/x509/x_name.c new file mode 100644 index 00000000..762756bf --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x_name.c @@ -0,0 +1,538 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../asn1/asn1_locl.h" + + +typedef STACK_OF(X509_NAME_ENTRY) STACK_OF_X509_NAME_ENTRY; +DECLARE_STACK_OF(STACK_OF_X509_NAME_ENTRY) + +static int x509_name_ex_d2i(ASN1_VALUE **val, + const unsigned char **in, long len, + const ASN1_ITEM *it, + int tag, int aclass, char opt, ASN1_TLC *ctx); + +static int x509_name_ex_i2d(ASN1_VALUE **val, unsigned char **out, + const ASN1_ITEM *it, int tag, int aclass); +static int x509_name_ex_new(ASN1_VALUE **val, const ASN1_ITEM *it); +static void x509_name_ex_free(ASN1_VALUE **val, const ASN1_ITEM *it); + +static int x509_name_encode(X509_NAME *a); +static int x509_name_canon(X509_NAME *a); +static int asn1_string_canon(ASN1_STRING *out, ASN1_STRING *in); +static int i2d_name_canon(STACK_OF(STACK_OF_X509_NAME_ENTRY) *intname, + unsigned char **in); + + +static int x509_name_ex_print(BIO *out, ASN1_VALUE **pval, + int indent, + const char *fname, + const ASN1_PCTX *pctx); + +ASN1_SEQUENCE(X509_NAME_ENTRY) = { + ASN1_SIMPLE(X509_NAME_ENTRY, object, ASN1_OBJECT), + ASN1_SIMPLE(X509_NAME_ENTRY, value, ASN1_PRINTABLE) +} ASN1_SEQUENCE_END(X509_NAME_ENTRY) + +IMPLEMENT_ASN1_FUNCTIONS(X509_NAME_ENTRY) +IMPLEMENT_ASN1_DUP_FUNCTION(X509_NAME_ENTRY) + +/* For the "Name" type we need a SEQUENCE OF { SET OF X509_NAME_ENTRY } + * so declare two template wrappers for this + */ + +ASN1_ITEM_TEMPLATE(X509_NAME_ENTRIES) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SET_OF, 0, RDNS, X509_NAME_ENTRY) +ASN1_ITEM_TEMPLATE_END(X509_NAME_ENTRIES) + +ASN1_ITEM_TEMPLATE(X509_NAME_INTERNAL) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, Name, X509_NAME_ENTRIES) +ASN1_ITEM_TEMPLATE_END(X509_NAME_INTERNAL) + +/* Normally that's where it would end: we'd have two nested STACK structures + * representing the ASN1. Unfortunately X509_NAME uses a completely different + * form and caches encodings so we have to process the internal form and convert + * to the external form. + */ + +const ASN1_EXTERN_FUNCS x509_name_ff = { + NULL, + x509_name_ex_new, + x509_name_ex_free, + 0, /* Default clear behaviour is OK */ + x509_name_ex_d2i, + x509_name_ex_i2d, + x509_name_ex_print +}; + +IMPLEMENT_EXTERN_ASN1(X509_NAME, V_ASN1_SEQUENCE, x509_name_ff) + +IMPLEMENT_ASN1_FUNCTIONS(X509_NAME) +IMPLEMENT_ASN1_DUP_FUNCTION(X509_NAME) + +static int x509_name_ex_new(ASN1_VALUE **val, const ASN1_ITEM *it) +{ + X509_NAME *ret = NULL; + ret = OPENSSL_malloc(sizeof(X509_NAME)); + if(!ret) goto memerr; + if ((ret->entries=sk_X509_NAME_ENTRY_new_null()) == NULL) + goto memerr; + if((ret->bytes = BUF_MEM_new()) == NULL) goto memerr; + ret->canon_enc = NULL; + ret->canon_enclen = 0; + ret->modified=1; + *val = (ASN1_VALUE *)ret; + return 1; + + memerr: + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + if (ret) + { + if (ret->entries) + sk_X509_NAME_ENTRY_free(ret->entries); + OPENSSL_free(ret); + } + return 0; +} + +static void x509_name_ex_free(ASN1_VALUE **pval, const ASN1_ITEM *it) +{ + X509_NAME *a; + if(!pval || !*pval) + return; + a = (X509_NAME *)*pval; + + BUF_MEM_free(a->bytes); + sk_X509_NAME_ENTRY_pop_free(a->entries,X509_NAME_ENTRY_free); + if (a->canon_enc) + OPENSSL_free(a->canon_enc); + OPENSSL_free(a); + *pval = NULL; +} + +static void local_sk_X509_NAME_ENTRY_free(STACK_OF(X509_NAME_ENTRY) *ne) +{ + sk_X509_NAME_ENTRY_free(ne); +} + +static void local_sk_X509_NAME_ENTRY_pop_free(STACK_OF(X509_NAME_ENTRY) *ne) +{ + sk_X509_NAME_ENTRY_pop_free(ne, X509_NAME_ENTRY_free); +} + +static int x509_name_ex_d2i(ASN1_VALUE **val, + const unsigned char **in, long len, const ASN1_ITEM *it, + int tag, int aclass, char opt, ASN1_TLC *ctx) +{ + const unsigned char *p = *in, *q; + union { STACK_OF(STACK_OF_X509_NAME_ENTRY) *s; + ASN1_VALUE *a; } intname = {NULL}; + union { X509_NAME *x; ASN1_VALUE *a; } nm = {NULL}; + size_t i, j; + int ret; + STACK_OF(X509_NAME_ENTRY) *entries; + X509_NAME_ENTRY *entry; + q = p; + + /* Get internal representation of Name */ + ret = ASN1_item_ex_d2i(&intname.a, + &p, len, ASN1_ITEM_rptr(X509_NAME_INTERNAL), + tag, aclass, opt, ctx); + + if(ret <= 0) return ret; + + if(*val) x509_name_ex_free(val, NULL); + /* We've decoded it: now cache encoding */ + if (!x509_name_ex_new(&nm.a, NULL) || + !BUF_MEM_grow(nm.x->bytes, p - q)) + { + sk_STACK_OF_X509_NAME_ENTRY_pop_free(intname.s, + local_sk_X509_NAME_ENTRY_pop_free); + goto err; + } + memcpy(nm.x->bytes->data, q, p - q); + + /* Convert internal representation to X509_NAME structure */ + for(i = 0; i < sk_STACK_OF_X509_NAME_ENTRY_num(intname.s); i++) { + entries = sk_STACK_OF_X509_NAME_ENTRY_value(intname.s, i); + for(j = 0; j < sk_X509_NAME_ENTRY_num(entries); j++) { + entry = sk_X509_NAME_ENTRY_value(entries, j); + entry->set = i; + if(!sk_X509_NAME_ENTRY_push(nm.x->entries, entry)) + goto err; + } + sk_X509_NAME_ENTRY_free(entries); + } + sk_STACK_OF_X509_NAME_ENTRY_free(intname.s); + ret = x509_name_canon(nm.x); + if (!ret) + goto err; + nm.x->modified = 0; + *val = nm.a; + *in = p; + return ret; +err: + if (nm.x != NULL) + X509_NAME_free(nm.x); + OPENSSL_PUT_ERROR(X509, ERR_R_ASN1_LIB); + return 0; +} + +static int x509_name_ex_i2d(ASN1_VALUE **val, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass) +{ + int ret; + X509_NAME *a = (X509_NAME *)*val; + if(a->modified) { + ret = x509_name_encode(a); + if(ret < 0) + return ret; + ret = x509_name_canon(a); + if(ret < 0) + return ret; + } + ret = a->bytes->length; + if(out != NULL) { + memcpy(*out,a->bytes->data,ret); + *out+=ret; + } + return ret; +} + +static int x509_name_encode(X509_NAME *a) +{ + union { STACK_OF(STACK_OF_X509_NAME_ENTRY) *s; + ASN1_VALUE *a; } intname = {NULL}; + int len; + unsigned char *p; + STACK_OF(X509_NAME_ENTRY) *entries = NULL; + X509_NAME_ENTRY *entry; + int set = -1; + size_t i; + intname.s = sk_STACK_OF_X509_NAME_ENTRY_new_null(); + if(!intname.s) goto memerr; + for(i = 0; i < sk_X509_NAME_ENTRY_num(a->entries); i++) { + entry = sk_X509_NAME_ENTRY_value(a->entries, i); + if(entry->set != set) { + entries = sk_X509_NAME_ENTRY_new_null(); + if(!entries) goto memerr; + if(!sk_STACK_OF_X509_NAME_ENTRY_push(intname.s, + entries)) + goto memerr; + set = entry->set; + } + if(!sk_X509_NAME_ENTRY_push(entries, entry)) goto memerr; + } + len = ASN1_item_ex_i2d(&intname.a, NULL, + ASN1_ITEM_rptr(X509_NAME_INTERNAL), -1, -1); + if (!BUF_MEM_grow(a->bytes,len)) goto memerr; + p=(unsigned char *)a->bytes->data; + ASN1_item_ex_i2d(&intname.a, + &p, ASN1_ITEM_rptr(X509_NAME_INTERNAL), -1, -1); + sk_STACK_OF_X509_NAME_ENTRY_pop_free(intname.s, + local_sk_X509_NAME_ENTRY_free); + a->modified = 0; + return len; +memerr: + sk_STACK_OF_X509_NAME_ENTRY_pop_free(intname.s, + local_sk_X509_NAME_ENTRY_free); + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return -1; +} + +static int x509_name_ex_print(BIO *out, ASN1_VALUE **pval, + int indent, + const char *fname, + const ASN1_PCTX *pctx) + { + if (X509_NAME_print_ex(out, (X509_NAME *)*pval, + indent, pctx->nm_flags) <= 0) + return 0; + return 2; + } + +/* This function generates the canonical encoding of the Name structure. + * In it all strings are converted to UTF8, leading, trailing and + * multiple spaces collapsed, converted to lower case and the leading + * SEQUENCE header removed. + * + * In future we could also normalize the UTF8 too. + * + * By doing this comparison of Name structures can be rapidly + * perfomed by just using memcmp() of the canonical encoding. + * By omitting the leading SEQUENCE name constraints of type + * dirName can also be checked with a simple memcmp(). + */ + +static int x509_name_canon(X509_NAME *a) + { + unsigned char *p; + STACK_OF(STACK_OF_X509_NAME_ENTRY) *intname = NULL; + STACK_OF(X509_NAME_ENTRY) *entries = NULL; + X509_NAME_ENTRY *entry, *tmpentry = NULL; + int set = -1, ret = 0; + size_t i; + + if (a->canon_enc) + { + OPENSSL_free(a->canon_enc); + a->canon_enc = NULL; + } + /* Special case: empty X509_NAME => null encoding */ + if (sk_X509_NAME_ENTRY_num(a->entries) == 0) + { + a->canon_enclen = 0; + return 1; + } + intname = sk_STACK_OF_X509_NAME_ENTRY_new_null(); + if(!intname) + goto err; + for(i = 0; i < sk_X509_NAME_ENTRY_num(a->entries); i++) + { + entry = sk_X509_NAME_ENTRY_value(a->entries, i); + if(entry->set != set) + { + entries = sk_X509_NAME_ENTRY_new_null(); + if(!entries) + goto err; + if(!sk_STACK_OF_X509_NAME_ENTRY_push(intname, entries)) + { + sk_X509_NAME_ENTRY_free(entries); + goto err; + } + set = entry->set; + } + tmpentry = X509_NAME_ENTRY_new(); + if (tmpentry == NULL) + goto err; + tmpentry->object = OBJ_dup(entry->object); + if (!asn1_string_canon(tmpentry->value, entry->value)) + goto err; + if(!sk_X509_NAME_ENTRY_push(entries, tmpentry)) + goto err; + tmpentry = NULL; + } + + /* Finally generate encoding */ + + a->canon_enclen = i2d_name_canon(intname, NULL); + + p = OPENSSL_malloc(a->canon_enclen); + + if (!p) + goto err; + + a->canon_enc = p; + + i2d_name_canon(intname, &p); + + ret = 1; + + err: + + if (tmpentry) + X509_NAME_ENTRY_free(tmpentry); + if (intname) + sk_STACK_OF_X509_NAME_ENTRY_pop_free(intname, + local_sk_X509_NAME_ENTRY_pop_free); + return ret; + } + +/* Bitmap of all the types of string that will be canonicalized. */ + +#define ASN1_MASK_CANON \ + (B_ASN1_UTF8STRING | B_ASN1_BMPSTRING | B_ASN1_UNIVERSALSTRING \ + | B_ASN1_PRINTABLESTRING | B_ASN1_T61STRING | B_ASN1_IA5STRING \ + | B_ASN1_VISIBLESTRING) + + +static int asn1_string_canon(ASN1_STRING *out, ASN1_STRING *in) + { + unsigned char *to, *from; + int len, i; + + /* If type not in bitmask just copy string across */ + if (!(ASN1_tag2bit(in->type) & ASN1_MASK_CANON)) + { + if (!ASN1_STRING_copy(out, in)) + return 0; + return 1; + } + + out->type = V_ASN1_UTF8STRING; + out->length = ASN1_STRING_to_UTF8(&out->data, in); + if (out->length == -1) + return 0; + + to = out->data; + from = to; + + len = out->length; + + /* Convert string in place to canonical form. + * Ultimately we may need to handle a wider range of characters + * but for now ignore anything with MSB set and rely on the + * isspace() and tolower() functions. + */ + + /* Ignore leading spaces */ + while((len > 0) && !(*from & 0x80) && isspace(*from)) + { + from++; + len--; + } + + to = from + len - 1; + + /* Ignore trailing spaces */ + while ((len > 0) && !(*to & 0x80) && isspace(*to)) + { + to--; + len--; + } + + to = out->data; + + i = 0; + while(i < len) + { + /* If MSB set just copy across */ + if (*from & 0x80) + { + *to++ = *from++; + i++; + } + /* Collapse multiple spaces */ + else if (isspace(*from)) + { + /* Copy one space across */ + *to++ = ' '; + /* Ignore subsequent spaces. Note: don't need to + * check len here because we know the last + * character is a non-space so we can't overflow. + */ + do + { + from++; + i++; + } + while(!(*from & 0x80) && isspace(*from)); + } + else + { + *to++ = tolower(*from); + from++; + i++; + } + } + + out->length = to - out->data; + + return 1; + + } + +static int i2d_name_canon(STACK_OF(STACK_OF_X509_NAME_ENTRY) *_intname, + unsigned char **in) + { + int len, ltmp; + size_t i; + ASN1_VALUE *v; + STACK_OF(ASN1_VALUE) *intname = (STACK_OF(ASN1_VALUE) *)_intname; + + len = 0; + for (i = 0; i < sk_ASN1_VALUE_num(intname); i++) + { + v = sk_ASN1_VALUE_value(intname, i); + ltmp = ASN1_item_ex_i2d(&v, in, + ASN1_ITEM_rptr(X509_NAME_ENTRIES), -1, -1); + if (ltmp < 0) + return ltmp; + len += ltmp; + } + return len; + } + +int X509_NAME_set(X509_NAME **xn, X509_NAME *name) + { + X509_NAME *in; + + if (!xn || !name) return(0); + + if (*xn != name) + { + in=X509_NAME_dup(name); + if (in != NULL) + { + X509_NAME_free(*xn); + *xn=in; + } + } + return(*xn != NULL); + } + +IMPLEMENT_ASN1_SET_OF(X509_NAME_ENTRY) diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x_pkey.c b/TMessagesProj/jni/boringssl/crypto/x509/x_pkey.c new file mode 100644 index 00000000..f5e98b82 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x_pkey.c @@ -0,0 +1,100 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include +#include + + +X509_PKEY *X509_PKEY_new(void) + { + X509_PKEY *ret = OPENSSL_malloc(sizeof(X509_PKEY)); + if (ret == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + goto err; + } + memset(ret, 0, sizeof(X509_PKEY)); + + ret->enc_algor = X509_ALGOR_new(); + if (ret->enc_algor == NULL) + goto err; + ret->enc_pkey = M_ASN1_OCTET_STRING_new(); + if (ret->enc_pkey == NULL) + goto err; + return ret; + +err: + if (ret != NULL) + X509_PKEY_free(ret); + return NULL; + } + +void X509_PKEY_free(X509_PKEY *x) + { + if (x == NULL) return; + + if (x->enc_algor != NULL) X509_ALGOR_free(x->enc_algor); + if (x->enc_pkey != NULL) M_ASN1_OCTET_STRING_free(x->enc_pkey); + if (x->dec_pkey != NULL)EVP_PKEY_free(x->dec_pkey); + if ((x->key_data != NULL) && (x->key_free)) OPENSSL_free(x->key_data); + OPENSSL_free(x); + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x_pubkey.c b/TMessagesProj/jni/boringssl/crypto/x509/x_pubkey.c new file mode 100644 index 00000000..a16edcab --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x_pubkey.c @@ -0,0 +1,384 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../evp/internal.h" +#include "../internal.h" + + +/* Minor tweak to operation: free up EVP_PKEY */ +static int pubkey_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, + void *exarg) + { + if (operation == ASN1_OP_FREE_POST) + { + X509_PUBKEY *pubkey = (X509_PUBKEY *)*pval; + EVP_PKEY_free(pubkey->pkey); + } + return 1; + } + +ASN1_SEQUENCE_cb(X509_PUBKEY, pubkey_cb) = { + ASN1_SIMPLE(X509_PUBKEY, algor, X509_ALGOR), + ASN1_SIMPLE(X509_PUBKEY, public_key, ASN1_BIT_STRING) +} ASN1_SEQUENCE_END_cb(X509_PUBKEY, X509_PUBKEY) + +IMPLEMENT_ASN1_FUNCTIONS(X509_PUBKEY) + +int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey) + { + X509_PUBKEY *pk=NULL; + + if (x == NULL) return(0); + + if ((pk=X509_PUBKEY_new()) == NULL) goto error; + + if (pkey->ameth) + { + if (pkey->ameth->pub_encode) + { + if (!pkey->ameth->pub_encode(pk, pkey)) + { + OPENSSL_PUT_ERROR(X509, X509_R_PUBLIC_KEY_ENCODE_ERROR); + goto error; + } + } + else + { + OPENSSL_PUT_ERROR(X509, X509_R_METHOD_NOT_SUPPORTED); + goto error; + } + } + else + { + OPENSSL_PUT_ERROR(X509, X509_R_UNSUPPORTED_ALGORITHM); + goto error; + } + + if (*x != NULL) + X509_PUBKEY_free(*x); + + *x=pk; + + return 1; +error: + if (pk != NULL) X509_PUBKEY_free(pk); + return 0; + } + +/* g_pubkey_lock is used to protect the initialisation of the |pkey| member of + * |X509_PUBKEY| objects. Really |X509_PUBKEY| should have a |CRYPTO_once_t| + * inside it for this, but |CRYPTO_once_t| is private and |X509_PUBKEY| is + * not. */ +static struct CRYPTO_STATIC_MUTEX g_pubkey_lock = CRYPTO_STATIC_MUTEX_INIT; + +EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key) + { + EVP_PKEY *ret=NULL; + + if (key == NULL) goto error; + + CRYPTO_STATIC_MUTEX_lock_read(&g_pubkey_lock); + if (key->pkey != NULL) + { + CRYPTO_STATIC_MUTEX_unlock(&g_pubkey_lock); + return EVP_PKEY_up_ref(key->pkey); + } + CRYPTO_STATIC_MUTEX_unlock(&g_pubkey_lock); + + if (key->public_key == NULL) goto error; + + if ((ret = EVP_PKEY_new()) == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + goto error; + } + + if (!EVP_PKEY_set_type(ret, OBJ_obj2nid(key->algor->algorithm))) + { + OPENSSL_PUT_ERROR(X509, X509_R_UNSUPPORTED_ALGORITHM); + goto error; + } + + if (ret->ameth->pub_decode) + { + if (!ret->ameth->pub_decode(ret, key)) + { + OPENSSL_PUT_ERROR(X509, X509_R_PUBLIC_KEY_DECODE_ERROR); + goto error; + } + } + else + { + OPENSSL_PUT_ERROR(X509, X509_R_METHOD_NOT_SUPPORTED); + goto error; + } + + /* Check to see if another thread set key->pkey first */ + CRYPTO_STATIC_MUTEX_lock_write(&g_pubkey_lock); + if (key->pkey) + { + CRYPTO_STATIC_MUTEX_unlock(&g_pubkey_lock); + EVP_PKEY_free(ret); + ret = key->pkey; + } + else + { + key->pkey = ret; + CRYPTO_STATIC_MUTEX_unlock(&g_pubkey_lock); + } + + return EVP_PKEY_up_ref(ret); + + error: + if (ret != NULL) + EVP_PKEY_free(ret); + return(NULL); + } + +/* Now two pseudo ASN1 routines that take an EVP_PKEY structure + * and encode or decode as X509_PUBKEY + */ + +EVP_PKEY *d2i_PUBKEY(EVP_PKEY **a, const unsigned char **pp, + long length) + { + X509_PUBKEY *xpk; + EVP_PKEY *pktmp; + xpk = d2i_X509_PUBKEY(NULL, pp, length); + if(!xpk) return NULL; + pktmp = X509_PUBKEY_get(xpk); + X509_PUBKEY_free(xpk); + if(!pktmp) return NULL; + if(a) + { + EVP_PKEY_free(*a); + *a = pktmp; + } + return pktmp; + } + +int i2d_PUBKEY(const EVP_PKEY *a, unsigned char **pp) + { + X509_PUBKEY *xpk=NULL; + int ret; + if(!a) return 0; + if(!X509_PUBKEY_set(&xpk, (EVP_PKEY*) a)) return 0; + ret = i2d_X509_PUBKEY(xpk, pp); + X509_PUBKEY_free(xpk); + return ret; + } + +/* The following are equivalents but which return RSA and DSA + * keys + */ +RSA *d2i_RSA_PUBKEY(RSA **a, const unsigned char **pp, + long length) + { + EVP_PKEY *pkey; + RSA *key; + const unsigned char *q; + q = *pp; + pkey = d2i_PUBKEY(NULL, &q, length); + if (!pkey) return NULL; + key = EVP_PKEY_get1_RSA(pkey); + EVP_PKEY_free(pkey); + if (!key) return NULL; + *pp = q; + if (a) + { + RSA_free(*a); + *a = key; + } + return key; + } + +int i2d_RSA_PUBKEY(const RSA *a, unsigned char **pp) + { + EVP_PKEY *pktmp; + int ret; + if (!a) return 0; + pktmp = EVP_PKEY_new(); + if (!pktmp) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return 0; + } + EVP_PKEY_set1_RSA(pktmp, (RSA*) a); + ret = i2d_PUBKEY(pktmp, pp); + EVP_PKEY_free(pktmp); + return ret; + } + +#ifndef OPENSSL_NO_DSA +DSA *d2i_DSA_PUBKEY(DSA **a, const unsigned char **pp, + long length) + { + EVP_PKEY *pkey; + DSA *key; + const unsigned char *q; + q = *pp; + pkey = d2i_PUBKEY(NULL, &q, length); + if (!pkey) return NULL; + key = EVP_PKEY_get1_DSA(pkey); + EVP_PKEY_free(pkey); + if (!key) return NULL; + *pp = q; + if (a) + { + DSA_free(*a); + *a = key; + } + return key; + } + +int i2d_DSA_PUBKEY(const DSA *a, unsigned char **pp) + { + EVP_PKEY *pktmp; + int ret; + if(!a) return 0; + pktmp = EVP_PKEY_new(); + if(!pktmp) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return 0; + } + EVP_PKEY_set1_DSA(pktmp, (DSA*) a); + ret = i2d_PUBKEY(pktmp, pp); + EVP_PKEY_free(pktmp); + return ret; + } +#endif + +EC_KEY *d2i_EC_PUBKEY(EC_KEY **a, const unsigned char **pp, long length) + { + EVP_PKEY *pkey; + EC_KEY *key; + const unsigned char *q; + q = *pp; + pkey = d2i_PUBKEY(NULL, &q, length); + if (!pkey) return(NULL); + key = EVP_PKEY_get1_EC_KEY(pkey); + EVP_PKEY_free(pkey); + if (!key) return(NULL); + *pp = q; + if (a) + { + EC_KEY_free(*a); + *a = key; + } + return(key); + } + +int i2d_EC_PUBKEY(const EC_KEY *a, unsigned char **pp) + { + EVP_PKEY *pktmp; + int ret; + if (!a) return(0); + if ((pktmp = EVP_PKEY_new()) == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return(0); + } + EVP_PKEY_set1_EC_KEY(pktmp, (EC_KEY*) a); + ret = i2d_PUBKEY(pktmp, pp); + EVP_PKEY_free(pktmp); + return(ret); + } + +int X509_PUBKEY_set0_param(X509_PUBKEY *pub, const ASN1_OBJECT *aobj, + int ptype, void *pval, + unsigned char *penc, int penclen) + { + if (!X509_ALGOR_set0(pub->algor, aobj, ptype, pval)) + return 0; + if (penc) + { + if (pub->public_key->data) + OPENSSL_free(pub->public_key->data); + pub->public_key->data = penc; + pub->public_key->length = penclen; + /* Set number of unused bits to zero */ + pub->public_key->flags&= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07); + pub->public_key->flags|=ASN1_STRING_FLAG_BITS_LEFT; + } + return 1; + } + +int X509_PUBKEY_get0_param(ASN1_OBJECT **ppkalg, + const unsigned char **pk, int *ppklen, + X509_ALGOR **pa, + X509_PUBKEY *pub) + { + if (ppkalg) + *ppkalg = pub->algor->algorithm; + if (pk) + { + *pk = pub->public_key->data; + *ppklen = pub->public_key->length; + } + if (pa) + *pa = pub->algor; + return 1; + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x_req.c b/TMessagesProj/jni/boringssl/crypto/x509/x_req.c new file mode 100644 index 00000000..3d301297 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x_req.c @@ -0,0 +1,112 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include + +/* X509_REQ_INFO is handled in an unusual way to get round + * invalid encodings. Some broken certificate requests don't + * encode the attributes field if it is empty. This is in + * violation of PKCS#10 but we need to tolerate it. We do + * this by making the attributes field OPTIONAL then using + * the callback to initialise it to an empty STACK. + * + * This means that the field will be correctly encoded unless + * we NULL out the field. + * + * As a result we no longer need the req_kludge field because + * the information is now contained in the attributes field: + * 1. If it is NULL then it's the invalid omission. + * 2. If it is empty it is the correct encoding. + * 3. If it is not empty then some attributes are present. + * + */ + +static int rinf_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, + void *exarg) +{ + X509_REQ_INFO *rinf = (X509_REQ_INFO *)*pval; + + if(operation == ASN1_OP_NEW_POST) { + rinf->attributes = sk_X509_ATTRIBUTE_new_null(); + if(!rinf->attributes) return 0; + } + return 1; +} + +ASN1_SEQUENCE_enc(X509_REQ_INFO, enc, rinf_cb) = { + ASN1_SIMPLE(X509_REQ_INFO, version, ASN1_INTEGER), + ASN1_SIMPLE(X509_REQ_INFO, subject, X509_NAME), + ASN1_SIMPLE(X509_REQ_INFO, pubkey, X509_PUBKEY), + /* This isn't really OPTIONAL but it gets round invalid + * encodings + */ + ASN1_IMP_SET_OF_OPT(X509_REQ_INFO, attributes, X509_ATTRIBUTE, 0) +} ASN1_SEQUENCE_END_enc(X509_REQ_INFO, X509_REQ_INFO) + +IMPLEMENT_ASN1_FUNCTIONS(X509_REQ_INFO) + +ASN1_SEQUENCE_ref(X509_REQ, 0) = { + ASN1_SIMPLE(X509_REQ, req_info, X509_REQ_INFO), + ASN1_SIMPLE(X509_REQ, sig_alg, X509_ALGOR), + ASN1_SIMPLE(X509_REQ, signature, ASN1_BIT_STRING) +} ASN1_SEQUENCE_END_ref(X509_REQ, X509_REQ) + +IMPLEMENT_ASN1_FUNCTIONS(X509_REQ) +IMPLEMENT_ASN1_DUP_FUNCTION(X509_REQ) diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x_sig.c b/TMessagesProj/jni/boringssl/crypto/x509/x_sig.c new file mode 100644 index 00000000..fabdb676 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x_sig.c @@ -0,0 +1,69 @@ +/* crypto/asn1/x_sig.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + +ASN1_SEQUENCE(X509_SIG) = { + ASN1_SIMPLE(X509_SIG, algor, X509_ALGOR), + ASN1_SIMPLE(X509_SIG, digest, ASN1_OCTET_STRING) +} ASN1_SEQUENCE_END(X509_SIG) + +IMPLEMENT_ASN1_FUNCTIONS(X509_SIG) diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x_spki.c b/TMessagesProj/jni/boringssl/crypto/x509/x_spki.c new file mode 100644 index 00000000..35bf2465 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x_spki.c @@ -0,0 +1,78 @@ +/* crypto/asn1/x_spki.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + + /* This module was send to me my Pat Richards who + * wrote it. It is under my Copyright with his permission. */ + +#include +#include + + +ASN1_SEQUENCE(NETSCAPE_SPKAC) = { + ASN1_SIMPLE(NETSCAPE_SPKAC, pubkey, X509_PUBKEY), + ASN1_SIMPLE(NETSCAPE_SPKAC, challenge, ASN1_IA5STRING) +} ASN1_SEQUENCE_END(NETSCAPE_SPKAC) + +IMPLEMENT_ASN1_FUNCTIONS(NETSCAPE_SPKAC) + +ASN1_SEQUENCE(NETSCAPE_SPKI) = { + ASN1_SIMPLE(NETSCAPE_SPKI, spkac, NETSCAPE_SPKAC), + ASN1_SIMPLE(NETSCAPE_SPKI, sig_algor, X509_ALGOR), + ASN1_SIMPLE(NETSCAPE_SPKI, signature, ASN1_BIT_STRING) +} ASN1_SEQUENCE_END(NETSCAPE_SPKI) + +IMPLEMENT_ASN1_FUNCTIONS(NETSCAPE_SPKI) diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x_val.c b/TMessagesProj/jni/boringssl/crypto/x509/x_val.c new file mode 100644 index 00000000..26200ee4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x_val.c @@ -0,0 +1,69 @@ +/* crypto/asn1/x_val.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + +ASN1_SEQUENCE(X509_VAL) = { + ASN1_SIMPLE(X509_VAL, notBefore, ASN1_TIME), + ASN1_SIMPLE(X509_VAL, notAfter, ASN1_TIME) +} ASN1_SEQUENCE_END(X509_VAL) + +IMPLEMENT_ASN1_FUNCTIONS(X509_VAL) diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x_x509.c b/TMessagesProj/jni/boringssl/crypto/x509/x_x509.c new file mode 100644 index 00000000..c975dd35 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x_x509.c @@ -0,0 +1,228 @@ +/* crypto/asn1/x_x509.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../internal.h" + + +static CRYPTO_EX_DATA_CLASS g_ex_data_class = CRYPTO_EX_DATA_CLASS_INIT; + +ASN1_SEQUENCE_enc(X509_CINF, enc, 0) = { + ASN1_EXP_OPT(X509_CINF, version, ASN1_INTEGER, 0), + ASN1_SIMPLE(X509_CINF, serialNumber, ASN1_INTEGER), + ASN1_SIMPLE(X509_CINF, signature, X509_ALGOR), + ASN1_SIMPLE(X509_CINF, issuer, X509_NAME), + ASN1_SIMPLE(X509_CINF, validity, X509_VAL), + ASN1_SIMPLE(X509_CINF, subject, X509_NAME), + ASN1_SIMPLE(X509_CINF, key, X509_PUBKEY), + ASN1_IMP_OPT(X509_CINF, issuerUID, ASN1_BIT_STRING, 1), + ASN1_IMP_OPT(X509_CINF, subjectUID, ASN1_BIT_STRING, 2), + ASN1_EXP_SEQUENCE_OF_OPT(X509_CINF, extensions, X509_EXTENSION, 3) +} ASN1_SEQUENCE_END_enc(X509_CINF, X509_CINF) + +IMPLEMENT_ASN1_FUNCTIONS(X509_CINF) +/* X509 top level structure needs a bit of customisation */ + +extern void policy_cache_free(X509_POLICY_CACHE *cache); + +static int x509_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, + void *exarg) +{ + X509 *ret = (X509 *)*pval; + + switch(operation) { + + case ASN1_OP_NEW_POST: + ret->valid=0; + ret->name = NULL; + ret->ex_flags = 0; + ret->ex_pathlen = -1; + ret->skid = NULL; + ret->akid = NULL; + ret->aux = NULL; + ret->crldp = NULL; + CRYPTO_new_ex_data(&g_ex_data_class, ret, &ret->ex_data); + break; + + case ASN1_OP_D2I_POST: + if (ret->name != NULL) OPENSSL_free(ret->name); + ret->name=X509_NAME_oneline(ret->cert_info->subject,NULL,0); + break; + + case ASN1_OP_FREE_POST: + CRYPTO_free_ex_data(&g_ex_data_class, ret, &ret->ex_data); + X509_CERT_AUX_free(ret->aux); + ASN1_OCTET_STRING_free(ret->skid); + AUTHORITY_KEYID_free(ret->akid); + CRL_DIST_POINTS_free(ret->crldp); + policy_cache_free(ret->policy_cache); + GENERAL_NAMES_free(ret->altname); + NAME_CONSTRAINTS_free(ret->nc); + + if (ret->name != NULL) OPENSSL_free(ret->name); + break; + + } + + return 1; + +} + +ASN1_SEQUENCE_ref(X509, x509_cb) = { + ASN1_SIMPLE(X509, cert_info, X509_CINF), + ASN1_SIMPLE(X509, sig_alg, X509_ALGOR), + ASN1_SIMPLE(X509, signature, ASN1_BIT_STRING) +} ASN1_SEQUENCE_END_ref(X509, X509) + +IMPLEMENT_ASN1_FUNCTIONS(X509) +IMPLEMENT_ASN1_DUP_FUNCTION(X509) + +X509 *X509_up_ref(X509 *x) + { + CRYPTO_refcount_inc(&x->references); + return x; + } + +int X509_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func) + { + int index; + if (!CRYPTO_get_ex_new_index(&g_ex_data_class, &index, argl, argp, + new_func, dup_func, free_func)) + { + return -1; + } + return index; + } + +int X509_set_ex_data(X509 *r, int idx, void *arg) + { + return(CRYPTO_set_ex_data(&r->ex_data,idx,arg)); + } + +void *X509_get_ex_data(X509 *r, int idx) + { + return(CRYPTO_get_ex_data(&r->ex_data,idx)); + } + +/* X509_AUX ASN1 routines. X509_AUX is the name given to + * a certificate with extra info tagged on the end. Since these + * functions set how a certificate is trusted they should only + * be used when the certificate comes from a reliable source + * such as local storage. + * + */ + +X509 *d2i_X509_AUX(X509 **a, const unsigned char **pp, long length) +{ + const unsigned char *q; + X509 *ret; + int freeret = 0; + + /* Save start position */ + q = *pp; + + if (!a || *a == NULL) + freeret = 1; + ret = d2i_X509(a, pp, length); + /* If certificate unreadable then forget it */ + if(!ret) return NULL; + /* update length */ + length -= *pp - q; + if(!length) return ret; + if(!d2i_X509_CERT_AUX(&ret->aux, pp, length)) goto err; + return ret; + err: + if (freeret) + { + X509_free(ret); + if (a) + *a = NULL; + } + return NULL; +} + +int i2d_X509_AUX(X509 *a, unsigned char **pp) +{ + int length; + length = i2d_X509(a, pp); + if(a) length += i2d_X509_CERT_AUX(a->aux, pp); + return length; +} + +void X509_get0_signature(ASN1_BIT_STRING **psig, X509_ALGOR **palg, + const X509 *x) + { + if (psig) + *psig = x->signature; + if (palg) + *palg = x->sig_alg; + } + +int X509_get_signature_nid(const X509 *x) + { + return OBJ_obj2nid(x->sig_alg->algorithm); + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x_x509a.c b/TMessagesProj/jni/boringssl/crypto/x509/x_x509a.c new file mode 100644 index 00000000..e13204b8 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x_x509a.c @@ -0,0 +1,177 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include +#include + + +/* X509_CERT_AUX routines. These are used to encode additional + * user modifiable data about a certificate. This data is + * appended to the X509 encoding when the *_X509_AUX routines + * are used. This means that the "traditional" X509 routines + * will simply ignore the extra data. */ + +static X509_CERT_AUX *aux_get(X509 *x); + +ASN1_SEQUENCE(X509_CERT_AUX) = { + ASN1_SEQUENCE_OF_OPT(X509_CERT_AUX, trust, ASN1_OBJECT), + ASN1_IMP_SEQUENCE_OF_OPT(X509_CERT_AUX, reject, ASN1_OBJECT, 0), + ASN1_OPT(X509_CERT_AUX, alias, ASN1_UTF8STRING), + ASN1_OPT(X509_CERT_AUX, keyid, ASN1_OCTET_STRING), + ASN1_IMP_SEQUENCE_OF_OPT(X509_CERT_AUX, other, X509_ALGOR, 1) +} ASN1_SEQUENCE_END(X509_CERT_AUX) + +IMPLEMENT_ASN1_FUNCTIONS(X509_CERT_AUX) + +static X509_CERT_AUX *aux_get(X509 *x) +{ + if(!x) return NULL; + if(!x->aux && !(x->aux = X509_CERT_AUX_new())) return NULL; + return x->aux; +} + +int X509_alias_set1(X509 *x, unsigned char *name, int len) +{ + X509_CERT_AUX *aux; + if (!name) + { + if (!x || !x->aux || !x->aux->alias) + return 1; + ASN1_UTF8STRING_free(x->aux->alias); + x->aux->alias = NULL; + return 1; + } + if(!(aux = aux_get(x))) return 0; + if(!aux->alias && !(aux->alias = ASN1_UTF8STRING_new())) return 0; + return ASN1_STRING_set(aux->alias, name, len); +} + +int X509_keyid_set1(X509 *x, unsigned char *id, int len) +{ + X509_CERT_AUX *aux; + if (!id) + { + if (!x || !x->aux || !x->aux->keyid) + return 1; + ASN1_OCTET_STRING_free(x->aux->keyid); + x->aux->keyid = NULL; + return 1; + } + if(!(aux = aux_get(x))) return 0; + if(!aux->keyid && !(aux->keyid = ASN1_OCTET_STRING_new())) return 0; + return ASN1_STRING_set(aux->keyid, id, len); +} + +unsigned char *X509_alias_get0(X509 *x, int *len) +{ + if(!x->aux || !x->aux->alias) return NULL; + if(len) *len = x->aux->alias->length; + return x->aux->alias->data; +} + +unsigned char *X509_keyid_get0(X509 *x, int *len) +{ + if(!x->aux || !x->aux->keyid) return NULL; + if(len) *len = x->aux->keyid->length; + return x->aux->keyid->data; +} + +int X509_add1_trust_object(X509 *x, ASN1_OBJECT *obj) +{ + X509_CERT_AUX *aux; + ASN1_OBJECT *objtmp; + if(!(objtmp = OBJ_dup(obj))) return 0; + if(!(aux = aux_get(x))) return 0; + if(!aux->trust + && !(aux->trust = sk_ASN1_OBJECT_new_null())) return 0; + return sk_ASN1_OBJECT_push(aux->trust, objtmp); +} + +int X509_add1_reject_object(X509 *x, ASN1_OBJECT *obj) +{ + X509_CERT_AUX *aux; + ASN1_OBJECT *objtmp; + if(!(objtmp = OBJ_dup(obj))) return 0; + if(!(aux = aux_get(x))) return 0; + if(!aux->reject + && !(aux->reject = sk_ASN1_OBJECT_new_null())) return 0; + return sk_ASN1_OBJECT_push(aux->reject, objtmp); +} + +void X509_trust_clear(X509 *x) +{ + if(x->aux && x->aux->trust) { + sk_ASN1_OBJECT_pop_free(x->aux->trust, ASN1_OBJECT_free); + x->aux->trust = NULL; + } +} + +void X509_reject_clear(X509 *x) +{ + if(x->aux && x->aux->reject) { + sk_ASN1_OBJECT_pop_free(x->aux->reject, ASN1_OBJECT_free); + x->aux->reject = NULL; + } +} + +ASN1_SEQUENCE(X509_CERT_PAIR) = { + ASN1_EXP_OPT(X509_CERT_PAIR, forward, X509, 0), + ASN1_EXP_OPT(X509_CERT_PAIR, reverse, X509, 1) +} ASN1_SEQUENCE_END(X509_CERT_PAIR) + +IMPLEMENT_ASN1_FUNCTIONS(X509_CERT_PAIR) diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/x509v3/CMakeLists.txt new file mode 100644 index 00000000..b8418a95 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/CMakeLists.txt @@ -0,0 +1,44 @@ +include_directories(. .. ../../include) + +add_library( + x509v3 + + OBJECT + + # v3_addr.c - disabled by upstream by default. + # v3_asid.c - disabled by upstream by default. + # v3_ocsp.c - missing OCSP for now. + + pcy_cache.c + pcy_data.c + pcy_lib.c + pcy_map.c + pcy_node.c + pcy_tree.c + v3_akey.c + v3_akeya.c + v3_alt.c + v3_bcons.c + v3_bitst.c + v3_conf.c + v3_cpols.c + v3_crld.c + v3_enum.c + v3_extku.c + v3_genn.c + v3_ia5.c + v3_info.c + v3_int.c + v3_lib.c + v3_ncons.c + v3_pci.c + v3_pcia.c + v3_pcons.c + v3_pku.c + v3_pmaps.c + v3_prn.c + v3_purp.c + v3_skey.c + v3_sxnet.c + v3_utl.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/ext_dat.h b/TMessagesProj/jni/boringssl/crypto/x509v3/ext_dat.h new file mode 100644 index 00000000..8b2c123b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/ext_dat.h @@ -0,0 +1,129 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999-2004 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +/* This file contains a table of "standard" extensions */ + +extern X509V3_EXT_METHOD v3_bcons, v3_nscert, v3_key_usage, v3_ext_ku; +extern X509V3_EXT_METHOD v3_pkey_usage_period, v3_sxnet, v3_info, v3_sinfo; +extern X509V3_EXT_METHOD v3_ns_ia5_list[], v3_alt[], v3_skey_id, v3_akey_id; +extern X509V3_EXT_METHOD v3_crl_num, v3_crl_reason, v3_crl_invdate; +extern X509V3_EXT_METHOD v3_delta_crl, v3_cpols, v3_crld, v3_freshest_crl; +extern X509V3_EXT_METHOD v3_ocsp_nonce, v3_ocsp_accresp, v3_ocsp_acutoff; +extern X509V3_EXT_METHOD v3_ocsp_crlid, v3_ocsp_nocheck, v3_ocsp_serviceloc; +extern X509V3_EXT_METHOD v3_crl_hold, v3_pci; +extern X509V3_EXT_METHOD v3_policy_mappings, v3_policy_constraints; +extern X509V3_EXT_METHOD v3_name_constraints, v3_inhibit_anyp, v3_idp; +extern X509V3_EXT_METHOD v3_addr, v3_asid; + +/* This table will be searched using OBJ_bsearch so it *must* kept in + * order of the ext_nid values. + */ + +/* TODO(fork): OCSP support */ +#define OPENSSL_NO_OCSP + +static const X509V3_EXT_METHOD *const standard_exts[] = { +&v3_nscert, +&v3_ns_ia5_list[0], +&v3_ns_ia5_list[1], +&v3_ns_ia5_list[2], +&v3_ns_ia5_list[3], +&v3_ns_ia5_list[4], +&v3_ns_ia5_list[5], +&v3_ns_ia5_list[6], +&v3_skey_id, +&v3_key_usage, +&v3_pkey_usage_period, +&v3_alt[0], +&v3_alt[1], +&v3_bcons, +&v3_crl_num, +&v3_cpols, +&v3_akey_id, +&v3_crld, +&v3_ext_ku, +&v3_delta_crl, +&v3_crl_reason, +#ifndef OPENSSL_NO_OCSP +&v3_crl_invdate, +#endif +&v3_sxnet, +&v3_info, +#ifndef OPENSSL_NO_OCSP +&v3_ocsp_nonce, +&v3_ocsp_crlid, +&v3_ocsp_accresp, +&v3_ocsp_nocheck, +&v3_ocsp_acutoff, +&v3_ocsp_serviceloc, +#endif +&v3_sinfo, +&v3_policy_constraints, +#ifndef OPENSSL_NO_OCSP +&v3_crl_hold, +#endif +&v3_pci, +&v3_name_constraints, +&v3_policy_mappings, +&v3_inhibit_anyp, +&v3_idp, +&v3_alt[2], +&v3_freshest_crl, +}; + +/* Number of standard extensions */ + +#define STANDARD_EXTENSION_COUNT (sizeof(standard_exts)/sizeof(X509V3_EXT_METHOD *)) + diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_cache.c b/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_cache.c new file mode 100644 index 00000000..08f20aa2 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_cache.c @@ -0,0 +1,299 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2004. + */ +/* ==================================================================== + * Copyright (c) 2004 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include +#include +#include +#include +#include + +#include "pcy_int.h" +#include "../internal.h" + + +static int policy_data_cmp(const X509_POLICY_DATA **a, + const X509_POLICY_DATA **b); +static int policy_cache_set_int(long *out, ASN1_INTEGER *value); + +/* Set cache entry according to CertificatePolicies extension. + * Note: this destroys the passed CERTIFICATEPOLICIES structure. + */ + +static int policy_cache_create(X509 *x, + CERTIFICATEPOLICIES *policies, int crit) + { + size_t i; + int ret = 0; + X509_POLICY_CACHE *cache = x->policy_cache; + X509_POLICY_DATA *data = NULL; + POLICYINFO *policy; + if (sk_POLICYINFO_num(policies) == 0) + goto bad_policy; + cache->data = sk_X509_POLICY_DATA_new(policy_data_cmp); + if (!cache->data) + goto bad_policy; + for (i = 0; i < sk_POLICYINFO_num(policies); i++) + { + policy = sk_POLICYINFO_value(policies, i); + data = policy_data_new(policy, NULL, crit); + if (!data) + goto bad_policy; + /* Duplicate policy OIDs are illegal: reject if matches + * found. + */ + if (OBJ_obj2nid(data->valid_policy) == NID_any_policy) + { + if (cache->anyPolicy) + { + ret = -1; + goto bad_policy; + } + cache->anyPolicy = data; + } + else if (sk_X509_POLICY_DATA_find(cache->data, NULL, data)) + { + ret = -1; + goto bad_policy; + } + else if (!sk_X509_POLICY_DATA_push(cache->data, data)) + goto bad_policy; + data = NULL; + } + ret = 1; + bad_policy: + if (ret == -1) + x->ex_flags |= EXFLAG_INVALID_POLICY; + if (data) + policy_data_free(data); + sk_POLICYINFO_pop_free(policies, POLICYINFO_free); + if (ret <= 0) + { + sk_X509_POLICY_DATA_pop_free(cache->data, policy_data_free); + cache->data = NULL; + } + return ret; + } + + +static int policy_cache_new(X509 *x) + { + X509_POLICY_CACHE *cache; + ASN1_INTEGER *ext_any = NULL; + POLICY_CONSTRAINTS *ext_pcons = NULL; + CERTIFICATEPOLICIES *ext_cpols = NULL; + POLICY_MAPPINGS *ext_pmaps = NULL; + int i; + cache = OPENSSL_malloc(sizeof(X509_POLICY_CACHE)); + if (!cache) + return 0; + cache->anyPolicy = NULL; + cache->data = NULL; + cache->any_skip = -1; + cache->explicit_skip = -1; + cache->map_skip = -1; + + x->policy_cache = cache; + + /* Handle requireExplicitPolicy *first*. Need to process this + * even if we don't have any policies. + */ + ext_pcons = X509_get_ext_d2i(x, NID_policy_constraints, &i, NULL); + + if (!ext_pcons) + { + if (i != -1) + goto bad_cache; + } + else + { + if (!ext_pcons->requireExplicitPolicy + && !ext_pcons->inhibitPolicyMapping) + goto bad_cache; + if (!policy_cache_set_int(&cache->explicit_skip, + ext_pcons->requireExplicitPolicy)) + goto bad_cache; + if (!policy_cache_set_int(&cache->map_skip, + ext_pcons->inhibitPolicyMapping)) + goto bad_cache; + } + + /* Process CertificatePolicies */ + + ext_cpols = X509_get_ext_d2i(x, NID_certificate_policies, &i, NULL); + /* If no CertificatePolicies extension or problem decoding then + * there is no point continuing because the valid policies will be + * NULL. + */ + if (!ext_cpols) + { + /* If not absent some problem with extension */ + if (i != -1) + goto bad_cache; + return 1; + } + + i = policy_cache_create(x, ext_cpols, i); + + /* NB: ext_cpols freed by policy_cache_set_policies */ + + if (i <= 0) + return i; + + ext_pmaps = X509_get_ext_d2i(x, NID_policy_mappings, &i, NULL); + + if (!ext_pmaps) + { + /* If not absent some problem with extension */ + if (i != -1) + goto bad_cache; + } + else + { + i = policy_cache_set_mapping(x, ext_pmaps); + if (i <= 0) + goto bad_cache; + } + + ext_any = X509_get_ext_d2i(x, NID_inhibit_any_policy, &i, NULL); + + if (!ext_any) + { + if (i != -1) + goto bad_cache; + } + else if (!policy_cache_set_int(&cache->any_skip, ext_any)) + goto bad_cache; + + if (0) + { + bad_cache: + x->ex_flags |= EXFLAG_INVALID_POLICY; + } + + if(ext_pcons) + POLICY_CONSTRAINTS_free(ext_pcons); + + if (ext_any) + ASN1_INTEGER_free(ext_any); + + return 1; + + +} + +void policy_cache_free(X509_POLICY_CACHE *cache) + { + if (!cache) + return; + if (cache->anyPolicy) + policy_data_free(cache->anyPolicy); + if (cache->data) + sk_X509_POLICY_DATA_pop_free(cache->data, policy_data_free); + OPENSSL_free(cache); + } + +/* g_x509_policy_cache_lock is used to protect against concurrent calls to + * |policy_cache_new|. Ideally this would be done with a |CRYPTO_once_t| + * in the |X509| structure, but |CRYPTO_once_t| isn't public. */ +static struct CRYPTO_STATIC_MUTEX g_x509_policy_cache_lock = + CRYPTO_STATIC_MUTEX_INIT; + +const X509_POLICY_CACHE *policy_cache_set(X509 *x) + { + X509_POLICY_CACHE *cache; + + CRYPTO_STATIC_MUTEX_lock_read(&g_x509_policy_cache_lock); + cache = x->policy_cache; + CRYPTO_STATIC_MUTEX_unlock(&g_x509_policy_cache_lock); + + if (cache != NULL) + return cache; + + CRYPTO_STATIC_MUTEX_lock_write(&g_x509_policy_cache_lock); + if (x->policy_cache == NULL) + policy_cache_new(x); + cache = x->policy_cache; + CRYPTO_STATIC_MUTEX_unlock(&g_x509_policy_cache_lock); + + return cache; + } + +X509_POLICY_DATA *policy_cache_find_data(const X509_POLICY_CACHE *cache, + const ASN1_OBJECT *id) + { + size_t idx; + X509_POLICY_DATA tmp; + + tmp.valid_policy = (ASN1_OBJECT *)id; + if (!sk_X509_POLICY_DATA_find(cache->data, &idx, &tmp)) + return NULL; + return sk_X509_POLICY_DATA_value(cache->data, idx); + } + +static int policy_data_cmp(const X509_POLICY_DATA **a, + const X509_POLICY_DATA **b) + { + return OBJ_cmp((*a)->valid_policy, (*b)->valid_policy); + } + +static int policy_cache_set_int(long *out, ASN1_INTEGER *value) + { + if (value == NULL) + return 1; + if (value->type == V_ASN1_NEG_INTEGER) + return 0; + *out = ASN1_INTEGER_get(value); + return 1; + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_data.c b/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_data.c new file mode 100644 index 00000000..cd45dcaa --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_data.c @@ -0,0 +1,137 @@ +/* pcy_data.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2004. + */ +/* ==================================================================== + * Copyright (c) 2004 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include +#include +#include +#include + +#include "pcy_int.h" + + +/* Policy Node routines */ + +void policy_data_free(X509_POLICY_DATA *data) + { + ASN1_OBJECT_free(data->valid_policy); + /* Don't free qualifiers if shared */ + if (!(data->flags & POLICY_DATA_FLAG_SHARED_QUALIFIERS)) + sk_POLICYQUALINFO_pop_free(data->qualifier_set, + POLICYQUALINFO_free); + sk_ASN1_OBJECT_pop_free(data->expected_policy_set, ASN1_OBJECT_free); + OPENSSL_free(data); + } + +/* Create a data based on an existing policy. If 'id' is NULL use the + * oid in the policy, otherwise use 'id'. This behaviour covers the two + * types of data in RFC3280: data with from a CertificatePolcies extension + * and additional data with just the qualifiers of anyPolicy and ID from + * another source. + */ + +X509_POLICY_DATA *policy_data_new(POLICYINFO *policy, + const ASN1_OBJECT *cid, int crit) + { + X509_POLICY_DATA *ret; + ASN1_OBJECT *id; + if (!policy && !cid) + return NULL; + if (cid) + { + id = OBJ_dup(cid); + if (!id) + return NULL; + } + else + id = NULL; + ret = OPENSSL_malloc(sizeof(X509_POLICY_DATA)); + if (!ret) + return NULL; + ret->expected_policy_set = sk_ASN1_OBJECT_new_null(); + if (!ret->expected_policy_set) + { + OPENSSL_free(ret); + if (id) + ASN1_OBJECT_free(id); + return NULL; + } + + if (crit) + ret->flags = POLICY_DATA_FLAG_CRITICAL; + else + ret->flags = 0; + + if (id) + ret->valid_policy = id; + else + { + ret->valid_policy = policy->policyid; + policy->policyid = NULL; + } + + if (policy) + { + ret->qualifier_set = policy->qualifiers; + policy->qualifiers = NULL; + } + else + ret->qualifier_set = NULL; + + return ret; + } + diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_int.h b/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_int.h new file mode 100644 index 00000000..ccff9284 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_int.h @@ -0,0 +1,212 @@ +/* pcy_int.h */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2004. + */ +/* ==================================================================== + * Copyright (c) 2004 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + + +typedef struct X509_POLICY_DATA_st X509_POLICY_DATA; + +DECLARE_STACK_OF(X509_POLICY_DATA) + +/* Internal structures */ + +/* This structure and the field names correspond to the Policy 'node' of + * RFC3280. NB this structure contains no pointers to parent or child + * data: X509_POLICY_NODE contains that. This means that the main policy data + * can be kept static and cached with the certificate. + */ + +struct X509_POLICY_DATA_st + { + unsigned int flags; + /* Policy OID and qualifiers for this data */ + ASN1_OBJECT *valid_policy; + STACK_OF(POLICYQUALINFO) *qualifier_set; + STACK_OF(ASN1_OBJECT) *expected_policy_set; + }; + +/* X509_POLICY_DATA flags values */ + +/* This flag indicates the structure has been mapped using a policy mapping + * extension. If policy mapping is not active its references get deleted. + */ + +#define POLICY_DATA_FLAG_MAPPED 0x1 + +/* This flag indicates the data doesn't correspond to a policy in Certificate + * Policies: it has been mapped to any policy. + */ + +#define POLICY_DATA_FLAG_MAPPED_ANY 0x2 + +/* AND with flags to see if any mapping has occurred */ + +#define POLICY_DATA_FLAG_MAP_MASK 0x3 + +/* qualifiers are shared and shouldn't be freed */ + +#define POLICY_DATA_FLAG_SHARED_QUALIFIERS 0x4 + +/* Parent node is an extra node and should be freed */ + +#define POLICY_DATA_FLAG_EXTRA_NODE 0x8 + +/* Corresponding CertificatePolicies is critical */ + +#define POLICY_DATA_FLAG_CRITICAL 0x10 + +/* This structure is cached with a certificate */ + +struct X509_POLICY_CACHE_st { + /* anyPolicy data or NULL if no anyPolicy */ + X509_POLICY_DATA *anyPolicy; + /* other policy data */ + STACK_OF(X509_POLICY_DATA) *data; + /* If InhibitAnyPolicy present this is its value or -1 if absent. */ + long any_skip; + /* If policyConstraints and requireExplicitPolicy present this is its + * value or -1 if absent. + */ + long explicit_skip; + /* If policyConstraints and policyMapping present this is its + * value or -1 if absent. + */ + long map_skip; + }; + +/*#define POLICY_CACHE_FLAG_CRITICAL POLICY_DATA_FLAG_CRITICAL*/ + +/* This structure represents the relationship between nodes */ + +struct X509_POLICY_NODE_st + { + /* node data this refers to */ + const X509_POLICY_DATA *data; + /* Parent node */ + X509_POLICY_NODE *parent; + /* Number of child nodes */ + int nchild; + }; + +struct X509_POLICY_LEVEL_st + { + /* Cert for this level */ + X509 *cert; + /* nodes at this level */ + STACK_OF(X509_POLICY_NODE) *nodes; + /* anyPolicy node */ + X509_POLICY_NODE *anyPolicy; + /* Extra data */ + /*STACK_OF(X509_POLICY_DATA) *extra_data;*/ + unsigned int flags; + }; + +struct X509_POLICY_TREE_st + { + /* This is the tree 'level' data */ + X509_POLICY_LEVEL *levels; + int nlevel; + /* Extra policy data when additional nodes (not from the certificate) + * are required. + */ + STACK_OF(X509_POLICY_DATA) *extra_data; + /* This is the authority constained policy set */ + STACK_OF(X509_POLICY_NODE) *auth_policies; + STACK_OF(X509_POLICY_NODE) *user_policies; + unsigned int flags; + }; + +/* Set if anyPolicy present in user policies */ +#define POLICY_FLAG_ANY_POLICY 0x2 + +/* Useful macros */ + +#define node_data_critical(data) (data->flags & POLICY_DATA_FLAG_CRITICAL) +#define node_critical(node) node_data_critical(node->data) + +/* Internal functions */ + +X509_POLICY_DATA *policy_data_new(POLICYINFO *policy, const ASN1_OBJECT *id, + int crit); +void policy_data_free(X509_POLICY_DATA *data); + +X509_POLICY_DATA *policy_cache_find_data(const X509_POLICY_CACHE *cache, + const ASN1_OBJECT *id); +int policy_cache_set_mapping(X509 *x, POLICY_MAPPINGS *maps); + + +STACK_OF(X509_POLICY_NODE) *policy_node_cmp_new(void); + +void policy_cache_init(void); + +void policy_cache_free(X509_POLICY_CACHE *cache); + +X509_POLICY_NODE *level_find_node(const X509_POLICY_LEVEL *level, + const X509_POLICY_NODE *parent, + const ASN1_OBJECT *id); + +X509_POLICY_NODE *tree_find_sk(STACK_OF(X509_POLICY_NODE) *sk, + const ASN1_OBJECT *id); + +X509_POLICY_NODE *level_add_node(X509_POLICY_LEVEL *level, + const X509_POLICY_DATA *data, + X509_POLICY_NODE *parent, + X509_POLICY_TREE *tree); +void policy_node_free(X509_POLICY_NODE *node); +int policy_node_match(const X509_POLICY_LEVEL *lvl, + const X509_POLICY_NODE *node, const ASN1_OBJECT *oid); + +const X509_POLICY_CACHE *policy_cache_set(X509 *x); diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_lib.c b/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_lib.c new file mode 100644 index 00000000..16be2f00 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_lib.c @@ -0,0 +1,165 @@ +/* pcy_lib.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2004. + */ +/* ==================================================================== + * Copyright (c) 2004 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + + +#include +#include + +#include "pcy_int.h" + + +/* accessor functions */ + +/* X509_POLICY_TREE stuff */ + +int X509_policy_tree_level_count(const X509_POLICY_TREE *tree) + { + if (!tree) + return 0; + return tree->nlevel; + } + +X509_POLICY_LEVEL * + X509_policy_tree_get0_level(const X509_POLICY_TREE *tree, int i) + { + if (!tree || (i < 0) || (i >= tree->nlevel)) + return NULL; + return tree->levels + i; + } + +STACK_OF(X509_POLICY_NODE) * + X509_policy_tree_get0_policies(const X509_POLICY_TREE *tree) + { + if (!tree) + return NULL; + return tree->auth_policies; + } + +STACK_OF(X509_POLICY_NODE) * + X509_policy_tree_get0_user_policies(const X509_POLICY_TREE *tree) + { + if (!tree) + return NULL; + if (tree->flags & POLICY_FLAG_ANY_POLICY) + return tree->auth_policies; + else + return tree->user_policies; + } + +/* X509_POLICY_LEVEL stuff */ + +int X509_policy_level_node_count(X509_POLICY_LEVEL *level) + { + int n; + if (!level) + return 0; + if (level->anyPolicy) + n = 1; + else + n = 0; + if (level->nodes) + n += sk_X509_POLICY_NODE_num(level->nodes); + return n; + } + +X509_POLICY_NODE *X509_policy_level_get0_node(X509_POLICY_LEVEL *level, int i) + { + if (!level) + return NULL; + if (level->anyPolicy) + { + if (i == 0) + return level->anyPolicy; + i--; + } + return sk_X509_POLICY_NODE_value(level->nodes, i); + } + +/* X509_POLICY_NODE stuff */ + +const ASN1_OBJECT *X509_policy_node_get0_policy(const X509_POLICY_NODE *node) + { + if (!node) + return NULL; + return node->data->valid_policy; + } + +#if 0 +int X509_policy_node_get_critical(const X509_POLICY_NODE *node) + { + if (node_critical(node)) + return 1; + return 0; + } +#endif + +STACK_OF(POLICYQUALINFO) * + X509_policy_node_get0_qualifiers(const X509_POLICY_NODE *node) + { + if (!node) + return NULL; + return node->data->qualifier_set; + } + +const X509_POLICY_NODE * + X509_policy_node_get0_parent(const X509_POLICY_NODE *node) + { + if (!node) + return NULL; + return node->parent; + } + + diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_map.c b/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_map.c new file mode 100644 index 00000000..2b8307b1 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_map.c @@ -0,0 +1,133 @@ +/* pcy_map.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2004. + */ +/* ==================================================================== + * Copyright (c) 2004 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include +#include +#include + +#include "pcy_int.h" + + +/* Set policy mapping entries in cache. + * Note: this modifies the passed POLICY_MAPPINGS structure + */ + +int policy_cache_set_mapping(X509 *x, POLICY_MAPPINGS *maps) + { + POLICY_MAPPING *map; + X509_POLICY_DATA *data; + X509_POLICY_CACHE *cache = x->policy_cache; + size_t i; + int ret = 0; + if (sk_POLICY_MAPPING_num(maps) == 0) + { + ret = -1; + goto bad_mapping; + } + for (i = 0; i < sk_POLICY_MAPPING_num(maps); i++) + { + map = sk_POLICY_MAPPING_value(maps, i); + /* Reject if map to or from anyPolicy */ + if ((OBJ_obj2nid(map->subjectDomainPolicy) == NID_any_policy) + || (OBJ_obj2nid(map->issuerDomainPolicy) == NID_any_policy)) + { + ret = -1; + goto bad_mapping; + } + + /* Attempt to find matching policy data */ + data = policy_cache_find_data(cache, map->issuerDomainPolicy); + /* If we don't have anyPolicy can't map */ + if (!data && !cache->anyPolicy) + continue; + + /* Create a NODE from anyPolicy */ + if (!data) + { + data = policy_data_new(NULL, map->issuerDomainPolicy, + cache->anyPolicy->flags + & POLICY_DATA_FLAG_CRITICAL); + if (!data) + goto bad_mapping; + data->qualifier_set = cache->anyPolicy->qualifier_set; + /*map->issuerDomainPolicy = NULL;*/ + data->flags |= POLICY_DATA_FLAG_MAPPED_ANY; + data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS; + if (!sk_X509_POLICY_DATA_push(cache->data, data)) + { + policy_data_free(data); + goto bad_mapping; + } + } + else + data->flags |= POLICY_DATA_FLAG_MAPPED; + if (!sk_ASN1_OBJECT_push(data->expected_policy_set, + map->subjectDomainPolicy)) + goto bad_mapping; + map->subjectDomainPolicy = NULL; + + } + + ret = 1; + bad_mapping: + if (ret == -1) + x->ex_flags |= EXFLAG_INVALID_POLICY; + sk_POLICY_MAPPING_pop_free(maps, POLICY_MAPPING_free); + return ret; + + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_node.c b/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_node.c new file mode 100644 index 00000000..55cc2039 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_node.c @@ -0,0 +1,197 @@ +/* pcy_node.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2004. + */ +/* ==================================================================== + * Copyright (c) 2004 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include +#include +#include +#include +#include + +#include "pcy_int.h" + + +static int node_cmp(const X509_POLICY_NODE **a, + const X509_POLICY_NODE **b) + { + return OBJ_cmp((*a)->data->valid_policy, (*b)->data->valid_policy); + } + +STACK_OF(X509_POLICY_NODE) *policy_node_cmp_new(void) + { + return sk_X509_POLICY_NODE_new(node_cmp); + } + +X509_POLICY_NODE *tree_find_sk(STACK_OF(X509_POLICY_NODE) *nodes, + const ASN1_OBJECT *id) + { + X509_POLICY_DATA n; + X509_POLICY_NODE l; + size_t idx; + + n.valid_policy = (ASN1_OBJECT *)id; + l.data = &n; + + if (!sk_X509_POLICY_NODE_find(nodes, &idx, &l)) + return NULL; + + return sk_X509_POLICY_NODE_value(nodes, idx); + + } + +X509_POLICY_NODE *level_find_node(const X509_POLICY_LEVEL *level, + const X509_POLICY_NODE *parent, + const ASN1_OBJECT *id) + { + X509_POLICY_NODE *node; + size_t i; + for (i = 0; i < sk_X509_POLICY_NODE_num(level->nodes); i++) + { + node = sk_X509_POLICY_NODE_value(level->nodes, i); + if (node->parent == parent) + { + if (!OBJ_cmp(node->data->valid_policy, id)) + return node; + } + } + return NULL; + } + +X509_POLICY_NODE *level_add_node(X509_POLICY_LEVEL *level, + const X509_POLICY_DATA *data, + X509_POLICY_NODE *parent, + X509_POLICY_TREE *tree) + { + X509_POLICY_NODE *node; + node = OPENSSL_malloc(sizeof(X509_POLICY_NODE)); + if (!node) + return NULL; + node->data = data; + node->parent = parent; + node->nchild = 0; + if (level) + { + if (OBJ_obj2nid(data->valid_policy) == NID_any_policy) + { + if (level->anyPolicy) + goto node_error; + level->anyPolicy = node; + } + else + { + + if (!level->nodes) + level->nodes = policy_node_cmp_new(); + if (!level->nodes) + goto node_error; + if (!sk_X509_POLICY_NODE_push(level->nodes, node)) + goto node_error; + } + } + + if (tree) + { + if (!tree->extra_data) + tree->extra_data = sk_X509_POLICY_DATA_new_null(); + if (!tree->extra_data) + goto node_error; + if (!sk_X509_POLICY_DATA_push(tree->extra_data, data)) + goto node_error; + } + + if (parent) + parent->nchild++; + + return node; + + node_error: + policy_node_free(node); + return 0; + + } + +void policy_node_free(X509_POLICY_NODE *node) + { + OPENSSL_free(node); + } + +/* See if a policy node matches a policy OID. If mapping enabled look through + * expected policy set otherwise just valid policy. + */ + +int policy_node_match(const X509_POLICY_LEVEL *lvl, + const X509_POLICY_NODE *node, const ASN1_OBJECT *oid) + { + size_t i; + ASN1_OBJECT *policy_oid; + const X509_POLICY_DATA *x = node->data; + + if ( (lvl->flags & X509_V_FLAG_INHIBIT_MAP) + || !(x->flags & POLICY_DATA_FLAG_MAP_MASK)) + { + if (!OBJ_cmp(x->valid_policy, oid)) + return 1; + return 0; + } + + for (i = 0; i < sk_ASN1_OBJECT_num(x->expected_policy_set); i++) + { + policy_oid = sk_ASN1_OBJECT_value(x->expected_policy_set, i); + if (!OBJ_cmp(policy_oid, oid)) + return 1; + } + return 0; + + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_tree.c b/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_tree.c new file mode 100644 index 00000000..682474d8 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_tree.c @@ -0,0 +1,876 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2004. + */ +/* ==================================================================== + * Copyright (c) 2004 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "pcy_int.h" + + +/* Enable this to print out the complete policy tree at various point during + * evaluation. + */ + +/*#define OPENSSL_POLICY_DEBUG*/ + +#ifdef OPENSSL_POLICY_DEBUG + +static void expected_print(BIO *err, X509_POLICY_LEVEL *lev, + X509_POLICY_NODE *node, int indent) + { + if ( (lev->flags & X509_V_FLAG_INHIBIT_MAP) + || !(node->data->flags & POLICY_DATA_FLAG_MAP_MASK)) + BIO_puts(err, " Not Mapped\n"); + else + { + int i; + STACK_OF(ASN1_OBJECT) *pset = node->data->expected_policy_set; + ASN1_OBJECT *oid; + BIO_puts(err, " Expected: "); + for (i = 0; i < sk_ASN1_OBJECT_num(pset); i++) + { + oid = sk_ASN1_OBJECT_value(pset, i); + if (i) + BIO_puts(err, ", "); + i2a_ASN1_OBJECT(err, oid); + } + BIO_puts(err, "\n"); + } + } + +static void tree_print(char *str, X509_POLICY_TREE *tree, + X509_POLICY_LEVEL *curr) + { + X509_POLICY_LEVEL *plev; + X509_POLICY_NODE *node; + int i; + BIO *err; + err = BIO_new_fp(stderr, BIO_NOCLOSE); + if (!curr) + curr = tree->levels + tree->nlevel; + else + curr++; + BIO_printf(err, "Level print after %s\n", str); + BIO_printf(err, "Printing Up to Level %ld\n", curr - tree->levels); + for (plev = tree->levels; plev != curr; plev++) + { + BIO_printf(err, "Level %ld, flags = %x\n", + plev - tree->levels, plev->flags); + for (i = 0; i < sk_X509_POLICY_NODE_num(plev->nodes); i++) + { + node = sk_X509_POLICY_NODE_value(plev->nodes, i); + X509_POLICY_NODE_print(err, node, 2); + expected_print(err, plev, node, 2); + BIO_printf(err, " Flags: %x\n", node->data->flags); + } + if (plev->anyPolicy) + X509_POLICY_NODE_print(err, plev->anyPolicy, 2); + } + + BIO_free(err); + + } +#else + +#define tree_print(a,b,c) /* */ + +#endif + +/* Initialize policy tree. Return values: + * 0 Some internal error occured. + * -1 Inconsistent or invalid extensions in certificates. + * 1 Tree initialized OK. + * 2 Policy tree is empty. + * 5 Tree OK and requireExplicitPolicy true. + * 6 Tree empty and requireExplicitPolicy true. + */ + +static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs, + unsigned int flags) + { + X509_POLICY_TREE *tree; + X509_POLICY_LEVEL *level; + const X509_POLICY_CACHE *cache; + X509_POLICY_DATA *data = NULL; + X509 *x; + int ret = 1; + int i, n; + int explicit_policy; + int any_skip; + int map_skip; + *ptree = NULL; + n = sk_X509_num(certs); + +#if 0 + /* Disable policy mapping for now... */ + flags |= X509_V_FLAG_INHIBIT_MAP; +#endif + + if (flags & X509_V_FLAG_EXPLICIT_POLICY) + explicit_policy = 0; + else + explicit_policy = n + 1; + + if (flags & X509_V_FLAG_INHIBIT_ANY) + any_skip = 0; + else + any_skip = n + 1; + + if (flags & X509_V_FLAG_INHIBIT_MAP) + map_skip = 0; + else + map_skip = n + 1; + + /* Can't do anything with just a trust anchor */ + if (n == 1) + return 1; + /* First setup policy cache in all certificates apart from the + * trust anchor. Note any bad cache results on the way. Also can + * calculate explicit_policy value at this point. + */ + for (i = n - 2; i >= 0; i--) + { + x = sk_X509_value(certs, i); + X509_check_purpose(x, -1, -1); + cache = policy_cache_set(x); + /* If cache NULL something bad happened: return immediately */ + if (cache == NULL) + return 0; + /* If inconsistent extensions keep a note of it but continue */ + if (x->ex_flags & EXFLAG_INVALID_POLICY) + ret = -1; + /* Otherwise if we have no data (hence no CertificatePolicies) + * and haven't already set an inconsistent code note it. + */ + else if ((ret == 1) && !cache->data) + ret = 2; + if (explicit_policy > 0) + { + if (!(x->ex_flags & EXFLAG_SI)) + explicit_policy--; + if ((cache->explicit_skip != -1) + && (cache->explicit_skip < explicit_policy)) + explicit_policy = cache->explicit_skip; + } + } + + if (ret != 1) + { + if (ret == 2 && !explicit_policy) + return 6; + return ret; + } + + + /* If we get this far initialize the tree */ + + tree = OPENSSL_malloc(sizeof(X509_POLICY_TREE)); + + if (!tree) + return 0; + + tree->flags = 0; + tree->levels = OPENSSL_malloc(sizeof(X509_POLICY_LEVEL) * n); + tree->nlevel = 0; + tree->extra_data = NULL; + tree->auth_policies = NULL; + tree->user_policies = NULL; + + if (!tree->levels) + { + OPENSSL_free(tree); + return 0; + } + + memset(tree->levels, 0, n * sizeof(X509_POLICY_LEVEL)); + + tree->nlevel = n; + + level = tree->levels; + + /* Root data: initialize to anyPolicy */ + + data = policy_data_new(NULL, OBJ_nid2obj(NID_any_policy), 0); + + if (!data || !level_add_node(level, data, NULL, tree)) + goto bad_tree; + + for (i = n - 2; i >= 0; i--) + { + level++; + x = sk_X509_value(certs, i); + cache = policy_cache_set(x); + level->cert = X509_up_ref(x); + + if (!cache->anyPolicy) + level->flags |= X509_V_FLAG_INHIBIT_ANY; + + /* Determine inhibit any and inhibit map flags */ + if (any_skip == 0) + { + /* Any matching allowed if certificate is self + * issued and not the last in the chain. + */ + if (!(x->ex_flags & EXFLAG_SI) || (i == 0)) + level->flags |= X509_V_FLAG_INHIBIT_ANY; + } + else + { + if (!(x->ex_flags & EXFLAG_SI)) + any_skip--; + if ((cache->any_skip >= 0) + && (cache->any_skip < any_skip)) + any_skip = cache->any_skip; + } + + if (map_skip == 0) + level->flags |= X509_V_FLAG_INHIBIT_MAP; + else + { + if (!(x->ex_flags & EXFLAG_SI)) + map_skip--; + if ((cache->map_skip >= 0) + && (cache->map_skip < map_skip)) + map_skip = cache->map_skip; + } + + } + + *ptree = tree; + + if (explicit_policy) + return 1; + else + return 5; + + bad_tree: + + X509_policy_tree_free(tree); + + return 0; + + } + +static int tree_link_matching_nodes(X509_POLICY_LEVEL *curr, + const X509_POLICY_DATA *data) + { + X509_POLICY_LEVEL *last = curr - 1; + X509_POLICY_NODE *node; + int matched = 0; + size_t i; + /* Iterate through all in nodes linking matches */ + for (i = 0; i < sk_X509_POLICY_NODE_num(last->nodes); i++) + { + node = sk_X509_POLICY_NODE_value(last->nodes, i); + if (policy_node_match(last, node, data->valid_policy)) + { + if (!level_add_node(curr, data, node, NULL)) + return 0; + matched = 1; + } + } + if (!matched && last->anyPolicy) + { + if (!level_add_node(curr, data, last->anyPolicy, NULL)) + return 0; + } + return 1; + } + +/* This corresponds to RFC3280 6.1.3(d)(1): + * link any data from CertificatePolicies onto matching parent + * or anyPolicy if no match. + */ + +static int tree_link_nodes(X509_POLICY_LEVEL *curr, + const X509_POLICY_CACHE *cache) + { + size_t i; + X509_POLICY_DATA *data; + + for (i = 0; i < sk_X509_POLICY_DATA_num(cache->data); i++) + { + data = sk_X509_POLICY_DATA_value(cache->data, i); + /* If a node is mapped any it doesn't have a corresponding + * CertificatePolicies entry. + * However such an identical node would be created + * if anyPolicy matching is enabled because there would be + * no match with the parent valid_policy_set. So we create + * link because then it will have the mapping flags + * right and we can prune it later. + */ +#if 0 + if ((data->flags & POLICY_DATA_FLAG_MAPPED_ANY) + && !(curr->flags & X509_V_FLAG_INHIBIT_ANY)) + continue; +#endif + /* Look for matching nodes in previous level */ + if (!tree_link_matching_nodes(curr, data)) + return 0; + } + return 1; + } + +/* This corresponds to RFC3280 6.1.3(d)(2): + * Create new data for any unmatched policies in the parent and link + * to anyPolicy. + */ + +static int tree_add_unmatched(X509_POLICY_LEVEL *curr, + const X509_POLICY_CACHE *cache, + const ASN1_OBJECT *id, + X509_POLICY_NODE *node, + X509_POLICY_TREE *tree) + { + X509_POLICY_DATA *data; + if (id == NULL) + id = node->data->valid_policy; + /* Create a new node with qualifiers from anyPolicy and + * id from unmatched node. + */ + data = policy_data_new(NULL, id, node_critical(node)); + + if (data == NULL) + return 0; + /* Curr may not have anyPolicy */ + data->qualifier_set = cache->anyPolicy->qualifier_set; + data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS; + if (!level_add_node(curr, data, node, tree)) + { + policy_data_free(data); + return 0; + } + + return 1; + } + +static int tree_link_unmatched(X509_POLICY_LEVEL *curr, + const X509_POLICY_CACHE *cache, + X509_POLICY_NODE *node, + X509_POLICY_TREE *tree) + { + const X509_POLICY_LEVEL *last = curr - 1; + size_t i; + + if ( (last->flags & X509_V_FLAG_INHIBIT_MAP) + || !(node->data->flags & POLICY_DATA_FLAG_MAPPED)) + { + /* If no policy mapping: matched if one child present */ + if (node->nchild) + return 1; + if (!tree_add_unmatched(curr, cache, NULL, node, tree)) + return 0; + /* Add it */ + } + else + { + /* If mapping: matched if one child per expected policy set */ + STACK_OF(ASN1_OBJECT) *expset = node->data->expected_policy_set; + if (node->nchild == sk_ASN1_OBJECT_num(expset)) + return 1; + /* Locate unmatched nodes */ + for (i = 0; i < sk_ASN1_OBJECT_num(expset); i++) + { + ASN1_OBJECT *oid = sk_ASN1_OBJECT_value(expset, i); + if (level_find_node(curr, node, oid)) + continue; + if (!tree_add_unmatched(curr, cache, oid, node, tree)) + return 0; + } + + } + + return 1; + + } + +static int tree_link_any(X509_POLICY_LEVEL *curr, + const X509_POLICY_CACHE *cache, + X509_POLICY_TREE *tree) + { + size_t i; + /*X509_POLICY_DATA *data;*/ + X509_POLICY_NODE *node; + X509_POLICY_LEVEL *last = curr - 1; + + for (i = 0; i < sk_X509_POLICY_NODE_num(last->nodes); i++) + { + node = sk_X509_POLICY_NODE_value(last->nodes, i); + + if (!tree_link_unmatched(curr, cache, node, tree)) + return 0; + +#if 0 + + /* Skip any node with any children: we only want unmathced + * nodes. + * + * Note: need something better for policy mapping + * because each node may have multiple children + */ + if (node->nchild) + continue; + + /* Create a new node with qualifiers from anyPolicy and + * id from unmatched node. + */ + data = policy_data_new(NULL, node->data->valid_policy, + node_critical(node)); + + if (data == NULL) + return 0; + /* Curr may not have anyPolicy */ + data->qualifier_set = cache->anyPolicy->qualifier_set; + data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS; + if (!level_add_node(curr, data, node, tree)) + { + policy_data_free(data); + return 0; + } + +#endif + + } + /* Finally add link to anyPolicy */ + if (last->anyPolicy) + { + if (!level_add_node(curr, cache->anyPolicy, + last->anyPolicy, NULL)) + return 0; + } + return 1; + } + +/* Prune the tree: delete any child mapped child data on the current level + * then proceed up the tree deleting any data with no children. If we ever + * have no data on a level we can halt because the tree will be empty. + */ + +static int tree_prune(X509_POLICY_TREE *tree, X509_POLICY_LEVEL *curr) + { + STACK_OF(X509_POLICY_NODE) *nodes; + X509_POLICY_NODE *node; + int i; + nodes = curr->nodes; + if (curr->flags & X509_V_FLAG_INHIBIT_MAP) + { + for (i = sk_X509_POLICY_NODE_num(nodes) - 1; i >= 0; i--) + { + node = sk_X509_POLICY_NODE_value(nodes, i); + /* Delete any mapped data: see RFC3280 XXXX */ + if (node->data->flags & POLICY_DATA_FLAG_MAP_MASK) + { + node->parent->nchild--; + OPENSSL_free(node); + (void)sk_X509_POLICY_NODE_delete(nodes,i); + } + } + } + + for(;;) { + --curr; + nodes = curr->nodes; + for (i = sk_X509_POLICY_NODE_num(nodes) - 1; i >= 0; i--) + { + node = sk_X509_POLICY_NODE_value(nodes, i); + if (node->nchild == 0) + { + node->parent->nchild--; + OPENSSL_free(node); + (void)sk_X509_POLICY_NODE_delete(nodes, i); + } + } + if (curr->anyPolicy && !curr->anyPolicy->nchild) + { + if (curr->anyPolicy->parent) + curr->anyPolicy->parent->nchild--; + OPENSSL_free(curr->anyPolicy); + curr->anyPolicy = NULL; + } + if (curr == tree->levels) + { + /* If we zapped anyPolicy at top then tree is empty */ + if (!curr->anyPolicy) + return 2; + return 1; + } + } + + } + +static int tree_add_auth_node(STACK_OF(X509_POLICY_NODE) **pnodes, + X509_POLICY_NODE *pcy) + { + if (!*pnodes) + { + *pnodes = policy_node_cmp_new(); + if (!*pnodes) + return 0; + } + else if (sk_X509_POLICY_NODE_find(*pnodes, NULL, pcy)) + return 1; + + if (!sk_X509_POLICY_NODE_push(*pnodes, pcy)) + return 0; + + return 1; + + } + +/* Calculate the authority set based on policy tree. + * The 'pnodes' parameter is used as a store for the set of policy nodes + * used to calculate the user set. If the authority set is not anyPolicy + * then pnodes will just point to the authority set. If however the authority + * set is anyPolicy then the set of valid policies (other than anyPolicy) + * is store in pnodes. The return value of '2' is used in this case to indicate + * that pnodes should be freed. + */ + +static int tree_calculate_authority_set(X509_POLICY_TREE *tree, + STACK_OF(X509_POLICY_NODE) **pnodes) + { + X509_POLICY_LEVEL *curr; + X509_POLICY_NODE *node, *anyptr; + STACK_OF(X509_POLICY_NODE) **addnodes; + int i; + size_t j; + curr = tree->levels + tree->nlevel - 1; + + /* If last level contains anyPolicy set is anyPolicy */ + if (curr->anyPolicy) + { + if (!tree_add_auth_node(&tree->auth_policies, curr->anyPolicy)) + return 0; + addnodes = pnodes; + } + else + /* Add policies to authority set */ + addnodes = &tree->auth_policies; + + curr = tree->levels; + for (i = 1; i < tree->nlevel; i++) + { + /* If no anyPolicy node on this this level it can't + * appear on lower levels so end search. + */ + if (!(anyptr = curr->anyPolicy)) + break; + curr++; + for (j = 0; j < sk_X509_POLICY_NODE_num(curr->nodes); j++) + { + node = sk_X509_POLICY_NODE_value(curr->nodes, j); + if ((node->parent == anyptr) + && !tree_add_auth_node(addnodes, node)) + return 0; + } + } + + if (addnodes == pnodes) + return 2; + + *pnodes = tree->auth_policies; + + return 1; + } + +static int tree_calculate_user_set(X509_POLICY_TREE *tree, + STACK_OF(ASN1_OBJECT) *policy_oids, + STACK_OF(X509_POLICY_NODE) *auth_nodes) + { + size_t i; + X509_POLICY_NODE *node; + ASN1_OBJECT *oid; + + X509_POLICY_NODE *anyPolicy; + X509_POLICY_DATA *extra; + + /* Check if anyPolicy present in authority constrained policy set: + * this will happen if it is a leaf node. + */ + + if (sk_ASN1_OBJECT_num(policy_oids) <= 0) + return 1; + + anyPolicy = tree->levels[tree->nlevel - 1].anyPolicy; + + for (i = 0; i < sk_ASN1_OBJECT_num(policy_oids); i++) + { + oid = sk_ASN1_OBJECT_value(policy_oids, i); + if (OBJ_obj2nid(oid) == NID_any_policy) + { + tree->flags |= POLICY_FLAG_ANY_POLICY; + return 1; + } + } + + for (i = 0; i < sk_ASN1_OBJECT_num(policy_oids); i++) + { + oid = sk_ASN1_OBJECT_value(policy_oids, i); + node = tree_find_sk(auth_nodes, oid); + if (!node) + { + if (!anyPolicy) + continue; + /* Create a new node with policy ID from user set + * and qualifiers from anyPolicy. + */ + extra = policy_data_new(NULL, oid, + node_critical(anyPolicy)); + if (!extra) + return 0; + extra->qualifier_set = anyPolicy->data->qualifier_set; + extra->flags = POLICY_DATA_FLAG_SHARED_QUALIFIERS + | POLICY_DATA_FLAG_EXTRA_NODE; + node = level_add_node(NULL, extra, anyPolicy->parent, + tree); + } + if (!tree->user_policies) + { + tree->user_policies = sk_X509_POLICY_NODE_new_null(); + if (!tree->user_policies) + return 1; + } + if (!sk_X509_POLICY_NODE_push(tree->user_policies, node)) + return 0; + } + return 1; + + } + +static int tree_evaluate(X509_POLICY_TREE *tree) + { + int ret, i; + X509_POLICY_LEVEL *curr = tree->levels + 1; + const X509_POLICY_CACHE *cache; + + for(i = 1; i < tree->nlevel; i++, curr++) + { + cache = policy_cache_set(curr->cert); + if (!tree_link_nodes(curr, cache)) + return 0; + + if (!(curr->flags & X509_V_FLAG_INHIBIT_ANY) + && !tree_link_any(curr, cache, tree)) + return 0; + tree_print("before tree_prune()", tree, curr); + ret = tree_prune(tree, curr); + if (ret != 1) + return ret; + } + + return 1; + + } + +static void exnode_free(X509_POLICY_NODE *node) + { + if (node->data && (node->data->flags & POLICY_DATA_FLAG_EXTRA_NODE)) + OPENSSL_free(node); + } + + +void X509_policy_tree_free(X509_POLICY_TREE *tree) + { + X509_POLICY_LEVEL *curr; + int i; + + if (!tree) + return; + + sk_X509_POLICY_NODE_free(tree->auth_policies); + sk_X509_POLICY_NODE_pop_free(tree->user_policies, exnode_free); + + for(i = 0, curr = tree->levels; i < tree->nlevel; i++, curr++) + { + if (curr->cert) + X509_free(curr->cert); + if (curr->nodes) + sk_X509_POLICY_NODE_pop_free(curr->nodes, + policy_node_free); + if (curr->anyPolicy) + policy_node_free(curr->anyPolicy); + } + + if (tree->extra_data) + sk_X509_POLICY_DATA_pop_free(tree->extra_data, + policy_data_free); + + OPENSSL_free(tree->levels); + OPENSSL_free(tree); + + } + +/* Application policy checking function. + * Return codes: + * 0 Internal Error. + * 1 Successful. + * -1 One or more certificates contain invalid or inconsistent extensions + * -2 User constrained policy set empty and requireExplicit true. + */ + +int X509_policy_check(X509_POLICY_TREE **ptree, int *pexplicit_policy, + STACK_OF(X509) *certs, + STACK_OF(ASN1_OBJECT) *policy_oids, + unsigned int flags) + { + int ret; + X509_POLICY_TREE *tree = NULL; + STACK_OF(X509_POLICY_NODE) *nodes, *auth_nodes = NULL; + *ptree = NULL; + + *pexplicit_policy = 0; + ret = tree_init(&tree, certs, flags); + + switch (ret) + { + + /* Tree empty requireExplicit False: OK */ + case 2: + return 1; + + /* Some internal error */ + case -1: + return -1; + + /* Some internal error */ + case 0: + return 0; + + /* Tree empty requireExplicit True: Error */ + + case 6: + *pexplicit_policy = 1; + return -2; + + /* Tree OK requireExplicit True: OK and continue */ + case 5: + *pexplicit_policy = 1; + break; + + /* Tree OK: continue */ + + case 1: + if (!tree) + /* + * tree_init() returns success and a null tree + * if it's just looking at a trust anchor. + * I'm not sure that returning success here is + * correct, but I'm sure that reporting this + * as an internal error which our caller + * interprets as a malloc failure is wrong. + */ + return 1; + break; + } + + if (!tree) goto error; + ret = tree_evaluate(tree); + + tree_print("tree_evaluate()", tree, NULL); + + if (ret <= 0) + goto error; + + /* Return value 2 means tree empty */ + if (ret == 2) + { + X509_policy_tree_free(tree); + if (*pexplicit_policy) + return -2; + else + return 1; + } + + /* Tree is not empty: continue */ + + ret = tree_calculate_authority_set(tree, &auth_nodes); + + if (!ret) + goto error; + + if (!tree_calculate_user_set(tree, policy_oids, auth_nodes)) + goto error; + + if (ret == 2) + sk_X509_POLICY_NODE_free(auth_nodes); + + if (tree) + *ptree = tree; + + if (*pexplicit_policy) + { + nodes = X509_policy_tree_get0_user_policies(tree); + if (sk_X509_POLICY_NODE_num(nodes) <= 0) + return -2; + } + + return 1; + + error: + + X509_policy_tree_free(tree); + + return 0; + + } + diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_akey.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_akey.c new file mode 100644 index 00000000..9578a570 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_akey.c @@ -0,0 +1,212 @@ +/* v3_akey.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +static STACK_OF(CONF_VALUE) *i2v_AUTHORITY_KEYID(X509V3_EXT_METHOD *method, + AUTHORITY_KEYID *akeyid, STACK_OF(CONF_VALUE) *extlist); +static AUTHORITY_KEYID *v2i_AUTHORITY_KEYID(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *values); + +const X509V3_EXT_METHOD v3_akey_id = + { + NID_authority_key_identifier, + X509V3_EXT_MULTILINE, ASN1_ITEM_ref(AUTHORITY_KEYID), + 0,0,0,0, + 0,0, + (X509V3_EXT_I2V)i2v_AUTHORITY_KEYID, + (X509V3_EXT_V2I)v2i_AUTHORITY_KEYID, + 0,0, + NULL + }; + +static STACK_OF(CONF_VALUE) *i2v_AUTHORITY_KEYID(X509V3_EXT_METHOD *method, + AUTHORITY_KEYID *akeyid, STACK_OF(CONF_VALUE) *extlist) +{ + char *tmp; + if(akeyid->keyid) { + tmp = hex_to_string(akeyid->keyid->data, akeyid->keyid->length); + X509V3_add_value("keyid", tmp, &extlist); + OPENSSL_free(tmp); + } + if(akeyid->issuer) + extlist = i2v_GENERAL_NAMES(NULL, akeyid->issuer, extlist); + if(akeyid->serial) { + tmp = hex_to_string(akeyid->serial->data, + akeyid->serial->length); + X509V3_add_value("serial", tmp, &extlist); + OPENSSL_free(tmp); + } + return extlist; +} + +/* Currently two options: + * keyid: use the issuers subject keyid, the value 'always' means its is + * an error if the issuer certificate doesn't have a key id. + * issuer: use the issuers cert issuer and serial number. The default is + * to only use this if keyid is not present. With the option 'always' + * this is always included. + */ + +static AUTHORITY_KEYID *v2i_AUTHORITY_KEYID(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *values) + { + char keyid=0, issuer=0; + size_t i; + int j; + CONF_VALUE *cnf; + ASN1_OCTET_STRING *ikeyid = NULL; + X509_NAME *isname = NULL; + GENERAL_NAMES * gens = NULL; + GENERAL_NAME *gen = NULL; + ASN1_INTEGER *serial = NULL; + X509_EXTENSION *ext; + X509 *cert; + AUTHORITY_KEYID *akeyid; + + for(i = 0; i < sk_CONF_VALUE_num(values); i++) + { + cnf = sk_CONF_VALUE_value(values, i); + if(!strcmp(cnf->name, "keyid")) + { + keyid = 1; + if(cnf->value && !strcmp(cnf->value, "always")) + keyid = 2; + } + else if(!strcmp(cnf->name, "issuer")) + { + issuer = 1; + if(cnf->value && !strcmp(cnf->value, "always")) + issuer = 2; + } + else + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNKNOWN_OPTION); + ERR_add_error_data(2, "name=", cnf->name); + return NULL; + } + } + + if(!ctx || !ctx->issuer_cert) + { + if(ctx && (ctx->flags==CTX_TEST)) + return AUTHORITY_KEYID_new(); + OPENSSL_PUT_ERROR(X509V3, X509V3_R_NO_ISSUER_CERTIFICATE); + return NULL; + } + + cert = ctx->issuer_cert; + + if(keyid) + { + j = X509_get_ext_by_NID(cert, NID_subject_key_identifier, -1); + if((j >= 0) && (ext = X509_get_ext(cert, j))) + ikeyid = X509V3_EXT_d2i(ext); + if(keyid==2 && !ikeyid) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNABLE_TO_GET_ISSUER_KEYID); + return NULL; + } + } + + if((issuer && !ikeyid) || (issuer == 2)) + { + isname = X509_NAME_dup(X509_get_issuer_name(cert)); + serial = M_ASN1_INTEGER_dup(X509_get_serialNumber(cert)); + if(!isname || !serial) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS); + goto err; + } + } + + if(!(akeyid = AUTHORITY_KEYID_new())) goto err; + + if(isname) + { + if(!(gens = sk_GENERAL_NAME_new_null()) + || !(gen = GENERAL_NAME_new()) + || !sk_GENERAL_NAME_push(gens, gen)) + { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + goto err; + } + gen->type = GEN_DIRNAME; + gen->d.dirn = isname; + } + + akeyid->issuer = gens; + akeyid->serial = serial; + akeyid->keyid = ikeyid; + + return akeyid; + + err: + X509_NAME_free(isname); + M_ASN1_INTEGER_free(serial); + M_ASN1_OCTET_STRING_free(ikeyid); + return NULL; + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_akeya.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_akeya.c new file mode 100644 index 00000000..8b72cca2 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_akeya.c @@ -0,0 +1,71 @@ +/* v3_akey_asn1.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include +#include + + +ASN1_SEQUENCE(AUTHORITY_KEYID) = { + ASN1_IMP_OPT(AUTHORITY_KEYID, keyid, ASN1_OCTET_STRING, 0), + ASN1_IMP_SEQUENCE_OF_OPT(AUTHORITY_KEYID, issuer, GENERAL_NAME, 1), + ASN1_IMP_OPT(AUTHORITY_KEYID, serial, ASN1_INTEGER, 2) +} ASN1_SEQUENCE_END(AUTHORITY_KEYID) + +IMPLEMENT_ASN1_FUNCTIONS(AUTHORITY_KEYID) diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_alt.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_alt.c new file mode 100644 index 00000000..e639f458 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_alt.c @@ -0,0 +1,620 @@ +/* v3_alt.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 1999-2003 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include +#include + +#include +#include +#include +#include +#include + + +static GENERAL_NAMES *v2i_subject_alt(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval); +static GENERAL_NAMES *v2i_issuer_alt(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval); +static int copy_email(X509V3_CTX *ctx, GENERAL_NAMES *gens, int move_p); +static int copy_issuer(X509V3_CTX *ctx, GENERAL_NAMES *gens); +static int do_othername(GENERAL_NAME *gen, char *value, X509V3_CTX *ctx); +static int do_dirname(GENERAL_NAME *gen, char *value, X509V3_CTX *ctx); + +const X509V3_EXT_METHOD v3_alt[] = { +{ NID_subject_alt_name, 0, ASN1_ITEM_ref(GENERAL_NAMES), +0,0,0,0, +0,0, +(X509V3_EXT_I2V)i2v_GENERAL_NAMES, +(X509V3_EXT_V2I)v2i_subject_alt, +NULL, NULL, NULL}, + +{ NID_issuer_alt_name, 0, ASN1_ITEM_ref(GENERAL_NAMES), +0,0,0,0, +0,0, +(X509V3_EXT_I2V)i2v_GENERAL_NAMES, +(X509V3_EXT_V2I)v2i_issuer_alt, +NULL, NULL, NULL}, + +{ NID_certificate_issuer, 0, ASN1_ITEM_ref(GENERAL_NAMES), +0,0,0,0, +0,0, +(X509V3_EXT_I2V)i2v_GENERAL_NAMES, +NULL, NULL, NULL, NULL}, +}; + +STACK_OF(CONF_VALUE) *i2v_GENERAL_NAMES(X509V3_EXT_METHOD *method, + GENERAL_NAMES *gens, STACK_OF(CONF_VALUE) *ret) +{ + size_t i; + GENERAL_NAME *gen; + for(i = 0; i < sk_GENERAL_NAME_num(gens); i++) { + gen = sk_GENERAL_NAME_value(gens, i); + ret = i2v_GENERAL_NAME(method, gen, ret); + } + if(!ret) return sk_CONF_VALUE_new_null(); + return ret; +} + +STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method, + GENERAL_NAME *gen, STACK_OF(CONF_VALUE) *ret) +{ + unsigned char *p; + char oline[256], htmp[5]; + int i; + switch (gen->type) + { + case GEN_OTHERNAME: + X509V3_add_value("othername","", &ret); + break; + + case GEN_X400: + X509V3_add_value("X400Name","", &ret); + break; + + case GEN_EDIPARTY: + X509V3_add_value("EdiPartyName","", &ret); + break; + + case GEN_EMAIL: + X509V3_add_value_uchar("email",gen->d.ia5->data, &ret); + break; + + case GEN_DNS: + X509V3_add_value_uchar("DNS",gen->d.ia5->data, &ret); + break; + + case GEN_URI: + X509V3_add_value_uchar("URI",gen->d.ia5->data, &ret); + break; + + case GEN_DIRNAME: + X509_NAME_oneline(gen->d.dirn, oline, 256); + X509V3_add_value("DirName",oline, &ret); + break; + + case GEN_IPADD: + p = gen->d.ip->data; + if(gen->d.ip->length == 4) + BIO_snprintf(oline, sizeof oline, + "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); + else if(gen->d.ip->length == 16) + { + oline[0] = 0; + for (i = 0; i < 8; i++) + { + BIO_snprintf(htmp, sizeof htmp, + "%X", p[0] << 8 | p[1]); + p += 2; + strcat(oline, htmp); + if (i != 7) + strcat(oline, ":"); + } + } + else + { + X509V3_add_value("IP Address","", &ret); + break; + } + X509V3_add_value("IP Address",oline, &ret); + break; + + case GEN_RID: + i2t_ASN1_OBJECT(oline, 256, gen->d.rid); + X509V3_add_value("Registered ID",oline, &ret); + break; + } + return ret; +} + +int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen) +{ + unsigned char *p; + int i; + switch (gen->type) + { + case GEN_OTHERNAME: + BIO_printf(out, "othername:"); + break; + + case GEN_X400: + BIO_printf(out, "X400Name:"); + break; + + case GEN_EDIPARTY: + /* Maybe fix this: it is supported now */ + BIO_printf(out, "EdiPartyName:"); + break; + + case GEN_EMAIL: + BIO_printf(out, "email:%s",gen->d.ia5->data); + break; + + case GEN_DNS: + BIO_printf(out, "DNS:%s",gen->d.ia5->data); + break; + + case GEN_URI: + BIO_printf(out, "URI:%s",gen->d.ia5->data); + break; + + case GEN_DIRNAME: + BIO_printf(out, "DirName: "); + X509_NAME_print_ex(out, gen->d.dirn, 0, XN_FLAG_ONELINE); + break; + + case GEN_IPADD: + p = gen->d.ip->data; + if(gen->d.ip->length == 4) + BIO_printf(out, "IP Address:%d.%d.%d.%d", + p[0], p[1], p[2], p[3]); + else if(gen->d.ip->length == 16) + { + BIO_printf(out, "IP Address"); + for (i = 0; i < 8; i++) + { + BIO_printf(out, ":%X", p[0] << 8 | p[1]); + p += 2; + } + BIO_puts(out, "\n"); + } + else + { + BIO_printf(out,"IP Address:"); + break; + } + break; + + case GEN_RID: + BIO_printf(out, "Registered ID"); + i2a_ASN1_OBJECT(out, gen->d.rid); + break; + } + return 1; +} + +static GENERAL_NAMES *v2i_issuer_alt(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval) +{ + GENERAL_NAMES *gens = NULL; + CONF_VALUE *cnf; + size_t i; + if(!(gens = sk_GENERAL_NAME_new_null())) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + for(i = 0; i < sk_CONF_VALUE_num(nval); i++) { + cnf = sk_CONF_VALUE_value(nval, i); + if(!name_cmp(cnf->name, "issuer") && cnf->value && + !strcmp(cnf->value, "copy")) { + if(!copy_issuer(ctx, gens)) goto err; + } else { + GENERAL_NAME *gen; + if(!(gen = v2i_GENERAL_NAME(method, ctx, cnf))) + goto err; + sk_GENERAL_NAME_push(gens, gen); + } + } + return gens; + err: + sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); + return NULL; +} + +/* Append subject altname of issuer to issuer alt name of subject */ + +static int copy_issuer(X509V3_CTX *ctx, GENERAL_NAMES *gens) +{ + GENERAL_NAMES *ialt; + GENERAL_NAME *gen; + X509_EXTENSION *ext; + int i; + size_t j; + if(ctx && (ctx->flags == CTX_TEST)) return 1; + if(!ctx || !ctx->issuer_cert) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_NO_ISSUER_DETAILS); + goto err; + } + i = X509_get_ext_by_NID(ctx->issuer_cert, NID_subject_alt_name, -1); + if(i < 0) return 1; + if(!(ext = X509_get_ext(ctx->issuer_cert, i)) || + !(ialt = X509V3_EXT_d2i(ext)) ) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_ISSUER_DECODE_ERROR); + goto err; + } + + for(j = 0; j < sk_GENERAL_NAME_num(ialt); j++) { + gen = sk_GENERAL_NAME_value(ialt, j); + if(!sk_GENERAL_NAME_push(gens, gen)) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + goto err; + } + } + sk_GENERAL_NAME_free(ialt); + + return 1; + + err: + return 0; + +} + +static GENERAL_NAMES *v2i_subject_alt(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval) +{ + GENERAL_NAMES *gens = NULL; + CONF_VALUE *cnf; + size_t i; + if(!(gens = sk_GENERAL_NAME_new_null())) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + for(i = 0; i < sk_CONF_VALUE_num(nval); i++) { + cnf = sk_CONF_VALUE_value(nval, i); + if(!name_cmp(cnf->name, "email") && cnf->value && + !strcmp(cnf->value, "copy")) { + if(!copy_email(ctx, gens, 0)) goto err; + } else if(!name_cmp(cnf->name, "email") && cnf->value && + !strcmp(cnf->value, "move")) { + if(!copy_email(ctx, gens, 1)) goto err; + } else { + GENERAL_NAME *gen; + if(!(gen = v2i_GENERAL_NAME(method, ctx, cnf))) + goto err; + sk_GENERAL_NAME_push(gens, gen); + } + } + return gens; + err: + sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); + return NULL; +} + +/* Copy any email addresses in a certificate or request to + * GENERAL_NAMES + */ + +static int copy_email(X509V3_CTX *ctx, GENERAL_NAMES *gens, int move_p) +{ + X509_NAME *nm; + ASN1_IA5STRING *email = NULL; + X509_NAME_ENTRY *ne; + GENERAL_NAME *gen = NULL; + int i; + if(ctx != NULL && ctx->flags == CTX_TEST) + return 1; + if(!ctx || (!ctx->subject_cert && !ctx->subject_req)) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_NO_SUBJECT_DETAILS); + goto err; + } + /* Find the subject name */ + if(ctx->subject_cert) nm = X509_get_subject_name(ctx->subject_cert); + else nm = X509_REQ_get_subject_name(ctx->subject_req); + + /* Now add any email address(es) to STACK */ + i = -1; + while((i = X509_NAME_get_index_by_NID(nm, + NID_pkcs9_emailAddress, i)) >= 0) { + ne = X509_NAME_get_entry(nm, i); + email = M_ASN1_IA5STRING_dup(X509_NAME_ENTRY_get_data(ne)); + if (move_p) + { + X509_NAME_delete_entry(nm, i); + X509_NAME_ENTRY_free(ne); + i--; + } + if(!email || !(gen = GENERAL_NAME_new())) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + goto err; + } + gen->d.ia5 = email; + email = NULL; + gen->type = GEN_EMAIL; + if(!sk_GENERAL_NAME_push(gens, gen)) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + goto err; + } + gen = NULL; + } + + + return 1; + + err: + GENERAL_NAME_free(gen); + M_ASN1_IA5STRING_free(email); + return 0; + +} + +GENERAL_NAMES *v2i_GENERAL_NAMES(const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval) +{ + GENERAL_NAME *gen; + GENERAL_NAMES *gens = NULL; + CONF_VALUE *cnf; + size_t i; + if(!(gens = sk_GENERAL_NAME_new_null())) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + for(i = 0; i < sk_CONF_VALUE_num(nval); i++) { + cnf = sk_CONF_VALUE_value(nval, i); + if(!(gen = v2i_GENERAL_NAME(method, ctx, cnf))) goto err; + sk_GENERAL_NAME_push(gens, gen); + } + return gens; + err: + sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); + return NULL; +} + +GENERAL_NAME *v2i_GENERAL_NAME(const X509V3_EXT_METHOD *method, X509V3_CTX *ctx, + CONF_VALUE *cnf) + { + return v2i_GENERAL_NAME_ex(NULL, method, ctx, cnf, 0); + } + +GENERAL_NAME *a2i_GENERAL_NAME(GENERAL_NAME *out, + const X509V3_EXT_METHOD *method, X509V3_CTX *ctx, + int gen_type, char *value, int is_nc) + { + char is_string = 0; + GENERAL_NAME *gen = NULL; + + if(!value) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_MISSING_VALUE); + return NULL; + } + + if (out) + gen = out; + else + { + gen = GENERAL_NAME_new(); + if(gen == NULL) + { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + } + + switch (gen_type) + { + case GEN_URI: + case GEN_EMAIL: + case GEN_DNS: + is_string = 1; + break; + + case GEN_RID: + { + ASN1_OBJECT *obj; + if(!(obj = OBJ_txt2obj(value,0))) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_BAD_OBJECT); + ERR_add_error_data(2, "value=", value); + goto err; + } + gen->d.rid = obj; + } + break; + + case GEN_IPADD: + if (is_nc) + gen->d.ip = a2i_IPADDRESS_NC(value); + else + gen->d.ip = a2i_IPADDRESS(value); + if(gen->d.ip == NULL) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_BAD_IP_ADDRESS); + ERR_add_error_data(2, "value=", value); + goto err; + } + break; + + case GEN_DIRNAME: + if (!do_dirname(gen, value, ctx)) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_DIRNAME_ERROR); + goto err; + } + break; + + case GEN_OTHERNAME: + if (!do_othername(gen, value, ctx)) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_OTHERNAME_ERROR); + goto err; + } + break; + default: + OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNSUPPORTED_TYPE); + goto err; + } + + if(is_string) + { + if(!(gen->d.ia5 = M_ASN1_IA5STRING_new()) || + !ASN1_STRING_set(gen->d.ia5, (unsigned char*)value, + strlen(value))) + { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + goto err; + } + } + + gen->type = gen_type; + + return gen; + + err: + if (!out) + GENERAL_NAME_free(gen); + return NULL; + } + +GENERAL_NAME *v2i_GENERAL_NAME_ex(GENERAL_NAME *out, + const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, CONF_VALUE *cnf, int is_nc) + { + int type; + + char *name, *value; + + name = cnf->name; + value = cnf->value; + + if(!value) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_MISSING_VALUE); + return NULL; + } + + if(!name_cmp(name, "email")) + type = GEN_EMAIL; + else if(!name_cmp(name, "URI")) + type = GEN_URI; + else if(!name_cmp(name, "DNS")) + type = GEN_DNS; + else if(!name_cmp(name, "RID")) + type = GEN_RID; + else if(!name_cmp(name, "IP")) + type = GEN_IPADD; + else if(!name_cmp(name, "dirName")) + type = GEN_DIRNAME; + else if(!name_cmp(name, "otherName")) + type = GEN_OTHERNAME; + else + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNSUPPORTED_OPTION); + ERR_add_error_data(2, "name=", name); + return NULL; + } + + return a2i_GENERAL_NAME(out, method, ctx, type, value, is_nc); + + } + +static int do_othername(GENERAL_NAME *gen, char *value, X509V3_CTX *ctx) + { + char *objtmp = NULL, *p; + int objlen; + if (!(p = strchr(value, ';'))) + return 0; + if (!(gen->d.otherName = OTHERNAME_new())) + return 0; + /* Free this up because we will overwrite it. + * no need to free type_id because it is static + */ + ASN1_TYPE_free(gen->d.otherName->value); + if (!(gen->d.otherName->value = ASN1_generate_v3(p + 1, ctx))) + return 0; + objlen = p - value; + objtmp = OPENSSL_malloc(objlen + 1); + if (objtmp == NULL) + return 0; + strncpy(objtmp, value, objlen); + objtmp[objlen] = 0; + gen->d.otherName->type_id = OBJ_txt2obj(objtmp, 0); + OPENSSL_free(objtmp); + if (!gen->d.otherName->type_id) + return 0; + return 1; + } + +static int do_dirname(GENERAL_NAME *gen, char *value, X509V3_CTX *ctx) + { + int ret; + STACK_OF(CONF_VALUE) *sk; + X509_NAME *nm; + if (!(nm = X509_NAME_new())) + return 0; + sk = X509V3_get_section(ctx, value); + if (!sk) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_SECTION_NOT_FOUND); + ERR_add_error_data(2, "section=", value); + X509_NAME_free(nm); + return 0; + } + /* FIXME: should allow other character types... */ + ret = X509V3_NAME_from_section(nm, sk, MBSTRING_ASC); + if (!ret) + X509_NAME_free(nm); + gen->d.dirn = nm; + X509V3_section_free(ctx, sk); + + return ret; + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_bcons.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_bcons.c new file mode 100644 index 00000000..73ef21ee --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_bcons.c @@ -0,0 +1,126 @@ +/* v3_bcons.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + + +#include +#include + +#include +#include +#include +#include +#include +#include + + +static STACK_OF(CONF_VALUE) *i2v_BASIC_CONSTRAINTS(X509V3_EXT_METHOD *method, BASIC_CONSTRAINTS *bcons, STACK_OF(CONF_VALUE) *extlist); +static BASIC_CONSTRAINTS *v2i_BASIC_CONSTRAINTS(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *values); + +const X509V3_EXT_METHOD v3_bcons = { +NID_basic_constraints, 0, +ASN1_ITEM_ref(BASIC_CONSTRAINTS), +0,0,0,0, +0,0, +(X509V3_EXT_I2V)i2v_BASIC_CONSTRAINTS, +(X509V3_EXT_V2I)v2i_BASIC_CONSTRAINTS, +NULL,NULL, +NULL +}; + +ASN1_SEQUENCE(BASIC_CONSTRAINTS) = { + ASN1_OPT(BASIC_CONSTRAINTS, ca, ASN1_FBOOLEAN), + ASN1_OPT(BASIC_CONSTRAINTS, pathlen, ASN1_INTEGER) +} ASN1_SEQUENCE_END(BASIC_CONSTRAINTS) + +IMPLEMENT_ASN1_FUNCTIONS(BASIC_CONSTRAINTS) + + +static STACK_OF(CONF_VALUE) *i2v_BASIC_CONSTRAINTS(X509V3_EXT_METHOD *method, + BASIC_CONSTRAINTS *bcons, STACK_OF(CONF_VALUE) *extlist) +{ + X509V3_add_value_bool("CA", bcons->ca, &extlist); + X509V3_add_value_int("pathlen", bcons->pathlen, &extlist); + return extlist; +} + +static BASIC_CONSTRAINTS *v2i_BASIC_CONSTRAINTS(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *values) +{ + BASIC_CONSTRAINTS *bcons=NULL; + CONF_VALUE *val; + size_t i; + if(!(bcons = BASIC_CONSTRAINTS_new())) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + for(i = 0; i < sk_CONF_VALUE_num(values); i++) { + val = sk_CONF_VALUE_value(values, i); + if(!strcmp(val->name, "CA")) { + if(!X509V3_get_value_bool(val, &bcons->ca)) goto err; + } else if(!strcmp(val->name, "pathlen")) { + if(!X509V3_get_value_int(val, &bcons->pathlen)) goto err; + } else { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NAME); + X509V3_conf_err(val); + goto err; + } + } + return bcons; + err: + BASIC_CONSTRAINTS_free(bcons); + return NULL; +} + diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_bitst.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_bitst.c new file mode 100644 index 00000000..e1e20871 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_bitst.c @@ -0,0 +1,141 @@ +/* v3_bitst.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include +#include + +#include +#include +#include +#include + + +static const BIT_STRING_BITNAME ns_cert_type_table[] = { +{0, "SSL Client", "client"}, +{1, "SSL Server", "server"}, +{2, "S/MIME", "email"}, +{3, "Object Signing", "objsign"}, +{4, "Unused", "reserved"}, +{5, "SSL CA", "sslCA"}, +{6, "S/MIME CA", "emailCA"}, +{7, "Object Signing CA", "objCA"}, +{-1, NULL, NULL} +}; + +static const BIT_STRING_BITNAME key_usage_type_table[] = { +{0, "Digital Signature", "digitalSignature"}, +{1, "Non Repudiation", "nonRepudiation"}, +{2, "Key Encipherment", "keyEncipherment"}, +{3, "Data Encipherment", "dataEncipherment"}, +{4, "Key Agreement", "keyAgreement"}, +{5, "Certificate Sign", "keyCertSign"}, +{6, "CRL Sign", "cRLSign"}, +{7, "Encipher Only", "encipherOnly"}, +{8, "Decipher Only", "decipherOnly"}, +{-1, NULL, NULL} +}; + + + +const X509V3_EXT_METHOD v3_nscert = EXT_BITSTRING(NID_netscape_cert_type, ns_cert_type_table); +const X509V3_EXT_METHOD v3_key_usage = EXT_BITSTRING(NID_key_usage, key_usage_type_table); + +STACK_OF(CONF_VALUE) *i2v_ASN1_BIT_STRING(X509V3_EXT_METHOD *method, + ASN1_BIT_STRING *bits, STACK_OF(CONF_VALUE) *ret) +{ + const BIT_STRING_BITNAME *bnam; + for(bnam =method->usr_data; bnam->lname; bnam++) { + if(ASN1_BIT_STRING_get_bit(bits, bnam->bitnum)) + X509V3_add_value(bnam->lname, NULL, &ret); + } + return ret; +} + +ASN1_BIT_STRING *v2i_ASN1_BIT_STRING(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval) +{ + CONF_VALUE *val; + ASN1_BIT_STRING *bs; + size_t i; + const BIT_STRING_BITNAME *bnam; + if(!(bs = M_ASN1_BIT_STRING_new())) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + for(i = 0; i < sk_CONF_VALUE_num(nval); i++) { + val = sk_CONF_VALUE_value(nval, i); + for(bnam = method->usr_data; bnam->lname; bnam++) { + if(!strcmp(bnam->sname, val->name) || + !strcmp(bnam->lname, val->name) ) { + if(!ASN1_BIT_STRING_set_bit(bs, bnam->bitnum, 1)) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + M_ASN1_BIT_STRING_free(bs); + return NULL; + } + break; + } + } + if(!bnam->lname) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNKNOWN_BIT_STRING_ARGUMENT); + X509V3_conf_err(val); + M_ASN1_BIT_STRING_free(bs); + return NULL; + } + } + return bs; +} + + diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_conf.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_conf.c new file mode 100644 index 00000000..fe715665 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_conf.c @@ -0,0 +1,459 @@ +/* v3_conf.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999-2002 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +/* extension creation utilities */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../internal.h" + + +static int v3_check_critical(char **value); +static int v3_check_generic(char **value); +static X509_EXTENSION *do_ext_nconf(CONF *conf, X509V3_CTX *ctx, int ext_nid, int crit, char *value); +static X509_EXTENSION *v3_generic_extension(const char *ext, char *value, int crit, int type, X509V3_CTX *ctx); +static X509_EXTENSION *do_ext_i2d(const X509V3_EXT_METHOD *method, int ext_nid, + int crit, void *ext_struc); +static unsigned char *generic_asn1(char *value, X509V3_CTX *ctx, long *ext_len); +/* CONF *conf: Config file */ +/* char *name: Name */ +/* char *value: Value */ +X509_EXTENSION *X509V3_EXT_nconf(CONF *conf, X509V3_CTX *ctx, char *name, + char *value) + { + int crit; + int ext_type; + X509_EXTENSION *ret; + crit = v3_check_critical(&value); + if ((ext_type = v3_check_generic(&value))) + return v3_generic_extension(name, value, crit, ext_type, ctx); + ret = do_ext_nconf(conf, ctx, OBJ_sn2nid(name), crit, value); + if (!ret) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_ERROR_IN_EXTENSION); + ERR_add_error_data(4,"name=", name, ", value=", value); + } + return ret; + } + +/* CONF *conf: Config file */ +/* char *value: Value */ +X509_EXTENSION *X509V3_EXT_nconf_nid(CONF *conf, X509V3_CTX *ctx, int ext_nid, + char *value) + { + int crit; + int ext_type; + crit = v3_check_critical(&value); + if ((ext_type = v3_check_generic(&value))) + return v3_generic_extension(OBJ_nid2sn(ext_nid), + value, crit, ext_type, ctx); + return do_ext_nconf(conf, ctx, ext_nid, crit, value); + } + +/* CONF *conf: Config file */ +/* char *value: Value */ +static X509_EXTENSION *do_ext_nconf(CONF *conf, X509V3_CTX *ctx, int ext_nid, + int crit, char *value) + { + const X509V3_EXT_METHOD *method; + X509_EXTENSION *ext; + STACK_OF(CONF_VALUE) *nval; + void *ext_struc; + if (ext_nid == NID_undef) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNKNOWN_EXTENSION_NAME); + return NULL; + } + if (!(method = X509V3_EXT_get_nid(ext_nid))) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNKNOWN_EXTENSION); + return NULL; + } + /* Now get internal extension representation based on type */ + if (method->v2i) + { + if(*value == '@') nval = NCONF_get_section(conf, value + 1); + else nval = X509V3_parse_list(value); + if(sk_CONF_VALUE_num(nval) <= 0) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_EXTENSION_STRING); + ERR_add_error_data(4, "name=", OBJ_nid2sn(ext_nid), ",section=", value); + return NULL; + } + ext_struc = method->v2i(method, ctx, nval); + if(*value != '@') sk_CONF_VALUE_pop_free(nval, + X509V3_conf_free); + if(!ext_struc) return NULL; + } + else if(method->s2i) + { + if(!(ext_struc = method->s2i(method, ctx, value))) return NULL; + } + else if(method->r2i) + { + if(!ctx->db || !ctx->db_meth) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_NO_CONFIG_DATABASE); + return NULL; + } + if(!(ext_struc = method->r2i(method, ctx, value))) return NULL; + } + else + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED); + ERR_add_error_data(2, "name=", OBJ_nid2sn(ext_nid)); + return NULL; + } + + ext = do_ext_i2d(method, ext_nid, crit, ext_struc); + if(method->it) ASN1_item_free(ext_struc, ASN1_ITEM_ptr(method->it)); + else method->ext_free(ext_struc); + return ext; + + } + +static X509_EXTENSION *do_ext_i2d(const X509V3_EXT_METHOD *method, int ext_nid, + int crit, void *ext_struc) + { + unsigned char *ext_der; + int ext_len; + ASN1_OCTET_STRING *ext_oct; + X509_EXTENSION *ext; + /* Convert internal representation to DER */ + if (method->it) + { + ext_der = NULL; + ext_len = ASN1_item_i2d(ext_struc, &ext_der, ASN1_ITEM_ptr(method->it)); + if (ext_len < 0) goto merr; + } + else + { + unsigned char *p; + ext_len = method->i2d(ext_struc, NULL); + if(!(ext_der = OPENSSL_malloc(ext_len))) goto merr; + p = ext_der; + method->i2d(ext_struc, &p); + } + if (!(ext_oct = M_ASN1_OCTET_STRING_new())) goto merr; + ext_oct->data = ext_der; + ext_oct->length = ext_len; + + ext = X509_EXTENSION_create_by_NID(NULL, ext_nid, crit, ext_oct); + if (!ext) goto merr; + M_ASN1_OCTET_STRING_free(ext_oct); + + return ext; + + merr: + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + + } + +/* Given an internal structure, nid and critical flag create an extension */ + +X509_EXTENSION *X509V3_EXT_i2d(int ext_nid, int crit, void *ext_struc) + { + const X509V3_EXT_METHOD *method; + if (!(method = X509V3_EXT_get_nid(ext_nid))) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNKNOWN_EXTENSION); + return NULL; + } + return do_ext_i2d(method, ext_nid, crit, ext_struc); +} + +/* Check the extension string for critical flag */ +static int v3_check_critical(char **value) +{ + char *p = *value; + if ((strlen(p) < 9) || strncmp(p, "critical,", 9)) return 0; + p+=9; + while(isspace((unsigned char)*p)) p++; + *value = p; + return 1; +} + +/* Check extension string for generic extension and return the type */ +static int v3_check_generic(char **value) +{ + int gen_type = 0; + char *p = *value; + if ((strlen(p) >= 4) && !strncmp(p, "DER:", 4)) + { + p+=4; + gen_type = 1; + } + else if ((strlen(p) >= 5) && !strncmp(p, "ASN1:", 5)) + { + p+=5; + gen_type = 2; + } + else + return 0; + + while (isspace((unsigned char)*p)) p++; + *value = p; + return gen_type; +} + +/* Create a generic extension: for now just handle DER type */ +static X509_EXTENSION *v3_generic_extension(const char *ext, char *value, + int crit, int gen_type, + X509V3_CTX *ctx) + OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS + { + unsigned char *ext_der=NULL; + long ext_len; + ASN1_OBJECT *obj=NULL; + ASN1_OCTET_STRING *oct=NULL; + X509_EXTENSION *extension=NULL; + if (!(obj = OBJ_txt2obj(ext, 0))) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_EXTENSION_NAME_ERROR); + ERR_add_error_data(2, "name=", ext); + goto err; + } + + if (gen_type == 1) + ext_der = string_to_hex(value, &ext_len); + else if (gen_type == 2) + ext_der = generic_asn1(value, ctx, &ext_len); + + if (ext_der == NULL) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_EXTENSION_VALUE_ERROR); + ERR_add_error_data(2, "value=", value); + goto err; + } + + if (!(oct = M_ASN1_OCTET_STRING_new())) + { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + goto err; + } + + oct->data = ext_der; + oct->length = ext_len; + ext_der = NULL; + + extension = X509_EXTENSION_create_by_OBJ(NULL, obj, crit, oct); + + err: + ASN1_OBJECT_free(obj); + M_ASN1_OCTET_STRING_free(oct); + if(ext_der) OPENSSL_free(ext_der); + return extension; + + } + +static unsigned char *generic_asn1(char *value, X509V3_CTX *ctx, long *ext_len) + { + ASN1_TYPE *typ; + unsigned char *ext_der = NULL; + typ = ASN1_generate_v3(value, ctx); + if (typ == NULL) + return NULL; + *ext_len = i2d_ASN1_TYPE(typ, &ext_der); + ASN1_TYPE_free(typ); + return ext_der; + } + +/* This is the main function: add a bunch of extensions based on a config file + * section to an extension STACK. + */ + + +int X509V3_EXT_add_nconf_sk(CONF *conf, X509V3_CTX *ctx, char *section, + STACK_OF(X509_EXTENSION) **sk) + { + X509_EXTENSION *ext; + STACK_OF(CONF_VALUE) *nval; + CONF_VALUE *val; + size_t i; + if (!(nval = NCONF_get_section(conf, section))) return 0; + for (i = 0; i < sk_CONF_VALUE_num(nval); i++) + { + val = sk_CONF_VALUE_value(nval, i); + if (!(ext = X509V3_EXT_nconf(conf, ctx, val->name, val->value))) + return 0; + if (sk) X509v3_add_ext(sk, ext, -1); + X509_EXTENSION_free(ext); + } + return 1; + } + +/* Convenience functions to add extensions to a certificate, CRL and request */ + +int X509V3_EXT_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section, + X509 *cert) + { + STACK_OF(X509_EXTENSION) **sk = NULL; + if (cert) + sk = &cert->cert_info->extensions; + return X509V3_EXT_add_nconf_sk(conf, ctx, section, sk); + } + +/* Same as above but for a CRL */ + +int X509V3_EXT_CRL_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section, + X509_CRL *crl) + { + STACK_OF(X509_EXTENSION) **sk = NULL; + if (crl) + sk = &crl->crl->extensions; + return X509V3_EXT_add_nconf_sk(conf, ctx, section, sk); + } + +/* Add extensions to certificate request */ + +int X509V3_EXT_REQ_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section, + X509_REQ *req) + { + STACK_OF(X509_EXTENSION) *extlist = NULL, **sk = NULL; + int i; + if (req) + sk = &extlist; + i = X509V3_EXT_add_nconf_sk(conf, ctx, section, sk); + if (!i || !sk) + return i; + i = X509_REQ_add_extensions(req, extlist); + sk_X509_EXTENSION_pop_free(extlist, X509_EXTENSION_free); + return i; + } + +/* Config database functions */ + +char * X509V3_get_string(X509V3_CTX *ctx, char *name, char *section) + { + if(!ctx->db || !ctx->db_meth || !ctx->db_meth->get_string) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_OPERATION_NOT_DEFINED); + return NULL; + } + if (ctx->db_meth->get_string) + return ctx->db_meth->get_string(ctx->db, name, section); + return NULL; + } + +STACK_OF(CONF_VALUE) * X509V3_get_section(X509V3_CTX *ctx, char *section) + { + if(!ctx->db || !ctx->db_meth || !ctx->db_meth->get_section) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_OPERATION_NOT_DEFINED); + return NULL; + } + if (ctx->db_meth->get_section) + return ctx->db_meth->get_section(ctx->db, section); + return NULL; + } + +void X509V3_string_free(X509V3_CTX *ctx, char *str) + { + if (!str) return; + if (ctx->db_meth->free_string) + ctx->db_meth->free_string(ctx->db, str); + } + +void X509V3_section_free(X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *section) + { + if (!section) return; + if (ctx->db_meth->free_section) + ctx->db_meth->free_section(ctx->db, section); + } + +static char *nconf_get_string(void *db, char *section, char *value) + { + /* TODO(fork): this should return a const value. */ + return (char *) NCONF_get_string(db, section, value); + } + +static STACK_OF(CONF_VALUE) *nconf_get_section(void *db, char *section) + { + return NCONF_get_section(db, section); + } + +static const X509V3_CONF_METHOD nconf_method = { +nconf_get_string, +nconf_get_section, +NULL, +NULL +}; + +void X509V3_set_nconf(X509V3_CTX *ctx, CONF *conf) + { + ctx->db_meth = &nconf_method; + ctx->db = conf; + } + +void X509V3_set_ctx(X509V3_CTX *ctx, X509 *issuer, X509 *subj, X509_REQ *req, + X509_CRL *crl, int flags) + { + ctx->issuer_cert = issuer; + ctx->subject_cert = subj; + ctx->crl = crl; + ctx->subject_req = req; + ctx->flags = flags; + } + diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_cpols.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_cpols.c new file mode 100644 index 00000000..0b586762 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_cpols.c @@ -0,0 +1,475 @@ +/* v3_cpols.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999-2004 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcy_int.h" + +/* Certificate policies extension support: this one is a bit complex... */ + +static int i2r_certpol(X509V3_EXT_METHOD *method, STACK_OF(POLICYINFO) *pol, BIO *out, int indent); +static STACK_OF(POLICYINFO) *r2i_certpol(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, char *value); +static void print_qualifiers(BIO *out, STACK_OF(POLICYQUALINFO) *quals, int indent); +static void print_notice(BIO *out, USERNOTICE *notice, int indent); +static POLICYINFO *policy_section(X509V3_CTX *ctx, + STACK_OF(CONF_VALUE) *polstrs, int ia5org); +static POLICYQUALINFO *notice_section(X509V3_CTX *ctx, + STACK_OF(CONF_VALUE) *unot, int ia5org); +static int nref_nos(STACK_OF(ASN1_INTEGER) *nnums, STACK_OF(CONF_VALUE) *nos); + +const X509V3_EXT_METHOD v3_cpols = { +NID_certificate_policies, 0,ASN1_ITEM_ref(CERTIFICATEPOLICIES), +0,0,0,0, +0,0, +0,0, +(X509V3_EXT_I2R)i2r_certpol, +(X509V3_EXT_R2I)r2i_certpol, +NULL +}; + +ASN1_ITEM_TEMPLATE(CERTIFICATEPOLICIES) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, CERTIFICATEPOLICIES, POLICYINFO) +ASN1_ITEM_TEMPLATE_END(CERTIFICATEPOLICIES) + +IMPLEMENT_ASN1_FUNCTIONS(CERTIFICATEPOLICIES) + +ASN1_SEQUENCE(POLICYINFO) = { + ASN1_SIMPLE(POLICYINFO, policyid, ASN1_OBJECT), + ASN1_SEQUENCE_OF_OPT(POLICYINFO, qualifiers, POLICYQUALINFO) +} ASN1_SEQUENCE_END(POLICYINFO) + +IMPLEMENT_ASN1_FUNCTIONS(POLICYINFO) + +ASN1_ADB_TEMPLATE(policydefault) = ASN1_SIMPLE(POLICYQUALINFO, d.other, ASN1_ANY); + +ASN1_ADB(POLICYQUALINFO) = { + ADB_ENTRY(NID_id_qt_cps, ASN1_SIMPLE(POLICYQUALINFO, d.cpsuri, ASN1_IA5STRING)), + ADB_ENTRY(NID_id_qt_unotice, ASN1_SIMPLE(POLICYQUALINFO, d.usernotice, USERNOTICE)) +} ASN1_ADB_END(POLICYQUALINFO, 0, pqualid, 0, &policydefault_tt, NULL); + +ASN1_SEQUENCE(POLICYQUALINFO) = { + ASN1_SIMPLE(POLICYQUALINFO, pqualid, ASN1_OBJECT), + ASN1_ADB_OBJECT(POLICYQUALINFO) +} ASN1_SEQUENCE_END(POLICYQUALINFO) + +IMPLEMENT_ASN1_FUNCTIONS(POLICYQUALINFO) + +ASN1_SEQUENCE(USERNOTICE) = { + ASN1_OPT(USERNOTICE, noticeref, NOTICEREF), + ASN1_OPT(USERNOTICE, exptext, DISPLAYTEXT) +} ASN1_SEQUENCE_END(USERNOTICE) + +IMPLEMENT_ASN1_FUNCTIONS(USERNOTICE) + +ASN1_SEQUENCE(NOTICEREF) = { + ASN1_SIMPLE(NOTICEREF, organization, DISPLAYTEXT), + ASN1_SEQUENCE_OF(NOTICEREF, noticenos, ASN1_INTEGER) +} ASN1_SEQUENCE_END(NOTICEREF) + +IMPLEMENT_ASN1_FUNCTIONS(NOTICEREF) + +static STACK_OF(POLICYINFO) *r2i_certpol(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, char *value) +{ + STACK_OF(POLICYINFO) *pols = NULL; + char *pstr; + POLICYINFO *pol; + ASN1_OBJECT *pobj; + STACK_OF(CONF_VALUE) *vals; + CONF_VALUE *cnf; + size_t i; + int ia5org; + pols = sk_POLICYINFO_new_null(); + if (pols == NULL) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + vals = X509V3_parse_list(value); + if (vals == NULL) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_X509V3_LIB); + goto err; + } + ia5org = 0; + for(i = 0; i < sk_CONF_VALUE_num(vals); i++) { + cnf = sk_CONF_VALUE_value(vals, i); + if(cnf->value || !cnf->name ) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_POLICY_IDENTIFIER); + X509V3_conf_err(cnf); + goto err; + } + pstr = cnf->name; + if(!strcmp(pstr,"ia5org")) { + ia5org = 1; + continue; + } else if(*pstr == '@') { + STACK_OF(CONF_VALUE) *polsect; + polsect = X509V3_get_section(ctx, pstr + 1); + if(!polsect) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_SECTION); + + X509V3_conf_err(cnf); + goto err; + } + pol = policy_section(ctx, polsect, ia5org); + X509V3_section_free(ctx, polsect); + if(!pol) goto err; + } else { + if(!(pobj = OBJ_txt2obj(cnf->name, 0))) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_OBJECT_IDENTIFIER); + X509V3_conf_err(cnf); + goto err; + } + pol = POLICYINFO_new(); + pol->policyid = pobj; + } + if (!sk_POLICYINFO_push(pols, pol)){ + POLICYINFO_free(pol); + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + goto err; + } + } + sk_CONF_VALUE_pop_free(vals, X509V3_conf_free); + return pols; + err: + sk_CONF_VALUE_pop_free(vals, X509V3_conf_free); + sk_POLICYINFO_pop_free(pols, POLICYINFO_free); + return NULL; +} + +static POLICYINFO *policy_section(X509V3_CTX *ctx, + STACK_OF(CONF_VALUE) *polstrs, int ia5org) +{ + size_t i; + CONF_VALUE *cnf; + POLICYINFO *pol; + POLICYQUALINFO *qual; + if(!(pol = POLICYINFO_new())) goto merr; + for(i = 0; i < sk_CONF_VALUE_num(polstrs); i++) { + cnf = sk_CONF_VALUE_value(polstrs, i); + if(!strcmp(cnf->name, "policyIdentifier")) { + ASN1_OBJECT *pobj; + if(!(pobj = OBJ_txt2obj(cnf->value, 0))) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_OBJECT_IDENTIFIER); + X509V3_conf_err(cnf); + goto err; + } + pol->policyid = pobj; + + } else if(!name_cmp(cnf->name, "CPS")) { + if(!pol->qualifiers) pol->qualifiers = + sk_POLICYQUALINFO_new_null(); + if(!(qual = POLICYQUALINFO_new())) goto merr; + if(!sk_POLICYQUALINFO_push(pol->qualifiers, qual)) + goto merr; + /* TODO(fork): const correctness */ + qual->pqualid = (ASN1_OBJECT*) OBJ_nid2obj(NID_id_qt_cps); + if (qual->pqualid == NULL) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_INTERNAL_ERROR); + goto err; + } + qual->d.cpsuri = M_ASN1_IA5STRING_new(); + if (qual->d.cpsuri == NULL) { + goto err; + } + if(!ASN1_STRING_set(qual->d.cpsuri, cnf->value, + strlen(cnf->value))) goto merr; + } else if(!name_cmp(cnf->name, "userNotice")) { + STACK_OF(CONF_VALUE) *unot; + if(*cnf->value != '@') { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_EXPECTED_A_SECTION_NAME); + X509V3_conf_err(cnf); + goto err; + } + unot = X509V3_get_section(ctx, cnf->value + 1); + if(!unot) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_SECTION); + + X509V3_conf_err(cnf); + goto err; + } + qual = notice_section(ctx, unot, ia5org); + X509V3_section_free(ctx, unot); + if(!qual) goto err; + if(!pol->qualifiers) pol->qualifiers = + sk_POLICYQUALINFO_new_null(); + if(!sk_POLICYQUALINFO_push(pol->qualifiers, qual)) + goto merr; + } else { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_OPTION); + + X509V3_conf_err(cnf); + goto err; + } + } + if(!pol->policyid) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_NO_POLICY_IDENTIFIER); + goto err; + } + + return pol; + + merr: + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + + err: + POLICYINFO_free(pol); + return NULL; + + +} + +static POLICYQUALINFO *notice_section(X509V3_CTX *ctx, + STACK_OF(CONF_VALUE) *unot, int ia5org) +{ + size_t i; + int ret; + CONF_VALUE *cnf; + USERNOTICE *not; + POLICYQUALINFO *qual; + if(!(qual = POLICYQUALINFO_new())) goto merr; + /* TODO(fork): const correctness */ + qual->pqualid = (ASN1_OBJECT *) OBJ_nid2obj(NID_id_qt_unotice); + if (qual->pqualid == NULL) + { + OPENSSL_PUT_ERROR(X509V3, ERR_R_INTERNAL_ERROR); + goto err; + } + if(!(not = USERNOTICE_new())) goto merr; + qual->d.usernotice = not; + for(i = 0; i < sk_CONF_VALUE_num(unot); i++) { + cnf = sk_CONF_VALUE_value(unot, i); + if(!strcmp(cnf->name, "explicitText")) { + not->exptext = M_ASN1_VISIBLESTRING_new(); + if (not->exptext == NULL) + goto merr; + if(!ASN1_STRING_set(not->exptext, cnf->value, + strlen(cnf->value))) goto merr; + } else if(!strcmp(cnf->name, "organization")) { + NOTICEREF *nref; + if(!not->noticeref) { + if(!(nref = NOTICEREF_new())) goto merr; + not->noticeref = nref; + } else nref = not->noticeref; + if(ia5org) nref->organization->type = V_ASN1_IA5STRING; + else nref->organization->type = V_ASN1_VISIBLESTRING; + if(!ASN1_STRING_set(nref->organization, cnf->value, + strlen(cnf->value))) goto merr; + } else if(!strcmp(cnf->name, "noticeNumbers")) { + NOTICEREF *nref; + STACK_OF(CONF_VALUE) *nos; + if(!not->noticeref) { + if(!(nref = NOTICEREF_new())) goto merr; + not->noticeref = nref; + } else nref = not->noticeref; + nos = X509V3_parse_list(cnf->value); + if(!nos || !sk_CONF_VALUE_num(nos)) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NUMBERS); + X509V3_conf_err(cnf); + goto err; + } + ret = nref_nos(nref->noticenos, nos); + sk_CONF_VALUE_pop_free(nos, X509V3_conf_free); + if (!ret) + goto err; + } else { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_OPTION); + X509V3_conf_err(cnf); + goto err; + } + } + + if(not->noticeref && + (!not->noticeref->noticenos || !not->noticeref->organization)) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_NEED_ORGANIZATION_AND_NUMBERS); + goto err; + } + + return qual; + + merr: + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + + err: + POLICYQUALINFO_free(qual); + return NULL; +} + +static int nref_nos(STACK_OF(ASN1_INTEGER) *nnums, STACK_OF(CONF_VALUE) *nos) +{ + CONF_VALUE *cnf; + ASN1_INTEGER *aint; + + size_t i; + + for(i = 0; i < sk_CONF_VALUE_num(nos); i++) { + cnf = sk_CONF_VALUE_value(nos, i); + if(!(aint = s2i_ASN1_INTEGER(NULL, cnf->name))) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NUMBER); + goto err; + } + if(!sk_ASN1_INTEGER_push(nnums, aint)) goto merr; + } + return 1; + + merr: + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + + err: + sk_ASN1_INTEGER_pop_free(nnums, ASN1_STRING_free); + return 0; +} + + +static int i2r_certpol(X509V3_EXT_METHOD *method, STACK_OF(POLICYINFO) *pol, + BIO *out, int indent) +{ + size_t i; + POLICYINFO *pinfo; + /* First print out the policy OIDs */ + for(i = 0; i < sk_POLICYINFO_num(pol); i++) { + pinfo = sk_POLICYINFO_value(pol, i); + BIO_printf(out, "%*sPolicy: ", indent, ""); + i2a_ASN1_OBJECT(out, pinfo->policyid); + BIO_puts(out, "\n"); + if(pinfo->qualifiers) + print_qualifiers(out, pinfo->qualifiers, indent + 2); + } + return 1; +} + +static void print_qualifiers(BIO *out, STACK_OF(POLICYQUALINFO) *quals, + int indent) +{ + POLICYQUALINFO *qualinfo; + size_t i; + for(i = 0; i < sk_POLICYQUALINFO_num(quals); i++) { + qualinfo = sk_POLICYQUALINFO_value(quals, i); + switch(OBJ_obj2nid(qualinfo->pqualid)) + { + case NID_id_qt_cps: + BIO_printf(out, "%*sCPS: %s\n", indent, "", + qualinfo->d.cpsuri->data); + break; + + case NID_id_qt_unotice: + BIO_printf(out, "%*sUser Notice:\n", indent, ""); + print_notice(out, qualinfo->d.usernotice, indent + 2); + break; + + default: + BIO_printf(out, "%*sUnknown Qualifier: ", + indent + 2, ""); + + i2a_ASN1_OBJECT(out, qualinfo->pqualid); + BIO_puts(out, "\n"); + break; + } + } +} + +static void print_notice(BIO *out, USERNOTICE *notice, int indent) +{ + size_t i; + if(notice->noticeref) { + NOTICEREF *ref; + ref = notice->noticeref; + BIO_printf(out, "%*sOrganization: %s\n", indent, "", + ref->organization->data); + BIO_printf(out, "%*sNumber%s: ", indent, "", + sk_ASN1_INTEGER_num(ref->noticenos) > 1 ? "s" : ""); + for(i = 0; i < sk_ASN1_INTEGER_num(ref->noticenos); i++) { + ASN1_INTEGER *num; + char *tmp; + num = sk_ASN1_INTEGER_value(ref->noticenos, i); + if(i) BIO_puts(out, ", "); + tmp = i2s_ASN1_INTEGER(NULL, num); + BIO_puts(out, tmp); + OPENSSL_free(tmp); + } + BIO_puts(out, "\n"); + } + if(notice->exptext) + BIO_printf(out, "%*sExplicit Text: %s\n", indent, "", + notice->exptext->data); +} + +void X509_POLICY_NODE_print(BIO *out, X509_POLICY_NODE *node, int indent) + { + const X509_POLICY_DATA *dat = node->data; + + BIO_printf(out, "%*sPolicy: ", indent, ""); + + i2a_ASN1_OBJECT(out, dat->valid_policy); + BIO_puts(out, "\n"); + BIO_printf(out, "%*s%s\n", indent + 2, "", + node_data_critical(dat) ? "Critical" : "Non Critical"); + if (dat->qualifier_set) + print_qualifiers(out, dat->qualifier_set, indent + 2); + else + BIO_printf(out, "%*sNo Qualifiers\n", indent + 2, ""); + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_crld.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_crld.c new file mode 100644 index 00000000..3984c316 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_crld.c @@ -0,0 +1,616 @@ +/* v3_crld.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999-2008 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +static void *v2i_crld(const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval); +static int i2r_crldp(const X509V3_EXT_METHOD *method, void *pcrldp, BIO *out, + int indent); + +const X509V3_EXT_METHOD v3_crld = + { + NID_crl_distribution_points, 0, ASN1_ITEM_ref(CRL_DIST_POINTS), + 0,0,0,0, + 0,0, + 0, + v2i_crld, + i2r_crldp,0, + NULL + }; + +const X509V3_EXT_METHOD v3_freshest_crl = + { + NID_freshest_crl, 0, ASN1_ITEM_ref(CRL_DIST_POINTS), + 0,0,0,0, + 0,0, + 0, + v2i_crld, + i2r_crldp,0, + NULL + }; + +static STACK_OF(GENERAL_NAME) *gnames_from_sectname(X509V3_CTX *ctx, char *sect) + { + STACK_OF(CONF_VALUE) *gnsect; + STACK_OF(GENERAL_NAME) *gens; + if (*sect == '@') + gnsect = X509V3_get_section(ctx, sect + 1); + else + gnsect = X509V3_parse_list(sect); + if (!gnsect) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_SECTION_NOT_FOUND); + return NULL; + } + gens = v2i_GENERAL_NAMES(NULL, ctx, gnsect); + if (*sect == '@') + X509V3_section_free(ctx, gnsect); + else + sk_CONF_VALUE_pop_free(gnsect, X509V3_conf_free); + return gens; + } + +static int set_dist_point_name(DIST_POINT_NAME **pdp, X509V3_CTX *ctx, + CONF_VALUE *cnf) + { + STACK_OF(GENERAL_NAME) *fnm = NULL; + STACK_OF(X509_NAME_ENTRY) *rnm = NULL; + if (!strncmp(cnf->name, "fullname", 9)) + { + fnm = gnames_from_sectname(ctx, cnf->value); + if (!fnm) + goto err; + } + else if (!strcmp(cnf->name, "relativename")) + { + int ret; + STACK_OF(CONF_VALUE) *dnsect; + X509_NAME *nm; + nm = X509_NAME_new(); + if (!nm) + return -1; + dnsect = X509V3_get_section(ctx, cnf->value); + if (!dnsect) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_SECTION_NOT_FOUND); + return -1; + } + ret = X509V3_NAME_from_section(nm, dnsect, MBSTRING_ASC); + X509V3_section_free(ctx, dnsect); + rnm = nm->entries; + nm->entries = NULL; + X509_NAME_free(nm); + if (!ret || sk_X509_NAME_ENTRY_num(rnm) <= 0) + goto err; + /* Since its a name fragment can't have more than one + * RDNSequence + */ + if (sk_X509_NAME_ENTRY_value(rnm, + sk_X509_NAME_ENTRY_num(rnm) - 1)->set) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_MULTIPLE_RDNS); + goto err; + } + } + else + return 0; + + if (*pdp) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_DISTPOINT_ALREADY_SET); + goto err; + } + + *pdp = DIST_POINT_NAME_new(); + if (!*pdp) + goto err; + if (fnm) + { + (*pdp)->type = 0; + (*pdp)->name.fullname = fnm; + } + else + { + (*pdp)->type = 1; + (*pdp)->name.relativename = rnm; + } + + return 1; + + err: + if (fnm) + sk_GENERAL_NAME_pop_free(fnm, GENERAL_NAME_free); + if (rnm) + sk_X509_NAME_ENTRY_pop_free(rnm, X509_NAME_ENTRY_free); + return -1; + } + +static const BIT_STRING_BITNAME reason_flags[] = { +{0, "Unused", "unused"}, +{1, "Key Compromise", "keyCompromise"}, +{2, "CA Compromise", "CACompromise"}, +{3, "Affiliation Changed", "affiliationChanged"}, +{4, "Superseded", "superseded"}, +{5, "Cessation Of Operation", "cessationOfOperation"}, +{6, "Certificate Hold", "certificateHold"}, +{7, "Privilege Withdrawn", "privilegeWithdrawn"}, +{8, "AA Compromise", "AACompromise"}, +{-1, NULL, NULL} +}; + +static int set_reasons(ASN1_BIT_STRING **preas, char *value) + { + STACK_OF(CONF_VALUE) *rsk = NULL; + const BIT_STRING_BITNAME *pbn; + const char *bnam; + size_t i; + int ret = 0; + rsk = X509V3_parse_list(value); + if (!rsk) + return 0; + if (*preas) + return 0; + for (i = 0; i < sk_CONF_VALUE_num(rsk); i++) + { + bnam = sk_CONF_VALUE_value(rsk, i)->name; + if (!*preas) + { + *preas = ASN1_BIT_STRING_new(); + if (!*preas) + goto err; + } + for (pbn = reason_flags; pbn->lname; pbn++) + { + if (!strcmp(pbn->sname, bnam)) + { + if (!ASN1_BIT_STRING_set_bit(*preas, + pbn->bitnum, 1)) + goto err; + break; + } + } + if (!pbn->lname) + goto err; + } + ret = 1; + + err: + sk_CONF_VALUE_pop_free(rsk, X509V3_conf_free); + return ret; + } + +static int print_reasons(BIO *out, const char *rname, + ASN1_BIT_STRING *rflags, int indent) + { + int first = 1; + const BIT_STRING_BITNAME *pbn; + BIO_printf(out, "%*s%s:\n%*s", indent, "", rname, indent + 2, ""); + for (pbn = reason_flags; pbn->lname; pbn++) + { + if (ASN1_BIT_STRING_get_bit(rflags, pbn->bitnum)) + { + if (first) + first = 0; + else + BIO_puts(out, ", "); + BIO_puts(out, pbn->lname); + } + } + if (first) + BIO_puts(out, "\n"); + else + BIO_puts(out, "\n"); + return 1; + } + +static DIST_POINT *crldp_from_section(X509V3_CTX *ctx, + STACK_OF(CONF_VALUE) *nval) + { + size_t i; + CONF_VALUE *cnf; + DIST_POINT *point = NULL; + point = DIST_POINT_new(); + if (!point) + goto err; + for(i = 0; i < sk_CONF_VALUE_num(nval); i++) + { + int ret; + cnf = sk_CONF_VALUE_value(nval, i); + ret = set_dist_point_name(&point->distpoint, ctx, cnf); + if (ret > 0) + continue; + if (ret < 0) + goto err; + if (!strcmp(cnf->name, "reasons")) + { + if (!set_reasons(&point->reasons, cnf->value)) + goto err; + } + else if (!strcmp(cnf->name, "CRLissuer")) + { + point->CRLissuer = + gnames_from_sectname(ctx, cnf->value); + if (!point->CRLissuer) + goto err; + } + } + + return point; + + + err: + if (point) + DIST_POINT_free(point); + return NULL; + } + +static void *v2i_crld(const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval) + { + STACK_OF(DIST_POINT) *crld = NULL; + GENERAL_NAMES *gens = NULL; + GENERAL_NAME *gen = NULL; + CONF_VALUE *cnf; + size_t i; + if(!(crld = sk_DIST_POINT_new_null())) goto merr; + for(i = 0; i < sk_CONF_VALUE_num(nval); i++) { + DIST_POINT *point; + cnf = sk_CONF_VALUE_value(nval, i); + if (!cnf->value) + { + STACK_OF(CONF_VALUE) *dpsect; + dpsect = X509V3_get_section(ctx, cnf->name); + if (!dpsect) + goto err; + point = crldp_from_section(ctx, dpsect); + X509V3_section_free(ctx, dpsect); + if (!point) + goto err; + if(!sk_DIST_POINT_push(crld, point)) + { + DIST_POINT_free(point); + goto merr; + } + } + else + { + if(!(gen = v2i_GENERAL_NAME(method, ctx, cnf))) + goto err; + if(!(gens = GENERAL_NAMES_new())) + goto merr; + if(!sk_GENERAL_NAME_push(gens, gen)) + goto merr; + gen = NULL; + if(!(point = DIST_POINT_new())) + goto merr; + if(!sk_DIST_POINT_push(crld, point)) + { + DIST_POINT_free(point); + goto merr; + } + if(!(point->distpoint = DIST_POINT_NAME_new())) + goto merr; + point->distpoint->name.fullname = gens; + point->distpoint->type = 0; + gens = NULL; + } + } + return crld; + + merr: + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + err: + GENERAL_NAME_free(gen); + GENERAL_NAMES_free(gens); + sk_DIST_POINT_pop_free(crld, DIST_POINT_free); + return NULL; +} + +IMPLEMENT_ASN1_SET_OF(DIST_POINT) + +static int dpn_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, + void *exarg) + { + DIST_POINT_NAME *dpn = (DIST_POINT_NAME *)*pval; + + switch(operation) + { + case ASN1_OP_NEW_POST: + dpn->dpname = NULL; + break; + + case ASN1_OP_FREE_POST: + if (dpn->dpname) + X509_NAME_free(dpn->dpname); + break; + } + return 1; + } + + +ASN1_CHOICE_cb(DIST_POINT_NAME, dpn_cb) = { + ASN1_IMP_SEQUENCE_OF(DIST_POINT_NAME, name.fullname, GENERAL_NAME, 0), + ASN1_IMP_SET_OF(DIST_POINT_NAME, name.relativename, X509_NAME_ENTRY, 1) +} ASN1_CHOICE_END_cb(DIST_POINT_NAME, DIST_POINT_NAME, type) + + +IMPLEMENT_ASN1_FUNCTIONS(DIST_POINT_NAME) + +ASN1_SEQUENCE(DIST_POINT) = { + ASN1_EXP_OPT(DIST_POINT, distpoint, DIST_POINT_NAME, 0), + ASN1_IMP_OPT(DIST_POINT, reasons, ASN1_BIT_STRING, 1), + ASN1_IMP_SEQUENCE_OF_OPT(DIST_POINT, CRLissuer, GENERAL_NAME, 2) +} ASN1_SEQUENCE_END(DIST_POINT) + +IMPLEMENT_ASN1_FUNCTIONS(DIST_POINT) + +ASN1_ITEM_TEMPLATE(CRL_DIST_POINTS) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, CRLDistributionPoints, DIST_POINT) +ASN1_ITEM_TEMPLATE_END(CRL_DIST_POINTS) + +IMPLEMENT_ASN1_FUNCTIONS(CRL_DIST_POINTS) + +ASN1_SEQUENCE(ISSUING_DIST_POINT) = { + ASN1_EXP_OPT(ISSUING_DIST_POINT, distpoint, DIST_POINT_NAME, 0), + ASN1_IMP_OPT(ISSUING_DIST_POINT, onlyuser, ASN1_FBOOLEAN, 1), + ASN1_IMP_OPT(ISSUING_DIST_POINT, onlyCA, ASN1_FBOOLEAN, 2), + ASN1_IMP_OPT(ISSUING_DIST_POINT, onlysomereasons, ASN1_BIT_STRING, 3), + ASN1_IMP_OPT(ISSUING_DIST_POINT, indirectCRL, ASN1_FBOOLEAN, 4), + ASN1_IMP_OPT(ISSUING_DIST_POINT, onlyattr, ASN1_FBOOLEAN, 5) +} ASN1_SEQUENCE_END(ISSUING_DIST_POINT) + +IMPLEMENT_ASN1_FUNCTIONS(ISSUING_DIST_POINT) + +static int i2r_idp(const X509V3_EXT_METHOD *method, void *pidp, BIO *out, + int indent); +static void *v2i_idp(const X509V3_EXT_METHOD *method, X509V3_CTX *ctx, + STACK_OF(CONF_VALUE) *nval); + +const X509V3_EXT_METHOD v3_idp = + { + NID_issuing_distribution_point, X509V3_EXT_MULTILINE, + ASN1_ITEM_ref(ISSUING_DIST_POINT), + 0,0,0,0, + 0,0, + 0, + v2i_idp, + i2r_idp,0, + NULL + }; + +static void *v2i_idp(const X509V3_EXT_METHOD *method, X509V3_CTX *ctx, + STACK_OF(CONF_VALUE) *nval) + { + ISSUING_DIST_POINT *idp = NULL; + CONF_VALUE *cnf; + char *name, *val; + size_t i; + int ret; + idp = ISSUING_DIST_POINT_new(); + if (!idp) + goto merr; + for(i = 0; i < sk_CONF_VALUE_num(nval); i++) + { + cnf = sk_CONF_VALUE_value(nval, i); + name = cnf->name; + val = cnf->value; + ret = set_dist_point_name(&idp->distpoint, ctx, cnf); + if (ret > 0) + continue; + if (ret < 0) + goto err; + if (!strcmp(name, "onlyuser")) + { + if (!X509V3_get_value_bool(cnf, &idp->onlyuser)) + goto err; + } + else if (!strcmp(name, "onlyCA")) + { + if (!X509V3_get_value_bool(cnf, &idp->onlyCA)) + goto err; + } + else if (!strcmp(name, "onlyAA")) + { + if (!X509V3_get_value_bool(cnf, &idp->onlyattr)) + goto err; + } + else if (!strcmp(name, "indirectCRL")) + { + if (!X509V3_get_value_bool(cnf, &idp->indirectCRL)) + goto err; + } + else if (!strcmp(name, "onlysomereasons")) + { + if (!set_reasons(&idp->onlysomereasons, val)) + goto err; + } + else + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NAME); + X509V3_conf_err(cnf); + goto err; + } + } + return idp; + + merr: + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + err: + ISSUING_DIST_POINT_free(idp); + return NULL; + } + +static int print_gens(BIO *out, STACK_OF(GENERAL_NAME) *gens, int indent) + { + size_t i; + for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) + { + BIO_printf(out, "%*s", indent + 2, ""); + GENERAL_NAME_print(out, sk_GENERAL_NAME_value(gens, i)); + BIO_puts(out, "\n"); + } + return 1; + } + +static int print_distpoint(BIO *out, DIST_POINT_NAME *dpn, int indent) + { + if (dpn->type == 0) + { + BIO_printf(out, "%*sFull Name:\n", indent, ""); + print_gens(out, dpn->name.fullname, indent); + } + else + { + X509_NAME ntmp; + ntmp.entries = dpn->name.relativename; + BIO_printf(out, "%*sRelative Name:\n%*s", + indent, "", indent + 2, ""); + X509_NAME_print_ex(out, &ntmp, 0, XN_FLAG_ONELINE); + BIO_puts(out, "\n"); + } + return 1; + } + +static int i2r_idp(const X509V3_EXT_METHOD *method, void *pidp, BIO *out, + int indent) + { + ISSUING_DIST_POINT *idp = pidp; + if (idp->distpoint) + print_distpoint(out, idp->distpoint, indent); + if (idp->onlyuser > 0) + BIO_printf(out, "%*sOnly User Certificates\n", indent, ""); + if (idp->onlyCA > 0) + BIO_printf(out, "%*sOnly CA Certificates\n", indent, ""); + if (idp->indirectCRL > 0) + BIO_printf(out, "%*sIndirect CRL\n", indent, ""); + if (idp->onlysomereasons) + print_reasons(out, "Only Some Reasons", + idp->onlysomereasons, indent); + if (idp->onlyattr > 0) + BIO_printf(out, "%*sOnly Attribute Certificates\n", indent, ""); + if (!idp->distpoint && (idp->onlyuser <= 0) && (idp->onlyCA <= 0) + && (idp->indirectCRL <= 0) && !idp->onlysomereasons + && (idp->onlyattr <= 0)) + BIO_printf(out, "%*s\n", indent, ""); + + return 1; + } + +static int i2r_crldp(const X509V3_EXT_METHOD *method, void *pcrldp, BIO *out, + int indent) + { + STACK_OF(DIST_POINT) *crld = pcrldp; + DIST_POINT *point; + size_t i; + for(i = 0; i < sk_DIST_POINT_num(crld); i++) + { + BIO_puts(out, "\n"); + point = sk_DIST_POINT_value(crld, i); + if(point->distpoint) + print_distpoint(out, point->distpoint, indent); + if(point->reasons) + print_reasons(out, "Reasons", point->reasons, + indent); + if(point->CRLissuer) + { + BIO_printf(out, "%*sCRL Issuer:\n", indent, ""); + print_gens(out, point->CRLissuer, indent); + } + } + return 1; + } + +int DIST_POINT_set_dpname(DIST_POINT_NAME *dpn, X509_NAME *iname) + { + size_t i; + STACK_OF(X509_NAME_ENTRY) *frag; + X509_NAME_ENTRY *ne; + if (!dpn || (dpn->type != 1)) + return 1; + frag = dpn->name.relativename; + dpn->dpname = X509_NAME_dup(iname); + if (!dpn->dpname) + return 0; + for (i = 0; i < sk_X509_NAME_ENTRY_num(frag); i++) + { + ne = sk_X509_NAME_ENTRY_value(frag, i); + if (!X509_NAME_add_entry(dpn->dpname, ne, -1, i ? 0 : 1)) + { + X509_NAME_free(dpn->dpname); + dpn->dpname = NULL; + return 0; + } + } + /* generate cached encoding of name */ + if (i2d_X509_NAME(dpn->dpname, NULL) < 0) + { + X509_NAME_free(dpn->dpname); + dpn->dpname = NULL; + return 0; + } + return 1; + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_enum.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_enum.c new file mode 100644 index 00000000..0fe6bb63 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_enum.c @@ -0,0 +1,98 @@ +/* v3_enum.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include + + +static const ENUMERATED_NAMES crl_reasons[] = { +{CRL_REASON_UNSPECIFIED, "Unspecified", "unspecified"}, +{CRL_REASON_KEY_COMPROMISE, "Key Compromise", "keyCompromise"}, +{CRL_REASON_CA_COMPROMISE, "CA Compromise", "CACompromise"}, +{CRL_REASON_AFFILIATION_CHANGED, "Affiliation Changed", "affiliationChanged"}, +{CRL_REASON_SUPERSEDED, "Superseded", "superseded"}, +{CRL_REASON_CESSATION_OF_OPERATION, + "Cessation Of Operation", "cessationOfOperation"}, +{CRL_REASON_CERTIFICATE_HOLD, "Certificate Hold", "certificateHold"}, +{CRL_REASON_REMOVE_FROM_CRL, "Remove From CRL", "removeFromCRL"}, +{CRL_REASON_PRIVILEGE_WITHDRAWN, "Privilege Withdrawn", "privilegeWithdrawn"}, +{CRL_REASON_AA_COMPROMISE, "AA Compromise", "AACompromise"}, +{-1, NULL, NULL} +}; + +const X509V3_EXT_METHOD v3_crl_reason = { +NID_crl_reason, 0, ASN1_ITEM_ref(ASN1_ENUMERATED), +0,0,0,0, +(X509V3_EXT_I2S)i2s_ASN1_ENUMERATED_TABLE, +0, +0,0,0,0, +(void *)crl_reasons}; + + +char *i2s_ASN1_ENUMERATED_TABLE(X509V3_EXT_METHOD *method, + ASN1_ENUMERATED *e) +{ + const ENUMERATED_NAMES *enam; + long strval; + strval = ASN1_ENUMERATED_get(e); + for(enam = method->usr_data; enam->lname; enam++) { + if(strval == enam->bitnum) return BUF_strdup(enam->lname); + } + return i2s_ASN1_ENUMERATED(method, e); +} diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_extku.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_extku.c new file mode 100644 index 00000000..d64eb9cc --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_extku.c @@ -0,0 +1,145 @@ +/* v3_extku.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + + +#include + +#include +#include +#include +#include +#include + + +static void *v2i_EXTENDED_KEY_USAGE(const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, + STACK_OF(CONF_VALUE) *nval); +static STACK_OF(CONF_VALUE) *i2v_EXTENDED_KEY_USAGE(const X509V3_EXT_METHOD *method, + void *eku, STACK_OF(CONF_VALUE) *extlist); + +const X509V3_EXT_METHOD v3_ext_ku = { + NID_ext_key_usage, 0, + ASN1_ITEM_ref(EXTENDED_KEY_USAGE), + 0,0,0,0, + 0,0, + i2v_EXTENDED_KEY_USAGE, + v2i_EXTENDED_KEY_USAGE, + 0,0, + NULL +}; + +/* NB OCSP acceptable responses also is a SEQUENCE OF OBJECT */ +const X509V3_EXT_METHOD v3_ocsp_accresp = { + NID_id_pkix_OCSP_acceptableResponses, 0, + ASN1_ITEM_ref(EXTENDED_KEY_USAGE), + 0,0,0,0, + 0,0, + i2v_EXTENDED_KEY_USAGE, + v2i_EXTENDED_KEY_USAGE, + 0,0, + NULL +}; + +ASN1_ITEM_TEMPLATE(EXTENDED_KEY_USAGE) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, EXTENDED_KEY_USAGE, ASN1_OBJECT) +ASN1_ITEM_TEMPLATE_END(EXTENDED_KEY_USAGE) + +IMPLEMENT_ASN1_FUNCTIONS(EXTENDED_KEY_USAGE) + +static STACK_OF(CONF_VALUE) * + i2v_EXTENDED_KEY_USAGE(const X509V3_EXT_METHOD *method, void *a, + STACK_OF(CONF_VALUE) *ext_list) +{ + EXTENDED_KEY_USAGE *eku = a; + size_t i; + ASN1_OBJECT *obj; + char obj_tmp[80]; + for(i = 0; i < sk_ASN1_OBJECT_num(eku); i++) { + obj = sk_ASN1_OBJECT_value(eku, i); + i2t_ASN1_OBJECT(obj_tmp, 80, obj); + X509V3_add_value(NULL, obj_tmp, &ext_list); + } + return ext_list; +} + +static void *v2i_EXTENDED_KEY_USAGE(const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval) +{ + EXTENDED_KEY_USAGE *extku; + char *extval; + ASN1_OBJECT *objtmp; + CONF_VALUE *val; + size_t i; + + if(!(extku = sk_ASN1_OBJECT_new_null())) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + + for(i = 0; i < sk_CONF_VALUE_num(nval); i++) { + val = sk_CONF_VALUE_value(nval, i); + if(val->value) extval = val->value; + else extval = val->name; + if(!(objtmp = OBJ_txt2obj(extval, 0))) { + sk_ASN1_OBJECT_pop_free(extku, ASN1_OBJECT_free); + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_OBJECT_IDENTIFIER); + X509V3_conf_err(val); + return NULL; + } + sk_ASN1_OBJECT_push(extku, objtmp); + } + return extku; +} diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_genn.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_genn.c new file mode 100644 index 00000000..8b0a68d4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_genn.c @@ -0,0 +1,252 @@ +/* v3_genn.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999-2008 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + + +#include + +#include +#include +#include +#include + + +ASN1_SEQUENCE(OTHERNAME) = { + ASN1_SIMPLE(OTHERNAME, type_id, ASN1_OBJECT), + /* Maybe have a true ANY DEFINED BY later */ + ASN1_EXP(OTHERNAME, value, ASN1_ANY, 0) +} ASN1_SEQUENCE_END(OTHERNAME) + +IMPLEMENT_ASN1_FUNCTIONS(OTHERNAME) + +ASN1_SEQUENCE(EDIPARTYNAME) = { + ASN1_IMP_OPT(EDIPARTYNAME, nameAssigner, DIRECTORYSTRING, 0), + ASN1_IMP_OPT(EDIPARTYNAME, partyName, DIRECTORYSTRING, 1) +} ASN1_SEQUENCE_END(EDIPARTYNAME) + +IMPLEMENT_ASN1_FUNCTIONS(EDIPARTYNAME) + +ASN1_CHOICE(GENERAL_NAME) = { + ASN1_IMP(GENERAL_NAME, d.otherName, OTHERNAME, GEN_OTHERNAME), + ASN1_IMP(GENERAL_NAME, d.rfc822Name, ASN1_IA5STRING, GEN_EMAIL), + ASN1_IMP(GENERAL_NAME, d.dNSName, ASN1_IA5STRING, GEN_DNS), + /* Don't decode this */ + ASN1_IMP(GENERAL_NAME, d.x400Address, ASN1_SEQUENCE, GEN_X400), + /* X509_NAME is a CHOICE type so use EXPLICIT */ + ASN1_EXP(GENERAL_NAME, d.directoryName, X509_NAME, GEN_DIRNAME), + ASN1_IMP(GENERAL_NAME, d.ediPartyName, EDIPARTYNAME, GEN_EDIPARTY), + ASN1_IMP(GENERAL_NAME, d.uniformResourceIdentifier, ASN1_IA5STRING, GEN_URI), + ASN1_IMP(GENERAL_NAME, d.iPAddress, ASN1_OCTET_STRING, GEN_IPADD), + ASN1_IMP(GENERAL_NAME, d.registeredID, ASN1_OBJECT, GEN_RID) +} ASN1_CHOICE_END(GENERAL_NAME) + +IMPLEMENT_ASN1_FUNCTIONS(GENERAL_NAME) + +ASN1_ITEM_TEMPLATE(GENERAL_NAMES) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, GeneralNames, GENERAL_NAME) +ASN1_ITEM_TEMPLATE_END(GENERAL_NAMES) + +IMPLEMENT_ASN1_FUNCTIONS(GENERAL_NAMES) + +GENERAL_NAME *GENERAL_NAME_dup(GENERAL_NAME *a) + { + return (GENERAL_NAME *) ASN1_dup((i2d_of_void *) i2d_GENERAL_NAME, + (d2i_of_void *) d2i_GENERAL_NAME, + (char *) a); + } + +/* Returns 0 if they are equal, != 0 otherwise. */ +int GENERAL_NAME_cmp(GENERAL_NAME *a, GENERAL_NAME *b) + { + int result = -1; + + if (!a || !b || a->type != b->type) return -1; + switch(a->type) + { + case GEN_X400: + case GEN_EDIPARTY: + result = ASN1_TYPE_cmp(a->d.other, b->d.other); + break; + + case GEN_OTHERNAME: + result = OTHERNAME_cmp(a->d.otherName, b->d.otherName); + break; + + case GEN_EMAIL: + case GEN_DNS: + case GEN_URI: + result = ASN1_STRING_cmp(a->d.ia5, b->d.ia5); + break; + + case GEN_DIRNAME: + result = X509_NAME_cmp(a->d.dirn, b->d.dirn); + break; + + case GEN_IPADD: + result = ASN1_OCTET_STRING_cmp(a->d.ip, b->d.ip); + break; + + case GEN_RID: + result = OBJ_cmp(a->d.rid, b->d.rid); + break; + } + return result; + } + +/* Returns 0 if they are equal, != 0 otherwise. */ +int OTHERNAME_cmp(OTHERNAME *a, OTHERNAME *b) + { + int result = -1; + + if (!a || !b) return -1; + /* Check their type first. */ + if ((result = OBJ_cmp(a->type_id, b->type_id)) != 0) + return result; + /* Check the value. */ + result = ASN1_TYPE_cmp(a->value, b->value); + return result; + } + +void GENERAL_NAME_set0_value(GENERAL_NAME *a, int type, void *value) + { + switch(type) + { + case GEN_X400: + case GEN_EDIPARTY: + a->d.other = value; + break; + + case GEN_OTHERNAME: + a->d.otherName = value; + break; + + case GEN_EMAIL: + case GEN_DNS: + case GEN_URI: + a->d.ia5 = value; + break; + + case GEN_DIRNAME: + a->d.dirn = value; + break; + + case GEN_IPADD: + a->d.ip = value; + break; + + case GEN_RID: + a->d.rid = value; + break; + } + a->type = type; + } + +void *GENERAL_NAME_get0_value(GENERAL_NAME *a, int *ptype) + { + if (ptype) + *ptype = a->type; + switch(a->type) + { + case GEN_X400: + case GEN_EDIPARTY: + return a->d.other; + + case GEN_OTHERNAME: + return a->d.otherName; + + case GEN_EMAIL: + case GEN_DNS: + case GEN_URI: + return a->d.ia5; + + case GEN_DIRNAME: + return a->d.dirn; + + case GEN_IPADD: + return a->d.ip; + + case GEN_RID: + return a->d.rid; + + default: + return NULL; + } + } + +int GENERAL_NAME_set0_othername(GENERAL_NAME *gen, + ASN1_OBJECT *oid, ASN1_TYPE *value) + { + OTHERNAME *oth; + oth = OTHERNAME_new(); + if (!oth) + return 0; + oth->type_id = oid; + oth->value = value; + GENERAL_NAME_set0_value(gen, GEN_OTHERNAME, oth); + return 1; + } + +int GENERAL_NAME_get0_otherName(GENERAL_NAME *gen, + ASN1_OBJECT **poid, ASN1_TYPE **pvalue) + { + if (gen->type != GEN_OTHERNAME) + return 0; + if (poid) + *poid = gen->d.otherName->type_id; + if (pvalue) + *pvalue = gen->d.otherName->value; + return 1; + } + diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_ia5.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_ia5.c new file mode 100644 index 00000000..5a272335 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_ia5.c @@ -0,0 +1,117 @@ +/* v3_ia5.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + + +static char *i2s_ASN1_IA5STRING(X509V3_EXT_METHOD *method, ASN1_IA5STRING *ia5); +static ASN1_IA5STRING *s2i_ASN1_IA5STRING(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, char *str); +const X509V3_EXT_METHOD v3_ns_ia5_list[] = { +EXT_IA5STRING(NID_netscape_base_url), +EXT_IA5STRING(NID_netscape_revocation_url), +EXT_IA5STRING(NID_netscape_ca_revocation_url), +EXT_IA5STRING(NID_netscape_renewal_url), +EXT_IA5STRING(NID_netscape_ca_policy_url), +EXT_IA5STRING(NID_netscape_ssl_server_name), +EXT_IA5STRING(NID_netscape_comment), +EXT_END +}; + + +static char *i2s_ASN1_IA5STRING(X509V3_EXT_METHOD *method, + ASN1_IA5STRING *ia5) +{ + char *tmp; + if(!ia5 || !ia5->length) return NULL; + if(!(tmp = OPENSSL_malloc(ia5->length + 1))) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + memcpy(tmp, ia5->data, ia5->length); + tmp[ia5->length] = 0; + return tmp; +} + +static ASN1_IA5STRING *s2i_ASN1_IA5STRING(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, char *str) +{ + ASN1_IA5STRING *ia5; + if(!str) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NULL_ARGUMENT); + return NULL; + } + if(!(ia5 = M_ASN1_IA5STRING_new())) goto err; + if(!ASN1_STRING_set((ASN1_STRING *)ia5, (unsigned char*)str, + strlen(str))) { + M_ASN1_IA5STRING_free(ia5); + goto err; + } + return ia5; + err: + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; +} + diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_info.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_info.c new file mode 100644 index 00000000..475c56f7 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_info.c @@ -0,0 +1,200 @@ +/* v3_info.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +static STACK_OF(CONF_VALUE) *i2v_AUTHORITY_INFO_ACCESS(X509V3_EXT_METHOD *method, + AUTHORITY_INFO_ACCESS *ainfo, + STACK_OF(CONF_VALUE) *ret); +static AUTHORITY_INFO_ACCESS *v2i_AUTHORITY_INFO_ACCESS(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval); + +const X509V3_EXT_METHOD v3_info = +{ NID_info_access, X509V3_EXT_MULTILINE, ASN1_ITEM_ref(AUTHORITY_INFO_ACCESS), +0,0,0,0, +0,0, +(X509V3_EXT_I2V)i2v_AUTHORITY_INFO_ACCESS, +(X509V3_EXT_V2I)v2i_AUTHORITY_INFO_ACCESS, +0,0, +NULL}; + +const X509V3_EXT_METHOD v3_sinfo = +{ NID_sinfo_access, X509V3_EXT_MULTILINE, ASN1_ITEM_ref(AUTHORITY_INFO_ACCESS), +0,0,0,0, +0,0, +(X509V3_EXT_I2V)i2v_AUTHORITY_INFO_ACCESS, +(X509V3_EXT_V2I)v2i_AUTHORITY_INFO_ACCESS, +0,0, +NULL}; + +ASN1_SEQUENCE(ACCESS_DESCRIPTION) = { + ASN1_SIMPLE(ACCESS_DESCRIPTION, method, ASN1_OBJECT), + ASN1_SIMPLE(ACCESS_DESCRIPTION, location, GENERAL_NAME) +} ASN1_SEQUENCE_END(ACCESS_DESCRIPTION) + +IMPLEMENT_ASN1_FUNCTIONS(ACCESS_DESCRIPTION) + +ASN1_ITEM_TEMPLATE(AUTHORITY_INFO_ACCESS) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, GeneralNames, ACCESS_DESCRIPTION) +ASN1_ITEM_TEMPLATE_END(AUTHORITY_INFO_ACCESS) + +IMPLEMENT_ASN1_FUNCTIONS(AUTHORITY_INFO_ACCESS) + +static STACK_OF(CONF_VALUE) *i2v_AUTHORITY_INFO_ACCESS(X509V3_EXT_METHOD *method, + AUTHORITY_INFO_ACCESS *ainfo, + STACK_OF(CONF_VALUE) *ret) +{ + ACCESS_DESCRIPTION *desc; + size_t i; + int nlen; + char objtmp[80], *ntmp; + CONF_VALUE *vtmp; + for(i = 0; i < sk_ACCESS_DESCRIPTION_num(ainfo); i++) { + desc = sk_ACCESS_DESCRIPTION_value(ainfo, i); + ret = i2v_GENERAL_NAME(method, desc->location, ret); + if(!ret) break; + vtmp = sk_CONF_VALUE_value(ret, i); + i2t_ASN1_OBJECT(objtmp, sizeof objtmp, desc->method); + nlen = strlen(objtmp) + strlen(vtmp->name) + 5; + ntmp = OPENSSL_malloc(nlen); + if(!ntmp) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + BUF_strlcpy(ntmp, objtmp, nlen); + BUF_strlcat(ntmp, " - ", nlen); + BUF_strlcat(ntmp, vtmp->name, nlen); + OPENSSL_free(vtmp->name); + vtmp->name = ntmp; + + } + if(!ret) return sk_CONF_VALUE_new_null(); + return ret; +} + +static AUTHORITY_INFO_ACCESS *v2i_AUTHORITY_INFO_ACCESS(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval) +{ + AUTHORITY_INFO_ACCESS *ainfo = NULL; + CONF_VALUE *cnf, ctmp; + ACCESS_DESCRIPTION *acc; + size_t i; + int objlen; + char *objtmp, *ptmp; + if(!(ainfo = sk_ACCESS_DESCRIPTION_new_null())) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + for(i = 0; i < sk_CONF_VALUE_num(nval); i++) { + cnf = sk_CONF_VALUE_value(nval, i); + if(!(acc = ACCESS_DESCRIPTION_new()) + || !sk_ACCESS_DESCRIPTION_push(ainfo, acc)) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + goto err; + } + ptmp = strchr(cnf->name, ';'); + if(!ptmp) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_SYNTAX); + goto err; + } + objlen = ptmp - cnf->name; + ctmp.name = ptmp + 1; + ctmp.value = cnf->value; + if(!v2i_GENERAL_NAME_ex(acc->location, method, ctx, &ctmp, 0)) + goto err; + if(!(objtmp = OPENSSL_malloc(objlen + 1))) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + goto err; + } + strncpy(objtmp, cnf->name, objlen); + objtmp[objlen] = 0; + acc->method = OBJ_txt2obj(objtmp, 0); + if(!acc->method) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_BAD_OBJECT); + ERR_add_error_data(2, "value=", objtmp); + OPENSSL_free(objtmp); + goto err; + } + OPENSSL_free(objtmp); + + } + return ainfo; + err: + sk_ACCESS_DESCRIPTION_pop_free(ainfo, ACCESS_DESCRIPTION_free); + return NULL; +} + +int i2a_ACCESS_DESCRIPTION(BIO *bp, ACCESS_DESCRIPTION* a) + { + i2a_ASN1_OBJECT(bp, a->method); +#ifdef UNDEF + i2a_GENERAL_NAME(bp, a->location); +#endif + return 2; + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_int.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_int.c new file mode 100644 index 00000000..8ca23bd7 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_int.c @@ -0,0 +1,87 @@ +/* v3_int.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999-2004 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include + + +const X509V3_EXT_METHOD v3_crl_num = { + NID_crl_number, 0, ASN1_ITEM_ref(ASN1_INTEGER), + 0,0,0,0, + (X509V3_EXT_I2S)i2s_ASN1_INTEGER, + 0, + 0,0,0,0, NULL}; + +const X509V3_EXT_METHOD v3_delta_crl = { + NID_delta_crl, 0, ASN1_ITEM_ref(ASN1_INTEGER), + 0,0,0,0, + (X509V3_EXT_I2S)i2s_ASN1_INTEGER, + 0, + 0,0,0,0, NULL}; + +static void * s2i_asn1_int(X509V3_EXT_METHOD *meth, X509V3_CTX *ctx, char *value) + { + return s2i_ASN1_INTEGER(meth, value); + } + +const X509V3_EXT_METHOD v3_inhibit_anyp = { + NID_inhibit_any_policy, 0, ASN1_ITEM_ref(ASN1_INTEGER), + 0,0,0,0, + (X509V3_EXT_I2S)i2s_ASN1_INTEGER, + (X509V3_EXT_S2I)s2i_asn1_int, + 0,0,0,0, NULL}; diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_lib.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_lib.c new file mode 100644 index 00000000..f8e5531d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_lib.c @@ -0,0 +1,335 @@ +/* v3_lib.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* X509 v3 extension utilities */ + +#include + +#include +#include +#include +#include +#include + +#include "ext_dat.h" +static STACK_OF(X509V3_EXT_METHOD) *ext_list = NULL; + +static void ext_list_free(X509V3_EXT_METHOD *ext); + +static int ext_stack_cmp(const X509V3_EXT_METHOD **a, const X509V3_EXT_METHOD **b) +{ + return ((*a)->ext_nid - (*b)->ext_nid); +} + +int X509V3_EXT_add(X509V3_EXT_METHOD *ext) +{ + if(!ext_list && !(ext_list = sk_X509V3_EXT_METHOD_new(ext_stack_cmp))) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + ext_list_free(ext); + return 0; + } + if(!sk_X509V3_EXT_METHOD_push(ext_list, ext)) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + ext_list_free(ext); + return 0; + } + return 1; +} + +static int ext_cmp(const void *void_a, + const void *void_b) +{ + const X509V3_EXT_METHOD **a = (const X509V3_EXT_METHOD**) void_a; + const X509V3_EXT_METHOD **b = (const X509V3_EXT_METHOD**) void_b; + return ext_stack_cmp(a, b); +} + +const X509V3_EXT_METHOD *X509V3_EXT_get_nid(int nid) +{ + X509V3_EXT_METHOD tmp; + const X509V3_EXT_METHOD *t = &tmp, * const *ret; + size_t idx; + + if(nid < 0) return NULL; + tmp.ext_nid = nid; + ret = bsearch(&t, standard_exts, STANDARD_EXTENSION_COUNT, sizeof(X509V3_EXT_METHOD*), ext_cmp); + if(ret) return *ret; + if(!ext_list) return NULL; + + if (!sk_X509V3_EXT_METHOD_find(ext_list, &idx, &tmp)) + return NULL; + return sk_X509V3_EXT_METHOD_value(ext_list, idx); +} + +const X509V3_EXT_METHOD *X509V3_EXT_get(X509_EXTENSION *ext) +{ + int nid; + if((nid = OBJ_obj2nid(ext->object)) == NID_undef) return NULL; + return X509V3_EXT_get_nid(nid); +} + +int X509V3_EXT_free(int nid, void *ext_data) +{ + const X509V3_EXT_METHOD *ext_method = X509V3_EXT_get_nid(nid); + if (ext_method == NULL) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_CANNOT_FIND_FREE_FUNCTION); + return 0; + } + + if (ext_method->it != NULL) + ASN1_item_free(ext_data, ASN1_ITEM_ptr(ext_method->it)); + else if (ext_method->ext_free != NULL) + ext_method->ext_free(ext_data); + else + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_CANNOT_FIND_FREE_FUNCTION); + return 0; + } + + return 1; +} + +int X509V3_EXT_add_list(X509V3_EXT_METHOD *extlist) +{ + for(;extlist->ext_nid!=-1;extlist++) + if(!X509V3_EXT_add(extlist)) return 0; + return 1; +} + +int X509V3_EXT_add_alias(int nid_to, int nid_from) +{ + const X509V3_EXT_METHOD *ext; + X509V3_EXT_METHOD *tmpext; + + if(!(ext = X509V3_EXT_get_nid(nid_from))) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_EXTENSION_NOT_FOUND); + return 0; + } + if(!(tmpext = (X509V3_EXT_METHOD *)OPENSSL_malloc(sizeof(X509V3_EXT_METHOD)))) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return 0; + } + *tmpext = *ext; + tmpext->ext_nid = nid_to; + tmpext->ext_flags |= X509V3_EXT_DYNAMIC; + return X509V3_EXT_add(tmpext); +} + +void X509V3_EXT_cleanup(void) +{ + sk_X509V3_EXT_METHOD_pop_free(ext_list, ext_list_free); + ext_list = NULL; +} + +static void ext_list_free(X509V3_EXT_METHOD *ext) +{ + if(ext->ext_flags & X509V3_EXT_DYNAMIC) OPENSSL_free(ext); +} + +/* Legacy function: we don't need to add standard extensions + * any more because they are now kept in ext_dat.h. + */ + +int X509V3_add_standard_extensions(void) +{ + return 1; +} + +/* Return an extension internal structure */ + +void *X509V3_EXT_d2i(X509_EXTENSION *ext) +{ + const X509V3_EXT_METHOD *method; + const unsigned char *p; + + if(!(method = X509V3_EXT_get(ext))) return NULL; + p = ext->value->data; + if(method->it) return ASN1_item_d2i(NULL, &p, ext->value->length, ASN1_ITEM_ptr(method->it)); + return method->d2i(NULL, &p, ext->value->length); +} + +/* Get critical flag and decoded version of extension from a NID. + * The "idx" variable returns the last found extension and can + * be used to retrieve multiple extensions of the same NID. + * However multiple extensions with the same NID is usually + * due to a badly encoded certificate so if idx is NULL we + * choke if multiple extensions exist. + * The "crit" variable is set to the critical value. + * The return value is the decoded extension or NULL on + * error. The actual error can have several different causes, + * the value of *crit reflects the cause: + * >= 0, extension found but not decoded (reflects critical value). + * -1 extension not found. + * -2 extension occurs more than once. + */ + +void *X509V3_get_d2i(STACK_OF(X509_EXTENSION) *x, int nid, int *crit, int *idx) +{ + int lastpos; + size_t i; + X509_EXTENSION *ex, *found_ex = NULL; + if(!x) { + if(idx) *idx = -1; + if(crit) *crit = -1; + return NULL; + } + if(idx) lastpos = *idx + 1; + else lastpos = 0; + if(lastpos < 0) lastpos = 0; + for(i = lastpos; i < sk_X509_EXTENSION_num(x); i++) + { + ex = sk_X509_EXTENSION_value(x, i); + if(OBJ_obj2nid(ex->object) == nid) { + if(idx) { + *idx = i; + found_ex = ex; + break; + } else if(found_ex) { + /* Found more than one */ + if(crit) *crit = -2; + return NULL; + } + found_ex = ex; + } + } + if(found_ex) { + /* Found it */ + if(crit) *crit = X509_EXTENSION_get_critical(found_ex); + return X509V3_EXT_d2i(found_ex); + } + + /* Extension not found */ + if(idx) *idx = -1; + if(crit) *crit = -1; + return NULL; +} + +/* This function is a general extension append, replace and delete utility. + * The precise operation is governed by the 'flags' value. The 'crit' and + * 'value' arguments (if relevant) are the extensions internal structure. + */ + +int X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid, void *value, + int crit, unsigned long flags) +{ + int extidx = -1; + int errcode; + X509_EXTENSION *ext, *extmp; + unsigned long ext_op = flags & X509V3_ADD_OP_MASK; + + /* If appending we don't care if it exists, otherwise + * look for existing extension. + */ + if(ext_op != X509V3_ADD_APPEND) + extidx = X509v3_get_ext_by_NID(*x, nid, -1); + + /* See if extension exists */ + if(extidx >= 0) { + /* If keep existing, nothing to do */ + if(ext_op == X509V3_ADD_KEEP_EXISTING) + return 1; + /* If default then its an error */ + if(ext_op == X509V3_ADD_DEFAULT) { + errcode = X509V3_R_EXTENSION_EXISTS; + goto err; + } + /* If delete, just delete it */ + if(ext_op == X509V3_ADD_DELETE) { + if(!sk_X509_EXTENSION_delete(*x, extidx)) return -1; + return 1; + } + } else { + /* If replace existing or delete, error since + * extension must exist + */ + if((ext_op == X509V3_ADD_REPLACE_EXISTING) || + (ext_op == X509V3_ADD_DELETE)) { + errcode = X509V3_R_EXTENSION_NOT_FOUND; + goto err; + } + } + + /* If we get this far then we have to create an extension: + * could have some flags for alternative encoding schemes... + */ + + ext = X509V3_EXT_i2d(nid, crit, value); + + if(!ext) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_ERROR_CREATING_EXTENSION); + return 0; + } + + /* If extension exists replace it.. */ + if(extidx >= 0) { + extmp = sk_X509_EXTENSION_value(*x, extidx); + X509_EXTENSION_free(extmp); + if(!sk_X509_EXTENSION_set(*x, extidx, ext)) return -1; + return 1; + } + + if(!*x && !(*x = sk_X509_EXTENSION_new_null())) return -1; + if(!sk_X509_EXTENSION_push(*x, ext)) return -1; + + return 1; + + err: + if(!(flags & X509V3_ADD_SILENT)) + OPENSSL_PUT_ERROR(X509V3, errcode); + return 0; +} diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_ncons.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_ncons.c new file mode 100644 index 00000000..19f5e949 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_ncons.c @@ -0,0 +1,510 @@ +/* v3_ncons.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 2003 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + + +#include +#include + +#include +#include +#include +#include +#include +#include + + +static void *v2i_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval); +static int i2r_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method, + void *a, BIO *bp, int ind); +static int do_i2r_name_constraints(const X509V3_EXT_METHOD *method, + STACK_OF(GENERAL_SUBTREE) *trees, + BIO *bp, int ind, const char *name); +static int print_nc_ipadd(BIO *bp, ASN1_OCTET_STRING *ip); + +static int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc); +static int nc_match_single(GENERAL_NAME *sub, GENERAL_NAME *gen); +static int nc_dn(X509_NAME *sub, X509_NAME *nm); +static int nc_dns(ASN1_IA5STRING *sub, ASN1_IA5STRING *dns); +static int nc_email(ASN1_IA5STRING *sub, ASN1_IA5STRING *eml); +static int nc_uri(ASN1_IA5STRING *uri, ASN1_IA5STRING *base); + +const X509V3_EXT_METHOD v3_name_constraints = { + NID_name_constraints, 0, + ASN1_ITEM_ref(NAME_CONSTRAINTS), + 0,0,0,0, + 0,0, + 0, v2i_NAME_CONSTRAINTS, + i2r_NAME_CONSTRAINTS,0, + NULL +}; + +ASN1_SEQUENCE(GENERAL_SUBTREE) = { + ASN1_SIMPLE(GENERAL_SUBTREE, base, GENERAL_NAME), + ASN1_IMP_OPT(GENERAL_SUBTREE, minimum, ASN1_INTEGER, 0), + ASN1_IMP_OPT(GENERAL_SUBTREE, maximum, ASN1_INTEGER, 1) +} ASN1_SEQUENCE_END(GENERAL_SUBTREE) + +ASN1_SEQUENCE(NAME_CONSTRAINTS) = { + ASN1_IMP_SEQUENCE_OF_OPT(NAME_CONSTRAINTS, permittedSubtrees, + GENERAL_SUBTREE, 0), + ASN1_IMP_SEQUENCE_OF_OPT(NAME_CONSTRAINTS, excludedSubtrees, + GENERAL_SUBTREE, 1), +} ASN1_SEQUENCE_END(NAME_CONSTRAINTS) + + +IMPLEMENT_ASN1_ALLOC_FUNCTIONS(GENERAL_SUBTREE) +IMPLEMENT_ASN1_ALLOC_FUNCTIONS(NAME_CONSTRAINTS) + +static void *v2i_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval) + { + size_t i; + CONF_VALUE tval, *val; + STACK_OF(GENERAL_SUBTREE) **ptree = NULL; + NAME_CONSTRAINTS *ncons = NULL; + GENERAL_SUBTREE *sub = NULL; + ncons = NAME_CONSTRAINTS_new(); + if (!ncons) + goto memerr; + for(i = 0; i < sk_CONF_VALUE_num(nval); i++) + { + val = sk_CONF_VALUE_value(nval, i); + if (!strncmp(val->name, "permitted", 9) && val->name[9]) + { + ptree = &ncons->permittedSubtrees; + tval.name = val->name + 10; + } + else if (!strncmp(val->name, "excluded", 8) && val->name[8]) + { + ptree = &ncons->excludedSubtrees; + tval.name = val->name + 9; + } + else + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_SYNTAX); + goto err; + } + tval.value = val->value; + sub = GENERAL_SUBTREE_new(); + if (!v2i_GENERAL_NAME_ex(sub->base, method, ctx, &tval, 1)) + goto err; + if (!*ptree) + *ptree = sk_GENERAL_SUBTREE_new_null(); + if (!*ptree || !sk_GENERAL_SUBTREE_push(*ptree, sub)) + goto memerr; + sub = NULL; + } + + return ncons; + + memerr: + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + err: + if (ncons) + NAME_CONSTRAINTS_free(ncons); + if (sub) + GENERAL_SUBTREE_free(sub); + + return NULL; + } + + + + +static int i2r_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method, void *a, + BIO *bp, int ind) + { + NAME_CONSTRAINTS *ncons = a; + do_i2r_name_constraints(method, ncons->permittedSubtrees, + bp, ind, "Permitted"); + do_i2r_name_constraints(method, ncons->excludedSubtrees, + bp, ind, "Excluded"); + return 1; + } + +static int do_i2r_name_constraints(const X509V3_EXT_METHOD *method, + STACK_OF(GENERAL_SUBTREE) *trees, + BIO *bp, int ind, const char *name) + { + GENERAL_SUBTREE *tree; + size_t i; + if (sk_GENERAL_SUBTREE_num(trees) > 0) + BIO_printf(bp, "%*s%s:\n", ind, "", name); + for(i = 0; i < sk_GENERAL_SUBTREE_num(trees); i++) + { + tree = sk_GENERAL_SUBTREE_value(trees, i); + BIO_printf(bp, "%*s", ind + 2, ""); + if (tree->base->type == GEN_IPADD) + print_nc_ipadd(bp, tree->base->d.ip); + else + GENERAL_NAME_print(bp, tree->base); + BIO_puts(bp, "\n"); + } + return 1; + } + +static int print_nc_ipadd(BIO *bp, ASN1_OCTET_STRING *ip) + { + int i, len; + unsigned char *p; + p = ip->data; + len = ip->length; + BIO_puts(bp, "IP:"); + if(len == 8) + { + BIO_printf(bp, "%d.%d.%d.%d/%d.%d.%d.%d", + p[0], p[1], p[2], p[3], + p[4], p[5], p[6], p[7]); + } + else if(len == 32) + { + for (i = 0; i < 16; i++) + { + BIO_printf(bp, "%X", p[0] << 8 | p[1]); + p += 2; + if (i == 7) + BIO_puts(bp, "/"); + else if (i != 15) + BIO_puts(bp, ":"); + } + } + else + BIO_printf(bp, "IP Address:"); + return 1; + } + +/* Check a certificate conforms to a specified set of constraints. + * Return values: + * X509_V_OK: All constraints obeyed. + * X509_V_ERR_PERMITTED_VIOLATION: Permitted subtree violation. + * X509_V_ERR_EXCLUDED_VIOLATION: Excluded subtree violation. + * X509_V_ERR_SUBTREE_MINMAX: Min or max values present and matching type. + * X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE: Unsupported constraint type. + * X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX: bad unsupported constraint syntax. + * X509_V_ERR_UNSUPPORTED_NAME_SYNTAX: bad or unsupported syntax of name + + */ + +int NAME_CONSTRAINTS_check(X509 *x, NAME_CONSTRAINTS *nc) + { + int r, i; + size_t j; + X509_NAME *nm; + + nm = X509_get_subject_name(x); + + if (X509_NAME_entry_count(nm) > 0) + { + GENERAL_NAME gntmp; + gntmp.type = GEN_DIRNAME; + gntmp.d.directoryName = nm; + + r = nc_match(&gntmp, nc); + + if (r != X509_V_OK) + return r; + + gntmp.type = GEN_EMAIL; + + + /* Process any email address attributes in subject name */ + + for (i = -1;;) + { + X509_NAME_ENTRY *ne; + i = X509_NAME_get_index_by_NID(nm, + NID_pkcs9_emailAddress, + i); + if (i == -1) + break; + ne = X509_NAME_get_entry(nm, i); + gntmp.d.rfc822Name = X509_NAME_ENTRY_get_data(ne); + if (gntmp.d.rfc822Name->type != V_ASN1_IA5STRING) + return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; + + r = nc_match(&gntmp, nc); + + if (r != X509_V_OK) + return r; + } + + } + + for (j = 0; j < sk_GENERAL_NAME_num(x->altname); j++) + { + GENERAL_NAME *gen = sk_GENERAL_NAME_value(x->altname, j); + r = nc_match(gen, nc); + if (r != X509_V_OK) + return r; + } + + return X509_V_OK; + + } + +static int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc) + { + GENERAL_SUBTREE *sub; + int r, match = 0; + size_t i; + + /* Permitted subtrees: if any subtrees exist of matching the type + * at least one subtree must match. + */ + + for (i = 0; i < sk_GENERAL_SUBTREE_num(nc->permittedSubtrees); i++) + { + sub = sk_GENERAL_SUBTREE_value(nc->permittedSubtrees, i); + if (gen->type != sub->base->type) + continue; + if (sub->minimum || sub->maximum) + return X509_V_ERR_SUBTREE_MINMAX; + /* If we already have a match don't bother trying any more */ + if (match == 2) + continue; + if (match == 0) + match = 1; + r = nc_match_single(gen, sub->base); + if (r == X509_V_OK) + match = 2; + else if (r != X509_V_ERR_PERMITTED_VIOLATION) + return r; + } + + if (match == 1) + return X509_V_ERR_PERMITTED_VIOLATION; + + /* Excluded subtrees: must not match any of these */ + + for (i = 0; i < sk_GENERAL_SUBTREE_num(nc->excludedSubtrees); i++) + { + sub = sk_GENERAL_SUBTREE_value(nc->excludedSubtrees, i); + if (gen->type != sub->base->type) + continue; + if (sub->minimum || sub->maximum) + return X509_V_ERR_SUBTREE_MINMAX; + + r = nc_match_single(gen, sub->base); + if (r == X509_V_OK) + return X509_V_ERR_EXCLUDED_VIOLATION; + else if (r != X509_V_ERR_PERMITTED_VIOLATION) + return r; + + } + + return X509_V_OK; + + } + +static int nc_match_single(GENERAL_NAME *gen, GENERAL_NAME *base) + { + switch(base->type) + { + case GEN_DIRNAME: + return nc_dn(gen->d.directoryName, base->d.directoryName); + + case GEN_DNS: + return nc_dns(gen->d.dNSName, base->d.dNSName); + + case GEN_EMAIL: + return nc_email(gen->d.rfc822Name, base->d.rfc822Name); + + case GEN_URI: + return nc_uri(gen->d.uniformResourceIdentifier, + base->d.uniformResourceIdentifier); + + default: + return X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE; + } + + } + +/* directoryName name constraint matching. + * The canonical encoding of X509_NAME makes this comparison easy. It is + * matched if the subtree is a subset of the name. + */ + +static int nc_dn(X509_NAME *nm, X509_NAME *base) + { + /* Ensure canonical encodings are up to date. */ + if (nm->modified && i2d_X509_NAME(nm, NULL) < 0) + return X509_V_ERR_OUT_OF_MEM; + if (base->modified && i2d_X509_NAME(base, NULL) < 0) + return X509_V_ERR_OUT_OF_MEM; + if (base->canon_enclen > nm->canon_enclen) + return X509_V_ERR_PERMITTED_VIOLATION; + if (memcmp(base->canon_enc, nm->canon_enc, base->canon_enclen)) + return X509_V_ERR_PERMITTED_VIOLATION; + return X509_V_OK; + } + +static int nc_dns(ASN1_IA5STRING *dns, ASN1_IA5STRING *base) + { + char *baseptr = (char *)base->data; + char *dnsptr = (char *)dns->data; + /* Empty matches everything */ + if (!*baseptr) + return X509_V_OK; + /* Otherwise can add zero or more components on the left so + * compare RHS and if dns is longer and expect '.' as preceding + * character. + */ + if (dns->length > base->length) + { + dnsptr += dns->length - base->length; + if (*baseptr != '.' && dnsptr[-1] != '.') + return X509_V_ERR_PERMITTED_VIOLATION; + } + + if (OPENSSL_strcasecmp(baseptr, dnsptr)) + return X509_V_ERR_PERMITTED_VIOLATION; + + return X509_V_OK; + + } + +static int nc_email(ASN1_IA5STRING *eml, ASN1_IA5STRING *base) + { + const char *baseptr = (char *)base->data; + const char *emlptr = (char *)eml->data; + + const char *baseat = strchr(baseptr, '@'); + const char *emlat = strchr(emlptr, '@'); + if (!emlat) + return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; + /* Special case: inital '.' is RHS match */ + if (!baseat && (*baseptr == '.')) + { + if (eml->length > base->length) + { + emlptr += eml->length - base->length; + if (!OPENSSL_strcasecmp(baseptr, emlptr)) + return X509_V_OK; + } + return X509_V_ERR_PERMITTED_VIOLATION; + } + + /* If we have anything before '@' match local part */ + + if (baseat) + { + if (baseat != baseptr) + { + if ((baseat - baseptr) != (emlat - emlptr)) + return X509_V_ERR_PERMITTED_VIOLATION; + /* Case sensitive match of local part */ + if (strncmp(baseptr, emlptr, emlat - emlptr)) + return X509_V_ERR_PERMITTED_VIOLATION; + } + /* Position base after '@' */ + baseptr = baseat + 1; + } + emlptr = emlat + 1; + /* Just have hostname left to match: case insensitive */ + if (OPENSSL_strcasecmp(baseptr, emlptr)) + return X509_V_ERR_PERMITTED_VIOLATION; + + return X509_V_OK; + + } + +static int nc_uri(ASN1_IA5STRING *uri, ASN1_IA5STRING *base) + { + const char *baseptr = (char *)base->data; + const char *hostptr = (char *)uri->data; + const char *p = strchr(hostptr, ':'); + int hostlen; + /* Check for foo:// and skip past it */ + if (!p || (p[1] != '/') || (p[2] != '/')) + return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; + hostptr = p + 3; + + /* Determine length of hostname part of URI */ + + /* Look for a port indicator as end of hostname first */ + + p = strchr(hostptr, ':'); + /* Otherwise look for trailing slash */ + if (!p) + p = strchr(hostptr, '/'); + + if (!p) + hostlen = strlen(hostptr); + else + hostlen = p - hostptr; + + if (hostlen == 0) + return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; + + /* Special case: inital '.' is RHS match */ + if (*baseptr == '.') + { + if (hostlen > base->length) + { + p = hostptr + hostlen - base->length; + if (!OPENSSL_strncasecmp(p, baseptr, base->length)) + return X509_V_OK; + } + return X509_V_ERR_PERMITTED_VIOLATION; + } + + if ((base->length != (int)hostlen) || OPENSSL_strncasecmp(hostptr, baseptr, hostlen)) + return X509_V_ERR_PERMITTED_VIOLATION; + + return X509_V_OK; + + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_pci.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_pci.c new file mode 100644 index 00000000..f19a37a8 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_pci.c @@ -0,0 +1,335 @@ +/* v3_pci.c -*- mode:C; c-file-style: "eay" -*- */ +/* Contributed to the OpenSSL Project 2004 + * by Richard Levitte (richard@levitte.org) + */ +/* Copyright (c) 2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include +#include +#include +#include +#include + + +static int i2r_pci(X509V3_EXT_METHOD *method, PROXY_CERT_INFO_EXTENSION *ext, + BIO *out, int indent); +static PROXY_CERT_INFO_EXTENSION *r2i_pci(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, char *str); + +const X509V3_EXT_METHOD v3_pci = + { NID_proxyCertInfo, 0, ASN1_ITEM_ref(PROXY_CERT_INFO_EXTENSION), + 0,0,0,0, + 0,0, + NULL, NULL, + (X509V3_EXT_I2R)i2r_pci, + (X509V3_EXT_R2I)r2i_pci, + NULL, + }; + +static int i2r_pci(X509V3_EXT_METHOD *method, PROXY_CERT_INFO_EXTENSION *pci, + BIO *out, int indent) + { + BIO_printf(out, "%*sPath Length Constraint: ", indent, ""); + if (pci->pcPathLengthConstraint) + i2a_ASN1_INTEGER(out, pci->pcPathLengthConstraint); + else + BIO_printf(out, "infinite"); + BIO_puts(out, "\n"); + BIO_printf(out, "%*sPolicy Language: ", indent, ""); + i2a_ASN1_OBJECT(out, pci->proxyPolicy->policyLanguage); + BIO_puts(out, "\n"); + if (pci->proxyPolicy->policy && pci->proxyPolicy->policy->data) + BIO_printf(out, "%*sPolicy Text: %s\n", indent, "", + pci->proxyPolicy->policy->data); + return 1; + } + +static int process_pci_value(CONF_VALUE *val, + ASN1_OBJECT **language, ASN1_INTEGER **pathlen, + ASN1_OCTET_STRING **policy) + { + int free_policy = 0; + + if (strcmp(val->name, "language") == 0) + { + if (*language) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_POLICY_LANGUAGE_ALREADY_DEFINED); + X509V3_conf_err(val); + return 0; + } + if (!(*language = OBJ_txt2obj(val->value, 0))) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_OBJECT_IDENTIFIER); + X509V3_conf_err(val); + return 0; + } + } + else if (strcmp(val->name, "pathlen") == 0) + { + if (*pathlen) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_POLICY_PATH_LENGTH_ALREADY_DEFINED); + X509V3_conf_err(val); + return 0; + } + if (!X509V3_get_value_int(val, pathlen)) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_POLICY_PATH_LENGTH); + X509V3_conf_err(val); + return 0; + } + } + else if (strcmp(val->name, "policy") == 0) + { + unsigned char *tmp_data = NULL; + long val_len; + if (!*policy) + { + *policy = ASN1_OCTET_STRING_new(); + if (!*policy) + { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + X509V3_conf_err(val); + return 0; + } + free_policy = 1; + } + if (strncmp(val->value, "hex:", 4) == 0) + { + unsigned char *tmp_data2 = + string_to_hex(val->value + 4, &val_len); + + if (!tmp_data2) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_ILLEGAL_HEX_DIGIT); + X509V3_conf_err(val); + goto err; + } + + tmp_data = OPENSSL_realloc((*policy)->data, + (*policy)->length + val_len + 1); + if (tmp_data) + { + (*policy)->data = tmp_data; + memcpy(&(*policy)->data[(*policy)->length], + tmp_data2, val_len); + (*policy)->length += val_len; + (*policy)->data[(*policy)->length] = '\0'; + } + else + { + OPENSSL_free(tmp_data2); + /* realloc failure implies the original data space is b0rked too! */ + (*policy)->data = NULL; + (*policy)->length = 0; + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + X509V3_conf_err(val); + goto err; + } + OPENSSL_free(tmp_data2); + } + else if (strncmp(val->value, "file:", 5) == 0) + { + unsigned char buf[2048]; + int n; + BIO *b = BIO_new_file(val->value + 5, "r"); + if (!b) + { + OPENSSL_PUT_ERROR(X509V3, ERR_R_BIO_LIB); + X509V3_conf_err(val); + goto err; + } + while((n = BIO_read(b, buf, sizeof(buf))) > 0 + || (n == 0 && BIO_should_retry(b))) + { + if (!n) continue; + + tmp_data = OPENSSL_realloc((*policy)->data, + (*policy)->length + n + 1); + + if (!tmp_data) + break; + + (*policy)->data = tmp_data; + memcpy(&(*policy)->data[(*policy)->length], + buf, n); + (*policy)->length += n; + (*policy)->data[(*policy)->length] = '\0'; + } + BIO_free_all(b); + + if (n < 0) + { + OPENSSL_PUT_ERROR(X509V3, ERR_R_BIO_LIB); + X509V3_conf_err(val); + goto err; + } + } + else if (strncmp(val->value, "text:", 5) == 0) + { + val_len = strlen(val->value + 5); + tmp_data = OPENSSL_realloc((*policy)->data, + (*policy)->length + val_len + 1); + if (tmp_data) + { + (*policy)->data = tmp_data; + memcpy(&(*policy)->data[(*policy)->length], + val->value + 5, val_len); + (*policy)->length += val_len; + (*policy)->data[(*policy)->length] = '\0'; + } + else + { + /* realloc failure implies the original data space is b0rked too! */ + (*policy)->data = NULL; + (*policy)->length = 0; + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + X509V3_conf_err(val); + goto err; + } + } + else + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INCORRECT_POLICY_SYNTAX_TAG); + X509V3_conf_err(val); + goto err; + } + if (!tmp_data) + { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + X509V3_conf_err(val); + goto err; + } + } + return 1; +err: + if (free_policy) + { + ASN1_OCTET_STRING_free(*policy); + *policy = NULL; + } + return 0; + } + +static PROXY_CERT_INFO_EXTENSION *r2i_pci(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, char *value) + { + PROXY_CERT_INFO_EXTENSION *pci = NULL; + STACK_OF(CONF_VALUE) *vals; + ASN1_OBJECT *language = NULL; + ASN1_INTEGER *pathlen = NULL; + ASN1_OCTET_STRING *policy = NULL; + size_t i, j; + int nid; + + vals = X509V3_parse_list(value); + for (i = 0; i < sk_CONF_VALUE_num(vals); i++) + { + CONF_VALUE *cnf = sk_CONF_VALUE_value(vals, i); + if (!cnf->name || (*cnf->name != '@' && !cnf->value)) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_PROXY_POLICY_SETTING); + X509V3_conf_err(cnf); + goto err; + } + if (*cnf->name == '@') + { + STACK_OF(CONF_VALUE) *sect; + int success_p = 1; + + sect = X509V3_get_section(ctx, cnf->name + 1); + if (!sect) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_SECTION); + X509V3_conf_err(cnf); + goto err; + } + for (j = 0; success_p && j < sk_CONF_VALUE_num(sect); j++) + { + success_p = + process_pci_value(sk_CONF_VALUE_value(sect, j), + &language, &pathlen, &policy); + } + X509V3_section_free(ctx, sect); + if (!success_p) + goto err; + } + else + { + if (!process_pci_value(cnf, + &language, &pathlen, &policy)) + { + X509V3_conf_err(cnf); + goto err; + } + } + } + + /* Language is mandatory */ + if (!language) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED); + goto err; + } + nid = OBJ_obj2nid(language); + if ((nid == NID_Independent || nid == NID_id_ppl_inheritAll) && policy) + { + OPENSSL_PUT_ERROR(X509V3, + X509V3_R_POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY); + goto err; + } + + pci = PROXY_CERT_INFO_EXTENSION_new(); + if (!pci) + { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + goto err; + } + + pci->proxyPolicy->policyLanguage = language; language = NULL; + pci->proxyPolicy->policy = policy; policy = NULL; + pci->pcPathLengthConstraint = pathlen; pathlen = NULL; + goto end; +err: + if (language) { ASN1_OBJECT_free(language); language = NULL; } + if (pathlen) { ASN1_INTEGER_free(pathlen); pathlen = NULL; } + if (policy) { ASN1_OCTET_STRING_free(policy); policy = NULL; } + if (pci) { PROXY_CERT_INFO_EXTENSION_free(pci); pci = NULL; } +end: + sk_CONF_VALUE_pop_free(vals, X509V3_conf_free); + return pci; + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_pcia.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_pcia.c new file mode 100644 index 00000000..e3e3192f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_pcia.c @@ -0,0 +1,56 @@ +/* v3_pcia.c -*- mode:C; c-file-style: "eay" -*- */ +/* Contributed to the OpenSSL Project 2004 + * by Richard Levitte (richard@levitte.org) + */ +/* Copyright (c) 2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + + +ASN1_SEQUENCE(PROXY_POLICY) = + { + ASN1_SIMPLE(PROXY_POLICY,policyLanguage,ASN1_OBJECT), + ASN1_OPT(PROXY_POLICY,policy,ASN1_OCTET_STRING) +} ASN1_SEQUENCE_END(PROXY_POLICY) + +IMPLEMENT_ASN1_FUNCTIONS(PROXY_POLICY) + +ASN1_SEQUENCE(PROXY_CERT_INFO_EXTENSION) = + { + ASN1_OPT(PROXY_CERT_INFO_EXTENSION,pcPathLengthConstraint,ASN1_INTEGER), + ASN1_SIMPLE(PROXY_CERT_INFO_EXTENSION,proxyPolicy,PROXY_POLICY) +} ASN1_SEQUENCE_END(PROXY_CERT_INFO_EXTENSION) + +IMPLEMENT_ASN1_FUNCTIONS(PROXY_CERT_INFO_EXTENSION) diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_pcons.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_pcons.c new file mode 100644 index 00000000..b7522904 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_pcons.c @@ -0,0 +1,142 @@ +/* v3_pcons.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 2003 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + + +#include +#include + +#include +#include +#include +#include +#include +#include + + +static STACK_OF(CONF_VALUE) * +i2v_POLICY_CONSTRAINTS(const X509V3_EXT_METHOD *method, void *bcons, + STACK_OF(CONF_VALUE) *extlist); +static void *v2i_POLICY_CONSTRAINTS(const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, + STACK_OF(CONF_VALUE) *values); + +const X509V3_EXT_METHOD v3_policy_constraints = { +NID_policy_constraints, 0, +ASN1_ITEM_ref(POLICY_CONSTRAINTS), +0,0,0,0, +0,0, +i2v_POLICY_CONSTRAINTS, +v2i_POLICY_CONSTRAINTS, +NULL,NULL, +NULL +}; + +ASN1_SEQUENCE(POLICY_CONSTRAINTS) = { + ASN1_IMP_OPT(POLICY_CONSTRAINTS, requireExplicitPolicy, ASN1_INTEGER,0), + ASN1_IMP_OPT(POLICY_CONSTRAINTS, inhibitPolicyMapping, ASN1_INTEGER,1) +} ASN1_SEQUENCE_END(POLICY_CONSTRAINTS) + +IMPLEMENT_ASN1_ALLOC_FUNCTIONS(POLICY_CONSTRAINTS) + + +static STACK_OF(CONF_VALUE) * +i2v_POLICY_CONSTRAINTS(const X509V3_EXT_METHOD *method, void *a, + STACK_OF(CONF_VALUE) *extlist) +{ + POLICY_CONSTRAINTS *pcons = a; + X509V3_add_value_int("Require Explicit Policy", + pcons->requireExplicitPolicy, &extlist); + X509V3_add_value_int("Inhibit Policy Mapping", + pcons->inhibitPolicyMapping, &extlist); + return extlist; +} + +static void *v2i_POLICY_CONSTRAINTS(const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, + STACK_OF(CONF_VALUE) *values) +{ + POLICY_CONSTRAINTS *pcons=NULL; + CONF_VALUE *val; + size_t i; + if(!(pcons = POLICY_CONSTRAINTS_new())) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + for(i = 0; i < sk_CONF_VALUE_num(values); i++) { + val = sk_CONF_VALUE_value(values, i); + if(!strcmp(val->name, "requireExplicitPolicy")) { + if(!X509V3_get_value_int(val, + &pcons->requireExplicitPolicy)) goto err; + } else if(!strcmp(val->name, "inhibitPolicyMapping")) { + if(!X509V3_get_value_int(val, + &pcons->inhibitPolicyMapping)) goto err; + } else { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NAME); + X509V3_conf_err(val); + goto err; + } + } + if (!pcons->inhibitPolicyMapping && !pcons->requireExplicitPolicy) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_ILLEGAL_EMPTY_EXTENSION); + goto err; + } + + return pcons; + err: + POLICY_CONSTRAINTS_free(pcons); + return NULL; +} + diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_pku.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_pku.c new file mode 100644 index 00000000..445eda67 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_pku.c @@ -0,0 +1,109 @@ +/* v3_pku.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include +#include +#include + + +static int i2r_PKEY_USAGE_PERIOD(X509V3_EXT_METHOD *method, PKEY_USAGE_PERIOD *usage, BIO *out, int indent); +/* +static PKEY_USAGE_PERIOD *v2i_PKEY_USAGE_PERIOD(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *values); +*/ +const X509V3_EXT_METHOD v3_pkey_usage_period = { +NID_private_key_usage_period, 0, ASN1_ITEM_ref(PKEY_USAGE_PERIOD), +0,0,0,0, +0,0,0,0, +(X509V3_EXT_I2R)i2r_PKEY_USAGE_PERIOD, NULL, +NULL +}; + +ASN1_SEQUENCE(PKEY_USAGE_PERIOD) = { + ASN1_IMP_OPT(PKEY_USAGE_PERIOD, notBefore, ASN1_GENERALIZEDTIME, 0), + ASN1_IMP_OPT(PKEY_USAGE_PERIOD, notAfter, ASN1_GENERALIZEDTIME, 1) +} ASN1_SEQUENCE_END(PKEY_USAGE_PERIOD) + +IMPLEMENT_ASN1_FUNCTIONS(PKEY_USAGE_PERIOD) + +static int i2r_PKEY_USAGE_PERIOD(X509V3_EXT_METHOD *method, + PKEY_USAGE_PERIOD *usage, BIO *out, int indent) +{ + BIO_printf(out, "%*s", indent, ""); + if(usage->notBefore) { + BIO_write(out, "Not Before: ", 12); + ASN1_GENERALIZEDTIME_print(out, usage->notBefore); + if(usage->notAfter) BIO_write(out, ", ", 2); + } + if(usage->notAfter) { + BIO_write(out, "Not After: ", 11); + ASN1_GENERALIZEDTIME_print(out, usage->notAfter); + } + return 1; +} + +/* +static PKEY_USAGE_PERIOD *v2i_PKEY_USAGE_PERIOD(method, ctx, values) +X509V3_EXT_METHOD *method; +X509V3_CTX *ctx; +STACK_OF(CONF_VALUE) *values; +{ +return NULL; +} +*/ diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_pmaps.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_pmaps.c new file mode 100644 index 00000000..5b909773 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_pmaps.c @@ -0,0 +1,156 @@ +/* v3_pmaps.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 2003 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + + +#include + +#include +#include +#include +#include +#include + + +static void *v2i_POLICY_MAPPINGS(const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval); +static STACK_OF(CONF_VALUE) * +i2v_POLICY_MAPPINGS(const X509V3_EXT_METHOD *method, void *pmps, + STACK_OF(CONF_VALUE) *extlist); + +const X509V3_EXT_METHOD v3_policy_mappings = { + NID_policy_mappings, 0, + ASN1_ITEM_ref(POLICY_MAPPINGS), + 0,0,0,0, + 0,0, + i2v_POLICY_MAPPINGS, + v2i_POLICY_MAPPINGS, + 0,0, + NULL +}; + +ASN1_SEQUENCE(POLICY_MAPPING) = { + ASN1_SIMPLE(POLICY_MAPPING, issuerDomainPolicy, ASN1_OBJECT), + ASN1_SIMPLE(POLICY_MAPPING, subjectDomainPolicy, ASN1_OBJECT) +} ASN1_SEQUENCE_END(POLICY_MAPPING) + +ASN1_ITEM_TEMPLATE(POLICY_MAPPINGS) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, POLICY_MAPPINGS, + POLICY_MAPPING) +ASN1_ITEM_TEMPLATE_END(POLICY_MAPPINGS) + +IMPLEMENT_ASN1_ALLOC_FUNCTIONS(POLICY_MAPPING) + + +static STACK_OF(CONF_VALUE) * +i2v_POLICY_MAPPINGS(const X509V3_EXT_METHOD *method, void *a, + STACK_OF(CONF_VALUE) *ext_list) +{ + POLICY_MAPPINGS *pmaps = a; + POLICY_MAPPING *pmap; + size_t i; + char obj_tmp1[80]; + char obj_tmp2[80]; + for(i = 0; i < sk_POLICY_MAPPING_num(pmaps); i++) { + pmap = sk_POLICY_MAPPING_value(pmaps, i); + i2t_ASN1_OBJECT(obj_tmp1, 80, pmap->issuerDomainPolicy); + i2t_ASN1_OBJECT(obj_tmp2, 80, pmap->subjectDomainPolicy); + X509V3_add_value(obj_tmp1, obj_tmp2, &ext_list); + } + return ext_list; +} + +static void *v2i_POLICY_MAPPINGS(const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval) +{ + POLICY_MAPPINGS *pmaps; + POLICY_MAPPING *pmap; + ASN1_OBJECT *obj1, *obj2; + CONF_VALUE *val; + size_t i; + + if(!(pmaps = sk_POLICY_MAPPING_new_null())) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + + for(i = 0; i < sk_CONF_VALUE_num(nval); i++) { + val = sk_CONF_VALUE_value(nval, i); + if(!val->value || !val->name) { + sk_POLICY_MAPPING_pop_free(pmaps, POLICY_MAPPING_free); + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_OBJECT_IDENTIFIER); + X509V3_conf_err(val); + return NULL; + } + obj1 = OBJ_txt2obj(val->name, 0); + obj2 = OBJ_txt2obj(val->value, 0); + if(!obj1 || !obj2) { + sk_POLICY_MAPPING_pop_free(pmaps, POLICY_MAPPING_free); + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_OBJECT_IDENTIFIER); + X509V3_conf_err(val); + return NULL; + } + pmap = POLICY_MAPPING_new(); + if (!pmap) { + sk_POLICY_MAPPING_pop_free(pmaps, POLICY_MAPPING_free); + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + pmap->issuerDomainPolicy = obj1; + pmap->subjectDomainPolicy = obj2; + sk_POLICY_MAPPING_push(pmaps, pmap); + } + return pmaps; +} diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_prn.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_prn.c new file mode 100644 index 00000000..87aef4d4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_prn.c @@ -0,0 +1,207 @@ +/* v3_prn.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +/* X509 v3 extension utilities */ + +#include + +#include +#include +#include +#include + + +/* Extension printing routines */ + +static int unknown_ext_print(BIO *out, X509_EXTENSION *ext, unsigned long flag, int indent, int supported); + +/* Print out a name+value stack */ + +void X509V3_EXT_val_prn(BIO *out, STACK_OF(CONF_VALUE) *val, int indent, int ml) +{ + size_t i; + CONF_VALUE *nval; + if(!val) return; + if(!ml || !sk_CONF_VALUE_num(val)) { + BIO_printf(out, "%*s", indent, ""); + if(!sk_CONF_VALUE_num(val)) BIO_puts(out, "\n"); + } + for(i = 0; i < sk_CONF_VALUE_num(val); i++) { + if(ml) BIO_printf(out, "%*s", indent, ""); + else if(i > 0) BIO_printf(out, ", "); + nval = sk_CONF_VALUE_value(val, i); + if(!nval->name) BIO_puts(out, nval->value); + else if(!nval->value) BIO_puts(out, nval->name); + else BIO_printf(out, "%s:%s", nval->name, nval->value); + if(ml) BIO_puts(out, "\n"); + } +} + +/* Main routine: print out a general extension */ + +int X509V3_EXT_print(BIO *out, X509_EXTENSION *ext, unsigned long flag, int indent) +{ + void *ext_str = NULL; + char *value = NULL; + const unsigned char *p; + const X509V3_EXT_METHOD *method; + STACK_OF(CONF_VALUE) *nval = NULL; + int ok = 1; + + if(!(method = X509V3_EXT_get(ext))) + return unknown_ext_print(out, ext, flag, indent, 0); + p = ext->value->data; + if(method->it) ext_str = ASN1_item_d2i(NULL, &p, ext->value->length, ASN1_ITEM_ptr(method->it)); + else ext_str = method->d2i(NULL, &p, ext->value->length); + + if(!ext_str) return unknown_ext_print(out, ext, flag, indent, 1); + + if(method->i2s) { + if(!(value = method->i2s(method, ext_str))) { + ok = 0; + goto err; + } + BIO_printf(out, "%*s%s", indent, "", value); + } else if(method->i2v) { + if(!(nval = method->i2v(method, ext_str, NULL))) { + ok = 0; + goto err; + } + X509V3_EXT_val_prn(out, nval, indent, + method->ext_flags & X509V3_EXT_MULTILINE); + } else if(method->i2r) { + if(!method->i2r(method, ext_str, out, indent)) ok = 0; + } else ok = 0; + + err: + sk_CONF_VALUE_pop_free(nval, X509V3_conf_free); + if(value) OPENSSL_free(value); + if(method->it) ASN1_item_free(ext_str, ASN1_ITEM_ptr(method->it)); + else method->ext_free(ext_str); + return ok; +} + +int X509V3_extensions_print(BIO *bp, const char *title, STACK_OF(X509_EXTENSION) *exts, unsigned long flag, int indent) +{ + size_t i; + int j; + + if(sk_X509_EXTENSION_num(exts) <= 0) return 1; + + if(title) + { + BIO_printf(bp,"%*s%s:\n",indent, "", title); + indent += 4; + } + + for (i=0; ivalue); + } + if (BIO_write(bp,"\n",1) <= 0) return 0; + } + return 1; +} + +static int unknown_ext_print(BIO *out, X509_EXTENSION *ext, unsigned long flag, int indent, int supported) +{ + switch(flag & X509V3_EXT_UNKNOWN_MASK) { + + case X509V3_EXT_DEFAULT: + return 0; + + case X509V3_EXT_ERROR_UNKNOWN: + if(supported) + BIO_printf(out, "%*s", indent, ""); + else + BIO_printf(out, "%*s", indent, ""); + return 1; + + case X509V3_EXT_PARSE_UNKNOWN: + return ASN1_parse_dump(out, + ext->value->data, ext->value->length, indent, -1); + case X509V3_EXT_DUMP_UNKNOWN: + return BIO_hexdump(out, ext->value->data, ext->value->length, indent); + + default: + return 1; + } +} + + +#ifndef OPENSSL_NO_FP_API +int X509V3_EXT_print_fp(FILE *fp, X509_EXTENSION *ext, int flag, int indent) +{ + BIO *bio_tmp; + int ret; + if(!(bio_tmp = BIO_new_fp(fp, BIO_NOCLOSE))) return 0; + ret = X509V3_EXT_print(bio_tmp, ext, flag, indent); + BIO_free(bio_tmp); + return ret; +} +#endif diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_purp.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_purp.c new file mode 100644 index 00000000..f53c0f11 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_purp.c @@ -0,0 +1,804 @@ +/* v3_purp.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2001. + */ +/* ==================================================================== + * Copyright (c) 1999-2004 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../internal.h" + + +static void x509v3_cache_extensions(X509 *x); + +static int check_ssl_ca(const X509 *x); +static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x, int ca); +static int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x, int ca); +static int check_purpose_ns_ssl_server(const X509_PURPOSE *xp, const X509 *x, int ca); +static int purpose_smime(const X509 *x, int ca); +static int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x, int ca); +static int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x, int ca); +static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x, int ca); +static int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x, int ca); +static int no_check(const X509_PURPOSE *xp, const X509 *x, int ca); +static int ocsp_helper(const X509_PURPOSE *xp, const X509 *x, int ca); + +static int xp_cmp(const X509_PURPOSE **a, const X509_PURPOSE **b); +static void xptable_free(X509_PURPOSE *p); + +static X509_PURPOSE xstandard[] = { + {X509_PURPOSE_SSL_CLIENT, X509_TRUST_SSL_CLIENT, 0, check_purpose_ssl_client, (char *) "SSL client", (char *) "sslclient", NULL}, + {X509_PURPOSE_SSL_SERVER, X509_TRUST_SSL_SERVER, 0, check_purpose_ssl_server, (char *) "SSL server", (char *) "sslserver", NULL}, + {X509_PURPOSE_NS_SSL_SERVER, X509_TRUST_SSL_SERVER, 0, check_purpose_ns_ssl_server, (char *) "Netscape SSL server", (char *) "nssslserver", NULL}, + {X509_PURPOSE_SMIME_SIGN, X509_TRUST_EMAIL, 0, check_purpose_smime_sign, (char *) "S/MIME signing", (char *) "smimesign", NULL}, + {X509_PURPOSE_SMIME_ENCRYPT, X509_TRUST_EMAIL, 0, check_purpose_smime_encrypt, (char *) "S/MIME encryption", (char *) "smimeencrypt", NULL}, + {X509_PURPOSE_CRL_SIGN, X509_TRUST_COMPAT, 0, check_purpose_crl_sign, (char *) "CRL signing", (char *) "crlsign", NULL}, + {X509_PURPOSE_ANY, X509_TRUST_DEFAULT, 0, no_check, (char *) "Any Purpose", (char *) "any", NULL}, + {X509_PURPOSE_OCSP_HELPER, X509_TRUST_COMPAT, 0, ocsp_helper, (char *) "OCSP helper", (char *) "ocsphelper", NULL}, + {X509_PURPOSE_TIMESTAMP_SIGN, X509_TRUST_TSA, 0, check_purpose_timestamp_sign, (char *) "Time Stamp signing", (char *) "timestampsign", NULL}, +}; + +#define X509_PURPOSE_COUNT (sizeof(xstandard)/sizeof(X509_PURPOSE)) + +static STACK_OF(X509_PURPOSE) *xptable = NULL; + +static int xp_cmp(const X509_PURPOSE **a, const X509_PURPOSE **b) +{ + return (*a)->purpose - (*b)->purpose; +} + +/* As much as I'd like to make X509_check_purpose use a "const" X509* + * I really can't because it does recalculate hashes and do other non-const + * things. */ +int X509_check_purpose(X509 *x, int id, int ca) +{ + int idx; + const X509_PURPOSE *pt; + if(!(x->ex_flags & EXFLAG_SET)) { + x509v3_cache_extensions(x); + } + if(id == -1) return 1; + idx = X509_PURPOSE_get_by_id(id); + if(idx == -1) return -1; + pt = X509_PURPOSE_get0(idx); + return pt->check_purpose(pt, x, ca); +} + +int X509_PURPOSE_set(int *p, int purpose) +{ + if(X509_PURPOSE_get_by_id(purpose) == -1) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_PURPOSE); + return 0; + } + *p = purpose; + return 1; +} + +int X509_PURPOSE_get_count(void) +{ + if(!xptable) return X509_PURPOSE_COUNT; + return sk_X509_PURPOSE_num(xptable) + X509_PURPOSE_COUNT; +} + +X509_PURPOSE * X509_PURPOSE_get0(int idx) +{ + if(idx < 0) return NULL; + if(idx < (int)X509_PURPOSE_COUNT) return xstandard + idx; + return sk_X509_PURPOSE_value(xptable, idx - X509_PURPOSE_COUNT); +} + +int X509_PURPOSE_get_by_sname(char *sname) +{ + int i; + X509_PURPOSE *xptmp; + for(i = 0; i < X509_PURPOSE_get_count(); i++) { + xptmp = X509_PURPOSE_get0(i); + if(!strcmp(xptmp->sname, sname)) return i; + } + return -1; +} + +int X509_PURPOSE_get_by_id(int purpose) +{ + X509_PURPOSE tmp; + size_t idx; + + if((purpose >= X509_PURPOSE_MIN) && (purpose <= X509_PURPOSE_MAX)) + return purpose - X509_PURPOSE_MIN; + tmp.purpose = purpose; + if(!xptable) return -1; + + if (!sk_X509_PURPOSE_find(xptable, &idx, &tmp)) + return -1; + return idx + X509_PURPOSE_COUNT; +} + +int X509_PURPOSE_add(int id, int trust, int flags, + int (*ck)(const X509_PURPOSE *, const X509 *, int), + char *name, char *sname, void *arg) +{ + int idx; + X509_PURPOSE *ptmp; + char *name_dup, *sname_dup; + + /* This is set according to what we change: application can't set it */ + flags &= ~X509_PURPOSE_DYNAMIC; + /* This will always be set for application modified trust entries */ + flags |= X509_PURPOSE_DYNAMIC_NAME; + /* Get existing entry if any */ + idx = X509_PURPOSE_get_by_id(id); + /* Need a new entry */ + if(idx == -1) { + if(!(ptmp = OPENSSL_malloc(sizeof(X509_PURPOSE)))) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return 0; + } + ptmp->flags = X509_PURPOSE_DYNAMIC; + } else ptmp = X509_PURPOSE_get0(idx); + + /* Duplicate the supplied names. */ + name_dup = BUF_strdup(name); + sname_dup = BUF_strdup(sname); + if (name_dup == NULL || sname_dup == NULL) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + if (name_dup != NULL) + OPENSSL_free(name_dup); + if (sname_dup != NULL) + OPENSSL_free(sname_dup); + if (idx == -1) + OPENSSL_free(ptmp); + return 0; + } + + /* OPENSSL_free existing name if dynamic */ + if(ptmp->flags & X509_PURPOSE_DYNAMIC_NAME) { + OPENSSL_free(ptmp->name); + OPENSSL_free(ptmp->sname); + } + /* dup supplied name */ + ptmp->name = name_dup; + ptmp->sname = sname_dup; + /* Keep the dynamic flag of existing entry */ + ptmp->flags &= X509_PURPOSE_DYNAMIC; + /* Set all other flags */ + ptmp->flags |= flags; + + ptmp->purpose = id; + ptmp->trust = trust; + ptmp->check_purpose = ck; + ptmp->usr_data = arg; + + /* If its a new entry manage the dynamic table */ + if(idx == -1) { + if(!xptable && !(xptable = sk_X509_PURPOSE_new(xp_cmp))) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + xptable_free(ptmp); + return 0; + } + if (!sk_X509_PURPOSE_push(xptable, ptmp)) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + xptable_free(ptmp); + return 0; + } + } + return 1; +} + +static void xptable_free(X509_PURPOSE *p) + { + if(!p) return; + if (p->flags & X509_PURPOSE_DYNAMIC) + { + if (p->flags & X509_PURPOSE_DYNAMIC_NAME) { + OPENSSL_free(p->name); + OPENSSL_free(p->sname); + } + OPENSSL_free(p); + } + } + +void X509_PURPOSE_cleanup(void) +{ + unsigned int i; + sk_X509_PURPOSE_pop_free(xptable, xptable_free); + for(i = 0; i < X509_PURPOSE_COUNT; i++) xptable_free(xstandard + i); + xptable = NULL; +} + +int X509_PURPOSE_get_id(X509_PURPOSE *xp) +{ + return xp->purpose; +} + +char *X509_PURPOSE_get0_name(X509_PURPOSE *xp) +{ + return xp->name; +} + +char *X509_PURPOSE_get0_sname(X509_PURPOSE *xp) +{ + return xp->sname; +} + +int X509_PURPOSE_get_trust(X509_PURPOSE *xp) +{ + return xp->trust; +} + +static int nid_cmp(const void *void_a, const void *void_b) + { + const int *a = void_a, *b = void_b; + + return *a - *b; + } + +int X509_supported_extension(X509_EXTENSION *ex) + { + /* This table is a list of the NIDs of supported extensions: + * that is those which are used by the verify process. If + * an extension is critical and doesn't appear in this list + * then the verify process will normally reject the certificate. + * The list must be kept in numerical order because it will be + * searched using bsearch. + */ + + static const int supported_nids[] = { + NID_netscape_cert_type, /* 71 */ + NID_key_usage, /* 83 */ + NID_subject_alt_name, /* 85 */ + NID_basic_constraints, /* 87 */ + NID_certificate_policies, /* 89 */ + NID_ext_key_usage, /* 126 */ + NID_policy_constraints, /* 401 */ + NID_proxyCertInfo, /* 663 */ + NID_name_constraints, /* 666 */ + NID_policy_mappings, /* 747 */ + NID_inhibit_any_policy /* 748 */ + }; + + int ex_nid = OBJ_obj2nid(X509_EXTENSION_get_object(ex)); + + if (ex_nid == NID_undef) + return 0; + + if (bsearch(&ex_nid, supported_nids, sizeof(supported_nids)/sizeof(int), sizeof(int), nid_cmp) != NULL) + return 1; + return 0; + } + +static void setup_dp(X509 *x, DIST_POINT *dp) + { + X509_NAME *iname = NULL; + size_t i; + if (dp->reasons) + { + if (dp->reasons->length > 0) + dp->dp_reasons = dp->reasons->data[0]; + if (dp->reasons->length > 1) + dp->dp_reasons |= (dp->reasons->data[1] << 8); + dp->dp_reasons &= CRLDP_ALL_REASONS; + } + else + dp->dp_reasons = CRLDP_ALL_REASONS; + if (!dp->distpoint || (dp->distpoint->type != 1)) + return; + for (i = 0; i < sk_GENERAL_NAME_num(dp->CRLissuer); i++) + { + GENERAL_NAME *gen = sk_GENERAL_NAME_value(dp->CRLissuer, i); + if (gen->type == GEN_DIRNAME) + { + iname = gen->d.directoryName; + break; + } + } + if (!iname) + iname = X509_get_issuer_name(x); + + DIST_POINT_set_dpname(dp->distpoint, iname); + + } + +static void setup_crldp(X509 *x) + { + size_t i; + x->crldp = X509_get_ext_d2i(x, NID_crl_distribution_points, NULL, NULL); + for (i = 0; i < sk_DIST_POINT_num(x->crldp); i++) + setup_dp(x, sk_DIST_POINT_value(x->crldp, i)); + } + +/* g_x509_cache_extensions_lock is used to protect against concurrent calls to + * |x509v3_cache_extensions|. Ideally this would be done with a |CRYPTO_once_t| + * in the |X509| structure, but |CRYPTO_once_t| isn't public. + * + * Note: it's not entirely clear whether this lock is needed. Not all paths to + * this function took a lock in OpenSSL. */ +static struct CRYPTO_STATIC_MUTEX g_x509_cache_extensions_lock = + CRYPTO_STATIC_MUTEX_INIT; + +static void x509v3_cache_extensions(X509 *x) +{ + BASIC_CONSTRAINTS *bs; + PROXY_CERT_INFO_EXTENSION *pci; + ASN1_BIT_STRING *usage; + ASN1_BIT_STRING *ns; + EXTENDED_KEY_USAGE *extusage; + X509_EXTENSION *ex; + size_t i; + int j; + + CRYPTO_STATIC_MUTEX_lock_write(&g_x509_cache_extensions_lock); + + if(x->ex_flags & EXFLAG_SET) + { + CRYPTO_STATIC_MUTEX_unlock(&g_x509_cache_extensions_lock); + return; + } + + X509_digest(x, EVP_sha1(), x->sha1_hash, NULL); + /* V1 should mean no extensions ... */ + if(!X509_get_version(x)) x->ex_flags |= EXFLAG_V1; + /* Handle basic constraints */ + if((bs=X509_get_ext_d2i(x, NID_basic_constraints, NULL, NULL))) { + if(bs->ca) x->ex_flags |= EXFLAG_CA; + if(bs->pathlen) { + if((bs->pathlen->type == V_ASN1_NEG_INTEGER) + || !bs->ca) { + x->ex_flags |= EXFLAG_INVALID; + x->ex_pathlen = 0; + } else x->ex_pathlen = ASN1_INTEGER_get(bs->pathlen); + } else x->ex_pathlen = -1; + BASIC_CONSTRAINTS_free(bs); + x->ex_flags |= EXFLAG_BCONS; + } + /* Handle proxy certificates */ + if((pci=X509_get_ext_d2i(x, NID_proxyCertInfo, NULL, NULL))) { + if (x->ex_flags & EXFLAG_CA + || X509_get_ext_by_NID(x, NID_subject_alt_name, -1) >= 0 + || X509_get_ext_by_NID(x, NID_issuer_alt_name, -1) >= 0) { + x->ex_flags |= EXFLAG_INVALID; + } + if (pci->pcPathLengthConstraint) { + x->ex_pcpathlen = + ASN1_INTEGER_get(pci->pcPathLengthConstraint); + } else x->ex_pcpathlen = -1; + PROXY_CERT_INFO_EXTENSION_free(pci); + x->ex_flags |= EXFLAG_PROXY; + } + /* Handle key usage */ + if((usage=X509_get_ext_d2i(x, NID_key_usage, NULL, NULL))) { + if(usage->length > 0) { + x->ex_kusage = usage->data[0]; + if(usage->length > 1) + x->ex_kusage |= usage->data[1] << 8; + } else x->ex_kusage = 0; + x->ex_flags |= EXFLAG_KUSAGE; + ASN1_BIT_STRING_free(usage); + } + x->ex_xkusage = 0; + if((extusage=X509_get_ext_d2i(x, NID_ext_key_usage, NULL, NULL))) { + x->ex_flags |= EXFLAG_XKUSAGE; + for(i = 0; i < sk_ASN1_OBJECT_num(extusage); i++) { + switch(OBJ_obj2nid(sk_ASN1_OBJECT_value(extusage,i))) { + case NID_server_auth: + x->ex_xkusage |= XKU_SSL_SERVER; + break; + + case NID_client_auth: + x->ex_xkusage |= XKU_SSL_CLIENT; + break; + + case NID_email_protect: + x->ex_xkusage |= XKU_SMIME; + break; + + case NID_code_sign: + x->ex_xkusage |= XKU_CODE_SIGN; + break; + + case NID_ms_sgc: + case NID_ns_sgc: + x->ex_xkusage |= XKU_SGC; + break; + + case NID_OCSP_sign: + x->ex_xkusage |= XKU_OCSP_SIGN; + break; + + case NID_time_stamp: + x->ex_xkusage |= XKU_TIMESTAMP; + break; + + case NID_dvcs: + x->ex_xkusage |= XKU_DVCS; + break; + + case NID_anyExtendedKeyUsage: + x->ex_xkusage |= XKU_ANYEKU; + break; + } + } + sk_ASN1_OBJECT_pop_free(extusage, ASN1_OBJECT_free); + } + + if((ns=X509_get_ext_d2i(x, NID_netscape_cert_type, NULL, NULL))) { + if(ns->length > 0) x->ex_nscert = ns->data[0]; + else x->ex_nscert = 0; + x->ex_flags |= EXFLAG_NSCERT; + ASN1_BIT_STRING_free(ns); + } + x->skid =X509_get_ext_d2i(x, NID_subject_key_identifier, NULL, NULL); + x->akid =X509_get_ext_d2i(x, NID_authority_key_identifier, NULL, NULL); + /* Does subject name match issuer ? */ + if(!X509_NAME_cmp(X509_get_subject_name(x), X509_get_issuer_name(x))) + { + x->ex_flags |= EXFLAG_SI; + /* If SKID matches AKID also indicate self signed */ + if (X509_check_akid(x, x->akid) == X509_V_OK) + x->ex_flags |= EXFLAG_SS; + } + x->altname = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL); + x->nc = X509_get_ext_d2i(x, NID_name_constraints, &j, NULL); + if (!x->nc && (j != -1)) + x->ex_flags |= EXFLAG_INVALID; + setup_crldp(x); + + for (j = 0; j < X509_get_ext_count(x); j++) + { + ex = X509_get_ext(x, j); + if (OBJ_obj2nid(X509_EXTENSION_get_object(ex)) + == NID_freshest_crl) + x->ex_flags |= EXFLAG_FRESHEST; + if (!X509_EXTENSION_get_critical(ex)) + continue; + if (!X509_supported_extension(ex)) + { + x->ex_flags |= EXFLAG_CRITICAL; + break; + } + } + x->ex_flags |= EXFLAG_SET; + + CRYPTO_STATIC_MUTEX_unlock(&g_x509_cache_extensions_lock); +} + +/* CA checks common to all purposes + * return codes: + * 0 not a CA + * 1 is a CA + * 2 basicConstraints absent so "maybe" a CA + * 3 basicConstraints absent but self signed V1. + * 4 basicConstraints absent but keyUsage present and keyCertSign asserted. + */ + +#define V1_ROOT (EXFLAG_V1|EXFLAG_SS) +#define ku_reject(x, usage) \ + (((x)->ex_flags & EXFLAG_KUSAGE) && !((x)->ex_kusage & (usage))) +#define xku_reject(x, usage) \ + (((x)->ex_flags & EXFLAG_XKUSAGE) && !((x)->ex_xkusage & (usage))) +#define ns_reject(x, usage) \ + (((x)->ex_flags & EXFLAG_NSCERT) && !((x)->ex_nscert & (usage))) + +static int check_ca(const X509 *x) +{ + /* keyUsage if present should allow cert signing */ + if(ku_reject(x, KU_KEY_CERT_SIGN)) return 0; + if(x->ex_flags & EXFLAG_BCONS) { + if(x->ex_flags & EXFLAG_CA) return 1; + /* If basicConstraints says not a CA then say so */ + else return 0; + } else { + /* we support V1 roots for... uh, I don't really know why. */ + if((x->ex_flags & V1_ROOT) == V1_ROOT) return 3; + /* If key usage present it must have certSign so tolerate it */ + else if (x->ex_flags & EXFLAG_KUSAGE) return 4; + /* Older certificates could have Netscape-specific CA types */ + else if (x->ex_flags & EXFLAG_NSCERT + && x->ex_nscert & NS_ANY_CA) return 5; + /* can this still be regarded a CA certificate? I doubt it */ + return 0; + } +} + +int X509_check_ca(X509 *x) +{ + if(!(x->ex_flags & EXFLAG_SET)) { + x509v3_cache_extensions(x); + } + + return check_ca(x); +} + +/* Check SSL CA: common checks for SSL client and server */ +static int check_ssl_ca(const X509 *x) +{ + int ca_ret; + ca_ret = check_ca(x); + if(!ca_ret) return 0; + /* check nsCertType if present */ + if(ca_ret != 5 || x->ex_nscert & NS_SSL_CA) return ca_ret; + else return 0; +} + + +static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x, int ca) +{ + if(xku_reject(x,XKU_SSL_CLIENT)) return 0; + if(ca) return check_ssl_ca(x); + /* We need to do digital signatures or key agreement */ + if(ku_reject(x,KU_DIGITAL_SIGNATURE|KU_KEY_AGREEMENT)) return 0; + /* nsCertType if present should allow SSL client use */ + if(ns_reject(x, NS_SSL_CLIENT)) return 0; + return 1; +} +/* Key usage needed for TLS/SSL server: digital signature, encipherment or + * key agreement. The ssl code can check this more thoroughly for individual + * key types. + */ +#define KU_TLS \ + KU_DIGITAL_SIGNATURE|KU_KEY_ENCIPHERMENT|KU_KEY_AGREEMENT + +static int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x, int ca) +{ + if(xku_reject(x,XKU_SSL_SERVER|XKU_SGC)) return 0; + if(ca) return check_ssl_ca(x); + + if(ns_reject(x, NS_SSL_SERVER)) return 0; + if(ku_reject(x, KU_TLS)) return 0; + + return 1; + +} + +static int check_purpose_ns_ssl_server(const X509_PURPOSE *xp, const X509 *x, int ca) +{ + int ret; + ret = check_purpose_ssl_server(xp, x, ca); + if(!ret || ca) return ret; + /* We need to encipher or Netscape complains */ + if(ku_reject(x, KU_KEY_ENCIPHERMENT)) return 0; + return ret; +} + +/* common S/MIME checks */ +static int purpose_smime(const X509 *x, int ca) +{ + if(xku_reject(x,XKU_SMIME)) return 0; + if(ca) { + int ca_ret; + ca_ret = check_ca(x); + if(!ca_ret) return 0; + /* check nsCertType if present */ + if(ca_ret != 5 || x->ex_nscert & NS_SMIME_CA) return ca_ret; + else return 0; + } + if(x->ex_flags & EXFLAG_NSCERT) { + if(x->ex_nscert & NS_SMIME) return 1; + /* Workaround for some buggy certificates */ + if(x->ex_nscert & NS_SSL_CLIENT) return 2; + return 0; + } + return 1; +} + +static int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x, int ca) +{ + int ret; + ret = purpose_smime(x, ca); + if(!ret || ca) return ret; + if(ku_reject(x, KU_DIGITAL_SIGNATURE|KU_NON_REPUDIATION)) return 0; + return ret; +} + +static int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x, int ca) +{ + int ret; + ret = purpose_smime(x, ca); + if(!ret || ca) return ret; + if(ku_reject(x, KU_KEY_ENCIPHERMENT)) return 0; + return ret; +} + +static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x, int ca) +{ + if(ca) { + int ca_ret; + if((ca_ret = check_ca(x)) != 2) return ca_ret; + else return 0; + } + if(ku_reject(x, KU_CRL_SIGN)) return 0; + return 1; +} + +/* OCSP helper: this is *not* a full OCSP check. It just checks that + * each CA is valid. Additional checks must be made on the chain. + */ + +static int ocsp_helper(const X509_PURPOSE *xp, const X509 *x, int ca) +{ + /* Must be a valid CA. Should we really support the "I don't know" + value (2)? */ + if(ca) return check_ca(x); + /* leaf certificate is checked in OCSP_verify() */ + return 1; +} + +static int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x, + int ca) +{ + int i_ext; + + /* If ca is true we must return if this is a valid CA certificate. */ + if (ca) return check_ca(x); + + /* + * Check the optional key usage field: + * if Key Usage is present, it must be one of digitalSignature + * and/or nonRepudiation (other values are not consistent and shall + * be rejected). + */ + if ((x->ex_flags & EXFLAG_KUSAGE) + && ((x->ex_kusage & ~(KU_NON_REPUDIATION | KU_DIGITAL_SIGNATURE)) || + !(x->ex_kusage & (KU_NON_REPUDIATION | KU_DIGITAL_SIGNATURE)))) + return 0; + + /* Only time stamp key usage is permitted and it's required. */ + if (!(x->ex_flags & EXFLAG_XKUSAGE) || x->ex_xkusage != XKU_TIMESTAMP) + return 0; + + /* Extended Key Usage MUST be critical */ + i_ext = X509_get_ext_by_NID((X509 *) x, NID_ext_key_usage, -1); + if (i_ext >= 0) + { + X509_EXTENSION *ext = X509_get_ext((X509 *) x, i_ext); + if (!X509_EXTENSION_get_critical(ext)) + return 0; + } + + return 1; +} + +static int no_check(const X509_PURPOSE *xp, const X509 *x, int ca) +{ + return 1; +} + +/* Various checks to see if one certificate issued the second. + * This can be used to prune a set of possible issuer certificates + * which have been looked up using some simple method such as by + * subject name. + * These are: + * 1. Check issuer_name(subject) == subject_name(issuer) + * 2. If akid(subject) exists check it matches issuer + * 3. If key_usage(issuer) exists check it supports certificate signing + * returns 0 for OK, positive for reason for mismatch, reasons match + * codes for X509_verify_cert() + */ + +int X509_check_issued(X509 *issuer, X509 *subject) +{ + if(X509_NAME_cmp(X509_get_subject_name(issuer), + X509_get_issuer_name(subject))) + return X509_V_ERR_SUBJECT_ISSUER_MISMATCH; + x509v3_cache_extensions(issuer); + x509v3_cache_extensions(subject); + + if(subject->akid) + { + int ret = X509_check_akid(issuer, subject->akid); + if (ret != X509_V_OK) + return ret; + } + + if(subject->ex_flags & EXFLAG_PROXY) + { + if(ku_reject(issuer, KU_DIGITAL_SIGNATURE)) + return X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE; + } + else if(ku_reject(issuer, KU_KEY_CERT_SIGN)) + return X509_V_ERR_KEYUSAGE_NO_CERTSIGN; + return X509_V_OK; +} + +int X509_check_akid(X509 *issuer, AUTHORITY_KEYID *akid) + { + + if(!akid) + return X509_V_OK; + + /* Check key ids (if present) */ + if(akid->keyid && issuer->skid && + ASN1_OCTET_STRING_cmp(akid->keyid, issuer->skid) ) + return X509_V_ERR_AKID_SKID_MISMATCH; + /* Check serial number */ + if(akid->serial && + ASN1_INTEGER_cmp(X509_get_serialNumber(issuer), akid->serial)) + return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH; + /* Check issuer name */ + if(akid->issuer) + { + /* Ugh, for some peculiar reason AKID includes + * SEQUENCE OF GeneralName. So look for a DirName. + * There may be more than one but we only take any + * notice of the first. + */ + GENERAL_NAMES *gens; + GENERAL_NAME *gen; + X509_NAME *nm = NULL; + size_t i; + gens = akid->issuer; + for(i = 0; i < sk_GENERAL_NAME_num(gens); i++) + { + gen = sk_GENERAL_NAME_value(gens, i); + if(gen->type == GEN_DIRNAME) + { + nm = gen->d.dirn; + break; + } + } + if(nm && X509_NAME_cmp(nm, X509_get_issuer_name(issuer))) + return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH; + } + return X509_V_OK; + } + diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_skey.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_skey.c new file mode 100644 index 00000000..e396f054 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_skey.c @@ -0,0 +1,148 @@ +/* v3_skey.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + + +#include +#include + +#include +#include +#include +#include + + +static ASN1_OCTET_STRING *s2i_skey_id(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, char *str); +const X509V3_EXT_METHOD v3_skey_id = { +NID_subject_key_identifier, 0, ASN1_ITEM_ref(ASN1_OCTET_STRING), +0,0,0,0, +(X509V3_EXT_I2S)i2s_ASN1_OCTET_STRING, +(X509V3_EXT_S2I)s2i_skey_id, +0,0,0,0, +NULL}; + +char *i2s_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method, + ASN1_OCTET_STRING *oct) +{ + return hex_to_string(oct->data, oct->length); +} + +ASN1_OCTET_STRING *s2i_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, char *str) +{ + ASN1_OCTET_STRING *oct; + long length; + + if(!(oct = M_ASN1_OCTET_STRING_new())) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + + if(!(oct->data = string_to_hex(str, &length))) { + M_ASN1_OCTET_STRING_free(oct); + return NULL; + } + + oct->length = length; + + return oct; + +} + +static ASN1_OCTET_STRING *s2i_skey_id(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, char *str) +{ + ASN1_OCTET_STRING *oct; + ASN1_BIT_STRING *pk; + unsigned char pkey_dig[EVP_MAX_MD_SIZE]; + unsigned int diglen; + + if(strcmp(str, "hash")) return s2i_ASN1_OCTET_STRING(method, ctx, str); + + if(!(oct = M_ASN1_OCTET_STRING_new())) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + + if(ctx && (ctx->flags == CTX_TEST)) return oct; + + if(!ctx || (!ctx->subject_req && !ctx->subject_cert)) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_NO_PUBLIC_KEY); + goto err; + } + + if(ctx->subject_req) + pk = ctx->subject_req->req_info->pubkey->public_key; + else pk = ctx->subject_cert->cert_info->key->public_key; + + if(!pk) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_NO_PUBLIC_KEY); + goto err; + } + + if (!EVP_Digest(pk->data, pk->length, pkey_dig, &diglen, EVP_sha1(), NULL)) + goto err; + + if(!M_ASN1_OCTET_STRING_set(oct, pkey_dig, diglen)) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + goto err; + } + + return oct; + + err: + M_ASN1_OCTET_STRING_free(oct); + return NULL; +} diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_sxnet.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_sxnet.c new file mode 100644 index 00000000..4dd5bfc1 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_sxnet.c @@ -0,0 +1,266 @@ +/* v3_sxnet.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +/* Support for Thawte strong extranet extension */ + +#define SXNET_TEST + +static int sxnet_i2r(X509V3_EXT_METHOD *method, SXNET *sx, BIO *out, int indent); +#ifdef SXNET_TEST +static SXNET * sxnet_v2i(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, + STACK_OF(CONF_VALUE) *nval); +#endif +const X509V3_EXT_METHOD v3_sxnet = { +NID_sxnet, X509V3_EXT_MULTILINE, ASN1_ITEM_ref(SXNET), +0,0,0,0, +0,0, +0, +#ifdef SXNET_TEST +(X509V3_EXT_V2I)sxnet_v2i, +#else +0, +#endif +(X509V3_EXT_I2R)sxnet_i2r, +0, +NULL +}; + +ASN1_SEQUENCE(SXNETID) = { + ASN1_SIMPLE(SXNETID, zone, ASN1_INTEGER), + ASN1_SIMPLE(SXNETID, user, ASN1_OCTET_STRING) +} ASN1_SEQUENCE_END(SXNETID) + +IMPLEMENT_ASN1_FUNCTIONS(SXNETID) + +ASN1_SEQUENCE(SXNET) = { + ASN1_SIMPLE(SXNET, version, ASN1_INTEGER), + ASN1_SEQUENCE_OF(SXNET, ids, SXNETID) +} ASN1_SEQUENCE_END(SXNET) + +IMPLEMENT_ASN1_FUNCTIONS(SXNET) + +static int sxnet_i2r(X509V3_EXT_METHOD *method, SXNET *sx, BIO *out, + int indent) +{ + long v; + char *tmp; + SXNETID *id; + size_t i; + v = ASN1_INTEGER_get(sx->version); + BIO_printf(out, "%*sVersion: %ld (0x%lX)", indent, "", v + 1, v); + for(i = 0; i < sk_SXNETID_num(sx->ids); i++) { + id = sk_SXNETID_value(sx->ids, i); + tmp = i2s_ASN1_INTEGER(NULL, id->zone); + BIO_printf(out, "\n%*sZone: %s, User: ", indent, "", tmp); + OPENSSL_free(tmp); + M_ASN1_OCTET_STRING_print(out, id->user); + } + return 1; +} + +#ifdef SXNET_TEST + +/* NBB: this is used for testing only. It should *not* be used for anything + * else because it will just take static IDs from the configuration file and + * they should really be separate values for each user. + */ + + +static SXNET * sxnet_v2i(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, + STACK_OF(CONF_VALUE) *nval) +{ + CONF_VALUE *cnf; + SXNET *sx = NULL; + size_t i; + for(i = 0; i < sk_CONF_VALUE_num(nval); i++) { + cnf = sk_CONF_VALUE_value(nval, i); + if(!SXNET_add_id_asc(&sx, cnf->name, cnf->value, -1)) + return NULL; + } + return sx; +} + + +#endif + +/* Strong Extranet utility functions */ + +/* Add an id given the zone as an ASCII number */ + +int SXNET_add_id_asc(SXNET **psx, char *zone, char *user, + int userlen) +{ + ASN1_INTEGER *izone = NULL; + if(!(izone = s2i_ASN1_INTEGER(NULL, zone))) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_ERROR_CONVERTING_ZONE); + return 0; + } + return SXNET_add_id_INTEGER(psx, izone, user, userlen); +} + +/* Add an id given the zone as an unsigned long */ + +int SXNET_add_id_ulong(SXNET **psx, unsigned long lzone, char *user, + int userlen) +{ + ASN1_INTEGER *izone = NULL; + if(!(izone = M_ASN1_INTEGER_new()) || !ASN1_INTEGER_set(izone, lzone)) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + M_ASN1_INTEGER_free(izone); + return 0; + } + return SXNET_add_id_INTEGER(psx, izone, user, userlen); + +} + +/* Add an id given the zone as an ASN1_INTEGER. + * Note this version uses the passed integer and doesn't make a copy so don't + * free it up afterwards. + */ + +int SXNET_add_id_INTEGER(SXNET **psx, ASN1_INTEGER *zone, char *user, + int userlen) +{ + SXNET *sx = NULL; + SXNETID *id = NULL; + if(!psx || !zone || !user) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NULL_ARGUMENT); + return 0; + } + if(userlen == -1) userlen = strlen(user); + if(userlen > 64) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_USER_TOO_LONG); + return 0; + } + if(!*psx) { + if(!(sx = SXNET_new())) goto err; + if(!ASN1_INTEGER_set(sx->version, 0)) goto err; + *psx = sx; + } else sx = *psx; + if(SXNET_get_id_INTEGER(sx, zone)) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_DUPLICATE_ZONE_ID); + return 0; + } + + if(!(id = SXNETID_new())) goto err; + if(userlen == -1) userlen = strlen(user); + + if(!M_ASN1_OCTET_STRING_set(id->user, user, userlen)) goto err; + if(!sk_SXNETID_push(sx->ids, id)) goto err; + id->zone = zone; + return 1; + + err: + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + SXNETID_free(id); + SXNET_free(sx); + *psx = NULL; + return 0; +} + +ASN1_OCTET_STRING *SXNET_get_id_asc(SXNET *sx, char *zone) +{ + ASN1_INTEGER *izone = NULL; + ASN1_OCTET_STRING *oct; + if(!(izone = s2i_ASN1_INTEGER(NULL, zone))) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_ERROR_CONVERTING_ZONE); + return NULL; + } + oct = SXNET_get_id_INTEGER(sx, izone); + M_ASN1_INTEGER_free(izone); + return oct; +} + +ASN1_OCTET_STRING *SXNET_get_id_ulong(SXNET *sx, unsigned long lzone) +{ + ASN1_INTEGER *izone = NULL; + ASN1_OCTET_STRING *oct; + if(!(izone = M_ASN1_INTEGER_new()) || !ASN1_INTEGER_set(izone, lzone)) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + M_ASN1_INTEGER_free(izone); + return NULL; + } + oct = SXNET_get_id_INTEGER(sx, izone); + M_ASN1_INTEGER_free(izone); + return oct; +} + +ASN1_OCTET_STRING *SXNET_get_id_INTEGER(SXNET *sx, ASN1_INTEGER *zone) +{ + SXNETID *id; + size_t i; + for(i = 0; i < sk_SXNETID_num(sx->ids); i++) { + id = sk_SXNETID_value(sx->ids, i); + if(!M_ASN1_INTEGER_cmp(id->zone, zone)) return id->user; + } + return NULL; +} + +IMPLEMENT_ASN1_SET_OF(SXNETID) diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_utl.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_utl.c new file mode 100644 index 00000000..790c5ab5 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_utl.c @@ -0,0 +1,1316 @@ +/* v3_utl.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 1999-2003 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* X509 v3 extension utilities */ + + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +static char *strip_spaces(char *name); +static int sk_strcmp(const OPENSSL_STRING *a, const OPENSSL_STRING *b); +static STACK_OF(OPENSSL_STRING) *get_email(X509_NAME *name, GENERAL_NAMES *gens); +static void str_free(OPENSSL_STRING str); +static int append_ia5(STACK_OF(OPENSSL_STRING) **sk, ASN1_IA5STRING *email); + +static int ipv4_from_asc(unsigned char *v4, const char *in); +static int ipv6_from_asc(unsigned char *v6, const char *in); +static int ipv6_cb(const char *elem, int len, void *usr); +static int ipv6_hex(unsigned char *out, const char *in, int inlen); + +/* Add a CONF_VALUE name value pair to stack */ + +int X509V3_add_value(const char *name, const char *value, + STACK_OF(CONF_VALUE) **extlist) +{ + CONF_VALUE *vtmp = NULL; + char *tname = NULL, *tvalue = NULL; + if(name && !(tname = BUF_strdup(name))) goto err; + if(value && !(tvalue = BUF_strdup(value))) goto err; + if(!(vtmp = (CONF_VALUE *)OPENSSL_malloc(sizeof(CONF_VALUE)))) goto err; + if(!*extlist && !(*extlist = sk_CONF_VALUE_new_null())) goto err; + vtmp->section = NULL; + vtmp->name = tname; + vtmp->value = tvalue; + if(!sk_CONF_VALUE_push(*extlist, vtmp)) goto err; + return 1; + err: + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + if(vtmp) OPENSSL_free(vtmp); + if(tname) OPENSSL_free(tname); + if(tvalue) OPENSSL_free(tvalue); + return 0; +} + +int X509V3_add_value_uchar(const char *name, const unsigned char *value, + STACK_OF(CONF_VALUE) **extlist) + { + return X509V3_add_value(name,(const char *)value,extlist); + } + +/* Free function for STACK_OF(CONF_VALUE) */ + +void X509V3_conf_free(CONF_VALUE *conf) +{ + if(!conf) return; + if(conf->name) OPENSSL_free(conf->name); + if(conf->value) OPENSSL_free(conf->value); + if(conf->section) OPENSSL_free(conf->section); + OPENSSL_free(conf); +} + +int X509V3_add_value_bool(const char *name, int asn1_bool, + STACK_OF(CONF_VALUE) **extlist) +{ + if(asn1_bool) return X509V3_add_value(name, "TRUE", extlist); + return X509V3_add_value(name, "FALSE", extlist); +} + +int X509V3_add_value_bool_nf(char *name, int asn1_bool, + STACK_OF(CONF_VALUE) **extlist) +{ + if(asn1_bool) return X509V3_add_value(name, "TRUE", extlist); + return 1; +} + + +char *i2s_ASN1_ENUMERATED(X509V3_EXT_METHOD *method, ASN1_ENUMERATED *a) +{ + BIGNUM *bntmp = NULL; + char *strtmp = NULL; + if(!a) return NULL; + if(!(bntmp = ASN1_ENUMERATED_to_BN(a, NULL)) || + !(strtmp = BN_bn2dec(bntmp)) ) + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + BN_free(bntmp); + return strtmp; +} + +char *i2s_ASN1_INTEGER(X509V3_EXT_METHOD *method, ASN1_INTEGER *a) +{ + BIGNUM *bntmp = NULL; + char *strtmp = NULL; + if(!a) return NULL; + if(!(bntmp = ASN1_INTEGER_to_BN(a, NULL)) || + !(strtmp = BN_bn2dec(bntmp)) ) + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + BN_free(bntmp); + return strtmp; +} + +ASN1_INTEGER *s2i_ASN1_INTEGER(X509V3_EXT_METHOD *method, char *value) +{ + BIGNUM *bn = NULL; + ASN1_INTEGER *aint; + int isneg, ishex; + int ret; + if (!value) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NULL_VALUE); + return 0; + } + bn = BN_new(); + if (value[0] == '-') { + value++; + isneg = 1; + } else isneg = 0; + + if (value[0] == '0' && ((value[1] == 'x') || (value[1] == 'X'))) { + value += 2; + ishex = 1; + } else ishex = 0; + + if (ishex) ret = BN_hex2bn(&bn, value); + else ret = BN_dec2bn(&bn, value); + + if (!ret || value[ret]) { + BN_free(bn); + OPENSSL_PUT_ERROR(X509V3, X509V3_R_BN_DEC2BN_ERROR); + return 0; + } + + if (isneg && BN_is_zero(bn)) isneg = 0; + + aint = BN_to_ASN1_INTEGER(bn, NULL); + BN_free(bn); + if (!aint) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_BN_TO_ASN1_INTEGER_ERROR); + return 0; + } + if (isneg) aint->type |= V_ASN1_NEG; + return aint; +} + +int X509V3_add_value_int(const char *name, ASN1_INTEGER *aint, + STACK_OF(CONF_VALUE) **extlist) +{ + char *strtmp; + int ret; + if(!aint) return 1; + if(!(strtmp = i2s_ASN1_INTEGER(NULL, aint))) return 0; + ret = X509V3_add_value(name, strtmp, extlist); + OPENSSL_free(strtmp); + return ret; +} + +int X509V3_get_value_bool(CONF_VALUE *value, int *asn1_bool) +{ + char *btmp; + if(!(btmp = value->value)) goto err; + if(!strcmp(btmp, "TRUE") || !strcmp(btmp, "true") + || !strcmp(btmp, "Y") || !strcmp(btmp, "y") + || !strcmp(btmp, "YES") || !strcmp(btmp, "yes")) { + *asn1_bool = 0xff; + return 1; + } else if(!strcmp(btmp, "FALSE") || !strcmp(btmp, "false") + || !strcmp(btmp, "N") || !strcmp(btmp, "n") + || !strcmp(btmp, "NO") || !strcmp(btmp, "no")) { + *asn1_bool = 0; + return 1; + } + err: + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_BOOLEAN_STRING); + X509V3_conf_err(value); + return 0; +} + +int X509V3_get_value_int(CONF_VALUE *value, ASN1_INTEGER **aint) +{ + ASN1_INTEGER *itmp; + if(!(itmp = s2i_ASN1_INTEGER(NULL, value->value))) { + X509V3_conf_err(value); + return 0; + } + *aint = itmp; + return 1; +} + +#define HDR_NAME 1 +#define HDR_VALUE 2 + +/*#define DEBUG*/ + +STACK_OF(CONF_VALUE) *X509V3_parse_list(const char *line) +{ + char *p, *q, c; + char *ntmp, *vtmp; + STACK_OF(CONF_VALUE) *values = NULL; + char *linebuf; + int state; + /* We are going to modify the line so copy it first */ + linebuf = BUF_strdup(line); + if (linebuf == NULL) + { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + goto err; + } + state = HDR_NAME; + ntmp = NULL; + /* Go through all characters */ + for(p = linebuf, q = linebuf; (c = *p) && (c!='\r') && (c!='\n'); p++) { + + switch(state) { + case HDR_NAME: + if(c == ':') { + state = HDR_VALUE; + *p = 0; + ntmp = strip_spaces(q); + if(!ntmp) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NULL_NAME); + goto err; + } + q = p + 1; + } else if(c == ',') { + *p = 0; + ntmp = strip_spaces(q); + q = p + 1; +#if 0 + printf("%s\n", ntmp); +#endif + if(!ntmp) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NULL_NAME); + goto err; + } + X509V3_add_value(ntmp, NULL, &values); + } + break ; + + case HDR_VALUE: + if(c == ',') { + state = HDR_NAME; + *p = 0; + vtmp = strip_spaces(q); +#if 0 + printf("%s\n", ntmp); +#endif + if(!vtmp) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NULL_VALUE); + goto err; + } + X509V3_add_value(ntmp, vtmp, &values); + ntmp = NULL; + q = p + 1; + } + + } + } + + if(state == HDR_VALUE) { + vtmp = strip_spaces(q); +#if 0 + printf("%s=%s\n", ntmp, vtmp); +#endif + if(!vtmp) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NULL_VALUE); + goto err; + } + X509V3_add_value(ntmp, vtmp, &values); + } else { + ntmp = strip_spaces(q); +#if 0 + printf("%s\n", ntmp); +#endif + if(!ntmp) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NULL_NAME); + goto err; + } + X509V3_add_value(ntmp, NULL, &values); + } +OPENSSL_free(linebuf); +return values; + +err: +OPENSSL_free(linebuf); +sk_CONF_VALUE_pop_free(values, X509V3_conf_free); +return NULL; + +} + +/* Delete leading and trailing spaces from a string */ +static char *strip_spaces(char *name) +{ + char *p, *q; + /* Skip over leading spaces */ + p = name; + while(*p && isspace((unsigned char)*p)) p++; + if(!*p) return NULL; + q = p + strlen(p) - 1; + while((q != p) && isspace((unsigned char)*q)) q--; + if(p != q) q[1] = 0; + if(!*p) return NULL; + return p; +} + +/* hex string utilities */ + +/* Given a buffer of length 'len' return a OPENSSL_malloc'ed string with its + * hex representation + * @@@ (Contents of buffer are always kept in ASCII, also on EBCDIC machines) + */ + +char *hex_to_string(const unsigned char *buffer, long len) +{ + char *tmp, *q; + const unsigned char *p; + int i; + static const char hexdig[] = "0123456789ABCDEF"; + if(!buffer || !len) return NULL; + if(!(tmp = OPENSSL_malloc(len * 3 + 1))) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + q = tmp; + for(i = 0, p = buffer; i < len; i++,p++) { + *q++ = hexdig[(*p >> 4) & 0xf]; + *q++ = hexdig[*p & 0xf]; + *q++ = ':'; + } + q[-1] = 0; + + return tmp; +} + +/* Give a string of hex digits convert to + * a buffer + */ + +unsigned char *string_to_hex(const char *str, long *len) +{ + unsigned char *hexbuf, *q; + unsigned char ch, cl, *p; + if(!str) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NULL_ARGUMENT); + return NULL; + } + if(!(hexbuf = OPENSSL_malloc(strlen(str) >> 1))) goto err; + for(p = (unsigned char *)str, q = hexbuf; *p;) { + ch = *p++; + if(ch == ':') continue; + cl = *p++; + if(!cl) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_ODD_NUMBER_OF_DIGITS); + OPENSSL_free(hexbuf); + return NULL; + } + if(isupper(ch)) ch = tolower(ch); + if(isupper(cl)) cl = tolower(cl); + + if((ch >= '0') && (ch <= '9')) ch -= '0'; + else if ((ch >= 'a') && (ch <= 'f')) ch -= 'a' - 10; + else goto badhex; + + if((cl >= '0') && (cl <= '9')) cl -= '0'; + else if ((cl >= 'a') && (cl <= 'f')) cl -= 'a' - 10; + else goto badhex; + + *q++ = (ch << 4) | cl; + } + + if(len) *len = q - hexbuf; + + return hexbuf; + + err: + if(hexbuf) OPENSSL_free(hexbuf); + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + + badhex: + OPENSSL_free(hexbuf); + OPENSSL_PUT_ERROR(X509V3, X509V3_R_ILLEGAL_HEX_DIGIT); + return NULL; + +} + +/* V2I name comparison function: returns zero if 'name' matches + * cmp or cmp.* + */ + +int name_cmp(const char *name, const char *cmp) +{ + int len, ret; + char c; + len = strlen(cmp); + if((ret = strncmp(name, cmp, len))) return ret; + c = name[len]; + if(!c || (c=='.')) return 0; + return 1; +} + +static int sk_strcmp(const OPENSSL_STRING *a, const OPENSSL_STRING *b) +{ + return strcmp(*a, *b); +} + +STACK_OF(OPENSSL_STRING) *X509_get1_email(X509 *x) +{ + GENERAL_NAMES *gens; + STACK_OF(OPENSSL_STRING) *ret; + + gens = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL); + ret = get_email(X509_get_subject_name(x), gens); + sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); + return ret; +} + +STACK_OF(OPENSSL_STRING) *X509_get1_ocsp(X509 *x) +{ + AUTHORITY_INFO_ACCESS *info; + STACK_OF(OPENSSL_STRING) *ret = NULL; + size_t i; + + info = X509_get_ext_d2i(x, NID_info_access, NULL, NULL); + if (!info) + return NULL; + for (i = 0; i < sk_ACCESS_DESCRIPTION_num(info); i++) + { + ACCESS_DESCRIPTION *ad = sk_ACCESS_DESCRIPTION_value(info, i); + if (OBJ_obj2nid(ad->method) == NID_ad_OCSP) + { + if (ad->location->type == GEN_URI) + { + if (!append_ia5(&ret, ad->location->d.uniformResourceIdentifier)) + break; + } + } + } + AUTHORITY_INFO_ACCESS_free(info); + return ret; +} + +STACK_OF(OPENSSL_STRING) *X509_REQ_get1_email(X509_REQ *x) +{ + GENERAL_NAMES *gens; + STACK_OF(X509_EXTENSION) *exts; + STACK_OF(OPENSSL_STRING) *ret; + + exts = X509_REQ_get_extensions(x); + gens = X509V3_get_d2i(exts, NID_subject_alt_name, NULL, NULL); + ret = get_email(X509_REQ_get_subject_name(x), gens); + sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); + sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); + return ret; +} + + +static STACK_OF(OPENSSL_STRING) *get_email(X509_NAME *name, GENERAL_NAMES *gens) +{ + STACK_OF(OPENSSL_STRING) *ret = NULL; + X509_NAME_ENTRY *ne; + ASN1_IA5STRING *email; + GENERAL_NAME *gen; + int i; + size_t j; + /* Now add any email address(es) to STACK */ + i = -1; + /* First supplied X509_NAME */ + while((i = X509_NAME_get_index_by_NID(name, + NID_pkcs9_emailAddress, i)) >= 0) { + ne = X509_NAME_get_entry(name, i); + email = X509_NAME_ENTRY_get_data(ne); + if(!append_ia5(&ret, email)) return NULL; + } + for(j = 0; j < sk_GENERAL_NAME_num(gens); j++) + { + gen = sk_GENERAL_NAME_value(gens, j); + if(gen->type != GEN_EMAIL) continue; + if(!append_ia5(&ret, gen->d.ia5)) return NULL; + } + return ret; +} + +static void str_free(OPENSSL_STRING str) +{ + OPENSSL_free(str); +} + +static int append_ia5(STACK_OF(OPENSSL_STRING) **sk, ASN1_IA5STRING *email) +{ + char *emtmp; + /* First some sanity checks */ + if(email->type != V_ASN1_IA5STRING) return 1; + if(!email->data || !email->length) return 1; + if(!*sk) *sk = sk_OPENSSL_STRING_new(sk_strcmp); + if(!*sk) return 0; + /* Don't add duplicates */ + if(sk_OPENSSL_STRING_find(*sk, NULL, (char *)email->data)) return 1; + emtmp = BUF_strdup((char *)email->data); + if(!emtmp || !sk_OPENSSL_STRING_push(*sk, emtmp)) { + X509_email_free(*sk); + *sk = NULL; + return 0; + } + return 1; +} + +void X509_email_free(STACK_OF(OPENSSL_STRING) *sk) +{ + sk_OPENSSL_STRING_pop_free(sk, str_free); +} + +typedef int (*equal_fn)(const unsigned char *pattern, size_t pattern_len, + const unsigned char *subject, size_t subject_len, + unsigned int flags); + +/* Skip pattern prefix to match "wildcard" subject */ +static void skip_prefix(const unsigned char **p, size_t *plen, + const unsigned char *subject, size_t subject_len, + unsigned int flags) + { + const unsigned char *pattern = *p; + size_t pattern_len = *plen; + + /* + * If subject starts with a leading '.' followed by more octets, and + * pattern is longer, compare just an equal-length suffix with the + * full subject (starting at the '.'), provided the prefix contains + * no NULs. + */ + if ((flags & _X509_CHECK_FLAG_DOT_SUBDOMAINS) == 0) + return; + + while (pattern_len > subject_len && *pattern) + { + if ((flags & X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS) && + *pattern == '.') + break; + ++pattern; + --pattern_len; + } + + /* Skip if entire prefix acceptable */ + if (pattern_len == subject_len) + { + *p = pattern; + *plen = pattern_len; + } + } + +/* Compare while ASCII ignoring case. */ +static int equal_nocase(const unsigned char *pattern, size_t pattern_len, + const unsigned char *subject, size_t subject_len, + unsigned int flags) + { + skip_prefix(&pattern, &pattern_len, subject, subject_len, flags); + if (pattern_len != subject_len) + return 0; + while (pattern_len) + { + unsigned char l = *pattern; + unsigned char r = *subject; + /* The pattern must not contain NUL characters. */ + if (l == 0) + return 0; + if (l != r) + { + if ('A' <= l && l <= 'Z') + l = (l - 'A') + 'a'; + if ('A' <= r && r <= 'Z') + r = (r - 'A') + 'a'; + if (l != r) + return 0; + } + ++pattern; + ++subject; + --pattern_len; + } + return 1; + } + +/* Compare using memcmp. */ +static int equal_case(const unsigned char *pattern, size_t pattern_len, + const unsigned char *subject, size_t subject_len, + unsigned int flags) +{ + skip_prefix(&pattern, &pattern_len, subject, subject_len, flags); + if (pattern_len != subject_len) + return 0; + return !memcmp(pattern, subject, pattern_len); +} + +/* RFC 5280, section 7.5, requires that only the domain is compared in + a case-insensitive manner. */ +static int equal_email(const unsigned char *a, size_t a_len, + const unsigned char *b, size_t b_len, + unsigned int unused_flags) + { + size_t i = a_len; + if (a_len != b_len) + return 0; + /* We search backwards for the '@' character, so that we do + not have to deal with quoted local-parts. The domain part + is compared in a case-insensitive manner. */ + while (i > 0) + { + --i; + if (a[i] == '@' || b[i] == '@') + { + if (!equal_nocase(a + i, a_len - i, + b + i, a_len - i, 0)) + return 0; + break; + } + } + if (i == 0) + i = a_len; + return equal_case(a, i, b, i, 0); + } + +/* Compare the prefix and suffix with the subject, and check that the + characters in-between are valid. */ +static int wildcard_match(const unsigned char *prefix, size_t prefix_len, + const unsigned char *suffix, size_t suffix_len, + const unsigned char *subject, size_t subject_len, + unsigned int flags) + { + const unsigned char *wildcard_start; + const unsigned char *wildcard_end; + const unsigned char *p; + int allow_multi = 0; + int allow_idna = 0; + + if (subject_len < prefix_len + suffix_len) + return 0; + if (!equal_nocase(prefix, prefix_len, subject, prefix_len, flags)) + return 0; + wildcard_start = subject + prefix_len; + wildcard_end = subject + (subject_len - suffix_len); + if (!equal_nocase(wildcard_end, suffix_len, suffix, suffix_len, flags)) + return 0; + /* + * If the wildcard makes up the entire first label, it must match at + * least one character. + */ + if (prefix_len == 0 && *suffix == '.') + { + if (wildcard_start == wildcard_end) + return 0; + allow_idna = 1; + if (flags & X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS) + allow_multi = 1; + } + /* IDNA labels cannot match partial wildcards */ + if (!allow_idna && + subject_len >= 4 && OPENSSL_strncasecmp((char *)subject, "xn--", 4) == 0) + return 0; + /* The wildcard may match a literal '*' */ + if (wildcard_end == wildcard_start + 1 && *wildcard_start == '*') + return 1; + /* + * Check that the part matched by the wildcard contains only + * permitted characters and only matches a single label unless + * allow_multi is set. + */ + for (p = wildcard_start; p != wildcard_end; ++p) + if (!(('0' <= *p && *p <= '9') || + ('A' <= *p && *p <= 'Z') || + ('a' <= *p && *p <= 'z') || + *p == '-' || (allow_multi && *p == '.'))) + return 0; + return 1; + } + +#define LABEL_START (1 << 0) +#define LABEL_END (1 << 1) +#define LABEL_HYPHEN (1 << 2) +#define LABEL_IDNA (1 << 3) + +static const unsigned char *valid_star(const unsigned char *p, size_t len, + unsigned int flags) + { + const unsigned char *star = 0; + size_t i; + int state = LABEL_START; + int dots = 0; + for (i = 0; i < len; ++i) + { + /* + * Locate first and only legal wildcard, either at the start + * or end of a non-IDNA first and not final label. + */ + if (p[i] == '*') + { + int atstart = (state & LABEL_START); + int atend = (i == len - 1 || p[i+1] == '.'); + /* + * At most one wildcard per pattern. + * No wildcards in IDNA labels. + * No wildcards after the first label. + */ + if (star != NULL || (state & LABEL_IDNA) != 0 || dots) + return NULL; + /* Only full-label '*.example.com' wildcards? */ + if ((flags & X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS) + && (!atstart || !atend)) + return NULL; + /* No 'foo*bar' wildcards */ + if (!atstart && !atend) + return NULL; + star = &p[i]; + state &= ~LABEL_START; + } + else if ((state & LABEL_START) != 0) + { + /* + * At the start of a label, skip any "xn--" and + * remain in the LABEL_START state, but set the + * IDNA label state + */ + if ((state & LABEL_IDNA) == 0 && len - i >= 4 + && OPENSSL_strncasecmp((char *)&p[i], "xn--", 4) == 0) + { + i += 3; + state |= LABEL_IDNA; + continue; + } + /* Labels must start with a letter or digit */ + state &= ~LABEL_START; + if (('a' <= p[i] && p[i] <= 'z') + || ('A' <= p[i] && p[i] <= 'Z') + || ('0' <= p[i] && p[i] <= '9')) + continue; + return NULL; + } + else if (('a' <= p[i] && p[i] <= 'z') + || ('A' <= p[i] && p[i] <= 'Z') + || ('0' <= p[i] && p[i] <= '9')) + { + state &= LABEL_IDNA; + continue; + } + else if (p[i] == '.') + { + if (state & (LABEL_HYPHEN | LABEL_START)) + return NULL; + state = LABEL_START; + ++dots; + } + else if (p[i] == '-') + { + if (state & LABEL_HYPHEN) + return NULL; + state |= LABEL_HYPHEN; + } + else + return NULL; + } + + /* + * The final label must not end in a hyphen or ".", and + * there must be at least two dots after the star. + */ + if ((state & (LABEL_START | LABEL_HYPHEN)) != 0 + || dots < 2) + return NULL; + return star; + } + +/* Compare using wildcards. */ +static int equal_wildcard(const unsigned char *pattern, size_t pattern_len, + const unsigned char *subject, size_t subject_len, + unsigned int flags) + { + const unsigned char *star = NULL; + + /* + * Subject names starting with '.' can only match a wildcard pattern + * via a subject sub-domain pattern suffix match. + */ + if (!(subject_len > 1 && subject[0] == '.')) + star = valid_star(pattern, pattern_len, flags); + if (star == NULL) + return equal_nocase(pattern, pattern_len, + subject, subject_len, flags); + return wildcard_match(pattern, star - pattern, + star + 1, (pattern + pattern_len) - star - 1, + subject, subject_len, flags); + } + +/* Compare an ASN1_STRING to a supplied string. If they match + * return 1. If cmp_type > 0 only compare if string matches the + * type, otherwise convert it to UTF8. + */ + +static int do_check_string(ASN1_STRING *a, int cmp_type, equal_fn equal, + unsigned int flags, const char *b, size_t blen, + char **peername) + { + int rv = 0; + + if (!a->data || !a->length) + return 0; + if (cmp_type > 0) + { + if (cmp_type != a->type) + return 0; + if (cmp_type == V_ASN1_IA5STRING) + rv = equal(a->data, a->length, + (unsigned char *)b, blen, flags); + else if (a->length == (int)blen && !memcmp(a->data, b, blen)) + rv = 1; + if (rv > 0 && peername) + *peername = BUF_strndup((char *)a->data, a->length); + } + else + { + int astrlen; + unsigned char *astr; + astrlen = ASN1_STRING_to_UTF8(&astr, a); + if (astrlen < 0) + return -1; + rv = equal(astr, astrlen, (unsigned char *)b, blen, flags); + if (rv > 0 && peername) + *peername = BUF_strndup((char *)astr, astrlen); + OPENSSL_free(astr); + } + return rv; + } + +static int do_x509_check(X509 *x, const char *chk, size_t chklen, + unsigned int flags, int check_type, + char **peername) + { + GENERAL_NAMES *gens = NULL; + X509_NAME *name = NULL; + size_t i; + int j; + int cnid; + int alt_type; + int san_present = 0; + int rv = 0; + equal_fn equal; + + /* See below, this flag is internal-only */ + flags &= ~_X509_CHECK_FLAG_DOT_SUBDOMAINS; + if (check_type == GEN_EMAIL) + { + cnid = NID_pkcs9_emailAddress; + alt_type = V_ASN1_IA5STRING; + equal = equal_email; + } + else if (check_type == GEN_DNS) + { + cnid = NID_commonName; + /* Implicit client-side DNS sub-domain pattern */ + if (chklen > 1 && chk[0] == '.') + flags |= _X509_CHECK_FLAG_DOT_SUBDOMAINS; + alt_type = V_ASN1_IA5STRING; + if (flags & X509_CHECK_FLAG_NO_WILDCARDS) + equal = equal_nocase; + else + equal = equal_wildcard; + } + else + { + cnid = 0; + alt_type = V_ASN1_OCTET_STRING; + equal = equal_case; + } + + gens = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL); + if (gens) + { + for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) + { + GENERAL_NAME *gen; + ASN1_STRING *cstr; + gen = sk_GENERAL_NAME_value(gens, i); + if (gen->type != check_type) + continue; + san_present = 1; + if (check_type == GEN_EMAIL) + cstr = gen->d.rfc822Name; + else if (check_type == GEN_DNS) + cstr = gen->d.dNSName; + else + cstr = gen->d.iPAddress; + /* Positive on success, negative on error! */ + if ((rv = do_check_string(cstr, alt_type, equal, flags, + chk, chklen, peername)) != 0) + break; + } + GENERAL_NAMES_free(gens); + if (rv != 0) + return rv; + if (!cnid + || (san_present + && !(flags & X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT))) + return 0; + } + j = -1; + name = X509_get_subject_name(x); + while((j = X509_NAME_get_index_by_NID(name, cnid, j)) >= 0) + { + X509_NAME_ENTRY *ne; + ASN1_STRING *str; + ne = X509_NAME_get_entry(name, j); + str = X509_NAME_ENTRY_get_data(ne); + /* Positive on success, negative on error! */ + if ((rv = do_check_string(str, -1, equal, flags, + chk, chklen, peername)) != 0) + return rv; + } + return 0; + } + +int X509_check_host(X509 *x, const char *chk, size_t chklen, + unsigned int flags, char **peername) + { + if (chk == NULL) + return -2; + if (memchr(chk, '\0', chklen)) + return -2; + return do_x509_check(x, chk, chklen, flags, GEN_DNS, peername); + } + +int X509_check_email(X509 *x, const char *chk, size_t chklen, + unsigned int flags) + { + if (chk == NULL) + return -2; + if (memchr(chk, '\0', chklen)) + return -2; + return do_x509_check(x, chk, chklen, flags, GEN_EMAIL, NULL); + } + +int X509_check_ip(X509 *x, const unsigned char *chk, size_t chklen, + unsigned int flags) + { + if (chk == NULL) + return -2; + return do_x509_check(x, (char *)chk, chklen, flags, GEN_IPADD, NULL); + } + +int X509_check_ip_asc(X509 *x, const char *ipasc, unsigned int flags) + { + unsigned char ipout[16]; + size_t iplen; + + if (ipasc == NULL) + return -2; + iplen = (size_t) a2i_ipadd(ipout, ipasc); + if (iplen == 0) + return -2; + return do_x509_check(x, (char *)ipout, iplen, flags, GEN_IPADD, NULL); + } + +/* Convert IP addresses both IPv4 and IPv6 into an + * OCTET STRING compatible with RFC3280. + */ + +ASN1_OCTET_STRING *a2i_IPADDRESS(const char *ipasc) + { + unsigned char ipout[16]; + ASN1_OCTET_STRING *ret; + int iplen; + + /* If string contains a ':' assume IPv6 */ + + iplen = a2i_ipadd(ipout, ipasc); + + if (!iplen) + return NULL; + + ret = ASN1_OCTET_STRING_new(); + if (!ret) + return NULL; + if (!ASN1_OCTET_STRING_set(ret, ipout, iplen)) + { + ASN1_OCTET_STRING_free(ret); + return NULL; + } + return ret; + } + +ASN1_OCTET_STRING *a2i_IPADDRESS_NC(const char *ipasc) + { + ASN1_OCTET_STRING *ret = NULL; + unsigned char ipout[32]; + char *iptmp = NULL, *p; + int iplen1, iplen2; + p = strchr(ipasc,'/'); + if (!p) + return NULL; + iptmp = BUF_strdup(ipasc); + if (!iptmp) + return NULL; + p = iptmp + (p - ipasc); + *p++ = 0; + + iplen1 = a2i_ipadd(ipout, iptmp); + + if (!iplen1) + goto err; + + iplen2 = a2i_ipadd(ipout + iplen1, p); + + OPENSSL_free(iptmp); + iptmp = NULL; + + if (!iplen2 || (iplen1 != iplen2)) + goto err; + + ret = ASN1_OCTET_STRING_new(); + if (!ret) + goto err; + if (!ASN1_OCTET_STRING_set(ret, ipout, iplen1 + iplen2)) + goto err; + + return ret; + + err: + if (iptmp) + OPENSSL_free(iptmp); + if (ret) + ASN1_OCTET_STRING_free(ret); + return NULL; + } + + +int a2i_ipadd(unsigned char *ipout, const char *ipasc) + { + /* If string contains a ':' assume IPv6 */ + + if (strchr(ipasc, ':')) + { + if (!ipv6_from_asc(ipout, ipasc)) + return 0; + return 16; + } + else + { + if (!ipv4_from_asc(ipout, ipasc)) + return 0; + return 4; + } + } + +static int ipv4_from_asc(unsigned char *v4, const char *in) + { + int a0, a1, a2, a3; + if (sscanf(in, "%d.%d.%d.%d", &a0, &a1, &a2, &a3) != 4) + return 0; + if ((a0 < 0) || (a0 > 255) || (a1 < 0) || (a1 > 255) + || (a2 < 0) || (a2 > 255) || (a3 < 0) || (a3 > 255)) + return 0; + v4[0] = a0; + v4[1] = a1; + v4[2] = a2; + v4[3] = a3; + return 1; + } + +typedef struct { + /* Temporary store for IPV6 output */ + unsigned char tmp[16]; + /* Total number of bytes in tmp */ + int total; + /* The position of a zero (corresponding to '::') */ + int zero_pos; + /* Number of zeroes */ + int zero_cnt; + } IPV6_STAT; + + +static int ipv6_from_asc(unsigned char *v6, const char *in) + { + IPV6_STAT v6stat; + v6stat.total = 0; + v6stat.zero_pos = -1; + v6stat.zero_cnt = 0; + /* Treat the IPv6 representation as a list of values + * separated by ':'. The presence of a '::' will parse + * as one, two or three zero length elements. + */ + if (!CONF_parse_list(in, ':', 0, ipv6_cb, &v6stat)) + return 0; + + /* Now for some sanity checks */ + + if (v6stat.zero_pos == -1) + { + /* If no '::' must have exactly 16 bytes */ + if (v6stat.total != 16) + return 0; + } + else + { + /* If '::' must have less than 16 bytes */ + if (v6stat.total == 16) + return 0; + /* More than three zeroes is an error */ + if (v6stat.zero_cnt > 3) + return 0; + /* Can only have three zeroes if nothing else present */ + else if (v6stat.zero_cnt == 3) + { + if (v6stat.total > 0) + return 0; + } + /* Can only have two zeroes if at start or end */ + else if (v6stat.zero_cnt == 2) + { + if ((v6stat.zero_pos != 0) + && (v6stat.zero_pos != v6stat.total)) + return 0; + } + else + /* Can only have one zero if *not* start or end */ + { + if ((v6stat.zero_pos == 0) + || (v6stat.zero_pos == v6stat.total)) + return 0; + } + } + + /* Format result */ + + if (v6stat.zero_pos >= 0) + { + /* Copy initial part */ + memcpy(v6, v6stat.tmp, v6stat.zero_pos); + /* Zero middle */ + memset(v6 + v6stat.zero_pos, 0, 16 - v6stat.total); + /* Copy final part */ + if (v6stat.total != v6stat.zero_pos) + memcpy(v6 + v6stat.zero_pos + 16 - v6stat.total, + v6stat.tmp + v6stat.zero_pos, + v6stat.total - v6stat.zero_pos); + } + else + memcpy(v6, v6stat.tmp, 16); + + return 1; + } + +static int ipv6_cb(const char *elem, int len, void *usr) + { + IPV6_STAT *s = usr; + /* Error if 16 bytes written */ + if (s->total == 16) + return 0; + if (len == 0) + { + /* Zero length element, corresponds to '::' */ + if (s->zero_pos == -1) + s->zero_pos = s->total; + /* If we've already got a :: its an error */ + else if (s->zero_pos != s->total) + return 0; + s->zero_cnt++; + } + else + { + /* If more than 4 characters could be final a.b.c.d form */ + if (len > 4) + { + /* Need at least 4 bytes left */ + if (s->total > 12) + return 0; + /* Must be end of string */ + if (elem[len]) + return 0; + if (!ipv4_from_asc(s->tmp + s->total, elem)) + return 0; + s->total += 4; + } + else + { + if (!ipv6_hex(s->tmp + s->total, elem, len)) + return 0; + s->total += 2; + } + } + return 1; + } + +/* Convert a string of up to 4 hex digits into the corresponding + * IPv6 form. + */ + +static int ipv6_hex(unsigned char *out, const char *in, int inlen) + { + unsigned char c; + unsigned int num = 0; + if (inlen > 4) + return 0; + while(inlen--) + { + c = *in++; + num <<= 4; + if ((c >= '0') && (c <= '9')) + num |= c - '0'; + else if ((c >= 'A') && (c <= 'F')) + num |= c - 'A' + 10; + else if ((c >= 'a') && (c <= 'f')) + num |= c - 'a' + 10; + else + return 0; + } + out[0] = num >> 8; + out[1] = num & 0xff; + return 1; + } + + +int X509V3_NAME_from_section(X509_NAME *nm, STACK_OF(CONF_VALUE)*dn_sk, + unsigned long chtype) + { + CONF_VALUE *v; + int mval; + size_t i; + char *p, *type; + if (!nm) + return 0; + + for (i = 0; i < sk_CONF_VALUE_num(dn_sk); i++) + { + v=sk_CONF_VALUE_value(dn_sk,i); + type=v->name; + /* Skip past any leading X. X: X, etc to allow for + * multiple instances + */ + for(p = type; *p ; p++) + if ((*p == ':') || (*p == ',') || (*p == '.')) + { + p++; + if(*p) type = p; + break; + } + if (*type == '+') + { + mval = -1; + type++; + } + else + mval = 0; + if (!X509_NAME_add_entry_by_txt(nm,type, chtype, + (unsigned char *) v->value,-1,-1,mval)) + return 0; + + } + return 1; + } diff --git a/TMessagesProj/jni/boringssl/include/openssl/aead.h b/TMessagesProj/jni/boringssl/include/openssl/aead.h new file mode 100644 index 00000000..d36cf95b --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/aead.h @@ -0,0 +1,315 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_AEAD_H +#define OPENSSL_HEADER_AEAD_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Authenticated Encryption with Additional Data. + * + * AEAD couples confidentiality and integrity in a single primtive. AEAD + * algorithms take a key and then can seal and open individual messages. Each + * message has a unique, per-message nonce and, optionally, additional data + * which is authenticated but not included in the ciphertext. + * + * The |EVP_AEAD_CTX_init| function initialises an |EVP_AEAD_CTX| structure and + * performs any precomputation needed to use |aead| with |key|. The length of + * the key, |key_len|, is given in bytes. + * + * The |tag_len| argument contains the length of the tags, in bytes, and allows + * for the processing of truncated authenticators. A zero value indicates that + * the default tag length should be used and this is defined as + * |EVP_AEAD_DEFAULT_TAG_LENGTH| in order to make the code clear. Using + * truncated tags increases an attacker's chance of creating a valid forgery. + * Be aware that the attacker's chance may increase more than exponentially as + * would naively be expected. + * + * When no longer needed, the initialised |EVP_AEAD_CTX| structure must be + * passed to |EVP_AEAD_CTX_cleanup|, which will deallocate any memory used. + * + * With an |EVP_AEAD_CTX| in hand, one can seal and open messages. These + * operations are intended to meet the standard notions of privacy and + * authenticity for authenticated encryption. For formal definitions see + * Bellare and Namprempre, "Authenticated encryption: relations among notions + * and analysis of the generic composition paradigm," Lecture Notes in Computer + * Science B<1976> (2000), 531–545, + * http://www-cse.ucsd.edu/~mihir/papers/oem.html. + * + * When sealing messages, a nonce must be given. The length of the nonce is + * fixed by the AEAD in use and is returned by |EVP_AEAD_nonce_length|. *The + * nonce must be unique for all messages with the same key*. This is critically + * important - nonce reuse may completely undermine the security of the AEAD. + * Nonces may be predictable and public, so long as they are unique. Uniqueness + * may be achieved with a simple counter or, if large enough, may be generated + * randomly. The nonce must be passed into the "open" operation by the receiver + * so must either be implicit (e.g. a counter), or must be transmitted along + * with the sealed message. + * + * The "seal" and "open" operations are atomic - an entire message must be + * encrypted or decrypted in a single call. Large messages may have to be split + * up in order to accomodate this. When doing so, be mindful of the need not to + * repeat nonces and the possibility that an attacker could duplicate, reorder + * or drop message chunks. For example, using a single key for a given (large) + * message and sealing chunks with nonces counting from zero would be secure as + * long as the number of chunks was securely transmitted. (Otherwise an + * attacker could truncate the message by dropping chunks from the end.) + * + * The number of chunks could be transmitted by prefixing it to the plaintext, + * for example. This also assumes that no other message would ever use the same + * key otherwise the rule that nonces must be unique for a given key would be + * violated. + * + * The "seal" and "open" operations also permit additional data to be + * authenticated via the |ad| parameter. This data is not included in the + * ciphertext and must be identical for both the "seal" and "open" call. This + * permits implicit context to be authenticated but may be empty if not needed. + * + * The "seal" and "open" operations may work in-place if the |out| and |in| + * arguments are equal. They may also be used to shift the data left inside the + * same buffer if |out| is less than |in|. However, |out| may not point inside + * the input data otherwise the input may be overwritten before it has been + * read. This situation will cause an error. + * + * The "seal" and "open" operations return one on success and zero on error. */ + + +/* AEAD algorithms. */ + +/* EVP_aead_aes_128_gcm is AES-128 in Galois Counter Mode. */ +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_gcm(void); + +/* EVP_aead_aes_256_gcm is AES-256 in Galois Counter Mode. */ +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_gcm(void); + +/* EVP_aead_chacha20_poly1305 is an AEAD built from ChaCha20 and Poly1305. */ +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_chacha20_poly1305(void); + +/* EVP_aead_aes_128_key_wrap is AES-128 Key Wrap mode. This should never be + * used except to interoperate with existing systems that use this mode. + * + * If the nonce is empty then the default nonce will be used, otherwise it must + * be eight bytes long. The input must be a multiple of eight bytes long. No + * additional data can be given to this mode. */ +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_key_wrap(void); + +/* EVP_aead_aes_256_key_wrap is AES-256 in Key Wrap mode. This should never be + * used except to interoperate with existing systems that use this mode. + * + * See |EVP_aead_aes_128_key_wrap| for details. */ +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_key_wrap(void); + +/* EVP_aead_aes_128_ctr_hmac_sha256 is AES-128 in CTR mode with HMAC-SHA256 for + * authentication. The nonce is 12 bytes; the bottom 32-bits are used as the + * block counter, thus the maximum plaintext size is 64GB. */ +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_ctr_hmac_sha256(void); + +/* EVP_aead_aes_128_ctr_hmac_sha256 is AES-256 in CTR mode with HMAC-SHA256 for + * authentication. See |EVP_aead_aes_128_ctr_hmac_sha256| for details. */ +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_ctr_hmac_sha256(void); + +/* EVP_has_aes_hardware returns one if we enable hardware support for fast and + * constant-time AES-GCM. */ +OPENSSL_EXPORT int EVP_has_aes_hardware(void); + + +/* TLS-specific AEAD algorithms. + * + * These AEAD primitives do not meet the definition of generic AEADs. They are + * all specific to TLS and should not be used outside of that context. They must + * be initialized with |EVP_AEAD_CTX_init_with_direction|, are stateful, and may + * not be used concurrently. Any nonces are used as IVs, so they must be + * unpredictable. They only accept an |ad| parameter of length 11 (the standard + * TLS one with length omitted). */ + +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_rc4_md5_tls(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_rc4_sha1_tls(void); + +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_tls(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_tls_implicit_iv(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_cbc_sha256_tls(void); + +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_cbc_sha1_tls(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_cbc_sha1_tls_implicit_iv(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_cbc_sha256_tls(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_cbc_sha384_tls(void); + +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_des_ede3_cbc_sha1_tls(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv(void); + + +/* SSLv3-specific AEAD algorithms. + * + * These AEAD primitives do not meet the definition of generic AEADs. They are + * all specific to SSLv3 and should not be used outside of that context. They + * must be initialized with |EVP_AEAD_CTX_init_with_direction|, are stateful, + * and may not be used concurrently. They only accept an |ad| parameter of + * length 9 (the standard TLS one with length and version omitted). */ + +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_rc4_md5_ssl3(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_rc4_sha1_ssl3(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_ssl3(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_cbc_sha1_ssl3(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_des_ede3_cbc_sha1_ssl3(void); + + +/* Utility functions. */ + +/* EVP_AEAD_key_length returns the length, in bytes, of the keys used by + * |aead|. */ +OPENSSL_EXPORT size_t EVP_AEAD_key_length(const EVP_AEAD *aead); + +/* EVP_AEAD_nonce_length returns the length, in bytes, of the per-message nonce + * for |aead|. */ +OPENSSL_EXPORT size_t EVP_AEAD_nonce_length(const EVP_AEAD *aead); + +/* EVP_AEAD_max_overhead returns the maximum number of additional bytes added + * by the act of sealing data with |aead|. */ +OPENSSL_EXPORT size_t EVP_AEAD_max_overhead(const EVP_AEAD *aead); + +/* EVP_AEAD_max_tag_len returns the maximum tag length when using |aead|. This + * is the largest value that can be passed as |tag_len| to + * |EVP_AEAD_CTX_init|. */ +OPENSSL_EXPORT size_t EVP_AEAD_max_tag_len(const EVP_AEAD *aead); + + +/* AEAD operations. */ + +/* An EVP_AEAD_CTX represents an AEAD algorithm configured with a specific key + * and message-independent IV. */ +typedef struct evp_aead_ctx_st { + const EVP_AEAD *aead; + /* aead_state is an opaque pointer to whatever state the AEAD needs to + * maintain. */ + void *aead_state; +} EVP_AEAD_CTX; + +/* EVP_AEAD_MAX_KEY_LENGTH contains the maximum key length used by + * any AEAD defined in this header. */ +#define EVP_AEAD_MAX_KEY_LENGTH 80 + +/* EVP_AEAD_MAX_NONCE_LENGTH contains the maximum nonce length used by + * any AEAD defined in this header. */ +#define EVP_AEAD_MAX_NONCE_LENGTH 16 + +/* EVP_AEAD_MAX_OVERHEAD contains the maximum overhead used by any AEAD + * defined in this header. */ +#define EVP_AEAD_MAX_OVERHEAD 64 + +/* EVP_AEAD_DEFAULT_TAG_LENGTH is a magic value that can be passed to + * EVP_AEAD_CTX_init to indicate that the default tag length for an AEAD should + * be used. */ +#define EVP_AEAD_DEFAULT_TAG_LENGTH 0 + +/* evp_aead_direction_t denotes the direction of an AEAD operation. */ +enum evp_aead_direction_t { + evp_aead_open, + evp_aead_seal, +}; + +/* EVP_AEAD_CTX_init initializes |ctx| for the given AEAD algorithm. The |impl| + * argument is ignored and should be NULL. Authentication tags may be truncated + * by passing a size as |tag_len|. A |tag_len| of zero indicates the default + * tag length and this is defined as EVP_AEAD_DEFAULT_TAG_LENGTH for + * readability. + * + * Returns 1 on success. Otherwise returns 0 and pushes to the error stack. In + * the error case, you do not need to call |EVP_AEAD_CTX_cleanup|, but it's + * harmless to do so. */ +OPENSSL_EXPORT int EVP_AEAD_CTX_init(EVP_AEAD_CTX *ctx, const EVP_AEAD *aead, + const uint8_t *key, size_t key_len, + size_t tag_len, ENGINE *impl); + +/* EVP_AEAD_CTX_init_with_direction calls |EVP_AEAD_CTX_init| for normal + * AEADs. For TLS-specific and SSL3-specific AEADs, it initializes |ctx| for a + * given direction. */ +OPENSSL_EXPORT int EVP_AEAD_CTX_init_with_direction( + EVP_AEAD_CTX *ctx, const EVP_AEAD *aead, const uint8_t *key, size_t key_len, + size_t tag_len, enum evp_aead_direction_t dir); + +/* EVP_AEAD_CTX_cleanup frees any data allocated by |ctx|. It is a no-op to + * call |EVP_AEAD_CTX_cleanup| on a |EVP_AEAD_CTX| that has been |memset| to + * all zeros. */ +OPENSSL_EXPORT void EVP_AEAD_CTX_cleanup(EVP_AEAD_CTX *ctx); + +/* EVP_AEAD_CTX_seal encrypts and authenticates |in_len| bytes from |in| and + * authenticates |ad_len| bytes from |ad| and writes the result to |out|. It + * returns one on success and zero otherwise. + * + * This function may be called (with the same |EVP_AEAD_CTX|) concurrently with + * itself or |EVP_AEAD_CTX_open|. + * + * At most |max_out_len| bytes are written to |out| and, in order to ensure + * success, |max_out_len| should be |in_len| plus the result of + * |EVP_AEAD_max_overhead|. On successful return, |*out_len| is set to the + * actual number of bytes written. + * + * The length of |nonce|, |nonce_len|, must be equal to the result of + * |EVP_AEAD_nonce_length| for this AEAD. + * + * |EVP_AEAD_CTX_seal| never results in a partial output. If |max_out_len| is + * insufficient, zero will be returned. (In this case, |*out_len| is set to + * zero.) + * + * If |in| and |out| alias then |out| must be <= |in|. */ +OPENSSL_EXPORT int EVP_AEAD_CTX_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len); + +/* EVP_AEAD_CTX_open authenticates |in_len| bytes from |in| and |ad_len| bytes + * from |ad| and decrypts at most |in_len| bytes into |out|. It returns one on + * success and zero otherwise. + * + * This function may be called (with the same |EVP_AEAD_CTX|) concurrently with + * itself or |EVP_AEAD_CTX_seal|. + * + * At most |in_len| bytes are written to |out|. In order to ensure success, + * |max_out_len| should be at least |in_len|. On successful return, |*out_len| + * is set to the the actual number of bytes written. + * + * The length of |nonce|, |nonce_len|, must be equal to the result of + * |EVP_AEAD_nonce_length| for this AEAD. + * + * |EVP_AEAD_CTX_open| never results in a partial output. If |max_out_len| is + * insufficient, zero will be returned. (In this case, |*out_len| is set to + * zero.) + * + * If |in| and |out| alias then |out| must be <= |in|. */ +OPENSSL_EXPORT int EVP_AEAD_CTX_open(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len); + + +/* Obscure functions. */ + +/* EVP_AEAD_CTX_get_rc4_state sets |*out_key| to point to an RC4 key structure. + * It returns one on success or zero if |ctx| doesn't have an RC4 key. */ +OPENSSL_EXPORT int EVP_AEAD_CTX_get_rc4_state(const EVP_AEAD_CTX *ctx, + const RC4_KEY **out_key); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_AEAD_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/aes.h b/TMessagesProj/jni/boringssl/include/openssl/aes.h new file mode 100644 index 00000000..cdec9406 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/aes.h @@ -0,0 +1,167 @@ +/* ==================================================================== + * Copyright (c) 2002-2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== */ + +#ifndef OPENSSL_HEADER_AES_H +#define OPENSSL_HEADER_AES_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Raw AES functions. */ + + +#define AES_ENCRYPT 1 +#define AES_DECRYPT 0 + +/* AES_MAXNR is the maximum number of AES rounds. */ +#define AES_MAXNR 14 + +#define AES_BLOCK_SIZE 16 + +/* aes_key_st should be an opaque type, but EVP requires that the size be + * known. */ +struct aes_key_st { + uint32_t rd_key[4 * (AES_MAXNR + 1)]; + unsigned rounds; +}; +typedef struct aes_key_st AES_KEY; + +/* AES_set_encrypt_key configures |aeskey| to encrypt with the |bits|-bit key, + * |key|. + * + * WARNING: unlike other OpenSSL functions, this returns zero on success and a + * negative number on error. */ +OPENSSL_EXPORT int AES_set_encrypt_key(const uint8_t *key, unsigned bits, + AES_KEY *aeskey); + +/* AES_set_decrypt_key configures |aeskey| to decrypt with the |bits|-bit key, + * |key|. + * + * WARNING: unlike other OpenSSL functions, this returns zero on success and a + * negative number on error. */ +OPENSSL_EXPORT int AES_set_decrypt_key(const uint8_t *key, unsigned bits, + AES_KEY *aeskey); + +/* AES_encrypt encrypts a single block from |in| to |out| with |key|. The |in| + * and |out| pointers may overlap. */ +OPENSSL_EXPORT void AES_encrypt(const uint8_t *in, uint8_t *out, + const AES_KEY *key); + +/* AES_decrypt decrypts a single block from |in| to |out| with |key|. The |in| + * and |out| pointers may overlap. */ +OPENSSL_EXPORT void AES_decrypt(const uint8_t *in, uint8_t *out, + const AES_KEY *key); + + +/* Block cipher modes. */ + +/* AES_ctr128_encrypt encrypts (or decrypts, it's the same in CTR mode) |len| + * bytes from |in| to |out|. The |num| parameter must be set to zero on the + * first call and |ivec| will be incremented. */ +OPENSSL_EXPORT void AES_ctr128_encrypt(const uint8_t *in, uint8_t *out, + size_t len, const AES_KEY *key, + uint8_t ivec[AES_BLOCK_SIZE], + uint8_t ecount_buf[AES_BLOCK_SIZE], + unsigned int *num); + +/* AES_ecb_encrypt encrypts (or decrypts, if |enc| == |AES_DECRYPT|) a single, + * 16 byte block from |in| to |out|. */ +OPENSSL_EXPORT void AES_ecb_encrypt(const uint8_t *in, uint8_t *out, + const AES_KEY *key, const int enc); + +/* AES_cbc_encrypt encrypts (or decrypts, if |enc| == |AES_DECRYPT|) |len| + * bytes from |in| to |out|. The length must be a multiple of the block size. */ +OPENSSL_EXPORT void AES_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const AES_KEY *key, uint8_t *ivec, + const int enc); + +/* AES_ofb128_encrypt encrypts (or decrypts, it's the same in OFB mode) |len| + * bytes from |in| to |out|. The |num| parameter must be set to zero on the + * first call. */ +OPENSSL_EXPORT void AES_ofb128_encrypt(const uint8_t *in, uint8_t *out, + size_t len, const AES_KEY *key, + uint8_t *ivec, int *num); + +/* AES_cfb128_encrypt encrypts (or decrypts, if |enc| == |AES_DECRYPT|) |len| + * bytes from |in| to |out|. The |num| parameter must be set to zero on the + * first call. */ +OPENSSL_EXPORT void AES_cfb128_encrypt(const uint8_t *in, uint8_t *out, + size_t len, const AES_KEY *key, + uint8_t *ivec, int *num, int enc); + +/* NB: the IV is _two_ blocks long */ +OPENSSL_EXPORT void AES_ige_encrypt(const unsigned char *in, unsigned char *out, + size_t length, const AES_KEY *key, + unsigned char *ivec, const int enc); +/* NB: the IV is _four_ blocks long */ +OPENSSL_EXPORT void AES_bi_ige_encrypt(const unsigned char *in, unsigned char *out, + size_t length, const AES_KEY *key, + const AES_KEY *key2, const unsigned char *ivec, + const int enc); + +/* Android compatibility section. + * + * These functions are declared, temporarily, for Android because + * wpa_supplicant will take a little time to sync with upstream. Outside of + * Android they'll have no definition. */ + +OPENSSL_EXPORT int AES_wrap_key(AES_KEY *key, const uint8_t *iv, uint8_t *out, + const uint8_t *in, unsigned in_len); +OPENSSL_EXPORT int AES_unwrap_key(AES_KEY *key, const uint8_t *iv, uint8_t *out, + const uint8_t *in, unsigned in_len); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_AES_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/asn1.h b/TMessagesProj/jni/boringssl/include/openssl/asn1.h new file mode 100644 index 00000000..401532ab --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/asn1.h @@ -0,0 +1,1169 @@ +/* crypto/asn1/asn1.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_ASN1_H +#define HEADER_ASN1_H + +#include + +#include + +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define V_ASN1_UNIVERSAL 0x00 +#define V_ASN1_APPLICATION 0x40 +#define V_ASN1_CONTEXT_SPECIFIC 0x80 +#define V_ASN1_PRIVATE 0xc0 + +#define V_ASN1_CONSTRUCTED 0x20 +#define V_ASN1_PRIMITIVE_TAG 0x1f +#define V_ASN1_PRIMATIVE_TAG 0x1f + +#define V_ASN1_APP_CHOOSE -2 /* let the recipient choose */ +#define V_ASN1_OTHER -3 /* used in ASN1_TYPE */ +#define V_ASN1_ANY -4 /* used in ASN1 template code */ + +#define V_ASN1_NEG 0x100 /* negative flag */ + +#define V_ASN1_UNDEF -1 +#define V_ASN1_EOC 0 +#define V_ASN1_BOOLEAN 1 /**/ +#define V_ASN1_INTEGER 2 +#define V_ASN1_NEG_INTEGER (2 | V_ASN1_NEG) +#define V_ASN1_BIT_STRING 3 +#define V_ASN1_OCTET_STRING 4 +#define V_ASN1_NULL 5 +#define V_ASN1_OBJECT 6 +#define V_ASN1_OBJECT_DESCRIPTOR 7 +#define V_ASN1_EXTERNAL 8 +#define V_ASN1_REAL 9 +#define V_ASN1_ENUMERATED 10 +#define V_ASN1_NEG_ENUMERATED (10 | V_ASN1_NEG) +#define V_ASN1_UTF8STRING 12 +#define V_ASN1_SEQUENCE 16 +#define V_ASN1_SET 17 +#define V_ASN1_NUMERICSTRING 18 /**/ +#define V_ASN1_PRINTABLESTRING 19 +#define V_ASN1_T61STRING 20 +#define V_ASN1_TELETEXSTRING 20 /* alias */ +#define V_ASN1_VIDEOTEXSTRING 21 /**/ +#define V_ASN1_IA5STRING 22 +#define V_ASN1_UTCTIME 23 +#define V_ASN1_GENERALIZEDTIME 24 /**/ +#define V_ASN1_GRAPHICSTRING 25 /**/ +#define V_ASN1_ISO64STRING 26 /**/ +#define V_ASN1_VISIBLESTRING 26 /* alias */ +#define V_ASN1_GENERALSTRING 27 /**/ +#define V_ASN1_UNIVERSALSTRING 28 /**/ +#define V_ASN1_BMPSTRING 30 + +/* For use with d2i_ASN1_type_bytes() */ +#define B_ASN1_NUMERICSTRING 0x0001 +#define B_ASN1_PRINTABLESTRING 0x0002 +#define B_ASN1_T61STRING 0x0004 +#define B_ASN1_TELETEXSTRING 0x0004 +#define B_ASN1_VIDEOTEXSTRING 0x0008 +#define B_ASN1_IA5STRING 0x0010 +#define B_ASN1_GRAPHICSTRING 0x0020 +#define B_ASN1_ISO64STRING 0x0040 +#define B_ASN1_VISIBLESTRING 0x0040 +#define B_ASN1_GENERALSTRING 0x0080 +#define B_ASN1_UNIVERSALSTRING 0x0100 +#define B_ASN1_OCTET_STRING 0x0200 +#define B_ASN1_BIT_STRING 0x0400 +#define B_ASN1_BMPSTRING 0x0800 +#define B_ASN1_UNKNOWN 0x1000 +#define B_ASN1_UTF8STRING 0x2000 +#define B_ASN1_UTCTIME 0x4000 +#define B_ASN1_GENERALIZEDTIME 0x8000 +#define B_ASN1_SEQUENCE 0x10000 + +/* For use with ASN1_mbstring_copy() */ +#define MBSTRING_FLAG 0x1000 +#define MBSTRING_UTF8 (MBSTRING_FLAG) +#define MBSTRING_ASC (MBSTRING_FLAG|1) +#define MBSTRING_BMP (MBSTRING_FLAG|2) +#define MBSTRING_UNIV (MBSTRING_FLAG|4) + +#define SMIME_OLDMIME 0x400 +#define SMIME_CRLFEOL 0x800 +#define SMIME_STREAM 0x1000 + +#define DECLARE_ASN1_SET_OF(type) /* filled in by mkstack.pl */ +#define IMPLEMENT_ASN1_SET_OF(type) /* nothing, no longer needed */ + +/* We MUST make sure that, except for constness, asn1_ctx_st and + asn1_const_ctx are exactly the same. Fortunately, as soon as + the old ASN1 parsing macros are gone, we can throw this away + as well... */ +typedef struct asn1_ctx_st + { + unsigned char *p;/* work char pointer */ + int eos; /* end of sequence read for indefinite encoding */ + int error; /* error code to use when returning an error */ + int inf; /* constructed if 0x20, indefinite is 0x21 */ + int tag; /* tag from last 'get object' */ + int xclass; /* class from last 'get object' */ + long slen; /* length of last 'get object' */ + unsigned char *max; /* largest value of p allowed */ + unsigned char *q;/* temporary variable */ + unsigned char **pp;/* variable */ + int line; /* used in error processing */ + } ASN1_CTX; + +typedef struct asn1_const_ctx_st + { + const unsigned char *p;/* work char pointer */ + int eos; /* end of sequence read for indefinite encoding */ + int error; /* error code to use when returning an error */ + int inf; /* constructed if 0x20, indefinite is 0x21 */ + int tag; /* tag from last 'get object' */ + int xclass; /* class from last 'get object' */ + long slen; /* length of last 'get object' */ + const unsigned char *max; /* largest value of p allowed */ + const unsigned char *q;/* temporary variable */ + const unsigned char **pp;/* variable */ + int line; /* used in error processing */ + } ASN1_const_CTX; + +/* These are used internally in the ASN1_OBJECT to keep track of + * whether the names and data need to be free()ed */ +#define ASN1_OBJECT_FLAG_DYNAMIC 0x01 /* internal use */ +#define ASN1_OBJECT_FLAG_CRITICAL 0x02 /* critical x509v3 object id */ +#define ASN1_OBJECT_FLAG_DYNAMIC_STRINGS 0x04 /* internal use */ +#define ASN1_OBJECT_FLAG_DYNAMIC_DATA 0x08 /* internal use */ +struct asn1_object_st + { + const char *sn,*ln; + int nid; + int length; + const unsigned char *data; /* data remains const after init */ + int flags; /* Should we free this one */ + }; + +#define ASN1_STRING_FLAG_BITS_LEFT 0x08 /* Set if 0x07 has bits left value */ +/* This indicates that the ASN1_STRING is not a real value but just a place + * holder for the location where indefinite length constructed data should + * be inserted in the memory buffer + */ +#define ASN1_STRING_FLAG_NDEF 0x010 + +/* This flag is used by the CMS code to indicate that a string is not + * complete and is a place holder for content when it had all been + * accessed. The flag will be reset when content has been written to it. + */ + +#define ASN1_STRING_FLAG_CONT 0x020 +/* This flag is used by ASN1 code to indicate an ASN1_STRING is an MSTRING + * type. + */ +#define ASN1_STRING_FLAG_MSTRING 0x040 +/* This is the base type that holds just about everything :-) */ +struct asn1_string_st + { + int length; + int type; + unsigned char *data; + /* The value of the following field depends on the type being + * held. It is mostly being used for BIT_STRING so if the + * input data has a non-zero 'unused bits' value, it will be + * handled correctly */ + long flags; + }; + +/* ASN1_ENCODING structure: this is used to save the received + * encoding of an ASN1 type. This is useful to get round + * problems with invalid encodings which can break signatures. + */ + +typedef struct ASN1_ENCODING_st + { + unsigned char *enc; /* DER encoding */ + long len; /* Length of encoding */ + int modified; /* set to 1 if 'enc' is invalid */ + } ASN1_ENCODING; + +/* Used with ASN1 LONG type: if a long is set to this it is omitted */ +#define ASN1_LONG_UNDEF 0x7fffffffL + +#define STABLE_FLAGS_MALLOC 0x01 +#define STABLE_NO_MASK 0x02 +#define DIRSTRING_TYPE \ + (B_ASN1_PRINTABLESTRING|B_ASN1_T61STRING|B_ASN1_BMPSTRING|B_ASN1_UTF8STRING) +#define PKCS9STRING_TYPE (DIRSTRING_TYPE|B_ASN1_IA5STRING) + +typedef struct asn1_string_table_st { + int nid; + long minsize; + long maxsize; + unsigned long mask; + unsigned long flags; +} ASN1_STRING_TABLE; + +/* size limits: this stuff is taken straight from RFC2459 */ + +#define ub_name 32768 +#define ub_common_name 64 +#define ub_locality_name 128 +#define ub_state_name 128 +#define ub_organization_name 64 +#define ub_organization_unit_name 64 +#define ub_title 64 +#define ub_email_address 128 + +/* Declarations for template structures: for full definitions + * see asn1t.h + */ +typedef struct ASN1_TEMPLATE_st ASN1_TEMPLATE; +typedef struct ASN1_TLC_st ASN1_TLC; +/* This is just an opaque pointer */ +typedef struct ASN1_VALUE_st ASN1_VALUE; + +/* Declare ASN1 functions: the implement macro in in asn1t.h */ + +#define DECLARE_ASN1_FUNCTIONS(type) DECLARE_ASN1_FUNCTIONS_name(type, type) + +#define DECLARE_ASN1_ALLOC_FUNCTIONS(type) \ + DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, type) + +#define DECLARE_ASN1_FUNCTIONS_name(type, name) \ + DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, name) \ + DECLARE_ASN1_ENCODE_FUNCTIONS(type, name, name) + +#define DECLARE_ASN1_FUNCTIONS_fname(type, itname, name) \ + DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, name) \ + DECLARE_ASN1_ENCODE_FUNCTIONS(type, itname, name) + +#define DECLARE_ASN1_ENCODE_FUNCTIONS(type, itname, name) \ + OPENSSL_EXPORT type *d2i_##name(type **a, const unsigned char **in, long len); \ + OPENSSL_EXPORT int i2d_##name(type *a, unsigned char **out); \ + DECLARE_ASN1_ITEM(itname) + +#define DECLARE_ASN1_ENCODE_FUNCTIONS_const(type, name) \ + OPENSSL_EXPORT type *d2i_##name(type **a, const unsigned char **in, long len); \ + OPENSSL_EXPORT int i2d_##name(const type *a, unsigned char **out); \ + DECLARE_ASN1_ITEM(name) + +#define DECLARE_ASN1_NDEF_FUNCTION(name) \ + OPENSSL_EXPORT int i2d_##name##_NDEF(name *a, unsigned char **out); + +#define DECLARE_ASN1_FUNCTIONS_const(name) \ + DECLARE_ASN1_ALLOC_FUNCTIONS(name) \ + DECLARE_ASN1_ENCODE_FUNCTIONS_const(name, name) + +#define DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, name) \ + OPENSSL_EXPORT type *name##_new(void); \ + OPENSSL_EXPORT void name##_free(type *a); + +#define DECLARE_ASN1_PRINT_FUNCTION(stname) \ + DECLARE_ASN1_PRINT_FUNCTION_fname(stname, stname) + +#define DECLARE_ASN1_PRINT_FUNCTION_fname(stname, fname) \ + OPENSSL_EXPORT int fname##_print_ctx(BIO *out, stname *x, int indent, \ + const ASN1_PCTX *pctx); + +#define D2I_OF(type) type *(*)(type **,const unsigned char **,long) +#define I2D_OF(type) int (*)(type *,unsigned char **) +#define I2D_OF_const(type) int (*)(const type *,unsigned char **) + +#define CHECKED_D2I_OF(type, d2i) \ + ((d2i_of_void*) (1 ? d2i : ((D2I_OF(type))0))) +#define CHECKED_I2D_OF(type, i2d) \ + ((i2d_of_void*) (1 ? i2d : ((I2D_OF(type))0))) +#define CHECKED_NEW_OF(type, xnew) \ + ((void *(*)(void)) (1 ? xnew : ((type *(*)(void))0))) +#define CHECKED_PPTR_OF(type, p) \ + ((void**) (1 ? p : (type**)0)) + +#define TYPEDEF_D2I_OF(type) typedef type *d2i_of_##type(type **,const unsigned char **,long) +#define TYPEDEF_I2D_OF(type) typedef int i2d_of_##type(const type *,unsigned char **) +#define TYPEDEF_D2I2D_OF(type) TYPEDEF_D2I_OF(type); TYPEDEF_I2D_OF(type) + +TYPEDEF_D2I2D_OF(void); + +/* The following macros and typedefs allow an ASN1_ITEM + * to be embedded in a structure and referenced. Since + * the ASN1_ITEM pointers need to be globally accessible + * (possibly from shared libraries) they may exist in + * different forms. On platforms that support it the + * ASN1_ITEM structure itself will be globally exported. + * Other platforms will export a function that returns + * an ASN1_ITEM pointer. + * + * To handle both cases transparently the macros below + * should be used instead of hard coding an ASN1_ITEM + * pointer in a structure. + * + * The structure will look like this: + * + * typedef struct SOMETHING_st { + * ... + * ASN1_ITEM_EXP *iptr; + * ... + * } SOMETHING; + * + * It would be initialised as e.g.: + * + * SOMETHING somevar = {...,ASN1_ITEM_ref(X509),...}; + * + * and the actual pointer extracted with: + * + * const ASN1_ITEM *it = ASN1_ITEM_ptr(somevar.iptr); + * + * Finally an ASN1_ITEM pointer can be extracted from an + * appropriate reference with: ASN1_ITEM_rptr(X509). This + * would be used when a function takes an ASN1_ITEM * argument. + * + */ + +/* ASN1_ITEM pointer exported type */ +typedef const ASN1_ITEM ASN1_ITEM_EXP; + +/* Macro to obtain ASN1_ITEM pointer from exported type */ +#define ASN1_ITEM_ptr(iptr) (iptr) + +/* Macro to include ASN1_ITEM pointer from base type */ +#define ASN1_ITEM_ref(iptr) (&(iptr##_it)) + +#define ASN1_ITEM_rptr(ref) (&(ref##_it)) + +#define DECLARE_ASN1_ITEM(name) \ + extern OPENSSL_EXPORT const ASN1_ITEM name##_it; + +/* Parameters used by ASN1_STRING_print_ex() */ + +/* These determine which characters to escape: + * RFC2253 special characters, control characters and + * MSB set characters + */ + +#define ASN1_STRFLGS_ESC_2253 1 +#define ASN1_STRFLGS_ESC_CTRL 2 +#define ASN1_STRFLGS_ESC_MSB 4 + + +/* This flag determines how we do escaping: normally + * RC2253 backslash only, set this to use backslash and + * quote. + */ + +#define ASN1_STRFLGS_ESC_QUOTE 8 + + +/* These three flags are internal use only. */ + +/* Character is a valid PrintableString character */ +#define CHARTYPE_PRINTABLESTRING 0x10 +/* Character needs escaping if it is the first character */ +#define CHARTYPE_FIRST_ESC_2253 0x20 +/* Character needs escaping if it is the last character */ +#define CHARTYPE_LAST_ESC_2253 0x40 + +/* NB the internal flags are safely reused below by flags + * handled at the top level. + */ + +/* If this is set we convert all character strings + * to UTF8 first + */ + +#define ASN1_STRFLGS_UTF8_CONVERT 0x10 + +/* If this is set we don't attempt to interpret content: + * just assume all strings are 1 byte per character. This + * will produce some pretty odd looking output! + */ + +#define ASN1_STRFLGS_IGNORE_TYPE 0x20 + +/* If this is set we include the string type in the output */ +#define ASN1_STRFLGS_SHOW_TYPE 0x40 + +/* This determines which strings to display and which to + * 'dump' (hex dump of content octets or DER encoding). We can + * only dump non character strings or everything. If we + * don't dump 'unknown' they are interpreted as character + * strings with 1 octet per character and are subject to + * the usual escaping options. + */ + +#define ASN1_STRFLGS_DUMP_ALL 0x80 +#define ASN1_STRFLGS_DUMP_UNKNOWN 0x100 + +/* These determine what 'dumping' does, we can dump the + * content octets or the DER encoding: both use the + * RFC2253 #XXXXX notation. + */ + +#define ASN1_STRFLGS_DUMP_DER 0x200 + +/* All the string flags consistent with RFC2253, + * escaping control characters isn't essential in + * RFC2253 but it is advisable anyway. + */ + +#define ASN1_STRFLGS_RFC2253 (ASN1_STRFLGS_ESC_2253 | \ + ASN1_STRFLGS_ESC_CTRL | \ + ASN1_STRFLGS_ESC_MSB | \ + ASN1_STRFLGS_UTF8_CONVERT | \ + ASN1_STRFLGS_DUMP_UNKNOWN | \ + ASN1_STRFLGS_DUMP_DER) + +DECLARE_ASN1_SET_OF(ASN1_INTEGER) + +typedef struct asn1_type_st + { + int type; + union { + char *ptr; + ASN1_BOOLEAN boolean; + ASN1_STRING * asn1_string; + ASN1_OBJECT * object; + ASN1_INTEGER * integer; + ASN1_ENUMERATED * enumerated; + ASN1_BIT_STRING * bit_string; + ASN1_OCTET_STRING * octet_string; + ASN1_PRINTABLESTRING * printablestring; + ASN1_T61STRING * t61string; + ASN1_IA5STRING * ia5string; + ASN1_GENERALSTRING * generalstring; + ASN1_BMPSTRING * bmpstring; + ASN1_UNIVERSALSTRING * universalstring; + ASN1_UTCTIME * utctime; + ASN1_GENERALIZEDTIME * generalizedtime; + ASN1_VISIBLESTRING * visiblestring; + ASN1_UTF8STRING * utf8string; + /* set and sequence are left complete and still + * contain the set or sequence bytes */ + ASN1_STRING * set; + ASN1_STRING * sequence; + ASN1_VALUE * asn1_value; + } value; + } ASN1_TYPE; + +DECLARE_ASN1_SET_OF(ASN1_TYPE) + +typedef STACK_OF(ASN1_TYPE) ASN1_SEQUENCE_ANY; + +DECLARE_ASN1_ENCODE_FUNCTIONS_const(ASN1_SEQUENCE_ANY, ASN1_SEQUENCE_ANY) +DECLARE_ASN1_ENCODE_FUNCTIONS_const(ASN1_SEQUENCE_ANY, ASN1_SET_ANY) + +struct X509_algor_st + { + ASN1_OBJECT *algorithm; + ASN1_TYPE *parameter; + } /* X509_ALGOR */; + +DECLARE_ASN1_FUNCTIONS(X509_ALGOR) + +typedef struct NETSCAPE_X509_st + { + ASN1_OCTET_STRING *header; + X509 *cert; + } NETSCAPE_X509; + +/* This is used to contain a list of bit names */ +typedef struct BIT_STRING_BITNAME_st { + int bitnum; + const char *lname; + const char *sname; +} BIT_STRING_BITNAME; + + +#define M_ASN1_STRING_length(x) ((x)->length) +#define M_ASN1_STRING_length_set(x, n) ((x)->length = (n)) +#define M_ASN1_STRING_type(x) ((x)->type) +#define M_ASN1_STRING_data(x) ((x)->data) + +/* Macros for string operations */ +#define M_ASN1_BIT_STRING_new() (ASN1_BIT_STRING *)\ + ASN1_STRING_type_new(V_ASN1_BIT_STRING) +#define M_ASN1_BIT_STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_BIT_STRING_dup(a) (ASN1_BIT_STRING *)\ + ASN1_STRING_dup((const ASN1_STRING *)a) +#define M_ASN1_BIT_STRING_cmp(a,b) ASN1_STRING_cmp(\ + (const ASN1_STRING *)a,(const ASN1_STRING *)b) +#define M_ASN1_BIT_STRING_set(a,b,c) ASN1_STRING_set((ASN1_STRING *)a,b,c) + +#define M_ASN1_INTEGER_new() (ASN1_INTEGER *)\ + ASN1_STRING_type_new(V_ASN1_INTEGER) +#define M_ASN1_INTEGER_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_INTEGER_dup(a) (ASN1_INTEGER *)\ + ASN1_STRING_dup((const ASN1_STRING *)a) +#define M_ASN1_INTEGER_cmp(a,b) ASN1_STRING_cmp(\ + (const ASN1_STRING *)a,(const ASN1_STRING *)b) + +#define M_ASN1_ENUMERATED_new() (ASN1_ENUMERATED *)\ + ASN1_STRING_type_new(V_ASN1_ENUMERATED) +#define M_ASN1_ENUMERATED_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_ENUMERATED_dup(a) (ASN1_ENUMERATED *)\ + ASN1_STRING_dup((const ASN1_STRING *)a) +#define M_ASN1_ENUMERATED_cmp(a,b) ASN1_STRING_cmp(\ + (const ASN1_STRING *)a,(const ASN1_STRING *)b) + +#define M_ASN1_OCTET_STRING_new() (ASN1_OCTET_STRING *)\ + ASN1_STRING_type_new(V_ASN1_OCTET_STRING) +#define M_ASN1_OCTET_STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_OCTET_STRING_dup(a) (ASN1_OCTET_STRING *)\ + ASN1_STRING_dup((const ASN1_STRING *)a) +#define M_ASN1_OCTET_STRING_cmp(a,b) ASN1_STRING_cmp(\ + (const ASN1_STRING *)a,(const ASN1_STRING *)b) +#define M_ASN1_OCTET_STRING_set(a,b,c) ASN1_STRING_set((ASN1_STRING *)a,b,c) +#define M_ASN1_OCTET_STRING_print(a,b) ASN1_STRING_print(a,(ASN1_STRING *)b) +#define M_i2d_ASN1_OCTET_STRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_OCTET_STRING,\ + V_ASN1_UNIVERSAL) + +#define B_ASN1_TIME \ + B_ASN1_UTCTIME | \ + B_ASN1_GENERALIZEDTIME + +#define B_ASN1_PRINTABLE \ + B_ASN1_NUMERICSTRING| \ + B_ASN1_PRINTABLESTRING| \ + B_ASN1_T61STRING| \ + B_ASN1_IA5STRING| \ + B_ASN1_BIT_STRING| \ + B_ASN1_UNIVERSALSTRING|\ + B_ASN1_BMPSTRING|\ + B_ASN1_UTF8STRING|\ + B_ASN1_SEQUENCE|\ + B_ASN1_UNKNOWN + +#define B_ASN1_DIRECTORYSTRING \ + B_ASN1_PRINTABLESTRING| \ + B_ASN1_TELETEXSTRING|\ + B_ASN1_BMPSTRING|\ + B_ASN1_UNIVERSALSTRING|\ + B_ASN1_UTF8STRING + +#define B_ASN1_DISPLAYTEXT \ + B_ASN1_IA5STRING| \ + B_ASN1_VISIBLESTRING| \ + B_ASN1_BMPSTRING|\ + B_ASN1_UTF8STRING + +#define M_ASN1_PRINTABLE_new() ASN1_STRING_type_new(V_ASN1_T61STRING) +#define M_ASN1_PRINTABLE_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_PRINTABLE(a,pp) i2d_ASN1_bytes((ASN1_STRING *)a,\ + pp,a->type,V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_PRINTABLE(a,pp,l) \ + d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l, \ + B_ASN1_PRINTABLE) + +#define M_DIRECTORYSTRING_new() ASN1_STRING_type_new(V_ASN1_PRINTABLESTRING) +#define M_DIRECTORYSTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_DIRECTORYSTRING(a,pp) i2d_ASN1_bytes((ASN1_STRING *)a,\ + pp,a->type,V_ASN1_UNIVERSAL) +#define M_d2i_DIRECTORYSTRING(a,pp,l) \ + d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l, \ + B_ASN1_DIRECTORYSTRING) + +#define M_DISPLAYTEXT_new() ASN1_STRING_type_new(V_ASN1_VISIBLESTRING) +#define M_DISPLAYTEXT_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_DISPLAYTEXT(a,pp) i2d_ASN1_bytes((ASN1_STRING *)a,\ + pp,a->type,V_ASN1_UNIVERSAL) +#define M_d2i_DISPLAYTEXT(a,pp,l) \ + d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l, \ + B_ASN1_DISPLAYTEXT) + +#define M_ASN1_PRINTABLESTRING_new() (ASN1_PRINTABLESTRING *)\ + ASN1_STRING_type_new(V_ASN1_PRINTABLESTRING) +#define M_ASN1_PRINTABLESTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_PRINTABLESTRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_PRINTABLESTRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_PRINTABLESTRING(a,pp,l) \ + (ASN1_PRINTABLESTRING *)d2i_ASN1_type_bytes\ + ((ASN1_STRING **)a,pp,l,B_ASN1_PRINTABLESTRING) + +#define M_ASN1_T61STRING_new() (ASN1_T61STRING *)\ + ASN1_STRING_type_new(V_ASN1_T61STRING) +#define M_ASN1_T61STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_T61STRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_T61STRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_T61STRING(a,pp,l) \ + (ASN1_T61STRING *)d2i_ASN1_type_bytes\ + ((ASN1_STRING **)a,pp,l,B_ASN1_T61STRING) + +#define M_ASN1_IA5STRING_new() (ASN1_IA5STRING *)\ + ASN1_STRING_type_new(V_ASN1_IA5STRING) +#define M_ASN1_IA5STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_IA5STRING_dup(a) \ + (ASN1_IA5STRING *)ASN1_STRING_dup((const ASN1_STRING *)a) +#define M_i2d_ASN1_IA5STRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_IA5STRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_IA5STRING(a,pp,l) \ + (ASN1_IA5STRING *)d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l,\ + B_ASN1_IA5STRING) + +#define M_ASN1_UTCTIME_new() (ASN1_UTCTIME *)\ + ASN1_STRING_type_new(V_ASN1_UTCTIME) +#define M_ASN1_UTCTIME_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_UTCTIME_dup(a) (ASN1_UTCTIME *)\ + ASN1_STRING_dup((const ASN1_STRING *)a) + +#define M_ASN1_GENERALIZEDTIME_new() (ASN1_GENERALIZEDTIME *)\ + ASN1_STRING_type_new(V_ASN1_GENERALIZEDTIME) +#define M_ASN1_GENERALIZEDTIME_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_GENERALIZEDTIME_dup(a) (ASN1_GENERALIZEDTIME *)ASN1_STRING_dup(\ + (const ASN1_STRING *)a) + +#define M_ASN1_TIME_new() (ASN1_TIME *)\ + ASN1_STRING_type_new(V_ASN1_UTCTIME) +#define M_ASN1_TIME_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_TIME_dup(a) (ASN1_TIME *)\ + ASN1_STRING_dup((const ASN1_STRING *)a) + +#define M_ASN1_GENERALSTRING_new() (ASN1_GENERALSTRING *)\ + ASN1_STRING_type_new(V_ASN1_GENERALSTRING) +#define M_ASN1_GENERALSTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_GENERALSTRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_GENERALSTRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_GENERALSTRING(a,pp,l) \ + (ASN1_GENERALSTRING *)d2i_ASN1_type_bytes\ + ((ASN1_STRING **)a,pp,l,B_ASN1_GENERALSTRING) + +#define M_ASN1_UNIVERSALSTRING_new() (ASN1_UNIVERSALSTRING *)\ + ASN1_STRING_type_new(V_ASN1_UNIVERSALSTRING) +#define M_ASN1_UNIVERSALSTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_UNIVERSALSTRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_UNIVERSALSTRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_UNIVERSALSTRING(a,pp,l) \ + (ASN1_UNIVERSALSTRING *)d2i_ASN1_type_bytes\ + ((ASN1_STRING **)a,pp,l,B_ASN1_UNIVERSALSTRING) + +#define M_ASN1_BMPSTRING_new() (ASN1_BMPSTRING *)\ + ASN1_STRING_type_new(V_ASN1_BMPSTRING) +#define M_ASN1_BMPSTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_BMPSTRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_BMPSTRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_BMPSTRING(a,pp,l) \ + (ASN1_BMPSTRING *)d2i_ASN1_type_bytes\ + ((ASN1_STRING **)a,pp,l,B_ASN1_BMPSTRING) + +#define M_ASN1_VISIBLESTRING_new() (ASN1_VISIBLESTRING *)\ + ASN1_STRING_type_new(V_ASN1_VISIBLESTRING) +#define M_ASN1_VISIBLESTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_VISIBLESTRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_VISIBLESTRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_VISIBLESTRING(a,pp,l) \ + (ASN1_VISIBLESTRING *)d2i_ASN1_type_bytes\ + ((ASN1_STRING **)a,pp,l,B_ASN1_VISIBLESTRING) + +#define M_ASN1_UTF8STRING_new() (ASN1_UTF8STRING *)\ + ASN1_STRING_type_new(V_ASN1_UTF8STRING) +#define M_ASN1_UTF8STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_UTF8STRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_UTF8STRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_UTF8STRING(a,pp,l) \ + (ASN1_UTF8STRING *)d2i_ASN1_type_bytes\ + ((ASN1_STRING **)a,pp,l,B_ASN1_UTF8STRING) + + /* for the is_set parameter to i2d_ASN1_SET */ +#define IS_SEQUENCE 0 +#define IS_SET 1 + +DECLARE_ASN1_FUNCTIONS_fname(ASN1_TYPE, ASN1_ANY, ASN1_TYPE) + +OPENSSL_EXPORT int ASN1_TYPE_get(ASN1_TYPE *a); +OPENSSL_EXPORT void ASN1_TYPE_set(ASN1_TYPE *a, int type, void *value); +OPENSSL_EXPORT int ASN1_TYPE_set1(ASN1_TYPE *a, int type, const void *value); +OPENSSL_EXPORT int ASN1_TYPE_cmp(const ASN1_TYPE *a, const ASN1_TYPE *b); + +OPENSSL_EXPORT ASN1_OBJECT * ASN1_OBJECT_new(void ); +OPENSSL_EXPORT void ASN1_OBJECT_free(ASN1_OBJECT *a); +OPENSSL_EXPORT int i2d_ASN1_OBJECT(ASN1_OBJECT *a,unsigned char **pp); +OPENSSL_EXPORT ASN1_OBJECT * c2i_ASN1_OBJECT(ASN1_OBJECT **a,const unsigned char **pp, + long length); +OPENSSL_EXPORT ASN1_OBJECT * d2i_ASN1_OBJECT(ASN1_OBJECT **a,const unsigned char **pp, + long length); + +DECLARE_ASN1_ITEM(ASN1_OBJECT) + +DECLARE_ASN1_SET_OF(ASN1_OBJECT) + +OPENSSL_EXPORT ASN1_STRING * ASN1_STRING_new(void); +OPENSSL_EXPORT void ASN1_STRING_free(ASN1_STRING *a); +OPENSSL_EXPORT int ASN1_STRING_copy(ASN1_STRING *dst, const ASN1_STRING *str); +OPENSSL_EXPORT ASN1_STRING * ASN1_STRING_dup(const ASN1_STRING *a); +OPENSSL_EXPORT ASN1_STRING * ASN1_STRING_type_new(int type ); +OPENSSL_EXPORT int ASN1_STRING_cmp(const ASN1_STRING *a, const ASN1_STRING *b); + /* Since this is used to store all sorts of things, via macros, for now, make + its data void * */ +OPENSSL_EXPORT int ASN1_STRING_set(ASN1_STRING *str, const void *data, int len); +OPENSSL_EXPORT void ASN1_STRING_set0(ASN1_STRING *str, void *data, int len); +OPENSSL_EXPORT int ASN1_STRING_length(const ASN1_STRING *x); +OPENSSL_EXPORT void ASN1_STRING_length_set(ASN1_STRING *x, int n); +OPENSSL_EXPORT int ASN1_STRING_type(ASN1_STRING *x); +OPENSSL_EXPORT unsigned char * ASN1_STRING_data(ASN1_STRING *x); + +DECLARE_ASN1_FUNCTIONS(ASN1_BIT_STRING) +OPENSSL_EXPORT int i2c_ASN1_BIT_STRING(ASN1_BIT_STRING *a,unsigned char **pp); +OPENSSL_EXPORT ASN1_BIT_STRING *c2i_ASN1_BIT_STRING(ASN1_BIT_STRING **a,const unsigned char **pp, long length); +OPENSSL_EXPORT int ASN1_BIT_STRING_set(ASN1_BIT_STRING *a, unsigned char *d, int length ); +OPENSSL_EXPORT int ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *a, int n, int value); +OPENSSL_EXPORT int ASN1_BIT_STRING_get_bit(ASN1_BIT_STRING *a, int n); +OPENSSL_EXPORT int ASN1_BIT_STRING_check(ASN1_BIT_STRING *a, unsigned char *flags, int flags_len); + +OPENSSL_EXPORT int ASN1_BIT_STRING_name_print(BIO *out, ASN1_BIT_STRING *bs, BIT_STRING_BITNAME *tbl, int indent); +OPENSSL_EXPORT int ASN1_BIT_STRING_num_asc(char *name, BIT_STRING_BITNAME *tbl); +OPENSSL_EXPORT int ASN1_BIT_STRING_set_asc(ASN1_BIT_STRING *bs, char *name, int value, BIT_STRING_BITNAME *tbl); + +OPENSSL_EXPORT int i2d_ASN1_BOOLEAN(int a,unsigned char **pp); +OPENSSL_EXPORT int d2i_ASN1_BOOLEAN(int *a,const unsigned char **pp,long length); + +DECLARE_ASN1_FUNCTIONS(ASN1_INTEGER) +OPENSSL_EXPORT int i2c_ASN1_INTEGER(ASN1_INTEGER *a,unsigned char **pp); +OPENSSL_EXPORT ASN1_INTEGER *c2i_ASN1_INTEGER(ASN1_INTEGER **a,const unsigned char **pp, long length); +OPENSSL_EXPORT ASN1_INTEGER *d2i_ASN1_UINTEGER(ASN1_INTEGER **a,const unsigned char **pp, long length); +OPENSSL_EXPORT ASN1_INTEGER * ASN1_INTEGER_dup(const ASN1_INTEGER *x); +OPENSSL_EXPORT int ASN1_INTEGER_cmp(const ASN1_INTEGER *x, const ASN1_INTEGER *y); + +DECLARE_ASN1_FUNCTIONS(ASN1_ENUMERATED) + +OPENSSL_EXPORT int ASN1_UTCTIME_check(const ASN1_UTCTIME *a); +OPENSSL_EXPORT ASN1_UTCTIME *ASN1_UTCTIME_set(ASN1_UTCTIME *s,time_t t); +OPENSSL_EXPORT ASN1_UTCTIME *ASN1_UTCTIME_adj(ASN1_UTCTIME *s, time_t t, int offset_day, long offset_sec); +OPENSSL_EXPORT int ASN1_UTCTIME_set_string(ASN1_UTCTIME *s, const char *str); +OPENSSL_EXPORT int ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *s, time_t t); +#if 0 +time_t ASN1_UTCTIME_get(const ASN1_UTCTIME *s); +#endif + +OPENSSL_EXPORT int ASN1_GENERALIZEDTIME_check(const ASN1_GENERALIZEDTIME *a); +OPENSSL_EXPORT ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_set(ASN1_GENERALIZEDTIME *s,time_t t); +OPENSSL_EXPORT ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_adj(ASN1_GENERALIZEDTIME *s, time_t t, int offset_day, long offset_sec); +OPENSSL_EXPORT int ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *s, const char *str); +OPENSSL_EXPORT int ASN1_TIME_diff(int *pday, int *psec, const ASN1_TIME *from, const ASN1_TIME *to); + +DECLARE_ASN1_FUNCTIONS(ASN1_OCTET_STRING) +OPENSSL_EXPORT ASN1_OCTET_STRING * ASN1_OCTET_STRING_dup(const ASN1_OCTET_STRING *a); +OPENSSL_EXPORT int ASN1_OCTET_STRING_cmp(const ASN1_OCTET_STRING *a, const ASN1_OCTET_STRING *b); +OPENSSL_EXPORT int ASN1_OCTET_STRING_set(ASN1_OCTET_STRING *str, const unsigned char *data, int len); + +DECLARE_ASN1_FUNCTIONS(ASN1_VISIBLESTRING) +DECLARE_ASN1_FUNCTIONS(ASN1_UNIVERSALSTRING) +DECLARE_ASN1_FUNCTIONS(ASN1_UTF8STRING) +DECLARE_ASN1_FUNCTIONS(ASN1_NULL) +DECLARE_ASN1_FUNCTIONS(ASN1_BMPSTRING) + +OPENSSL_EXPORT int UTF8_getc(const unsigned char *str, int len, unsigned long *val); +OPENSSL_EXPORT int UTF8_putc(unsigned char *str, int len, unsigned long value); + +DECLARE_ASN1_FUNCTIONS_name(ASN1_STRING, ASN1_PRINTABLE) + +DECLARE_ASN1_FUNCTIONS_name(ASN1_STRING, DIRECTORYSTRING) +DECLARE_ASN1_FUNCTIONS_name(ASN1_STRING, DISPLAYTEXT) +DECLARE_ASN1_FUNCTIONS(ASN1_PRINTABLESTRING) +DECLARE_ASN1_FUNCTIONS(ASN1_T61STRING) +DECLARE_ASN1_FUNCTIONS(ASN1_IA5STRING) +DECLARE_ASN1_FUNCTIONS(ASN1_GENERALSTRING) +DECLARE_ASN1_FUNCTIONS(ASN1_UTCTIME) +DECLARE_ASN1_FUNCTIONS(ASN1_GENERALIZEDTIME) +DECLARE_ASN1_FUNCTIONS(ASN1_TIME) + +DECLARE_ASN1_ITEM(ASN1_OCTET_STRING_NDEF) + +OPENSSL_EXPORT ASN1_TIME *ASN1_TIME_set(ASN1_TIME *s,time_t t); +OPENSSL_EXPORT ASN1_TIME *ASN1_TIME_adj(ASN1_TIME *s,time_t t, int offset_day, long offset_sec); +OPENSSL_EXPORT int ASN1_TIME_check(ASN1_TIME *t); +OPENSSL_EXPORT ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(ASN1_TIME *t, ASN1_GENERALIZEDTIME **out); +OPENSSL_EXPORT int ASN1_TIME_set_string(ASN1_TIME *s, const char *str); + +OPENSSL_EXPORT int i2d_ASN1_SET(STACK_OF(OPENSSL_BLOCK) *a, unsigned char **pp, i2d_of_void *i2d, int ex_tag, int ex_class, int is_set); +OPENSSL_EXPORT STACK_OF(OPENSSL_BLOCK) *d2i_ASN1_SET(STACK_OF(OPENSSL_BLOCK) **a, + const unsigned char **pp, + long length, d2i_of_void *d2i, + void (*free_func)(OPENSSL_BLOCK), int ex_tag, + int ex_class); + +OPENSSL_EXPORT int i2a_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *a); +OPENSSL_EXPORT int a2i_ASN1_INTEGER(BIO *bp,ASN1_INTEGER *bs,char *buf,int size); +OPENSSL_EXPORT int i2a_ASN1_ENUMERATED(BIO *bp, ASN1_ENUMERATED *a); +OPENSSL_EXPORT int a2i_ASN1_ENUMERATED(BIO *bp,ASN1_ENUMERATED *bs,char *buf,int size); +OPENSSL_EXPORT int i2a_ASN1_OBJECT(BIO *bp,ASN1_OBJECT *a); +OPENSSL_EXPORT int a2i_ASN1_STRING(BIO *bp,ASN1_STRING *bs,char *buf,int size); +OPENSSL_EXPORT int i2a_ASN1_STRING(BIO *bp, ASN1_STRING *a, int type); +OPENSSL_EXPORT int i2t_ASN1_OBJECT(char *buf,int buf_len,ASN1_OBJECT *a); + +OPENSSL_EXPORT int a2d_ASN1_OBJECT(unsigned char *out,int olen, const char *buf, int num); +OPENSSL_EXPORT ASN1_OBJECT *ASN1_OBJECT_create(int nid, unsigned char *data,int len, const char *sn, const char *ln); + +OPENSSL_EXPORT int ASN1_INTEGER_set(ASN1_INTEGER *a, long v); +OPENSSL_EXPORT long ASN1_INTEGER_get(const ASN1_INTEGER *a); +OPENSSL_EXPORT ASN1_INTEGER *BN_to_ASN1_INTEGER(const BIGNUM *bn, ASN1_INTEGER *ai); +OPENSSL_EXPORT BIGNUM *ASN1_INTEGER_to_BN(const ASN1_INTEGER *ai,BIGNUM *bn); + +OPENSSL_EXPORT int ASN1_ENUMERATED_set(ASN1_ENUMERATED *a, long v); +OPENSSL_EXPORT long ASN1_ENUMERATED_get(ASN1_ENUMERATED *a); +OPENSSL_EXPORT ASN1_ENUMERATED *BN_to_ASN1_ENUMERATED(BIGNUM *bn, ASN1_ENUMERATED *ai); +OPENSSL_EXPORT BIGNUM *ASN1_ENUMERATED_to_BN(ASN1_ENUMERATED *ai,BIGNUM *bn); + +/* General */ +/* given a string, return the correct type, max is the maximum length */ +OPENSSL_EXPORT int ASN1_PRINTABLE_type(const unsigned char *s, int max); + +OPENSSL_EXPORT int i2d_ASN1_bytes(ASN1_STRING *a, unsigned char **pp, int tag, int xclass); +OPENSSL_EXPORT ASN1_STRING *d2i_ASN1_bytes(ASN1_STRING **a, const unsigned char **pp, long length, int Ptag, int Pclass); +OPENSSL_EXPORT unsigned long ASN1_tag2bit(int tag); +/* type is one or more of the B_ASN1_ values. */ +OPENSSL_EXPORT ASN1_STRING *d2i_ASN1_type_bytes(ASN1_STRING **a,const unsigned char **pp, long length,int type); + +/* PARSING */ +OPENSSL_EXPORT int asn1_Finish(ASN1_CTX *c); +OPENSSL_EXPORT int asn1_const_Finish(ASN1_const_CTX *c); + +/* SPECIALS */ +OPENSSL_EXPORT int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag, int *pclass, long omax); +OPENSSL_EXPORT int ASN1_check_infinite_end(unsigned char **p,long len); +OPENSSL_EXPORT int ASN1_const_check_infinite_end(const unsigned char **p,long len); +OPENSSL_EXPORT void ASN1_put_object(unsigned char **pp, int constructed, int length, int tag, int xclass); +OPENSSL_EXPORT int ASN1_put_eoc(unsigned char **pp); +OPENSSL_EXPORT int ASN1_object_size(int constructed, int length, int tag); + +/* Used to implement other functions */ +OPENSSL_EXPORT void *ASN1_dup(i2d_of_void *i2d, d2i_of_void *d2i, void *x); + +#define ASN1_dup_of(type,i2d,d2i,x) \ + ((type*)ASN1_dup(CHECKED_I2D_OF(type, i2d), \ + CHECKED_D2I_OF(type, d2i), \ + CHECKED_PTR_OF(type, x))) + +#define ASN1_dup_of_const(type,i2d,d2i,x) \ + ((type*)ASN1_dup(CHECKED_I2D_OF(const type, i2d), \ + CHECKED_D2I_OF(type, d2i), \ + CHECKED_PTR_OF(const type, x))) + +OPENSSL_EXPORT void *ASN1_item_dup(const ASN1_ITEM *it, void *x); + +/* ASN1 alloc/free macros for when a type is only used internally */ + +#define M_ASN1_new_of(type) (type *)ASN1_item_new(ASN1_ITEM_rptr(type)) +#define M_ASN1_free_of(x, type) \ + ASN1_item_free(CHECKED_PTR_OF(type, x), ASN1_ITEM_rptr(type)) + +#ifndef OPENSSL_NO_FP_API +OPENSSL_EXPORT void *ASN1_d2i_fp(void *(*xnew)(void), d2i_of_void *d2i, FILE *in, void **x); + +#define ASN1_d2i_fp_of(type,xnew,d2i,in,x) \ + ((type*)ASN1_d2i_fp(CHECKED_NEW_OF(type, xnew), \ + CHECKED_D2I_OF(type, d2i), \ + in, \ + CHECKED_PPTR_OF(type, x))) + +OPENSSL_EXPORT void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x); +OPENSSL_EXPORT int ASN1_i2d_fp(i2d_of_void *i2d,FILE *out,void *x); + +#define ASN1_i2d_fp_of(type,i2d,out,x) \ + (ASN1_i2d_fp(CHECKED_I2D_OF(type, i2d), \ + out, \ + CHECKED_PTR_OF(type, x))) + +#define ASN1_i2d_fp_of_const(type,i2d,out,x) \ + (ASN1_i2d_fp(CHECKED_I2D_OF(const type, i2d), \ + out, \ + CHECKED_PTR_OF(const type, x))) + +OPENSSL_EXPORT int ASN1_item_i2d_fp(const ASN1_ITEM *it, FILE *out, void *x); +OPENSSL_EXPORT int ASN1_STRING_print_ex_fp(FILE *fp, ASN1_STRING *str, unsigned long flags); +#endif + +OPENSSL_EXPORT int ASN1_STRING_to_UTF8(unsigned char **out, ASN1_STRING *in); + +OPENSSL_EXPORT void *ASN1_d2i_bio(void *(*xnew)(void), d2i_of_void *d2i, BIO *in, void **x); + +#define ASN1_d2i_bio_of(type,xnew,d2i,in,x) \ + ((type*)ASN1_d2i_bio( CHECKED_NEW_OF(type, xnew), \ + CHECKED_D2I_OF(type, d2i), \ + in, \ + CHECKED_PPTR_OF(type, x))) + +OPENSSL_EXPORT void *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *x); +OPENSSL_EXPORT int ASN1_i2d_bio(i2d_of_void *i2d,BIO *out, unsigned char *x); + +#define ASN1_i2d_bio_of(type,i2d,out,x) \ + (ASN1_i2d_bio(CHECKED_I2D_OF(type, i2d), \ + out, \ + CHECKED_PTR_OF(type, x))) + +#define ASN1_i2d_bio_of_const(type,i2d,out,x) \ + (ASN1_i2d_bio(CHECKED_I2D_OF(const type, i2d), \ + out, \ + CHECKED_PTR_OF(const type, x))) + +OPENSSL_EXPORT int ASN1_item_i2d_bio(const ASN1_ITEM *it, BIO *out, void *x); +OPENSSL_EXPORT int ASN1_UTCTIME_print(BIO *fp, const ASN1_UTCTIME *a); +OPENSSL_EXPORT int ASN1_GENERALIZEDTIME_print(BIO *fp, const ASN1_GENERALIZEDTIME *a); +OPENSSL_EXPORT int ASN1_TIME_print(BIO *fp, const ASN1_TIME *a); +OPENSSL_EXPORT int ASN1_STRING_print(BIO *bp, const ASN1_STRING *v); +OPENSSL_EXPORT int ASN1_STRING_print_ex(BIO *out, ASN1_STRING *str, unsigned long flags); +OPENSSL_EXPORT int ASN1_bn_print(BIO *bp, const char *number, const BIGNUM *num, unsigned char *buf, int off); +OPENSSL_EXPORT int ASN1_parse(BIO *bp,const unsigned char *pp,long len,int indent); +OPENSSL_EXPORT int ASN1_parse_dump(BIO *bp,const unsigned char *pp,long len,int indent,int dump); +OPENSSL_EXPORT const char *ASN1_tag2str(int tag); + +/* Used to load and write netscape format cert */ + +DECLARE_ASN1_FUNCTIONS(NETSCAPE_X509) + +int ASN1_UNIVERSALSTRING_to_string(ASN1_UNIVERSALSTRING *s); + +OPENSSL_EXPORT STACK_OF(OPENSSL_BLOCK) *ASN1_seq_unpack(const unsigned char *buf, int len, d2i_of_void *d2i, void (*free_func)(OPENSSL_BLOCK)); +OPENSSL_EXPORT unsigned char *ASN1_seq_pack(STACK_OF(OPENSSL_BLOCK) *safes, i2d_of_void *i2d, unsigned char **buf, int *len ); +OPENSSL_EXPORT void *ASN1_unpack_string(ASN1_STRING *oct, d2i_of_void *d2i); +OPENSSL_EXPORT void *ASN1_item_unpack(ASN1_STRING *oct, const ASN1_ITEM *it); +OPENSSL_EXPORT ASN1_STRING *ASN1_pack_string(void *obj, i2d_of_void *i2d, ASN1_OCTET_STRING **oct); + +#define ASN1_pack_string_of(type,obj,i2d,oct) \ + (ASN1_pack_string(CHECKED_PTR_OF(type, obj), \ + CHECKED_I2D_OF(type, i2d), \ + oct)) + +OPENSSL_EXPORT ASN1_STRING *ASN1_item_pack(void *obj, const ASN1_ITEM *it, ASN1_OCTET_STRING **oct); + +OPENSSL_EXPORT void ASN1_STRING_set_default_mask(unsigned long mask); +OPENSSL_EXPORT int ASN1_STRING_set_default_mask_asc(const char *p); +OPENSSL_EXPORT unsigned long ASN1_STRING_get_default_mask(void); +OPENSSL_EXPORT int ASN1_mbstring_copy(ASN1_STRING **out, const unsigned char *in, int len, int inform, unsigned long mask); +OPENSSL_EXPORT int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len, int inform, unsigned long mask, long minsize, long maxsize); + +OPENSSL_EXPORT ASN1_STRING *ASN1_STRING_set_by_NID(ASN1_STRING **out, const unsigned char *in, int inlen, int inform, int nid); +OPENSSL_EXPORT ASN1_STRING_TABLE *ASN1_STRING_TABLE_get(int nid); +OPENSSL_EXPORT int ASN1_STRING_TABLE_add(int, long, long, unsigned long, unsigned long); +OPENSSL_EXPORT void ASN1_STRING_TABLE_cleanup(void); + +/* ASN1 template functions */ + +/* Old API compatible functions */ +OPENSSL_EXPORT ASN1_VALUE *ASN1_item_new(const ASN1_ITEM *it); +OPENSSL_EXPORT void ASN1_item_free(ASN1_VALUE *val, const ASN1_ITEM *it); +OPENSSL_EXPORT ASN1_VALUE * ASN1_item_d2i(ASN1_VALUE **val, const unsigned char **in, long len, const ASN1_ITEM *it); +OPENSSL_EXPORT int ASN1_item_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it); +OPENSSL_EXPORT int ASN1_item_ndef_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it); + +OPENSSL_EXPORT void ASN1_add_oid_module(void); + +OPENSSL_EXPORT ASN1_TYPE *ASN1_generate_nconf(char *str, CONF *nconf); +OPENSSL_EXPORT ASN1_TYPE *ASN1_generate_v3(char *str, X509V3_CTX *cnf); + +/* ASN1 Print flags */ + +/* Indicate missing OPTIONAL fields */ +#define ASN1_PCTX_FLAGS_SHOW_ABSENT 0x001 +/* Mark start and end of SEQUENCE */ +#define ASN1_PCTX_FLAGS_SHOW_SEQUENCE 0x002 +/* Mark start and end of SEQUENCE/SET OF */ +#define ASN1_PCTX_FLAGS_SHOW_SSOF 0x004 +/* Show the ASN1 type of primitives */ +#define ASN1_PCTX_FLAGS_SHOW_TYPE 0x008 +/* Don't show ASN1 type of ANY */ +#define ASN1_PCTX_FLAGS_NO_ANY_TYPE 0x010 +/* Don't show ASN1 type of MSTRINGs */ +#define ASN1_PCTX_FLAGS_NO_MSTRING_TYPE 0x020 +/* Don't show field names in SEQUENCE */ +#define ASN1_PCTX_FLAGS_NO_FIELD_NAME 0x040 +/* Show structure names of each SEQUENCE field */ +#define ASN1_PCTX_FLAGS_SHOW_FIELD_STRUCT_NAME 0x080 +/* Don't show structure name even at top level */ +#define ASN1_PCTX_FLAGS_NO_STRUCT_NAME 0x100 + +OPENSSL_EXPORT int ASN1_item_print(BIO *out, ASN1_VALUE *ifld, int indent, const ASN1_ITEM *it, const ASN1_PCTX *pctx); +OPENSSL_EXPORT ASN1_PCTX *ASN1_PCTX_new(void); +OPENSSL_EXPORT void ASN1_PCTX_free(ASN1_PCTX *p); +OPENSSL_EXPORT unsigned long ASN1_PCTX_get_flags(ASN1_PCTX *p); +OPENSSL_EXPORT void ASN1_PCTX_set_flags(ASN1_PCTX *p, unsigned long flags); +OPENSSL_EXPORT unsigned long ASN1_PCTX_get_nm_flags(ASN1_PCTX *p); +OPENSSL_EXPORT void ASN1_PCTX_set_nm_flags(ASN1_PCTX *p, unsigned long flags); +OPENSSL_EXPORT unsigned long ASN1_PCTX_get_cert_flags(ASN1_PCTX *p); +OPENSSL_EXPORT void ASN1_PCTX_set_cert_flags(ASN1_PCTX *p, unsigned long flags); +OPENSSL_EXPORT unsigned long ASN1_PCTX_get_oid_flags(ASN1_PCTX *p); +OPENSSL_EXPORT void ASN1_PCTX_set_oid_flags(ASN1_PCTX *p, unsigned long flags); +OPENSSL_EXPORT unsigned long ASN1_PCTX_get_str_flags(ASN1_PCTX *p); +OPENSSL_EXPORT void ASN1_PCTX_set_str_flags(ASN1_PCTX *p, unsigned long flags); + +OPENSSL_EXPORT const BIO_METHOD *BIO_f_asn1(void); + +OPENSSL_EXPORT BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it); + +OPENSSL_EXPORT int i2d_ASN1_bio_stream(BIO *out, ASN1_VALUE *val, BIO *in, int flags, const ASN1_ITEM *it); +OPENSSL_EXPORT int PEM_write_bio_ASN1_stream(BIO *out, ASN1_VALUE *val, BIO *in, int flags, const char *hdr, const ASN1_ITEM *it); +OPENSSL_EXPORT ASN1_VALUE *SMIME_read_ASN1(BIO *bio, BIO **bcont, const ASN1_ITEM *it); +OPENSSL_EXPORT int SMIME_crlf_copy(BIO *in, BIO *out, int flags); +OPENSSL_EXPORT int SMIME_text(BIO *in, BIO *out); + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_ASN1_strings(void); + +typedef int asn1_ps_func(BIO *b, unsigned char **pbuf, int *plen, void *parg); +OPENSSL_EXPORT int BIO_asn1_set_prefix(BIO *b, asn1_ps_func *prefix, asn1_ps_func *prefix_free); +OPENSSL_EXPORT int BIO_asn1_get_prefix(BIO *b, asn1_ps_func **pprefix, asn1_ps_func **pprefix_free); +OPENSSL_EXPORT int BIO_asn1_set_suffix(BIO *b, asn1_ps_func *suffix, asn1_ps_func *suffix_free); +OPENSSL_EXPORT int BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix, asn1_ps_func **psuffix_free); + +#ifdef __cplusplus +} +#endif + +#define ASN1_R_ASN1_LENGTH_MISMATCH 100 +#define ASN1_R_AUX_ERROR 101 +#define ASN1_R_BAD_GET_ASN1_OBJECT_CALL 102 +#define ASN1_R_BAD_OBJECT_HEADER 103 +#define ASN1_R_BMPSTRING_IS_WRONG_LENGTH 104 +#define ASN1_R_BN_LIB 105 +#define ASN1_R_BOOLEAN_IS_WRONG_LENGTH 106 +#define ASN1_R_BUFFER_TOO_SMALL 107 +#define ASN1_R_DECODE_ERROR 108 +#define ASN1_R_DEPTH_EXCEEDED 109 +#define ASN1_R_ENCODE_ERROR 110 +#define ASN1_R_ERROR_GETTING_TIME 111 +#define ASN1_R_EXPECTING_AN_ASN1_SEQUENCE 112 +#define ASN1_R_EXPECTING_AN_INTEGER 113 +#define ASN1_R_EXPECTING_AN_OBJECT 114 +#define ASN1_R_EXPECTING_A_BOOLEAN 115 +#define ASN1_R_EXPECTING_A_TIME 116 +#define ASN1_R_EXPLICIT_LENGTH_MISMATCH 117 +#define ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED 118 +#define ASN1_R_FIELD_MISSING 119 +#define ASN1_R_FIRST_NUM_TOO_LARGE 120 +#define ASN1_R_HEADER_TOO_LONG 121 +#define ASN1_R_ILLEGAL_BITSTRING_FORMAT 122 +#define ASN1_R_ILLEGAL_BOOLEAN 123 +#define ASN1_R_ILLEGAL_CHARACTERS 124 +#define ASN1_R_ILLEGAL_FORMAT 125 +#define ASN1_R_ILLEGAL_HEX 126 +#define ASN1_R_ILLEGAL_IMPLICIT_TAG 127 +#define ASN1_R_ILLEGAL_INTEGER 128 +#define ASN1_R_ILLEGAL_NESTED_TAGGING 129 +#define ASN1_R_ILLEGAL_NULL 130 +#define ASN1_R_ILLEGAL_NULL_VALUE 131 +#define ASN1_R_ILLEGAL_OBJECT 132 +#define ASN1_R_ILLEGAL_OPTIONAL_ANY 133 +#define ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE 134 +#define ASN1_R_ILLEGAL_TAGGED_ANY 135 +#define ASN1_R_ILLEGAL_TIME_VALUE 136 +#define ASN1_R_INTEGER_NOT_ASCII_FORMAT 137 +#define ASN1_R_INTEGER_TOO_LARGE_FOR_LONG 138 +#define ASN1_R_INVALID_BIT_STRING_BITS_LEFT 139 +#define ASN1_R_INVALID_BMPSTRING_LENGTH 140 +#define ASN1_R_INVALID_DIGIT 141 +#define ASN1_R_INVALID_MODIFIER 142 +#define ASN1_R_INVALID_NUMBER 143 +#define ASN1_R_INVALID_OBJECT_ENCODING 144 +#define ASN1_R_INVALID_SEPARATOR 145 +#define ASN1_R_INVALID_TIME_FORMAT 146 +#define ASN1_R_INVALID_UNIVERSALSTRING_LENGTH 147 +#define ASN1_R_INVALID_UTF8STRING 148 +#define ASN1_R_LIST_ERROR 149 +#define ASN1_R_MALLOC_FAILURE 150 +#define ASN1_R_MISSING_ASN1_EOS 151 +#define ASN1_R_MISSING_EOC 152 +#define ASN1_R_MISSING_SECOND_NUMBER 153 +#define ASN1_R_MISSING_VALUE 154 +#define ASN1_R_MSTRING_NOT_UNIVERSAL 155 +#define ASN1_R_MSTRING_WRONG_TAG 156 +#define ASN1_R_NESTED_ASN1_ERROR 157 +#define ASN1_R_NESTED_ASN1_STRING 158 +#define ASN1_R_NON_HEX_CHARACTERS 159 +#define ASN1_R_NOT_ASCII_FORMAT 160 +#define ASN1_R_NOT_ENOUGH_DATA 161 +#define ASN1_R_NO_MATCHING_CHOICE_TYPE 162 +#define ASN1_R_NULL_IS_WRONG_LENGTH 163 +#define ASN1_R_OBJECT_NOT_ASCII_FORMAT 164 +#define ASN1_R_ODD_NUMBER_OF_CHARS 165 +#define ASN1_R_SECOND_NUMBER_TOO_LARGE 166 +#define ASN1_R_SEQUENCE_LENGTH_MISMATCH 167 +#define ASN1_R_SEQUENCE_NOT_CONSTRUCTED 168 +#define ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG 169 +#define ASN1_R_SHORT_LINE 170 +#define ASN1_R_STREAMING_NOT_SUPPORTED 171 +#define ASN1_R_STRING_TOO_LONG 172 +#define ASN1_R_STRING_TOO_SHORT 173 +#define ASN1_R_TAG_VALUE_TOO_HIGH 174 +#define ASN1_R_TIME_NOT_ASCII_FORMAT 175 +#define ASN1_R_TOO_LONG 176 +#define ASN1_R_TYPE_NOT_CONSTRUCTED 177 +#define ASN1_R_TYPE_NOT_PRIMITIVE 178 +#define ASN1_R_UNEXPECTED_EOC 179 +#define ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH 180 +#define ASN1_R_UNKNOWN_FORMAT 181 +#define ASN1_R_UNKNOWN_TAG 182 +#define ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE 183 +#define ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE 184 +#define ASN1_R_UNSUPPORTED_TYPE 185 +#define ASN1_R_WRONG_TAG 186 +#define ASN1_R_WRONG_TYPE 187 + +#endif diff --git a/TMessagesProj/jni/boringssl/include/openssl/asn1_mac.h b/TMessagesProj/jni/boringssl/include/openssl/asn1_mac.h new file mode 100644 index 00000000..49b2a286 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/asn1_mac.h @@ -0,0 +1,76 @@ +/* crypto/asn1/asn1_mac.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_ASN1_MAC_H +#define HEADER_ASN1_MAC_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +OPENSSL_EXPORT int asn1_GetSequence(ASN1_const_CTX *c, long *length); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/TMessagesProj/jni/boringssl/include/openssl/asn1t.h b/TMessagesProj/jni/boringssl/include/openssl/asn1t.h new file mode 100644 index 00000000..0f2560b7 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/asn1t.h @@ -0,0 +1,907 @@ +/* asn1t.h */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2000. + */ +/* ==================================================================== + * Copyright (c) 2000-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +#ifndef HEADER_ASN1T_H +#define HEADER_ASN1T_H + +#include +#include + +#ifdef OPENSSL_BUILD_SHLIBCRYPTO +# undef OPENSSL_EXTERN +# define OPENSSL_EXTERN OPENSSL_EXPORT +#endif + +/* ASN1 template defines, structures and functions */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Macro to obtain ASN1_ADB pointer from a type (only used internally) */ +#define ASN1_ADB_ptr(iptr) ((const ASN1_ADB *)(iptr)) + + +/* Macros for start and end of ASN1_ITEM definition */ + +#define ASN1_ITEM_start(itname) \ + const ASN1_ITEM itname##_it = { + +#define ASN1_ITEM_end(itname) \ + }; + +/* Macros to aid ASN1 template writing */ + +#define ASN1_ITEM_TEMPLATE(tname) \ + static const ASN1_TEMPLATE tname##_item_tt + +#define ASN1_ITEM_TEMPLATE_END(tname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_PRIMITIVE,\ + -1,\ + &tname##_item_tt,\ + 0,\ + NULL,\ + 0,\ + #tname \ + ASN1_ITEM_end(tname) + + +/* This is a ASN1 type which just embeds a template */ + +/* This pair helps declare a SEQUENCE. We can do: + * + * ASN1_SEQUENCE(stname) = { + * ... SEQUENCE components ... + * } ASN1_SEQUENCE_END(stname) + * + * This will produce an ASN1_ITEM called stname_it + * for a structure called stname. + * + * If you want the same structure but a different + * name then use: + * + * ASN1_SEQUENCE(itname) = { + * ... SEQUENCE components ... + * } ASN1_SEQUENCE_END_name(stname, itname) + * + * This will create an item called itname_it using + * a structure called stname. + */ + +#define ASN1_SEQUENCE(tname) \ + static const ASN1_TEMPLATE tname##_seq_tt[] + +#define ASN1_SEQUENCE_END(stname) ASN1_SEQUENCE_END_name(stname, stname) + +#define ASN1_SEQUENCE_END_name(stname, tname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_SEQUENCE,\ + V_ASN1_SEQUENCE,\ + tname##_seq_tt,\ + sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\ + NULL,\ + sizeof(stname),\ + #stname \ + ASN1_ITEM_end(tname) + +#define ASN1_NDEF_SEQUENCE(tname) \ + ASN1_SEQUENCE(tname) + +#define ASN1_NDEF_SEQUENCE_cb(tname, cb) \ + ASN1_SEQUENCE_cb(tname, cb) + +#define ASN1_SEQUENCE_cb(tname, cb) \ + static const ASN1_AUX tname##_aux = {NULL, 0, 0, cb, 0}; \ + ASN1_SEQUENCE(tname) + +#define ASN1_BROKEN_SEQUENCE(tname) \ + static const ASN1_AUX tname##_aux = {NULL, ASN1_AFLG_BROKEN, 0, 0, 0}; \ + ASN1_SEQUENCE(tname) + +#define ASN1_SEQUENCE_ref(tname, cb) \ + static const ASN1_AUX tname##_aux = {NULL, ASN1_AFLG_REFCOUNT, offsetof(tname, references), cb, 0}; \ + ASN1_SEQUENCE(tname) + +#define ASN1_SEQUENCE_enc(tname, enc, cb) \ + static const ASN1_AUX tname##_aux = {NULL, ASN1_AFLG_ENCODING, 0, cb, offsetof(tname, enc)}; \ + ASN1_SEQUENCE(tname) + +#define ASN1_NDEF_SEQUENCE_END(tname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_NDEF_SEQUENCE,\ + V_ASN1_SEQUENCE,\ + tname##_seq_tt,\ + sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\ + NULL,\ + sizeof(tname),\ + #tname \ + ASN1_ITEM_end(tname) + +#define ASN1_BROKEN_SEQUENCE_END(stname) ASN1_SEQUENCE_END_ref(stname, stname) + +#define ASN1_SEQUENCE_END_enc(stname, tname) ASN1_SEQUENCE_END_ref(stname, tname) + +#define ASN1_SEQUENCE_END_cb(stname, tname) ASN1_SEQUENCE_END_ref(stname, tname) + +#define ASN1_SEQUENCE_END_ref(stname, tname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_SEQUENCE,\ + V_ASN1_SEQUENCE,\ + tname##_seq_tt,\ + sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\ + &tname##_aux,\ + sizeof(stname),\ + #stname \ + ASN1_ITEM_end(tname) + +#define ASN1_NDEF_SEQUENCE_END_cb(stname, tname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_NDEF_SEQUENCE,\ + V_ASN1_SEQUENCE,\ + tname##_seq_tt,\ + sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\ + &tname##_aux,\ + sizeof(stname),\ + #stname \ + ASN1_ITEM_end(tname) + + +/* This pair helps declare a CHOICE type. We can do: + * + * ASN1_CHOICE(chname) = { + * ... CHOICE options ... + * ASN1_CHOICE_END(chname) + * + * This will produce an ASN1_ITEM called chname_it + * for a structure called chname. The structure + * definition must look like this: + * typedef struct { + * int type; + * union { + * ASN1_SOMETHING *opt1; + * ASN1_SOMEOTHER *opt2; + * } value; + * } chname; + * + * the name of the selector must be 'type'. + * to use an alternative selector name use the + * ASN1_CHOICE_END_selector() version. + */ + +#define ASN1_CHOICE(tname) \ + static const ASN1_TEMPLATE tname##_ch_tt[] + +#define ASN1_CHOICE_cb(tname, cb) \ + static const ASN1_AUX tname##_aux = {NULL, 0, 0, cb, 0}; \ + ASN1_CHOICE(tname) + +#define ASN1_CHOICE_END(stname) ASN1_CHOICE_END_name(stname, stname) + +#define ASN1_CHOICE_END_name(stname, tname) ASN1_CHOICE_END_selector(stname, tname, type) + +#define ASN1_CHOICE_END_selector(stname, tname, selname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_CHOICE,\ + offsetof(stname,selname) ,\ + tname##_ch_tt,\ + sizeof(tname##_ch_tt) / sizeof(ASN1_TEMPLATE),\ + NULL,\ + sizeof(stname),\ + #stname \ + ASN1_ITEM_end(tname) + +#define ASN1_CHOICE_END_cb(stname, tname, selname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_CHOICE,\ + offsetof(stname,selname) ,\ + tname##_ch_tt,\ + sizeof(tname##_ch_tt) / sizeof(ASN1_TEMPLATE),\ + &tname##_aux,\ + sizeof(stname),\ + #stname \ + ASN1_ITEM_end(tname) + +/* This helps with the template wrapper form of ASN1_ITEM */ + +#define ASN1_EX_TEMPLATE_TYPE(flags, tag, name, type) { \ + (flags), (tag), 0,\ + #name, ASN1_ITEM_ref(type) } + +/* These help with SEQUENCE or CHOICE components */ + +/* used to declare other types */ + +#define ASN1_EX_TYPE(flags, tag, stname, field, type) { \ + (flags), (tag), offsetof(stname, field),\ + #field, ASN1_ITEM_ref(type) } + +/* used when the structure is combined with the parent */ + +#define ASN1_EX_COMBINE(flags, tag, type) { \ + (flags)|ASN1_TFLG_COMBINE, (tag), 0, NULL, ASN1_ITEM_ref(type) } + +/* implicit and explicit helper macros */ + +#define ASN1_IMP_EX(stname, field, type, tag, ex) \ + ASN1_EX_TYPE(ASN1_TFLG_IMPLICIT | ex, tag, stname, field, type) + +#define ASN1_EXP_EX(stname, field, type, tag, ex) \ + ASN1_EX_TYPE(ASN1_TFLG_EXPLICIT | ex, tag, stname, field, type) + +/* Any defined by macros: the field used is in the table itself */ + +#define ASN1_ADB_OBJECT(tblname) { ASN1_TFLG_ADB_OID, -1, 0, #tblname, (const ASN1_ITEM *)&(tblname##_adb) } +#define ASN1_ADB_INTEGER(tblname) { ASN1_TFLG_ADB_INT, -1, 0, #tblname, (const ASN1_ITEM *)&(tblname##_adb) } +/* Plain simple type */ +#define ASN1_SIMPLE(stname, field, type) ASN1_EX_TYPE(0,0, stname, field, type) + +/* OPTIONAL simple type */ +#define ASN1_OPT(stname, field, type) ASN1_EX_TYPE(ASN1_TFLG_OPTIONAL, 0, stname, field, type) + +/* IMPLICIT tagged simple type */ +#define ASN1_IMP(stname, field, type, tag) ASN1_IMP_EX(stname, field, type, tag, 0) + +/* IMPLICIT tagged OPTIONAL simple type */ +#define ASN1_IMP_OPT(stname, field, type, tag) ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL) + +/* Same as above but EXPLICIT */ + +#define ASN1_EXP(stname, field, type, tag) ASN1_EXP_EX(stname, field, type, tag, 0) +#define ASN1_EXP_OPT(stname, field, type, tag) ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL) + +/* SEQUENCE OF type */ +#define ASN1_SEQUENCE_OF(stname, field, type) \ + ASN1_EX_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, stname, field, type) + +/* OPTIONAL SEQUENCE OF */ +#define ASN1_SEQUENCE_OF_OPT(stname, field, type) \ + ASN1_EX_TYPE(ASN1_TFLG_SEQUENCE_OF|ASN1_TFLG_OPTIONAL, 0, stname, field, type) + +/* Same as above but for SET OF */ + +#define ASN1_SET_OF(stname, field, type) \ + ASN1_EX_TYPE(ASN1_TFLG_SET_OF, 0, stname, field, type) + +#define ASN1_SET_OF_OPT(stname, field, type) \ + ASN1_EX_TYPE(ASN1_TFLG_SET_OF|ASN1_TFLG_OPTIONAL, 0, stname, field, type) + +/* Finally compound types of SEQUENCE, SET, IMPLICIT, EXPLICIT and OPTIONAL */ + +#define ASN1_IMP_SET_OF(stname, field, type, tag) \ + ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF) + +#define ASN1_EXP_SET_OF(stname, field, type, tag) \ + ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF) + +#define ASN1_IMP_SET_OF_OPT(stname, field, type, tag) \ + ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF|ASN1_TFLG_OPTIONAL) + +#define ASN1_EXP_SET_OF_OPT(stname, field, type, tag) \ + ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF|ASN1_TFLG_OPTIONAL) + +#define ASN1_IMP_SEQUENCE_OF(stname, field, type, tag) \ + ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF) + +#define ASN1_IMP_SEQUENCE_OF_OPT(stname, field, type, tag) \ + ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF|ASN1_TFLG_OPTIONAL) + +#define ASN1_EXP_SEQUENCE_OF(stname, field, type, tag) \ + ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF) + +#define ASN1_EXP_SEQUENCE_OF_OPT(stname, field, type, tag) \ + ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF|ASN1_TFLG_OPTIONAL) + +/* EXPLICIT using indefinite length constructed form */ +#define ASN1_NDEF_EXP(stname, field, type, tag) \ + ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_NDEF) + +/* EXPLICIT OPTIONAL using indefinite length constructed form */ +#define ASN1_NDEF_EXP_OPT(stname, field, type, tag) \ + ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL|ASN1_TFLG_NDEF) + +/* Macros for the ASN1_ADB structure */ + +#define ASN1_ADB(name) \ + static const ASN1_ADB_TABLE name##_adbtbl[] + +#define ASN1_ADB_END(name, flags, field, app_table, def, none) \ + ;\ + static const ASN1_ADB name##_adb = {\ + flags,\ + offsetof(name, field),\ + app_table,\ + name##_adbtbl,\ + sizeof(name##_adbtbl) / sizeof(ASN1_ADB_TABLE),\ + def,\ + none\ + } + +#define ADB_ENTRY(val, template) {val, template} + +#define ASN1_ADB_TEMPLATE(name) \ + static const ASN1_TEMPLATE name##_tt + +/* This is the ASN1 template structure that defines + * a wrapper round the actual type. It determines the + * actual position of the field in the value structure, + * various flags such as OPTIONAL and the field name. + */ + +struct ASN1_TEMPLATE_st { +unsigned long flags; /* Various flags */ +long tag; /* tag, not used if no tagging */ +unsigned long offset; /* Offset of this field in structure */ +#ifndef NO_ASN1_FIELD_NAMES +const char *field_name; /* Field name */ +#endif +ASN1_ITEM_EXP *item; /* Relevant ASN1_ITEM or ASN1_ADB */ +}; + +/* Macro to extract ASN1_ITEM and ASN1_ADB pointer from ASN1_TEMPLATE */ + +#define ASN1_TEMPLATE_item(t) (t->item_ptr) +#define ASN1_TEMPLATE_adb(t) (t->item_ptr) + +typedef struct ASN1_ADB_TABLE_st ASN1_ADB_TABLE; +typedef struct ASN1_ADB_st ASN1_ADB; + +struct ASN1_ADB_st { + unsigned long flags; /* Various flags */ + unsigned long offset; /* Offset of selector field */ + STACK_OF(ASN1_ADB_TABLE) **app_items; /* Application defined items */ + const ASN1_ADB_TABLE *tbl; /* Table of possible types */ + long tblcount; /* Number of entries in tbl */ + const ASN1_TEMPLATE *default_tt; /* Type to use if no match */ + const ASN1_TEMPLATE *null_tt; /* Type to use if selector is NULL */ +}; + +struct ASN1_ADB_TABLE_st { + long value; /* NID for an object or value for an int */ + const ASN1_TEMPLATE tt; /* item for this value */ +}; + +/* template flags */ + +/* Field is optional */ +#define ASN1_TFLG_OPTIONAL (0x1) + +/* Field is a SET OF */ +#define ASN1_TFLG_SET_OF (0x1 << 1) + +/* Field is a SEQUENCE OF */ +#define ASN1_TFLG_SEQUENCE_OF (0x2 << 1) + +/* Special case: this refers to a SET OF that + * will be sorted into DER order when encoded *and* + * the corresponding STACK will be modified to match + * the new order. + */ +#define ASN1_TFLG_SET_ORDER (0x3 << 1) + +/* Mask for SET OF or SEQUENCE OF */ +#define ASN1_TFLG_SK_MASK (0x3 << 1) + +/* These flags mean the tag should be taken from the + * tag field. If EXPLICIT then the underlying type + * is used for the inner tag. + */ + +/* IMPLICIT tagging */ +#define ASN1_TFLG_IMPTAG (0x1 << 3) + + +/* EXPLICIT tagging, inner tag from underlying type */ +#define ASN1_TFLG_EXPTAG (0x2 << 3) + +#define ASN1_TFLG_TAG_MASK (0x3 << 3) + +/* context specific IMPLICIT */ +#define ASN1_TFLG_IMPLICIT ASN1_TFLG_IMPTAG|ASN1_TFLG_CONTEXT + +/* context specific EXPLICIT */ +#define ASN1_TFLG_EXPLICIT ASN1_TFLG_EXPTAG|ASN1_TFLG_CONTEXT + +/* If tagging is in force these determine the + * type of tag to use. Otherwise the tag is + * determined by the underlying type. These + * values reflect the actual octet format. + */ + +/* Universal tag */ +#define ASN1_TFLG_UNIVERSAL (0x0<<6) +/* Application tag */ +#define ASN1_TFLG_APPLICATION (0x1<<6) +/* Context specific tag */ +#define ASN1_TFLG_CONTEXT (0x2<<6) +/* Private tag */ +#define ASN1_TFLG_PRIVATE (0x3<<6) + +#define ASN1_TFLG_TAG_CLASS (0x3<<6) + +/* These are for ANY DEFINED BY type. In this case + * the 'item' field points to an ASN1_ADB structure + * which contains a table of values to decode the + * relevant type + */ + +#define ASN1_TFLG_ADB_MASK (0x3<<8) + +#define ASN1_TFLG_ADB_OID (0x1<<8) + +#define ASN1_TFLG_ADB_INT (0x1<<9) + +/* This flag means a parent structure is passed + * instead of the field: this is useful is a + * SEQUENCE is being combined with a CHOICE for + * example. Since this means the structure and + * item name will differ we need to use the + * ASN1_CHOICE_END_name() macro for example. + */ + +#define ASN1_TFLG_COMBINE (0x1<<10) + +/* This flag when present in a SEQUENCE OF, SET OF + * or EXPLICIT causes indefinite length constructed + * encoding to be used if required. + */ + +#define ASN1_TFLG_NDEF (0x1<<11) + +/* This is the actual ASN1 item itself */ + +struct ASN1_ITEM_st { +char itype; /* The item type, primitive, SEQUENCE, CHOICE or extern */ +long utype; /* underlying type */ +const ASN1_TEMPLATE *templates; /* If SEQUENCE or CHOICE this contains the contents */ +long tcount; /* Number of templates if SEQUENCE or CHOICE */ +const void *funcs; /* functions that handle this type */ +long size; /* Structure size (usually)*/ +#ifndef NO_ASN1_FIELD_NAMES +const char *sname; /* Structure name */ +#endif +}; + +/* These are values for the itype field and + * determine how the type is interpreted. + * + * For PRIMITIVE types the underlying type + * determines the behaviour if items is NULL. + * + * Otherwise templates must contain a single + * template and the type is treated in the + * same way as the type specified in the template. + * + * For SEQUENCE types the templates field points + * to the members, the size field is the + * structure size. + * + * For CHOICE types the templates field points + * to each possible member (typically a union) + * and the 'size' field is the offset of the + * selector. + * + * The 'funcs' field is used for application + * specific functions. + * + * For COMPAT types the funcs field gives a + * set of functions that handle this type, this + * supports the old d2i, i2d convention. + * + * The EXTERN type uses a new style d2i/i2d. + * The new style should be used where possible + * because it avoids things like the d2i IMPLICIT + * hack. + * + * MSTRING is a multiple string type, it is used + * for a CHOICE of character strings where the + * actual strings all occupy an ASN1_STRING + * structure. In this case the 'utype' field + * has a special meaning, it is used as a mask + * of acceptable types using the B_ASN1 constants. + * + * NDEF_SEQUENCE is the same as SEQUENCE except + * that it will use indefinite length constructed + * encoding if requested. + * + */ + +#define ASN1_ITYPE_PRIMITIVE 0x0 + +#define ASN1_ITYPE_SEQUENCE 0x1 + +#define ASN1_ITYPE_CHOICE 0x2 + +#define ASN1_ITYPE_COMPAT 0x3 + +#define ASN1_ITYPE_EXTERN 0x4 + +#define ASN1_ITYPE_MSTRING 0x5 + +#define ASN1_ITYPE_NDEF_SEQUENCE 0x6 + +/* Cache for ASN1 tag and length, so we + * don't keep re-reading it for things + * like CHOICE + */ + +struct ASN1_TLC_st{ + char valid; /* Values below are valid */ + int ret; /* return value */ + long plen; /* length */ + int ptag; /* class value */ + int pclass; /* class value */ + int hdrlen; /* header length */ +}; + +/* Typedefs for ASN1 function pointers */ + +typedef ASN1_VALUE * ASN1_new_func(void); +typedef void ASN1_free_func(ASN1_VALUE *a); +typedef ASN1_VALUE * ASN1_d2i_func(ASN1_VALUE **a, const unsigned char ** in, long length); +typedef int ASN1_i2d_func(ASN1_VALUE * a, unsigned char **in); + +typedef int ASN1_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_ITEM *it, + int tag, int aclass, char opt, ASN1_TLC *ctx); + +typedef int ASN1_ex_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass); +typedef int ASN1_ex_new_func(ASN1_VALUE **pval, const ASN1_ITEM *it); +typedef void ASN1_ex_free_func(ASN1_VALUE **pval, const ASN1_ITEM *it); + +typedef int ASN1_ex_print_func(BIO *out, ASN1_VALUE **pval, + int indent, const char *fname, + const ASN1_PCTX *pctx); + +typedef int ASN1_primitive_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, const ASN1_ITEM *it); +typedef int ASN1_primitive_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, int utype, char *free_cont, const ASN1_ITEM *it); +typedef int ASN1_primitive_print(BIO *out, ASN1_VALUE **pval, const ASN1_ITEM *it, int indent, const ASN1_PCTX *pctx); + +typedef struct ASN1_COMPAT_FUNCS_st { + ASN1_new_func *asn1_new; + ASN1_free_func *asn1_free; + ASN1_d2i_func *asn1_d2i; + ASN1_i2d_func *asn1_i2d; +} ASN1_COMPAT_FUNCS; + +typedef struct ASN1_EXTERN_FUNCS_st { + void *app_data; + ASN1_ex_new_func *asn1_ex_new; + ASN1_ex_free_func *asn1_ex_free; + ASN1_ex_free_func *asn1_ex_clear; + ASN1_ex_d2i *asn1_ex_d2i; + ASN1_ex_i2d *asn1_ex_i2d; + ASN1_ex_print_func *asn1_ex_print; +} ASN1_EXTERN_FUNCS; + +typedef struct ASN1_PRIMITIVE_FUNCS_st { + void *app_data; + unsigned long flags; + ASN1_ex_new_func *prim_new; + ASN1_ex_free_func *prim_free; + ASN1_ex_free_func *prim_clear; + ASN1_primitive_c2i *prim_c2i; + ASN1_primitive_i2c *prim_i2c; + ASN1_primitive_print *prim_print; +} ASN1_PRIMITIVE_FUNCS; + +/* This is the ASN1_AUX structure: it handles various + * miscellaneous requirements. For example the use of + * reference counts and an informational callback. + * + * The "informational callback" is called at various + * points during the ASN1 encoding and decoding. It can + * be used to provide minor customisation of the structures + * used. This is most useful where the supplied routines + * *almost* do the right thing but need some extra help + * at a few points. If the callback returns zero then + * it is assumed a fatal error has occurred and the + * main operation should be abandoned. + * + * If major changes in the default behaviour are required + * then an external type is more appropriate. + */ + +typedef int ASN1_aux_cb(int operation, ASN1_VALUE **in, const ASN1_ITEM *it, + void *exarg); + +typedef struct ASN1_AUX_st { + void *app_data; + int flags; + int ref_offset; /* Offset of reference value */ + ASN1_aux_cb *asn1_cb; + int enc_offset; /* Offset of ASN1_ENCODING structure */ +} ASN1_AUX; + +/* For print related callbacks exarg points to this structure */ +typedef struct ASN1_PRINT_ARG_st { + BIO *out; + int indent; + const ASN1_PCTX *pctx; +} ASN1_PRINT_ARG; + +/* For streaming related callbacks exarg points to this structure */ +typedef struct ASN1_STREAM_ARG_st { + /* BIO to stream through */ + BIO *out; + /* BIO with filters appended */ + BIO *ndef_bio; + /* Streaming I/O boundary */ + unsigned char **boundary; +} ASN1_STREAM_ARG; + +/* Flags in ASN1_AUX */ + +/* Use a reference count */ +#define ASN1_AFLG_REFCOUNT 1 +/* Save the encoding of structure (useful for signatures) */ +#define ASN1_AFLG_ENCODING 2 +/* The Sequence length is invalid */ +#define ASN1_AFLG_BROKEN 4 + +/* operation values for asn1_cb */ + +#define ASN1_OP_NEW_PRE 0 +#define ASN1_OP_NEW_POST 1 +#define ASN1_OP_FREE_PRE 2 +#define ASN1_OP_FREE_POST 3 +#define ASN1_OP_D2I_PRE 4 +#define ASN1_OP_D2I_POST 5 +#define ASN1_OP_I2D_PRE 6 +#define ASN1_OP_I2D_POST 7 +#define ASN1_OP_PRINT_PRE 8 +#define ASN1_OP_PRINT_POST 9 +#define ASN1_OP_STREAM_PRE 10 +#define ASN1_OP_STREAM_POST 11 +#define ASN1_OP_DETACHED_PRE 12 +#define ASN1_OP_DETACHED_POST 13 + +/* Macro to implement a primitive type */ +#define IMPLEMENT_ASN1_TYPE(stname) IMPLEMENT_ASN1_TYPE_ex(stname, stname, 0) +#define IMPLEMENT_ASN1_TYPE_ex(itname, vname, ex) \ + ASN1_ITEM_start(itname) \ + ASN1_ITYPE_PRIMITIVE, V_##vname, NULL, 0, NULL, ex, #itname \ + ASN1_ITEM_end(itname) + +/* Macro to implement a multi string type */ +#define IMPLEMENT_ASN1_MSTRING(itname, mask) \ + ASN1_ITEM_start(itname) \ + ASN1_ITYPE_MSTRING, mask, NULL, 0, NULL, sizeof(ASN1_STRING), #itname \ + ASN1_ITEM_end(itname) + +/* Macro to implement an ASN1_ITEM in terms of old style funcs */ + +#define IMPLEMENT_COMPAT_ASN1(sname) IMPLEMENT_COMPAT_ASN1_type(sname, V_ASN1_SEQUENCE) + +#define IMPLEMENT_COMPAT_ASN1_type(sname, tag) \ + static const ASN1_COMPAT_FUNCS sname##_ff = { \ + (ASN1_new_func *)sname##_new, \ + (ASN1_free_func *)sname##_free, \ + (ASN1_d2i_func *)d2i_##sname, \ + (ASN1_i2d_func *)i2d_##sname, \ + }; \ + ASN1_ITEM_start(sname) \ + ASN1_ITYPE_COMPAT, \ + tag, \ + NULL, \ + 0, \ + &sname##_ff, \ + 0, \ + #sname \ + ASN1_ITEM_end(sname) + +#define IMPLEMENT_EXTERN_ASN1(sname, tag, fptrs) \ + ASN1_ITEM_start(sname) \ + ASN1_ITYPE_EXTERN, \ + tag, \ + NULL, \ + 0, \ + &fptrs, \ + 0, \ + #sname \ + ASN1_ITEM_end(sname) + +/* Macro to implement standard functions in terms of ASN1_ITEM structures */ + +#define IMPLEMENT_ASN1_FUNCTIONS(stname) IMPLEMENT_ASN1_FUNCTIONS_fname(stname, stname, stname) + +#define IMPLEMENT_ASN1_FUNCTIONS_name(stname, itname) IMPLEMENT_ASN1_FUNCTIONS_fname(stname, itname, itname) + +#define IMPLEMENT_ASN1_FUNCTIONS_ENCODE_name(stname, itname) \ + IMPLEMENT_ASN1_FUNCTIONS_ENCODE_fname(stname, itname, itname) + +#define IMPLEMENT_STATIC_ASN1_ALLOC_FUNCTIONS(stname) \ + IMPLEMENT_ASN1_ALLOC_FUNCTIONS_pfname(static, stname, stname, stname) + +#define IMPLEMENT_ASN1_ALLOC_FUNCTIONS(stname) \ + IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, stname, stname) + +#define IMPLEMENT_ASN1_ALLOC_FUNCTIONS_pfname(pre, stname, itname, fname) \ + pre stname *fname##_new(void) \ + { \ + return (stname *)ASN1_item_new(ASN1_ITEM_rptr(itname)); \ + } \ + pre void fname##_free(stname *a) \ + { \ + ASN1_item_free((ASN1_VALUE *)a, ASN1_ITEM_rptr(itname)); \ + } + +#define IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname) \ + stname *fname##_new(void) \ + { \ + return (stname *)ASN1_item_new(ASN1_ITEM_rptr(itname)); \ + } \ + void fname##_free(stname *a) \ + { \ + ASN1_item_free((ASN1_VALUE *)a, ASN1_ITEM_rptr(itname)); \ + } + +#define IMPLEMENT_ASN1_FUNCTIONS_fname(stname, itname, fname) \ + IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(stname, itname, fname) \ + IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname) + +#define IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(stname, itname, fname) \ + stname *d2i_##fname(stname **a, const unsigned char **in, long len) \ + { \ + return (stname *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, ASN1_ITEM_rptr(itname));\ + } \ + int i2d_##fname(stname *a, unsigned char **out) \ + { \ + return ASN1_item_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(itname));\ + } + +#define IMPLEMENT_ASN1_NDEF_FUNCTION(stname) \ + int i2d_##stname##_NDEF(stname *a, unsigned char **out) \ + { \ + return ASN1_item_ndef_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(stname));\ + } + +/* This includes evil casts to remove const: they will go away when full + * ASN1 constification is done. + */ +#define IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(stname, itname, fname) \ + stname *d2i_##fname(stname **a, const unsigned char **in, long len) \ + { \ + return (stname *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, ASN1_ITEM_rptr(itname));\ + } \ + int i2d_##fname(const stname *a, unsigned char **out) \ + { \ + return ASN1_item_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(itname));\ + } + +#define IMPLEMENT_ASN1_DUP_FUNCTION(stname) \ + stname * stname##_dup(stname *x) \ + { \ + return ASN1_item_dup(ASN1_ITEM_rptr(stname), x); \ + } + +#define IMPLEMENT_ASN1_PRINT_FUNCTION(stname) \ + IMPLEMENT_ASN1_PRINT_FUNCTION_fname(stname, stname, stname) + +#define IMPLEMENT_ASN1_PRINT_FUNCTION_fname(stname, itname, fname) \ + int fname##_print_ctx(BIO *out, stname *x, int indent, \ + const ASN1_PCTX *pctx) \ + { \ + return ASN1_item_print(out, (ASN1_VALUE *)x, indent, \ + ASN1_ITEM_rptr(itname), pctx); \ + } + +#define IMPLEMENT_ASN1_FUNCTIONS_const(name) \ + IMPLEMENT_ASN1_FUNCTIONS_const_fname(name, name, name) + +#define IMPLEMENT_ASN1_FUNCTIONS_const_fname(stname, itname, fname) \ + IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(stname, itname, fname) \ + IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname) + +/* external definitions for primitive types */ + +DECLARE_ASN1_ITEM(ASN1_BOOLEAN) +DECLARE_ASN1_ITEM(ASN1_TBOOLEAN) +DECLARE_ASN1_ITEM(ASN1_FBOOLEAN) +DECLARE_ASN1_ITEM(ASN1_SEQUENCE) +DECLARE_ASN1_ITEM(CBIGNUM) +DECLARE_ASN1_ITEM(BIGNUM) +DECLARE_ASN1_ITEM(LONG) +DECLARE_ASN1_ITEM(ZLONG) + +DECLARE_STACK_OF(ASN1_VALUE) + +/* Functions used internally by the ASN1 code */ + +int ASN1_item_ex_new(ASN1_VALUE **pval, const ASN1_ITEM *it); +void ASN1_item_ex_free(ASN1_VALUE **pval, const ASN1_ITEM *it); +int ASN1_template_new(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt); +int ASN1_primitive_new(ASN1_VALUE **pval, const ASN1_ITEM *it); + +void ASN1_template_free(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt); +int ASN1_template_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_TEMPLATE *tt); +int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_ITEM *it, + int tag, int aclass, char opt, ASN1_TLC *ctx); + +int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass); +int ASN1_template_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_TEMPLATE *tt); +void ASN1_primitive_free(ASN1_VALUE **pval, const ASN1_ITEM *it); + +int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, const ASN1_ITEM *it); +int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, int utype, char *free_cont, const ASN1_ITEM *it); + +int asn1_get_choice_selector(ASN1_VALUE **pval, const ASN1_ITEM *it); +int asn1_set_choice_selector(ASN1_VALUE **pval, int value, const ASN1_ITEM *it); + +ASN1_VALUE ** asn1_get_field_ptr(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt); + +const ASN1_TEMPLATE *asn1_do_adb(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt, int nullerr); + +void asn1_refcount_set_one(ASN1_VALUE **pval, const ASN1_ITEM *it); +int asn1_refcount_dec_and_test_zero(ASN1_VALUE **pval, const ASN1_ITEM *it); + +void asn1_enc_init(ASN1_VALUE **pval, const ASN1_ITEM *it); +void asn1_enc_free(ASN1_VALUE **pval, const ASN1_ITEM *it); +int asn1_enc_restore(int *len, unsigned char **out, ASN1_VALUE **pval, const ASN1_ITEM *it); +int asn1_enc_save(ASN1_VALUE **pval, const unsigned char *in, int inlen, const ASN1_ITEM *it); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/TMessagesProj/jni/boringssl/include/openssl/base.h b/TMessagesProj/jni/boringssl/include/openssl/base.h new file mode 100644 index 00000000..8468b778 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/base.h @@ -0,0 +1,257 @@ +/* ==================================================================== + * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef OPENSSL_HEADER_BASE_H +#define OPENSSL_HEADER_BASE_H + + +/* This file should be the first included by all BoringSSL headers. */ + +#include +#include +#include + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +#if defined(__x86_64) || defined(_M_AMD64) || defined(_M_X64) +#define OPENSSL_64_BIT +#define OPENSSL_X86_64 +#elif defined(__x86) || defined(__i386) || defined(__i386__) || defined(_M_IX86) +#define OPENSSL_32_BIT +#define OPENSSL_X86 +#elif defined(__aarch64__) +#define OPENSSL_64_BIT +#define OPENSSL_AARCH64 +#elif defined(__arm) || defined(__arm__) || defined(_M_ARM) +#define OPENSSL_32_BIT +#define OPENSSL_ARM +#elif defined(__PPC64__) || defined(__powerpc64__) +#define OPENSSL_64_BIT +#elif defined(__mips__) && !defined(__LP64__) +#define OPENSSL_32_BIT +#define OPENSSL_MIPS +#elif defined(__mips__) && defined(__LP64__) +#define OPENSSL_64_BIT +#define OPENSSL_MIPS64 +#elif defined(__pnacl__) +#define OPENSSL_32_BIT +#define OPENSSL_PNACL +#else +#error "Unknown target CPU" +#endif + +#if defined(__APPLE__) +#define OPENSSL_APPLE +#endif + +#if defined(_WIN32) +#define OPENSSL_WINDOWS +#endif + +#if defined(TRUSTY) +#define OPENSSL_TRUSTY +#define OPENSSL_NO_THREADS +#endif + +#define OPENSSL_IS_BORINGSSL +#define OPENSSL_VERSION_NUMBER 0x10002000 +#define SSLEAY_VERSION_NUMBER OPENSSL_VERSION_NUMBER + +#if defined(BORINGSSL_SHARED_LIBRARY) + +#if defined(OPENSSL_WINDOWS) + +#if defined(BORINGSSL_IMPLEMENTATION) +#define OPENSSL_EXPORT __declspec(dllexport) +#else +#define OPENSSL_EXPORT __declspec(dllimport) +#endif + +#else /* defined(OPENSSL_WINDOWS) */ + +#if defined(BORINGSSL_IMPLEMENTATION) +#define OPENSSL_EXPORT __attribute__((visibility("default"))) +#else +#define OPENSSL_EXPORT +#endif + +#endif /* defined(OPENSSL_WINDOWS) */ + +#else /* defined(BORINGSSL_SHARED_LIBRARY) */ + +#define OPENSSL_EXPORT + +#endif /* defined(BORINGSSL_SHARED_LIBRARY) */ + +/* CRYPTO_THREADID is a dummy value. */ +typedef int CRYPTO_THREADID; + +typedef int ASN1_BOOLEAN; +typedef int ASN1_NULL; +typedef struct ASN1_ITEM_st ASN1_ITEM; +typedef struct asn1_object_st ASN1_OBJECT; +typedef struct asn1_pctx_st ASN1_PCTX; +typedef struct asn1_string_st ASN1_BIT_STRING; +typedef struct asn1_string_st ASN1_BMPSTRING; +typedef struct asn1_string_st ASN1_ENUMERATED; +typedef struct asn1_string_st ASN1_GENERALIZEDTIME; +typedef struct asn1_string_st ASN1_GENERALSTRING; +typedef struct asn1_string_st ASN1_IA5STRING; +typedef struct asn1_string_st ASN1_INTEGER; +typedef struct asn1_string_st ASN1_OCTET_STRING; +typedef struct asn1_string_st ASN1_PRINTABLESTRING; +typedef struct asn1_string_st ASN1_STRING; +typedef struct asn1_string_st ASN1_T61STRING; +typedef struct asn1_string_st ASN1_TIME; +typedef struct asn1_string_st ASN1_UNIVERSALSTRING; +typedef struct asn1_string_st ASN1_UTCTIME; +typedef struct asn1_string_st ASN1_UTF8STRING; +typedef struct asn1_string_st ASN1_VISIBLESTRING; + +typedef struct AUTHORITY_KEYID_st AUTHORITY_KEYID; +typedef struct DIST_POINT_st DIST_POINT; +typedef struct ISSUING_DIST_POINT_st ISSUING_DIST_POINT; +typedef struct NAME_CONSTRAINTS_st NAME_CONSTRAINTS; +typedef struct Netscape_certificate_sequence NETSCAPE_CERT_SEQUENCE; +typedef struct Netscape_spkac_st NETSCAPE_SPKAC; +typedef struct Netscape_spki_st NETSCAPE_SPKI; +typedef struct PBE2PARAM_st PBE2PARAM; +typedef struct PBEPARAM_st PBEPARAM; +typedef struct PBKDF2PARAM_st PBKDF2PARAM; +typedef struct X509_POLICY_CACHE_st X509_POLICY_CACHE; +typedef struct X509_POLICY_LEVEL_st X509_POLICY_LEVEL; +typedef struct X509_POLICY_NODE_st X509_POLICY_NODE; +typedef struct X509_POLICY_TREE_st X509_POLICY_TREE; +typedef struct X509_algor_st X509_ALGOR; +typedef struct X509_crl_info_st X509_CRL_INFO; +typedef struct X509_crl_st X509_CRL; +typedef struct X509_extension_st X509_EXTENSION; +typedef struct X509_info_st X509_INFO; +typedef struct X509_name_entry_st X509_NAME_ENTRY; +typedef struct X509_name_st X509_NAME; +typedef struct X509_objects_st X509_OBJECTS; +typedef struct X509_pubkey_st X509_PUBKEY; +typedef struct X509_req_info_st X509_REQ_INFO; +typedef struct X509_req_st X509_REQ; +typedef struct X509_sig_st X509_SIG; +typedef struct X509_val_st X509_VAL; +typedef struct bignum_ctx BN_CTX; +typedef struct bignum_st BIGNUM; +typedef struct bio_method_st BIO_METHOD; +typedef struct bio_st BIO; +typedef struct bn_gencb_st BN_GENCB; +typedef struct bn_mont_ctx_st BN_MONT_CTX; +typedef struct buf_mem_st BUF_MEM; +typedef struct cbb_st CBB; +typedef struct cbs_st CBS; +typedef struct cmac_ctx_st CMAC_CTX; +typedef struct conf_st CONF; +typedef struct conf_value_st CONF_VALUE; +typedef struct dh_method DH_METHOD; +typedef struct dh_st DH; +typedef struct dsa_method DSA_METHOD; +typedef struct dsa_st DSA; +typedef struct ec_key_st EC_KEY; +typedef struct ecdsa_method_st ECDSA_METHOD; +typedef struct ecdsa_sig_st ECDSA_SIG; +typedef struct engine_st ENGINE; +typedef struct env_md_ctx_st EVP_MD_CTX; +typedef struct env_md_st EVP_MD; +typedef struct evp_aead_st EVP_AEAD; +typedef struct evp_cipher_ctx_st EVP_CIPHER_CTX; +typedef struct evp_cipher_st EVP_CIPHER; +typedef struct evp_pkey_asn1_method_st EVP_PKEY_ASN1_METHOD; +typedef struct evp_pkey_ctx_st EVP_PKEY_CTX; +typedef struct evp_pkey_method_st EVP_PKEY_METHOD; +typedef struct evp_pkey_st EVP_PKEY; +typedef struct hmac_ctx_st HMAC_CTX; +typedef struct md4_state_st MD4_CTX; +typedef struct md5_state_st MD5_CTX; +typedef struct pkcs12_st PKCS12; +typedef struct pkcs8_priv_key_info_st PKCS8_PRIV_KEY_INFO; +typedef struct private_key_st X509_PKEY; +typedef struct rand_meth_st RAND_METHOD; +typedef struct rc4_key_st RC4_KEY; +typedef struct rsa_meth_st RSA_METHOD; +typedef struct rsa_st RSA; +typedef struct sha256_state_st SHA256_CTX; +typedef struct sha512_state_st SHA512_CTX; +typedef struct sha_state_st SHA_CTX; +typedef struct ssl_ctx_st SSL_CTX; +typedef struct ssl_custom_extension SSL_CUSTOM_EXTENSION; +typedef struct ssl_st SSL; +typedef struct st_ERR_FNS ERR_FNS; +typedef struct v3_ext_ctx X509V3_CTX; +typedef struct x509_attributes_st X509_ATTRIBUTE; +typedef struct x509_cert_aux_st X509_CERT_AUX; +typedef struct x509_cert_pair_st X509_CERT_PAIR; +typedef struct x509_cinf_st X509_CINF; +typedef struct x509_crl_method_st X509_CRL_METHOD; +typedef struct x509_revoked_st X509_REVOKED; +typedef struct x509_st X509; +typedef struct x509_store_ctx_st X509_STORE_CTX; +typedef struct x509_store_st X509_STORE; +typedef struct x509_trust_st X509_TRUST; + +typedef void *OPENSSL_BLOCK; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_BASE_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/base64.h b/TMessagesProj/jni/boringssl/include/openssl/base64.h new file mode 100644 index 00000000..7aee9907 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/base64.h @@ -0,0 +1,179 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_BASE64_H +#define OPENSSL_HEADER_BASE64_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* base64 functions. + * + * For historical reasons, these functions have the EVP_ prefix but just do + * base64 encoding and decoding. */ + + +typedef struct evp_encode_ctx_st EVP_ENCODE_CTX; + + +/* Encoding */ + +/* EVP_EncodeInit initialises |*ctx|, which is typically stack + * allocated, for an encoding operation. + * + * NOTE: The encoding operation breaks its output with newlines every + * 64 characters of output (48 characters of input). Use + * EVP_EncodeBlock to encode raw base64. */ +OPENSSL_EXPORT void EVP_EncodeInit(EVP_ENCODE_CTX *ctx); + +/* EVP_EncodeUpdate encodes |in_len| bytes from |in| and writes an encoded + * version of them to |out| and sets |*out_len| to the number of bytes written. + * Some state may be contained in |ctx| so |EVP_EncodeFinal| must be used to + * flush it before using the encoded data. */ +OPENSSL_EXPORT void EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx, uint8_t *out, + int *out_len, const uint8_t *in, + size_t in_len); + +/* EVP_EncodeFinal flushes any remaining output bytes from |ctx| to |out| and + * sets |*out_len| to the number of bytes written. */ +OPENSSL_EXPORT void EVP_EncodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out, + int *out_len); + +/* EVP_EncodeBlock encodes |src_len| bytes from |src| and writes the + * result to |dst| with a trailing NUL. It returns the number of bytes + * written, not including this trailing NUL. */ +OPENSSL_EXPORT size_t EVP_EncodeBlock(uint8_t *dst, const uint8_t *src, + size_t src_len); + +/* EVP_EncodedLength sets |*out_len| to the number of bytes that will be needed + * to call |EVP_EncodeBlock| on an input of length |len|. This includes the + * final NUL that |EVP_EncodeBlock| writes. It returns one on success or zero + * on error. */ +OPENSSL_EXPORT int EVP_EncodedLength(size_t *out_len, size_t len); + + +/* Decoding */ + +/* EVP_DecodedLength sets |*out_len| to the maximum number of bytes + * that will be needed to call |EVP_DecodeBase64| on an input of + * length |len|. */ +OPENSSL_EXPORT int EVP_DecodedLength(size_t *out_len, size_t len); + +/* EVP_DecodeBase64 decodes |in_len| bytes from base64 and writes + * |*out_len| bytes to |out|. |max_out| is the size of the output + * buffer. If it is not enough for the maximum output size, the + * operation fails. */ +OPENSSL_EXPORT int EVP_DecodeBase64(uint8_t *out, size_t *out_len, + size_t max_out, const uint8_t *in, + size_t in_len); + +/* EVP_DecodeInit initialises |*ctx|, which is typically stack allocated, for + * a decoding operation. + * + * TODO(davidben): This isn't a straight-up base64 decode either. Document + * and/or fix exactly what's going on here; maximum line length and such. */ +OPENSSL_EXPORT void EVP_DecodeInit(EVP_ENCODE_CTX *ctx); + +/* EVP_DecodeUpdate decodes |in_len| bytes from |in| and writes the decoded + * data to |out| and sets |*out_len| to the number of bytes written. Some state + * may be contained in |ctx| so |EVP_DecodeFinal| must be used to flush it + * before using the encoded data. + * + * It returns -1 on error, one if a full line of input was processed and zero + * if the line was short (i.e. it was the last line). */ +OPENSSL_EXPORT int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, uint8_t *out, + int *out_len, const uint8_t *in, + size_t in_len); + +/* EVP_DecodeFinal flushes any remaining output bytes from |ctx| to |out| and + * sets |*out_len| to the number of bytes written. It returns one on success + * and minus one on error. */ +OPENSSL_EXPORT int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out, + int *out_len); + +/* Deprecated: EVP_DecodeBlock encodes |src_len| bytes from |src| and + * writes the result to |dst|. It returns the number of bytes written + * or -1 on error. + * + * WARNING: EVP_DecodeBlock's return value does not take padding into + * account. It also strips leading whitespace and trailing + * whitespace. */ +OPENSSL_EXPORT int EVP_DecodeBlock(uint8_t *dst, const uint8_t *src, + size_t src_len); + + +struct evp_encode_ctx_st { + unsigned num; /* number saved in a partial encode/decode */ + unsigned length; /* The length is either the output line length + * (in input bytes) or the shortest input line + * length that is ok. Once decoding begins, + * the length is adjusted up each time a longer + * line is decoded */ + uint8_t enc_data[80]; /* data to encode */ + unsigned line_num; /* number read on current line */ + int expect_nl; +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_BASE64_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/bio.h b/TMessagesProj/jni/boringssl/include/openssl/bio.h new file mode 100644 index 00000000..a3c1f62e --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/bio.h @@ -0,0 +1,904 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_BIO_H +#define OPENSSL_HEADER_BIO_H + +#include + +#include /* For FILE */ + +#include /* for ERR_print_errors_fp */ +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* BIO abstracts over a file-descriptor like interface. */ + + +/* Allocation and freeing. */ + +/* BIO_new creates a new BIO with the given type and a reference count of one. + * It returns the fresh |BIO|, or NULL on error. */ +OPENSSL_EXPORT BIO *BIO_new(const BIO_METHOD *type); + +/* BIO_free decrements the reference count of |bio|. If the reference count + * drops to zero, it (optionally) calls the BIO's callback with |BIO_CB_FREE|, + * frees the ex_data and then, if the BIO has a destroy callback for the + * method, calls it. Finally it frees |bio| itself. It then repeats that for + * the next BIO in the chain, if any. + * + * It returns one on success or zero otherwise. */ +OPENSSL_EXPORT int BIO_free(BIO *bio); + +/* BIO_vfree performs the same actions as |BIO_free|, but has a void return + * value. This is provided for API-compat. + * + * TODO(fork): remove. */ +OPENSSL_EXPORT void BIO_vfree(BIO *bio); + +/* BIO_up_ref increments the reference count of |bio| and returns it. */ +OPENSSL_EXPORT BIO *BIO_up_ref(BIO *bio); + + +/* Basic I/O. */ + +/* BIO_read attempts to read |len| bytes into |data|. It returns the number of + * bytes read, zero on EOF, or a negative number on error. */ +OPENSSL_EXPORT int BIO_read(BIO *bio, void *data, int len); + +/* BIO_gets "reads a line" from |bio| and puts at most |size| bytes into |buf|. + * It returns the number of bytes read or a negative number on error. The + * phrase "reads a line" is in quotes in the previous sentence because the + * exact operation depends on the BIO's method. For example, a digest BIO will + * return the digest in response to a |BIO_gets| call. + * + * TODO(fork): audit the set of BIOs that we end up needing. If all actually + * return a line for this call, remove the warning above. */ +OPENSSL_EXPORT int BIO_gets(BIO *bio, char *buf, int size); + +/* BIO_write writes |len| bytes from |data| to BIO. It returns the number of + * bytes written or a negative number on error. */ +OPENSSL_EXPORT int BIO_write(BIO *bio, const void *data, int len); + +/* BIO_puts writes a NUL terminated string from |buf| to |bio|. It returns the + * number of bytes written or a negative number on error. */ +OPENSSL_EXPORT int BIO_puts(BIO *bio, const char *buf); + +/* BIO_flush flushes any buffered output. It returns one on success and zero + * otherwise. */ +OPENSSL_EXPORT int BIO_flush(BIO *bio); + + +/* Low-level control functions. + * + * These are generic functions for sending control requests to a BIO. In + * general one should use the wrapper functions like |BIO_get_close|. */ + +/* BIO_ctrl sends the control request |cmd| to |bio|. The |cmd| argument should + * be one of the |BIO_C_*| values. */ +OPENSSL_EXPORT long BIO_ctrl(BIO *bio, int cmd, long larg, void *parg); + +/* BIO_ptr_ctrl acts like |BIO_ctrl| but passes the address of a |void*| + * pointer as |parg| and returns the value that is written to it, or NULL if + * the control request returns <= 0. */ +OPENSSL_EXPORT char *BIO_ptr_ctrl(BIO *bp, int cmd, long larg); + +/* BIO_int_ctrl acts like |BIO_ctrl| but passes the address of a copy of |iarg| + * as |parg|. */ +OPENSSL_EXPORT long BIO_int_ctrl(BIO *bp, int cmd, long larg, int iarg); + +/* BIO_reset resets |bio| to its initial state, the precise meaning of which + * depends on the concrete type of |bio|. It returns one on success and zero + * otherwise. */ +OPENSSL_EXPORT int BIO_reset(BIO *bio); + +/* BIO_set_flags ORs |flags| with |bio->flags|. */ +OPENSSL_EXPORT void BIO_set_flags(BIO *bio, int flags); + +/* BIO_test_flags returns |bio->flags| AND |flags|. */ +OPENSSL_EXPORT int BIO_test_flags(const BIO *bio, int flags); + +/* BIO_should_read returns non-zero if |bio| encountered a temporary error + * while reading (i.e. EAGAIN), indicating that the caller should retry the + * read. */ +OPENSSL_EXPORT int BIO_should_read(const BIO *bio); + +/* BIO_should_write returns non-zero if |bio| encountered a temporary error + * while writing (i.e. EAGAIN), indicating that the caller should retry the + * write. */ +OPENSSL_EXPORT int BIO_should_write(const BIO *bio); + +/* BIO_should_retry returns non-zero if the reason that caused a failed I/O + * operation is temporary and thus the operation should be retried. Otherwise, + * it was a permanent error and it returns zero. */ +OPENSSL_EXPORT int BIO_should_retry(const BIO *bio); + +/* BIO_should_io_special returns non-zero if |bio| encountered a temporary + * error while performing a special I/O operation, indicating that the caller + * should retry. The operation that caused the error is returned by + * |BIO_get_retry_reason|. */ +OPENSSL_EXPORT int BIO_should_io_special(const BIO *bio); + +/* BIO_RR_SSL_X509_LOOKUP indicates that an SSL BIO blocked because the SSL + * library returned with SSL_ERROR_WANT_X509_LOOKUP. + * + * TODO(fork): remove. */ +#define BIO_RR_SSL_X509_LOOKUP 0x01 + +/* BIO_RR_CONNECT indicates that a connect would have blocked */ +#define BIO_RR_CONNECT 0x02 + +/* BIO_RR_ACCEPT indicates that an accept would have blocked */ +#define BIO_RR_ACCEPT 0x03 + +/* BIO_RR_SSL_CHANNEL_ID_LOOKUP indicates that the ChannelID code cannot find + * a private key for a TLS connection. */ +#define BIO_RR_SSL_CHANNEL_ID_LOOKUP 0x04 + +/* BIO_get_retry_reason returns the special I/O operation that needs to be + * retried. The return value is one of the |BIO_RR_*| values. */ +OPENSSL_EXPORT int BIO_get_retry_reason(const BIO *bio); + +/* BIO_clear_flags ANDs |bio->flags| with the bitwise-complement of |flags|. */ +OPENSSL_EXPORT void BIO_clear_flags(BIO *bio, int flags); + +/* BIO_set_retry_read sets the |BIO_FLAGS_READ| and |BIO_FLAGS_SHOULD_RETRY| + * flags on |bio|. */ +OPENSSL_EXPORT void BIO_set_retry_read(BIO *bio); + +/* BIO_set_retry_write sets the |BIO_FLAGS_WRITE| and |BIO_FLAGS_SHOULD_RETRY| + * flags on |bio|. */ +OPENSSL_EXPORT void BIO_set_retry_write(BIO *bio); + +/* BIO_get_retry_flags gets the |BIO_FLAGS_READ|, |BIO_FLAGS_WRITE|, + * |BIO_FLAGS_IO_SPECIAL| and |BIO_FLAGS_SHOULD_RETRY| flags from |bio|. */ +OPENSSL_EXPORT int BIO_get_retry_flags(BIO *bio); + +/* BIO_clear_retry_flags clears the |BIO_FLAGS_READ|, |BIO_FLAGS_WRITE|, + * |BIO_FLAGS_IO_SPECIAL| and |BIO_FLAGS_SHOULD_RETRY| flags from |bio|. */ +OPENSSL_EXPORT void BIO_clear_retry_flags(BIO *bio); + +/* BIO_method_type returns the type of |bio|, which is one of the |BIO_TYPE_*| + * values. */ +OPENSSL_EXPORT int BIO_method_type(const BIO *bio); + +/* bio_info_cb is the type of a callback function that can be called for most + * BIO operations. The |event| argument is one of |BIO_CB_*| and can be ORed + * with |BIO_CB_RETURN| if the callback is being made after the operation in + * question. In that case, |return_value| will contain the return value from + * the operation. */ +typedef long (*bio_info_cb)(BIO *bio, int event, const char *parg, int cmd, + long larg, long return_value); + +/* BIO_callback_ctrl allows the callback function to be manipulated. The |cmd| + * arg will generally be |BIO_CTRL_SET_CALLBACK| but arbitary command values + * can be interpreted by the |BIO|. */ +OPENSSL_EXPORT long BIO_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp); + +/* BIO_pending returns the number of bytes pending to be read. */ +OPENSSL_EXPORT size_t BIO_pending(const BIO *bio); + +/* BIO_ctrl_pending calls |BIO_pending| and exists only for compatibility with + * OpenSSL. */ +OPENSSL_EXPORT size_t BIO_ctrl_pending(const BIO *bio); + +/* BIO_wpending returns the number of bytes pending to be written. */ +OPENSSL_EXPORT size_t BIO_wpending(const BIO *bio); + +/* BIO_set_close sets the close flag for |bio|. The meaning of which depends on + * the type of |bio| but, for example, a memory BIO interprets the close flag + * as meaning that it owns its buffer. It returns one on success and zero + * otherwise. */ +OPENSSL_EXPORT int BIO_set_close(BIO *bio, int close_flag); + +/* BIO_set_callback sets a callback function that will be called before and + * after most operations. See the comment above |bio_info_cb|. */ +OPENSSL_EXPORT void BIO_set_callback(BIO *bio, bio_info_cb callback_func); + +/* BIO_set_callback_arg sets the opaque pointer value that can be read within a + * callback with |BIO_get_callback_arg|. */ +OPENSSL_EXPORT void BIO_set_callback_arg(BIO *bio, char *arg); + +/* BIO_get_callback_arg returns the last value of the opaque callback pointer + * set by |BIO_set_callback_arg|. */ +OPENSSL_EXPORT char *BIO_get_callback_arg(const BIO *bio); + +/* BIO_number_read returns the number of bytes that have been read from + * |bio|. */ +OPENSSL_EXPORT size_t BIO_number_read(const BIO *bio); + +/* BIO_number_written returns the number of bytes that have been written to + * |bio|. */ +OPENSSL_EXPORT size_t BIO_number_written(const BIO *bio); + + +/* Managing chains of BIOs. + * + * BIOs can be put into chains where the output of one is used as the input of + * the next etc. The most common case is a buffering BIO, which accepts and + * buffers writes until flushed into the next BIO in the chain. */ + +/* BIO_push adds |appended_bio| to the end of the chain with |bio| at the head. + * It returns |bio|. Note that |appended_bio| may be the head of a chain itself + * and thus this function can be used to join two chains. + * + * BIO_push takes ownership of the caller's reference to |appended_bio|. */ +OPENSSL_EXPORT BIO *BIO_push(BIO *bio, BIO *appended_bio); + +/* BIO_pop removes |bio| from the head of a chain and returns the next BIO in + * the chain, or NULL if there is no next BIO. + * + * The caller takes ownership of the chain's reference to |bio|. */ +OPENSSL_EXPORT BIO *BIO_pop(BIO *bio); + +/* BIO_next returns the next BIO in the chain after |bio|, or NULL if there is + * no such BIO. */ +OPENSSL_EXPORT BIO *BIO_next(BIO *bio); + +/* BIO_free_all calls |BIO_free|. + * + * TODO(fork): update callers and remove. */ +OPENSSL_EXPORT void BIO_free_all(BIO *bio); + +/* BIO_find_type walks a chain of BIOs and returns the first that matches + * |type|, which is one of the |BIO_TYPE_*| values. */ +OPENSSL_EXPORT BIO *BIO_find_type(BIO *bio, int type); + +/* BIO_copy_next_retry sets the retry flags and |retry_reason| of |bio| from + * the next BIO in the chain. */ +OPENSSL_EXPORT void BIO_copy_next_retry(BIO *bio); + + +/* Printf functions. + * + * These functions are versions of printf functions that output to a BIO rather + * than a FILE. */ +#ifdef __GNUC__ +#define __bio_h__attr__ __attribute__ +#else +#define __bio_h__attr__(x) +#endif +OPENSSL_EXPORT int BIO_printf(BIO *bio, const char *format, ...) + __bio_h__attr__((__format__(__printf__, 2, 3))); +#undef __bio_h__attr__ + + +/* Utility functions. */ + +/* BIO_indent prints min(|indent|, |max_indent|) spaces. It returns one on + * success and zero otherwise. */ +OPENSSL_EXPORT int BIO_indent(BIO *bio, unsigned indent, unsigned max_indent); + +/* BIO_hexdump writes a hex dump of |data| to |bio|. Each line will be indented + * by |indent| spaces. */ +OPENSSL_EXPORT int BIO_hexdump(BIO *bio, const uint8_t *data, size_t len, + unsigned indent); + +/* BIO_print_errors prints the current contents of the error stack to |bio| + * using human readable strings where possible. */ +OPENSSL_EXPORT void BIO_print_errors(BIO *bio); + +/* BIO_read_asn1 reads a single ASN.1 object from |bio|. If successful it sets + * |*out| to be an allocated buffer (that should be freed with |OPENSSL_free|), + * |*out_size| to the length, in bytes, of that buffer and returns one. + * Otherwise it returns zero. + * + * If the length of the object is greater than |max_len| or 2^32 then the + * function will fail. Long-form tags are not supported. If the length of the + * object is indefinite the full contents of |bio| are read, unless it would be + * greater than |max_len|, in which case the function fails. + * + * If the function fails then some unknown amount of data may have been read + * from |bio|. */ +OPENSSL_EXPORT int BIO_read_asn1(BIO *bio, uint8_t **out, size_t *out_len, + size_t max_len); + + +/* Memory BIOs. + * + * Memory BIOs can be used as a read-only source (with |BIO_new_mem_buf|) or a + * writable sink (with |BIO_new|, |BIO_s_mem| and |BIO_get_mem_buf|). Data + * written to a writable, memory BIO can be recalled by reading from it. + * + * Calling |BIO_reset| on a read-only BIO resets it to the original contents. + * On a writable BIO, it clears any data. + * + * If the close flag is set to |BIO_NOCLOSE| (not the default) then the + * underlying |BUF_MEM| will not be freed when the |BIO| is freed. + * + * Memory BIOs support |BIO_gets| and |BIO_puts|. + * + * |BIO_eof| is true if no data is in the BIO. + * + * |BIO_ctrl_pending| returns the number of bytes currently stored. */ + +/* BIO_s_mem returns a |BIO_METHOD| that uses a in-memory buffer. */ +OPENSSL_EXPORT const BIO_METHOD *BIO_s_mem(void); + +/* BIO_new_mem_buf creates BIO that reads and writes from |len| bytes at |buf|. + * It does not take ownership of |buf|. It returns the BIO or NULL on error. + * + * If |len| is negative, then |buf| is treated as a NUL-terminated string, but + * don't depend on this in new code. */ +OPENSSL_EXPORT BIO *BIO_new_mem_buf(void *buf, int len); + +/* BIO_mem_contents sets |*out_contents| to point to the current contents of + * |bio| and |*out_len| to contain the length of that data. It returns one on + * success and zero otherwise. */ +OPENSSL_EXPORT int BIO_mem_contents(const BIO *bio, + const uint8_t **out_contents, + size_t *out_len); + +/* BIO_get_mem_data sets |*contents| to point to the current contents of |bio| + * and returns the length of the data. + * + * WARNING: don't use this, use |BIO_mem_contents|. A return value of zero from + * this function can mean either that it failed or that the memory buffer is + * empty. */ +OPENSSL_EXPORT long BIO_get_mem_data(BIO *bio, char **contents); + +/* BIO_get_mem_ptr sets |*out| to a BUF_MEM containing the current contents of + * |bio|. It returns one on success or zero on error. */ +OPENSSL_EXPORT int BIO_get_mem_ptr(BIO *bio, BUF_MEM **out); + +/* BIO_set_mem_buf sets |b| as the contents of |bio|. If |take_ownership| is + * non-zero, then |b| will be freed when |bio| is closed. Returns one on + * success or zero otherwise. */ +OPENSSL_EXPORT int BIO_set_mem_buf(BIO *bio, BUF_MEM *b, int take_ownership); + +/* BIO_set_mem_eof_return sets the value that will be returned from reading + * |bio| when empty. If |eof_value| is zero then an empty memory BIO will + * return EOF (that is it will return zero and |BIO_should_retry| will be + * false). If |eof_value| is non zero then it will return |eof_value| when it + * is empty and it will set the read retry flag (that is |BIO_read_retry| is + * true). To avoid ambiguity with a normal positive return value, |eof_value| + * should be set to a negative value, typically -1. + * + * For a read-only BIO, the default is zero (EOF). For a writable BIO, the + * default is -1 so that additional data can be written once exhausted. */ +OPENSSL_EXPORT int BIO_set_mem_eof_return(BIO *bio, int eof_value); + + +/* File descriptor BIOs. + * + * File descriptor BIOs are wrappers around the system's |read| and |write| + * functions. If the close flag is set then then |close| is called on the + * underlying file descriptor when the BIO is freed. + * + * |BIO_reset| attempts to seek the file pointer to the start of file using + * |lseek|. + * + * |BIO_seek| sets the file pointer to position |off| from start of file using + * |lseek|. + * + * |BIO_tell| returns the current file position. */ + +/* BIO_s_fd returns a |BIO_METHOD| for file descriptor fds. */ +OPENSSL_EXPORT const BIO_METHOD *BIO_s_fd(void); + +/* BIO_new_fd creates a new file descriptor BIO wrapping |fd|. If |close_flag| + * is non-zero, then |fd| will be closed when the BIO is. */ +OPENSSL_EXPORT BIO *BIO_new_fd(int fd, int close_flag); + +/* BIO_set_fd sets the file descriptor of |bio| to |fd|. If |close_flag| is + * non-zero then |fd| will be closed when |bio| is. It returns one on success + * or zero on error. */ +OPENSSL_EXPORT int BIO_set_fd(BIO *bio, int fd, int close_flag); + +/* BIO_get_fd sets |*out_fd| to the file descriptor currently in use by |bio|. + * It returns one on success and zero on error. */ +OPENSSL_EXPORT int BIO_get_fd(BIO *bio, int *out_fd); + + +/* File BIOs. + * + * File BIOs are wrappers around a C |FILE| object. + * + * |BIO_flush| on a file BIO calls |fflush| on the wrapped stream. + * + * |BIO_reset| attempts to seek the file pointer to the start of file using + * |fseek|. + * + * |BIO_seek| sets the file pointer to the given position from the start of + * file using |fseek|. + * + * |BIO_eof| calls |feof|. + * + * Setting the close flag causes |fclose| to be called on the stream when the + * BIO is freed. */ + +/* BIO_s_file returns a BIO_METHOD that wraps a |FILE|. */ +OPENSSL_EXPORT const BIO_METHOD *BIO_s_file(void); + +/* BIO_new_file creates a file BIO by opening |filename| with the given mode. + * See the |fopen| manual page for details of the mode argument. */ +OPENSSL_EXPORT BIO *BIO_new_file(const char *filename, const char *mode); + +/* BIO_new_fp creates a new file BIO that wraps the given |FILE|. If + * |close_flag| is |BIO_CLOSE|, then |fclose| will be called on |stream| when + * the BIO is closed. */ +OPENSSL_EXPORT BIO *BIO_new_fp(FILE *stream, int close_flag); + +/* BIO_get_fp sets |*out_file| to the current |FILE| for |bio|. It returns one + * on success and zero otherwise. */ +OPENSSL_EXPORT int BIO_get_fp(BIO *bio, FILE **out_file); + +/* BIO_set_fp sets the |FILE| for |bio|. If |close_flag| is |BIO_CLOSE| then + * |fclose| will be called on |file| when |bio| is closed. It returns one on + * sucess and zero otherwise. */ +OPENSSL_EXPORT int BIO_set_fp(BIO *bio, FILE *file, int close_flag); + +/* BIO_read_filename opens |filename| for reading and sets the result as the + * |FILE| for |bio|. It returns one on success and zero otherwise. The |FILE| + * will be closed when |bio| is freed. */ +OPENSSL_EXPORT int BIO_read_filename(BIO *bio, const char *filename); + +/* BIO_write_filename opens |filename| for writing and sets the result as the + * |FILE| for |bio|. It returns one on success and zero otherwise. The |FILE| + * will be closed when |bio| is freed. */ +OPENSSL_EXPORT int BIO_write_filename(BIO *bio, const char *filename); + +/* BIO_append_filename opens |filename| for appending and sets the result as + * the |FILE| for |bio|. It returns one on success and zero otherwise. The + * |FILE| will be closed when |bio| is freed. */ +OPENSSL_EXPORT int BIO_append_filename(BIO *bio, const char *filename); + +/* BIO_rw_filename opens |filename| for reading and writing and sets the result + * as the |FILE| for |bio|. It returns one on success and zero otherwise. The + * |FILE| will be closed when |bio| is freed. */ +OPENSSL_EXPORT int BIO_rw_filename(BIO *bio, const char *filename); + + +/* Buffer BIOs. + * + * Buffer BIOs are a filter-type BIO, i.e. they are designed to be used in a + * chain of BIOs. They provide buffering to reduce the number of operations on + * the underlying BIOs. */ + +OPENSSL_EXPORT const BIO_METHOD *BIO_f_buffer(void); + +/* BIO_set_read_buffer_size sets the size, in bytes, of the read buffer and + * clears it. It returns one on success and zero on failure. */ +OPENSSL_EXPORT int BIO_set_read_buffer_size(BIO *bio, int buffer_size); + +/* BIO_set_write_buffer_size sets the size, in bytes, of the write buffer and + * clears it. It returns one on success and zero on failure. */ +OPENSSL_EXPORT int BIO_set_write_buffer_size(BIO *bio, int buffer_size); + + +/* Socket BIOs. */ + +OPENSSL_EXPORT const BIO_METHOD *BIO_s_socket(void); + +/* BIO_new_socket allocates and initialises a fresh BIO which will read and + * write to the socket |fd|. If |close_flag| is |BIO_CLOSE| then closing the + * BIO will close |fd|. It returns the fresh |BIO| or NULL on error. */ +OPENSSL_EXPORT BIO *BIO_new_socket(int fd, int close_flag); + + +/* Connect BIOs. + * + * A connection BIO creates a network connection and transfers data over the + * resulting socket. */ + +OPENSSL_EXPORT const BIO_METHOD *BIO_s_connect(void); + +/* BIO_new_connect returns a BIO that connects to the given hostname and port. + * The |host_and_optional_port| argument should be of the form + * "www.example.com" or "www.example.com:443". If the port is omitted, it must + * be provided with |BIO_set_conn_port|. + * + * It returns the new BIO on success, or NULL on error. */ +OPENSSL_EXPORT BIO *BIO_new_connect(const char *host_and_optional_port); + +/* BIO_set_conn_hostname sets |host_and_optional_port| as the hostname and + * optional port that |bio| will connect to. If the port is omitted, it must be + * provided with |BIO_set_conn_port|. + * + * It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int BIO_set_conn_hostname(BIO *bio, + const char *host_and_optional_port); + +/* BIO_set_conn_port sets |port_str| as the port or service name that |bio| + * will connect to. It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int BIO_set_conn_port(BIO *bio, const char *port_str); + +/* BIO_set_nbio sets whether |bio| will use non-blocking I/O operations. It + * returns one on success and zero otherwise. */ +OPENSSL_EXPORT int BIO_set_nbio(BIO *bio, int on); + + +/* Datagram BIOs. + * + * TODO(fork): not implemented. */ + +#define BIO_CTRL_DGRAM_QUERY_MTU 40 /* as kernel for current MTU */ + +#define BIO_CTRL_DGRAM_SET_MTU 42 /* set cached value for MTU. want to use + this if asking the kernel fails */ + +#define BIO_CTRL_DGRAM_MTU_EXCEEDED 43 /* check whether the MTU was exceed in + the previous write operation. */ + +#define BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT \ + 45 /* Next DTLS handshake timeout to adjust socket timeouts */ + +#define BIO_CTRL_DGRAM_GET_PEER 46 + +#define BIO_CTRL_DGRAM_GET_FALLBACK_MTU 47 + + +/* BIO Pairs. + * + * BIO pairs provide a "loopback" like system: a pair of BIOs where data + * written to one can be read from the other and vice versa. */ + +/* BIO_new_bio_pair sets |*out1| and |*out2| to two freshly created BIOs where + * data written to one can be read from the other and vice versa. The + * |writebuf1| argument gives the size of the buffer used in |*out1| and + * |writebuf2| for |*out2|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int BIO_new_bio_pair(BIO **out1, size_t writebuf1, BIO **out2, + size_t writebuf2); + +/* BIO_new_bio_pair_external_buf is the same as |BIO_new_bio_pair| with the + * difference that the caller keeps ownership of the write buffers + * |ext_writebuf1_len| and |ext_writebuf2_len|. This is useful when using zero + * copy API for read and write operations, in cases where the buffers need to + * outlive the BIO pairs. It returns one on success and zero on error. */ +OPENSSL_EXPORT int BIO_new_bio_pair_external_buf(BIO** bio1_p, + size_t writebuf1_len, + uint8_t* ext_writebuf1, + BIO** bio2_p, + size_t writebuf2_len, + uint8_t* ext_writebuf2); + +/* BIO_ctrl_get_read_request returns the number of bytes that the other side of + * |bio| tried (unsuccessfully) to read. */ +OPENSSL_EXPORT size_t BIO_ctrl_get_read_request(BIO *bio); + +/* BIO_ctrl_get_write_guarantee returns the number of bytes that |bio| (which + * must have been returned by |BIO_new_bio_pair|) will accept on the next + * |BIO_write| call. */ +OPENSSL_EXPORT size_t BIO_ctrl_get_write_guarantee(BIO *bio); + +/* BIO_shutdown_wr marks |bio| as closed, from the point of view of the other + * side of the pair. Future |BIO_write| calls on |bio| will fail. It returns + * one on success and zero otherwise. */ +OPENSSL_EXPORT int BIO_shutdown_wr(BIO *bio); + + +/* Zero copy versions of BIO_read and BIO_write for BIO pairs. */ + +/* BIO_zero_copy_get_read_buf initiates a zero copy read operation. + * |out_read_buf| is set to the internal read buffer, and |out_buf_offset| is + * set to the current read position of |out_read_buf|. The number of bytes + * available for read from |out_read_buf| + |out_buf_offset| is returned in + * |out_available_bytes|. Note that this function might report fewer bytes + * available than |BIO_pending|, if the internal ring buffer is wrapped. It + * returns one on success. In case of error it returns zero and pushes to the + * error stack. + * + * The zero copy read operation is completed by calling + * |BIO_zero_copy_get_read_buf_done|. Neither |BIO_zero_copy_get_read_buf| nor + * any other I/O read operation may be called while a zero copy read operation + * is active. */ +OPENSSL_EXPORT int BIO_zero_copy_get_read_buf(BIO* bio, + uint8_t** out_read_buf, + size_t* out_buf_offset, + size_t* out_available_bytes); + +/* BIO_zero_copy_get_read_buf_done must be called after reading from a BIO using + * |BIO_zero_copy_get_read_buf| to finish the read operation. The |bytes_read| + * argument is the number of bytes read. + * + * It returns one on success. In case of error it returns zero and pushes to the + * error stack. */ +OPENSSL_EXPORT int BIO_zero_copy_get_read_buf_done(BIO* bio, size_t bytes_read); + +/* BIO_zero_copy_get_write_buf initiates a zero copy write operation. + * |out_write_buf| is set to to the internal write buffer, and |out_buf_offset| + * is set to the current write position of |out_write_buf|. + * The number of bytes available for write from |out_write_buf| + + * |out_buf_offset| is returned in |out_available_bytes|. Note that this + * function might report fewer bytes available than + * |BIO_ctrl_get_write_guarantee|, if the internal buffer is wrapped. It returns + * one on success. In case of error it returns zero and pushes to the error + * stack. + * + * The zero copy write operation is completed by calling + * |BIO_zero_copy_get_write_buf_done|. Neither |BIO_zero_copy_get_write_buf| + * nor any other I/O write operation may be called while a zero copy write + * operation is active. */ +OPENSSL_EXPORT int BIO_zero_copy_get_write_buf(BIO* bio, + uint8_t** out_write_buf, + size_t* out_buf_offset, + size_t* out_available_bytes); + +/* BIO_zero_copy_get_write_buf_done must be called after writing to a BIO using + * |BIO_zero_copy_get_write_buf| to finish the write operation. The + * |bytes_written| argument gives the number of bytes written. + * + * It returns one on success. In case of error it returns zero and pushes to the + * error stack. */ +OPENSSL_EXPORT int BIO_zero_copy_get_write_buf_done(BIO* bio, + size_t bytes_written); + + +/* Deprecated functions. */ + +/* ERR_print_errors is an alias for |BIO_print_errors|. */ +OPENSSL_EXPORT void ERR_print_errors(BIO *bio); + + +/* BIO_NOCLOSE and |BIO_CLOSE| can be used as symbolic arguments when a "close + * flag" is passed to a BIO function. */ +#define BIO_NOCLOSE 0 +#define BIO_CLOSE 1 + +/* These are passed to the BIO callback */ +#define BIO_CB_FREE 0x01 +#define BIO_CB_READ 0x02 +#define BIO_CB_WRITE 0x03 +#define BIO_CB_PUTS 0x04 +#define BIO_CB_GETS 0x05 +#define BIO_CB_CTRL 0x06 + +/* The callback is called before and after the underling operation, + * The BIO_CB_RETURN flag indicates if it is after the call */ +#define BIO_CB_RETURN 0x80 + +/* These are values of the |cmd| argument to |BIO_ctrl|. */ +#define BIO_CTRL_RESET 1 /* opt - rewind/zero etc */ +#define BIO_CTRL_EOF 2 /* opt - are we at the eof */ +#define BIO_CTRL_INFO 3 /* opt - extra tit-bits */ +#define BIO_CTRL_SET 4 /* man - set the 'IO' type */ +#define BIO_CTRL_GET 5 /* man - get the 'IO' type */ +#define BIO_CTRL_GET_CLOSE 8 /* man - set the 'close' on free */ +#define BIO_CTRL_SET_CLOSE 9 /* man - set the 'close' on free */ +#define BIO_CTRL_PENDING 10 /* opt - is their more data buffered */ +#define BIO_CTRL_FLUSH 11 /* opt - 'flush' buffered output */ +#define BIO_CTRL_WPENDING 13 /* opt - number of bytes still to write */ +/* callback is int cb(BIO *bio,state,ret); */ +#define BIO_CTRL_SET_CALLBACK 14 /* opt - set callback function */ +#define BIO_CTRL_GET_CALLBACK 15 /* opt - set callback function */ +#define BIO_CTRL_SET_FILENAME 30 /* BIO_s_file special */ + + +/* Android compatibility section. + * + * A previous version of BoringSSL used in Android renamed ERR_print_errors_fp + * to BIO_print_errors_fp. It has subsequently been renamed back to + * ERR_print_errors_fp. */ +#define BIO_print_errors_fp ERR_print_errors_fp + + +/* Deprecated functions. */ + +/* Returns a filter |BIO| that base64-encodes data written into it, and decodes + * data read from it. |BIO_gets| is not supported. Call |BIO_flush| when done + * writing, to signal that no more data are to be encoded. The flag + * |BIO_FLAGS_BASE64_NO_NL| may be set to encode all the data on one line. */ +OPENSSL_EXPORT const BIO_METHOD *BIO_f_base64(void); + + +/* Private functions */ + +#define BIO_FLAGS_READ 0x01 +#define BIO_FLAGS_WRITE 0x02 +#define BIO_FLAGS_IO_SPECIAL 0x04 +#define BIO_FLAGS_RWS (BIO_FLAGS_READ | BIO_FLAGS_WRITE | BIO_FLAGS_IO_SPECIAL) +#define BIO_FLAGS_SHOULD_RETRY 0x08 +#define BIO_FLAGS_BASE64_NO_NL 0x100 +/* This is used with memory BIOs: it means we shouldn't free up or change the + * data in any way. */ +#define BIO_FLAGS_MEM_RDONLY 0x200 + +/* These are the 'types' of BIOs */ +#define BIO_TYPE_NONE 0 +#define BIO_TYPE_MEM (1 | 0x0400) +#define BIO_TYPE_FILE (2 | 0x0400) +#define BIO_TYPE_FD (4 | 0x0400 | 0x0100) +#define BIO_TYPE_SOCKET (5 | 0x0400 | 0x0100) +#define BIO_TYPE_NULL (6 | 0x0400) +#define BIO_TYPE_SSL (7 | 0x0200) +#define BIO_TYPE_MD (8 | 0x0200) /* passive filter */ +#define BIO_TYPE_BUFFER (9 | 0x0200) /* filter */ +#define BIO_TYPE_CIPHER (10 | 0x0200) /* filter */ +#define BIO_TYPE_BASE64 (11 | 0x0200) /* filter */ +#define BIO_TYPE_CONNECT (12 | 0x0400 | 0x0100) /* socket - connect */ +#define BIO_TYPE_ACCEPT (13 | 0x0400 | 0x0100) /* socket for accept */ +#define BIO_TYPE_PROXY_CLIENT (14 | 0x0200) /* client proxy BIO */ +#define BIO_TYPE_PROXY_SERVER (15 | 0x0200) /* server proxy BIO */ +#define BIO_TYPE_NBIO_TEST (16 | 0x0200) /* server proxy BIO */ +#define BIO_TYPE_NULL_FILTER (17 | 0x0200) +#define BIO_TYPE_BER (18 | 0x0200) /* BER -> bin filter */ +#define BIO_TYPE_BIO (19 | 0x0400) /* (half a) BIO pair */ +#define BIO_TYPE_LINEBUFFER (20 | 0x0200) /* filter */ +#define BIO_TYPE_DGRAM (21 | 0x0400 | 0x0100) +#define BIO_TYPE_ASN1 (22 | 0x0200) /* filter */ +#define BIO_TYPE_COMP (23 | 0x0200) /* filter */ + +#define BIO_TYPE_DESCRIPTOR 0x0100 /* socket, fd, connect or accept */ +#define BIO_TYPE_FILTER 0x0200 +#define BIO_TYPE_SOURCE_SINK 0x0400 + +struct bio_method_st { + int type; + const char *name; + int (*bwrite)(BIO *, const char *, int); + int (*bread)(BIO *, char *, int); + /* TODO(fork): remove bputs. */ + int (*bputs)(BIO *, const char *); + int (*bgets)(BIO *, char *, int); + long (*ctrl)(BIO *, int, long, void *); + int (*create)(BIO *); + int (*destroy)(BIO *); + long (*callback_ctrl)(BIO *, int, bio_info_cb); +}; + +struct bio_st { + const BIO_METHOD *method; + /* bio, mode, argp, argi, argl, ret */ + long (*callback)(struct bio_st *, int, const char *, int, long, long); + char *cb_arg; /* first argument for the callback */ + + /* init is non-zero if this |BIO| has been initialised. */ + int init; + /* shutdown is often used by specific |BIO_METHOD|s to determine whether + * they own some underlying resource. This flag can often by controlled by + * |BIO_set_close|. For example, whether an fd BIO closes the underlying fd + * when it, itself, is closed. */ + int shutdown; + int flags; + int retry_reason; + /* num is a BIO-specific value. For example, in fd BIOs it's used to store a + * file descriptor. */ + int num; + CRYPTO_refcount_t references; + void *ptr; + /* next_bio points to the next |BIO| in a chain. This |BIO| owns a reference + * to |next_bio|. */ + struct bio_st *next_bio; /* used by filter BIOs */ + size_t num_read, num_write; +}; + +#define BIO_C_SET_CONNECT 100 +#define BIO_C_DO_STATE_MACHINE 101 +#define BIO_C_SET_NBIO 102 +#define BIO_C_SET_PROXY_PARAM 103 +#define BIO_C_SET_FD 104 +#define BIO_C_GET_FD 105 +#define BIO_C_SET_FILE_PTR 106 +#define BIO_C_GET_FILE_PTR 107 +#define BIO_C_SET_FILENAME 108 +#define BIO_C_SET_SSL 109 +#define BIO_C_GET_SSL 110 +#define BIO_C_SET_MD 111 +#define BIO_C_GET_MD 112 +#define BIO_C_GET_CIPHER_STATUS 113 +#define BIO_C_SET_BUF_MEM 114 +#define BIO_C_GET_BUF_MEM_PTR 115 +#define BIO_C_GET_BUFF_NUM_LINES 116 +#define BIO_C_SET_BUFF_SIZE 117 +#define BIO_C_SET_ACCEPT 118 +#define BIO_C_SSL_MODE 119 +#define BIO_C_GET_MD_CTX 120 +#define BIO_C_GET_PROXY_PARAM 121 +#define BIO_C_SET_BUFF_READ_DATA 122 /* data to read first */ +#define BIO_C_GET_CONNECT 123 +#define BIO_C_GET_ACCEPT 124 +#define BIO_C_SET_SSL_RENEGOTIATE_BYTES 125 +#define BIO_C_GET_SSL_NUM_RENEGOTIATES 126 +#define BIO_C_SET_SSL_RENEGOTIATE_TIMEOUT 127 +#define BIO_C_FILE_SEEK 128 +#define BIO_C_GET_CIPHER_CTX 129 +#define BIO_C_SET_BUF_MEM_EOF_RETURN 130/*return end of input value*/ +#define BIO_C_SET_BIND_MODE 131 +#define BIO_C_GET_BIND_MODE 132 +#define BIO_C_FILE_TELL 133 +#define BIO_C_GET_SOCKS 134 +#define BIO_C_SET_SOCKS 135 + +#define BIO_C_SET_WRITE_BUF_SIZE 136/* for BIO_s_bio */ +#define BIO_C_GET_WRITE_BUF_SIZE 137 +#define BIO_C_GET_WRITE_GUARANTEE 140 +#define BIO_C_GET_READ_REQUEST 141 +#define BIO_C_SHUTDOWN_WR 142 +#define BIO_C_NREAD0 143 +#define BIO_C_NREAD 144 +#define BIO_C_NWRITE0 145 +#define BIO_C_NWRITE 146 +#define BIO_C_RESET_READ_REQUEST 147 +#define BIO_C_SET_MD_CTX 148 + +#define BIO_C_SET_PREFIX 149 +#define BIO_C_GET_PREFIX 150 +#define BIO_C_SET_SUFFIX 151 +#define BIO_C_GET_SUFFIX 152 + +#define BIO_C_SET_EX_ARG 153 +#define BIO_C_GET_EX_ARG 154 + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define BIO_R_BAD_FOPEN_MODE 100 +#define BIO_R_BROKEN_PIPE 101 +#define BIO_R_CONNECT_ERROR 102 +#define BIO_R_ERROR_SETTING_NBIO 103 +#define BIO_R_INVALID_ARGUMENT 104 +#define BIO_R_IN_USE 105 +#define BIO_R_KEEPALIVE 106 +#define BIO_R_NBIO_CONNECT_ERROR 107 +#define BIO_R_NO_HOSTNAME_SPECIFIED 108 +#define BIO_R_NO_PORT_SPECIFIED 109 +#define BIO_R_NO_SUCH_FILE 110 +#define BIO_R_NULL_PARAMETER 111 +#define BIO_R_SYS_LIB 112 +#define BIO_R_UNABLE_TO_CREATE_SOCKET 113 +#define BIO_R_UNINITIALIZED 114 +#define BIO_R_UNSUPPORTED_METHOD 115 +#define BIO_R_WRITE_TO_READ_ONLY_BIO 116 + +#endif /* OPENSSL_HEADER_BIO_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/blowfish.h b/TMessagesProj/jni/boringssl/include/openssl/blowfish.h new file mode 100644 index 00000000..fa60d533 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/blowfish.h @@ -0,0 +1,93 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_BLOWFISH_H +#define OPENSSL_HEADER_BLOWFISH_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +#define BF_ENCRYPT 1 +#define BF_DECRYPT 0 + +#define BF_ROUNDS 16 +#define BF_BLOCK 8 + +typedef struct bf_key_st { + uint32_t P[BF_ROUNDS + 2]; + uint32_t S[4 * 256]; +} BF_KEY; + +OPENSSL_EXPORT void BF_set_key(BF_KEY *key, size_t len, const uint8_t *data); +OPENSSL_EXPORT void BF_encrypt(uint32_t *data, const BF_KEY *key); +OPENSSL_EXPORT void BF_decrypt(uint32_t *data, const BF_KEY *key); + +OPENSSL_EXPORT void BF_ecb_encrypt(const uint8_t *in, uint8_t *out, + const BF_KEY *key, int enc); +OPENSSL_EXPORT void BF_cbc_encrypt(const uint8_t *in, uint8_t *out, long length, + const BF_KEY *schedule, uint8_t *ivec, + int enc); + + +#ifdef __cplusplus +} +#endif + +#endif /* OPENSSL_HEADER_BLOWFISH_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/bn.h b/TMessagesProj/jni/boringssl/include/openssl/bn.h new file mode 100644 index 00000000..f84aba5d --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/bn.h @@ -0,0 +1,862 @@ +/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the Eric Young open source + * license provided above. + * + * The binary polynomial arithmetic software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems + * Laboratories. */ + +#ifndef OPENSSL_HEADER_BN_H +#define OPENSSL_HEADER_BN_H + +#include +#include + +#include /* for PRIu64 and friends */ +#include /* for FILE* */ + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* BN provides support for working with arbitary sized integers. For example, + * although the largest integer supported by the compiler might be 64 bits, BN + * will allow you to work with numbers until you run out of memory. */ + + +/* BN_ULONG is the native word size when working with big integers. + * + * Note: on some platforms, inttypes.h does not define print format macros in + * C++ unless |__STDC_FORMAT_MACROS| defined. As this is a public header, bn.h + * does not define |__STDC_FORMAT_MACROS| itself. C++ source files which use the + * FMT macros must define it externally. */ +#if defined(OPENSSL_64_BIT) +#define BN_ULONG uint64_t +#define BN_BITS2 64 +#define BN_DEC_FMT1 "%" PRIu64 +#define BN_DEC_FMT2 "%019" PRIu64 +#define BN_HEX_FMT1 "%" PRIx64 +#elif defined(OPENSSL_32_BIT) +#define BN_ULONG uint32_t +#define BN_BITS2 32 +#define BN_DEC_FMT1 "%" PRIu32 +#define BN_DEC_FMT2 "%09" PRIu32 +#define BN_HEX_FMT1 "%" PRIx32 +#else +#error "Must define either OPENSSL_32_BIT or OPENSSL_64_BIT" +#endif + + +/* Allocation and freeing. */ + +/* BN_new creates a new, allocated BIGNUM and initialises it. */ +OPENSSL_EXPORT BIGNUM *BN_new(void); + +/* BN_init initialises a stack allocated |BIGNUM|. */ +OPENSSL_EXPORT void BN_init(BIGNUM *bn); + +/* BN_free frees the data referenced by |bn| and, if |bn| was originally + * allocated on the heap, frees |bn| also. */ +OPENSSL_EXPORT void BN_free(BIGNUM *bn); + +/* BN_clear_free erases and frees the data referenced by |bn| and, if |bn| was + * originally allocated on the heap, frees |bn| also. */ +OPENSSL_EXPORT void BN_clear_free(BIGNUM *bn); + +/* BN_dup allocates a new BIGNUM and sets it equal to |src|. It returns the + * allocated BIGNUM on success or NULL otherwise. */ +OPENSSL_EXPORT BIGNUM *BN_dup(const BIGNUM *src); + +/* BN_copy sets |dest| equal to |src| and returns |dest| or NULL on allocation + * failure. */ +OPENSSL_EXPORT BIGNUM *BN_copy(BIGNUM *dest, const BIGNUM *src); + +/* BN_clear sets |bn| to zero and erases the old data. */ +OPENSSL_EXPORT void BN_clear(BIGNUM *bn); + +/* BN_value_one returns a static BIGNUM with value 1. */ +OPENSSL_EXPORT const BIGNUM *BN_value_one(void); + +/* BN_with_flags initialises a stack allocated |BIGNUM| with pointers to the + * contents of |in| but with |flags| ORed into the flags field. + * + * Note: the two BIGNUMs share state and so |out| should /not/ be passed to + * |BN_free|. */ +OPENSSL_EXPORT void BN_with_flags(BIGNUM *out, const BIGNUM *in, int flags); + + +/* Basic functions. */ + +/* BN_num_bits returns the minimum number of bits needed to represent the + * absolute value of |bn|. */ +OPENSSL_EXPORT unsigned BN_num_bits(const BIGNUM *bn); + +/* BN_num_bytes returns the minimum number of bytes needed to represent the + * absolute value of |bn|. */ +OPENSSL_EXPORT unsigned BN_num_bytes(const BIGNUM *bn); + +/* BN_zero sets |bn| to zero. */ +OPENSSL_EXPORT void BN_zero(BIGNUM *bn); + +/* BN_one sets |bn| to one. It returns one on success or zero on allocation + * failure. */ +OPENSSL_EXPORT int BN_one(BIGNUM *bn); + +/* BN_set_word sets |bn| to |value|. It returns one on success or zero on + * allocation failure. */ +OPENSSL_EXPORT int BN_set_word(BIGNUM *bn, BN_ULONG value); + +/* BN_set_negative sets the sign of |bn|. */ +OPENSSL_EXPORT void BN_set_negative(BIGNUM *bn, int sign); + +/* BN_is_negative returns one if |bn| is negative and zero otherwise. */ +OPENSSL_EXPORT int BN_is_negative(const BIGNUM *bn); + +/* BN_get_flags returns |bn->flags| & |flags|. */ +OPENSSL_EXPORT int BN_get_flags(const BIGNUM *bn, int flags); + +/* BN_set_flags sets |flags| on |bn|. */ +OPENSSL_EXPORT void BN_set_flags(BIGNUM *bn, int flags); + + +/* Conversion functions. */ + +/* BN_bin2bn sets |*ret| to the value of |len| bytes from |in|, interpreted as + * a big-endian number, and returns |ret|. If |ret| is NULL then a fresh + * |BIGNUM| is allocated and returned. It returns NULL on allocation + * failure. */ +OPENSSL_EXPORT BIGNUM *BN_bin2bn(const uint8_t *in, size_t len, BIGNUM *ret); + +/* BN_bn2bin serialises the absolute value of |in| to |out| as a big-endian + * integer, which must have |BN_num_bytes| of space available. It returns the + * number of bytes written. */ +OPENSSL_EXPORT size_t BN_bn2bin(const BIGNUM *in, uint8_t *out); + +/* BN_bn2bin_padded serialises the absolute value of |in| to |out| as a + * big-endian integer. The integer is padded with leading zeros up to size + * |len|. If |len| is smaller than |BN_num_bytes|, the function fails and + * returns 0. Otherwise, it returns 1. */ +OPENSSL_EXPORT int BN_bn2bin_padded(uint8_t *out, size_t len, const BIGNUM *in); + +/* BN_bn2hex returns an allocated string that contains a NUL-terminated, hex + * representation of |bn|. If |bn| is negative, the first char in the resulting + * string will be '-'. Returns NULL on allocation failure. */ +OPENSSL_EXPORT char *BN_bn2hex(const BIGNUM *bn); + +/* BN_hex2bn parses the leading hex number from |in|, which may be proceeded by + * a '-' to indicate a negative number and may contain trailing, non-hex data. + * If |outp| is not NULL, it constructs a BIGNUM equal to the hex number and + * stores it in |*outp|. If |*outp| is NULL then it allocates a new BIGNUM and + * updates |*outp|. It returns the number of bytes of |in| processed or zero on + * error. */ +OPENSSL_EXPORT int BN_hex2bn(BIGNUM **outp, const char *in); + +/* BN_bn2dec returns an allocated string that contains a NUL-terminated, + * decimal representation of |bn|. If |bn| is negative, the first char in the + * resulting string will be '-'. Returns NULL on allocation failure. */ +OPENSSL_EXPORT char *BN_bn2dec(const BIGNUM *a); + +/* BN_dec2bn parses the leading decimal number from |in|, which may be + * proceeded by a '-' to indicate a negative number and may contain trailing, + * non-decimal data. If |outp| is not NULL, it constructs a BIGNUM equal to the + * decimal number and stores it in |*outp|. If |*outp| is NULL then it + * allocates a new BIGNUM and updates |*outp|. It returns the number of bytes + * of |in| processed or zero on error. */ +OPENSSL_EXPORT int BN_dec2bn(BIGNUM **outp, const char *in); + +/* BN_asc2bn acts like |BN_dec2bn| or |BN_hex2bn| depending on whether |in| + * begins with "0X" or "0x" (indicating hex) or not (indicating decimal). A + * leading '-' is still permitted and comes before the optional 0X/0x. It + * returns one on success or zero on error. */ +OPENSSL_EXPORT int BN_asc2bn(BIGNUM **outp, const char *in); + +/* BN_print writes a hex encoding of |a| to |bio|. It returns one on success + * and zero on error. */ +OPENSSL_EXPORT int BN_print(BIO *bio, const BIGNUM *a); + +/* BN_print_fp acts like |BIO_print|, but wraps |fp| in a |BIO| first. */ +OPENSSL_EXPORT int BN_print_fp(FILE *fp, const BIGNUM *a); + +/* BN_get_word returns the absolute value of |bn| as a single word. If |bn| is + * too large to be represented as a single word, the maximum possible value + * will be returned. */ +OPENSSL_EXPORT BN_ULONG BN_get_word(const BIGNUM *bn); + + +/* ASN.1 functions. */ + +/* BN_cbs2unsigned parses a non-negative DER INTEGER from |cbs| writes the + * result to |ret|. It returns one on success and zero on failure. */ +OPENSSL_EXPORT int BN_cbs2unsigned(CBS *cbs, BIGNUM *ret); + +/* BN_bn2cbb marshals |bn| as a non-negative DER INTEGER and appends the result + * to |cbb|. It returns one on success and zero on failure. */ +OPENSSL_EXPORT int BN_bn2cbb(CBB *cbb, const BIGNUM *bn); + + +/* Internal functions. + * + * These functions are useful for code that is doing low-level manipulations of + * BIGNUM values. However, be sure that no other function in this file does + * what you want before turning to these. */ + +/* bn_correct_top decrements |bn->top| until |bn->d[top-1]| is non-zero or + * until |top| is zero. */ +OPENSSL_EXPORT void bn_correct_top(BIGNUM *bn); + +/* bn_wexpand ensures that |bn| has at least |words| works of space without + * altering its value. It returns one on success or zero on allocation + * failure. */ +OPENSSL_EXPORT BIGNUM *bn_wexpand(BIGNUM *bn, unsigned words); + + +/* BIGNUM pools. + * + * Certain BIGNUM operations need to use many temporary variables and + * allocating and freeing them can be quite slow. Thus such opertions typically + * take a |BN_CTX| parameter, which contains a pool of |BIGNUMs|. The |ctx| + * argument to a public function may be NULL, in which case a local |BN_CTX| + * will be created just for the lifetime of that call. + * + * A function must call |BN_CTX_start| first. Then, |BN_CTX_get| may be called + * repeatedly to obtain temporary |BIGNUM|s. All |BN_CTX_get| calls must be made + * before calling any other functions that use the |ctx| as an argument. + * + * Finally, |BN_CTX_end| must be called before returning from the function. + * When |BN_CTX_end| is called, the |BIGNUM| pointers obtained from + * |BN_CTX_get| become invalid. */ + +/* BN_CTX_new returns a new, empty BN_CTX or NULL on allocation failure. */ +OPENSSL_EXPORT BN_CTX *BN_CTX_new(void); + +/* BN_CTX_free frees all BIGNUMs contained in |ctx| and then frees |ctx| + * itself. */ +OPENSSL_EXPORT void BN_CTX_free(BN_CTX *ctx); + +/* BN_CTX_start "pushes" a new entry onto the |ctx| stack and allows future + * calls to |BN_CTX_get|. */ +OPENSSL_EXPORT void BN_CTX_start(BN_CTX *ctx); + +/* BN_CTX_get returns a new |BIGNUM|, or NULL on allocation failure. Once + * |BN_CTX_get| has returned NULL, all future calls will also return NULL until + * |BN_CTX_end| is called. */ +OPENSSL_EXPORT BIGNUM *BN_CTX_get(BN_CTX *ctx); + +/* BN_CTX_end invalidates all |BIGNUM|s returned from |BN_CTX_get| since the + * matching |BN_CTX_start| call. */ +OPENSSL_EXPORT void BN_CTX_end(BN_CTX *ctx); + + +/* Simple arithmetic */ + +/* BN_add sets |r| = |a| + |b|, where |r| may be the same pointer as either |a| + * or |b|. It returns one on success and zero on allocation failure. */ +OPENSSL_EXPORT int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b); + +/* BN_uadd sets |r| = |a| + |b|, where |a| and |b| are non-negative and |r| may + * be the same pointer as either |a| or |b|. It returns one on success and zero + * on allocation failure. */ +OPENSSL_EXPORT int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b); + +/* BN_add_word adds |w| to |a|. It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int BN_add_word(BIGNUM *a, BN_ULONG w); + +/* BN_sub sets |r| = |a| - |b|, where |r| must be a distinct pointer from |a| + * and |b|. It returns one on success and zero on allocation failure. */ +OPENSSL_EXPORT int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b); + +/* BN_usub sets |r| = |a| - |b|, where |a| and |b| are non-negative integers, + * |b| < |a| and |r| must be a distinct pointer from |a| and |b|. It returns + * one on success and zero on allocation failure. */ +OPENSSL_EXPORT int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b); + +/* BN_sub_word subtracts |w| from |a|. It returns one on success and zero on + * allocation failure. */ +OPENSSL_EXPORT int BN_sub_word(BIGNUM *a, BN_ULONG w); + +/* BN_mul sets |r| = |a| * |b|, where |r| may be the same pointer as |a| or + * |b|. Returns one on success and zero otherwise. */ +OPENSSL_EXPORT int BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + BN_CTX *ctx); + +/* BN_mul_word sets |bn| = |bn| * |w|. It returns one on success or zero on + * allocation failure. */ +OPENSSL_EXPORT int BN_mul_word(BIGNUM *bn, BN_ULONG w); + +/* BN_sqr sets |r| = |a|^2 (i.e. squares), where |r| may be the same pointer as + * |a|. Returns one on success and zero otherwise. This is more efficient than + * BN_mul(r, a, a, ctx). */ +OPENSSL_EXPORT int BN_sqr(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx); + +/* BN_div divides |numerator| by |divisor| and places the result in |quotient| + * and the remainder in |rem|. Either of |quotient| or |rem| may be NULL, in + * which case the respective value is not returned. The result is rounded + * towards zero; thus if |numerator| is negative, the remainder will be zero or + * negative. It returns one on success or zero on error. */ +OPENSSL_EXPORT int BN_div(BIGNUM *quotient, BIGNUM *rem, + const BIGNUM *numerator, const BIGNUM *divisor, + BN_CTX *ctx); + +/* BN_div_word sets |numerator| = |numerator|/|divisor| and returns the + * remainder or (BN_ULONG)-1 on error. */ +OPENSSL_EXPORT BN_ULONG BN_div_word(BIGNUM *numerator, BN_ULONG divisor); + +/* BN_sqrt sets |*out_sqrt| (which may be the same |BIGNUM| as |in|) to the + * square root of |in|, using |ctx|. It returns one on success or zero on + * error. Negative numbers and non-square numbers will result in an error with + * appropriate errors on the error queue. */ +OPENSSL_EXPORT int BN_sqrt(BIGNUM *out_sqrt, const BIGNUM *in, BN_CTX *ctx); + + +/* Comparison functions */ + +/* BN_cmp returns a value less than, equal to or greater than zero if |a| is + * less than, equal to or greater than |b|, respectively. */ +OPENSSL_EXPORT int BN_cmp(const BIGNUM *a, const BIGNUM *b); + +/* BN_ucmp returns a value less than, equal to or greater than zero if the + * absolute value of |a| is less than, equal to or greater than the absolute + * value of |b|, respectively. */ +OPENSSL_EXPORT int BN_ucmp(const BIGNUM *a, const BIGNUM *b); + +/* BN_abs_is_word returns one if the absolute value of |bn| equals |w| and zero + * otherwise. */ +OPENSSL_EXPORT int BN_abs_is_word(const BIGNUM *bn, BN_ULONG w); + +/* BN_is_zero returns one if |bn| is zero and zero otherwise. */ +OPENSSL_EXPORT int BN_is_zero(const BIGNUM *bn); + +/* BN_is_one returns one if |bn| equals one and zero otherwise. */ +OPENSSL_EXPORT int BN_is_one(const BIGNUM *bn); + +/* BN_is_word returns one if |bn| is exactly |w| and zero otherwise. */ +OPENSSL_EXPORT int BN_is_word(const BIGNUM *bn, BN_ULONG w); + +/* BN_is_odd returns one if |bn| is odd and zero otherwise. */ +OPENSSL_EXPORT int BN_is_odd(const BIGNUM *bn); + + +/* Bitwise operations. */ + +/* BN_lshift sets |r| equal to |a| << n. The |a| and |r| arguments may be the + * same |BIGNUM|. It returns one on success and zero on allocation failure. */ +OPENSSL_EXPORT int BN_lshift(BIGNUM *r, const BIGNUM *a, int n); + +/* BN_lshift1 sets |r| equal to |a| << 1, where |r| and |a| may be the same + * pointer. It returns one on success and zero on allocation failure. */ +OPENSSL_EXPORT int BN_lshift1(BIGNUM *r, const BIGNUM *a); + +/* BN_rshift sets |r| equal to |a| >> n, where |r| and |a| may be the same + * pointer. It returns one on success and zero on allocation failure. */ +OPENSSL_EXPORT int BN_rshift(BIGNUM *r, const BIGNUM *a, int n); + +/* BN_rshift1 sets |r| equal to |a| >> 1, where |r| and |a| may be the same + * pointer. It returns one on success and zero on allocation failure. */ +OPENSSL_EXPORT int BN_rshift1(BIGNUM *r, const BIGNUM *a); + +/* BN_set_bit sets the |n|th, least-significant bit in |a|. For example, if |a| + * is 2 then setting bit zero will make it 3. It returns one on success or zero + * on allocation failure. */ +OPENSSL_EXPORT int BN_set_bit(BIGNUM *a, int n); + +/* BN_clear_bit clears the |n|th, least-significant bit in |a|. For example, if + * |a| is 3, clearing bit zero will make it two. It returns one on success or + * zero on allocation failure. */ +OPENSSL_EXPORT int BN_clear_bit(BIGNUM *a, int n); + +/* BN_is_bit_set returns the value of the |n|th, least-significant bit in |a|, + * or zero if the bit doesn't exist. */ +OPENSSL_EXPORT int BN_is_bit_set(const BIGNUM *a, int n); + +/* BN_mask_bits truncates |a| so that it is only |n| bits long. It returns one + * on success or zero if |n| is greater than the length of |a| already. */ +OPENSSL_EXPORT int BN_mask_bits(BIGNUM *a, int n); + + +/* Modulo arithmetic. */ + +/* BN_mod_word returns |a| mod |w|. */ +OPENSSL_EXPORT BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w); + +/* BN_mod is a helper macro that calls |BN_div| and discards the quotient. */ +#define BN_mod(rem, numerator, divisor, ctx) \ + BN_div(NULL, (rem), (numerator), (divisor), (ctx)) + +/* BN_nnmod is a non-negative modulo function. It acts like |BN_mod|, but 0 <= + * |rem| < |divisor| is always true. It returns one on success and zero on + * error. */ +OPENSSL_EXPORT int BN_nnmod(BIGNUM *rem, const BIGNUM *numerator, + const BIGNUM *divisor, BN_CTX *ctx); + +/* BN_mod_add sets |r| = |a| + |b| mod |m|. It returns one on success and zero + * on error. */ +OPENSSL_EXPORT int BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const BIGNUM *m, BN_CTX *ctx); + +/* BN_mod_add_quick acts like |BN_mod_add| but requires that |a| and |b| be + * non-negative and less than |m|. */ +OPENSSL_EXPORT int BN_mod_add_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const BIGNUM *m); + +/* BN_mod_sub sets |r| = |a| - |b| mod |m|. It returns one on success and zero + * on error. */ +OPENSSL_EXPORT int BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const BIGNUM *m, BN_CTX *ctx); + +/* BN_mod_sub_quick acts like |BN_mod_sub| but requires that |a| and |b| be + * non-negative and less than |m|. */ +OPENSSL_EXPORT int BN_mod_sub_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const BIGNUM *m); + +/* BN_mod_mul sets |r| = |a|*|b| mod |m|. It returns one on success and zero + * on error. */ +OPENSSL_EXPORT int BN_mod_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const BIGNUM *m, BN_CTX *ctx); + +/* BN_mod_mul sets |r| = |a|^2 mod |m|. It returns one on success and zero + * on error. */ +OPENSSL_EXPORT int BN_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, + BN_CTX *ctx); + +/* BN_mod_lshift sets |r| = (|a| << n) mod |m|, where |r| and |a| may be the + * same pointer. It returns one on success and zero on error. */ +OPENSSL_EXPORT int BN_mod_lshift(BIGNUM *r, const BIGNUM *a, int n, + const BIGNUM *m, BN_CTX *ctx); + +/* BN_mod_lshift_quick acts like |BN_mod_lshift| but requires that |a| be + * non-negative and less than |m|. */ +OPENSSL_EXPORT int BN_mod_lshift_quick(BIGNUM *r, const BIGNUM *a, int n, + const BIGNUM *m); + +/* BN_mod_lshift1 sets |r| = (|a| << 1) mod |m|, where |r| and |a| may be the + * same pointer. It returns one on success and zero on error. */ +OPENSSL_EXPORT int BN_mod_lshift1(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, + BN_CTX *ctx); + +/* BN_mod_lshift1_quick acts like |BN_mod_lshift1| but requires that |a| be + * non-negative and less than |m|. */ +OPENSSL_EXPORT int BN_mod_lshift1_quick(BIGNUM *r, const BIGNUM *a, + const BIGNUM *m); + +/* BN_mod_sqrt returns a |BIGNUM|, r, such that r^2 == a (mod p). */ +OPENSSL_EXPORT BIGNUM *BN_mod_sqrt(BIGNUM *in, const BIGNUM *a, const BIGNUM *p, + BN_CTX *ctx); + + +/* Random and prime number generation. */ + +/* BN_rand sets |rnd| to a random number of length |bits|. If |top| is zero, the + * most-significant bit, if any, will be set. If |top| is one, the two most + * significant bits, if any, will be set. + * + * If |top| is -1 then no extra action will be taken and |BN_num_bits(rnd)| may + * not equal |bits| if the most significant bits randomly ended up as zeros. + * + * If |bottom| is non-zero, the least-significant bit, if any, will be set. The + * function returns one on success or zero otherwise. */ +OPENSSL_EXPORT int BN_rand(BIGNUM *rnd, int bits, int top, int bottom); + +/* BN_pseudo_rand is an alias for |BN_rand|. */ +OPENSSL_EXPORT int BN_pseudo_rand(BIGNUM *rnd, int bits, int top, int bottom); + +/* BN_rand_range sets |rnd| to a random value [0..range). It returns one on + * success and zero otherwise. */ +OPENSSL_EXPORT int BN_rand_range(BIGNUM *rnd, const BIGNUM *range); + +/* BN_pseudo_rand_range is an alias for BN_rand_range. */ +OPENSSL_EXPORT int BN_pseudo_rand_range(BIGNUM *rnd, const BIGNUM *range); + +/* BN_generate_dsa_nonce generates a random number 0 <= out < range. Unlike + * BN_rand_range, it also includes the contents of |priv| and |message| in the + * generation so that an RNG failure isn't fatal as long as |priv| remains + * secret. This is intended for use in DSA and ECDSA where an RNG weakness + * leads directly to private key exposure unless this function is used. + * It returns one on success and zero on error. */ +OPENSSL_EXPORT int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range, + const BIGNUM *priv, + const uint8_t *message, + size_t message_len, BN_CTX *ctx); + +/* BN_GENCB holds a callback function that is used by generation functions that + * can take a very long time to complete. Use |BN_GENCB_set| to initialise a + * |BN_GENCB| structure. + * + * The callback receives the address of that |BN_GENCB| structure as its last + * argument and the user is free to put an arbitary pointer in |arg|. The other + * arguments are set as follows: + * event=BN_GENCB_GENERATED, n=i: after generating the i'th possible prime + * number. + * event=BN_GENCB_PRIME_TEST, n=-1: when finished trial division primality + * checks. + * event=BN_GENCB_PRIME_TEST, n=i: when the i'th primality test has finished. + * + * The callback can return zero to abort the generation progress or one to + * allow it to continue. + * + * When other code needs to call a BN generation function it will often take a + * BN_GENCB argument and may call the function with other argument values. */ +#define BN_GENCB_GENERATED 0 +#define BN_GENCB_PRIME_TEST 1 + +struct bn_gencb_st { + void *arg; /* callback-specific data */ + int (*callback)(int event, int n, struct bn_gencb_st *); +}; + +/* BN_GENCB_set configures |callback| to call |f| and sets |callout->arg| to + * |arg|. */ +OPENSSL_EXPORT void BN_GENCB_set(BN_GENCB *callback, + int (*f)(int event, int n, + struct bn_gencb_st *), + void *arg); + +/* BN_GENCB_call calls |callback|, if not NULL, and returns the return value of + * the callback, or 1 if |callback| is NULL. */ +OPENSSL_EXPORT int BN_GENCB_call(BN_GENCB *callback, int event, int n); + +/* BN_generate_prime_ex sets |ret| to a prime number of |bits| length. If safe + * is non-zero then the prime will be such that (ret-1)/2 is also a prime. + * (This is needed for Diffie-Hellman groups to ensure that the only subgroups + * are of size 2 and (p-1)/2.). + * + * If |add| is not NULL, the prime will fulfill the condition |ret| % |add| == + * |rem| in order to suit a given generator. (If |rem| is NULL then |ret| % + * |add| == 1.) + * + * If |cb| is not NULL, it will be called during processing to give an + * indication of progress. See the comments for |BN_GENCB|. It returns one on + * success and zero otherwise. */ +OPENSSL_EXPORT int BN_generate_prime_ex(BIGNUM *ret, int bits, int safe, + const BIGNUM *add, const BIGNUM *rem, + BN_GENCB *cb); + +/* BN_prime_checks is magic value that can be used as the |checks| argument to + * the primality testing functions in order to automatically select a number of + * Miller-Rabin checks that gives a false positive rate of ~2^{-80}. */ +#define BN_prime_checks 0 + +/* BN_primality_test sets |*is_probably_prime| to one if |candidate| is + * probably a prime number by the Miller-Rabin test or zero if it's certainly + * not. + * + * If |do_trial_division| is non-zero then |candidate| will be tested against a + * list of small primes before Miller-Rabin tests. The probability of this + * function returning a false positive is 2^{2*checks}. If |checks| is + * |BN_prime_checks| then a value that results in approximately 2^{-80} false + * positive probability is used. If |cb| is not NULL then it is called during + * the checking process. See the comment above |BN_GENCB|. + * + * The function returns one on success and zero on error. + * + * (If you are unsure whether you want |do_trial_division|, don't set it.) */ +OPENSSL_EXPORT int BN_primality_test(int *is_probably_prime, + const BIGNUM *candidate, int checks, + BN_CTX *ctx, int do_trial_division, + BN_GENCB *cb); + +/* BN_is_prime_fasttest_ex returns one if |candidate| is probably a prime + * number by the Miller-Rabin test, zero if it's certainly not and -1 on error. + * + * If |do_trial_division| is non-zero then |candidate| will be tested against a + * list of small primes before Miller-Rabin tests. The probability of this + * function returning one when |candidate| is composite is 2^{2*checks}. If + * |checks| is |BN_prime_checks| then a value that results in approximately + * 2^{-80} false positive probability is used. If |cb| is not NULL then it is + * called during the checking process. See the comment above |BN_GENCB|. + * + * WARNING: deprecated. Use |BN_primality_test|. */ +OPENSSL_EXPORT int BN_is_prime_fasttest_ex(const BIGNUM *candidate, int checks, + BN_CTX *ctx, int do_trial_division, + BN_GENCB *cb); + +/* BN_is_prime_ex acts the same as |BN_is_prime_fasttest_ex| with + * |do_trial_division| set to zero. + * + * WARNING: deprecated: Use |BN_primality_test|. */ +OPENSSL_EXPORT int BN_is_prime_ex(const BIGNUM *candidate, int checks, + BN_CTX *ctx, BN_GENCB *cb); + + +/* Number theory functions */ + +/* BN_gcd sets |r| = gcd(|a|, |b|). It returns one on success and zero + * otherwise. */ +OPENSSL_EXPORT int BN_gcd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + BN_CTX *ctx); + +/* BN_mod_inverse sets |out| equal to |a|^-1, mod |n|. If either of |a| or |n| + * have |BN_FLG_CONSTTIME| set then the operation is performed in constant + * time. If |out| is NULL, a fresh BIGNUM is allocated. It returns the result + * or NULL on error. */ +OPENSSL_EXPORT BIGNUM *BN_mod_inverse(BIGNUM *out, const BIGNUM *a, + const BIGNUM *n, BN_CTX *ctx); + +/* BN_kronecker returns the Kronecker symbol of |a| and |b| (which is -1, 0 or + * 1), or -2 on error. */ +OPENSSL_EXPORT int BN_kronecker(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx); + + +/* Montgomery arithmetic. */ + +/* BN_MONT_CTX contains the precomputed values needed to work in a specific + * Montgomery domain. */ + +/* BN_MONT_CTX_new returns a fresh BN_MONT_CTX or NULL on allocation failure. */ +OPENSSL_EXPORT BN_MONT_CTX *BN_MONT_CTX_new(void); + +/* BN_MONT_CTX_init initialises a stack allocated |BN_MONT_CTX|. */ +OPENSSL_EXPORT void BN_MONT_CTX_init(BN_MONT_CTX *mont); + +/* BN_MONT_CTX_free frees the contexts of |mont| and, if it was originally + * allocated with |BN_MONT_CTX_new|, |mont| itself. */ +OPENSSL_EXPORT void BN_MONT_CTX_free(BN_MONT_CTX *mont); + +/* BN_MONT_CTX_copy sets |to| equal to |from|. It returns |to| on success or + * NULL on error. */ +OPENSSL_EXPORT BN_MONT_CTX *BN_MONT_CTX_copy(BN_MONT_CTX *to, + BN_MONT_CTX *from); + +/* BN_MONT_CTX_set sets up a Montgomery context given the modulus, |mod|. It + * returns one on success and zero on error. */ +OPENSSL_EXPORT int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, + BN_CTX *ctx); + +/* BN_MONT_CTX_set_locked takes |lock| and checks whether |*pmont| is NULL. If + * so, it creates a new |BN_MONT_CTX| and sets the modulus for it to |mod|. It + * then stores it as |*pmont| and returns it, or NULL on error. + * + * If |*pmont| is already non-NULL then the existing value is returned. */ +BN_MONT_CTX *BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, CRYPTO_MUTEX *lock, + const BIGNUM *mod, BN_CTX *bn_ctx); + +/* BN_to_montgomery sets |ret| equal to |a| in the Montgomery domain. It + * returns one on success and zero on error. */ +OPENSSL_EXPORT int BN_to_montgomery(BIGNUM *ret, const BIGNUM *a, + const BN_MONT_CTX *mont, BN_CTX *ctx); + +/* BN_from_montgomery sets |ret| equal to |a| * R^-1, i.e. translates values + * out of the Montgomery domain. It returns one on success or zero on error. */ +OPENSSL_EXPORT int BN_from_montgomery(BIGNUM *ret, const BIGNUM *a, + const BN_MONT_CTX *mont, BN_CTX *ctx); + +/* BN_mod_mul_montgomery set |r| equal to |a| * |b|, in the Montgomery domain. + * Both |a| and |b| must already be in the Montgomery domain (by + * |BN_to_montgomery|). It returns one on success or zero on error. */ +OPENSSL_EXPORT int BN_mod_mul_montgomery(BIGNUM *r, const BIGNUM *a, + const BIGNUM *b, + const BN_MONT_CTX *mont, BN_CTX *ctx); + + +/* Exponentiation. */ + +/* BN_exp sets |r| equal to |a|^{|p|}. It does so with a square-and-multiply + * algorithm that leaks side-channel information. It returns one on success or + * zero otherwise. */ +OPENSSL_EXPORT int BN_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + BN_CTX *ctx); + +/* BN_mod_exp sets |r| equal to |a|^{|p|} mod |m|. It does so with the best + * algorithm for the values provided and can run in constant time if + * |BN_FLG_CONSTTIME| is set for |p|. It returns one on success or zero + * otherwise. */ +OPENSSL_EXPORT int BN_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx); + +OPENSSL_EXPORT int BN_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, + BN_MONT_CTX *m_ctx); + +OPENSSL_EXPORT int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, + const BIGNUM *p, const BIGNUM *m, + BN_CTX *ctx, BN_MONT_CTX *in_mont); + +OPENSSL_EXPORT int BN_mod_exp_mont_word(BIGNUM *r, BN_ULONG a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, + BN_MONT_CTX *m_ctx); +OPENSSL_EXPORT int BN_mod_exp2_mont(BIGNUM *r, const BIGNUM *a1, + const BIGNUM *p1, const BIGNUM *a2, + const BIGNUM *p2, const BIGNUM *m, + BN_CTX *ctx, BN_MONT_CTX *m_ctx); + + +/* Private functions */ + +struct bignum_st { + BN_ULONG *d; /* Pointer to an array of 'BN_BITS2' bit chunks in little-endian + order. */ + int top; /* Index of last used element in |d|, plus one. */ + int dmax; /* Size of |d|, in words. */ + int neg; /* one if the number is negative */ + int flags; /* bitmask of BN_FLG_* values */ +}; + +struct bn_mont_ctx_st { + BIGNUM RR; /* used to convert to montgomery form */ + BIGNUM N; /* The modulus */ + BIGNUM Ni; /* R*(1/R mod N) - N*Ni = 1 + * (Ni is only stored for bignum algorithm) */ + BN_ULONG n0[2]; /* least significant word(s) of Ni; + (type changed with 0.9.9, was "BN_ULONG n0;" before) */ + int flags; + int ri; /* number of bits in R */ +}; + +OPENSSL_EXPORT unsigned BN_num_bits_word(BN_ULONG l); + +#define BN_FLG_MALLOCED 0x01 +#define BN_FLG_STATIC_DATA 0x02 +/* avoid leaking exponent information through timing, BN_mod_exp_mont() will + * call BN_mod_exp_mont_consttime, BN_div() will call BN_div_no_branch, + * BN_mod_inverse() will call BN_mod_inverse_no_branch. */ +#define BN_FLG_CONSTTIME 0x04 + + +/* Android compatibility section. + * + * These functions are declared, temporarily, for Android because + * wpa_supplicant will take a little time to sync with upstream. Outside of + * Android they'll have no definition. */ + +OPENSSL_EXPORT BIGNUM *get_rfc3526_prime_1536(BIGNUM *bn); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define BN_R_ARG2_LT_ARG3 100 +#define BN_R_BAD_RECIPROCAL 101 +#define BN_R_BIGNUM_TOO_LONG 102 +#define BN_R_BITS_TOO_SMALL 103 +#define BN_R_CALLED_WITH_EVEN_MODULUS 104 +#define BN_R_DIV_BY_ZERO 105 +#define BN_R_EXPAND_ON_STATIC_BIGNUM_DATA 106 +#define BN_R_INPUT_NOT_REDUCED 107 +#define BN_R_INVALID_RANGE 108 +#define BN_R_NEGATIVE_NUMBER 109 +#define BN_R_NOT_A_SQUARE 110 +#define BN_R_NOT_INITIALIZED 111 +#define BN_R_NO_INVERSE 112 +#define BN_R_PRIVATE_KEY_TOO_LARGE 113 +#define BN_R_P_IS_NOT_PRIME 114 +#define BN_R_TOO_MANY_ITERATIONS 115 +#define BN_R_TOO_MANY_TEMPORARY_VARIABLES 116 +#define BN_R_BAD_ENCODING 117 +#define BN_R_ENCODE_ERROR 118 + +#endif /* OPENSSL_HEADER_BN_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/buf.h b/TMessagesProj/jni/boringssl/include/openssl/buf.h new file mode 100644 index 00000000..76e3795e --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/buf.h @@ -0,0 +1,118 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_BUFFER_H +#define OPENSSL_HEADER_BUFFER_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Memory and string functions, see also mem.h. */ + + +/* BUF_MEM is a generic buffer object used by OpenSSL. */ +struct buf_mem_st { + size_t length; /* current number of bytes */ + char *data; + size_t max; /* size of buffer */ +}; + +/* BUF_MEM_new creates a new BUF_MEM which has no allocated data buffer. */ +OPENSSL_EXPORT BUF_MEM *BUF_MEM_new(void); + +/* BUF_MEM_free frees |buf->data| if needed and then frees |buf| itself. */ +OPENSSL_EXPORT void BUF_MEM_free(BUF_MEM *buf); + +/* BUF_MEM_grow ensures that |buf| has length |len| and allocates memory if + * needed. If the length of |buf| increased, the new bytes are filled with + * zeros. It returns the length of |buf|, or zero if there's an error. */ +OPENSSL_EXPORT size_t BUF_MEM_grow(BUF_MEM *buf, size_t len); + +/* BUF_MEM_grow_clean acts the same as |BUF_MEM_grow|, but clears the previous + * contents of memory if reallocing. */ +OPENSSL_EXPORT size_t BUF_MEM_grow_clean(BUF_MEM *str, size_t len); + +/* BUF_strdup returns an allocated, duplicate of |str|. */ +OPENSSL_EXPORT char *BUF_strdup(const char *str); + +/* BUF_strnlen returns the number of characters in |str|, excluding the NUL + * byte, but at most |max_len|. This function never reads more than |max_len| + * bytes from |str|. */ +OPENSSL_EXPORT size_t BUF_strnlen(const char *str, size_t max_len); + +/* BUF_strndup returns an allocated, duplicate of |str|, which is, at most, + * |size| bytes. The result is always NUL terminated. */ +OPENSSL_EXPORT char *BUF_strndup(const char *str, size_t size); + +/* BUF_memdup returns an allocated, duplicate of |size| bytes from |data|. */ +OPENSSL_EXPORT void *BUF_memdup(const void *data, size_t size); + +/* BUF_strlcpy acts like strlcpy(3). */ +OPENSSL_EXPORT size_t BUF_strlcpy(char *dst, const char *src, size_t dst_size); + +/* BUF_strlcat acts like strlcat(3). */ +OPENSSL_EXPORT size_t BUF_strlcat(char *dst, const char *src, size_t size); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_BUFFER_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/buffer.h b/TMessagesProj/jni/boringssl/include/openssl/buffer.h new file mode 100644 index 00000000..c6b721c2 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/buffer.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is provided in order to make compiling against code that expects + OpenSSL easier. */ + +#include "buf.h" diff --git a/TMessagesProj/jni/boringssl/include/openssl/bytestring.h b/TMessagesProj/jni/boringssl/include/openssl/bytestring.h new file mode 100644 index 00000000..4fceeaab --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/bytestring.h @@ -0,0 +1,349 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_BYTESTRING_H +#define OPENSSL_HEADER_BYTESTRING_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Bytestrings are used for parsing and building TLS and ASN.1 messages. + * + * A "CBS" (CRYPTO ByteString) represents a string of bytes in memory and + * provides utility functions for safely parsing length-prefixed structures + * like TLS and ASN.1 from it. + * + * A "CBB" (CRYPTO ByteBuilder) is a memory buffer that grows as needed and + * provides utility functions for building length-prefixed messages. */ + + +/* CRYPTO ByteString */ + +struct cbs_st { + const uint8_t *data; + size_t len; +}; + +/* CBS_init sets |cbs| to point to |data|. It does not take ownership of + * |data|. */ +OPENSSL_EXPORT void CBS_init(CBS *cbs, const uint8_t *data, size_t len); + +/* CBS_skip advances |cbs| by |len| bytes. It returns one on success and zero + * otherwise. */ +OPENSSL_EXPORT int CBS_skip(CBS *cbs, size_t len); + +/* CBS_data returns a pointer to the contents of |cbs|. */ +OPENSSL_EXPORT const uint8_t *CBS_data(const CBS *cbs); + +/* CBS_len returns the number of bytes remaining in |cbs|. */ +OPENSSL_EXPORT size_t CBS_len(const CBS *cbs); + +/* CBS_stow copies the current contents of |cbs| into |*out_ptr| and + * |*out_len|. If |*out_ptr| is not NULL, the contents are freed with + * OPENSSL_free. It returns one on success and zero on allocation failure. On + * success, |*out_ptr| should be freed with OPENSSL_free. If |cbs| is empty, + * |*out_ptr| will be NULL. */ +OPENSSL_EXPORT int CBS_stow(const CBS *cbs, uint8_t **out_ptr, size_t *out_len); + +/* CBS_strdup copies the current contents of |cbs| into |*out_ptr| as a + * NUL-terminated C string. If |*out_ptr| is not NULL, the contents are freed + * with OPENSSL_free. It returns one on success and zero on allocation + * failure. On success, |*out_ptr| should be freed with OPENSSL_free. + * + * NOTE: If |cbs| contains NUL bytes, the string will be truncated. Call + * |CBS_contains_zero_byte(cbs)| to check for NUL bytes. */ +OPENSSL_EXPORT int CBS_strdup(const CBS *cbs, char **out_ptr); + +/* CBS_contains_zero_byte returns one if the current contents of |cbs| contains + * a NUL byte and zero otherwise. */ +OPENSSL_EXPORT int CBS_contains_zero_byte(const CBS *cbs); + +/* CBS_mem_equal compares the current contents of |cbs| with the |len| bytes + * starting at |data|. If they're equal, it returns one, otherwise zero. If the + * lengths match, it uses a constant-time comparison. */ +OPENSSL_EXPORT int CBS_mem_equal(const CBS *cbs, const uint8_t *data, + size_t len); + +/* CBS_get_u8 sets |*out| to the next uint8_t from |cbs| and advances |cbs|. It + * returns one on success and zero on error. */ +OPENSSL_EXPORT int CBS_get_u8(CBS *cbs, uint8_t *out); + +/* CBS_get_u16 sets |*out| to the next, big-endian uint16_t from |cbs| and + * advances |cbs|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int CBS_get_u16(CBS *cbs, uint16_t *out); + +/* CBS_get_u24 sets |*out| to the next, big-endian 24-bit value from |cbs| and + * advances |cbs|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int CBS_get_u24(CBS *cbs, uint32_t *out); + +/* CBS_get_u32 sets |*out| to the next, big-endian uint32_t value from |cbs| + * and advances |cbs|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int CBS_get_u32(CBS *cbs, uint32_t *out); + +/* CBS_get_bytes sets |*out| to the next |len| bytes from |cbs| and advances + * |cbs|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int CBS_get_bytes(CBS *cbs, CBS *out, size_t len); + +/* CBS_get_u8_length_prefixed sets |*out| to the contents of an 8-bit, + * length-prefixed value from |cbs| and advances |cbs| over it. It returns one + * on success and zero on error. */ +OPENSSL_EXPORT int CBS_get_u8_length_prefixed(CBS *cbs, CBS *out); + +/* CBS_get_u16_length_prefixed sets |*out| to the contents of a 16-bit, + * big-endian, length-prefixed value from |cbs| and advances |cbs| over it. It + * returns one on success and zero on error. */ +OPENSSL_EXPORT int CBS_get_u16_length_prefixed(CBS *cbs, CBS *out); + +/* CBS_get_u24_length_prefixed sets |*out| to the contents of a 24-bit, + * big-endian, length-prefixed value from |cbs| and advances |cbs| over it. It + * returns one on success and zero on error. */ +OPENSSL_EXPORT int CBS_get_u24_length_prefixed(CBS *cbs, CBS *out); + + +/* Parsing ASN.1 */ + +#define CBS_ASN1_BOOLEAN 0x1 +#define CBS_ASN1_INTEGER 0x2 +#define CBS_ASN1_BITSTRING 0x3 +#define CBS_ASN1_OCTETSTRING 0x4 +#define CBS_ASN1_NULL 0x5 +#define CBS_ASN1_OBJECT 0x6 +#define CBS_ASN1_ENUMERATED 0xa +#define CBS_ASN1_SEQUENCE (0x10 | CBS_ASN1_CONSTRUCTED) +#define CBS_ASN1_SET (0x11 | CBS_ASN1_CONSTRUCTED) +#define CBS_ASN1_GENERALIZEDTIME 0x18 + +#define CBS_ASN1_CONSTRUCTED 0x20 +#define CBS_ASN1_CONTEXT_SPECIFIC 0x80 + +/* CBS_get_asn1 sets |*out| to the contents of DER-encoded, ASN.1 element (not + * including tag and length bytes) and advances |cbs| over it. The ASN.1 + * element must match |tag_value|. It returns one on success and zero + * on error. + * + * Tag numbers greater than 30 are not supported (i.e. short form only). */ +OPENSSL_EXPORT int CBS_get_asn1(CBS *cbs, CBS *out, unsigned tag_value); + +/* CBS_get_asn1_element acts like |CBS_get_asn1| but |out| will include the + * ASN.1 header bytes too. */ +OPENSSL_EXPORT int CBS_get_asn1_element(CBS *cbs, CBS *out, unsigned tag_value); + +/* CBS_peek_asn1_tag looks ahead at the next ASN.1 tag and returns one + * if the next ASN.1 element on |cbs| would have tag |tag_value|. If + * |cbs| is empty or the tag does not match, it returns zero. Note: if + * it returns one, CBS_get_asn1 may still fail if the rest of the + * element is malformed. */ +OPENSSL_EXPORT int CBS_peek_asn1_tag(const CBS *cbs, unsigned tag_value); + +/* CBS_get_any_asn1_element sets |*out| to contain the next ASN.1 element from + * |*cbs| (including header bytes) and advances |*cbs|. It sets |*out_tag| to + * the tag number and |*out_header_len| to the length of the ASN.1 header. Each + * of |out|, |out_tag|, and |out_header_len| may be NULL to ignore the value. + * + * Tag numbers greater than 30 are not supported (i.e. short form only). */ +OPENSSL_EXPORT int CBS_get_any_asn1_element(CBS *cbs, CBS *out, + unsigned *out_tag, + size_t *out_header_len); + +/* CBS_get_any_ber_asn1_element acts the same as |CBS_get_any_asn1_element| but + * also allows indefinite-length elements to be returned. In that case, + * |*out_header_len| and |CBS_len(out)| will both be two as only the header is + * returned, otherwise it behaves the same as the previous function. */ +OPENSSL_EXPORT int CBS_get_any_ber_asn1_element(CBS *cbs, CBS *out, + unsigned *out_tag, + size_t *out_header_len); + +/* CBS_get_asn1_uint64 gets an ASN.1 INTEGER from |cbs| using |CBS_get_asn1| + * and sets |*out| to its value. It returns one on success and zero on error, + * where error includes the integer being negative, or too large to represent + * in 64 bits. */ +OPENSSL_EXPORT int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out); + +/* CBS_get_optional_asn1 gets an optional explicitly-tagged element + * from |cbs| tagged with |tag| and sets |*out| to its contents. If + * present, it sets |*out_present| to one, otherwise zero. It returns + * one on success, whether or not the element was present, and zero on + * decode failure. */ +OPENSSL_EXPORT int CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present, + unsigned tag); + +/* CBS_get_optional_asn1_octet_string gets an optional + * explicitly-tagged OCTET STRING from |cbs|. If present, it sets + * |*out| to the string and |*out_present| to one. Otherwise, it sets + * |*out| to empty and |*out_present| to zero. |out_present| may be + * NULL. It returns one on success, whether or not the element was + * present, and zero on decode failure. */ +OPENSSL_EXPORT int CBS_get_optional_asn1_octet_string(CBS *cbs, CBS *out, + int *out_present, + unsigned tag); + +/* CBS_get_optional_asn1_uint64 gets an optional explicitly-tagged + * INTEGER from |cbs|. If present, it sets |*out| to the + * value. Otherwise, it sets |*out| to |default_value|. It returns one + * on success, whether or not the element was present, and zero on + * decode failure. */ +OPENSSL_EXPORT int CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out, + unsigned tag, + uint64_t default_value); + +/* CBS_get_optional_asn1_bool gets an optional, explicitly-tagged BOOLEAN from + * |cbs|. If present, it sets |*out| to either zero or one, based on the + * boolean. Otherwise, it sets |*out| to |default_value|. It returns one on + * success, whether or not the element was present, and zero on decode + * failure. */ +OPENSSL_EXPORT int CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned tag, + int default_value); + + +/* CRYPTO ByteBuilder. + * + * |CBB| objects allow one to build length-prefixed serialisations. A |CBB| + * object is associated with a buffer and new buffers are created with + * |CBB_init|. Several |CBB| objects can point at the same buffer when a + * length-prefix is pending, however only a single |CBB| can be 'current' at + * any one time. For example, if one calls |CBB_add_u8_length_prefixed| then + * the new |CBB| points at the same buffer as the original. But if the original + * |CBB| is used then the length prefix is written out and the new |CBB| must + * not be used again. + * + * If one needs to force a length prefix to be written out because a |CBB| is + * going out of scope, use |CBB_flush|. */ + +struct cbb_buffer_st { + uint8_t *buf; + size_t len; /* The number of valid bytes. */ + size_t cap; /* The size of buf. */ + char can_resize; /* One iff |buf| is owned by this object. If not then |buf| + cannot be resized. */ +}; + +struct cbb_st { + struct cbb_buffer_st *base; + /* offset is the offset from the start of |base->buf| to the position of any + * pending length-prefix. */ + size_t offset; + /* child points to a child CBB if a length-prefix is pending. */ + struct cbb_st *child; + /* pending_len_len contains the number of bytes in a pending length-prefix, + * or zero if no length-prefix is pending. */ + uint8_t pending_len_len; + char pending_is_asn1; + /* is_top_level is true iff this is a top-level |CBB| (as opposed to a child + * |CBB|). Top-level objects are valid arguments for |CBB_finish|. */ + char is_top_level; +}; + +/* CBB_zero sets an uninitialised |cbb| to the zero state. It must be + * initialised with |CBB_init| or |CBB_init_fixed| before use, but it is safe to + * call |CBB_cleanup| without a successful |CBB_init|. This may be used for more + * uniform cleanup of a |CBB|. */ +OPENSSL_EXPORT void CBB_zero(CBB *cbb); + +/* CBB_init initialises |cbb| with |initial_capacity|. Since a |CBB| grows as + * needed, the |initial_capacity| is just a hint. It returns one on success or + * zero on error. */ +OPENSSL_EXPORT int CBB_init(CBB *cbb, size_t initial_capacity); + +/* CBB_init_fixed initialises |cbb| to write to |len| bytes at |buf|. Since + * |buf| cannot grow, trying to write more than |len| bytes will cause CBB + * functions to fail. It returns one on success or zero on error. */ +OPENSSL_EXPORT int CBB_init_fixed(CBB *cbb, uint8_t *buf, size_t len); + +/* CBB_cleanup frees all resources owned by |cbb| and other |CBB| objects + * writing to the same buffer. This should be used in an error case where a + * serialisation is abandoned. */ +OPENSSL_EXPORT void CBB_cleanup(CBB *cbb); + +/* CBB_finish completes any pending length prefix and sets |*out_data| to a + * malloced buffer and |*out_len| to the length of that buffer. The caller + * takes ownership of the buffer and, unless the buffer was fixed with + * |CBB_init_fixed|, must call |OPENSSL_free| when done. + * + * It can only be called on a "top level" |CBB|, i.e. one initialised with + * |CBB_init| or |CBB_init_fixed|. It returns one on success and zero on + * error. */ +OPENSSL_EXPORT int CBB_finish(CBB *cbb, uint8_t **out_data, size_t *out_len); + +/* CBB_flush causes any pending length prefixes to be written out and any child + * |CBB| objects of |cbb| to be invalidated. It returns one on success or zero + * on error. */ +OPENSSL_EXPORT int CBB_flush(CBB *cbb); + +/* CBB_len returns the number of bytes written to |cbb|'s top-level |CBB|. It + * may be compared before and after an operation to determine how many bytes + * were written. + * + * It is a fatal error to call this on a CBB with any active children. This does + * not flush |cbb|. */ +OPENSSL_EXPORT size_t CBB_len(const CBB *cbb); + +/* CBB_add_u8_length_prefixed sets |*out_contents| to a new child of |cbb|. The + * data written to |*out_contents| will be prefixed in |cbb| with an 8-bit + * length. It returns one on success or zero on error. */ +OPENSSL_EXPORT int CBB_add_u8_length_prefixed(CBB *cbb, CBB *out_contents); + +/* CBB_add_u16_length_prefixed sets |*out_contents| to a new child of |cbb|. + * The data written to |*out_contents| will be prefixed in |cbb| with a 16-bit, + * big-endian length. It returns one on success or zero on error. */ +OPENSSL_EXPORT int CBB_add_u16_length_prefixed(CBB *cbb, CBB *out_contents); + +/* CBB_add_u24_length_prefixed sets |*out_contents| to a new child of |cbb|. + * The data written to |*out_contents| will be prefixed in |cbb| with a 24-bit, + * big-endian length. It returns one on success or zero on error. */ +OPENSSL_EXPORT int CBB_add_u24_length_prefixed(CBB *cbb, CBB *out_contents); + +/* CBB_add_asn1 sets |*out_contents| to a |CBB| into which the contents of an + * ASN.1 object can be written. The |tag| argument will be used as the tag for + * the object. Passing in |tag| number 31 will return in an error since only + * single octet identifiers are supported. It returns one on success or zero + * on error. */ +OPENSSL_EXPORT int CBB_add_asn1(CBB *cbb, CBB *out_contents, uint8_t tag); + +/* CBB_add_bytes appends |len| bytes from |data| to |cbb|. It returns one on + * success and zero otherwise. */ +OPENSSL_EXPORT int CBB_add_bytes(CBB *cbb, const uint8_t *data, size_t len); + +/* CBB_add_space appends |len| bytes to |cbb| and sets |*out_data| to point to + * the beginning of that space. The caller must then write |len| bytes of + * actual contents to |*out_data|. It returns one on success and zero + * otherwise. */ +OPENSSL_EXPORT int CBB_add_space(CBB *cbb, uint8_t **out_data, size_t len); + +/* CBB_add_u8 appends an 8-bit number from |value| to |cbb|. It returns one on + * success and zero otherwise. */ +OPENSSL_EXPORT int CBB_add_u8(CBB *cbb, uint8_t value); + +/* CBB_add_u16 appends a 16-bit, big-endian number from |value| to |cbb|. It + * returns one on success and zero otherwise. */ +OPENSSL_EXPORT int CBB_add_u16(CBB *cbb, uint16_t value); + +/* CBB_add_u24 appends a 24-bit, big-endian number from |value| to |cbb|. It + * returns one on success and zero otherwise. */ +OPENSSL_EXPORT int CBB_add_u24(CBB *cbb, uint32_t value); + +/* CBB_add_asn1_uint64 writes an ASN.1 INTEGER into |cbb| using |CBB_add_asn1| + * and writes |value| in its contents. It returns one on success and zero on + * error. */ +OPENSSL_EXPORT int CBB_add_asn1_uint64(CBB *cbb, uint64_t value); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_BYTESTRING_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/cast.h b/TMessagesProj/jni/boringssl/include/openssl/cast.h new file mode 100644 index 00000000..80217239 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/cast.h @@ -0,0 +1,96 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_CAST_H +#define OPENSSL_HEADER_CAST_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +#define CAST_ENCRYPT 1 +#define CAST_DECRYPT 0 + +#define CAST_BLOCK 8 +#define CAST_KEY_LENGTH 16 + +typedef struct cast_key_st { + uint32_t data[32]; + int short_key; /* Use reduced rounds for short key */ +} CAST_KEY; + +OPENSSL_EXPORT void CAST_set_key(CAST_KEY *key, size_t len, + const uint8_t *data); +OPENSSL_EXPORT void CAST_ecb_encrypt(const uint8_t *in, uint8_t *out, + const CAST_KEY *key, int enc); +OPENSSL_EXPORT void CAST_encrypt(uint32_t *data, const CAST_KEY *key); +OPENSSL_EXPORT void CAST_decrypt(uint32_t *data, const CAST_KEY *key); +OPENSSL_EXPORT void CAST_cbc_encrypt(const uint8_t *in, uint8_t *out, + long length, const CAST_KEY *ks, + uint8_t *iv, int enc); + +OPENSSL_EXPORT void CAST_cfb64_encrypt(const uint8_t *in, uint8_t *out, + long length, const CAST_KEY *schedule, + uint8_t *ivec, int *num, int enc); + +#ifdef __cplusplus +} +#endif + +#endif /* OPENSSL_HEADER_CAST_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/chacha.h b/TMessagesProj/jni/boringssl/include/openssl/chacha.h new file mode 100644 index 00000000..b7f58828 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/chacha.h @@ -0,0 +1,37 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_CHACHA_H +#define OPENSSL_HEADER_CHACHA_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* CRYPTO_chacha_20 encrypts |in_len| bytes from |in| with the given key and + * nonce and writes the result to |out|, which may be equal to |in|. The + * initial block counter is specified by |counter|. */ +OPENSSL_EXPORT void CRYPTO_chacha_20(uint8_t *out, const uint8_t *in, + size_t in_len, const uint8_t key[32], + const uint8_t nonce[8], size_t counter); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_CHACHA_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/cipher.h b/TMessagesProj/jni/boringssl/include/openssl/cipher.h new file mode 100644 index 00000000..eb000825 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/cipher.h @@ -0,0 +1,565 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_CIPHER_H +#define OPENSSL_HEADER_CIPHER_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Ciphers. */ + + +/* Cipher primitives. + * + * The following functions return |EVP_CIPHER| objects that implement the named + * cipher algorithm. */ + +OPENSSL_EXPORT const EVP_CIPHER *EVP_rc4(void); + +OPENSSL_EXPORT const EVP_CIPHER *EVP_des_cbc(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_des_ede3_cbc(void); + +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_128_ecb(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_128_cbc(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_128_ctr(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_128_ofb(void); + +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_256_ecb(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_256_cbc(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_256_ctr(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_256_ofb(void); + +/* Deprecated AES-GCM implementations that set |EVP_CIPH_FLAG_CUSTOM_CIPHER|. + * Use |EVP_aead_aes_128_gcm| and |EVP_aead_aes_256_gcm| instead. */ +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_128_gcm(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_256_gcm(void); + +/* Deprecated 192-bit version of AES. */ +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_192_ecb(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_192_cbc(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_192_ctr(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_192_gcm(void); + +/* EVP_enc_null returns a 'cipher' that passes plaintext through as + * ciphertext. */ +OPENSSL_EXPORT const EVP_CIPHER *EVP_enc_null(void); + +/* EVP_rc2_cbc returns a cipher that implements 128-bit RC2 in CBC mode. */ +OPENSSL_EXPORT const EVP_CIPHER *EVP_rc2_cbc(void); + +/* EVP_rc2_40_cbc returns a cipher that implements 40-bit RC2 in CBC mode. This + * is obviously very, very weak and is included only in order to read PKCS#12 + * files, which often encrypt the certificate chain using this cipher. It is + * deliberately not exported. */ +const EVP_CIPHER *EVP_rc2_40_cbc(void); + +/* EVP_get_cipherbynid returns the cipher corresponding to the given NID, or + * NULL if no such cipher is known. */ +OPENSSL_EXPORT const EVP_CIPHER *EVP_get_cipherbynid(int nid); + + +/* Cipher context allocation. + * + * An |EVP_CIPHER_CTX| represents the state of an encryption or decryption in + * progress. */ + +/* EVP_CIPHER_CTX_init initialises an, already allocated, |EVP_CIPHER_CTX|. */ +OPENSSL_EXPORT void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_new allocates a fresh |EVP_CIPHER_CTX|, calls + * |EVP_CIPHER_CTX_init| and returns it, or NULL on allocation failure. */ +OPENSSL_EXPORT EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void); + +/* EVP_CIPHER_CTX_cleanup frees any memory referenced by |ctx|. It returns + * one. */ +OPENSSL_EXPORT int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_free calls |EVP_CIPHER_CTX_cleanup| on |ctx| and then frees + * |ctx| itself. */ +OPENSSL_EXPORT void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_copy sets |out| to be a duplicate of the current state of + * |in|. The |out| argument must have been previously initialised. */ +OPENSSL_EXPORT int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, + const EVP_CIPHER_CTX *in); + + +/* Cipher context configuration. */ + +/* EVP_CipherInit_ex configures |ctx| for a fresh encryption (or decryption, if + * |enc| is zero) operation using |cipher|. If |ctx| has been previously + * configured with a cipher then |cipher|, |key| and |iv| may be |NULL| and + * |enc| may be -1 to reuse the previous values. The operation will use |key| + * as the key and |iv| as the IV (if any). These should have the correct + * lengths given by |EVP_CIPHER_key_length| and |EVP_CIPHER_iv_length|. It + * returns one on success and zero on error. */ +OPENSSL_EXPORT int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, + const EVP_CIPHER *cipher, ENGINE *engine, + const uint8_t *key, const uint8_t *iv, + int enc); + +/* EVP_EncryptInit_ex calls |EVP_CipherInit_ex| with |enc| equal to one. */ +OPENSSL_EXPORT int EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx, + const EVP_CIPHER *cipher, ENGINE *impl, + const uint8_t *key, const uint8_t *iv); + +/* EVP_DecryptInit_ex calls |EVP_CipherInit_ex| with |enc| equal to zero. */ +OPENSSL_EXPORT int EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx, + const EVP_CIPHER *cipher, ENGINE *impl, + const uint8_t *key, const uint8_t *iv); + + +/* Cipher operations. */ + +/* EVP_EncryptUpdate encrypts |in_len| bytes from |in| to |out|. The number + * of output bytes may be up to |in_len| plus the block length minus one and + * |out| must have sufficient space. The number of bytes actually output is + * written to |*out_len|. It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, + int *out_len, const uint8_t *in, + int in_len); + +/* EVP_EncryptFinal_ex writes at most a block of ciphertext to |out| and sets + * |*out_len| to the number of bytes written. If padding is enabled (the + * default) then standard padding is applied to create the final block. If + * padding is disabled (with |EVP_CIPHER_CTX_set_padding|) then any partial + * block remaining will cause an error. The function returns one on success and + * zero otherwise. */ +OPENSSL_EXPORT int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, uint8_t *out, + int *out_len); + +/* EVP_DecryptUpdate decrypts |in_len| bytes from |in| to |out|. The number of + * output bytes may be up to |in_len| plus the block length minus one and |out| + * must have sufficient space. The number of bytes actually output is written + * to |*out_len|. It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, + int *out_len, const uint8_t *in, + int in_len); + +/* EVP_DecryptFinal_ex writes at most a block of ciphertext to |out| and sets + * |*out_len| to the number of bytes written. If padding is enabled (the + * default) then padding is removed from the final block. + * + * WARNING: it is unsafe to call this function with unauthenticted + * ciphertext if padding is enabled. */ +OPENSSL_EXPORT int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, + int *out_len); + +/* EVP_Cipher performs a one-shot encryption/decryption operation. No partial + * blocks are maintained between calls. However, any internal cipher state is + * still updated. For CBC-mode ciphers, the IV is updated to the final + * ciphertext block. For stream ciphers, the stream is advanced past the bytes + * used. It returns one on success and zero otherwise, unless |EVP_CIPHER_flags| + * has |EVP_CIPH_FLAG_CUSTOM_CIPHER| set. Then it returns the number of bytes + * written or -1 on error. + * + * WARNING: this differs from the usual return value convention when using + * |EVP_CIPH_FLAG_CUSTOM_CIPHER|. + * + * TODO(davidben): The normal ciphers currently never fail, even if, e.g., + * |in_len| is not a multiple of the block size for CBC-mode decryption. The + * input just gets rounded up while the output gets truncated. This should + * either be officially documented or fail. */ +OPENSSL_EXPORT int EVP_Cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, + const uint8_t *in, size_t in_len); + +/* EVP_CipherUpdate calls either |EVP_EncryptUpdate| or |EVP_DecryptUpdate| + * depending on how |ctx| has been setup. */ +OPENSSL_EXPORT int EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, + int *out_len, const uint8_t *in, + int in_len); + +/* EVP_CipherFinal_ex calls either |EVP_EncryptFinal_ex| or + * |EVP_DecryptFinal_ex| depending on how |ctx| has been setup. */ +OPENSSL_EXPORT int EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, uint8_t *out, + int *out_len); + + +/* Cipher context accessors. */ + +/* EVP_CIPHER_CTX_cipher returns the |EVP_CIPHER| underlying |ctx|, or NULL if + * none has been set. */ +OPENSSL_EXPORT const EVP_CIPHER *EVP_CIPHER_CTX_cipher( + const EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_nid returns a NID identifying the |EVP_CIPHER| underlying + * |ctx| (e.g. |NID_aes_128_gcm|). It will crash if no cipher has been + * configured. */ +OPENSSL_EXPORT int EVP_CIPHER_CTX_nid(const EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_block_size returns the block size, in bytes, of the cipher + * underlying |ctx|, or one if the cipher is a stream cipher. It will crash if + * no cipher has been configured. */ +OPENSSL_EXPORT unsigned EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_key_length returns the key size, in bytes, of the cipher + * underlying |ctx| or zero if no cipher has been configured. */ +OPENSSL_EXPORT unsigned EVP_CIPHER_CTX_key_length(const EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_iv_length returns the IV size, in bytes, of the cipher + * underlying |ctx|. It will crash if no cipher has been configured. */ +OPENSSL_EXPORT unsigned EVP_CIPHER_CTX_iv_length(const EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_get_app_data returns the opaque, application data pointer for + * |ctx|, or NULL if none has been set. */ +OPENSSL_EXPORT void *EVP_CIPHER_CTX_get_app_data(const EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_set_app_data sets the opaque, application data pointer for + * |ctx| to |data|. */ +OPENSSL_EXPORT void EVP_CIPHER_CTX_set_app_data(EVP_CIPHER_CTX *ctx, + void *data); + +/* EVP_CIPHER_CTX_flags returns a value which is the OR of zero or more + * |EVP_CIPH_*| flags. It will crash if no cipher has been configured. */ +OPENSSL_EXPORT uint32_t EVP_CIPHER_CTX_flags(const EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_mode returns one of the |EVP_CIPH_*| cipher mode values + * enumerated below. It will crash if no cipher has been configured. */ +OPENSSL_EXPORT uint32_t EVP_CIPHER_CTX_mode(const EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_ctrl is an |ioctl| like function. The |command| argument + * should be one of the |EVP_CTRL_*| values. The |arg| and |ptr| arguments are + * specific to the command in question. */ +OPENSSL_EXPORT int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int command, + int arg, void *ptr); + +/* EVP_CIPHER_CTX_set_padding sets whether padding is enabled for |ctx| and + * returns one. Pass a non-zero |pad| to enable padding (the default) or zero + * to disable. */ +OPENSSL_EXPORT int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *ctx, int pad); + +/* EVP_CIPHER_CTX_set_key_length sets the key length for |ctx|. This is only + * valid for ciphers that can take a variable length key. It returns one on + * success and zero on error. */ +OPENSSL_EXPORT int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *ctx, unsigned key_len); + + +/* Cipher accessors. */ + +/* EVP_CIPHER_nid returns a NID identifing |cipher|. (For example, + * |NID_aes_128_gcm|.) */ +OPENSSL_EXPORT int EVP_CIPHER_nid(const EVP_CIPHER *cipher); + +/* EVP_CIPHER_block_size returns the block size, in bytes, for |cipher|, or one + * if |cipher| is a stream cipher. */ +OPENSSL_EXPORT unsigned EVP_CIPHER_block_size(const EVP_CIPHER *cipher); + +/* EVP_CIPHER_key_length returns the key size, in bytes, for |cipher|. If + * |cipher| can take a variable key length then this function returns the + * default key length and |EVP_CIPHER_flags| will return a value with + * |EVP_CIPH_VARIABLE_LENGTH| set. */ +OPENSSL_EXPORT unsigned EVP_CIPHER_key_length(const EVP_CIPHER *cipher); + +/* EVP_CIPHER_iv_length returns the IV size, in bytes, of |cipher|, or zero if + * |cipher| doesn't take an IV. */ +OPENSSL_EXPORT unsigned EVP_CIPHER_iv_length(const EVP_CIPHER *cipher); + +/* EVP_CIPHER_flags returns a value which is the OR of zero or more + * |EVP_CIPH_*| flags. */ +OPENSSL_EXPORT uint32_t EVP_CIPHER_flags(const EVP_CIPHER *cipher); + +/* EVP_CIPHER_mode returns one of the cipher mode values enumerated below. */ +OPENSSL_EXPORT uint32_t EVP_CIPHER_mode(const EVP_CIPHER *cipher); + + +/* Key derivation. */ + +/* EVP_BytesToKey generates a key and IV for the cipher |type| by iterating + * |md| |count| times using |data| and |salt|. On entry, the |key| and |iv| + * buffers must have enough space to hold a key and IV for |type|. It returns + * the length of the key on success or zero on error. */ +OPENSSL_EXPORT int EVP_BytesToKey(const EVP_CIPHER *type, const EVP_MD *md, + const uint8_t *salt, const uint8_t *data, + size_t data_len, unsigned count, uint8_t *key, + uint8_t *iv); + + +/* Cipher modes (for |EVP_CIPHER_mode|). */ + +#define EVP_CIPH_STREAM_CIPHER 0x0 +#define EVP_CIPH_ECB_MODE 0x1 +#define EVP_CIPH_CBC_MODE 0x2 +#define EVP_CIPH_CFB_MODE 0x3 +#define EVP_CIPH_OFB_MODE 0x4 +#define EVP_CIPH_CTR_MODE 0x5 +#define EVP_CIPH_GCM_MODE 0x6 + + +/* Cipher flags (for |EVP_CIPHER_flags|). */ + +/* EVP_CIPH_VARIABLE_LENGTH indicates that the cipher takes a variable length + * key. */ +#define EVP_CIPH_VARIABLE_LENGTH 0x40 + +/* EVP_CIPH_ALWAYS_CALL_INIT indicates that the |init| function for the cipher + * should always be called when initialising a new operation, even if the key + * is NULL to indicate that the same key is being used. */ +#define EVP_CIPH_ALWAYS_CALL_INIT 0x80 + +/* EVP_CIPH_CUSTOM_IV indicates that the cipher manages the IV itself rather + * than keeping it in the |iv| member of |EVP_CIPHER_CTX|. */ +#define EVP_CIPH_CUSTOM_IV 0x100 + +/* EVP_CIPH_CTRL_INIT indicates that EVP_CTRL_INIT should be used when + * initialising an |EVP_CIPHER_CTX|. */ +#define EVP_CIPH_CTRL_INIT 0x200 + +/* EVP_CIPH_FLAG_CUSTOM_CIPHER indicates that the cipher manages blocking + * itself. This causes EVP_(En|De)crypt_ex to be simple wrapper functions. */ +#define EVP_CIPH_FLAG_CUSTOM_CIPHER 0x400 + +/* EVP_CIPH_FLAG_AEAD_CIPHER specifies that the cipher is an AEAD. This is an + * older version of the proper AEAD interface. See aead.h for the current + * one. */ +#define EVP_CIPH_FLAG_AEAD_CIPHER 0x800 + +/* EVP_CIPH_CUSTOM_COPY indicates that the |ctrl| callback should be called + * with |EVP_CTRL_COPY| at the end of normal |EVP_CIPHER_CTX_copy| + * processing. */ +#define EVP_CIPH_CUSTOM_COPY 0x1000 + + +/* Deprecated functions */ + +/* EVP_CipherInit acts like EVP_CipherInit_ex except that |EVP_CIPHER_CTX_init| + * is called on |cipher| first, if |cipher| is not NULL. */ +OPENSSL_EXPORT int EVP_CipherInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, + const uint8_t *key, const uint8_t *iv, + int enc); + +/* EVP_EncryptInit calls |EVP_CipherInit| with |enc| equal to one. */ +OPENSSL_EXPORT int EVP_EncryptInit(EVP_CIPHER_CTX *ctx, + const EVP_CIPHER *cipher, const uint8_t *key, + const uint8_t *iv); + +/* EVP_DecryptInit calls |EVP_CipherInit| with |enc| equal to zero. */ +OPENSSL_EXPORT int EVP_DecryptInit(EVP_CIPHER_CTX *ctx, + const EVP_CIPHER *cipher, const uint8_t *key, + const uint8_t *iv); + +/* EVP_add_cipher_alias does nothing and returns one. */ +OPENSSL_EXPORT int EVP_add_cipher_alias(const char *a, const char *b); + +/* EVP_get_cipherbyname returns an |EVP_CIPHER| given a human readable name in + * |name|, or NULL if the name is unknown. */ +OPENSSL_EXPORT const EVP_CIPHER *EVP_get_cipherbyname(const char *name); + + +/* Private functions. */ + +/* EVP_CIPH_NO_PADDING disables padding in block ciphers. */ +#define EVP_CIPH_NO_PADDING 0x800 + +/* EVP_CIPHER_CTX_ctrl commands. */ +#define EVP_CTRL_INIT 0x0 +#define EVP_CTRL_SET_KEY_LENGTH 0x1 +#define EVP_CTRL_GET_RC2_KEY_BITS 0x2 +#define EVP_CTRL_SET_RC2_KEY_BITS 0x3 +#define EVP_CTRL_GET_RC5_ROUNDS 0x4 +#define EVP_CTRL_SET_RC5_ROUNDS 0x5 +#define EVP_CTRL_RAND_KEY 0x6 +#define EVP_CTRL_PBE_PRF_NID 0x7 +#define EVP_CTRL_COPY 0x8 +#define EVP_CTRL_GCM_SET_IVLEN 0x9 +#define EVP_CTRL_GCM_GET_TAG 0x10 +#define EVP_CTRL_GCM_SET_TAG 0x11 +#define EVP_CTRL_GCM_SET_IV_FIXED 0x12 +#define EVP_CTRL_GCM_IV_GEN 0x13 +#define EVP_CTRL_AEAD_SET_MAC_KEY 0x17 +/* Set the GCM invocation field, decrypt only */ +#define EVP_CTRL_GCM_SET_IV_INV 0x18 + +/* GCM TLS constants */ +/* Length of fixed part of IV derived from PRF */ +#define EVP_GCM_TLS_FIXED_IV_LEN 4 +/* Length of explicit part of IV part of TLS records */ +#define EVP_GCM_TLS_EXPLICIT_IV_LEN 8 +/* Length of tag for TLS */ +#define EVP_GCM_TLS_TAG_LEN 16 + +#define EVP_MAX_KEY_LENGTH 64 +#define EVP_MAX_IV_LENGTH 16 +#define EVP_MAX_BLOCK_LENGTH 32 + +struct evp_cipher_ctx_st { + /* cipher contains the underlying cipher for this context. */ + const EVP_CIPHER *cipher; + + /* app_data is a pointer to opaque, user data. */ + void *app_data; /* application stuff */ + + /* cipher_data points to the |cipher| specific state. */ + void *cipher_data; + + /* key_len contains the length of the key, which may differ from + * |cipher->key_len| if the cipher can take a variable key length. */ + unsigned key_len; + + /* encrypt is one if encrypting and zero if decrypting. */ + int encrypt; + + /* flags contains the OR of zero or more |EVP_CIPH_*| flags, above. */ + uint32_t flags; + + /* oiv contains the original IV value. */ + uint8_t oiv[EVP_MAX_IV_LENGTH]; + + /* iv contains the current IV value, which may have been updated. */ + uint8_t iv[EVP_MAX_IV_LENGTH]; + + /* buf contains a partial block which is used by, for example, CTR mode to + * store unused keystream bytes. */ + uint8_t buf[EVP_MAX_BLOCK_LENGTH]; + + /* buf_len contains the number of bytes of a partial block contained in + * |buf|. */ + int buf_len; + + /* num contains the number of bytes of |iv| which are valid for modes that + * manage partial blocks themselves. */ + int num; + + /* final_used is non-zero if the |final| buffer contains plaintext. */ + int final_used; + + /* block_mask contains |cipher->block_size| minus one. (The block size + * assumed to be a power of two.) */ + int block_mask; + + uint8_t final[EVP_MAX_BLOCK_LENGTH]; /* possible final block */ +} /* EVP_CIPHER_CTX */; + +typedef struct evp_cipher_info_st { + const EVP_CIPHER *cipher; + unsigned char iv[EVP_MAX_IV_LENGTH]; +} EVP_CIPHER_INFO; + +struct evp_cipher_st { + /* type contains a NID identifing the cipher. (e.g. NID_aes_128_gcm.) */ + int nid; + + /* block_size contains the block size, in bytes, of the cipher, or 1 for a + * stream cipher. */ + unsigned block_size; + + /* key_len contains the key size, in bytes, for the cipher. If the cipher + * takes a variable key size then this contains the default size. */ + unsigned key_len; + + /* iv_len contains the IV size, in bytes, or zero if inapplicable. */ + unsigned iv_len; + + /* ctx_size contains the size, in bytes, of the per-key context for this + * cipher. */ + unsigned ctx_size; + + /* flags contains the OR of a number of flags. See |EVP_CIPH_*|. */ + uint32_t flags; + + /* app_data is a pointer to opaque, user data. */ + void *app_data; + + int (*init)(EVP_CIPHER_CTX *ctx, const uint8_t *key, const uint8_t *iv, + int enc); + + int (*cipher)(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, + size_t inl); + + /* cleanup, if non-NULL, releases memory associated with the context. It is + * called if |EVP_CTRL_INIT| succeeds. Note that |init| may not have been + * called at this point. */ + void (*cleanup)(EVP_CIPHER_CTX *); + + int (*ctrl)(EVP_CIPHER_CTX *, int type, int arg, void *ptr); +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define CIPHER_R_AES_KEY_SETUP_FAILED 100 +#define CIPHER_R_BAD_DECRYPT 101 +#define CIPHER_R_BAD_KEY_LENGTH 102 +#define CIPHER_R_BUFFER_TOO_SMALL 103 +#define CIPHER_R_CTRL_NOT_IMPLEMENTED 104 +#define CIPHER_R_CTRL_OPERATION_NOT_IMPLEMENTED 105 +#define CIPHER_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH 106 +#define CIPHER_R_INITIALIZATION_ERROR 107 +#define CIPHER_R_INPUT_NOT_INITIALIZED 108 +#define CIPHER_R_INVALID_AD_SIZE 109 +#define CIPHER_R_INVALID_KEY_LENGTH 110 +#define CIPHER_R_INVALID_NONCE_SIZE 111 +#define CIPHER_R_INVALID_OPERATION 112 +#define CIPHER_R_IV_TOO_LARGE 113 +#define CIPHER_R_NO_CIPHER_SET 114 +#define CIPHER_R_OUTPUT_ALIASES_INPUT 115 +#define CIPHER_R_TAG_TOO_LARGE 116 +#define CIPHER_R_TOO_LARGE 117 +#define CIPHER_R_UNSUPPORTED_AD_SIZE 118 +#define CIPHER_R_UNSUPPORTED_INPUT_SIZE 119 +#define CIPHER_R_UNSUPPORTED_KEY_SIZE 120 +#define CIPHER_R_UNSUPPORTED_NONCE_SIZE 121 +#define CIPHER_R_UNSUPPORTED_TAG_SIZE 122 +#define CIPHER_R_WRONG_FINAL_BLOCK_LENGTH 123 +#define CIPHER_R_NO_DIRECTION_SET 124 + +#endif /* OPENSSL_HEADER_CIPHER_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/cmac.h b/TMessagesProj/jni/boringssl/include/openssl/cmac.h new file mode 100644 index 00000000..183f41bc --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/cmac.h @@ -0,0 +1,76 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_CMAC_H +#define OPENSSL_HEADER_CMAC_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* CMAC. + * + * CMAC is a MAC based on AES-CBC and defined in + * https://tools.ietf.org/html/rfc4493#section-2.3. */ + + +/* One-shot functions. */ + +/* AES_CMAC calculates the 16-byte, CMAC authenticator of |in_len| bytes of + * |in| and writes it to |out|. The |key_len| may be 16 or 32 bytes to select + * between AES-128 and AES-256. It returns one on success or zero on error. */ +OPENSSL_EXPORT int AES_CMAC(uint8_t out[16], const uint8_t *key, size_t key_len, + const uint8_t *in, size_t in_len); + + +/* Incremental interface. */ + +/* CMAC_CTX_new allocates a fresh |CMAC_CTX| and returns it, or NULL on + * error. */ +OPENSSL_EXPORT CMAC_CTX *CMAC_CTX_new(void); + +/* CMAC_CTX_free frees a |CMAC_CTX|. */ +OPENSSL_EXPORT void CMAC_CTX_free(CMAC_CTX *ctx); + +/* CMAC_Init configures |ctx| to use the given |key| and |cipher|. The CMAC RFC + * only specifies the use of AES-128 thus |key_len| should be 16 and |cipher| + * should be |EVP_aes_128_cbc()|. However, this implementation also supports + * AES-256 by setting |key_len| to 32 and |cipher| to |EVP_aes_256_cbc()|. The + * |engine| argument is ignored. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int CMAC_Init(CMAC_CTX *ctx, const void *key, size_t key_len, + const EVP_CIPHER *cipher, ENGINE *engine); + + +/* CMAC_Reset resets |ctx| so that a fresh message can be authenticated. */ +OPENSSL_EXPORT int CMAC_Reset(CMAC_CTX *ctx); + +/* CMAC_Update processes |in_len| bytes of message from |in|. It returns one on + * success or zero on error. */ +OPENSSL_EXPORT int CMAC_Update(CMAC_CTX *ctx, const uint8_t *in, size_t in_len); + +/* CMAC_Final sets |*out_len| to 16 and, if |out| is not NULL, writes 16 bytes + * of authenticator to it. It returns one on success or zero on error. */ +OPENSSL_EXPORT int CMAC_Final(CMAC_CTX *ctx, uint8_t *out, size_t *out_len); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_CBC_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/conf.h b/TMessagesProj/jni/boringssl/include/openssl/conf.h new file mode 100644 index 00000000..a2741a8a --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/conf.h @@ -0,0 +1,145 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_CONF_H +#define OPENSSL_HEADER_CONF_H + +#include + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Config files look like: + * + * # Comment + * + * # This key is in the default section. + * key=value + * + * [section_name] + * key2=value2 + * + * Config files are representated by a |CONF|. */ + +struct conf_value_st { + char *section; + char *name; + char *value; +}; + +struct conf_st { + LHASH_OF(CONF_VALUE) *data; +}; + + +/* NCONF_new returns a fresh, empty |CONF|, or NULL on error. The |method| + * argument must be NULL. */ +CONF *NCONF_new(void *method); + +/* NCONF_free frees all the data owned by |conf| and then |conf| itself. */ +void NCONF_free(CONF *conf); + +/* NCONF_load parses the file named |filename| and adds the values found to + * |conf|. It returns one on success and zero on error. In the event of an + * error, if |out_error_line| is not NULL, |*out_error_line| is set to the + * number of the line that contained the error. */ +int NCONF_load(CONF *conf, const char *filename, long *out_error_line); + +/* NCONF_load_bio acts like |NCONF_load| but reads from |bio| rather than from + * a named file. */ +int NCONF_load_bio(CONF *conf, BIO *bio, long *out_error_line); + +/* NCONF_get_section returns a stack of values for a given section in |conf|. + * If |section| is NULL, the default section is returned. It returns NULL on + * error. */ +STACK_OF(CONF_VALUE) *NCONF_get_section(const CONF *conf, const char *section); + +/* NCONF_get_string returns the value of the key |name|, in section |section|. + * The |section| argument may be NULL to indicate the default section. It + * returns the value or NULL on error. */ +const char *NCONF_get_string(const CONF *conf, const char *section, + const char *name); + + +/* Utility functions */ + +/* CONF_parse_list takes a list separated by 'sep' and calls |list_cb| giving + * the start and length of each member, optionally stripping leading and + * trailing whitespace. This can be used to parse comma separated lists for + * example. If |list_cb| returns <= 0, then the iteration is halted and that + * value is returned immediately. Otherwise it returns one. Note that |list_cb| + * may be called on an empty member. */ +int CONF_parse_list(const char *list, char sep, int remove_whitespace, + int (*list_cb)(const char *elem, int len, void *usr), + void *arg); + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define CONF_R_LIST_CANNOT_BE_NULL 100 +#define CONF_R_MISSING_CLOSE_SQUARE_BRACKET 101 +#define CONF_R_MISSING_EQUAL_SIGN 102 +#define CONF_R_NO_CLOSE_BRACE 103 +#define CONF_R_UNABLE_TO_CREATE_NEW_SECTION 104 +#define CONF_R_VARIABLE_HAS_NO_VALUE 105 + +#endif /* OPENSSL_HEADER_THREAD_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/cpu.h b/TMessagesProj/jni/boringssl/include/openssl/cpu.h new file mode 100644 index 00000000..981d246b --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/cpu.h @@ -0,0 +1,126 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef OPENSSL_HEADER_CPU_H +#define OPENSSL_HEADER_CPU_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Runtime CPU feature support */ + + +#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) +/* OPENSSL_ia32cap_P contains the Intel CPUID bits when running on an x86 or + * x86-64 system. + * + * Index 0: + * EDX for CPUID where EAX = 1 + * Bit 20 is always zero + * Bit 28 is adjusted to reflect whether the data cache is shared between + * multiple logical cores + * Bit 30 is used to indicate an Intel CPU + * Index 1: + * ECX for CPUID where EAX = 1 + * Bit 11 is used to indicate AMD XOP support, not SDBG + * Index 2: + * EBX for CPUID where EAX = 7 + * Index 3 is set to zero. + * + * Note: the CPUID bits are pre-adjusted for the OSXSAVE bit and the YMM and XMM + * bits in XCR0, so it is not necessary to check those. */ +extern uint32_t OPENSSL_ia32cap_P[4]; +#endif + +#if defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) +/* CRYPTO_is_NEON_capable returns true if the current CPU has a NEON unit. Note + * that |OPENSSL_armcap_P| also exists and contains the same information in a + * form that's easier for assembly to use. */ +OPENSSL_EXPORT char CRYPTO_is_NEON_capable(void); + +/* CRYPTO_set_NEON_capable sets the return value of |CRYPTO_is_NEON_capable|. + * By default, unless the code was compiled with |-mfpu=neon|, NEON is assumed + * not to be present. It is not autodetected. Calling this with a zero + * argument also causes |CRYPTO_is_NEON_functional| to return false. */ +OPENSSL_EXPORT void CRYPTO_set_NEON_capable(char neon_capable); + +/* CRYPTO_is_NEON_functional returns true if the current CPU has a /working/ + * NEON unit. Some phones have a NEON unit, but the Poly1305 NEON code causes + * it to fail. See https://code.google.com/p/chromium/issues/detail?id=341598 */ +OPENSSL_EXPORT char CRYPTO_is_NEON_functional(void); + +/* CRYPTO_set_NEON_functional sets the "NEON functional" flag. For + * |CRYPTO_is_NEON_functional| to return true, both this flag and the NEON flag + * must be true. By default NEON is assumed to be functional if the code was + * compiled with |-mfpu=neon| or if |CRYPTO_set_NEON_capable| has been called + * with a non-zero argument. */ +OPENSSL_EXPORT void CRYPTO_set_NEON_functional(char neon_functional); +#endif /* OPENSSL_ARM */ + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_CPU_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/crypto.h b/TMessagesProj/jni/boringssl/include/openssl/crypto.h new file mode 100644 index 00000000..5207a126 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/crypto.h @@ -0,0 +1,62 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_CRYPTO_H +#define OPENSSL_HEADER_CRYPTO_H + +#include + +/* Upstream OpenSSL defines |OPENSSL_malloc|, etc., in crypto.h rather than + * mem.h. */ +#include + +/* Upstream OpenSSL defines |CRYPTO_LOCK|, etc., in crypto.h rather than + * thread.h. */ +#include + + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* crypto.h contains functions for initializing the crypto library. */ + + +/* CRYPTO_library_init initializes the crypto library. It must be called if the + * library is built with BORINGSSL_NO_STATIC_INITIALIZER. Otherwise, it does + * nothing and a static initializer is used instead. */ +OPENSSL_EXPORT void CRYPTO_library_init(void); + + +/* Deprecated functions. */ + +#define OPENSSL_VERSION_TEXT "BoringSSL" + +#define SSLEAY_VERSION 0 + +/* SSLeay_version is a compatibility function that returns the string + * "BoringSSL". */ +OPENSSL_EXPORT const char *SSLeay_version(int unused); + +/* SSLeay is a compatibility function that returns OPENSSL_VERSION_NUMBER from + * base.h. */ +OPENSSL_EXPORT unsigned long SSLeay(void); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_CRYPTO_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/des.h b/TMessagesProj/jni/boringssl/include/openssl/des.h new file mode 100644 index 00000000..f9db62d6 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/des.h @@ -0,0 +1,164 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_DES_H +#define OPENSSL_HEADER_DES_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* DES. */ + + +typedef struct DES_cblock_st { + uint8_t bytes[8]; +} DES_cblock; + +typedef struct DES_ks { + uint32_t subkeys[16][2]; +} DES_key_schedule; + + +#define DES_KEY_SZ (sizeof(DES_cblock)) +#define DES_SCHEDULE_SZ (sizeof(DES_key_schedule)) + +#define DES_ENCRYPT 1 +#define DES_DECRYPT 0 + +#define DES_CBC_MODE 0 +#define DES_PCBC_MODE 1 + +/* DES_set_key performs a key schedule and initialises |schedule| with |key|. */ +OPENSSL_EXPORT void DES_set_key(const DES_cblock *key, + DES_key_schedule *schedule); + +/* DES_set_odd_parity sets the parity bits (the least-significant bits in each + * byte) of |key| given the other bits in each byte. */ +OPENSSL_EXPORT void DES_set_odd_parity(DES_cblock *key); + +/* DES_ecb_encrypt encrypts (or decrypts, if |is_encrypt| is |DES_DECRYPT|) a + * single DES block (8 bytes) from in to out, using the key configured in + * |schedule|. */ +OPENSSL_EXPORT void DES_ecb_encrypt(const DES_cblock *in, DES_cblock *out, + const DES_key_schedule *schedule, + int is_encrypt); + +/* DES_ncbc_encrypt encrypts (or decrypts, if |enc| is |DES_DECRYPT|) |len| + * bytes from |in| to |out| with DES in CBC mode. */ +OPENSSL_EXPORT void DES_ncbc_encrypt(const uint8_t *in, uint8_t *out, + size_t len, + const DES_key_schedule *schedule, + DES_cblock *ivec, int enc); + +/* DES_ecb3_encrypt encrypts (or decrypts, if |enc| is |DES_DECRYPT|) a single + * block (8 bytes) of data from |input| to |output| using 3DES. */ +OPENSSL_EXPORT void DES_ecb3_encrypt(const DES_cblock *input, + DES_cblock *output, + const DES_key_schedule *ks1, + const DES_key_schedule *ks2, + const DES_key_schedule *ks3, + int enc); + +/* DES_ede3_cbc_encrypt encrypts (or decrypts, if |enc| is |DES_DECRYPT|) |len| + * bytes from |in| to |out| with 3DES in CBC mode. 3DES uses three keys, thus + * the function takes three different |DES_key_schedule|s. */ +OPENSSL_EXPORT void DES_ede3_cbc_encrypt(const uint8_t *in, uint8_t *out, + size_t len, + const DES_key_schedule *ks1, + const DES_key_schedule *ks2, + const DES_key_schedule *ks3, + DES_cblock *ivec, int enc); + +/* DES_ede2_cbc_encrypt encrypts (or decrypts, if |enc| is |DES_DECRYPT|) |len| + * bytes from |in| to |out| with 3DES in CBC mode. With this keying option, the + * first and third 3DES keys are identical. Thus, this function takes only two + * different |DES_key_schedule|s. */ +OPENSSL_EXPORT void DES_ede2_cbc_encrypt(const uint8_t *in, uint8_t *out, + size_t len, + const DES_key_schedule *ks1, + const DES_key_schedule *ks2, + DES_cblock *ivec, int enc); + + +/* Deprecated functions. */ + +/* DES_set_key_unchecked calls |DES_set_key|. */ +OPENSSL_EXPORT void DES_set_key_unchecked(const DES_cblock *key, + DES_key_schedule *schedule); + +OPENSSL_EXPORT void DES_ede3_cfb64_encrypt(const uint8_t *in, uint8_t *out, + long length, DES_key_schedule *ks1, + DES_key_schedule *ks2, + DES_key_schedule *ks3, + DES_cblock *ivec, int *num, int enc); + +OPENSSL_EXPORT void DES_ede3_cfb_encrypt(const uint8_t *in, uint8_t *out, + int numbits, long length, + DES_key_schedule *ks1, + DES_key_schedule *ks2, + DES_key_schedule *ks3, + DES_cblock *ivec, int enc); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_DES_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/dh.h b/TMessagesProj/jni/boringssl/include/openssl/dh.h new file mode 100644 index 00000000..0174f07c --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/dh.h @@ -0,0 +1,270 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_DH_H +#define OPENSSL_HEADER_DH_H + +#include + +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* DH contains functions for performing Diffie-Hellman key agreement in + * multiplicative groups. */ + + +/* Allocation and destruction. */ + +/* DH_new returns a new, empty DH object or NULL on error. */ +OPENSSL_EXPORT DH *DH_new(void); + +/* DH_new_method acts the same as |DH_new| but takes an explicit |ENGINE|. */ +OPENSSL_EXPORT DH *DH_new_method(const ENGINE *engine); + +/* DH_free decrements the reference count of |dh| and frees it if the reference + * count drops to zero. */ +OPENSSL_EXPORT void DH_free(DH *dh); + +/* DH_up_ref increments the reference count of |dh|. */ +OPENSSL_EXPORT int DH_up_ref(DH *dh); + + +/* Standard parameters. + * + * These functions return new DH objects with standard parameters configured + * that use the given ENGINE, which may be NULL. They return NULL on allocation + * failure. */ + +/* These parameters are taken from RFC 5114. */ + +OPENSSL_EXPORT DH *DH_get_1024_160(const ENGINE *engine); +OPENSSL_EXPORT DH *DH_get_2048_224(const ENGINE *engine); +OPENSSL_EXPORT DH *DH_get_2048_256(const ENGINE *engine); + + +/* Parameter generation. */ + +#define DH_GENERATOR_2 2 +#define DH_GENERATOR_5 5 + +/* DH_generate_parameters_ex generates a suitable Diffie-Hellman group with a + * prime that is |prime_bits| long and stores it in |dh|. The generator of the + * group will be |generator|, which should be |DH_GENERATOR_2| unless there's a + * good reason to use a different value. The |cb| argument contains a callback + * function that will be called during the generation. See the documentation in + * |bn.h| about this. In addition to the callback invocations from |BN|, |cb| + * will also be called with |event| equal to three when the generation is + * complete. */ +OPENSSL_EXPORT int DH_generate_parameters_ex(DH *dh, int prime_bits, + int generator, BN_GENCB *cb); + + +/* Diffie-Hellman operations. */ + +/* DH_generate_key generates a new, random, private key and stores it in + * |dh|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int DH_generate_key(DH *dh); + +/* DH_compute_key calculates the shared key between |dh| and |peers_key| and + * writes it as a big-endian integer into |out|, which must have |DH_size| + * bytes of space. It returns the number of bytes written, or a negative number + * on error. */ +OPENSSL_EXPORT int DH_compute_key(uint8_t *out, const BIGNUM *peers_key, + DH *dh); + + +/* Utility functions. */ + +/* DH_size returns the number of bytes in the DH group's prime. */ +OPENSSL_EXPORT int DH_size(const DH *dh); + +/* DH_num_bits returns the minimum number of bits needed to represent the + * absolute value of the DH group's prime. */ +OPENSSL_EXPORT unsigned DH_num_bits(const DH *dh); + +#define DH_CHECK_P_NOT_PRIME 0x01 +#define DH_CHECK_P_NOT_SAFE_PRIME 0x02 +#define DH_CHECK_UNABLE_TO_CHECK_GENERATOR 0x04 +#define DH_CHECK_NOT_SUITABLE_GENERATOR 0x08 +#define DH_CHECK_Q_NOT_PRIME 0x10 +#define DH_CHECK_INVALID_Q_VALUE 0x20 +#define DH_CHECK_INVALID_J_VALUE 0x40 + +/* These are compatibility defines. */ +#define DH_NOT_SUITABLE_GENERATOR DH_CHECK_NOT_SUITABLE_GENERATOR +#define DH_UNABLE_TO_CHECK_GENERATOR DH_CHECK_UNABLE_TO_CHECK_GENERATOR + +/* DH_check checks the suitability of |dh| as a Diffie-Hellman group. and sets + * |DH_CHECK_*| flags in |*out_flags| if it finds any errors. It returns one if + * |*out_flags| was successfully set and zero on error. + * + * Note: these checks may be quite computationally expensive. */ +OPENSSL_EXPORT int DH_check(const DH *dh, int *out_flags); + +#define DH_CHECK_PUBKEY_TOO_SMALL 1 +#define DH_CHECK_PUBKEY_TOO_LARGE 2 + +/* DH_check_pub_key checks the suitability of |pub_key| as a public key for the + * DH group in |dh| and sets |DH_CHECK_PUBKEY_*| flags in |*out_flags| if it + * finds any errors. It returns one if |*out_flags| was successfully set and + * zero on error. */ +OPENSSL_EXPORT int DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, + int *out_flags); + +/* DHparams_dup allocates a fresh |DH| and copies the parameters from |dh| into + * it. It returns the new |DH| or NULL on error. */ +OPENSSL_EXPORT DH *DHparams_dup(const DH *dh); + + +/* ASN.1 functions. */ + +/* d2i_DHparams parses an ASN.1, DER encoded Diffie-Hellman parameters + * structure from |len| bytes at |*inp|. If |ret| is not NULL then, on exit, a + * pointer to the result is in |*ret|. If |*ret| is already non-NULL on entry + * then the result is written directly into |*ret|, otherwise a fresh |DH| is + * allocated. On successful exit, |*inp| is advanced past the DER structure. It + * returns the result or NULL on error. */ +OPENSSL_EXPORT DH *d2i_DHparams(DH **ret, const unsigned char **inp, long len); + +/* i2d_DHparams marshals |in| to an ASN.1, DER structure. If |outp| is not NULL + * then the result is written to |*outp| and |*outp| is advanced just past the + * output. It returns the number of bytes in the result, whether written or + * not, or a negative value on error. */ +OPENSSL_EXPORT int i2d_DHparams(const DH *in, unsigned char **outp); + + +/* ex_data functions. + * + * See |ex_data.h| for details. */ + +OPENSSL_EXPORT int DH_get_ex_new_index(long argl, void *argp, + CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func); +OPENSSL_EXPORT int DH_set_ex_data(DH *d, int idx, void *arg); +OPENSSL_EXPORT void *DH_get_ex_data(DH *d, int idx); + + +/* dh_method contains function pointers to override the implementation of DH. + * See |engine.h| for details. */ +struct dh_method { + struct openssl_method_common_st common; + + /* app_data is an opaque pointer for the method to use. */ + void *app_data; + + /* init is called just before the return of |DH_new_method|. It returns one + * on success or zero on error. */ + int (*init)(DH *dh); + + /* finish is called before |dh| is destructed. */ + void (*finish)(DH *dh); + + /* generate_parameters is called by |DH_generate_parameters_ex|. */ + int (*generate_parameters)(DH *dh, int prime_bits, int generator, + BN_GENCB *cb); + + /* generate_parameters is called by |DH_generate_key|. */ + int (*generate_key)(DH *dh); + + /* compute_key is called by |DH_compute_key|. */ + int (*compute_key)(DH *dh, uint8_t *out, const BIGNUM *pub_key); +}; + +struct dh_st { + DH_METHOD *meth; + + BIGNUM *p; + BIGNUM *g; + BIGNUM *pub_key; /* g^x */ + BIGNUM *priv_key; /* x */ + + /* priv_length contains the length, in bits, of the private value. If zero, + * the private value will be the same length as |p|. */ + unsigned priv_length; + + CRYPTO_MUTEX method_mont_p_lock; + BN_MONT_CTX *method_mont_p; + + /* Place holders if we want to do X9.42 DH */ + BIGNUM *q; + BIGNUM *j; + unsigned char *seed; + int seedlen; + BIGNUM *counter; + + int flags; + CRYPTO_refcount_t references; + CRYPTO_EX_DATA ex_data; +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define DH_R_BAD_GENERATOR 100 +#define DH_R_INVALID_PUBKEY 101 +#define DH_R_MODULUS_TOO_LARGE 102 +#define DH_R_NO_PRIVATE_VALUE 103 + +#endif /* OPENSSL_HEADER_DH_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/digest.h b/TMessagesProj/jni/boringssl/include/openssl/digest.h new file mode 100644 index 00000000..66be4d04 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/digest.h @@ -0,0 +1,257 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_DIGEST_H +#define OPENSSL_HEADER_DIGEST_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Digest functions. + * + * An EVP_MD abstracts the details of a specific hash function allowing code to + * deal with the concept of a "hash function" without needing to know exactly + * which hash function it is. */ + + +/* Hash algorithms. + * + * The following functions return |EVP_MD| objects that implement the named hash + * function. */ + +OPENSSL_EXPORT const EVP_MD *EVP_md4(void); +OPENSSL_EXPORT const EVP_MD *EVP_md5(void); +OPENSSL_EXPORT const EVP_MD *EVP_sha1(void); +OPENSSL_EXPORT const EVP_MD *EVP_sha224(void); +OPENSSL_EXPORT const EVP_MD *EVP_sha256(void); +OPENSSL_EXPORT const EVP_MD *EVP_sha384(void); +OPENSSL_EXPORT const EVP_MD *EVP_sha512(void); + +/* EVP_md5_sha1 is a TLS-specific |EVP_MD| which computes the concatenation of + * MD5 and SHA-1, as used in TLS 1.1 and below. */ +OPENSSL_EXPORT const EVP_MD *EVP_md5_sha1(void); + +/* EVP_get_digestbynid returns an |EVP_MD| for the given NID, or NULL if no + * such digest is known. */ +OPENSSL_EXPORT const EVP_MD *EVP_get_digestbynid(int nid); + +/* EVP_get_digestbyobj returns an |EVP_MD| for the given |ASN1_OBJECT|, or NULL + * if no such digest is known. */ +OPENSSL_EXPORT const EVP_MD *EVP_get_digestbyobj(const ASN1_OBJECT *obj); + + +/* Digest contexts. + * + * An EVP_MD_CTX represents the state of a specific digest operation in + * progress. */ + +/* EVP_MD_CTX_init initialises an, already allocated, |EVP_MD_CTX|. */ +OPENSSL_EXPORT void EVP_MD_CTX_init(EVP_MD_CTX *ctx); + +/* EVP_MD_CTX_create allocates and initialises a fresh |EVP_MD_CTX| and returns + * it, or NULL on allocation failure. */ +OPENSSL_EXPORT EVP_MD_CTX *EVP_MD_CTX_create(void); + +/* EVP_MD_CTX_cleanup frees any resources owned by |ctx| and resets it to a + * freshly initialised state. It does not free |ctx| itself. It returns one. */ +OPENSSL_EXPORT int EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx); + +/* EVP_MD_CTX_destroy calls |EVP_MD_CTX_cleanup| and then frees |ctx| itself. */ +OPENSSL_EXPORT void EVP_MD_CTX_destroy(EVP_MD_CTX *ctx); + +/* EVP_MD_CTX_copy_ex sets |out|, which must already be initialised, to be a + * copy of |in|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in); + + +/* Digest operations. */ + +/* EVP_DigestInit_ex configures |ctx|, which must already have been + * initialised, for a fresh hashing operation using |type|. It returns one on + * success and zero otherwise. */ +OPENSSL_EXPORT int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, + ENGINE *engine); + +/* EVP_DigestInit acts like |EVP_DigestInit_ex| except that |ctx| is + * initialised before use. */ +OPENSSL_EXPORT int EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type); + +/* EVP_DigestUpdate hashes |len| bytes from |data| into the hashing operation + * in |ctx|. It returns one. */ +OPENSSL_EXPORT int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *data, + size_t len); + +/* EVP_MAX_MD_SIZE is the largest digest size supported. Functions that output + * a digest generally require the buffer have at least this much space. */ +#define EVP_MAX_MD_SIZE 64 /* SHA-512 is the longest so far. */ + +/* EVP_DigestFinal_ex finishes the digest in |ctx| and writes the output to + * |md_out|. At most |EVP_MAX_MD_SIZE| bytes are written. If |out_size| is not + * NULL then |*out_size| is set to the number of bytes written. It returns one. + * After this call, the hash cannot be updated or finished again until + * |EVP_DigestInit_ex| is called to start another hashing operation. */ +OPENSSL_EXPORT int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, uint8_t *md_out, + unsigned int *out_size); + +/* EVP_DigestFinal acts like |EVP_DigestFinal_ex| except that + * |EVP_MD_CTX_cleanup| is called on |ctx| before returning. */ +OPENSSL_EXPORT int EVP_DigestFinal(EVP_MD_CTX *ctx, uint8_t *md_out, + unsigned int *out_size); + +/* EVP_Digest performs a complete hashing operation in one call. It hashes + * |len| bytes from |data| and writes the digest to |md_out|. At most + * |EVP_MAX_MD_SIZE| bytes are written. If |out_size| is not NULL then + * |*out_size| is set to the number of bytes written. It returns one on success + * and zero otherwise. */ +OPENSSL_EXPORT int EVP_Digest(const void *data, size_t len, uint8_t *md_out, + unsigned int *md_out_size, const EVP_MD *type, + ENGINE *impl); + + +/* Digest function accessors. + * + * These functions allow code to learn details about an abstract hash + * function. */ + +/* EVP_MD_type returns a NID identifing |md|. (For example, |NID_sha256|.) */ +OPENSSL_EXPORT int EVP_MD_type(const EVP_MD *md); + +/* EVP_MD_flags returns the flags for |md|, which is a set of |EVP_MD_FLAG_*| + * values, ORed together. */ +OPENSSL_EXPORT uint32_t EVP_MD_flags(const EVP_MD *md); + +/* EVP_MD_size returns the digest size of |md|, in bytes. */ +OPENSSL_EXPORT size_t EVP_MD_size(const EVP_MD *md); + +/* EVP_MD_block_size returns the native block-size of |md|. */ +OPENSSL_EXPORT size_t EVP_MD_block_size(const EVP_MD *md); + +/* EVP_MD_FLAG_PKEY_DIGEST indicates the the digest function is used with a + * specific public key in order to verify signatures. (For example, + * EVP_dss1.) */ +#define EVP_MD_FLAG_PKEY_DIGEST 1 + +/* EVP_MD_FLAG_DIGALGID_ABSENT indicates that the parameter type in an X.509 + * DigestAlgorithmIdentifier representing this digest function should be + * undefined rather than NULL. */ +#define EVP_MD_FLAG_DIGALGID_ABSENT 2 + + +/* Deprecated functions. */ + +/* EVP_MD_CTX_copy sets |out|, which must /not/ be initialised, to be a copy of + * |in|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int EVP_MD_CTX_copy(EVP_MD_CTX *out, const EVP_MD_CTX *in); + +/* EVP_add_digest does nothing and returns one. It exists only for + * compatibility with OpenSSL. */ +OPENSSL_EXPORT int EVP_add_digest(const EVP_MD *digest); + +/* EVP_get_cipherbyname returns an |EVP_MD| given a human readable name in + * |name|, or NULL if the name is unknown. */ +OPENSSL_EXPORT const EVP_MD *EVP_get_digestbyname(const char *); + + +/* Digest operation accessors. */ + +/* EVP_MD_CTX_md returns the underlying digest function, or NULL if one has not + * been set. */ +OPENSSL_EXPORT const EVP_MD *EVP_MD_CTX_md(const EVP_MD_CTX *ctx); + +/* EVP_MD_CTX_size returns the digest size of |ctx|. It will crash if a digest + * hasn't been set on |ctx|. */ +OPENSSL_EXPORT unsigned EVP_MD_CTX_size(const EVP_MD_CTX *ctx); + +/* EVP_MD_CTX_block_size returns the block size of the digest function used by + * |ctx|. It will crash if a digest hasn't been set on |ctx|. */ +OPENSSL_EXPORT unsigned EVP_MD_CTX_block_size(const EVP_MD_CTX *ctx); + +/* EVP_MD_CTX_type returns a NID describing the digest function used by |ctx|. + * (For example, |NID_sha256|.) It will crash if a digest hasn't been set on + * |ctx|. */ +OPENSSL_EXPORT int EVP_MD_CTX_type(const EVP_MD_CTX *ctx); + + +struct evp_md_pctx_ops; + +struct env_md_ctx_st { + /* digest is the underlying digest function, or NULL if not set. */ + const EVP_MD *digest; + /* md_data points to a block of memory that contains the hash-specific + * context. */ + void *md_data; + + /* pctx is an opaque (at this layer) pointer to additional context that + * EVP_PKEY functions may store in this object. */ + EVP_PKEY_CTX *pctx; + + /* pctx_ops, if not NULL, points to a vtable that contains functions to + * manipulate |pctx|. */ + const struct evp_md_pctx_ops *pctx_ops; +} /* EVP_MD_CTX */; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define DIGEST_R_INPUT_NOT_INITIALIZED 100 + +#endif /* OPENSSL_HEADER_DIGEST_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/dsa.h b/TMessagesProj/jni/boringssl/include/openssl/dsa.h new file mode 100644 index 00000000..b1e73091 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/dsa.h @@ -0,0 +1,374 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * The DSS routines are based on patches supplied by + * Steven Schoch . */ + +#ifndef OPENSSL_HEADER_DSA_H +#define OPENSSL_HEADER_DSA_H + +#include + +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* DSA contains functions for signing and verifing with the Digital Signature + * Algorithm. */ + + +/* Allocation and destruction. */ + +/* DSA_new returns a new, empty DSA object or NULL on error. */ +OPENSSL_EXPORT DSA *DSA_new(void); + +/* DSA_new_method acts the same as |DH_new| but takes an explicit |ENGINE|. */ +OPENSSL_EXPORT DSA *DSA_new_method(const ENGINE *engine); + +/* DSA_free decrements the reference count of |dsa| and frees it if the + * reference count drops to zero. */ +OPENSSL_EXPORT void DSA_free(DSA *dsa); + +/* DSA_up_ref increments the reference count of |dsa|. */ +OPENSSL_EXPORT int DSA_up_ref(DSA *dsa); + + +/* Parameter generation. */ + +/* DSA_generate_parameters_ex generates a set of DSA parameters by following + * the procedure given in FIPS 186-4, appendix A. + * (http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf) + * + * The larger prime will have a length of |bits| (e.g. 2048). The |seed| value + * allows others to generate and verify the same parameters and should be + * random input which is kept for reference. If |out_counter| or |out_h| are + * not NULL then the counter and h value used in the generation are written to + * them. + * + * The |cb| argument is passed to |BN_generate_prime_ex| and is thus called + * during the generation process in order to indicate progress. See the + * comments for that function for details. In addition to the calls made by + * |BN_generate_prime_ex|, |DSA_generate_parameters_ex| will call it with + * |event| equal to 2 and 3 at different stages of the process. + * + * It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int DSA_generate_parameters_ex(DSA *dsa, unsigned bits, + const uint8_t *seed, + size_t seed_len, int *out_counter, + unsigned long *out_h, + BN_GENCB *cb); + +/* DSAparams_dup returns a freshly allocated |DSA| that contains a copy of the + * parameters from |dsa|. It returns NULL on error. */ +OPENSSL_EXPORT DSA *DSAparams_dup(const DSA *dsa); + + +/* Key generation. */ + +/* DSA_generate_key generates a public/private key pair in |dsa|, which must + * already have parameters setup. It returns one on success and zero on + * error. */ +OPENSSL_EXPORT int DSA_generate_key(DSA *dsa); + + +/* Signatures. */ + +/* DSA_SIG contains a DSA signature as a pair of integers. */ +typedef struct DSA_SIG_st { + BIGNUM *r, *s; +} DSA_SIG; + +/* DSA_SIG_new returns a freshly allocated, DIG_SIG structure or NULL on error. + * Both |r| and |s| in the signature will be NULL. */ +OPENSSL_EXPORT DSA_SIG *DSA_SIG_new(void); + +/* DSA_SIG_free frees the contents of |sig| and then frees |sig| itself. */ +OPENSSL_EXPORT void DSA_SIG_free(DSA_SIG *sig); + +/* DSA_do_sign returns a signature of the hash in |digest| by the key in |dsa| + * and returns an allocated, DSA_SIG structure, or NULL on error. */ +OPENSSL_EXPORT DSA_SIG *DSA_do_sign(const uint8_t *digest, size_t digest_len, + DSA *dsa); + +/* DSA_do_verify verifies that |sig| is a valid signature, by the public key in + * |dsa|, of the hash in |digest|. It returns one if so, zero if invalid and -1 + * on error. + * + * WARNING: do not use. This function returns -1 for error, 0 for invalid and 1 + * for valid. However, this is dangerously different to the usual OpenSSL + * convention and could be a disaster if a user did |if (DSA_do_verify(...))|. + * Because of this, |DSA_check_signature| is a safer version of this. + * + * TODO(fork): deprecate. */ +OPENSSL_EXPORT int DSA_do_verify(const uint8_t *digest, size_t digest_len, + DSA_SIG *sig, const DSA *dsa); + +/* DSA_do_check_signature sets |*out_valid| to zero. Then it verifies that |sig| + * is a valid signature, by the public key in |dsa| of the hash in |digest| + * and, if so, it sets |*out_valid| to one. + * + * It returns one if it was able to verify the signature as valid or invalid, + * and zero on error. */ +OPENSSL_EXPORT int DSA_do_check_signature(int *out_valid, const uint8_t *digest, + size_t digest_len, DSA_SIG *sig, + const DSA *dsa); + + +/* ASN.1 signatures. + * + * These functions also perform DSA signature operations, but deal with ASN.1 + * encoded signatures as opposed to raw |BIGNUM|s. If you don't know what + * encoding a DSA signature is in, it's probably ASN.1. */ + +/* DSA_sign signs |digest| with the key in |dsa| and writes the resulting + * signature, in ASN.1 form, to |out_sig| and the length of the signature to + * |*out_siglen|. There must be, at least, |DSA_size(dsa)| bytes of space in + * |out_sig|. It returns one on success and zero otherwise. + * + * (The |type| argument is ignored.) */ +OPENSSL_EXPORT int DSA_sign(int type, const uint8_t *digest, size_t digest_len, + uint8_t *out_sig, unsigned int *out_siglen, + DSA *dsa); + +/* DSA_verify verifies that |sig| is a valid, ASN.1 signature, by the public + * key in |dsa|, of the hash in |digest|. It returns one if so, zero if invalid + * and -1 on error. + * + * (The |type| argument is ignored.) + * + * WARNING: do not use. This function returns -1 for error, 0 for invalid and 1 + * for valid. However, this is dangerously different to the usual OpenSSL + * convention and could be a disaster if a user did |if (DSA_do_verify(...))|. + * Because of this, |DSA_check_signature| is a safer version of this. + * + * TODO(fork): deprecate. */ +OPENSSL_EXPORT int DSA_verify(int type, const uint8_t *digest, + size_t digest_len, const uint8_t *sig, + size_t sig_len, const DSA *dsa); + +/* DSA_check_signature sets |*out_valid| to zero. Then it verifies that |sig| + * is a valid, ASN.1 signature, by the public key in |dsa|, of the hash in + * |digest|. If so, it sets |*out_valid| to one. + * + * It returns one if it was able to verify the signature as valid or invalid, + * and zero on error. */ +OPENSSL_EXPORT int DSA_check_signature(int *out_valid, const uint8_t *digest, + size_t digest_len, const uint8_t *sig, + size_t sig_len, const DSA *dsa); + +/* DSA_size returns the size, in bytes, of an ASN.1 encoded, DSA signature + * generated by |dsa|. Parameters must already have been setup in |dsa|. */ +OPENSSL_EXPORT int DSA_size(const DSA *dsa); + + +/* ASN.1 encoding. */ + +/* d2i_DSA_SIG parses an ASN.1, DER-encoded, DSA signature from |len| bytes at + * |*inp|. If |out_sig| is not NULL then, on exit, a pointer to the result is + * in |*out_sig|. If |*out_sig| is already non-NULL on entry then the result is + * written directly into |*out_sig|, otherwise a fresh |DSA_SIG| is allocated. + * On successful exit, |*inp| is advanced past the DER structure. It returns + * the result or NULL on error. */ +OPENSSL_EXPORT DSA_SIG *d2i_DSA_SIG(DSA_SIG **out_sig, const uint8_t **inp, + long len); + +/* i2d_DSA_SIG marshals |in| to an ASN.1, DER structure. If |outp| is not NULL + * then the result is written to |*outp| and |*outp| is advanced just past the + * output. It returns the number of bytes in the result, whether written or not, + * or a negative value on error. */ +OPENSSL_EXPORT int i2d_DSA_SIG(const DSA_SIG *in, uint8_t **outp); + +/* d2i_DSAPublicKey parses an ASN.1, DER-encoded, DSA public key from |len| + * bytes at |*inp|. If |out| is not NULL then, on exit, a pointer to the result + * is in |*out|. If |*out| is already non-NULL on entry then the result is + * written directly into |*out|, otherwise a fresh |DSA| is allocated. On + * successful exit, |*inp| is advanced past the DER structure. It returns the + * result or NULL on error. */ +OPENSSL_EXPORT DSA *d2i_DSAPublicKey(DSA **out, const uint8_t **inp, long len); + +/* i2d_DSAPublicKey marshals a public key from |in| to an ASN.1, DER structure. + * If |outp| is not NULL then the result is written to |*outp| and |*outp| is + * advanced just past the output. It returns the number of bytes in the result, + * whether written or not, or a negative value on error. */ +OPENSSL_EXPORT int i2d_DSAPublicKey(const DSA *in, unsigned char **outp); + +/* d2i_DSAPrivateKey parses an ASN.1, DER-encoded, DSA private key from |len| + * bytes at |*inp|. If |out| is not NULL then, on exit, a pointer to the result + * is in |*out|. If |*out| is already non-NULL on entry then the result is + * written directly into |*out|, otherwise a fresh |DSA| is allocated. On + * successful exit, |*inp| is advanced past the DER structure. It returns the + * result or NULL on error. */ +OPENSSL_EXPORT DSA *d2i_DSAPrivateKey(DSA **out, const uint8_t **inp, long len); + +/* i2d_DSAPrivateKey marshals a private key from |in| to an ASN.1, DER structure. + * If |outp| is not NULL then the result is written to |*outp| and |*outp| is + * advanced just past the output. It returns the number of bytes in the result, + * whether written or not, or a negative value on error. */ +OPENSSL_EXPORT int i2d_DSAPrivateKey(const DSA *in, unsigned char **outp); + +/* d2i_DSAparams parses ASN.1, DER-encoded, DSA parameters from |len| bytes at + * |*inp|. If |out| is not NULL then, on exit, a pointer to the result is in + * |*out|. If |*out| is already non-NULL on entry then the result is written + * directly into |*out|, otherwise a fresh |DSA| is allocated. On successful + * exit, |*inp| is advanced past the DER structure. It returns the result or + * NULL on error. */ +OPENSSL_EXPORT DSA *d2i_DSAparams(DSA **out, const uint8_t **inp, long len); + +/* i2d_DSAparams marshals DSA parameters from |in| to an ASN.1, DER structure. + * If |outp| is not NULL then the result is written to |*outp| and |*outp| is + * advanced just past the output. It returns the number of bytes in the result, + * whether written or not, or a negative value on error. */ +OPENSSL_EXPORT int i2d_DSAparams(const DSA *in, unsigned char **outp); + + +/* Precomputation. */ + +/* DSA_sign_setup precomputes the message independent part of the DSA signature + * and writes them to |*out_kinv| and |*out_r|. Returns one on success, zero on + * error. + * + * TODO(fork): decide what to do with this. Since making DSA* opaque there's no + * way for the user to install them. Also, it forces the DSA* not to be const + * when passing to the signing function. */ +OPENSSL_EXPORT int DSA_sign_setup(const DSA *dsa, BN_CTX *ctx, + BIGNUM **out_kinv, BIGNUM **out_r); + + +/* Conversion. */ + +/* DSA_dup_DH returns a |DH| constructed from the parameters of |dsa|. This is + * sometimes needed when Diffie-Hellman parameters are stored in the form of + * DSA parameters. It returns an allocated |DH| on success or NULL on error. */ +OPENSSL_EXPORT DH *DSA_dup_DH(const DSA *dsa); + + +/* ex_data functions. + * + * See |ex_data.h| for details. */ + +OPENSSL_EXPORT int DSA_get_ex_new_index(long argl, void *argp, + CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func); +OPENSSL_EXPORT int DSA_set_ex_data(DSA *d, int idx, void *arg); +OPENSSL_EXPORT void *DSA_get_ex_data(const DSA *d, int idx); + + +struct dsa_method { + struct openssl_method_common_st common; + + void *app_data; + + int (*init)(DSA *dsa); + int (*finish)(DSA *dsa); + + DSA_SIG *(*sign)(const uint8_t *digest, size_t digest_len, DSA *dsa); + + int (*sign_setup)(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp, + const uint8_t *digest, size_t digest_len); + + int (*verify)(int *out_valid, const uint8_t *digest, size_t digest_len, + DSA_SIG *sig, const DSA *dsa); + + /* generate_parameters, if non-NULL, is used to generate DSA parameters. */ + int (*generate_parameters)(DSA *dsa, unsigned bits, const uint8_t *seed, + size_t seed_len, int *counter_ret, + unsigned long *h_ret, BN_GENCB *cb); + + /* keygen, if non-NULL, is used to generate DSA keys. */ + int (*keygen)(DSA *dsa); +}; + +struct dsa_st { + long version; + int write_params; + BIGNUM *p; + BIGNUM *q; /* == 20 */ + BIGNUM *g; + + BIGNUM *pub_key; /* y public key */ + BIGNUM *priv_key; /* x private key */ + + BIGNUM *kinv; /* Signing pre-calc */ + BIGNUM *r; /* Signing pre-calc */ + + int flags; + /* Normally used to cache montgomery values */ + CRYPTO_MUTEX method_mont_p_lock; + BN_MONT_CTX *method_mont_p; + CRYPTO_refcount_t references; + CRYPTO_EX_DATA ex_data; + DSA_METHOD *meth; + /* functional reference if 'meth' is ENGINE-provided */ + ENGINE *engine; +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define DSA_R_BAD_Q_VALUE 100 +#define DSA_R_MISSING_PARAMETERS 101 +#define DSA_R_MODULUS_TOO_LARGE 102 +#define DSA_R_NEED_NEW_SETUP_VALUES 103 + +#endif /* OPENSSL_HEADER_DSA_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/dtls1.h b/TMessagesProj/jni/boringssl/include/openssl/dtls1.h new file mode 100644 index 00000000..38ca801c --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/dtls1.h @@ -0,0 +1,16 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is provided in order to make compiling against code that expects + OpenSSL easier. */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/ec.h b/TMessagesProj/jni/boringssl/include/openssl/ec.h new file mode 100644 index 00000000..f664211c --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/ec.h @@ -0,0 +1,366 @@ +/* Originally written by Bodo Moeller for the OpenSSL project. + * ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * The elliptic curve binary polynomial software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems + * Laboratories. */ + +#ifndef OPENSSL_HEADER_EC_H +#define OPENSSL_HEADER_EC_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Low-level operations on elliptic curves. */ + + +typedef struct ec_group_st EC_GROUP; +typedef struct ec_point_st EC_POINT; + +/** Enum for the point conversion form as defined in X9.62 (ECDSA) + * for the encoding of a elliptic curve point (x,y) */ +typedef enum { + /** the point is encoded as z||x, where the octet z specifies + * which solution of the quadratic equation y is */ + POINT_CONVERSION_COMPRESSED = 2, + /** the point is encoded as z||x||y, where z is the octet 0x02 */ + POINT_CONVERSION_UNCOMPRESSED = 4 +} point_conversion_form_t; + + +/* Elliptic curve groups. */ + +/* EC_GROUP_new_by_curve_name returns a fresh EC_GROUP object for the elliptic + * curve specified by |nid|, or NULL on error. + * + * The supported NIDs are: + * NID_secp224r1, + * NID_X9_62_prime256v1, + * NID_secp384r1, + * NID_secp521r1 */ +OPENSSL_EXPORT EC_GROUP *EC_GROUP_new_by_curve_name(int nid); + +/* EC_GROUP_free frees |group| and the data that it points to. */ +OPENSSL_EXPORT void EC_GROUP_free(EC_GROUP *group); + +/* EC_GROUP_dup returns a fresh |EC_GROUP| which is equal to |a| or NULL on + * error. */ +OPENSSL_EXPORT EC_GROUP *EC_GROUP_dup(const EC_GROUP *a); + +/* EC_GROUP_cmp returns zero if |a| and |b| are the same group and non-zero + * otherwise. */ +OPENSSL_EXPORT int EC_GROUP_cmp(const EC_GROUP *a, const EC_GROUP *b, + BN_CTX *ignored); + +/* EC_GROUP_get0_generator returns a pointer to the internal |EC_POINT| object + * in |group| that specifies the generator for the group. */ +OPENSSL_EXPORT const EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *group); + +/* EC_GROUP_get_order sets |*order| to the order of |group|, if it's not + * NULL. It returns one on success and zero otherwise. |ctx| is ignored. */ +OPENSSL_EXPORT int EC_GROUP_get_order(const EC_GROUP *group, BIGNUM *order, + BN_CTX *ctx); + +/* EC_GROUP_get_cofactor sets |*cofactor| to the cofactor of |group| using + * |ctx|, if it's not NULL. It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int EC_GROUP_get_cofactor(const EC_GROUP *group, + BIGNUM *cofactor, BN_CTX *ctx); + +/* EC_GROUP_get_curve_GFp gets various parameters about a group. It sets + * |*out_p| to the order of the coordinate field and |*out_a| and |*out_b| to + * the parameters of the curve when expressed as y² = x³ + ax + b. Any of the + * output parameters can be NULL. It returns one on success and zero on + * error. */ +OPENSSL_EXPORT int EC_GROUP_get_curve_GFp(const EC_GROUP *group, BIGNUM *out_p, + BIGNUM *out_a, BIGNUM *out_b, + BN_CTX *ctx); + +/* EC_GROUP_get_curve_name returns a NID that identifies |group|. */ +OPENSSL_EXPORT int EC_GROUP_get_curve_name(const EC_GROUP *group); + +/* EC_GROUP_get_degree returns the number of bits needed to represent an + * element of the field underlying |group|. */ +OPENSSL_EXPORT int EC_GROUP_get_degree(const EC_GROUP *group); + +/* EC_GROUP_precompute_mult precomputes multiplies of the generator in order to + * speed up operations that involve calculating generator multiples. It returns + * one on sucess and zero otherwise. If |ctx| is not NULL, it may be used. */ +OPENSSL_EXPORT int EC_GROUP_precompute_mult(EC_GROUP *group, BN_CTX *ctx); + +/* EC_GROUP_have_precompute_mult returns one if |group| contains precomputed + * generator multiples. */ +OPENSSL_EXPORT int EC_GROUP_have_precompute_mult(const EC_GROUP *group); + + +/* Points on elliptic curves. */ + +/* EC_POINT_new returns a fresh |EC_POINT| object in the given group, or NULL + * on error. */ +OPENSSL_EXPORT EC_POINT *EC_POINT_new(const EC_GROUP *group); + +/* EC_POINT_free frees |point| and the data that it points to. */ +OPENSSL_EXPORT void EC_POINT_free(EC_POINT *point); + +/* EC_POINT_clear_free clears the data that |point| points to, frees it and + * then frees |point| itself. */ +OPENSSL_EXPORT void EC_POINT_clear_free(EC_POINT *point); + +/* EC_POINT_copy sets |*dest| equal to |*src|. It returns one on success and + * zero otherwise. */ +OPENSSL_EXPORT int EC_POINT_copy(EC_POINT *dest, const EC_POINT *src); + +/* EC_POINT_dup returns a fresh |EC_POINT| that contains the same values as + * |src|, or NULL on error. */ +OPENSSL_EXPORT EC_POINT *EC_POINT_dup(const EC_POINT *src, + const EC_GROUP *group); + +/* EC_POINT_set_to_infinity sets |point| to be the "point at infinity" for the + * given group. */ +OPENSSL_EXPORT int EC_POINT_set_to_infinity(const EC_GROUP *group, + EC_POINT *point); + +/* EC_POINT_is_at_infinity returns one iff |point| is the point at infinity and + * zero otherwise. */ +OPENSSL_EXPORT int EC_POINT_is_at_infinity(const EC_GROUP *group, + const EC_POINT *point); + +/* EC_POINT_is_on_curve returns one if |point| is an element of |group| and + * zero otheriwse. If |ctx| is non-NULL, it may be used. */ +OPENSSL_EXPORT int EC_POINT_is_on_curve(const EC_GROUP *group, + const EC_POINT *point, BN_CTX *ctx); + +/* EC_POINT_cmp returns zero if |a| is equal to |b|, greater than zero is + * non-equal and -1 on error. If |ctx| is not NULL, it may be used. */ +OPENSSL_EXPORT int EC_POINT_cmp(const EC_GROUP *group, const EC_POINT *a, + const EC_POINT *b, BN_CTX *ctx); + +/* EC_POINT_make_affine converts |point| to affine form, internally. It returns + * one on success and zero otherwise. If |ctx| is not NULL, it may be used. */ +OPENSSL_EXPORT int EC_POINT_make_affine(const EC_GROUP *group, EC_POINT *point, + BN_CTX *ctx); + +/* EC_POINTs_make_affine converts |num| points from |points| to affine form, + * internally. It returns one on success and zero otherwise. If |ctx| is not + * NULL, it may be used. */ +OPENSSL_EXPORT int EC_POINTs_make_affine(const EC_GROUP *group, size_t num, + EC_POINT *points[], BN_CTX *ctx); + + +/* Point conversion. */ + +/* EC_POINT_get_affine_coordinates_GFp sets |x| and |y| to the affine value of + * |point| using |ctx|, if it's not NULL. It returns one on success and zero + * otherwise. */ +OPENSSL_EXPORT int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *group, + const EC_POINT *point, + BIGNUM *x, BIGNUM *y, + BN_CTX *ctx); + +/* EC_POINT_set_affine_coordinates_GFp sets the value of |p| to be (|x|, |y|). The + * |ctx| argument may be used if not NULL. */ +OPENSSL_EXPORT int EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *group, + EC_POINT *point, + const BIGNUM *x, + const BIGNUM *y, + BN_CTX *ctx); + +/* EC_POINT_point2oct serialises |point| into the X9.62 form given by |form| + * into, at most, |len| bytes at |buf|. It returns the number of bytes written + * or zero on error if |buf| is non-NULL, else the number of bytes needed. The + * |ctx| argument may be used if not NULL. */ +OPENSSL_EXPORT size_t EC_POINT_point2oct(const EC_GROUP *group, + const EC_POINT *point, + point_conversion_form_t form, + uint8_t *buf, size_t len, BN_CTX *ctx); + +/* EC_POINT_oct2point sets |point| from |len| bytes of X9.62 format + * serialisation in |buf|. It returns one on success and zero otherwise. The + * |ctx| argument may be used if not NULL. */ +OPENSSL_EXPORT int EC_POINT_oct2point(const EC_GROUP *group, EC_POINT *point, + const uint8_t *buf, size_t len, + BN_CTX *ctx); + +/* EC_POINT_set_compressed_coordinates_GFp sets |point| to equal the point with + * the given |x| coordinate and the y coordinate specified by |y_bit| (see + * X9.62). It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int EC_POINT_set_compressed_coordinates_GFp( + const EC_GROUP *group, EC_POINT *point, const BIGNUM *x, int y_bit, + BN_CTX *ctx); + + +/* Group operations. */ + +/* EC_POINT_add sets |r| equal to |a| plus |b|. It returns one on success and + * zero otherwise. If |ctx| is not NULL, it may be used. */ +OPENSSL_EXPORT int EC_POINT_add(const EC_GROUP *group, EC_POINT *r, + const EC_POINT *a, const EC_POINT *b, + BN_CTX *ctx); + +/* EC_POINT_dbl sets |r| equal to |a| plus |a|. It returns one on success and + * zero otherwise. If |ctx| is not NULL, it may be used. */ +OPENSSL_EXPORT int EC_POINT_dbl(const EC_GROUP *group, EC_POINT *r, + const EC_POINT *a, BN_CTX *ctx); + +/* EC_POINT_invert sets |a| equal to minus |a|. It returns one on success and zero + * otherwise. If |ctx| is not NULL, it may be used. */ +OPENSSL_EXPORT int EC_POINT_invert(const EC_GROUP *group, EC_POINT *a, + BN_CTX *ctx); + +/* EC_POINT_mul sets r = generator*n + q*m. It returns one on success and zero + * otherwise. If |ctx| is not NULL, it may be used. */ +OPENSSL_EXPORT int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, + const BIGNUM *n, const EC_POINT *q, + const BIGNUM *m, BN_CTX *ctx); + +/* EC_POINTs_mul sets r = generator*n + sum(p[i]*m[i]). It returns one on + * success and zero otherwise. If |ctx| is not NULL, it may be used. */ +OPENSSL_EXPORT int EC_POINTs_mul(const EC_GROUP *group, EC_POINT *r, + const BIGNUM *n, size_t num, + const EC_POINT *p[], const BIGNUM *m[], + BN_CTX *ctx); + + +/* Deprecated functions. */ + +/* EC_GROUP_new_curve_GFp creates a new, arbitrary elliptic curve group based + * on the equation y² = x³ + a·x + b. It returns the new group or NULL on + * error. + * + * |EC_GROUP|s returned by this function will always compare as unequal via + * |EC_GROUP_cmp| (even to themselves). |EC_GROUP_get_curve_name| will always + * return |NID_undef|. */ +OPENSSL_EXPORT EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, + const BIGNUM *a, + const BIGNUM *b, BN_CTX *ctx); + +/* EC_GROUP_set_generator sets the generator for |group| to |generator|, which + * must have the given order and cofactor. This should only be used with + * |EC_GROUP| objects returned by |EC_GROUP_new_curve_GFp|. */ +OPENSSL_EXPORT int EC_GROUP_set_generator(EC_GROUP *group, + const EC_POINT *generator, + const BIGNUM *order, + const BIGNUM *cofactor); + +/* EC_GROUP_set_asn1_flag does nothing. */ +OPENSSL_EXPORT void EC_GROUP_set_asn1_flag(EC_GROUP *group, int flag); + +#define OPENSSL_EC_NAMED_CURVE 0 + +typedef struct ec_method_st EC_METHOD; + +/* EC_GROUP_method_of returns NULL. */ +OPENSSL_EXPORT const EC_METHOD *EC_GROUP_method_of(const EC_GROUP *group); + +/* EC_METHOD_get_field_type returns NID_X9_62_prime_field. */ +OPENSSL_EXPORT int EC_METHOD_get_field_type(const EC_METHOD *meth); + +/* EC_GROUP_set_point_conversion_form aborts the process if |form| is not + * |POINT_CONVERSION_UNCOMPRESSED| and otherwise does nothing. */ +OPENSSL_EXPORT void EC_GROUP_set_point_conversion_form( + EC_GROUP *group, point_conversion_form_t form); + + +/* Old code expects to get EC_KEY from ec.h. */ +#if !defined(OPENSSL_HEADER_EC_KEY_H) +#include +#endif + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define EC_R_BUFFER_TOO_SMALL 100 +#define EC_R_COORDINATES_OUT_OF_RANGE 101 +#define EC_R_D2I_ECPKPARAMETERS_FAILURE 102 +#define EC_R_EC_GROUP_NEW_BY_NAME_FAILURE 103 +#define EC_R_GROUP2PKPARAMETERS_FAILURE 104 +#define EC_R_I2D_ECPKPARAMETERS_FAILURE 105 +#define EC_R_INCOMPATIBLE_OBJECTS 106 +#define EC_R_INVALID_COMPRESSED_POINT 107 +#define EC_R_INVALID_COMPRESSION_BIT 108 +#define EC_R_INVALID_ENCODING 109 +#define EC_R_INVALID_FIELD 110 +#define EC_R_INVALID_FORM 111 +#define EC_R_INVALID_GROUP_ORDER 112 +#define EC_R_INVALID_PRIVATE_KEY 113 +#define EC_R_MISSING_PARAMETERS 114 +#define EC_R_MISSING_PRIVATE_KEY 115 +#define EC_R_NON_NAMED_CURVE 116 +#define EC_R_NOT_INITIALIZED 117 +#define EC_R_PKPARAMETERS2GROUP_FAILURE 118 +#define EC_R_POINT_AT_INFINITY 119 +#define EC_R_POINT_IS_NOT_ON_CURVE 120 +#define EC_R_SLOT_FULL 121 +#define EC_R_UNDEFINED_GENERATOR 122 +#define EC_R_UNKNOWN_GROUP 123 +#define EC_R_UNKNOWN_ORDER 124 +#define EC_R_WRONG_ORDER 125 +#define EC_R_BIGNUM_OUT_OF_RANGE 126 +#define EC_R_WRONG_CURVE_PARAMETERS 127 + +#endif /* OPENSSL_HEADER_EC_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/ec_key.h b/TMessagesProj/jni/boringssl/include/openssl/ec_key.h new file mode 100644 index 00000000..1cd4e6e6 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/ec_key.h @@ -0,0 +1,286 @@ +/* Originally written by Bodo Moeller for the OpenSSL project. + * ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * The elliptic curve binary polynomial software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems + * Laboratories. */ + +#ifndef OPENSSL_HEADER_EC_KEY_H +#define OPENSSL_HEADER_EC_KEY_H + +#include + +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* ec_key.h contains functions that handle elliptic-curve points that are + * public/private keys. */ + + +/* EC key objects. */ + +/* EC_KEY_new returns a fresh |EC_KEY| object or NULL on error. */ +OPENSSL_EXPORT EC_KEY *EC_KEY_new(void); + +/* EC_KEY_new_method acts the same as |EC_KEY_new|, but takes an explicit + * |ENGINE|. */ +OPENSSL_EXPORT EC_KEY *EC_KEY_new_method(const ENGINE *engine); + +/* EC_KEY_new_by_curve_name returns a fresh EC_KEY for group specified by |nid| + * or NULL on error. */ +OPENSSL_EXPORT EC_KEY *EC_KEY_new_by_curve_name(int nid); + +/* EC_KEY_free frees all the data owned by |key| and |key| itself. */ +OPENSSL_EXPORT void EC_KEY_free(EC_KEY *key); + +/* EC_KEY_copy sets |dst| equal to |src| and returns |dst| or NULL on error. */ +OPENSSL_EXPORT EC_KEY *EC_KEY_copy(EC_KEY *dst, const EC_KEY *src); + +/* EC_KEY_dup returns a fresh copy of |src| or NULL on error. */ +OPENSSL_EXPORT EC_KEY *EC_KEY_dup(const EC_KEY *src); + +/* EC_KEY_up_ref increases the reference count of |key|. It returns one on + * success and zero otherwise. */ +OPENSSL_EXPORT int EC_KEY_up_ref(EC_KEY *key); + +/* EC_KEY_is_opaque returns one if |key| is opaque and doesn't expose its key + * material. Otherwise it return zero. */ +OPENSSL_EXPORT int EC_KEY_is_opaque(const EC_KEY *key); + +/* EC_KEY_get0_group returns a pointer to the |EC_GROUP| object inside |key|. */ +OPENSSL_EXPORT const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key); + +/* EC_KEY_set_group sets the |EC_GROUP| object that |key| will use to |group|. + * It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int EC_KEY_set_group(EC_KEY *key, const EC_GROUP *group); + +/* EC_KEY_get0_private_key returns a pointer to the private key inside |key|. */ +OPENSSL_EXPORT const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *key); + +/* EC_KEY_set_private_key sets the private key of |key| to |priv|. It returns + * one on success and zero otherwise. */ +OPENSSL_EXPORT int EC_KEY_set_private_key(EC_KEY *key, const BIGNUM *prv); + +/* EC_KEY_get0_public_key returns a pointer to the public key point inside + * |key|. */ +OPENSSL_EXPORT const EC_POINT *EC_KEY_get0_public_key(const EC_KEY *key); + +/* EC_KEY_set_public_key sets the public key of |key| to |pub|, by copying it. + * It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int EC_KEY_set_public_key(EC_KEY *key, const EC_POINT *pub); + +#define EC_PKEY_NO_PARAMETERS 0x001 +#define EC_PKEY_NO_PUBKEY 0x002 + +/* EC_KEY_get_enc_flags returns the encoding flags for |key|, which is a + * bitwise-OR of |EC_PKEY_*| values. */ +OPENSSL_EXPORT unsigned EC_KEY_get_enc_flags(const EC_KEY *key); + +/* EC_KEY_set_enc_flags sets the encoding flags for |key|, which is a + * bitwise-OR of |EC_PKEY_*| values. */ +OPENSSL_EXPORT void EC_KEY_set_enc_flags(EC_KEY *key, unsigned flags); + +/* EC_KEY_get_conv_form returns the conversation form that will be used by + * |key|. */ +OPENSSL_EXPORT point_conversion_form_t EC_KEY_get_conv_form(const EC_KEY *key); + +/* EC_KEY_set_conv_form sets the conversion form to be used by |key|. */ +OPENSSL_EXPORT void EC_KEY_set_conv_form(EC_KEY *key, + point_conversion_form_t cform); + +/* EC_KEY_precompute_mult precomputes multiplies of the generator of the + * underlying group in order to speed up operations that calculate generator + * multiples. If |ctx| is not NULL, it may be used. It returns one on success + * and zero otherwise. */ +OPENSSL_EXPORT int EC_KEY_precompute_mult(EC_KEY *key, BN_CTX *ctx); + +/* EC_KEY_check_key performs several checks on |key| (possibly including an + * expensive check that the public key is in the primary subgroup). It returns + * one if all checks pass and zero otherwise. If it returns zero then detail + * about the problem can be found on the error stack. */ +OPENSSL_EXPORT int EC_KEY_check_key(const EC_KEY *key); + +/* EC_KEY_set_public_key_affine_coordinates sets the public key in |key| to + * (|x|, |y|). It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int EC_KEY_set_public_key_affine_coordinates(EC_KEY *key, + BIGNUM *x, + BIGNUM *y); + + +/* Key generation. */ + +/* EC_KEY_generate_key generates a random, private key, calculates the + * corresponding public key and stores both in |key|. It returns one on success + * or zero otherwise. */ +OPENSSL_EXPORT int EC_KEY_generate_key(EC_KEY *key); + + +/* Serialisation. */ + +/* d2i_ECPrivateKey parses an ASN.1, DER-encoded, private key from |len| bytes + * at |*inp|. If |out_key| is not NULL then, on exit, a pointer to the result + * is in |*out_key|. If |*out_key| is already non-NULL on entry then the result + * is written directly into |*out_key|, otherwise a fresh |EC_KEY| is + * allocated. On successful exit, |*inp| is advanced past the DER structure. It + * returns the result or NULL on error. */ +OPENSSL_EXPORT EC_KEY *d2i_ECPrivateKey(EC_KEY **out_key, const uint8_t **inp, + long len); + +/* i2d_ECPrivateKey marshals an EC private key from |key| to an ASN.1, DER + * structure. If |outp| is not NULL then the result is written to |*outp| and + * |*outp| is advanced just past the output. It returns the number of bytes in + * the result, whether written or not, or a negative value on error. */ +OPENSSL_EXPORT int i2d_ECPrivateKey(const EC_KEY *key, uint8_t **outp); + +/* d2i_ECParameters parses an ASN.1, DER-encoded, set of EC parameters from + * |len| bytes at |*inp|. If |out_key| is not NULL then, on exit, a pointer to + * the result is in |*out_key|. If |*out_key| is already non-NULL on entry then + * the result is written directly into |*out_key|, otherwise a fresh |EC_KEY| + * is allocated. On successful exit, |*inp| is advanced past the DER structure. + * It returns the result or NULL on error. */ +OPENSSL_EXPORT EC_KEY *d2i_ECParameters(EC_KEY **out_key, const uint8_t **inp, + long len); + +/* i2d_ECParameters marshals EC parameters from |key| to an ASN.1, DER + * structure. If |outp| is not NULL then the result is written to |*outp| and + * |*outp| is advanced just past the output. It returns the number of bytes in + * the result, whether written or not, or a negative value on error. */ +OPENSSL_EXPORT int i2d_ECParameters(const EC_KEY *key, uint8_t **outp); + +/* o2i_ECPublicKey parses an EC point from |len| bytes at |*inp| into + * |*out_key|. Note that this differs from the d2i format in that |*out_key| + * must be non-NULL with a group set. On successful exit, |*inp| is advanced by + * |len| bytes. It returns |*out_key| or NULL on error. */ +OPENSSL_EXPORT EC_KEY *o2i_ECPublicKey(EC_KEY **out_key, const uint8_t **inp, + long len); + +/* i2o_ECPublicKey marshals an EC point from |key|. If |outp| is not NULL then + * the result is written to |*outp| and |*outp| is advanced just past the + * output. It returns the number of bytes in the result, whether written or + * not, or a negative value on error. */ +OPENSSL_EXPORT int i2o_ECPublicKey(const EC_KEY *key, unsigned char **outp); + + +/* ex_data functions. + * + * These functions are wrappers. See |ex_data.h| for details. */ + +OPENSSL_EXPORT int EC_KEY_get_ex_new_index(long argl, void *argp, + CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func); +OPENSSL_EXPORT int EC_KEY_set_ex_data(EC_KEY *r, int idx, void *arg); +OPENSSL_EXPORT void *EC_KEY_get_ex_data(const EC_KEY *r, int idx); + + +/* ECDSA method. */ + +/* ECDSA_FLAG_OPAQUE specifies that this ECDSA_METHOD does not expose its key + * material. This may be set if, for instance, it is wrapping some other crypto + * API, like a platform key store. */ +#define ECDSA_FLAG_OPAQUE 1 + +/* ecdsa_method_st is a structure of function pointers for implementing ECDSA. + * See engine.h. */ +struct ecdsa_method_st { + struct openssl_method_common_st common; + + void *app_data; + + int (*init)(EC_KEY *key); + int (*finish)(EC_KEY *key); + + /* group_order_size returns the number of bytes needed to represent the order + * of the group. This is used to calculate the maximum size of an ECDSA + * signature in |ECDSA_size|. */ + size_t (*group_order_size)(const EC_KEY *key); + + /* sign matches the arguments and behaviour of |ECDSA_sign|. */ + int (*sign)(const uint8_t *digest, size_t digest_len, uint8_t *sig, + unsigned int *sig_len, EC_KEY *eckey); + + /* verify matches the arguments and behaviour of |ECDSA_verify|. */ + int (*verify)(const uint8_t *digest, size_t digest_len, const uint8_t *sig, + size_t sig_len, EC_KEY *eckey); + + int flags; +}; + + +/* Deprecated functions. */ + +/* EC_KEY_set_asn1_flag does nothing. */ +OPENSSL_EXPORT void EC_KEY_set_asn1_flag(EC_KEY *key, int flag); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_EC_KEY_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/ecdh.h b/TMessagesProj/jni/boringssl/include/openssl/ecdh.h new file mode 100644 index 00000000..878cbeb5 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/ecdh.h @@ -0,0 +1,102 @@ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * The Elliptic Curve Public-Key Crypto Library (ECC Code) included + * herein is developed by SUN MICROSYSTEMS, INC., and is contributed + * to the OpenSSL project. + * + * The ECC Code is licensed pursuant to the OpenSSL open source + * license provided below. + * + * The ECDH software is originally written by Douglas Stebila of + * Sun Microsystems Laboratories. + * + */ +/* ==================================================================== + * Copyright (c) 2000-2002 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef OPENSSL_HEADER_ECDH_H +#define OPENSSL_HEADER_ECDH_H + +#include + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Elliptic curve Diffie-Hellman. */ + + +/* ECDH_compute_key calculates the shared key between |pub_key| and |priv_key|. + * If |KDF| is not NULL, then it is called with the bytes of the shared key and + * the parameter |out|. When |KDF| returns, the value of |*outlen| becomes the + * return value. Otherwise, as many bytes of the shared key as will fit are + * copied directly to, at most, |outlen| bytes at |out|. It returns the number + * of bytes written to |out|, or -1 on error. */ +OPENSSL_EXPORT int ECDH_compute_key(void *out, size_t outlen, + const EC_POINT *pub_key, EC_KEY *priv_key, + void *(*KDF)(const void *in, size_t inlen, + void *out, size_t *outlen)); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define ECDH_R_KDF_FAILED 100 +#define ECDH_R_NO_PRIVATE_VALUE 101 +#define ECDH_R_POINT_ARITHMETIC_FAILURE 102 + +#endif /* OPENSSL_HEADER_ECDH_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/ecdsa.h b/TMessagesProj/jni/boringssl/include/openssl/ecdsa.h new file mode 100644 index 00000000..84702c33 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/ecdsa.h @@ -0,0 +1,206 @@ +/* ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef OPENSSL_HEADER_ECDSA_H +#define OPENSSL_HEADER_ECDSA_H + +#include + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* ECDSA contains functions for signing and verifying with the Digital Signature + * Algorithm over elliptic curves. */ + + +/* Signing and verifing. */ + +/* ECDSA_sign signs |digest_len| bytes from |digest| with |key| and writes the + * resulting signature to |sig|, which must have |ECDSA_size(key)| bytes of + * space. On successful exit, |*sig_len| is set to the actual number of bytes + * written. The |type| argument should be zero. It returns one on success and + * zero otherwise. */ +OPENSSL_EXPORT int ECDSA_sign(int type, const uint8_t *digest, + size_t digest_len, uint8_t *sig, + unsigned int *sig_len, EC_KEY *key); + +/* ECDSA_verify verifies that |sig_len| bytes from |sig| constitute a valid + * signature by |key| of |digest|. (The |type| argument should be zero.) It + * returns one on success or zero if the signature is invalid or an error + * occured. */ +OPENSSL_EXPORT int ECDSA_verify(int type, const uint8_t *digest, + size_t digest_len, const uint8_t *sig, + size_t sig_len, EC_KEY *key); + +/* ECDSA_size returns the maximum size of an ECDSA signature using |key|. It + * returns zero on error. */ +OPENSSL_EXPORT size_t ECDSA_size(const EC_KEY *key); + + +/* Low-level signing and verification. + * + * Low-level functions handle signatures as |ECDSA_SIG| structures which allow + * the two values in an ECDSA signature to be handled separately. */ + +struct ecdsa_sig_st { + BIGNUM *r; + BIGNUM *s; +}; + +/* ECDSA_SIG_new returns a fresh |ECDSA_SIG| structure or NULL on error. */ +OPENSSL_EXPORT ECDSA_SIG *ECDSA_SIG_new(void); + +/* ECDSA_SIG_free frees |sig| its member |BIGNUM|s. */ +OPENSSL_EXPORT void ECDSA_SIG_free(ECDSA_SIG *sig); + +/* ECDSA_sign signs |digest_len| bytes from |digest| with |key| and returns the + * resulting signature structure, or NULL on error. */ +OPENSSL_EXPORT ECDSA_SIG *ECDSA_do_sign(const uint8_t *digest, + size_t digest_len, EC_KEY *key); + +/* ECDSA_verify verifies that |sig| constitutes a valid signature by |key| of + * |digest|. It returns one on success or zero if the signature is invalid or + * on error. */ +OPENSSL_EXPORT int ECDSA_do_verify(const uint8_t *digest, size_t digest_len, + const ECDSA_SIG *sig, EC_KEY *key); + + +/* Signing with precomputation. + * + * Parts of the ECDSA signature can be independent of the message to be signed + * thus it's possible to precompute them and reduce the signing latency. + * + * TODO(fork): remove support for this as it cannot support safe-randomness. */ + +/* ECDSA_sign_setup precomputes parts of an ECDSA signing operation. It sets + * |*kinv| and |*rp| to the precomputed values and uses the |ctx| argument, if + * not NULL. It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int ECDSA_sign_setup(EC_KEY *eckey, BN_CTX *ctx, BIGNUM **kinv, + BIGNUM **rp); + +/* ECDSA_do_sign_ex is the same as |ECDSA_do_sign| but takes precomputed values + * as generated by |ECDSA_sign_setup|. */ +OPENSSL_EXPORT ECDSA_SIG *ECDSA_do_sign_ex(const uint8_t *digest, + size_t digest_len, + const BIGNUM *kinv, const BIGNUM *rp, + EC_KEY *eckey); + +/* ECDSA_sign_ex is the same as |ECDSA_sign| but takes precomputed values as + * generated by |ECDSA_sign_setup|. */ +OPENSSL_EXPORT int ECDSA_sign_ex(int type, const uint8_t *digest, + size_t digest_len, uint8_t *sig, + unsigned int *sig_len, const BIGNUM *kinv, + const BIGNUM *rp, EC_KEY *eckey); + + +/* ASN.1 functions. */ + +/* ECDSA_SIG_parse parses a DER-encoded ECDSA-Sig-Value structure from |cbs| and + * advances |cbs|. It returns a newly-allocated |ECDSA_SIG| or NULL on error. */ +OPENSSL_EXPORT ECDSA_SIG *ECDSA_SIG_parse(CBS *cbs); + +/* ECDSA_SIG_from_bytes parses |in| as a DER-encoded ECDSA-Sig-Value structure. + * It returns a newly-allocated |ECDSA_SIG| structure or NULL on error. */ +OPENSSL_EXPORT ECDSA_SIG *ECDSA_SIG_from_bytes(const uint8_t *in, + size_t in_len); + +/* ECDSA_SIG_marshal marshals |sig| as a DER-encoded ECDSA-Sig-Value and appends + * the result to |cbb|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int ECDSA_SIG_marshal(CBB *cbb, const ECDSA_SIG *sig); + +/* ECDSA_SIG_to_asn1 marshals |sig| as a DER-encoded ECDSA-Sig-Value and, on + * success, sets |*out_bytes| to a newly allocated buffer containing the result + * and returns one. Otherwise, it returns zero. The result should be freed with + * |OPENSSL_free|. */ +OPENSSL_EXPORT int ECDSA_SIG_to_bytes(uint8_t **out_bytes, size_t *out_len, + const ECDSA_SIG *sig); + +/* ECDSA_SIG_max_len returns the maximum length of a DER-encoded ECDSA-Sig-Value + * structure for a group whose order is represented in |order_len| bytes, or + * zero on overflow. */ +OPENSSL_EXPORT size_t ECDSA_SIG_max_len(size_t order_len); + + +/* Deprecated functions. */ + +/* d2i_ECDSA_SIG parses an ASN.1, DER-encoded, signature from |len| bytes at + * |*inp|. If |out| is not NULL then, on exit, a pointer to the result is in + * |*out|. If |*out| is already non-NULL on entry then the result is written + * directly into |*out|, otherwise a fresh |ECDSA_SIG| is allocated. On + * successful exit, |*inp| is advanced past the DER structure. It returns the + * result or NULL on error. */ +OPENSSL_EXPORT ECDSA_SIG *d2i_ECDSA_SIG(ECDSA_SIG **out, const uint8_t **inp, + long len); + +/* i2d_ECDSA_SIG marshals a signature from |sig| to an ASN.1, DER + * structure. If |outp| is not NULL then the result is written to |*outp| and + * |*outp| is advanced just past the output. It returns the number of bytes in + * the result, whether written or not, or a negative value on error. */ +OPENSSL_EXPORT int i2d_ECDSA_SIG(const ECDSA_SIG *sig, uint8_t **outp); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define ECDSA_R_BAD_SIGNATURE 100 +#define ECDSA_R_MISSING_PARAMETERS 101 +#define ECDSA_R_NEED_NEW_SETUP_VALUES 102 +#define ECDSA_R_NOT_IMPLEMENTED 103 +#define ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED 104 +#define ECDSA_R_ENCODE_ERROR 105 + +#endif /* OPENSSL_HEADER_ECDSA_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/engine.h b/TMessagesProj/jni/boringssl/include/openssl/engine.h new file mode 100644 index 00000000..d3d278a6 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/engine.h @@ -0,0 +1,107 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_ENGINE_H +#define OPENSSL_HEADER_ENGINE_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Engines are collections of methods. Methods are tables of function pointers, + * defined for certain algorithms, that allow operations on those algorithms to + * be overridden via a callback. This can be used, for example, to implement an + * RSA* that forwards operations to a hardware module. + * + * Methods are reference counted but |ENGINE|s are not. When creating a method, + * you should zero the whole structure and fill in the function pointers that + * you wish before setting it on an |ENGINE|. Any functions pointers that + * are NULL indicate that the default behaviour should be used. */ + + +/* Allocation and destruction. */ + +/* ENGINE_new returns an empty ENGINE that uses the default method for all + * algorithms. */ +OPENSSL_EXPORT ENGINE *ENGINE_new(void); + +/* ENGINE_free decrements the reference counts for all methods linked from + * |engine| and frees |engine| itself. */ +OPENSSL_EXPORT void ENGINE_free(ENGINE *engine); + + +/* Method accessors. + * + * Method accessors take a method pointer and the size of the structure. The + * size allows for ABI compatibility in the case that the method structure is + * extended with extra elements at the end. Methods are always copied by the + * set functions. + * + * Set functions return one on success and zero on allocation failure. */ + +OPENSSL_EXPORT int ENGINE_set_DH_method(ENGINE *engine, const DH_METHOD *method, + size_t method_size); +OPENSSL_EXPORT DH_METHOD *ENGINE_get_DH_method(const ENGINE *engine); + +OPENSSL_EXPORT int ENGINE_set_DSA_method(ENGINE *engine, + const DSA_METHOD *method, + size_t method_size); +OPENSSL_EXPORT DSA_METHOD *ENGINE_get_DSA_method(const ENGINE *engine); + +OPENSSL_EXPORT int ENGINE_set_RSA_method(ENGINE *engine, + const RSA_METHOD *method, + size_t method_size); +OPENSSL_EXPORT RSA_METHOD *ENGINE_get_RSA_method(const ENGINE *engine); + +OPENSSL_EXPORT int ENGINE_set_ECDSA_method(ENGINE *engine, + const ECDSA_METHOD *method, + size_t method_size); +OPENSSL_EXPORT ECDSA_METHOD *ENGINE_get_ECDSA_method(const ENGINE *engine); + + +/* Generic method functions. + * + * These functions take a void* type but actually operate on all method + * structures. */ + +/* METHOD_ref increments the reference count of |method|. This is a no-op for + * now because all methods are currently static. */ +void METHOD_ref(void *method); + +/* METHOD_unref decrements the reference count of |method| and frees it if the + * reference count drops to zero. This is a no-op for now because all methods + * are currently static. */ +void METHOD_unref(void *method); + + +/* Private functions. */ + +/* openssl_method_common_st contains the common part of all method structures. + * This must be the first member of all method structures. */ +struct openssl_method_common_st { + int references; /* dummy – not used. */ + char is_static; +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define ENGINE_R_OPERATION_NOT_SUPPORTED 100 + +#endif /* OPENSSL_HEADER_ENGINE_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/err.h b/TMessagesProj/jni/boringssl/include/openssl/err.h new file mode 100644 index 00000000..0a90b0e3 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/err.h @@ -0,0 +1,503 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef OPENSSL_HEADER_ERR_H +#define OPENSSL_HEADER_ERR_H + +#include + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Error queue handling functions. + * + * Errors in OpenSSL are generally signalled by the return value of a function. + * When a function fails it may add an entry to a per-thread error queue, + * which is managed by the functions in this header. + * + * Each error contains: + * 1) The library (i.e. ec, pem, rsa) which created it. + * 2) The function, file, and line number of the call that added the error. + * 3) A pointer to some error specific data, which may be NULL. + * + * The library identifier and reason code are packed in a uint32_t and there + * exist various functions for unpacking it. + * + * The typical behaviour is that an error will occur deep in a call queue and + * that code will push an error onto the error queue. As the error queue + * unwinds, other functions will push their own errors. Thus, the "least + * recent" error is the most specific and the other errors will provide a + * backtrace of sorts. */ + + +/* Startup and shutdown. */ + +/* ERR_load_BIO_strings does nothing. + * + * TODO(fork): remove. libjingle calls this. */ +OPENSSL_EXPORT void ERR_load_BIO_strings(void); + +/* ERR_load_ERR_strings does nothing. */ +OPENSSL_EXPORT void ERR_load_ERR_strings(void); + +/* ERR_load_crypto_strings does nothing. */ +OPENSSL_EXPORT void ERR_load_crypto_strings(void); + +/* ERR_free_strings does nothing. */ +OPENSSL_EXPORT void ERR_free_strings(void); + + +/* Reading and formatting errors. */ + +/* ERR_get_error gets the packed error code for the least recent error and + * removes that error from the queue. If there are no errors in the queue then + * it returns zero. */ +OPENSSL_EXPORT uint32_t ERR_get_error(void); + +/* ERR_get_error_line acts like |ERR_get_error|, except that the file and line + * number of the call that added the error are also returned. */ +OPENSSL_EXPORT uint32_t ERR_get_error_line(const char **file, int *line); + +/* ERR_get_error_line_data acts like |ERR_get_error_line|, but also returns the + * error-specific data pointer and flags. The flags are a bitwise-OR of + * |ERR_FLAG_*| values. The error-specific data is owned by the error queue + * and the pointer becomes invalid after the next call that affects the same + * thread's error queue. If |*flags| contains |ERR_FLAG_STRING| then |*data| is + * human-readable. */ +OPENSSL_EXPORT uint32_t ERR_get_error_line_data(const char **file, int *line, + const char **data, int *flags); + +/* The "peek" functions act like the |ERR_get_error| functions, above, but they + * do not remove the error from the queue. */ +OPENSSL_EXPORT uint32_t ERR_peek_error(void); +OPENSSL_EXPORT uint32_t ERR_peek_error_line(const char **file, int *line); +OPENSSL_EXPORT uint32_t ERR_peek_error_line_data(const char **file, int *line, + const char **data, int *flags); + +/* ERR_peek_function returns the name of the function which added the least + * recent error or NULL if the queue is empty. */ +OPENSSL_EXPORT const char *ERR_peek_function(void); + +/* The "peek last" functions act like the "peek" functions, above, except that + * they return the most recent error. */ +OPENSSL_EXPORT uint32_t ERR_peek_last_error(void); +OPENSSL_EXPORT uint32_t ERR_peek_last_error_line(const char **file, int *line); +OPENSSL_EXPORT uint32_t ERR_peek_last_error_line_data(const char **file, + int *line, + const char **data, + int *flags); + +/* ERR_error_string generates a human-readable string representing + * |packed_error|, places it at |buf| (which must be at least + * ERR_ERROR_STRING_BUF_LEN bytes long) and returns |buf|. If |buf| is NULL, + * the error string is placed in a static buffer which is returned. (The static + * buffer may be overridden by concurrent calls in other threads so this form + * is deprecated.) + * + * The string will have the following format: + * + * error:[error code]:[library name]:OPENSSL_internal:[reason string] + * + * error code is an 8 digit hexadecimal number; library name and reason string + * are ASCII text. + * + * TODO(fork): remove in favour of |ERR_error_string_n|. */ +OPENSSL_EXPORT char *ERR_error_string(uint32_t packed_error, char *buf); +#define ERR_ERROR_STRING_BUF_LEN 256 + +/* ERR_error_string_n is a variant of |ERR_error_string| that writes at most + * len characters (including the terminating NUL) and truncates the string if + * necessary. If |len| is greater than zero then |buf| is always NUL + * terminated. */ +OPENSSL_EXPORT void ERR_error_string_n(uint32_t packed_error, char *buf, + size_t len); + +/* ERR_lib_error_string returns a string representation of the library that + * generated |packed_error|. */ +OPENSSL_EXPORT const char *ERR_lib_error_string(uint32_t packed_error); + +/* ERR_reason_error_string returns a string representation of the reason for + * |packed_error|. */ +OPENSSL_EXPORT const char *ERR_reason_error_string(uint32_t packed_error); + +/* ERR_print_errors_callback_t is the type of a function used by + * |ERR_print_errors_cb|. It takes a pointer to a human readable string (and + * its length) that describes an entry in the error queue. The |ctx| argument + * is an opaque pointer given to |ERR_print_errors_cb|. + * + * It should return one on success or zero on error, which will stop the + * iteration over the error queue. */ +typedef int (*ERR_print_errors_callback_t)(const char *str, size_t len, + void *ctx); + +/* ERR_print_errors_cb calls |callback| with a string representation of each + * error in the current thread's error queue, from the least recent to the most + * recent error. + * + * The string will have the following format (which differs from + * |ERR_error_string|): + * + * [thread id]:error:[error code]:[library name]:[function name]: + * [reason string]:[file]:[line number]:[optional string data] + * + * (All in one line.) + * + * The callback can return one to continue the iteration or zero to stop it. + * The |ctx| argument is an opaque value that is passed through to the + * callback. */ +OPENSSL_EXPORT void ERR_print_errors_cb(ERR_print_errors_callback_t callback, + void *ctx); + + +/* ERR_print_errors_fp prints the current contents of the error stack to |file| + * using human readable strings where possible. */ +OPENSSL_EXPORT void ERR_print_errors_fp(FILE *file); + +/* Clearing errors. */ + +/* ERR_clear_error clears the error queue for the current thread. */ +OPENSSL_EXPORT void ERR_clear_error(void); + +/* ERR_remove_thread_state clears the error queue for the current thread if + * |tid| is NULL. Otherwise it calls |assert(0)|, because it's no longer + * possible to delete the error queue for other threads. + * + * Error queues are thread-local data and are deleted automatically. You do not + * need to call this function. Use |ERR_clear_error|. */ +OPENSSL_EXPORT void ERR_remove_thread_state(const CRYPTO_THREADID *tid); + + +/* Custom errors. */ + +/* ERR_get_next_error_library returns a value suitable for passing as the + * |library| argument to |ERR_put_error|. This is intended for code that wishes + * to push its own, non-standard errors to the error queue. */ +OPENSSL_EXPORT int ERR_get_next_error_library(void); + + +/* Deprecated functions. */ + +/* ERR_remove_state calls |ERR_clear_error|. */ +OPENSSL_EXPORT void ERR_remove_state(unsigned long pid); + +/* ERR_func_error_string returns the string "OPENSSL_internal". */ +OPENSSL_EXPORT const char *ERR_func_error_string(uint32_t packed_error); + + +/* Private functions. */ + +/* ERR_clear_system_error clears the system's error value (i.e. errno). */ +OPENSSL_EXPORT void ERR_clear_system_error(void); + +#if defined(OPENSSL_WINDOWS) +/* TODO(davidben): Use |__func__| directly once the minimum MSVC version + * supports it. */ +#define OPENSSL_CURRENT_FUNCTION __FUNCTION__ +#else +#define OPENSSL_CURRENT_FUNCTION __func__ +#endif + +/* OPENSSL_PUT_ERROR is used by OpenSSL code to add an error to the error + * queue. */ +#define OPENSSL_PUT_ERROR(library, reason) \ + ERR_put_error(ERR_LIB_##library, reason, OPENSSL_CURRENT_FUNCTION, __FILE__, \ + __LINE__) + +/* OPENSSL_PUT_SYSTEM_ERROR is used by OpenSSL code to add an error from the + * operating system to the error queue. */ +/* TODO(fork): include errno. */ +#define OPENSSL_PUT_SYSTEM_ERROR(func) \ + ERR_put_error(ERR_LIB_SYS, 0, #func, __FILE__, __LINE__); + +/* ERR_put_error adds an error to the error queue, dropping the least recent + * error if neccessary for space reasons. */ +OPENSSL_EXPORT void ERR_put_error(int library, int reason, const char *function, + const char *file, unsigned line); + +/* ERR_add_error_data takes a variable number (|count|) of const char* + * pointers, concatenates them and sets the result as the data on the most + * recent error. */ +OPENSSL_EXPORT void ERR_add_error_data(unsigned count, ...); + +/* ERR_add_error_dataf takes a printf-style format and arguments, and sets the + * result as the data on the most recent error. */ +OPENSSL_EXPORT void ERR_add_error_dataf(const char *format, ...); + +/* ERR_set_mark "marks" the most recent error for use with |ERR_pop_to_mark|. + * It returns one if an error was marked and zero if there are no errors. */ +OPENSSL_EXPORT int ERR_set_mark(void); + +/* ERR_pop_to_mark removes errors from the most recent to the least recent + * until (and not including) a "marked" error. It returns zero if no marked + * error was found (and thus all errors were removed) and one otherwise. Errors + * are marked using |ERR_set_mark|. */ +OPENSSL_EXPORT int ERR_pop_to_mark(void); + +struct err_error_st { + /* function contains the name of the function where the error occured. */ + const char *function; + /* file contains the filename where the error occured. */ + const char *file; + /* data contains optional data. It must be freed with |OPENSSL_free| if + * |flags&ERR_FLAG_MALLOCED|. */ + char *data; + /* packed contains the error library, function and reason, as packed by + * ERR_PACK. */ + uint32_t packed; + /* line contains the line number where the error occured. */ + uint16_t line; + /* flags contains a bitwise-OR of ERR_FLAG_* values. */ + uint8_t flags; +}; + +/* ERR_FLAG_STRING means that the |data| member is a NUL-terminated string that + * can be printed. */ +#define ERR_FLAG_STRING 1 +/* ERR_TXT_STRING is provided for compatibility with code that assumes that + * it's using OpenSSL. */ +#define ERR_TXT_STRING ERR_FLAG_STRING + +/* ERR_FLAG_PUBLIC_MASK is applied to the flags field before it is returned + * from functions like |ERR_get_error_line_data|. */ +#define ERR_FLAG_PUBLIC_MASK 0xf + +/* The following flag values are internal and are masked when flags are + * returned from functions like |ERR_get_error_line_data|. */ + +/* ERR_FLAG_MALLOCED means the the |data| member must be freed when no longer + * needed. */ +#define ERR_FLAG_MALLOCED 16 +/* ERR_FLAG_MARK is used to indicate a reversion point in the queue. See + * |ERR_pop_to_mark|. */ +#define ERR_FLAG_MARK 32 + +/* ERR_NUM_ERRORS is the limit of the number of errors in the queue. */ +#define ERR_NUM_ERRORS 16 + +/* ERR_STATE contains the per-thread, error queue. */ +typedef struct err_state_st { + /* errors contains the ERR_NUM_ERRORS most recent errors, organised as a ring + * buffer. */ + struct err_error_st errors[ERR_NUM_ERRORS]; + /* top contains the index one past the most recent error. If |top| equals + * |bottom| then the queue is empty. */ + unsigned top; + /* bottom contains the index of the last error in the queue. */ + unsigned bottom; + + /* to_free, if not NULL, contains a pointer owned by this structure that was + * previously a |data| pointer of one of the elements of |errors|. */ + void *to_free; +} ERR_STATE; + +enum { + ERR_LIB_NONE = 1, + ERR_LIB_SYS, + ERR_LIB_BN, + ERR_LIB_RSA, + ERR_LIB_DH, + ERR_LIB_EVP, + ERR_LIB_BUF, + ERR_LIB_OBJ, + ERR_LIB_PEM, + ERR_LIB_DSA, + ERR_LIB_X509, + ERR_LIB_ASN1, + ERR_LIB_CONF, + ERR_LIB_CRYPTO, + ERR_LIB_EC, + ERR_LIB_SSL, + ERR_LIB_BIO, + ERR_LIB_PKCS7, + ERR_LIB_PKCS8, + ERR_LIB_X509V3, + ERR_LIB_RAND, + ERR_LIB_ENGINE, + ERR_LIB_OCSP, + ERR_LIB_UI, + ERR_LIB_COMP, + ERR_LIB_ECDSA, + ERR_LIB_ECDH, + ERR_LIB_HMAC, + ERR_LIB_DIGEST, + ERR_LIB_CIPHER, + ERR_LIB_HKDF, + ERR_LIB_USER, + ERR_NUM_LIBS +}; + +#define ERR_R_SYS_LIB ERR_LIB_SYS +#define ERR_R_BN_LIB ERR_LIB_BN +#define ERR_R_RSA_LIB ERR_LIB_RSA +#define ERR_R_DH_LIB ERR_LIB_DH +#define ERR_R_EVP_LIB ERR_LIB_EVP +#define ERR_R_BUF_LIB ERR_LIB_BUF +#define ERR_R_OBJ_LIB ERR_LIB_OBJ +#define ERR_R_PEM_LIB ERR_LIB_PEM +#define ERR_R_DSA_LIB ERR_LIB_DSA +#define ERR_R_X509_LIB ERR_LIB_X509 +#define ERR_R_ASN1_LIB ERR_LIB_ASN1 +#define ERR_R_CONF_LIB ERR_LIB_CONF +#define ERR_R_CRYPTO_LIB ERR_LIB_CRYPTO +#define ERR_R_EC_LIB ERR_LIB_EC +#define ERR_R_SSL_LIB ERR_LIB_SSL +#define ERR_R_BIO_LIB ERR_LIB_BIO +#define ERR_R_PKCS7_LIB ERR_LIB_PKCS7 +#define ERR_R_PKCS8_LIB ERR_LIB_PKCS8 +#define ERR_R_X509V3_LIB ERR_LIB_X509V3 +#define ERR_R_RAND_LIB ERR_LIB_RAND +#define ERR_R_DSO_LIB ERR_LIB_DSO +#define ERR_R_ENGINE_LIB ERR_LIB_ENGINE +#define ERR_R_OCSP_LIB ERR_LIB_OCSP +#define ERR_R_UI_LIB ERR_LIB_UI +#define ERR_R_COMP_LIB ERR_LIB_COMP +#define ERR_R_ECDSA_LIB ERR_LIB_ECDSA +#define ERR_R_ECDH_LIB ERR_LIB_ECDH +#define ERR_R_STORE_LIB ERR_LIB_STORE +#define ERR_R_FIPS_LIB ERR_LIB_FIPS +#define ERR_R_CMS_LIB ERR_LIB_CMS +#define ERR_R_TS_LIB ERR_LIB_TS +#define ERR_R_HMAC_LIB ERR_LIB_HMAC +#define ERR_R_JPAKE_LIB ERR_LIB_JPAKE +#define ERR_R_USER_LIB ERR_LIB_USER +#define ERR_R_DIGEST_LIB ERR_LIB_DIGEST +#define ERR_R_CIPHER_LIB ERR_LIB_CIPHER +#define ERR_R_HKDF_LIB ERR_LIB_HKDF + +/* Global reasons. */ +#define ERR_R_FATAL 64 +#define ERR_R_MALLOC_FAILURE (1 | ERR_R_FATAL) +#define ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED (2 | ERR_R_FATAL) +#define ERR_R_PASSED_NULL_PARAMETER (3 | ERR_R_FATAL) +#define ERR_R_INTERNAL_ERROR (4 | ERR_R_FATAL) +#define ERR_R_OVERFLOW (5 | ERR_R_FATAL) + +#define ERR_PACK(lib, reason) \ + (((((uint32_t)lib) & 0xff) << 24) | ((((uint32_t)reason) & 0xfff))) + +#define ERR_GET_LIB(packed_error) ((int)(((packed_error) >> 24) & 0xff)) +#define ERR_GET_FUNC(packed_error) 0 +#define ERR_GET_REASON(packed_error) ((int)((packed_error) & 0xfff)) + +/* OPENSSL_DECLARE_ERROR_REASON is used by util/make_errors.h (which generates + * the error defines) to recognise that an additional reason value is needed. + * This is needed when the reason value is used outside of an + * |OPENSSL_PUT_ERROR| macro. The resulting define will be + * ${lib}_R_${reason}. */ +#define OPENSSL_DECLARE_ERROR_REASON(lib, reason) + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_ERR_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/evp.h b/TMessagesProj/jni/boringssl/include/openssl/evp.h new file mode 100644 index 00000000..99b147e1 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/evp.h @@ -0,0 +1,743 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_EVP_H +#define OPENSSL_HEADER_EVP_H + +#include + +#include + +/* OpenSSL included digest and cipher functions in this header so we include + * them for users that still expect that. + * + * TODO(fork): clean up callers so that they include what they use. */ +#include +#include +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* EVP abstracts over public/private key algorithms. */ + + +/* Public key objects. */ + +/* EVP_PKEY_new creates a new, empty public-key object and returns it or NULL + * on allocation failure. */ +OPENSSL_EXPORT EVP_PKEY *EVP_PKEY_new(void); + +/* EVP_PKEY_free frees all data referenced by |pkey| and then frees |pkey| + * itself. */ +OPENSSL_EXPORT void EVP_PKEY_free(EVP_PKEY *pkey); + +/* EVP_PKEY_up_ref increments the reference count of |pkey| and returns it. */ +OPENSSL_EXPORT EVP_PKEY *EVP_PKEY_up_ref(EVP_PKEY *pkey); + +/* EVP_PKEY_is_opaque returns one if |pkey| is opaque. Opaque keys are backed by + * custom implementations which do not expose key material and parameters. It is + * an error to attempt to duplicate, export, or compare an opaque key. */ +OPENSSL_EXPORT int EVP_PKEY_is_opaque(const EVP_PKEY *pkey); + +/* EVP_PKEY_supports_digest returns one if |pkey| supports digests of + * type |md|. This is intended for use with EVP_PKEYs backing custom + * implementations which can't sign all digests. */ +OPENSSL_EXPORT int EVP_PKEY_supports_digest(const EVP_PKEY *pkey, + const EVP_MD *md); + +/* EVP_PKEY_cmp compares |a| and |b| and returns one if they are equal, zero if + * not and a negative number on error. + * + * WARNING: this differs from the traditional return value of a "cmp" + * function. */ +OPENSSL_EXPORT int EVP_PKEY_cmp(const EVP_PKEY *a, const EVP_PKEY *b); + +/* EVP_PKEY_copy_parameters sets the parameters of |to| to equal the parameters + * of |from|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from); + +/* EVP_PKEY_missing_parameters returns one if |pkey| is missing needed + * parameters or zero if not, or if the algorithm doesn't take parameters. */ +OPENSSL_EXPORT int EVP_PKEY_missing_parameters(const EVP_PKEY *pkey); + +/* EVP_PKEY_size returns the maximum size, in bytes, of a signature signed by + * |pkey|. For an RSA key, this returns the number of bytes needed to represent + * the modulus. For an EC key, this returns the maximum size of a DER-encoded + * ECDSA signature. */ +OPENSSL_EXPORT int EVP_PKEY_size(const EVP_PKEY *pkey); + +/* EVP_PKEY_bits returns the "size", in bits, of |pkey|. For an RSA key, this + * returns the bit length of the modulus. For an EC key, this returns the bit + * length of the group order. */ +OPENSSL_EXPORT int EVP_PKEY_bits(EVP_PKEY *pkey); + +/* EVP_PKEY_id returns the type of |pkey|, which is one of the |EVP_PKEY_*| + * values. */ +OPENSSL_EXPORT int EVP_PKEY_id(const EVP_PKEY *pkey); + +/* EVP_PKEY_type returns a canonicalised form of |NID|. For example, + * |EVP_PKEY_RSA2| will be turned into |EVP_PKEY_RSA|. */ +OPENSSL_EXPORT int EVP_PKEY_type(int nid); + + +/* Getting and setting concrete public key types. + * + * The following functions get and set the underlying public key in an + * |EVP_PKEY| object. The |set1| functions take an additional reference to the + * underlying key and return one on success or zero on error. The |assign| + * functions adopt the caller's reference. The getters return a fresh reference + * to the underlying object. */ + +OPENSSL_EXPORT int EVP_PKEY_set1_RSA(EVP_PKEY *pkey, RSA *key); +OPENSSL_EXPORT int EVP_PKEY_assign_RSA(EVP_PKEY *pkey, RSA *key); +OPENSSL_EXPORT RSA *EVP_PKEY_get1_RSA(EVP_PKEY *pkey); + +OPENSSL_EXPORT int EVP_PKEY_set1_DSA(EVP_PKEY *pkey, struct dsa_st *key); +OPENSSL_EXPORT int EVP_PKEY_assign_DSA(EVP_PKEY *pkey, DSA *key); +OPENSSL_EXPORT struct dsa_st *EVP_PKEY_get1_DSA(EVP_PKEY *pkey); + +OPENSSL_EXPORT int EVP_PKEY_set1_EC_KEY(EVP_PKEY *pkey, struct ec_key_st *key); +OPENSSL_EXPORT int EVP_PKEY_assign_EC_KEY(EVP_PKEY *pkey, EC_KEY *key); +OPENSSL_EXPORT struct ec_key_st *EVP_PKEY_get1_EC_KEY(EVP_PKEY *pkey); + +OPENSSL_EXPORT int EVP_PKEY_set1_DH(EVP_PKEY *pkey, struct dh_st *key); +OPENSSL_EXPORT int EVP_PKEY_assign_DH(EVP_PKEY *pkey, DH *key); +OPENSSL_EXPORT struct dh_st *EVP_PKEY_get1_DH(EVP_PKEY *pkey); + +#define EVP_PKEY_NONE NID_undef +#define EVP_PKEY_RSA NID_rsaEncryption +#define EVP_PKEY_RSA2 NID_rsa +#define EVP_PKEY_DSA NID_dsa +#define EVP_PKEY_DH NID_dhKeyAgreement +#define EVP_PKEY_DHX NID_dhpublicnumber +#define EVP_PKEY_EC NID_X9_62_id_ecPublicKey + +/* EVP_PKEY_assign sets the underlying key of |pkey| to |key|, which must be of + * the given type. The |type| argument should be one of the |EVP_PKEY_*| + * values. */ +OPENSSL_EXPORT int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key); + +/* EVP_PKEY_set_type sets the type of |pkey| to |type|, which should be one of + * the |EVP_PKEY_*| values. It returns one if sucessful or zero otherwise. If + * |pkey| is NULL, it simply reports whether the type is known. */ +OPENSSL_EXPORT int EVP_PKEY_set_type(EVP_PKEY *pkey, int type); + +/* EVP_PKEY_cmp_parameters compares the parameters of |a| and |b|. It returns + * one if they match, zero if not, or a negative number of on error. + * + * WARNING: the return value differs from the usual return value convention. */ +OPENSSL_EXPORT int EVP_PKEY_cmp_parameters(const EVP_PKEY *a, + const EVP_PKEY *b); + + +/* ASN.1 functions */ + +/* d2i_PrivateKey parses an ASN.1, DER-encoded, private key from |len| bytes at + * |*inp|. If |out| is not NULL then, on exit, a pointer to the result is in + * |*out|. If |*out| is already non-NULL on entry then the result is written + * directly into |*out|, otherwise a fresh |EVP_PKEY| is allocated. On + * successful exit, |*inp| is advanced past the DER structure. It returns the + * result or NULL on error. */ +OPENSSL_EXPORT EVP_PKEY *d2i_PrivateKey(int type, EVP_PKEY **out, + const uint8_t **inp, long len); + +/* d2i_AutoPrivateKey acts the same as |d2i_PrivateKey|, but detects the type + * of the private key. */ +OPENSSL_EXPORT EVP_PKEY *d2i_AutoPrivateKey(EVP_PKEY **out, const uint8_t **inp, + long len); + +/* i2d_PrivateKey marshals a private key from |key| to an ASN.1, DER + * structure. If |outp| is not NULL then the result is written to |*outp| and + * |*outp| is advanced just past the output. It returns the number of bytes in + * the result, whether written or not, or a negative value on error. */ +OPENSSL_EXPORT int i2d_PrivateKey(const EVP_PKEY *key, uint8_t **outp); + +/* i2d_PublicKey marshals a public key from |key| to a type-specific format. + * If |outp| is not NULL then the result is written to |*outp| and + * |*outp| is advanced just past the output. It returns the number of bytes in + * the result, whether written or not, or a negative value on error. + * + * RSA keys are serialized as a DER-encoded RSAPublicKey (RFC 3447) structure. + * EC keys are serialized as an EC point per SEC 1. */ +OPENSSL_EXPORT int i2d_PublicKey(EVP_PKEY *key, uint8_t **outp); + + +/* Signing */ + +/* EVP_DigestSignInit sets up |ctx| for a signing operation with |type| and + * |pkey|. The |ctx| argument must have been initialised with + * |EVP_MD_CTX_init|. If |pctx| is not NULL, the |EVP_PKEY_CTX| of the signing + * operation will be written to |*pctx|; this can be used to set alternative + * signing options. + * + * It returns one on success, or zero on error. */ +OPENSSL_EXPORT int EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, + const EVP_MD *type, ENGINE *e, + EVP_PKEY *pkey); + +/* EVP_DigestSignUpdate appends |len| bytes from |data| to the data which will + * be signed in |EVP_DigestSignFinal|. It returns one. */ +OPENSSL_EXPORT int EVP_DigestSignUpdate(EVP_MD_CTX *ctx, const void *data, + size_t len); + +/* EVP_DigestSignFinal signs the data that has been included by one or more + * calls to |EVP_DigestSignUpdate|. If |out_sig| is NULL then |*out_sig_len| is + * set to the maximum number of output bytes. Otherwise, on entry, + * |*out_sig_len| must contain the length of the |out_sig| buffer. If the call + * is successful, the signature is written to |out_sig| and |*out_sig_len| is + * set to its length. + * + * It returns one on success, or zero on error. */ +OPENSSL_EXPORT int EVP_DigestSignFinal(EVP_MD_CTX *ctx, uint8_t *out_sig, + size_t *out_sig_len); + +/* EVP_DigestSignAlgorithm encodes the signing parameters of |ctx| as an + * AlgorithmIdentifer and saves the result in |algor|. + * + * It returns one on success, or zero on error. + * + * TODO(davidben): This API should eventually lose the dependency on + * crypto/asn1/. */ +OPENSSL_EXPORT int EVP_DigestSignAlgorithm(EVP_MD_CTX *ctx, X509_ALGOR *algor); + + +/* Verifying */ + +/* EVP_DigestVerifyInit sets up |ctx| for a signature verification operation + * with |type| and |pkey|. The |ctx| argument must have been initialised with + * |EVP_MD_CTX_init|. If |pctx| is not NULL, the |EVP_PKEY_CTX| of the signing + * operation will be written to |*pctx|; this can be used to set alternative + * signing options. + * + * It returns one on success, or zero on error. */ +OPENSSL_EXPORT int EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, + const EVP_MD *type, ENGINE *e, + EVP_PKEY *pkey); + +/* EVP_DigestVerifyInitFromAlgorithm sets up |ctx| for a signature verification + * operation with public key |pkey| and parameters from |algor|. The |ctx| + * argument must have been initialised with |EVP_MD_CTX_init|. + * + * It returns one on success, or zero on error. + * + * TODO(davidben): This API should eventually lose the dependency on + * crypto/asn1/. */ +OPENSSL_EXPORT int EVP_DigestVerifyInitFromAlgorithm(EVP_MD_CTX *ctx, + X509_ALGOR *algor, + EVP_PKEY *pkey); + +/* EVP_DigestVerifyUpdate appends |len| bytes from |data| to the data which + * will be verified by |EVP_DigestVerifyFinal|. It returns one. */ +OPENSSL_EXPORT int EVP_DigestVerifyUpdate(EVP_MD_CTX *ctx, const void *data, + size_t len); + +/* EVP_DigestVerifyFinal verifies that |sig_len| bytes of |sig| are a valid + * signature for the data that has been included by one or more calls to + * |EVP_DigestVerifyUpdate|. It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig, + size_t sig_len); + + +/* Signing (old functions) */ + +/* EVP_SignInit_ex configures |ctx|, which must already have been initialised, + * for a fresh signing operation using the hash function |type|. It returns one + * on success and zero otherwise. + * + * (In order to initialise |ctx|, either obtain it initialised with + * |EVP_MD_CTX_create|, or use |EVP_MD_CTX_init|.) */ +OPENSSL_EXPORT int EVP_SignInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, + ENGINE *impl); + +/* EVP_SignInit is a deprecated version of |EVP_SignInit_ex|. + * + * TODO(fork): remove. */ +OPENSSL_EXPORT int EVP_SignInit(EVP_MD_CTX *ctx, const EVP_MD *type); + +/* EVP_SignUpdate appends |len| bytes from |data| to the data which will be + * signed in |EVP_SignFinal|. */ +OPENSSL_EXPORT int EVP_SignUpdate(EVP_MD_CTX *ctx, const void *data, + size_t len); + +/* EVP_SignFinal signs the data that has been included by one or more calls to + * |EVP_SignUpdate|, using the key |pkey|, and writes it to |sig|. On entry, + * |sig| must point to at least |EVP_PKEY_size(pkey)| bytes of space. The + * actual size of the signature is written to |*out_sig_len|. + * + * It returns one on success and zero otherwise. + * + * It does not modify |ctx|, thus it's possible to continue to use |ctx| in + * order to sign a longer message. */ +OPENSSL_EXPORT int EVP_SignFinal(const EVP_MD_CTX *ctx, uint8_t *sig, + unsigned int *out_sig_len, EVP_PKEY *pkey); + + +/* Verifying (old functions) */ + +/* EVP_VerifyInit_ex configures |ctx|, which must already have been + * initialised, for a fresh signature verification operation using the hash + * function |type|. It returns one on success and zero otherwise. + * + * (In order to initialise |ctx|, either obtain it initialised with + * |EVP_MD_CTX_create|, or use |EVP_MD_CTX_init|.) */ +OPENSSL_EXPORT int EVP_VerifyInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, + ENGINE *impl); + +/* EVP_VerifyInit is a deprecated version of |EVP_VerifyInit_ex|. + * + * TODO(fork): remove. */ +OPENSSL_EXPORT int EVP_VerifyInit(EVP_MD_CTX *ctx, const EVP_MD *type); + +/* EVP_VerifyUpdate appends |len| bytes from |data| to the data which will be + * signed in |EVP_VerifyFinal|. */ +OPENSSL_EXPORT int EVP_VerifyUpdate(EVP_MD_CTX *ctx, const void *data, + size_t len); + +/* EVP_VerifyFinal verifies that |sig_len| bytes of |sig| are a valid + * signature, by |pkey|, for the data that has been included by one or more + * calls to |EVP_VerifyUpdate|. + * + * It returns one on success and zero otherwise. + * + * It does not modify |ctx|, thus it's possible to continue to use |ctx| in + * order to sign a longer message. */ +OPENSSL_EXPORT int EVP_VerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig, + size_t sig_len, EVP_PKEY *pkey); + + +/* Printing */ + +/* EVP_PKEY_print_public prints a textual representation of the public key in + * |pkey| to |out|. Returns one on success or zero otherwise. */ +OPENSSL_EXPORT int EVP_PKEY_print_public(BIO *out, const EVP_PKEY *pkey, + int indent, ASN1_PCTX *pctx); + +/* EVP_PKEY_print_private prints a textual representation of the private key in + * |pkey| to |out|. Returns one on success or zero otherwise. */ +OPENSSL_EXPORT int EVP_PKEY_print_private(BIO *out, const EVP_PKEY *pkey, + int indent, ASN1_PCTX *pctx); + +/* EVP_PKEY_print_params prints a textual representation of the parameters in + * |pkey| to |out|. Returns one on success or zero otherwise. */ +OPENSSL_EXPORT int EVP_PKEY_print_params(BIO *out, const EVP_PKEY *pkey, + int indent, ASN1_PCTX *pctx); + + +/* Password stretching. + * + * Password stretching functions take a low-entropy password and apply a slow + * function that results in a key suitable for use in symmetric + * cryptography. */ + +/* PKCS5_PBKDF2_HMAC computes |iterations| iterations of PBKDF2 of |password| + * and |salt|, using |digest|, and outputs |key_len| bytes to |out_key|. It + * returns one on success and zero on error. */ +OPENSSL_EXPORT int PKCS5_PBKDF2_HMAC(const char *password, size_t password_len, + const uint8_t *salt, size_t salt_len, + unsigned iterations, const EVP_MD *digest, + size_t key_len, uint8_t *out_key); + +/* PKCS5_PBKDF2_HMAC_SHA1 is the same as PKCS5_PBKDF2_HMAC, but with |digest| + * fixed to |EVP_sha1|. */ +OPENSSL_EXPORT int PKCS5_PBKDF2_HMAC_SHA1(const char *password, + size_t password_len, const uint8_t *salt, + size_t salt_len, unsigned iterations, + size_t key_len, uint8_t *out_key); + + +/* Public key contexts. + * + * |EVP_PKEY_CTX| objects hold the context of an operation (e.g. signing or + * encrypting) that uses a public key. */ + +/* EVP_PKEY_CTX_new allocates a fresh |EVP_PKEY_CTX| for use with |pkey|. It + * returns the context or NULL on error. */ +OPENSSL_EXPORT EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *e); + +/* EVP_PKEY_CTX_new_id allocates a fresh |EVP_PKEY_CTX| for a key of type |id| + * (e.g. |EVP_PKEY_HMAC|). This can be used for key generation where + * |EVP_PKEY_CTX_new| can't be used because there isn't an |EVP_PKEY| to pass + * it. It returns the context or NULL on error. */ +OPENSSL_EXPORT EVP_PKEY_CTX *EVP_PKEY_CTX_new_id(int id, ENGINE *e); + +/* EVP_PKEY_CTX_free frees |ctx| and the data it owns. */ +OPENSSL_EXPORT void EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx); + +/* EVP_PKEY_CTX_dup allocates a fresh |EVP_PKEY_CTX| and sets it equal to the + * state of |ctx|. It returns the fresh |EVP_PKEY_CTX| or NULL on error. */ +OPENSSL_EXPORT EVP_PKEY_CTX *EVP_PKEY_CTX_dup(EVP_PKEY_CTX *ctx); + +/* EVP_PKEY_CTX_get0_pkey returns the |EVP_PKEY| associated with |ctx|. */ +OPENSSL_EXPORT EVP_PKEY *EVP_PKEY_CTX_get0_pkey(EVP_PKEY_CTX *ctx); + +/* EVP_PKEY_CTX_set_app_data sets an opaque pointer on |ctx|. */ +OPENSSL_EXPORT void EVP_PKEY_CTX_set_app_data(EVP_PKEY_CTX *ctx, void *data); + +/* EVP_PKEY_CTX_get_app_data returns the opaque pointer from |ctx| that was + * previously set with |EVP_PKEY_CTX_set_app_data|, or NULL if none has been + * set. */ +OPENSSL_EXPORT void *EVP_PKEY_CTX_get_app_data(EVP_PKEY_CTX *ctx); + +/* EVP_PKEY_sign_init initialises an |EVP_PKEY_CTX| for a signing operation. It + * should be called before |EVP_PKEY_sign|. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx); + +/* EVP_PKEY_sign signs |data_len| bytes from |data| using |ctx|. If |sig| is + * NULL, the maximum size of the signature is written to + * |out_sig_len|. Otherwise, |*sig_len| must contain the number of bytes of + * space available at |sig|. If sufficient, the signature will be written to + * |sig| and |*sig_len| updated with the true length. + * + * WARNING: Setting |sig| to NULL only gives the maximum size of the + * signature. The actual signature may be smaller. + * + * It returns one on success or zero on error. (Note: this differs from + * OpenSSL, which can also return negative values to indicate an error. ) */ +OPENSSL_EXPORT int EVP_PKEY_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, + size_t *sig_len, const uint8_t *data, + size_t data_len); + +/* EVP_PKEY_verify_init initialises an |EVP_PKEY_CTX| for a signature + * verification operation. It should be called before |EVP_PKEY_verify|. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_verify_init(EVP_PKEY_CTX *ctx); + +/* EVP_PKEY_verify verifies that |sig_len| bytes from |sig| are a valid signature + * for |data|. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig, + size_t sig_len, const uint8_t *data, + size_t data_len); + +/* EVP_PKEY_encrypt_init initialises an |EVP_PKEY_CTX| for an encryption + * operation. It should be called before |EVP_PKEY_encrypt|. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_encrypt_init(EVP_PKEY_CTX *ctx); + +/* EVP_PKEY_encrypt encrypts |in_len| bytes from |in|. If |out| is NULL, the + * maximum size of the ciphertext is written to |out_len|. Otherwise, |*out_len| + * must contain the number of bytes of space available at |out|. If sufficient, + * the ciphertext will be written to |out| and |*out_len| updated with the true + * length. + * + * WARNING: Setting |out| to NULL only gives the maximum size of the + * ciphertext. The actual ciphertext may be smaller. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_encrypt(EVP_PKEY_CTX *ctx, uint8_t *out, + size_t *out_len, const uint8_t *in, + size_t in_len); + +/* EVP_PKEY_decrypt_init initialises an |EVP_PKEY_CTX| for a decryption + * operation. It should be called before |EVP_PKEY_decrypt|. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_decrypt_init(EVP_PKEY_CTX *ctx); + +/* EVP_PKEY_decrypt decrypts |in_len| bytes from |in|. If |out| is NULL, the + * maximum size of the plaintext is written to |out_len|. Otherwise, |*out_len| + * must contain the number of bytes of space available at |out|. If sufficient, + * the ciphertext will be written to |out| and |*out_len| updated with the true + * length. + * + * WARNING: Setting |out| to NULL only gives the maximum size of the + * plaintext. The actual plaintext may be smaller. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_decrypt(EVP_PKEY_CTX *ctx, uint8_t *out, + size_t *out_len, const uint8_t *in, + size_t in_len); + +/* EVP_PKEY_derive_init initialises an |EVP_PKEY_CTX| for a key derivation + * operation. It should be called before |EVP_PKEY_derive_set_peer| and + * |EVP_PKEY_derive|. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx); + +/* EVP_PKEY_derive_set_peer sets the peer's key to be used for key derivation + * by |ctx| to |peer|. It should be called after |EVP_PKEY_derive_init|. (For + * example, this is used to set the peer's key in (EC)DH.) It returns one on + * success and zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer); + +/* EVP_PKEY_derive derives a shared key between the two keys configured in + * |ctx|. If |key| is non-NULL then, on entry, |out_key_len| must contain the + * amount of space at |key|. If sufficient then the shared key will be written + * to |key| and |*out_key_len| will be set to the length. If |key| is NULL then + * |out_key_len| will be set to the maximum length. + * + * WARNING: Setting |out| to NULL only gives the maximum size of the key. The + * actual key may be smaller. + * + * It returns one on success and zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, uint8_t *key, + size_t *out_key_len); + +/* EVP_PKEY_keygen_init initialises an |EVP_PKEY_CTX| for a key generation + * operation. It should be called before |EVP_PKEY_keygen|. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx); + +/* EVP_PKEY_keygen performs a key generation operation using the values from + * |ctx| and sets |*ppkey| to a fresh |EVP_PKEY| containing the resulting key. + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey); + + +/* Generic control functions. */ + +/* EVP_PKEY_CTX_set_signature_md sets |md| as the digest to be used in a + * signature operation. It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX *ctx, + const EVP_MD *md); + +/* EVP_PKEY_CTX_get_signature_md sets |*out_md| to the digest to be used in a + * signature operation. It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_get_signature_md(EVP_PKEY_CTX *ctx, + const EVP_MD **out_md); + + +/* RSA specific control functions. */ + +/* EVP_PKEY_CTX_set_rsa_padding sets the padding type to use. It should be one + * of the |RSA_*_PADDING| values. Returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX *ctx, int padding); + +/* EVP_PKEY_CTX_get_rsa_padding sets |*out_padding| to the current padding + * value, which is one of the |RSA_*_PADDING| values. Returns one on success or + * zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_get_rsa_padding(EVP_PKEY_CTX *ctx, + int *out_padding); + +/* EVP_PKEY_CTX_set_rsa_pss_saltlen sets the length of the salt in a PSS-padded + * signature. A value of -1 cause the salt to be the same length as the digest + * in the signature. A value of -2 causes the salt to be the maximum length + * that will fit. Otherwise the value gives the size of the salt in bytes. + * + * Returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_set_rsa_pss_saltlen(EVP_PKEY_CTX *ctx, + int salt_len); + +/* EVP_PKEY_CTX_get_rsa_pss_saltlen sets |*out_salt_len| to the salt length of + * a PSS-padded signature. See the documentation for + * |EVP_PKEY_CTX_set_rsa_pss_saltlen| for details of the special values that it + * can take. + * + * Returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_get_rsa_pss_saltlen(EVP_PKEY_CTX *ctx, + int *out_salt_len); + +/* EVP_PKEY_CTX_set_rsa_keygen_bits sets the size of the desired RSA modulus, + * in bits, for key generation. Returns one on success or zero on + * error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_set_rsa_keygen_bits(EVP_PKEY_CTX *ctx, + int bits); + +/* EVP_PKEY_CTX_set_rsa_keygen_pubexp sets |e| as the public exponent for key + * generation. Returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_set_rsa_keygen_pubexp(EVP_PKEY_CTX *ctx, + BIGNUM *e); + +/* EVP_PKEY_CTX_set_rsa_oaep_md sets |md| as the digest used in OAEP padding. + * Returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_set_rsa_oaep_md(EVP_PKEY_CTX *ctx, + const EVP_MD *md); + +/* EVP_PKEY_CTX_get_rsa_oaep_md sets |*out_md| to the digest function used in + * OAEP padding. Returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_get_rsa_oaep_md(EVP_PKEY_CTX *ctx, + const EVP_MD **out_md); + +/* EVP_PKEY_CTX_set_rsa_mgf1_md sets |md| as the digest used in MGF1. Returns + * one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_set_rsa_mgf1_md(EVP_PKEY_CTX *ctx, + const EVP_MD *md); + +/* EVP_PKEY_CTX_get_rsa_mgf1_md sets |*out_md| to the digest function used in + * MGF1. Returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_get_rsa_mgf1_md(EVP_PKEY_CTX *ctx, + const EVP_MD **out_md); + +/* EVP_PKEY_CTX_set0_rsa_oaep_label sets |label_len| bytes from |label| as the + * label used in OAEP. DANGER: On success, this call takes ownership of |label| + * and will call |OPENSSL_free| on it when |ctx| is destroyed. + * + * Returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_set0_rsa_oaep_label(EVP_PKEY_CTX *ctx, + const uint8_t *label, + size_t label_len); + +/* EVP_PKEY_CTX_get0_rsa_oaep_label sets |*out_label| to point to the internal + * buffer containing the OAEP label (which may be NULL) and returns the length + * of the label or a negative value on error. + * + * WARNING: the return value differs from the usual return value convention. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_get0_rsa_oaep_label(EVP_PKEY_CTX *ctx, + const uint8_t **out_label); + + +/* Deprecated functions. */ + +/* OpenSSL_add_all_algorithms does nothing. */ +OPENSSL_EXPORT void OpenSSL_add_all_algorithms(void); + +/* OpenSSL_add_all_ciphers does nothing. */ +OPENSSL_EXPORT void OpenSSL_add_all_ciphers(void); + +/* OpenSSL_add_all_digests does nothing. */ +OPENSSL_EXPORT void OpenSSL_add_all_digests(void); + +/* EVP_cleanup does nothing. */ +OPENSSL_EXPORT void EVP_cleanup(void); + + +/* Private functions */ + +/* EVP_PKEY_asn1_find returns the ASN.1 method table for the given |nid|, which + * should be one of the |EVP_PKEY_*| values. It returns NULL if |nid| is + * unknown. */ +OPENSSL_EXPORT const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find(ENGINE **pengine, + int nid); + +/* TODO(fork): move to PEM? */ +OPENSSL_EXPORT const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find_str( + ENGINE **pengine, const char *name, size_t len); + +struct evp_pkey_st { + CRYPTO_refcount_t references; + + /* type contains one of the EVP_PKEY_* values or NID_undef and determines + * which element (if any) of the |pkey| union is valid. */ + int type; + + union { + char *ptr; + RSA *rsa; + DSA *dsa; + DH *dh; + EC_KEY *ec; + } pkey; + + /* ameth contains a pointer to a method table that contains many ASN.1 + * methods for the key type. */ + const EVP_PKEY_ASN1_METHOD *ameth; +} /* EVP_PKEY */; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define EVP_R_BUFFER_TOO_SMALL 100 +#define EVP_R_COMMAND_NOT_SUPPORTED 101 +#define EVP_R_DIFFERENT_KEY_TYPES 104 +#define EVP_R_DIFFERENT_PARAMETERS 105 +#define EVP_R_EXPECTING_AN_EC_KEY_KEY 107 +#define EVP_R_EXPECTING_A_DH_KEY 109 +#define EVP_R_EXPECTING_A_DSA_KEY 110 +#define EVP_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE 111 +#define EVP_R_INVALID_CURVE 112 +#define EVP_R_INVALID_DIGEST_LENGTH 113 +#define EVP_R_INVALID_DIGEST_TYPE 114 +#define EVP_R_INVALID_KEYBITS 115 +#define EVP_R_INVALID_MGF1_MD 116 +#define EVP_R_INVALID_PADDING_MODE 118 +#define EVP_R_INVALID_PSS_PARAMETERS 119 +#define EVP_R_INVALID_SALT_LENGTH 121 +#define EVP_R_INVALID_TRAILER 122 +#define EVP_R_KEYS_NOT_SET 123 +#define EVP_R_MISSING_PARAMETERS 124 +#define EVP_R_NO_DEFAULT_DIGEST 125 +#define EVP_R_NO_KEY_SET 126 +#define EVP_R_NO_MDC2_SUPPORT 127 +#define EVP_R_NO_NID_FOR_CURVE 128 +#define EVP_R_NO_OPERATION_SET 129 +#define EVP_R_NO_PARAMETERS_SET 130 +#define EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE 131 +#define EVP_R_OPERATON_NOT_INITIALIZED 132 +#define EVP_R_UNKNOWN_DIGEST 133 +#define EVP_R_UNKNOWN_MASK_DIGEST 134 +#define EVP_R_UNSUPPORTED_ALGORITHM 138 +#define EVP_R_UNSUPPORTED_MASK_ALGORITHM 139 +#define EVP_R_UNSUPPORTED_MASK_PARAMETER 140 +#define EVP_R_EXPECTING_AN_RSA_KEY 141 +#define EVP_R_INVALID_OPERATION 142 +#define EVP_R_DECODE_ERROR 143 +#define EVP_R_INVALID_PSS_SALTLEN 144 +#define EVP_R_UNKNOWN_PUBLIC_KEY_TYPE 145 +#define EVP_R_CONTEXT_NOT_INITIALISED 146 +#define EVP_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED 147 +#define EVP_R_WRONG_PUBLIC_KEY_TYPE 148 +#define EVP_R_UNKNOWN_SIGNATURE_ALGORITHM 149 +#define EVP_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM 150 +#define EVP_R_BN_DECODE_ERROR 151 +#define EVP_R_PARAMETER_ENCODING_ERROR 152 +#define EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE 153 +#define EVP_R_UNSUPPORTED_SIGNATURE_TYPE 154 + +#endif /* OPENSSL_HEADER_EVP_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/ex_data.h b/TMessagesProj/jni/boringssl/include/openssl/ex_data.h new file mode 100644 index 00000000..c0d37731 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/ex_data.h @@ -0,0 +1,214 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef OPENSSL_HEADER_EX_DATA_H +#define OPENSSL_HEADER_EX_DATA_H + +#include + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* ex_data is a mechanism for associating arbitrary extra data with objects. + * For each type of object that supports ex_data, different users can be + * assigned indexes in which to store their data. Each index has callback + * functions that are called when a new object of that type is created, freed + * and duplicated. */ + + +typedef struct crypto_ex_data_st CRYPTO_EX_DATA; + + +/* Type-specific functions. + * + * Each type that supports ex_data provides three functions: */ + +#if 0 /* Sample */ + +/* TYPE_get_ex_new_index allocates a new index for |TYPE|. See the + * descriptions of the callback typedefs for details of when they are + * called. Any of the callback arguments may be NULL. The |argl| and |argp| + * arguments are opaque values that are passed to the callbacks. It returns the + * new index or a negative number on error. + * + * TODO(fork): this should follow the standard calling convention. */ +OPENSSL_EXPORT int TYPE_get_ex_new_index(long argl, void *argp, + CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func); + +/* TYPE_set_ex_data sets an extra data pointer on |t|. The |index| argument + * should have been returned from a previous call to |TYPE_get_ex_new_index|. */ +OPENSSL_EXPORT int TYPE_set_ex_data(TYPE *t, int index, void *arg); + +/* TYPE_get_ex_data returns an extra data pointer for |t|, or NULL if no such + * pointer exists. The |index| argument should have been returned from a + * previous call to |TYPE_get_ex_new_index|. */ +OPENSSL_EXPORT void *TYPE_get_ex_data(const TYPE *t, int index); + +#endif /* Sample */ + + +/* Callback types. */ + +/* CRYPTO_EX_new is the type of a callback function that is called whenever a + * new object of a given class is created. For example, if this callback has + * been passed to |SSL_get_ex_new_index| then it'll be called each time an SSL* + * is created. + * + * The callback is passed the new object (i.e. the SSL*) in |parent|. The + * arguments |argl| and |argp| contain opaque values that were given to + * |CRYPTO_get_ex_new_index|. The callback should return one on success, but + * the value is ignored. + * + * TODO(fork): the |ptr| argument is always NULL, no? */ +typedef int CRYPTO_EX_new(void *parent, void *ptr, CRYPTO_EX_DATA *ad, + int index, long argl, void *argp); + +/* CRYPTO_EX_free is a callback function that is called when an object of the + * class is being destroyed. See |CRYPTO_EX_new| for a discussion of the + * arguments. + * + * If |CRYPTO_get_ex_new_index| was called after the creation of objects of the + * class that this applies to then, when those those objects are destroyed, + * this callback will be called with a NULL value for |ptr|. */ +typedef void CRYPTO_EX_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, + int index, long argl, void *argp); + +/* CRYPTO_EX_dup is a callback function that is called when an object of the + * class is being copied and thus the ex_data linked to it also needs to be + * copied. On entry, |*from_d| points to the data for this index from the + * original object. When the callback returns, |*from_d| will be set as the + * data for this index in |to|. + * + * If |CRYPTO_get_ex_new_index| was called after the creation of objects of the + * class that this applies to then, when those those objects are copies, this + * callback will be called with a NULL value for |*from_d|. */ +typedef int CRYPTO_EX_dup(CRYPTO_EX_DATA *to, const CRYPTO_EX_DATA *from, + void **from_d, int index, long argl, void *argp); + + +/* Deprecated functions. */ + +/* CRYPTO_cleanup_all_ex_data does nothing. */ +OPENSSL_EXPORT void CRYPTO_cleanup_all_ex_data(void); + +struct crypto_ex_data_st { + STACK_OF(void) *sk; +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_EX_DATA_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/hkdf.h b/TMessagesProj/jni/boringssl/include/openssl/hkdf.h new file mode 100644 index 00000000..b7a0dc25 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/hkdf.h @@ -0,0 +1,44 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_HKDF_H +#define OPENSSL_HEADER_HKDF_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Computes HKDF (as specified by RFC 5869) of initial keying material |secret| + * with |salt| and |info| using |digest|, and outputs |out_len| bytes to + * |out_key|. It returns one on success and zero on error. + * + * HKDF is an Extract-and-Expand algorithm. It does not do any key stretching, + * and as such, is not suited to be used alone to generate a key from a + * password. */ +OPENSSL_EXPORT int HKDF(uint8_t *out_key, size_t out_len, const EVP_MD *digest, + const uint8_t *secret, size_t secret_len, + const uint8_t *salt, size_t salt_len, + const uint8_t *info, size_t info_len); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define HKDF_R_OUTPUT_TOO_LARGE 100 + +#endif /* OPENSSL_HEADER_HKDF_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/hmac.h b/TMessagesProj/jni/boringssl/include/openssl/hmac.h new file mode 100644 index 00000000..e521212d --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/hmac.h @@ -0,0 +1,160 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_HMAC_H +#define OPENSSL_HEADER_HMAC_H + +#include + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* HMAC contains functions for constructing PRFs from Merkle–Damgård hash + * functions using HMAC. */ + + +/* One-shot operation. */ + +/* HMAC calculates the HMAC of |data_len| bytes of |data|, using the given key + * and hash function, and writes the result to |out|. On entry, |out| must + * contain |EVP_MAX_MD_SIZE| bytes of space. The actual length of the result is + * written to |*out_len|. It returns |out| or NULL on error. */ +OPENSSL_EXPORT uint8_t *HMAC(const EVP_MD *evp_md, const void *key, + size_t key_len, const uint8_t *data, + size_t data_len, uint8_t *out, + unsigned int *out_len); + + +/* Incremental operation. */ + +/* HMAC_CTX_init initialises |ctx| for use in an HMAC operation. It's assumed + * that HMAC_CTX objects will be allocated on the stack thus no allocation + * function is provided. If needed, allocate |sizeof(HMAC_CTX)| and call + * |HMAC_CTX_init| on it. */ +OPENSSL_EXPORT void HMAC_CTX_init(HMAC_CTX *ctx); + +/* HMAC_CTX_cleanup frees data owned by |ctx|. */ +OPENSSL_EXPORT void HMAC_CTX_cleanup(HMAC_CTX *ctx); + +/* HMAC_Init_ex sets up an initialised |HMAC_CTX| to use |md| as the hash + * function and |key| as the key. For a non-initial call, |md| may be NULL, in + * which case the previous hash function will be used. If the hash function has + * not changed and |key| is NULL, |ctx| reuses the previous key. It returns one + * on success or zero otherwise. + * + * WARNING: NULL and empty keys are ambiguous on non-initial calls. Passing NULL + * |key| but repeating the previous |md| reuses the previous key rather than the + * empty key. */ +OPENSSL_EXPORT int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, size_t key_len, + const EVP_MD *md, ENGINE *impl); + +/* HMAC_Update hashes |data_len| bytes from |data| into the current HMAC + * operation in |ctx|. It returns one. */ +OPENSSL_EXPORT int HMAC_Update(HMAC_CTX *ctx, const uint8_t *data, + size_t data_len); + +/* HMAC_Final completes the HMAC operation in |ctx| and writes the result to + * |out| and the sets |*out_len| to the length of the result. On entry, |out| + * must contain at least |EVP_MAX_MD_SIZE| bytes of space. It returns one on + * success or zero on error. */ +OPENSSL_EXPORT int HMAC_Final(HMAC_CTX *ctx, uint8_t *out, + unsigned int *out_len); + + +/* Utility functions. */ + +/* HMAC_size returns the size, in bytes, of the HMAC that will be produced by + * |ctx|. On entry, |ctx| must have been setup with |HMAC_Init_ex|. */ +OPENSSL_EXPORT size_t HMAC_size(const HMAC_CTX *ctx); + +/* HMAC_CTX_copy_ex sets |dest| equal to |src|. On entry, |dest| must have been + * initialised by calling |HMAC_CTX_init|. It returns one on success and zero + * on error. */ +OPENSSL_EXPORT int HMAC_CTX_copy_ex(HMAC_CTX *dest, const HMAC_CTX *src); + + +/* Deprecated functions. */ + +OPENSSL_EXPORT int HMAC_Init(HMAC_CTX *ctx, const void *key, int key_len, + const EVP_MD *md); + +/* HMAC_CTX_copy calls |HMAC_CTX_init| on |dest| and then sets it equal to + * |src|. On entry, |dest| must /not/ be initialised for an operation with + * |HMAC_Init_ex|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int HMAC_CTX_copy(HMAC_CTX *dest, const HMAC_CTX *src); + + +/* Private functions */ + +#define HMAC_MAX_MD_CBLOCK 128 /* largest known is SHA512 */ + +struct hmac_ctx_st { + const EVP_MD *md; + EVP_MD_CTX md_ctx; + EVP_MD_CTX i_ctx; + EVP_MD_CTX o_ctx; +} /* HMAC_CTX */; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_HMAC_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/lhash.h b/TMessagesProj/jni/boringssl/include/openssl/lhash.h new file mode 100644 index 00000000..691b247c --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/lhash.h @@ -0,0 +1,192 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_LHASH_H +#define OPENSSL_HEADER_LHASH_H + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* lhash is a traditional, chaining hash table that automatically expands and + * contracts as needed. One should not use the lh_* functions directly, rather + * use the type-safe macro wrappers: + * + * A hash table of a specific type of object has type |LHASH_OF(type)|. This + * can be defined (once) with |DEFINE_LHASH_OF(type)| and declared where needed + * with |DECLARE_LHASH_OF(type)|. For example: + * + * struct foo { + * int bar; + * }; + * + * DEFINE_LHASH_OF(struct foo); + * + * Although note that the hash table will contain /pointers/ to |foo|. + * + * A macro will be defined for each of the lh_* functions below. For + * LHASH_OF(foo), the macros would be lh_foo_new, lh_foo_num_items etc. */ + + +#define LHASH_OF(type) struct lhash_st_##type + +#define DEFINE_LHASH_OF(type) LHASH_OF(type) { int dummy; } + +#define DECLARE_LHASH_OF(type) LHASH_OF(type); + +/* The make_macros.sh script in this directory parses the following lines and + * generates the lhash_macros.h file that contains macros for the following + * types of stacks: + * + * LHASH_OF:ASN1_OBJECT + * LHASH_OF:CONF_VALUE + * LHASH_OF:SSL_SESSION */ + +#define IN_LHASH_H +#include +#undef IN_LHASH_H + + +/* lhash_item_st is an element of a hash chain. It points to the opaque data + * for this element and to the next item in the chain. The linked-list is NULL + * terminated. */ +typedef struct lhash_item_st { + void *data; + struct lhash_item_st *next; + /* hash contains the cached, hash value of |data|. */ + uint32_t hash; +} LHASH_ITEM; + +/* lhash_cmp_func is a comparison function that returns a value equal, or not + * equal, to zero depending on whether |*a| is equal, or not equal to |*b|, + * respectively. Note the difference between this and |stack_cmp_func| in that + * this takes pointers to the objects directly. */ +typedef int (*lhash_cmp_func)(const void *a, const void *b); + +/* lhash_hash_func is a function that maps an object to a uniformly distributed + * uint32_t. */ +typedef uint32_t (*lhash_hash_func)(const void *a); + +typedef struct lhash_st { + /* num_items contains the total number of items in the hash table. */ + size_t num_items; + /* buckets is an array of |num_buckets| pointers. Each points to the head of + * a chain of LHASH_ITEM objects that have the same hash value, mod + * |num_buckets|. */ + LHASH_ITEM **buckets; + /* num_buckets contains the length of |buckets|. This value is always >= + * kMinNumBuckets. */ + size_t num_buckets; + /* callback_depth contains the current depth of |lh_doall| or |lh_doall_arg| + * calls. If non-zero then this suppresses resizing of the |buckets| array, + * which would otherwise disrupt the iteration. */ + unsigned callback_depth; + + lhash_cmp_func comp; + lhash_hash_func hash; +} _LHASH; + +/* lh_new returns a new, empty hash table or NULL on error. If |comp| is NULL, + * |strcmp| will be used. If |hash| is NULL, a generic hash function will be + * used. */ +OPENSSL_EXPORT _LHASH *lh_new(lhash_hash_func hash, lhash_cmp_func comp); + +/* lh_free frees the hash table itself but none of the elements. See + * |lh_doall|. */ +OPENSSL_EXPORT void lh_free(_LHASH *lh); + +/* lh_num_items returns the number of items in |lh|. */ +OPENSSL_EXPORT size_t lh_num_items(const _LHASH *lh); + +/* lh_retrieve finds an element equal to |data| in the hash table and returns + * it. If no such element exists, it returns NULL. */ +OPENSSL_EXPORT void *lh_retrieve(const _LHASH *lh, const void *data); + +/* lh_insert inserts |data| into the hash table. If an existing element is + * equal to |data| (with respect to the comparison function) then |*old_data| + * will be set to that value and it will be replaced. Otherwise, or in the + * event of an error, |*old_data| will be set to NULL. It returns one on + * success or zero in the case of an allocation error. */ +OPENSSL_EXPORT int lh_insert(_LHASH *lh, void **old_data, void *data); + +/* lh_delete removes an element equal to |data| from the hash table and returns + * it. If no such element is found, it returns NULL. */ +OPENSSL_EXPORT void *lh_delete(_LHASH *lh, const void *data); + +/* lh_doall calls |func| on each element of the hash table. + * TODO(fork): rename this */ +OPENSSL_EXPORT void lh_doall(_LHASH *lh, void (*func)(void *)); + +/* lh_doall_arg calls |func| on each element of the hash table and also passes + * |arg| as the second argument. + * TODO(fork): rename this */ +OPENSSL_EXPORT void lh_doall_arg(_LHASH *lh, void (*func)(void *, void *), + void *arg); + +/* lh_strhash is the default hash function which processes NUL-terminated + * strings. */ +OPENSSL_EXPORT uint32_t lh_strhash(const char *c); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_STACK_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/lhash_macros.h b/TMessagesProj/jni/boringssl/include/openssl/lhash_macros.h new file mode 100644 index 00000000..1d981073 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/lhash_macros.h @@ -0,0 +1,132 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#if !defined(IN_LHASH_H) +#error "Don't include this file directly. Include lhash.h" +#endif + +/* ASN1_OBJECT */ +#define lh_ASN1_OBJECT_new(hash, comp) \ + ((LHASH_OF(ASN1_OBJECT) *)lh_new( \ + CHECKED_CAST(lhash_hash_func, uint32_t (*)(const ASN1_OBJECT *), hash), \ + CHECKED_CAST(lhash_cmp_func, \ + int (*)(const ASN1_OBJECT *a, const ASN1_OBJECT *b), \ + comp))) + +#define lh_ASN1_OBJECT_free(lh) \ + lh_free(CHECKED_CAST(_LHASH *, LHASH_OF(ASN1_OBJECT) *, lh)); + +#define lh_ASN1_OBJECT_num_items(lh) \ + lh_num_items(CHECKED_CAST(_LHASH *, LHASH_OF(ASN1_OBJECT) *, lh)) + +#define lh_ASN1_OBJECT_retrieve(lh, data) \ + ((ASN1_OBJECT *)lh_retrieve( \ + CHECKED_CAST(_LHASH *, LHASH_OF(ASN1_OBJECT) *, lh), \ + CHECKED_CAST(void *, ASN1_OBJECT *, data))) + +#define lh_ASN1_OBJECT_insert(lh, old_data, data) \ + lh_insert(CHECKED_CAST(_LHASH *, LHASH_OF(ASN1_OBJECT) *, lh), \ + CHECKED_CAST(void **, ASN1_OBJECT **, old_data), \ + CHECKED_CAST(void *, ASN1_OBJECT *, data)) + +#define lh_ASN1_OBJECT_delete(lh, data) \ + ((ASN1_OBJECT *)lh_delete( \ + CHECKED_CAST(_LHASH *, LHASH_OF(ASN1_OBJECT) *, lh), \ + CHECKED_CAST(void *, ASN1_OBJECT *, data))) + +#define lh_ASN1_OBJECT_doall(lh, func) \ + lh_doall(CHECKED_CAST(_LHASH *, LHASH_OF(ASN1_OBJECT) *, lh), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_OBJECT *), func)); + +#define lh_ASN1_OBJECT_doall_arg(lh, func, arg) \ + lh_doall_arg(CHECKED_CAST(_LHASH *, LHASH_OF(ASN1_OBJECT) *, lh), \ + CHECKED_CAST(void (*)(void *, void *), \ + void (*)(ASN1_OBJECT *, void *), func), \ + arg); + +/* CONF_VALUE */ +#define lh_CONF_VALUE_new(hash, comp) \ + ((LHASH_OF(CONF_VALUE) *)lh_new( \ + CHECKED_CAST(lhash_hash_func, uint32_t (*)(const CONF_VALUE *), hash), \ + CHECKED_CAST(lhash_cmp_func, \ + int (*)(const CONF_VALUE *a, const CONF_VALUE *b), comp))) + +#define lh_CONF_VALUE_free(lh) \ + lh_free(CHECKED_CAST(_LHASH *, LHASH_OF(CONF_VALUE) *, lh)); + +#define lh_CONF_VALUE_num_items(lh) \ + lh_num_items(CHECKED_CAST(_LHASH *, LHASH_OF(CONF_VALUE) *, lh)) + +#define lh_CONF_VALUE_retrieve(lh, data) \ + ((CONF_VALUE *)lh_retrieve( \ + CHECKED_CAST(_LHASH *, LHASH_OF(CONF_VALUE) *, lh), \ + CHECKED_CAST(void *, CONF_VALUE *, data))) + +#define lh_CONF_VALUE_insert(lh, old_data, data) \ + lh_insert(CHECKED_CAST(_LHASH *, LHASH_OF(CONF_VALUE) *, lh), \ + CHECKED_CAST(void **, CONF_VALUE **, old_data), \ + CHECKED_CAST(void *, CONF_VALUE *, data)) + +#define lh_CONF_VALUE_delete(lh, data) \ + ((CONF_VALUE *)lh_delete(CHECKED_CAST(_LHASH *, LHASH_OF(CONF_VALUE) *, lh), \ + CHECKED_CAST(void *, CONF_VALUE *, data))) + +#define lh_CONF_VALUE_doall(lh, func) \ + lh_doall(CHECKED_CAST(_LHASH *, LHASH_OF(CONF_VALUE) *, lh), \ + CHECKED_CAST(void (*)(void *), void (*)(CONF_VALUE *), func)); + +#define lh_CONF_VALUE_doall_arg(lh, func, arg) \ + lh_doall_arg(CHECKED_CAST(_LHASH *, LHASH_OF(CONF_VALUE) *, lh), \ + CHECKED_CAST(void (*)(void *, void *), \ + void (*)(CONF_VALUE *, void *), func), \ + arg); + +/* SSL_SESSION */ +#define lh_SSL_SESSION_new(hash, comp) \ + ((LHASH_OF(SSL_SESSION) *)lh_new( \ + CHECKED_CAST(lhash_hash_func, uint32_t (*)(const SSL_SESSION *), hash), \ + CHECKED_CAST(lhash_cmp_func, \ + int (*)(const SSL_SESSION *a, const SSL_SESSION *b), \ + comp))) + +#define lh_SSL_SESSION_free(lh) \ + lh_free(CHECKED_CAST(_LHASH *, LHASH_OF(SSL_SESSION) *, lh)); + +#define lh_SSL_SESSION_num_items(lh) \ + lh_num_items(CHECKED_CAST(_LHASH *, LHASH_OF(SSL_SESSION) *, lh)) + +#define lh_SSL_SESSION_retrieve(lh, data) \ + ((SSL_SESSION *)lh_retrieve( \ + CHECKED_CAST(_LHASH *, LHASH_OF(SSL_SESSION) *, lh), \ + CHECKED_CAST(void *, SSL_SESSION *, data))) + +#define lh_SSL_SESSION_insert(lh, old_data, data) \ + lh_insert(CHECKED_CAST(_LHASH *, LHASH_OF(SSL_SESSION) *, lh), \ + CHECKED_CAST(void **, SSL_SESSION **, old_data), \ + CHECKED_CAST(void *, SSL_SESSION *, data)) + +#define lh_SSL_SESSION_delete(lh, data) \ + ((SSL_SESSION *)lh_delete( \ + CHECKED_CAST(_LHASH *, LHASH_OF(SSL_SESSION) *, lh), \ + CHECKED_CAST(void *, SSL_SESSION *, data))) + +#define lh_SSL_SESSION_doall(lh, func) \ + lh_doall(CHECKED_CAST(_LHASH *, LHASH_OF(SSL_SESSION) *, lh), \ + CHECKED_CAST(void (*)(void *), void (*)(SSL_SESSION *), func)); + +#define lh_SSL_SESSION_doall_arg(lh, func, arg) \ + lh_doall_arg(CHECKED_CAST(_LHASH *, LHASH_OF(SSL_SESSION) *, lh), \ + CHECKED_CAST(void (*)(void *, void *), \ + void (*)(SSL_SESSION *, void *), func), \ + arg); diff --git a/TMessagesProj/jni/boringssl/include/openssl/md5.h b/TMessagesProj/jni/boringssl/include/openssl/md5.h new file mode 100644 index 00000000..9b139222 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/md5.h @@ -0,0 +1,107 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_MD5_H +#define OPENSSL_HEADER_MD5_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* MD5. */ + + +/* MD5_CBLOCK is the block size of MD5. */ +#define MD5_CBLOCK 64 + +/* MD5_DIGEST_LENGTH is the length of an MD5 digest. */ +#define MD5_DIGEST_LENGTH 16 + +/* MD5_Init initialises |md5| and returns one. */ +OPENSSL_EXPORT int MD5_Init(MD5_CTX *md5); + +/* MD5_Update adds |len| bytes from |data| to |md5| and returns one. */ +OPENSSL_EXPORT int MD5_Update(MD5_CTX *md5, const void *data, size_t len); + +/* MD5_Final adds the final padding to |md5| and writes the resulting digest to + * |md|, which must have at least |MD5_DIGEST_LENGTH| bytes of space. It + * returns one. */ +OPENSSL_EXPORT int MD5_Final(uint8_t *md, MD5_CTX *md5); + +/* MD5 writes the digest of |len| bytes from |data| to |out| and returns |out|. + * There must be at least |MD5_DIGEST_LENGTH| bytes of space in |out|. */ +OPENSSL_EXPORT uint8_t *MD5(const uint8_t *data, size_t len, uint8_t *out); + +/* MD5_Transform is a low-level function that performs a single, MD5 block + * transformation using the state from |md5| and 64 bytes from |block|. */ +OPENSSL_EXPORT void MD5_Transform(MD5_CTX *md5, const uint8_t *block); + +struct md5_state_st { + uint32_t A, B, C, D; + uint32_t Nl, Nh; + uint32_t data[16]; + unsigned int num; +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_MD5_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/mem.h b/TMessagesProj/jni/boringssl/include/openssl/mem.h new file mode 100644 index 00000000..c8e2b3ef --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/mem.h @@ -0,0 +1,140 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_MEM_H +#define OPENSSL_HEADER_MEM_H + +#include + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Memory and string functions, see also buf.h. + * + * OpenSSL has, historically, had a complex set of malloc debugging options. + * However, that was written in a time before Valgrind and ASAN. Since we now + * have those tools, the OpenSSL allocation functions are simply macros around + * the standard memory functions. */ + + +#define OPENSSL_malloc malloc +#define OPENSSL_realloc realloc +#define OPENSSL_free free + +/* OPENSSL_realloc_clean acts like |realloc|, but clears the previous memory + * buffer. Because this is implemented as a wrapper around |malloc|, it needs + * to be given the size of the buffer pointed to by |ptr|. */ +void *OPENSSL_realloc_clean(void *ptr, size_t old_size, size_t new_size); + +/* OPENSSL_cleanse zeros out |len| bytes of memory at |ptr|. This is similar to + * |memset_s| from C11. */ +OPENSSL_EXPORT void OPENSSL_cleanse(void *ptr, size_t len); + +/* CRYPTO_memcmp returns zero iff the |len| bytes at |a| and |b| are equal. It + * takes an amount of time dependent on |len|, but independent of the contents + * of |a| and |b|. Unlike memcmp, it cannot be used to put elements into a + * defined order as the return value when a != b is undefined, other than to be + * non-zero. */ +OPENSSL_EXPORT int CRYPTO_memcmp(const void *a, const void *b, size_t len); + +/* OPENSSL_hash32 implements the 32 bit, FNV-1a hash. */ +OPENSSL_EXPORT uint32_t OPENSSL_hash32(const void *ptr, size_t len); + +/* OPENSSL_strdup has the same behaviour as strdup(3). */ +OPENSSL_EXPORT char *OPENSSL_strdup(const char *s); + +/* OPENSSL_strnlen has the same behaviour as strnlen(3). */ +OPENSSL_EXPORT size_t OPENSSL_strnlen(const char *s, size_t len); + +/* OPENSSL_strcasecmp has the same behaviour as strcasecmp(3). */ +OPENSSL_EXPORT int OPENSSL_strcasecmp(const char *a, const char *b); + +/* OPENSSL_strncasecmp has the same behaviour as strncasecmp(3). */ +OPENSSL_EXPORT int OPENSSL_strncasecmp(const char *a, const char *b, size_t n); + +/* DECIMAL_SIZE returns an upper bound for the length of the decimal + * representation of the given type. */ +#define DECIMAL_SIZE(type) ((sizeof(type)*8+2)/3+1) + +/* Printf functions. + * + * These functions are either OpenSSL wrappers for standard functions (i.e. + * |BIO_snprintf| and |BIO_vsnprintf|) which don't exist in C89, or are + * versions of printf functions that output to a BIO rather than a FILE. */ +#ifdef __GNUC__ +#define __bio_h__attr__ __attribute__ +#else +#define __bio_h__attr__(x) +#endif +OPENSSL_EXPORT int BIO_snprintf(char *buf, size_t n, const char *format, ...) + __bio_h__attr__((__format__(__printf__, 3, 4))); + +OPENSSL_EXPORT int BIO_vsnprintf(char *buf, size_t n, const char *format, + va_list args) + __bio_h__attr__((__format__(__printf__, 3, 0))); +#undef __bio_h__attr__ + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_MEM_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/modes.h b/TMessagesProj/jni/boringssl/include/openssl/modes.h new file mode 100644 index 00000000..220adec5 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/modes.h @@ -0,0 +1,223 @@ +/* ==================================================================== + * Copyright (c) 2008 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== */ + +#ifndef OPENSSL_HEADER_MODES_H +#define OPENSSL_HEADER_MODES_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* modes.h contains functions that implement various block-cipher modes. */ + + +/* block128_f is the type of a 128-bit, block cipher. */ +typedef void (*block128_f)(const uint8_t in[16], uint8_t out[16], + const void *key); + + +/* CTR. */ + +/* ctr128_f is the type of a function that performs CTR-mode encryption. */ +typedef void (*ctr128_f)(const uint8_t *in, uint8_t *out, size_t blocks, + const void *key, const uint8_t ivec[16]); + +/* CRYPTO_ctr128_encrypt encrypts (or decrypts, it's the same in CTR mode) + * |len| bytes from |in| to |out| using |block| in counter mode. There's no + * requirement that |len| be a multiple of any value and any partial blocks are + * stored in |ecount_buf| and |*num|, which must be zeroed before the initial + * call. The counter is a 128-bit, big-endian value in |ivec| and is + * incremented by this function. */ +OPENSSL_EXPORT void CRYPTO_ctr128_encrypt(const uint8_t *in, uint8_t *out, + size_t len, const void *key, + uint8_t ivec[16], + uint8_t ecount_buf[16], + unsigned int *num, block128_f block); + +/* CRYPTO_ctr128_encrypt_ctr32 acts like |CRYPTO_ctr128_encrypt| but takes + * |ctr|, a function that performs CTR mode but only deals with the lower 32 + * bits of the counter. This is useful when |ctr| can be an optimised + * function. */ +OPENSSL_EXPORT void CRYPTO_ctr128_encrypt_ctr32( + const uint8_t *in, uint8_t *out, size_t len, const void *key, + uint8_t ivec[16], uint8_t ecount_buf[16], unsigned int *num, ctr128_f ctr); + + +/* GCM. */ + +typedef struct gcm128_context GCM128_CONTEXT; + +/* CRYPTO_gcm128_new allocates a fresh |GCM128_CONTEXT| and calls + * |CRYPTO_gcm128_init|. It returns the new context, or NULL on error. */ +OPENSSL_EXPORT GCM128_CONTEXT *CRYPTO_gcm128_new(void *key, block128_f block); + +/* CRYPTO_gcm128_init initialises |ctx| to use |block| (typically AES) with the + * given key. */ +OPENSSL_EXPORT void CRYPTO_gcm128_init(GCM128_CONTEXT *ctx, void *key, + block128_f block); + +/* CRYPTO_gcm128_setiv sets the IV (nonce) for |ctx|. */ +OPENSSL_EXPORT void CRYPTO_gcm128_setiv(GCM128_CONTEXT *ctx, const uint8_t *iv, + size_t len); + +/* CRYPTO_gcm128_aad sets the authenticated data for an instance of GCM. This + * must be called before and data is encrypted. It returns one on success and + * zero otherwise. */ +OPENSSL_EXPORT int CRYPTO_gcm128_aad(GCM128_CONTEXT *ctx, const uint8_t *aad, + size_t len); + +/* CRYPTO_gcm128_encrypt encrypts |len| bytes from |in| to |out|. It returns + * one on success and zero otherwise. */ +OPENSSL_EXPORT int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const uint8_t *in, + uint8_t *out, size_t len); + +/* CRYPTO_gcm128_decrypt decrypts |len| bytes from |in| to |out|. It returns + * one on success and zero otherwise. */ +OPENSSL_EXPORT int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const uint8_t *in, + uint8_t *out, size_t len); + +/* CRYPTO_gcm128_encrypt_ctr32 encrypts |len| bytes from |in| to |out| using a + * CTR function that only handles the bottom 32 bits of the nonce, like + * |CRYPTO_ctr128_encrypt_ctr32|. It returns one on success and zero + * otherwise. */ +OPENSSL_EXPORT int CRYPTO_gcm128_encrypt_ctr32(GCM128_CONTEXT *ctx, + const uint8_t *in, uint8_t *out, + size_t len, ctr128_f stream); + +/* CRYPTO_gcm128_decrypt_ctr32 decrypts |len| bytes from |in| to |out| using a + * CTR function that only handles the bottom 32 bits of the nonce, like + * |CRYPTO_ctr128_encrypt_ctr32|. It returns one on success and zero + * otherwise. */ +OPENSSL_EXPORT int CRYPTO_gcm128_decrypt_ctr32(GCM128_CONTEXT *ctx, + const uint8_t *in, uint8_t *out, + size_t len, ctr128_f stream); + +/* CRYPTO_gcm128_finish calculates the authenticator and compares it against + * |len| bytes of |tag|. It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int CRYPTO_gcm128_finish(GCM128_CONTEXT *ctx, const uint8_t *tag, + size_t len); + +/* CRYPTO_gcm128_tag calculates the authenticator and copies it into |tag|. The + * minimum of |len| and 16 bytes are copied into |tag|. */ +OPENSSL_EXPORT void CRYPTO_gcm128_tag(GCM128_CONTEXT *ctx, uint8_t *tag, + size_t len); + +/* CRYPTO_gcm128_release clears and frees |ctx|. */ +OPENSSL_EXPORT void CRYPTO_gcm128_release(GCM128_CONTEXT *ctx); + + +/* CBC. */ + +/* cbc128_f is the type of a function that performs CBC-mode encryption. */ +typedef void (*cbc128_f)(const uint8_t *in, uint8_t *out, size_t len, + const void *key, uint8_t ivec[16], int enc); + +/* CRYPTO_cbc128_encrypt encrypts |len| bytes from |in| to |out| using the + * given IV and block cipher in CBC mode. The input need not be a multiple of + * 128 bits long, but the output will round up to the nearest 128 bit multiple, + * zero padding the input if needed. The IV will be updated on return. */ +void CRYPTO_cbc128_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const void *key, uint8_t ivec[16], block128_f block); + +/* CRYPTO_cbc128_decrypt decrypts |len| bytes from |in| to |out| using the + * given IV and block cipher in CBC mode. If |len| is not a multiple of 128 + * bits then only that many bytes will be written, but a multiple of 128 bits + * is always read from |in|. The IV will be updated on return. */ +void CRYPTO_cbc128_decrypt(const uint8_t *in, uint8_t *out, size_t len, + const void *key, uint8_t ivec[16], block128_f block); + + +/* OFB. */ + +/* CRYPTO_ofb128_encrypt encrypts (or decrypts, it's the same with OFB mode) + * |len| bytes from |in| to |out| using |block| in OFB mode. There's no + * requirement that |len| be a multiple of any value and any partial blocks are + * stored in |ivec| and |*num|, the latter must be zero before the initial + * call. */ +void CRYPTO_ofb128_encrypt(const uint8_t *in, uint8_t *out, + size_t len, const void *key, uint8_t ivec[16], + int *num, block128_f block); + + +/* CFB. */ + +/* CRYPTO_cfb128_encrypt encrypts (or decrypts, if |enc| is zero) |len| bytes + * from |in| to |out| using |block| in CFB mode. There's no requirement that + * |len| be a multiple of any value and any partial blocks are stored in |ivec| + * and |*num|, the latter must be zero before the initial call. */ +void CRYPTO_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const void *key, uint8_t ivec[16], int *num, int enc, + block128_f block); + +/* CRYPTO_cfb128_8_encrypt encrypts (or decrypts, if |enc| is zero) |len| bytes + * from |in| to |out| using |block| in CFB-8 mode. Prior to the first call + * |num| should be set to zero. */ +void CRYPTO_cfb128_8_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const void *key, uint8_t ivec[16], int *num, + int enc, block128_f block); + +/* CRYPTO_cfb128_1_encrypt encrypts (or decrypts, if |enc| is zero) |len| bytes + * from |in| to |out| using |block| in CFB-1 mode. Prior to the first call + * |num| should be set to zero. */ +void CRYPTO_cfb128_1_encrypt(const uint8_t *in, uint8_t *out, size_t bits, + const void *key, uint8_t ivec[16], int *num, + int enc, block128_f block); + +size_t CRYPTO_cts128_encrypt_block(const uint8_t *in, uint8_t *out, size_t len, + const void *key, uint8_t ivec[16], + block128_f block); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_MODES_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/obj.h b/TMessagesProj/jni/boringssl/include/openssl/obj.h new file mode 100644 index 00000000..0c7ae60b --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/obj.h @@ -0,0 +1,198 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_OBJECTS_H +#define OPENSSL_HEADER_OBJECTS_H + +#include + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* The objects library deals with the registration and indexing of ASN.1 object + * identifiers. These values are often written as a dotted sequence of numbers, + * e.g. 1.2.840.113549.1.9.16.3.9. + * + * Internally, OpenSSL likes to deal with these values by numbering them with + * numbers called "nids". OpenSSL has a large, built-in database of common + * object identifiers and also has both short and long names for them. + * + * This library provides functions for translating between object identifiers, + * nids, short names and long names. + * + * The nid values should not be used outside of a single process: they are not + * stable identifiers. */ + + +/* Basic operations. */ + +/* OBJ_dup returns a duplicate copy of |obj| or NULL on allocation failure. */ +OPENSSL_EXPORT ASN1_OBJECT *OBJ_dup(const ASN1_OBJECT *obj); + +/* OBJ_cmp returns a value less than, equal to or greater than zero if |a| is + * less than, equal to or greater than |b|, respectively. */ +OPENSSL_EXPORT int OBJ_cmp(const ASN1_OBJECT *a, const ASN1_OBJECT *b); + + +/* Looking up nids. */ + +/* OBJ_obj2nid returns the nid corresponding to |obj|, or |NID_undef| if no + * such object is known. */ +OPENSSL_EXPORT int OBJ_obj2nid(const ASN1_OBJECT *obj); + +/* OBJ_cbs2nid returns the nid corresponding to the DER data in |cbs|, or + * |NID_undef| if no such object is known. */ +OPENSSL_EXPORT int OBJ_cbs2nid(const CBS *cbs); + +/* OBJ_sn2nid returns the nid corresponding to |short_name|, or |NID_undef| if + * no such short name is known. */ +OPENSSL_EXPORT int OBJ_sn2nid(const char *short_name); + +/* OBJ_ln2nid returns the nid corresponding to |long_name|, or |NID_undef| if + * no such long name is known. */ +OPENSSL_EXPORT int OBJ_ln2nid(const char *long_name); + +/* OBJ_txt2nid returns the nid corresponding to |s|, which may be a short name, + * long name, or an ASCII string containing a dotted sequence of numbers. It + * returns the nid or NID_undef if unknown. */ +OPENSSL_EXPORT int OBJ_txt2nid(const char *s); + + +/* Getting information about nids. */ + +/* OBJ_nid2obj returns the ASN1_OBJECT corresponding to |nid|, or NULL if |nid| + * is unknown. */ +OPENSSL_EXPORT const ASN1_OBJECT *OBJ_nid2obj(int nid); + +/* OBJ_nid2sn returns the short name for |nid|, or NULL if |nid| is unknown. */ +OPENSSL_EXPORT const char *OBJ_nid2sn(int nid); + +/* OBJ_nid2sn returns the long name for |nid|, or NULL if |nid| is unknown. */ +OPENSSL_EXPORT const char *OBJ_nid2ln(int nid); + +/* OBJ_nid2cbb writes |nid| as an ASN.1 OBJECT IDENTIFIER to |out|. It returns + * one on success or zero otherwise. */ +OPENSSL_EXPORT int OBJ_nid2cbb(CBB *out, int nid); + + +/* Dealing with textual representations of object identifiers. */ + +/* OBJ_txt2obj returns an ASN1_OBJECT for the textual respresentation in |s|. + * If |dont_search_names| is zero, then |s| will be matched against the long + * and short names of a known objects to find a match. Otherwise |s| must + * contain an ASCII string with a dotted sequence of numbers. The resulting + * object need not be previously known. It returns a freshly allocated + * |ASN1_OBJECT| or NULL on error. */ +OPENSSL_EXPORT ASN1_OBJECT *OBJ_txt2obj(const char *s, int dont_search_names); + +/* OBJ_obj2txt converts |obj| to a textual representation. If + * |dont_return_name| is zero then |obj| will be matched against known objects + * and the long (preferably) or short name will be used if found. Otherwise + * |obj| will be converted into a dotted sequence of integers. If |out| is not + * NULL, then at most |out_len| bytes of the textual form will be written + * there. If |out_len| is at least one, then string written to |out| will + * always be NUL terminated. It returns the number of characters that could + * have been written, not including the final NUL, or -1 on error. */ +OPENSSL_EXPORT int OBJ_obj2txt(char *out, int out_len, const ASN1_OBJECT *obj, + int dont_return_name); + + +/* Adding objects at runtime. */ + +/* OBJ_create adds a known object and returns the nid of the new object, or + * NID_undef on error. */ +OPENSSL_EXPORT int OBJ_create(const char *oid, const char *short_name, + const char *long_name); + + +/* Handling signature algorithm identifiers. + * + * Some NIDs (e.g. sha256WithRSAEncryption) specify both a digest algorithm and + * a public key algorithm. The following functions map between pairs of digest + * and public-key algorithms and the NIDs that specify their combination. + * + * Sometimes the combination NID leaves the digest unspecified (e.g. + * rsassaPss). In these cases, the digest NID is |NID_undef|. */ + +/* OBJ_find_sigid_algs finds the digest and public-key NIDs that correspond to + * the signing algorithm |sign_nid|. If successful, it sets |*out_digest_nid| + * and |*out_pkey_nid| and returns one. Otherwise it returns zero. Any of + * |out_digest_nid| or |out_pkey_nid| can be NULL if the caller doesn't need + * that output value. */ +OPENSSL_EXPORT int OBJ_find_sigid_algs(int sign_nid, int *out_digest_nid, + int *out_pkey_nid); + +/* OBJ_find_sigid_by_algs finds the signature NID that corresponds to the + * combination of |digest_nid| and |pkey_nid|. If success, it sets + * |*out_sign_nid| and returns one. Otherwise it returns zero. The + * |out_sign_nid| argument can be NULL if the caller only wishes to learn + * whether the combination is valid. */ +OPENSSL_EXPORT int OBJ_find_sigid_by_algs(int *out_sign_nid, int digest_nid, + int pkey_nid); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define OBJ_R_UNKNOWN_NID 100 + +#endif /* OPENSSL_HEADER_OBJECTS_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/obj_mac.h b/TMessagesProj/jni/boringssl/include/openssl/obj_mac.h new file mode 100644 index 00000000..55e1cba2 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/obj_mac.h @@ -0,0 +1,4140 @@ +/* THIS FILE IS GENERATED FROM objects.txt by objects.pl via the + * following command: + * perl objects.pl objects.txt obj_mac.num ../../include/openssl/obj_mac.h */ + +/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#define SN_undef "UNDEF" +#define LN_undef "undefined" +#define NID_undef 0 +#define OBJ_undef 0L + +#define SN_itu_t "ITU-T" +#define LN_itu_t "itu-t" +#define NID_itu_t 645 +#define OBJ_itu_t 0L + +#define NID_ccitt 404 +#define OBJ_ccitt OBJ_itu_t + +#define SN_iso "ISO" +#define LN_iso "iso" +#define NID_iso 181 +#define OBJ_iso 1L + +#define SN_joint_iso_itu_t "JOINT-ISO-ITU-T" +#define LN_joint_iso_itu_t "joint-iso-itu-t" +#define NID_joint_iso_itu_t 646 +#define OBJ_joint_iso_itu_t 2L + +#define NID_joint_iso_ccitt 393 +#define OBJ_joint_iso_ccitt OBJ_joint_iso_itu_t + +#define SN_member_body "member-body" +#define LN_member_body "ISO Member Body" +#define NID_member_body 182 +#define OBJ_member_body OBJ_iso,2L + +#define SN_identified_organization "identified-organization" +#define NID_identified_organization 676 +#define OBJ_identified_organization OBJ_iso,3L + +#define SN_hmac_md5 "HMAC-MD5" +#define LN_hmac_md5 "hmac-md5" +#define NID_hmac_md5 780 +#define OBJ_hmac_md5 OBJ_identified_organization,6L,1L,5L,5L,8L,1L,1L + +#define SN_hmac_sha1 "HMAC-SHA1" +#define LN_hmac_sha1 "hmac-sha1" +#define NID_hmac_sha1 781 +#define OBJ_hmac_sha1 OBJ_identified_organization,6L,1L,5L,5L,8L,1L,2L + +#define SN_certicom_arc "certicom-arc" +#define NID_certicom_arc 677 +#define OBJ_certicom_arc OBJ_identified_organization,132L + +#define SN_international_organizations "international-organizations" +#define LN_international_organizations "International Organizations" +#define NID_international_organizations 647 +#define OBJ_international_organizations OBJ_joint_iso_itu_t,23L + +#define SN_wap "wap" +#define NID_wap 678 +#define OBJ_wap OBJ_international_organizations,43L + +#define SN_wap_wsg "wap-wsg" +#define NID_wap_wsg 679 +#define OBJ_wap_wsg OBJ_wap,1L + +#define SN_selected_attribute_types "selected-attribute-types" +#define LN_selected_attribute_types "Selected Attribute Types" +#define NID_selected_attribute_types 394 +#define OBJ_selected_attribute_types OBJ_joint_iso_itu_t,5L,1L,5L + +#define SN_clearance "clearance" +#define NID_clearance 395 +#define OBJ_clearance OBJ_selected_attribute_types,55L + +#define SN_ISO_US "ISO-US" +#define LN_ISO_US "ISO US Member Body" +#define NID_ISO_US 183 +#define OBJ_ISO_US OBJ_member_body,840L + +#define SN_X9_57 "X9-57" +#define LN_X9_57 "X9.57" +#define NID_X9_57 184 +#define OBJ_X9_57 OBJ_ISO_US,10040L + +#define SN_X9cm "X9cm" +#define LN_X9cm "X9.57 CM ?" +#define NID_X9cm 185 +#define OBJ_X9cm OBJ_X9_57,4L + +#define SN_dsa "DSA" +#define LN_dsa "dsaEncryption" +#define NID_dsa 116 +#define OBJ_dsa OBJ_X9cm,1L + +#define SN_dsaWithSHA1 "DSA-SHA1" +#define LN_dsaWithSHA1 "dsaWithSHA1" +#define NID_dsaWithSHA1 113 +#define OBJ_dsaWithSHA1 OBJ_X9cm,3L + +#define SN_ansi_X9_62 "ansi-X9-62" +#define LN_ansi_X9_62 "ANSI X9.62" +#define NID_ansi_X9_62 405 +#define OBJ_ansi_X9_62 OBJ_ISO_US,10045L + +#define OBJ_X9_62_id_fieldType OBJ_ansi_X9_62,1L + +#define SN_X9_62_prime_field "prime-field" +#define NID_X9_62_prime_field 406 +#define OBJ_X9_62_prime_field OBJ_X9_62_id_fieldType,1L + +#define SN_X9_62_characteristic_two_field "characteristic-two-field" +#define NID_X9_62_characteristic_two_field 407 +#define OBJ_X9_62_characteristic_two_field OBJ_X9_62_id_fieldType,2L + +#define SN_X9_62_id_characteristic_two_basis "id-characteristic-two-basis" +#define NID_X9_62_id_characteristic_two_basis 680 +#define OBJ_X9_62_id_characteristic_two_basis OBJ_X9_62_characteristic_two_field,3L + +#define SN_X9_62_onBasis "onBasis" +#define NID_X9_62_onBasis 681 +#define OBJ_X9_62_onBasis OBJ_X9_62_id_characteristic_two_basis,1L + +#define SN_X9_62_tpBasis "tpBasis" +#define NID_X9_62_tpBasis 682 +#define OBJ_X9_62_tpBasis OBJ_X9_62_id_characteristic_two_basis,2L + +#define SN_X9_62_ppBasis "ppBasis" +#define NID_X9_62_ppBasis 683 +#define OBJ_X9_62_ppBasis OBJ_X9_62_id_characteristic_two_basis,3L + +#define OBJ_X9_62_id_publicKeyType OBJ_ansi_X9_62,2L + +#define SN_X9_62_id_ecPublicKey "id-ecPublicKey" +#define NID_X9_62_id_ecPublicKey 408 +#define OBJ_X9_62_id_ecPublicKey OBJ_X9_62_id_publicKeyType,1L + +#define OBJ_X9_62_ellipticCurve OBJ_ansi_X9_62,3L + +#define OBJ_X9_62_c_TwoCurve OBJ_X9_62_ellipticCurve,0L + +#define SN_X9_62_c2pnb163v1 "c2pnb163v1" +#define NID_X9_62_c2pnb163v1 684 +#define OBJ_X9_62_c2pnb163v1 OBJ_X9_62_c_TwoCurve,1L + +#define SN_X9_62_c2pnb163v2 "c2pnb163v2" +#define NID_X9_62_c2pnb163v2 685 +#define OBJ_X9_62_c2pnb163v2 OBJ_X9_62_c_TwoCurve,2L + +#define SN_X9_62_c2pnb163v3 "c2pnb163v3" +#define NID_X9_62_c2pnb163v3 686 +#define OBJ_X9_62_c2pnb163v3 OBJ_X9_62_c_TwoCurve,3L + +#define SN_X9_62_c2pnb176v1 "c2pnb176v1" +#define NID_X9_62_c2pnb176v1 687 +#define OBJ_X9_62_c2pnb176v1 OBJ_X9_62_c_TwoCurve,4L + +#define SN_X9_62_c2tnb191v1 "c2tnb191v1" +#define NID_X9_62_c2tnb191v1 688 +#define OBJ_X9_62_c2tnb191v1 OBJ_X9_62_c_TwoCurve,5L + +#define SN_X9_62_c2tnb191v2 "c2tnb191v2" +#define NID_X9_62_c2tnb191v2 689 +#define OBJ_X9_62_c2tnb191v2 OBJ_X9_62_c_TwoCurve,6L + +#define SN_X9_62_c2tnb191v3 "c2tnb191v3" +#define NID_X9_62_c2tnb191v3 690 +#define OBJ_X9_62_c2tnb191v3 OBJ_X9_62_c_TwoCurve,7L + +#define SN_X9_62_c2onb191v4 "c2onb191v4" +#define NID_X9_62_c2onb191v4 691 +#define OBJ_X9_62_c2onb191v4 OBJ_X9_62_c_TwoCurve,8L + +#define SN_X9_62_c2onb191v5 "c2onb191v5" +#define NID_X9_62_c2onb191v5 692 +#define OBJ_X9_62_c2onb191v5 OBJ_X9_62_c_TwoCurve,9L + +#define SN_X9_62_c2pnb208w1 "c2pnb208w1" +#define NID_X9_62_c2pnb208w1 693 +#define OBJ_X9_62_c2pnb208w1 OBJ_X9_62_c_TwoCurve,10L + +#define SN_X9_62_c2tnb239v1 "c2tnb239v1" +#define NID_X9_62_c2tnb239v1 694 +#define OBJ_X9_62_c2tnb239v1 OBJ_X9_62_c_TwoCurve,11L + +#define SN_X9_62_c2tnb239v2 "c2tnb239v2" +#define NID_X9_62_c2tnb239v2 695 +#define OBJ_X9_62_c2tnb239v2 OBJ_X9_62_c_TwoCurve,12L + +#define SN_X9_62_c2tnb239v3 "c2tnb239v3" +#define NID_X9_62_c2tnb239v3 696 +#define OBJ_X9_62_c2tnb239v3 OBJ_X9_62_c_TwoCurve,13L + +#define SN_X9_62_c2onb239v4 "c2onb239v4" +#define NID_X9_62_c2onb239v4 697 +#define OBJ_X9_62_c2onb239v4 OBJ_X9_62_c_TwoCurve,14L + +#define SN_X9_62_c2onb239v5 "c2onb239v5" +#define NID_X9_62_c2onb239v5 698 +#define OBJ_X9_62_c2onb239v5 OBJ_X9_62_c_TwoCurve,15L + +#define SN_X9_62_c2pnb272w1 "c2pnb272w1" +#define NID_X9_62_c2pnb272w1 699 +#define OBJ_X9_62_c2pnb272w1 OBJ_X9_62_c_TwoCurve,16L + +#define SN_X9_62_c2pnb304w1 "c2pnb304w1" +#define NID_X9_62_c2pnb304w1 700 +#define OBJ_X9_62_c2pnb304w1 OBJ_X9_62_c_TwoCurve,17L + +#define SN_X9_62_c2tnb359v1 "c2tnb359v1" +#define NID_X9_62_c2tnb359v1 701 +#define OBJ_X9_62_c2tnb359v1 OBJ_X9_62_c_TwoCurve,18L + +#define SN_X9_62_c2pnb368w1 "c2pnb368w1" +#define NID_X9_62_c2pnb368w1 702 +#define OBJ_X9_62_c2pnb368w1 OBJ_X9_62_c_TwoCurve,19L + +#define SN_X9_62_c2tnb431r1 "c2tnb431r1" +#define NID_X9_62_c2tnb431r1 703 +#define OBJ_X9_62_c2tnb431r1 OBJ_X9_62_c_TwoCurve,20L + +#define OBJ_X9_62_primeCurve OBJ_X9_62_ellipticCurve,1L + +#define SN_X9_62_prime192v1 "prime192v1" +#define NID_X9_62_prime192v1 409 +#define OBJ_X9_62_prime192v1 OBJ_X9_62_primeCurve,1L + +#define SN_X9_62_prime192v2 "prime192v2" +#define NID_X9_62_prime192v2 410 +#define OBJ_X9_62_prime192v2 OBJ_X9_62_primeCurve,2L + +#define SN_X9_62_prime192v3 "prime192v3" +#define NID_X9_62_prime192v3 411 +#define OBJ_X9_62_prime192v3 OBJ_X9_62_primeCurve,3L + +#define SN_X9_62_prime239v1 "prime239v1" +#define NID_X9_62_prime239v1 412 +#define OBJ_X9_62_prime239v1 OBJ_X9_62_primeCurve,4L + +#define SN_X9_62_prime239v2 "prime239v2" +#define NID_X9_62_prime239v2 413 +#define OBJ_X9_62_prime239v2 OBJ_X9_62_primeCurve,5L + +#define SN_X9_62_prime239v3 "prime239v3" +#define NID_X9_62_prime239v3 414 +#define OBJ_X9_62_prime239v3 OBJ_X9_62_primeCurve,6L + +#define SN_X9_62_prime256v1 "prime256v1" +#define NID_X9_62_prime256v1 415 +#define OBJ_X9_62_prime256v1 OBJ_X9_62_primeCurve,7L + +#define OBJ_X9_62_id_ecSigType OBJ_ansi_X9_62,4L + +#define SN_ecdsa_with_SHA1 "ecdsa-with-SHA1" +#define NID_ecdsa_with_SHA1 416 +#define OBJ_ecdsa_with_SHA1 OBJ_X9_62_id_ecSigType,1L + +#define SN_ecdsa_with_Recommended "ecdsa-with-Recommended" +#define NID_ecdsa_with_Recommended 791 +#define OBJ_ecdsa_with_Recommended OBJ_X9_62_id_ecSigType,2L + +#define SN_ecdsa_with_Specified "ecdsa-with-Specified" +#define NID_ecdsa_with_Specified 792 +#define OBJ_ecdsa_with_Specified OBJ_X9_62_id_ecSigType,3L + +#define SN_ecdsa_with_SHA224 "ecdsa-with-SHA224" +#define NID_ecdsa_with_SHA224 793 +#define OBJ_ecdsa_with_SHA224 OBJ_ecdsa_with_Specified,1L + +#define SN_ecdsa_with_SHA256 "ecdsa-with-SHA256" +#define NID_ecdsa_with_SHA256 794 +#define OBJ_ecdsa_with_SHA256 OBJ_ecdsa_with_Specified,2L + +#define SN_ecdsa_with_SHA384 "ecdsa-with-SHA384" +#define NID_ecdsa_with_SHA384 795 +#define OBJ_ecdsa_with_SHA384 OBJ_ecdsa_with_Specified,3L + +#define SN_ecdsa_with_SHA512 "ecdsa-with-SHA512" +#define NID_ecdsa_with_SHA512 796 +#define OBJ_ecdsa_with_SHA512 OBJ_ecdsa_with_Specified,4L + +#define OBJ_secg_ellipticCurve OBJ_certicom_arc,0L + +#define SN_secp112r1 "secp112r1" +#define NID_secp112r1 704 +#define OBJ_secp112r1 OBJ_secg_ellipticCurve,6L + +#define SN_secp112r2 "secp112r2" +#define NID_secp112r2 705 +#define OBJ_secp112r2 OBJ_secg_ellipticCurve,7L + +#define SN_secp128r1 "secp128r1" +#define NID_secp128r1 706 +#define OBJ_secp128r1 OBJ_secg_ellipticCurve,28L + +#define SN_secp128r2 "secp128r2" +#define NID_secp128r2 707 +#define OBJ_secp128r2 OBJ_secg_ellipticCurve,29L + +#define SN_secp160k1 "secp160k1" +#define NID_secp160k1 708 +#define OBJ_secp160k1 OBJ_secg_ellipticCurve,9L + +#define SN_secp160r1 "secp160r1" +#define NID_secp160r1 709 +#define OBJ_secp160r1 OBJ_secg_ellipticCurve,8L + +#define SN_secp160r2 "secp160r2" +#define NID_secp160r2 710 +#define OBJ_secp160r2 OBJ_secg_ellipticCurve,30L + +#define SN_secp192k1 "secp192k1" +#define NID_secp192k1 711 +#define OBJ_secp192k1 OBJ_secg_ellipticCurve,31L + +#define SN_secp224k1 "secp224k1" +#define NID_secp224k1 712 +#define OBJ_secp224k1 OBJ_secg_ellipticCurve,32L + +#define SN_secp224r1 "secp224r1" +#define NID_secp224r1 713 +#define OBJ_secp224r1 OBJ_secg_ellipticCurve,33L + +#define SN_secp256k1 "secp256k1" +#define NID_secp256k1 714 +#define OBJ_secp256k1 OBJ_secg_ellipticCurve,10L + +#define SN_secp384r1 "secp384r1" +#define NID_secp384r1 715 +#define OBJ_secp384r1 OBJ_secg_ellipticCurve,34L + +#define SN_secp521r1 "secp521r1" +#define NID_secp521r1 716 +#define OBJ_secp521r1 OBJ_secg_ellipticCurve,35L + +#define SN_sect113r1 "sect113r1" +#define NID_sect113r1 717 +#define OBJ_sect113r1 OBJ_secg_ellipticCurve,4L + +#define SN_sect113r2 "sect113r2" +#define NID_sect113r2 718 +#define OBJ_sect113r2 OBJ_secg_ellipticCurve,5L + +#define SN_sect131r1 "sect131r1" +#define NID_sect131r1 719 +#define OBJ_sect131r1 OBJ_secg_ellipticCurve,22L + +#define SN_sect131r2 "sect131r2" +#define NID_sect131r2 720 +#define OBJ_sect131r2 OBJ_secg_ellipticCurve,23L + +#define SN_sect163k1 "sect163k1" +#define NID_sect163k1 721 +#define OBJ_sect163k1 OBJ_secg_ellipticCurve,1L + +#define SN_sect163r1 "sect163r1" +#define NID_sect163r1 722 +#define OBJ_sect163r1 OBJ_secg_ellipticCurve,2L + +#define SN_sect163r2 "sect163r2" +#define NID_sect163r2 723 +#define OBJ_sect163r2 OBJ_secg_ellipticCurve,15L + +#define SN_sect193r1 "sect193r1" +#define NID_sect193r1 724 +#define OBJ_sect193r1 OBJ_secg_ellipticCurve,24L + +#define SN_sect193r2 "sect193r2" +#define NID_sect193r2 725 +#define OBJ_sect193r2 OBJ_secg_ellipticCurve,25L + +#define SN_sect233k1 "sect233k1" +#define NID_sect233k1 726 +#define OBJ_sect233k1 OBJ_secg_ellipticCurve,26L + +#define SN_sect233r1 "sect233r1" +#define NID_sect233r1 727 +#define OBJ_sect233r1 OBJ_secg_ellipticCurve,27L + +#define SN_sect239k1 "sect239k1" +#define NID_sect239k1 728 +#define OBJ_sect239k1 OBJ_secg_ellipticCurve,3L + +#define SN_sect283k1 "sect283k1" +#define NID_sect283k1 729 +#define OBJ_sect283k1 OBJ_secg_ellipticCurve,16L + +#define SN_sect283r1 "sect283r1" +#define NID_sect283r1 730 +#define OBJ_sect283r1 OBJ_secg_ellipticCurve,17L + +#define SN_sect409k1 "sect409k1" +#define NID_sect409k1 731 +#define OBJ_sect409k1 OBJ_secg_ellipticCurve,36L + +#define SN_sect409r1 "sect409r1" +#define NID_sect409r1 732 +#define OBJ_sect409r1 OBJ_secg_ellipticCurve,37L + +#define SN_sect571k1 "sect571k1" +#define NID_sect571k1 733 +#define OBJ_sect571k1 OBJ_secg_ellipticCurve,38L + +#define SN_sect571r1 "sect571r1" +#define NID_sect571r1 734 +#define OBJ_sect571r1 OBJ_secg_ellipticCurve,39L + +#define OBJ_wap_wsg_idm_ecid OBJ_wap_wsg,4L + +#define SN_wap_wsg_idm_ecid_wtls1 "wap-wsg-idm-ecid-wtls1" +#define NID_wap_wsg_idm_ecid_wtls1 735 +#define OBJ_wap_wsg_idm_ecid_wtls1 OBJ_wap_wsg_idm_ecid,1L + +#define SN_wap_wsg_idm_ecid_wtls3 "wap-wsg-idm-ecid-wtls3" +#define NID_wap_wsg_idm_ecid_wtls3 736 +#define OBJ_wap_wsg_idm_ecid_wtls3 OBJ_wap_wsg_idm_ecid,3L + +#define SN_wap_wsg_idm_ecid_wtls4 "wap-wsg-idm-ecid-wtls4" +#define NID_wap_wsg_idm_ecid_wtls4 737 +#define OBJ_wap_wsg_idm_ecid_wtls4 OBJ_wap_wsg_idm_ecid,4L + +#define SN_wap_wsg_idm_ecid_wtls5 "wap-wsg-idm-ecid-wtls5" +#define NID_wap_wsg_idm_ecid_wtls5 738 +#define OBJ_wap_wsg_idm_ecid_wtls5 OBJ_wap_wsg_idm_ecid,5L + +#define SN_wap_wsg_idm_ecid_wtls6 "wap-wsg-idm-ecid-wtls6" +#define NID_wap_wsg_idm_ecid_wtls6 739 +#define OBJ_wap_wsg_idm_ecid_wtls6 OBJ_wap_wsg_idm_ecid,6L + +#define SN_wap_wsg_idm_ecid_wtls7 "wap-wsg-idm-ecid-wtls7" +#define NID_wap_wsg_idm_ecid_wtls7 740 +#define OBJ_wap_wsg_idm_ecid_wtls7 OBJ_wap_wsg_idm_ecid,7L + +#define SN_wap_wsg_idm_ecid_wtls8 "wap-wsg-idm-ecid-wtls8" +#define NID_wap_wsg_idm_ecid_wtls8 741 +#define OBJ_wap_wsg_idm_ecid_wtls8 OBJ_wap_wsg_idm_ecid,8L + +#define SN_wap_wsg_idm_ecid_wtls9 "wap-wsg-idm-ecid-wtls9" +#define NID_wap_wsg_idm_ecid_wtls9 742 +#define OBJ_wap_wsg_idm_ecid_wtls9 OBJ_wap_wsg_idm_ecid,9L + +#define SN_wap_wsg_idm_ecid_wtls10 "wap-wsg-idm-ecid-wtls10" +#define NID_wap_wsg_idm_ecid_wtls10 743 +#define OBJ_wap_wsg_idm_ecid_wtls10 OBJ_wap_wsg_idm_ecid,10L + +#define SN_wap_wsg_idm_ecid_wtls11 "wap-wsg-idm-ecid-wtls11" +#define NID_wap_wsg_idm_ecid_wtls11 744 +#define OBJ_wap_wsg_idm_ecid_wtls11 OBJ_wap_wsg_idm_ecid,11L + +#define SN_wap_wsg_idm_ecid_wtls12 "wap-wsg-idm-ecid-wtls12" +#define NID_wap_wsg_idm_ecid_wtls12 745 +#define OBJ_wap_wsg_idm_ecid_wtls12 OBJ_wap_wsg_idm_ecid,12L + +#define SN_cast5_cbc "CAST5-CBC" +#define LN_cast5_cbc "cast5-cbc" +#define NID_cast5_cbc 108 +#define OBJ_cast5_cbc OBJ_ISO_US,113533L,7L,66L,10L + +#define SN_cast5_ecb "CAST5-ECB" +#define LN_cast5_ecb "cast5-ecb" +#define NID_cast5_ecb 109 + +#define SN_cast5_cfb64 "CAST5-CFB" +#define LN_cast5_cfb64 "cast5-cfb" +#define NID_cast5_cfb64 110 + +#define SN_cast5_ofb64 "CAST5-OFB" +#define LN_cast5_ofb64 "cast5-ofb" +#define NID_cast5_ofb64 111 + +#define LN_pbeWithMD5AndCast5_CBC "pbeWithMD5AndCast5CBC" +#define NID_pbeWithMD5AndCast5_CBC 112 +#define OBJ_pbeWithMD5AndCast5_CBC OBJ_ISO_US,113533L,7L,66L,12L + +#define SN_id_PasswordBasedMAC "id-PasswordBasedMAC" +#define LN_id_PasswordBasedMAC "password based MAC" +#define NID_id_PasswordBasedMAC 782 +#define OBJ_id_PasswordBasedMAC OBJ_ISO_US,113533L,7L,66L,13L + +#define SN_id_DHBasedMac "id-DHBasedMac" +#define LN_id_DHBasedMac "Diffie-Hellman based MAC" +#define NID_id_DHBasedMac 783 +#define OBJ_id_DHBasedMac OBJ_ISO_US,113533L,7L,66L,30L + +#define SN_rsadsi "rsadsi" +#define LN_rsadsi "RSA Data Security, Inc." +#define NID_rsadsi 1 +#define OBJ_rsadsi OBJ_ISO_US,113549L + +#define SN_pkcs "pkcs" +#define LN_pkcs "RSA Data Security, Inc. PKCS" +#define NID_pkcs 2 +#define OBJ_pkcs OBJ_rsadsi,1L + +#define SN_pkcs1 "pkcs1" +#define NID_pkcs1 186 +#define OBJ_pkcs1 OBJ_pkcs,1L + +#define LN_rsaEncryption "rsaEncryption" +#define NID_rsaEncryption 6 +#define OBJ_rsaEncryption OBJ_pkcs1,1L + +#define SN_md2WithRSAEncryption "RSA-MD2" +#define LN_md2WithRSAEncryption "md2WithRSAEncryption" +#define NID_md2WithRSAEncryption 7 +#define OBJ_md2WithRSAEncryption OBJ_pkcs1,2L + +#define SN_md4WithRSAEncryption "RSA-MD4" +#define LN_md4WithRSAEncryption "md4WithRSAEncryption" +#define NID_md4WithRSAEncryption 396 +#define OBJ_md4WithRSAEncryption OBJ_pkcs1,3L + +#define SN_md5WithRSAEncryption "RSA-MD5" +#define LN_md5WithRSAEncryption "md5WithRSAEncryption" +#define NID_md5WithRSAEncryption 8 +#define OBJ_md5WithRSAEncryption OBJ_pkcs1,4L + +#define SN_sha1WithRSAEncryption "RSA-SHA1" +#define LN_sha1WithRSAEncryption "sha1WithRSAEncryption" +#define NID_sha1WithRSAEncryption 65 +#define OBJ_sha1WithRSAEncryption OBJ_pkcs1,5L + +#define SN_rsaesOaep "RSAES-OAEP" +#define LN_rsaesOaep "rsaesOaep" +#define NID_rsaesOaep 919 +#define OBJ_rsaesOaep OBJ_pkcs1,7L + +#define SN_mgf1 "MGF1" +#define LN_mgf1 "mgf1" +#define NID_mgf1 911 +#define OBJ_mgf1 OBJ_pkcs1,8L + +#define SN_pSpecified "PSPECIFIED" +#define LN_pSpecified "pSpecified" +#define NID_pSpecified 935 +#define OBJ_pSpecified OBJ_pkcs1,9L + +#define SN_rsassaPss "RSASSA-PSS" +#define LN_rsassaPss "rsassaPss" +#define NID_rsassaPss 912 +#define OBJ_rsassaPss OBJ_pkcs1,10L + +#define SN_sha256WithRSAEncryption "RSA-SHA256" +#define LN_sha256WithRSAEncryption "sha256WithRSAEncryption" +#define NID_sha256WithRSAEncryption 668 +#define OBJ_sha256WithRSAEncryption OBJ_pkcs1,11L + +#define SN_sha384WithRSAEncryption "RSA-SHA384" +#define LN_sha384WithRSAEncryption "sha384WithRSAEncryption" +#define NID_sha384WithRSAEncryption 669 +#define OBJ_sha384WithRSAEncryption OBJ_pkcs1,12L + +#define SN_sha512WithRSAEncryption "RSA-SHA512" +#define LN_sha512WithRSAEncryption "sha512WithRSAEncryption" +#define NID_sha512WithRSAEncryption 670 +#define OBJ_sha512WithRSAEncryption OBJ_pkcs1,13L + +#define SN_sha224WithRSAEncryption "RSA-SHA224" +#define LN_sha224WithRSAEncryption "sha224WithRSAEncryption" +#define NID_sha224WithRSAEncryption 671 +#define OBJ_sha224WithRSAEncryption OBJ_pkcs1,14L + +#define SN_pkcs3 "pkcs3" +#define NID_pkcs3 27 +#define OBJ_pkcs3 OBJ_pkcs,3L + +#define LN_dhKeyAgreement "dhKeyAgreement" +#define NID_dhKeyAgreement 28 +#define OBJ_dhKeyAgreement OBJ_pkcs3,1L + +#define SN_pkcs5 "pkcs5" +#define NID_pkcs5 187 +#define OBJ_pkcs5 OBJ_pkcs,5L + +#define SN_pbeWithMD2AndDES_CBC "PBE-MD2-DES" +#define LN_pbeWithMD2AndDES_CBC "pbeWithMD2AndDES-CBC" +#define NID_pbeWithMD2AndDES_CBC 9 +#define OBJ_pbeWithMD2AndDES_CBC OBJ_pkcs5,1L + +#define SN_pbeWithMD5AndDES_CBC "PBE-MD5-DES" +#define LN_pbeWithMD5AndDES_CBC "pbeWithMD5AndDES-CBC" +#define NID_pbeWithMD5AndDES_CBC 10 +#define OBJ_pbeWithMD5AndDES_CBC OBJ_pkcs5,3L + +#define SN_pbeWithMD2AndRC2_CBC "PBE-MD2-RC2-64" +#define LN_pbeWithMD2AndRC2_CBC "pbeWithMD2AndRC2-CBC" +#define NID_pbeWithMD2AndRC2_CBC 168 +#define OBJ_pbeWithMD2AndRC2_CBC OBJ_pkcs5,4L + +#define SN_pbeWithMD5AndRC2_CBC "PBE-MD5-RC2-64" +#define LN_pbeWithMD5AndRC2_CBC "pbeWithMD5AndRC2-CBC" +#define NID_pbeWithMD5AndRC2_CBC 169 +#define OBJ_pbeWithMD5AndRC2_CBC OBJ_pkcs5,6L + +#define SN_pbeWithSHA1AndDES_CBC "PBE-SHA1-DES" +#define LN_pbeWithSHA1AndDES_CBC "pbeWithSHA1AndDES-CBC" +#define NID_pbeWithSHA1AndDES_CBC 170 +#define OBJ_pbeWithSHA1AndDES_CBC OBJ_pkcs5,10L + +#define SN_pbeWithSHA1AndRC2_CBC "PBE-SHA1-RC2-64" +#define LN_pbeWithSHA1AndRC2_CBC "pbeWithSHA1AndRC2-CBC" +#define NID_pbeWithSHA1AndRC2_CBC 68 +#define OBJ_pbeWithSHA1AndRC2_CBC OBJ_pkcs5,11L + +#define LN_id_pbkdf2 "PBKDF2" +#define NID_id_pbkdf2 69 +#define OBJ_id_pbkdf2 OBJ_pkcs5,12L + +#define LN_pbes2 "PBES2" +#define NID_pbes2 161 +#define OBJ_pbes2 OBJ_pkcs5,13L + +#define LN_pbmac1 "PBMAC1" +#define NID_pbmac1 162 +#define OBJ_pbmac1 OBJ_pkcs5,14L + +#define SN_pkcs7 "pkcs7" +#define NID_pkcs7 20 +#define OBJ_pkcs7 OBJ_pkcs,7L + +#define LN_pkcs7_data "pkcs7-data" +#define NID_pkcs7_data 21 +#define OBJ_pkcs7_data OBJ_pkcs7,1L + +#define LN_pkcs7_signed "pkcs7-signedData" +#define NID_pkcs7_signed 22 +#define OBJ_pkcs7_signed OBJ_pkcs7,2L + +#define LN_pkcs7_enveloped "pkcs7-envelopedData" +#define NID_pkcs7_enveloped 23 +#define OBJ_pkcs7_enveloped OBJ_pkcs7,3L + +#define LN_pkcs7_signedAndEnveloped "pkcs7-signedAndEnvelopedData" +#define NID_pkcs7_signedAndEnveloped 24 +#define OBJ_pkcs7_signedAndEnveloped OBJ_pkcs7,4L + +#define LN_pkcs7_digest "pkcs7-digestData" +#define NID_pkcs7_digest 25 +#define OBJ_pkcs7_digest OBJ_pkcs7,5L + +#define LN_pkcs7_encrypted "pkcs7-encryptedData" +#define NID_pkcs7_encrypted 26 +#define OBJ_pkcs7_encrypted OBJ_pkcs7,6L + +#define SN_pkcs9 "pkcs9" +#define NID_pkcs9 47 +#define OBJ_pkcs9 OBJ_pkcs,9L + +#define LN_pkcs9_emailAddress "emailAddress" +#define NID_pkcs9_emailAddress 48 +#define OBJ_pkcs9_emailAddress OBJ_pkcs9,1L + +#define LN_pkcs9_unstructuredName "unstructuredName" +#define NID_pkcs9_unstructuredName 49 +#define OBJ_pkcs9_unstructuredName OBJ_pkcs9,2L + +#define LN_pkcs9_contentType "contentType" +#define NID_pkcs9_contentType 50 +#define OBJ_pkcs9_contentType OBJ_pkcs9,3L + +#define LN_pkcs9_messageDigest "messageDigest" +#define NID_pkcs9_messageDigest 51 +#define OBJ_pkcs9_messageDigest OBJ_pkcs9,4L + +#define LN_pkcs9_signingTime "signingTime" +#define NID_pkcs9_signingTime 52 +#define OBJ_pkcs9_signingTime OBJ_pkcs9,5L + +#define LN_pkcs9_countersignature "countersignature" +#define NID_pkcs9_countersignature 53 +#define OBJ_pkcs9_countersignature OBJ_pkcs9,6L + +#define LN_pkcs9_challengePassword "challengePassword" +#define NID_pkcs9_challengePassword 54 +#define OBJ_pkcs9_challengePassword OBJ_pkcs9,7L + +#define LN_pkcs9_unstructuredAddress "unstructuredAddress" +#define NID_pkcs9_unstructuredAddress 55 +#define OBJ_pkcs9_unstructuredAddress OBJ_pkcs9,8L + +#define LN_pkcs9_extCertAttributes "extendedCertificateAttributes" +#define NID_pkcs9_extCertAttributes 56 +#define OBJ_pkcs9_extCertAttributes OBJ_pkcs9,9L + +#define SN_ext_req "extReq" +#define LN_ext_req "Extension Request" +#define NID_ext_req 172 +#define OBJ_ext_req OBJ_pkcs9,14L + +#define SN_SMIMECapabilities "SMIME-CAPS" +#define LN_SMIMECapabilities "S/MIME Capabilities" +#define NID_SMIMECapabilities 167 +#define OBJ_SMIMECapabilities OBJ_pkcs9,15L + +#define SN_SMIME "SMIME" +#define LN_SMIME "S/MIME" +#define NID_SMIME 188 +#define OBJ_SMIME OBJ_pkcs9,16L + +#define SN_id_smime_mod "id-smime-mod" +#define NID_id_smime_mod 189 +#define OBJ_id_smime_mod OBJ_SMIME,0L + +#define SN_id_smime_ct "id-smime-ct" +#define NID_id_smime_ct 190 +#define OBJ_id_smime_ct OBJ_SMIME,1L + +#define SN_id_smime_aa "id-smime-aa" +#define NID_id_smime_aa 191 +#define OBJ_id_smime_aa OBJ_SMIME,2L + +#define SN_id_smime_alg "id-smime-alg" +#define NID_id_smime_alg 192 +#define OBJ_id_smime_alg OBJ_SMIME,3L + +#define SN_id_smime_cd "id-smime-cd" +#define NID_id_smime_cd 193 +#define OBJ_id_smime_cd OBJ_SMIME,4L + +#define SN_id_smime_spq "id-smime-spq" +#define NID_id_smime_spq 194 +#define OBJ_id_smime_spq OBJ_SMIME,5L + +#define SN_id_smime_cti "id-smime-cti" +#define NID_id_smime_cti 195 +#define OBJ_id_smime_cti OBJ_SMIME,6L + +#define SN_id_smime_mod_cms "id-smime-mod-cms" +#define NID_id_smime_mod_cms 196 +#define OBJ_id_smime_mod_cms OBJ_id_smime_mod,1L + +#define SN_id_smime_mod_ess "id-smime-mod-ess" +#define NID_id_smime_mod_ess 197 +#define OBJ_id_smime_mod_ess OBJ_id_smime_mod,2L + +#define SN_id_smime_mod_oid "id-smime-mod-oid" +#define NID_id_smime_mod_oid 198 +#define OBJ_id_smime_mod_oid OBJ_id_smime_mod,3L + +#define SN_id_smime_mod_msg_v3 "id-smime-mod-msg-v3" +#define NID_id_smime_mod_msg_v3 199 +#define OBJ_id_smime_mod_msg_v3 OBJ_id_smime_mod,4L + +#define SN_id_smime_mod_ets_eSignature_88 "id-smime-mod-ets-eSignature-88" +#define NID_id_smime_mod_ets_eSignature_88 200 +#define OBJ_id_smime_mod_ets_eSignature_88 OBJ_id_smime_mod,5L + +#define SN_id_smime_mod_ets_eSignature_97 "id-smime-mod-ets-eSignature-97" +#define NID_id_smime_mod_ets_eSignature_97 201 +#define OBJ_id_smime_mod_ets_eSignature_97 OBJ_id_smime_mod,6L + +#define SN_id_smime_mod_ets_eSigPolicy_88 "id-smime-mod-ets-eSigPolicy-88" +#define NID_id_smime_mod_ets_eSigPolicy_88 202 +#define OBJ_id_smime_mod_ets_eSigPolicy_88 OBJ_id_smime_mod,7L + +#define SN_id_smime_mod_ets_eSigPolicy_97 "id-smime-mod-ets-eSigPolicy-97" +#define NID_id_smime_mod_ets_eSigPolicy_97 203 +#define OBJ_id_smime_mod_ets_eSigPolicy_97 OBJ_id_smime_mod,8L + +#define SN_id_smime_ct_receipt "id-smime-ct-receipt" +#define NID_id_smime_ct_receipt 204 +#define OBJ_id_smime_ct_receipt OBJ_id_smime_ct,1L + +#define SN_id_smime_ct_authData "id-smime-ct-authData" +#define NID_id_smime_ct_authData 205 +#define OBJ_id_smime_ct_authData OBJ_id_smime_ct,2L + +#define SN_id_smime_ct_publishCert "id-smime-ct-publishCert" +#define NID_id_smime_ct_publishCert 206 +#define OBJ_id_smime_ct_publishCert OBJ_id_smime_ct,3L + +#define SN_id_smime_ct_TSTInfo "id-smime-ct-TSTInfo" +#define NID_id_smime_ct_TSTInfo 207 +#define OBJ_id_smime_ct_TSTInfo OBJ_id_smime_ct,4L + +#define SN_id_smime_ct_TDTInfo "id-smime-ct-TDTInfo" +#define NID_id_smime_ct_TDTInfo 208 +#define OBJ_id_smime_ct_TDTInfo OBJ_id_smime_ct,5L + +#define SN_id_smime_ct_contentInfo "id-smime-ct-contentInfo" +#define NID_id_smime_ct_contentInfo 209 +#define OBJ_id_smime_ct_contentInfo OBJ_id_smime_ct,6L + +#define SN_id_smime_ct_DVCSRequestData "id-smime-ct-DVCSRequestData" +#define NID_id_smime_ct_DVCSRequestData 210 +#define OBJ_id_smime_ct_DVCSRequestData OBJ_id_smime_ct,7L + +#define SN_id_smime_ct_DVCSResponseData "id-smime-ct-DVCSResponseData" +#define NID_id_smime_ct_DVCSResponseData 211 +#define OBJ_id_smime_ct_DVCSResponseData OBJ_id_smime_ct,8L + +#define SN_id_smime_ct_compressedData "id-smime-ct-compressedData" +#define NID_id_smime_ct_compressedData 786 +#define OBJ_id_smime_ct_compressedData OBJ_id_smime_ct,9L + +#define SN_id_ct_asciiTextWithCRLF "id-ct-asciiTextWithCRLF" +#define NID_id_ct_asciiTextWithCRLF 787 +#define OBJ_id_ct_asciiTextWithCRLF OBJ_id_smime_ct,27L + +#define SN_id_smime_aa_receiptRequest "id-smime-aa-receiptRequest" +#define NID_id_smime_aa_receiptRequest 212 +#define OBJ_id_smime_aa_receiptRequest OBJ_id_smime_aa,1L + +#define SN_id_smime_aa_securityLabel "id-smime-aa-securityLabel" +#define NID_id_smime_aa_securityLabel 213 +#define OBJ_id_smime_aa_securityLabel OBJ_id_smime_aa,2L + +#define SN_id_smime_aa_mlExpandHistory "id-smime-aa-mlExpandHistory" +#define NID_id_smime_aa_mlExpandHistory 214 +#define OBJ_id_smime_aa_mlExpandHistory OBJ_id_smime_aa,3L + +#define SN_id_smime_aa_contentHint "id-smime-aa-contentHint" +#define NID_id_smime_aa_contentHint 215 +#define OBJ_id_smime_aa_contentHint OBJ_id_smime_aa,4L + +#define SN_id_smime_aa_msgSigDigest "id-smime-aa-msgSigDigest" +#define NID_id_smime_aa_msgSigDigest 216 +#define OBJ_id_smime_aa_msgSigDigest OBJ_id_smime_aa,5L + +#define SN_id_smime_aa_encapContentType "id-smime-aa-encapContentType" +#define NID_id_smime_aa_encapContentType 217 +#define OBJ_id_smime_aa_encapContentType OBJ_id_smime_aa,6L + +#define SN_id_smime_aa_contentIdentifier "id-smime-aa-contentIdentifier" +#define NID_id_smime_aa_contentIdentifier 218 +#define OBJ_id_smime_aa_contentIdentifier OBJ_id_smime_aa,7L + +#define SN_id_smime_aa_macValue "id-smime-aa-macValue" +#define NID_id_smime_aa_macValue 219 +#define OBJ_id_smime_aa_macValue OBJ_id_smime_aa,8L + +#define SN_id_smime_aa_equivalentLabels "id-smime-aa-equivalentLabels" +#define NID_id_smime_aa_equivalentLabels 220 +#define OBJ_id_smime_aa_equivalentLabels OBJ_id_smime_aa,9L + +#define SN_id_smime_aa_contentReference "id-smime-aa-contentReference" +#define NID_id_smime_aa_contentReference 221 +#define OBJ_id_smime_aa_contentReference OBJ_id_smime_aa,10L + +#define SN_id_smime_aa_encrypKeyPref "id-smime-aa-encrypKeyPref" +#define NID_id_smime_aa_encrypKeyPref 222 +#define OBJ_id_smime_aa_encrypKeyPref OBJ_id_smime_aa,11L + +#define SN_id_smime_aa_signingCertificate "id-smime-aa-signingCertificate" +#define NID_id_smime_aa_signingCertificate 223 +#define OBJ_id_smime_aa_signingCertificate OBJ_id_smime_aa,12L + +#define SN_id_smime_aa_smimeEncryptCerts "id-smime-aa-smimeEncryptCerts" +#define NID_id_smime_aa_smimeEncryptCerts 224 +#define OBJ_id_smime_aa_smimeEncryptCerts OBJ_id_smime_aa,13L + +#define SN_id_smime_aa_timeStampToken "id-smime-aa-timeStampToken" +#define NID_id_smime_aa_timeStampToken 225 +#define OBJ_id_smime_aa_timeStampToken OBJ_id_smime_aa,14L + +#define SN_id_smime_aa_ets_sigPolicyId "id-smime-aa-ets-sigPolicyId" +#define NID_id_smime_aa_ets_sigPolicyId 226 +#define OBJ_id_smime_aa_ets_sigPolicyId OBJ_id_smime_aa,15L + +#define SN_id_smime_aa_ets_commitmentType "id-smime-aa-ets-commitmentType" +#define NID_id_smime_aa_ets_commitmentType 227 +#define OBJ_id_smime_aa_ets_commitmentType OBJ_id_smime_aa,16L + +#define SN_id_smime_aa_ets_signerLocation "id-smime-aa-ets-signerLocation" +#define NID_id_smime_aa_ets_signerLocation 228 +#define OBJ_id_smime_aa_ets_signerLocation OBJ_id_smime_aa,17L + +#define SN_id_smime_aa_ets_signerAttr "id-smime-aa-ets-signerAttr" +#define NID_id_smime_aa_ets_signerAttr 229 +#define OBJ_id_smime_aa_ets_signerAttr OBJ_id_smime_aa,18L + +#define SN_id_smime_aa_ets_otherSigCert "id-smime-aa-ets-otherSigCert" +#define NID_id_smime_aa_ets_otherSigCert 230 +#define OBJ_id_smime_aa_ets_otherSigCert OBJ_id_smime_aa,19L + +#define SN_id_smime_aa_ets_contentTimestamp "id-smime-aa-ets-contentTimestamp" +#define NID_id_smime_aa_ets_contentTimestamp 231 +#define OBJ_id_smime_aa_ets_contentTimestamp OBJ_id_smime_aa,20L + +#define SN_id_smime_aa_ets_CertificateRefs "id-smime-aa-ets-CertificateRefs" +#define NID_id_smime_aa_ets_CertificateRefs 232 +#define OBJ_id_smime_aa_ets_CertificateRefs OBJ_id_smime_aa,21L + +#define SN_id_smime_aa_ets_RevocationRefs "id-smime-aa-ets-RevocationRefs" +#define NID_id_smime_aa_ets_RevocationRefs 233 +#define OBJ_id_smime_aa_ets_RevocationRefs OBJ_id_smime_aa,22L + +#define SN_id_smime_aa_ets_certValues "id-smime-aa-ets-certValues" +#define NID_id_smime_aa_ets_certValues 234 +#define OBJ_id_smime_aa_ets_certValues OBJ_id_smime_aa,23L + +#define SN_id_smime_aa_ets_revocationValues "id-smime-aa-ets-revocationValues" +#define NID_id_smime_aa_ets_revocationValues 235 +#define OBJ_id_smime_aa_ets_revocationValues OBJ_id_smime_aa,24L + +#define SN_id_smime_aa_ets_escTimeStamp "id-smime-aa-ets-escTimeStamp" +#define NID_id_smime_aa_ets_escTimeStamp 236 +#define OBJ_id_smime_aa_ets_escTimeStamp OBJ_id_smime_aa,25L + +#define SN_id_smime_aa_ets_certCRLTimestamp "id-smime-aa-ets-certCRLTimestamp" +#define NID_id_smime_aa_ets_certCRLTimestamp 237 +#define OBJ_id_smime_aa_ets_certCRLTimestamp OBJ_id_smime_aa,26L + +#define SN_id_smime_aa_ets_archiveTimeStamp "id-smime-aa-ets-archiveTimeStamp" +#define NID_id_smime_aa_ets_archiveTimeStamp 238 +#define OBJ_id_smime_aa_ets_archiveTimeStamp OBJ_id_smime_aa,27L + +#define SN_id_smime_aa_signatureType "id-smime-aa-signatureType" +#define NID_id_smime_aa_signatureType 239 +#define OBJ_id_smime_aa_signatureType OBJ_id_smime_aa,28L + +#define SN_id_smime_aa_dvcs_dvc "id-smime-aa-dvcs-dvc" +#define NID_id_smime_aa_dvcs_dvc 240 +#define OBJ_id_smime_aa_dvcs_dvc OBJ_id_smime_aa,29L + +#define SN_id_smime_alg_ESDHwith3DES "id-smime-alg-ESDHwith3DES" +#define NID_id_smime_alg_ESDHwith3DES 241 +#define OBJ_id_smime_alg_ESDHwith3DES OBJ_id_smime_alg,1L + +#define SN_id_smime_alg_ESDHwithRC2 "id-smime-alg-ESDHwithRC2" +#define NID_id_smime_alg_ESDHwithRC2 242 +#define OBJ_id_smime_alg_ESDHwithRC2 OBJ_id_smime_alg,2L + +#define SN_id_smime_alg_3DESwrap "id-smime-alg-3DESwrap" +#define NID_id_smime_alg_3DESwrap 243 +#define OBJ_id_smime_alg_3DESwrap OBJ_id_smime_alg,3L + +#define SN_id_smime_alg_RC2wrap "id-smime-alg-RC2wrap" +#define NID_id_smime_alg_RC2wrap 244 +#define OBJ_id_smime_alg_RC2wrap OBJ_id_smime_alg,4L + +#define SN_id_smime_alg_ESDH "id-smime-alg-ESDH" +#define NID_id_smime_alg_ESDH 245 +#define OBJ_id_smime_alg_ESDH OBJ_id_smime_alg,5L + +#define SN_id_smime_alg_CMS3DESwrap "id-smime-alg-CMS3DESwrap" +#define NID_id_smime_alg_CMS3DESwrap 246 +#define OBJ_id_smime_alg_CMS3DESwrap OBJ_id_smime_alg,6L + +#define SN_id_smime_alg_CMSRC2wrap "id-smime-alg-CMSRC2wrap" +#define NID_id_smime_alg_CMSRC2wrap 247 +#define OBJ_id_smime_alg_CMSRC2wrap OBJ_id_smime_alg,7L + +#define SN_id_alg_PWRI_KEK "id-alg-PWRI-KEK" +#define NID_id_alg_PWRI_KEK 893 +#define OBJ_id_alg_PWRI_KEK OBJ_id_smime_alg,9L + +#define SN_id_smime_cd_ldap "id-smime-cd-ldap" +#define NID_id_smime_cd_ldap 248 +#define OBJ_id_smime_cd_ldap OBJ_id_smime_cd,1L + +#define SN_id_smime_spq_ets_sqt_uri "id-smime-spq-ets-sqt-uri" +#define NID_id_smime_spq_ets_sqt_uri 249 +#define OBJ_id_smime_spq_ets_sqt_uri OBJ_id_smime_spq,1L + +#define SN_id_smime_spq_ets_sqt_unotice "id-smime-spq-ets-sqt-unotice" +#define NID_id_smime_spq_ets_sqt_unotice 250 +#define OBJ_id_smime_spq_ets_sqt_unotice OBJ_id_smime_spq,2L + +#define SN_id_smime_cti_ets_proofOfOrigin "id-smime-cti-ets-proofOfOrigin" +#define NID_id_smime_cti_ets_proofOfOrigin 251 +#define OBJ_id_smime_cti_ets_proofOfOrigin OBJ_id_smime_cti,1L + +#define SN_id_smime_cti_ets_proofOfReceipt "id-smime-cti-ets-proofOfReceipt" +#define NID_id_smime_cti_ets_proofOfReceipt 252 +#define OBJ_id_smime_cti_ets_proofOfReceipt OBJ_id_smime_cti,2L + +#define SN_id_smime_cti_ets_proofOfDelivery "id-smime-cti-ets-proofOfDelivery" +#define NID_id_smime_cti_ets_proofOfDelivery 253 +#define OBJ_id_smime_cti_ets_proofOfDelivery OBJ_id_smime_cti,3L + +#define SN_id_smime_cti_ets_proofOfSender "id-smime-cti-ets-proofOfSender" +#define NID_id_smime_cti_ets_proofOfSender 254 +#define OBJ_id_smime_cti_ets_proofOfSender OBJ_id_smime_cti,4L + +#define SN_id_smime_cti_ets_proofOfApproval "id-smime-cti-ets-proofOfApproval" +#define NID_id_smime_cti_ets_proofOfApproval 255 +#define OBJ_id_smime_cti_ets_proofOfApproval OBJ_id_smime_cti,5L + +#define SN_id_smime_cti_ets_proofOfCreation "id-smime-cti-ets-proofOfCreation" +#define NID_id_smime_cti_ets_proofOfCreation 256 +#define OBJ_id_smime_cti_ets_proofOfCreation OBJ_id_smime_cti,6L + +#define LN_friendlyName "friendlyName" +#define NID_friendlyName 156 +#define OBJ_friendlyName OBJ_pkcs9,20L + +#define LN_localKeyID "localKeyID" +#define NID_localKeyID 157 +#define OBJ_localKeyID OBJ_pkcs9,21L + +#define SN_ms_csp_name "CSPName" +#define LN_ms_csp_name "Microsoft CSP Name" +#define NID_ms_csp_name 417 +#define OBJ_ms_csp_name 1L,3L,6L,1L,4L,1L,311L,17L,1L + +#define SN_LocalKeySet "LocalKeySet" +#define LN_LocalKeySet "Microsoft Local Key set" +#define NID_LocalKeySet 856 +#define OBJ_LocalKeySet 1L,3L,6L,1L,4L,1L,311L,17L,2L + +#define OBJ_certTypes OBJ_pkcs9,22L + +#define LN_x509Certificate "x509Certificate" +#define NID_x509Certificate 158 +#define OBJ_x509Certificate OBJ_certTypes,1L + +#define LN_sdsiCertificate "sdsiCertificate" +#define NID_sdsiCertificate 159 +#define OBJ_sdsiCertificate OBJ_certTypes,2L + +#define OBJ_crlTypes OBJ_pkcs9,23L + +#define LN_x509Crl "x509Crl" +#define NID_x509Crl 160 +#define OBJ_x509Crl OBJ_crlTypes,1L + +#define OBJ_pkcs12 OBJ_pkcs,12L + +#define OBJ_pkcs12_pbeids OBJ_pkcs12,1L + +#define SN_pbe_WithSHA1And128BitRC4 "PBE-SHA1-RC4-128" +#define LN_pbe_WithSHA1And128BitRC4 "pbeWithSHA1And128BitRC4" +#define NID_pbe_WithSHA1And128BitRC4 144 +#define OBJ_pbe_WithSHA1And128BitRC4 OBJ_pkcs12_pbeids,1L + +#define SN_pbe_WithSHA1And40BitRC4 "PBE-SHA1-RC4-40" +#define LN_pbe_WithSHA1And40BitRC4 "pbeWithSHA1And40BitRC4" +#define NID_pbe_WithSHA1And40BitRC4 145 +#define OBJ_pbe_WithSHA1And40BitRC4 OBJ_pkcs12_pbeids,2L + +#define SN_pbe_WithSHA1And3_Key_TripleDES_CBC "PBE-SHA1-3DES" +#define LN_pbe_WithSHA1And3_Key_TripleDES_CBC "pbeWithSHA1And3-KeyTripleDES-CBC" +#define NID_pbe_WithSHA1And3_Key_TripleDES_CBC 146 +#define OBJ_pbe_WithSHA1And3_Key_TripleDES_CBC OBJ_pkcs12_pbeids,3L + +#define SN_pbe_WithSHA1And2_Key_TripleDES_CBC "PBE-SHA1-2DES" +#define LN_pbe_WithSHA1And2_Key_TripleDES_CBC "pbeWithSHA1And2-KeyTripleDES-CBC" +#define NID_pbe_WithSHA1And2_Key_TripleDES_CBC 147 +#define OBJ_pbe_WithSHA1And2_Key_TripleDES_CBC OBJ_pkcs12_pbeids,4L + +#define SN_pbe_WithSHA1And128BitRC2_CBC "PBE-SHA1-RC2-128" +#define LN_pbe_WithSHA1And128BitRC2_CBC "pbeWithSHA1And128BitRC2-CBC" +#define NID_pbe_WithSHA1And128BitRC2_CBC 148 +#define OBJ_pbe_WithSHA1And128BitRC2_CBC OBJ_pkcs12_pbeids,5L + +#define SN_pbe_WithSHA1And40BitRC2_CBC "PBE-SHA1-RC2-40" +#define LN_pbe_WithSHA1And40BitRC2_CBC "pbeWithSHA1And40BitRC2-CBC" +#define NID_pbe_WithSHA1And40BitRC2_CBC 149 +#define OBJ_pbe_WithSHA1And40BitRC2_CBC OBJ_pkcs12_pbeids,6L + +#define OBJ_pkcs12_Version1 OBJ_pkcs12,10L + +#define OBJ_pkcs12_BagIds OBJ_pkcs12_Version1,1L + +#define LN_keyBag "keyBag" +#define NID_keyBag 150 +#define OBJ_keyBag OBJ_pkcs12_BagIds,1L + +#define LN_pkcs8ShroudedKeyBag "pkcs8ShroudedKeyBag" +#define NID_pkcs8ShroudedKeyBag 151 +#define OBJ_pkcs8ShroudedKeyBag OBJ_pkcs12_BagIds,2L + +#define LN_certBag "certBag" +#define NID_certBag 152 +#define OBJ_certBag OBJ_pkcs12_BagIds,3L + +#define LN_crlBag "crlBag" +#define NID_crlBag 153 +#define OBJ_crlBag OBJ_pkcs12_BagIds,4L + +#define LN_secretBag "secretBag" +#define NID_secretBag 154 +#define OBJ_secretBag OBJ_pkcs12_BagIds,5L + +#define LN_safeContentsBag "safeContentsBag" +#define NID_safeContentsBag 155 +#define OBJ_safeContentsBag OBJ_pkcs12_BagIds,6L + +#define SN_md2 "MD2" +#define LN_md2 "md2" +#define NID_md2 3 +#define OBJ_md2 OBJ_rsadsi,2L,2L + +#define SN_md4 "MD4" +#define LN_md4 "md4" +#define NID_md4 257 +#define OBJ_md4 OBJ_rsadsi,2L,4L + +#define SN_md5 "MD5" +#define LN_md5 "md5" +#define NID_md5 4 +#define OBJ_md5 OBJ_rsadsi,2L,5L + +#define SN_md5_sha1 "MD5-SHA1" +#define LN_md5_sha1 "md5-sha1" +#define NID_md5_sha1 114 + +#define LN_hmacWithMD5 "hmacWithMD5" +#define NID_hmacWithMD5 797 +#define OBJ_hmacWithMD5 OBJ_rsadsi,2L,6L + +#define LN_hmacWithSHA1 "hmacWithSHA1" +#define NID_hmacWithSHA1 163 +#define OBJ_hmacWithSHA1 OBJ_rsadsi,2L,7L + +#define LN_hmacWithSHA224 "hmacWithSHA224" +#define NID_hmacWithSHA224 798 +#define OBJ_hmacWithSHA224 OBJ_rsadsi,2L,8L + +#define LN_hmacWithSHA256 "hmacWithSHA256" +#define NID_hmacWithSHA256 799 +#define OBJ_hmacWithSHA256 OBJ_rsadsi,2L,9L + +#define LN_hmacWithSHA384 "hmacWithSHA384" +#define NID_hmacWithSHA384 800 +#define OBJ_hmacWithSHA384 OBJ_rsadsi,2L,10L + +#define LN_hmacWithSHA512 "hmacWithSHA512" +#define NID_hmacWithSHA512 801 +#define OBJ_hmacWithSHA512 OBJ_rsadsi,2L,11L + +#define SN_rc2_cbc "RC2-CBC" +#define LN_rc2_cbc "rc2-cbc" +#define NID_rc2_cbc 37 +#define OBJ_rc2_cbc OBJ_rsadsi,3L,2L + +#define SN_rc2_ecb "RC2-ECB" +#define LN_rc2_ecb "rc2-ecb" +#define NID_rc2_ecb 38 + +#define SN_rc2_cfb64 "RC2-CFB" +#define LN_rc2_cfb64 "rc2-cfb" +#define NID_rc2_cfb64 39 + +#define SN_rc2_ofb64 "RC2-OFB" +#define LN_rc2_ofb64 "rc2-ofb" +#define NID_rc2_ofb64 40 + +#define SN_rc2_40_cbc "RC2-40-CBC" +#define LN_rc2_40_cbc "rc2-40-cbc" +#define NID_rc2_40_cbc 98 + +#define SN_rc2_64_cbc "RC2-64-CBC" +#define LN_rc2_64_cbc "rc2-64-cbc" +#define NID_rc2_64_cbc 166 + +#define SN_rc4 "RC4" +#define LN_rc4 "rc4" +#define NID_rc4 5 +#define OBJ_rc4 OBJ_rsadsi,3L,4L + +#define SN_rc4_40 "RC4-40" +#define LN_rc4_40 "rc4-40" +#define NID_rc4_40 97 + +#define SN_des_ede3_cbc "DES-EDE3-CBC" +#define LN_des_ede3_cbc "des-ede3-cbc" +#define NID_des_ede3_cbc 44 +#define OBJ_des_ede3_cbc OBJ_rsadsi,3L,7L + +#define SN_rc5_cbc "RC5-CBC" +#define LN_rc5_cbc "rc5-cbc" +#define NID_rc5_cbc 120 +#define OBJ_rc5_cbc OBJ_rsadsi,3L,8L + +#define SN_rc5_ecb "RC5-ECB" +#define LN_rc5_ecb "rc5-ecb" +#define NID_rc5_ecb 121 + +#define SN_rc5_cfb64 "RC5-CFB" +#define LN_rc5_cfb64 "rc5-cfb" +#define NID_rc5_cfb64 122 + +#define SN_rc5_ofb64 "RC5-OFB" +#define LN_rc5_ofb64 "rc5-ofb" +#define NID_rc5_ofb64 123 + +#define SN_ms_ext_req "msExtReq" +#define LN_ms_ext_req "Microsoft Extension Request" +#define NID_ms_ext_req 171 +#define OBJ_ms_ext_req 1L,3L,6L,1L,4L,1L,311L,2L,1L,14L + +#define SN_ms_code_ind "msCodeInd" +#define LN_ms_code_ind "Microsoft Individual Code Signing" +#define NID_ms_code_ind 134 +#define OBJ_ms_code_ind 1L,3L,6L,1L,4L,1L,311L,2L,1L,21L + +#define SN_ms_code_com "msCodeCom" +#define LN_ms_code_com "Microsoft Commercial Code Signing" +#define NID_ms_code_com 135 +#define OBJ_ms_code_com 1L,3L,6L,1L,4L,1L,311L,2L,1L,22L + +#define SN_ms_ctl_sign "msCTLSign" +#define LN_ms_ctl_sign "Microsoft Trust List Signing" +#define NID_ms_ctl_sign 136 +#define OBJ_ms_ctl_sign 1L,3L,6L,1L,4L,1L,311L,10L,3L,1L + +#define SN_ms_sgc "msSGC" +#define LN_ms_sgc "Microsoft Server Gated Crypto" +#define NID_ms_sgc 137 +#define OBJ_ms_sgc 1L,3L,6L,1L,4L,1L,311L,10L,3L,3L + +#define SN_ms_efs "msEFS" +#define LN_ms_efs "Microsoft Encrypted File System" +#define NID_ms_efs 138 +#define OBJ_ms_efs 1L,3L,6L,1L,4L,1L,311L,10L,3L,4L + +#define SN_ms_smartcard_login "msSmartcardLogin" +#define LN_ms_smartcard_login "Microsoft Smartcardlogin" +#define NID_ms_smartcard_login 648 +#define OBJ_ms_smartcard_login 1L,3L,6L,1L,4L,1L,311L,20L,2L,2L + +#define SN_ms_upn "msUPN" +#define LN_ms_upn "Microsoft Universal Principal Name" +#define NID_ms_upn 649 +#define OBJ_ms_upn 1L,3L,6L,1L,4L,1L,311L,20L,2L,3L + +#define SN_idea_cbc "IDEA-CBC" +#define LN_idea_cbc "idea-cbc" +#define NID_idea_cbc 34 +#define OBJ_idea_cbc 1L,3L,6L,1L,4L,1L,188L,7L,1L,1L,2L + +#define SN_idea_ecb "IDEA-ECB" +#define LN_idea_ecb "idea-ecb" +#define NID_idea_ecb 36 + +#define SN_idea_cfb64 "IDEA-CFB" +#define LN_idea_cfb64 "idea-cfb" +#define NID_idea_cfb64 35 + +#define SN_idea_ofb64 "IDEA-OFB" +#define LN_idea_ofb64 "idea-ofb" +#define NID_idea_ofb64 46 + +#define SN_bf_cbc "BF-CBC" +#define LN_bf_cbc "bf-cbc" +#define NID_bf_cbc 91 +#define OBJ_bf_cbc 1L,3L,6L,1L,4L,1L,3029L,1L,2L + +#define SN_bf_ecb "BF-ECB" +#define LN_bf_ecb "bf-ecb" +#define NID_bf_ecb 92 + +#define SN_bf_cfb64 "BF-CFB" +#define LN_bf_cfb64 "bf-cfb" +#define NID_bf_cfb64 93 + +#define SN_bf_ofb64 "BF-OFB" +#define LN_bf_ofb64 "bf-ofb" +#define NID_bf_ofb64 94 + +#define SN_id_pkix "PKIX" +#define NID_id_pkix 127 +#define OBJ_id_pkix 1L,3L,6L,1L,5L,5L,7L + +#define SN_id_pkix_mod "id-pkix-mod" +#define NID_id_pkix_mod 258 +#define OBJ_id_pkix_mod OBJ_id_pkix,0L + +#define SN_id_pe "id-pe" +#define NID_id_pe 175 +#define OBJ_id_pe OBJ_id_pkix,1L + +#define SN_id_qt "id-qt" +#define NID_id_qt 259 +#define OBJ_id_qt OBJ_id_pkix,2L + +#define SN_id_kp "id-kp" +#define NID_id_kp 128 +#define OBJ_id_kp OBJ_id_pkix,3L + +#define SN_id_it "id-it" +#define NID_id_it 260 +#define OBJ_id_it OBJ_id_pkix,4L + +#define SN_id_pkip "id-pkip" +#define NID_id_pkip 261 +#define OBJ_id_pkip OBJ_id_pkix,5L + +#define SN_id_alg "id-alg" +#define NID_id_alg 262 +#define OBJ_id_alg OBJ_id_pkix,6L + +#define SN_id_cmc "id-cmc" +#define NID_id_cmc 263 +#define OBJ_id_cmc OBJ_id_pkix,7L + +#define SN_id_on "id-on" +#define NID_id_on 264 +#define OBJ_id_on OBJ_id_pkix,8L + +#define SN_id_pda "id-pda" +#define NID_id_pda 265 +#define OBJ_id_pda OBJ_id_pkix,9L + +#define SN_id_aca "id-aca" +#define NID_id_aca 266 +#define OBJ_id_aca OBJ_id_pkix,10L + +#define SN_id_qcs "id-qcs" +#define NID_id_qcs 267 +#define OBJ_id_qcs OBJ_id_pkix,11L + +#define SN_id_cct "id-cct" +#define NID_id_cct 268 +#define OBJ_id_cct OBJ_id_pkix,12L + +#define SN_id_ppl "id-ppl" +#define NID_id_ppl 662 +#define OBJ_id_ppl OBJ_id_pkix,21L + +#define SN_id_ad "id-ad" +#define NID_id_ad 176 +#define OBJ_id_ad OBJ_id_pkix,48L + +#define SN_id_pkix1_explicit_88 "id-pkix1-explicit-88" +#define NID_id_pkix1_explicit_88 269 +#define OBJ_id_pkix1_explicit_88 OBJ_id_pkix_mod,1L + +#define SN_id_pkix1_implicit_88 "id-pkix1-implicit-88" +#define NID_id_pkix1_implicit_88 270 +#define OBJ_id_pkix1_implicit_88 OBJ_id_pkix_mod,2L + +#define SN_id_pkix1_explicit_93 "id-pkix1-explicit-93" +#define NID_id_pkix1_explicit_93 271 +#define OBJ_id_pkix1_explicit_93 OBJ_id_pkix_mod,3L + +#define SN_id_pkix1_implicit_93 "id-pkix1-implicit-93" +#define NID_id_pkix1_implicit_93 272 +#define OBJ_id_pkix1_implicit_93 OBJ_id_pkix_mod,4L + +#define SN_id_mod_crmf "id-mod-crmf" +#define NID_id_mod_crmf 273 +#define OBJ_id_mod_crmf OBJ_id_pkix_mod,5L + +#define SN_id_mod_cmc "id-mod-cmc" +#define NID_id_mod_cmc 274 +#define OBJ_id_mod_cmc OBJ_id_pkix_mod,6L + +#define SN_id_mod_kea_profile_88 "id-mod-kea-profile-88" +#define NID_id_mod_kea_profile_88 275 +#define OBJ_id_mod_kea_profile_88 OBJ_id_pkix_mod,7L + +#define SN_id_mod_kea_profile_93 "id-mod-kea-profile-93" +#define NID_id_mod_kea_profile_93 276 +#define OBJ_id_mod_kea_profile_93 OBJ_id_pkix_mod,8L + +#define SN_id_mod_cmp "id-mod-cmp" +#define NID_id_mod_cmp 277 +#define OBJ_id_mod_cmp OBJ_id_pkix_mod,9L + +#define SN_id_mod_qualified_cert_88 "id-mod-qualified-cert-88" +#define NID_id_mod_qualified_cert_88 278 +#define OBJ_id_mod_qualified_cert_88 OBJ_id_pkix_mod,10L + +#define SN_id_mod_qualified_cert_93 "id-mod-qualified-cert-93" +#define NID_id_mod_qualified_cert_93 279 +#define OBJ_id_mod_qualified_cert_93 OBJ_id_pkix_mod,11L + +#define SN_id_mod_attribute_cert "id-mod-attribute-cert" +#define NID_id_mod_attribute_cert 280 +#define OBJ_id_mod_attribute_cert OBJ_id_pkix_mod,12L + +#define SN_id_mod_timestamp_protocol "id-mod-timestamp-protocol" +#define NID_id_mod_timestamp_protocol 281 +#define OBJ_id_mod_timestamp_protocol OBJ_id_pkix_mod,13L + +#define SN_id_mod_ocsp "id-mod-ocsp" +#define NID_id_mod_ocsp 282 +#define OBJ_id_mod_ocsp OBJ_id_pkix_mod,14L + +#define SN_id_mod_dvcs "id-mod-dvcs" +#define NID_id_mod_dvcs 283 +#define OBJ_id_mod_dvcs OBJ_id_pkix_mod,15L + +#define SN_id_mod_cmp2000 "id-mod-cmp2000" +#define NID_id_mod_cmp2000 284 +#define OBJ_id_mod_cmp2000 OBJ_id_pkix_mod,16L + +#define SN_info_access "authorityInfoAccess" +#define LN_info_access "Authority Information Access" +#define NID_info_access 177 +#define OBJ_info_access OBJ_id_pe,1L + +#define SN_biometricInfo "biometricInfo" +#define LN_biometricInfo "Biometric Info" +#define NID_biometricInfo 285 +#define OBJ_biometricInfo OBJ_id_pe,2L + +#define SN_qcStatements "qcStatements" +#define NID_qcStatements 286 +#define OBJ_qcStatements OBJ_id_pe,3L + +#define SN_ac_auditEntity "ac-auditEntity" +#define NID_ac_auditEntity 287 +#define OBJ_ac_auditEntity OBJ_id_pe,4L + +#define SN_ac_targeting "ac-targeting" +#define NID_ac_targeting 288 +#define OBJ_ac_targeting OBJ_id_pe,5L + +#define SN_aaControls "aaControls" +#define NID_aaControls 289 +#define OBJ_aaControls OBJ_id_pe,6L + +#define SN_sbgp_ipAddrBlock "sbgp-ipAddrBlock" +#define NID_sbgp_ipAddrBlock 290 +#define OBJ_sbgp_ipAddrBlock OBJ_id_pe,7L + +#define SN_sbgp_autonomousSysNum "sbgp-autonomousSysNum" +#define NID_sbgp_autonomousSysNum 291 +#define OBJ_sbgp_autonomousSysNum OBJ_id_pe,8L + +#define SN_sbgp_routerIdentifier "sbgp-routerIdentifier" +#define NID_sbgp_routerIdentifier 292 +#define OBJ_sbgp_routerIdentifier OBJ_id_pe,9L + +#define SN_ac_proxying "ac-proxying" +#define NID_ac_proxying 397 +#define OBJ_ac_proxying OBJ_id_pe,10L + +#define SN_sinfo_access "subjectInfoAccess" +#define LN_sinfo_access "Subject Information Access" +#define NID_sinfo_access 398 +#define OBJ_sinfo_access OBJ_id_pe,11L + +#define SN_proxyCertInfo "proxyCertInfo" +#define LN_proxyCertInfo "Proxy Certificate Information" +#define NID_proxyCertInfo 663 +#define OBJ_proxyCertInfo OBJ_id_pe,14L + +#define SN_id_qt_cps "id-qt-cps" +#define LN_id_qt_cps "Policy Qualifier CPS" +#define NID_id_qt_cps 164 +#define OBJ_id_qt_cps OBJ_id_qt,1L + +#define SN_id_qt_unotice "id-qt-unotice" +#define LN_id_qt_unotice "Policy Qualifier User Notice" +#define NID_id_qt_unotice 165 +#define OBJ_id_qt_unotice OBJ_id_qt,2L + +#define SN_textNotice "textNotice" +#define NID_textNotice 293 +#define OBJ_textNotice OBJ_id_qt,3L + +#define SN_server_auth "serverAuth" +#define LN_server_auth "TLS Web Server Authentication" +#define NID_server_auth 129 +#define OBJ_server_auth OBJ_id_kp,1L + +#define SN_client_auth "clientAuth" +#define LN_client_auth "TLS Web Client Authentication" +#define NID_client_auth 130 +#define OBJ_client_auth OBJ_id_kp,2L + +#define SN_code_sign "codeSigning" +#define LN_code_sign "Code Signing" +#define NID_code_sign 131 +#define OBJ_code_sign OBJ_id_kp,3L + +#define SN_email_protect "emailProtection" +#define LN_email_protect "E-mail Protection" +#define NID_email_protect 132 +#define OBJ_email_protect OBJ_id_kp,4L + +#define SN_ipsecEndSystem "ipsecEndSystem" +#define LN_ipsecEndSystem "IPSec End System" +#define NID_ipsecEndSystem 294 +#define OBJ_ipsecEndSystem OBJ_id_kp,5L + +#define SN_ipsecTunnel "ipsecTunnel" +#define LN_ipsecTunnel "IPSec Tunnel" +#define NID_ipsecTunnel 295 +#define OBJ_ipsecTunnel OBJ_id_kp,6L + +#define SN_ipsecUser "ipsecUser" +#define LN_ipsecUser "IPSec User" +#define NID_ipsecUser 296 +#define OBJ_ipsecUser OBJ_id_kp,7L + +#define SN_time_stamp "timeStamping" +#define LN_time_stamp "Time Stamping" +#define NID_time_stamp 133 +#define OBJ_time_stamp OBJ_id_kp,8L + +#define SN_OCSP_sign "OCSPSigning" +#define LN_OCSP_sign "OCSP Signing" +#define NID_OCSP_sign 180 +#define OBJ_OCSP_sign OBJ_id_kp,9L + +#define SN_dvcs "DVCS" +#define LN_dvcs "dvcs" +#define NID_dvcs 297 +#define OBJ_dvcs OBJ_id_kp,10L + +#define SN_id_it_caProtEncCert "id-it-caProtEncCert" +#define NID_id_it_caProtEncCert 298 +#define OBJ_id_it_caProtEncCert OBJ_id_it,1L + +#define SN_id_it_signKeyPairTypes "id-it-signKeyPairTypes" +#define NID_id_it_signKeyPairTypes 299 +#define OBJ_id_it_signKeyPairTypes OBJ_id_it,2L + +#define SN_id_it_encKeyPairTypes "id-it-encKeyPairTypes" +#define NID_id_it_encKeyPairTypes 300 +#define OBJ_id_it_encKeyPairTypes OBJ_id_it,3L + +#define SN_id_it_preferredSymmAlg "id-it-preferredSymmAlg" +#define NID_id_it_preferredSymmAlg 301 +#define OBJ_id_it_preferredSymmAlg OBJ_id_it,4L + +#define SN_id_it_caKeyUpdateInfo "id-it-caKeyUpdateInfo" +#define NID_id_it_caKeyUpdateInfo 302 +#define OBJ_id_it_caKeyUpdateInfo OBJ_id_it,5L + +#define SN_id_it_currentCRL "id-it-currentCRL" +#define NID_id_it_currentCRL 303 +#define OBJ_id_it_currentCRL OBJ_id_it,6L + +#define SN_id_it_unsupportedOIDs "id-it-unsupportedOIDs" +#define NID_id_it_unsupportedOIDs 304 +#define OBJ_id_it_unsupportedOIDs OBJ_id_it,7L + +#define SN_id_it_subscriptionRequest "id-it-subscriptionRequest" +#define NID_id_it_subscriptionRequest 305 +#define OBJ_id_it_subscriptionRequest OBJ_id_it,8L + +#define SN_id_it_subscriptionResponse "id-it-subscriptionResponse" +#define NID_id_it_subscriptionResponse 306 +#define OBJ_id_it_subscriptionResponse OBJ_id_it,9L + +#define SN_id_it_keyPairParamReq "id-it-keyPairParamReq" +#define NID_id_it_keyPairParamReq 307 +#define OBJ_id_it_keyPairParamReq OBJ_id_it,10L + +#define SN_id_it_keyPairParamRep "id-it-keyPairParamRep" +#define NID_id_it_keyPairParamRep 308 +#define OBJ_id_it_keyPairParamRep OBJ_id_it,11L + +#define SN_id_it_revPassphrase "id-it-revPassphrase" +#define NID_id_it_revPassphrase 309 +#define OBJ_id_it_revPassphrase OBJ_id_it,12L + +#define SN_id_it_implicitConfirm "id-it-implicitConfirm" +#define NID_id_it_implicitConfirm 310 +#define OBJ_id_it_implicitConfirm OBJ_id_it,13L + +#define SN_id_it_confirmWaitTime "id-it-confirmWaitTime" +#define NID_id_it_confirmWaitTime 311 +#define OBJ_id_it_confirmWaitTime OBJ_id_it,14L + +#define SN_id_it_origPKIMessage "id-it-origPKIMessage" +#define NID_id_it_origPKIMessage 312 +#define OBJ_id_it_origPKIMessage OBJ_id_it,15L + +#define SN_id_it_suppLangTags "id-it-suppLangTags" +#define NID_id_it_suppLangTags 784 +#define OBJ_id_it_suppLangTags OBJ_id_it,16L + +#define SN_id_regCtrl "id-regCtrl" +#define NID_id_regCtrl 313 +#define OBJ_id_regCtrl OBJ_id_pkip,1L + +#define SN_id_regInfo "id-regInfo" +#define NID_id_regInfo 314 +#define OBJ_id_regInfo OBJ_id_pkip,2L + +#define SN_id_regCtrl_regToken "id-regCtrl-regToken" +#define NID_id_regCtrl_regToken 315 +#define OBJ_id_regCtrl_regToken OBJ_id_regCtrl,1L + +#define SN_id_regCtrl_authenticator "id-regCtrl-authenticator" +#define NID_id_regCtrl_authenticator 316 +#define OBJ_id_regCtrl_authenticator OBJ_id_regCtrl,2L + +#define SN_id_regCtrl_pkiPublicationInfo "id-regCtrl-pkiPublicationInfo" +#define NID_id_regCtrl_pkiPublicationInfo 317 +#define OBJ_id_regCtrl_pkiPublicationInfo OBJ_id_regCtrl,3L + +#define SN_id_regCtrl_pkiArchiveOptions "id-regCtrl-pkiArchiveOptions" +#define NID_id_regCtrl_pkiArchiveOptions 318 +#define OBJ_id_regCtrl_pkiArchiveOptions OBJ_id_regCtrl,4L + +#define SN_id_regCtrl_oldCertID "id-regCtrl-oldCertID" +#define NID_id_regCtrl_oldCertID 319 +#define OBJ_id_regCtrl_oldCertID OBJ_id_regCtrl,5L + +#define SN_id_regCtrl_protocolEncrKey "id-regCtrl-protocolEncrKey" +#define NID_id_regCtrl_protocolEncrKey 320 +#define OBJ_id_regCtrl_protocolEncrKey OBJ_id_regCtrl,6L + +#define SN_id_regInfo_utf8Pairs "id-regInfo-utf8Pairs" +#define NID_id_regInfo_utf8Pairs 321 +#define OBJ_id_regInfo_utf8Pairs OBJ_id_regInfo,1L + +#define SN_id_regInfo_certReq "id-regInfo-certReq" +#define NID_id_regInfo_certReq 322 +#define OBJ_id_regInfo_certReq OBJ_id_regInfo,2L + +#define SN_id_alg_des40 "id-alg-des40" +#define NID_id_alg_des40 323 +#define OBJ_id_alg_des40 OBJ_id_alg,1L + +#define SN_id_alg_noSignature "id-alg-noSignature" +#define NID_id_alg_noSignature 324 +#define OBJ_id_alg_noSignature OBJ_id_alg,2L + +#define SN_id_alg_dh_sig_hmac_sha1 "id-alg-dh-sig-hmac-sha1" +#define NID_id_alg_dh_sig_hmac_sha1 325 +#define OBJ_id_alg_dh_sig_hmac_sha1 OBJ_id_alg,3L + +#define SN_id_alg_dh_pop "id-alg-dh-pop" +#define NID_id_alg_dh_pop 326 +#define OBJ_id_alg_dh_pop OBJ_id_alg,4L + +#define SN_id_cmc_statusInfo "id-cmc-statusInfo" +#define NID_id_cmc_statusInfo 327 +#define OBJ_id_cmc_statusInfo OBJ_id_cmc,1L + +#define SN_id_cmc_identification "id-cmc-identification" +#define NID_id_cmc_identification 328 +#define OBJ_id_cmc_identification OBJ_id_cmc,2L + +#define SN_id_cmc_identityProof "id-cmc-identityProof" +#define NID_id_cmc_identityProof 329 +#define OBJ_id_cmc_identityProof OBJ_id_cmc,3L + +#define SN_id_cmc_dataReturn "id-cmc-dataReturn" +#define NID_id_cmc_dataReturn 330 +#define OBJ_id_cmc_dataReturn OBJ_id_cmc,4L + +#define SN_id_cmc_transactionId "id-cmc-transactionId" +#define NID_id_cmc_transactionId 331 +#define OBJ_id_cmc_transactionId OBJ_id_cmc,5L + +#define SN_id_cmc_senderNonce "id-cmc-senderNonce" +#define NID_id_cmc_senderNonce 332 +#define OBJ_id_cmc_senderNonce OBJ_id_cmc,6L + +#define SN_id_cmc_recipientNonce "id-cmc-recipientNonce" +#define NID_id_cmc_recipientNonce 333 +#define OBJ_id_cmc_recipientNonce OBJ_id_cmc,7L + +#define SN_id_cmc_addExtensions "id-cmc-addExtensions" +#define NID_id_cmc_addExtensions 334 +#define OBJ_id_cmc_addExtensions OBJ_id_cmc,8L + +#define SN_id_cmc_encryptedPOP "id-cmc-encryptedPOP" +#define NID_id_cmc_encryptedPOP 335 +#define OBJ_id_cmc_encryptedPOP OBJ_id_cmc,9L + +#define SN_id_cmc_decryptedPOP "id-cmc-decryptedPOP" +#define NID_id_cmc_decryptedPOP 336 +#define OBJ_id_cmc_decryptedPOP OBJ_id_cmc,10L + +#define SN_id_cmc_lraPOPWitness "id-cmc-lraPOPWitness" +#define NID_id_cmc_lraPOPWitness 337 +#define OBJ_id_cmc_lraPOPWitness OBJ_id_cmc,11L + +#define SN_id_cmc_getCert "id-cmc-getCert" +#define NID_id_cmc_getCert 338 +#define OBJ_id_cmc_getCert OBJ_id_cmc,15L + +#define SN_id_cmc_getCRL "id-cmc-getCRL" +#define NID_id_cmc_getCRL 339 +#define OBJ_id_cmc_getCRL OBJ_id_cmc,16L + +#define SN_id_cmc_revokeRequest "id-cmc-revokeRequest" +#define NID_id_cmc_revokeRequest 340 +#define OBJ_id_cmc_revokeRequest OBJ_id_cmc,17L + +#define SN_id_cmc_regInfo "id-cmc-regInfo" +#define NID_id_cmc_regInfo 341 +#define OBJ_id_cmc_regInfo OBJ_id_cmc,18L + +#define SN_id_cmc_responseInfo "id-cmc-responseInfo" +#define NID_id_cmc_responseInfo 342 +#define OBJ_id_cmc_responseInfo OBJ_id_cmc,19L + +#define SN_id_cmc_queryPending "id-cmc-queryPending" +#define NID_id_cmc_queryPending 343 +#define OBJ_id_cmc_queryPending OBJ_id_cmc,21L + +#define SN_id_cmc_popLinkRandom "id-cmc-popLinkRandom" +#define NID_id_cmc_popLinkRandom 344 +#define OBJ_id_cmc_popLinkRandom OBJ_id_cmc,22L + +#define SN_id_cmc_popLinkWitness "id-cmc-popLinkWitness" +#define NID_id_cmc_popLinkWitness 345 +#define OBJ_id_cmc_popLinkWitness OBJ_id_cmc,23L + +#define SN_id_cmc_confirmCertAcceptance "id-cmc-confirmCertAcceptance" +#define NID_id_cmc_confirmCertAcceptance 346 +#define OBJ_id_cmc_confirmCertAcceptance OBJ_id_cmc,24L + +#define SN_id_on_personalData "id-on-personalData" +#define NID_id_on_personalData 347 +#define OBJ_id_on_personalData OBJ_id_on,1L + +#define SN_id_on_permanentIdentifier "id-on-permanentIdentifier" +#define LN_id_on_permanentIdentifier "Permanent Identifier" +#define NID_id_on_permanentIdentifier 858 +#define OBJ_id_on_permanentIdentifier OBJ_id_on,3L + +#define SN_id_pda_dateOfBirth "id-pda-dateOfBirth" +#define NID_id_pda_dateOfBirth 348 +#define OBJ_id_pda_dateOfBirth OBJ_id_pda,1L + +#define SN_id_pda_placeOfBirth "id-pda-placeOfBirth" +#define NID_id_pda_placeOfBirth 349 +#define OBJ_id_pda_placeOfBirth OBJ_id_pda,2L + +#define SN_id_pda_gender "id-pda-gender" +#define NID_id_pda_gender 351 +#define OBJ_id_pda_gender OBJ_id_pda,3L + +#define SN_id_pda_countryOfCitizenship "id-pda-countryOfCitizenship" +#define NID_id_pda_countryOfCitizenship 352 +#define OBJ_id_pda_countryOfCitizenship OBJ_id_pda,4L + +#define SN_id_pda_countryOfResidence "id-pda-countryOfResidence" +#define NID_id_pda_countryOfResidence 353 +#define OBJ_id_pda_countryOfResidence OBJ_id_pda,5L + +#define SN_id_aca_authenticationInfo "id-aca-authenticationInfo" +#define NID_id_aca_authenticationInfo 354 +#define OBJ_id_aca_authenticationInfo OBJ_id_aca,1L + +#define SN_id_aca_accessIdentity "id-aca-accessIdentity" +#define NID_id_aca_accessIdentity 355 +#define OBJ_id_aca_accessIdentity OBJ_id_aca,2L + +#define SN_id_aca_chargingIdentity "id-aca-chargingIdentity" +#define NID_id_aca_chargingIdentity 356 +#define OBJ_id_aca_chargingIdentity OBJ_id_aca,3L + +#define SN_id_aca_group "id-aca-group" +#define NID_id_aca_group 357 +#define OBJ_id_aca_group OBJ_id_aca,4L + +#define SN_id_aca_role "id-aca-role" +#define NID_id_aca_role 358 +#define OBJ_id_aca_role OBJ_id_aca,5L + +#define SN_id_aca_encAttrs "id-aca-encAttrs" +#define NID_id_aca_encAttrs 399 +#define OBJ_id_aca_encAttrs OBJ_id_aca,6L + +#define SN_id_qcs_pkixQCSyntax_v1 "id-qcs-pkixQCSyntax-v1" +#define NID_id_qcs_pkixQCSyntax_v1 359 +#define OBJ_id_qcs_pkixQCSyntax_v1 OBJ_id_qcs,1L + +#define SN_id_cct_crs "id-cct-crs" +#define NID_id_cct_crs 360 +#define OBJ_id_cct_crs OBJ_id_cct,1L + +#define SN_id_cct_PKIData "id-cct-PKIData" +#define NID_id_cct_PKIData 361 +#define OBJ_id_cct_PKIData OBJ_id_cct,2L + +#define SN_id_cct_PKIResponse "id-cct-PKIResponse" +#define NID_id_cct_PKIResponse 362 +#define OBJ_id_cct_PKIResponse OBJ_id_cct,3L + +#define SN_id_ppl_anyLanguage "id-ppl-anyLanguage" +#define LN_id_ppl_anyLanguage "Any language" +#define NID_id_ppl_anyLanguage 664 +#define OBJ_id_ppl_anyLanguage OBJ_id_ppl,0L + +#define SN_id_ppl_inheritAll "id-ppl-inheritAll" +#define LN_id_ppl_inheritAll "Inherit all" +#define NID_id_ppl_inheritAll 665 +#define OBJ_id_ppl_inheritAll OBJ_id_ppl,1L + +#define SN_Independent "id-ppl-independent" +#define LN_Independent "Independent" +#define NID_Independent 667 +#define OBJ_Independent OBJ_id_ppl,2L + +#define SN_ad_OCSP "OCSP" +#define LN_ad_OCSP "OCSP" +#define NID_ad_OCSP 178 +#define OBJ_ad_OCSP OBJ_id_ad,1L + +#define SN_ad_ca_issuers "caIssuers" +#define LN_ad_ca_issuers "CA Issuers" +#define NID_ad_ca_issuers 179 +#define OBJ_ad_ca_issuers OBJ_id_ad,2L + +#define SN_ad_timeStamping "ad_timestamping" +#define LN_ad_timeStamping "AD Time Stamping" +#define NID_ad_timeStamping 363 +#define OBJ_ad_timeStamping OBJ_id_ad,3L + +#define SN_ad_dvcs "AD_DVCS" +#define LN_ad_dvcs "ad dvcs" +#define NID_ad_dvcs 364 +#define OBJ_ad_dvcs OBJ_id_ad,4L + +#define SN_caRepository "caRepository" +#define LN_caRepository "CA Repository" +#define NID_caRepository 785 +#define OBJ_caRepository OBJ_id_ad,5L + +#define OBJ_id_pkix_OCSP OBJ_ad_OCSP + +#define SN_id_pkix_OCSP_basic "basicOCSPResponse" +#define LN_id_pkix_OCSP_basic "Basic OCSP Response" +#define NID_id_pkix_OCSP_basic 365 +#define OBJ_id_pkix_OCSP_basic OBJ_id_pkix_OCSP,1L + +#define SN_id_pkix_OCSP_Nonce "Nonce" +#define LN_id_pkix_OCSP_Nonce "OCSP Nonce" +#define NID_id_pkix_OCSP_Nonce 366 +#define OBJ_id_pkix_OCSP_Nonce OBJ_id_pkix_OCSP,2L + +#define SN_id_pkix_OCSP_CrlID "CrlID" +#define LN_id_pkix_OCSP_CrlID "OCSP CRL ID" +#define NID_id_pkix_OCSP_CrlID 367 +#define OBJ_id_pkix_OCSP_CrlID OBJ_id_pkix_OCSP,3L + +#define SN_id_pkix_OCSP_acceptableResponses "acceptableResponses" +#define LN_id_pkix_OCSP_acceptableResponses "Acceptable OCSP Responses" +#define NID_id_pkix_OCSP_acceptableResponses 368 +#define OBJ_id_pkix_OCSP_acceptableResponses OBJ_id_pkix_OCSP,4L + +#define SN_id_pkix_OCSP_noCheck "noCheck" +#define LN_id_pkix_OCSP_noCheck "OCSP No Check" +#define NID_id_pkix_OCSP_noCheck 369 +#define OBJ_id_pkix_OCSP_noCheck OBJ_id_pkix_OCSP,5L + +#define SN_id_pkix_OCSP_archiveCutoff "archiveCutoff" +#define LN_id_pkix_OCSP_archiveCutoff "OCSP Archive Cutoff" +#define NID_id_pkix_OCSP_archiveCutoff 370 +#define OBJ_id_pkix_OCSP_archiveCutoff OBJ_id_pkix_OCSP,6L + +#define SN_id_pkix_OCSP_serviceLocator "serviceLocator" +#define LN_id_pkix_OCSP_serviceLocator "OCSP Service Locator" +#define NID_id_pkix_OCSP_serviceLocator 371 +#define OBJ_id_pkix_OCSP_serviceLocator OBJ_id_pkix_OCSP,7L + +#define SN_id_pkix_OCSP_extendedStatus "extendedStatus" +#define LN_id_pkix_OCSP_extendedStatus "Extended OCSP Status" +#define NID_id_pkix_OCSP_extendedStatus 372 +#define OBJ_id_pkix_OCSP_extendedStatus OBJ_id_pkix_OCSP,8L + +#define SN_id_pkix_OCSP_valid "valid" +#define NID_id_pkix_OCSP_valid 373 +#define OBJ_id_pkix_OCSP_valid OBJ_id_pkix_OCSP,9L + +#define SN_id_pkix_OCSP_path "path" +#define NID_id_pkix_OCSP_path 374 +#define OBJ_id_pkix_OCSP_path OBJ_id_pkix_OCSP,10L + +#define SN_id_pkix_OCSP_trustRoot "trustRoot" +#define LN_id_pkix_OCSP_trustRoot "Trust Root" +#define NID_id_pkix_OCSP_trustRoot 375 +#define OBJ_id_pkix_OCSP_trustRoot OBJ_id_pkix_OCSP,11L + +#define SN_algorithm "algorithm" +#define LN_algorithm "algorithm" +#define NID_algorithm 376 +#define OBJ_algorithm 1L,3L,14L,3L,2L + +#define SN_md5WithRSA "RSA-NP-MD5" +#define LN_md5WithRSA "md5WithRSA" +#define NID_md5WithRSA 104 +#define OBJ_md5WithRSA OBJ_algorithm,3L + +#define SN_des_ecb "DES-ECB" +#define LN_des_ecb "des-ecb" +#define NID_des_ecb 29 +#define OBJ_des_ecb OBJ_algorithm,6L + +#define SN_des_cbc "DES-CBC" +#define LN_des_cbc "des-cbc" +#define NID_des_cbc 31 +#define OBJ_des_cbc OBJ_algorithm,7L + +#define SN_des_ofb64 "DES-OFB" +#define LN_des_ofb64 "des-ofb" +#define NID_des_ofb64 45 +#define OBJ_des_ofb64 OBJ_algorithm,8L + +#define SN_des_cfb64 "DES-CFB" +#define LN_des_cfb64 "des-cfb" +#define NID_des_cfb64 30 +#define OBJ_des_cfb64 OBJ_algorithm,9L + +#define SN_rsaSignature "rsaSignature" +#define NID_rsaSignature 377 +#define OBJ_rsaSignature OBJ_algorithm,11L + +#define SN_dsa_2 "DSA-old" +#define LN_dsa_2 "dsaEncryption-old" +#define NID_dsa_2 67 +#define OBJ_dsa_2 OBJ_algorithm,12L + +#define SN_dsaWithSHA "DSA-SHA" +#define LN_dsaWithSHA "dsaWithSHA" +#define NID_dsaWithSHA 66 +#define OBJ_dsaWithSHA OBJ_algorithm,13L + +#define SN_shaWithRSAEncryption "RSA-SHA" +#define LN_shaWithRSAEncryption "shaWithRSAEncryption" +#define NID_shaWithRSAEncryption 42 +#define OBJ_shaWithRSAEncryption OBJ_algorithm,15L + +#define SN_des_ede_ecb "DES-EDE" +#define LN_des_ede_ecb "des-ede" +#define NID_des_ede_ecb 32 +#define OBJ_des_ede_ecb OBJ_algorithm,17L + +#define SN_des_ede3_ecb "DES-EDE3" +#define LN_des_ede3_ecb "des-ede3" +#define NID_des_ede3_ecb 33 + +#define SN_des_ede_cbc "DES-EDE-CBC" +#define LN_des_ede_cbc "des-ede-cbc" +#define NID_des_ede_cbc 43 + +#define SN_des_ede_cfb64 "DES-EDE-CFB" +#define LN_des_ede_cfb64 "des-ede-cfb" +#define NID_des_ede_cfb64 60 + +#define SN_des_ede3_cfb64 "DES-EDE3-CFB" +#define LN_des_ede3_cfb64 "des-ede3-cfb" +#define NID_des_ede3_cfb64 61 + +#define SN_des_ede_ofb64 "DES-EDE-OFB" +#define LN_des_ede_ofb64 "des-ede-ofb" +#define NID_des_ede_ofb64 62 + +#define SN_des_ede3_ofb64 "DES-EDE3-OFB" +#define LN_des_ede3_ofb64 "des-ede3-ofb" +#define NID_des_ede3_ofb64 63 + +#define SN_desx_cbc "DESX-CBC" +#define LN_desx_cbc "desx-cbc" +#define NID_desx_cbc 80 + +#define SN_sha "SHA" +#define LN_sha "sha" +#define NID_sha 41 +#define OBJ_sha OBJ_algorithm,18L + +#define SN_sha1 "SHA1" +#define LN_sha1 "sha1" +#define NID_sha1 64 +#define OBJ_sha1 OBJ_algorithm,26L + +#define SN_dsaWithSHA1_2 "DSA-SHA1-old" +#define LN_dsaWithSHA1_2 "dsaWithSHA1-old" +#define NID_dsaWithSHA1_2 70 +#define OBJ_dsaWithSHA1_2 OBJ_algorithm,27L + +#define SN_sha1WithRSA "RSA-SHA1-2" +#define LN_sha1WithRSA "sha1WithRSA" +#define NID_sha1WithRSA 115 +#define OBJ_sha1WithRSA OBJ_algorithm,29L + +#define SN_ripemd160 "RIPEMD160" +#define LN_ripemd160 "ripemd160" +#define NID_ripemd160 117 +#define OBJ_ripemd160 1L,3L,36L,3L,2L,1L + +#define SN_ripemd160WithRSA "RSA-RIPEMD160" +#define LN_ripemd160WithRSA "ripemd160WithRSA" +#define NID_ripemd160WithRSA 119 +#define OBJ_ripemd160WithRSA 1L,3L,36L,3L,3L,1L,2L + +#define SN_sxnet "SXNetID" +#define LN_sxnet "Strong Extranet ID" +#define NID_sxnet 143 +#define OBJ_sxnet 1L,3L,101L,1L,4L,1L + +#define SN_X500 "X500" +#define LN_X500 "directory services (X.500)" +#define NID_X500 11 +#define OBJ_X500 2L,5L + +#define SN_X509 "X509" +#define NID_X509 12 +#define OBJ_X509 OBJ_X500,4L + +#define SN_commonName "CN" +#define LN_commonName "commonName" +#define NID_commonName 13 +#define OBJ_commonName OBJ_X509,3L + +#define SN_surname "SN" +#define LN_surname "surname" +#define NID_surname 100 +#define OBJ_surname OBJ_X509,4L + +#define LN_serialNumber "serialNumber" +#define NID_serialNumber 105 +#define OBJ_serialNumber OBJ_X509,5L + +#define SN_countryName "C" +#define LN_countryName "countryName" +#define NID_countryName 14 +#define OBJ_countryName OBJ_X509,6L + +#define SN_localityName "L" +#define LN_localityName "localityName" +#define NID_localityName 15 +#define OBJ_localityName OBJ_X509,7L + +#define SN_stateOrProvinceName "ST" +#define LN_stateOrProvinceName "stateOrProvinceName" +#define NID_stateOrProvinceName 16 +#define OBJ_stateOrProvinceName OBJ_X509,8L + +#define SN_streetAddress "street" +#define LN_streetAddress "streetAddress" +#define NID_streetAddress 660 +#define OBJ_streetAddress OBJ_X509,9L + +#define SN_organizationName "O" +#define LN_organizationName "organizationName" +#define NID_organizationName 17 +#define OBJ_organizationName OBJ_X509,10L + +#define SN_organizationalUnitName "OU" +#define LN_organizationalUnitName "organizationalUnitName" +#define NID_organizationalUnitName 18 +#define OBJ_organizationalUnitName OBJ_X509,11L + +#define SN_title "title" +#define LN_title "title" +#define NID_title 106 +#define OBJ_title OBJ_X509,12L + +#define LN_description "description" +#define NID_description 107 +#define OBJ_description OBJ_X509,13L + +#define LN_searchGuide "searchGuide" +#define NID_searchGuide 859 +#define OBJ_searchGuide OBJ_X509,14L + +#define LN_businessCategory "businessCategory" +#define NID_businessCategory 860 +#define OBJ_businessCategory OBJ_X509,15L + +#define LN_postalAddress "postalAddress" +#define NID_postalAddress 861 +#define OBJ_postalAddress OBJ_X509,16L + +#define LN_postalCode "postalCode" +#define NID_postalCode 661 +#define OBJ_postalCode OBJ_X509,17L + +#define LN_postOfficeBox "postOfficeBox" +#define NID_postOfficeBox 862 +#define OBJ_postOfficeBox OBJ_X509,18L + +#define LN_physicalDeliveryOfficeName "physicalDeliveryOfficeName" +#define NID_physicalDeliveryOfficeName 863 +#define OBJ_physicalDeliveryOfficeName OBJ_X509,19L + +#define LN_telephoneNumber "telephoneNumber" +#define NID_telephoneNumber 864 +#define OBJ_telephoneNumber OBJ_X509,20L + +#define LN_telexNumber "telexNumber" +#define NID_telexNumber 865 +#define OBJ_telexNumber OBJ_X509,21L + +#define LN_teletexTerminalIdentifier "teletexTerminalIdentifier" +#define NID_teletexTerminalIdentifier 866 +#define OBJ_teletexTerminalIdentifier OBJ_X509,22L + +#define LN_facsimileTelephoneNumber "facsimileTelephoneNumber" +#define NID_facsimileTelephoneNumber 867 +#define OBJ_facsimileTelephoneNumber OBJ_X509,23L + +#define LN_x121Address "x121Address" +#define NID_x121Address 868 +#define OBJ_x121Address OBJ_X509,24L + +#define LN_internationaliSDNNumber "internationaliSDNNumber" +#define NID_internationaliSDNNumber 869 +#define OBJ_internationaliSDNNumber OBJ_X509,25L + +#define LN_registeredAddress "registeredAddress" +#define NID_registeredAddress 870 +#define OBJ_registeredAddress OBJ_X509,26L + +#define LN_destinationIndicator "destinationIndicator" +#define NID_destinationIndicator 871 +#define OBJ_destinationIndicator OBJ_X509,27L + +#define LN_preferredDeliveryMethod "preferredDeliveryMethod" +#define NID_preferredDeliveryMethod 872 +#define OBJ_preferredDeliveryMethod OBJ_X509,28L + +#define LN_presentationAddress "presentationAddress" +#define NID_presentationAddress 873 +#define OBJ_presentationAddress OBJ_X509,29L + +#define LN_supportedApplicationContext "supportedApplicationContext" +#define NID_supportedApplicationContext 874 +#define OBJ_supportedApplicationContext OBJ_X509,30L + +#define SN_member "member" +#define NID_member 875 +#define OBJ_member OBJ_X509,31L + +#define SN_owner "owner" +#define NID_owner 876 +#define OBJ_owner OBJ_X509,32L + +#define LN_roleOccupant "roleOccupant" +#define NID_roleOccupant 877 +#define OBJ_roleOccupant OBJ_X509,33L + +#define SN_seeAlso "seeAlso" +#define NID_seeAlso 878 +#define OBJ_seeAlso OBJ_X509,34L + +#define LN_userPassword "userPassword" +#define NID_userPassword 879 +#define OBJ_userPassword OBJ_X509,35L + +#define LN_userCertificate "userCertificate" +#define NID_userCertificate 880 +#define OBJ_userCertificate OBJ_X509,36L + +#define LN_cACertificate "cACertificate" +#define NID_cACertificate 881 +#define OBJ_cACertificate OBJ_X509,37L + +#define LN_authorityRevocationList "authorityRevocationList" +#define NID_authorityRevocationList 882 +#define OBJ_authorityRevocationList OBJ_X509,38L + +#define LN_certificateRevocationList "certificateRevocationList" +#define NID_certificateRevocationList 883 +#define OBJ_certificateRevocationList OBJ_X509,39L + +#define LN_crossCertificatePair "crossCertificatePair" +#define NID_crossCertificatePair 884 +#define OBJ_crossCertificatePair OBJ_X509,40L + +#define SN_name "name" +#define LN_name "name" +#define NID_name 173 +#define OBJ_name OBJ_X509,41L + +#define SN_givenName "GN" +#define LN_givenName "givenName" +#define NID_givenName 99 +#define OBJ_givenName OBJ_X509,42L + +#define SN_initials "initials" +#define LN_initials "initials" +#define NID_initials 101 +#define OBJ_initials OBJ_X509,43L + +#define LN_generationQualifier "generationQualifier" +#define NID_generationQualifier 509 +#define OBJ_generationQualifier OBJ_X509,44L + +#define LN_x500UniqueIdentifier "x500UniqueIdentifier" +#define NID_x500UniqueIdentifier 503 +#define OBJ_x500UniqueIdentifier OBJ_X509,45L + +#define SN_dnQualifier "dnQualifier" +#define LN_dnQualifier "dnQualifier" +#define NID_dnQualifier 174 +#define OBJ_dnQualifier OBJ_X509,46L + +#define LN_enhancedSearchGuide "enhancedSearchGuide" +#define NID_enhancedSearchGuide 885 +#define OBJ_enhancedSearchGuide OBJ_X509,47L + +#define LN_protocolInformation "protocolInformation" +#define NID_protocolInformation 886 +#define OBJ_protocolInformation OBJ_X509,48L + +#define LN_distinguishedName "distinguishedName" +#define NID_distinguishedName 887 +#define OBJ_distinguishedName OBJ_X509,49L + +#define LN_uniqueMember "uniqueMember" +#define NID_uniqueMember 888 +#define OBJ_uniqueMember OBJ_X509,50L + +#define LN_houseIdentifier "houseIdentifier" +#define NID_houseIdentifier 889 +#define OBJ_houseIdentifier OBJ_X509,51L + +#define LN_supportedAlgorithms "supportedAlgorithms" +#define NID_supportedAlgorithms 890 +#define OBJ_supportedAlgorithms OBJ_X509,52L + +#define LN_deltaRevocationList "deltaRevocationList" +#define NID_deltaRevocationList 891 +#define OBJ_deltaRevocationList OBJ_X509,53L + +#define SN_dmdName "dmdName" +#define NID_dmdName 892 +#define OBJ_dmdName OBJ_X509,54L + +#define LN_pseudonym "pseudonym" +#define NID_pseudonym 510 +#define OBJ_pseudonym OBJ_X509,65L + +#define SN_role "role" +#define LN_role "role" +#define NID_role 400 +#define OBJ_role OBJ_X509,72L + +#define SN_X500algorithms "X500algorithms" +#define LN_X500algorithms "directory services - algorithms" +#define NID_X500algorithms 378 +#define OBJ_X500algorithms OBJ_X500,8L + +#define SN_rsa "RSA" +#define LN_rsa "rsa" +#define NID_rsa 19 +#define OBJ_rsa OBJ_X500algorithms,1L,1L + +#define SN_mdc2WithRSA "RSA-MDC2" +#define LN_mdc2WithRSA "mdc2WithRSA" +#define NID_mdc2WithRSA 96 +#define OBJ_mdc2WithRSA OBJ_X500algorithms,3L,100L + +#define SN_mdc2 "MDC2" +#define LN_mdc2 "mdc2" +#define NID_mdc2 95 +#define OBJ_mdc2 OBJ_X500algorithms,3L,101L + +#define SN_id_ce "id-ce" +#define NID_id_ce 81 +#define OBJ_id_ce OBJ_X500,29L + +#define SN_subject_directory_attributes "subjectDirectoryAttributes" +#define LN_subject_directory_attributes "X509v3 Subject Directory Attributes" +#define NID_subject_directory_attributes 769 +#define OBJ_subject_directory_attributes OBJ_id_ce,9L + +#define SN_subject_key_identifier "subjectKeyIdentifier" +#define LN_subject_key_identifier "X509v3 Subject Key Identifier" +#define NID_subject_key_identifier 82 +#define OBJ_subject_key_identifier OBJ_id_ce,14L + +#define SN_key_usage "keyUsage" +#define LN_key_usage "X509v3 Key Usage" +#define NID_key_usage 83 +#define OBJ_key_usage OBJ_id_ce,15L + +#define SN_private_key_usage_period "privateKeyUsagePeriod" +#define LN_private_key_usage_period "X509v3 Private Key Usage Period" +#define NID_private_key_usage_period 84 +#define OBJ_private_key_usage_period OBJ_id_ce,16L + +#define SN_subject_alt_name "subjectAltName" +#define LN_subject_alt_name "X509v3 Subject Alternative Name" +#define NID_subject_alt_name 85 +#define OBJ_subject_alt_name OBJ_id_ce,17L + +#define SN_issuer_alt_name "issuerAltName" +#define LN_issuer_alt_name "X509v3 Issuer Alternative Name" +#define NID_issuer_alt_name 86 +#define OBJ_issuer_alt_name OBJ_id_ce,18L + +#define SN_basic_constraints "basicConstraints" +#define LN_basic_constraints "X509v3 Basic Constraints" +#define NID_basic_constraints 87 +#define OBJ_basic_constraints OBJ_id_ce,19L + +#define SN_crl_number "crlNumber" +#define LN_crl_number "X509v3 CRL Number" +#define NID_crl_number 88 +#define OBJ_crl_number OBJ_id_ce,20L + +#define SN_crl_reason "CRLReason" +#define LN_crl_reason "X509v3 CRL Reason Code" +#define NID_crl_reason 141 +#define OBJ_crl_reason OBJ_id_ce,21L + +#define SN_invalidity_date "invalidityDate" +#define LN_invalidity_date "Invalidity Date" +#define NID_invalidity_date 142 +#define OBJ_invalidity_date OBJ_id_ce,24L + +#define SN_delta_crl "deltaCRL" +#define LN_delta_crl "X509v3 Delta CRL Indicator" +#define NID_delta_crl 140 +#define OBJ_delta_crl OBJ_id_ce,27L + +#define SN_issuing_distribution_point "issuingDistributionPoint" +#define LN_issuing_distribution_point "X509v3 Issuing Distribution Point" +#define NID_issuing_distribution_point 770 +#define OBJ_issuing_distribution_point OBJ_id_ce,28L + +#define SN_certificate_issuer "certificateIssuer" +#define LN_certificate_issuer "X509v3 Certificate Issuer" +#define NID_certificate_issuer 771 +#define OBJ_certificate_issuer OBJ_id_ce,29L + +#define SN_name_constraints "nameConstraints" +#define LN_name_constraints "X509v3 Name Constraints" +#define NID_name_constraints 666 +#define OBJ_name_constraints OBJ_id_ce,30L + +#define SN_crl_distribution_points "crlDistributionPoints" +#define LN_crl_distribution_points "X509v3 CRL Distribution Points" +#define NID_crl_distribution_points 103 +#define OBJ_crl_distribution_points OBJ_id_ce,31L + +#define SN_certificate_policies "certificatePolicies" +#define LN_certificate_policies "X509v3 Certificate Policies" +#define NID_certificate_policies 89 +#define OBJ_certificate_policies OBJ_id_ce,32L + +#define SN_any_policy "anyPolicy" +#define LN_any_policy "X509v3 Any Policy" +#define NID_any_policy 746 +#define OBJ_any_policy OBJ_certificate_policies,0L + +#define SN_policy_mappings "policyMappings" +#define LN_policy_mappings "X509v3 Policy Mappings" +#define NID_policy_mappings 747 +#define OBJ_policy_mappings OBJ_id_ce,33L + +#define SN_authority_key_identifier "authorityKeyIdentifier" +#define LN_authority_key_identifier "X509v3 Authority Key Identifier" +#define NID_authority_key_identifier 90 +#define OBJ_authority_key_identifier OBJ_id_ce,35L + +#define SN_policy_constraints "policyConstraints" +#define LN_policy_constraints "X509v3 Policy Constraints" +#define NID_policy_constraints 401 +#define OBJ_policy_constraints OBJ_id_ce,36L + +#define SN_ext_key_usage "extendedKeyUsage" +#define LN_ext_key_usage "X509v3 Extended Key Usage" +#define NID_ext_key_usage 126 +#define OBJ_ext_key_usage OBJ_id_ce,37L + +#define SN_freshest_crl "freshestCRL" +#define LN_freshest_crl "X509v3 Freshest CRL" +#define NID_freshest_crl 857 +#define OBJ_freshest_crl OBJ_id_ce,46L + +#define SN_inhibit_any_policy "inhibitAnyPolicy" +#define LN_inhibit_any_policy "X509v3 Inhibit Any Policy" +#define NID_inhibit_any_policy 748 +#define OBJ_inhibit_any_policy OBJ_id_ce,54L + +#define SN_target_information "targetInformation" +#define LN_target_information "X509v3 AC Targeting" +#define NID_target_information 402 +#define OBJ_target_information OBJ_id_ce,55L + +#define SN_no_rev_avail "noRevAvail" +#define LN_no_rev_avail "X509v3 No Revocation Available" +#define NID_no_rev_avail 403 +#define OBJ_no_rev_avail OBJ_id_ce,56L + +#define SN_anyExtendedKeyUsage "anyExtendedKeyUsage" +#define LN_anyExtendedKeyUsage "Any Extended Key Usage" +#define NID_anyExtendedKeyUsage 910 +#define OBJ_anyExtendedKeyUsage OBJ_ext_key_usage,0L + +#define SN_netscape "Netscape" +#define LN_netscape "Netscape Communications Corp." +#define NID_netscape 57 +#define OBJ_netscape 2L,16L,840L,1L,113730L + +#define SN_netscape_cert_extension "nsCertExt" +#define LN_netscape_cert_extension "Netscape Certificate Extension" +#define NID_netscape_cert_extension 58 +#define OBJ_netscape_cert_extension OBJ_netscape,1L + +#define SN_netscape_data_type "nsDataType" +#define LN_netscape_data_type "Netscape Data Type" +#define NID_netscape_data_type 59 +#define OBJ_netscape_data_type OBJ_netscape,2L + +#define SN_netscape_cert_type "nsCertType" +#define LN_netscape_cert_type "Netscape Cert Type" +#define NID_netscape_cert_type 71 +#define OBJ_netscape_cert_type OBJ_netscape_cert_extension,1L + +#define SN_netscape_base_url "nsBaseUrl" +#define LN_netscape_base_url "Netscape Base Url" +#define NID_netscape_base_url 72 +#define OBJ_netscape_base_url OBJ_netscape_cert_extension,2L + +#define SN_netscape_revocation_url "nsRevocationUrl" +#define LN_netscape_revocation_url "Netscape Revocation Url" +#define NID_netscape_revocation_url 73 +#define OBJ_netscape_revocation_url OBJ_netscape_cert_extension,3L + +#define SN_netscape_ca_revocation_url "nsCaRevocationUrl" +#define LN_netscape_ca_revocation_url "Netscape CA Revocation Url" +#define NID_netscape_ca_revocation_url 74 +#define OBJ_netscape_ca_revocation_url OBJ_netscape_cert_extension,4L + +#define SN_netscape_renewal_url "nsRenewalUrl" +#define LN_netscape_renewal_url "Netscape Renewal Url" +#define NID_netscape_renewal_url 75 +#define OBJ_netscape_renewal_url OBJ_netscape_cert_extension,7L + +#define SN_netscape_ca_policy_url "nsCaPolicyUrl" +#define LN_netscape_ca_policy_url "Netscape CA Policy Url" +#define NID_netscape_ca_policy_url 76 +#define OBJ_netscape_ca_policy_url OBJ_netscape_cert_extension,8L + +#define SN_netscape_ssl_server_name "nsSslServerName" +#define LN_netscape_ssl_server_name "Netscape SSL Server Name" +#define NID_netscape_ssl_server_name 77 +#define OBJ_netscape_ssl_server_name OBJ_netscape_cert_extension,12L + +#define SN_netscape_comment "nsComment" +#define LN_netscape_comment "Netscape Comment" +#define NID_netscape_comment 78 +#define OBJ_netscape_comment OBJ_netscape_cert_extension,13L + +#define SN_netscape_cert_sequence "nsCertSequence" +#define LN_netscape_cert_sequence "Netscape Certificate Sequence" +#define NID_netscape_cert_sequence 79 +#define OBJ_netscape_cert_sequence OBJ_netscape_data_type,5L + +#define SN_ns_sgc "nsSGC" +#define LN_ns_sgc "Netscape Server Gated Crypto" +#define NID_ns_sgc 139 +#define OBJ_ns_sgc OBJ_netscape,4L,1L + +#define SN_org "ORG" +#define LN_org "org" +#define NID_org 379 +#define OBJ_org OBJ_iso,3L + +#define SN_dod "DOD" +#define LN_dod "dod" +#define NID_dod 380 +#define OBJ_dod OBJ_org,6L + +#define SN_iana "IANA" +#define LN_iana "iana" +#define NID_iana 381 +#define OBJ_iana OBJ_dod,1L + +#define OBJ_internet OBJ_iana + +#define SN_Directory "directory" +#define LN_Directory "Directory" +#define NID_Directory 382 +#define OBJ_Directory OBJ_internet,1L + +#define SN_Management "mgmt" +#define LN_Management "Management" +#define NID_Management 383 +#define OBJ_Management OBJ_internet,2L + +#define SN_Experimental "experimental" +#define LN_Experimental "Experimental" +#define NID_Experimental 384 +#define OBJ_Experimental OBJ_internet,3L + +#define SN_Private "private" +#define LN_Private "Private" +#define NID_Private 385 +#define OBJ_Private OBJ_internet,4L + +#define SN_Security "security" +#define LN_Security "Security" +#define NID_Security 386 +#define OBJ_Security OBJ_internet,5L + +#define SN_SNMPv2 "snmpv2" +#define LN_SNMPv2 "SNMPv2" +#define NID_SNMPv2 387 +#define OBJ_SNMPv2 OBJ_internet,6L + +#define LN_Mail "Mail" +#define NID_Mail 388 +#define OBJ_Mail OBJ_internet,7L + +#define SN_Enterprises "enterprises" +#define LN_Enterprises "Enterprises" +#define NID_Enterprises 389 +#define OBJ_Enterprises OBJ_Private,1L + +#define SN_dcObject "dcobject" +#define LN_dcObject "dcObject" +#define NID_dcObject 390 +#define OBJ_dcObject OBJ_Enterprises,1466L,344L + +#define SN_mime_mhs "mime-mhs" +#define LN_mime_mhs "MIME MHS" +#define NID_mime_mhs 504 +#define OBJ_mime_mhs OBJ_Mail,1L + +#define SN_mime_mhs_headings "mime-mhs-headings" +#define LN_mime_mhs_headings "mime-mhs-headings" +#define NID_mime_mhs_headings 505 +#define OBJ_mime_mhs_headings OBJ_mime_mhs,1L + +#define SN_mime_mhs_bodies "mime-mhs-bodies" +#define LN_mime_mhs_bodies "mime-mhs-bodies" +#define NID_mime_mhs_bodies 506 +#define OBJ_mime_mhs_bodies OBJ_mime_mhs,2L + +#define SN_id_hex_partial_message "id-hex-partial-message" +#define LN_id_hex_partial_message "id-hex-partial-message" +#define NID_id_hex_partial_message 507 +#define OBJ_id_hex_partial_message OBJ_mime_mhs_headings,1L + +#define SN_id_hex_multipart_message "id-hex-multipart-message" +#define LN_id_hex_multipart_message "id-hex-multipart-message" +#define NID_id_hex_multipart_message 508 +#define OBJ_id_hex_multipart_message OBJ_mime_mhs_headings,2L + +#define SN_zlib_compression "ZLIB" +#define LN_zlib_compression "zlib compression" +#define NID_zlib_compression 125 +#define OBJ_zlib_compression OBJ_id_smime_alg,8L + +#define OBJ_csor 2L,16L,840L,1L,101L,3L + +#define OBJ_nistAlgorithms OBJ_csor,4L + +#define OBJ_aes OBJ_nistAlgorithms,1L + +#define SN_aes_128_ecb "AES-128-ECB" +#define LN_aes_128_ecb "aes-128-ecb" +#define NID_aes_128_ecb 418 +#define OBJ_aes_128_ecb OBJ_aes,1L + +#define SN_aes_128_cbc "AES-128-CBC" +#define LN_aes_128_cbc "aes-128-cbc" +#define NID_aes_128_cbc 419 +#define OBJ_aes_128_cbc OBJ_aes,2L + +#define SN_aes_128_ofb128 "AES-128-OFB" +#define LN_aes_128_ofb128 "aes-128-ofb" +#define NID_aes_128_ofb128 420 +#define OBJ_aes_128_ofb128 OBJ_aes,3L + +#define SN_aes_128_cfb128 "AES-128-CFB" +#define LN_aes_128_cfb128 "aes-128-cfb" +#define NID_aes_128_cfb128 421 +#define OBJ_aes_128_cfb128 OBJ_aes,4L + +#define SN_id_aes128_wrap "id-aes128-wrap" +#define NID_id_aes128_wrap 788 +#define OBJ_id_aes128_wrap OBJ_aes,5L + +#define SN_aes_128_gcm "id-aes128-GCM" +#define LN_aes_128_gcm "aes-128-gcm" +#define NID_aes_128_gcm 895 +#define OBJ_aes_128_gcm OBJ_aes,6L + +#define SN_aes_128_ccm "id-aes128-CCM" +#define LN_aes_128_ccm "aes-128-ccm" +#define NID_aes_128_ccm 896 +#define OBJ_aes_128_ccm OBJ_aes,7L + +#define SN_id_aes128_wrap_pad "id-aes128-wrap-pad" +#define NID_id_aes128_wrap_pad 897 +#define OBJ_id_aes128_wrap_pad OBJ_aes,8L + +#define SN_aes_192_ecb "AES-192-ECB" +#define LN_aes_192_ecb "aes-192-ecb" +#define NID_aes_192_ecb 422 +#define OBJ_aes_192_ecb OBJ_aes,21L + +#define SN_aes_192_cbc "AES-192-CBC" +#define LN_aes_192_cbc "aes-192-cbc" +#define NID_aes_192_cbc 423 +#define OBJ_aes_192_cbc OBJ_aes,22L + +#define SN_aes_192_ofb128 "AES-192-OFB" +#define LN_aes_192_ofb128 "aes-192-ofb" +#define NID_aes_192_ofb128 424 +#define OBJ_aes_192_ofb128 OBJ_aes,23L + +#define SN_aes_192_cfb128 "AES-192-CFB" +#define LN_aes_192_cfb128 "aes-192-cfb" +#define NID_aes_192_cfb128 425 +#define OBJ_aes_192_cfb128 OBJ_aes,24L + +#define SN_id_aes192_wrap "id-aes192-wrap" +#define NID_id_aes192_wrap 789 +#define OBJ_id_aes192_wrap OBJ_aes,25L + +#define SN_aes_192_gcm "id-aes192-GCM" +#define LN_aes_192_gcm "aes-192-gcm" +#define NID_aes_192_gcm 898 +#define OBJ_aes_192_gcm OBJ_aes,26L + +#define SN_aes_192_ccm "id-aes192-CCM" +#define LN_aes_192_ccm "aes-192-ccm" +#define NID_aes_192_ccm 899 +#define OBJ_aes_192_ccm OBJ_aes,27L + +#define SN_id_aes192_wrap_pad "id-aes192-wrap-pad" +#define NID_id_aes192_wrap_pad 900 +#define OBJ_id_aes192_wrap_pad OBJ_aes,28L + +#define SN_aes_256_ecb "AES-256-ECB" +#define LN_aes_256_ecb "aes-256-ecb" +#define NID_aes_256_ecb 426 +#define OBJ_aes_256_ecb OBJ_aes,41L + +#define SN_aes_256_cbc "AES-256-CBC" +#define LN_aes_256_cbc "aes-256-cbc" +#define NID_aes_256_cbc 427 +#define OBJ_aes_256_cbc OBJ_aes,42L + +#define SN_aes_256_ofb128 "AES-256-OFB" +#define LN_aes_256_ofb128 "aes-256-ofb" +#define NID_aes_256_ofb128 428 +#define OBJ_aes_256_ofb128 OBJ_aes,43L + +#define SN_aes_256_cfb128 "AES-256-CFB" +#define LN_aes_256_cfb128 "aes-256-cfb" +#define NID_aes_256_cfb128 429 +#define OBJ_aes_256_cfb128 OBJ_aes,44L + +#define SN_id_aes256_wrap "id-aes256-wrap" +#define NID_id_aes256_wrap 790 +#define OBJ_id_aes256_wrap OBJ_aes,45L + +#define SN_aes_256_gcm "id-aes256-GCM" +#define LN_aes_256_gcm "aes-256-gcm" +#define NID_aes_256_gcm 901 +#define OBJ_aes_256_gcm OBJ_aes,46L + +#define SN_aes_256_ccm "id-aes256-CCM" +#define LN_aes_256_ccm "aes-256-ccm" +#define NID_aes_256_ccm 902 +#define OBJ_aes_256_ccm OBJ_aes,47L + +#define SN_id_aes256_wrap_pad "id-aes256-wrap-pad" +#define NID_id_aes256_wrap_pad 903 +#define OBJ_id_aes256_wrap_pad OBJ_aes,48L + +#define SN_aes_128_cfb1 "AES-128-CFB1" +#define LN_aes_128_cfb1 "aes-128-cfb1" +#define NID_aes_128_cfb1 650 + +#define SN_aes_192_cfb1 "AES-192-CFB1" +#define LN_aes_192_cfb1 "aes-192-cfb1" +#define NID_aes_192_cfb1 651 + +#define SN_aes_256_cfb1 "AES-256-CFB1" +#define LN_aes_256_cfb1 "aes-256-cfb1" +#define NID_aes_256_cfb1 652 + +#define SN_aes_128_cfb8 "AES-128-CFB8" +#define LN_aes_128_cfb8 "aes-128-cfb8" +#define NID_aes_128_cfb8 653 + +#define SN_aes_192_cfb8 "AES-192-CFB8" +#define LN_aes_192_cfb8 "aes-192-cfb8" +#define NID_aes_192_cfb8 654 + +#define SN_aes_256_cfb8 "AES-256-CFB8" +#define LN_aes_256_cfb8 "aes-256-cfb8" +#define NID_aes_256_cfb8 655 + +#define SN_aes_128_ctr "AES-128-CTR" +#define LN_aes_128_ctr "aes-128-ctr" +#define NID_aes_128_ctr 904 + +#define SN_aes_192_ctr "AES-192-CTR" +#define LN_aes_192_ctr "aes-192-ctr" +#define NID_aes_192_ctr 905 + +#define SN_aes_256_ctr "AES-256-CTR" +#define LN_aes_256_ctr "aes-256-ctr" +#define NID_aes_256_ctr 906 + +#define SN_aes_128_xts "AES-128-XTS" +#define LN_aes_128_xts "aes-128-xts" +#define NID_aes_128_xts 913 + +#define SN_aes_256_xts "AES-256-XTS" +#define LN_aes_256_xts "aes-256-xts" +#define NID_aes_256_xts 914 + +#define SN_des_cfb1 "DES-CFB1" +#define LN_des_cfb1 "des-cfb1" +#define NID_des_cfb1 656 + +#define SN_des_cfb8 "DES-CFB8" +#define LN_des_cfb8 "des-cfb8" +#define NID_des_cfb8 657 + +#define SN_des_ede3_cfb1 "DES-EDE3-CFB1" +#define LN_des_ede3_cfb1 "des-ede3-cfb1" +#define NID_des_ede3_cfb1 658 + +#define SN_des_ede3_cfb8 "DES-EDE3-CFB8" +#define LN_des_ede3_cfb8 "des-ede3-cfb8" +#define NID_des_ede3_cfb8 659 + +#define OBJ_nist_hashalgs OBJ_nistAlgorithms,2L + +#define SN_sha256 "SHA256" +#define LN_sha256 "sha256" +#define NID_sha256 672 +#define OBJ_sha256 OBJ_nist_hashalgs,1L + +#define SN_sha384 "SHA384" +#define LN_sha384 "sha384" +#define NID_sha384 673 +#define OBJ_sha384 OBJ_nist_hashalgs,2L + +#define SN_sha512 "SHA512" +#define LN_sha512 "sha512" +#define NID_sha512 674 +#define OBJ_sha512 OBJ_nist_hashalgs,3L + +#define SN_sha224 "SHA224" +#define LN_sha224 "sha224" +#define NID_sha224 675 +#define OBJ_sha224 OBJ_nist_hashalgs,4L + +#define OBJ_dsa_with_sha2 OBJ_nistAlgorithms,3L + +#define SN_dsa_with_SHA224 "dsa_with_SHA224" +#define NID_dsa_with_SHA224 802 +#define OBJ_dsa_with_SHA224 OBJ_dsa_with_sha2,1L + +#define SN_dsa_with_SHA256 "dsa_with_SHA256" +#define NID_dsa_with_SHA256 803 +#define OBJ_dsa_with_SHA256 OBJ_dsa_with_sha2,2L + +#define SN_hold_instruction_code "holdInstructionCode" +#define LN_hold_instruction_code "Hold Instruction Code" +#define NID_hold_instruction_code 430 +#define OBJ_hold_instruction_code OBJ_id_ce,23L + +#define OBJ_holdInstruction OBJ_X9_57,2L + +#define SN_hold_instruction_none "holdInstructionNone" +#define LN_hold_instruction_none "Hold Instruction None" +#define NID_hold_instruction_none 431 +#define OBJ_hold_instruction_none OBJ_holdInstruction,1L + +#define SN_hold_instruction_call_issuer "holdInstructionCallIssuer" +#define LN_hold_instruction_call_issuer "Hold Instruction Call Issuer" +#define NID_hold_instruction_call_issuer 432 +#define OBJ_hold_instruction_call_issuer OBJ_holdInstruction,2L + +#define SN_hold_instruction_reject "holdInstructionReject" +#define LN_hold_instruction_reject "Hold Instruction Reject" +#define NID_hold_instruction_reject 433 +#define OBJ_hold_instruction_reject OBJ_holdInstruction,3L + +#define SN_data "data" +#define NID_data 434 +#define OBJ_data OBJ_itu_t,9L + +#define SN_pss "pss" +#define NID_pss 435 +#define OBJ_pss OBJ_data,2342L + +#define SN_ucl "ucl" +#define NID_ucl 436 +#define OBJ_ucl OBJ_pss,19200300L + +#define SN_pilot "pilot" +#define NID_pilot 437 +#define OBJ_pilot OBJ_ucl,100L + +#define LN_pilotAttributeType "pilotAttributeType" +#define NID_pilotAttributeType 438 +#define OBJ_pilotAttributeType OBJ_pilot,1L + +#define LN_pilotAttributeSyntax "pilotAttributeSyntax" +#define NID_pilotAttributeSyntax 439 +#define OBJ_pilotAttributeSyntax OBJ_pilot,3L + +#define LN_pilotObjectClass "pilotObjectClass" +#define NID_pilotObjectClass 440 +#define OBJ_pilotObjectClass OBJ_pilot,4L + +#define LN_pilotGroups "pilotGroups" +#define NID_pilotGroups 441 +#define OBJ_pilotGroups OBJ_pilot,10L + +#define LN_iA5StringSyntax "iA5StringSyntax" +#define NID_iA5StringSyntax 442 +#define OBJ_iA5StringSyntax OBJ_pilotAttributeSyntax,4L + +#define LN_caseIgnoreIA5StringSyntax "caseIgnoreIA5StringSyntax" +#define NID_caseIgnoreIA5StringSyntax 443 +#define OBJ_caseIgnoreIA5StringSyntax OBJ_pilotAttributeSyntax,5L + +#define LN_pilotObject "pilotObject" +#define NID_pilotObject 444 +#define OBJ_pilotObject OBJ_pilotObjectClass,3L + +#define LN_pilotPerson "pilotPerson" +#define NID_pilotPerson 445 +#define OBJ_pilotPerson OBJ_pilotObjectClass,4L + +#define SN_account "account" +#define NID_account 446 +#define OBJ_account OBJ_pilotObjectClass,5L + +#define SN_document "document" +#define NID_document 447 +#define OBJ_document OBJ_pilotObjectClass,6L + +#define SN_room "room" +#define NID_room 448 +#define OBJ_room OBJ_pilotObjectClass,7L + +#define LN_documentSeries "documentSeries" +#define NID_documentSeries 449 +#define OBJ_documentSeries OBJ_pilotObjectClass,9L + +#define SN_Domain "domain" +#define LN_Domain "Domain" +#define NID_Domain 392 +#define OBJ_Domain OBJ_pilotObjectClass,13L + +#define LN_rFC822localPart "rFC822localPart" +#define NID_rFC822localPart 450 +#define OBJ_rFC822localPart OBJ_pilotObjectClass,14L + +#define LN_dNSDomain "dNSDomain" +#define NID_dNSDomain 451 +#define OBJ_dNSDomain OBJ_pilotObjectClass,15L + +#define LN_domainRelatedObject "domainRelatedObject" +#define NID_domainRelatedObject 452 +#define OBJ_domainRelatedObject OBJ_pilotObjectClass,17L + +#define LN_friendlyCountry "friendlyCountry" +#define NID_friendlyCountry 453 +#define OBJ_friendlyCountry OBJ_pilotObjectClass,18L + +#define LN_simpleSecurityObject "simpleSecurityObject" +#define NID_simpleSecurityObject 454 +#define OBJ_simpleSecurityObject OBJ_pilotObjectClass,19L + +#define LN_pilotOrganization "pilotOrganization" +#define NID_pilotOrganization 455 +#define OBJ_pilotOrganization OBJ_pilotObjectClass,20L + +#define LN_pilotDSA "pilotDSA" +#define NID_pilotDSA 456 +#define OBJ_pilotDSA OBJ_pilotObjectClass,21L + +#define LN_qualityLabelledData "qualityLabelledData" +#define NID_qualityLabelledData 457 +#define OBJ_qualityLabelledData OBJ_pilotObjectClass,22L + +#define SN_userId "UID" +#define LN_userId "userId" +#define NID_userId 458 +#define OBJ_userId OBJ_pilotAttributeType,1L + +#define LN_textEncodedORAddress "textEncodedORAddress" +#define NID_textEncodedORAddress 459 +#define OBJ_textEncodedORAddress OBJ_pilotAttributeType,2L + +#define SN_rfc822Mailbox "mail" +#define LN_rfc822Mailbox "rfc822Mailbox" +#define NID_rfc822Mailbox 460 +#define OBJ_rfc822Mailbox OBJ_pilotAttributeType,3L + +#define SN_info "info" +#define NID_info 461 +#define OBJ_info OBJ_pilotAttributeType,4L + +#define LN_favouriteDrink "favouriteDrink" +#define NID_favouriteDrink 462 +#define OBJ_favouriteDrink OBJ_pilotAttributeType,5L + +#define LN_roomNumber "roomNumber" +#define NID_roomNumber 463 +#define OBJ_roomNumber OBJ_pilotAttributeType,6L + +#define SN_photo "photo" +#define NID_photo 464 +#define OBJ_photo OBJ_pilotAttributeType,7L + +#define LN_userClass "userClass" +#define NID_userClass 465 +#define OBJ_userClass OBJ_pilotAttributeType,8L + +#define SN_host "host" +#define NID_host 466 +#define OBJ_host OBJ_pilotAttributeType,9L + +#define SN_manager "manager" +#define NID_manager 467 +#define OBJ_manager OBJ_pilotAttributeType,10L + +#define LN_documentIdentifier "documentIdentifier" +#define NID_documentIdentifier 468 +#define OBJ_documentIdentifier OBJ_pilotAttributeType,11L + +#define LN_documentTitle "documentTitle" +#define NID_documentTitle 469 +#define OBJ_documentTitle OBJ_pilotAttributeType,12L + +#define LN_documentVersion "documentVersion" +#define NID_documentVersion 470 +#define OBJ_documentVersion OBJ_pilotAttributeType,13L + +#define LN_documentAuthor "documentAuthor" +#define NID_documentAuthor 471 +#define OBJ_documentAuthor OBJ_pilotAttributeType,14L + +#define LN_documentLocation "documentLocation" +#define NID_documentLocation 472 +#define OBJ_documentLocation OBJ_pilotAttributeType,15L + +#define LN_homeTelephoneNumber "homeTelephoneNumber" +#define NID_homeTelephoneNumber 473 +#define OBJ_homeTelephoneNumber OBJ_pilotAttributeType,20L + +#define SN_secretary "secretary" +#define NID_secretary 474 +#define OBJ_secretary OBJ_pilotAttributeType,21L + +#define LN_otherMailbox "otherMailbox" +#define NID_otherMailbox 475 +#define OBJ_otherMailbox OBJ_pilotAttributeType,22L + +#define LN_lastModifiedTime "lastModifiedTime" +#define NID_lastModifiedTime 476 +#define OBJ_lastModifiedTime OBJ_pilotAttributeType,23L + +#define LN_lastModifiedBy "lastModifiedBy" +#define NID_lastModifiedBy 477 +#define OBJ_lastModifiedBy OBJ_pilotAttributeType,24L + +#define SN_domainComponent "DC" +#define LN_domainComponent "domainComponent" +#define NID_domainComponent 391 +#define OBJ_domainComponent OBJ_pilotAttributeType,25L + +#define LN_aRecord "aRecord" +#define NID_aRecord 478 +#define OBJ_aRecord OBJ_pilotAttributeType,26L + +#define LN_pilotAttributeType27 "pilotAttributeType27" +#define NID_pilotAttributeType27 479 +#define OBJ_pilotAttributeType27 OBJ_pilotAttributeType,27L + +#define LN_mXRecord "mXRecord" +#define NID_mXRecord 480 +#define OBJ_mXRecord OBJ_pilotAttributeType,28L + +#define LN_nSRecord "nSRecord" +#define NID_nSRecord 481 +#define OBJ_nSRecord OBJ_pilotAttributeType,29L + +#define LN_sOARecord "sOARecord" +#define NID_sOARecord 482 +#define OBJ_sOARecord OBJ_pilotAttributeType,30L + +#define LN_cNAMERecord "cNAMERecord" +#define NID_cNAMERecord 483 +#define OBJ_cNAMERecord OBJ_pilotAttributeType,31L + +#define LN_associatedDomain "associatedDomain" +#define NID_associatedDomain 484 +#define OBJ_associatedDomain OBJ_pilotAttributeType,37L + +#define LN_associatedName "associatedName" +#define NID_associatedName 485 +#define OBJ_associatedName OBJ_pilotAttributeType,38L + +#define LN_homePostalAddress "homePostalAddress" +#define NID_homePostalAddress 486 +#define OBJ_homePostalAddress OBJ_pilotAttributeType,39L + +#define LN_personalTitle "personalTitle" +#define NID_personalTitle 487 +#define OBJ_personalTitle OBJ_pilotAttributeType,40L + +#define LN_mobileTelephoneNumber "mobileTelephoneNumber" +#define NID_mobileTelephoneNumber 488 +#define OBJ_mobileTelephoneNumber OBJ_pilotAttributeType,41L + +#define LN_pagerTelephoneNumber "pagerTelephoneNumber" +#define NID_pagerTelephoneNumber 489 +#define OBJ_pagerTelephoneNumber OBJ_pilotAttributeType,42L + +#define LN_friendlyCountryName "friendlyCountryName" +#define NID_friendlyCountryName 490 +#define OBJ_friendlyCountryName OBJ_pilotAttributeType,43L + +#define LN_organizationalStatus "organizationalStatus" +#define NID_organizationalStatus 491 +#define OBJ_organizationalStatus OBJ_pilotAttributeType,45L + +#define LN_janetMailbox "janetMailbox" +#define NID_janetMailbox 492 +#define OBJ_janetMailbox OBJ_pilotAttributeType,46L + +#define LN_mailPreferenceOption "mailPreferenceOption" +#define NID_mailPreferenceOption 493 +#define OBJ_mailPreferenceOption OBJ_pilotAttributeType,47L + +#define LN_buildingName "buildingName" +#define NID_buildingName 494 +#define OBJ_buildingName OBJ_pilotAttributeType,48L + +#define LN_dSAQuality "dSAQuality" +#define NID_dSAQuality 495 +#define OBJ_dSAQuality OBJ_pilotAttributeType,49L + +#define LN_singleLevelQuality "singleLevelQuality" +#define NID_singleLevelQuality 496 +#define OBJ_singleLevelQuality OBJ_pilotAttributeType,50L + +#define LN_subtreeMinimumQuality "subtreeMinimumQuality" +#define NID_subtreeMinimumQuality 497 +#define OBJ_subtreeMinimumQuality OBJ_pilotAttributeType,51L + +#define LN_subtreeMaximumQuality "subtreeMaximumQuality" +#define NID_subtreeMaximumQuality 498 +#define OBJ_subtreeMaximumQuality OBJ_pilotAttributeType,52L + +#define LN_personalSignature "personalSignature" +#define NID_personalSignature 499 +#define OBJ_personalSignature OBJ_pilotAttributeType,53L + +#define LN_dITRedirect "dITRedirect" +#define NID_dITRedirect 500 +#define OBJ_dITRedirect OBJ_pilotAttributeType,54L + +#define SN_audio "audio" +#define NID_audio 501 +#define OBJ_audio OBJ_pilotAttributeType,55L + +#define LN_documentPublisher "documentPublisher" +#define NID_documentPublisher 502 +#define OBJ_documentPublisher OBJ_pilotAttributeType,56L + +#define SN_id_set "id-set" +#define LN_id_set "Secure Electronic Transactions" +#define NID_id_set 512 +#define OBJ_id_set OBJ_international_organizations,42L + +#define SN_set_ctype "set-ctype" +#define LN_set_ctype "content types" +#define NID_set_ctype 513 +#define OBJ_set_ctype OBJ_id_set,0L + +#define SN_set_msgExt "set-msgExt" +#define LN_set_msgExt "message extensions" +#define NID_set_msgExt 514 +#define OBJ_set_msgExt OBJ_id_set,1L + +#define SN_set_attr "set-attr" +#define NID_set_attr 515 +#define OBJ_set_attr OBJ_id_set,3L + +#define SN_set_policy "set-policy" +#define NID_set_policy 516 +#define OBJ_set_policy OBJ_id_set,5L + +#define SN_set_certExt "set-certExt" +#define LN_set_certExt "certificate extensions" +#define NID_set_certExt 517 +#define OBJ_set_certExt OBJ_id_set,7L + +#define SN_set_brand "set-brand" +#define NID_set_brand 518 +#define OBJ_set_brand OBJ_id_set,8L + +#define SN_setct_PANData "setct-PANData" +#define NID_setct_PANData 519 +#define OBJ_setct_PANData OBJ_set_ctype,0L + +#define SN_setct_PANToken "setct-PANToken" +#define NID_setct_PANToken 520 +#define OBJ_setct_PANToken OBJ_set_ctype,1L + +#define SN_setct_PANOnly "setct-PANOnly" +#define NID_setct_PANOnly 521 +#define OBJ_setct_PANOnly OBJ_set_ctype,2L + +#define SN_setct_OIData "setct-OIData" +#define NID_setct_OIData 522 +#define OBJ_setct_OIData OBJ_set_ctype,3L + +#define SN_setct_PI "setct-PI" +#define NID_setct_PI 523 +#define OBJ_setct_PI OBJ_set_ctype,4L + +#define SN_setct_PIData "setct-PIData" +#define NID_setct_PIData 524 +#define OBJ_setct_PIData OBJ_set_ctype,5L + +#define SN_setct_PIDataUnsigned "setct-PIDataUnsigned" +#define NID_setct_PIDataUnsigned 525 +#define OBJ_setct_PIDataUnsigned OBJ_set_ctype,6L + +#define SN_setct_HODInput "setct-HODInput" +#define NID_setct_HODInput 526 +#define OBJ_setct_HODInput OBJ_set_ctype,7L + +#define SN_setct_AuthResBaggage "setct-AuthResBaggage" +#define NID_setct_AuthResBaggage 527 +#define OBJ_setct_AuthResBaggage OBJ_set_ctype,8L + +#define SN_setct_AuthRevReqBaggage "setct-AuthRevReqBaggage" +#define NID_setct_AuthRevReqBaggage 528 +#define OBJ_setct_AuthRevReqBaggage OBJ_set_ctype,9L + +#define SN_setct_AuthRevResBaggage "setct-AuthRevResBaggage" +#define NID_setct_AuthRevResBaggage 529 +#define OBJ_setct_AuthRevResBaggage OBJ_set_ctype,10L + +#define SN_setct_CapTokenSeq "setct-CapTokenSeq" +#define NID_setct_CapTokenSeq 530 +#define OBJ_setct_CapTokenSeq OBJ_set_ctype,11L + +#define SN_setct_PInitResData "setct-PInitResData" +#define NID_setct_PInitResData 531 +#define OBJ_setct_PInitResData OBJ_set_ctype,12L + +#define SN_setct_PI_TBS "setct-PI-TBS" +#define NID_setct_PI_TBS 532 +#define OBJ_setct_PI_TBS OBJ_set_ctype,13L + +#define SN_setct_PResData "setct-PResData" +#define NID_setct_PResData 533 +#define OBJ_setct_PResData OBJ_set_ctype,14L + +#define SN_setct_AuthReqTBS "setct-AuthReqTBS" +#define NID_setct_AuthReqTBS 534 +#define OBJ_setct_AuthReqTBS OBJ_set_ctype,16L + +#define SN_setct_AuthResTBS "setct-AuthResTBS" +#define NID_setct_AuthResTBS 535 +#define OBJ_setct_AuthResTBS OBJ_set_ctype,17L + +#define SN_setct_AuthResTBSX "setct-AuthResTBSX" +#define NID_setct_AuthResTBSX 536 +#define OBJ_setct_AuthResTBSX OBJ_set_ctype,18L + +#define SN_setct_AuthTokenTBS "setct-AuthTokenTBS" +#define NID_setct_AuthTokenTBS 537 +#define OBJ_setct_AuthTokenTBS OBJ_set_ctype,19L + +#define SN_setct_CapTokenData "setct-CapTokenData" +#define NID_setct_CapTokenData 538 +#define OBJ_setct_CapTokenData OBJ_set_ctype,20L + +#define SN_setct_CapTokenTBS "setct-CapTokenTBS" +#define NID_setct_CapTokenTBS 539 +#define OBJ_setct_CapTokenTBS OBJ_set_ctype,21L + +#define SN_setct_AcqCardCodeMsg "setct-AcqCardCodeMsg" +#define NID_setct_AcqCardCodeMsg 540 +#define OBJ_setct_AcqCardCodeMsg OBJ_set_ctype,22L + +#define SN_setct_AuthRevReqTBS "setct-AuthRevReqTBS" +#define NID_setct_AuthRevReqTBS 541 +#define OBJ_setct_AuthRevReqTBS OBJ_set_ctype,23L + +#define SN_setct_AuthRevResData "setct-AuthRevResData" +#define NID_setct_AuthRevResData 542 +#define OBJ_setct_AuthRevResData OBJ_set_ctype,24L + +#define SN_setct_AuthRevResTBS "setct-AuthRevResTBS" +#define NID_setct_AuthRevResTBS 543 +#define OBJ_setct_AuthRevResTBS OBJ_set_ctype,25L + +#define SN_setct_CapReqTBS "setct-CapReqTBS" +#define NID_setct_CapReqTBS 544 +#define OBJ_setct_CapReqTBS OBJ_set_ctype,26L + +#define SN_setct_CapReqTBSX "setct-CapReqTBSX" +#define NID_setct_CapReqTBSX 545 +#define OBJ_setct_CapReqTBSX OBJ_set_ctype,27L + +#define SN_setct_CapResData "setct-CapResData" +#define NID_setct_CapResData 546 +#define OBJ_setct_CapResData OBJ_set_ctype,28L + +#define SN_setct_CapRevReqTBS "setct-CapRevReqTBS" +#define NID_setct_CapRevReqTBS 547 +#define OBJ_setct_CapRevReqTBS OBJ_set_ctype,29L + +#define SN_setct_CapRevReqTBSX "setct-CapRevReqTBSX" +#define NID_setct_CapRevReqTBSX 548 +#define OBJ_setct_CapRevReqTBSX OBJ_set_ctype,30L + +#define SN_setct_CapRevResData "setct-CapRevResData" +#define NID_setct_CapRevResData 549 +#define OBJ_setct_CapRevResData OBJ_set_ctype,31L + +#define SN_setct_CredReqTBS "setct-CredReqTBS" +#define NID_setct_CredReqTBS 550 +#define OBJ_setct_CredReqTBS OBJ_set_ctype,32L + +#define SN_setct_CredReqTBSX "setct-CredReqTBSX" +#define NID_setct_CredReqTBSX 551 +#define OBJ_setct_CredReqTBSX OBJ_set_ctype,33L + +#define SN_setct_CredResData "setct-CredResData" +#define NID_setct_CredResData 552 +#define OBJ_setct_CredResData OBJ_set_ctype,34L + +#define SN_setct_CredRevReqTBS "setct-CredRevReqTBS" +#define NID_setct_CredRevReqTBS 553 +#define OBJ_setct_CredRevReqTBS OBJ_set_ctype,35L + +#define SN_setct_CredRevReqTBSX "setct-CredRevReqTBSX" +#define NID_setct_CredRevReqTBSX 554 +#define OBJ_setct_CredRevReqTBSX OBJ_set_ctype,36L + +#define SN_setct_CredRevResData "setct-CredRevResData" +#define NID_setct_CredRevResData 555 +#define OBJ_setct_CredRevResData OBJ_set_ctype,37L + +#define SN_setct_PCertReqData "setct-PCertReqData" +#define NID_setct_PCertReqData 556 +#define OBJ_setct_PCertReqData OBJ_set_ctype,38L + +#define SN_setct_PCertResTBS "setct-PCertResTBS" +#define NID_setct_PCertResTBS 557 +#define OBJ_setct_PCertResTBS OBJ_set_ctype,39L + +#define SN_setct_BatchAdminReqData "setct-BatchAdminReqData" +#define NID_setct_BatchAdminReqData 558 +#define OBJ_setct_BatchAdminReqData OBJ_set_ctype,40L + +#define SN_setct_BatchAdminResData "setct-BatchAdminResData" +#define NID_setct_BatchAdminResData 559 +#define OBJ_setct_BatchAdminResData OBJ_set_ctype,41L + +#define SN_setct_CardCInitResTBS "setct-CardCInitResTBS" +#define NID_setct_CardCInitResTBS 560 +#define OBJ_setct_CardCInitResTBS OBJ_set_ctype,42L + +#define SN_setct_MeAqCInitResTBS "setct-MeAqCInitResTBS" +#define NID_setct_MeAqCInitResTBS 561 +#define OBJ_setct_MeAqCInitResTBS OBJ_set_ctype,43L + +#define SN_setct_RegFormResTBS "setct-RegFormResTBS" +#define NID_setct_RegFormResTBS 562 +#define OBJ_setct_RegFormResTBS OBJ_set_ctype,44L + +#define SN_setct_CertReqData "setct-CertReqData" +#define NID_setct_CertReqData 563 +#define OBJ_setct_CertReqData OBJ_set_ctype,45L + +#define SN_setct_CertReqTBS "setct-CertReqTBS" +#define NID_setct_CertReqTBS 564 +#define OBJ_setct_CertReqTBS OBJ_set_ctype,46L + +#define SN_setct_CertResData "setct-CertResData" +#define NID_setct_CertResData 565 +#define OBJ_setct_CertResData OBJ_set_ctype,47L + +#define SN_setct_CertInqReqTBS "setct-CertInqReqTBS" +#define NID_setct_CertInqReqTBS 566 +#define OBJ_setct_CertInqReqTBS OBJ_set_ctype,48L + +#define SN_setct_ErrorTBS "setct-ErrorTBS" +#define NID_setct_ErrorTBS 567 +#define OBJ_setct_ErrorTBS OBJ_set_ctype,49L + +#define SN_setct_PIDualSignedTBE "setct-PIDualSignedTBE" +#define NID_setct_PIDualSignedTBE 568 +#define OBJ_setct_PIDualSignedTBE OBJ_set_ctype,50L + +#define SN_setct_PIUnsignedTBE "setct-PIUnsignedTBE" +#define NID_setct_PIUnsignedTBE 569 +#define OBJ_setct_PIUnsignedTBE OBJ_set_ctype,51L + +#define SN_setct_AuthReqTBE "setct-AuthReqTBE" +#define NID_setct_AuthReqTBE 570 +#define OBJ_setct_AuthReqTBE OBJ_set_ctype,52L + +#define SN_setct_AuthResTBE "setct-AuthResTBE" +#define NID_setct_AuthResTBE 571 +#define OBJ_setct_AuthResTBE OBJ_set_ctype,53L + +#define SN_setct_AuthResTBEX "setct-AuthResTBEX" +#define NID_setct_AuthResTBEX 572 +#define OBJ_setct_AuthResTBEX OBJ_set_ctype,54L + +#define SN_setct_AuthTokenTBE "setct-AuthTokenTBE" +#define NID_setct_AuthTokenTBE 573 +#define OBJ_setct_AuthTokenTBE OBJ_set_ctype,55L + +#define SN_setct_CapTokenTBE "setct-CapTokenTBE" +#define NID_setct_CapTokenTBE 574 +#define OBJ_setct_CapTokenTBE OBJ_set_ctype,56L + +#define SN_setct_CapTokenTBEX "setct-CapTokenTBEX" +#define NID_setct_CapTokenTBEX 575 +#define OBJ_setct_CapTokenTBEX OBJ_set_ctype,57L + +#define SN_setct_AcqCardCodeMsgTBE "setct-AcqCardCodeMsgTBE" +#define NID_setct_AcqCardCodeMsgTBE 576 +#define OBJ_setct_AcqCardCodeMsgTBE OBJ_set_ctype,58L + +#define SN_setct_AuthRevReqTBE "setct-AuthRevReqTBE" +#define NID_setct_AuthRevReqTBE 577 +#define OBJ_setct_AuthRevReqTBE OBJ_set_ctype,59L + +#define SN_setct_AuthRevResTBE "setct-AuthRevResTBE" +#define NID_setct_AuthRevResTBE 578 +#define OBJ_setct_AuthRevResTBE OBJ_set_ctype,60L + +#define SN_setct_AuthRevResTBEB "setct-AuthRevResTBEB" +#define NID_setct_AuthRevResTBEB 579 +#define OBJ_setct_AuthRevResTBEB OBJ_set_ctype,61L + +#define SN_setct_CapReqTBE "setct-CapReqTBE" +#define NID_setct_CapReqTBE 580 +#define OBJ_setct_CapReqTBE OBJ_set_ctype,62L + +#define SN_setct_CapReqTBEX "setct-CapReqTBEX" +#define NID_setct_CapReqTBEX 581 +#define OBJ_setct_CapReqTBEX OBJ_set_ctype,63L + +#define SN_setct_CapResTBE "setct-CapResTBE" +#define NID_setct_CapResTBE 582 +#define OBJ_setct_CapResTBE OBJ_set_ctype,64L + +#define SN_setct_CapRevReqTBE "setct-CapRevReqTBE" +#define NID_setct_CapRevReqTBE 583 +#define OBJ_setct_CapRevReqTBE OBJ_set_ctype,65L + +#define SN_setct_CapRevReqTBEX "setct-CapRevReqTBEX" +#define NID_setct_CapRevReqTBEX 584 +#define OBJ_setct_CapRevReqTBEX OBJ_set_ctype,66L + +#define SN_setct_CapRevResTBE "setct-CapRevResTBE" +#define NID_setct_CapRevResTBE 585 +#define OBJ_setct_CapRevResTBE OBJ_set_ctype,67L + +#define SN_setct_CredReqTBE "setct-CredReqTBE" +#define NID_setct_CredReqTBE 586 +#define OBJ_setct_CredReqTBE OBJ_set_ctype,68L + +#define SN_setct_CredReqTBEX "setct-CredReqTBEX" +#define NID_setct_CredReqTBEX 587 +#define OBJ_setct_CredReqTBEX OBJ_set_ctype,69L + +#define SN_setct_CredResTBE "setct-CredResTBE" +#define NID_setct_CredResTBE 588 +#define OBJ_setct_CredResTBE OBJ_set_ctype,70L + +#define SN_setct_CredRevReqTBE "setct-CredRevReqTBE" +#define NID_setct_CredRevReqTBE 589 +#define OBJ_setct_CredRevReqTBE OBJ_set_ctype,71L + +#define SN_setct_CredRevReqTBEX "setct-CredRevReqTBEX" +#define NID_setct_CredRevReqTBEX 590 +#define OBJ_setct_CredRevReqTBEX OBJ_set_ctype,72L + +#define SN_setct_CredRevResTBE "setct-CredRevResTBE" +#define NID_setct_CredRevResTBE 591 +#define OBJ_setct_CredRevResTBE OBJ_set_ctype,73L + +#define SN_setct_BatchAdminReqTBE "setct-BatchAdminReqTBE" +#define NID_setct_BatchAdminReqTBE 592 +#define OBJ_setct_BatchAdminReqTBE OBJ_set_ctype,74L + +#define SN_setct_BatchAdminResTBE "setct-BatchAdminResTBE" +#define NID_setct_BatchAdminResTBE 593 +#define OBJ_setct_BatchAdminResTBE OBJ_set_ctype,75L + +#define SN_setct_RegFormReqTBE "setct-RegFormReqTBE" +#define NID_setct_RegFormReqTBE 594 +#define OBJ_setct_RegFormReqTBE OBJ_set_ctype,76L + +#define SN_setct_CertReqTBE "setct-CertReqTBE" +#define NID_setct_CertReqTBE 595 +#define OBJ_setct_CertReqTBE OBJ_set_ctype,77L + +#define SN_setct_CertReqTBEX "setct-CertReqTBEX" +#define NID_setct_CertReqTBEX 596 +#define OBJ_setct_CertReqTBEX OBJ_set_ctype,78L + +#define SN_setct_CertResTBE "setct-CertResTBE" +#define NID_setct_CertResTBE 597 +#define OBJ_setct_CertResTBE OBJ_set_ctype,79L + +#define SN_setct_CRLNotificationTBS "setct-CRLNotificationTBS" +#define NID_setct_CRLNotificationTBS 598 +#define OBJ_setct_CRLNotificationTBS OBJ_set_ctype,80L + +#define SN_setct_CRLNotificationResTBS "setct-CRLNotificationResTBS" +#define NID_setct_CRLNotificationResTBS 599 +#define OBJ_setct_CRLNotificationResTBS OBJ_set_ctype,81L + +#define SN_setct_BCIDistributionTBS "setct-BCIDistributionTBS" +#define NID_setct_BCIDistributionTBS 600 +#define OBJ_setct_BCIDistributionTBS OBJ_set_ctype,82L + +#define SN_setext_genCrypt "setext-genCrypt" +#define LN_setext_genCrypt "generic cryptogram" +#define NID_setext_genCrypt 601 +#define OBJ_setext_genCrypt OBJ_set_msgExt,1L + +#define SN_setext_miAuth "setext-miAuth" +#define LN_setext_miAuth "merchant initiated auth" +#define NID_setext_miAuth 602 +#define OBJ_setext_miAuth OBJ_set_msgExt,3L + +#define SN_setext_pinSecure "setext-pinSecure" +#define NID_setext_pinSecure 603 +#define OBJ_setext_pinSecure OBJ_set_msgExt,4L + +#define SN_setext_pinAny "setext-pinAny" +#define NID_setext_pinAny 604 +#define OBJ_setext_pinAny OBJ_set_msgExt,5L + +#define SN_setext_track2 "setext-track2" +#define NID_setext_track2 605 +#define OBJ_setext_track2 OBJ_set_msgExt,7L + +#define SN_setext_cv "setext-cv" +#define LN_setext_cv "additional verification" +#define NID_setext_cv 606 +#define OBJ_setext_cv OBJ_set_msgExt,8L + +#define SN_set_policy_root "set-policy-root" +#define NID_set_policy_root 607 +#define OBJ_set_policy_root OBJ_set_policy,0L + +#define SN_setCext_hashedRoot "setCext-hashedRoot" +#define NID_setCext_hashedRoot 608 +#define OBJ_setCext_hashedRoot OBJ_set_certExt,0L + +#define SN_setCext_certType "setCext-certType" +#define NID_setCext_certType 609 +#define OBJ_setCext_certType OBJ_set_certExt,1L + +#define SN_setCext_merchData "setCext-merchData" +#define NID_setCext_merchData 610 +#define OBJ_setCext_merchData OBJ_set_certExt,2L + +#define SN_setCext_cCertRequired "setCext-cCertRequired" +#define NID_setCext_cCertRequired 611 +#define OBJ_setCext_cCertRequired OBJ_set_certExt,3L + +#define SN_setCext_tunneling "setCext-tunneling" +#define NID_setCext_tunneling 612 +#define OBJ_setCext_tunneling OBJ_set_certExt,4L + +#define SN_setCext_setExt "setCext-setExt" +#define NID_setCext_setExt 613 +#define OBJ_setCext_setExt OBJ_set_certExt,5L + +#define SN_setCext_setQualf "setCext-setQualf" +#define NID_setCext_setQualf 614 +#define OBJ_setCext_setQualf OBJ_set_certExt,6L + +#define SN_setCext_PGWYcapabilities "setCext-PGWYcapabilities" +#define NID_setCext_PGWYcapabilities 615 +#define OBJ_setCext_PGWYcapabilities OBJ_set_certExt,7L + +#define SN_setCext_TokenIdentifier "setCext-TokenIdentifier" +#define NID_setCext_TokenIdentifier 616 +#define OBJ_setCext_TokenIdentifier OBJ_set_certExt,8L + +#define SN_setCext_Track2Data "setCext-Track2Data" +#define NID_setCext_Track2Data 617 +#define OBJ_setCext_Track2Data OBJ_set_certExt,9L + +#define SN_setCext_TokenType "setCext-TokenType" +#define NID_setCext_TokenType 618 +#define OBJ_setCext_TokenType OBJ_set_certExt,10L + +#define SN_setCext_IssuerCapabilities "setCext-IssuerCapabilities" +#define NID_setCext_IssuerCapabilities 619 +#define OBJ_setCext_IssuerCapabilities OBJ_set_certExt,11L + +#define SN_setAttr_Cert "setAttr-Cert" +#define NID_setAttr_Cert 620 +#define OBJ_setAttr_Cert OBJ_set_attr,0L + +#define SN_setAttr_PGWYcap "setAttr-PGWYcap" +#define LN_setAttr_PGWYcap "payment gateway capabilities" +#define NID_setAttr_PGWYcap 621 +#define OBJ_setAttr_PGWYcap OBJ_set_attr,1L + +#define SN_setAttr_TokenType "setAttr-TokenType" +#define NID_setAttr_TokenType 622 +#define OBJ_setAttr_TokenType OBJ_set_attr,2L + +#define SN_setAttr_IssCap "setAttr-IssCap" +#define LN_setAttr_IssCap "issuer capabilities" +#define NID_setAttr_IssCap 623 +#define OBJ_setAttr_IssCap OBJ_set_attr,3L + +#define SN_set_rootKeyThumb "set-rootKeyThumb" +#define NID_set_rootKeyThumb 624 +#define OBJ_set_rootKeyThumb OBJ_setAttr_Cert,0L + +#define SN_set_addPolicy "set-addPolicy" +#define NID_set_addPolicy 625 +#define OBJ_set_addPolicy OBJ_setAttr_Cert,1L + +#define SN_setAttr_Token_EMV "setAttr-Token-EMV" +#define NID_setAttr_Token_EMV 626 +#define OBJ_setAttr_Token_EMV OBJ_setAttr_TokenType,1L + +#define SN_setAttr_Token_B0Prime "setAttr-Token-B0Prime" +#define NID_setAttr_Token_B0Prime 627 +#define OBJ_setAttr_Token_B0Prime OBJ_setAttr_TokenType,2L + +#define SN_setAttr_IssCap_CVM "setAttr-IssCap-CVM" +#define NID_setAttr_IssCap_CVM 628 +#define OBJ_setAttr_IssCap_CVM OBJ_setAttr_IssCap,3L + +#define SN_setAttr_IssCap_T2 "setAttr-IssCap-T2" +#define NID_setAttr_IssCap_T2 629 +#define OBJ_setAttr_IssCap_T2 OBJ_setAttr_IssCap,4L + +#define SN_setAttr_IssCap_Sig "setAttr-IssCap-Sig" +#define NID_setAttr_IssCap_Sig 630 +#define OBJ_setAttr_IssCap_Sig OBJ_setAttr_IssCap,5L + +#define SN_setAttr_GenCryptgrm "setAttr-GenCryptgrm" +#define LN_setAttr_GenCryptgrm "generate cryptogram" +#define NID_setAttr_GenCryptgrm 631 +#define OBJ_setAttr_GenCryptgrm OBJ_setAttr_IssCap_CVM,1L + +#define SN_setAttr_T2Enc "setAttr-T2Enc" +#define LN_setAttr_T2Enc "encrypted track 2" +#define NID_setAttr_T2Enc 632 +#define OBJ_setAttr_T2Enc OBJ_setAttr_IssCap_T2,1L + +#define SN_setAttr_T2cleartxt "setAttr-T2cleartxt" +#define LN_setAttr_T2cleartxt "cleartext track 2" +#define NID_setAttr_T2cleartxt 633 +#define OBJ_setAttr_T2cleartxt OBJ_setAttr_IssCap_T2,2L + +#define SN_setAttr_TokICCsig "setAttr-TokICCsig" +#define LN_setAttr_TokICCsig "ICC or token signature" +#define NID_setAttr_TokICCsig 634 +#define OBJ_setAttr_TokICCsig OBJ_setAttr_IssCap_Sig,1L + +#define SN_setAttr_SecDevSig "setAttr-SecDevSig" +#define LN_setAttr_SecDevSig "secure device signature" +#define NID_setAttr_SecDevSig 635 +#define OBJ_setAttr_SecDevSig OBJ_setAttr_IssCap_Sig,2L + +#define SN_set_brand_IATA_ATA "set-brand-IATA-ATA" +#define NID_set_brand_IATA_ATA 636 +#define OBJ_set_brand_IATA_ATA OBJ_set_brand,1L + +#define SN_set_brand_Diners "set-brand-Diners" +#define NID_set_brand_Diners 637 +#define OBJ_set_brand_Diners OBJ_set_brand,30L + +#define SN_set_brand_AmericanExpress "set-brand-AmericanExpress" +#define NID_set_brand_AmericanExpress 638 +#define OBJ_set_brand_AmericanExpress OBJ_set_brand,34L + +#define SN_set_brand_JCB "set-brand-JCB" +#define NID_set_brand_JCB 639 +#define OBJ_set_brand_JCB OBJ_set_brand,35L + +#define SN_set_brand_Visa "set-brand-Visa" +#define NID_set_brand_Visa 640 +#define OBJ_set_brand_Visa OBJ_set_brand,4L + +#define SN_set_brand_MasterCard "set-brand-MasterCard" +#define NID_set_brand_MasterCard 641 +#define OBJ_set_brand_MasterCard OBJ_set_brand,5L + +#define SN_set_brand_Novus "set-brand-Novus" +#define NID_set_brand_Novus 642 +#define OBJ_set_brand_Novus OBJ_set_brand,6011L + +#define SN_des_cdmf "DES-CDMF" +#define LN_des_cdmf "des-cdmf" +#define NID_des_cdmf 643 +#define OBJ_des_cdmf OBJ_rsadsi,3L,10L + +#define SN_rsaOAEPEncryptionSET "rsaOAEPEncryptionSET" +#define NID_rsaOAEPEncryptionSET 644 +#define OBJ_rsaOAEPEncryptionSET OBJ_rsadsi,1L,1L,6L + +#define SN_ipsec3 "Oakley-EC2N-3" +#define LN_ipsec3 "ipsec3" +#define NID_ipsec3 749 + +#define SN_ipsec4 "Oakley-EC2N-4" +#define LN_ipsec4 "ipsec4" +#define NID_ipsec4 750 + +#define SN_whirlpool "whirlpool" +#define NID_whirlpool 804 +#define OBJ_whirlpool OBJ_iso,0L,10118L,3L,0L,55L + +#define SN_cryptopro "cryptopro" +#define NID_cryptopro 805 +#define OBJ_cryptopro OBJ_member_body,643L,2L,2L + +#define SN_cryptocom "cryptocom" +#define NID_cryptocom 806 +#define OBJ_cryptocom OBJ_member_body,643L,2L,9L + +#define SN_id_GostR3411_94_with_GostR3410_2001 "id-GostR3411-94-with-GostR3410-2001" +#define LN_id_GostR3411_94_with_GostR3410_2001 "GOST R 34.11-94 with GOST R 34.10-2001" +#define NID_id_GostR3411_94_with_GostR3410_2001 807 +#define OBJ_id_GostR3411_94_with_GostR3410_2001 OBJ_cryptopro,3L + +#define SN_id_GostR3411_94_with_GostR3410_94 "id-GostR3411-94-with-GostR3410-94" +#define LN_id_GostR3411_94_with_GostR3410_94 "GOST R 34.11-94 with GOST R 34.10-94" +#define NID_id_GostR3411_94_with_GostR3410_94 808 +#define OBJ_id_GostR3411_94_with_GostR3410_94 OBJ_cryptopro,4L + +#define SN_id_GostR3411_94 "md_gost94" +#define LN_id_GostR3411_94 "GOST R 34.11-94" +#define NID_id_GostR3411_94 809 +#define OBJ_id_GostR3411_94 OBJ_cryptopro,9L + +#define SN_id_HMACGostR3411_94 "id-HMACGostR3411-94" +#define LN_id_HMACGostR3411_94 "HMAC GOST 34.11-94" +#define NID_id_HMACGostR3411_94 810 +#define OBJ_id_HMACGostR3411_94 OBJ_cryptopro,10L + +#define SN_id_GostR3410_2001 "gost2001" +#define LN_id_GostR3410_2001 "GOST R 34.10-2001" +#define NID_id_GostR3410_2001 811 +#define OBJ_id_GostR3410_2001 OBJ_cryptopro,19L + +#define SN_id_GostR3410_94 "gost94" +#define LN_id_GostR3410_94 "GOST R 34.10-94" +#define NID_id_GostR3410_94 812 +#define OBJ_id_GostR3410_94 OBJ_cryptopro,20L + +#define SN_id_Gost28147_89 "gost89" +#define LN_id_Gost28147_89 "GOST 28147-89" +#define NID_id_Gost28147_89 813 +#define OBJ_id_Gost28147_89 OBJ_cryptopro,21L + +#define SN_gost89_cnt "gost89-cnt" +#define NID_gost89_cnt 814 + +#define SN_id_Gost28147_89_MAC "gost-mac" +#define LN_id_Gost28147_89_MAC "GOST 28147-89 MAC" +#define NID_id_Gost28147_89_MAC 815 +#define OBJ_id_Gost28147_89_MAC OBJ_cryptopro,22L + +#define SN_id_GostR3411_94_prf "prf-gostr3411-94" +#define LN_id_GostR3411_94_prf "GOST R 34.11-94 PRF" +#define NID_id_GostR3411_94_prf 816 +#define OBJ_id_GostR3411_94_prf OBJ_cryptopro,23L + +#define SN_id_GostR3410_2001DH "id-GostR3410-2001DH" +#define LN_id_GostR3410_2001DH "GOST R 34.10-2001 DH" +#define NID_id_GostR3410_2001DH 817 +#define OBJ_id_GostR3410_2001DH OBJ_cryptopro,98L + +#define SN_id_GostR3410_94DH "id-GostR3410-94DH" +#define LN_id_GostR3410_94DH "GOST R 34.10-94 DH" +#define NID_id_GostR3410_94DH 818 +#define OBJ_id_GostR3410_94DH OBJ_cryptopro,99L + +#define SN_id_Gost28147_89_CryptoPro_KeyMeshing "id-Gost28147-89-CryptoPro-KeyMeshing" +#define NID_id_Gost28147_89_CryptoPro_KeyMeshing 819 +#define OBJ_id_Gost28147_89_CryptoPro_KeyMeshing OBJ_cryptopro,14L,1L + +#define SN_id_Gost28147_89_None_KeyMeshing "id-Gost28147-89-None-KeyMeshing" +#define NID_id_Gost28147_89_None_KeyMeshing 820 +#define OBJ_id_Gost28147_89_None_KeyMeshing OBJ_cryptopro,14L,0L + +#define SN_id_GostR3411_94_TestParamSet "id-GostR3411-94-TestParamSet" +#define NID_id_GostR3411_94_TestParamSet 821 +#define OBJ_id_GostR3411_94_TestParamSet OBJ_cryptopro,30L,0L + +#define SN_id_GostR3411_94_CryptoProParamSet "id-GostR3411-94-CryptoProParamSet" +#define NID_id_GostR3411_94_CryptoProParamSet 822 +#define OBJ_id_GostR3411_94_CryptoProParamSet OBJ_cryptopro,30L,1L + +#define SN_id_Gost28147_89_TestParamSet "id-Gost28147-89-TestParamSet" +#define NID_id_Gost28147_89_TestParamSet 823 +#define OBJ_id_Gost28147_89_TestParamSet OBJ_cryptopro,31L,0L + +#define SN_id_Gost28147_89_CryptoPro_A_ParamSet "id-Gost28147-89-CryptoPro-A-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_A_ParamSet 824 +#define OBJ_id_Gost28147_89_CryptoPro_A_ParamSet OBJ_cryptopro,31L,1L + +#define SN_id_Gost28147_89_CryptoPro_B_ParamSet "id-Gost28147-89-CryptoPro-B-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_B_ParamSet 825 +#define OBJ_id_Gost28147_89_CryptoPro_B_ParamSet OBJ_cryptopro,31L,2L + +#define SN_id_Gost28147_89_CryptoPro_C_ParamSet "id-Gost28147-89-CryptoPro-C-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_C_ParamSet 826 +#define OBJ_id_Gost28147_89_CryptoPro_C_ParamSet OBJ_cryptopro,31L,3L + +#define SN_id_Gost28147_89_CryptoPro_D_ParamSet "id-Gost28147-89-CryptoPro-D-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_D_ParamSet 827 +#define OBJ_id_Gost28147_89_CryptoPro_D_ParamSet OBJ_cryptopro,31L,4L + +#define SN_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet "id-Gost28147-89-CryptoPro-Oscar-1-1-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet 828 +#define OBJ_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet OBJ_cryptopro,31L,5L + +#define SN_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet "id-Gost28147-89-CryptoPro-Oscar-1-0-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet 829 +#define OBJ_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet OBJ_cryptopro,31L,6L + +#define SN_id_Gost28147_89_CryptoPro_RIC_1_ParamSet "id-Gost28147-89-CryptoPro-RIC-1-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_RIC_1_ParamSet 830 +#define OBJ_id_Gost28147_89_CryptoPro_RIC_1_ParamSet OBJ_cryptopro,31L,7L + +#define SN_id_GostR3410_94_TestParamSet "id-GostR3410-94-TestParamSet" +#define NID_id_GostR3410_94_TestParamSet 831 +#define OBJ_id_GostR3410_94_TestParamSet OBJ_cryptopro,32L,0L + +#define SN_id_GostR3410_94_CryptoPro_A_ParamSet "id-GostR3410-94-CryptoPro-A-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_A_ParamSet 832 +#define OBJ_id_GostR3410_94_CryptoPro_A_ParamSet OBJ_cryptopro,32L,2L + +#define SN_id_GostR3410_94_CryptoPro_B_ParamSet "id-GostR3410-94-CryptoPro-B-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_B_ParamSet 833 +#define OBJ_id_GostR3410_94_CryptoPro_B_ParamSet OBJ_cryptopro,32L,3L + +#define SN_id_GostR3410_94_CryptoPro_C_ParamSet "id-GostR3410-94-CryptoPro-C-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_C_ParamSet 834 +#define OBJ_id_GostR3410_94_CryptoPro_C_ParamSet OBJ_cryptopro,32L,4L + +#define SN_id_GostR3410_94_CryptoPro_D_ParamSet "id-GostR3410-94-CryptoPro-D-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_D_ParamSet 835 +#define OBJ_id_GostR3410_94_CryptoPro_D_ParamSet OBJ_cryptopro,32L,5L + +#define SN_id_GostR3410_94_CryptoPro_XchA_ParamSet "id-GostR3410-94-CryptoPro-XchA-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_XchA_ParamSet 836 +#define OBJ_id_GostR3410_94_CryptoPro_XchA_ParamSet OBJ_cryptopro,33L,1L + +#define SN_id_GostR3410_94_CryptoPro_XchB_ParamSet "id-GostR3410-94-CryptoPro-XchB-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_XchB_ParamSet 837 +#define OBJ_id_GostR3410_94_CryptoPro_XchB_ParamSet OBJ_cryptopro,33L,2L + +#define SN_id_GostR3410_94_CryptoPro_XchC_ParamSet "id-GostR3410-94-CryptoPro-XchC-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_XchC_ParamSet 838 +#define OBJ_id_GostR3410_94_CryptoPro_XchC_ParamSet OBJ_cryptopro,33L,3L + +#define SN_id_GostR3410_2001_TestParamSet "id-GostR3410-2001-TestParamSet" +#define NID_id_GostR3410_2001_TestParamSet 839 +#define OBJ_id_GostR3410_2001_TestParamSet OBJ_cryptopro,35L,0L + +#define SN_id_GostR3410_2001_CryptoPro_A_ParamSet "id-GostR3410-2001-CryptoPro-A-ParamSet" +#define NID_id_GostR3410_2001_CryptoPro_A_ParamSet 840 +#define OBJ_id_GostR3410_2001_CryptoPro_A_ParamSet OBJ_cryptopro,35L,1L + +#define SN_id_GostR3410_2001_CryptoPro_B_ParamSet "id-GostR3410-2001-CryptoPro-B-ParamSet" +#define NID_id_GostR3410_2001_CryptoPro_B_ParamSet 841 +#define OBJ_id_GostR3410_2001_CryptoPro_B_ParamSet OBJ_cryptopro,35L,2L + +#define SN_id_GostR3410_2001_CryptoPro_C_ParamSet "id-GostR3410-2001-CryptoPro-C-ParamSet" +#define NID_id_GostR3410_2001_CryptoPro_C_ParamSet 842 +#define OBJ_id_GostR3410_2001_CryptoPro_C_ParamSet OBJ_cryptopro,35L,3L + +#define SN_id_GostR3410_2001_CryptoPro_XchA_ParamSet "id-GostR3410-2001-CryptoPro-XchA-ParamSet" +#define NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet 843 +#define OBJ_id_GostR3410_2001_CryptoPro_XchA_ParamSet OBJ_cryptopro,36L,0L + +#define SN_id_GostR3410_2001_CryptoPro_XchB_ParamSet "id-GostR3410-2001-CryptoPro-XchB-ParamSet" +#define NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet 844 +#define OBJ_id_GostR3410_2001_CryptoPro_XchB_ParamSet OBJ_cryptopro,36L,1L + +#define SN_id_GostR3410_94_a "id-GostR3410-94-a" +#define NID_id_GostR3410_94_a 845 +#define OBJ_id_GostR3410_94_a OBJ_id_GostR3410_94,1L + +#define SN_id_GostR3410_94_aBis "id-GostR3410-94-aBis" +#define NID_id_GostR3410_94_aBis 846 +#define OBJ_id_GostR3410_94_aBis OBJ_id_GostR3410_94,2L + +#define SN_id_GostR3410_94_b "id-GostR3410-94-b" +#define NID_id_GostR3410_94_b 847 +#define OBJ_id_GostR3410_94_b OBJ_id_GostR3410_94,3L + +#define SN_id_GostR3410_94_bBis "id-GostR3410-94-bBis" +#define NID_id_GostR3410_94_bBis 848 +#define OBJ_id_GostR3410_94_bBis OBJ_id_GostR3410_94,4L + +#define SN_id_Gost28147_89_cc "id-Gost28147-89-cc" +#define LN_id_Gost28147_89_cc "GOST 28147-89 Cryptocom ParamSet" +#define NID_id_Gost28147_89_cc 849 +#define OBJ_id_Gost28147_89_cc OBJ_cryptocom,1L,6L,1L + +#define SN_id_GostR3410_94_cc "gost94cc" +#define LN_id_GostR3410_94_cc "GOST 34.10-94 Cryptocom" +#define NID_id_GostR3410_94_cc 850 +#define OBJ_id_GostR3410_94_cc OBJ_cryptocom,1L,5L,3L + +#define SN_id_GostR3410_2001_cc "gost2001cc" +#define LN_id_GostR3410_2001_cc "GOST 34.10-2001 Cryptocom" +#define NID_id_GostR3410_2001_cc 851 +#define OBJ_id_GostR3410_2001_cc OBJ_cryptocom,1L,5L,4L + +#define SN_id_GostR3411_94_with_GostR3410_94_cc "id-GostR3411-94-with-GostR3410-94-cc" +#define LN_id_GostR3411_94_with_GostR3410_94_cc "GOST R 34.11-94 with GOST R 34.10-94 Cryptocom" +#define NID_id_GostR3411_94_with_GostR3410_94_cc 852 +#define OBJ_id_GostR3411_94_with_GostR3410_94_cc OBJ_cryptocom,1L,3L,3L + +#define SN_id_GostR3411_94_with_GostR3410_2001_cc "id-GostR3411-94-with-GostR3410-2001-cc" +#define LN_id_GostR3411_94_with_GostR3410_2001_cc "GOST R 34.11-94 with GOST R 34.10-2001 Cryptocom" +#define NID_id_GostR3411_94_with_GostR3410_2001_cc 853 +#define OBJ_id_GostR3411_94_with_GostR3410_2001_cc OBJ_cryptocom,1L,3L,4L + +#define SN_id_GostR3410_2001_ParamSet_cc "id-GostR3410-2001-ParamSet-cc" +#define LN_id_GostR3410_2001_ParamSet_cc "GOST R 3410-2001 Parameter Set Cryptocom" +#define NID_id_GostR3410_2001_ParamSet_cc 854 +#define OBJ_id_GostR3410_2001_ParamSet_cc OBJ_cryptocom,1L,8L,1L + +#define SN_camellia_128_cbc "CAMELLIA-128-CBC" +#define LN_camellia_128_cbc "camellia-128-cbc" +#define NID_camellia_128_cbc 751 +#define OBJ_camellia_128_cbc 1L,2L,392L,200011L,61L,1L,1L,1L,2L + +#define SN_camellia_192_cbc "CAMELLIA-192-CBC" +#define LN_camellia_192_cbc "camellia-192-cbc" +#define NID_camellia_192_cbc 752 +#define OBJ_camellia_192_cbc 1L,2L,392L,200011L,61L,1L,1L,1L,3L + +#define SN_camellia_256_cbc "CAMELLIA-256-CBC" +#define LN_camellia_256_cbc "camellia-256-cbc" +#define NID_camellia_256_cbc 753 +#define OBJ_camellia_256_cbc 1L,2L,392L,200011L,61L,1L,1L,1L,4L + +#define SN_id_camellia128_wrap "id-camellia128-wrap" +#define NID_id_camellia128_wrap 907 +#define OBJ_id_camellia128_wrap 1L,2L,392L,200011L,61L,1L,1L,3L,2L + +#define SN_id_camellia192_wrap "id-camellia192-wrap" +#define NID_id_camellia192_wrap 908 +#define OBJ_id_camellia192_wrap 1L,2L,392L,200011L,61L,1L,1L,3L,3L + +#define SN_id_camellia256_wrap "id-camellia256-wrap" +#define NID_id_camellia256_wrap 909 +#define OBJ_id_camellia256_wrap 1L,2L,392L,200011L,61L,1L,1L,3L,4L + +#define OBJ_ntt_ds 0L,3L,4401L,5L + +#define OBJ_camellia OBJ_ntt_ds,3L,1L,9L + +#define SN_camellia_128_ecb "CAMELLIA-128-ECB" +#define LN_camellia_128_ecb "camellia-128-ecb" +#define NID_camellia_128_ecb 754 +#define OBJ_camellia_128_ecb OBJ_camellia,1L + +#define SN_camellia_128_ofb128 "CAMELLIA-128-OFB" +#define LN_camellia_128_ofb128 "camellia-128-ofb" +#define NID_camellia_128_ofb128 766 +#define OBJ_camellia_128_ofb128 OBJ_camellia,3L + +#define SN_camellia_128_cfb128 "CAMELLIA-128-CFB" +#define LN_camellia_128_cfb128 "camellia-128-cfb" +#define NID_camellia_128_cfb128 757 +#define OBJ_camellia_128_cfb128 OBJ_camellia,4L + +#define SN_camellia_192_ecb "CAMELLIA-192-ECB" +#define LN_camellia_192_ecb "camellia-192-ecb" +#define NID_camellia_192_ecb 755 +#define OBJ_camellia_192_ecb OBJ_camellia,21L + +#define SN_camellia_192_ofb128 "CAMELLIA-192-OFB" +#define LN_camellia_192_ofb128 "camellia-192-ofb" +#define NID_camellia_192_ofb128 767 +#define OBJ_camellia_192_ofb128 OBJ_camellia,23L + +#define SN_camellia_192_cfb128 "CAMELLIA-192-CFB" +#define LN_camellia_192_cfb128 "camellia-192-cfb" +#define NID_camellia_192_cfb128 758 +#define OBJ_camellia_192_cfb128 OBJ_camellia,24L + +#define SN_camellia_256_ecb "CAMELLIA-256-ECB" +#define LN_camellia_256_ecb "camellia-256-ecb" +#define NID_camellia_256_ecb 756 +#define OBJ_camellia_256_ecb OBJ_camellia,41L + +#define SN_camellia_256_ofb128 "CAMELLIA-256-OFB" +#define LN_camellia_256_ofb128 "camellia-256-ofb" +#define NID_camellia_256_ofb128 768 +#define OBJ_camellia_256_ofb128 OBJ_camellia,43L + +#define SN_camellia_256_cfb128 "CAMELLIA-256-CFB" +#define LN_camellia_256_cfb128 "camellia-256-cfb" +#define NID_camellia_256_cfb128 759 +#define OBJ_camellia_256_cfb128 OBJ_camellia,44L + +#define SN_camellia_128_cfb1 "CAMELLIA-128-CFB1" +#define LN_camellia_128_cfb1 "camellia-128-cfb1" +#define NID_camellia_128_cfb1 760 + +#define SN_camellia_192_cfb1 "CAMELLIA-192-CFB1" +#define LN_camellia_192_cfb1 "camellia-192-cfb1" +#define NID_camellia_192_cfb1 761 + +#define SN_camellia_256_cfb1 "CAMELLIA-256-CFB1" +#define LN_camellia_256_cfb1 "camellia-256-cfb1" +#define NID_camellia_256_cfb1 762 + +#define SN_camellia_128_cfb8 "CAMELLIA-128-CFB8" +#define LN_camellia_128_cfb8 "camellia-128-cfb8" +#define NID_camellia_128_cfb8 763 + +#define SN_camellia_192_cfb8 "CAMELLIA-192-CFB8" +#define LN_camellia_192_cfb8 "camellia-192-cfb8" +#define NID_camellia_192_cfb8 764 + +#define SN_camellia_256_cfb8 "CAMELLIA-256-CFB8" +#define LN_camellia_256_cfb8 "camellia-256-cfb8" +#define NID_camellia_256_cfb8 765 + +#define SN_kisa "KISA" +#define LN_kisa "kisa" +#define NID_kisa 773 +#define OBJ_kisa OBJ_member_body,410L,200004L + +#define SN_seed_ecb "SEED-ECB" +#define LN_seed_ecb "seed-ecb" +#define NID_seed_ecb 776 +#define OBJ_seed_ecb OBJ_kisa,1L,3L + +#define SN_seed_cbc "SEED-CBC" +#define LN_seed_cbc "seed-cbc" +#define NID_seed_cbc 777 +#define OBJ_seed_cbc OBJ_kisa,1L,4L + +#define SN_seed_cfb128 "SEED-CFB" +#define LN_seed_cfb128 "seed-cfb" +#define NID_seed_cfb128 779 +#define OBJ_seed_cfb128 OBJ_kisa,1L,5L + +#define SN_seed_ofb128 "SEED-OFB" +#define LN_seed_ofb128 "seed-ofb" +#define NID_seed_ofb128 778 +#define OBJ_seed_ofb128 OBJ_kisa,1L,6L + +#define SN_hmac "HMAC" +#define LN_hmac "hmac" +#define NID_hmac 855 + +#define SN_cmac "CMAC" +#define LN_cmac "cmac" +#define NID_cmac 894 + +#define SN_rc4_hmac_md5 "RC4-HMAC-MD5" +#define LN_rc4_hmac_md5 "rc4-hmac-md5" +#define NID_rc4_hmac_md5 915 + +#define SN_aes_128_cbc_hmac_sha1 "AES-128-CBC-HMAC-SHA1" +#define LN_aes_128_cbc_hmac_sha1 "aes-128-cbc-hmac-sha1" +#define NID_aes_128_cbc_hmac_sha1 916 + +#define SN_aes_192_cbc_hmac_sha1 "AES-192-CBC-HMAC-SHA1" +#define LN_aes_192_cbc_hmac_sha1 "aes-192-cbc-hmac-sha1" +#define NID_aes_192_cbc_hmac_sha1 917 + +#define SN_aes_256_cbc_hmac_sha1 "AES-256-CBC-HMAC-SHA1" +#define LN_aes_256_cbc_hmac_sha1 "aes-256-cbc-hmac-sha1" +#define NID_aes_256_cbc_hmac_sha1 918 + +#define SN_dhpublicnumber "dhpublicnumber" +#define LN_dhpublicnumber "X9.42 DH" +#define NID_dhpublicnumber 920 +#define OBJ_dhpublicnumber OBJ_ISO_US,10046L,2L,1L + +#define SN_brainpoolP160r1 "brainpoolP160r1" +#define NID_brainpoolP160r1 921 +#define OBJ_brainpoolP160r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,1L + +#define SN_brainpoolP160t1 "brainpoolP160t1" +#define NID_brainpoolP160t1 922 +#define OBJ_brainpoolP160t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,2L + +#define SN_brainpoolP192r1 "brainpoolP192r1" +#define NID_brainpoolP192r1 923 +#define OBJ_brainpoolP192r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,3L + +#define SN_brainpoolP192t1 "brainpoolP192t1" +#define NID_brainpoolP192t1 924 +#define OBJ_brainpoolP192t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,4L + +#define SN_brainpoolP224r1 "brainpoolP224r1" +#define NID_brainpoolP224r1 925 +#define OBJ_brainpoolP224r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,5L + +#define SN_brainpoolP224t1 "brainpoolP224t1" +#define NID_brainpoolP224t1 926 +#define OBJ_brainpoolP224t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,6L + +#define SN_brainpoolP256r1 "brainpoolP256r1" +#define NID_brainpoolP256r1 927 +#define OBJ_brainpoolP256r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,7L + +#define SN_brainpoolP256t1 "brainpoolP256t1" +#define NID_brainpoolP256t1 928 +#define OBJ_brainpoolP256t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,8L + +#define SN_brainpoolP320r1 "brainpoolP320r1" +#define NID_brainpoolP320r1 929 +#define OBJ_brainpoolP320r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,9L + +#define SN_brainpoolP320t1 "brainpoolP320t1" +#define NID_brainpoolP320t1 930 +#define OBJ_brainpoolP320t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,10L + +#define SN_brainpoolP384r1 "brainpoolP384r1" +#define NID_brainpoolP384r1 931 +#define OBJ_brainpoolP384r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,11L + +#define SN_brainpoolP384t1 "brainpoolP384t1" +#define NID_brainpoolP384t1 932 +#define OBJ_brainpoolP384t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,12L + +#define SN_brainpoolP512r1 "brainpoolP512r1" +#define NID_brainpoolP512r1 933 +#define OBJ_brainpoolP512r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,13L + +#define SN_brainpoolP512t1 "brainpoolP512t1" +#define NID_brainpoolP512t1 934 +#define OBJ_brainpoolP512t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,14L + +#define OBJ_x9_63_scheme 1L,3L,133L,16L,840L,63L,0L + +#define OBJ_secg_scheme OBJ_certicom_arc,1L + +#define SN_dhSinglePass_stdDH_sha1kdf_scheme "dhSinglePass-stdDH-sha1kdf-scheme" +#define NID_dhSinglePass_stdDH_sha1kdf_scheme 936 +#define OBJ_dhSinglePass_stdDH_sha1kdf_scheme OBJ_x9_63_scheme,2L + +#define SN_dhSinglePass_stdDH_sha224kdf_scheme "dhSinglePass-stdDH-sha224kdf-scheme" +#define NID_dhSinglePass_stdDH_sha224kdf_scheme 937 +#define OBJ_dhSinglePass_stdDH_sha224kdf_scheme OBJ_secg_scheme,11L,0L + +#define SN_dhSinglePass_stdDH_sha256kdf_scheme "dhSinglePass-stdDH-sha256kdf-scheme" +#define NID_dhSinglePass_stdDH_sha256kdf_scheme 938 +#define OBJ_dhSinglePass_stdDH_sha256kdf_scheme OBJ_secg_scheme,11L,1L + +#define SN_dhSinglePass_stdDH_sha384kdf_scheme "dhSinglePass-stdDH-sha384kdf-scheme" +#define NID_dhSinglePass_stdDH_sha384kdf_scheme 939 +#define OBJ_dhSinglePass_stdDH_sha384kdf_scheme OBJ_secg_scheme,11L,2L + +#define SN_dhSinglePass_stdDH_sha512kdf_scheme "dhSinglePass-stdDH-sha512kdf-scheme" +#define NID_dhSinglePass_stdDH_sha512kdf_scheme 940 +#define OBJ_dhSinglePass_stdDH_sha512kdf_scheme OBJ_secg_scheme,11L,3L + +#define SN_dhSinglePass_cofactorDH_sha1kdf_scheme "dhSinglePass-cofactorDH-sha1kdf-scheme" +#define NID_dhSinglePass_cofactorDH_sha1kdf_scheme 941 +#define OBJ_dhSinglePass_cofactorDH_sha1kdf_scheme OBJ_x9_63_scheme,3L + +#define SN_dhSinglePass_cofactorDH_sha224kdf_scheme "dhSinglePass-cofactorDH-sha224kdf-scheme" +#define NID_dhSinglePass_cofactorDH_sha224kdf_scheme 942 +#define OBJ_dhSinglePass_cofactorDH_sha224kdf_scheme OBJ_secg_scheme,14L,0L + +#define SN_dhSinglePass_cofactorDH_sha256kdf_scheme "dhSinglePass-cofactorDH-sha256kdf-scheme" +#define NID_dhSinglePass_cofactorDH_sha256kdf_scheme 943 +#define OBJ_dhSinglePass_cofactorDH_sha256kdf_scheme OBJ_secg_scheme,14L,1L + +#define SN_dhSinglePass_cofactorDH_sha384kdf_scheme "dhSinglePass-cofactorDH-sha384kdf-scheme" +#define NID_dhSinglePass_cofactorDH_sha384kdf_scheme 944 +#define OBJ_dhSinglePass_cofactorDH_sha384kdf_scheme OBJ_secg_scheme,14L,2L + +#define SN_dhSinglePass_cofactorDH_sha512kdf_scheme "dhSinglePass-cofactorDH-sha512kdf-scheme" +#define NID_dhSinglePass_cofactorDH_sha512kdf_scheme 945 +#define OBJ_dhSinglePass_cofactorDH_sha512kdf_scheme OBJ_secg_scheme,14L,3L + +#define SN_dh_std_kdf "dh-std-kdf" +#define NID_dh_std_kdf 946 + +#define SN_dh_cofactor_kdf "dh-cofactor-kdf" +#define NID_dh_cofactor_kdf 947 + diff --git a/TMessagesProj/jni/boringssl/include/openssl/objects.h b/TMessagesProj/jni/boringssl/include/openssl/objects.h new file mode 100644 index 00000000..dd6556f2 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/objects.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is provided in order to make compiling against code that expects + OpenSSL easier. */ + +#include "obj.h" diff --git a/TMessagesProj/jni/boringssl/include/openssl/opensslfeatures.h b/TMessagesProj/jni/boringssl/include/openssl/opensslfeatures.h new file mode 100644 index 00000000..73814e54 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/opensslfeatures.h @@ -0,0 +1,60 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is provided in order to make compiling against code that expects + OpenSSL easier. */ + +#ifndef OPENSSL_HEADER_OPENSSLFEATURES_H +#define OPENSSL_HEADER_OPENSSLFEATURES_H + +#define TRUSTY +#define OPENSSL_NO_BF +#define OPENSSL_NO_BUF_FREELISTS +#define OPENSSL_NO_CAMELLIA +#define OPENSSL_NO_CAPIENG +#define OPENSSL_NO_CAST +#define OPENSSL_NO_CMS +#define OPENSSL_NO_COMP +#define OPENSSL_NO_DANE +#define OPENSSL_NO_DEPRECATED +#define OPENSSL_NO_DYNAMIC_ENGINE +#define OPENSSL_NO_EC_NISTP_64_GCC_128 +#define OPENSSL_NO_EC2M +#define OPENSSL_NO_ENGINE +#define OPENSSL_NO_GMP +#define OPENSSL_NO_GOST +#define OPENSSL_NO_HEARTBEATS +#define OPENSSL_NO_HW +#define OPENSSL_NO_IDEA +#define OPENSSL_NO_JPAKE +#define OPENSSL_NO_KRB5 +#define OPENSSL_NO_MD2 +#define OPENSSL_NO_MDC2 +#define OPENSSL_NO_OCB +#define OPENSSL_NO_OCSP +#define OPENSSL_NO_RC2 +#define OPENSSL_NO_RC5 +#define OPENSSL_NO_RFC3779 +#define OPENSSL_NO_RIPEMD +#define OPENSSL_NO_RMD160 +#define OPENSSL_NO_SCTP +#define OPENSSL_NO_SEED +#define OPENSSL_NO_SRP +#define OPENSSL_NO_SSL2 +#define OPENSSL_NO_STATIC_ENGINE +#define OPENSSL_NO_STORE +#define OPENSSL_NO_WHIRLPOOL + + +#endif /* OPENSSL_HEADER_OPENSSLFEATURES_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/opensslv.h b/TMessagesProj/jni/boringssl/include/openssl/opensslv.h new file mode 100644 index 00000000..a3555d4f --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/opensslv.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is provided in order to make compiling against code that expects + OpenSSL easier. */ + +#include "crypto.h" diff --git a/TMessagesProj/jni/boringssl/include/openssl/ossl_typ.h b/TMessagesProj/jni/boringssl/include/openssl/ossl_typ.h new file mode 100644 index 00000000..c2b3fe7c --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/ossl_typ.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is provided in order to make compiling against code that expects + OpenSSL easier. */ + +#include "base.h" diff --git a/TMessagesProj/jni/boringssl/include/openssl/pem.h b/TMessagesProj/jni/boringssl/include/openssl/pem.h new file mode 100644 index 00000000..db763d5a --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/pem.h @@ -0,0 +1,521 @@ +/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_PEM_H +#define OPENSSL_HEADER_PEM_H + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +#define PEM_BUFSIZE 1024 + +#define PEM_OBJ_UNDEF 0 +#define PEM_OBJ_X509 1 +#define PEM_OBJ_X509_REQ 2 +#define PEM_OBJ_CRL 3 +#define PEM_OBJ_SSL_SESSION 4 +#define PEM_OBJ_PRIV_KEY 10 +#define PEM_OBJ_PRIV_RSA 11 +#define PEM_OBJ_PRIV_DSA 12 +#define PEM_OBJ_PRIV_DH 13 +#define PEM_OBJ_PUB_RSA 14 +#define PEM_OBJ_PUB_DSA 15 +#define PEM_OBJ_PUB_DH 16 +#define PEM_OBJ_DHPARAMS 17 +#define PEM_OBJ_DSAPARAMS 18 +#define PEM_OBJ_PRIV_RSA_PUBLIC 19 +#define PEM_OBJ_PRIV_ECDSA 20 +#define PEM_OBJ_PUB_ECDSA 21 +#define PEM_OBJ_ECPARAMETERS 22 + +#define PEM_ERROR 30 +#define PEM_DEK_DES_CBC 40 +#define PEM_DEK_IDEA_CBC 45 +#define PEM_DEK_DES_EDE 50 +#define PEM_DEK_DES_ECB 60 +#define PEM_DEK_RSA 70 +#define PEM_DEK_RSA_MD2 80 +#define PEM_DEK_RSA_MD5 90 + +#define PEM_MD_MD2 NID_md2 +#define PEM_MD_MD5 NID_md5 +#define PEM_MD_SHA NID_sha +#define PEM_MD_MD2_RSA NID_md2WithRSAEncryption +#define PEM_MD_MD5_RSA NID_md5WithRSAEncryption +#define PEM_MD_SHA_RSA NID_sha1WithRSAEncryption + +#define PEM_STRING_X509_OLD "X509 CERTIFICATE" +#define PEM_STRING_X509 "CERTIFICATE" +#define PEM_STRING_X509_PAIR "CERTIFICATE PAIR" +#define PEM_STRING_X509_TRUSTED "TRUSTED CERTIFICATE" +#define PEM_STRING_X509_REQ_OLD "NEW CERTIFICATE REQUEST" +#define PEM_STRING_X509_REQ "CERTIFICATE REQUEST" +#define PEM_STRING_X509_CRL "X509 CRL" +#define PEM_STRING_EVP_PKEY "ANY PRIVATE KEY" +#define PEM_STRING_PUBLIC "PUBLIC KEY" +#define PEM_STRING_RSA "RSA PRIVATE KEY" +#define PEM_STRING_RSA_PUBLIC "RSA PUBLIC KEY" +#define PEM_STRING_DSA "DSA PRIVATE KEY" +#define PEM_STRING_DSA_PUBLIC "DSA PUBLIC KEY" +#define PEM_STRING_PKCS7 "PKCS7" +#define PEM_STRING_PKCS7_SIGNED "PKCS #7 SIGNED DATA" +#define PEM_STRING_PKCS8 "ENCRYPTED PRIVATE KEY" +#define PEM_STRING_PKCS8INF "PRIVATE KEY" +#define PEM_STRING_DHPARAMS "DH PARAMETERS" +#define PEM_STRING_DHXPARAMS "X9.42 DH PARAMETERS" +#define PEM_STRING_SSL_SESSION "SSL SESSION PARAMETERS" +#define PEM_STRING_DSAPARAMS "DSA PARAMETERS" +#define PEM_STRING_ECDSA_PUBLIC "ECDSA PUBLIC KEY" +#define PEM_STRING_ECPARAMETERS "EC PARAMETERS" +#define PEM_STRING_ECPRIVATEKEY "EC PRIVATE KEY" +#define PEM_STRING_PARAMETERS "PARAMETERS" +#define PEM_STRING_CMS "CMS" + + /* Note that this structure is initialised by PEM_SealInit and cleaned up + by PEM_SealFinal (at least for now) */ +typedef struct PEM_Encode_Seal_st + { + EVP_ENCODE_CTX encode; + EVP_MD_CTX md; + EVP_CIPHER_CTX cipher; + } PEM_ENCODE_SEAL_CTX; + +/* enc_type is one off */ +#define PEM_TYPE_ENCRYPTED 10 +#define PEM_TYPE_MIC_ONLY 20 +#define PEM_TYPE_MIC_CLEAR 30 +#define PEM_TYPE_CLEAR 40 + +typedef struct pem_recip_st + { + char *name; + X509_NAME *dn; + + int cipher; + int key_enc; + /* char iv[8]; unused and wrong size */ + } PEM_USER; + +typedef struct pem_ctx_st + { + int type; /* what type of object */ + + struct { + int version; + int mode; + } proc_type; + + char *domain; + + struct { + int cipher; + /* unused, and wrong size + unsigned char iv[8]; */ + } DEK_info; + + PEM_USER *originator; + + int num_recipient; + PEM_USER **recipient; + + EVP_MD *md; /* signature type */ + + int md_enc; /* is the md encrypted or not? */ + int md_len; /* length of md_data */ + char *md_data; /* message digest, could be pkey encrypted */ + + EVP_CIPHER *dec; /* date encryption cipher */ + int key_len; /* key length */ + unsigned char *key; /* key */ + /* unused, and wrong size + unsigned char iv[8]; */ + + + int data_enc; /* is the data encrypted */ + int data_len; + unsigned char *data; + } PEM_CTX; + +/* These macros make the PEM_read/PEM_write functions easier to maintain and + * write. Now they are all implemented with either: + * IMPLEMENT_PEM_rw(...) or IMPLEMENT_PEM_rw_cb(...) + */ + +#ifdef OPENSSL_NO_FP_API + +#define IMPLEMENT_PEM_read_fp(name, type, str, asn1) /**/ +#define IMPLEMENT_PEM_write_fp(name, type, str, asn1) /**/ +#define IMPLEMENT_PEM_write_fp_const(name, type, str, asn1) /**/ +#define IMPLEMENT_PEM_write_cb_fp(name, type, str, asn1) /**/ +#define IMPLEMENT_PEM_write_cb_fp_const(name, type, str, asn1) /**/ + +#else + +#define IMPLEMENT_PEM_read_fp(name, type, str, asn1) \ +OPENSSL_EXPORT type *PEM_read_##name(FILE *fp, type **x, pem_password_cb *cb, void *u)\ +{ \ +return PEM_ASN1_read((d2i_of_void *)d2i_##asn1, str,fp,(void **)x,cb,u); \ +} + +#define IMPLEMENT_PEM_write_fp(name, type, str, asn1) \ +OPENSSL_EXPORT int PEM_write_##name(FILE *fp, type *x) \ +{ \ +return PEM_ASN1_write((i2d_of_void *)i2d_##asn1,str,fp,x,NULL,NULL,0,NULL,NULL); \ +} + +#define IMPLEMENT_PEM_write_fp_const(name, type, str, asn1) \ +OPENSSL_EXPORT int PEM_write_##name(FILE *fp, const type *x) \ +{ \ +return PEM_ASN1_write((i2d_of_void *)i2d_##asn1,str,fp,(void *)x,NULL,NULL,0,NULL,NULL); \ +} + +#define IMPLEMENT_PEM_write_cb_fp(name, type, str, asn1) \ +OPENSSL_EXPORT int PEM_write_##name(FILE *fp, type *x, const EVP_CIPHER *enc, \ + unsigned char *kstr, int klen, pem_password_cb *cb, \ + void *u) \ + { \ + return PEM_ASN1_write((i2d_of_void *)i2d_##asn1,str,fp,x,enc,kstr,klen,cb,u); \ + } + +#define IMPLEMENT_PEM_write_cb_fp_const(name, type, str, asn1) \ +OPENSSL_EXPORT int PEM_write_##name(FILE *fp, type *x, const EVP_CIPHER *enc, \ + unsigned char *kstr, int klen, pem_password_cb *cb, \ + void *u) \ + { \ + return PEM_ASN1_write((i2d_of_void *)i2d_##asn1,str,fp,x,enc,kstr,klen,cb,u); \ + } + +#endif + +#define IMPLEMENT_PEM_read_bio(name, type, str, asn1) \ +OPENSSL_EXPORT type *PEM_read_bio_##name(BIO *bp, type **x, pem_password_cb *cb, void *u)\ +{ \ +return PEM_ASN1_read_bio((d2i_of_void *)d2i_##asn1, str,bp,(void **)x,cb,u); \ +} + +#define IMPLEMENT_PEM_write_bio(name, type, str, asn1) \ +OPENSSL_EXPORT int PEM_write_bio_##name(BIO *bp, type *x) \ +{ \ +return PEM_ASN1_write_bio((i2d_of_void *)i2d_##asn1,str,bp,x,NULL,NULL,0,NULL,NULL); \ +} + +#define IMPLEMENT_PEM_write_bio_const(name, type, str, asn1) \ +OPENSSL_EXPORT int PEM_write_bio_##name(BIO *bp, const type *x) \ +{ \ +return PEM_ASN1_write_bio((i2d_of_void *)i2d_##asn1,str,bp,(void *)x,NULL,NULL,0,NULL,NULL); \ +} + +#define IMPLEMENT_PEM_write_cb_bio(name, type, str, asn1) \ +OPENSSL_EXPORT int PEM_write_bio_##name(BIO *bp, type *x, const EVP_CIPHER *enc, \ + unsigned char *kstr, int klen, pem_password_cb *cb, void *u) \ + { \ + return PEM_ASN1_write_bio((i2d_of_void *)i2d_##asn1,str,bp,x,enc,kstr,klen,cb,u); \ + } + +#define IMPLEMENT_PEM_write_cb_bio_const(name, type, str, asn1) \ +OPENSSL_EXPORT int PEM_write_bio_##name(BIO *bp, type *x, const EVP_CIPHER *enc, \ + unsigned char *kstr, int klen, pem_password_cb *cb, void *u) \ + { \ + return PEM_ASN1_write_bio((i2d_of_void *)i2d_##asn1,str,bp,(void *)x,enc,kstr,klen,cb,u); \ + } + +#define IMPLEMENT_PEM_write(name, type, str, asn1) \ + IMPLEMENT_PEM_write_bio(name, type, str, asn1) \ + IMPLEMENT_PEM_write_fp(name, type, str, asn1) + +#define IMPLEMENT_PEM_write_const(name, type, str, asn1) \ + IMPLEMENT_PEM_write_bio_const(name, type, str, asn1) \ + IMPLEMENT_PEM_write_fp_const(name, type, str, asn1) + +#define IMPLEMENT_PEM_write_cb(name, type, str, asn1) \ + IMPLEMENT_PEM_write_cb_bio(name, type, str, asn1) \ + IMPLEMENT_PEM_write_cb_fp(name, type, str, asn1) + +#define IMPLEMENT_PEM_write_cb_const(name, type, str, asn1) \ + IMPLEMENT_PEM_write_cb_bio_const(name, type, str, asn1) \ + IMPLEMENT_PEM_write_cb_fp_const(name, type, str, asn1) + +#define IMPLEMENT_PEM_read(name, type, str, asn1) \ + IMPLEMENT_PEM_read_bio(name, type, str, asn1) \ + IMPLEMENT_PEM_read_fp(name, type, str, asn1) + +#define IMPLEMENT_PEM_rw(name, type, str, asn1) \ + IMPLEMENT_PEM_read(name, type, str, asn1) \ + IMPLEMENT_PEM_write(name, type, str, asn1) + +#define IMPLEMENT_PEM_rw_const(name, type, str, asn1) \ + IMPLEMENT_PEM_read(name, type, str, asn1) \ + IMPLEMENT_PEM_write_const(name, type, str, asn1) + +#define IMPLEMENT_PEM_rw_cb(name, type, str, asn1) \ + IMPLEMENT_PEM_read(name, type, str, asn1) \ + IMPLEMENT_PEM_write_cb(name, type, str, asn1) + +/* These are the same except they are for the declarations */ + +#if defined(OPENSSL_NO_FP_API) + +#define DECLARE_PEM_read_fp(name, type) /**/ +#define DECLARE_PEM_write_fp(name, type) /**/ +#define DECLARE_PEM_write_cb_fp(name, type) /**/ + +#else + +#define DECLARE_PEM_read_fp(name, type) \ + OPENSSL_EXPORT type *PEM_read_##name(FILE *fp, type **x, pem_password_cb *cb, void *u); + +#define DECLARE_PEM_write_fp(name, type) \ + OPENSSL_EXPORT int PEM_write_##name(FILE *fp, type *x); + +#define DECLARE_PEM_write_fp_const(name, type) \ + OPENSSL_EXPORT int PEM_write_##name(FILE *fp, const type *x); + +#define DECLARE_PEM_write_cb_fp(name, type) \ + OPENSSL_EXPORT int PEM_write_##name(FILE *fp, type *x, const EVP_CIPHER *enc, \ + unsigned char *kstr, int klen, pem_password_cb *cb, void *u); + +#endif + +#define DECLARE_PEM_read_bio(name, type) \ + OPENSSL_EXPORT type *PEM_read_bio_##name(BIO *bp, type **x, pem_password_cb *cb, void *u); + +#define DECLARE_PEM_write_bio(name, type) \ + OPENSSL_EXPORT int PEM_write_bio_##name(BIO *bp, type *x); + +#define DECLARE_PEM_write_bio_const(name, type) \ + OPENSSL_EXPORT int PEM_write_bio_##name(BIO *bp, const type *x); + +#define DECLARE_PEM_write_cb_bio(name, type) \ + OPENSSL_EXPORT int PEM_write_bio_##name(BIO *bp, type *x, const EVP_CIPHER *enc, \ + unsigned char *kstr, int klen, pem_password_cb *cb, void *u); + + +#define DECLARE_PEM_write(name, type) \ + DECLARE_PEM_write_bio(name, type) \ + DECLARE_PEM_write_fp(name, type) + +#define DECLARE_PEM_write_const(name, type) \ + DECLARE_PEM_write_bio_const(name, type) \ + DECLARE_PEM_write_fp_const(name, type) + +#define DECLARE_PEM_write_cb(name, type) \ + DECLARE_PEM_write_cb_bio(name, type) \ + DECLARE_PEM_write_cb_fp(name, type) + +#define DECLARE_PEM_read(name, type) \ + DECLARE_PEM_read_bio(name, type) \ + DECLARE_PEM_read_fp(name, type) + +#define DECLARE_PEM_rw(name, type) \ + DECLARE_PEM_read(name, type) \ + DECLARE_PEM_write(name, type) + +#define DECLARE_PEM_rw_const(name, type) \ + DECLARE_PEM_read(name, type) \ + DECLARE_PEM_write_const(name, type) + +#define DECLARE_PEM_rw_cb(name, type) \ + DECLARE_PEM_read(name, type) \ + DECLARE_PEM_write_cb(name, type) + +/* "userdata": new with OpenSSL 0.9.4 */ +typedef int pem_password_cb(char *buf, int size, int rwflag, void *userdata); + +OPENSSL_EXPORT int PEM_get_EVP_CIPHER_INFO(char *header, EVP_CIPHER_INFO *cipher); +OPENSSL_EXPORT int PEM_do_header (EVP_CIPHER_INFO *cipher, unsigned char *data,long *len, pem_password_cb *callback,void *u); + +OPENSSL_EXPORT int PEM_read_bio(BIO *bp, char **name, char **header, unsigned char **data,long *len); +OPENSSL_EXPORT int PEM_write_bio(BIO *bp,const char *name, const char *hdr, const unsigned char *data, long len); +OPENSSL_EXPORT int PEM_bytes_read_bio(unsigned char **pdata, long *plen, char **pnm, const char *name, BIO *bp, pem_password_cb *cb, void *u); +OPENSSL_EXPORT void * PEM_ASN1_read_bio(d2i_of_void *d2i, const char *name, BIO *bp, void **x, pem_password_cb *cb, void *u); +OPENSSL_EXPORT int PEM_ASN1_write_bio(i2d_of_void *i2d,const char *name,BIO *bp, void *x, const EVP_CIPHER *enc,unsigned char *kstr,int klen, pem_password_cb *cb, void *u); + +OPENSSL_EXPORT STACK_OF(X509_INFO) * PEM_X509_INFO_read_bio(BIO *bp, STACK_OF(X509_INFO) *sk, pem_password_cb *cb, void *u); +OPENSSL_EXPORT int PEM_X509_INFO_write_bio(BIO *bp,X509_INFO *xi, EVP_CIPHER *enc, unsigned char *kstr, int klen, pem_password_cb *cd, void *u); + +OPENSSL_EXPORT int PEM_read(FILE *fp, char **name, char **header, unsigned char **data,long *len); +OPENSSL_EXPORT int PEM_write(FILE *fp, const char *name, const char *hdr, const unsigned char *data, long len); +OPENSSL_EXPORT void * PEM_ASN1_read(d2i_of_void *d2i, const char *name, FILE *fp, void **x, pem_password_cb *cb, void *u); +OPENSSL_EXPORT int PEM_ASN1_write(i2d_of_void *i2d,const char *name,FILE *fp, void *x,const EVP_CIPHER *enc,unsigned char *kstr, int klen,pem_password_cb *callback, void *u); +OPENSSL_EXPORT STACK_OF(X509_INFO) * PEM_X509_INFO_read(FILE *fp, STACK_OF(X509_INFO) *sk, pem_password_cb *cb, void *u); + +OPENSSL_EXPORT int PEM_SealInit(PEM_ENCODE_SEAL_CTX *ctx, EVP_CIPHER *type, EVP_MD *md_type, unsigned char **ek, int *ekl, unsigned char *iv, EVP_PKEY **pubk, int npubk); +OPENSSL_EXPORT void PEM_SealUpdate(PEM_ENCODE_SEAL_CTX *ctx, unsigned char *out, int *outl, unsigned char *in, int inl); +OPENSSL_EXPORT int PEM_SealFinal(PEM_ENCODE_SEAL_CTX *ctx, unsigned char *sig,int *sigl, unsigned char *out, int *outl, EVP_PKEY *priv); + +OPENSSL_EXPORT void PEM_SignInit(EVP_MD_CTX *ctx, EVP_MD *type); +OPENSSL_EXPORT void PEM_SignUpdate(EVP_MD_CTX *ctx,unsigned char *d,unsigned int cnt); +OPENSSL_EXPORT int PEM_SignFinal(EVP_MD_CTX *ctx, unsigned char *sigret, unsigned int *siglen, EVP_PKEY *pkey); + +/* PEM_def_callback treats |userdata| as a string and copies it into |buf|, + * assuming its |size| is sufficient. Returns the length of the string, or 0 + * if there is not enough room. If either |buf| or |userdata| is NULL, 0 is + * returned. Note that this is different from OpenSSL, which prompts for a + * password. */ +OPENSSL_EXPORT int PEM_def_callback(char *buf, int size, int rwflag, void *userdata); +OPENSSL_EXPORT void PEM_proc_type(char *buf, int type); +OPENSSL_EXPORT void PEM_dek_info(char *buf, const char *type, int len, char *str); + + +DECLARE_PEM_rw(X509, X509) + +DECLARE_PEM_rw(X509_AUX, X509) + +DECLARE_PEM_rw(X509_CERT_PAIR, X509_CERT_PAIR) + +DECLARE_PEM_rw(X509_REQ, X509_REQ) +DECLARE_PEM_write(X509_REQ_NEW, X509_REQ) + +DECLARE_PEM_rw(X509_CRL, X509_CRL) + +/* DECLARE_PEM_rw(PKCS7, PKCS7) */ + +DECLARE_PEM_rw(NETSCAPE_CERT_SEQUENCE, NETSCAPE_CERT_SEQUENCE) + +DECLARE_PEM_rw(PKCS8, X509_SIG) + +DECLARE_PEM_rw(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO) + +DECLARE_PEM_rw_cb(RSAPrivateKey, RSA) + +DECLARE_PEM_rw_const(RSAPublicKey, RSA) +DECLARE_PEM_rw(RSA_PUBKEY, RSA) + +#ifndef OPENSSL_NO_DSA + +DECLARE_PEM_rw_cb(DSAPrivateKey, DSA) + +DECLARE_PEM_rw(DSA_PUBKEY, DSA) + +DECLARE_PEM_rw_const(DSAparams, DSA) + +#endif + +DECLARE_PEM_rw_const(ECPKParameters, EC_GROUP) +DECLARE_PEM_rw_cb(ECPrivateKey, EC_KEY) +DECLARE_PEM_rw(EC_PUBKEY, EC_KEY) + + +DECLARE_PEM_rw_const(DHparams, DH) +DECLARE_PEM_write_const(DHxparams, DH) + + +DECLARE_PEM_rw_cb(PrivateKey, EVP_PKEY) + +DECLARE_PEM_rw(PUBKEY, EVP_PKEY) + +OPENSSL_EXPORT int PEM_write_bio_PKCS8PrivateKey_nid(BIO *bp, EVP_PKEY *x, int nid, char *kstr, int klen, pem_password_cb *cb, void *u); +OPENSSL_EXPORT int PEM_write_bio_PKCS8PrivateKey(BIO *, EVP_PKEY *, const EVP_CIPHER *, char *, int, pem_password_cb *, void *); +OPENSSL_EXPORT int i2d_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc, char *kstr, int klen, pem_password_cb *cb, void *u); +OPENSSL_EXPORT int i2d_PKCS8PrivateKey_nid_bio(BIO *bp, EVP_PKEY *x, int nid, char *kstr, int klen, pem_password_cb *cb, void *u); +OPENSSL_EXPORT EVP_PKEY *d2i_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, void *u); + +OPENSSL_EXPORT int i2d_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc, char *kstr, int klen, pem_password_cb *cb, void *u); +OPENSSL_EXPORT int i2d_PKCS8PrivateKey_nid_fp(FILE *fp, EVP_PKEY *x, int nid, char *kstr, int klen, pem_password_cb *cb, void *u); +OPENSSL_EXPORT int PEM_write_PKCS8PrivateKey_nid(FILE *fp, EVP_PKEY *x, int nid, char *kstr, int klen, pem_password_cb *cb, void *u); + +OPENSSL_EXPORT EVP_PKEY *d2i_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY **x, pem_password_cb *cb, void *u); + +OPENSSL_EXPORT int PEM_write_PKCS8PrivateKey(FILE *fp,EVP_PKEY *x,const EVP_CIPHER *enc, char *kstr,int klen, pem_password_cb *cd, void *u); + +OPENSSL_EXPORT EVP_PKEY *PEM_read_bio_Parameters(BIO *bp, EVP_PKEY **x); +OPENSSL_EXPORT int PEM_write_bio_Parameters(BIO *bp, EVP_PKEY *x); + + +OPENSSL_EXPORT EVP_PKEY *b2i_PrivateKey(const unsigned char **in, long length); +OPENSSL_EXPORT EVP_PKEY *b2i_PublicKey(const unsigned char **in, long length); +OPENSSL_EXPORT EVP_PKEY *b2i_PrivateKey_bio(BIO *in); +OPENSSL_EXPORT EVP_PKEY *b2i_PublicKey_bio(BIO *in); +OPENSSL_EXPORT int i2b_PrivateKey_bio(BIO *out, EVP_PKEY *pk); +OPENSSL_EXPORT int i2b_PublicKey_bio(BIO *out, EVP_PKEY *pk); +OPENSSL_EXPORT EVP_PKEY *b2i_PVK_bio(BIO *in, pem_password_cb *cb, void *u); +OPENSSL_EXPORT int i2b_PVK_bio(BIO *out, EVP_PKEY *pk, int enclevel, pem_password_cb *cb, void *u); + + +void ERR_load_PEM_strings(void); + + +#ifdef __cplusplus +} +#endif + +#define PEM_R_BAD_BASE64_DECODE 100 +#define PEM_R_BAD_DECRYPT 101 +#define PEM_R_BAD_END_LINE 102 +#define PEM_R_BAD_IV_CHARS 103 +#define PEM_R_BAD_PASSWORD_READ 104 +#define PEM_R_CIPHER_IS_NULL 105 +#define PEM_R_ERROR_CONVERTING_PRIVATE_KEY 106 +#define PEM_R_NOT_DEK_INFO 107 +#define PEM_R_NOT_ENCRYPTED 108 +#define PEM_R_NOT_PROC_TYPE 109 +#define PEM_R_NO_START_LINE 110 +#define PEM_R_READ_KEY 111 +#define PEM_R_SHORT_HEADER 112 +#define PEM_R_UNSUPPORTED_CIPHER 113 +#define PEM_R_UNSUPPORTED_ENCRYPTION 114 + +#endif /* OPENSSL_HEADER_PEM_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/pkcs12.h b/TMessagesProj/jni/boringssl/include/openssl/pkcs12.h new file mode 100644 index 00000000..b5e95163 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/pkcs12.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is provided in order to make compiling against code that expects + OpenSSL easier. */ + +#include "pkcs8.h" diff --git a/TMessagesProj/jni/boringssl/include/openssl/pkcs7.h b/TMessagesProj/jni/boringssl/include/openssl/pkcs7.h new file mode 100644 index 00000000..6e5e4330 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/pkcs7.h @@ -0,0 +1,16 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is provided in order to make compiling against code that expects + OpenSSL easier. */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/pkcs8.h b/TMessagesProj/jni/boringssl/include/openssl/pkcs8.h new file mode 100644 index 00000000..677b46f2 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/pkcs8.h @@ -0,0 +1,199 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + + +#ifndef OPENSSL_HEADER_PKCS8_H +#define OPENSSL_HEADER_PKCS8_H + +#include +#include + + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* PKCS8_encrypt_pbe serializes and encrypts a PKCS8_PRIV_KEY_INFO with PBES1 as + * defined in PKCS #5. Only pbeWithSHAAnd128BitRC4, + * pbeWithSHAAnd3-KeyTripleDES-CBC and pbeWithSHA1And40BitRC2, defined in PKCS + * #12, are supported. The |pass_raw_len| bytes pointed to by |pass_raw| are + * used as the password. Note that any conversions from the password as + * supplied in a text string (such as those specified in B.1 of PKCS #12) must + * be performed by the caller. + * + * If |salt| is NULL, a random salt of |salt_len| bytes is generated. If + * |salt_len| is zero, a default salt length is used instead. + * + * The resulting structure is stored in an X509_SIG which must be freed by the + * caller. + * + * TODO(davidben): Really? An X509_SIG? OpenSSL probably did that because it has + * the same structure as EncryptedPrivateKeyInfo. */ +OPENSSL_EXPORT X509_SIG *PKCS8_encrypt_pbe(int pbe_nid, + const uint8_t *pass_raw, + size_t pass_raw_len, + uint8_t *salt, size_t salt_len, + int iterations, + PKCS8_PRIV_KEY_INFO *p8inf); + +/* PKCS8_decrypt_pbe decrypts and decodes a PKCS8_PRIV_KEY_INFO with PBES1 as + * defined in PKCS #5. Only pbeWithSHAAnd128BitRC4, + * pbeWithSHAAnd3-KeyTripleDES-CBC and pbeWithSHA1And40BitRC2, defined in PKCS + * #12, are supported. The |pass_raw_len| bytes pointed to by |pass_raw| are + * used as the password. Note that any conversions from the password as + * supplied in a text string (such as those specified in B.1 of PKCS #12) must + * be performed by the caller. + * + * The resulting structure must be freed by the caller. */ +OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *PKCS8_decrypt_pbe(X509_SIG *pkcs8, + const uint8_t *pass_raw, + size_t pass_raw_len); + + +/* Deprecated functions. */ + +/* PKCS8_encrypt calls PKCS8_encrypt_pbe after treating |pass| as an ASCII + * string, appending U+0000, and converting to UCS-2. (So the empty password + * encodes as two NUL bytes.) The |cipher| argument is ignored. */ +OPENSSL_EXPORT X509_SIG *PKCS8_encrypt(int pbe_nid, const EVP_CIPHER *cipher, + const char *pass, int pass_len, + uint8_t *salt, size_t salt_len, + int iterations, + PKCS8_PRIV_KEY_INFO *p8inf); + +/* PKCS8_decrypt calls PKCS8_decrypt_pbe after treating |pass| as an ASCII + * string, appending U+0000, and converting to UCS-2. (So the empty password + * encodes as two NUL bytes.) */ +OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *PKCS8_decrypt(X509_SIG *pkcs8, + const char *pass, + int pass_len); + +/* PKCS12_get_key_and_certs parses a PKCS#12 structure from |in|, authenticates + * and decrypts it using |password|, sets |*out_key| to the included private + * key and appends the included certificates to |out_certs|. It returns one on + * success and zero on error. The caller takes ownership of the outputs. */ +OPENSSL_EXPORT int PKCS12_get_key_and_certs(EVP_PKEY **out_key, + STACK_OF(X509) *out_certs, + CBS *in, const char *password); + + +/* Deprecated functions. */ + +/* PKCS12_PBE_add does nothing. It exists for compatibility with OpenSSL. */ +OPENSSL_EXPORT void PKCS12_PBE_add(void); + +/* d2i_PKCS12 is a dummy function that copies |*ber_bytes| into a + * |PKCS12| structure. The |out_p12| argument must be NULL. On exit, + * |*ber_bytes| will be advanced by |ber_len|. It returns a fresh |PKCS12| + * structure or NULL on error. + * + * Note: unlike other d2i functions, |d2i_PKCS12| will always consume |ber_len| + * bytes.*/ +OPENSSL_EXPORT PKCS12 *d2i_PKCS12(PKCS12 **out_p12, const uint8_t **ber_bytes, + size_t ber_len); + +/* d2i_PKCS12_bio acts like |d2i_PKCS12| but reads from a |BIO|. */ +OPENSSL_EXPORT PKCS12* d2i_PKCS12_bio(BIO *bio, PKCS12 **out_p12); + +/* d2i_PKCS12_fp acts like |d2i_PKCS12| but reads from a |FILE|. */ +OPENSSL_EXPORT PKCS12* d2i_PKCS12_fp(FILE *fp, PKCS12 **out_p12); + +/* PKCS12_parse calls |PKCS12_get_key_and_certs| on the ASN.1 data stored in + * |p12|. The |out_pkey| and |out_cert| arguments must not be NULL and, on + * successful exit, the private key and first certificate will be stored in + * them. The |out_ca_certs| argument may be NULL but, if not, then any extra + * certificates will be appended to |*out_ca_certs|. If |*out_ca_certs| is NULL + * then it will be set to a freshly allocated stack containing the extra certs. + * + * It returns one on success and zero on error. */ +OPENSSL_EXPORT int PKCS12_parse(const PKCS12 *p12, const char *password, + EVP_PKEY **out_pkey, X509 **out_cert, + STACK_OF(X509) **out_ca_certs); + +/* PKCS12_free frees |p12| and its contents. */ +OPENSSL_EXPORT void PKCS12_free(PKCS12 *p12); + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define PKCS8_R_BAD_PKCS12_DATA 100 +#define PKCS8_R_BAD_PKCS12_VERSION 101 +#define PKCS8_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER 102 +#define PKCS8_R_CRYPT_ERROR 103 +#define PKCS8_R_DECODE_ERROR 104 +#define PKCS8_R_ENCODE_ERROR 105 +#define PKCS8_R_ENCRYPT_ERROR 106 +#define PKCS8_R_ERROR_SETTING_CIPHER_PARAMS 107 +#define PKCS8_R_INCORRECT_PASSWORD 108 +#define PKCS8_R_KEYGEN_FAILURE 109 +#define PKCS8_R_KEY_GEN_ERROR 110 +#define PKCS8_R_METHOD_NOT_SUPPORTED 111 +#define PKCS8_R_MISSING_MAC 112 +#define PKCS8_R_MULTIPLE_PRIVATE_KEYS_IN_PKCS12 113 +#define PKCS8_R_PKCS12_PUBLIC_KEY_INTEGRITY_NOT_SUPPORTED 114 +#define PKCS8_R_PKCS12_TOO_DEEPLY_NESTED 115 +#define PKCS8_R_PRIVATE_KEY_DECODE_ERROR 116 +#define PKCS8_R_PRIVATE_KEY_ENCODE_ERROR 117 +#define PKCS8_R_TOO_LONG 118 +#define PKCS8_R_UNKNOWN_ALGORITHM 119 +#define PKCS8_R_UNKNOWN_CIPHER 120 +#define PKCS8_R_UNKNOWN_CIPHER_ALGORITHM 121 +#define PKCS8_R_UNKNOWN_DIGEST 122 +#define PKCS8_R_UNKNOWN_HASH 123 +#define PKCS8_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM 124 + +#endif /* OPENSSL_HEADER_PKCS8_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/poly1305.h b/TMessagesProj/jni/boringssl/include/openssl/poly1305.h new file mode 100644 index 00000000..0da9f6e1 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/poly1305.h @@ -0,0 +1,50 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_POLY1305_H +#define OPENSSL_HEADER_POLY1305_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef uint8_t poly1305_state[512]; + +/* poly1305_init sets up |state| so that it can be used to calculate an + * authentication tag with the one-time key |key|. Note that |key| is a + * one-time key and therefore there is no `reset' method because that would + * enable several messages to be authenticated with the same key. */ +OPENSSL_EXPORT void CRYPTO_poly1305_init(poly1305_state* state, + const uint8_t key[32]); + +/* poly1305_update processes |in_len| bytes from |in|. It can be called zero or + * more times after poly1305_init. */ +OPENSSL_EXPORT void CRYPTO_poly1305_update(poly1305_state* state, + const uint8_t* in, + size_t in_len); + +/* poly1305_finish completes the poly1305 calculation and writes a 16 byte + * authentication tag to |mac|. The |mac| address must be 16-byte aligned. */ +OPENSSL_EXPORT void CRYPTO_poly1305_finish(poly1305_state* state, + uint8_t mac[16]); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_POLY1305_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/pqueue.h b/TMessagesProj/jni/boringssl/include/openssl/pqueue.h new file mode 100644 index 00000000..ceb1fa2a --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/pqueue.h @@ -0,0 +1,146 @@ +/* + * DTLS implementation written by Nagendra Modadugu + * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. + */ +/* ==================================================================== + * Copyright (c) 1999-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef OPENSSL_HEADER_PQUEUE_H +#define OPENSSL_HEADER_PQUEUE_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Priority queue. + * + * The priority queue maintains a linked-list of nodes, each with a unique, + * 64-bit priority, in ascending priority order. */ + +typedef struct _pqueue *pqueue; + +typedef struct _pitem { + uint8_t priority[8]; /* 64-bit value in big-endian encoding */ + void *data; + struct _pitem *next; +} pitem; + +typedef struct _pitem *piterator; + + +/* Creating and freeing queues. */ + +/* pqueue_new allocates a fresh, empty priority queue object and returns it, or + * NULL on error. */ +OPENSSL_EXPORT pqueue pqueue_new(void); + +/* pqueue_free frees |pq| but not any of the items it points to. Thus |pq| must + * be empty or a memory leak will occur. */ +OPENSSL_EXPORT void pqueue_free(pqueue pq); + + +/* Creating and freeing items. */ + +/* pitem_new allocates a fresh priority queue item that points at |data| and + * has a priority given by |prio64be|, which is a 64-bit, unsigned number + * expressed in big-endian form. It returns the fresh item, or NULL on + * error. */ +OPENSSL_EXPORT pitem *pitem_new(uint8_t prio64be[8], void *data); + +/* pitem_free frees |item|, but not any data that it points to. */ +OPENSSL_EXPORT void pitem_free(pitem *item); + + +/* Queue accessor functions */ + +/* pqueue_peek returns the item with the smallest priority from |pq|, or NULL + * if empty. */ +OPENSSL_EXPORT pitem *pqueue_peek(pqueue pq); + +/* pqueue_find returns the item whose priority matches |prio64be| or NULL if no + * such item exists. */ +OPENSSL_EXPORT pitem *pqueue_find(pqueue pq, uint8_t *prio64be); + + +/* Queue mutation functions */ + +/* pqueue_insert inserts |item| into |pq| and returns item. */ +OPENSSL_EXPORT pitem *pqueue_insert(pqueue pq, pitem *item); + +/* pqueue_pop takes the item with the least priority from |pq| and returns it, + * or NULL if |pq| is empty. */ +OPENSSL_EXPORT pitem *pqueue_pop(pqueue pq); + +/* pqueue_size returns the number of items in |pq|. */ +OPENSSL_EXPORT size_t pqueue_size(pqueue pq); + + +/* Iterating */ + +/* pqueue_iterator returns an iterator that can be used to iterate over the + * contents of the queue. */ +OPENSSL_EXPORT piterator pqueue_iterator(pqueue pq); + +/* pqueue_next returns the current value of |iter| and advances it to the next + * position. If the iterator has advanced over all the elements, it returns + * NULL. */ +OPENSSL_EXPORT pitem *pqueue_next(piterator *iter); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_PQUEUE_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/rand.h b/TMessagesProj/jni/boringssl/include/openssl/rand.h new file mode 100644 index 00000000..335c76ed --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/rand.h @@ -0,0 +1,97 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_RAND_H +#define OPENSSL_HEADER_RAND_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Random number generation. */ + + +/* RAND_bytes writes |len| bytes of random data to |buf| and returns one. */ +OPENSSL_EXPORT int RAND_bytes(uint8_t *buf, size_t len); + +/* RAND_cleanup frees any resources used by the RNG. This is not safe if other + * threads might still be calling |RAND_bytes|. */ +OPENSSL_EXPORT void RAND_cleanup(void); + + +/* Obscure functions. */ + +#if !defined(OPENSSL_WINDOWS) +/* RAND_set_urandom_fd causes the module to use a copy of |fd| for system + * randomness rather opening /dev/urandom internally. The caller retains + * ownership of |fd| and is at liberty to close it at any time. This is useful + * if, due to a sandbox, /dev/urandom isn't available. If used, it must be + * called before |RAND_bytes| is called in the current address space. + * + * |RAND_set_urandom_fd| does not buffer any entropy, so it is safe to call + * |fork| between |RAND_set_urandom_fd| and the first call to |RAND_bytes|. */ +OPENSSL_EXPORT void RAND_set_urandom_fd(int fd); +#endif + + +/* Deprecated functions */ + +/* RAND_pseudo_bytes is a wrapper around |RAND_bytes|. */ +OPENSSL_EXPORT int RAND_pseudo_bytes(uint8_t *buf, size_t len); + +/* RAND_seed does nothing. */ +OPENSSL_EXPORT void RAND_seed(const void *buf, int num); + +/* RAND_load_file returns a nonnegative number. */ +OPENSSL_EXPORT int RAND_load_file(const char *path, long num); + +/* RAND_add does nothing. */ +OPENSSL_EXPORT void RAND_add(const void *buf, int num, double entropy); + +/* RAND_egd returns 255. */ +OPENSSL_EXPORT int RAND_egd(const char *); + +/* RAND_poll returns one. */ +OPENSSL_EXPORT int RAND_poll(void); + +/* RAND_status returns one. */ +OPENSSL_EXPORT int RAND_status(void); + +/* rand_meth_st is typedefed to |RAND_METHOD| in base.h. It isn't used; it + * exists only to be the return type of |RAND_SSLeay|. It's + * external so that variables of this type can be initialized. */ +struct rand_meth_st { + void (*seed) (const void *buf, int num); + int (*bytes) (uint8_t *buf, size_t num); + void (*cleanup) (void); + void (*add) (const void *buf, int num, double entropy); + int (*pseudorand) (uint8_t *buf, size_t num); + int (*status) (void); +}; + +/* RAND_SSLeay returns a pointer to a dummy |RAND_METHOD|. */ +OPENSSL_EXPORT RAND_METHOD *RAND_SSLeay(void); + +/* RAND_set_rand_method does nothing. */ +OPENSSL_EXPORT void RAND_set_rand_method(const RAND_METHOD *); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_RAND_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/rc4.h b/TMessagesProj/jni/boringssl/include/openssl/rc4.h new file mode 100644 index 00000000..0619cac3 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/rc4.h @@ -0,0 +1,90 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_RC4_H +#define OPENSSL_HEADER_RC4_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* RC4. */ + + +struct rc4_key_st { + uint32_t x, y; + uint32_t data[256]; +} /* RC4_KEY */; + +/* RC4_set_key performs an RC4 key schedule and initialises |rc4key| with |len| + * bytes of key material from |key|. */ +OPENSSL_EXPORT void RC4_set_key(RC4_KEY *rc4key, unsigned len, + const uint8_t *key); + +/* RC4 encrypts (or decrypts, it's the same with RC4) |len| bytes from |in| to + * |out|. */ +OPENSSL_EXPORT void RC4(RC4_KEY *key, size_t len, const uint8_t *in, + uint8_t *out); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_RC4_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/rsa.h b/TMessagesProj/jni/boringssl/include/openssl/rsa.h new file mode 100644 index 00000000..0d87f278 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/rsa.h @@ -0,0 +1,633 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_RSA_H +#define OPENSSL_HEADER_RSA_H + +#include + +#include +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* rsa.h contains functions for handling encryption and signature using RSA. */ + + +/* Allocation and destruction. */ + +/* RSA_new returns a new, empty RSA object or NULL on error. */ +OPENSSL_EXPORT RSA *RSA_new(void); + +/* RSA_new_method acts the same as |RSA_new| but takes an explicit |ENGINE|. */ +OPENSSL_EXPORT RSA *RSA_new_method(const ENGINE *engine); + +/* RSA_free decrements the reference count of |rsa| and frees it if the + * reference count drops to zero. */ +OPENSSL_EXPORT void RSA_free(RSA *rsa); + +/* RSA_up_ref increments the reference count of |rsa|. */ +OPENSSL_EXPORT int RSA_up_ref(RSA *rsa); + + +/* Key generation. */ + +/* RSA_generate_key_ex generates a new RSA key where the modulus has size + * |bits| and the public exponent is |e|. If unsure, |RSA_F4| is a good value + * for |e|. If |cb| is not NULL then it is called during the key generation + * process. In addition to the calls documented for |BN_generate_prime_ex|, it + * is called with event=2 when the n'th prime is rejected as unsuitable and + * with event=3 when a suitable value for |p| is found. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e, + BN_GENCB *cb); + +/* RSA_generate_multi_prime_key acts like |RSA_generate_key_ex| but can + * generate an RSA private key with more than two primes. */ +OPENSSL_EXPORT int RSA_generate_multi_prime_key(RSA *rsa, int bits, + int num_primes, BIGNUM *e, + BN_GENCB *cb); + + +/* Encryption / Decryption */ + +/* Padding types for encryption. */ +#define RSA_PKCS1_PADDING 1 +#define RSA_NO_PADDING 3 +#define RSA_PKCS1_OAEP_PADDING 4 +/* RSA_PKCS1_PSS_PADDING can only be used via the EVP interface. */ +#define RSA_PKCS1_PSS_PADDING 6 + +/* RSA_encrypt encrypts |in_len| bytes from |in| to the public key from |rsa| + * and writes, at most, |max_out| bytes of encrypted data to |out|. The + * |max_out| argument must be, at least, |RSA_size| in order to ensure success. + * + * It returns 1 on success or zero on error. + * + * The |padding| argument must be one of the |RSA_*_PADDING| values. If in + * doubt, |RSA_PKCS1_PADDING| is the most common but |RSA_PKCS1_OAEP_PADDING| + * is the most secure. */ +OPENSSL_EXPORT int RSA_encrypt(RSA *rsa, size_t *out_len, uint8_t *out, + size_t max_out, const uint8_t *in, size_t in_len, + int padding); + +/* RSA_decrypt decrypts |in_len| bytes from |in| with the private key from + * |rsa| and writes, at most, |max_out| bytes of plaintext to |out|. The + * |max_out| argument must be, at least, |RSA_size| in order to ensure success. + * + * It returns 1 on success or zero on error. + * + * The |padding| argument must be one of the |RSA_*_PADDING| values. If in + * doubt, |RSA_PKCS1_PADDING| is the most common but |RSA_PKCS1_OAEP_PADDING| + * is the most secure. */ +OPENSSL_EXPORT int RSA_decrypt(RSA *rsa, size_t *out_len, uint8_t *out, + size_t max_out, const uint8_t *in, size_t in_len, + int padding); + +/* RSA_public_encrypt encrypts |flen| bytes from |from| to the public key in + * |rsa| and writes the encrypted data to |to|. The |to| buffer must have at + * least |RSA_size| bytes of space. It returns the number of bytes written, or + * -1 on error. The |padding| argument must be one of the |RSA_*_PADDING| + * values. If in doubt, |RSA_PKCS1_PADDING| is the most common but + * |RSA_PKCS1_OAEP_PADDING| is the most secure. + * + * WARNING: this function is dangerous because it breaks the usual return value + * convention. Use |RSA_encrypt| instead. */ +OPENSSL_EXPORT int RSA_public_encrypt(int flen, const uint8_t *from, + uint8_t *to, RSA *rsa, int padding); + +/* RSA_private_decrypt decrypts |flen| bytes from |from| with the public key in + * |rsa| and writes the plaintext to |to|. The |to| buffer must have at + * least |RSA_size| bytes of space. It returns the number of bytes written, or + * -1 on error. The |padding| argument must be one of the |RSA_*_PADDING| + * values. If in doubt, |RSA_PKCS1_PADDING| is the most common but + * |RSA_PKCS1_OAEP_PADDING| is the most secure. + * + * WARNING: this function is dangerous because it breaks the usual return value + * convention. Use |RSA_decrypt| instead. */ +OPENSSL_EXPORT int RSA_private_decrypt(int flen, const uint8_t *from, + uint8_t *to, RSA *rsa, int padding); + +/* RSA_message_index_PKCS1_type_2 performs the first step of a PKCS #1 padding + * check for decryption. If the |from_len| bytes pointed to at |from| are a + * valid PKCS #1 message, it returns one and sets |*out_index| to the start of + * the unpadded message. The unpadded message is a suffix of the input and has + * length |from_len - *out_index|. Otherwise, it returns zero and sets + * |*out_index| to zero. This function runs in time independent of the input + * data and is intended to be used directly to avoid Bleichenbacher's attack. + * + * WARNING: This function behaves differently from the usual OpenSSL convention + * in that it does NOT put an error on the queue in the error case. */ +OPENSSL_EXPORT int RSA_message_index_PKCS1_type_2(const uint8_t *from, + size_t from_len, + size_t *out_index); + + +/* Signing / Verification */ + +/* RSA_sign signs |in_len| bytes of digest from |in| with |rsa| and writes, at + * most, |RSA_size(rsa)| bytes to |out|. On successful return, the actual + * number of bytes written is written to |*out_len|. + * + * The |hash_nid| argument identifies the hash function used to calculate |in| + * and is embedded in the resulting signature. For example, it might be + * |NID_sha256|. + * + * It returns 1 on success and zero on error. */ +OPENSSL_EXPORT int RSA_sign(int hash_nid, const uint8_t *in, + unsigned int in_len, uint8_t *out, + unsigned int *out_len, RSA *rsa); + +/* RSA_sign_raw signs |in_len| bytes from |in| with the public key from |rsa| + * and writes, at most, |max_out| bytes of signature data to |out|. The + * |max_out| argument must be, at least, |RSA_size| in order to ensure success. + * + * It returns 1 on success or zero on error. + * + * The |padding| argument must be one of the |RSA_*_PADDING| values. If in + * doubt, |RSA_PKCS1_PADDING| is the most common. */ +OPENSSL_EXPORT int RSA_sign_raw(RSA *rsa, size_t *out_len, uint8_t *out, + size_t max_out, const uint8_t *in, + size_t in_len, int padding); + +/* RSA_verify verifies that |sig_len| bytes from |sig| are a valid, PKCS#1 + * signature of |msg_len| bytes at |msg| by |rsa|. + * + * The |hash_nid| argument identifies the hash function used to calculate |in| + * and is embedded in the resulting signature in order to prevent hash + * confusion attacks. For example, it might be |NID_sha256|. + * + * It returns one if the signature is valid and zero otherwise. + * + * WARNING: this differs from the original, OpenSSL function which additionally + * returned -1 on error. */ +OPENSSL_EXPORT int RSA_verify(int hash_nid, const uint8_t *msg, size_t msg_len, + const uint8_t *sig, size_t sig_len, RSA *rsa); + +/* RSA_verify_raw verifies |in_len| bytes of signature from |in| using the + * public key from |rsa| and writes, at most, |max_out| bytes of plaintext to + * |out|. The |max_out| argument must be, at least, |RSA_size| in order to + * ensure success. + * + * It returns 1 on success or zero on error. + * + * The |padding| argument must be one of the |RSA_*_PADDING| values. If in + * doubt, |RSA_PKCS1_PADDING| is the most common. */ +OPENSSL_EXPORT int RSA_verify_raw(RSA *rsa, size_t *out_len, uint8_t *out, + size_t max_out, const uint8_t *in, + size_t in_len, int padding); + +/* RSA_private_encrypt encrypts |flen| bytes from |from| with the private key in + * |rsa| and writes the encrypted data to |to|. The |to| buffer must have at + * least |RSA_size| bytes of space. It returns the number of bytes written, or + * -1 on error. The |padding| argument must be one of the |RSA_*_PADDING| + * values. If in doubt, |RSA_PKCS1_PADDING| is the most common. + * + * WARNING: this function is dangerous because it breaks the usual return value + * convention. Use |RSA_sign_raw| instead. */ +OPENSSL_EXPORT int RSA_private_encrypt(int flen, const uint8_t *from, + uint8_t *to, RSA *rsa, int padding); + +/* RSA_public_decrypt verifies |flen| bytes of signature from |from| using the + * public key in |rsa| and writes the plaintext to |to|. The |to| buffer must + * have at least |RSA_size| bytes of space. It returns the number of bytes + * written, or -1 on error. The |padding| argument must be one of the + * |RSA_*_PADDING| values. If in doubt, |RSA_PKCS1_PADDING| is the most common. + * + * WARNING: this function is dangerous because it breaks the usual return value + * convention. Use |RSA_verify_raw| instead. */ +OPENSSL_EXPORT int RSA_public_decrypt(int flen, const uint8_t *from, + uint8_t *to, RSA *rsa, int padding); + + +/* Utility functions. */ + +/* RSA_size returns the number of bytes in the modulus, which is also the size + * of a signature or encrypted value using |rsa|. */ +OPENSSL_EXPORT unsigned RSA_size(const RSA *rsa); + +/* RSA_is_opaque returns one if |rsa| is opaque and doesn't expose its key + * material. Otherwise it returns zero. */ +OPENSSL_EXPORT int RSA_is_opaque(const RSA *rsa); + +/* RSA_supports_digest returns one if |rsa| supports signing digests + * of type |md|. Otherwise it returns zero. */ +OPENSSL_EXPORT int RSA_supports_digest(const RSA *rsa, const EVP_MD *md); + +/* RSAPublicKey_dup allocates a fresh |RSA| and copies the public key from + * |rsa| into it. It returns the fresh |RSA| object, or NULL on error. */ +OPENSSL_EXPORT RSA *RSAPublicKey_dup(const RSA *rsa); + +/* RSAPrivateKey_dup allocates a fresh |RSA| and copies the private key from + * |rsa| into it. It returns the fresh |RSA| object, or NULL on error. */ +OPENSSL_EXPORT RSA *RSAPrivateKey_dup(const RSA *rsa); + +/* RSA_check_key performs basic validatity tests on |rsa|. It returns one if + * they pass and zero otherwise. Opaque keys and public keys always pass. If it + * returns zero then a more detailed error is available on the error queue. */ +OPENSSL_EXPORT int RSA_check_key(const RSA *rsa); + +/* RSA_recover_crt_params uses |rsa->n|, |rsa->d| and |rsa->e| in order to + * calculate the two primes used and thus the precomputed, CRT values. These + * values are set in the |p|, |q|, |dmp1|, |dmq1| and |iqmp| members of |rsa|, + * which must be |NULL| on entry. It returns one on success and zero + * otherwise. */ +OPENSSL_EXPORT int RSA_recover_crt_params(RSA *rsa); + +/* RSA_verify_PKCS1_PSS_mgf1 verifies that |EM| is a correct PSS padding of + * |mHash|, where |mHash| is a digest produced by |Hash|. |EM| must point to + * exactly |RSA_size(rsa)| bytes of data. The |mgf1Hash| argument specifies the + * hash function for generating the mask. If NULL, |Hash| is used. The |sLen| + * argument specifies the expected salt length in bytes. If |sLen| is -1 then + * the salt length is the same as the hash length. If -2, then the salt length + * is maximal and is taken from the size of |EM|. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int RSA_verify_PKCS1_PSS_mgf1(RSA *rsa, const uint8_t *mHash, + const EVP_MD *Hash, + const EVP_MD *mgf1Hash, + const uint8_t *EM, int sLen); + +/* RSA_padding_add_PKCS1_PSS_mgf1 writes a PSS padding of |mHash| to |EM|, + * where |mHash| is a digest produced by |Hash|. |RSA_size(rsa)| bytes of + * output will be written to |EM|. The |mgf1Hash| argument specifies the hash + * function for generating the mask. If NULL, |Hash| is used. The |sLen| + * argument specifies the expected salt length in bytes. If |sLen| is -1 then + * the salt length is the same as the hash length. If -2, then the salt length + * is maximal given the space in |EM|. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int RSA_padding_add_PKCS1_PSS_mgf1(RSA *rsa, uint8_t *EM, + const uint8_t *mHash, + const EVP_MD *Hash, + const EVP_MD *mgf1Hash, + int sLen); + +/* RSA_add_pkcs1_prefix builds a version of |msg| prefixed with the DigestInfo + * header for the given hash function and sets |out_msg| to point to it. On + * successful return, |*out_msg| may be allocated memory and, if so, + * |*is_alloced| will be 1. */ +OPENSSL_EXPORT int RSA_add_pkcs1_prefix(uint8_t **out_msg, size_t *out_msg_len, + int *is_alloced, int hash_nid, + const uint8_t *msg, size_t msg_len); + + +/* ASN.1 functions. */ + +/* RSA_parse_public_key parses a DER-encoded RSAPublicKey structure (RFC 3447) + * from |cbs| and advances |cbs|. It returns a newly-allocated |RSA| or NULL on + * error. */ +OPENSSL_EXPORT RSA *RSA_parse_public_key(CBS *cbs); + +/* RSA_public_key_from_bytes parses |in| as a DER-encoded RSAPublicKey structure + * (RFC 3447). It returns a newly-allocated |RSA| or NULL on error. */ +OPENSSL_EXPORT RSA *RSA_public_key_from_bytes(const uint8_t *in, size_t in_len); + +/* RSA_marshal_public_key marshals |rsa| as a DER-encoded RSAPublicKey structure + * (RFC 3447) and appends the result to |cbb|. It returns one on success and + * zero on failure. */ +OPENSSL_EXPORT int RSA_marshal_public_key(CBB *cbb, const RSA *rsa); + +/* RSA_public_key_to_bytes marshals |rsa| as a DER-encoded RSAPublicKey + * structure (RFC 3447) and, on success, sets |*out_bytes| to a newly allocated + * buffer containing the result and returns one. Otherwise, it returns zero. The + * result should be freed with |OPENSSL_free|. */ +OPENSSL_EXPORT int RSA_public_key_to_bytes(uint8_t **out_bytes, size_t *out_len, + const RSA *rsa); + +/* RSA_parse_private_key parses a DER-encoded RSAPrivateKey structure (RFC 3447) + * from |cbs| and advances |cbs|. It returns a newly-allocated |RSA| or NULL on + * error. */ +OPENSSL_EXPORT RSA *RSA_parse_private_key(CBS *cbs); + +/* RSA_private_key_from_bytes parses |in| as a DER-encoded RSAPrivateKey + * structure (RFC 3447). It returns a newly-allocated |RSA| or NULL on error. */ +OPENSSL_EXPORT RSA *RSA_private_key_from_bytes(const uint8_t *in, + size_t in_len); + +/* RSA_marshal_private_key marshals |rsa| as a DER-encoded RSAPrivateKey + * structure (RFC 3447) and appends the result to |cbb|. It returns one on + * success and zero on failure. */ +OPENSSL_EXPORT int RSA_marshal_private_key(CBB *cbb, const RSA *rsa); + +/* RSA_private_key_to_bytes marshals |rsa| as a DER-encoded RSAPrivateKey + * structure (RFC 3447) and, on success, sets |*out_bytes| to a newly allocated + * buffer containing the result and returns one. Otherwise, it returns zero. The + * result should be freed with |OPENSSL_free|. */ +OPENSSL_EXPORT int RSA_private_key_to_bytes(uint8_t **out_bytes, + size_t *out_len, const RSA *rsa); + + +/* Deprecated functions. */ + +/* d2i_RSAPublicKey parses an ASN.1, DER-encoded, RSA public key from |len| + * bytes at |*inp|. If |out| is not NULL then, on exit, a pointer to the result + * is in |*out|. If |*out| is already non-NULL on entry then the result is + * written directly into |*out|, otherwise a fresh |RSA| is allocated. On + * successful exit, |*inp| is advanced past the DER structure. It returns the + * result or NULL on error. */ +OPENSSL_EXPORT RSA *d2i_RSAPublicKey(RSA **out, const uint8_t **inp, long len); + +/* i2d_RSAPublicKey marshals |in| to an ASN.1, DER structure. If |outp| is not + * NULL then the result is written to |*outp| and |*outp| is advanced just past + * the output. It returns the number of bytes in the result, whether written or + * not, or a negative value on error. */ +OPENSSL_EXPORT int i2d_RSAPublicKey(const RSA *in, uint8_t **outp); + +/* d2i_RSAPrivateKey parses an ASN.1, DER-encoded, RSA private key from |len| + * bytes at |*inp|. If |out| is not NULL then, on exit, a pointer to the result + * is in |*out|. If |*out| is already non-NULL on entry then the result is + * written directly into |*out|, otherwise a fresh |RSA| is allocated. On + * successful exit, |*inp| is advanced past the DER structure. It returns the + * result or NULL on error. */ +OPENSSL_EXPORT RSA *d2i_RSAPrivateKey(RSA **out, const uint8_t **inp, long len); + +/* i2d_RSAPrivateKey marshals |in| to an ASN.1, DER structure. If |outp| is not + * NULL then the result is written to |*outp| and |*outp| is advanced just past + * the output. It returns the number of bytes in the result, whether written or + * not, or a negative value on error. */ +OPENSSL_EXPORT int i2d_RSAPrivateKey(const RSA *in, uint8_t **outp); + + +/* ex_data functions. + * + * See |ex_data.h| for details. */ + +OPENSSL_EXPORT int RSA_get_ex_new_index(long argl, void *argp, + CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func); +OPENSSL_EXPORT int RSA_set_ex_data(RSA *r, int idx, void *arg); +OPENSSL_EXPORT void *RSA_get_ex_data(const RSA *r, int idx); + +/* RSA_FLAG_OPAQUE specifies that this RSA_METHOD does not expose its key + * material. This may be set if, for instance, it is wrapping some other crypto + * API, like a platform key store. */ +#define RSA_FLAG_OPAQUE 1 + +/* RSA_FLAG_CACHE_PUBLIC causes a precomputed Montgomery context to be created, + * on demand, for the public key operations. */ +#define RSA_FLAG_CACHE_PUBLIC 2 + +/* RSA_FLAG_CACHE_PRIVATE causes a precomputed Montgomery context to be + * created, on demand, for the private key operations. */ +#define RSA_FLAG_CACHE_PRIVATE 4 + +/* RSA_FLAG_NO_BLINDING disables blinding of private operations. */ +#define RSA_FLAG_NO_BLINDING 8 + +/* RSA_FLAG_EXT_PKEY means that private key operations will be handled by + * |mod_exp| and that they do not depend on the private key components being + * present: for example a key stored in external hardware. */ +#define RSA_FLAG_EXT_PKEY 0x20 + +/* RSA_FLAG_SIGN_VER causes the |sign| and |verify| functions of |rsa_meth_st| + * to be called when set. */ +#define RSA_FLAG_SIGN_VER 0x40 + + +/* RSA public exponent values. */ + +#define RSA_3 0x3 +#define RSA_F4 0x10001 + + +/* Deprecated functions. */ + +/* RSA_blinding_on returns one. */ +OPENSSL_EXPORT int RSA_blinding_on(RSA *rsa, BN_CTX *ctx); + +/* RSA_generate_key behaves like |RSA_generate_key_ex|, which is what you + * should use instead. It returns NULL on error, or a newly-allocated |RSA| on + * success. This function is provided for compatibility only. The |callback| + * and |cb_arg| parameters must be NULL. */ +OPENSSL_EXPORT RSA *RSA_generate_key(int bits, unsigned long e, void *callback, + void *cb_arg); + +typedef struct rsa_pss_params_st { + X509_ALGOR *hashAlgorithm; + X509_ALGOR *maskGenAlgorithm; + ASN1_INTEGER *saltLength; + ASN1_INTEGER *trailerField; +} RSA_PSS_PARAMS; + +DECLARE_ASN1_FUNCTIONS(RSA_PSS_PARAMS) + + +struct rsa_meth_st { + struct openssl_method_common_st common; + + void *app_data; + + int (*init)(RSA *rsa); + int (*finish)(RSA *rsa); + + /* size returns the size of the RSA modulus in bytes. */ + size_t (*size)(const RSA *rsa); + + int (*sign)(int type, const uint8_t *m, unsigned int m_length, + uint8_t *sigret, unsigned int *siglen, const RSA *rsa); + + int (*verify)(int dtype, const uint8_t *m, unsigned int m_length, + const uint8_t *sigbuf, unsigned int siglen, const RSA *rsa); + + + /* These functions mirror the |RSA_*| functions of the same name. */ + int (*encrypt)(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, + const uint8_t *in, size_t in_len, int padding); + int (*sign_raw)(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, + const uint8_t *in, size_t in_len, int padding); + + int (*decrypt)(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, + const uint8_t *in, size_t in_len, int padding); + int (*verify_raw)(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, + const uint8_t *in, size_t in_len, int padding); + + /* private_transform takes a big-endian integer from |in|, calculates the + * d'th power of it, modulo the RSA modulus and writes the result as a + * big-endian integer to |out|. Both |in| and |out| are |len| bytes long and + * |len| is always equal to |RSA_size(rsa)|. If the result of the transform + * can be represented in fewer than |len| bytes, then |out| must be zero + * padded on the left. + * + * It returns one on success and zero otherwise. + * + * RSA decrypt and sign operations will call this, thus an ENGINE might wish + * to override it in order to avoid having to implement the padding + * functionality demanded by those, higher level, operations. */ + int (*private_transform)(RSA *rsa, uint8_t *out, const uint8_t *in, + size_t len); + + int (*mod_exp)(BIGNUM *r0, const BIGNUM *I, RSA *rsa, + BN_CTX *ctx); /* Can be null */ + int (*bn_mod_exp)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, + BN_MONT_CTX *m_ctx); + + int flags; + + int (*keygen)(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb); + + int (*multi_prime_keygen)(RSA *rsa, int bits, int num_primes, BIGNUM *e, + BN_GENCB *cb); + + /* supports_digest returns one if |rsa| supports digests of type + * |md|. If null, it is assumed that all digests are supported. */ + int (*supports_digest)(const RSA *rsa, const EVP_MD *md); +}; + + +/* Private functions. */ + +typedef struct bn_blinding_st BN_BLINDING; + +struct rsa_st { + RSA_METHOD *meth; + + BIGNUM *n; + BIGNUM *e; + BIGNUM *d; + BIGNUM *p; + BIGNUM *q; + BIGNUM *dmp1; + BIGNUM *dmq1; + BIGNUM *iqmp; + + STACK_OF(RSA_additional_prime) *additional_primes; + + /* be careful using this if the RSA structure is shared */ + CRYPTO_EX_DATA ex_data; + CRYPTO_refcount_t references; + int flags; + + CRYPTO_MUTEX lock; + + /* Used to cache montgomery values. The creation of these values is protected + * by |lock|. */ + BN_MONT_CTX *_method_mod_n; + BN_MONT_CTX *_method_mod_p; + BN_MONT_CTX *_method_mod_q; + + /* num_blindings contains the size of the |blindings| and |blindings_inuse| + * arrays. This member and the |blindings_inuse| array are protected by + * |lock|. */ + unsigned num_blindings; + /* blindings is an array of BN_BLINDING structures that can be reserved by a + * thread by locking |lock| and changing the corresponding element in + * |blindings_inuse| from 0 to 1. */ + BN_BLINDING **blindings; + unsigned char *blindings_inuse; +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define RSA_R_BAD_E_VALUE 100 +#define RSA_R_BAD_FIXED_HEADER_DECRYPT 101 +#define RSA_R_BAD_PAD_BYTE_COUNT 102 +#define RSA_R_BAD_RSA_PARAMETERS 103 +#define RSA_R_BAD_SIGNATURE 104 +#define RSA_R_BLOCK_TYPE_IS_NOT_01 105 +#define RSA_R_BN_NOT_INITIALIZED 106 +#define RSA_R_CRT_PARAMS_ALREADY_GIVEN 107 +#define RSA_R_CRT_VALUES_INCORRECT 108 +#define RSA_R_DATA_LEN_NOT_EQUAL_TO_MOD_LEN 109 +#define RSA_R_DATA_TOO_LARGE 110 +#define RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE 111 +#define RSA_R_DATA_TOO_LARGE_FOR_MODULUS 112 +#define RSA_R_DATA_TOO_SMALL 113 +#define RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE 114 +#define RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY 115 +#define RSA_R_D_E_NOT_CONGRUENT_TO_1 116 +#define RSA_R_EMPTY_PUBLIC_KEY 117 +#define RSA_R_FIRST_OCTET_INVALID 118 +#define RSA_R_INCONSISTENT_SET_OF_CRT_VALUES 119 +#define RSA_R_INTERNAL_ERROR 120 +#define RSA_R_INVALID_MESSAGE_LENGTH 121 +#define RSA_R_KEY_SIZE_TOO_SMALL 122 +#define RSA_R_LAST_OCTET_INVALID 123 +#define RSA_R_MODULUS_TOO_LARGE 124 +#define RSA_R_NO_PUBLIC_EXPONENT 125 +#define RSA_R_NULL_BEFORE_BLOCK_MISSING 126 +#define RSA_R_N_NOT_EQUAL_P_Q 127 +#define RSA_R_OAEP_DECODING_ERROR 128 +#define RSA_R_ONLY_ONE_OF_P_Q_GIVEN 129 +#define RSA_R_OUTPUT_BUFFER_TOO_SMALL 130 +#define RSA_R_PADDING_CHECK_FAILED 131 +#define RSA_R_PKCS_DECODING_ERROR 132 +#define RSA_R_SLEN_CHECK_FAILED 133 +#define RSA_R_SLEN_RECOVERY_FAILED 134 +#define RSA_R_TOO_LONG 135 +#define RSA_R_TOO_MANY_ITERATIONS 136 +#define RSA_R_UNKNOWN_ALGORITHM_TYPE 137 +#define RSA_R_UNKNOWN_PADDING_TYPE 138 +#define RSA_R_VALUE_MISSING 139 +#define RSA_R_WRONG_SIGNATURE_LENGTH 140 +#define RSA_R_MUST_HAVE_AT_LEAST_TWO_PRIMES 141 +#define RSA_R_CANNOT_RECOVER_MULTI_PRIME_KEY 142 +#define RSA_R_BAD_ENCODING 143 +#define RSA_R_ENCODE_ERROR 144 +#define RSA_R_BAD_VERSION 145 + +#endif /* OPENSSL_HEADER_RSA_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/safestack.h b/TMessagesProj/jni/boringssl/include/openssl/safestack.h new file mode 100644 index 00000000..6e5e4330 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/safestack.h @@ -0,0 +1,16 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is provided in order to make compiling against code that expects + OpenSSL easier. */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/sha.h b/TMessagesProj/jni/boringssl/include/openssl/sha.h new file mode 100644 index 00000000..ac2ab758 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/sha.h @@ -0,0 +1,241 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_SHA_H +#define OPENSSL_HEADER_SHA_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* The SHA family of hash functions (SHA-1 and SHA-2). */ + + +/* SHA_CBLOCK is the block size of SHA-1. */ +#define SHA_CBLOCK 64 + +/* SHA_DIGEST_LENGTH is the length of a SHA-1 digest. */ +#define SHA_DIGEST_LENGTH 20 + +/* TODO(fork): remove */ +#define SHA_LBLOCK 16 +#define SHA_LONG uint32_t + +/* SHA1_Init initialises |sha| and returns one. */ +OPENSSL_EXPORT int SHA1_Init(SHA_CTX *sha); + +/* SHA1_Update adds |len| bytes from |data| to |sha| and returns one. */ +OPENSSL_EXPORT int SHA1_Update(SHA_CTX *sha, const void *data, size_t len); + +/* SHA1_Final adds the final padding to |sha| and writes the resulting digest + * to |md|, which must have at least |SHA_DIGEST_LENGTH| bytes of space. It + * returns one. */ +OPENSSL_EXPORT int SHA1_Final(uint8_t *md, SHA_CTX *sha); + +/* SHA1 writes the digest of |len| bytes from |data| to |out| and returns + * |out|. There must be at least |SHA_DIGEST_LENGTH| bytes of space in + * |out|. */ +OPENSSL_EXPORT uint8_t *SHA1(const uint8_t *data, size_t len, uint8_t *out); + +/* SHA1_Transform is a low-level function that performs a single, SHA-1 block + * transformation using the state from |sha| and 64 bytes from |block|. */ +OPENSSL_EXPORT void SHA1_Transform(SHA_CTX *sha, const uint8_t *block); + +struct sha_state_st { + uint32_t h0, h1, h2, h3, h4; + uint32_t Nl, Nh; + uint32_t data[16]; + unsigned int num; +}; + + +/* SHA-224. */ + +/* SHA224_CBLOCK is the block size of SHA-224. */ +#define SHA224_CBLOCK 64 + +/* SHA224_DIGEST_LENGTH is the length of a SHA-224 digest. */ +#define SHA224_DIGEST_LENGTH 28 + +/* SHA224_Init initialises |sha| and returns 1. */ +OPENSSL_EXPORT int SHA224_Init(SHA256_CTX *sha); + +/* SHA224_Update adds |len| bytes from |data| to |sha| and returns 1. */ +OPENSSL_EXPORT int SHA224_Update(SHA256_CTX *sha, const void *data, size_t len); + +/* SHA224_Final adds the final padding to |sha| and writes the resulting digest + * to |md|, which must have at least |SHA224_DIGEST_LENGTH| bytes of space. It + * returns one on success and zero on programmer error. */ +OPENSSL_EXPORT int SHA224_Final(uint8_t *md, SHA256_CTX *sha); + +/* SHA224 writes the digest of |len| bytes from |data| to |out| and returns + * |out|. There must be at least |SHA224_DIGEST_LENGTH| bytes of space in + * |out|. */ +OPENSSL_EXPORT uint8_t *SHA224(const uint8_t *data, size_t len, uint8_t *out); + + +/* SHA-256. */ + +/* SHA256_CBLOCK is the block size of SHA-256. */ +#define SHA256_CBLOCK 64 + +/* SHA256_DIGEST_LENGTH is the length of a SHA-256 digest. */ +#define SHA256_DIGEST_LENGTH 32 + +/* SHA256_Init initialises |sha| and returns 1. */ +OPENSSL_EXPORT int SHA256_Init(SHA256_CTX *sha); + +/* SHA256_Update adds |len| bytes from |data| to |sha| and returns 1. */ +OPENSSL_EXPORT int SHA256_Update(SHA256_CTX *sha, const void *data, size_t len); + +/* SHA256_Final adds the final padding to |sha| and writes the resulting digest + * to |md|, which must have at least |SHA256_DIGEST_LENGTH| bytes of space. It + * returns one on success and zero on programmer error. */ +OPENSSL_EXPORT int SHA256_Final(uint8_t *md, SHA256_CTX *sha); + +/* SHA256 writes the digest of |len| bytes from |data| to |out| and returns + * |out|. There must be at least |SHA256_DIGEST_LENGTH| bytes of space in + * |out|. */ +OPENSSL_EXPORT uint8_t *SHA256(const uint8_t *data, size_t len, uint8_t *out); + +/* SHA256_Transform is a low-level function that performs a single, SHA-1 block + * transformation using the state from |sha| and 64 bytes from |block|. */ +OPENSSL_EXPORT void SHA256_Transform(SHA256_CTX *sha, const uint8_t *data); + +struct sha256_state_st { + uint32_t h[8]; + uint32_t Nl, Nh; + uint32_t data[16]; + unsigned int num, md_len; +}; + + +/* SHA-384. */ + +/* SHA384_CBLOCK is the block size of SHA-384. */ +#define SHA384_CBLOCK 128 + +/* SHA384_DIGEST_LENGTH is the length of a SHA-384 digest. */ +#define SHA384_DIGEST_LENGTH 48 + +/* SHA384_Init initialises |sha| and returns 1. */ +OPENSSL_EXPORT int SHA384_Init(SHA512_CTX *sha); + +/* SHA384_Update adds |len| bytes from |data| to |sha| and returns 1. */ +OPENSSL_EXPORT int SHA384_Update(SHA512_CTX *sha, const void *data, size_t len); + +/* SHA384_Final adds the final padding to |sha| and writes the resulting digest + * to |md|, which must have at least |SHA384_DIGEST_LENGTH| bytes of space. It + * returns one on success and zero on programmer error. */ +OPENSSL_EXPORT int SHA384_Final(uint8_t *md, SHA512_CTX *sha); + +/* SHA384 writes the digest of |len| bytes from |data| to |out| and returns + * |out|. There must be at least |SHA384_DIGEST_LENGTH| bytes of space in + * |out|. */ +OPENSSL_EXPORT uint8_t *SHA384(const uint8_t *data, size_t len, uint8_t *out); + +/* SHA384_Transform is a low-level function that performs a single, SHA-1 block + * transformation using the state from |sha| and 64 bytes from |block|. */ +OPENSSL_EXPORT void SHA384_Transform(SHA512_CTX *sha, const uint8_t *data); + + +/* SHA-512. */ + +/* SHA512_CBLOCK is the block size of SHA-512. */ +#define SHA512_CBLOCK 128 + +/* SHA512_DIGEST_LENGTH is the length of a SHA-512 digest. */ +#define SHA512_DIGEST_LENGTH 64 + +/* SHA512_Init initialises |sha| and returns 1. */ +OPENSSL_EXPORT int SHA512_Init(SHA512_CTX *sha); + +/* SHA512_Update adds |len| bytes from |data| to |sha| and returns 1. */ +OPENSSL_EXPORT int SHA512_Update(SHA512_CTX *sha, const void *data, size_t len); + +/* SHA512_Final adds the final padding to |sha| and writes the resulting digest + * to |md|, which must have at least |SHA512_DIGEST_LENGTH| bytes of space. It + * returns one on success and zero on programmer error. */ +OPENSSL_EXPORT int SHA512_Final(uint8_t *md, SHA512_CTX *sha); + +/* SHA512 writes the digest of |len| bytes from |data| to |out| and returns + * |out|. There must be at least |SHA512_DIGEST_LENGTH| bytes of space in + * |out|. */ +OPENSSL_EXPORT uint8_t *SHA512(const uint8_t *data, size_t len, uint8_t *out); + +/* SHA512_Transform is a low-level function that performs a single, SHA-1 block + * transformation using the state from |sha| and 64 bytes from |block|. */ +OPENSSL_EXPORT void SHA512_Transform(SHA512_CTX *sha, const uint8_t *data); + +struct sha512_state_st { + uint64_t h[8]; + uint64_t Nl, Nh; + union { + uint64_t d[16]; + uint8_t p[128]; + } u; + unsigned int num, md_len; +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_SHA_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/srtp.h b/TMessagesProj/jni/boringssl/include/openssl/srtp.h new file mode 100644 index 00000000..3f5a53e2 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/srtp.h @@ -0,0 +1,178 @@ +/* ssl/tls1.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* + DTLS code by Eric Rescorla + + Copyright (C) 2006, Network Resonance, Inc. + Copyright (C) 2011, RTFM, Inc. +*/ + +#ifndef OPENSSL_HEADER_SRTP_H +#define OPENSSL_HEADER_SRTP_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Constants for SRTP profiles */ +#define SRTP_AES128_CM_SHA1_80 0x0001 +#define SRTP_AES128_CM_SHA1_32 0x0002 +#define SRTP_AES128_F8_SHA1_80 0x0003 +#define SRTP_AES128_F8_SHA1_32 0x0004 +#define SRTP_NULL_SHA1_80 0x0005 +#define SRTP_NULL_SHA1_32 0x0006 + +/* SSL_CTX_set_srtp_profiles enables SRTP for all SSL objects created from + * |ctx|. |profile| contains a colon-separated list of profile names. It returns + * one on success and zero on failure. */ +OPENSSL_EXPORT int SSL_CTX_set_srtp_profiles(SSL_CTX *ctx, + const char *profiles); + +/* SSL_set_srtp_profiles enables SRTP for |ssl|. |profile| contains a + * colon-separated list of profile names. It returns one on success and zero on + * failure. */ +OPENSSL_EXPORT int SSL_set_srtp_profiles(SSL *ctx, const char *profiles); + +/* SSL_get_srtp_profiles returns the SRTP profiles supported by |ssl|. */ +OPENSSL_EXPORT STACK_OF(SRTP_PROTECTION_PROFILE) *SSL_get_srtp_profiles( + SSL *ssl); + +/* SSL_get_selected_srtp_profile returns the selected SRTP profile, or NULL if + * SRTP was not negotiated. */ +OPENSSL_EXPORT const SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile( + SSL *s); + + +/* Deprecated functions */ + +/* SSL_CTX_set_tlsext_use_srtp calls SSL_CTX_set_srtp_profiles. It returns zero + * on success and one on failure. + * + * WARNING: this function is dangerous because it breaks the usual return value + * convention. Use SSL_CTX_set_srtp_profiles instead. */ +OPENSSL_EXPORT int SSL_CTX_set_tlsext_use_srtp(SSL_CTX *ctx, + const char *profiles); + +/* SSL_set_tlsext_use_srtp calls SSL_set_srtp_profiles. It returns zero on + * success and one on failure. + * + * WARNING: this function is dangerous because it breaks the usual return value + * convention. Use SSL_set_srtp_profiles instead. */ +OPENSSL_EXPORT int SSL_set_tlsext_use_srtp(SSL *ctx, const char *profiles); + + +#ifdef __cplusplus +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_SRTP_H */ + diff --git a/TMessagesProj/jni/boringssl/include/openssl/ssl.h b/TMessagesProj/jni/boringssl/include/openssl/ssl.h new file mode 100644 index 00000000..ffbd8cae --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/ssl.h @@ -0,0 +1,3067 @@ +/* ssl/ssl.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * ECC cipher suite support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ +/* ==================================================================== + * Copyright 2005 Nokia. All rights reserved. + * + * The portions of the attached software ("Contribution") is developed by + * Nokia Corporation and is licensed pursuant to the OpenSSL open source + * license. + * + * The Contribution, originally written by Mika Kousa and Pasi Eronen of + * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites + * support (see RFC 4279) to OpenSSL. + * + * No patent licenses or other rights except those expressly stated in + * the OpenSSL open source license shall be deemed granted or received + * expressly, by implication, estoppel, or otherwise. + * + * No assurances are provided by Nokia that the Contribution does not + * infringe the patent or other intellectual property rights of any third + * party or that the license provides you with all the necessary rights + * to make use of the Contribution. + * + * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN + * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA + * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY + * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR + * OTHERWISE. + */ + +#ifndef OPENSSL_HEADER_SSL_H +#define OPENSSL_HEADER_SSL_H + +#include + +#include +#include +#include +#include +#include +#include +#include + +#if !defined(OPENSSL_WINDOWS) +#include +#endif + +/* wpa_supplicant expects to get the version functions from ssl.h */ +#include + +/* Forward-declare struct timeval. On Windows, it is defined in winsock2.h and + * Windows headers define too many macros to be included in public headers. + * However, only a forward declaration is needed. */ +struct timeval; + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* SSL implementation. */ + + +/* Initialization. */ + +/* SSL_library_init initializes the crypto and SSL libraries and returns one. */ +OPENSSL_EXPORT int SSL_library_init(void); + + +/* Cipher suites. */ + +/* An SSL_CIPHER represents a cipher suite. */ +typedef struct ssl_cipher_st { + /* name is the OpenSSL name for the cipher. */ + const char *name; + /* id is the cipher suite value bitwise OR-d with 0x03000000. */ + uint32_t id; + + /* The following are internal fields. See ssl/internal.h for their values. */ + + uint32_t algorithm_mkey; + uint32_t algorithm_auth; + uint32_t algorithm_enc; + uint32_t algorithm_mac; + uint32_t algorithm_ssl; + uint32_t algo_strength; + uint32_t algorithm_prf; + + /* strength_bits is the strength of the cipher in bits. */ + int strength_bits; + /* alg_bits is the number of bits of key material used by the algorithm. */ + int alg_bits; +} SSL_CIPHER; + +DECLARE_STACK_OF(SSL_CIPHER) + +/* SSL_get_cipher_by_value returns the structure representing a TLS cipher + * suite based on its assigned number, or NULL if unknown. See + * https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4. */ +OPENSSL_EXPORT const SSL_CIPHER *SSL_get_cipher_by_value(uint16_t value); + +/* SSL_CIPHER_get_id returns |cipher|'s id. It may be cast to a |uint16_t| to + * get the cipher suite value. */ +OPENSSL_EXPORT uint32_t SSL_CIPHER_get_id(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_is_AES returns one if |cipher| uses AES (either GCM or CBC + * mode). */ +OPENSSL_EXPORT int SSL_CIPHER_is_AES(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_has_MD5_HMAC returns one if |cipher| uses HMAC-MD5. */ +OPENSSL_EXPORT int SSL_CIPHER_has_MD5_HMAC(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_is_AESGCM returns one if |cipher| uses AES-GCM. */ +OPENSSL_EXPORT int SSL_CIPHER_is_AESGCM(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_is_CHACHA20POLY1305 returns one if |cipher| uses + * CHACHA20_POLY1305. */ +OPENSSL_EXPORT int SSL_CIPHER_is_CHACHA20POLY1305(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_get_name returns the OpenSSL name of |cipher|. */ +OPENSSL_EXPORT const char *SSL_CIPHER_get_name(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_get_kx_name returns a string that describes the key-exchange + * method used by |cipher|. For example, "ECDHE_ECDSA". */ +OPENSSL_EXPORT const char *SSL_CIPHER_get_kx_name(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_get_rfc_name returns a newly-allocated string with the standard + * name for |cipher| or NULL on error. For example, + * "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256". The caller is responsible for + * calling |OPENSSL_free| on the result. */ +OPENSSL_EXPORT char *SSL_CIPHER_get_rfc_name(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_get_bits returns the strength, in bits, of |cipher|. If + * |out_alg_bits| is not NULL, it writes the number of bits consumed by the + * symmetric algorithm to |*out_alg_bits|. */ +OPENSSL_EXPORT int SSL_CIPHER_get_bits(const SSL_CIPHER *cipher, + int *out_alg_bits); + + +/* SSL contexts. */ + +/* An SSL_METHOD selects whether to use TLS or DTLS. */ +typedef struct ssl_method_st SSL_METHOD; + +/* TLS_method is the |SSL_METHOD| used for TLS (and SSLv3) connections. */ +OPENSSL_EXPORT const SSL_METHOD *TLS_method(void); + +/* DTLS_method is the |SSL_METHOD| used for DTLS connections. */ +OPENSSL_EXPORT const SSL_METHOD *DTLS_method(void); + +/* SSL_CTX_new returns a newly-allocated |SSL_CTX| with default settings or NULL + * on error. An |SSL_CTX| manages shared state and configuration between + * multiple TLS or DTLS connections. */ +OPENSSL_EXPORT SSL_CTX *SSL_CTX_new(const SSL_METHOD *method); + +/* SSL_CTX_free releases memory associated with |ctx|. */ +OPENSSL_EXPORT void SSL_CTX_free(SSL_CTX *ctx); + + +/* SSL connections. */ + +/* SSL_new returns a newly-allocated |SSL| using |ctx| or NULL on error. An + * |SSL| object represents a single TLS or DTLS connection. It inherits settings + * from |ctx| at the time of creation. Settings may also be individually + * configured on the connection. + * + * On creation, an |SSL| is not configured to be either a client or server. Call + * |SSL_set_connect_state| or |SSL_set_accept_state| to set this. */ +OPENSSL_EXPORT SSL *SSL_new(SSL_CTX *ctx); + +/* SSL_free releases memory associated with |ssl|. */ +OPENSSL_EXPORT void SSL_free(SSL *ssl); + +/* SSL_set_connect_state configures |ssl| to be a client. */ +OPENSSL_EXPORT void SSL_set_connect_state(SSL *ssl); + +/* SSL_set_accept_state configures |ssl| to be a server. */ +OPENSSL_EXPORT void SSL_set_accept_state(SSL *ssl); + + +/* Protocol versions. */ + +#define SSL3_VERSION_MAJOR 0x03 + +#define SSL3_VERSION 0x0300 +#define TLS1_VERSION 0x0301 +#define TLS1_1_VERSION 0x0302 +#define TLS1_2_VERSION 0x0303 + +#define DTLS1_VERSION 0xfeff +#define DTLS1_2_VERSION 0xfefd + +/* SSL_CTX_set_min_version sets the minimum protocol version for |ctx| to + * |version|. */ +OPENSSL_EXPORT void SSL_CTX_set_min_version(SSL_CTX *ctx, uint16_t version); + +/* SSL_CTX_set_max_version sets the maximum protocol version for |ctx| to + * |version|. */ +OPENSSL_EXPORT void SSL_CTX_set_max_version(SSL_CTX *ctx, uint16_t version); + +/* SSL_set_min_version sets the minimum protocol version for |ssl| to + * |version|. */ +OPENSSL_EXPORT void SSL_set_min_version(SSL *ssl, uint16_t version); + +/* SSL_set_max_version sets the maximum protocol version for |ssl| to + * |version|. */ +OPENSSL_EXPORT void SSL_set_max_version(SSL *ssl, uint16_t version); + + +/* Options. + * + * Options configure protocol behavior. */ + +/* SSL_OP_LEGACY_SERVER_CONNECT allows initial connections to servers that don't + * support the renegotiation_info extension (RFC 5746). It is on by default. */ +#define SSL_OP_LEGACY_SERVER_CONNECT 0x00000004L + +/* SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER allows for record sizes |SSL3_RT_MAX_EXTRA| + * bytes above the maximum record size. */ +#define SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER 0x00000020L + +/* SSL_OP_TLS_D5_BUG accepts an RSAClientKeyExchange in TLS encoded as in SSL3 + * (i.e. without a length prefix). */ +#define SSL_OP_TLS_D5_BUG 0x00000100L + +/* SSL_OP_ALL enables the above bug workarounds that are enabled by many + * consumers. + * TODO(davidben): Determine which of the remaining may be removed now. */ +#define SSL_OP_ALL 0x00000BFFL + +/* SSL_OP_NO_QUERY_MTU, in DTLS, disables querying the MTU from the underlying + * |BIO|. Instead, the MTU is configured with |SSL_set_mtu|. */ +#define SSL_OP_NO_QUERY_MTU 0x00001000L + +/* SSL_OP_NO_TICKET disables session ticket support (RFC 4507). */ +#define SSL_OP_NO_TICKET 0x00004000L + +/* SSL_OP_CIPHER_SERVER_PREFERENCE configures servers to select ciphers and + * ECDHE curves according to the server's preferences instead of the + * client's. */ +#define SSL_OP_CIPHER_SERVER_PREFERENCE 0x00400000L + +/* The following flags toggle individual protocol versions. This is deprecated. + * Use |SSL_CTX_set_min_version| and |SSL_CTX_set_max_version| instead. */ +#define SSL_OP_NO_SSLv3 0x02000000L +#define SSL_OP_NO_TLSv1 0x04000000L +#define SSL_OP_NO_TLSv1_2 0x08000000L +#define SSL_OP_NO_TLSv1_1 0x10000000L +#define SSL_OP_NO_DTLSv1 SSL_OP_NO_TLSv1 +#define SSL_OP_NO_DTLSv1_2 SSL_OP_NO_TLSv1_2 + +/* The following flags do nothing and are included only to make it easier to + * compile code with BoringSSL. */ +#define SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0 +#define SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS 0 +#define SSL_OP_EPHEMERAL_RSA 0 +#define SSL_OP_MICROSOFT_SESS_ID_BUG 0 +#define SSL_OP_MSIE_SSLV2_RSA_PADDING 0 +#define SSL_OP_NETSCAPE_CA_DN_BUG 0 +#define SSL_OP_NETSCAPE_CHALLENGE_BUG 0 +#define SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG 0 +#define SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG 0 +#define SSL_OP_NO_COMPRESSION 0 +#define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION 0 +#define SSL_OP_NO_SSLv2 0 +#define SSL_OP_PKCS1_CHECK_1 0 +#define SSL_OP_PKCS1_CHECK_2 0 +#define SSL_OP_SINGLE_DH_USE 0 +#define SSL_OP_SINGLE_ECDH_USE 0 +#define SSL_OP_SSLEAY_080_CLIENT_DH_BUG 0 +#define SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG 0 +#define SSL_OP_TLS_BLOCK_PADDING_BUG 0 +#define SSL_OP_TLS_ROLLBACK_BUG 0 + +/* SSL_CTX_set_options enables all options set in |options| (which should be one + * or more of the |SSL_OP_*| values, ORed together) in |ctx|. It returns a + * bitmask representing the resulting enabled options. */ +OPENSSL_EXPORT uint32_t SSL_CTX_set_options(SSL_CTX *ctx, uint32_t options); + +/* SSL_CTX_clear_options disables all options set in |options| (which should be + * one or more of the |SSL_OP_*| values, ORed together) in |ctx|. It returns a + * bitmask representing the resulting enabled options. */ +OPENSSL_EXPORT uint32_t SSL_CTX_clear_options(SSL_CTX *ctx, uint32_t options); + +/* SSL_CTX_get_options returns a bitmask of |SSL_OP_*| values that represent all + * the options enabled for |ctx|. */ +OPENSSL_EXPORT uint32_t SSL_CTX_get_options(const SSL_CTX *ctx); + +/* SSL_set_options enables all options set in |options| (which should be one or + * more of the |SSL_OP_*| values, ORed together) in |ssl|. It returns a bitmask + * representing the resulting enabled options. */ +OPENSSL_EXPORT uint32_t SSL_set_options(SSL *ssl, uint32_t options); + +/* SSL_clear_options disables all options set in |options| (which should be one + * or more of the |SSL_OP_*| values, ORed together) in |ssl|. It returns a + * bitmask representing the resulting enabled options. */ +OPENSSL_EXPORT uint32_t SSL_clear_options(SSL *ssl, uint32_t options); + +/* SSL_get_options returns a bitmask of |SSL_OP_*| values that represent all the + * options enabled for |ssl|. */ +OPENSSL_EXPORT uint32_t SSL_get_options(const SSL *ssl); + + +/* Modes. + * + * Modes configure API behavior. */ + +/* SSL_MODE_ENABLE_PARTIAL_WRITE allows |SSL_write| to complete with a partial + * result when the only part of the input was written in a single record. */ +#define SSL_MODE_ENABLE_PARTIAL_WRITE 0x00000001L + +/* SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER allows retrying an incomplete |SSL_write| + * with a different buffer. However, |SSL_write| still assumes the buffer + * contents are unchanged. This is not the default to avoid the misconception + * that non-blocking |SSL_write| behaves like non-blocking |write|. */ +#define SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER 0x00000002L + +/* SSL_MODE_NO_AUTO_CHAIN disables automatically building a certificate chain + * before sending certificates to the peer. + * TODO(davidben): Remove this behavior. https://crbug.com/486295. */ +#define SSL_MODE_NO_AUTO_CHAIN 0x00000008L + +/* SSL_MODE_ENABLE_FALSE_START allows clients to send application data before + * receipt of CCS and Finished. This mode enables full-handshakes to 'complete' + * in one RTT. See draft-bmoeller-tls-falsestart-01. */ +#define SSL_MODE_ENABLE_FALSE_START 0x00000080L + +/* Deprecated: SSL_MODE_HANDSHAKE_CUTTHROUGH is the same as + * SSL_MODE_ENABLE_FALSE_START. */ +#define SSL_MODE_HANDSHAKE_CUTTHROUGH SSL_MODE_ENABLE_FALSE_START + +/* SSL_MODE_CBC_RECORD_SPLITTING causes multi-byte CBC records in SSL 3.0 and + * TLS 1.0 to be split in two: the first record will contain a single byte and + * the second will contain the remainder. This effectively randomises the IV and + * prevents BEAST attacks. */ +#define SSL_MODE_CBC_RECORD_SPLITTING 0x00000100L + +/* SSL_MODE_NO_SESSION_CREATION will cause any attempts to create a session to + * fail with SSL_R_SESSION_MAY_NOT_BE_CREATED. This can be used to enforce that + * session resumption is used for a given SSL*. */ +#define SSL_MODE_NO_SESSION_CREATION 0x00000200L + +/* SSL_MODE_SEND_FALLBACK_SCSV sends TLS_FALLBACK_SCSV in the ClientHello. + * To be set only by applications that reconnect with a downgraded protocol + * version; see RFC 7507 for details. + * + * DO NOT ENABLE THIS if your application attempts a normal handshake. Only use + * this in explicit fallback retries, following the guidance in RFC 7507. */ +#define SSL_MODE_SEND_FALLBACK_SCSV 0x00000400L + +/* The following flags do nothing and are included only to make it easier to + * compile code with BoringSSL. */ +#define SSL_MODE_AUTO_RETRY 0 +#define SSL_MODE_RELEASE_BUFFERS 0 +#define SSL_MODE_SEND_CLIENTHELLO_TIME 0 +#define SSL_MODE_SEND_SERVERHELLO_TIME 0 + +/* SSL_CTX_set_mode enables all modes set in |mode| (which should be one or more + * of the |SSL_MODE_*| values, ORed together) in |ctx|. It returns a bitmask + * representing the resulting enabled modes. */ +OPENSSL_EXPORT uint32_t SSL_CTX_set_mode(SSL_CTX *ctx, uint32_t mode); + +/* SSL_CTX_clear_mode disables all modes set in |mode| (which should be one or + * more of the |SSL_MODE_*| values, ORed together) in |ctx|. It returns a + * bitmask representing the resulting enabled modes. */ +OPENSSL_EXPORT uint32_t SSL_CTX_clear_mode(SSL_CTX *ctx, uint32_t mode); + +/* SSL_CTX_get_mode returns a bitmask of |SSL_MODE_*| values that represent all + * the modes enabled for |ssl|. */ +OPENSSL_EXPORT uint32_t SSL_CTX_get_mode(const SSL_CTX *ctx); + +/* SSL_set_mode enables all modes set in |mode| (which should be one or more of + * the |SSL_MODE_*| values, ORed together) in |ssl|. It returns a bitmask + * representing the resulting enabled modes. */ +OPENSSL_EXPORT uint32_t SSL_set_mode(SSL *ssl, uint32_t mode); + +/* SSL_clear_mode disables all modes set in |mode| (which should be one or more + * of the |SSL_MODE_*| values, ORed together) in |ssl|. It returns a bitmask + * representing the resulting enabled modes. */ +OPENSSL_EXPORT uint32_t SSL_clear_mode(SSL *ssl, uint32_t mode); + +/* SSL_get_mode returns a bitmask of |SSL_MODE_*| values that represent all the + * modes enabled for |ssl|. */ +OPENSSL_EXPORT uint32_t SSL_get_mode(const SSL *ssl); + + +/* Configuring certificates and private keys. + * + * These functions configure the connection's leaf certificate, private key, and + * certificate chain. The certificate chain is ordered leaf to root (as sent on + * the wire) but does not include the leaf. Both client and server certificates + * use these functions. + * + * Certificates and keys may be configured before the handshake or dynamically + * in the early callback and certificate callback. */ + +/* SSL_CTX_use_certificate sets |ctx|'s leaf certificate to |x509|. It returns + * one on success and zero on failure. */ +OPENSSL_EXPORT int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x509); + +/* SSL_use_certificate sets |ssl|'s leaf certificate to |x509|. It returns one + * on success and zero on failure. */ +OPENSSL_EXPORT int SSL_use_certificate(SSL *ssl, X509 *x509); + +/* SSL_CTX_use_PrivateKey sets |ctx|'s private key to |pkey|. It returns one on + * success and zero on failure. */ +OPENSSL_EXPORT int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey); + +/* SSL_use_PrivateKey sets |ssl|'s private key to |pkey|. It returns one on + * success and zero on failure. */ +OPENSSL_EXPORT int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey); + +/* SSL_CTX_set0_chain sets |ctx|'s certificate chain, excluding the leaf, to + * |chain|. On success, it returns one and takes ownership of |chain|. + * Otherwise, it returns zero. */ +OPENSSL_EXPORT int SSL_CTX_set0_chain(SSL_CTX *ctx, STACK_OF(X509) *chain); + +/* SSL_CTX_set1_chain sets |ctx|'s certificate chain, excluding the leaf, to + * |chain|. It returns one on success and zero on failure. The caller retains + * ownership of |chain| and may release it freely. */ +OPENSSL_EXPORT int SSL_CTX_set1_chain(SSL_CTX *ctx, STACK_OF(X509) *chain); + +/* SSL_set0_chain sets |ssl|'s certificate chain, excluding the leaf, to + * |chain|. On success, it returns one and takes ownership of |chain|. + * Otherwise, it returns zero. */ +OPENSSL_EXPORT int SSL_set0_chain(SSL *ssl, STACK_OF(X509) *chain); + +/* SSL_set1_chain sets |ssl|'s certificate chain, excluding the leaf, to + * |chain|. It returns one on success and zero on failure. The caller retains + * ownership of |chain| and may release it freely. */ +OPENSSL_EXPORT int SSL_set1_chain(SSL *ssl, STACK_OF(X509) *chain); + +/* SSL_CTX_add0_chain_cert appends |x509| to |ctx|'s certificate chain. On + * success, it returns one and takes ownership of |x509|. Otherwise, it returns + * zero. */ +OPENSSL_EXPORT int SSL_CTX_add0_chain_cert(SSL_CTX *ctx, X509 *x509); + +/* SSL_CTX_add1_chain_cert appends |x509| to |ctx|'s certificate chain. It + * returns one on success and zero on failure. The caller retains ownership of + * |x509| and may release it freely. */ +OPENSSL_EXPORT int SSL_CTX_add1_chain_cert(SSL_CTX *ctx, X509 *x509); + +/* SSL_add0_chain_cert appends |x509| to |ctx|'s certificate chain. On success, + * it returns one and takes ownership of |x509|. Otherwise, it returns zero. */ +OPENSSL_EXPORT int SSL_add0_chain_cert(SSL *ssl, X509 *x509); + +/* SSL_CTX_add_extra_chain_cert calls |SSL_CTX_add0_chain_cert|. */ +OPENSSL_EXPORT int SSL_CTX_add_extra_chain_cert(SSL_CTX *ctx, X509 *x509); + +/* SSL_add1_chain_cert appends |x509| to |ctx|'s certificate chain. It returns + * one on success and zero on failure. The caller retains ownership of |x509| + * and may release it freely. */ +OPENSSL_EXPORT int SSL_add1_chain_cert(SSL *ssl, X509 *x509); + +/* SSL_CTX_clear_chain_certs clears |ctx|'s certificate chain and returns + * one. */ +OPENSSL_EXPORT int SSL_CTX_clear_chain_certs(SSL_CTX *ctx); + +/* SSL_CTX_clear_extra_chain_certs calls |SSL_CTX_clear_chain_certs|. */ +OPENSSL_EXPORT int SSL_CTX_clear_extra_chain_certs(SSL_CTX *ctx); + +/* SSL_clear_chain_certs clears |ssl|'s certificate chain and returns one. */ +OPENSSL_EXPORT int SSL_clear_chain_certs(SSL *ssl); + +/* SSL_CTX_set_cert_cb sets a callback that is called to select a certificate. + * The callback returns one on success, zero on internal error, and a negative + * number on failure or to pause the handshake. If the handshake is paused, + * |SSL_get_error| will return |SSL_ERROR_WANT_X509_LOOKUP|. */ +OPENSSL_EXPORT void SSL_CTX_set_cert_cb(SSL_CTX *ctx, + int (*cb)(SSL *ssl, void *arg), + void *arg); + +/* SSL_set_cert_cb sets a callback that is called to select a certificate. The + * callback returns one on success, zero on internal error, and a negative + * number on failure or to pause the handshake. If the handshake is paused, + * |SSL_get_error| will return |SSL_ERROR_WANT_X509_LOOKUP|. */ +OPENSSL_EXPORT void SSL_set_cert_cb(SSL *ssl, int (*cb)(SSL *ssl, void *arg), + void *arg); + +/* SSL_certs_clear resets the private key, leaf certificate, and certificate + * chain of |ssl|. */ +OPENSSL_EXPORT void SSL_certs_clear(SSL *ssl); + +/* SSL_CTX_check_private_key returns one if the certificate and private key + * configured in |ctx| are consistent and zero otherwise. */ +OPENSSL_EXPORT int SSL_CTX_check_private_key(const SSL_CTX *ctx); + +/* SSL_check_private_key returns one if the certificate and private key + * configured in |ssl| are consistent and zero otherwise. */ +OPENSSL_EXPORT int SSL_check_private_key(const SSL *ssl); + +/* SSL_CTX_get0_certificate returns |ctx|'s leaf certificate. */ +OPENSSL_EXPORT X509 *SSL_CTX_get0_certificate(const SSL_CTX *ctx); + +/* SSL_get_certificate returns |ssl|'s leaf certificate. */ +OPENSSL_EXPORT X509 *SSL_get_certificate(const SSL *ssl); + +/* SSL_CTX_get0_privatekey returns |ctx|'s private key. */ +OPENSSL_EXPORT EVP_PKEY *SSL_CTX_get0_privatekey(const SSL_CTX *ctx); + +/* SSL_get_privatekey returns |ssl|'s private key. */ +OPENSSL_EXPORT EVP_PKEY *SSL_get_privatekey(const SSL *ssl); + +/* SSL_CTX_get0_chain_certs sets |*out_chain| to |ctx|'s certificate chain and + * returns one. */ +OPENSSL_EXPORT int SSL_CTX_get0_chain_certs(const SSL_CTX *ctx, + STACK_OF(X509) **out_chain); + +/* SSL_CTX_get_extra_chain_certs calls |SSL_CTX_get0_chain_certs|. */ +OPENSSL_EXPORT int SSL_CTX_get_extra_chain_certs(const SSL_CTX *ctx, + STACK_OF(X509) **out_chain); + +/* SSL_get0_chain_certs sets |*out_chain| to |ssl|'s certificate chain and + * returns one. */ +OPENSSL_EXPORT int SSL_get0_chain_certs(const SSL *ssl, + STACK_OF(X509) **out_chain); + + +/* Certificate and private key convenience functions. */ + +/* SSL_CTX_use_RSAPrivateKey sets |ctx|'s private key to |rsa|. It returns one + * on success and zero on failure. */ +OPENSSL_EXPORT int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa); + +/* SSL_use_RSAPrivateKey sets |ctx|'s private key to |rsa|. It returns one on + * success and zero on failure. */ +OPENSSL_EXPORT int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa); + +/* The following functions configure certificates or private keys but take as + * input DER-encoded structures. They return one on success and zero on + * failure. */ + +OPENSSL_EXPORT int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, + const uint8_t *d); +OPENSSL_EXPORT int SSL_use_certificate_ASN1(SSL *ssl, const uint8_t *der, + int len); + +OPENSSL_EXPORT int SSL_CTX_use_PrivateKey_ASN1(int pk, SSL_CTX *ctx, + const uint8_t *d, long len); +OPENSSL_EXPORT int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, + const uint8_t *d, long len); + +OPENSSL_EXPORT int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, + const uint8_t *der, + size_t der_len); +OPENSSL_EXPORT int SSL_use_RSAPrivateKey_ASN1(SSL *ssl, const uint8_t *der, + size_t der_len); + +/* The following functions configure certificates or private keys but take as + * input files to read from. They return one on success and zero on failure. The + * |type| parameter is one of the |SSL_FILETYPE_*| values and determines whether + * the file's contents are read as PEM or DER. */ + +#define SSL_FILETYPE_ASN1 X509_FILETYPE_ASN1 +#define SSL_FILETYPE_PEM X509_FILETYPE_PEM + +OPENSSL_EXPORT int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, + const char *file, + int type); +OPENSSL_EXPORT int SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, + int type); + +OPENSSL_EXPORT int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, + int type); +OPENSSL_EXPORT int SSL_use_certificate_file(SSL *ssl, const char *file, + int type); + +OPENSSL_EXPORT int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, + int type); +OPENSSL_EXPORT int SSL_use_PrivateKey_file(SSL *ssl, const char *file, + int type); + +/* SSL_CTX_use_certificate_file configures certificates for |ctx|. It reads the + * contents of |file| as a PEM-encoded leaf certificate followed optionally by + * the certificate chain to send to the peer. It returns one on success and zero + * on failure. */ +OPENSSL_EXPORT int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, + const char *file); + + +/* Custom private keys. */ + +enum ssl_private_key_result_t { + ssl_private_key_success, + ssl_private_key_retry, + ssl_private_key_failure, +}; + +/* SSL_PRIVATE_KEY_METHOD describes private key hooks. This is used to off-load + * signing operations to a custom, potentially asynchronous, backend. */ +typedef struct ssl_private_key_method_st { + /* type returns either |EVP_PKEY_RSA| or |EVP_PKEY_EC| to denote the type of + * key used by |ssl|. */ + int (*type)(SSL *ssl); + + /* supports_digest returns one if the key used by |ssl| supports signing + * digests of type |md| and zero otherwise. */ + int (*supports_digest)(SSL *ssl, const EVP_MD *md); + + /* max_signature_len returns the maximum length of a signature signed by the + * key used by |ssl|. This must be a constant value for a given |ssl|. */ + size_t (*max_signature_len)(SSL *ssl); + + /* sign signs |in_len| bytes of digest from |in|. |md| is the hash function + * used to calculate |in|. On success, it returns |ssl_private_key_success| + * and writes at most |max_out| bytes of signature data to |out|. On failure, + * it returns |ssl_private_key_failure|. If the operation has not completed, + * it returns |ssl_private_key_retry|. |sign| should arrange for the + * high-level operation on |ssl| to be retried when the operation is + * completed. This will result in a call to |sign_complete|. + * + * If the key is an RSA key, implementations must use PKCS#1 padding. |in| is + * the digest itself, so the DigestInfo prefix, if any, must be prepended by + * |sign|. If |md| is |EVP_md5_sha1|, there is no prefix. + * + * It is an error to call |sign| while another private key operation is in + * progress on |ssl|. */ + enum ssl_private_key_result_t (*sign)(SSL *ssl, uint8_t *out, size_t *out_len, + size_t max_out, const EVP_MD *md, + const uint8_t *in, size_t in_len); + + /* sign_complete completes a pending |sign| operation. If the operation has + * completed, it returns |ssl_private_key_success| and writes the result to + * |out| as in |sign|. Otherwise, it returns |ssl_private_key_failure| on + * failure and |ssl_private_key_retry| if the operation is still in progress. + * + * |sign_complete| may be called arbitrarily many times before completion, but + * it is an error to call |sign_complete| if there is no pending |sign| + * operation in progress on |ssl|. */ + enum ssl_private_key_result_t (*sign_complete)(SSL *ssl, uint8_t *out, + size_t *out_len, size_t max_out); +} SSL_PRIVATE_KEY_METHOD; + +/* SSL_use_private_key_method configures a custom private key on |ssl|. + * |key_method| must remain valid for the lifetime of |ssl|. */ +OPENSSL_EXPORT void SSL_set_private_key_method( + SSL *ssl, const SSL_PRIVATE_KEY_METHOD *key_method); + + +/* Connection information. */ + +/* SSL_get_tls_unique writes at most |max_out| bytes of the tls-unique value + * for |ssl| to |out| and sets |*out_len| to the number of bytes written. It + * returns one on success or zero on error. In general |max_out| should be at + * least 12. + * + * This function will always fail if the initial handshake has not completed. + * The tls-unique value will change after a renegotiation but, since + * renegotiations can be initiated by the server at any point, the higher-level + * protocol must either leave them disabled or define states in which the + * tls-unique value can be read. + * + * The tls-unique value is defined by + * https://tools.ietf.org/html/rfc5929#section-3.1. Due to a weakness in the + * TLS protocol, tls-unique is broken for resumed connections unless the + * Extended Master Secret extension is negotiated. Thus this function will + * return zero if |ssl| performed session resumption unless EMS was used when + * negotiating the original session. */ +OPENSSL_EXPORT int SSL_get_tls_unique(const SSL *ssl, uint8_t *out, + size_t *out_len, size_t max_out); + + +/* Custom extensions. + * + * The custom extension functions allow TLS extensions to be added to + * ClientHello and ServerHello messages. */ + +/* SSL_custom_ext_add_cb is a callback function that is called when the + * ClientHello (for clients) or ServerHello (for servers) is constructed. In + * the case of a server, this callback will only be called for a given + * extension if the ClientHello contained that extension – it's not possible to + * inject extensions into a ServerHello that the client didn't request. + * + * When called, |extension_value| will contain the extension number that is + * being considered for addition (so that a single callback can handle multiple + * extensions). If the callback wishes to include the extension, it must set + * |*out| to point to |*out_len| bytes of extension contents and return one. In + * this case, the corresponding |SSL_custom_ext_free_cb| callback will later be + * called with the value of |*out| once that data has been copied. + * + * If the callback does not wish to add an extension it must return zero. + * + * Alternatively, the callback can abort the connection by setting + * |*out_alert_value| to a TLS alert number and returning -1. */ +typedef int (*SSL_custom_ext_add_cb)(SSL *ssl, unsigned extension_value, + const uint8_t **out, size_t *out_len, + int *out_alert_value, void *add_arg); + +/* SSL_custom_ext_free_cb is a callback function that is called by OpenSSL iff + * an |SSL_custom_ext_add_cb| callback previously returned one. In that case, + * this callback is called and passed the |out| pointer that was returned by + * the add callback. This is to free any dynamically allocated data created by + * the add callback. */ +typedef void (*SSL_custom_ext_free_cb)(SSL *ssl, unsigned extension_value, + const uint8_t *out, void *add_arg); + +/* SSL_custom_ext_parse_cb is a callback function that is called by OpenSSL to + * parse an extension from the peer: that is from the ServerHello for a client + * and from the ClientHello for a server. + * + * When called, |extension_value| will contain the extension number and the + * contents of the extension are |contents_len| bytes at |contents|. + * + * The callback must return one to continue the handshake. Otherwise, if it + * returns zero, a fatal alert with value |*out_alert_value| is sent and the + * handshake is aborted. */ +typedef int (*SSL_custom_ext_parse_cb)(SSL *ssl, unsigned extension_value, + const uint8_t *contents, + size_t contents_len, + int *out_alert_value, void *parse_arg); + +/* SSL_extension_supported returns one iff OpenSSL internally handles + * extensions of type |extension_value|. This can be used to avoid registering + * custom extension handlers for extensions that a future version of OpenSSL + * may handle internally. */ +OPENSSL_EXPORT int SSL_extension_supported(unsigned extension_value); + +/* SSL_CTX_add_client_custom_ext registers callback functions for handling + * custom TLS extensions for client connections. + * + * If |add_cb| is NULL then an empty extension will be added in each + * ClientHello. Otherwise, see the comment for |SSL_custom_ext_add_cb| about + * this callback. + * + * The |free_cb| may be NULL if |add_cb| doesn't dynamically allocate data that + * needs to be freed. + * + * It returns one on success or zero on error. It's always an error to register + * callbacks for the same extension twice, or to register callbacks for an + * extension that OpenSSL handles internally. See |SSL_extension_supported| to + * discover, at runtime, which extensions OpenSSL handles internally. */ +OPENSSL_EXPORT int SSL_CTX_add_client_custom_ext( + SSL_CTX *ctx, unsigned extension_value, SSL_custom_ext_add_cb add_cb, + SSL_custom_ext_free_cb free_cb, void *add_arg, + SSL_custom_ext_parse_cb parse_cb, void *parse_arg); + +/* SSL_CTX_add_server_custom_ext is the same as + * |SSL_CTX_add_client_custom_ext|, but for server connections. + * + * Unlike on the client side, if |add_cb| is NULL no extension will be added. + * The |add_cb|, if any, will only be called if the ClientHello contained a + * matching extension. */ +OPENSSL_EXPORT int SSL_CTX_add_server_custom_ext( + SSL_CTX *ctx, unsigned extension_value, SSL_custom_ext_add_cb add_cb, + SSL_custom_ext_free_cb free_cb, void *add_arg, + SSL_custom_ext_parse_cb parse_cb, void *parse_arg); + + +/* Session tickets. */ + +/* SSL_CTX_get_tlsext_ticket_keys writes |ctx|'s session ticket key material to + * |len| bytes of |out|. It returns one on success and zero if |len| is not + * 48. If |out| is NULL, it returns 48 instead. */ +OPENSSL_EXPORT int SSL_CTX_get_tlsext_ticket_keys(SSL_CTX *ctx, void *out, + size_t len); + +/* SSL_CTX_set_tlsext_ticket_keys sets |ctx|'s session ticket key material to + * |len| bytes of |in|. It returns one on success and zero if |len| is not + * 48. If |in| is NULL, it returns 48 instead. */ +OPENSSL_EXPORT int SSL_CTX_set_tlsext_ticket_keys(SSL_CTX *ctx, const void *in, + size_t len); + +/* SSL_TICKET_KEY_NAME_LEN is the length of the key name prefix of a session + * ticket. */ +#define SSL_TICKET_KEY_NAME_LEN 16 + +/* SSL_CTX_set_tlsext_ticket_key_cb sets the ticket callback to |callback| and + * returns one. |callback| will be called when encrypting a new ticket and when + * decrypting a ticket from the client. + * + * In both modes, |ctx| and |hmac_ctx| will already have been initialized with + * |EVP_CIPHER_CTX_init| and |HMAC_CTX_init|, respectively. |callback| + * configures |hmac_ctx| with an HMAC digest and key, and configures |ctx| + * for encryption or decryption, based on the mode. + * + * When encrypting a new ticket, |encrypt| will be one. It writes a public + * 16-byte key name to |key_name| and a fresh IV to |iv|. The output IV length + * must match |EVP_CIPHER_CTX_iv_length| of the cipher selected. In this mode, + * |callback| returns 1 on success and -1 on error. + * + * When decrypting a ticket, |encrypt| will be zero. |key_name| will point to a + * 16-byte key name and |iv| points to an IV. The length of the IV consumed must + * match |EVP_CIPHER_CTX_iv_length| of the cipher selected. In this mode, + * |callback| returns -1 to abort the handshake, 0 if decrypting the ticket + * failed, and 1 or 2 on success. If it returns 2, the ticket will be renewed. + * This may be used to re-key the ticket. + * + * WARNING: |callback| wildly breaks the usual return value convention and is + * called in two different modes. */ +OPENSSL_EXPORT int SSL_CTX_set_tlsext_ticket_key_cb( + SSL_CTX *ctx, int (*callback)(SSL *ssl, uint8_t *key_name, uint8_t *iv, + EVP_CIPHER_CTX *ctx, HMAC_CTX *hmac_ctx, + int encrypt)); + + +/* Underdocumented functions. + * + * Functions below here haven't been touched up and may be underdocumented. */ + +/* SSLeay version number for ASN.1 encoding of the session information */ +/* Version 0 - initial version + * Version 1 - added the optional peer certificate. */ +#define SSL_SESSION_ASN1_VERSION 0x0001 + +#define SSL_MAX_SSL_SESSION_ID_LENGTH 32 +#define SSL_MAX_SID_CTX_LENGTH 32 +#define SSL_MAX_MASTER_KEY_LENGTH 48 + +/* These are used to specify which ciphers to use and not to use */ + +#define SSL_TXT_MEDIUM "MEDIUM" +#define SSL_TXT_HIGH "HIGH" +#define SSL_TXT_FIPS "FIPS" + +#define SSL_TXT_kRSA "kRSA" +#define SSL_TXT_kDHE "kDHE" +#define SSL_TXT_kEDH "kEDH" /* same as "kDHE" */ +#define SSL_TXT_kECDHE "kECDHE" +#define SSL_TXT_kEECDH "kEECDH" /* same as "kECDHE" */ +#define SSL_TXT_kPSK "kPSK" + +#define SSL_TXT_aRSA "aRSA" +#define SSL_TXT_aECDSA "aECDSA" +#define SSL_TXT_aPSK "aPSK" + +#define SSL_TXT_DH "DH" +#define SSL_TXT_DHE "DHE" /* same as "kDHE" */ +#define SSL_TXT_EDH "EDH" /* same as "DHE" */ +#define SSL_TXT_RSA "RSA" +#define SSL_TXT_ECDH "ECDH" +#define SSL_TXT_ECDHE "ECDHE" /* same as "kECDHE" */ +#define SSL_TXT_EECDH "EECDH" /* same as "ECDHE" */ +#define SSL_TXT_ECDSA "ECDSA" +#define SSL_TXT_PSK "PSK" + +#define SSL_TXT_3DES "3DES" +#define SSL_TXT_RC4 "RC4" +#define SSL_TXT_AES128 "AES128" +#define SSL_TXT_AES256 "AES256" +#define SSL_TXT_AES "AES" +#define SSL_TXT_AES_GCM "AESGCM" +#define SSL_TXT_CHACHA20 "CHACHA20" + +#define SSL_TXT_MD5 "MD5" +#define SSL_TXT_SHA1 "SHA1" +#define SSL_TXT_SHA "SHA" /* same as "SHA1" */ +#define SSL_TXT_SHA256 "SHA256" +#define SSL_TXT_SHA384 "SHA384" + +#define SSL_TXT_SSLV3 "SSLv3" +#define SSL_TXT_TLSV1 "TLSv1" +#define SSL_TXT_TLSV1_1 "TLSv1.1" +#define SSL_TXT_TLSV1_2 "TLSv1.2" + +#define SSL_TXT_ALL "ALL" + +/* COMPLEMENTOF* definitions. These identifiers are used to (de-select) ciphers + * normally not being used. + * + * Example: "RC4" will activate all ciphers using RC4 including ciphers without + * authentication, which would normally disabled by DEFAULT (due the "!ADH" + * being part of default). Therefore "RC4:!COMPLEMENTOFDEFAULT" will make sure + * that it is also disabled in the specific selection. COMPLEMENTOF* + * identifiers are portable between version, as adjustments to the default + * cipher setup will also be included here. + * + * COMPLEMENTOFDEFAULT does not experience the same special treatment that + * DEFAULT gets, as only selection is being done and no sorting as needed for + * DEFAULT. */ +#define SSL_TXT_CMPDEF "COMPLEMENTOFDEFAULT" + +/* The following cipher list is used by default. It also is substituted when an + * application-defined cipher list string starts with 'DEFAULT'. */ +#define SSL_DEFAULT_CIPHER_LIST "ALL" + +/* As of OpenSSL 1.0.0, ssl_create_cipher_list() in ssl/ssl_ciph.c always + * starts with a reasonable order, and all we have to do for DEFAULT is + * throwing out anonymous and unencrypted ciphersuites! (The latter are not + * actually enabled by ALL, but "ALL:RSA" would enable some of them.) */ + +/* Used in SSL_set_shutdown()/SSL_get_shutdown(); */ +#define SSL_SENT_SHUTDOWN 1 +#define SSL_RECEIVED_SHUTDOWN 2 + +typedef struct ssl_protocol_method_st SSL_PROTOCOL_METHOD; +typedef struct ssl_session_st SSL_SESSION; +typedef struct ssl_conf_ctx_st SSL_CONF_CTX; +typedef struct ssl3_enc_method SSL3_ENC_METHOD; + +/* SRTP protection profiles for use with the use_srtp extension (RFC 5764). */ +typedef struct srtp_protection_profile_st { + const char *name; + unsigned long id; +} SRTP_PROTECTION_PROFILE; + +DECLARE_STACK_OF(SRTP_PROTECTION_PROFILE) + +/* An SSL_SESSION represents an SSL session that may be resumed in an + * abbreviated handshake. */ +struct ssl_session_st { + int ssl_version; /* what ssl version session info is being kept in here? */ + + int master_key_length; + uint8_t master_key[SSL_MAX_MASTER_KEY_LENGTH]; + /* session_id - valid? */ + unsigned int session_id_length; + uint8_t session_id[SSL_MAX_SSL_SESSION_ID_LENGTH]; + /* this is used to determine whether the session is being reused in + * the appropriate context. It is up to the application to set this, + * via SSL_new */ + unsigned int sid_ctx_length; + uint8_t sid_ctx[SSL_MAX_SID_CTX_LENGTH]; + + char *psk_identity; + /* Used to indicate that session resumption is not allowed. Applications can + * also set this bit for a new session via not_resumable_session_cb to + * disable session caching and tickets. */ + int not_resumable; + + /* The cert is the certificate used to establish this connection + * + * TODO(davidben): Remove this field. It is not serialized as part of the + * session, but some APIs access it. Certificate-related fields, where not + * redundant with |peer|, should be added to the session. Others should + * probably not be retained across resumptions. */ + struct sess_cert_st /* SESS_CERT */ *sess_cert; + + /* This is the cert for the other end. On clients, it will be the same as + * sess_cert->peer_key->x509 (the latter is not enough as sess_cert is not + * retained in the external representation of sessions, see ssl_asn1.c). */ + X509 *peer; + /* when app_verify_callback accepts a session where the peer's certificate is + * not ok, we must remember the error for session reuse: */ + long verify_result; /* only for servers */ + + CRYPTO_refcount_t references; + long timeout; + long time; + + const SSL_CIPHER *cipher; + + CRYPTO_EX_DATA ex_data; /* application specific data */ + + /* These are used to make removal of session-ids more efficient and to + * implement a maximum cache size. */ + SSL_SESSION *prev, *next; + char *tlsext_hostname; + /* RFC4507 info */ + uint8_t *tlsext_tick; /* Session ticket */ + size_t tlsext_ticklen; /* Session ticket length */ + uint32_t tlsext_tick_lifetime_hint; /* Session lifetime hint in seconds */ + + size_t tlsext_signed_cert_timestamp_list_length; + uint8_t *tlsext_signed_cert_timestamp_list; /* Server's list. */ + + /* The OCSP response that came with the session. */ + size_t ocsp_response_length; + uint8_t *ocsp_response; + + char peer_sha256_valid; /* Non-zero if peer_sha256 is valid */ + uint8_t + peer_sha256[SHA256_DIGEST_LENGTH]; /* SHA256 of peer certificate */ + + /* original_handshake_hash contains the handshake hash (either SHA-1+MD5 or + * SHA-2, depending on TLS version) for the original, full handshake that + * created a session. This is used by Channel IDs during resumption. */ + uint8_t original_handshake_hash[EVP_MAX_MD_SIZE]; + unsigned int original_handshake_hash_len; + + /* extended_master_secret is true if the master secret in this session was + * generated using EMS and thus isn't vulnerable to the Triple Handshake + * attack. */ + char extended_master_secret; +}; + + +/* SSL_set_mtu sets the |ssl|'s MTU in DTLS to |mtu|. It returns one on success + * and zero on failure. */ +OPENSSL_EXPORT int SSL_set_mtu(SSL *ssl, unsigned mtu); + +/* SSL_get_secure_renegotiation_support returns one if the peer supports secure + * renegotiation (RFC 5746) and zero otherwise. */ +OPENSSL_EXPORT int SSL_get_secure_renegotiation_support(const SSL *ssl); + +/* SSL_CTX_set_msg_callback installs |cb| as the message callback for |ctx|. + * This callback will be called when sending or receiving low-level record + * headers, complete handshake messages, ChangeCipherSpec, and alerts. + * |write_p| is one for outgoing messages and zero for incoming messages. + * + * For each record header, |cb| is called with |version| = 0 and |content_type| + * = |SSL3_RT_HEADER|. The |len| bytes from |buf| contain the header. Note that + * this does not include the record body. If the record is sealed, the length + * in the header is the length of the ciphertext. + * + * For each handshake message, ChangeCipherSpec, and alert, |version| is the + * protocol version and |content_type| is the corresponding record type. The + * |len| bytes from |buf| contain the handshake message, one-byte + * ChangeCipherSpec body, and two-byte alert, respectively. */ +OPENSSL_EXPORT void SSL_CTX_set_msg_callback( + SSL_CTX *ctx, void (*cb)(int write_p, int version, int content_type, + const void *buf, size_t len, SSL *ssl, void *arg)); + +/* SSL_CTX_set_msg_callback_arg sets the |arg| parameter of the message + * callback. */ +OPENSSL_EXPORT void SSL_CTX_set_msg_callback_arg(SSL_CTX *ctx, void *arg); + +/* SSL_set_msg_callback installs |cb| as the message callback of |ssl|. See + * |SSL_CTX_set_msg_callback| for when this callback is called. */ +OPENSSL_EXPORT void SSL_set_msg_callback( + SSL *ssl, void (*cb)(int write_p, int version, int content_type, + const void *buf, size_t len, SSL *ssl, void *arg)); + +/* SSL_set_msg_callback_arg sets the |arg| parameter of the message callback. */ +OPENSSL_EXPORT void SSL_set_msg_callback_arg(SSL *ssl, void *arg); + +/* SSL_CTX_set_keylog_bio sets configures all SSL objects attached to |ctx| to + * log session material to |keylog_bio|. This is intended for debugging use + * with tools like Wireshark. |ctx| takes ownership of |keylog_bio|. + * + * The format is described in + * https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format. */ +OPENSSL_EXPORT void SSL_CTX_set_keylog_bio(SSL_CTX *ctx, BIO *keylog_bio); + + +struct ssl_aead_ctx_st; +typedef struct ssl_aead_ctx_st SSL_AEAD_CTX; + +#define SSL_MAX_CERT_LIST_DEFAULT 1024 * 100 /* 100k max cert list */ + +#define SSL_SESSION_CACHE_MAX_SIZE_DEFAULT (1024 * 20) + +#define SSL_DEFAULT_SESSION_TIMEOUT (2 * 60 * 60) + +/* This callback type is used inside SSL_CTX, SSL, and in the functions that + * set them. It is used to override the generation of SSL/TLS session IDs in a + * server. Return value should be zero on an error, non-zero to proceed. Also, + * callbacks should themselves check if the id they generate is unique + * otherwise the SSL handshake will fail with an error - callbacks can do this + * using the 'ssl' value they're passed by; + * SSL_has_matching_session_id(ssl, id, *id_len) + * The length value passed in is set at the maximum size the session ID can be. + * In SSLv2 this is 16 bytes, whereas SSLv3/TLSv1 it is 32 bytes. The callback + * can alter this length to be less if desired, but under SSLv2 session IDs are + * supposed to be fixed at 16 bytes so the id will be padded after the callback + * returns in this case. It is also an error for the callback to set the size + * to zero. */ +typedef int (*GEN_SESSION_CB)(const SSL *ssl, uint8_t *id, + unsigned int *id_len); + +/* ssl_early_callback_ctx is passed to certain callbacks that are called very + * early on during the server handshake. At this point, much of the SSL* hasn't + * been filled out and only the ClientHello can be depended on. */ +struct ssl_early_callback_ctx { + SSL *ssl; + const uint8_t *client_hello; + size_t client_hello_len; + const uint8_t *session_id; + size_t session_id_len; + const uint8_t *cipher_suites; + size_t cipher_suites_len; + const uint8_t *compression_methods; + size_t compression_methods_len; + const uint8_t *extensions; + size_t extensions_len; +}; + +/* SSL_early_callback_ctx_extension_get searches the extensions in |ctx| for an + * extension of the given type. If not found, it returns zero. Otherwise it + * sets |out_data| to point to the extension contents (not including the type + * and length bytes), sets |out_len| to the length of the extension contents + * and returns one. */ +OPENSSL_EXPORT char SSL_early_callback_ctx_extension_get( + const struct ssl_early_callback_ctx *ctx, uint16_t extension_type, + const uint8_t **out_data, size_t *out_len); + +typedef struct ssl_comp_st SSL_COMP; + +struct ssl_comp_st { + int id; + const char *name; + char *method; +}; + +DECLARE_STACK_OF(SSL_COMP) +DECLARE_LHASH_OF(SSL_SESSION) + +/* ssl_cipher_preference_list_st contains a list of SSL_CIPHERs with + * equal-preference groups. For TLS clients, the groups are moot because the + * server picks the cipher and groups cannot be expressed on the wire. However, + * for servers, the equal-preference groups allow the client's preferences to + * be partially respected. (This only has an effect with + * SSL_OP_CIPHER_SERVER_PREFERENCE). + * + * The equal-preference groups are expressed by grouping SSL_CIPHERs together. + * All elements of a group have the same priority: no ordering is expressed + * within a group. + * + * The values in |ciphers| are in one-to-one correspondence with + * |in_group_flags|. (That is, sk_SSL_CIPHER_num(ciphers) is the number of + * bytes in |in_group_flags|.) The bytes in |in_group_flags| are either 1, to + * indicate that the corresponding SSL_CIPHER is not the last element of a + * group, or 0 to indicate that it is. + * + * For example, if |in_group_flags| contains all zeros then that indicates a + * traditional, fully-ordered preference. Every SSL_CIPHER is the last element + * of the group (i.e. they are all in a one-element group). + * + * For a more complex example, consider: + * ciphers: A B C D E F + * in_group_flags: 1 1 0 0 1 0 + * + * That would express the following, order: + * + * A E + * B -> D -> F + * C + */ +struct ssl_cipher_preference_list_st { + STACK_OF(SSL_CIPHER) *ciphers; + uint8_t *in_group_flags; +}; + +struct ssl_ctx_st { + const SSL_PROTOCOL_METHOD *method; + + /* lock is used to protect various operations on this object. */ + CRYPTO_MUTEX lock; + + /* max_version is the maximum acceptable protocol version. If zero, the + * maximum supported version, currently (D)TLS 1.2, is used. */ + uint16_t max_version; + + /* min_version is the minimum acceptable protocl version. If zero, the + * minimum supported version, currently SSL 3.0 and DTLS 1.0, is used */ + uint16_t min_version; + + struct ssl_cipher_preference_list_st *cipher_list; + /* same as above but sorted for lookup */ + STACK_OF(SSL_CIPHER) *cipher_list_by_id; + /* cipher_list_tls11 is the list of ciphers when TLS 1.1 or greater is in + * use. This only applies to server connections as, for clients, the version + * number is known at connect time and so the cipher list can be set then. */ + struct ssl_cipher_preference_list_st *cipher_list_tls11; + + X509_STORE *cert_store; + LHASH_OF(SSL_SESSION) *sessions; + /* Most session-ids that will be cached, default is + * SSL_SESSION_CACHE_MAX_SIZE_DEFAULT. 0 is unlimited. */ + unsigned long session_cache_size; + SSL_SESSION *session_cache_head; + SSL_SESSION *session_cache_tail; + + /* handshakes_since_cache_flush is the number of successful handshakes since + * the last cache flush. */ + int handshakes_since_cache_flush; + + /* This can have one of 2 values, ored together, + * SSL_SESS_CACHE_CLIENT, + * SSL_SESS_CACHE_SERVER, + * Default is SSL_SESSION_CACHE_SERVER, which means only + * SSL_accept which cache SSL_SESSIONS. */ + int session_cache_mode; + + /* If timeout is not 0, it is the default timeout value set when SSL_new() is + * called. This has been put in to make life easier to set things up */ + long session_timeout; + + /* If this callback is not null, it will be called each time a session id is + * added to the cache. If this function returns 1, it means that the + * callback will do a SSL_SESSION_free() when it has finished using it. + * Otherwise, on 0, it means the callback has finished with it. If + * remove_session_cb is not null, it will be called when a session-id is + * removed from the cache. After the call, OpenSSL will SSL_SESSION_free() + * it. */ + int (*new_session_cb)(SSL *ssl, SSL_SESSION *sess); + void (*remove_session_cb)(SSL_CTX *ctx, SSL_SESSION *sess); + SSL_SESSION *(*get_session_cb)(SSL *ssl, uint8_t *data, int len, + int *copy); + + CRYPTO_refcount_t references; + + /* if defined, these override the X509_verify_cert() calls */ + int (*app_verify_callback)(X509_STORE_CTX *, void *); + void *app_verify_arg; + /* before OpenSSL 0.9.7, 'app_verify_arg' was ignored ('app_verify_callback' + * was called with just one argument) */ + + /* Default password callback. */ + pem_password_cb *default_passwd_callback; + + /* Default password callback user data. */ + void *default_passwd_callback_userdata; + + /* get client cert callback */ + int (*client_cert_cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey); + + /* get channel id callback */ + void (*channel_id_cb)(SSL *ssl, EVP_PKEY **pkey); + + CRYPTO_EX_DATA ex_data; + + /* custom_*_extensions stores any callback sets for custom extensions. Note + * that these pointers will be NULL if the stack would otherwise be empty. */ + STACK_OF(SSL_CUSTOM_EXTENSION) *client_custom_extensions; + STACK_OF(SSL_CUSTOM_EXTENSION) *server_custom_extensions; + + /* Default values used when no per-SSL value is defined follow */ + + void (*info_callback)(const SSL *ssl, int type, + int val); /* used if SSL's info_callback is NULL */ + + /* what we put in client cert requests */ + STACK_OF(X509_NAME) *client_CA; + + + /* Default values to use in SSL structures follow (these are copied by + * SSL_new) */ + + uint32_t options; + uint32_t mode; + uint32_t max_cert_list; + + struct cert_st /* CERT */ *cert; + + /* callback that allows applications to peek at protocol messages */ + void (*msg_callback)(int write_p, int version, int content_type, + const void *buf, size_t len, SSL *ssl, void *arg); + void *msg_callback_arg; + + int verify_mode; + unsigned int sid_ctx_length; + uint8_t sid_ctx[SSL_MAX_SID_CTX_LENGTH]; + int (*default_verify_callback)( + int ok, X509_STORE_CTX *ctx); /* called 'verify_callback' in the SSL */ + + /* Default generate session ID callback. */ + GEN_SESSION_CB generate_session_id; + + X509_VERIFY_PARAM *param; + + /* select_certificate_cb is called before most ClientHello processing and + * before the decision whether to resume a session is made. It may return one + * to continue the handshake or zero to cause the handshake loop to return + * with an error and cause SSL_get_error to return + * SSL_ERROR_PENDING_CERTIFICATE. Note: when the handshake loop is resumed, it + * will not call the callback a second time. */ + int (*select_certificate_cb)(const struct ssl_early_callback_ctx *); + + /* dos_protection_cb is called once the resumption decision for a ClientHello + * has been made. It returns one to continue the handshake or zero to + * abort. */ + int (*dos_protection_cb) (const struct ssl_early_callback_ctx *); + + /* quiet_shutdown is true if the connection should not send a close_notify on + * shutdown. */ + int quiet_shutdown; + + /* Maximum amount of data to send in one fragment. actual record size can be + * more than this due to padding and MAC overheads. */ + uint16_t max_send_fragment; + + /* TLS extensions servername callback */ + int (*tlsext_servername_callback)(SSL *, int *, void *); + void *tlsext_servername_arg; + /* RFC 4507 session ticket keys */ + uint8_t tlsext_tick_key_name[SSL_TICKET_KEY_NAME_LEN]; + uint8_t tlsext_tick_hmac_key[16]; + uint8_t tlsext_tick_aes_key[16]; + /* Callback to support customisation of ticket key setting */ + int (*tlsext_ticket_key_cb)(SSL *ssl, uint8_t *name, uint8_t *iv, + EVP_CIPHER_CTX *ectx, HMAC_CTX *hctx, int enc); + + /* Server-only: psk_identity_hint is the default identity hint to send in + * PSK-based key exchanges. */ + char *psk_identity_hint; + + unsigned int (*psk_client_callback)(SSL *ssl, const char *hint, + char *identity, + unsigned int max_identity_len, + uint8_t *psk, unsigned int max_psk_len); + unsigned int (*psk_server_callback)(SSL *ssl, const char *identity, + uint8_t *psk, unsigned int max_psk_len); + + + /* retain_only_sha256_of_client_certs is true if we should compute the SHA256 + * hash of the peer's certifiate and then discard it to save memory and + * session space. Only effective on the server side. */ + char retain_only_sha256_of_client_certs; + + /* Next protocol negotiation information */ + /* (for experimental NPN extension). */ + + /* For a server, this contains a callback function by which the set of + * advertised protocols can be provided. */ + int (*next_protos_advertised_cb)(SSL *s, const uint8_t **buf, + unsigned int *len, void *arg); + void *next_protos_advertised_cb_arg; + /* For a client, this contains a callback function that selects the + * next protocol from the list provided by the server. */ + int (*next_proto_select_cb)(SSL *s, uint8_t **out, uint8_t *outlen, + const uint8_t *in, unsigned int inlen, void *arg); + void *next_proto_select_cb_arg; + + /* ALPN information + * (we are in the process of transitioning from NPN to ALPN.) */ + + /* For a server, this contains a callback function that allows the + * server to select the protocol for the connection. + * out: on successful return, this must point to the raw protocol + * name (without the length prefix). + * outlen: on successful return, this contains the length of |*out|. + * in: points to the client's list of supported protocols in + * wire-format. + * inlen: the length of |in|. */ + int (*alpn_select_cb)(SSL *s, const uint8_t **out, uint8_t *outlen, + const uint8_t *in, unsigned int inlen, void *arg); + void *alpn_select_cb_arg; + + /* For a client, this contains the list of supported protocols in wire + * format. */ + uint8_t *alpn_client_proto_list; + unsigned alpn_client_proto_list_len; + + /* SRTP profiles we are willing to do from RFC 5764 */ + STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles; + + /* EC extension values inherited by SSL structure */ + size_t tlsext_ellipticcurvelist_length; + uint16_t *tlsext_ellipticcurvelist; + + /* If true, a client will advertise the Channel ID extension and a server + * will echo it. */ + char tlsext_channel_id_enabled; + /* The client's Channel ID private key. */ + EVP_PKEY *tlsext_channel_id_private; + + /* If true, a client will request certificate timestamps. */ + char signed_cert_timestamps_enabled; + + /* If true, a client will request a stapled OCSP response. */ + char ocsp_stapling_enabled; + + /* If not NULL, session key material will be logged to this BIO for debugging + * purposes. The format matches NSS's and is readable by Wireshark. */ + BIO *keylog_bio; + + /* current_time_cb, if not NULL, is the function to use to get the current + * time. It sets |*out_clock| to the current time. */ + void (*current_time_cb)(const SSL *ssl, struct timeval *out_clock); +}; + +OPENSSL_EXPORT LHASH_OF(SSL_SESSION) *SSL_CTX_sessions(SSL_CTX *ctx); + +/* SSL_CTX_sess_number returns the number of sessions in |ctx|'s internal + * session cache. */ +OPENSSL_EXPORT size_t SSL_CTX_sess_number(const SSL_CTX *ctx); + +OPENSSL_EXPORT void SSL_CTX_sess_set_new_cb( + SSL_CTX *ctx, int (*new_session_cb)(SSL *ssl, SSL_SESSION *sess)); +OPENSSL_EXPORT int (*SSL_CTX_sess_get_new_cb(SSL_CTX *ctx))(SSL *ssl, + SSL_SESSION *sess); +OPENSSL_EXPORT void SSL_CTX_sess_set_remove_cb( + SSL_CTX *ctx, + void (*remove_session_cb)(SSL_CTX *ctx, SSL_SESSION *sess)); +OPENSSL_EXPORT void (*SSL_CTX_sess_get_remove_cb(SSL_CTX *ctx))( + SSL_CTX *ctx, SSL_SESSION *sess); +OPENSSL_EXPORT void SSL_CTX_sess_set_get_cb( + SSL_CTX *ctx, + SSL_SESSION *(*get_session_cb)(SSL *ssl, uint8_t *data, int len, + int *copy)); +OPENSSL_EXPORT SSL_SESSION *(*SSL_CTX_sess_get_get_cb(SSL_CTX *ctx))( + SSL *ssl, uint8_t *data, int len, int *copy); +/* SSL_magic_pending_session_ptr returns a magic SSL_SESSION* which indicates + * that the session isn't currently unavailable. SSL_get_error will then return + * SSL_ERROR_PENDING_SESSION and the handshake can be retried later when the + * lookup has completed. */ +OPENSSL_EXPORT SSL_SESSION *SSL_magic_pending_session_ptr(void); +OPENSSL_EXPORT void SSL_CTX_set_info_callback(SSL_CTX *ctx, + void (*cb)(const SSL *ssl, + int type, int val)); +OPENSSL_EXPORT void (*SSL_CTX_get_info_callback(SSL_CTX *ctx))(const SSL *ssl, + int type, + int val); +OPENSSL_EXPORT void SSL_CTX_set_client_cert_cb( + SSL_CTX *ctx, + int (*client_cert_cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey)); +OPENSSL_EXPORT int (*SSL_CTX_get_client_cert_cb(SSL_CTX *ctx))(SSL *ssl, + X509 **x509, + EVP_PKEY **pkey); +OPENSSL_EXPORT void SSL_CTX_set_channel_id_cb( + SSL_CTX *ctx, void (*channel_id_cb)(SSL *ssl, EVP_PKEY **pkey)); +OPENSSL_EXPORT void (*SSL_CTX_get_channel_id_cb(SSL_CTX *ctx))(SSL *ssl, + EVP_PKEY **pkey); + +/* SSL_enable_signed_cert_timestamps causes |ssl| (which must be the client end + * of a connection) to request SCTs from the server. See + * https://tools.ietf.org/html/rfc6962. It returns one. */ +OPENSSL_EXPORT int SSL_enable_signed_cert_timestamps(SSL *ssl); + +/* SSL_CTX_enable_signed_cert_timestamps enables SCT requests on all client SSL + * objects created from |ctx|. */ +OPENSSL_EXPORT void SSL_CTX_enable_signed_cert_timestamps(SSL_CTX *ctx); + +/* SSL_enable_ocsp_stapling causes |ssl| (which must be the client end of a + * connection) to request a stapled OCSP response from the server. It returns + * one. */ +OPENSSL_EXPORT int SSL_enable_ocsp_stapling(SSL *ssl); + +/* SSL_CTX_enable_ocsp_stapling enables OCSP stapling on all client SSL objects + * created from |ctx|. */ +OPENSSL_EXPORT void SSL_CTX_enable_ocsp_stapling(SSL_CTX *ctx); + +/* SSL_get0_signed_cert_timestamp_list sets |*out| and |*out_len| to point to + * |*out_len| bytes of SCT information from the server. This is only valid if + * |ssl| is a client. The SCT information is a SignedCertificateTimestampList + * (including the two leading length bytes). + * See https://tools.ietf.org/html/rfc6962#section-3.3 + * If no SCT was received then |*out_len| will be zero on return. + * + * WARNING: the returned data is not guaranteed to be well formed. */ +OPENSSL_EXPORT void SSL_get0_signed_cert_timestamp_list(const SSL *ssl, + const uint8_t **out, + size_t *out_len); + +/* SSL_get0_ocsp_response sets |*out| and |*out_len| to point to |*out_len| + * bytes of an OCSP response from the server. This is the DER encoding of an + * OCSPResponse type as defined in RFC 2560. + * + * WARNING: the returned data is not guaranteed to be well formed. */ +OPENSSL_EXPORT void SSL_get0_ocsp_response(const SSL *ssl, const uint8_t **out, + size_t *out_len); + +OPENSSL_EXPORT void SSL_CTX_set_next_protos_advertised_cb( + SSL_CTX *s, + int (*cb)(SSL *ssl, const uint8_t **out, unsigned int *outlen, void *arg), + void *arg); +OPENSSL_EXPORT void SSL_CTX_set_next_proto_select_cb( + SSL_CTX *s, int (*cb)(SSL *ssl, uint8_t **out, uint8_t *outlen, + const uint8_t *in, unsigned int inlen, void *arg), + void *arg); +OPENSSL_EXPORT void SSL_get0_next_proto_negotiated(const SSL *s, + const uint8_t **data, + unsigned *len); + +OPENSSL_EXPORT int SSL_select_next_proto(uint8_t **out, uint8_t *outlen, + const uint8_t *in, unsigned int inlen, + const uint8_t *client, + unsigned int client_len); + +#define OPENSSL_NPN_UNSUPPORTED 0 +#define OPENSSL_NPN_NEGOTIATED 1 +#define OPENSSL_NPN_NO_OVERLAP 2 + +/* SSL_CTX_set_alpn_protos sets the ALPN protocol list on |ctx| to |protos|. + * |protos| must be in wire-format (i.e. a series of non-empty, 8-bit + * length-prefixed strings). It returns zero on success and one on failure. + * + * WARNING: this function is dangerous because it breaks the usual return value + * convention. */ +OPENSSL_EXPORT int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const uint8_t *protos, + unsigned protos_len); + +/* SSL_set_alpn_protos sets the ALPN protocol list on |ssl| to |protos|. + * |protos| must be in wire-format (i.e. a series of non-empty, 8-bit + * length-prefixed strings). It returns zero on success and one on failure. + * + * WARNING: this function is dangerous because it breaks the usual return value + * convention. */ +OPENSSL_EXPORT int SSL_set_alpn_protos(SSL *ssl, const uint8_t *protos, + unsigned protos_len); + +OPENSSL_EXPORT void SSL_CTX_set_alpn_select_cb( + SSL_CTX *ctx, int (*cb)(SSL *ssl, const uint8_t **out, uint8_t *outlen, + const uint8_t *in, unsigned int inlen, void *arg), + void *arg); +OPENSSL_EXPORT void SSL_get0_alpn_selected(const SSL *ssl, const uint8_t **data, + unsigned *len); + +/* SSL_set_reject_peer_renegotiations controls whether renegotiation attempts by + * the peer are rejected. It may be set at any point in a connection's lifetime + * to control future renegotiations programmatically. By default, renegotiations + * are rejected. (Renegotiations requested by a client are always rejected.) */ +OPENSSL_EXPORT void SSL_set_reject_peer_renegotiations(SSL *ssl, int reject); + +/* the maximum length of the buffer given to callbacks containing the resulting + * identity/psk */ +#define PSK_MAX_IDENTITY_LEN 128 +#define PSK_MAX_PSK_LEN 256 +OPENSSL_EXPORT void SSL_CTX_set_psk_client_callback( + SSL_CTX *ctx, + unsigned int (*psk_client_callback)( + SSL *ssl, const char *hint, char *identity, + unsigned int max_identity_len, uint8_t *psk, unsigned int max_psk_len)); +OPENSSL_EXPORT void SSL_set_psk_client_callback( + SSL *ssl, unsigned int (*psk_client_callback)(SSL *ssl, const char *hint, + char *identity, + unsigned int max_identity_len, + uint8_t *psk, + unsigned int max_psk_len)); +OPENSSL_EXPORT void SSL_CTX_set_psk_server_callback( + SSL_CTX *ctx, + unsigned int (*psk_server_callback)(SSL *ssl, const char *identity, + uint8_t *psk, + unsigned int max_psk_len)); +OPENSSL_EXPORT void SSL_set_psk_server_callback( + SSL *ssl, + unsigned int (*psk_server_callback)(SSL *ssl, const char *identity, + uint8_t *psk, + unsigned int max_psk_len)); +OPENSSL_EXPORT int SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, + const char *identity_hint); +OPENSSL_EXPORT int SSL_use_psk_identity_hint(SSL *s, const char *identity_hint); +OPENSSL_EXPORT const char *SSL_get_psk_identity_hint(const SSL *s); +OPENSSL_EXPORT const char *SSL_get_psk_identity(const SSL *s); + +#define SSL_NOTHING 1 +#define SSL_WRITING 2 +#define SSL_READING 3 +#define SSL_X509_LOOKUP 4 +#define SSL_CHANNEL_ID_LOOKUP 5 +#define SSL_PENDING_SESSION 7 +#define SSL_CERTIFICATE_SELECTION_PENDING 8 +#define SSL_PRIVATE_KEY_OPERATION 9 + +/* These will only be used when doing non-blocking IO */ +#define SSL_want_nothing(s) (SSL_want(s) == SSL_NOTHING) +#define SSL_want_read(s) (SSL_want(s) == SSL_READING) +#define SSL_want_write(s) (SSL_want(s) == SSL_WRITING) +#define SSL_want_x509_lookup(s) (SSL_want(s) == SSL_X509_LOOKUP) +#define SSL_want_channel_id_lookup(s) (SSL_want(s) == SSL_CHANNEL_ID_LOOKUP) +#define SSL_want_session(s) (SSL_want(s) == SSL_PENDING_SESSION) +#define SSL_want_certificate(s) \ + (SSL_want(s) == SSL_CERTIFICATE_SELECTION_PENDING) +#define SSL_want_private_key_operation(s) \ + (SSL_want(s) == SSL_PRIVATE_KEY_OPERATION) + +struct ssl_st { + /* version is the protocol version. */ + int version; + + /* method is the method table corresponding to the current protocol (DTLS or + * TLS). */ + const SSL_PROTOCOL_METHOD *method; + + /* enc_method is the method table corresponding to the current protocol + * version. */ + const SSL3_ENC_METHOD *enc_method; + + /* max_version is the maximum acceptable protocol version. If zero, the + * maximum supported version, currently (D)TLS 1.2, is used. */ + uint16_t max_version; + + /* min_version is the minimum acceptable protocl version. If zero, the + * minimum supported version, currently SSL 3.0 and DTLS 1.0, is used */ + uint16_t min_version; + + /* There are 2 BIO's even though they are normally both the same. This is so + * data can be read and written to different handlers */ + + BIO *rbio; /* used by SSL_read */ + BIO *wbio; /* used by SSL_write */ + BIO *bbio; /* used during session-id reuse to concatenate + * messages */ + + /* This holds a variable that indicates what we were doing when a 0 or -1 is + * returned. This is needed for non-blocking IO so we know what request + * needs re-doing when in SSL_accept or SSL_connect */ + int rwstate; + + /* true when we are actually in SSL_accept() or SSL_connect() */ + int in_handshake; + int (*handshake_func)(SSL *); + + /* Imagine that here's a boolean member "init" that is switched as soon as + * SSL_set_{accept/connect}_state is called for the first time, so that + * "state" and "handshake_func" are properly initialized. But as + * handshake_func is == 0 until then, we use this test instead of an "init" + * member. */ + + /* server is true iff the this SSL* is the server half. Note: before the SSL* + * is initialized by either SSL_set_accept_state or SSL_set_connect_state, + * the side is not determined. In this state, server is always false. */ + int server; + + /* quiet_shutdown is true if the connection should not send a close_notify on + * shutdown. */ + int quiet_shutdown; + + int shutdown; /* we have shut things down, 0x01 sent, 0x02 + * for received */ + int state; /* where we are */ + int rstate; /* where we are when reading */ + + BUF_MEM *init_buf; /* buffer used during init */ + uint8_t *init_msg; /* pointer to handshake message body, set by + ssl3_get_message() */ + int init_num; /* amount read/written */ + int init_off; /* amount read/written */ + + /* used internally to point at a raw packet */ + uint8_t *packet; + unsigned int packet_length; + + struct ssl3_state_st *s3; /* SSLv3 variables */ + struct dtls1_state_st *d1; /* DTLSv1 variables */ + + /* callback that allows applications to peek at protocol messages */ + void (*msg_callback)(int write_p, int version, int content_type, + const void *buf, size_t len, SSL *ssl, void *arg); + void *msg_callback_arg; + + int hit; /* reusing a previous session */ + + X509_VERIFY_PARAM *param; + + /* crypto */ + struct ssl_cipher_preference_list_st *cipher_list; + STACK_OF(SSL_CIPHER) *cipher_list_by_id; + + SSL_AEAD_CTX *aead_read_ctx; + SSL_AEAD_CTX *aead_write_ctx; + + /* session info */ + + /* client cert? */ + /* This is used to hold the server certificate used */ + struct cert_st /* CERT */ *cert; + + /* the session_id_context is used to ensure sessions are only reused + * in the appropriate context */ + unsigned int sid_ctx_length; + uint8_t sid_ctx[SSL_MAX_SID_CTX_LENGTH]; + + /* This can also be in the session once a session is established */ + SSL_SESSION *session; + + /* Default generate session ID callback. */ + GEN_SESSION_CB generate_session_id; + + /* Used in SSL2 and SSL3 */ + int verify_mode; /* 0 don't care about verify failure. + * 1 fail if verify fails */ + int (*verify_callback)(int ok, + X509_STORE_CTX *ctx); /* fail if callback returns 0 */ + + void (*info_callback)(const SSL *ssl, int type, + int val); /* optional informational callback */ + + /* Server-only: psk_identity_hint is the identity hint to send in + * PSK-based key exchanges. */ + char *psk_identity_hint; + + unsigned int (*psk_client_callback)(SSL *ssl, const char *hint, + char *identity, + unsigned int max_identity_len, + uint8_t *psk, unsigned int max_psk_len); + unsigned int (*psk_server_callback)(SSL *ssl, const char *identity, + uint8_t *psk, unsigned int max_psk_len); + + SSL_CTX *ctx; + + /* extra application data */ + long verify_result; + CRYPTO_EX_DATA ex_data; + + /* for server side, keep the list of CA_dn we can use */ + STACK_OF(X509_NAME) *client_CA; + + uint32_t options; /* protocol behaviour */ + uint32_t mode; /* API behaviour */ + uint32_t max_cert_list; + int client_version; /* what was passed, used for + * SSLv3/TLS rollback check */ + uint16_t max_send_fragment; + char *tlsext_hostname; + /* RFC4507 session ticket expected to be received or sent */ + int tlsext_ticket_expected; + size_t tlsext_ellipticcurvelist_length; + uint16_t *tlsext_ellipticcurvelist; /* our list */ + + SSL_CTX *initial_ctx; /* initial ctx, used to store sessions */ + + /* Next protocol negotiation. For the client, this is the protocol that we + * sent in NextProtocol and is set when handling ServerHello extensions. + * + * For a server, this is the client's selected_protocol from NextProtocol and + * is set when handling the NextProtocol message, before the Finished + * message. */ + uint8_t *next_proto_negotiated; + size_t next_proto_negotiated_len; + + /* srtp_profiles is the list of configured SRTP protection profiles for + * DTLS-SRTP. */ + STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles; + + /* srtp_profile is the selected SRTP protection profile for + * DTLS-SRTP. */ + const SRTP_PROTECTION_PROFILE *srtp_profile; + + /* Copied from the SSL_CTX. For a server, means that we'll accept Channel IDs + * from clients. For a client, means that we'll advertise support. */ + char tlsext_channel_id_enabled; + /* The client's Channel ID private key. */ + EVP_PKEY *tlsext_channel_id_private; + + /* Enable signed certificate time stamps. Currently client only. */ + char signed_cert_timestamps_enabled; + + /* Enable OCSP stapling. Currently client only. + * TODO(davidben): Add a server-side implementation when it becomes + * necesary. */ + char ocsp_stapling_enabled; + + /* For a client, this contains the list of supported protocols in wire + * format. */ + uint8_t *alpn_client_proto_list; + unsigned alpn_client_proto_list_len; + + /* accept_peer_renegotiations, if one, accepts renegotiation attempts from the + * peer. Otherwise, they will be rejected with a fatal error. */ + char accept_peer_renegotiations; + + /* These fields are always NULL and exist only to keep wpa_supplicant happy + * about the change to EVP_AEAD. They are only needed for EAP-FAST, which we + * don't support. */ + EVP_CIPHER_CTX *enc_read_ctx; + EVP_MD_CTX *read_hash; +}; + +/* compatibility */ +#define SSL_set_app_data(s, arg) (SSL_set_ex_data(s, 0, (char *)arg)) +#define SSL_get_app_data(s) (SSL_get_ex_data(s, 0)) +#define SSL_SESSION_set_app_data(s, a) \ + (SSL_SESSION_set_ex_data(s, 0, (char *)a)) +#define SSL_SESSION_get_app_data(s) (SSL_SESSION_get_ex_data(s, 0)) +#define SSL_CTX_get_app_data(ctx) (SSL_CTX_get_ex_data(ctx, 0)) +#define SSL_CTX_set_app_data(ctx, arg) \ + (SSL_CTX_set_ex_data(ctx, 0, (char *)arg)) + +/* The following are the possible values for ssl->state are are used to + * indicate where we are up to in the SSL connection establishment. The macros + * that follow are about the only things you should need to use and even then, + * only when using non-blocking IO. It can also be useful to work out where you + * were when the connection failed */ + +#define SSL_ST_CONNECT 0x1000 +#define SSL_ST_ACCEPT 0x2000 +#define SSL_ST_MASK 0x0FFF +#define SSL_ST_INIT (SSL_ST_CONNECT | SSL_ST_ACCEPT) +#define SSL_ST_OK 0x03 +#define SSL_ST_RENEGOTIATE (0x04 | SSL_ST_INIT) + +#define SSL_CB_LOOP 0x01 +#define SSL_CB_EXIT 0x02 +#define SSL_CB_READ 0x04 +#define SSL_CB_WRITE 0x08 +#define SSL_CB_ALERT 0x4000 /* used in callback */ +#define SSL_CB_READ_ALERT (SSL_CB_ALERT | SSL_CB_READ) +#define SSL_CB_WRITE_ALERT (SSL_CB_ALERT | SSL_CB_WRITE) +#define SSL_CB_ACCEPT_LOOP (SSL_ST_ACCEPT | SSL_CB_LOOP) +#define SSL_CB_ACCEPT_EXIT (SSL_ST_ACCEPT | SSL_CB_EXIT) +#define SSL_CB_CONNECT_LOOP (SSL_ST_CONNECT | SSL_CB_LOOP) +#define SSL_CB_CONNECT_EXIT (SSL_ST_CONNECT | SSL_CB_EXIT) +#define SSL_CB_HANDSHAKE_START 0x10 +#define SSL_CB_HANDSHAKE_DONE 0x20 + +/* Is the SSL_connection established? */ +#define SSL_get_state(a) SSL_state(a) +#define SSL_is_init_finished(a) (SSL_state(a) == SSL_ST_OK) +#define SSL_in_init(a) (SSL_state(a) & SSL_ST_INIT) +#define SSL_in_connect_init(a) (SSL_state(a) & SSL_ST_CONNECT) +#define SSL_in_accept_init(a) (SSL_state(a) & SSL_ST_ACCEPT) + +/* SSL_in_false_start returns one if |s| has a pending unfinished handshake that + * is in False Start. |SSL_write| may be called at this point without waiting + * for the peer, but |SSL_read| will require the handshake to be completed. */ +OPENSSL_EXPORT int SSL_in_false_start(const SSL *s); + +/* The following 2 states are kept in ssl->rstate when reads fail, + * you should not need these */ +#define SSL_ST_READ_HEADER 0xF0 +#define SSL_ST_READ_BODY 0xF1 +#define SSL_ST_READ_DONE 0xF2 + +/* Obtain latest Finished message + * -- that we sent (SSL_get_finished) + * -- that we expected from peer (SSL_get_peer_finished). + * Returns length (0 == no Finished so far), copies up to 'count' bytes. */ +OPENSSL_EXPORT size_t SSL_get_finished(const SSL *s, void *buf, size_t count); +OPENSSL_EXPORT size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count); + +/* use either SSL_VERIFY_NONE or SSL_VERIFY_PEER, the last 3 options + * are 'ored' with SSL_VERIFY_PEER if they are desired */ +#define SSL_VERIFY_NONE 0x00 +#define SSL_VERIFY_PEER 0x01 +#define SSL_VERIFY_FAIL_IF_NO_PEER_CERT 0x02 +/* SSL_VERIFY_CLIENT_ONCE does nothing. */ +#define SSL_VERIFY_CLIENT_ONCE 0x04 +#define SSL_VERIFY_PEER_IF_NO_OBC 0x08 + +#define OpenSSL_add_ssl_algorithms() SSL_library_init() +#define SSLeay_add_ssl_algorithms() SSL_library_init() + +/* For backward compatibility */ +#define SSL_get_cipher(s) SSL_CIPHER_get_name(SSL_get_current_cipher(s)) +#define SSL_get_cipher_bits(s, np) \ + SSL_CIPHER_get_bits(SSL_get_current_cipher(s), np) +#define SSL_get_cipher_version(s) \ + SSL_CIPHER_get_version(SSL_get_current_cipher(s)) +#define SSL_get_cipher_name(s) SSL_CIPHER_get_name(SSL_get_current_cipher(s)) +#define SSL_get_time(a) SSL_SESSION_get_time(a) +#define SSL_set_time(a, b) SSL_SESSION_set_time((a), (b)) +#define SSL_get_timeout(a) SSL_SESSION_get_timeout(a) +#define SSL_set_timeout(a, b) SSL_SESSION_set_timeout((a), (b)) + +#define d2i_SSL_SESSION_bio(bp, s_id) \ + ASN1_d2i_bio_of(SSL_SESSION, SSL_SESSION_new, d2i_SSL_SESSION, bp, s_id) +#define i2d_SSL_SESSION_bio(bp, s_id) \ + ASN1_i2d_bio_of(SSL_SESSION, i2d_SSL_SESSION, bp, s_id) + +DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION) + +/* make_errors.go reserves error codes above 1000 for manually-assigned errors. + * This value must be kept in sync with reservedReasonCode in make_errors.h */ +#define SSL_AD_REASON_OFFSET \ + 1000 /* offset to get SSL_R_... value from SSL_AD_... */ + +/* These alert types are for SSLv3 and TLSv1 */ +#define SSL_AD_CLOSE_NOTIFY SSL3_AD_CLOSE_NOTIFY +#define SSL_AD_UNEXPECTED_MESSAGE SSL3_AD_UNEXPECTED_MESSAGE /* fatal */ +#define SSL_AD_BAD_RECORD_MAC SSL3_AD_BAD_RECORD_MAC /* fatal */ +#define SSL_AD_DECRYPTION_FAILED TLS1_AD_DECRYPTION_FAILED +#define SSL_AD_RECORD_OVERFLOW TLS1_AD_RECORD_OVERFLOW +#define SSL_AD_DECOMPRESSION_FAILURE SSL3_AD_DECOMPRESSION_FAILURE /* fatal */ +#define SSL_AD_HANDSHAKE_FAILURE SSL3_AD_HANDSHAKE_FAILURE /* fatal */ +#define SSL_AD_NO_CERTIFICATE SSL3_AD_NO_CERTIFICATE /* Not for TLS */ +#define SSL_AD_BAD_CERTIFICATE SSL3_AD_BAD_CERTIFICATE +#define SSL_AD_UNSUPPORTED_CERTIFICATE SSL3_AD_UNSUPPORTED_CERTIFICATE +#define SSL_AD_CERTIFICATE_REVOKED SSL3_AD_CERTIFICATE_REVOKED +#define SSL_AD_CERTIFICATE_EXPIRED SSL3_AD_CERTIFICATE_EXPIRED +#define SSL_AD_CERTIFICATE_UNKNOWN SSL3_AD_CERTIFICATE_UNKNOWN +#define SSL_AD_ILLEGAL_PARAMETER SSL3_AD_ILLEGAL_PARAMETER /* fatal */ +#define SSL_AD_UNKNOWN_CA TLS1_AD_UNKNOWN_CA /* fatal */ +#define SSL_AD_ACCESS_DENIED TLS1_AD_ACCESS_DENIED /* fatal */ +#define SSL_AD_DECODE_ERROR TLS1_AD_DECODE_ERROR /* fatal */ +#define SSL_AD_DECRYPT_ERROR TLS1_AD_DECRYPT_ERROR +#define SSL_AD_EXPORT_RESTRICTION TLS1_AD_EXPORT_RESTRICTION /* fatal */ +#define SSL_AD_PROTOCOL_VERSION TLS1_AD_PROTOCOL_VERSION /* fatal */ +#define SSL_AD_INSUFFICIENT_SECURITY TLS1_AD_INSUFFICIENT_SECURITY /* fatal */ +#define SSL_AD_INTERNAL_ERROR TLS1_AD_INTERNAL_ERROR /* fatal */ +#define SSL_AD_USER_CANCELLED TLS1_AD_USER_CANCELLED +#define SSL_AD_NO_RENEGOTIATION TLS1_AD_NO_RENEGOTIATION +#define SSL_AD_UNSUPPORTED_EXTENSION TLS1_AD_UNSUPPORTED_EXTENSION +#define SSL_AD_CERTIFICATE_UNOBTAINABLE TLS1_AD_CERTIFICATE_UNOBTAINABLE +#define SSL_AD_UNRECOGNIZED_NAME TLS1_AD_UNRECOGNIZED_NAME +#define SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE \ + TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE +#define SSL_AD_BAD_CERTIFICATE_HASH_VALUE TLS1_AD_BAD_CERTIFICATE_HASH_VALUE +#define SSL_AD_UNKNOWN_PSK_IDENTITY TLS1_AD_UNKNOWN_PSK_IDENTITY /* fatal */ +#define SSL_AD_INAPPROPRIATE_FALLBACK SSL3_AD_INAPPROPRIATE_FALLBACK /* fatal */ + +#define SSL_ERROR_NONE 0 +#define SSL_ERROR_SSL 1 +#define SSL_ERROR_WANT_READ 2 +#define SSL_ERROR_WANT_WRITE 3 +#define SSL_ERROR_WANT_X509_LOOKUP 4 +#define SSL_ERROR_SYSCALL 5 /* look at error stack/return value/errno */ +#define SSL_ERROR_ZERO_RETURN 6 +#define SSL_ERROR_WANT_CONNECT 7 +#define SSL_ERROR_WANT_ACCEPT 8 +#define SSL_ERROR_WANT_CHANNEL_ID_LOOKUP 9 +#define SSL_ERROR_PENDING_SESSION 11 +#define SSL_ERROR_PENDING_CERTIFICATE 12 +#define SSL_ERROR_WANT_PRIVATE_KEY_OPERATION 13 + +#define SSL_CTRL_GET_CURVES 90 +#define SSL_CTRL_SET_CURVES 91 +#define SSL_CTRL_SET_CURVES_LIST 92 +#define SSL_CTRL_SET_SIGALGS 97 +#define SSL_CTRL_SET_SIGALGS_LIST 98 +#define SSL_CTRL_SET_CLIENT_SIGALGS 101 +#define SSL_CTRL_SET_CLIENT_SIGALGS_LIST 102 +#define SSL_CTRL_GET_CLIENT_CERT_TYPES 103 +#define SSL_CTRL_SET_CLIENT_CERT_TYPES 104 +#define SSL_CTRL_SET_VERIFY_CERT_STORE 106 +#define SSL_CTRL_SET_CHAIN_CERT_STORE 107 + +/* DTLSv1_get_timeout queries the next DTLS handshake timeout. If there is a + * timeout in progress, it sets |*out| to the time remaining and returns one. + * Otherwise, it returns zero. + * + * When the timeout expires, call |DTLSv1_handle_timeout| to handle the + * retransmit behavior. + * + * NOTE: This function must be queried again whenever the handshake state + * machine changes, including when |DTLSv1_handle_timeout| is called. */ +OPENSSL_EXPORT int DTLSv1_get_timeout(const SSL *ssl, struct timeval *out); + +/* DTLSv1_handle_timeout is called when a DTLS handshake timeout expires. If no + * timeout had expired, it returns 0. Otherwise, it retransmits the previous + * flight of handshake messages and returns 1. If too many timeouts had expired + * without progress or an error occurs, it returns -1. + * + * NOTE: The caller's external timer should be compatible with the one |ssl| + * queries within some fudge factor. Otherwise, the call will be a no-op, but + * |DTLSv1_get_timeout| will return an updated timeout. + * + * WARNING: This function breaks the usual return value convention. */ +OPENSSL_EXPORT int DTLSv1_handle_timeout(SSL *ssl); + +/* SSL_session_reused returns one if |ssl| performed an abbreviated handshake + * and zero otherwise. + * + * TODO(davidben): Hammer down the semantics of this API while a handshake, + * initial or renego, is in progress. */ +OPENSSL_EXPORT int SSL_session_reused(const SSL *ssl); + +/* SSL_total_renegotiations returns the total number of renegotiation handshakes + * peformed by |ssl|. This includes the pending renegotiation, if any. */ +OPENSSL_EXPORT int SSL_total_renegotiations(const SSL *ssl); + +/* SSL_CTX_set_tmp_dh configures |ctx| to use the group from |dh| as the group + * for DHE. Only the group is used, so |dh| needn't have a keypair. It returns + * one on success and zero on error. */ +OPENSSL_EXPORT int SSL_CTX_set_tmp_dh(SSL_CTX *ctx, const DH *dh); + +/* SSL_set_tmp_dh configures |ssl| to use the group from |dh| as the group for + * DHE. Only the group is used, so |dh| needn't have a keypair. It returns one + * on success and zero on error. */ +OPENSSL_EXPORT int SSL_set_tmp_dh(SSL *ssl, const DH *dh); + +/* SSL_CTX_set_tmp_ecdh configures |ctx| to use the curve from |ecdh| as the + * curve for ephemeral ECDH keys. For historical reasons, this API expects an + * |EC_KEY|, but only the curve is used. It returns one on success and zero on + * error. If unset, an appropriate curve will be chosen automatically. (This is + * recommended.) */ +OPENSSL_EXPORT int SSL_CTX_set_tmp_ecdh(SSL_CTX *ctx, const EC_KEY *ec_key); + +/* SSL_set_tmp_ecdh configures |ssl| to use the curve from |ecdh| as the curve + * for ephemeral ECDH keys. For historical reasons, this API expects an + * |EC_KEY|, but only the curve is used. It returns one on success and zero on + * error. If unset, an appropriate curve will be chosen automatically. (This is + * recommended.) */ +OPENSSL_EXPORT int SSL_set_tmp_ecdh(SSL *ssl, const EC_KEY *ec_key); + +/* SSL_CTX_enable_tls_channel_id either configures a TLS server to accept TLS + * client IDs from clients, or configures a client to send TLS client IDs to + * a server. It returns one. */ +OPENSSL_EXPORT int SSL_CTX_enable_tls_channel_id(SSL_CTX *ctx); + +/* SSL_enable_tls_channel_id either configures a TLS server to accept TLS + * client IDs from clients, or configure a client to send TLS client IDs to + * server. It returns one. */ +OPENSSL_EXPORT int SSL_enable_tls_channel_id(SSL *ssl); + +/* SSL_CTX_set1_tls_channel_id configures a TLS client to send a TLS Channel ID + * to compatible servers. |private_key| must be a P-256 EC key. It returns one + * on success and zero on error. */ +OPENSSL_EXPORT int SSL_CTX_set1_tls_channel_id(SSL_CTX *ctx, + EVP_PKEY *private_key); + +/* SSL_set1_tls_channel_id configures a TLS client to send a TLS Channel ID to + * compatible servers. |private_key| must be a P-256 EC key. It returns one on + * success and zero on error. */ +OPENSSL_EXPORT int SSL_set1_tls_channel_id(SSL *ssl, EVP_PKEY *private_key); + +/* SSL_get_tls_channel_id gets the client's TLS Channel ID from a server SSL* + * and copies up to the first |max_out| bytes into |out|. The Channel ID + * consists of the client's P-256 public key as an (x,y) pair where each is a + * 32-byte, big-endian field element. It returns 0 if the client didn't offer a + * Channel ID and the length of the complete Channel ID otherwise. */ +OPENSSL_EXPORT size_t SSL_get_tls_channel_id(SSL *ssl, uint8_t *out, + size_t max_out); + +#define SSL_CTX_set0_verify_cert_store(ctx, st) \ + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_VERIFY_CERT_STORE, 0, (char *)st) +#define SSL_CTX_set1_verify_cert_store(ctx, st) \ + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_VERIFY_CERT_STORE, 1, (char *)st) +#define SSL_CTX_set0_chain_cert_store(ctx, st) \ + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_CHAIN_CERT_STORE, 0, (char *)st) +#define SSL_CTX_set1_chain_cert_store(ctx, st) \ + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_CHAIN_CERT_STORE, 1, (char *)st) + +#define SSL_set0_verify_cert_store(s, st) \ + SSL_ctrl(s, SSL_CTRL_SET_VERIFY_CERT_STORE, 0, (char *)st) +#define SSL_set1_verify_cert_store(s, st) \ + SSL_ctrl(s, SSL_CTRL_SET_VERIFY_CERT_STORE, 1, (char *)st) +#define SSL_set0_chain_cert_store(s, st) \ + SSL_ctrl(s, SSL_CTRL_SET_CHAIN_CERT_STORE, 0, (char *)st) +#define SSL_set1_chain_cert_store(s, st) \ + SSL_ctrl(s, SSL_CTRL_SET_CHAIN_CERT_STORE, 1, (char *)st) + +#define SSL_get1_curves(ctx, s) SSL_ctrl(ctx, SSL_CTRL_GET_CURVES, 0, (char *)s) +#define SSL_CTX_set1_curves(ctx, clist, clistlen) \ + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_CURVES, clistlen, (char *)clist) +#define SSL_CTX_set1_curves_list(ctx, s) \ + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_CURVES_LIST, 0, (char *)s) +#define SSL_set1_curves(ctx, clist, clistlen) \ + SSL_ctrl(ctx, SSL_CTRL_SET_CURVES, clistlen, (char *)clist) +#define SSL_set1_curves_list(ctx, s) \ + SSL_ctrl(ctx, SSL_CTRL_SET_CURVES_LIST, 0, (char *)s) + +#define SSL_CTX_set1_sigalgs(ctx, slist, slistlen) \ + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_SIGALGS, slistlen, (int *)slist) +#define SSL_CTX_set1_sigalgs_list(ctx, s) \ + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_SIGALGS_LIST, 0, (char *)s) +#define SSL_set1_sigalgs(ctx, slist, slistlen) \ + SSL_ctrl(ctx, SSL_CTRL_SET_SIGALGS, clistlen, (int *)slist) +#define SSL_set1_sigalgs_list(ctx, s) \ + SSL_ctrl(ctx, SSL_CTRL_SET_SIGALGS_LIST, 0, (char *)s) + +#define SSL_CTX_set1_client_sigalgs(ctx, slist, slistlen) \ + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_CLIENT_SIGALGS, slistlen, (int *)slist) +#define SSL_CTX_set1_client_sigalgs_list(ctx, s) \ + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_CLIENT_SIGALGS_LIST, 0, (char *)s) +#define SSL_set1_client_sigalgs(ctx, slist, slistlen) \ + SSL_ctrl(ctx, SSL_CTRL_SET_CLIENT_SIGALGS, clistlen, (int *)slist) +#define SSL_set1_client_sigalgs_list(ctx, s) \ + SSL_ctrl(ctx, SSL_CTRL_SET_CLIENT_SIGALGS_LIST, 0, (char *)s) + +#define SSL_get0_certificate_types(s, clist) \ + SSL_ctrl(s, SSL_CTRL_GET_CLIENT_CERT_TYPES, 0, (char *)clist) + +#define SSL_CTX_set1_client_certificate_types(ctx, clist, clistlen) \ + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_CLIENT_CERT_TYPES, clistlen, (char *)clist) +#define SSL_set1_client_certificate_types(s, clist, clistlen) \ + SSL_ctrl(s, SSL_CTRL_SET_CLIENT_CERT_TYPES, clistlen, (char *)clist) + +OPENSSL_EXPORT int SSL_CTX_set_cipher_list(SSL_CTX *, const char *str); +OPENSSL_EXPORT int SSL_CTX_set_cipher_list_tls11(SSL_CTX *, const char *str); +OPENSSL_EXPORT long SSL_CTX_set_timeout(SSL_CTX *ctx, long t); +OPENSSL_EXPORT long SSL_CTX_get_timeout(const SSL_CTX *ctx); +OPENSSL_EXPORT X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *); +OPENSSL_EXPORT void SSL_CTX_set_cert_store(SSL_CTX *, X509_STORE *); +OPENSSL_EXPORT int SSL_want(const SSL *s); + +OPENSSL_EXPORT void SSL_CTX_flush_sessions(SSL_CTX *ctx, long tm); + +/* SSL_get_current_cipher returns the cipher used in the current outgoing + * connection state, or NULL if the null cipher is active. */ +OPENSSL_EXPORT const SSL_CIPHER *SSL_get_current_cipher(const SSL *s); + +OPENSSL_EXPORT int SSL_get_fd(const SSL *s); +OPENSSL_EXPORT int SSL_get_rfd(const SSL *s); +OPENSSL_EXPORT int SSL_get_wfd(const SSL *s); +OPENSSL_EXPORT const char *SSL_get_cipher_list(const SSL *s, int n); +OPENSSL_EXPORT int SSL_pending(const SSL *s); +OPENSSL_EXPORT int SSL_set_fd(SSL *s, int fd); +OPENSSL_EXPORT int SSL_set_rfd(SSL *s, int fd); +OPENSSL_EXPORT int SSL_set_wfd(SSL *s, int fd); +OPENSSL_EXPORT void SSL_set_bio(SSL *s, BIO *rbio, BIO *wbio); +OPENSSL_EXPORT BIO *SSL_get_rbio(const SSL *s); +OPENSSL_EXPORT BIO *SSL_get_wbio(const SSL *s); +OPENSSL_EXPORT int SSL_set_cipher_list(SSL *s, const char *str); +OPENSSL_EXPORT int SSL_get_verify_mode(const SSL *s); +OPENSSL_EXPORT int SSL_get_verify_depth(const SSL *s); +OPENSSL_EXPORT int (*SSL_get_verify_callback(const SSL *s))(int, + X509_STORE_CTX *); +OPENSSL_EXPORT void SSL_set_verify(SSL *s, int mode, + int (*callback)(int ok, + X509_STORE_CTX *ctx)); +OPENSSL_EXPORT void SSL_set_verify_depth(SSL *s, int depth); +OPENSSL_EXPORT STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file); +OPENSSL_EXPORT int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) * + stackCAs, + const char *file); +OPENSSL_EXPORT int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) * + stackCAs, + const char *dir); + +/* SSL_load_error_strings does nothing. */ +OPENSSL_EXPORT void SSL_load_error_strings(void); + +OPENSSL_EXPORT const char *SSL_state_string(const SSL *s); +OPENSSL_EXPORT const char *SSL_rstate_string(const SSL *s); +OPENSSL_EXPORT const char *SSL_state_string_long(const SSL *s); +OPENSSL_EXPORT const char *SSL_rstate_string_long(const SSL *s); +OPENSSL_EXPORT long SSL_SESSION_get_time(const SSL_SESSION *s); +OPENSSL_EXPORT long SSL_SESSION_set_time(SSL_SESSION *s, long t); +OPENSSL_EXPORT long SSL_SESSION_get_timeout(const SSL_SESSION *s); +OPENSSL_EXPORT long SSL_SESSION_set_timeout(SSL_SESSION *s, long t); +OPENSSL_EXPORT X509 *SSL_SESSION_get0_peer(SSL_SESSION *s); +OPENSSL_EXPORT int SSL_SESSION_set1_id_context(SSL_SESSION *s, + const uint8_t *sid_ctx, + unsigned int sid_ctx_len); + +OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_new(void); +OPENSSL_EXPORT const uint8_t *SSL_SESSION_get_id(const SSL_SESSION *s, + unsigned int *len); +OPENSSL_EXPORT int SSL_SESSION_print_fp(FILE *fp, const SSL_SESSION *ses); +OPENSSL_EXPORT int SSL_SESSION_print(BIO *fp, const SSL_SESSION *ses); + +/* SSL_SESSION_up_ref, if |session| is not NULL, increments the reference count + * of |session|. It then returns |session|. */ +OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_up_ref(SSL_SESSION *session); + +/* SSL_SESSION_free decrements the reference count of |session|. If it reaches + * zero, all data referenced by |session| and |session| itself are released. */ +OPENSSL_EXPORT void SSL_SESSION_free(SSL_SESSION *session); + +OPENSSL_EXPORT int SSL_set_session(SSL *to, SSL_SESSION *session); +OPENSSL_EXPORT int SSL_CTX_add_session(SSL_CTX *s, SSL_SESSION *c); +OPENSSL_EXPORT int SSL_CTX_remove_session(SSL_CTX *, SSL_SESSION *c); +OPENSSL_EXPORT int SSL_CTX_set_generate_session_id(SSL_CTX *, GEN_SESSION_CB); +OPENSSL_EXPORT int SSL_set_generate_session_id(SSL *, GEN_SESSION_CB); +OPENSSL_EXPORT int SSL_has_matching_session_id(const SSL *ssl, + const uint8_t *id, + unsigned int id_len); + +/* SSL_SESSION_to_bytes serializes |in| into a newly allocated buffer and sets + * |*out_data| to that buffer and |*out_len| to its length. The caller takes + * ownership of the buffer and must call |OPENSSL_free| when done. It returns + * one on success and zero on error. */ +OPENSSL_EXPORT int SSL_SESSION_to_bytes(SSL_SESSION *in, uint8_t **out_data, + size_t *out_len); + +/* SSL_SESSION_to_bytes_for_ticket serializes |in|, but excludes the session + * identification information, namely the session ID and ticket. */ +OPENSSL_EXPORT int SSL_SESSION_to_bytes_for_ticket(SSL_SESSION *in, + uint8_t **out_data, + size_t *out_len); + +/* SSL_SESSION_from_bytes parses |in_len| bytes from |in| as an SSL_SESSION. It + * returns a newly-allocated |SSL_SESSION| on success or NULL on error. */ +OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_from_bytes(const uint8_t *in, + size_t in_len); + +/* Deprecated: i2d_SSL_SESSION serializes |in| to the bytes pointed to by + * |*pp|. On success, it returns the number of bytes written and advances |*pp| + * by that many bytes. On failure, it returns -1. If |pp| is NULL, no bytes are + * written and only the length is returned. + * + * Use |SSL_SESSION_to_bytes| instead. */ +OPENSSL_EXPORT int i2d_SSL_SESSION(SSL_SESSION *in, uint8_t **pp); + +/* Deprecated: d2i_SSL_SESSION parses a serialized session from the |length| + * bytes pointed to by |*pp|. It returns the new |SSL_SESSION| and advances + * |*pp| by the number of bytes consumed on success and NULL on failure. The + * caller takes ownership of the new session and must call |SSL_SESSION_free| + * when done. + * + * If |a| is non-NULL, |*a| is released and set the new |SSL_SESSION|. + * + * Use |SSL_SESSION_from_bytes| instead. */ +OPENSSL_EXPORT SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const uint8_t **pp, + long length); + +OPENSSL_EXPORT X509 *SSL_get_peer_certificate(const SSL *s); + +OPENSSL_EXPORT STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *s); + +OPENSSL_EXPORT int SSL_CTX_get_verify_mode(const SSL_CTX *ctx); +OPENSSL_EXPORT int SSL_CTX_get_verify_depth(const SSL_CTX *ctx); +OPENSSL_EXPORT int (*SSL_CTX_get_verify_callback(const SSL_CTX *ctx))( + int, X509_STORE_CTX *); +OPENSSL_EXPORT void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, + int (*callback)(int, X509_STORE_CTX *)); +OPENSSL_EXPORT void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth); +OPENSSL_EXPORT void SSL_CTX_set_cert_verify_callback( + SSL_CTX *ctx, int (*cb)(X509_STORE_CTX *, void *), void *arg); + +OPENSSL_EXPORT void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, + pem_password_cb *cb); +OPENSSL_EXPORT void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, + void *u); + +OPENSSL_EXPORT int SSL_CTX_set_session_id_context(SSL_CTX *ctx, + const uint8_t *sid_ctx, + unsigned int sid_ctx_len); + +OPENSSL_EXPORT int SSL_set_session_id_context(SSL *ssl, const uint8_t *sid_ctx, + unsigned int sid_ctx_len); + +OPENSSL_EXPORT int SSL_CTX_set_purpose(SSL_CTX *s, int purpose); +OPENSSL_EXPORT int SSL_set_purpose(SSL *s, int purpose); +OPENSSL_EXPORT int SSL_CTX_set_trust(SSL_CTX *s, int trust); +OPENSSL_EXPORT int SSL_set_trust(SSL *s, int trust); + +OPENSSL_EXPORT int SSL_CTX_set1_param(SSL_CTX *ctx, X509_VERIFY_PARAM *vpm); +OPENSSL_EXPORT int SSL_set1_param(SSL *ssl, X509_VERIFY_PARAM *vpm); + +OPENSSL_EXPORT X509_VERIFY_PARAM *SSL_CTX_get0_param(SSL_CTX *ctx); +OPENSSL_EXPORT X509_VERIFY_PARAM *SSL_get0_param(SSL *ssl); + +OPENSSL_EXPORT int SSL_accept(SSL *ssl); +OPENSSL_EXPORT int SSL_connect(SSL *ssl); +OPENSSL_EXPORT int SSL_read(SSL *ssl, void *buf, int num); +OPENSSL_EXPORT int SSL_peek(SSL *ssl, void *buf, int num); +OPENSSL_EXPORT int SSL_write(SSL *ssl, const void *buf, int num); +OPENSSL_EXPORT long SSL_ctrl(SSL *ssl, int cmd, long larg, void *parg); +OPENSSL_EXPORT long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg); + +OPENSSL_EXPORT int SSL_get_error(const SSL *s, int ret_code); +/* SSL_get_version returns a string describing the TLS version used by |s|. For + * example, "TLSv1.2" or "SSLv3". */ +OPENSSL_EXPORT const char *SSL_get_version(const SSL *s); +/* SSL_SESSION_get_version returns a string describing the TLS version used by + * |sess|. For example, "TLSv1.2" or "SSLv3". */ +OPENSSL_EXPORT const char *SSL_SESSION_get_version(const SSL_SESSION *sess); + +OPENSSL_EXPORT STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s); + +OPENSSL_EXPORT int SSL_do_handshake(SSL *s); + +/* SSL_renegotiate_pending returns one if |ssl| is in the middle of a + * renegotiation. */ +OPENSSL_EXPORT int SSL_renegotiate_pending(SSL *ssl); + +OPENSSL_EXPORT int SSL_shutdown(SSL *s); + +OPENSSL_EXPORT const char *SSL_alert_type_string_long(int value); +OPENSSL_EXPORT const char *SSL_alert_type_string(int value); +OPENSSL_EXPORT const char *SSL_alert_desc_string_long(int value); +OPENSSL_EXPORT const char *SSL_alert_desc_string(int value); + +OPENSSL_EXPORT void SSL_set_client_CA_list(SSL *s, + STACK_OF(X509_NAME) *name_list); +OPENSSL_EXPORT void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, + STACK_OF(X509_NAME) *name_list); +OPENSSL_EXPORT STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *s); +OPENSSL_EXPORT STACK_OF(X509_NAME) * + SSL_CTX_get_client_CA_list(const SSL_CTX *s); +OPENSSL_EXPORT int SSL_add_client_CA(SSL *ssl, X509 *x); +OPENSSL_EXPORT int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x); + +OPENSSL_EXPORT long SSL_get_default_timeout(const SSL *s); + +OPENSSL_EXPORT STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *sk); + +OPENSSL_EXPORT void SSL_CTX_set_quiet_shutdown(SSL_CTX *ctx, int mode); +OPENSSL_EXPORT int SSL_CTX_get_quiet_shutdown(const SSL_CTX *ctx); +OPENSSL_EXPORT void SSL_set_quiet_shutdown(SSL *ssl, int mode); +OPENSSL_EXPORT int SSL_get_quiet_shutdown(const SSL *ssl); +OPENSSL_EXPORT void SSL_set_shutdown(SSL *ssl, int mode); +OPENSSL_EXPORT int SSL_get_shutdown(const SSL *ssl); +OPENSSL_EXPORT int SSL_version(const SSL *ssl); +OPENSSL_EXPORT int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx); +OPENSSL_EXPORT int SSL_CTX_load_verify_locations(SSL_CTX *ctx, + const char *CAfile, + const char *CApath); +#define SSL_get0_session SSL_get_session /* just peek at pointer */ +OPENSSL_EXPORT SSL_SESSION *SSL_get_session(const SSL *ssl); +OPENSSL_EXPORT SSL_SESSION *SSL_get1_session( + SSL *ssl); /* obtain a reference count */ +OPENSSL_EXPORT SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl); +OPENSSL_EXPORT SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX *ctx); +OPENSSL_EXPORT void SSL_set_info_callback(SSL *ssl, + void (*cb)(const SSL *ssl, int type, + int val)); +OPENSSL_EXPORT void (*SSL_get_info_callback(const SSL *ssl))(const SSL *ssl, + int type, int val); +OPENSSL_EXPORT int SSL_state(const SSL *ssl); + +OPENSSL_EXPORT void SSL_set_verify_result(SSL *ssl, long v); +OPENSSL_EXPORT long SSL_get_verify_result(const SSL *ssl); + +OPENSSL_EXPORT int SSL_set_ex_data(SSL *ssl, int idx, void *data); +OPENSSL_EXPORT void *SSL_get_ex_data(const SSL *ssl, int idx); +OPENSSL_EXPORT int SSL_get_ex_new_index(long argl, void *argp, + CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func); + +OPENSSL_EXPORT int SSL_SESSION_set_ex_data(SSL_SESSION *ss, int idx, + void *data); +OPENSSL_EXPORT void *SSL_SESSION_get_ex_data(const SSL_SESSION *ss, int idx); +OPENSSL_EXPORT int SSL_SESSION_get_ex_new_index(long argl, void *argp, + CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func); + +OPENSSL_EXPORT int SSL_CTX_set_ex_data(SSL_CTX *ssl, int idx, void *data); +OPENSSL_EXPORT void *SSL_CTX_get_ex_data(const SSL_CTX *ssl, int idx); +OPENSSL_EXPORT int SSL_CTX_get_ex_new_index(long argl, void *argp, + CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func); + +OPENSSL_EXPORT int SSL_get_ex_data_X509_STORE_CTX_idx(void); + +/* SSL_CTX_sess_set_cache_size sets the maximum size of |ctx|'s session cache to + * |size|. It returns the previous value. */ +OPENSSL_EXPORT unsigned long SSL_CTX_sess_set_cache_size(SSL_CTX *ctx, + unsigned long size); + +/* SSL_CTX_sess_get_cache_size returns the maximum size of |ctx|'s session + * cache. */ +OPENSSL_EXPORT unsigned long SSL_CTX_sess_get_cache_size(const SSL_CTX *ctx); + +/* SSL_SESS_CACHE_* are the possible session cache mode bits. + * TODO(davidben): Document. */ +#define SSL_SESS_CACHE_OFF 0x0000 +#define SSL_SESS_CACHE_CLIENT 0x0001 +#define SSL_SESS_CACHE_SERVER 0x0002 +#define SSL_SESS_CACHE_BOTH (SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_SERVER) +#define SSL_SESS_CACHE_NO_AUTO_CLEAR 0x0080 +#define SSL_SESS_CACHE_NO_INTERNAL_LOOKUP 0x0100 +#define SSL_SESS_CACHE_NO_INTERNAL_STORE 0x0200 +#define SSL_SESS_CACHE_NO_INTERNAL \ + (SSL_SESS_CACHE_NO_INTERNAL_LOOKUP | SSL_SESS_CACHE_NO_INTERNAL_STORE) + +/* SSL_CTX_set_session_cache_mode sets the session cache mode bits for |ctx| to + * |mode|. It returns the previous value. */ +OPENSSL_EXPORT int SSL_CTX_set_session_cache_mode(SSL_CTX *ctx, int mode); + +/* SSL_CTX_get_session_cache_mode returns the session cache mode bits for + * |ctx| */ +OPENSSL_EXPORT int SSL_CTX_get_session_cache_mode(const SSL_CTX *ctx); + +/* SSL_CTX_get_max_cert_list returns the maximum length, in bytes, of a peer + * certificate chain accepted by |ctx|. */ +OPENSSL_EXPORT size_t SSL_CTX_get_max_cert_list(const SSL_CTX *ctx); + +/* SSL_CTX_set_max_cert_list sets the maximum length, in bytes, of a peer + * certificate chain to |max_cert_list|. This affects how much memory may be + * consumed during the handshake. */ +OPENSSL_EXPORT void SSL_CTX_set_max_cert_list(SSL_CTX *ctx, + size_t max_cert_list); + +/* SSL_get_max_cert_list returns the maximum length, in bytes, of a peer + * certificate chain accepted by |ssl|. */ +OPENSSL_EXPORT size_t SSL_get_max_cert_list(const SSL *ssl); + +/* SSL_set_max_cert_list sets the maximum length, in bytes, of a peer + * certificate chain to |max_cert_list|. This affects how much memory may be + * consumed during the handshake. */ +OPENSSL_EXPORT void SSL_set_max_cert_list(SSL *ssl, size_t max_cert_list); + +/* SSL_CTX_set_max_send_fragment sets the maximum length, in bytes, of records + * sent by |ctx|. Beyond this length, handshake messages and application data + * will be split into multiple records. */ +OPENSSL_EXPORT void SSL_CTX_set_max_send_fragment(SSL_CTX *ctx, + size_t max_send_fragment); + +/* SSL_set_max_send_fragment sets the maximum length, in bytes, of records + * sent by |ssl|. Beyond this length, handshake messages and application data + * will be split into multiple records. */ +OPENSSL_EXPORT void SSL_set_max_send_fragment(SSL *ssl, + size_t max_send_fragment); + +/* SSL_CTX_set_tmp_dh_callback configures |ctx| to use |callback| to determine + * the group for DHE ciphers. |callback| should ignore |is_export| and + * |keylength| and return a |DH| of the selected group or NULL on error. Only + * the parameters are used, so the |DH| needn't have a generated keypair. + * + * WARNING: The caller does not take ownership of the resulting |DH|, so + * |callback| must save and release the object elsewhere. */ +OPENSSL_EXPORT void SSL_CTX_set_tmp_dh_callback( + SSL_CTX *ctx, DH *(*callback)(SSL *ssl, int is_export, int keylength)); + +/* SSL_set_tmp_dh_callback configures |ssl| to use |callback| to determine the + * group for DHE ciphers. |callback| should ignore |is_export| and |keylength| + * and return a |DH| of the selected group or NULL on error. Only the + * parameters are used, so the |DH| needn't have a generated keypair. + * + * WARNING: The caller does not take ownership of the resulting |DH|, so + * |callback| must save and release the object elsewhere. */ +OPENSSL_EXPORT void SSL_set_tmp_dh_callback(SSL *ssl, + DH *(*dh)(SSL *ssl, int is_export, + int keylength)); + +/* SSL_CTX_set_tmp_ecdh_callback configures |ctx| to use |callback| to determine + * the curve for ephemeral ECDH keys. |callback| should ignore |is_export| and + * |keylength| and return an |EC_KEY| of the selected curve or NULL on + * error. Only the curve is used, so the |EC_KEY| needn't have a generated + * keypair. + * + * If the callback is unset, an appropriate curve will be chosen automatically. + * (This is recommended.) + * + * WARNING: The caller does not take ownership of the resulting |EC_KEY|, so + * |callback| must save and release the object elsewhere. */ +OPENSSL_EXPORT void SSL_CTX_set_tmp_ecdh_callback( + SSL_CTX *ctx, EC_KEY *(*callback)(SSL *ssl, int is_export, int keylength)); + +/* SSL_set_tmp_ecdh_callback configures |ssl| to use |callback| to determine the + * curve for ephemeral ECDH keys. |callback| should ignore |is_export| and + * |keylength| and return an |EC_KEY| of the selected curve or NULL on + * error. Only the curve is used, so the |EC_KEY| needn't have a generated + * keypair. + * + * If the callback is unset, an appropriate curve will be chosen automatically. + * (This is recommended.) + * + * WARNING: The caller does not take ownership of the resulting |EC_KEY|, so + * |callback| must save and release the object elsewhere. */ +OPENSSL_EXPORT void SSL_set_tmp_ecdh_callback( + SSL *ssl, EC_KEY *(*callback)(SSL *ssl, int is_export, int keylength)); + +typedef void COMP_METHOD; + +/* SSL_get_current_compression returns NULL. */ +OPENSSL_EXPORT const COMP_METHOD *SSL_get_current_compression(SSL *s); + +/* SSL_get_current_expansion returns NULL. */ +OPENSSL_EXPORT const COMP_METHOD *SSL_get_current_expansion(SSL *s); + +OPENSSL_EXPORT int SSL_cache_hit(SSL *s); +OPENSSL_EXPORT int SSL_is_server(SSL *s); + +/* SSL_CTX_set_dos_protection_cb sets a callback that is called once the + * resumption decision for a ClientHello has been made. It can return 1 to + * allow the handshake to continue or zero to cause the handshake to abort. */ +OPENSSL_EXPORT void SSL_CTX_set_dos_protection_cb( + SSL_CTX *ctx, int (*cb)(const struct ssl_early_callback_ctx *)); + +/* SSL_get_structure_sizes returns the sizes of the SSL, SSL_CTX and + * SSL_SESSION structures so that a test can ensure that outside code agrees on + * these values. */ +OPENSSL_EXPORT void SSL_get_structure_sizes(size_t *ssl_size, + size_t *ssl_ctx_size, + size_t *ssl_session_size); + +OPENSSL_EXPORT void ERR_load_SSL_strings(void); + +/* SSL_get_rc4_state sets |*read_key| and |*write_key| to the RC4 states for + * the read and write directions. It returns one on success or zero if |ssl| + * isn't using an RC4-based cipher suite. */ +OPENSSL_EXPORT int SSL_get_rc4_state(const SSL *ssl, const RC4_KEY **read_key, + const RC4_KEY **write_key); + + +/* Deprecated functions. */ + +/* SSL_CIPHER_description writes a description of |cipher| into |buf| and + * returns |buf|. If |buf| is NULL, it returns a newly allocated string, to be + * freed with |OPENSSL_free|, or NULL on error. + * + * The description includes a trailing newline and has the form: + * AES128-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA1 + * + * Consider |SSL_CIPHER_get_name| or |SSL_CIPHER_get_rfc_name| instead. */ +OPENSSL_EXPORT const char *SSL_CIPHER_description(const SSL_CIPHER *cipher, + char *buf, int len); + +/* SSL_CIPHER_get_version returns the string "TLSv1/SSLv3". */ +OPENSSL_EXPORT const char *SSL_CIPHER_get_version(const SSL_CIPHER *cipher); + +/* SSL_COMP_get_compression_methods returns NULL. */ +OPENSSL_EXPORT COMP_METHOD *SSL_COMP_get_compression_methods(void); + +/* SSL_COMP_add_compression_method returns one. */ +OPENSSL_EXPORT int SSL_COMP_add_compression_method(int id, COMP_METHOD *cm); + +/* SSL_COMP_get_name returns NULL. */ +OPENSSL_EXPORT const char *SSL_COMP_get_name(const COMP_METHOD *comp); + +/* SSLv23_method calls |TLS_method|. */ +OPENSSL_EXPORT const SSL_METHOD *SSLv23_method(void); + +/* Version-specific methods behave exactly like |TLS_method| and |DTLS_method| + * except they also call |SSL_CTX_set_min_version| and |SSL_CTX_set_max_version| + * to lock connections to that protocol version. */ +OPENSSL_EXPORT const SSL_METHOD *SSLv3_method(void); +OPENSSL_EXPORT const SSL_METHOD *TLSv1_method(void); +OPENSSL_EXPORT const SSL_METHOD *TLSv1_1_method(void); +OPENSSL_EXPORT const SSL_METHOD *TLSv1_2_method(void); +OPENSSL_EXPORT const SSL_METHOD *DTLSv1_method(void); +OPENSSL_EXPORT const SSL_METHOD *DTLSv1_2_method(void); + +/* Client- and server-specific methods call their corresponding generic + * methods. */ +OPENSSL_EXPORT const SSL_METHOD *SSLv23_server_method(void); +OPENSSL_EXPORT const SSL_METHOD *SSLv23_client_method(void); +OPENSSL_EXPORT const SSL_METHOD *SSLv3_server_method(void); +OPENSSL_EXPORT const SSL_METHOD *SSLv3_client_method(void); +OPENSSL_EXPORT const SSL_METHOD *TLSv1_server_method(void); +OPENSSL_EXPORT const SSL_METHOD *TLSv1_client_method(void); +OPENSSL_EXPORT const SSL_METHOD *TLSv1_1_server_method(void); +OPENSSL_EXPORT const SSL_METHOD *TLSv1_1_client_method(void); +OPENSSL_EXPORT const SSL_METHOD *TLSv1_2_server_method(void); +OPENSSL_EXPORT const SSL_METHOD *TLSv1_2_client_method(void); +OPENSSL_EXPORT const SSL_METHOD *DTLS_server_method(void); +OPENSSL_EXPORT const SSL_METHOD *DTLS_client_method(void); +OPENSSL_EXPORT const SSL_METHOD *DTLSv1_server_method(void); +OPENSSL_EXPORT const SSL_METHOD *DTLSv1_client_method(void); +OPENSSL_EXPORT const SSL_METHOD *DTLSv1_2_server_method(void); +OPENSSL_EXPORT const SSL_METHOD *DTLSv1_2_client_method(void); + +/* SSL_clear resets |ssl| to allow another connection and returns one on success + * or zero on failure. It returns most configuration state but releases memory + * associated with the current connection. + * + * Free |ssl| and create a new one instead. */ +OPENSSL_EXPORT int SSL_clear(SSL *ssl); + +/* SSL_CTX_set_tmp_rsa_callback does nothing. */ +OPENSSL_EXPORT void SSL_CTX_set_tmp_rsa_callback( + SSL_CTX *ctx, RSA *(*cb)(SSL *ssl, int is_export, int keylength)); + +/* SSL_set_tmp_rsa_callback does nothing. */ +OPENSSL_EXPORT void SSL_set_tmp_rsa_callback(SSL *ssl, + RSA *(*cb)(SSL *ssl, int is_export, + int keylength)); + +/* SSL_CTX_sess_connect returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_connect(const SSL_CTX *ctx); + +/* SSL_CTX_sess_connect_good returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_connect_good(const SSL_CTX *ctx); + +/* SSL_CTX_sess_connect_renegotiate returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_connect_renegotiate(const SSL_CTX *ctx); + +/* SSL_CTX_sess_accept returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_accept(const SSL_CTX *ctx); + +/* SSL_CTX_sess_accept_renegotiate returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_accept_renegotiate(const SSL_CTX *ctx); + +/* SSL_CTX_sess_accept_good returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_accept_good(const SSL_CTX *ctx); + +/* SSL_CTX_sess_hits returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_hits(const SSL_CTX *ctx); + +/* SSL_CTX_sess_cb_hits returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_cb_hits(const SSL_CTX *ctx); + +/* SSL_CTX_sess_misses returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_misses(const SSL_CTX *ctx); + +/* SSL_CTX_sess_timeouts returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_timeouts(const SSL_CTX *ctx); + +/* SSL_CTX_sess_cache_full returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_cache_full(const SSL_CTX *ctx); + +/* SSL_cutthrough_complete calls |SSL_in_false_start|. */ +OPENSSL_EXPORT int SSL_cutthrough_complete(const SSL *s); + +/* SSL_num_renegotiations calls |SSL_total_renegotiations|. */ +OPENSSL_EXPORT int SSL_num_renegotiations(const SSL *ssl); + +/* SSL_CTX_need_tmp_RSA returns zero. */ +OPENSSL_EXPORT int SSL_CTX_need_tmp_RSA(const SSL_CTX *ctx); + +/* SSL_need_tmp_RSA returns zero. */ +OPENSSL_EXPORT int SSL_need_tmp_RSA(const SSL *ssl); + +/* SSL_CTX_set_tmp_rsa returns one. */ +OPENSSL_EXPORT int SSL_CTX_set_tmp_rsa(SSL_CTX *ctx, const RSA *rsa); + +/* SSL_set_tmp_rsa returns one. */ +OPENSSL_EXPORT int SSL_set_tmp_rsa(SSL *ssl, const RSA *rsa); + +/* SSL_CTX_get_read_ahead returns zero. */ +OPENSSL_EXPORT int SSL_CTX_get_read_ahead(const SSL_CTX *ctx); + +/* SSL_CTX_set_read_ahead does nothing. */ +OPENSSL_EXPORT void SSL_CTX_set_read_ahead(SSL_CTX *ctx, int yes); + +/* SSL_get_read_ahead returns zero. */ +OPENSSL_EXPORT int SSL_get_read_ahead(const SSL *s); + +/* SSL_set_read_ahead does nothing. */ +OPENSSL_EXPORT void SSL_set_read_ahead(SSL *s, int yes); + +/* SSL_renegotiate put an error on the error queue and returns zero. */ +OPENSSL_EXPORT int SSL_renegotiate(SSL *ssl); + +/* SSL_set_state does nothing. */ +OPENSSL_EXPORT void SSL_set_state(SSL *ssl, int state); + + +/* Android compatibility section. + * + * These functions are declared, temporarily, for Android because + * wpa_supplicant will take a little time to sync with upstream. Outside of + * Android they'll have no definition. */ + +#define SSL_F_SSL_SET_SESSION_TICKET_EXT doesnt_exist + +OPENSSL_EXPORT int SSL_set_session_ticket_ext(SSL *s, void *ext_data, + int ext_len); +OPENSSL_EXPORT int SSL_set_session_secret_cb(SSL *s, void *cb, void *arg); +OPENSSL_EXPORT int SSL_set_session_ticket_ext_cb(SSL *s, void *cb, void *arg); +OPENSSL_EXPORT int SSL_set_ssl_method(SSL *s, const SSL_METHOD *method); + +#define OPENSSL_VERSION_TEXT "BoringSSL" + +#define SSLEAY_VERSION 0 + +/* SSLeay_version is a compatibility function that returns the string + * "BoringSSL". */ +OPENSSL_EXPORT const char *SSLeay_version(int unused); + + +/* Preprocessor compatibility section. + * + * Historically, a number of APIs were implemented in OpenSSL as macros and + * constants to 'ctrl' functions. To avoid breaking #ifdefs in consumers, this + * section defines a number of legacy macros. + * + * Although using either the CTRL values or their wrapper macros in #ifdefs is + * still supported, the CTRL values may not be passed to |SSL_ctrl| and + * |SSL_CTX_ctrl|. Call the functions (previously wrapper macros) instead. */ + +#define DTLS_CTRL_GET_TIMEOUT doesnt_exist +#define DTLS_CTRL_HANDLE_TIMEOUT doesnt_exist +#define SSL_CTRL_CHAIN doesnt_exist +#define SSL_CTRL_CHAIN_CERT doesnt_exist +#define SSL_CTRL_CHANNEL_ID doesnt_exist +#define SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS doesnt_exist +#define SSL_CTRL_CLEAR_MODE doesnt_exist +#define SSL_CTRL_CLEAR_OPTIONS doesnt_exist +#define SSL_CTRL_EXTRA_CHAIN_CERT doesnt_exist +#define SSL_CTRL_GET_CHAIN_CERTS doesnt_exist +#define SSL_CTRL_GET_CHANNEL_ID doesnt_exist +#define SSL_CTRL_GET_EXTRA_CHAIN_CERTS doesnt_exist +#define SSL_CTRL_GET_MAX_CERT_LIST doesnt_exist +#define SSL_CTRL_GET_NUM_RENEGOTIATIONS doesnt_exist +#define SSL_CTRL_GET_READ_AHEAD doesnt_exist +#define SSL_CTRL_GET_RI_SUPPORT doesnt_exist +#define SSL_CTRL_GET_SESSION_REUSED doesnt_exist +#define SSL_CTRL_GET_SESS_CACHE_MODE doesnt_exist +#define SSL_CTRL_GET_SESS_CACHE_SIZE doesnt_exist +#define SSL_CTRL_GET_TLSEXT_TICKET_KEYS doesnt_exist +#define SSL_CTRL_GET_TOTAL_RENEGOTIATIONS doesnt_exist +#define SSL_CTRL_MODE doesnt_exist +#define SSL_CTRL_NEED_TMP_RSA doesnt_exist +#define SSL_CTRL_OPTIONS doesnt_exist +#define SSL_CTRL_SESS_NUMBER doesnt_exist +#define SSL_CTRL_SET_CHANNEL_ID doesnt_exist +#define SSL_CTRL_SET_MAX_CERT_LIST doesnt_exist +#define SSL_CTRL_SET_MAX_SEND_FRAGMENT doesnt_exist +#define SSL_CTRL_SET_MSG_CALLBACK doesnt_exist +#define SSL_CTRL_SET_MSG_CALLBACK_ARG doesnt_exist +#define SSL_CTRL_SET_MTU doesnt_exist +#define SSL_CTRL_SET_READ_AHEAD doesnt_exist +#define SSL_CTRL_SET_SESS_CACHE_MODE doesnt_exist +#define SSL_CTRL_SET_SESS_CACHE_SIZE doesnt_exist +#define SSL_CTRL_SET_TLSEXT_HOSTNAME doesnt_exist +#define SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG doesnt_exist +#define SSL_CTRL_SET_TLSEXT_SERVERNAME_CB doesnt_exist +#define SSL_CTRL_SET_TLSEXT_TICKET_KEYS doesnt_exist +#define SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB doesnt_exist +#define SSL_CTRL_SET_TMP_DH doesnt_exist +#define SSL_CTRL_SET_TMP_DH_CB doesnt_exist +#define SSL_CTRL_SET_TMP_ECDH doesnt_exist +#define SSL_CTRL_SET_TMP_ECDH_CB doesnt_exist +#define SSL_CTRL_SET_TMP_RSA doesnt_exist +#define SSL_CTRL_SET_TMP_RSA_CB doesnt_exist + +#define DTLSv1_get_timeout DTLSv1_get_timeout +#define DTLSv1_handle_timeout DTLSv1_handle_timeout +#define SSL_CTX_add0_chain_cert SSL_CTX_add0_chain_cert +#define SSL_CTX_add1_chain_cert SSL_CTX_add1_chain_cert +#define SSL_CTX_add_extra_chain_cert SSL_CTX_add_extra_chain_cert +#define SSL_CTX_clear_extra_chain_certs SSL_CTX_clear_extra_chain_certs +#define SSL_CTX_clear_chain_certs SSL_CTX_clear_chain_certs +#define SSL_CTX_clear_mode SSL_CTX_clear_mode +#define SSL_CTX_clear_options SSL_CTX_clear_options +#define SSL_CTX_enable_tls_channel_id SSL_CTX_enable_tls_channel_id +#define SSL_CTX_get0_chain_certs SSL_CTX_get0_chain_certs +#define SSL_CTX_get_extra_chain_certs SSL_CTX_get_extra_chain_certs +#define SSL_CTX_get_max_cert_list SSL_CTX_get_max_cert_list +#define SSL_CTX_get_mode SSL_CTX_get_mode +#define SSL_CTX_get_options SSL_CTX_get_options +#define SSL_CTX_get_read_ahead SSL_CTX_get_read_ahead +#define SSL_CTX_get_session_cache_mode SSL_CTX_get_session_cache_mode +#define SSL_CTX_get_tlsext_ticket_keys SSL_CTX_get_tlsext_ticket_keys +#define SSL_CTX_need_tmp_RSA SSL_CTX_need_tmp_RSA +#define SSL_CTX_sess_get_cache_size SSL_CTX_sess_get_cache_size +#define SSL_CTX_sess_number SSL_CTX_sess_number +#define SSL_CTX_sess_set_cache_size SSL_CTX_sess_set_cache_size +#define SSL_CTX_set0_chain SSL_CTX_set0_chain +#define SSL_CTX_set1_chain SSL_CTX_set1_chain +#define SSL_CTX_set1_tls_channel_id SSL_CTX_set1_tls_channel_id +#define SSL_CTX_set_max_cert_list SSL_CTX_set_max_cert_list +#define SSL_CTX_set_max_send_fragment SSL_CTX_set_max_send_fragment +#define SSL_CTX_set_mode SSL_CTX_set_mode +#define SSL_CTX_set_msg_callback_arg SSL_CTX_set_msg_callback_arg +#define SSL_CTX_set_options SSL_CTX_set_options +#define SSL_CTX_set_read_ahead SSL_CTX_set_read_ahead +#define SSL_CTX_set_session_cache_mode SSL_CTX_set_session_cache_mode +#define SSL_CTX_set_tlsext_servername_arg SSL_CTX_set_tlsext_servername_arg +#define SSL_CTX_set_tlsext_servername_callback \ + SSL_CTX_set_tlsext_servername_callback +#define SSL_CTX_set_tlsext_ticket_key_cb SSL_CTX_set_tlsext_ticket_key_cb +#define SSL_CTX_set_tlsext_ticket_keys SSL_CTX_set_tlsext_ticket_keys +#define SSL_CTX_set_tmp_dh SSL_CTX_set_tmp_dh +#define SSL_CTX_set_tmp_ecdh SSL_CTX_set_tmp_ecdh +#define SSL_CTX_set_tmp_rsa SSL_CTX_set_tmp_rsa +#define SSL_add0_chain_cert SSL_add0_chain_cert +#define SSL_add1_chain_cert SSL_add1_chain_cert +#define SSL_clear_chain_certs SSL_clear_chain_certs +#define SSL_clear_mode SSL_clear_mode +#define SSL_clear_options SSL_clear_options +#define SSL_enable_tls_channel_id SSL_enable_tls_channel_id +#define SSL_get0_chain_certs SSL_get0_chain_certs +#define SSL_get_max_cert_list SSL_get_max_cert_list +#define SSL_get_mode SSL_get_mode +#define SSL_get_options SSL_get_options +#define SSL_get_secure_renegotiation_support \ + SSL_get_secure_renegotiation_support +#define SSL_get_tls_channel_id SSL_get_tls_channel_id +#define SSL_need_tmp_RSA SSL_need_tmp_RSA +#define SSL_num_renegotiations SSL_num_renegotiations +#define SSL_session_reused SSL_session_reused +#define SSL_set0_chain SSL_set0_chain +#define SSL_set1_chain SSL_set1_chain +#define SSL_set1_tls_channel_id SSL_set1_tls_channel_id +#define SSL_set_max_cert_list SSL_set_max_cert_list +#define SSL_set_max_send_fragment SSL_set_max_send_fragment +#define SSL_set_mode SSL_set_mode +#define SSL_set_msg_callback_arg SSL_set_msg_callback_arg +#define SSL_set_mtu SSL_set_mtu +#define SSL_set_options SSL_set_options +#define SSL_set_tlsext_host_name SSL_set_tlsext_host_name +#define SSL_set_tmp_dh SSL_set_tmp_dh +#define SSL_set_tmp_ecdh SSL_set_tmp_ecdh +#define SSL_set_tmp_rsa SSL_set_tmp_rsa +#define SSL_total_renegotiations SSL_total_renegotiations + + +#if defined(__cplusplus) +} /* extern C */ +#endif + + +/* Library consumers assume these headers are included by ssl.h, but they depend + * on ssl.h, so include them after all declarations. + * + * TODO(davidben): The separation between ssl.h and these version-specific + * headers introduces circular dependencies and is inconsistent. The function + * declarations should move to ssl.h. Many of the constants can probably be + * pruned or unexported. */ +#include +#include /* This is mostly sslv3 with a few tweaks */ +#include /* Support for the use_srtp extension */ + + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script make_errors.go. Any + * changes made after this point may be overwritten when the script is next run. + */ +#define SSL_R_APP_DATA_IN_HANDSHAKE 100 +#define SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT 101 +#define SSL_R_BAD_ALERT 102 +#define SSL_R_BAD_CHANGE_CIPHER_SPEC 103 +#define SSL_R_BAD_DATA_RETURNED_BY_CALLBACK 104 +#define SSL_R_BAD_DH_P_LENGTH 105 +#define SSL_R_BAD_DIGEST_LENGTH 106 +#define SSL_R_BAD_ECC_CERT 107 +#define SSL_R_BAD_ECPOINT 108 +#define SSL_R_BAD_HANDSHAKE_LENGTH 109 +#define SSL_R_BAD_HANDSHAKE_RECORD 110 +#define SSL_R_BAD_HELLO_REQUEST 111 +#define SSL_R_BAD_LENGTH 112 +#define SSL_R_BAD_PACKET_LENGTH 113 +#define SSL_R_BAD_RSA_ENCRYPT 114 +#define SSL_R_BAD_SIGNATURE 115 +#define SSL_R_BAD_SRTP_MKI_VALUE 116 +#define SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST 117 +#define SSL_R_BAD_SSL_FILETYPE 118 +#define SSL_R_BAD_WRITE_RETRY 119 +#define SSL_R_BIO_NOT_SET 120 +#define SSL_R_BN_LIB 121 +#define SSL_R_CANNOT_SERIALIZE_PUBLIC_KEY 122 +#define SSL_R_CA_DN_LENGTH_MISMATCH 123 +#define SSL_R_CA_DN_TOO_LONG 124 +#define SSL_R_CCS_RECEIVED_EARLY 125 +#define SSL_R_CERTIFICATE_VERIFY_FAILED 126 +#define SSL_R_CERT_CB_ERROR 127 +#define SSL_R_CERT_LENGTH_MISMATCH 128 +#define SSL_R_CHANNEL_ID_NOT_P256 129 +#define SSL_R_CHANNEL_ID_SIGNATURE_INVALID 130 +#define SSL_R_CIPHER_CODE_WRONG_LENGTH 131 +#define SSL_R_CIPHER_OR_HASH_UNAVAILABLE 132 +#define SSL_R_CLIENTHELLO_PARSE_FAILED 133 +#define SSL_R_CLIENTHELLO_TLSEXT 134 +#define SSL_R_CONNECTION_REJECTED 135 +#define SSL_R_CONNECTION_TYPE_NOT_SET 136 +#define SSL_R_COOKIE_MISMATCH 137 +#define SSL_R_D2I_ECDSA_SIG 138 +#define SSL_R_DATA_BETWEEN_CCS_AND_FINISHED 139 +#define SSL_R_DATA_LENGTH_TOO_LONG 140 +#define SSL_R_DECODE_ERROR 141 +#define SSL_R_DECRYPTION_FAILED 142 +#define SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC 143 +#define SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG 144 +#define SSL_R_DIGEST_CHECK_FAILED 145 +#define SSL_R_DTLS_MESSAGE_TOO_BIG 146 +#define SSL_R_ECC_CERT_NOT_FOR_SIGNING 147 +#define SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST 148 +#define SSL_R_ENCRYPTED_LENGTH_TOO_LONG 149 +#define SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST 150 +#define SSL_R_EVP_DIGESTSIGNFINAL_FAILED 151 +#define SSL_R_EVP_DIGESTSIGNINIT_FAILED 152 +#define SSL_R_EXCESSIVE_MESSAGE_SIZE 153 +#define SSL_R_EXTRA_DATA_IN_MESSAGE 154 +#define SSL_R_GOT_A_FIN_BEFORE_A_CCS 155 +#define SSL_R_GOT_CHANNEL_ID_BEFORE_A_CCS 156 +#define SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS 157 +#define SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION 158 +#define SSL_R_HANDSHAKE_FAILURE_ON_CLIENT_HELLO 159 +#define SSL_R_HANDSHAKE_RECORD_BEFORE_CCS 160 +#define SSL_R_HTTPS_PROXY_REQUEST 161 +#define SSL_R_HTTP_REQUEST 162 +#define SSL_R_INAPPROPRIATE_FALLBACK 163 +#define SSL_R_INVALID_COMMAND 164 +#define SSL_R_INVALID_MESSAGE 165 +#define SSL_R_INVALID_SSL_SESSION 166 +#define SSL_R_INVALID_TICKET_KEYS_LENGTH 167 +#define SSL_R_LENGTH_MISMATCH 168 +#define SSL_R_LIBRARY_HAS_NO_CIPHERS 169 +#define SSL_R_MISSING_DH_KEY 170 +#define SSL_R_MISSING_ECDSA_SIGNING_CERT 171 +#define SSL_R_MISSING_RSA_CERTIFICATE 172 +#define SSL_R_MISSING_RSA_ENCRYPTING_CERT 173 +#define SSL_R_MISSING_RSA_SIGNING_CERT 174 +#define SSL_R_MISSING_TMP_DH_KEY 175 +#define SSL_R_MISSING_TMP_ECDH_KEY 176 +#define SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS 177 +#define SSL_R_MTU_TOO_SMALL 178 +#define SSL_R_NESTED_GROUP 179 +#define SSL_R_NO_CERTIFICATES_RETURNED 180 +#define SSL_R_NO_CERTIFICATE_ASSIGNED 181 +#define SSL_R_NO_CERTIFICATE_SET 182 +#define SSL_R_NO_CIPHERS_AVAILABLE 183 +#define SSL_R_NO_CIPHERS_PASSED 184 +#define SSL_R_NO_CIPHERS_SPECIFIED 185 +#define SSL_R_NO_CIPHER_MATCH 186 +#define SSL_R_NO_COMPRESSION_SPECIFIED 187 +#define SSL_R_NO_METHOD_SPECIFIED 188 +#define SSL_R_NO_P256_SUPPORT 189 +#define SSL_R_NO_PRIVATE_KEY_ASSIGNED 190 +#define SSL_R_NO_RENEGOTIATION 191 +#define SSL_R_NO_REQUIRED_DIGEST 192 +#define SSL_R_NO_SHARED_CIPHER 193 +#define SSL_R_NO_SHARED_SIGATURE_ALGORITHMS 194 +#define SSL_R_NO_SRTP_PROFILES 195 +#define SSL_R_NULL_SSL_CTX 196 +#define SSL_R_NULL_SSL_METHOD_PASSED 197 +#define SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED 198 +#define SSL_R_PACKET_LENGTH_TOO_LONG 199 +#define SSL_R_PARSE_TLSEXT 200 +#define SSL_R_PATH_TOO_LONG 201 +#define SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE 202 +#define SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE 203 +#define SSL_R_PROTOCOL_IS_SHUTDOWN 204 +#define SSL_R_PSK_IDENTITY_NOT_FOUND 205 +#define SSL_R_PSK_NO_CLIENT_CB 206 +#define SSL_R_PSK_NO_SERVER_CB 207 +#define SSL_R_READ_BIO_NOT_SET 208 +#define SSL_R_READ_TIMEOUT_EXPIRED 209 +#define SSL_R_RECORD_LENGTH_MISMATCH 210 +#define SSL_R_RECORD_TOO_LARGE 211 +#define SSL_R_RENEGOTIATE_EXT_TOO_LONG 212 +#define SSL_R_RENEGOTIATION_ENCODING_ERR 213 +#define SSL_R_RENEGOTIATION_MISMATCH 214 +#define SSL_R_REQUIRED_CIPHER_MISSING 215 +#define SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING 216 +#define SSL_R_SERVERHELLO_TLSEXT 217 +#define SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED 218 +#define SSL_R_SESSION_MAY_NOT_BE_CREATED 219 +#define SSL_R_SIGNATURE_ALGORITHMS_ERROR 220 +#define SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES 221 +#define SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG 222 +#define SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE 223 +#define SSL_R_SSL3_EXT_INVALID_SERVERNAME 224 +#define SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE 225 +#define SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION 226 +#define SSL_R_SSL_HANDSHAKE_FAILURE 227 +#define SSL_R_SSL_SESSION_ID_CALLBACK_FAILED 228 +#define SSL_R_SSL_SESSION_ID_CONFLICT 229 +#define SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG 230 +#define SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH 231 +#define SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER 232 +#define SSL_R_TLS_ILLEGAL_EXPORTER_LABEL 233 +#define SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST 234 +#define SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST 235 +#define SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG 236 +#define SSL_R_TOO_MANY_EMPTY_FRAGMENTS 237 +#define SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS 238 +#define SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS 239 +#define SSL_R_UNEXPECTED_GROUP_CLOSE 240 +#define SSL_R_UNEXPECTED_MESSAGE 241 +#define SSL_R_UNEXPECTED_OPERATOR_IN_GROUP 242 +#define SSL_R_UNEXPECTED_RECORD 243 +#define SSL_R_UNINITIALIZED 244 +#define SSL_R_UNKNOWN_ALERT_TYPE 245 +#define SSL_R_UNKNOWN_CERTIFICATE_TYPE 246 +#define SSL_R_UNKNOWN_CIPHER_RETURNED 247 +#define SSL_R_UNKNOWN_CIPHER_TYPE 248 +#define SSL_R_UNKNOWN_DIGEST 249 +#define SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE 250 +#define SSL_R_UNKNOWN_PROTOCOL 251 +#define SSL_R_UNKNOWN_SSL_VERSION 252 +#define SSL_R_UNKNOWN_STATE 253 +#define SSL_R_UNPROCESSED_HANDSHAKE_DATA 254 +#define SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED 255 +#define SSL_R_UNSUPPORTED_CIPHER 256 +#define SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM 257 +#define SSL_R_UNSUPPORTED_ELLIPTIC_CURVE 258 +#define SSL_R_UNSUPPORTED_PROTOCOL 259 +#define SSL_R_UNSUPPORTED_SSL_VERSION 260 +#define SSL_R_USE_SRTP_NOT_NEGOTIATED 261 +#define SSL_R_WRONG_CERTIFICATE_TYPE 262 +#define SSL_R_WRONG_CIPHER_RETURNED 263 +#define SSL_R_WRONG_CURVE 264 +#define SSL_R_WRONG_MESSAGE_TYPE 265 +#define SSL_R_WRONG_SIGNATURE_TYPE 266 +#define SSL_R_WRONG_SSL_VERSION 267 +#define SSL_R_WRONG_VERSION_NUMBER 268 +#define SSL_R_X509_LIB 269 +#define SSL_R_X509_VERIFICATION_SETUP_PROBLEMS 270 +#define SSL_R_FRAGMENT_MISMATCH 271 +#define SSL_R_BUFFER_TOO_SMALL 272 +#define SSL_R_OLD_SESSION_VERSION_NOT_RETURNED 273 +#define SSL_R_OUTPUT_ALIASES_INPUT 274 +#define SSL_R_RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION 275 +#define SSL_R_EMS_STATE_INCONSISTENT 276 +#define SSL_R_RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION 277 +#define SSL_R_TOO_MANY_WARNING_ALERTS 278 +#define SSL_R_UNEXPECTED_EXTENSION 279 +#define SSL_R_SIGNATURE_ALGORITHMS_EXTENSION_SENT_BY_SERVER 280 +#define SSL_R_ERROR_ADDING_EXTENSION 281 +#define SSL_R_ERROR_PARSING_EXTENSION 282 +#define SSL_R_MISSING_EXTENSION 283 +#define SSL_R_CUSTOM_EXTENSION_CONTENTS_TOO_LARGE 284 +#define SSL_R_CUSTOM_EXTENSION_ERROR 285 +#define SSL_R_SSLV3_ALERT_CLOSE_NOTIFY 1000 +#define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010 +#define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020 +#define SSL_R_TLSV1_ALERT_DECRYPTION_FAILED 1021 +#define SSL_R_TLSV1_ALERT_RECORD_OVERFLOW 1022 +#define SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE 1030 +#define SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE 1040 +#define SSL_R_SSLV3_ALERT_NO_CERTIFICATE 1041 +#define SSL_R_SSLV3_ALERT_BAD_CERTIFICATE 1042 +#define SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE 1043 +#define SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED 1044 +#define SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED 1045 +#define SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN 1046 +#define SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER 1047 +#define SSL_R_TLSV1_ALERT_UNKNOWN_CA 1048 +#define SSL_R_TLSV1_ALERT_ACCESS_DENIED 1049 +#define SSL_R_TLSV1_ALERT_DECODE_ERROR 1050 +#define SSL_R_TLSV1_ALERT_DECRYPT_ERROR 1051 +#define SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION 1060 +#define SSL_R_TLSV1_ALERT_PROTOCOL_VERSION 1070 +#define SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY 1071 +#define SSL_R_TLSV1_ALERT_INTERNAL_ERROR 1080 +#define SSL_R_TLSV1_ALERT_INAPPROPRIATE_FALLBACK 1086 +#define SSL_R_TLSV1_ALERT_USER_CANCELLED 1090 +#define SSL_R_TLSV1_ALERT_NO_RENEGOTIATION 1100 +#define SSL_R_TLSV1_UNSUPPORTED_EXTENSION 1110 +#define SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE 1111 +#define SSL_R_TLSV1_UNRECOGNIZED_NAME 1112 +#define SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE 1113 +#define SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE 1114 + +#endif /* OPENSSL_HEADER_SSL_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/ssl3.h b/TMessagesProj/jni/boringssl/include/openssl/ssl3.h new file mode 100644 index 00000000..e07488d0 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/ssl3.h @@ -0,0 +1,696 @@ +/* ssl/ssl3.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * ECC cipher suite support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ + +#ifndef HEADER_SSL3_H +#define HEADER_SSL3_H + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* These are kept to support clients that negotiates higher protocol versions + * using SSLv2 client hello records. */ +#define SSL2_MT_CLIENT_HELLO 1 +#define SSL2_VERSION 0x0002 + +/* Signalling cipher suite value from RFC 5746. */ +#define SSL3_CK_SCSV 0x030000FF +/* Fallback signalling cipher suite value from RFC 7507. */ +#define SSL3_CK_FALLBACK_SCSV 0x03005600 + +#define SSL3_CK_RSA_NULL_MD5 0x03000001 +#define SSL3_CK_RSA_NULL_SHA 0x03000002 +#define SSL3_CK_RSA_RC4_40_MD5 0x03000003 +#define SSL3_CK_RSA_RC4_128_MD5 0x03000004 +#define SSL3_CK_RSA_RC4_128_SHA 0x03000005 +#define SSL3_CK_RSA_RC2_40_MD5 0x03000006 +#define SSL3_CK_RSA_IDEA_128_SHA 0x03000007 +#define SSL3_CK_RSA_DES_40_CBC_SHA 0x03000008 +#define SSL3_CK_RSA_DES_64_CBC_SHA 0x03000009 +#define SSL3_CK_RSA_DES_192_CBC3_SHA 0x0300000A + +#define SSL3_CK_DH_DSS_DES_40_CBC_SHA 0x0300000B +#define SSL3_CK_DH_DSS_DES_64_CBC_SHA 0x0300000C +#define SSL3_CK_DH_DSS_DES_192_CBC3_SHA 0x0300000D +#define SSL3_CK_DH_RSA_DES_40_CBC_SHA 0x0300000E +#define SSL3_CK_DH_RSA_DES_64_CBC_SHA 0x0300000F +#define SSL3_CK_DH_RSA_DES_192_CBC3_SHA 0x03000010 + +#define SSL3_CK_EDH_DSS_DES_40_CBC_SHA 0x03000011 +#define SSL3_CK_EDH_DSS_DES_64_CBC_SHA 0x03000012 +#define SSL3_CK_EDH_DSS_DES_192_CBC3_SHA 0x03000013 +#define SSL3_CK_EDH_RSA_DES_40_CBC_SHA 0x03000014 +#define SSL3_CK_EDH_RSA_DES_64_CBC_SHA 0x03000015 +#define SSL3_CK_EDH_RSA_DES_192_CBC3_SHA 0x03000016 + +#define SSL3_CK_ADH_RC4_40_MD5 0x03000017 +#define SSL3_CK_ADH_RC4_128_MD5 0x03000018 +#define SSL3_CK_ADH_DES_40_CBC_SHA 0x03000019 +#define SSL3_CK_ADH_DES_64_CBC_SHA 0x0300001A +#define SSL3_CK_ADH_DES_192_CBC_SHA 0x0300001B + +#define SSL3_TXT_RSA_NULL_MD5 "NULL-MD5" +#define SSL3_TXT_RSA_NULL_SHA "NULL-SHA" +#define SSL3_TXT_RSA_RC4_40_MD5 "EXP-RC4-MD5" +#define SSL3_TXT_RSA_RC4_128_MD5 "RC4-MD5" +#define SSL3_TXT_RSA_RC4_128_SHA "RC4-SHA" +#define SSL3_TXT_RSA_RC2_40_MD5 "EXP-RC2-CBC-MD5" +#define SSL3_TXT_RSA_IDEA_128_SHA "IDEA-CBC-SHA" +#define SSL3_TXT_RSA_DES_40_CBC_SHA "EXP-DES-CBC-SHA" +#define SSL3_TXT_RSA_DES_64_CBC_SHA "DES-CBC-SHA" +#define SSL3_TXT_RSA_DES_192_CBC3_SHA "DES-CBC3-SHA" + +#define SSL3_TXT_DH_DSS_DES_40_CBC_SHA "EXP-DH-DSS-DES-CBC-SHA" +#define SSL3_TXT_DH_DSS_DES_64_CBC_SHA "DH-DSS-DES-CBC-SHA" +#define SSL3_TXT_DH_DSS_DES_192_CBC3_SHA "DH-DSS-DES-CBC3-SHA" +#define SSL3_TXT_DH_RSA_DES_40_CBC_SHA "EXP-DH-RSA-DES-CBC-SHA" +#define SSL3_TXT_DH_RSA_DES_64_CBC_SHA "DH-RSA-DES-CBC-SHA" +#define SSL3_TXT_DH_RSA_DES_192_CBC3_SHA "DH-RSA-DES-CBC3-SHA" + +#define SSL3_TXT_EDH_DSS_DES_40_CBC_SHA "EXP-EDH-DSS-DES-CBC-SHA" +#define SSL3_TXT_EDH_DSS_DES_64_CBC_SHA "EDH-DSS-DES-CBC-SHA" +#define SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA "EDH-DSS-DES-CBC3-SHA" +#define SSL3_TXT_EDH_RSA_DES_40_CBC_SHA "EXP-EDH-RSA-DES-CBC-SHA" +#define SSL3_TXT_EDH_RSA_DES_64_CBC_SHA "EDH-RSA-DES-CBC-SHA" +#define SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA "EDH-RSA-DES-CBC3-SHA" + +#define SSL3_TXT_ADH_RC4_40_MD5 "EXP-ADH-RC4-MD5" +#define SSL3_TXT_ADH_RC4_128_MD5 "ADH-RC4-MD5" +#define SSL3_TXT_ADH_DES_40_CBC_SHA "EXP-ADH-DES-CBC-SHA" +#define SSL3_TXT_ADH_DES_64_CBC_SHA "ADH-DES-CBC-SHA" +#define SSL3_TXT_ADH_DES_192_CBC_SHA "ADH-DES-CBC3-SHA" + +#define SSL3_SSL_SESSION_ID_LENGTH 32 +#define SSL3_MAX_SSL_SESSION_ID_LENGTH 32 + +#define SSL3_MASTER_SECRET_SIZE 48 +#define SSL3_RANDOM_SIZE 32 +#define SSL3_SESSION_ID_SIZE 32 +#define SSL3_RT_HEADER_LENGTH 5 + +#define SSL3_HM_HEADER_LENGTH 4 + +#ifndef SSL3_ALIGN_PAYLOAD +/* Some will argue that this increases memory footprint, but it's not actually + * true. Point is that malloc has to return at least 64-bit aligned pointers, + * meaning that allocating 5 bytes wastes 3 bytes in either case. Suggested + * pre-gaping simply moves these wasted bytes from the end of allocated region + * to its front, but makes data payload aligned, which improves performance. */ +#define SSL3_ALIGN_PAYLOAD 8 +#else +#if (SSL3_ALIGN_PAYLOAD & (SSL3_ALIGN_PAYLOAD - 1)) != 0 +#error "insane SSL3_ALIGN_PAYLOAD" +#undef SSL3_ALIGN_PAYLOAD +#endif +#endif + +/* This is the maximum MAC (digest) size used by the SSL library. Currently + * maximum of 20 is used by SHA1, but we reserve for future extension for + * 512-bit hashes. */ + +#define SSL3_RT_MAX_MD_SIZE 64 + +/* Maximum block size used in all ciphersuites. Currently 16 for AES. */ + +#define SSL_RT_MAX_CIPHER_BLOCK_SIZE 16 + +#define SSL3_RT_MAX_EXTRA (16384) + +/* Maximum plaintext length: defined by SSL/TLS standards */ +#define SSL3_RT_MAX_PLAIN_LENGTH 16384 +/* Maximum compression overhead: defined by SSL/TLS standards */ +#define SSL3_RT_MAX_COMPRESSED_OVERHEAD 1024 + +/* The standards give a maximum encryption overhead of 1024 bytes. In practice + * the value is lower than this. The overhead is the maximum number of padding + * bytes (256) plus the mac size. + * + * TODO(davidben): This derivation doesn't take AEADs into account, or TLS 1.1 + * explicit nonces. It happens to work because |SSL3_RT_MAX_MD_SIZE| is larger + * than necessary and no true AEAD has variable overhead in TLS 1.2. */ +#define SSL3_RT_MAX_ENCRYPTED_OVERHEAD (256 + SSL3_RT_MAX_MD_SIZE) + +/* SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD is the maximum overhead in encrypting a + * record. This does not include the record header. Some ciphers use explicit + * nonces, so it includes both the AEAD overhead as well as the nonce. */ +#define SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD \ + (EVP_AEAD_MAX_OVERHEAD + EVP_AEAD_MAX_NONCE_LENGTH) + +OPENSSL_COMPILE_ASSERT( + SSL3_RT_MAX_ENCRYPTED_OVERHEAD >= SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD, + max_overheads_are_consistent); + +/* SSL3_RT_MAX_COMPRESSED_LENGTH is an alias for + * |SSL3_RT_MAX_PLAIN_LENGTH|. Compression is gone, so don't include the + * compression overhead. */ +#define SSL3_RT_MAX_COMPRESSED_LENGTH SSL3_RT_MAX_PLAIN_LENGTH + +#define SSL3_RT_MAX_ENCRYPTED_LENGTH \ + (SSL3_RT_MAX_ENCRYPTED_OVERHEAD + SSL3_RT_MAX_COMPRESSED_LENGTH) +#define SSL3_RT_MAX_PACKET_SIZE \ + (SSL3_RT_MAX_ENCRYPTED_LENGTH + SSL3_RT_HEADER_LENGTH) + +#define SSL3_MD_CLIENT_FINISHED_CONST "\x43\x4C\x4E\x54" +#define SSL3_MD_SERVER_FINISHED_CONST "\x53\x52\x56\x52" + +#define SSL3_VERSION 0x0300 +#define SSL3_VERSION_MAJOR 0x03 +#define SSL3_VERSION_MINOR 0x00 + +#define SSL3_RT_CHANGE_CIPHER_SPEC 20 +#define SSL3_RT_ALERT 21 +#define SSL3_RT_HANDSHAKE 22 +#define SSL3_RT_APPLICATION_DATA 23 + +/* Pseudo content type for SSL/TLS header info */ +#define SSL3_RT_HEADER 0x100 + +#define SSL3_AL_WARNING 1 +#define SSL3_AL_FATAL 2 + +#define SSL3_AD_CLOSE_NOTIFY 0 +#define SSL3_AD_UNEXPECTED_MESSAGE 10 /* fatal */ +#define SSL3_AD_BAD_RECORD_MAC 20 /* fatal */ +#define SSL3_AD_DECOMPRESSION_FAILURE 30 /* fatal */ +#define SSL3_AD_HANDSHAKE_FAILURE 40 /* fatal */ +#define SSL3_AD_NO_CERTIFICATE 41 +#define SSL3_AD_BAD_CERTIFICATE 42 +#define SSL3_AD_UNSUPPORTED_CERTIFICATE 43 +#define SSL3_AD_CERTIFICATE_REVOKED 44 +#define SSL3_AD_CERTIFICATE_EXPIRED 45 +#define SSL3_AD_CERTIFICATE_UNKNOWN 46 +#define SSL3_AD_ILLEGAL_PARAMETER 47 /* fatal */ +#define SSL3_AD_INAPPROPRIATE_FALLBACK 86 /* fatal */ + +typedef struct ssl3_record_st { + /* type is the record type. */ + uint8_t type; + /* length is the number of unconsumed bytes of |data|. */ + uint16_t length; + /* off is the number of consumed bytes of |data|. */ + uint16_t off; + /* data is a non-owning pointer to the record contents. The total length of + * the buffer is |off| + |length|. */ + uint8_t *data; + /* epoch, in DTLS, is the epoch number of the record. */ + uint16_t epoch; +} SSL3_RECORD; + +typedef struct ssl3_buffer_st { + uint8_t *buf; /* at least SSL3_RT_MAX_PACKET_SIZE bytes, see + ssl3_setup_buffers() */ + size_t len; /* buffer size */ + int offset; /* where to 'copy from' */ + int left; /* how many bytes left */ +} SSL3_BUFFER; + +#define SSL3_CT_RSA_SIGN 1 +#define SSL3_CT_DSS_SIGN 2 +#define SSL3_CT_RSA_FIXED_DH 3 +#define SSL3_CT_DSS_FIXED_DH 4 +#define SSL3_CT_RSA_EPHEMERAL_DH 5 +#define SSL3_CT_DSS_EPHEMERAL_DH 6 +#define SSL3_CT_FORTEZZA_DMS 20 + + +/* TODO(davidben): This flag can probably be merged into s3->change_cipher_spec + * to something tri-state. (Normal / Expect CCS / Between CCS and Finished). */ +#define SSL3_FLAGS_EXPECT_CCS 0x0080 + +typedef struct ssl3_state_st { + long flags; + + uint8_t read_sequence[8]; + int read_mac_secret_size; + uint8_t read_mac_secret[EVP_MAX_MD_SIZE]; + uint8_t write_sequence[8]; + int write_mac_secret_size; + uint8_t write_mac_secret[EVP_MAX_MD_SIZE]; + + uint8_t server_random[SSL3_RANDOM_SIZE]; + uint8_t client_random[SSL3_RANDOM_SIZE]; + + /* flags for countermeasure against known-IV weakness */ + int need_record_splitting; + + /* The value of 'extra' when the buffers were initialized */ + int init_extra; + + /* have_version is true if the connection's final version is known. Otherwise + * the version has not been negotiated yet. */ + char have_version; + + /* initial_handshake_complete is true if the initial handshake has + * completed. */ + char initial_handshake_complete; + + /* sniff_buffer is used by the server in the initial handshake to read a + * V2ClientHello before the record layer is initialized. */ + BUF_MEM *sniff_buffer; + size_t sniff_buffer_len; + + SSL3_BUFFER rbuf; /* read IO goes into here */ + SSL3_BUFFER wbuf; /* write IO goes into here */ + + SSL3_RECORD rrec; /* each decoded record goes in here */ + + /* storage for Handshake protocol data received but not yet processed by + * ssl3_read_bytes: */ + uint8_t handshake_fragment[4]; + unsigned int handshake_fragment_len; + + /* partial write - check the numbers match */ + unsigned int wnum; /* number of bytes sent so far */ + int wpend_tot; /* number bytes written */ + int wpend_type; + int wpend_ret; /* number of bytes submitted */ + const uint8_t *wpend_buf; + + /* handshake_buffer, if non-NULL, contains the handshake transcript. */ + BUF_MEM *handshake_buffer; + /* handshake_hash, if initialized with an |EVP_MD|, maintains the handshake + * hash. For TLS 1.1 and below, it is the SHA-1 half. */ + EVP_MD_CTX handshake_hash; + /* handshake_md5, if initialized with an |EVP_MD|, maintains the MD5 half of + * the handshake hash for TLS 1.1 and below. */ + EVP_MD_CTX handshake_md5; + + /* this is set whenerver we see a change_cipher_spec message come in when we + * are not looking for one */ + int change_cipher_spec; + + int warn_alert; + int fatal_alert; + /* we allow one fatal and one warning alert to be outstanding, send close + * alert via the warning alert */ + int alert_dispatch; + uint8_t send_alert[2]; + + int total_renegotiations; + + /* empty_record_count is the number of consecutive empty records received. */ + uint8_t empty_record_count; + + /* warning_alert_count is the number of consecutive warning alerts + * received. */ + uint8_t warning_alert_count; + + /* State pertaining to the pending handshake. + * + * TODO(davidben): State is current spread all over the place. Move + * pending handshake state here so it can be managed separately from + * established connection state in case of renegotiations. */ + struct { + /* actually only need to be 16+20 for SSLv3 and 12 for TLS */ + uint8_t finish_md[EVP_MAX_MD_SIZE * 2]; + int finish_md_len; + uint8_t peer_finish_md[EVP_MAX_MD_SIZE * 2]; + int peer_finish_md_len; + + unsigned long message_size; + int message_type; + + /* used to hold the new cipher we are going to use */ + const SSL_CIPHER *new_cipher; + DH *dh; + + EC_KEY *ecdh; /* holds short lived ECDH key */ + + /* used when SSL_ST_FLUSH_DATA is entered */ + int next_state; + + int reuse_message; + + union { + /* sent is a bitset where the bits correspond to elements of kExtensions + * in t1_lib.c. Each bit is set if that extension was sent in a + * ClientHello. It's not used by servers. */ + uint32_t sent; + /* received is a bitset, like |sent|, but is used by servers to record + * which extensions were received from a client. */ + uint32_t received; + } extensions; + + union { + /* sent is a bitset where the bits correspond to elements of + * |client_custom_extensions| in the |SSL_CTX|. Each bit is set if that + * extension was sent in a ClientHello. It's not used by servers. */ + uint16_t sent; + /* received is a bitset, like |sent|, but is used by servers to record + * which custom extensions were received from a client. The bits here + * correspond to |server_custom_extensions|. */ + uint16_t received; + } custom_extensions; + + /* SNI extension */ + + /* should_ack_sni is used by a server and indicates that the SNI extension + * should be echoed in the ServerHello. */ + unsigned should_ack_sni:1; + + + /* Client-only: cert_req determines if a client certificate is to be sent. + * This is 0 if no client Certificate message is to be sent, 1 if there is + * a client certificate, and 2 to send an empty client Certificate + * message. */ + int cert_req; + + /* Client-only: ca_names contains the list of CAs received in a + * CertificateRequest message. */ + STACK_OF(X509_NAME) *ca_names; + + /* Client-only: certificate_types contains the set of certificate types + * received in a CertificateRequest message. */ + uint8_t *certificate_types; + size_t num_certificate_types; + + int key_block_length; + uint8_t *key_block; + + const EVP_AEAD *new_aead; + uint8_t new_mac_secret_len; + uint8_t new_fixed_iv_len; + uint8_t new_variable_iv_len; + + /* Server-only: cert_request is true if a client certificate was + * requested. */ + int cert_request; + + /* certificate_status_expected is true if OCSP stapling was negotiated and + * the server is expected to send a CertificateStatus message. */ + char certificate_status_expected; + + /* Server-only: peer_ellipticcurvelist contains the EC curve IDs advertised + * by the peer. This is only set on the server's end. The server does not + * advertise this extension to the client. */ + uint16_t *peer_ellipticcurvelist; + size_t peer_ellipticcurvelist_length; + + /* extended_master_secret indicates whether the extended master secret + * computation is used in this handshake. Note that this is different from + * whether it was used for the current session. If this is a resumption + * handshake then EMS might be negotiated in the client and server hello + * messages, but it doesn't matter if the session that's being resumed + * didn't use it to create the master secret initially. */ + char extended_master_secret; + + /* Client-only: peer_psk_identity_hint is the psk_identity_hint sent by the + * server when using a PSK key exchange. */ + char *peer_psk_identity_hint; + + /* new_mac_secret_size is unused and exists only until wpa_supplicant can + * be updated. It is only needed for EAP-FAST, which we don't support. */ + uint8_t new_mac_secret_size; + + /* Client-only: in_false_start is one if there is a pending handshake in + * False Start. The client may write data at this point. */ + char in_false_start; + } tmp; + + /* Connection binding to prevent renegotiation attacks */ + uint8_t previous_client_finished[EVP_MAX_MD_SIZE]; + uint8_t previous_client_finished_len; + uint8_t previous_server_finished[EVP_MAX_MD_SIZE]; + uint8_t previous_server_finished_len; + int send_connection_binding; /* TODOEKR */ + + /* Set if we saw the Next Protocol Negotiation extension from our peer. */ + int next_proto_neg_seen; + + /* ALPN information + * (we are in the process of transitioning from NPN to ALPN.) */ + + /* In a server these point to the selected ALPN protocol after the + * ClientHello has been processed. In a client these contain the protocol + * that the server selected once the ServerHello has been processed. */ + uint8_t *alpn_selected; + size_t alpn_selected_len; + + /* In a client, this means that the server supported Channel ID and that a + * Channel ID was sent. In a server it means that we echoed support for + * Channel IDs and that tlsext_channel_id will be valid after the + * handshake. */ + char tlsext_channel_id_valid; + /* For a server: + * If |tlsext_channel_id_valid| is true, then this contains the + * verified Channel ID from the client: a P256 point, (x,y), where + * each are big-endian values. */ + uint8_t tlsext_channel_id[64]; +} SSL3_STATE; + +/* SSLv3 */ +/* client */ +/* extra state */ +#define SSL3_ST_CW_FLUSH (0x100 | SSL_ST_CONNECT) +#define SSL3_ST_FALSE_START (0x101 | SSL_ST_CONNECT) +/* write to server */ +#define SSL3_ST_CW_CLNT_HELLO_A (0x110 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CLNT_HELLO_B (0x111 | SSL_ST_CONNECT) +/* read from server */ +#define SSL3_ST_CR_SRVR_HELLO_A (0x120 | SSL_ST_CONNECT) +#define SSL3_ST_CR_SRVR_HELLO_B (0x121 | SSL_ST_CONNECT) +#define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A (0x126 | SSL_ST_CONNECT) +#define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B (0x127 | SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_A (0x130 | SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_B (0x131 | SSL_ST_CONNECT) +#define SSL3_ST_CR_KEY_EXCH_A (0x140 | SSL_ST_CONNECT) +#define SSL3_ST_CR_KEY_EXCH_B (0x141 | SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_REQ_A (0x150 | SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_REQ_B (0x151 | SSL_ST_CONNECT) +#define SSL3_ST_CR_SRVR_DONE_A (0x160 | SSL_ST_CONNECT) +#define SSL3_ST_CR_SRVR_DONE_B (0x161 | SSL_ST_CONNECT) +/* write to server */ +#define SSL3_ST_CW_CERT_A (0x170 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CERT_B (0x171 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CERT_C (0x172 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CERT_D (0x173 | SSL_ST_CONNECT) +#define SSL3_ST_CW_KEY_EXCH_A (0x180 | SSL_ST_CONNECT) +#define SSL3_ST_CW_KEY_EXCH_B (0x181 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CERT_VRFY_A (0x190 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CERT_VRFY_B (0x191 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CERT_VRFY_C (0x192 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CHANGE_A (0x1A0 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CHANGE_B (0x1A1 | SSL_ST_CONNECT) +#define SSL3_ST_CW_NEXT_PROTO_A (0x200 | SSL_ST_CONNECT) +#define SSL3_ST_CW_NEXT_PROTO_B (0x201 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CHANNEL_ID_A (0x220 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CHANNEL_ID_B (0x221 | SSL_ST_CONNECT) +#define SSL3_ST_CW_FINISHED_A (0x1B0 | SSL_ST_CONNECT) +#define SSL3_ST_CW_FINISHED_B (0x1B1 | SSL_ST_CONNECT) +/* read from server */ +#define SSL3_ST_CR_CHANGE (0x1C0 | SSL_ST_CONNECT) +#define SSL3_ST_CR_FINISHED_A (0x1D0 | SSL_ST_CONNECT) +#define SSL3_ST_CR_FINISHED_B (0x1D1 | SSL_ST_CONNECT) +#define SSL3_ST_CR_SESSION_TICKET_A (0x1E0 | SSL_ST_CONNECT) +#define SSL3_ST_CR_SESSION_TICKET_B (0x1E1 | SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_STATUS_A (0x1F0 | SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_STATUS_B (0x1F1 | SSL_ST_CONNECT) + +/* server */ +/* extra state */ +#define SSL3_ST_SW_FLUSH (0x100 | SSL_ST_ACCEPT) +/* read from client */ +#define SSL3_ST_SR_INITIAL_BYTES (0x240 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_V2_CLIENT_HELLO (0x241 | SSL_ST_ACCEPT) +/* Do not change the number values, they do matter */ +#define SSL3_ST_SR_CLNT_HELLO_A (0x110 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_CLNT_HELLO_B (0x111 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_CLNT_HELLO_C (0x112 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_CLNT_HELLO_D (0x115 | SSL_ST_ACCEPT) +/* write to client */ +#define SSL3_ST_SW_HELLO_REQ_A (0x120 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_HELLO_REQ_B (0x121 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_HELLO_REQ_C (0x122 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_SRVR_HELLO_A (0x130 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_SRVR_HELLO_B (0x131 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_CERT_A (0x140 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_CERT_B (0x141 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_KEY_EXCH_A (0x150 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_KEY_EXCH_B (0x151 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_KEY_EXCH_C (0x152 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_KEY_EXCH_D (0x153 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_CERT_REQ_A (0x160 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_CERT_REQ_B (0x161 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_SRVR_DONE_A (0x170 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_SRVR_DONE_B (0x171 | SSL_ST_ACCEPT) +/* read from client */ +#define SSL3_ST_SR_CERT_A (0x180 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_CERT_B (0x181 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_KEY_EXCH_A (0x190 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_KEY_EXCH_B (0x191 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_CERT_VRFY_A (0x1A0 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_CERT_VRFY_B (0x1A1 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_CHANGE (0x1B0 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_NEXT_PROTO_A (0x210 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_NEXT_PROTO_B (0x211 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_CHANNEL_ID_A (0x230 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_CHANNEL_ID_B (0x231 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_FINISHED_A (0x1C0 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_FINISHED_B (0x1C1 | SSL_ST_ACCEPT) + +/* write to client */ +#define SSL3_ST_SW_CHANGE_A (0x1D0 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_CHANGE_B (0x1D1 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_FINISHED_A (0x1E0 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_FINISHED_B (0x1E1 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_SESSION_TICKET_A (0x1F0 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_SESSION_TICKET_B (0x1F1 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_CERT_STATUS_A (0x200 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_CERT_STATUS_B (0x201 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_SUPPLEMENTAL_DATA_A (0x220 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_SUPPLEMENTAL_DATA_B (0x221 | SSL_ST_ACCEPT) + +#define SSL3_MT_HELLO_REQUEST 0 +#define SSL3_MT_CLIENT_HELLO 1 +#define SSL3_MT_SERVER_HELLO 2 +#define SSL3_MT_NEWSESSION_TICKET 4 +#define SSL3_MT_CERTIFICATE 11 +#define SSL3_MT_SERVER_KEY_EXCHANGE 12 +#define SSL3_MT_CERTIFICATE_REQUEST 13 +#define SSL3_MT_SERVER_DONE 14 +#define SSL3_MT_CERTIFICATE_VERIFY 15 +#define SSL3_MT_CLIENT_KEY_EXCHANGE 16 +#define SSL3_MT_FINISHED 20 +#define SSL3_MT_CERTIFICATE_STATUS 22 +#define SSL3_MT_SUPPLEMENTAL_DATA 23 +#define SSL3_MT_NEXT_PROTO 67 +#define SSL3_MT_ENCRYPTED_EXTENSIONS 203 +#define DTLS1_MT_HELLO_VERIFY_REQUEST 3 + + +#define SSL3_MT_CCS 1 + +/* These are used when changing over to a new cipher */ +#define SSL3_CC_READ 0x01 +#define SSL3_CC_WRITE 0x02 +#define SSL3_CC_CLIENT 0x10 +#define SSL3_CC_SERVER 0x20 +#define SSL3_CHANGE_CIPHER_CLIENT_WRITE (SSL3_CC_CLIENT | SSL3_CC_WRITE) +#define SSL3_CHANGE_CIPHER_SERVER_READ (SSL3_CC_SERVER | SSL3_CC_READ) +#define SSL3_CHANGE_CIPHER_CLIENT_READ (SSL3_CC_CLIENT | SSL3_CC_READ) +#define SSL3_CHANGE_CIPHER_SERVER_WRITE (SSL3_CC_SERVER | SSL3_CC_WRITE) + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/TMessagesProj/jni/boringssl/include/openssl/stack.h b/TMessagesProj/jni/boringssl/include/openssl/stack.h new file mode 100644 index 00000000..b600b43d --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/stack.h @@ -0,0 +1,298 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_STACK_H +#define OPENSSL_HEADER_STACK_H + +#include + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* A stack, in OpenSSL, is an array of pointers. They are the most commonly + * used collection object. + * + * This file defines macros for type safe use of the stack functions. A stack + * of a specific type of object has type |STACK_OF(type)|. This can be defined + * (once) with |DEFINE_STACK_OF(type)| and declared where needed with + * |DECLARE_STACK_OF(type)|. For example: + * + * struct foo { + * int bar; + * }; + * + * DEFINE_STACK_OF(struct foo); + * + * Although note that the stack will contain /pointers/ to |foo|. + * + * A macro will be defined for each of the sk_* functions below. For + * STACK_OF(foo), the macros would be sk_foo_new, sk_foo_pop etc. */ + + +/* stack_cmp_func is a comparison function that returns a value < 0, 0 or > 0 + * if |*a| is less than, equal to or greater than |*b|, respectively. Note the + * extra indirection - the function is given a pointer to a pointer to the + * element. This differs from the usual qsort/bsearch comparison function. */ +typedef int (*stack_cmp_func)(const void **a, const void **b); + +/* stack_st contains an array of pointers. It is not designed to be used + * directly, rather the wrapper macros should be used. */ +typedef struct stack_st { + /* num contains the number of valid pointers in |data|. */ + size_t num; + void **data; + /* sorted is non-zero if the values pointed to by |data| are in ascending + * order, based on |comp|. */ + size_t sorted; + /* num_alloc contains the number of pointers allocated in the buffer pointed + * to by |data|, which may be larger than |num|. */ + size_t num_alloc; + /* comp is an optional comparison function. */ + stack_cmp_func comp; +} _STACK; + + +#define STACK_OF(type) struct stack_st_##type + +#define DECLARE_STACK_OF(type) STACK_OF(type); + +/* The make_macros.sh script in this directory parses the following lines and + * generates the stack_macros.h file that contains macros for the following + * types of stacks: + * + * STACK_OF:ACCESS_DESCRIPTION + * STACK_OF:ASN1_ADB_TABLE + * STACK_OF:ASN1_GENERALSTRING + * STACK_OF:ASN1_INTEGER + * STACK_OF:ASN1_OBJECT + * STACK_OF:ASN1_STRING_TABLE + * STACK_OF:ASN1_TYPE + * STACK_OF:ASN1_VALUE + * STACK_OF:BIO + * STACK_OF:BY_DIR_ENTRY + * STACK_OF:BY_DIR_HASH + * STACK_OF:CONF_VALUE + * STACK_OF:CRYPTO_EX_DATA_FUNCS + * STACK_OF:DIST_POINT + * STACK_OF:GENERAL_NAME + * STACK_OF:GENERAL_NAMES + * STACK_OF:GENERAL_SUBTREE + * STACK_OF:MIME_HEADER + * STACK_OF:PKCS7_RECIP_INFO + * STACK_OF:PKCS7_SIGNER_INFO + * STACK_OF:POLICYINFO + * STACK_OF:POLICYQUALINFO + * STACK_OF:POLICY_MAPPING + * STACK_OF:RSA_additional_prime + * STACK_OF:SSL_COMP + * STACK_OF:SSL_CUSTOM_EXTENSION + * STACK_OF:STACK_OF_X509_NAME_ENTRY + * STACK_OF:SXNETID + * STACK_OF:X509 + * STACK_OF:X509V3_EXT_METHOD + * STACK_OF:X509_ALGOR + * STACK_OF:X509_ATTRIBUTE + * STACK_OF:X509_CRL + * STACK_OF:X509_EXTENSION + * STACK_OF:X509_INFO + * STACK_OF:X509_LOOKUP + * STACK_OF:X509_NAME + * STACK_OF:X509_NAME_ENTRY + * STACK_OF:X509_OBJECT + * STACK_OF:X509_POLICY_DATA + * STACK_OF:X509_POLICY_NODE + * STACK_OF:X509_PURPOSE + * STACK_OF:X509_REVOKED + * STACK_OF:X509_TRUST + * STACK_OF:X509_VERIFY_PARAM + * STACK_OF:void + * + * Some stacks contain only const structures, so the stack should return const + * pointers to retain type-checking. + * + * CONST_STACK_OF:SRTP_PROTECTION_PROFILE + * CONST_STACK_OF:SSL_CIPHER */ + + +/* Some stacks are special because, although we would like STACK_OF(char *), + * that would actually be a stack of pointers to char*, but we just want to + * point to the string directly. In this case we call them "special" and use + * |DEFINE_SPECIAL_STACK_OF(type)| */ +#define DEFINE_SPECIAL_STACK_OF(type, inner) \ + STACK_OF(type) { _STACK special_stack; }; \ + OPENSSL_COMPILE_ASSERT(sizeof(type) == sizeof(void *), \ + special_stack_of_non_pointer_##type); + +typedef char *OPENSSL_STRING; + +DEFINE_SPECIAL_STACK_OF(OPENSSL_STRING, char) +DEFINE_SPECIAL_STACK_OF(OPENSSL_BLOCK, uint8_t) + +/* The make_macros.sh script in this directory parses the following lines and + * generates the stack_macros.h file that contains macros for the following + * types of stacks: + * + * SPECIAL_STACK_OF:OPENSSL_STRING + * SPECIAL_STACK_OF:OPENSSL_BLOCK */ + +#define IN_STACK_H +#include +#undef IN_STACK_H + + +/* These are the raw stack functions, you shouldn't be using them. Rather you + * should be using the type stack macros implemented above. */ + +/* sk_new creates a new, empty stack with the given comparison function, which + * may be zero. It returns the new stack or NULL on allocation failure. */ +OPENSSL_EXPORT _STACK *sk_new(stack_cmp_func comp); + +/* sk_new_null creates a new, empty stack. It returns the new stack or NULL on + * allocation failure. */ +OPENSSL_EXPORT _STACK *sk_new_null(void); + +/* sk_num returns the number of elements in |s|. */ +OPENSSL_EXPORT size_t sk_num(const _STACK *sk); + +/* sk_zero resets |sk| to the empty state but does nothing to free the + * individual elements themselves. */ +OPENSSL_EXPORT void sk_zero(_STACK *sk); + +/* sk_value returns the |i|th pointer in |sk|, or NULL if |i| is out of + * range. */ +OPENSSL_EXPORT void *sk_value(const _STACK *sk, size_t i); + +/* sk_set sets the |i|th pointer in |sk| to |p| and returns |p|. If |i| is out + * of range, it returns NULL. */ +OPENSSL_EXPORT void *sk_set(_STACK *sk, size_t i, void *p); + +/* sk_free frees the given stack and array of pointers, but does nothing to + * free the individual elements. Also see |sk_pop_free|. */ +OPENSSL_EXPORT void sk_free(_STACK *sk); + +/* sk_pop_free calls |free_func| on each element in the stack and then frees + * the stack itself. */ +OPENSSL_EXPORT void sk_pop_free(_STACK *sk, void (*free_func)(void *)); + +/* sk_insert inserts |p| into the stack at index |where|, moving existing + * elements if needed. It returns the length of the new stack, or zero on + * error. */ +OPENSSL_EXPORT size_t sk_insert(_STACK *sk, void *p, size_t where); + +/* sk_delete removes the pointer at index |where|, moving other elements down + * if needed. It returns the removed pointer, or NULL if |where| is out of + * range. */ +OPENSSL_EXPORT void *sk_delete(_STACK *sk, size_t where); + +/* sk_delete_ptr removes, at most, one instance of |p| from the stack based on + * pointer equality. If an instance of |p| is found then |p| is returned, + * otherwise it returns NULL. */ +OPENSSL_EXPORT void *sk_delete_ptr(_STACK *sk, void *p); + +/* sk_find returns the first value in the stack equal to |p|. If a comparison + * function has been set on the stack, then equality is defined by it and the + * stack will be sorted if need be so that a binary search can be used. + * Otherwise pointer equality is used. If a matching element is found, its + * index is written to |*out_index| (if |out_index| is not NULL) and one is + * returned. Otherwise zero is returned. */ +OPENSSL_EXPORT int sk_find(_STACK *sk, size_t *out_index, void *p); + +/* sk_shift removes and returns the first element in the stack, or returns NULL + * if the stack is empty. */ +OPENSSL_EXPORT void *sk_shift(_STACK *sk); + +/* sk_push appends |p| to the stack and returns the length of the new stack, or + * 0 on allocation failure. */ +OPENSSL_EXPORT size_t sk_push(_STACK *sk, void *p); + +/* sk_pop returns and removes the last element on the stack, or NULL if the + * stack is empty. */ +OPENSSL_EXPORT void *sk_pop(_STACK *sk); + +/* sk_dup performs a shallow copy of a stack and returns the new stack, or NULL + * on error. */ +OPENSSL_EXPORT _STACK *sk_dup(const _STACK *sk); + +/* sk_sort sorts the elements of |sk| into ascending order based on the + * comparison function. The stack maintains a |sorted| flag and sorting an + * already sorted stack is a no-op. */ +OPENSSL_EXPORT void sk_sort(_STACK *sk); + +/* sk_is_sorted returns one if |sk| is known to be sorted and zero + * otherwise. */ +OPENSSL_EXPORT int sk_is_sorted(const _STACK *sk); + +/* sk_set_cmp_func sets the comparison function to be used by |sk| and returns + * the previous one. */ +OPENSSL_EXPORT stack_cmp_func sk_set_cmp_func(_STACK *sk, stack_cmp_func comp); + +/* sk_deep_copy performs a copy of |sk| and of each of the non-NULL elements in + * |sk| by using |copy_func|. If an error occurs, |free_func| is used to free + * any copies already made and NULL is returned. */ +OPENSSL_EXPORT _STACK *sk_deep_copy(const _STACK *sk, + void *(*copy_func)(void *), + void (*free_func)(void *)); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_STACK_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/stack_macros.h b/TMessagesProj/jni/boringssl/include/openssl/stack_macros.h new file mode 100644 index 00000000..08097af3 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/stack_macros.h @@ -0,0 +1,4190 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#if !defined(IN_STACK_H) +#error "Don't include this file directly. Include stack.h." +#endif + +/* ACCESS_DESCRIPTION */ +#define sk_ACCESS_DESCRIPTION_new(comp) \ + ((STACK_OF(ACCESS_DESCRIPTION) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const ACCESS_DESCRIPTION **a, const ACCESS_DESCRIPTION **b), \ + comp))) + +#define sk_ACCESS_DESCRIPTION_new_null() \ + ((STACK_OF(ACCESS_DESCRIPTION) *)sk_new_null()) + +#define sk_ACCESS_DESCRIPTION_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk)) + +#define sk_ACCESS_DESCRIPTION_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk)); + +#define sk_ACCESS_DESCRIPTION_value(sk, i) \ + ((ACCESS_DESCRIPTION *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(ACCESS_DESCRIPTION) *, sk), (i))) + +#define sk_ACCESS_DESCRIPTION_set(sk, i, p) \ + ((ACCESS_DESCRIPTION *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), (i), \ + CHECKED_CAST(void *, ACCESS_DESCRIPTION *, p))) + +#define sk_ACCESS_DESCRIPTION_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk)) + +#define sk_ACCESS_DESCRIPTION_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(ACCESS_DESCRIPTION *), \ + free_func)) + +#define sk_ACCESS_DESCRIPTION_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), \ + CHECKED_CAST(void *, ACCESS_DESCRIPTION *, p), (where)) + +#define sk_ACCESS_DESCRIPTION_delete(sk, where) \ + ((ACCESS_DESCRIPTION *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), (where))) + +#define sk_ACCESS_DESCRIPTION_delete_ptr(sk, p) \ + ((ACCESS_DESCRIPTION *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), \ + CHECKED_CAST(void *, ACCESS_DESCRIPTION *, p))) + +#define sk_ACCESS_DESCRIPTION_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), \ + (out_index), CHECKED_CAST(void *, ACCESS_DESCRIPTION *, p)) + +#define sk_ACCESS_DESCRIPTION_shift(sk) \ + ((ACCESS_DESCRIPTION *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk))) + +#define sk_ACCESS_DESCRIPTION_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), \ + CHECKED_CAST(void *, ACCESS_DESCRIPTION *, p)) + +#define sk_ACCESS_DESCRIPTION_pop(sk) \ + ((ACCESS_DESCRIPTION *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk))) + +#define sk_ACCESS_DESCRIPTION_dup(sk) \ + ((STACK_OF(ACCESS_DESCRIPTION) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(ACCESS_DESCRIPTION) *, sk))) + +#define sk_ACCESS_DESCRIPTION_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk)) + +#define sk_ACCESS_DESCRIPTION_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ACCESS_DESCRIPTION) *, sk)) + +#define sk_ACCESS_DESCRIPTION_set_cmp_func(sk, comp) \ + ((int (*)(const ACCESS_DESCRIPTION **a, const ACCESS_DESCRIPTION **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const ACCESS_DESCRIPTION **a, \ + const ACCESS_DESCRIPTION **b), \ + comp))) + +#define sk_ACCESS_DESCRIPTION_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(ACCESS_DESCRIPTION) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ACCESS_DESCRIPTION) *, sk), \ + CHECKED_CAST(void *(*)(void *), \ + ACCESS_DESCRIPTION *(*)(ACCESS_DESCRIPTION *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(ACCESS_DESCRIPTION *), \ + free_func))) + +/* ASN1_ADB_TABLE */ +#define sk_ASN1_ADB_TABLE_new(comp) \ + ((STACK_OF(ASN1_ADB_TABLE) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const ASN1_ADB_TABLE **a, const ASN1_ADB_TABLE **b), comp))) + +#define sk_ASN1_ADB_TABLE_new_null() ((STACK_OF(ASN1_ADB_TABLE) *)sk_new_null()) + +#define sk_ASN1_ADB_TABLE_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk)) + +#define sk_ASN1_ADB_TABLE_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk)); + +#define sk_ASN1_ADB_TABLE_value(sk, i) \ + ((ASN1_ADB_TABLE *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_ADB_TABLE) *, sk), (i))) + +#define sk_ASN1_ADB_TABLE_set(sk, i, p) \ + ((ASN1_ADB_TABLE *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), (i), \ + CHECKED_CAST(void *, ASN1_ADB_TABLE *, p))) + +#define sk_ASN1_ADB_TABLE_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk)) + +#define sk_ASN1_ADB_TABLE_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_ADB_TABLE *), free_func)) + +#define sk_ASN1_ADB_TABLE_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), \ + CHECKED_CAST(void *, ASN1_ADB_TABLE *, p), (where)) + +#define sk_ASN1_ADB_TABLE_delete(sk, where) \ + ((ASN1_ADB_TABLE *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), (where))) + +#define sk_ASN1_ADB_TABLE_delete_ptr(sk, p) \ + ((ASN1_ADB_TABLE *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), \ + CHECKED_CAST(void *, ASN1_ADB_TABLE *, p))) + +#define sk_ASN1_ADB_TABLE_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), (out_index), \ + CHECKED_CAST(void *, ASN1_ADB_TABLE *, p)) + +#define sk_ASN1_ADB_TABLE_shift(sk) \ + ((ASN1_ADB_TABLE *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk))) + +#define sk_ASN1_ADB_TABLE_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), \ + CHECKED_CAST(void *, ASN1_ADB_TABLE *, p)) + +#define sk_ASN1_ADB_TABLE_pop(sk) \ + ((ASN1_ADB_TABLE *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk))) + +#define sk_ASN1_ADB_TABLE_dup(sk) \ + ((STACK_OF(ASN1_ADB_TABLE) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_ADB_TABLE) *, sk))) + +#define sk_ASN1_ADB_TABLE_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk)) + +#define sk_ASN1_ADB_TABLE_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_ADB_TABLE) *, sk)) + +#define sk_ASN1_ADB_TABLE_set_cmp_func(sk, comp) \ + ((int (*)(const ASN1_ADB_TABLE **a, const ASN1_ADB_TABLE **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const ASN1_ADB_TABLE **a, \ + const ASN1_ADB_TABLE **b), \ + comp))) + +#define sk_ASN1_ADB_TABLE_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(ASN1_ADB_TABLE) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_ADB_TABLE) *, sk), \ + CHECKED_CAST(void *(*)(void *), ASN1_ADB_TABLE *(*)(ASN1_ADB_TABLE *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_ADB_TABLE *), free_func))) + +/* ASN1_GENERALSTRING */ +#define sk_ASN1_GENERALSTRING_new(comp) \ + ((STACK_OF(ASN1_GENERALSTRING) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const ASN1_GENERALSTRING **a, const ASN1_GENERALSTRING **b), \ + comp))) + +#define sk_ASN1_GENERALSTRING_new_null() \ + ((STACK_OF(ASN1_GENERALSTRING) *)sk_new_null()) + +#define sk_ASN1_GENERALSTRING_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk)) + +#define sk_ASN1_GENERALSTRING_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk)); + +#define sk_ASN1_GENERALSTRING_value(sk, i) \ + ((ASN1_GENERALSTRING *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_GENERALSTRING) *, sk), (i))) + +#define sk_ASN1_GENERALSTRING_set(sk, i, p) \ + ((ASN1_GENERALSTRING *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), (i), \ + CHECKED_CAST(void *, ASN1_GENERALSTRING *, p))) + +#define sk_ASN1_GENERALSTRING_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk)) + +#define sk_ASN1_GENERALSTRING_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_GENERALSTRING *), \ + free_func)) + +#define sk_ASN1_GENERALSTRING_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), \ + CHECKED_CAST(void *, ASN1_GENERALSTRING *, p), (where)) + +#define sk_ASN1_GENERALSTRING_delete(sk, where) \ + ((ASN1_GENERALSTRING *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), (where))) + +#define sk_ASN1_GENERALSTRING_delete_ptr(sk, p) \ + ((ASN1_GENERALSTRING *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), \ + CHECKED_CAST(void *, ASN1_GENERALSTRING *, p))) + +#define sk_ASN1_GENERALSTRING_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), \ + (out_index), CHECKED_CAST(void *, ASN1_GENERALSTRING *, p)) + +#define sk_ASN1_GENERALSTRING_shift(sk) \ + ((ASN1_GENERALSTRING *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk))) + +#define sk_ASN1_GENERALSTRING_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), \ + CHECKED_CAST(void *, ASN1_GENERALSTRING *, p)) + +#define sk_ASN1_GENERALSTRING_pop(sk) \ + ((ASN1_GENERALSTRING *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk))) + +#define sk_ASN1_GENERALSTRING_dup(sk) \ + ((STACK_OF(ASN1_GENERALSTRING) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_GENERALSTRING) *, sk))) + +#define sk_ASN1_GENERALSTRING_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk)) + +#define sk_ASN1_GENERALSTRING_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_GENERALSTRING) *, sk)) + +#define sk_ASN1_GENERALSTRING_set_cmp_func(sk, comp) \ + ((int (*)(const ASN1_GENERALSTRING **a, const ASN1_GENERALSTRING **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const ASN1_GENERALSTRING **a, \ + const ASN1_GENERALSTRING **b), \ + comp))) + +#define sk_ASN1_GENERALSTRING_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(ASN1_GENERALSTRING) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_GENERALSTRING) *, sk), \ + CHECKED_CAST(void *(*)(void *), \ + ASN1_GENERALSTRING *(*)(ASN1_GENERALSTRING *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_GENERALSTRING *), \ + free_func))) + +/* ASN1_INTEGER */ +#define sk_ASN1_INTEGER_new(comp) \ + ((STACK_OF(ASN1_INTEGER) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const ASN1_INTEGER **a, const ASN1_INTEGER **b), \ + comp))) + +#define sk_ASN1_INTEGER_new_null() ((STACK_OF(ASN1_INTEGER) *)sk_new_null()) + +#define sk_ASN1_INTEGER_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk)) + +#define sk_ASN1_INTEGER_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk)); + +#define sk_ASN1_INTEGER_value(sk, i) \ + ((ASN1_INTEGER *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_INTEGER) *, sk), (i))) + +#define sk_ASN1_INTEGER_set(sk, i, p) \ + ((ASN1_INTEGER *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), (i), \ + CHECKED_CAST(void *, ASN1_INTEGER *, p))) + +#define sk_ASN1_INTEGER_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk)) + +#define sk_ASN1_INTEGER_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_INTEGER *), free_func)) + +#define sk_ASN1_INTEGER_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), \ + CHECKED_CAST(void *, ASN1_INTEGER *, p), (where)) + +#define sk_ASN1_INTEGER_delete(sk, where) \ + ((ASN1_INTEGER *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), (where))) + +#define sk_ASN1_INTEGER_delete_ptr(sk, p) \ + ((ASN1_INTEGER *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), \ + CHECKED_CAST(void *, ASN1_INTEGER *, p))) + +#define sk_ASN1_INTEGER_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), (out_index), \ + CHECKED_CAST(void *, ASN1_INTEGER *, p)) + +#define sk_ASN1_INTEGER_shift(sk) \ + ((ASN1_INTEGER *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk))) + +#define sk_ASN1_INTEGER_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), \ + CHECKED_CAST(void *, ASN1_INTEGER *, p)) + +#define sk_ASN1_INTEGER_pop(sk) \ + ((ASN1_INTEGER *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk))) + +#define sk_ASN1_INTEGER_dup(sk) \ + ((STACK_OF(ASN1_INTEGER) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_INTEGER) *, sk))) + +#define sk_ASN1_INTEGER_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk)) + +#define sk_ASN1_INTEGER_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_INTEGER) *, sk)) + +#define sk_ASN1_INTEGER_set_cmp_func(sk, comp) \ + ((int (*)(const ASN1_INTEGER **a, const ASN1_INTEGER **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const ASN1_INTEGER **a, const ASN1_INTEGER **b), \ + comp))) + +#define sk_ASN1_INTEGER_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(ASN1_INTEGER) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_INTEGER) *, sk), \ + CHECKED_CAST(void *(*)(void *), ASN1_INTEGER *(*)(ASN1_INTEGER *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_INTEGER *), free_func))) + +/* ASN1_OBJECT */ +#define sk_ASN1_OBJECT_new(comp) \ + ((STACK_OF(ASN1_OBJECT) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const ASN1_OBJECT **a, const ASN1_OBJECT **b), \ + comp))) + +#define sk_ASN1_OBJECT_new_null() ((STACK_OF(ASN1_OBJECT) *)sk_new_null()) + +#define sk_ASN1_OBJECT_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk)) + +#define sk_ASN1_OBJECT_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk)); + +#define sk_ASN1_OBJECT_value(sk, i) \ + ((ASN1_OBJECT *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_OBJECT) *, sk), (i))) + +#define sk_ASN1_OBJECT_set(sk, i, p) \ + ((ASN1_OBJECT *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), \ + (i), CHECKED_CAST(void *, ASN1_OBJECT *, p))) + +#define sk_ASN1_OBJECT_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk)) + +#define sk_ASN1_OBJECT_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_OBJECT *), free_func)) + +#define sk_ASN1_OBJECT_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), \ + CHECKED_CAST(void *, ASN1_OBJECT *, p), (where)) + +#define sk_ASN1_OBJECT_delete(sk, where) \ + ((ASN1_OBJECT *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), (where))) + +#define sk_ASN1_OBJECT_delete_ptr(sk, p) \ + ((ASN1_OBJECT *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), \ + CHECKED_CAST(void *, ASN1_OBJECT *, p))) + +#define sk_ASN1_OBJECT_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), (out_index), \ + CHECKED_CAST(void *, ASN1_OBJECT *, p)) + +#define sk_ASN1_OBJECT_shift(sk) \ + ((ASN1_OBJECT *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk))) + +#define sk_ASN1_OBJECT_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), \ + CHECKED_CAST(void *, ASN1_OBJECT *, p)) + +#define sk_ASN1_OBJECT_pop(sk) \ + ((ASN1_OBJECT *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk))) + +#define sk_ASN1_OBJECT_dup(sk) \ + ((STACK_OF(ASN1_OBJECT) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_OBJECT) *, sk))) + +#define sk_ASN1_OBJECT_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk)) + +#define sk_ASN1_OBJECT_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_OBJECT) *, sk)) + +#define sk_ASN1_OBJECT_set_cmp_func(sk, comp) \ + ((int (*)(const ASN1_OBJECT **a, const ASN1_OBJECT **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const ASN1_OBJECT **a, const ASN1_OBJECT **b), \ + comp))) + +#define sk_ASN1_OBJECT_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(ASN1_OBJECT) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_OBJECT) *, sk), \ + CHECKED_CAST(void *(*)(void *), ASN1_OBJECT *(*)(ASN1_OBJECT *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_OBJECT *), free_func))) + +/* ASN1_STRING_TABLE */ +#define sk_ASN1_STRING_TABLE_new(comp) \ + ((STACK_OF(ASN1_STRING_TABLE) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const ASN1_STRING_TABLE **a, const ASN1_STRING_TABLE **b), \ + comp))) + +#define sk_ASN1_STRING_TABLE_new_null() \ + ((STACK_OF(ASN1_STRING_TABLE) *)sk_new_null()) + +#define sk_ASN1_STRING_TABLE_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk)) + +#define sk_ASN1_STRING_TABLE_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk)); + +#define sk_ASN1_STRING_TABLE_value(sk, i) \ + ((ASN1_STRING_TABLE *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_STRING_TABLE) *, sk), (i))) + +#define sk_ASN1_STRING_TABLE_set(sk, i, p) \ + ((ASN1_STRING_TABLE *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), (i), \ + CHECKED_CAST(void *, ASN1_STRING_TABLE *, p))) + +#define sk_ASN1_STRING_TABLE_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk)) + +#define sk_ASN1_STRING_TABLE_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_STRING_TABLE *), \ + free_func)) + +#define sk_ASN1_STRING_TABLE_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), \ + CHECKED_CAST(void *, ASN1_STRING_TABLE *, p), (where)) + +#define sk_ASN1_STRING_TABLE_delete(sk, where) \ + ((ASN1_STRING_TABLE *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), (where))) + +#define sk_ASN1_STRING_TABLE_delete_ptr(sk, p) \ + ((ASN1_STRING_TABLE *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), \ + CHECKED_CAST(void *, ASN1_STRING_TABLE *, p))) + +#define sk_ASN1_STRING_TABLE_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), \ + (out_index), CHECKED_CAST(void *, ASN1_STRING_TABLE *, p)) + +#define sk_ASN1_STRING_TABLE_shift(sk) \ + ((ASN1_STRING_TABLE *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk))) + +#define sk_ASN1_STRING_TABLE_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), \ + CHECKED_CAST(void *, ASN1_STRING_TABLE *, p)) + +#define sk_ASN1_STRING_TABLE_pop(sk) \ + ((ASN1_STRING_TABLE *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk))) + +#define sk_ASN1_STRING_TABLE_dup(sk) \ + ((STACK_OF(ASN1_STRING_TABLE) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_STRING_TABLE) *, sk))) + +#define sk_ASN1_STRING_TABLE_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk)) + +#define sk_ASN1_STRING_TABLE_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_STRING_TABLE) *, sk)) + +#define sk_ASN1_STRING_TABLE_set_cmp_func(sk, comp) \ + ((int (*)(const ASN1_STRING_TABLE **a, const ASN1_STRING_TABLE **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const ASN1_STRING_TABLE **a, \ + const ASN1_STRING_TABLE **b), \ + comp))) + +#define sk_ASN1_STRING_TABLE_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(ASN1_STRING_TABLE) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_STRING_TABLE) *, sk), \ + CHECKED_CAST(void *(*)(void *), \ + ASN1_STRING_TABLE *(*)(ASN1_STRING_TABLE *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_STRING_TABLE *), \ + free_func))) + +/* ASN1_TYPE */ +#define sk_ASN1_TYPE_new(comp) \ + ((STACK_OF(ASN1_TYPE) *)sk_new( \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const ASN1_TYPE **a, const ASN1_TYPE **b), comp))) + +#define sk_ASN1_TYPE_new_null() ((STACK_OF(ASN1_TYPE) *)sk_new_null()) + +#define sk_ASN1_TYPE_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk)) + +#define sk_ASN1_TYPE_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk)); + +#define sk_ASN1_TYPE_value(sk, i) \ + ((ASN1_TYPE *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_TYPE) *, sk), (i))) + +#define sk_ASN1_TYPE_set(sk, i, p) \ + ((ASN1_TYPE *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), (i), \ + CHECKED_CAST(void *, ASN1_TYPE *, p))) + +#define sk_ASN1_TYPE_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk)) + +#define sk_ASN1_TYPE_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_TYPE *), free_func)) + +#define sk_ASN1_TYPE_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), \ + CHECKED_CAST(void *, ASN1_TYPE *, p), (where)) + +#define sk_ASN1_TYPE_delete(sk, where) \ + ((ASN1_TYPE *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), \ + (where))) + +#define sk_ASN1_TYPE_delete_ptr(sk, p) \ + ((ASN1_TYPE *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), \ + CHECKED_CAST(void *, ASN1_TYPE *, p))) + +#define sk_ASN1_TYPE_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), (out_index), \ + CHECKED_CAST(void *, ASN1_TYPE *, p)) + +#define sk_ASN1_TYPE_shift(sk) \ + ((ASN1_TYPE *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk))) + +#define sk_ASN1_TYPE_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), \ + CHECKED_CAST(void *, ASN1_TYPE *, p)) + +#define sk_ASN1_TYPE_pop(sk) \ + ((ASN1_TYPE *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk))) + +#define sk_ASN1_TYPE_dup(sk) \ + ((STACK_OF(ASN1_TYPE) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_TYPE) *, sk))) + +#define sk_ASN1_TYPE_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk)) + +#define sk_ASN1_TYPE_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_TYPE) *, sk)) + +#define sk_ASN1_TYPE_set_cmp_func(sk, comp) \ + ((int (*)(const ASN1_TYPE **a, const ASN1_TYPE **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const ASN1_TYPE **a, const ASN1_TYPE **b), comp))) + +#define sk_ASN1_TYPE_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(ASN1_TYPE) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_TYPE) *, sk), \ + CHECKED_CAST(void *(*)(void *), ASN1_TYPE *(*)(ASN1_TYPE *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_TYPE *), free_func))) + +/* ASN1_VALUE */ +#define sk_ASN1_VALUE_new(comp) \ + ((STACK_OF(ASN1_VALUE) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const ASN1_VALUE **a, const ASN1_VALUE **b), \ + comp))) + +#define sk_ASN1_VALUE_new_null() ((STACK_OF(ASN1_VALUE) *)sk_new_null()) + +#define sk_ASN1_VALUE_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk)) + +#define sk_ASN1_VALUE_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk)); + +#define sk_ASN1_VALUE_value(sk, i) \ + ((ASN1_VALUE *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_VALUE) *, sk), (i))) + +#define sk_ASN1_VALUE_set(sk, i, p) \ + ((ASN1_VALUE *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), \ + (i), CHECKED_CAST(void *, ASN1_VALUE *, p))) + +#define sk_ASN1_VALUE_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk)) + +#define sk_ASN1_VALUE_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_VALUE *), free_func)) + +#define sk_ASN1_VALUE_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), \ + CHECKED_CAST(void *, ASN1_VALUE *, p), (where)) + +#define sk_ASN1_VALUE_delete(sk, where) \ + ((ASN1_VALUE *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), \ + (where))) + +#define sk_ASN1_VALUE_delete_ptr(sk, p) \ + ((ASN1_VALUE *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), \ + CHECKED_CAST(void *, ASN1_VALUE *, p))) + +#define sk_ASN1_VALUE_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), (out_index), \ + CHECKED_CAST(void *, ASN1_VALUE *, p)) + +#define sk_ASN1_VALUE_shift(sk) \ + ((ASN1_VALUE *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk))) + +#define sk_ASN1_VALUE_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), \ + CHECKED_CAST(void *, ASN1_VALUE *, p)) + +#define sk_ASN1_VALUE_pop(sk) \ + ((ASN1_VALUE *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk))) + +#define sk_ASN1_VALUE_dup(sk) \ + ((STACK_OF(ASN1_VALUE) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_VALUE) *, sk))) + +#define sk_ASN1_VALUE_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk)) + +#define sk_ASN1_VALUE_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_VALUE) *, sk)) + +#define sk_ASN1_VALUE_set_cmp_func(sk, comp) \ + ((int (*)(const ASN1_VALUE **a, const ASN1_VALUE **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const ASN1_VALUE **a, const ASN1_VALUE **b), \ + comp))) + +#define sk_ASN1_VALUE_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(ASN1_VALUE) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_VALUE) *, sk), \ + CHECKED_CAST(void *(*)(void *), ASN1_VALUE *(*)(ASN1_VALUE *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_VALUE *), free_func))) + +/* BIO */ +#define sk_BIO_new(comp) \ + ((STACK_OF(BIO) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const BIO **a, const BIO **b), comp))) + +#define sk_BIO_new_null() ((STACK_OF(BIO) *)sk_new_null()) + +#define sk_BIO_num(sk) sk_num(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk)) + +#define sk_BIO_zero(sk) sk_zero(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk)); + +#define sk_BIO_value(sk, i) \ + ((BIO *)sk_value(CHECKED_CAST(_STACK *, const STACK_OF(BIO) *, sk), (i))) + +#define sk_BIO_set(sk, i, p) \ + ((BIO *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), (i), \ + CHECKED_CAST(void *, BIO *, p))) + +#define sk_BIO_free(sk) sk_free(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk)) + +#define sk_BIO_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(BIO *), free_func)) + +#define sk_BIO_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), \ + CHECKED_CAST(void *, BIO *, p), (where)) + +#define sk_BIO_delete(sk, where) \ + ((BIO *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), (where))) + +#define sk_BIO_delete_ptr(sk, p) \ + ((BIO *)sk_delete_ptr(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), \ + CHECKED_CAST(void *, BIO *, p))) + +#define sk_BIO_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), (out_index), \ + CHECKED_CAST(void *, BIO *, p)) + +#define sk_BIO_shift(sk) \ + ((BIO *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk))) + +#define sk_BIO_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), \ + CHECKED_CAST(void *, BIO *, p)) + +#define sk_BIO_pop(sk) \ + ((BIO *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk))) + +#define sk_BIO_dup(sk) \ + ((STACK_OF(BIO) *)sk_dup(CHECKED_CAST(_STACK *, const STACK_OF(BIO) *, sk))) + +#define sk_BIO_sort(sk) sk_sort(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk)) + +#define sk_BIO_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(BIO) *, sk)) + +#define sk_BIO_set_cmp_func(sk, comp) \ + ((int (*)(const BIO **a, const BIO **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const BIO **a, const BIO **b), \ + comp))) + +#define sk_BIO_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(BIO) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(BIO) *, sk), \ + CHECKED_CAST(void *(*)(void *), BIO *(*)(BIO *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(BIO *), free_func))) + +/* BY_DIR_ENTRY */ +#define sk_BY_DIR_ENTRY_new(comp) \ + ((STACK_OF(BY_DIR_ENTRY) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const BY_DIR_ENTRY **a, const BY_DIR_ENTRY **b), \ + comp))) + +#define sk_BY_DIR_ENTRY_new_null() ((STACK_OF(BY_DIR_ENTRY) *)sk_new_null()) + +#define sk_BY_DIR_ENTRY_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk)) + +#define sk_BY_DIR_ENTRY_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk)); + +#define sk_BY_DIR_ENTRY_value(sk, i) \ + ((BY_DIR_ENTRY *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(BY_DIR_ENTRY) *, sk), (i))) + +#define sk_BY_DIR_ENTRY_set(sk, i, p) \ + ((BY_DIR_ENTRY *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), (i), \ + CHECKED_CAST(void *, BY_DIR_ENTRY *, p))) + +#define sk_BY_DIR_ENTRY_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk)) + +#define sk_BY_DIR_ENTRY_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(BY_DIR_ENTRY *), free_func)) + +#define sk_BY_DIR_ENTRY_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), \ + CHECKED_CAST(void *, BY_DIR_ENTRY *, p), (where)) + +#define sk_BY_DIR_ENTRY_delete(sk, where) \ + ((BY_DIR_ENTRY *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), (where))) + +#define sk_BY_DIR_ENTRY_delete_ptr(sk, p) \ + ((BY_DIR_ENTRY *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), \ + CHECKED_CAST(void *, BY_DIR_ENTRY *, p))) + +#define sk_BY_DIR_ENTRY_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), (out_index), \ + CHECKED_CAST(void *, BY_DIR_ENTRY *, p)) + +#define sk_BY_DIR_ENTRY_shift(sk) \ + ((BY_DIR_ENTRY *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk))) + +#define sk_BY_DIR_ENTRY_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), \ + CHECKED_CAST(void *, BY_DIR_ENTRY *, p)) + +#define sk_BY_DIR_ENTRY_pop(sk) \ + ((BY_DIR_ENTRY *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk))) + +#define sk_BY_DIR_ENTRY_dup(sk) \ + ((STACK_OF(BY_DIR_ENTRY) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(BY_DIR_ENTRY) *, sk))) + +#define sk_BY_DIR_ENTRY_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk)) + +#define sk_BY_DIR_ENTRY_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(BY_DIR_ENTRY) *, sk)) + +#define sk_BY_DIR_ENTRY_set_cmp_func(sk, comp) \ + ((int (*)(const BY_DIR_ENTRY **a, const BY_DIR_ENTRY **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const BY_DIR_ENTRY **a, const BY_DIR_ENTRY **b), \ + comp))) + +#define sk_BY_DIR_ENTRY_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(BY_DIR_ENTRY) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(BY_DIR_ENTRY) *, sk), \ + CHECKED_CAST(void *(*)(void *), BY_DIR_ENTRY *(*)(BY_DIR_ENTRY *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(BY_DIR_ENTRY *), free_func))) + +/* BY_DIR_HASH */ +#define sk_BY_DIR_HASH_new(comp) \ + ((STACK_OF(BY_DIR_HASH) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const BY_DIR_HASH **a, const BY_DIR_HASH **b), \ + comp))) + +#define sk_BY_DIR_HASH_new_null() ((STACK_OF(BY_DIR_HASH) *)sk_new_null()) + +#define sk_BY_DIR_HASH_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk)) + +#define sk_BY_DIR_HASH_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk)); + +#define sk_BY_DIR_HASH_value(sk, i) \ + ((BY_DIR_HASH *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(BY_DIR_HASH) *, sk), (i))) + +#define sk_BY_DIR_HASH_set(sk, i, p) \ + ((BY_DIR_HASH *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), \ + (i), CHECKED_CAST(void *, BY_DIR_HASH *, p))) + +#define sk_BY_DIR_HASH_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk)) + +#define sk_BY_DIR_HASH_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(BY_DIR_HASH *), free_func)) + +#define sk_BY_DIR_HASH_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), \ + CHECKED_CAST(void *, BY_DIR_HASH *, p), (where)) + +#define sk_BY_DIR_HASH_delete(sk, where) \ + ((BY_DIR_HASH *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), (where))) + +#define sk_BY_DIR_HASH_delete_ptr(sk, p) \ + ((BY_DIR_HASH *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), \ + CHECKED_CAST(void *, BY_DIR_HASH *, p))) + +#define sk_BY_DIR_HASH_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), (out_index), \ + CHECKED_CAST(void *, BY_DIR_HASH *, p)) + +#define sk_BY_DIR_HASH_shift(sk) \ + ((BY_DIR_HASH *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk))) + +#define sk_BY_DIR_HASH_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), \ + CHECKED_CAST(void *, BY_DIR_HASH *, p)) + +#define sk_BY_DIR_HASH_pop(sk) \ + ((BY_DIR_HASH *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk))) + +#define sk_BY_DIR_HASH_dup(sk) \ + ((STACK_OF(BY_DIR_HASH) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(BY_DIR_HASH) *, sk))) + +#define sk_BY_DIR_HASH_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk)) + +#define sk_BY_DIR_HASH_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(BY_DIR_HASH) *, sk)) + +#define sk_BY_DIR_HASH_set_cmp_func(sk, comp) \ + ((int (*)(const BY_DIR_HASH **a, const BY_DIR_HASH **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const BY_DIR_HASH **a, const BY_DIR_HASH **b), \ + comp))) + +#define sk_BY_DIR_HASH_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(BY_DIR_HASH) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(BY_DIR_HASH) *, sk), \ + CHECKED_CAST(void *(*)(void *), BY_DIR_HASH *(*)(BY_DIR_HASH *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(BY_DIR_HASH *), free_func))) + +/* CONF_VALUE */ +#define sk_CONF_VALUE_new(comp) \ + ((STACK_OF(CONF_VALUE) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const CONF_VALUE **a, const CONF_VALUE **b), \ + comp))) + +#define sk_CONF_VALUE_new_null() ((STACK_OF(CONF_VALUE) *)sk_new_null()) + +#define sk_CONF_VALUE_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk)) + +#define sk_CONF_VALUE_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk)); + +#define sk_CONF_VALUE_value(sk, i) \ + ((CONF_VALUE *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(CONF_VALUE) *, sk), (i))) + +#define sk_CONF_VALUE_set(sk, i, p) \ + ((CONF_VALUE *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), \ + (i), CHECKED_CAST(void *, CONF_VALUE *, p))) + +#define sk_CONF_VALUE_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk)) + +#define sk_CONF_VALUE_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(CONF_VALUE *), free_func)) + +#define sk_CONF_VALUE_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), \ + CHECKED_CAST(void *, CONF_VALUE *, p), (where)) + +#define sk_CONF_VALUE_delete(sk, where) \ + ((CONF_VALUE *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), \ + (where))) + +#define sk_CONF_VALUE_delete_ptr(sk, p) \ + ((CONF_VALUE *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), \ + CHECKED_CAST(void *, CONF_VALUE *, p))) + +#define sk_CONF_VALUE_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), (out_index), \ + CHECKED_CAST(void *, CONF_VALUE *, p)) + +#define sk_CONF_VALUE_shift(sk) \ + ((CONF_VALUE *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk))) + +#define sk_CONF_VALUE_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), \ + CHECKED_CAST(void *, CONF_VALUE *, p)) + +#define sk_CONF_VALUE_pop(sk) \ + ((CONF_VALUE *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk))) + +#define sk_CONF_VALUE_dup(sk) \ + ((STACK_OF(CONF_VALUE) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(CONF_VALUE) *, sk))) + +#define sk_CONF_VALUE_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk)) + +#define sk_CONF_VALUE_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(CONF_VALUE) *, sk)) + +#define sk_CONF_VALUE_set_cmp_func(sk, comp) \ + ((int (*)(const CONF_VALUE **a, const CONF_VALUE **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const CONF_VALUE **a, const CONF_VALUE **b), \ + comp))) + +#define sk_CONF_VALUE_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(CONF_VALUE) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(CONF_VALUE) *, sk), \ + CHECKED_CAST(void *(*)(void *), CONF_VALUE *(*)(CONF_VALUE *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(CONF_VALUE *), free_func))) + +/* CRYPTO_EX_DATA_FUNCS */ +#define sk_CRYPTO_EX_DATA_FUNCS_new(comp) \ + ((STACK_OF(CRYPTO_EX_DATA_FUNCS) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const CRYPTO_EX_DATA_FUNCS **a, const CRYPTO_EX_DATA_FUNCS **b), \ + comp))) + +#define sk_CRYPTO_EX_DATA_FUNCS_new_null() \ + ((STACK_OF(CRYPTO_EX_DATA_FUNCS) *)sk_new_null()) + +#define sk_CRYPTO_EX_DATA_FUNCS_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk)) + +#define sk_CRYPTO_EX_DATA_FUNCS_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk)); + +#define sk_CRYPTO_EX_DATA_FUNCS_value(sk, i) \ + ((CRYPTO_EX_DATA_FUNCS *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), \ + (i))) + +#define sk_CRYPTO_EX_DATA_FUNCS_set(sk, i, p) \ + ((CRYPTO_EX_DATA_FUNCS *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), (i), \ + CHECKED_CAST(void *, CRYPTO_EX_DATA_FUNCS *, p))) + +#define sk_CRYPTO_EX_DATA_FUNCS_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk)) + +#define sk_CRYPTO_EX_DATA_FUNCS_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(CRYPTO_EX_DATA_FUNCS *), \ + free_func)) + +#define sk_CRYPTO_EX_DATA_FUNCS_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), \ + CHECKED_CAST(void *, CRYPTO_EX_DATA_FUNCS *, p), (where)) + +#define sk_CRYPTO_EX_DATA_FUNCS_delete(sk, where) \ + ((CRYPTO_EX_DATA_FUNCS *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), (where))) + +#define sk_CRYPTO_EX_DATA_FUNCS_delete_ptr(sk, p) \ + ((CRYPTO_EX_DATA_FUNCS *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), \ + CHECKED_CAST(void *, CRYPTO_EX_DATA_FUNCS *, p))) + +#define sk_CRYPTO_EX_DATA_FUNCS_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), \ + (out_index), CHECKED_CAST(void *, CRYPTO_EX_DATA_FUNCS *, p)) + +#define sk_CRYPTO_EX_DATA_FUNCS_shift(sk) \ + ((CRYPTO_EX_DATA_FUNCS *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk))) + +#define sk_CRYPTO_EX_DATA_FUNCS_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), \ + CHECKED_CAST(void *, CRYPTO_EX_DATA_FUNCS *, p)) + +#define sk_CRYPTO_EX_DATA_FUNCS_pop(sk) \ + ((CRYPTO_EX_DATA_FUNCS *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk))) + +#define sk_CRYPTO_EX_DATA_FUNCS_dup(sk) \ + ((STACK_OF(CRYPTO_EX_DATA_FUNCS) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk))) + +#define sk_CRYPTO_EX_DATA_FUNCS_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk)) + +#define sk_CRYPTO_EX_DATA_FUNCS_is_sorted(sk) \ + sk_is_sorted( \ + CHECKED_CAST(_STACK *, const STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk)) + +#define sk_CRYPTO_EX_DATA_FUNCS_set_cmp_func(sk, comp) \ + ((int (*)(const CRYPTO_EX_DATA_FUNCS **a, const CRYPTO_EX_DATA_FUNCS **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const CRYPTO_EX_DATA_FUNCS **a, \ + const CRYPTO_EX_DATA_FUNCS **b), \ + comp))) + +#define sk_CRYPTO_EX_DATA_FUNCS_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(CRYPTO_EX_DATA_FUNCS) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(CRYPTO_EX_DATA_FUNCS) *, \ + sk), \ + CHECKED_CAST(void *(*)(void *), \ + CRYPTO_EX_DATA_FUNCS *(*)(CRYPTO_EX_DATA_FUNCS *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(CRYPTO_EX_DATA_FUNCS *), \ + free_func))) + +/* DIST_POINT */ +#define sk_DIST_POINT_new(comp) \ + ((STACK_OF(DIST_POINT) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const DIST_POINT **a, const DIST_POINT **b), \ + comp))) + +#define sk_DIST_POINT_new_null() ((STACK_OF(DIST_POINT) *)sk_new_null()) + +#define sk_DIST_POINT_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk)) + +#define sk_DIST_POINT_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk)); + +#define sk_DIST_POINT_value(sk, i) \ + ((DIST_POINT *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(DIST_POINT) *, sk), (i))) + +#define sk_DIST_POINT_set(sk, i, p) \ + ((DIST_POINT *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), \ + (i), CHECKED_CAST(void *, DIST_POINT *, p))) + +#define sk_DIST_POINT_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk)) + +#define sk_DIST_POINT_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(DIST_POINT *), free_func)) + +#define sk_DIST_POINT_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), \ + CHECKED_CAST(void *, DIST_POINT *, p), (where)) + +#define sk_DIST_POINT_delete(sk, where) \ + ((DIST_POINT *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), \ + (where))) + +#define sk_DIST_POINT_delete_ptr(sk, p) \ + ((DIST_POINT *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), \ + CHECKED_CAST(void *, DIST_POINT *, p))) + +#define sk_DIST_POINT_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), (out_index), \ + CHECKED_CAST(void *, DIST_POINT *, p)) + +#define sk_DIST_POINT_shift(sk) \ + ((DIST_POINT *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk))) + +#define sk_DIST_POINT_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), \ + CHECKED_CAST(void *, DIST_POINT *, p)) + +#define sk_DIST_POINT_pop(sk) \ + ((DIST_POINT *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk))) + +#define sk_DIST_POINT_dup(sk) \ + ((STACK_OF(DIST_POINT) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(DIST_POINT) *, sk))) + +#define sk_DIST_POINT_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk)) + +#define sk_DIST_POINT_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(DIST_POINT) *, sk)) + +#define sk_DIST_POINT_set_cmp_func(sk, comp) \ + ((int (*)(const DIST_POINT **a, const DIST_POINT **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const DIST_POINT **a, const DIST_POINT **b), \ + comp))) + +#define sk_DIST_POINT_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(DIST_POINT) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(DIST_POINT) *, sk), \ + CHECKED_CAST(void *(*)(void *), DIST_POINT *(*)(DIST_POINT *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(DIST_POINT *), free_func))) + +/* GENERAL_NAME */ +#define sk_GENERAL_NAME_new(comp) \ + ((STACK_OF(GENERAL_NAME) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const GENERAL_NAME **a, const GENERAL_NAME **b), \ + comp))) + +#define sk_GENERAL_NAME_new_null() ((STACK_OF(GENERAL_NAME) *)sk_new_null()) + +#define sk_GENERAL_NAME_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk)) + +#define sk_GENERAL_NAME_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk)); + +#define sk_GENERAL_NAME_value(sk, i) \ + ((GENERAL_NAME *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_NAME) *, sk), (i))) + +#define sk_GENERAL_NAME_set(sk, i, p) \ + ((GENERAL_NAME *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), (i), \ + CHECKED_CAST(void *, GENERAL_NAME *, p))) + +#define sk_GENERAL_NAME_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk)) + +#define sk_GENERAL_NAME_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(GENERAL_NAME *), free_func)) + +#define sk_GENERAL_NAME_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), \ + CHECKED_CAST(void *, GENERAL_NAME *, p), (where)) + +#define sk_GENERAL_NAME_delete(sk, where) \ + ((GENERAL_NAME *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), (where))) + +#define sk_GENERAL_NAME_delete_ptr(sk, p) \ + ((GENERAL_NAME *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), \ + CHECKED_CAST(void *, GENERAL_NAME *, p))) + +#define sk_GENERAL_NAME_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), (out_index), \ + CHECKED_CAST(void *, GENERAL_NAME *, p)) + +#define sk_GENERAL_NAME_shift(sk) \ + ((GENERAL_NAME *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk))) + +#define sk_GENERAL_NAME_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), \ + CHECKED_CAST(void *, GENERAL_NAME *, p)) + +#define sk_GENERAL_NAME_pop(sk) \ + ((GENERAL_NAME *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk))) + +#define sk_GENERAL_NAME_dup(sk) \ + ((STACK_OF(GENERAL_NAME) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_NAME) *, sk))) + +#define sk_GENERAL_NAME_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk)) + +#define sk_GENERAL_NAME_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_NAME) *, sk)) + +#define sk_GENERAL_NAME_set_cmp_func(sk, comp) \ + ((int (*)(const GENERAL_NAME **a, const GENERAL_NAME **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const GENERAL_NAME **a, const GENERAL_NAME **b), \ + comp))) + +#define sk_GENERAL_NAME_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(GENERAL_NAME) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(GENERAL_NAME) *, sk), \ + CHECKED_CAST(void *(*)(void *), GENERAL_NAME *(*)(GENERAL_NAME *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(GENERAL_NAME *), free_func))) + +/* GENERAL_NAMES */ +#define sk_GENERAL_NAMES_new(comp) \ + ((STACK_OF(GENERAL_NAMES) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const GENERAL_NAMES **a, const GENERAL_NAMES **b), comp))) + +#define sk_GENERAL_NAMES_new_null() ((STACK_OF(GENERAL_NAMES) *)sk_new_null()) + +#define sk_GENERAL_NAMES_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk)) + +#define sk_GENERAL_NAMES_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk)); + +#define sk_GENERAL_NAMES_value(sk, i) \ + ((GENERAL_NAMES *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_NAMES) *, sk), (i))) + +#define sk_GENERAL_NAMES_set(sk, i, p) \ + ((GENERAL_NAMES *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), (i), \ + CHECKED_CAST(void *, GENERAL_NAMES *, p))) + +#define sk_GENERAL_NAMES_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk)) + +#define sk_GENERAL_NAMES_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(GENERAL_NAMES *), free_func)) + +#define sk_GENERAL_NAMES_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), \ + CHECKED_CAST(void *, GENERAL_NAMES *, p), (where)) + +#define sk_GENERAL_NAMES_delete(sk, where) \ + ((GENERAL_NAMES *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), (where))) + +#define sk_GENERAL_NAMES_delete_ptr(sk, p) \ + ((GENERAL_NAMES *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), \ + CHECKED_CAST(void *, GENERAL_NAMES *, p))) + +#define sk_GENERAL_NAMES_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), (out_index), \ + CHECKED_CAST(void *, GENERAL_NAMES *, p)) + +#define sk_GENERAL_NAMES_shift(sk) \ + ((GENERAL_NAMES *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk))) + +#define sk_GENERAL_NAMES_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), \ + CHECKED_CAST(void *, GENERAL_NAMES *, p)) + +#define sk_GENERAL_NAMES_pop(sk) \ + ((GENERAL_NAMES *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk))) + +#define sk_GENERAL_NAMES_dup(sk) \ + ((STACK_OF(GENERAL_NAMES) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_NAMES) *, sk))) + +#define sk_GENERAL_NAMES_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk)) + +#define sk_GENERAL_NAMES_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_NAMES) *, sk)) + +#define sk_GENERAL_NAMES_set_cmp_func(sk, comp) \ + ((int (*)(const GENERAL_NAMES **a, const GENERAL_NAMES **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const GENERAL_NAMES **a, const GENERAL_NAMES **b), \ + comp))) + +#define sk_GENERAL_NAMES_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(GENERAL_NAMES) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(GENERAL_NAMES) *, sk), \ + CHECKED_CAST(void *(*)(void *), GENERAL_NAMES *(*)(GENERAL_NAMES *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(GENERAL_NAMES *), free_func))) + +/* GENERAL_SUBTREE */ +#define sk_GENERAL_SUBTREE_new(comp) \ + ((STACK_OF(GENERAL_SUBTREE) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const GENERAL_SUBTREE **a, const GENERAL_SUBTREE **b), comp))) + +#define sk_GENERAL_SUBTREE_new_null() \ + ((STACK_OF(GENERAL_SUBTREE) *)sk_new_null()) + +#define sk_GENERAL_SUBTREE_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk)) + +#define sk_GENERAL_SUBTREE_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk)); + +#define sk_GENERAL_SUBTREE_value(sk, i) \ + ((GENERAL_SUBTREE *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_SUBTREE) *, sk), (i))) + +#define sk_GENERAL_SUBTREE_set(sk, i, p) \ + ((GENERAL_SUBTREE *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), (i), \ + CHECKED_CAST(void *, GENERAL_SUBTREE *, p))) + +#define sk_GENERAL_SUBTREE_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk)) + +#define sk_GENERAL_SUBTREE_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(GENERAL_SUBTREE *), free_func)) + +#define sk_GENERAL_SUBTREE_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), \ + CHECKED_CAST(void *, GENERAL_SUBTREE *, p), (where)) + +#define sk_GENERAL_SUBTREE_delete(sk, where) \ + ((GENERAL_SUBTREE *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), (where))) + +#define sk_GENERAL_SUBTREE_delete_ptr(sk, p) \ + ((GENERAL_SUBTREE *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), \ + CHECKED_CAST(void *, GENERAL_SUBTREE *, p))) + +#define sk_GENERAL_SUBTREE_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), \ + (out_index), CHECKED_CAST(void *, GENERAL_SUBTREE *, p)) + +#define sk_GENERAL_SUBTREE_shift(sk) \ + ((GENERAL_SUBTREE *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk))) + +#define sk_GENERAL_SUBTREE_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), \ + CHECKED_CAST(void *, GENERAL_SUBTREE *, p)) + +#define sk_GENERAL_SUBTREE_pop(sk) \ + ((GENERAL_SUBTREE *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk))) + +#define sk_GENERAL_SUBTREE_dup(sk) \ + ((STACK_OF(GENERAL_SUBTREE) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_SUBTREE) *, sk))) + +#define sk_GENERAL_SUBTREE_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk)) + +#define sk_GENERAL_SUBTREE_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_SUBTREE) *, sk)) + +#define sk_GENERAL_SUBTREE_set_cmp_func(sk, comp) \ + ((int (*)(const GENERAL_SUBTREE **a, const GENERAL_SUBTREE **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const GENERAL_SUBTREE **a, \ + const GENERAL_SUBTREE **b), \ + comp))) + +#define sk_GENERAL_SUBTREE_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(GENERAL_SUBTREE) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(GENERAL_SUBTREE) *, sk), \ + CHECKED_CAST(void *(*)(void *), GENERAL_SUBTREE *(*)(GENERAL_SUBTREE *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(GENERAL_SUBTREE *), free_func))) + +/* MIME_HEADER */ +#define sk_MIME_HEADER_new(comp) \ + ((STACK_OF(MIME_HEADER) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const MIME_HEADER **a, const MIME_HEADER **b), \ + comp))) + +#define sk_MIME_HEADER_new_null() ((STACK_OF(MIME_HEADER) *)sk_new_null()) + +#define sk_MIME_HEADER_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk)) + +#define sk_MIME_HEADER_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk)); + +#define sk_MIME_HEADER_value(sk, i) \ + ((MIME_HEADER *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(MIME_HEADER) *, sk), (i))) + +#define sk_MIME_HEADER_set(sk, i, p) \ + ((MIME_HEADER *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk), \ + (i), CHECKED_CAST(void *, MIME_HEADER *, p))) + +#define sk_MIME_HEADER_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk)) + +#define sk_MIME_HEADER_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(MIME_HEADER *), free_func)) + +#define sk_MIME_HEADER_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk), \ + CHECKED_CAST(void *, MIME_HEADER *, p), (where)) + +#define sk_MIME_HEADER_delete(sk, where) \ + ((MIME_HEADER *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk), (where))) + +#define sk_MIME_HEADER_delete_ptr(sk, p) \ + ((MIME_HEADER *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk), \ + CHECKED_CAST(void *, MIME_HEADER *, p))) + +#define sk_MIME_HEADER_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk), (out_index), \ + CHECKED_CAST(void *, MIME_HEADER *, p)) + +#define sk_MIME_HEADER_shift(sk) \ + ((MIME_HEADER *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk))) + +#define sk_MIME_HEADER_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk), \ + CHECKED_CAST(void *, MIME_HEADER *, p)) + +#define sk_MIME_HEADER_pop(sk) \ + ((MIME_HEADER *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk))) + +#define sk_MIME_HEADER_dup(sk) \ + ((STACK_OF(MIME_HEADER) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(MIME_HEADER) *, sk))) + +#define sk_MIME_HEADER_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk)) + +#define sk_MIME_HEADER_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(MIME_HEADER) *, sk)) + +#define sk_MIME_HEADER_set_cmp_func(sk, comp) \ + ((int (*)(const MIME_HEADER **a, const MIME_HEADER **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const MIME_HEADER **a, const MIME_HEADER **b), \ + comp))) + +#define sk_MIME_HEADER_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(MIME_HEADER) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(MIME_HEADER) *, sk), \ + CHECKED_CAST(void *(*)(void *), MIME_HEADER *(*)(MIME_HEADER *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(MIME_HEADER *), free_func))) + +/* PKCS7_RECIP_INFO */ +#define sk_PKCS7_RECIP_INFO_new(comp) \ + ((STACK_OF(PKCS7_RECIP_INFO) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const PKCS7_RECIP_INFO **a, const PKCS7_RECIP_INFO **b), comp))) + +#define sk_PKCS7_RECIP_INFO_new_null() \ + ((STACK_OF(PKCS7_RECIP_INFO) *)sk_new_null()) + +#define sk_PKCS7_RECIP_INFO_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk)) + +#define sk_PKCS7_RECIP_INFO_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk)); + +#define sk_PKCS7_RECIP_INFO_value(sk, i) \ + ((PKCS7_RECIP_INFO *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(PKCS7_RECIP_INFO) *, sk), (i))) + +#define sk_PKCS7_RECIP_INFO_set(sk, i, p) \ + ((PKCS7_RECIP_INFO *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), (i), \ + CHECKED_CAST(void *, PKCS7_RECIP_INFO *, p))) + +#define sk_PKCS7_RECIP_INFO_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk)) + +#define sk_PKCS7_RECIP_INFO_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(PKCS7_RECIP_INFO *), free_func)) + +#define sk_PKCS7_RECIP_INFO_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), \ + CHECKED_CAST(void *, PKCS7_RECIP_INFO *, p), (where)) + +#define sk_PKCS7_RECIP_INFO_delete(sk, where) \ + ((PKCS7_RECIP_INFO *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), (where))) + +#define sk_PKCS7_RECIP_INFO_delete_ptr(sk, p) \ + ((PKCS7_RECIP_INFO *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), \ + CHECKED_CAST(void *, PKCS7_RECIP_INFO *, p))) + +#define sk_PKCS7_RECIP_INFO_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), \ + (out_index), CHECKED_CAST(void *, PKCS7_RECIP_INFO *, p)) + +#define sk_PKCS7_RECIP_INFO_shift(sk) \ + ((PKCS7_RECIP_INFO *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk))) + +#define sk_PKCS7_RECIP_INFO_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), \ + CHECKED_CAST(void *, PKCS7_RECIP_INFO *, p)) + +#define sk_PKCS7_RECIP_INFO_pop(sk) \ + ((PKCS7_RECIP_INFO *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk))) + +#define sk_PKCS7_RECIP_INFO_dup(sk) \ + ((STACK_OF(PKCS7_RECIP_INFO) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(PKCS7_RECIP_INFO) *, sk))) + +#define sk_PKCS7_RECIP_INFO_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk)) + +#define sk_PKCS7_RECIP_INFO_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(PKCS7_RECIP_INFO) *, sk)) + +#define sk_PKCS7_RECIP_INFO_set_cmp_func(sk, comp) \ + ((int (*)(const PKCS7_RECIP_INFO **a, const PKCS7_RECIP_INFO **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const PKCS7_RECIP_INFO **a, \ + const PKCS7_RECIP_INFO **b), \ + comp))) + +#define sk_PKCS7_RECIP_INFO_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(PKCS7_RECIP_INFO) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(PKCS7_RECIP_INFO) *, sk), \ + CHECKED_CAST(void *(*)(void *), \ + PKCS7_RECIP_INFO *(*)(PKCS7_RECIP_INFO *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(PKCS7_RECIP_INFO *), \ + free_func))) + +/* PKCS7_SIGNER_INFO */ +#define sk_PKCS7_SIGNER_INFO_new(comp) \ + ((STACK_OF(PKCS7_SIGNER_INFO) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const PKCS7_SIGNER_INFO **a, const PKCS7_SIGNER_INFO **b), \ + comp))) + +#define sk_PKCS7_SIGNER_INFO_new_null() \ + ((STACK_OF(PKCS7_SIGNER_INFO) *)sk_new_null()) + +#define sk_PKCS7_SIGNER_INFO_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk)) + +#define sk_PKCS7_SIGNER_INFO_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk)); + +#define sk_PKCS7_SIGNER_INFO_value(sk, i) \ + ((PKCS7_SIGNER_INFO *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(PKCS7_SIGNER_INFO) *, sk), (i))) + +#define sk_PKCS7_SIGNER_INFO_set(sk, i, p) \ + ((PKCS7_SIGNER_INFO *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk), (i), \ + CHECKED_CAST(void *, PKCS7_SIGNER_INFO *, p))) + +#define sk_PKCS7_SIGNER_INFO_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk)) + +#define sk_PKCS7_SIGNER_INFO_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(PKCS7_SIGNER_INFO *), \ + free_func)) + +#define sk_PKCS7_SIGNER_INFO_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk), \ + CHECKED_CAST(void *, PKCS7_SIGNER_INFO *, p), (where)) + +#define sk_PKCS7_SIGNER_INFO_delete(sk, where) \ + ((PKCS7_SIGNER_INFO *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk), (where))) + +#define sk_PKCS7_SIGNER_INFO_delete_ptr(sk, p) \ + ((PKCS7_SIGNER_INFO *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk), \ + CHECKED_CAST(void *, PKCS7_SIGNER_INFO *, p))) + +#define sk_PKCS7_SIGNER_INFO_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk), \ + (out_index), CHECKED_CAST(void *, PKCS7_SIGNER_INFO *, p)) + +#define sk_PKCS7_SIGNER_INFO_shift(sk) \ + ((PKCS7_SIGNER_INFO *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk))) + +#define sk_PKCS7_SIGNER_INFO_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk), \ + CHECKED_CAST(void *, PKCS7_SIGNER_INFO *, p)) + +#define sk_PKCS7_SIGNER_INFO_pop(sk) \ + ((PKCS7_SIGNER_INFO *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk))) + +#define sk_PKCS7_SIGNER_INFO_dup(sk) \ + ((STACK_OF(PKCS7_SIGNER_INFO) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(PKCS7_SIGNER_INFO) *, sk))) + +#define sk_PKCS7_SIGNER_INFO_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk)) + +#define sk_PKCS7_SIGNER_INFO_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(PKCS7_SIGNER_INFO) *, sk)) + +#define sk_PKCS7_SIGNER_INFO_set_cmp_func(sk, comp) \ + ((int (*)(const PKCS7_SIGNER_INFO **a, const PKCS7_SIGNER_INFO **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const PKCS7_SIGNER_INFO **a, \ + const PKCS7_SIGNER_INFO **b), \ + comp))) + +#define sk_PKCS7_SIGNER_INFO_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(PKCS7_SIGNER_INFO) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(PKCS7_SIGNER_INFO) *, sk), \ + CHECKED_CAST(void *(*)(void *), \ + PKCS7_SIGNER_INFO *(*)(PKCS7_SIGNER_INFO *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(PKCS7_SIGNER_INFO *), \ + free_func))) + +/* POLICYINFO */ +#define sk_POLICYINFO_new(comp) \ + ((STACK_OF(POLICYINFO) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const POLICYINFO **a, const POLICYINFO **b), \ + comp))) + +#define sk_POLICYINFO_new_null() ((STACK_OF(POLICYINFO) *)sk_new_null()) + +#define sk_POLICYINFO_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk)) + +#define sk_POLICYINFO_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk)); + +#define sk_POLICYINFO_value(sk, i) \ + ((POLICYINFO *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(POLICYINFO) *, sk), (i))) + +#define sk_POLICYINFO_set(sk, i, p) \ + ((POLICYINFO *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), \ + (i), CHECKED_CAST(void *, POLICYINFO *, p))) + +#define sk_POLICYINFO_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk)) + +#define sk_POLICYINFO_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(POLICYINFO *), free_func)) + +#define sk_POLICYINFO_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), \ + CHECKED_CAST(void *, POLICYINFO *, p), (where)) + +#define sk_POLICYINFO_delete(sk, where) \ + ((POLICYINFO *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), \ + (where))) + +#define sk_POLICYINFO_delete_ptr(sk, p) \ + ((POLICYINFO *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), \ + CHECKED_CAST(void *, POLICYINFO *, p))) + +#define sk_POLICYINFO_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), (out_index), \ + CHECKED_CAST(void *, POLICYINFO *, p)) + +#define sk_POLICYINFO_shift(sk) \ + ((POLICYINFO *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk))) + +#define sk_POLICYINFO_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), \ + CHECKED_CAST(void *, POLICYINFO *, p)) + +#define sk_POLICYINFO_pop(sk) \ + ((POLICYINFO *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk))) + +#define sk_POLICYINFO_dup(sk) \ + ((STACK_OF(POLICYINFO) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(POLICYINFO) *, sk))) + +#define sk_POLICYINFO_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk)) + +#define sk_POLICYINFO_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(POLICYINFO) *, sk)) + +#define sk_POLICYINFO_set_cmp_func(sk, comp) \ + ((int (*)(const POLICYINFO **a, const POLICYINFO **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const POLICYINFO **a, const POLICYINFO **b), \ + comp))) + +#define sk_POLICYINFO_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(POLICYINFO) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(POLICYINFO) *, sk), \ + CHECKED_CAST(void *(*)(void *), POLICYINFO *(*)(POLICYINFO *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(POLICYINFO *), free_func))) + +/* POLICYQUALINFO */ +#define sk_POLICYQUALINFO_new(comp) \ + ((STACK_OF(POLICYQUALINFO) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const POLICYQUALINFO **a, const POLICYQUALINFO **b), comp))) + +#define sk_POLICYQUALINFO_new_null() ((STACK_OF(POLICYQUALINFO) *)sk_new_null()) + +#define sk_POLICYQUALINFO_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk)) + +#define sk_POLICYQUALINFO_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk)); + +#define sk_POLICYQUALINFO_value(sk, i) \ + ((POLICYQUALINFO *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(POLICYQUALINFO) *, sk), (i))) + +#define sk_POLICYQUALINFO_set(sk, i, p) \ + ((POLICYQUALINFO *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), (i), \ + CHECKED_CAST(void *, POLICYQUALINFO *, p))) + +#define sk_POLICYQUALINFO_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk)) + +#define sk_POLICYQUALINFO_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(POLICYQUALINFO *), free_func)) + +#define sk_POLICYQUALINFO_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), \ + CHECKED_CAST(void *, POLICYQUALINFO *, p), (where)) + +#define sk_POLICYQUALINFO_delete(sk, where) \ + ((POLICYQUALINFO *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), (where))) + +#define sk_POLICYQUALINFO_delete_ptr(sk, p) \ + ((POLICYQUALINFO *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), \ + CHECKED_CAST(void *, POLICYQUALINFO *, p))) + +#define sk_POLICYQUALINFO_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), (out_index), \ + CHECKED_CAST(void *, POLICYQUALINFO *, p)) + +#define sk_POLICYQUALINFO_shift(sk) \ + ((POLICYQUALINFO *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk))) + +#define sk_POLICYQUALINFO_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), \ + CHECKED_CAST(void *, POLICYQUALINFO *, p)) + +#define sk_POLICYQUALINFO_pop(sk) \ + ((POLICYQUALINFO *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk))) + +#define sk_POLICYQUALINFO_dup(sk) \ + ((STACK_OF(POLICYQUALINFO) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(POLICYQUALINFO) *, sk))) + +#define sk_POLICYQUALINFO_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk)) + +#define sk_POLICYQUALINFO_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(POLICYQUALINFO) *, sk)) + +#define sk_POLICYQUALINFO_set_cmp_func(sk, comp) \ + ((int (*)(const POLICYQUALINFO **a, const POLICYQUALINFO **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const POLICYQUALINFO **a, \ + const POLICYQUALINFO **b), \ + comp))) + +#define sk_POLICYQUALINFO_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(POLICYQUALINFO) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(POLICYQUALINFO) *, sk), \ + CHECKED_CAST(void *(*)(void *), POLICYQUALINFO *(*)(POLICYQUALINFO *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(POLICYQUALINFO *), free_func))) + +/* POLICY_MAPPING */ +#define sk_POLICY_MAPPING_new(comp) \ + ((STACK_OF(POLICY_MAPPING) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const POLICY_MAPPING **a, const POLICY_MAPPING **b), comp))) + +#define sk_POLICY_MAPPING_new_null() ((STACK_OF(POLICY_MAPPING) *)sk_new_null()) + +#define sk_POLICY_MAPPING_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk)) + +#define sk_POLICY_MAPPING_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk)); + +#define sk_POLICY_MAPPING_value(sk, i) \ + ((POLICY_MAPPING *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(POLICY_MAPPING) *, sk), (i))) + +#define sk_POLICY_MAPPING_set(sk, i, p) \ + ((POLICY_MAPPING *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), (i), \ + CHECKED_CAST(void *, POLICY_MAPPING *, p))) + +#define sk_POLICY_MAPPING_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk)) + +#define sk_POLICY_MAPPING_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(POLICY_MAPPING *), free_func)) + +#define sk_POLICY_MAPPING_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), \ + CHECKED_CAST(void *, POLICY_MAPPING *, p), (where)) + +#define sk_POLICY_MAPPING_delete(sk, where) \ + ((POLICY_MAPPING *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), (where))) + +#define sk_POLICY_MAPPING_delete_ptr(sk, p) \ + ((POLICY_MAPPING *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), \ + CHECKED_CAST(void *, POLICY_MAPPING *, p))) + +#define sk_POLICY_MAPPING_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), (out_index), \ + CHECKED_CAST(void *, POLICY_MAPPING *, p)) + +#define sk_POLICY_MAPPING_shift(sk) \ + ((POLICY_MAPPING *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk))) + +#define sk_POLICY_MAPPING_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), \ + CHECKED_CAST(void *, POLICY_MAPPING *, p)) + +#define sk_POLICY_MAPPING_pop(sk) \ + ((POLICY_MAPPING *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk))) + +#define sk_POLICY_MAPPING_dup(sk) \ + ((STACK_OF(POLICY_MAPPING) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(POLICY_MAPPING) *, sk))) + +#define sk_POLICY_MAPPING_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk)) + +#define sk_POLICY_MAPPING_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(POLICY_MAPPING) *, sk)) + +#define sk_POLICY_MAPPING_set_cmp_func(sk, comp) \ + ((int (*)(const POLICY_MAPPING **a, const POLICY_MAPPING **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const POLICY_MAPPING **a, \ + const POLICY_MAPPING **b), \ + comp))) + +#define sk_POLICY_MAPPING_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(POLICY_MAPPING) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(POLICY_MAPPING) *, sk), \ + CHECKED_CAST(void *(*)(void *), POLICY_MAPPING *(*)(POLICY_MAPPING *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(POLICY_MAPPING *), free_func))) + +/* RSA_additional_prime */ +#define sk_RSA_additional_prime_new(comp) \ + ((STACK_OF(RSA_additional_prime) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const RSA_additional_prime **a, const RSA_additional_prime **b), \ + comp))) + +#define sk_RSA_additional_prime_new_null() \ + ((STACK_OF(RSA_additional_prime) *)sk_new_null()) + +#define sk_RSA_additional_prime_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk)) + +#define sk_RSA_additional_prime_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk)); + +#define sk_RSA_additional_prime_value(sk, i) \ + ((RSA_additional_prime *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(RSA_additional_prime) *, sk), \ + (i))) + +#define sk_RSA_additional_prime_set(sk, i, p) \ + ((RSA_additional_prime *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk), (i), \ + CHECKED_CAST(void *, RSA_additional_prime *, p))) + +#define sk_RSA_additional_prime_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk)) + +#define sk_RSA_additional_prime_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(RSA_additional_prime *), \ + free_func)) + +#define sk_RSA_additional_prime_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk), \ + CHECKED_CAST(void *, RSA_additional_prime *, p), (where)) + +#define sk_RSA_additional_prime_delete(sk, where) \ + ((RSA_additional_prime *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk), (where))) + +#define sk_RSA_additional_prime_delete_ptr(sk, p) \ + ((RSA_additional_prime *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk), \ + CHECKED_CAST(void *, RSA_additional_prime *, p))) + +#define sk_RSA_additional_prime_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk), \ + (out_index), CHECKED_CAST(void *, RSA_additional_prime *, p)) + +#define sk_RSA_additional_prime_shift(sk) \ + ((RSA_additional_prime *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk))) + +#define sk_RSA_additional_prime_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk), \ + CHECKED_CAST(void *, RSA_additional_prime *, p)) + +#define sk_RSA_additional_prime_pop(sk) \ + ((RSA_additional_prime *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk))) + +#define sk_RSA_additional_prime_dup(sk) \ + ((STACK_OF(RSA_additional_prime) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(RSA_additional_prime) *, sk))) + +#define sk_RSA_additional_prime_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk)) + +#define sk_RSA_additional_prime_is_sorted(sk) \ + sk_is_sorted( \ + CHECKED_CAST(_STACK *, const STACK_OF(RSA_additional_prime) *, sk)) + +#define sk_RSA_additional_prime_set_cmp_func(sk, comp) \ + ((int (*)(const RSA_additional_prime **a, const RSA_additional_prime **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const RSA_additional_prime **a, \ + const RSA_additional_prime **b), \ + comp))) + +#define sk_RSA_additional_prime_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(RSA_additional_prime) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(RSA_additional_prime) *, \ + sk), \ + CHECKED_CAST(void *(*)(void *), \ + RSA_additional_prime *(*)(RSA_additional_prime *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(RSA_additional_prime *), \ + free_func))) + +/* SSL_COMP */ +#define sk_SSL_COMP_new(comp) \ + ((STACK_OF(SSL_COMP) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const SSL_COMP **a, const SSL_COMP **b), comp))) + +#define sk_SSL_COMP_new_null() ((STACK_OF(SSL_COMP) *)sk_new_null()) + +#define sk_SSL_COMP_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk)) + +#define sk_SSL_COMP_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk)); + +#define sk_SSL_COMP_value(sk, i) \ + ((SSL_COMP *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(SSL_COMP) *, sk), (i))) + +#define sk_SSL_COMP_set(sk, i, p) \ + ((SSL_COMP *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), (i), \ + CHECKED_CAST(void *, SSL_COMP *, p))) + +#define sk_SSL_COMP_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk)) + +#define sk_SSL_COMP_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(SSL_COMP *), free_func)) + +#define sk_SSL_COMP_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), \ + CHECKED_CAST(void *, SSL_COMP *, p), (where)) + +#define sk_SSL_COMP_delete(sk, where) \ + ((SSL_COMP *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), \ + (where))) + +#define sk_SSL_COMP_delete_ptr(sk, p) \ + ((SSL_COMP *)sk_delete_ptr(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), \ + CHECKED_CAST(void *, SSL_COMP *, p))) + +#define sk_SSL_COMP_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), (out_index), \ + CHECKED_CAST(void *, SSL_COMP *, p)) + +#define sk_SSL_COMP_shift(sk) \ + ((SSL_COMP *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk))) + +#define sk_SSL_COMP_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), \ + CHECKED_CAST(void *, SSL_COMP *, p)) + +#define sk_SSL_COMP_pop(sk) \ + ((SSL_COMP *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk))) + +#define sk_SSL_COMP_dup(sk) \ + ((STACK_OF(SSL_COMP) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(SSL_COMP) *, sk))) + +#define sk_SSL_COMP_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk)) + +#define sk_SSL_COMP_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(SSL_COMP) *, sk)) + +#define sk_SSL_COMP_set_cmp_func(sk, comp) \ + ((int (*)(const SSL_COMP **a, const SSL_COMP **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const SSL_COMP **a, const SSL_COMP **b), comp))) + +#define sk_SSL_COMP_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(SSL_COMP) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(SSL_COMP) *, sk), \ + CHECKED_CAST(void *(*)(void *), SSL_COMP *(*)(SSL_COMP *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(SSL_COMP *), free_func))) + +/* SSL_CUSTOM_EXTENSION */ +#define sk_SSL_CUSTOM_EXTENSION_new(comp) \ + ((STACK_OF(SSL_CUSTOM_EXTENSION) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const SSL_CUSTOM_EXTENSION **a, const SSL_CUSTOM_EXTENSION **b), \ + comp))) + +#define sk_SSL_CUSTOM_EXTENSION_new_null() \ + ((STACK_OF(SSL_CUSTOM_EXTENSION) *)sk_new_null()) + +#define sk_SSL_CUSTOM_EXTENSION_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk)) + +#define sk_SSL_CUSTOM_EXTENSION_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk)); + +#define sk_SSL_CUSTOM_EXTENSION_value(sk, i) \ + ((SSL_CUSTOM_EXTENSION *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), \ + (i))) + +#define sk_SSL_CUSTOM_EXTENSION_set(sk, i, p) \ + ((SSL_CUSTOM_EXTENSION *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), (i), \ + CHECKED_CAST(void *, SSL_CUSTOM_EXTENSION *, p))) + +#define sk_SSL_CUSTOM_EXTENSION_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk)) + +#define sk_SSL_CUSTOM_EXTENSION_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(SSL_CUSTOM_EXTENSION *), \ + free_func)) + +#define sk_SSL_CUSTOM_EXTENSION_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), \ + CHECKED_CAST(void *, SSL_CUSTOM_EXTENSION *, p), (where)) + +#define sk_SSL_CUSTOM_EXTENSION_delete(sk, where) \ + ((SSL_CUSTOM_EXTENSION *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), (where))) + +#define sk_SSL_CUSTOM_EXTENSION_delete_ptr(sk, p) \ + ((SSL_CUSTOM_EXTENSION *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), \ + CHECKED_CAST(void *, SSL_CUSTOM_EXTENSION *, p))) + +#define sk_SSL_CUSTOM_EXTENSION_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), \ + (out_index), CHECKED_CAST(void *, SSL_CUSTOM_EXTENSION *, p)) + +#define sk_SSL_CUSTOM_EXTENSION_shift(sk) \ + ((SSL_CUSTOM_EXTENSION *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk))) + +#define sk_SSL_CUSTOM_EXTENSION_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), \ + CHECKED_CAST(void *, SSL_CUSTOM_EXTENSION *, p)) + +#define sk_SSL_CUSTOM_EXTENSION_pop(sk) \ + ((SSL_CUSTOM_EXTENSION *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk))) + +#define sk_SSL_CUSTOM_EXTENSION_dup(sk) \ + ((STACK_OF(SSL_CUSTOM_EXTENSION) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(SSL_CUSTOM_EXTENSION) *, sk))) + +#define sk_SSL_CUSTOM_EXTENSION_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk)) + +#define sk_SSL_CUSTOM_EXTENSION_is_sorted(sk) \ + sk_is_sorted( \ + CHECKED_CAST(_STACK *, const STACK_OF(SSL_CUSTOM_EXTENSION) *, sk)) + +#define sk_SSL_CUSTOM_EXTENSION_set_cmp_func(sk, comp) \ + ((int (*)(const SSL_CUSTOM_EXTENSION **a, const SSL_CUSTOM_EXTENSION **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const SSL_CUSTOM_EXTENSION **a, \ + const SSL_CUSTOM_EXTENSION **b), \ + comp))) + +#define sk_SSL_CUSTOM_EXTENSION_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(SSL_CUSTOM_EXTENSION) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(SSL_CUSTOM_EXTENSION) *, \ + sk), \ + CHECKED_CAST(void *(*)(void *), \ + SSL_CUSTOM_EXTENSION *(*)(SSL_CUSTOM_EXTENSION *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(SSL_CUSTOM_EXTENSION *), \ + free_func))) + +/* STACK_OF_X509_NAME_ENTRY */ +#define sk_STACK_OF_X509_NAME_ENTRY_new(comp) \ + ((STACK_OF(STACK_OF_X509_NAME_ENTRY) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const STACK_OF_X509_NAME_ENTRY **a, \ + const STACK_OF_X509_NAME_ENTRY **b), \ + comp))) + +#define sk_STACK_OF_X509_NAME_ENTRY_new_null() \ + ((STACK_OF(STACK_OF_X509_NAME_ENTRY) *)sk_new_null()) + +#define sk_STACK_OF_X509_NAME_ENTRY_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk)) + +#define sk_STACK_OF_X509_NAME_ENTRY_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk)); + +#define sk_STACK_OF_X509_NAME_ENTRY_value(sk, i) \ + ((STACK_OF_X509_NAME_ENTRY *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \ + (i))) + +#define sk_STACK_OF_X509_NAME_ENTRY_set(sk, i, p) \ + ((STACK_OF_X509_NAME_ENTRY *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), (i), \ + CHECKED_CAST(void *, STACK_OF_X509_NAME_ENTRY *, p))) + +#define sk_STACK_OF_X509_NAME_ENTRY_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk)) + +#define sk_STACK_OF_X509_NAME_ENTRY_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(STACK_OF_X509_NAME_ENTRY *), \ + free_func)) + +#define sk_STACK_OF_X509_NAME_ENTRY_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(void *, STACK_OF_X509_NAME_ENTRY *, p), (where)) + +#define sk_STACK_OF_X509_NAME_ENTRY_delete(sk, where) \ + ((STACK_OF_X509_NAME_ENTRY *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \ + (where))) + +#define sk_STACK_OF_X509_NAME_ENTRY_delete_ptr(sk, p) \ + ((STACK_OF_X509_NAME_ENTRY *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(void *, STACK_OF_X509_NAME_ENTRY *, p))) + +#define sk_STACK_OF_X509_NAME_ENTRY_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \ + (out_index), CHECKED_CAST(void *, STACK_OF_X509_NAME_ENTRY *, p)) + +#define sk_STACK_OF_X509_NAME_ENTRY_shift(sk) \ + ((STACK_OF_X509_NAME_ENTRY *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk))) + +#define sk_STACK_OF_X509_NAME_ENTRY_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(void *, STACK_OF_X509_NAME_ENTRY *, p)) + +#define sk_STACK_OF_X509_NAME_ENTRY_pop(sk) \ + ((STACK_OF_X509_NAME_ENTRY *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk))) + +#define sk_STACK_OF_X509_NAME_ENTRY_dup(sk) \ + ((STACK_OF(STACK_OF_X509_NAME_ENTRY) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk))) + +#define sk_STACK_OF_X509_NAME_ENTRY_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk)) + +#define sk_STACK_OF_X509_NAME_ENTRY_is_sorted(sk) \ + sk_is_sorted( \ + CHECKED_CAST(_STACK *, const STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk)) + +#define sk_STACK_OF_X509_NAME_ENTRY_set_cmp_func(sk, comp) \ + ((int (*)(const STACK_OF_X509_NAME_ENTRY **a, \ + const STACK_OF_X509_NAME_ENTRY **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const STACK_OF_X509_NAME_ENTRY **a, \ + const STACK_OF_X509_NAME_ENTRY **b), \ + comp))) + +#define sk_STACK_OF_X509_NAME_ENTRY_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(STACK_OF_X509_NAME_ENTRY) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(STACK_OF_X509_NAME_ENTRY) *, \ + sk), \ + CHECKED_CAST(void *(*)(void *), \ + STACK_OF_X509_NAME_ENTRY *(*)(STACK_OF_X509_NAME_ENTRY *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(STACK_OF_X509_NAME_ENTRY *), \ + free_func))) + +/* SXNETID */ +#define sk_SXNETID_new(comp) \ + ((STACK_OF(SXNETID) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const SXNETID **a, const SXNETID **b), comp))) + +#define sk_SXNETID_new_null() ((STACK_OF(SXNETID) *)sk_new_null()) + +#define sk_SXNETID_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk)) + +#define sk_SXNETID_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk)); + +#define sk_SXNETID_value(sk, i) \ + ((SXNETID *)sk_value(CHECKED_CAST(_STACK *, const STACK_OF(SXNETID) *, sk), \ + (i))) + +#define sk_SXNETID_set(sk, i, p) \ + ((SXNETID *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), (i), \ + CHECKED_CAST(void *, SXNETID *, p))) + +#define sk_SXNETID_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk)) + +#define sk_SXNETID_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(SXNETID *), free_func)) + +#define sk_SXNETID_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), \ + CHECKED_CAST(void *, SXNETID *, p), (where)) + +#define sk_SXNETID_delete(sk, where) \ + ((SXNETID *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), \ + (where))) + +#define sk_SXNETID_delete_ptr(sk, p) \ + ((SXNETID *)sk_delete_ptr(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), \ + CHECKED_CAST(void *, SXNETID *, p))) + +#define sk_SXNETID_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), (out_index), \ + CHECKED_CAST(void *, SXNETID *, p)) + +#define sk_SXNETID_shift(sk) \ + ((SXNETID *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk))) + +#define sk_SXNETID_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), \ + CHECKED_CAST(void *, SXNETID *, p)) + +#define sk_SXNETID_pop(sk) \ + ((SXNETID *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk))) + +#define sk_SXNETID_dup(sk) \ + ((STACK_OF(SXNETID) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(SXNETID) *, sk))) + +#define sk_SXNETID_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk)) + +#define sk_SXNETID_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(SXNETID) *, sk)) + +#define sk_SXNETID_set_cmp_func(sk, comp) \ + ((int (*)(const SXNETID **a, const SXNETID **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const SXNETID **a, const SXNETID **b), comp))) + +#define sk_SXNETID_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(SXNETID) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(SXNETID) *, sk), \ + CHECKED_CAST(void *(*)(void *), SXNETID *(*)(SXNETID *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(SXNETID *), free_func))) + +/* X509 */ +#define sk_X509_new(comp) \ + ((STACK_OF(X509) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const X509 **a, const X509 **b), comp))) + +#define sk_X509_new_null() ((STACK_OF(X509) *)sk_new_null()) + +#define sk_X509_num(sk) sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk)) + +#define sk_X509_zero(sk) sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk)); + +#define sk_X509_value(sk, i) \ + ((X509 *)sk_value(CHECKED_CAST(_STACK *, const STACK_OF(X509) *, sk), (i))) + +#define sk_X509_set(sk, i, p) \ + ((X509 *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), (i), \ + CHECKED_CAST(void *, X509 *, p))) + +#define sk_X509_free(sk) sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk)) + +#define sk_X509_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509 *), free_func)) + +#define sk_X509_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), \ + CHECKED_CAST(void *, X509 *, p), (where)) + +#define sk_X509_delete(sk, where) \ + ((X509 *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), (where))) + +#define sk_X509_delete_ptr(sk, p) \ + ((X509 *)sk_delete_ptr(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), \ + CHECKED_CAST(void *, X509 *, p))) + +#define sk_X509_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), (out_index), \ + CHECKED_CAST(void *, X509 *, p)) + +#define sk_X509_shift(sk) \ + ((X509 *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk))) + +#define sk_X509_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), \ + CHECKED_CAST(void *, X509 *, p)) + +#define sk_X509_pop(sk) \ + ((X509 *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk))) + +#define sk_X509_dup(sk) \ + ((STACK_OF(X509) *)sk_dup(CHECKED_CAST(_STACK *, const STACK_OF(X509) *, sk))) + +#define sk_X509_sort(sk) sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk)) + +#define sk_X509_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509) *, sk)) + +#define sk_X509_set_cmp_func(sk, comp) \ + ((int (*)(const X509 **a, const X509 **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const X509 **a, const X509 **b), \ + comp))) + +#define sk_X509_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509 *(*)(X509 *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509 *), free_func))) + +/* X509V3_EXT_METHOD */ +#define sk_X509V3_EXT_METHOD_new(comp) \ + ((STACK_OF(X509V3_EXT_METHOD) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const X509V3_EXT_METHOD **a, const X509V3_EXT_METHOD **b), \ + comp))) + +#define sk_X509V3_EXT_METHOD_new_null() \ + ((STACK_OF(X509V3_EXT_METHOD) *)sk_new_null()) + +#define sk_X509V3_EXT_METHOD_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk)) + +#define sk_X509V3_EXT_METHOD_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk)); + +#define sk_X509V3_EXT_METHOD_value(sk, i) \ + ((X509V3_EXT_METHOD *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509V3_EXT_METHOD) *, sk), (i))) + +#define sk_X509V3_EXT_METHOD_set(sk, i, p) \ + ((X509V3_EXT_METHOD *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), (i), \ + CHECKED_CAST(void *, X509V3_EXT_METHOD *, p))) + +#define sk_X509V3_EXT_METHOD_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk)) + +#define sk_X509V3_EXT_METHOD_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509V3_EXT_METHOD *), \ + free_func)) + +#define sk_X509V3_EXT_METHOD_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), \ + CHECKED_CAST(void *, X509V3_EXT_METHOD *, p), (where)) + +#define sk_X509V3_EXT_METHOD_delete(sk, where) \ + ((X509V3_EXT_METHOD *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), (where))) + +#define sk_X509V3_EXT_METHOD_delete_ptr(sk, p) \ + ((X509V3_EXT_METHOD *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), \ + CHECKED_CAST(void *, X509V3_EXT_METHOD *, p))) + +#define sk_X509V3_EXT_METHOD_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), \ + (out_index), CHECKED_CAST(void *, X509V3_EXT_METHOD *, p)) + +#define sk_X509V3_EXT_METHOD_shift(sk) \ + ((X509V3_EXT_METHOD *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk))) + +#define sk_X509V3_EXT_METHOD_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), \ + CHECKED_CAST(void *, X509V3_EXT_METHOD *, p)) + +#define sk_X509V3_EXT_METHOD_pop(sk) \ + ((X509V3_EXT_METHOD *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk))) + +#define sk_X509V3_EXT_METHOD_dup(sk) \ + ((STACK_OF(X509V3_EXT_METHOD) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509V3_EXT_METHOD) *, sk))) + +#define sk_X509V3_EXT_METHOD_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk)) + +#define sk_X509V3_EXT_METHOD_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509V3_EXT_METHOD) *, sk)) + +#define sk_X509V3_EXT_METHOD_set_cmp_func(sk, comp) \ + ((int (*)(const X509V3_EXT_METHOD **a, const X509V3_EXT_METHOD **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const X509V3_EXT_METHOD **a, \ + const X509V3_EXT_METHOD **b), \ + comp))) + +#define sk_X509V3_EXT_METHOD_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509V3_EXT_METHOD) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509V3_EXT_METHOD) *, sk), \ + CHECKED_CAST(void *(*)(void *), \ + X509V3_EXT_METHOD *(*)(X509V3_EXT_METHOD *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509V3_EXT_METHOD *), \ + free_func))) + +/* X509_ALGOR */ +#define sk_X509_ALGOR_new(comp) \ + ((STACK_OF(X509_ALGOR) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const X509_ALGOR **a, const X509_ALGOR **b), \ + comp))) + +#define sk_X509_ALGOR_new_null() ((STACK_OF(X509_ALGOR) *)sk_new_null()) + +#define sk_X509_ALGOR_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk)) + +#define sk_X509_ALGOR_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk)); + +#define sk_X509_ALGOR_value(sk, i) \ + ((X509_ALGOR *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_ALGOR) *, sk), (i))) + +#define sk_X509_ALGOR_set(sk, i, p) \ + ((X509_ALGOR *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \ + (i), CHECKED_CAST(void *, X509_ALGOR *, p))) + +#define sk_X509_ALGOR_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk)) + +#define sk_X509_ALGOR_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_ALGOR *), free_func)) + +#define sk_X509_ALGOR_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \ + CHECKED_CAST(void *, X509_ALGOR *, p), (where)) + +#define sk_X509_ALGOR_delete(sk, where) \ + ((X509_ALGOR *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \ + (where))) + +#define sk_X509_ALGOR_delete_ptr(sk, p) \ + ((X509_ALGOR *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \ + CHECKED_CAST(void *, X509_ALGOR *, p))) + +#define sk_X509_ALGOR_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_ALGOR *, p)) + +#define sk_X509_ALGOR_shift(sk) \ + ((X509_ALGOR *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk))) + +#define sk_X509_ALGOR_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \ + CHECKED_CAST(void *, X509_ALGOR *, p)) + +#define sk_X509_ALGOR_pop(sk) \ + ((X509_ALGOR *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk))) + +#define sk_X509_ALGOR_dup(sk) \ + ((STACK_OF(X509_ALGOR) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_ALGOR) *, sk))) + +#define sk_X509_ALGOR_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk)) + +#define sk_X509_ALGOR_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_ALGOR) *, sk)) + +#define sk_X509_ALGOR_set_cmp_func(sk, comp) \ + ((int (*)(const X509_ALGOR **a, const X509_ALGOR **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_ALGOR **a, const X509_ALGOR **b), \ + comp))) + +#define sk_X509_ALGOR_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_ALGOR) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_ALGOR) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_ALGOR *(*)(X509_ALGOR *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_ALGOR *), free_func))) + +/* X509_ATTRIBUTE */ +#define sk_X509_ATTRIBUTE_new(comp) \ + ((STACK_OF(X509_ATTRIBUTE) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const X509_ATTRIBUTE **a, const X509_ATTRIBUTE **b), comp))) + +#define sk_X509_ATTRIBUTE_new_null() ((STACK_OF(X509_ATTRIBUTE) *)sk_new_null()) + +#define sk_X509_ATTRIBUTE_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk)) + +#define sk_X509_ATTRIBUTE_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk)); + +#define sk_X509_ATTRIBUTE_value(sk, i) \ + ((X509_ATTRIBUTE *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_ATTRIBUTE) *, sk), (i))) + +#define sk_X509_ATTRIBUTE_set(sk, i, p) \ + ((X509_ATTRIBUTE *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), (i), \ + CHECKED_CAST(void *, X509_ATTRIBUTE *, p))) + +#define sk_X509_ATTRIBUTE_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk)) + +#define sk_X509_ATTRIBUTE_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_ATTRIBUTE *), free_func)) + +#define sk_X509_ATTRIBUTE_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), \ + CHECKED_CAST(void *, X509_ATTRIBUTE *, p), (where)) + +#define sk_X509_ATTRIBUTE_delete(sk, where) \ + ((X509_ATTRIBUTE *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), (where))) + +#define sk_X509_ATTRIBUTE_delete_ptr(sk, p) \ + ((X509_ATTRIBUTE *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), \ + CHECKED_CAST(void *, X509_ATTRIBUTE *, p))) + +#define sk_X509_ATTRIBUTE_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_ATTRIBUTE *, p)) + +#define sk_X509_ATTRIBUTE_shift(sk) \ + ((X509_ATTRIBUTE *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk))) + +#define sk_X509_ATTRIBUTE_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), \ + CHECKED_CAST(void *, X509_ATTRIBUTE *, p)) + +#define sk_X509_ATTRIBUTE_pop(sk) \ + ((X509_ATTRIBUTE *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk))) + +#define sk_X509_ATTRIBUTE_dup(sk) \ + ((STACK_OF(X509_ATTRIBUTE) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_ATTRIBUTE) *, sk))) + +#define sk_X509_ATTRIBUTE_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk)) + +#define sk_X509_ATTRIBUTE_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_ATTRIBUTE) *, sk)) + +#define sk_X509_ATTRIBUTE_set_cmp_func(sk, comp) \ + ((int (*)(const X509_ATTRIBUTE **a, const X509_ATTRIBUTE **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const X509_ATTRIBUTE **a, \ + const X509_ATTRIBUTE **b), \ + comp))) + +#define sk_X509_ATTRIBUTE_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_ATTRIBUTE) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_ATTRIBUTE) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_ATTRIBUTE *(*)(X509_ATTRIBUTE *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_ATTRIBUTE *), free_func))) + +/* X509_CRL */ +#define sk_X509_CRL_new(comp) \ + ((STACK_OF(X509_CRL) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const X509_CRL **a, const X509_CRL **b), comp))) + +#define sk_X509_CRL_new_null() ((STACK_OF(X509_CRL) *)sk_new_null()) + +#define sk_X509_CRL_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk)) + +#define sk_X509_CRL_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk)); + +#define sk_X509_CRL_value(sk, i) \ + ((X509_CRL *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_CRL) *, sk), (i))) + +#define sk_X509_CRL_set(sk, i, p) \ + ((X509_CRL *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), (i), \ + CHECKED_CAST(void *, X509_CRL *, p))) + +#define sk_X509_CRL_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk)) + +#define sk_X509_CRL_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_CRL *), free_func)) + +#define sk_X509_CRL_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \ + CHECKED_CAST(void *, X509_CRL *, p), (where)) + +#define sk_X509_CRL_delete(sk, where) \ + ((X509_CRL *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \ + (where))) + +#define sk_X509_CRL_delete_ptr(sk, p) \ + ((X509_CRL *)sk_delete_ptr(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \ + CHECKED_CAST(void *, X509_CRL *, p))) + +#define sk_X509_CRL_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_CRL *, p)) + +#define sk_X509_CRL_shift(sk) \ + ((X509_CRL *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk))) + +#define sk_X509_CRL_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \ + CHECKED_CAST(void *, X509_CRL *, p)) + +#define sk_X509_CRL_pop(sk) \ + ((X509_CRL *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk))) + +#define sk_X509_CRL_dup(sk) \ + ((STACK_OF(X509_CRL) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_CRL) *, sk))) + +#define sk_X509_CRL_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk)) + +#define sk_X509_CRL_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_CRL) *, sk)) + +#define sk_X509_CRL_set_cmp_func(sk, comp) \ + ((int (*)(const X509_CRL **a, const X509_CRL **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_CRL **a, const X509_CRL **b), comp))) + +#define sk_X509_CRL_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_CRL) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_CRL) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_CRL *(*)(X509_CRL *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_CRL *), free_func))) + +/* X509_EXTENSION */ +#define sk_X509_EXTENSION_new(comp) \ + ((STACK_OF(X509_EXTENSION) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const X509_EXTENSION **a, const X509_EXTENSION **b), comp))) + +#define sk_X509_EXTENSION_new_null() ((STACK_OF(X509_EXTENSION) *)sk_new_null()) + +#define sk_X509_EXTENSION_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk)) + +#define sk_X509_EXTENSION_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk)); + +#define sk_X509_EXTENSION_value(sk, i) \ + ((X509_EXTENSION *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_EXTENSION) *, sk), (i))) + +#define sk_X509_EXTENSION_set(sk, i, p) \ + ((X509_EXTENSION *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), (i), \ + CHECKED_CAST(void *, X509_EXTENSION *, p))) + +#define sk_X509_EXTENSION_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk)) + +#define sk_X509_EXTENSION_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_EXTENSION *), free_func)) + +#define sk_X509_EXTENSION_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), \ + CHECKED_CAST(void *, X509_EXTENSION *, p), (where)) + +#define sk_X509_EXTENSION_delete(sk, where) \ + ((X509_EXTENSION *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), (where))) + +#define sk_X509_EXTENSION_delete_ptr(sk, p) \ + ((X509_EXTENSION *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), \ + CHECKED_CAST(void *, X509_EXTENSION *, p))) + +#define sk_X509_EXTENSION_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_EXTENSION *, p)) + +#define sk_X509_EXTENSION_shift(sk) \ + ((X509_EXTENSION *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk))) + +#define sk_X509_EXTENSION_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), \ + CHECKED_CAST(void *, X509_EXTENSION *, p)) + +#define sk_X509_EXTENSION_pop(sk) \ + ((X509_EXTENSION *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk))) + +#define sk_X509_EXTENSION_dup(sk) \ + ((STACK_OF(X509_EXTENSION) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_EXTENSION) *, sk))) + +#define sk_X509_EXTENSION_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk)) + +#define sk_X509_EXTENSION_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_EXTENSION) *, sk)) + +#define sk_X509_EXTENSION_set_cmp_func(sk, comp) \ + ((int (*)(const X509_EXTENSION **a, const X509_EXTENSION **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const X509_EXTENSION **a, \ + const X509_EXTENSION **b), \ + comp))) + +#define sk_X509_EXTENSION_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_EXTENSION) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_EXTENSION) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_EXTENSION *(*)(X509_EXTENSION *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_EXTENSION *), free_func))) + +/* X509_INFO */ +#define sk_X509_INFO_new(comp) \ + ((STACK_OF(X509_INFO) *)sk_new( \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_INFO **a, const X509_INFO **b), comp))) + +#define sk_X509_INFO_new_null() ((STACK_OF(X509_INFO) *)sk_new_null()) + +#define sk_X509_INFO_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk)) + +#define sk_X509_INFO_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk)); + +#define sk_X509_INFO_value(sk, i) \ + ((X509_INFO *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_INFO) *, sk), (i))) + +#define sk_X509_INFO_set(sk, i, p) \ + ((X509_INFO *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), (i), \ + CHECKED_CAST(void *, X509_INFO *, p))) + +#define sk_X509_INFO_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk)) + +#define sk_X509_INFO_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_INFO *), free_func)) + +#define sk_X509_INFO_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \ + CHECKED_CAST(void *, X509_INFO *, p), (where)) + +#define sk_X509_INFO_delete(sk, where) \ + ((X509_INFO *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \ + (where))) + +#define sk_X509_INFO_delete_ptr(sk, p) \ + ((X509_INFO *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \ + CHECKED_CAST(void *, X509_INFO *, p))) + +#define sk_X509_INFO_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_INFO *, p)) + +#define sk_X509_INFO_shift(sk) \ + ((X509_INFO *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk))) + +#define sk_X509_INFO_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \ + CHECKED_CAST(void *, X509_INFO *, p)) + +#define sk_X509_INFO_pop(sk) \ + ((X509_INFO *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk))) + +#define sk_X509_INFO_dup(sk) \ + ((STACK_OF(X509_INFO) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_INFO) *, sk))) + +#define sk_X509_INFO_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk)) + +#define sk_X509_INFO_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_INFO) *, sk)) + +#define sk_X509_INFO_set_cmp_func(sk, comp) \ + ((int (*)(const X509_INFO **a, const X509_INFO **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_INFO **a, const X509_INFO **b), comp))) + +#define sk_X509_INFO_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_INFO) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_INFO) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_INFO *(*)(X509_INFO *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_INFO *), free_func))) + +/* X509_LOOKUP */ +#define sk_X509_LOOKUP_new(comp) \ + ((STACK_OF(X509_LOOKUP) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const X509_LOOKUP **a, const X509_LOOKUP **b), \ + comp))) + +#define sk_X509_LOOKUP_new_null() ((STACK_OF(X509_LOOKUP) *)sk_new_null()) + +#define sk_X509_LOOKUP_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk)) + +#define sk_X509_LOOKUP_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk)); + +#define sk_X509_LOOKUP_value(sk, i) \ + ((X509_LOOKUP *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_LOOKUP) *, sk), (i))) + +#define sk_X509_LOOKUP_set(sk, i, p) \ + ((X509_LOOKUP *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \ + (i), CHECKED_CAST(void *, X509_LOOKUP *, p))) + +#define sk_X509_LOOKUP_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk)) + +#define sk_X509_LOOKUP_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_LOOKUP *), free_func)) + +#define sk_X509_LOOKUP_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \ + CHECKED_CAST(void *, X509_LOOKUP *, p), (where)) + +#define sk_X509_LOOKUP_delete(sk, where) \ + ((X509_LOOKUP *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), (where))) + +#define sk_X509_LOOKUP_delete_ptr(sk, p) \ + ((X509_LOOKUP *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \ + CHECKED_CAST(void *, X509_LOOKUP *, p))) + +#define sk_X509_LOOKUP_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_LOOKUP *, p)) + +#define sk_X509_LOOKUP_shift(sk) \ + ((X509_LOOKUP *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk))) + +#define sk_X509_LOOKUP_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \ + CHECKED_CAST(void *, X509_LOOKUP *, p)) + +#define sk_X509_LOOKUP_pop(sk) \ + ((X509_LOOKUP *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk))) + +#define sk_X509_LOOKUP_dup(sk) \ + ((STACK_OF(X509_LOOKUP) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_LOOKUP) *, sk))) + +#define sk_X509_LOOKUP_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk)) + +#define sk_X509_LOOKUP_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_LOOKUP) *, sk)) + +#define sk_X509_LOOKUP_set_cmp_func(sk, comp) \ + ((int (*)(const X509_LOOKUP **a, const X509_LOOKUP **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_LOOKUP **a, const X509_LOOKUP **b), \ + comp))) + +#define sk_X509_LOOKUP_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_LOOKUP) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_LOOKUP) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_LOOKUP *(*)(X509_LOOKUP *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_LOOKUP *), free_func))) + +/* X509_NAME */ +#define sk_X509_NAME_new(comp) \ + ((STACK_OF(X509_NAME) *)sk_new( \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_NAME **a, const X509_NAME **b), comp))) + +#define sk_X509_NAME_new_null() ((STACK_OF(X509_NAME) *)sk_new_null()) + +#define sk_X509_NAME_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk)) + +#define sk_X509_NAME_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk)); + +#define sk_X509_NAME_value(sk, i) \ + ((X509_NAME *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME) *, sk), (i))) + +#define sk_X509_NAME_set(sk, i, p) \ + ((X509_NAME *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), (i), \ + CHECKED_CAST(void *, X509_NAME *, p))) + +#define sk_X509_NAME_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk)) + +#define sk_X509_NAME_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_NAME *), free_func)) + +#define sk_X509_NAME_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \ + CHECKED_CAST(void *, X509_NAME *, p), (where)) + +#define sk_X509_NAME_delete(sk, where) \ + ((X509_NAME *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \ + (where))) + +#define sk_X509_NAME_delete_ptr(sk, p) \ + ((X509_NAME *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \ + CHECKED_CAST(void *, X509_NAME *, p))) + +#define sk_X509_NAME_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_NAME *, p)) + +#define sk_X509_NAME_shift(sk) \ + ((X509_NAME *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk))) + +#define sk_X509_NAME_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \ + CHECKED_CAST(void *, X509_NAME *, p)) + +#define sk_X509_NAME_pop(sk) \ + ((X509_NAME *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk))) + +#define sk_X509_NAME_dup(sk) \ + ((STACK_OF(X509_NAME) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME) *, sk))) + +#define sk_X509_NAME_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk)) + +#define sk_X509_NAME_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME) *, sk)) + +#define sk_X509_NAME_set_cmp_func(sk, comp) \ + ((int (*)(const X509_NAME **a, const X509_NAME **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_NAME **a, const X509_NAME **b), comp))) + +#define sk_X509_NAME_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_NAME) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_NAME) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_NAME *(*)(X509_NAME *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_NAME *), free_func))) + +/* X509_NAME_ENTRY */ +#define sk_X509_NAME_ENTRY_new(comp) \ + ((STACK_OF(X509_NAME_ENTRY) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const X509_NAME_ENTRY **a, const X509_NAME_ENTRY **b), comp))) + +#define sk_X509_NAME_ENTRY_new_null() \ + ((STACK_OF(X509_NAME_ENTRY) *)sk_new_null()) + +#define sk_X509_NAME_ENTRY_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk)) + +#define sk_X509_NAME_ENTRY_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk)); + +#define sk_X509_NAME_ENTRY_value(sk, i) \ + ((X509_NAME_ENTRY *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk), (i))) + +#define sk_X509_NAME_ENTRY_set(sk, i, p) \ + ((X509_NAME_ENTRY *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), (i), \ + CHECKED_CAST(void *, X509_NAME_ENTRY *, p))) + +#define sk_X509_NAME_ENTRY_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk)) + +#define sk_X509_NAME_ENTRY_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_NAME_ENTRY *), free_func)) + +#define sk_X509_NAME_ENTRY_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(void *, X509_NAME_ENTRY *, p), (where)) + +#define sk_X509_NAME_ENTRY_delete(sk, where) \ + ((X509_NAME_ENTRY *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), (where))) + +#define sk_X509_NAME_ENTRY_delete_ptr(sk, p) \ + ((X509_NAME_ENTRY *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(void *, X509_NAME_ENTRY *, p))) + +#define sk_X509_NAME_ENTRY_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \ + (out_index), CHECKED_CAST(void *, X509_NAME_ENTRY *, p)) + +#define sk_X509_NAME_ENTRY_shift(sk) \ + ((X509_NAME_ENTRY *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk))) + +#define sk_X509_NAME_ENTRY_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(void *, X509_NAME_ENTRY *, p)) + +#define sk_X509_NAME_ENTRY_pop(sk) \ + ((X509_NAME_ENTRY *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk))) + +#define sk_X509_NAME_ENTRY_dup(sk) \ + ((STACK_OF(X509_NAME_ENTRY) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk))) + +#define sk_X509_NAME_ENTRY_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk)) + +#define sk_X509_NAME_ENTRY_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk)) + +#define sk_X509_NAME_ENTRY_set_cmp_func(sk, comp) \ + ((int (*)(const X509_NAME_ENTRY **a, const X509_NAME_ENTRY **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const X509_NAME_ENTRY **a, \ + const X509_NAME_ENTRY **b), \ + comp))) + +#define sk_X509_NAME_ENTRY_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_NAME_ENTRY) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_NAME_ENTRY *(*)(X509_NAME_ENTRY *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_NAME_ENTRY *), free_func))) + +/* X509_OBJECT */ +#define sk_X509_OBJECT_new(comp) \ + ((STACK_OF(X509_OBJECT) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const X509_OBJECT **a, const X509_OBJECT **b), \ + comp))) + +#define sk_X509_OBJECT_new_null() ((STACK_OF(X509_OBJECT) *)sk_new_null()) + +#define sk_X509_OBJECT_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk)) + +#define sk_X509_OBJECT_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk)); + +#define sk_X509_OBJECT_value(sk, i) \ + ((X509_OBJECT *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_OBJECT) *, sk), (i))) + +#define sk_X509_OBJECT_set(sk, i, p) \ + ((X509_OBJECT *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \ + (i), CHECKED_CAST(void *, X509_OBJECT *, p))) + +#define sk_X509_OBJECT_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk)) + +#define sk_X509_OBJECT_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_OBJECT *), free_func)) + +#define sk_X509_OBJECT_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \ + CHECKED_CAST(void *, X509_OBJECT *, p), (where)) + +#define sk_X509_OBJECT_delete(sk, where) \ + ((X509_OBJECT *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), (where))) + +#define sk_X509_OBJECT_delete_ptr(sk, p) \ + ((X509_OBJECT *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \ + CHECKED_CAST(void *, X509_OBJECT *, p))) + +#define sk_X509_OBJECT_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_OBJECT *, p)) + +#define sk_X509_OBJECT_shift(sk) \ + ((X509_OBJECT *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk))) + +#define sk_X509_OBJECT_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \ + CHECKED_CAST(void *, X509_OBJECT *, p)) + +#define sk_X509_OBJECT_pop(sk) \ + ((X509_OBJECT *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk))) + +#define sk_X509_OBJECT_dup(sk) \ + ((STACK_OF(X509_OBJECT) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_OBJECT) *, sk))) + +#define sk_X509_OBJECT_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk)) + +#define sk_X509_OBJECT_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_OBJECT) *, sk)) + +#define sk_X509_OBJECT_set_cmp_func(sk, comp) \ + ((int (*)(const X509_OBJECT **a, const X509_OBJECT **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_OBJECT **a, const X509_OBJECT **b), \ + comp))) + +#define sk_X509_OBJECT_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_OBJECT) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_OBJECT) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_OBJECT *(*)(X509_OBJECT *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_OBJECT *), free_func))) + +/* X509_POLICY_DATA */ +#define sk_X509_POLICY_DATA_new(comp) \ + ((STACK_OF(X509_POLICY_DATA) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const X509_POLICY_DATA **a, const X509_POLICY_DATA **b), comp))) + +#define sk_X509_POLICY_DATA_new_null() \ + ((STACK_OF(X509_POLICY_DATA) *)sk_new_null()) + +#define sk_X509_POLICY_DATA_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk)) + +#define sk_X509_POLICY_DATA_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk)); + +#define sk_X509_POLICY_DATA_value(sk, i) \ + ((X509_POLICY_DATA *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_DATA) *, sk), (i))) + +#define sk_X509_POLICY_DATA_set(sk, i, p) \ + ((X509_POLICY_DATA *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), (i), \ + CHECKED_CAST(void *, X509_POLICY_DATA *, p))) + +#define sk_X509_POLICY_DATA_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk)) + +#define sk_X509_POLICY_DATA_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_POLICY_DATA *), free_func)) + +#define sk_X509_POLICY_DATA_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \ + CHECKED_CAST(void *, X509_POLICY_DATA *, p), (where)) + +#define sk_X509_POLICY_DATA_delete(sk, where) \ + ((X509_POLICY_DATA *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), (where))) + +#define sk_X509_POLICY_DATA_delete_ptr(sk, p) \ + ((X509_POLICY_DATA *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \ + CHECKED_CAST(void *, X509_POLICY_DATA *, p))) + +#define sk_X509_POLICY_DATA_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \ + (out_index), CHECKED_CAST(void *, X509_POLICY_DATA *, p)) + +#define sk_X509_POLICY_DATA_shift(sk) \ + ((X509_POLICY_DATA *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk))) + +#define sk_X509_POLICY_DATA_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \ + CHECKED_CAST(void *, X509_POLICY_DATA *, p)) + +#define sk_X509_POLICY_DATA_pop(sk) \ + ((X509_POLICY_DATA *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk))) + +#define sk_X509_POLICY_DATA_dup(sk) \ + ((STACK_OF(X509_POLICY_DATA) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_DATA) *, sk))) + +#define sk_X509_POLICY_DATA_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk)) + +#define sk_X509_POLICY_DATA_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_DATA) *, sk)) + +#define sk_X509_POLICY_DATA_set_cmp_func(sk, comp) \ + ((int (*)(const X509_POLICY_DATA **a, const X509_POLICY_DATA **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const X509_POLICY_DATA **a, \ + const X509_POLICY_DATA **b), \ + comp))) + +#define sk_X509_POLICY_DATA_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_POLICY_DATA) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_POLICY_DATA) *, sk), \ + CHECKED_CAST(void *(*)(void *), \ + X509_POLICY_DATA *(*)(X509_POLICY_DATA *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_POLICY_DATA *), \ + free_func))) + +/* X509_POLICY_NODE */ +#define sk_X509_POLICY_NODE_new(comp) \ + ((STACK_OF(X509_POLICY_NODE) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const X509_POLICY_NODE **a, const X509_POLICY_NODE **b), comp))) + +#define sk_X509_POLICY_NODE_new_null() \ + ((STACK_OF(X509_POLICY_NODE) *)sk_new_null()) + +#define sk_X509_POLICY_NODE_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk)) + +#define sk_X509_POLICY_NODE_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk)); + +#define sk_X509_POLICY_NODE_value(sk, i) \ + ((X509_POLICY_NODE *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_NODE) *, sk), (i))) + +#define sk_X509_POLICY_NODE_set(sk, i, p) \ + ((X509_POLICY_NODE *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), (i), \ + CHECKED_CAST(void *, X509_POLICY_NODE *, p))) + +#define sk_X509_POLICY_NODE_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk)) + +#define sk_X509_POLICY_NODE_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_POLICY_NODE *), free_func)) + +#define sk_X509_POLICY_NODE_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \ + CHECKED_CAST(void *, X509_POLICY_NODE *, p), (where)) + +#define sk_X509_POLICY_NODE_delete(sk, where) \ + ((X509_POLICY_NODE *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), (where))) + +#define sk_X509_POLICY_NODE_delete_ptr(sk, p) \ + ((X509_POLICY_NODE *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \ + CHECKED_CAST(void *, X509_POLICY_NODE *, p))) + +#define sk_X509_POLICY_NODE_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \ + (out_index), CHECKED_CAST(void *, X509_POLICY_NODE *, p)) + +#define sk_X509_POLICY_NODE_shift(sk) \ + ((X509_POLICY_NODE *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk))) + +#define sk_X509_POLICY_NODE_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \ + CHECKED_CAST(void *, X509_POLICY_NODE *, p)) + +#define sk_X509_POLICY_NODE_pop(sk) \ + ((X509_POLICY_NODE *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk))) + +#define sk_X509_POLICY_NODE_dup(sk) \ + ((STACK_OF(X509_POLICY_NODE) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_NODE) *, sk))) + +#define sk_X509_POLICY_NODE_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk)) + +#define sk_X509_POLICY_NODE_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_NODE) *, sk)) + +#define sk_X509_POLICY_NODE_set_cmp_func(sk, comp) \ + ((int (*)(const X509_POLICY_NODE **a, const X509_POLICY_NODE **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const X509_POLICY_NODE **a, \ + const X509_POLICY_NODE **b), \ + comp))) + +#define sk_X509_POLICY_NODE_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_POLICY_NODE) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_POLICY_NODE) *, sk), \ + CHECKED_CAST(void *(*)(void *), \ + X509_POLICY_NODE *(*)(X509_POLICY_NODE *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_POLICY_NODE *), \ + free_func))) + +/* X509_PURPOSE */ +#define sk_X509_PURPOSE_new(comp) \ + ((STACK_OF(X509_PURPOSE) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const X509_PURPOSE **a, const X509_PURPOSE **b), \ + comp))) + +#define sk_X509_PURPOSE_new_null() ((STACK_OF(X509_PURPOSE) *)sk_new_null()) + +#define sk_X509_PURPOSE_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk)) + +#define sk_X509_PURPOSE_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk)); + +#define sk_X509_PURPOSE_value(sk, i) \ + ((X509_PURPOSE *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_PURPOSE) *, sk), (i))) + +#define sk_X509_PURPOSE_set(sk, i, p) \ + ((X509_PURPOSE *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), (i), \ + CHECKED_CAST(void *, X509_PURPOSE *, p))) + +#define sk_X509_PURPOSE_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk)) + +#define sk_X509_PURPOSE_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_PURPOSE *), free_func)) + +#define sk_X509_PURPOSE_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), \ + CHECKED_CAST(void *, X509_PURPOSE *, p), (where)) + +#define sk_X509_PURPOSE_delete(sk, where) \ + ((X509_PURPOSE *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), (where))) + +#define sk_X509_PURPOSE_delete_ptr(sk, p) \ + ((X509_PURPOSE *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), \ + CHECKED_CAST(void *, X509_PURPOSE *, p))) + +#define sk_X509_PURPOSE_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_PURPOSE *, p)) + +#define sk_X509_PURPOSE_shift(sk) \ + ((X509_PURPOSE *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk))) + +#define sk_X509_PURPOSE_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), \ + CHECKED_CAST(void *, X509_PURPOSE *, p)) + +#define sk_X509_PURPOSE_pop(sk) \ + ((X509_PURPOSE *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk))) + +#define sk_X509_PURPOSE_dup(sk) \ + ((STACK_OF(X509_PURPOSE) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_PURPOSE) *, sk))) + +#define sk_X509_PURPOSE_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk)) + +#define sk_X509_PURPOSE_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_PURPOSE) *, sk)) + +#define sk_X509_PURPOSE_set_cmp_func(sk, comp) \ + ((int (*)(const X509_PURPOSE **a, const X509_PURPOSE **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_PURPOSE **a, const X509_PURPOSE **b), \ + comp))) + +#define sk_X509_PURPOSE_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_PURPOSE) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_PURPOSE) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_PURPOSE *(*)(X509_PURPOSE *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_PURPOSE *), free_func))) + +/* X509_REVOKED */ +#define sk_X509_REVOKED_new(comp) \ + ((STACK_OF(X509_REVOKED) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const X509_REVOKED **a, const X509_REVOKED **b), \ + comp))) + +#define sk_X509_REVOKED_new_null() ((STACK_OF(X509_REVOKED) *)sk_new_null()) + +#define sk_X509_REVOKED_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk)) + +#define sk_X509_REVOKED_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk)); + +#define sk_X509_REVOKED_value(sk, i) \ + ((X509_REVOKED *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_REVOKED) *, sk), (i))) + +#define sk_X509_REVOKED_set(sk, i, p) \ + ((X509_REVOKED *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), (i), \ + CHECKED_CAST(void *, X509_REVOKED *, p))) + +#define sk_X509_REVOKED_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk)) + +#define sk_X509_REVOKED_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_REVOKED *), free_func)) + +#define sk_X509_REVOKED_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), \ + CHECKED_CAST(void *, X509_REVOKED *, p), (where)) + +#define sk_X509_REVOKED_delete(sk, where) \ + ((X509_REVOKED *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), (where))) + +#define sk_X509_REVOKED_delete_ptr(sk, p) \ + ((X509_REVOKED *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), \ + CHECKED_CAST(void *, X509_REVOKED *, p))) + +#define sk_X509_REVOKED_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_REVOKED *, p)) + +#define sk_X509_REVOKED_shift(sk) \ + ((X509_REVOKED *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk))) + +#define sk_X509_REVOKED_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), \ + CHECKED_CAST(void *, X509_REVOKED *, p)) + +#define sk_X509_REVOKED_pop(sk) \ + ((X509_REVOKED *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk))) + +#define sk_X509_REVOKED_dup(sk) \ + ((STACK_OF(X509_REVOKED) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_REVOKED) *, sk))) + +#define sk_X509_REVOKED_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk)) + +#define sk_X509_REVOKED_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_REVOKED) *, sk)) + +#define sk_X509_REVOKED_set_cmp_func(sk, comp) \ + ((int (*)(const X509_REVOKED **a, const X509_REVOKED **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_REVOKED **a, const X509_REVOKED **b), \ + comp))) + +#define sk_X509_REVOKED_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_REVOKED) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_REVOKED) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_REVOKED *(*)(X509_REVOKED *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_REVOKED *), free_func))) + +/* X509_TRUST */ +#define sk_X509_TRUST_new(comp) \ + ((STACK_OF(X509_TRUST) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const X509_TRUST **a, const X509_TRUST **b), \ + comp))) + +#define sk_X509_TRUST_new_null() ((STACK_OF(X509_TRUST) *)sk_new_null()) + +#define sk_X509_TRUST_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk)) + +#define sk_X509_TRUST_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk)); + +#define sk_X509_TRUST_value(sk, i) \ + ((X509_TRUST *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_TRUST) *, sk), (i))) + +#define sk_X509_TRUST_set(sk, i, p) \ + ((X509_TRUST *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \ + (i), CHECKED_CAST(void *, X509_TRUST *, p))) + +#define sk_X509_TRUST_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk)) + +#define sk_X509_TRUST_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_TRUST *), free_func)) + +#define sk_X509_TRUST_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \ + CHECKED_CAST(void *, X509_TRUST *, p), (where)) + +#define sk_X509_TRUST_delete(sk, where) \ + ((X509_TRUST *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \ + (where))) + +#define sk_X509_TRUST_delete_ptr(sk, p) \ + ((X509_TRUST *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \ + CHECKED_CAST(void *, X509_TRUST *, p))) + +#define sk_X509_TRUST_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_TRUST *, p)) + +#define sk_X509_TRUST_shift(sk) \ + ((X509_TRUST *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk))) + +#define sk_X509_TRUST_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \ + CHECKED_CAST(void *, X509_TRUST *, p)) + +#define sk_X509_TRUST_pop(sk) \ + ((X509_TRUST *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk))) + +#define sk_X509_TRUST_dup(sk) \ + ((STACK_OF(X509_TRUST) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_TRUST) *, sk))) + +#define sk_X509_TRUST_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk)) + +#define sk_X509_TRUST_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_TRUST) *, sk)) + +#define sk_X509_TRUST_set_cmp_func(sk, comp) \ + ((int (*)(const X509_TRUST **a, const X509_TRUST **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_TRUST **a, const X509_TRUST **b), \ + comp))) + +#define sk_X509_TRUST_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_TRUST) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_TRUST) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_TRUST *(*)(X509_TRUST *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_TRUST *), free_func))) + +/* X509_VERIFY_PARAM */ +#define sk_X509_VERIFY_PARAM_new(comp) \ + ((STACK_OF(X509_VERIFY_PARAM) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const X509_VERIFY_PARAM **a, const X509_VERIFY_PARAM **b), \ + comp))) + +#define sk_X509_VERIFY_PARAM_new_null() \ + ((STACK_OF(X509_VERIFY_PARAM) *)sk_new_null()) + +#define sk_X509_VERIFY_PARAM_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk)) + +#define sk_X509_VERIFY_PARAM_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk)); + +#define sk_X509_VERIFY_PARAM_value(sk, i) \ + ((X509_VERIFY_PARAM *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_VERIFY_PARAM) *, sk), (i))) + +#define sk_X509_VERIFY_PARAM_set(sk, i, p) \ + ((X509_VERIFY_PARAM *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), (i), \ + CHECKED_CAST(void *, X509_VERIFY_PARAM *, p))) + +#define sk_X509_VERIFY_PARAM_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk)) + +#define sk_X509_VERIFY_PARAM_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_VERIFY_PARAM *), \ + free_func)) + +#define sk_X509_VERIFY_PARAM_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), \ + CHECKED_CAST(void *, X509_VERIFY_PARAM *, p), (where)) + +#define sk_X509_VERIFY_PARAM_delete(sk, where) \ + ((X509_VERIFY_PARAM *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), (where))) + +#define sk_X509_VERIFY_PARAM_delete_ptr(sk, p) \ + ((X509_VERIFY_PARAM *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), \ + CHECKED_CAST(void *, X509_VERIFY_PARAM *, p))) + +#define sk_X509_VERIFY_PARAM_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), \ + (out_index), CHECKED_CAST(void *, X509_VERIFY_PARAM *, p)) + +#define sk_X509_VERIFY_PARAM_shift(sk) \ + ((X509_VERIFY_PARAM *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk))) + +#define sk_X509_VERIFY_PARAM_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), \ + CHECKED_CAST(void *, X509_VERIFY_PARAM *, p)) + +#define sk_X509_VERIFY_PARAM_pop(sk) \ + ((X509_VERIFY_PARAM *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk))) + +#define sk_X509_VERIFY_PARAM_dup(sk) \ + ((STACK_OF(X509_VERIFY_PARAM) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_VERIFY_PARAM) *, sk))) + +#define sk_X509_VERIFY_PARAM_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk)) + +#define sk_X509_VERIFY_PARAM_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_VERIFY_PARAM) *, sk)) + +#define sk_X509_VERIFY_PARAM_set_cmp_func(sk, comp) \ + ((int (*)(const X509_VERIFY_PARAM **a, const X509_VERIFY_PARAM **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const X509_VERIFY_PARAM **a, \ + const X509_VERIFY_PARAM **b), \ + comp))) + +#define sk_X509_VERIFY_PARAM_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_VERIFY_PARAM) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_VERIFY_PARAM) *, sk), \ + CHECKED_CAST(void *(*)(void *), \ + X509_VERIFY_PARAM *(*)(X509_VERIFY_PARAM *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_VERIFY_PARAM *), \ + free_func))) + +/* void */ +#define sk_void_new(comp) \ + ((STACK_OF(void)*)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const void **a, const void **b), comp))) + +#define sk_void_new_null() ((STACK_OF(void)*)sk_new_null()) + +#define sk_void_num(sk) sk_num(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk)) + +#define sk_void_zero(sk) sk_zero(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk)); + +#define sk_void_value(sk, i) \ + ((void *)sk_value(CHECKED_CAST(_STACK *, const STACK_OF(void) *, sk), (i))) + +#define sk_void_set(sk, i, p) \ + ((void *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), (i), \ + CHECKED_CAST(void *, void *, p))) + +#define sk_void_free(sk) sk_free(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk)) + +#define sk_void_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(void *), free_func)) + +#define sk_void_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk), \ + CHECKED_CAST(void *, void *, p), (where)) + +#define sk_void_delete(sk, where) \ + ((void *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), (where))) + +#define sk_void_delete_ptr(sk, p) \ + ((void *)sk_delete_ptr(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), \ + CHECKED_CAST(void *, void *, p))) + +#define sk_void_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk), (out_index), \ + CHECKED_CAST(void *, void *, p)) + +#define sk_void_shift(sk) \ + ((void *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk))) + +#define sk_void_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk), \ + CHECKED_CAST(void *, void *, p)) + +#define sk_void_pop(sk) \ + ((void *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk))) + +#define sk_void_dup(sk) \ + ((STACK_OF(void)*)sk_dup(CHECKED_CAST(_STACK *, const STACK_OF(void) *, sk))) + +#define sk_void_sort(sk) sk_sort(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk)) + +#define sk_void_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(void) *, sk)) + +#define sk_void_set_cmp_func(sk, comp) \ + ((int (*)(const void **a, const void **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const void **a, const void **b), \ + comp))) + +#define sk_void_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(void)*)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(void) *, sk), \ + CHECKED_CAST(void *(*)(void *), void *(*)(void *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(void *), free_func))) + +/* SRTP_PROTECTION_PROFILE */ +#define sk_SRTP_PROTECTION_PROFILE_new(comp) \ + ((STACK_OF(SRTP_PROTECTION_PROFILE) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const const SRTP_PROTECTION_PROFILE **a, \ + const const SRTP_PROTECTION_PROFILE **b), \ + comp))) + +#define sk_SRTP_PROTECTION_PROFILE_new_null() \ + ((STACK_OF(SRTP_PROTECTION_PROFILE) *)sk_new_null()) + +#define sk_SRTP_PROTECTION_PROFILE_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk)) + +#define sk_SRTP_PROTECTION_PROFILE_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk)); + +#define sk_SRTP_PROTECTION_PROFILE_value(sk, i) \ + ((const SRTP_PROTECTION_PROFILE *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \ + (i))) + +#define sk_SRTP_PROTECTION_PROFILE_set(sk, i, p) \ + ((const SRTP_PROTECTION_PROFILE *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), (i), \ + CHECKED_CAST(void *, const SRTP_PROTECTION_PROFILE *, p))) + +#define sk_SRTP_PROTECTION_PROFILE_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk)) + +#define sk_SRTP_PROTECTION_PROFILE_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \ + CHECKED_CAST(void (*)(void *), \ + void (*)(const SRTP_PROTECTION_PROFILE *), free_func)) + +#define sk_SRTP_PROTECTION_PROFILE_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \ + CHECKED_CAST(void *, const SRTP_PROTECTION_PROFILE *, p), (where)) + +#define sk_SRTP_PROTECTION_PROFILE_delete(sk, where) \ + ((const SRTP_PROTECTION_PROFILE *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \ + (where))) + +#define sk_SRTP_PROTECTION_PROFILE_delete_ptr(sk, p) \ + ((const SRTP_PROTECTION_PROFILE *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \ + CHECKED_CAST(void *, const SRTP_PROTECTION_PROFILE *, p))) + +#define sk_SRTP_PROTECTION_PROFILE_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \ + (out_index), \ + CHECKED_CAST(void *, const SRTP_PROTECTION_PROFILE *, p)) + +#define sk_SRTP_PROTECTION_PROFILE_shift(sk) \ + ((const SRTP_PROTECTION_PROFILE *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk))) + +#define sk_SRTP_PROTECTION_PROFILE_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \ + CHECKED_CAST(void *, const SRTP_PROTECTION_PROFILE *, p)) + +#define sk_SRTP_PROTECTION_PROFILE_pop(sk) \ + ((const SRTP_PROTECTION_PROFILE *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk))) + +#define sk_SRTP_PROTECTION_PROFILE_dup(sk) \ + ((STACK_OF(SRTP_PROTECTION_PROFILE) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(SRTP_PROTECTION_PROFILE) *, sk))) + +#define sk_SRTP_PROTECTION_PROFILE_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk)) + +#define sk_SRTP_PROTECTION_PROFILE_is_sorted(sk) \ + sk_is_sorted( \ + CHECKED_CAST(_STACK *, const STACK_OF(SRTP_PROTECTION_PROFILE) *, sk)) + +#define sk_SRTP_PROTECTION_PROFILE_set_cmp_func(sk, comp) \ + ((int (*)(const SRTP_PROTECTION_PROFILE **a, \ + const SRTP_PROTECTION_PROFILE **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const SRTP_PROTECTION_PROFILE **a, \ + const SRTP_PROTECTION_PROFILE **b), \ + comp))) + +#define sk_SRTP_PROTECTION_PROFILE_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(SRTP_PROTECTION_PROFILE) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(SRTP_PROTECTION_PROFILE) *, \ + sk), \ + CHECKED_CAST(void *(*)(void *), const SRTP_PROTECTION_PROFILE *(*)( \ + const SRTP_PROTECTION_PROFILE *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), \ + void (*)(const SRTP_PROTECTION_PROFILE *), free_func))) + +/* SSL_CIPHER */ +#define sk_SSL_CIPHER_new(comp) \ + ((STACK_OF(SSL_CIPHER) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const const SSL_CIPHER **a, const const SSL_CIPHER **b), comp))) + +#define sk_SSL_CIPHER_new_null() ((STACK_OF(SSL_CIPHER) *)sk_new_null()) + +#define sk_SSL_CIPHER_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk)) + +#define sk_SSL_CIPHER_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk)); + +#define sk_SSL_CIPHER_value(sk, i) \ + ((const SSL_CIPHER *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(SSL_CIPHER) *, sk), (i))) + +#define sk_SSL_CIPHER_set(sk, i, p) \ + ((const SSL_CIPHER *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), (i), \ + CHECKED_CAST(void *, const SSL_CIPHER *, p))) + +#define sk_SSL_CIPHER_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk)) + +#define sk_SSL_CIPHER_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(const SSL_CIPHER *), free_func)) + +#define sk_SSL_CIPHER_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), \ + CHECKED_CAST(void *, const SSL_CIPHER *, p), (where)) + +#define sk_SSL_CIPHER_delete(sk, where) \ + ((const SSL_CIPHER *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), (where))) + +#define sk_SSL_CIPHER_delete_ptr(sk, p) \ + ((const SSL_CIPHER *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), \ + CHECKED_CAST(void *, const SSL_CIPHER *, p))) + +#define sk_SSL_CIPHER_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), (out_index), \ + CHECKED_CAST(void *, const SSL_CIPHER *, p)) + +#define sk_SSL_CIPHER_shift(sk) \ + ((const SSL_CIPHER *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk))) + +#define sk_SSL_CIPHER_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), \ + CHECKED_CAST(void *, const SSL_CIPHER *, p)) + +#define sk_SSL_CIPHER_pop(sk) \ + ((const SSL_CIPHER *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk))) + +#define sk_SSL_CIPHER_dup(sk) \ + ((STACK_OF(SSL_CIPHER) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(SSL_CIPHER) *, sk))) + +#define sk_SSL_CIPHER_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk)) + +#define sk_SSL_CIPHER_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(SSL_CIPHER) *, sk)) + +#define sk_SSL_CIPHER_set_cmp_func(sk, comp) \ + ((int (*)(const SSL_CIPHER **a, const SSL_CIPHER **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const SSL_CIPHER **a, const SSL_CIPHER **b), \ + comp))) + +#define sk_SSL_CIPHER_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(SSL_CIPHER) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(SSL_CIPHER) *, sk), \ + CHECKED_CAST(void *(*)(void *), \ + const SSL_CIPHER *(*)(const SSL_CIPHER *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(const SSL_CIPHER *), \ + free_func))) + +/* OPENSSL_STRING */ +#define sk_OPENSSL_STRING_new(comp) \ + ((STACK_OF(OPENSSL_STRING) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const OPENSSL_STRING *a, const OPENSSL_STRING *b), comp))) + +#define sk_OPENSSL_STRING_new_null() ((STACK_OF(OPENSSL_STRING) *)sk_new_null()) + +#define sk_OPENSSL_STRING_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk)) + +#define sk_OPENSSL_STRING_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk)); + +#define sk_OPENSSL_STRING_value(sk, i) \ + ((OPENSSL_STRING)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(OPENSSL_STRING) *, sk), (i))) + +#define sk_OPENSSL_STRING_set(sk, i, p) \ + ((OPENSSL_STRING)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), (i), \ + CHECKED_CAST(void *, OPENSSL_STRING, p))) + +#define sk_OPENSSL_STRING_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk)) + +#define sk_OPENSSL_STRING_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(OPENSSL_STRING), free_func)) + +#define sk_OPENSSL_STRING_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), \ + CHECKED_CAST(void *, OPENSSL_STRING, p), (where)) + +#define sk_OPENSSL_STRING_delete(sk, where) \ + ((OPENSSL_STRING)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), (where))) + +#define sk_OPENSSL_STRING_delete_ptr(sk, p) \ + ((OPENSSL_STRING)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), \ + CHECKED_CAST(void *, OPENSSL_STRING, p))) + +#define sk_OPENSSL_STRING_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), (out_index), \ + CHECKED_CAST(void *, OPENSSL_STRING, p)) + +#define sk_OPENSSL_STRING_shift(sk) \ + ((OPENSSL_STRING)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk))) + +#define sk_OPENSSL_STRING_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), \ + CHECKED_CAST(void *, OPENSSL_STRING, p)) + +#define sk_OPENSSL_STRING_pop(sk) \ + ((OPENSSL_STRING)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk))) + +#define sk_OPENSSL_STRING_dup(sk) \ + ((STACK_OF(OPENSSL_STRING) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(OPENSSL_STRING) *, sk))) + +#define sk_OPENSSL_STRING_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk)) + +#define sk_OPENSSL_STRING_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(OPENSSL_STRING) *, sk)) + +#define sk_OPENSSL_STRING_set_cmp_func(sk, comp) \ + ((int (*)(const OPENSSL_STRING **a, const OPENSSL_STRING **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const OPENSSL_STRING **a, \ + const OPENSSL_STRING **b), \ + comp))) + +#define sk_OPENSSL_STRING_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(OPENSSL_STRING) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(OPENSSL_STRING) *, sk), \ + CHECKED_CAST(void *(*)(void *), OPENSSL_STRING (*)(OPENSSL_STRING), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(OPENSSL_STRING), free_func))) + +/* OPENSSL_BLOCK */ +#define sk_OPENSSL_BLOCK_new(comp) \ + ((STACK_OF(OPENSSL_BLOCK) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const OPENSSL_BLOCK *a, const OPENSSL_BLOCK *b), \ + comp))) + +#define sk_OPENSSL_BLOCK_new_null() ((STACK_OF(OPENSSL_BLOCK) *)sk_new_null()) + +#define sk_OPENSSL_BLOCK_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk)) + +#define sk_OPENSSL_BLOCK_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk)); + +#define sk_OPENSSL_BLOCK_value(sk, i) \ + ((OPENSSL_BLOCK)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(OPENSSL_BLOCK) *, sk), (i))) + +#define sk_OPENSSL_BLOCK_set(sk, i, p) \ + ((OPENSSL_BLOCK)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), (i), \ + CHECKED_CAST(void *, OPENSSL_BLOCK, p))) + +#define sk_OPENSSL_BLOCK_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk)) + +#define sk_OPENSSL_BLOCK_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(OPENSSL_BLOCK), free_func)) + +#define sk_OPENSSL_BLOCK_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), \ + CHECKED_CAST(void *, OPENSSL_BLOCK, p), (where)) + +#define sk_OPENSSL_BLOCK_delete(sk, where) \ + ((OPENSSL_BLOCK)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), (where))) + +#define sk_OPENSSL_BLOCK_delete_ptr(sk, p) \ + ((OPENSSL_BLOCK)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), \ + CHECKED_CAST(void *, OPENSSL_BLOCK, p))) + +#define sk_OPENSSL_BLOCK_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), (out_index), \ + CHECKED_CAST(void *, OPENSSL_BLOCK, p)) + +#define sk_OPENSSL_BLOCK_shift(sk) \ + ((OPENSSL_BLOCK)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk))) + +#define sk_OPENSSL_BLOCK_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), \ + CHECKED_CAST(void *, OPENSSL_BLOCK, p)) + +#define sk_OPENSSL_BLOCK_pop(sk) \ + ((OPENSSL_BLOCK)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk))) + +#define sk_OPENSSL_BLOCK_dup(sk) \ + ((STACK_OF(OPENSSL_BLOCK) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(OPENSSL_BLOCK) *, sk))) + +#define sk_OPENSSL_BLOCK_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk)) + +#define sk_OPENSSL_BLOCK_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(OPENSSL_BLOCK) *, sk)) + +#define sk_OPENSSL_BLOCK_set_cmp_func(sk, comp) \ + ((int (*)(const OPENSSL_BLOCK **a, const OPENSSL_BLOCK **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const OPENSSL_BLOCK **a, const OPENSSL_BLOCK **b), \ + comp))) + +#define sk_OPENSSL_BLOCK_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(OPENSSL_BLOCK) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(OPENSSL_BLOCK) *, sk), \ + CHECKED_CAST(void *(*)(void *), OPENSSL_BLOCK (*)(OPENSSL_BLOCK), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(OPENSSL_BLOCK), free_func))) diff --git a/TMessagesProj/jni/boringssl/include/openssl/thread.h b/TMessagesProj/jni/boringssl/include/openssl/thread.h new file mode 100644 index 00000000..568a8583 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/thread.h @@ -0,0 +1,173 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_THREAD_H +#define OPENSSL_HEADER_THREAD_H + +#include + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +#if defined(OPENSSL_NO_THREADS) +typedef struct crypto_mutex_st {} CRYPTO_MUTEX; +#elif defined(OPENSSL_WINDOWS) +/* CRYPTO_MUTEX can appear in public header files so we really don't want to + * pull in windows.h. It's statically asserted that this structure is large + * enough to contain a Windows CRITICAL_SECTION by thread_win.c. */ +typedef union crypto_mutex_st { + double alignment; + uint8_t padding[4*sizeof(void*) + 2*sizeof(int)]; +} CRYPTO_MUTEX; +#elif defined(__MACH__) && defined(__APPLE__) +typedef pthread_rwlock_t CRYPTO_MUTEX; +#else +/* It is reasonable to include pthread.h on non-Windows systems, however the + * |pthread_rwlock_t| that we need is hidden under feature flags, and we can't + * ensure that we'll be able to get it. It's statically asserted that this + * structure is large enough to contain a |pthread_rwlock_t| by + * thread_pthread.c. */ +typedef union crypto_mutex_st { + double alignment; + uint8_t padding[3*sizeof(int) + 5*sizeof(unsigned) + 16 + 8]; +} CRYPTO_MUTEX; +#endif + +/* CRYPTO_refcount_t is the type of a reference count. + * + * Since some platforms use C11 atomics to access this, it should have the + * _Atomic qualifier. However, this header is included by C++ programs as well + * as C code that might not set -std=c11. So, in practice, it's not possible to + * do that. Instead we statically assert that the size and native alignment of + * a plain uint32_t and an _Atomic uint32_t are equal in refcount_c11.c. */ +typedef uint32_t CRYPTO_refcount_t; + + +/* Deprecated functions */ + +/* These defines do nothing but are provided to make old code easier to + * compile. */ +#define CRYPTO_LOCK 1 +#define CRYPTO_UNLOCK 2 +#define CRYPTO_READ 4 +#define CRYPTO_WRITE 8 + +/* CRYPTO_num_locks returns one. (This is non-zero that callers who allocate + * sizeof(lock) times this value don't get zero and then fail because malloc(0) + * returned NULL.) */ +OPENSSL_EXPORT int CRYPTO_num_locks(void); + +/* CRYPTO_set_locking_callback does nothing. */ +OPENSSL_EXPORT void CRYPTO_set_locking_callback( + void (*func)(int mode, int lock_num, const char *file, int line)); + +/* CRYPTO_set_add_lock_callback does nothing. */ +OPENSSL_EXPORT void CRYPTO_set_add_lock_callback(int (*func)( + int *num, int amount, int lock_num, const char *file, int line)); + +/* CRYPTO_get_lock_name returns a fixed, dummy string. */ +OPENSSL_EXPORT const char *CRYPTO_get_lock_name(int lock_num); + +/* CRYPTO_THREADID_set_callback returns one. */ +OPENSSL_EXPORT int CRYPTO_THREADID_set_callback( + void (*threadid_func)(CRYPTO_THREADID *threadid)); + +/* CRYPTO_THREADID_set_numeric does nothing. */ +OPENSSL_EXPORT void CRYPTO_THREADID_set_numeric(CRYPTO_THREADID *id, + unsigned long val); + +/* CRYPTO_THREADID_set_pointer does nothing. */ +OPENSSL_EXPORT void CRYPTO_THREADID_set_pointer(CRYPTO_THREADID *id, void *ptr); + +/* CRYPTO_THREADID_current does nothing. */ +OPENSSL_EXPORT void CRYPTO_THREADID_current(CRYPTO_THREADID *id); + + +/* Private functions. + * + * Some old code calls these functions and so no-op implementations are + * provided. + * + * TODO(fork): cleanup callers and remove. */ + +OPENSSL_EXPORT void CRYPTO_set_id_callback(unsigned long (*func)(void)); + +typedef struct { + int references; + struct CRYPTO_dynlock_value *data; +} CRYPTO_dynlock; + +OPENSSL_EXPORT void CRYPTO_set_dynlock_create_callback( + struct CRYPTO_dynlock_value *(*dyn_create_function)(const char *file, + int line)); + +OPENSSL_EXPORT void CRYPTO_set_dynlock_lock_callback(void (*dyn_lock_function)( + int mode, struct CRYPTO_dynlock_value *l, const char *file, int line)); + +OPENSSL_EXPORT void CRYPTO_set_dynlock_destroy_callback( + void (*dyn_destroy_function)(struct CRYPTO_dynlock_value *l, + const char *file, int line)); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_THREAD_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/time_support.h b/TMessagesProj/jni/boringssl/include/openssl/time_support.h new file mode 100644 index 00000000..912e6724 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/time_support.h @@ -0,0 +1,90 @@ +/* Written by Richard Levitte (richard@levitte.org) for the OpenSSL + * project 2001. + * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2008. + */ +/* ==================================================================== + * Copyright (c) 2001 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef OPENSSL_HEADER_TIME_H +#define OPENSSL_HEADER_TIME_H + +#include + + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Wrapper functions for time functions. */ + + +/* OPENSSL_gmtime wraps |gmtime_r|. See the manual page for that function. */ +struct tm *OPENSSL_gmtime(const time_t *timer, struct tm *result); + +/* OPENSSL_gmtime_adj updates |tm| by adding |offset_day| days and |offset_sec| + * seconds. */ +int OPENSSL_gmtime_adj(struct tm *tm, int offset_day, long offset_sec); + +/* OPENSSL_gmtime_diff calculates the difference between |from| and |to| and + * outputs the difference as a number of days and seconds in |*out_days| and + * |*out_secs|. */ +int OPENSSL_gmtime_diff(int *out_days, int *out_secs, const struct tm *from, + const struct tm *to); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_TIME_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/tls1.h b/TMessagesProj/jni/boringssl/include/openssl/tls1.h new file mode 100644 index 00000000..b68db3d6 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/tls1.h @@ -0,0 +1,672 @@ +/* ssl/tls1.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * ECC cipher suite support in OpenSSL originally written by + * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories. + * + */ +/* ==================================================================== + * Copyright 2005 Nokia. All rights reserved. + * + * The portions of the attached software ("Contribution") is developed by + * Nokia Corporation and is licensed pursuant to the OpenSSL open source + * license. + * + * The Contribution, originally written by Mika Kousa and Pasi Eronen of + * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites + * support (see RFC 4279) to OpenSSL. + * + * No patent licenses or other rights except those expressly stated in + * the OpenSSL open source license shall be deemed granted or received + * expressly, by implication, estoppel, or otherwise. + * + * No assurances are provided by Nokia that the Contribution does not + * infringe the patent or other intellectual property rights of any third + * party or that the license provides you with all the necessary rights + * to make use of the Contribution. + * + * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN + * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA + * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY + * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR + * OTHERWISE. + */ + +#ifndef HEADER_TLS1_H +#define HEADER_TLS1_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +#define TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES 0 + +#define TLS1_AD_DECRYPTION_FAILED 21 +#define TLS1_AD_RECORD_OVERFLOW 22 +#define TLS1_AD_UNKNOWN_CA 48 /* fatal */ +#define TLS1_AD_ACCESS_DENIED 49 /* fatal */ +#define TLS1_AD_DECODE_ERROR 50 /* fatal */ +#define TLS1_AD_DECRYPT_ERROR 51 +#define TLS1_AD_EXPORT_RESTRICTION 60 /* fatal */ +#define TLS1_AD_PROTOCOL_VERSION 70 /* fatal */ +#define TLS1_AD_INSUFFICIENT_SECURITY 71 /* fatal */ +#define TLS1_AD_INTERNAL_ERROR 80 /* fatal */ +#define TLS1_AD_USER_CANCELLED 90 +#define TLS1_AD_NO_RENEGOTIATION 100 +/* codes 110-114 are from RFC3546 */ +#define TLS1_AD_UNSUPPORTED_EXTENSION 110 +#define TLS1_AD_CERTIFICATE_UNOBTAINABLE 111 +#define TLS1_AD_UNRECOGNIZED_NAME 112 +#define TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE 113 +#define TLS1_AD_BAD_CERTIFICATE_HASH_VALUE 114 +#define TLS1_AD_UNKNOWN_PSK_IDENTITY 115 /* fatal */ + +/* ExtensionType values from RFC3546 / RFC4366 / RFC6066 */ +#define TLSEXT_TYPE_server_name 0 +#define TLSEXT_TYPE_max_fragment_length 1 +#define TLSEXT_TYPE_client_certificate_url 2 +#define TLSEXT_TYPE_trusted_ca_keys 3 +#define TLSEXT_TYPE_truncated_hmac 4 +#define TLSEXT_TYPE_status_request 5 +/* ExtensionType values from RFC4681 */ +#define TLSEXT_TYPE_user_mapping 6 + +/* ExtensionType values from RFC5878 */ +#define TLSEXT_TYPE_client_authz 7 +#define TLSEXT_TYPE_server_authz 8 + +/* ExtensionType values from RFC6091 */ +#define TLSEXT_TYPE_cert_type 9 + +/* ExtensionType values from RFC4492 */ +#define TLSEXT_TYPE_elliptic_curves 10 +#define TLSEXT_TYPE_ec_point_formats 11 + +/* ExtensionType value from RFC5054 */ +#define TLSEXT_TYPE_srp 12 + +/* ExtensionType values from RFC5246 */ +#define TLSEXT_TYPE_signature_algorithms 13 + +/* ExtensionType value from RFC5764 */ +#define TLSEXT_TYPE_srtp 14 + +/* ExtensionType value from RFC5620 */ +#define TLSEXT_TYPE_heartbeat 15 + +/* ExtensionType value from RFC7301 */ +#define TLSEXT_TYPE_application_layer_protocol_negotiation 16 + +/* ExtensionType value for TLS padding extension. + * http://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml + * http://tools.ietf.org/html/draft-agl-tls-padding-03 + */ +#define TLSEXT_TYPE_padding 21 + +/* https://tools.ietf.org/html/draft-ietf-tls-session-hash-01 */ +#define TLSEXT_TYPE_extended_master_secret 23 + +/* ExtensionType value from RFC4507 */ +#define TLSEXT_TYPE_session_ticket 35 + +/* ExtensionType value from RFC5746 */ +#define TLSEXT_TYPE_renegotiate 0xff01 + +/* ExtensionType value from RFC6962 */ +#define TLSEXT_TYPE_certificate_timestamp 18 + +/* This is not an IANA defined extension number */ +#define TLSEXT_TYPE_next_proto_neg 13172 + +/* This is not an IANA defined extension number */ +#define TLSEXT_TYPE_channel_id 30032 + +/* NameType value from RFC 3546 */ +#define TLSEXT_NAMETYPE_host_name 0 +/* status request value from RFC 3546 */ +#define TLSEXT_STATUSTYPE_ocsp 1 + +/* ECPointFormat values from RFC 4492 */ +#define TLSEXT_ECPOINTFORMAT_uncompressed 0 +#define TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime 1 +#define TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2 2 + +/* Signature and hash algorithms from RFC 5246 */ + +#define TLSEXT_signature_anonymous 0 +#define TLSEXT_signature_rsa 1 +#define TLSEXT_signature_dsa 2 +#define TLSEXT_signature_ecdsa 3 + +#define TLSEXT_hash_none 0 +#define TLSEXT_hash_md5 1 +#define TLSEXT_hash_sha1 2 +#define TLSEXT_hash_sha224 3 +#define TLSEXT_hash_sha256 4 +#define TLSEXT_hash_sha384 5 +#define TLSEXT_hash_sha512 6 + +/* Flag set for unrecognised algorithms */ +#define TLSEXT_nid_unknown 0x1000000 + +/* ECC curves */ + +#define TLSEXT_curve_P_256 23 +#define TLSEXT_curve_P_384 24 + + +#define TLSEXT_MAXLEN_host_name 255 + +OPENSSL_EXPORT const char *SSL_get_servername(const SSL *s, const int type); +OPENSSL_EXPORT int SSL_get_servername_type(const SSL *s); + +/* SSL_export_keying_material exports a value derived from the master secret, as + * specified in RFC 5705. It writes |out_len| bytes to |out| given a label and + * optional context. (Since a zero length context is allowed, the |use_context| + * flag controls whether a context is included.) + * + * It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int SSL_export_keying_material( + SSL *s, uint8_t *out, size_t out_len, const char *label, size_t label_len, + const uint8_t *context, size_t context_len, int use_context); + +/* SSL_set_tlsext_host_name, for a client, configures |ssl| to advertise |name| + * in the server_name extension. It returns one on success and zero on error. */ +OPENSSL_EXPORT int SSL_set_tlsext_host_name(SSL *ssl, const char *name); + +/* SSL_CTX_set_tlsext_servername_callback configures |callback| to be called on + * the server after ClientHello extensions have been parsed and returns one. + * |callback| may use |SSL_get_servername| to examine the server_name extension + * and return a |SSL_TLSEXT_ERR_*| value. If it returns |SSL_TLSEXT_ERR_NOACK|, + * the server_name extension is not acknowledged in the ServerHello. If the + * return value signals an alert, |callback| should set |*out_alert| to the + * alert to send. */ +OPENSSL_EXPORT int SSL_CTX_set_tlsext_servername_callback( + SSL_CTX *ctx, int (*callback)(SSL *ssl, int *out_alert, void *arg)); + +#define SSL_TLSEXT_ERR_OK 0 +#define SSL_TLSEXT_ERR_ALERT_WARNING 1 +#define SSL_TLSEXT_ERR_ALERT_FATAL 2 +#define SSL_TLSEXT_ERR_NOACK 3 + +/* SSL_CTX_set_tlsext_servername_arg sets the argument to the servername + * callback and returns one. See |SSL_CTX_set_tlsext_servername_callback|. */ +OPENSSL_EXPORT int SSL_CTX_set_tlsext_servername_arg(SSL_CTX *ctx, void *arg); + +/* PSK ciphersuites from 4279 */ +#define TLS1_CK_PSK_WITH_RC4_128_SHA 0x0300008A +#define TLS1_CK_PSK_WITH_3DES_EDE_CBC_SHA 0x0300008B +#define TLS1_CK_PSK_WITH_AES_128_CBC_SHA 0x0300008C +#define TLS1_CK_PSK_WITH_AES_256_CBC_SHA 0x0300008D + +/* PSK ciphersuites from RFC 5489 */ +#define TLS1_CK_ECDHE_PSK_WITH_AES_128_CBC_SHA 0x0300C035 +#define TLS1_CK_ECDHE_PSK_WITH_AES_256_CBC_SHA 0x0300C036 + +/* Additional TLS ciphersuites from expired Internet Draft + * draft-ietf-tls-56-bit-ciphersuites-01.txt + * (available if TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES is defined, see + * s3_lib.c). We actually treat them like SSL 3.0 ciphers, which we probably + * shouldn't. Note that the first two are actually not in the IDs. */ +#define TLS1_CK_RSA_EXPORT1024_WITH_RC4_56_MD5 0x03000060 /* not in ID */ +#define TLS1_CK_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5 0x03000061 /* not in ID */ +#define TLS1_CK_RSA_EXPORT1024_WITH_DES_CBC_SHA 0x03000062 +#define TLS1_CK_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA 0x03000063 +#define TLS1_CK_RSA_EXPORT1024_WITH_RC4_56_SHA 0x03000064 +#define TLS1_CK_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA 0x03000065 +#define TLS1_CK_DHE_DSS_WITH_RC4_128_SHA 0x03000066 + +/* AES ciphersuites from RFC3268 */ + +#define TLS1_CK_RSA_WITH_AES_128_SHA 0x0300002F +#define TLS1_CK_DH_DSS_WITH_AES_128_SHA 0x03000030 +#define TLS1_CK_DH_RSA_WITH_AES_128_SHA 0x03000031 +#define TLS1_CK_DHE_DSS_WITH_AES_128_SHA 0x03000032 +#define TLS1_CK_DHE_RSA_WITH_AES_128_SHA 0x03000033 +#define TLS1_CK_ADH_WITH_AES_128_SHA 0x03000034 + +#define TLS1_CK_RSA_WITH_AES_256_SHA 0x03000035 +#define TLS1_CK_DH_DSS_WITH_AES_256_SHA 0x03000036 +#define TLS1_CK_DH_RSA_WITH_AES_256_SHA 0x03000037 +#define TLS1_CK_DHE_DSS_WITH_AES_256_SHA 0x03000038 +#define TLS1_CK_DHE_RSA_WITH_AES_256_SHA 0x03000039 +#define TLS1_CK_ADH_WITH_AES_256_SHA 0x0300003A + +/* TLS v1.2 ciphersuites */ +#define TLS1_CK_RSA_WITH_NULL_SHA256 0x0300003B +#define TLS1_CK_RSA_WITH_AES_128_SHA256 0x0300003C +#define TLS1_CK_RSA_WITH_AES_256_SHA256 0x0300003D +#define TLS1_CK_DH_DSS_WITH_AES_128_SHA256 0x0300003E +#define TLS1_CK_DH_RSA_WITH_AES_128_SHA256 0x0300003F +#define TLS1_CK_DHE_DSS_WITH_AES_128_SHA256 0x03000040 + +/* Camellia ciphersuites from RFC4132 */ +#define TLS1_CK_RSA_WITH_CAMELLIA_128_CBC_SHA 0x03000041 +#define TLS1_CK_DH_DSS_WITH_CAMELLIA_128_CBC_SHA 0x03000042 +#define TLS1_CK_DH_RSA_WITH_CAMELLIA_128_CBC_SHA 0x03000043 +#define TLS1_CK_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA 0x03000044 +#define TLS1_CK_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA 0x03000045 +#define TLS1_CK_ADH_WITH_CAMELLIA_128_CBC_SHA 0x03000046 + +/* TLS v1.2 ciphersuites */ +#define TLS1_CK_DHE_RSA_WITH_AES_128_SHA256 0x03000067 +#define TLS1_CK_DH_DSS_WITH_AES_256_SHA256 0x03000068 +#define TLS1_CK_DH_RSA_WITH_AES_256_SHA256 0x03000069 +#define TLS1_CK_DHE_DSS_WITH_AES_256_SHA256 0x0300006A +#define TLS1_CK_DHE_RSA_WITH_AES_256_SHA256 0x0300006B +#define TLS1_CK_ADH_WITH_AES_128_SHA256 0x0300006C +#define TLS1_CK_ADH_WITH_AES_256_SHA256 0x0300006D + +/* Camellia ciphersuites from RFC4132 */ +#define TLS1_CK_RSA_WITH_CAMELLIA_256_CBC_SHA 0x03000084 +#define TLS1_CK_DH_DSS_WITH_CAMELLIA_256_CBC_SHA 0x03000085 +#define TLS1_CK_DH_RSA_WITH_CAMELLIA_256_CBC_SHA 0x03000086 +#define TLS1_CK_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA 0x03000087 +#define TLS1_CK_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA 0x03000088 +#define TLS1_CK_ADH_WITH_CAMELLIA_256_CBC_SHA 0x03000089 + +/* SEED ciphersuites from RFC4162 */ +#define TLS1_CK_RSA_WITH_SEED_SHA 0x03000096 +#define TLS1_CK_DH_DSS_WITH_SEED_SHA 0x03000097 +#define TLS1_CK_DH_RSA_WITH_SEED_SHA 0x03000098 +#define TLS1_CK_DHE_DSS_WITH_SEED_SHA 0x03000099 +#define TLS1_CK_DHE_RSA_WITH_SEED_SHA 0x0300009A +#define TLS1_CK_ADH_WITH_SEED_SHA 0x0300009B + +/* TLS v1.2 GCM ciphersuites from RFC5288 */ +#define TLS1_CK_RSA_WITH_AES_128_GCM_SHA256 0x0300009C +#define TLS1_CK_RSA_WITH_AES_256_GCM_SHA384 0x0300009D +#define TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256 0x0300009E +#define TLS1_CK_DHE_RSA_WITH_AES_256_GCM_SHA384 0x0300009F +#define TLS1_CK_DH_RSA_WITH_AES_128_GCM_SHA256 0x030000A0 +#define TLS1_CK_DH_RSA_WITH_AES_256_GCM_SHA384 0x030000A1 +#define TLS1_CK_DHE_DSS_WITH_AES_128_GCM_SHA256 0x030000A2 +#define TLS1_CK_DHE_DSS_WITH_AES_256_GCM_SHA384 0x030000A3 +#define TLS1_CK_DH_DSS_WITH_AES_128_GCM_SHA256 0x030000A4 +#define TLS1_CK_DH_DSS_WITH_AES_256_GCM_SHA384 0x030000A5 +#define TLS1_CK_ADH_WITH_AES_128_GCM_SHA256 0x030000A6 +#define TLS1_CK_ADH_WITH_AES_256_GCM_SHA384 0x030000A7 + +/* ECC ciphersuites from RFC4492 */ +#define TLS1_CK_ECDH_ECDSA_WITH_NULL_SHA 0x0300C001 +#define TLS1_CK_ECDH_ECDSA_WITH_RC4_128_SHA 0x0300C002 +#define TLS1_CK_ECDH_ECDSA_WITH_DES_192_CBC3_SHA 0x0300C003 +#define TLS1_CK_ECDH_ECDSA_WITH_AES_128_CBC_SHA 0x0300C004 +#define TLS1_CK_ECDH_ECDSA_WITH_AES_256_CBC_SHA 0x0300C005 + +#define TLS1_CK_ECDHE_ECDSA_WITH_NULL_SHA 0x0300C006 +#define TLS1_CK_ECDHE_ECDSA_WITH_RC4_128_SHA 0x0300C007 +#define TLS1_CK_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA 0x0300C008 +#define TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA 0x0300C009 +#define TLS1_CK_ECDHE_ECDSA_WITH_AES_256_CBC_SHA 0x0300C00A + +#define TLS1_CK_ECDH_RSA_WITH_NULL_SHA 0x0300C00B +#define TLS1_CK_ECDH_RSA_WITH_RC4_128_SHA 0x0300C00C +#define TLS1_CK_ECDH_RSA_WITH_DES_192_CBC3_SHA 0x0300C00D +#define TLS1_CK_ECDH_RSA_WITH_AES_128_CBC_SHA 0x0300C00E +#define TLS1_CK_ECDH_RSA_WITH_AES_256_CBC_SHA 0x0300C00F + +#define TLS1_CK_ECDHE_RSA_WITH_NULL_SHA 0x0300C010 +#define TLS1_CK_ECDHE_RSA_WITH_RC4_128_SHA 0x0300C011 +#define TLS1_CK_ECDHE_RSA_WITH_DES_192_CBC3_SHA 0x0300C012 +#define TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA 0x0300C013 +#define TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA 0x0300C014 + +#define TLS1_CK_ECDH_anon_WITH_NULL_SHA 0x0300C015 +#define TLS1_CK_ECDH_anon_WITH_RC4_128_SHA 0x0300C016 +#define TLS1_CK_ECDH_anon_WITH_DES_192_CBC3_SHA 0x0300C017 +#define TLS1_CK_ECDH_anon_WITH_AES_128_CBC_SHA 0x0300C018 +#define TLS1_CK_ECDH_anon_WITH_AES_256_CBC_SHA 0x0300C019 + +/* SRP ciphersuites from RFC 5054 */ +#define TLS1_CK_SRP_SHA_WITH_3DES_EDE_CBC_SHA 0x0300C01A +#define TLS1_CK_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA 0x0300C01B +#define TLS1_CK_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA 0x0300C01C +#define TLS1_CK_SRP_SHA_WITH_AES_128_CBC_SHA 0x0300C01D +#define TLS1_CK_SRP_SHA_RSA_WITH_AES_128_CBC_SHA 0x0300C01E +#define TLS1_CK_SRP_SHA_DSS_WITH_AES_128_CBC_SHA 0x0300C01F +#define TLS1_CK_SRP_SHA_WITH_AES_256_CBC_SHA 0x0300C020 +#define TLS1_CK_SRP_SHA_RSA_WITH_AES_256_CBC_SHA 0x0300C021 +#define TLS1_CK_SRP_SHA_DSS_WITH_AES_256_CBC_SHA 0x0300C022 + +/* ECDH HMAC based ciphersuites from RFC5289 */ + +#define TLS1_CK_ECDHE_ECDSA_WITH_AES_128_SHA256 0x0300C023 +#define TLS1_CK_ECDHE_ECDSA_WITH_AES_256_SHA384 0x0300C024 +#define TLS1_CK_ECDH_ECDSA_WITH_AES_128_SHA256 0x0300C025 +#define TLS1_CK_ECDH_ECDSA_WITH_AES_256_SHA384 0x0300C026 +#define TLS1_CK_ECDHE_RSA_WITH_AES_128_SHA256 0x0300C027 +#define TLS1_CK_ECDHE_RSA_WITH_AES_256_SHA384 0x0300C028 +#define TLS1_CK_ECDH_RSA_WITH_AES_128_SHA256 0x0300C029 +#define TLS1_CK_ECDH_RSA_WITH_AES_256_SHA384 0x0300C02A + +/* ECDH GCM based ciphersuites from RFC5289 */ +#define TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 0x0300C02B +#define TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 0x0300C02C +#define TLS1_CK_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 0x0300C02D +#define TLS1_CK_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 0x0300C02E +#define TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256 0x0300C02F +#define TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384 0x0300C030 +#define TLS1_CK_ECDH_RSA_WITH_AES_128_GCM_SHA256 0x0300C031 +#define TLS1_CK_ECDH_RSA_WITH_AES_256_GCM_SHA384 0x0300C032 + +#define TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305 0x0300CC13 +#define TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305 0x0300CC14 +#define TLS1_CK_DHE_RSA_CHACHA20_POLY1305 0x0300CC15 + +/* XXX + * Inconsistency alert: + * The OpenSSL names of ciphers with ephemeral DH here include the string + * "DHE", while elsewhere it has always been "EDH". + * (The alias for the list of all such ciphers also is "EDH".) + * The specifications speak of "EDH"; maybe we should allow both forms + * for everything. */ +#define TLS1_TXT_RSA_EXPORT1024_WITH_RC4_56_MD5 "EXP1024-RC4-MD5" +#define TLS1_TXT_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5 "EXP1024-RC2-CBC-MD5" +#define TLS1_TXT_RSA_EXPORT1024_WITH_DES_CBC_SHA "EXP1024-DES-CBC-SHA" +#define TLS1_TXT_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA \ + "EXP1024-DHE-DSS-DES-CBC-SHA" +#define TLS1_TXT_RSA_EXPORT1024_WITH_RC4_56_SHA "EXP1024-RC4-SHA" +#define TLS1_TXT_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA "EXP1024-DHE-DSS-RC4-SHA" +#define TLS1_TXT_DHE_DSS_WITH_RC4_128_SHA "DHE-DSS-RC4-SHA" + +/* AES ciphersuites from RFC3268 */ +#define TLS1_TXT_RSA_WITH_AES_128_SHA "AES128-SHA" +#define TLS1_TXT_DH_DSS_WITH_AES_128_SHA "DH-DSS-AES128-SHA" +#define TLS1_TXT_DH_RSA_WITH_AES_128_SHA "DH-RSA-AES128-SHA" +#define TLS1_TXT_DHE_DSS_WITH_AES_128_SHA "DHE-DSS-AES128-SHA" +#define TLS1_TXT_DHE_RSA_WITH_AES_128_SHA "DHE-RSA-AES128-SHA" +#define TLS1_TXT_ADH_WITH_AES_128_SHA "ADH-AES128-SHA" + +#define TLS1_TXT_RSA_WITH_AES_256_SHA "AES256-SHA" +#define TLS1_TXT_DH_DSS_WITH_AES_256_SHA "DH-DSS-AES256-SHA" +#define TLS1_TXT_DH_RSA_WITH_AES_256_SHA "DH-RSA-AES256-SHA" +#define TLS1_TXT_DHE_DSS_WITH_AES_256_SHA "DHE-DSS-AES256-SHA" +#define TLS1_TXT_DHE_RSA_WITH_AES_256_SHA "DHE-RSA-AES256-SHA" +#define TLS1_TXT_ADH_WITH_AES_256_SHA "ADH-AES256-SHA" + +/* ECC ciphersuites from RFC4492 */ +#define TLS1_TXT_ECDH_ECDSA_WITH_NULL_SHA "ECDH-ECDSA-NULL-SHA" +#define TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA "ECDH-ECDSA-RC4-SHA" +#define TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA "ECDH-ECDSA-DES-CBC3-SHA" +#define TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA "ECDH-ECDSA-AES128-SHA" +#define TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA "ECDH-ECDSA-AES256-SHA" + +#define TLS1_TXT_ECDHE_ECDSA_WITH_NULL_SHA "ECDHE-ECDSA-NULL-SHA" +#define TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA "ECDHE-ECDSA-RC4-SHA" +#define TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA "ECDHE-ECDSA-DES-CBC3-SHA" +#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA "ECDHE-ECDSA-AES128-SHA" +#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA "ECDHE-ECDSA-AES256-SHA" + +#define TLS1_TXT_ECDH_RSA_WITH_NULL_SHA "ECDH-RSA-NULL-SHA" +#define TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA "ECDH-RSA-RC4-SHA" +#define TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA "ECDH-RSA-DES-CBC3-SHA" +#define TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA "ECDH-RSA-AES128-SHA" +#define TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA "ECDH-RSA-AES256-SHA" + +#define TLS1_TXT_ECDHE_RSA_WITH_NULL_SHA "ECDHE-RSA-NULL-SHA" +#define TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA "ECDHE-RSA-RC4-SHA" +#define TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA "ECDHE-RSA-DES-CBC3-SHA" +#define TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA "ECDHE-RSA-AES128-SHA" +#define TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA "ECDHE-RSA-AES256-SHA" + +#define TLS1_TXT_ECDH_anon_WITH_NULL_SHA "AECDH-NULL-SHA" +#define TLS1_TXT_ECDH_anon_WITH_RC4_128_SHA "AECDH-RC4-SHA" +#define TLS1_TXT_ECDH_anon_WITH_DES_192_CBC3_SHA "AECDH-DES-CBC3-SHA" +#define TLS1_TXT_ECDH_anon_WITH_AES_128_CBC_SHA "AECDH-AES128-SHA" +#define TLS1_TXT_ECDH_anon_WITH_AES_256_CBC_SHA "AECDH-AES256-SHA" + +/* PSK ciphersuites from RFC 4279 */ +#define TLS1_TXT_PSK_WITH_RC4_128_SHA "PSK-RC4-SHA" +#define TLS1_TXT_PSK_WITH_3DES_EDE_CBC_SHA "PSK-3DES-EDE-CBC-SHA" +#define TLS1_TXT_PSK_WITH_AES_128_CBC_SHA "PSK-AES128-CBC-SHA" +#define TLS1_TXT_PSK_WITH_AES_256_CBC_SHA "PSK-AES256-CBC-SHA" + +/* PSK ciphersuites from RFC 5489 */ +#define TLS1_TXT_ECDHE_PSK_WITH_AES_128_CBC_SHA "ECDHE-PSK-AES128-CBC-SHA" +#define TLS1_TXT_ECDHE_PSK_WITH_AES_256_CBC_SHA "ECDHE-PSK-AES256-CBC-SHA" + +/* SRP ciphersuite from RFC 5054 */ +#define TLS1_TXT_SRP_SHA_WITH_3DES_EDE_CBC_SHA "SRP-3DES-EDE-CBC-SHA" +#define TLS1_TXT_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA "SRP-RSA-3DES-EDE-CBC-SHA" +#define TLS1_TXT_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA "SRP-DSS-3DES-EDE-CBC-SHA" +#define TLS1_TXT_SRP_SHA_WITH_AES_128_CBC_SHA "SRP-AES-128-CBC-SHA" +#define TLS1_TXT_SRP_SHA_RSA_WITH_AES_128_CBC_SHA "SRP-RSA-AES-128-CBC-SHA" +#define TLS1_TXT_SRP_SHA_DSS_WITH_AES_128_CBC_SHA "SRP-DSS-AES-128-CBC-SHA" +#define TLS1_TXT_SRP_SHA_WITH_AES_256_CBC_SHA "SRP-AES-256-CBC-SHA" +#define TLS1_TXT_SRP_SHA_RSA_WITH_AES_256_CBC_SHA "SRP-RSA-AES-256-CBC-SHA" +#define TLS1_TXT_SRP_SHA_DSS_WITH_AES_256_CBC_SHA "SRP-DSS-AES-256-CBC-SHA" + +/* Camellia ciphersuites from RFC4132 */ +#define TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA "CAMELLIA128-SHA" +#define TLS1_TXT_DH_DSS_WITH_CAMELLIA_128_CBC_SHA "DH-DSS-CAMELLIA128-SHA" +#define TLS1_TXT_DH_RSA_WITH_CAMELLIA_128_CBC_SHA "DH-RSA-CAMELLIA128-SHA" +#define TLS1_TXT_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA "DHE-DSS-CAMELLIA128-SHA" +#define TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA "DHE-RSA-CAMELLIA128-SHA" +#define TLS1_TXT_ADH_WITH_CAMELLIA_128_CBC_SHA "ADH-CAMELLIA128-SHA" + +#define TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA "CAMELLIA256-SHA" +#define TLS1_TXT_DH_DSS_WITH_CAMELLIA_256_CBC_SHA "DH-DSS-CAMELLIA256-SHA" +#define TLS1_TXT_DH_RSA_WITH_CAMELLIA_256_CBC_SHA "DH-RSA-CAMELLIA256-SHA" +#define TLS1_TXT_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA "DHE-DSS-CAMELLIA256-SHA" +#define TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA "DHE-RSA-CAMELLIA256-SHA" +#define TLS1_TXT_ADH_WITH_CAMELLIA_256_CBC_SHA "ADH-CAMELLIA256-SHA" + +/* SEED ciphersuites from RFC4162 */ +#define TLS1_TXT_RSA_WITH_SEED_SHA "SEED-SHA" +#define TLS1_TXT_DH_DSS_WITH_SEED_SHA "DH-DSS-SEED-SHA" +#define TLS1_TXT_DH_RSA_WITH_SEED_SHA "DH-RSA-SEED-SHA" +#define TLS1_TXT_DHE_DSS_WITH_SEED_SHA "DHE-DSS-SEED-SHA" +#define TLS1_TXT_DHE_RSA_WITH_SEED_SHA "DHE-RSA-SEED-SHA" +#define TLS1_TXT_ADH_WITH_SEED_SHA "ADH-SEED-SHA" + +/* TLS v1.2 ciphersuites */ +#define TLS1_TXT_RSA_WITH_NULL_SHA256 "NULL-SHA256" +#define TLS1_TXT_RSA_WITH_AES_128_SHA256 "AES128-SHA256" +#define TLS1_TXT_RSA_WITH_AES_256_SHA256 "AES256-SHA256" +#define TLS1_TXT_DH_DSS_WITH_AES_128_SHA256 "DH-DSS-AES128-SHA256" +#define TLS1_TXT_DH_RSA_WITH_AES_128_SHA256 "DH-RSA-AES128-SHA256" +#define TLS1_TXT_DHE_DSS_WITH_AES_128_SHA256 "DHE-DSS-AES128-SHA256" +#define TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256 "DHE-RSA-AES128-SHA256" +#define TLS1_TXT_DH_DSS_WITH_AES_256_SHA256 "DH-DSS-AES256-SHA256" +#define TLS1_TXT_DH_RSA_WITH_AES_256_SHA256 "DH-RSA-AES256-SHA256" +#define TLS1_TXT_DHE_DSS_WITH_AES_256_SHA256 "DHE-DSS-AES256-SHA256" +#define TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256 "DHE-RSA-AES256-SHA256" +#define TLS1_TXT_ADH_WITH_AES_128_SHA256 "ADH-AES128-SHA256" +#define TLS1_TXT_ADH_WITH_AES_256_SHA256 "ADH-AES256-SHA256" + +/* TLS v1.2 GCM ciphersuites from RFC5288 */ +#define TLS1_TXT_RSA_WITH_AES_128_GCM_SHA256 "AES128-GCM-SHA256" +#define TLS1_TXT_RSA_WITH_AES_256_GCM_SHA384 "AES256-GCM-SHA384" +#define TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256 "DHE-RSA-AES128-GCM-SHA256" +#define TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384 "DHE-RSA-AES256-GCM-SHA384" +#define TLS1_TXT_DH_RSA_WITH_AES_128_GCM_SHA256 "DH-RSA-AES128-GCM-SHA256" +#define TLS1_TXT_DH_RSA_WITH_AES_256_GCM_SHA384 "DH-RSA-AES256-GCM-SHA384" +#define TLS1_TXT_DHE_DSS_WITH_AES_128_GCM_SHA256 "DHE-DSS-AES128-GCM-SHA256" +#define TLS1_TXT_DHE_DSS_WITH_AES_256_GCM_SHA384 "DHE-DSS-AES256-GCM-SHA384" +#define TLS1_TXT_DH_DSS_WITH_AES_128_GCM_SHA256 "DH-DSS-AES128-GCM-SHA256" +#define TLS1_TXT_DH_DSS_WITH_AES_256_GCM_SHA384 "DH-DSS-AES256-GCM-SHA384" +#define TLS1_TXT_ADH_WITH_AES_128_GCM_SHA256 "ADH-AES128-GCM-SHA256" +#define TLS1_TXT_ADH_WITH_AES_256_GCM_SHA384 "ADH-AES256-GCM-SHA384" + +/* ECDH HMAC based ciphersuites from RFC5289 */ + +#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_SHA256 "ECDHE-ECDSA-AES128-SHA256" +#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_SHA384 "ECDHE-ECDSA-AES256-SHA384" +#define TLS1_TXT_ECDH_ECDSA_WITH_AES_128_SHA256 "ECDH-ECDSA-AES128-SHA256" +#define TLS1_TXT_ECDH_ECDSA_WITH_AES_256_SHA384 "ECDH-ECDSA-AES256-SHA384" +#define TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256 "ECDHE-RSA-AES128-SHA256" +#define TLS1_TXT_ECDHE_RSA_WITH_AES_256_SHA384 "ECDHE-RSA-AES256-SHA384" +#define TLS1_TXT_ECDH_RSA_WITH_AES_128_SHA256 "ECDH-RSA-AES128-SHA256" +#define TLS1_TXT_ECDH_RSA_WITH_AES_256_SHA384 "ECDH-RSA-AES256-SHA384" + +/* ECDH GCM based ciphersuites from RFC5289 */ +#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 \ + "ECDHE-ECDSA-AES128-GCM-SHA256" +#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 \ + "ECDHE-ECDSA-AES256-GCM-SHA384" +#define TLS1_TXT_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 \ + "ECDH-ECDSA-AES128-GCM-SHA256" +#define TLS1_TXT_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 \ + "ECDH-ECDSA-AES256-GCM-SHA384" +#define TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 "ECDHE-RSA-AES128-GCM-SHA256" +#define TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384 "ECDHE-RSA-AES256-GCM-SHA384" +#define TLS1_TXT_ECDH_RSA_WITH_AES_128_GCM_SHA256 "ECDH-RSA-AES128-GCM-SHA256" +#define TLS1_TXT_ECDH_RSA_WITH_AES_256_GCM_SHA384 "ECDH-RSA-AES256-GCM-SHA384" + +#define TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305 "ECDHE-RSA-CHACHA20-POLY1305" +#define TLS1_TXT_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 \ + "ECDHE-ECDSA-CHACHA20-POLY1305" +#define TLS1_TXT_DHE_RSA_WITH_CHACHA20_POLY1305 "DHE-RSA-CHACHA20-POLY1305" + +#define TLS_CT_RSA_SIGN 1 +#define TLS_CT_DSS_SIGN 2 +#define TLS_CT_RSA_FIXED_DH 3 +#define TLS_CT_DSS_FIXED_DH 4 +#define TLS_CT_ECDSA_SIGN 64 +#define TLS_CT_RSA_FIXED_ECDH 65 +#define TLS_CT_ECDSA_FIXED_ECDH 66 + +#define TLS_MD_MAX_CONST_SIZE 20 +#define TLS_MD_CLIENT_FINISH_CONST "client finished" +#define TLS_MD_CLIENT_FINISH_CONST_SIZE 15 +#define TLS_MD_SERVER_FINISH_CONST "server finished" +#define TLS_MD_SERVER_FINISH_CONST_SIZE 15 +#define TLS_MD_KEY_EXPANSION_CONST "key expansion" +#define TLS_MD_KEY_EXPANSION_CONST_SIZE 13 +#define TLS_MD_CLIENT_WRITE_KEY_CONST "client write key" +#define TLS_MD_CLIENT_WRITE_KEY_CONST_SIZE 16 +#define TLS_MD_SERVER_WRITE_KEY_CONST "server write key" +#define TLS_MD_SERVER_WRITE_KEY_CONST_SIZE 16 +#define TLS_MD_IV_BLOCK_CONST "IV block" +#define TLS_MD_IV_BLOCK_CONST_SIZE 8 +#define TLS_MD_MASTER_SECRET_CONST "master secret" +#define TLS_MD_MASTER_SECRET_CONST_SIZE 13 +#define TLS_MD_EXTENDED_MASTER_SECRET_CONST "extended master secret" +#define TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE 22 + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/TMessagesProj/jni/boringssl/include/openssl/type_check.h b/TMessagesProj/jni/boringssl/include/openssl/type_check.h new file mode 100644 index 00000000..674913a3 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/type_check.h @@ -0,0 +1,91 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_TYPE_CHECK_H +#define OPENSSL_HEADER_TYPE_CHECK_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* This header file contains some common macros for enforcing type checking. + * Several, common OpenSSL structures (i.e. stack and lhash) operate on void + * pointers, but we wish to have type checking when they are used with a + * specific type. */ + +/* CHECKED_CAST casts |p| from type |from| to type |to|. */ +#define CHECKED_CAST(to, from, p) ((to) (1 ? (p) : (from)0)) + +/* CHECKED_PTR_OF casts a given pointer to void* and statically checks that it + * was a pointer to |type|. */ +#define CHECKED_PTR_OF(type, p) CHECKED_CAST(void*, type*, (p)) + +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +#define OPENSSL_COMPILE_ASSERT(cond, msg) _Static_assert(cond, #msg) +#else +#define OPENSSL_COMPILE_ASSERT(cond, msg) \ + typedef char OPENSSL_COMPILE_ASSERT_##msg[((cond) ? 1 : -1)] +#endif + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_TYPE_CHECK_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/x509.h b/TMessagesProj/jni/boringssl/include/openssl/x509.h new file mode 100644 index 00000000..88719109 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/x509.h @@ -0,0 +1,1258 @@ +/* crypto/x509/x509.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * ECDH support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ + +#ifndef HEADER_X509_H +#define HEADER_X509_H + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +#define X509_FILETYPE_PEM 1 +#define X509_FILETYPE_ASN1 2 +#define X509_FILETYPE_DEFAULT 3 + +#define X509v3_KU_DIGITAL_SIGNATURE 0x0080 +#define X509v3_KU_NON_REPUDIATION 0x0040 +#define X509v3_KU_KEY_ENCIPHERMENT 0x0020 +#define X509v3_KU_DATA_ENCIPHERMENT 0x0010 +#define X509v3_KU_KEY_AGREEMENT 0x0008 +#define X509v3_KU_KEY_CERT_SIGN 0x0004 +#define X509v3_KU_CRL_SIGN 0x0002 +#define X509v3_KU_ENCIPHER_ONLY 0x0001 +#define X509v3_KU_DECIPHER_ONLY 0x8000 +#define X509v3_KU_UNDEF 0xffff + +struct X509_objects_st + { + int nid; + int (*a2i)(void); + int (*i2a)(void); + } /* X509_OBJECTS */; + +DECLARE_ASN1_SET_OF(X509_ALGOR) + +typedef STACK_OF(X509_ALGOR) X509_ALGORS; + +struct X509_val_st + { + ASN1_TIME *notBefore; + ASN1_TIME *notAfter; + } /* X509_VAL */; + +struct X509_pubkey_st + { + X509_ALGOR *algor; + ASN1_BIT_STRING *public_key; + EVP_PKEY *pkey; + }; + +struct X509_sig_st + { + X509_ALGOR *algor; + ASN1_OCTET_STRING *digest; + } /* X509_SIG */; + +struct X509_name_entry_st + { + ASN1_OBJECT *object; + ASN1_STRING *value; + int set; + int size; /* temp variable */ + } /* X509_NAME_ENTRY */; + +DECLARE_STACK_OF(X509_NAME_ENTRY) +DECLARE_ASN1_SET_OF(X509_NAME_ENTRY) + +/* we always keep X509_NAMEs in 2 forms. */ +struct X509_name_st + { + STACK_OF(X509_NAME_ENTRY) *entries; + int modified; /* true if 'bytes' needs to be built */ +#ifndef OPENSSL_NO_BUFFER + BUF_MEM *bytes; +#else + char *bytes; +#endif +/* unsigned long hash; Keep the hash around for lookups */ + unsigned char *canon_enc; + int canon_enclen; + } /* X509_NAME */; + +DECLARE_STACK_OF(X509_NAME) + +#define X509_EX_V_NETSCAPE_HACK 0x8000 +#define X509_EX_V_INIT 0x0001 +struct X509_extension_st + { + ASN1_OBJECT *object; + ASN1_BOOLEAN critical; + ASN1_OCTET_STRING *value; + } /* X509_EXTENSION */; + +typedef STACK_OF(X509_EXTENSION) X509_EXTENSIONS; + +DECLARE_STACK_OF(X509_EXTENSION) +DECLARE_ASN1_SET_OF(X509_EXTENSION) + +/* a sequence of these are used */ +struct x509_attributes_st + { + ASN1_OBJECT *object; + int single; /* 0 for a set, 1 for a single item (which is wrong) */ + union { + char *ptr; +/* 0 */ STACK_OF(ASN1_TYPE) *set; +/* 1 */ ASN1_TYPE *single; + } value; + } /* X509_ATTRIBUTE */; + +DECLARE_STACK_OF(X509_ATTRIBUTE) +DECLARE_ASN1_SET_OF(X509_ATTRIBUTE) + + +struct X509_req_info_st + { + ASN1_ENCODING enc; + ASN1_INTEGER *version; + X509_NAME *subject; + X509_PUBKEY *pubkey; + /* d=2 hl=2 l= 0 cons: cont: 00 */ + STACK_OF(X509_ATTRIBUTE) *attributes; /* [ 0 ] */ + } /* X509_REQ_INFO */; + +struct X509_req_st + { + X509_REQ_INFO *req_info; + X509_ALGOR *sig_alg; + ASN1_BIT_STRING *signature; + CRYPTO_refcount_t references; + } /* X509_REQ */; + +struct x509_cinf_st + { + ASN1_INTEGER *version; /* [ 0 ] default of v1 */ + ASN1_INTEGER *serialNumber; + X509_ALGOR *signature; + X509_NAME *issuer; + X509_VAL *validity; + X509_NAME *subject; + X509_PUBKEY *key; + ASN1_BIT_STRING *issuerUID; /* [ 1 ] optional in v2 */ + ASN1_BIT_STRING *subjectUID; /* [ 2 ] optional in v2 */ + STACK_OF(X509_EXTENSION) *extensions; /* [ 3 ] optional in v3 */ + ASN1_ENCODING enc; + } /* X509_CINF */; + +/* This stuff is certificate "auxiliary info" + * it contains details which are useful in certificate + * stores and databases. When used this is tagged onto + * the end of the certificate itself + */ + +struct x509_cert_aux_st + { + STACK_OF(ASN1_OBJECT) *trust; /* trusted uses */ + STACK_OF(ASN1_OBJECT) *reject; /* rejected uses */ + ASN1_UTF8STRING *alias; /* "friendly name" */ + ASN1_OCTET_STRING *keyid; /* key id of private key */ + STACK_OF(X509_ALGOR) *other; /* other unspecified info */ + } /* X509_CERT_AUX */; + +struct x509_st + { + X509_CINF *cert_info; + X509_ALGOR *sig_alg; + ASN1_BIT_STRING *signature; + int valid; + CRYPTO_refcount_t references; + char *name; + CRYPTO_EX_DATA ex_data; + /* These contain copies of various extension values */ + long ex_pathlen; + long ex_pcpathlen; + unsigned long ex_flags; + unsigned long ex_kusage; + unsigned long ex_xkusage; + unsigned long ex_nscert; + ASN1_OCTET_STRING *skid; + AUTHORITY_KEYID *akid; + X509_POLICY_CACHE *policy_cache; + STACK_OF(DIST_POINT) *crldp; + STACK_OF(GENERAL_NAME) *altname; + NAME_CONSTRAINTS *nc; + unsigned char sha1_hash[SHA_DIGEST_LENGTH]; + X509_CERT_AUX *aux; + } /* X509 */; + +DECLARE_STACK_OF(X509) +DECLARE_ASN1_SET_OF(X509) + +/* This is used for a table of trust checking functions */ + +struct x509_trust_st { + int trust; + int flags; + int (*check_trust)(struct x509_trust_st *, X509 *, int); + char *name; + int arg1; + void *arg2; +} /* X509_TRUST */; + +DECLARE_STACK_OF(X509_TRUST) + +struct x509_cert_pair_st { + X509 *forward; + X509 *reverse; +} /* X509_CERT_PAIR */; + +/* standard trust ids */ + +#define X509_TRUST_DEFAULT -1 /* Only valid in purpose settings */ + +#define X509_TRUST_COMPAT 1 +#define X509_TRUST_SSL_CLIENT 2 +#define X509_TRUST_SSL_SERVER 3 +#define X509_TRUST_EMAIL 4 +#define X509_TRUST_OBJECT_SIGN 5 +#define X509_TRUST_OCSP_SIGN 6 +#define X509_TRUST_OCSP_REQUEST 7 +#define X509_TRUST_TSA 8 + +/* Keep these up to date! */ +#define X509_TRUST_MIN 1 +#define X509_TRUST_MAX 8 + + +/* trust_flags values */ +#define X509_TRUST_DYNAMIC 1 +#define X509_TRUST_DYNAMIC_NAME 2 + +/* check_trust return codes */ + +#define X509_TRUST_TRUSTED 1 +#define X509_TRUST_REJECTED 2 +#define X509_TRUST_UNTRUSTED 3 + +/* Flags for X509_print_ex() */ + +#define X509_FLAG_COMPAT 0 +#define X509_FLAG_NO_HEADER 1L +#define X509_FLAG_NO_VERSION (1L << 1) +#define X509_FLAG_NO_SERIAL (1L << 2) +#define X509_FLAG_NO_SIGNAME (1L << 3) +#define X509_FLAG_NO_ISSUER (1L << 4) +#define X509_FLAG_NO_VALIDITY (1L << 5) +#define X509_FLAG_NO_SUBJECT (1L << 6) +#define X509_FLAG_NO_PUBKEY (1L << 7) +#define X509_FLAG_NO_EXTENSIONS (1L << 8) +#define X509_FLAG_NO_SIGDUMP (1L << 9) +#define X509_FLAG_NO_AUX (1L << 10) +#define X509_FLAG_NO_ATTRIBUTES (1L << 11) +#define X509_FLAG_NO_IDS (1L << 12) + +/* Flags specific to X509_NAME_print_ex() */ + +/* The field separator information */ + +#define XN_FLAG_SEP_MASK (0xf << 16) + +#define XN_FLAG_COMPAT 0 /* Traditional SSLeay: use old X509_NAME_print */ +#define XN_FLAG_SEP_COMMA_PLUS (1 << 16) /* RFC2253 ,+ */ +#define XN_FLAG_SEP_CPLUS_SPC (2 << 16) /* ,+ spaced: more readable */ +#define XN_FLAG_SEP_SPLUS_SPC (3 << 16) /* ;+ spaced */ +#define XN_FLAG_SEP_MULTILINE (4 << 16) /* One line per field */ + +#define XN_FLAG_DN_REV (1 << 20) /* Reverse DN order */ + +/* How the field name is shown */ + +#define XN_FLAG_FN_MASK (0x3 << 21) + +#define XN_FLAG_FN_SN 0 /* Object short name */ +#define XN_FLAG_FN_LN (1 << 21) /* Object long name */ +#define XN_FLAG_FN_OID (2 << 21) /* Always use OIDs */ +#define XN_FLAG_FN_NONE (3 << 21) /* No field names */ + +#define XN_FLAG_SPC_EQ (1 << 23) /* Put spaces round '=' */ + +/* This determines if we dump fields we don't recognise: + * RFC2253 requires this. + */ + +#define XN_FLAG_DUMP_UNKNOWN_FIELDS (1 << 24) + +#define XN_FLAG_FN_ALIGN (1 << 25) /* Align field names to 20 characters */ + +/* Complete set of RFC2253 flags */ + +#define XN_FLAG_RFC2253 (ASN1_STRFLGS_RFC2253 | \ + XN_FLAG_SEP_COMMA_PLUS | \ + XN_FLAG_DN_REV | \ + XN_FLAG_FN_SN | \ + XN_FLAG_DUMP_UNKNOWN_FIELDS) + +/* readable oneline form */ + +#define XN_FLAG_ONELINE (ASN1_STRFLGS_RFC2253 | \ + ASN1_STRFLGS_ESC_QUOTE | \ + XN_FLAG_SEP_CPLUS_SPC | \ + XN_FLAG_SPC_EQ | \ + XN_FLAG_FN_SN) + +/* readable multiline form */ + +#define XN_FLAG_MULTILINE (ASN1_STRFLGS_ESC_CTRL | \ + ASN1_STRFLGS_ESC_MSB | \ + XN_FLAG_SEP_MULTILINE | \ + XN_FLAG_SPC_EQ | \ + XN_FLAG_FN_LN | \ + XN_FLAG_FN_ALIGN) + +struct x509_revoked_st + { + ASN1_INTEGER *serialNumber; + ASN1_TIME *revocationDate; + STACK_OF(X509_EXTENSION) /* optional */ *extensions; + /* Set up if indirect CRL */ + STACK_OF(GENERAL_NAME) *issuer; + /* Revocation reason */ + int reason; + int sequence; /* load sequence */ + }; + +DECLARE_STACK_OF(X509_REVOKED) +DECLARE_ASN1_SET_OF(X509_REVOKED) + +struct X509_crl_info_st + { + ASN1_INTEGER *version; + X509_ALGOR *sig_alg; + X509_NAME *issuer; + ASN1_TIME *lastUpdate; + ASN1_TIME *nextUpdate; + STACK_OF(X509_REVOKED) *revoked; + STACK_OF(X509_EXTENSION) /* [0] */ *extensions; + ASN1_ENCODING enc; + } /* X509_CRL_INFO */; + +struct X509_crl_st + { + /* actual signature */ + X509_CRL_INFO *crl; + X509_ALGOR *sig_alg; + ASN1_BIT_STRING *signature; + CRYPTO_refcount_t references; + int flags; + /* Copies of various extensions */ + AUTHORITY_KEYID *akid; + ISSUING_DIST_POINT *idp; + /* Convenient breakdown of IDP */ + int idp_flags; + int idp_reasons; + /* CRL and base CRL numbers for delta processing */ + ASN1_INTEGER *crl_number; + ASN1_INTEGER *base_crl_number; + unsigned char sha1_hash[SHA_DIGEST_LENGTH]; + STACK_OF(GENERAL_NAMES) *issuers; + const X509_CRL_METHOD *meth; + void *meth_data; + } /* X509_CRL */; + +DECLARE_STACK_OF(X509_CRL) +DECLARE_ASN1_SET_OF(X509_CRL) + +struct private_key_st + { + int version; + /* The PKCS#8 data types */ + X509_ALGOR *enc_algor; + ASN1_OCTET_STRING *enc_pkey; /* encrypted pub key */ + + /* When decrypted, the following will not be NULL */ + EVP_PKEY *dec_pkey; + + /* used to encrypt and decrypt */ + int key_length; + char *key_data; + int key_free; /* true if we should auto free key_data */ + + /* expanded version of 'enc_algor' */ + EVP_CIPHER_INFO cipher; + } /* X509_PKEY */; + +#ifndef OPENSSL_NO_EVP +struct X509_info_st + { + X509 *x509; + X509_CRL *crl; + X509_PKEY *x_pkey; + + EVP_CIPHER_INFO enc_cipher; + int enc_len; + char *enc_data; + + } /* X509_INFO */; + +DECLARE_STACK_OF(X509_INFO) +#endif + +/* The next 2 structures and their 8 routines were sent to me by + * Pat Richard and are used to manipulate + * Netscapes spki structures - useful if you are writing a CA web page + */ +struct Netscape_spkac_st + { + X509_PUBKEY *pubkey; + ASN1_IA5STRING *challenge; /* challenge sent in atlas >= PR2 */ + } /* NETSCAPE_SPKAC */; + +struct Netscape_spki_st + { + NETSCAPE_SPKAC *spkac; /* signed public key and challenge */ + X509_ALGOR *sig_algor; + ASN1_BIT_STRING *signature; + } /* NETSCAPE_SPKI */; + +/* Netscape certificate sequence structure */ +struct Netscape_certificate_sequence + { + ASN1_OBJECT *type; + STACK_OF(X509) *certs; + } /* NETSCAPE_CERT_SEQUENCE */; + +/* Unused (and iv length is wrong) +typedef struct CBCParameter_st + { + unsigned char iv[8]; + } CBC_PARAM; +*/ + +/* Password based encryption structure */ + +struct PBEPARAM_st { +ASN1_OCTET_STRING *salt; +ASN1_INTEGER *iter; +} /* PBEPARAM */; + +/* Password based encryption V2 structures */ + +struct PBE2PARAM_st { +X509_ALGOR *keyfunc; +X509_ALGOR *encryption; +} /* PBE2PARAM */; + +struct PBKDF2PARAM_st { +ASN1_TYPE *salt; /* Usually OCTET STRING but could be anything */ +ASN1_INTEGER *iter; +ASN1_INTEGER *keylength; +X509_ALGOR *prf; +} /* PBKDF2PARAM */; + + +/* PKCS#8 private key info structure */ + +struct pkcs8_priv_key_info_st + { + int broken; /* Flag for various broken formats */ +#define PKCS8_OK 0 +#define PKCS8_NO_OCTET 1 +#define PKCS8_EMBEDDED_PARAM 2 +#define PKCS8_NS_DB 3 +#define PKCS8_NEG_PRIVKEY 4 + ASN1_INTEGER *version; + X509_ALGOR *pkeyalg; + ASN1_TYPE *pkey; /* Should be OCTET STRING but some are broken */ + STACK_OF(X509_ATTRIBUTE) *attributes; + }; + +#ifdef __cplusplus +} +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define X509_EXT_PACK_UNKNOWN 1 +#define X509_EXT_PACK_STRING 2 + +#define X509_get_version(x) ASN1_INTEGER_get((x)->cert_info->version) +/* #define X509_get_serialNumber(x) ((x)->cert_info->serialNumber) */ +#define X509_get_notBefore(x) ((x)->cert_info->validity->notBefore) +#define X509_get_notAfter(x) ((x)->cert_info->validity->notAfter) +#define X509_get_cert_info(x) ((x)->cert_info) +#define X509_extract_key(x) X509_get_pubkey(x) /*****/ +#define X509_REQ_get_version(x) ASN1_INTEGER_get((x)->req_info->version) +#define X509_REQ_get_subject_name(x) ((x)->req_info->subject) +#define X509_REQ_extract_key(a) X509_REQ_get_pubkey(a) +#define X509_name_cmp(a,b) X509_NAME_cmp((a),(b)) +#define X509_get_signature_type(x) EVP_PKEY_type(OBJ_obj2nid((x)->sig_alg->algorithm)) + +#define X509_CRL_get_version(x) ASN1_INTEGER_get((x)->crl->version) +#define X509_CRL_get_lastUpdate(x) ((x)->crl->lastUpdate) +#define X509_CRL_get_nextUpdate(x) ((x)->crl->nextUpdate) +#define X509_CRL_get_issuer(x) ((x)->crl->issuer) +#define X509_CRL_get_REVOKED(x) ((x)->crl->revoked) + +#define X509_CINF_set_modified(c) ((c)->enc.modified = 1) +#define X509_CINF_get_issuer(c) (&(c)->issuer) +#define X509_CINF_get_extensions(c) ((c)->extensions) +#define X509_CINF_get_signature(c) ((c)->signature) + +OPENSSL_EXPORT void X509_CRL_set_default_method(const X509_CRL_METHOD *meth); +OPENSSL_EXPORT X509_CRL_METHOD *X509_CRL_METHOD_new( + int (*crl_init)(X509_CRL *crl), + int (*crl_free)(X509_CRL *crl), + int (*crl_lookup)(X509_CRL *crl, X509_REVOKED **ret, + ASN1_INTEGER *ser, X509_NAME *issuer), + int (*crl_verify)(X509_CRL *crl, EVP_PKEY *pk)); +OPENSSL_EXPORT void X509_CRL_METHOD_free(X509_CRL_METHOD *m); + +OPENSSL_EXPORT void X509_CRL_set_meth_data(X509_CRL *crl, void *dat); +OPENSSL_EXPORT void *X509_CRL_get_meth_data(X509_CRL *crl); + +/* This one is only used so that a binary form can output, as in + * i2d_X509_NAME(X509_get_X509_PUBKEY(x),&buf) */ +#define X509_get_X509_PUBKEY(x) ((x)->cert_info->key) + + +OPENSSL_EXPORT const char *X509_verify_cert_error_string(long n); + +#ifndef OPENSSL_NO_EVP +OPENSSL_EXPORT int X509_verify(X509 *a, EVP_PKEY *r); + +OPENSSL_EXPORT int X509_REQ_verify(X509_REQ *a, EVP_PKEY *r); +OPENSSL_EXPORT int X509_CRL_verify(X509_CRL *a, EVP_PKEY *r); +OPENSSL_EXPORT int NETSCAPE_SPKI_verify(NETSCAPE_SPKI *a, EVP_PKEY *r); + +OPENSSL_EXPORT NETSCAPE_SPKI * NETSCAPE_SPKI_b64_decode(const char *str, int len); +OPENSSL_EXPORT char * NETSCAPE_SPKI_b64_encode(NETSCAPE_SPKI *x); +OPENSSL_EXPORT EVP_PKEY *NETSCAPE_SPKI_get_pubkey(NETSCAPE_SPKI *x); +OPENSSL_EXPORT int NETSCAPE_SPKI_set_pubkey(NETSCAPE_SPKI *x, EVP_PKEY *pkey); + +OPENSSL_EXPORT int NETSCAPE_SPKI_print(BIO *out, NETSCAPE_SPKI *spki); + +OPENSSL_EXPORT int X509_signature_dump(BIO *bp,const ASN1_STRING *sig, int indent); +OPENSSL_EXPORT int X509_signature_print(BIO *bp,X509_ALGOR *alg, ASN1_STRING *sig); + +OPENSSL_EXPORT int X509_sign(X509 *x, EVP_PKEY *pkey, const EVP_MD *md); +OPENSSL_EXPORT int X509_sign_ctx(X509 *x, EVP_MD_CTX *ctx); +/* int X509_http_nbio(OCSP_REQ_CTX *rctx, X509 **pcert); */ +OPENSSL_EXPORT int X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, const EVP_MD *md); +OPENSSL_EXPORT int X509_REQ_sign_ctx(X509_REQ *x, EVP_MD_CTX *ctx); +OPENSSL_EXPORT int X509_CRL_sign(X509_CRL *x, EVP_PKEY *pkey, const EVP_MD *md); +OPENSSL_EXPORT int X509_CRL_sign_ctx(X509_CRL *x, EVP_MD_CTX *ctx); +/* int X509_CRL_http_nbio(OCSP_REQ_CTX *rctx, X509_CRL **pcrl); */ +OPENSSL_EXPORT int NETSCAPE_SPKI_sign(NETSCAPE_SPKI *x, EVP_PKEY *pkey, const EVP_MD *md); + +OPENSSL_EXPORT int X509_pubkey_digest(const X509 *data,const EVP_MD *type, + unsigned char *md, unsigned int *len); +OPENSSL_EXPORT int X509_digest(const X509 *data,const EVP_MD *type, + unsigned char *md, unsigned int *len); +OPENSSL_EXPORT int X509_CRL_digest(const X509_CRL *data,const EVP_MD *type, + unsigned char *md, unsigned int *len); +OPENSSL_EXPORT int X509_REQ_digest(const X509_REQ *data,const EVP_MD *type, + unsigned char *md, unsigned int *len); +OPENSSL_EXPORT int X509_NAME_digest(const X509_NAME *data,const EVP_MD *type, + unsigned char *md, unsigned int *len); +#endif + +#ifndef OPENSSL_NO_FP_API +OPENSSL_EXPORT X509 *d2i_X509_fp(FILE *fp, X509 **x509); +OPENSSL_EXPORT int i2d_X509_fp(FILE *fp,X509 *x509); +OPENSSL_EXPORT X509_CRL *d2i_X509_CRL_fp(FILE *fp,X509_CRL **crl); +OPENSSL_EXPORT int i2d_X509_CRL_fp(FILE *fp,X509_CRL *crl); +OPENSSL_EXPORT X509_REQ *d2i_X509_REQ_fp(FILE *fp,X509_REQ **req); +OPENSSL_EXPORT int i2d_X509_REQ_fp(FILE *fp,X509_REQ *req); +OPENSSL_EXPORT RSA *d2i_RSAPrivateKey_fp(FILE *fp,RSA **rsa); +OPENSSL_EXPORT int i2d_RSAPrivateKey_fp(FILE *fp,RSA *rsa); +OPENSSL_EXPORT RSA *d2i_RSAPublicKey_fp(FILE *fp,RSA **rsa); +OPENSSL_EXPORT int i2d_RSAPublicKey_fp(FILE *fp,RSA *rsa); +OPENSSL_EXPORT RSA *d2i_RSA_PUBKEY_fp(FILE *fp,RSA **rsa); +OPENSSL_EXPORT int i2d_RSA_PUBKEY_fp(FILE *fp,RSA *rsa); +#ifndef OPENSSL_NO_DSA +OPENSSL_EXPORT DSA *d2i_DSA_PUBKEY_fp(FILE *fp, DSA **dsa); +OPENSSL_EXPORT int i2d_DSA_PUBKEY_fp(FILE *fp, DSA *dsa); +OPENSSL_EXPORT DSA *d2i_DSAPrivateKey_fp(FILE *fp, DSA **dsa); +OPENSSL_EXPORT int i2d_DSAPrivateKey_fp(FILE *fp, DSA *dsa); +#endif +OPENSSL_EXPORT EC_KEY *d2i_EC_PUBKEY_fp(FILE *fp, EC_KEY **eckey); +OPENSSL_EXPORT int i2d_EC_PUBKEY_fp(FILE *fp, EC_KEY *eckey); +OPENSSL_EXPORT EC_KEY *d2i_ECPrivateKey_fp(FILE *fp, EC_KEY **eckey); +OPENSSL_EXPORT int i2d_ECPrivateKey_fp(FILE *fp, EC_KEY *eckey); +OPENSSL_EXPORT X509_SIG *d2i_PKCS8_fp(FILE *fp,X509_SIG **p8); +OPENSSL_EXPORT int i2d_PKCS8_fp(FILE *fp,X509_SIG *p8); +OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_fp(FILE *fp, + PKCS8_PRIV_KEY_INFO **p8inf); +OPENSSL_EXPORT int i2d_PKCS8_PRIV_KEY_INFO_fp(FILE *fp,PKCS8_PRIV_KEY_INFO *p8inf); +OPENSSL_EXPORT int i2d_PKCS8PrivateKeyInfo_fp(FILE *fp, EVP_PKEY *key); +OPENSSL_EXPORT int i2d_PrivateKey_fp(FILE *fp, EVP_PKEY *pkey); +OPENSSL_EXPORT EVP_PKEY *d2i_PrivateKey_fp(FILE *fp, EVP_PKEY **a); +OPENSSL_EXPORT int i2d_PUBKEY_fp(FILE *fp, EVP_PKEY *pkey); +OPENSSL_EXPORT EVP_PKEY *d2i_PUBKEY_fp(FILE *fp, EVP_PKEY **a); +#endif + +OPENSSL_EXPORT X509 *d2i_X509_bio(BIO *bp,X509 **x509); +OPENSSL_EXPORT int i2d_X509_bio(BIO *bp,X509 *x509); +OPENSSL_EXPORT X509_CRL *d2i_X509_CRL_bio(BIO *bp,X509_CRL **crl); +OPENSSL_EXPORT int i2d_X509_CRL_bio(BIO *bp,X509_CRL *crl); +OPENSSL_EXPORT X509_REQ *d2i_X509_REQ_bio(BIO *bp,X509_REQ **req); +OPENSSL_EXPORT int i2d_X509_REQ_bio(BIO *bp,X509_REQ *req); +OPENSSL_EXPORT RSA *d2i_RSAPrivateKey_bio(BIO *bp,RSA **rsa); +OPENSSL_EXPORT int i2d_RSAPrivateKey_bio(BIO *bp,RSA *rsa); +OPENSSL_EXPORT RSA *d2i_RSAPublicKey_bio(BIO *bp,RSA **rsa); +OPENSSL_EXPORT int i2d_RSAPublicKey_bio(BIO *bp,RSA *rsa); +OPENSSL_EXPORT RSA *d2i_RSA_PUBKEY_bio(BIO *bp,RSA **rsa); +OPENSSL_EXPORT int i2d_RSA_PUBKEY_bio(BIO *bp,RSA *rsa); +#ifndef OPENSSL_NO_DSA +OPENSSL_EXPORT DSA *d2i_DSA_PUBKEY_bio(BIO *bp, DSA **dsa); +OPENSSL_EXPORT int i2d_DSA_PUBKEY_bio(BIO *bp, DSA *dsa); +OPENSSL_EXPORT DSA *d2i_DSAPrivateKey_bio(BIO *bp, DSA **dsa); +OPENSSL_EXPORT int i2d_DSAPrivateKey_bio(BIO *bp, DSA *dsa); +#endif +OPENSSL_EXPORT EC_KEY *d2i_EC_PUBKEY_bio(BIO *bp, EC_KEY **eckey); +OPENSSL_EXPORT int i2d_EC_PUBKEY_bio(BIO *bp, EC_KEY *eckey); +OPENSSL_EXPORT EC_KEY *d2i_ECPrivateKey_bio(BIO *bp, EC_KEY **eckey); +OPENSSL_EXPORT int i2d_ECPrivateKey_bio(BIO *bp, EC_KEY *eckey); +OPENSSL_EXPORT X509_SIG *d2i_PKCS8_bio(BIO *bp,X509_SIG **p8); +OPENSSL_EXPORT int i2d_PKCS8_bio(BIO *bp,X509_SIG *p8); +OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_bio(BIO *bp, + PKCS8_PRIV_KEY_INFO **p8inf); +OPENSSL_EXPORT int i2d_PKCS8_PRIV_KEY_INFO_bio(BIO *bp,PKCS8_PRIV_KEY_INFO *p8inf); +OPENSSL_EXPORT int i2d_PKCS8PrivateKeyInfo_bio(BIO *bp, EVP_PKEY *key); +OPENSSL_EXPORT int i2d_PrivateKey_bio(BIO *bp, EVP_PKEY *pkey); +OPENSSL_EXPORT EVP_PKEY *d2i_PrivateKey_bio(BIO *bp, EVP_PKEY **a); +OPENSSL_EXPORT int i2d_PUBKEY_bio(BIO *bp, EVP_PKEY *pkey); +OPENSSL_EXPORT EVP_PKEY *d2i_PUBKEY_bio(BIO *bp, EVP_PKEY **a); + +OPENSSL_EXPORT X509 *X509_dup(X509 *x509); +OPENSSL_EXPORT X509_ATTRIBUTE *X509_ATTRIBUTE_dup(X509_ATTRIBUTE *xa); +OPENSSL_EXPORT X509_EXTENSION *X509_EXTENSION_dup(X509_EXTENSION *ex); +OPENSSL_EXPORT X509_CRL *X509_CRL_dup(X509_CRL *crl); +OPENSSL_EXPORT X509_REVOKED *X509_REVOKED_dup(X509_REVOKED *rev); +OPENSSL_EXPORT X509_REQ *X509_REQ_dup(X509_REQ *req); +OPENSSL_EXPORT X509_ALGOR *X509_ALGOR_dup(X509_ALGOR *xn); +OPENSSL_EXPORT int X509_ALGOR_set0(X509_ALGOR *alg, const ASN1_OBJECT *aobj, int ptype, void *pval); +OPENSSL_EXPORT void X509_ALGOR_get0(ASN1_OBJECT **paobj, int *pptype, void **ppval, + X509_ALGOR *algor); +OPENSSL_EXPORT void X509_ALGOR_set_md(X509_ALGOR *alg, const EVP_MD *md); +OPENSSL_EXPORT int X509_ALGOR_cmp(const X509_ALGOR *a, const X509_ALGOR *b); + +OPENSSL_EXPORT X509_NAME *X509_NAME_dup(X509_NAME *xn); +OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_dup(X509_NAME_ENTRY *ne); + +OPENSSL_EXPORT int X509_cmp_time(const ASN1_TIME *s, time_t *t); +OPENSSL_EXPORT int X509_cmp_current_time(const ASN1_TIME *s); +OPENSSL_EXPORT ASN1_TIME * X509_time_adj(ASN1_TIME *s, long adj, time_t *t); +OPENSSL_EXPORT ASN1_TIME * X509_time_adj_ex(ASN1_TIME *s, int offset_day, long offset_sec, time_t *t); +OPENSSL_EXPORT ASN1_TIME * X509_gmtime_adj(ASN1_TIME *s, long adj); + +OPENSSL_EXPORT const char * X509_get_default_cert_area(void ); +OPENSSL_EXPORT const char * X509_get_default_cert_dir(void ); +OPENSSL_EXPORT const char * X509_get_default_cert_file(void ); +OPENSSL_EXPORT const char * X509_get_default_cert_dir_env(void ); +OPENSSL_EXPORT const char * X509_get_default_cert_file_env(void ); +OPENSSL_EXPORT const char * X509_get_default_private_dir(void ); + +OPENSSL_EXPORT X509_REQ * X509_to_X509_REQ(X509 *x, EVP_PKEY *pkey, const EVP_MD *md); +OPENSSL_EXPORT X509 * X509_REQ_to_X509(X509_REQ *r, int days,EVP_PKEY *pkey); + +DECLARE_ASN1_ENCODE_FUNCTIONS(X509_ALGORS, X509_ALGORS, X509_ALGORS) +DECLARE_ASN1_FUNCTIONS(X509_VAL) + +DECLARE_ASN1_FUNCTIONS(X509_PUBKEY) + +OPENSSL_EXPORT int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey); +OPENSSL_EXPORT EVP_PKEY * X509_PUBKEY_get(X509_PUBKEY *key); +OPENSSL_EXPORT int i2d_PUBKEY(const EVP_PKEY *a,unsigned char **pp); +OPENSSL_EXPORT EVP_PKEY * d2i_PUBKEY(EVP_PKEY **a,const unsigned char **pp, + long length); +OPENSSL_EXPORT int i2d_RSA_PUBKEY(const RSA *a,unsigned char **pp); +OPENSSL_EXPORT RSA * d2i_RSA_PUBKEY(RSA **a,const unsigned char **pp, + long length); +#ifndef OPENSSL_NO_DSA +OPENSSL_EXPORT int i2d_DSA_PUBKEY(const DSA *a,unsigned char **pp); +OPENSSL_EXPORT DSA * d2i_DSA_PUBKEY(DSA **a,const unsigned char **pp, + long length); +#endif +OPENSSL_EXPORT int i2d_EC_PUBKEY(const EC_KEY *a, unsigned char **pp); +OPENSSL_EXPORT EC_KEY *d2i_EC_PUBKEY(EC_KEY **a, const unsigned char **pp, + long length); + +DECLARE_ASN1_FUNCTIONS(X509_SIG) +DECLARE_ASN1_FUNCTIONS(X509_REQ_INFO) +DECLARE_ASN1_FUNCTIONS(X509_REQ) + +DECLARE_ASN1_FUNCTIONS(X509_ATTRIBUTE) +OPENSSL_EXPORT X509_ATTRIBUTE *X509_ATTRIBUTE_create(int nid, int atrtype, void *value); + +DECLARE_ASN1_FUNCTIONS(X509_EXTENSION) +DECLARE_ASN1_ENCODE_FUNCTIONS(X509_EXTENSIONS, X509_EXTENSIONS, X509_EXTENSIONS) + +DECLARE_ASN1_FUNCTIONS(X509_NAME_ENTRY) + +DECLARE_ASN1_FUNCTIONS(X509_NAME) + +OPENSSL_EXPORT int X509_NAME_set(X509_NAME **xn, X509_NAME *name); + +DECLARE_ASN1_FUNCTIONS(X509_CINF) + +DECLARE_ASN1_FUNCTIONS(X509) +DECLARE_ASN1_FUNCTIONS(X509_CERT_AUX) + +DECLARE_ASN1_FUNCTIONS(X509_CERT_PAIR) + +/* X509_up_ref adds one to the reference count of |x| and returns + * |x|. */ +OPENSSL_EXPORT X509 *X509_up_ref(X509 *x); + +OPENSSL_EXPORT int X509_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func); +OPENSSL_EXPORT int X509_set_ex_data(X509 *r, int idx, void *arg); +OPENSSL_EXPORT void *X509_get_ex_data(X509 *r, int idx); +OPENSSL_EXPORT int i2d_X509_AUX(X509 *a,unsigned char **pp); +OPENSSL_EXPORT X509 * d2i_X509_AUX(X509 **a,const unsigned char **pp,long length); + +OPENSSL_EXPORT void X509_get0_signature(ASN1_BIT_STRING **psig, X509_ALGOR **palg, + const X509 *x); +OPENSSL_EXPORT int X509_get_signature_nid(const X509 *x); + +OPENSSL_EXPORT int X509_alias_set1(X509 *x, unsigned char *name, int len); +OPENSSL_EXPORT int X509_keyid_set1(X509 *x, unsigned char *id, int len); +OPENSSL_EXPORT unsigned char * X509_alias_get0(X509 *x, int *len); +OPENSSL_EXPORT unsigned char * X509_keyid_get0(X509 *x, int *len); +OPENSSL_EXPORT int (*X509_TRUST_set_default(int (*trust)(int , X509 *, int)))(int, X509 *, int); +OPENSSL_EXPORT int X509_TRUST_set(int *t, int trust); +OPENSSL_EXPORT int X509_add1_trust_object(X509 *x, ASN1_OBJECT *obj); +OPENSSL_EXPORT int X509_add1_reject_object(X509 *x, ASN1_OBJECT *obj); +OPENSSL_EXPORT void X509_trust_clear(X509 *x); +OPENSSL_EXPORT void X509_reject_clear(X509 *x); + +DECLARE_ASN1_FUNCTIONS(X509_REVOKED) +DECLARE_ASN1_FUNCTIONS(X509_CRL_INFO) +DECLARE_ASN1_FUNCTIONS(X509_CRL) + +OPENSSL_EXPORT int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev); +OPENSSL_EXPORT int X509_CRL_get0_by_serial(X509_CRL *crl, + X509_REVOKED **ret, ASN1_INTEGER *serial); +OPENSSL_EXPORT int X509_CRL_get0_by_cert(X509_CRL *crl, X509_REVOKED **ret, X509 *x); + +OPENSSL_EXPORT X509_PKEY * X509_PKEY_new(void ); +OPENSSL_EXPORT void X509_PKEY_free(X509_PKEY *a); + +DECLARE_ASN1_FUNCTIONS(NETSCAPE_SPKI) +DECLARE_ASN1_FUNCTIONS(NETSCAPE_SPKAC) +DECLARE_ASN1_FUNCTIONS(NETSCAPE_CERT_SEQUENCE) + +#ifndef OPENSSL_NO_EVP +OPENSSL_EXPORT X509_INFO * X509_INFO_new(void); +OPENSSL_EXPORT void X509_INFO_free(X509_INFO *a); +OPENSSL_EXPORT char * X509_NAME_oneline(X509_NAME *a,char *buf,int size); + +OPENSSL_EXPORT int ASN1_digest(i2d_of_void *i2d,const EVP_MD *type,char *data, + unsigned char *md,unsigned int *len); + +OPENSSL_EXPORT int ASN1_item_digest(const ASN1_ITEM *it,const EVP_MD *type,void *data, + unsigned char *md,unsigned int *len); + +OPENSSL_EXPORT int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *algor1, + ASN1_BIT_STRING *signature,void *data,EVP_PKEY *pkey); + +OPENSSL_EXPORT int ASN1_item_sign(const ASN1_ITEM *it, X509_ALGOR *algor1, X509_ALGOR *algor2, + ASN1_BIT_STRING *signature, + void *data, EVP_PKEY *pkey, const EVP_MD *type); +OPENSSL_EXPORT int ASN1_item_sign_ctx(const ASN1_ITEM *it, + X509_ALGOR *algor1, X509_ALGOR *algor2, + ASN1_BIT_STRING *signature, void *asn, EVP_MD_CTX *ctx); +#endif + +OPENSSL_EXPORT int X509_set_version(X509 *x,long version); +OPENSSL_EXPORT int X509_set_serialNumber(X509 *x, ASN1_INTEGER *serial); +OPENSSL_EXPORT ASN1_INTEGER * X509_get_serialNumber(X509 *x); +OPENSSL_EXPORT int X509_set_issuer_name(X509 *x, X509_NAME *name); +OPENSSL_EXPORT X509_NAME * X509_get_issuer_name(X509 *a); +OPENSSL_EXPORT int X509_set_subject_name(X509 *x, X509_NAME *name); +OPENSSL_EXPORT X509_NAME * X509_get_subject_name(X509 *a); +OPENSSL_EXPORT int X509_set_notBefore(X509 *x, const ASN1_TIME *tm); +OPENSSL_EXPORT int X509_set_notAfter(X509 *x, const ASN1_TIME *tm); +OPENSSL_EXPORT int X509_set_pubkey(X509 *x, EVP_PKEY *pkey); +OPENSSL_EXPORT EVP_PKEY * X509_get_pubkey(X509 *x); +OPENSSL_EXPORT ASN1_BIT_STRING * X509_get0_pubkey_bitstr(const X509 *x); +OPENSSL_EXPORT int X509_certificate_type(X509 *x,EVP_PKEY *pubkey /* optional */); + +OPENSSL_EXPORT int X509_REQ_set_version(X509_REQ *x,long version); +OPENSSL_EXPORT int X509_REQ_set_subject_name(X509_REQ *req,X509_NAME *name); +OPENSSL_EXPORT int X509_REQ_set_pubkey(X509_REQ *x, EVP_PKEY *pkey); +OPENSSL_EXPORT EVP_PKEY * X509_REQ_get_pubkey(X509_REQ *req); +OPENSSL_EXPORT int X509_REQ_extension_nid(int nid); +OPENSSL_EXPORT const int * X509_REQ_get_extension_nids(void); +OPENSSL_EXPORT void X509_REQ_set_extension_nids(const int *nids); +OPENSSL_EXPORT STACK_OF(X509_EXTENSION) *X509_REQ_get_extensions(X509_REQ *req); +OPENSSL_EXPORT int X509_REQ_add_extensions_nid(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts, + int nid); +OPENSSL_EXPORT int X509_REQ_add_extensions(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts); +OPENSSL_EXPORT int X509_REQ_get_attr_count(const X509_REQ *req); +OPENSSL_EXPORT int X509_REQ_get_attr_by_NID(const X509_REQ *req, int nid, + int lastpos); +OPENSSL_EXPORT int X509_REQ_get_attr_by_OBJ(const X509_REQ *req, ASN1_OBJECT *obj, + int lastpos); +OPENSSL_EXPORT X509_ATTRIBUTE *X509_REQ_get_attr(const X509_REQ *req, int loc); +OPENSSL_EXPORT X509_ATTRIBUTE *X509_REQ_delete_attr(X509_REQ *req, int loc); +OPENSSL_EXPORT int X509_REQ_add1_attr(X509_REQ *req, X509_ATTRIBUTE *attr); +OPENSSL_EXPORT int X509_REQ_add1_attr_by_OBJ(X509_REQ *req, + const ASN1_OBJECT *obj, int type, + const unsigned char *bytes, int len); +OPENSSL_EXPORT int X509_REQ_add1_attr_by_NID(X509_REQ *req, + int nid, int type, + const unsigned char *bytes, int len); +OPENSSL_EXPORT int X509_REQ_add1_attr_by_txt(X509_REQ *req, + const char *attrname, int type, + const unsigned char *bytes, int len); + +OPENSSL_EXPORT int X509_CRL_set_version(X509_CRL *x, long version); +OPENSSL_EXPORT int X509_CRL_set_issuer_name(X509_CRL *x, X509_NAME *name); +OPENSSL_EXPORT int X509_CRL_set_lastUpdate(X509_CRL *x, const ASN1_TIME *tm); +OPENSSL_EXPORT int X509_CRL_set_nextUpdate(X509_CRL *x, const ASN1_TIME *tm); +OPENSSL_EXPORT int X509_CRL_sort(X509_CRL *crl); + +OPENSSL_EXPORT int X509_REVOKED_set_serialNumber(X509_REVOKED *x, ASN1_INTEGER *serial); +OPENSSL_EXPORT int X509_REVOKED_set_revocationDate(X509_REVOKED *r, ASN1_TIME *tm); + +OPENSSL_EXPORT X509_CRL *X509_CRL_diff(X509_CRL *base, X509_CRL *newer, + EVP_PKEY *skey, const EVP_MD *md, unsigned int flags); + +OPENSSL_EXPORT int X509_REQ_check_private_key(X509_REQ *x509,EVP_PKEY *pkey); + +OPENSSL_EXPORT int X509_check_private_key(X509 *x509,EVP_PKEY *pkey); +OPENSSL_EXPORT int X509_chain_check_suiteb(int *perror_depth, + X509 *x, STACK_OF(X509) *chain, + unsigned long flags); +OPENSSL_EXPORT int X509_CRL_check_suiteb(X509_CRL *crl, EVP_PKEY *pk, + unsigned long flags); +OPENSSL_EXPORT STACK_OF(X509) *X509_chain_up_ref(STACK_OF(X509) *chain); + +OPENSSL_EXPORT int X509_issuer_and_serial_cmp(const X509 *a, const X509 *b); +OPENSSL_EXPORT unsigned long X509_issuer_and_serial_hash(X509 *a); + +OPENSSL_EXPORT int X509_issuer_name_cmp(const X509 *a, const X509 *b); +OPENSSL_EXPORT unsigned long X509_issuer_name_hash(X509 *a); + +OPENSSL_EXPORT int X509_subject_name_cmp(const X509 *a, const X509 *b); +OPENSSL_EXPORT unsigned long X509_subject_name_hash(X509 *x); + +OPENSSL_EXPORT unsigned long X509_issuer_name_hash_old(X509 *a); +OPENSSL_EXPORT unsigned long X509_subject_name_hash_old(X509 *x); + +OPENSSL_EXPORT int X509_cmp(const X509 *a, const X509 *b); +OPENSSL_EXPORT int X509_NAME_cmp(const X509_NAME *a, const X509_NAME *b); +OPENSSL_EXPORT unsigned long X509_NAME_hash(X509_NAME *x); +OPENSSL_EXPORT unsigned long X509_NAME_hash_old(X509_NAME *x); + +OPENSSL_EXPORT int X509_CRL_cmp(const X509_CRL *a, const X509_CRL *b); +OPENSSL_EXPORT int X509_CRL_match(const X509_CRL *a, const X509_CRL *b); +#ifndef OPENSSL_NO_FP_API +OPENSSL_EXPORT int X509_print_ex_fp(FILE *bp,X509 *x, unsigned long nmflag, unsigned long cflag); +OPENSSL_EXPORT int X509_print_fp(FILE *bp,X509 *x); +OPENSSL_EXPORT int X509_CRL_print_fp(FILE *bp,X509_CRL *x); +OPENSSL_EXPORT int X509_REQ_print_fp(FILE *bp,X509_REQ *req); +OPENSSL_EXPORT int X509_NAME_print_ex_fp(FILE *fp, X509_NAME *nm, int indent, unsigned long flags); +#endif + +OPENSSL_EXPORT int X509_NAME_print(BIO *bp, X509_NAME *name, int obase); +OPENSSL_EXPORT int X509_NAME_print_ex(BIO *out, X509_NAME *nm, int indent, unsigned long flags); +OPENSSL_EXPORT int X509_print_ex(BIO *bp,X509 *x, unsigned long nmflag, unsigned long cflag); +OPENSSL_EXPORT int X509_print(BIO *bp,X509 *x); +OPENSSL_EXPORT int X509_ocspid_print(BIO *bp,X509 *x); +OPENSSL_EXPORT int X509_CERT_AUX_print(BIO *bp,X509_CERT_AUX *x, int indent); +OPENSSL_EXPORT int X509_CRL_print(BIO *bp,X509_CRL *x); +OPENSSL_EXPORT int X509_REQ_print_ex(BIO *bp, X509_REQ *x, unsigned long nmflag, unsigned long cflag); +OPENSSL_EXPORT int X509_REQ_print(BIO *bp,X509_REQ *req); + +OPENSSL_EXPORT int X509_NAME_entry_count(X509_NAME *name); +OPENSSL_EXPORT int X509_NAME_get_text_by_NID(X509_NAME *name, int nid, + char *buf,int len); +OPENSSL_EXPORT int X509_NAME_get_text_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj, + char *buf,int len); + +/* NOTE: you should be passsing -1, not 0 as lastpos. The functions that use + * lastpos, search after that position on. */ +OPENSSL_EXPORT int X509_NAME_get_index_by_NID(X509_NAME *name,int nid,int lastpos); +OPENSSL_EXPORT int X509_NAME_get_index_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj, + int lastpos); +OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_get_entry(X509_NAME *name, int loc); +OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_delete_entry(X509_NAME *name, int loc); +OPENSSL_EXPORT int X509_NAME_add_entry(X509_NAME *name,X509_NAME_ENTRY *ne, + int loc, int set); +OPENSSL_EXPORT int X509_NAME_add_entry_by_OBJ(X509_NAME *name, ASN1_OBJECT *obj, int type, + unsigned char *bytes, int len, int loc, int set); +OPENSSL_EXPORT int X509_NAME_add_entry_by_NID(X509_NAME *name, int nid, int type, + unsigned char *bytes, int len, int loc, int set); +OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_txt(X509_NAME_ENTRY **ne, + const char *field, int type, const unsigned char *bytes, int len); +OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_NID(X509_NAME_ENTRY **ne, int nid, + int type,unsigned char *bytes, int len); +OPENSSL_EXPORT int X509_NAME_add_entry_by_txt(X509_NAME *name, const char *field, int type, + const unsigned char *bytes, int len, int loc, int set); +OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_OBJ(X509_NAME_ENTRY **ne, + const ASN1_OBJECT *obj, int type,const unsigned char *bytes, + int len); +OPENSSL_EXPORT int X509_NAME_ENTRY_set_object(X509_NAME_ENTRY *ne, + const ASN1_OBJECT *obj); +OPENSSL_EXPORT int X509_NAME_ENTRY_set_data(X509_NAME_ENTRY *ne, int type, + const unsigned char *bytes, int len); +OPENSSL_EXPORT ASN1_OBJECT * X509_NAME_ENTRY_get_object(X509_NAME_ENTRY *ne); +OPENSSL_EXPORT ASN1_STRING * X509_NAME_ENTRY_get_data(X509_NAME_ENTRY *ne); + +OPENSSL_EXPORT int X509v3_get_ext_count(const STACK_OF(X509_EXTENSION) *x); +OPENSSL_EXPORT int X509v3_get_ext_by_NID(const STACK_OF(X509_EXTENSION) *x, + int nid, int lastpos); +OPENSSL_EXPORT int X509v3_get_ext_by_OBJ(const STACK_OF(X509_EXTENSION) *x, + const ASN1_OBJECT *obj,int lastpos); +OPENSSL_EXPORT int X509v3_get_ext_by_critical(const STACK_OF(X509_EXTENSION) *x, + int crit, int lastpos); +OPENSSL_EXPORT X509_EXTENSION *X509v3_get_ext(const STACK_OF(X509_EXTENSION) *x, int loc); +OPENSSL_EXPORT X509_EXTENSION *X509v3_delete_ext(STACK_OF(X509_EXTENSION) *x, int loc); +OPENSSL_EXPORT STACK_OF(X509_EXTENSION) *X509v3_add_ext(STACK_OF(X509_EXTENSION) **x, + X509_EXTENSION *ex, int loc); + +OPENSSL_EXPORT int X509_get_ext_count(X509 *x); +OPENSSL_EXPORT int X509_get_ext_by_NID(X509 *x, int nid, int lastpos); +OPENSSL_EXPORT int X509_get_ext_by_OBJ(X509 *x,ASN1_OBJECT *obj,int lastpos); +OPENSSL_EXPORT int X509_get_ext_by_critical(X509 *x, int crit, int lastpos); +OPENSSL_EXPORT X509_EXTENSION *X509_get_ext(X509 *x, int loc); +OPENSSL_EXPORT X509_EXTENSION *X509_delete_ext(X509 *x, int loc); +OPENSSL_EXPORT int X509_add_ext(X509 *x, X509_EXTENSION *ex, int loc); +OPENSSL_EXPORT void * X509_get_ext_d2i(X509 *x, int nid, int *crit, int *idx); +OPENSSL_EXPORT int X509_add1_ext_i2d(X509 *x, int nid, void *value, int crit, + unsigned long flags); + +OPENSSL_EXPORT int X509_CRL_get_ext_count(X509_CRL *x); +OPENSSL_EXPORT int X509_CRL_get_ext_by_NID(X509_CRL *x, int nid, int lastpos); +OPENSSL_EXPORT int X509_CRL_get_ext_by_OBJ(X509_CRL *x,ASN1_OBJECT *obj,int lastpos); +OPENSSL_EXPORT int X509_CRL_get_ext_by_critical(X509_CRL *x, int crit, int lastpos); +OPENSSL_EXPORT X509_EXTENSION *X509_CRL_get_ext(X509_CRL *x, int loc); +OPENSSL_EXPORT X509_EXTENSION *X509_CRL_delete_ext(X509_CRL *x, int loc); +OPENSSL_EXPORT int X509_CRL_add_ext(X509_CRL *x, X509_EXTENSION *ex, int loc); +OPENSSL_EXPORT void * X509_CRL_get_ext_d2i(X509_CRL *x, int nid, int *crit, int *idx); +OPENSSL_EXPORT int X509_CRL_add1_ext_i2d(X509_CRL *x, int nid, void *value, int crit, + unsigned long flags); + +OPENSSL_EXPORT int X509_REVOKED_get_ext_count(X509_REVOKED *x); +OPENSSL_EXPORT int X509_REVOKED_get_ext_by_NID(X509_REVOKED *x, int nid, int lastpos); +OPENSSL_EXPORT int X509_REVOKED_get_ext_by_OBJ(X509_REVOKED *x,ASN1_OBJECT *obj,int lastpos); +OPENSSL_EXPORT int X509_REVOKED_get_ext_by_critical(X509_REVOKED *x, int crit, int lastpos); +OPENSSL_EXPORT X509_EXTENSION *X509_REVOKED_get_ext(X509_REVOKED *x, int loc); +OPENSSL_EXPORT X509_EXTENSION *X509_REVOKED_delete_ext(X509_REVOKED *x, int loc); +OPENSSL_EXPORT int X509_REVOKED_add_ext(X509_REVOKED *x, X509_EXTENSION *ex, int loc); +OPENSSL_EXPORT void * X509_REVOKED_get_ext_d2i(X509_REVOKED *x, int nid, int *crit, int *idx); +OPENSSL_EXPORT int X509_REVOKED_add1_ext_i2d(X509_REVOKED *x, int nid, void *value, int crit, + unsigned long flags); + +OPENSSL_EXPORT X509_EXTENSION *X509_EXTENSION_create_by_NID(X509_EXTENSION **ex, + int nid, int crit, ASN1_OCTET_STRING *data); +OPENSSL_EXPORT X509_EXTENSION *X509_EXTENSION_create_by_OBJ(X509_EXTENSION **ex, + const ASN1_OBJECT *obj,int crit,ASN1_OCTET_STRING *data); +OPENSSL_EXPORT int X509_EXTENSION_set_object(X509_EXTENSION *ex,const ASN1_OBJECT *obj); +OPENSSL_EXPORT int X509_EXTENSION_set_critical(X509_EXTENSION *ex, int crit); +OPENSSL_EXPORT int X509_EXTENSION_set_data(X509_EXTENSION *ex, + ASN1_OCTET_STRING *data); +OPENSSL_EXPORT ASN1_OBJECT * X509_EXTENSION_get_object(X509_EXTENSION *ex); +OPENSSL_EXPORT ASN1_OCTET_STRING *X509_EXTENSION_get_data(X509_EXTENSION *ne); +OPENSSL_EXPORT int X509_EXTENSION_get_critical(X509_EXTENSION *ex); + +OPENSSL_EXPORT int X509at_get_attr_count(const STACK_OF(X509_ATTRIBUTE) *x); +OPENSSL_EXPORT int X509at_get_attr_by_NID(const STACK_OF(X509_ATTRIBUTE) *x, int nid, + int lastpos); +OPENSSL_EXPORT int X509at_get_attr_by_OBJ(const STACK_OF(X509_ATTRIBUTE) *sk, const ASN1_OBJECT *obj, + int lastpos); +OPENSSL_EXPORT X509_ATTRIBUTE *X509at_get_attr(const STACK_OF(X509_ATTRIBUTE) *x, int loc); +OPENSSL_EXPORT X509_ATTRIBUTE *X509at_delete_attr(STACK_OF(X509_ATTRIBUTE) *x, int loc); +OPENSSL_EXPORT STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x, + X509_ATTRIBUTE *attr); +OPENSSL_EXPORT STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_OBJ(STACK_OF(X509_ATTRIBUTE) **x, + const ASN1_OBJECT *obj, int type, + const unsigned char *bytes, int len); +OPENSSL_EXPORT STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_NID(STACK_OF(X509_ATTRIBUTE) **x, + int nid, int type, + const unsigned char *bytes, int len); +OPENSSL_EXPORT STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_txt(STACK_OF(X509_ATTRIBUTE) **x, + const char *attrname, int type, + const unsigned char *bytes, int len); +OPENSSL_EXPORT void *X509at_get0_data_by_OBJ(STACK_OF(X509_ATTRIBUTE) *x, + ASN1_OBJECT *obj, int lastpos, int type); +OPENSSL_EXPORT X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_NID(X509_ATTRIBUTE **attr, int nid, + int atrtype, const void *data, int len); +OPENSSL_EXPORT X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_OBJ(X509_ATTRIBUTE **attr, + const ASN1_OBJECT *obj, int atrtype, const void *data, int len); +OPENSSL_EXPORT X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_txt(X509_ATTRIBUTE **attr, + const char *atrname, int type, const unsigned char *bytes, int len); +OPENSSL_EXPORT int X509_ATTRIBUTE_set1_object(X509_ATTRIBUTE *attr, const ASN1_OBJECT *obj); +OPENSSL_EXPORT int X509_ATTRIBUTE_set1_data(X509_ATTRIBUTE *attr, int attrtype, const void *data, int len); +OPENSSL_EXPORT void *X509_ATTRIBUTE_get0_data(X509_ATTRIBUTE *attr, int idx, + int atrtype, void *data); +OPENSSL_EXPORT int X509_ATTRIBUTE_count(X509_ATTRIBUTE *attr); +OPENSSL_EXPORT ASN1_OBJECT *X509_ATTRIBUTE_get0_object(X509_ATTRIBUTE *attr); +OPENSSL_EXPORT ASN1_TYPE *X509_ATTRIBUTE_get0_type(X509_ATTRIBUTE *attr, int idx); + +OPENSSL_EXPORT int EVP_PKEY_get_attr_count(const EVP_PKEY *key); +OPENSSL_EXPORT int EVP_PKEY_get_attr_by_NID(const EVP_PKEY *key, int nid, + int lastpos); +OPENSSL_EXPORT int EVP_PKEY_get_attr_by_OBJ(const EVP_PKEY *key, ASN1_OBJECT *obj, + int lastpos); +OPENSSL_EXPORT X509_ATTRIBUTE *EVP_PKEY_get_attr(const EVP_PKEY *key, int loc); +OPENSSL_EXPORT X509_ATTRIBUTE *EVP_PKEY_delete_attr(EVP_PKEY *key, int loc); +OPENSSL_EXPORT int EVP_PKEY_add1_attr(EVP_PKEY *key, X509_ATTRIBUTE *attr); +OPENSSL_EXPORT int EVP_PKEY_add1_attr_by_OBJ(EVP_PKEY *key, + const ASN1_OBJECT *obj, int type, + const unsigned char *bytes, int len); +OPENSSL_EXPORT int EVP_PKEY_add1_attr_by_NID(EVP_PKEY *key, + int nid, int type, + const unsigned char *bytes, int len); +OPENSSL_EXPORT int EVP_PKEY_add1_attr_by_txt(EVP_PKEY *key, + const char *attrname, int type, + const unsigned char *bytes, int len); + +OPENSSL_EXPORT int X509_verify_cert(X509_STORE_CTX *ctx); + +/* lookup a cert from a X509 STACK */ +OPENSSL_EXPORT X509 *X509_find_by_issuer_and_serial(STACK_OF(X509) *sk,X509_NAME *name, + ASN1_INTEGER *serial); +OPENSSL_EXPORT X509 *X509_find_by_subject(STACK_OF(X509) *sk,X509_NAME *name); + +DECLARE_ASN1_FUNCTIONS(PBEPARAM) +DECLARE_ASN1_FUNCTIONS(PBE2PARAM) +DECLARE_ASN1_FUNCTIONS(PBKDF2PARAM) + +OPENSSL_EXPORT int PKCS5_pbe_set0_algor(X509_ALGOR *algor, int alg, int iter, + const unsigned char *salt, int saltlen); + +OPENSSL_EXPORT X509_ALGOR *PKCS5_pbe_set(int alg, int iter, + const unsigned char *salt, int saltlen); +OPENSSL_EXPORT X509_ALGOR *PKCS5_pbe2_set(const EVP_CIPHER *cipher, int iter, + unsigned char *salt, int saltlen); +OPENSSL_EXPORT X509_ALGOR *PKCS5_pbe2_set_iv(const EVP_CIPHER *cipher, int iter, + unsigned char *salt, int saltlen, + unsigned char *aiv, int prf_nid); + +OPENSSL_EXPORT X509_ALGOR *PKCS5_pbkdf2_set(int iter, unsigned char *salt, int saltlen, + int prf_nid, int keylen); + +/* PKCS#8 utilities */ + +DECLARE_ASN1_FUNCTIONS(PKCS8_PRIV_KEY_INFO) + +OPENSSL_EXPORT EVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *p8); +OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(EVP_PKEY *pkey); +OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8_broken(EVP_PKEY *pkey, int broken); +OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *PKCS8_set_broken(PKCS8_PRIV_KEY_INFO *p8, int broken); + +OPENSSL_EXPORT int PKCS8_pkey_set0(PKCS8_PRIV_KEY_INFO *priv, ASN1_OBJECT *aobj, + int version, int ptype, void *pval, + unsigned char *penc, int penclen); +OPENSSL_EXPORT int PKCS8_pkey_get0(ASN1_OBJECT **ppkalg, + const unsigned char **pk, int *ppklen, + X509_ALGOR **pa, + PKCS8_PRIV_KEY_INFO *p8); + +OPENSSL_EXPORT int X509_PUBKEY_set0_param(X509_PUBKEY *pub, const ASN1_OBJECT *aobj, + int ptype, void *pval, + unsigned char *penc, int penclen); +OPENSSL_EXPORT int X509_PUBKEY_get0_param(ASN1_OBJECT **ppkalg, + const unsigned char **pk, int *ppklen, + X509_ALGOR **pa, + X509_PUBKEY *pub); + +OPENSSL_EXPORT int X509_check_trust(X509 *x, int id, int flags); +OPENSSL_EXPORT int X509_TRUST_get_count(void); +OPENSSL_EXPORT X509_TRUST * X509_TRUST_get0(int idx); +OPENSSL_EXPORT int X509_TRUST_get_by_id(int id); +OPENSSL_EXPORT int X509_TRUST_add(int id, int flags, int (*ck)(X509_TRUST *, X509 *, int), + char *name, int arg1, void *arg2); +OPENSSL_EXPORT void X509_TRUST_cleanup(void); +OPENSSL_EXPORT int X509_TRUST_get_flags(X509_TRUST *xp); +OPENSSL_EXPORT char *X509_TRUST_get0_name(X509_TRUST *xp); +OPENSSL_EXPORT int X509_TRUST_get_trust(X509_TRUST *xp); + +/* PKCS7_get_certificates parses a PKCS#7, SignedData structure from |cbs| and + * appends the included certificates to |out_certs|. It returns one on success + * and zero on error. */ +OPENSSL_EXPORT int PKCS7_get_certificates(STACK_OF(X509) *out_certs, CBS *cbs); + +/* PKCS7_bundle_certificates appends a PKCS#7, SignedData structure containing + * |certs| to |out|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int PKCS7_bundle_certificates( + CBB *out, const STACK_OF(X509) *certs); + +/* PKCS7_get_CRLs parses a PKCS#7, SignedData structure from |cbs| and appends + * the included CRLs to |out_crls|. It returns one on success and zero on + * error. */ +OPENSSL_EXPORT int PKCS7_get_CRLs(STACK_OF(X509_CRL) *out_crls, CBS *cbs); + +/* PKCS7_bundle_CRLs appends a PKCS#7, SignedData structure containing + * |crls| to |out|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int PKCS7_bundle_CRLs(CBB *out, const STACK_OF(X509_CRL) *crls); + +/* PKCS7_get_PEM_certificates reads a PEM-encoded, PKCS#7, SignedData structure + * from |pem_bio| and appends the included certificates to |out_certs|. It + * returns one on success and zero on error. */ +OPENSSL_EXPORT int PKCS7_get_PEM_certificates(STACK_OF(X509) *out_certs, + BIO *pem_bio); + +/* PKCS7_get_PEM_CRLs reads a PEM-encoded, PKCS#7, SignedData structure from + * |pem_bio| and appends the included CRLs to |out_crls|. It returns one on + * success and zero on error. */ +OPENSSL_EXPORT int PKCS7_get_PEM_CRLs(STACK_OF(X509_CRL) *out_crls, + BIO *pem_bio); + +/* EVP_PK values indicate the algorithm of the public key in a certificate. */ + +#define EVP_PK_RSA 0x0001 +#define EVP_PK_DSA 0x0002 +#define EVP_PK_DH 0x0004 +#define EVP_PK_EC 0x0008 + +/* EVP_PKS values indicate the algorithm used to sign a certificate. */ + +#define EVP_PKS_RSA 0x0100 +#define EVP_PKS_DSA 0x0200 +#define EVP_PKS_EC 0x0400 + +/* EVP_PKT values are flags that define what public-key operations can be + * performed with the public key from a certificate. */ + +/* EVP_PKT_SIGN indicates that the public key can be used for signing. */ +#define EVP_PKT_SIGN 0x0010 +/* EVP_PKT_ENC indicates that a session key can be encrypted to the public + * key. */ +#define EVP_PKT_ENC 0x0020 +/* EVP_PKT_EXCH indicates that key-agreement can be performed. */ +#define EVP_PKT_EXCH 0x0040 +/* EVP_PKT_EXP indicates that key is weak (i.e. "export"). */ +#define EVP_PKT_EXP 0x1000 + + +#ifdef __cplusplus +} +#endif + +#define X509_R_AKID_MISMATCH 100 +#define X509_R_BAD_PKCS7_VERSION 101 +#define X509_R_BAD_X509_FILETYPE 102 +#define X509_R_BASE64_DECODE_ERROR 103 +#define X509_R_CANT_CHECK_DH_KEY 104 +#define X509_R_CERT_ALREADY_IN_HASH_TABLE 105 +#define X509_R_CRL_ALREADY_DELTA 106 +#define X509_R_CRL_VERIFY_FAILURE 107 +#define X509_R_IDP_MISMATCH 108 +#define X509_R_INVALID_BIT_STRING_BITS_LEFT 109 +#define X509_R_INVALID_DIRECTORY 110 +#define X509_R_INVALID_FIELD_NAME 111 +#define X509_R_INVALID_TRUST 112 +#define X509_R_ISSUER_MISMATCH 113 +#define X509_R_KEY_TYPE_MISMATCH 114 +#define X509_R_KEY_VALUES_MISMATCH 115 +#define X509_R_LOADING_CERT_DIR 116 +#define X509_R_LOADING_DEFAULTS 117 +#define X509_R_METHOD_NOT_SUPPORTED 118 +#define X509_R_NEWER_CRL_NOT_NEWER 119 +#define X509_R_NOT_PKCS7_SIGNED_DATA 120 +#define X509_R_NO_CERTIFICATES_INCLUDED 121 +#define X509_R_NO_CERT_SET_FOR_US_TO_VERIFY 122 +#define X509_R_NO_CRL_NUMBER 123 +#define X509_R_PUBLIC_KEY_DECODE_ERROR 124 +#define X509_R_PUBLIC_KEY_ENCODE_ERROR 125 +#define X509_R_SHOULD_RETRY 126 +#define X509_R_UNABLE_TO_FIND_PARAMETERS_IN_CHAIN 127 +#define X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY 128 +#define X509_R_UNKNOWN_KEY_TYPE 129 +#define X509_R_UNKNOWN_NID 130 +#define X509_R_UNKNOWN_PURPOSE_ID 131 +#define X509_R_UNKNOWN_TRUST_ID 132 +#define X509_R_UNSUPPORTED_ALGORITHM 133 +#define X509_R_WRONG_LOOKUP_TYPE 134 +#define X509_R_WRONG_TYPE 135 +#define X509_R_NO_CRLS_INCLUDED 136 + +#endif diff --git a/TMessagesProj/jni/boringssl/include/openssl/x509_vfy.h b/TMessagesProj/jni/boringssl/include/openssl/x509_vfy.h new file mode 100644 index 00000000..146e047a --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/x509_vfy.h @@ -0,0 +1,612 @@ +/* crypto/x509/x509_vfy.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_X509_H +#include +/* openssl/x509.h ends up #include-ing this file at about the only + * appropriate moment. */ +#endif + +#ifndef HEADER_X509_VFY_H +#define HEADER_X509_VFY_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if 0 +/* Outer object */ +typedef struct x509_hash_dir_st + { + int num_dirs; + char **dirs; + int *dirs_type; + int num_dirs_alloced; + } X509_HASH_DIR_CTX; +#endif + +typedef struct x509_file_st + { + int num_paths; /* number of paths to files or directories */ + int num_alloced; + char **paths; /* the list of paths or directories */ + int *path_type; + } X509_CERT_FILE_CTX; + +/*******************************/ +/* +SSL_CTX -> X509_STORE + -> X509_LOOKUP + ->X509_LOOKUP_METHOD + -> X509_LOOKUP + ->X509_LOOKUP_METHOD + +SSL -> X509_STORE_CTX + ->X509_STORE + +The X509_STORE holds the tables etc for verification stuff. +A X509_STORE_CTX is used while validating a single certificate. +The X509_STORE has X509_LOOKUPs for looking up certs. +The X509_STORE then calls a function to actually verify the +certificate chain. +*/ + +#define X509_LU_RETRY -1 +#define X509_LU_FAIL 0 +#define X509_LU_X509 1 +#define X509_LU_CRL 2 +#define X509_LU_PKEY 3 + +typedef struct x509_object_st + { + /* one of the above types */ + int type; + union { + char *ptr; + X509 *x509; + X509_CRL *crl; + EVP_PKEY *pkey; + } data; + } X509_OBJECT; + +typedef struct x509_lookup_st X509_LOOKUP; + +DECLARE_STACK_OF(X509_LOOKUP) +DECLARE_STACK_OF(X509_OBJECT) + +/* This is a static that defines the function interface */ +typedef struct x509_lookup_method_st + { + const char *name; + int (*new_item)(X509_LOOKUP *ctx); + void (*free)(X509_LOOKUP *ctx); + int (*init)(X509_LOOKUP *ctx); + int (*shutdown)(X509_LOOKUP *ctx); + int (*ctrl)(X509_LOOKUP *ctx,int cmd,const char *argc,long argl, + char **ret); + int (*get_by_subject)(X509_LOOKUP *ctx,int type,X509_NAME *name, + X509_OBJECT *ret); + int (*get_by_issuer_serial)(X509_LOOKUP *ctx,int type,X509_NAME *name, + ASN1_INTEGER *serial,X509_OBJECT *ret); + int (*get_by_fingerprint)(X509_LOOKUP *ctx,int type, + unsigned char *bytes,int len, + X509_OBJECT *ret); + int (*get_by_alias)(X509_LOOKUP *ctx,int type,char *str,int len, + X509_OBJECT *ret); + } X509_LOOKUP_METHOD; + +typedef struct X509_VERIFY_PARAM_ID_st X509_VERIFY_PARAM_ID; + +/* This structure hold all parameters associated with a verify operation + * by including an X509_VERIFY_PARAM structure in related structures the + * parameters used can be customized + */ + +typedef struct X509_VERIFY_PARAM_st + { + char *name; + time_t check_time; /* Time to use */ + unsigned long inh_flags; /* Inheritance flags */ + unsigned long flags; /* Various verify flags */ + int purpose; /* purpose to check untrusted certificates */ + int trust; /* trust setting to check */ + int depth; /* Verify depth */ + STACK_OF(ASN1_OBJECT) *policies; /* Permissible policies */ + X509_VERIFY_PARAM_ID *id; /* opaque ID data */ + } X509_VERIFY_PARAM; + +DECLARE_STACK_OF(X509_VERIFY_PARAM) + +/* This is used to hold everything. It is used for all certificate + * validation. Once we have a certificate chain, the 'verify' + * function is then called to actually check the cert chain. */ +struct x509_store_st + { + /* The following is a cache of trusted certs */ + int cache; /* if true, stash any hits */ + STACK_OF(X509_OBJECT) *objs; /* Cache of all objects */ + CRYPTO_MUTEX objs_lock; + + /* These are external lookup methods */ + STACK_OF(X509_LOOKUP) *get_cert_methods; + + X509_VERIFY_PARAM *param; + + /* Callbacks for various operations */ + int (*verify)(X509_STORE_CTX *ctx); /* called to verify a certificate */ + int (*verify_cb)(int ok,X509_STORE_CTX *ctx); /* error callback */ + int (*get_issuer)(X509 **issuer, X509_STORE_CTX *ctx, X509 *x); /* get issuers cert from ctx */ + int (*check_issued)(X509_STORE_CTX *ctx, X509 *x, X509 *issuer); /* check issued */ + int (*check_revocation)(X509_STORE_CTX *ctx); /* Check revocation status of chain */ + int (*get_crl)(X509_STORE_CTX *ctx, X509_CRL **crl, X509 *x); /* retrieve CRL */ + int (*check_crl)(X509_STORE_CTX *ctx, X509_CRL *crl); /* Check CRL validity */ + int (*cert_crl)(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x); /* Check certificate against CRL */ + STACK_OF(X509) * (*lookup_certs)(X509_STORE_CTX *ctx, X509_NAME *nm); + STACK_OF(X509_CRL) * (*lookup_crls)(X509_STORE_CTX *ctx, X509_NAME *nm); + int (*cleanup)(X509_STORE_CTX *ctx); + + CRYPTO_refcount_t references; + } /* X509_STORE */; + +OPENSSL_EXPORT int X509_STORE_set_depth(X509_STORE *store, int depth); + +#define X509_STORE_set_verify_cb_func(ctx,func) ((ctx)->verify_cb=(func)) +#define X509_STORE_set_verify_func(ctx,func) ((ctx)->verify=(func)) + +/* This is the functions plus an instance of the local variables. */ +struct x509_lookup_st + { + int init; /* have we been started */ + int skip; /* don't use us. */ + X509_LOOKUP_METHOD *method; /* the functions */ + char *method_data; /* method data */ + + X509_STORE *store_ctx; /* who owns us */ + } /* X509_LOOKUP */; + +/* This is a used when verifying cert chains. Since the + * gathering of the cert chain can take some time (and have to be + * 'retried', this needs to be kept and passed around. */ +struct x509_store_ctx_st /* X509_STORE_CTX */ + { + X509_STORE *ctx; + int current_method; /* used when looking up certs */ + + /* The following are set by the caller */ + X509 *cert; /* The cert to check */ + STACK_OF(X509) *untrusted; /* chain of X509s - untrusted - passed in */ + STACK_OF(X509_CRL) *crls; /* set of CRLs passed in */ + + X509_VERIFY_PARAM *param; + void *other_ctx; /* Other info for use with get_issuer() */ + + /* Callbacks for various operations */ + int (*verify)(X509_STORE_CTX *ctx); /* called to verify a certificate */ + int (*verify_cb)(int ok,X509_STORE_CTX *ctx); /* error callback */ + int (*get_issuer)(X509 **issuer, X509_STORE_CTX *ctx, X509 *x); /* get issuers cert from ctx */ + int (*check_issued)(X509_STORE_CTX *ctx, X509 *x, X509 *issuer); /* check issued */ + int (*check_revocation)(X509_STORE_CTX *ctx); /* Check revocation status of chain */ + int (*get_crl)(X509_STORE_CTX *ctx, X509_CRL **crl, X509 *x); /* retrieve CRL */ + int (*check_crl)(X509_STORE_CTX *ctx, X509_CRL *crl); /* Check CRL validity */ + int (*cert_crl)(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x); /* Check certificate against CRL */ + int (*check_policy)(X509_STORE_CTX *ctx); + STACK_OF(X509) * (*lookup_certs)(X509_STORE_CTX *ctx, X509_NAME *nm); + STACK_OF(X509_CRL) * (*lookup_crls)(X509_STORE_CTX *ctx, X509_NAME *nm); + int (*cleanup)(X509_STORE_CTX *ctx); + + /* The following is built up */ + int valid; /* if 0, rebuild chain */ + int last_untrusted; /* index of last untrusted cert */ + STACK_OF(X509) *chain; /* chain of X509s - built up and trusted */ + X509_POLICY_TREE *tree; /* Valid policy tree */ + + int explicit_policy; /* Require explicit policy value */ + + /* When something goes wrong, this is why */ + int error_depth; + int error; + X509 *current_cert; + X509 *current_issuer; /* cert currently being tested as valid issuer */ + X509_CRL *current_crl; /* current CRL */ + + int current_crl_score; /* score of current CRL */ + unsigned int current_reasons; /* Reason mask */ + + X509_STORE_CTX *parent; /* For CRL path validation: parent context */ + + CRYPTO_EX_DATA ex_data; + } /* X509_STORE_CTX */; + +OPENSSL_EXPORT void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth); + +#define X509_STORE_CTX_set_app_data(ctx,data) \ + X509_STORE_CTX_set_ex_data(ctx,0,data) +#define X509_STORE_CTX_get_app_data(ctx) \ + X509_STORE_CTX_get_ex_data(ctx,0) + +#define X509_L_FILE_LOAD 1 +#define X509_L_ADD_DIR 2 + +#define X509_LOOKUP_load_file(x,name,type) \ + X509_LOOKUP_ctrl((x),X509_L_FILE_LOAD,(name),(long)(type),NULL) + +#define X509_LOOKUP_add_dir(x,name,type) \ + X509_LOOKUP_ctrl((x),X509_L_ADD_DIR,(name),(long)(type),NULL) + +#define X509_V_OK 0 +/* illegal error (for uninitialized values, to avoid X509_V_OK): 1 */ + +#define X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT 2 +#define X509_V_ERR_UNABLE_TO_GET_CRL 3 +#define X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE 4 +#define X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE 5 +#define X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY 6 +#define X509_V_ERR_CERT_SIGNATURE_FAILURE 7 +#define X509_V_ERR_CRL_SIGNATURE_FAILURE 8 +#define X509_V_ERR_CERT_NOT_YET_VALID 9 +#define X509_V_ERR_CERT_HAS_EXPIRED 10 +#define X509_V_ERR_CRL_NOT_YET_VALID 11 +#define X509_V_ERR_CRL_HAS_EXPIRED 12 +#define X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD 13 +#define X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD 14 +#define X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD 15 +#define X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD 16 +#define X509_V_ERR_OUT_OF_MEM 17 +#define X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT 18 +#define X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN 19 +#define X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY 20 +#define X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE 21 +#define X509_V_ERR_CERT_CHAIN_TOO_LONG 22 +#define X509_V_ERR_CERT_REVOKED 23 +#define X509_V_ERR_INVALID_CA 24 +#define X509_V_ERR_PATH_LENGTH_EXCEEDED 25 +#define X509_V_ERR_INVALID_PURPOSE 26 +#define X509_V_ERR_CERT_UNTRUSTED 27 +#define X509_V_ERR_CERT_REJECTED 28 +/* These are 'informational' when looking for issuer cert */ +#define X509_V_ERR_SUBJECT_ISSUER_MISMATCH 29 +#define X509_V_ERR_AKID_SKID_MISMATCH 30 +#define X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH 31 +#define X509_V_ERR_KEYUSAGE_NO_CERTSIGN 32 + +#define X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER 33 +#define X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION 34 +#define X509_V_ERR_KEYUSAGE_NO_CRL_SIGN 35 +#define X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION 36 +#define X509_V_ERR_INVALID_NON_CA 37 +#define X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED 38 +#define X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE 39 +#define X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED 40 + +#define X509_V_ERR_INVALID_EXTENSION 41 +#define X509_V_ERR_INVALID_POLICY_EXTENSION 42 +#define X509_V_ERR_NO_EXPLICIT_POLICY 43 +#define X509_V_ERR_DIFFERENT_CRL_SCOPE 44 +#define X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE 45 + +#define X509_V_ERR_UNNESTED_RESOURCE 46 + +#define X509_V_ERR_PERMITTED_VIOLATION 47 +#define X509_V_ERR_EXCLUDED_VIOLATION 48 +#define X509_V_ERR_SUBTREE_MINMAX 49 +#define X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE 51 +#define X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX 52 +#define X509_V_ERR_UNSUPPORTED_NAME_SYNTAX 53 +#define X509_V_ERR_CRL_PATH_VALIDATION_ERROR 54 + +/* Suite B mode algorithm violation */ +#define X509_V_ERR_SUITE_B_INVALID_VERSION 56 +#define X509_V_ERR_SUITE_B_INVALID_ALGORITHM 57 +#define X509_V_ERR_SUITE_B_INVALID_CURVE 58 +#define X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM 59 +#define X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED 60 +#define X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256 61 + +/* Host, email and IP check errors */ +#define X509_V_ERR_HOSTNAME_MISMATCH 62 +#define X509_V_ERR_EMAIL_MISMATCH 63 +#define X509_V_ERR_IP_ADDRESS_MISMATCH 64 + +/* The application is not happy */ +#define X509_V_ERR_APPLICATION_VERIFICATION 50 + +/* Certificate verify flags */ + +/* Send issuer+subject checks to verify_cb */ +#define X509_V_FLAG_CB_ISSUER_CHECK 0x1 +/* Use check time instead of current time */ +#define X509_V_FLAG_USE_CHECK_TIME 0x2 +/* Lookup CRLs */ +#define X509_V_FLAG_CRL_CHECK 0x4 +/* Lookup CRLs for whole chain */ +#define X509_V_FLAG_CRL_CHECK_ALL 0x8 +/* Ignore unhandled critical extensions */ +#define X509_V_FLAG_IGNORE_CRITICAL 0x10 +/* Disable workarounds for broken certificates */ +#define X509_V_FLAG_X509_STRICT 0x20 +/* Enable proxy certificate validation */ +#define X509_V_FLAG_ALLOW_PROXY_CERTS 0x40 +/* Enable policy checking */ +#define X509_V_FLAG_POLICY_CHECK 0x80 +/* Policy variable require-explicit-policy */ +#define X509_V_FLAG_EXPLICIT_POLICY 0x100 +/* Policy variable inhibit-any-policy */ +#define X509_V_FLAG_INHIBIT_ANY 0x200 +/* Policy variable inhibit-policy-mapping */ +#define X509_V_FLAG_INHIBIT_MAP 0x400 +/* Notify callback that policy is OK */ +#define X509_V_FLAG_NOTIFY_POLICY 0x800 +/* Extended CRL features such as indirect CRLs, alternate CRL signing keys */ +#define X509_V_FLAG_EXTENDED_CRL_SUPPORT 0x1000 +/* Delta CRL support */ +#define X509_V_FLAG_USE_DELTAS 0x2000 +/* Check selfsigned CA signature */ +#define X509_V_FLAG_CHECK_SS_SIGNATURE 0x4000 +/* Use trusted store first */ +#define X509_V_FLAG_TRUSTED_FIRST 0x8000 +/* Suite B 128 bit only mode: not normally used */ +#define X509_V_FLAG_SUITEB_128_LOS_ONLY 0x10000 +/* Suite B 192 bit only mode */ +#define X509_V_FLAG_SUITEB_192_LOS 0x20000 +/* Suite B 128 bit mode allowing 192 bit algorithms */ +#define X509_V_FLAG_SUITEB_128_LOS 0x30000 + +/* Allow partial chains if at least one certificate is in trusted store */ +#define X509_V_FLAG_PARTIAL_CHAIN 0x80000 + +#define X509_VP_FLAG_DEFAULT 0x1 +#define X509_VP_FLAG_OVERWRITE 0x2 +#define X509_VP_FLAG_RESET_FLAGS 0x4 +#define X509_VP_FLAG_LOCKED 0x8 +#define X509_VP_FLAG_ONCE 0x10 + +/* Internal use: mask of policy related options */ +#define X509_V_FLAG_POLICY_MASK (X509_V_FLAG_POLICY_CHECK \ + | X509_V_FLAG_EXPLICIT_POLICY \ + | X509_V_FLAG_INHIBIT_ANY \ + | X509_V_FLAG_INHIBIT_MAP) + +OPENSSL_EXPORT int X509_OBJECT_idx_by_subject(STACK_OF(X509_OBJECT) *h, int type, + X509_NAME *name); +OPENSSL_EXPORT X509_OBJECT *X509_OBJECT_retrieve_by_subject(STACK_OF(X509_OBJECT) *h,int type,X509_NAME *name); +OPENSSL_EXPORT X509_OBJECT *X509_OBJECT_retrieve_match(STACK_OF(X509_OBJECT) *h, X509_OBJECT *x); +OPENSSL_EXPORT void X509_OBJECT_up_ref_count(X509_OBJECT *a); +OPENSSL_EXPORT void X509_OBJECT_free_contents(X509_OBJECT *a); +OPENSSL_EXPORT X509_STORE *X509_STORE_new(void ); +OPENSSL_EXPORT void X509_STORE_free(X509_STORE *v); + +OPENSSL_EXPORT STACK_OF(X509)* X509_STORE_get1_certs(X509_STORE_CTX *st, X509_NAME *nm); +OPENSSL_EXPORT STACK_OF(X509_CRL)* X509_STORE_get1_crls(X509_STORE_CTX *st, X509_NAME *nm); +OPENSSL_EXPORT int X509_STORE_set_flags(X509_STORE *ctx, unsigned long flags); +OPENSSL_EXPORT int X509_STORE_set_purpose(X509_STORE *ctx, int purpose); +OPENSSL_EXPORT int X509_STORE_set_trust(X509_STORE *ctx, int trust); +OPENSSL_EXPORT int X509_STORE_set1_param(X509_STORE *ctx, X509_VERIFY_PARAM *pm); + +OPENSSL_EXPORT void X509_STORE_set_verify_cb(X509_STORE *ctx, + int (*verify_cb)(int, X509_STORE_CTX *)); + +OPENSSL_EXPORT void X509_STORE_set_lookup_crls_cb(X509_STORE *ctx, + STACK_OF(X509_CRL)* (*cb)(X509_STORE_CTX *ctx, X509_NAME *nm)); + +OPENSSL_EXPORT X509_STORE_CTX *X509_STORE_CTX_new(void); + +OPENSSL_EXPORT int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x); + +OPENSSL_EXPORT void X509_STORE_CTX_free(X509_STORE_CTX *ctx); +OPENSSL_EXPORT int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, + X509 *x509, STACK_OF(X509) *chain); +OPENSSL_EXPORT void X509_STORE_CTX_trusted_stack(X509_STORE_CTX *ctx, STACK_OF(X509) *sk); +OPENSSL_EXPORT void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx); + +OPENSSL_EXPORT X509_STORE *X509_STORE_CTX_get0_store(X509_STORE_CTX *ctx); + +OPENSSL_EXPORT X509_LOOKUP *X509_STORE_add_lookup(X509_STORE *v, X509_LOOKUP_METHOD *m); + +OPENSSL_EXPORT X509_LOOKUP_METHOD *X509_LOOKUP_hash_dir(void); +OPENSSL_EXPORT X509_LOOKUP_METHOD *X509_LOOKUP_file(void); + +OPENSSL_EXPORT int X509_STORE_add_cert(X509_STORE *ctx, X509 *x); +OPENSSL_EXPORT int X509_STORE_add_crl(X509_STORE *ctx, X509_CRL *x); + +OPENSSL_EXPORT int X509_STORE_get_by_subject(X509_STORE_CTX *vs,int type,X509_NAME *name, + X509_OBJECT *ret); + +OPENSSL_EXPORT int X509_LOOKUP_ctrl(X509_LOOKUP *ctx, int cmd, const char *argc, + long argl, char **ret); + +#ifndef OPENSSL_NO_STDIO +OPENSSL_EXPORT int X509_load_cert_file(X509_LOOKUP *ctx, const char *file, int type); +OPENSSL_EXPORT int X509_load_crl_file(X509_LOOKUP *ctx, const char *file, int type); +OPENSSL_EXPORT int X509_load_cert_crl_file(X509_LOOKUP *ctx, const char *file, int type); +#endif + + +OPENSSL_EXPORT X509_LOOKUP *X509_LOOKUP_new(X509_LOOKUP_METHOD *method); +OPENSSL_EXPORT void X509_LOOKUP_free(X509_LOOKUP *ctx); +OPENSSL_EXPORT int X509_LOOKUP_init(X509_LOOKUP *ctx); +OPENSSL_EXPORT int X509_LOOKUP_by_subject(X509_LOOKUP *ctx, int type, X509_NAME *name, + X509_OBJECT *ret); +OPENSSL_EXPORT int X509_LOOKUP_by_issuer_serial(X509_LOOKUP *ctx, int type, X509_NAME *name, + ASN1_INTEGER *serial, X509_OBJECT *ret); +OPENSSL_EXPORT int X509_LOOKUP_by_fingerprint(X509_LOOKUP *ctx, int type, + unsigned char *bytes, int len, X509_OBJECT *ret); +OPENSSL_EXPORT int X509_LOOKUP_by_alias(X509_LOOKUP *ctx, int type, char *str, + int len, X509_OBJECT *ret); +OPENSSL_EXPORT int X509_LOOKUP_shutdown(X509_LOOKUP *ctx); + +#ifndef OPENSSL_NO_STDIO +OPENSSL_EXPORT int X509_STORE_load_locations (X509_STORE *ctx, + const char *file, const char *dir); +OPENSSL_EXPORT int X509_STORE_set_default_paths(X509_STORE *ctx); +#endif + +OPENSSL_EXPORT int X509_STORE_CTX_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func); +OPENSSL_EXPORT int X509_STORE_CTX_set_ex_data(X509_STORE_CTX *ctx,int idx,void *data); +OPENSSL_EXPORT void * X509_STORE_CTX_get_ex_data(X509_STORE_CTX *ctx,int idx); +OPENSSL_EXPORT int X509_STORE_CTX_get_error(X509_STORE_CTX *ctx); +OPENSSL_EXPORT void X509_STORE_CTX_set_error(X509_STORE_CTX *ctx,int s); +OPENSSL_EXPORT int X509_STORE_CTX_get_error_depth(X509_STORE_CTX *ctx); +OPENSSL_EXPORT X509 * X509_STORE_CTX_get_current_cert(X509_STORE_CTX *ctx); +OPENSSL_EXPORT X509 *X509_STORE_CTX_get0_current_issuer(X509_STORE_CTX *ctx); +OPENSSL_EXPORT X509_CRL *X509_STORE_CTX_get0_current_crl(X509_STORE_CTX *ctx); +OPENSSL_EXPORT X509_STORE_CTX *X509_STORE_CTX_get0_parent_ctx(X509_STORE_CTX *ctx); +OPENSSL_EXPORT STACK_OF(X509) *X509_STORE_CTX_get_chain(X509_STORE_CTX *ctx); +OPENSSL_EXPORT STACK_OF(X509) *X509_STORE_CTX_get1_chain(X509_STORE_CTX *ctx); +OPENSSL_EXPORT void X509_STORE_CTX_set_cert(X509_STORE_CTX *c,X509 *x); +OPENSSL_EXPORT void X509_STORE_CTX_set_chain(X509_STORE_CTX *c,STACK_OF(X509) *sk); +OPENSSL_EXPORT void X509_STORE_CTX_set0_crls(X509_STORE_CTX *c,STACK_OF(X509_CRL) *sk); +OPENSSL_EXPORT int X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose); +OPENSSL_EXPORT int X509_STORE_CTX_set_trust(X509_STORE_CTX *ctx, int trust); +OPENSSL_EXPORT int X509_STORE_CTX_purpose_inherit(X509_STORE_CTX *ctx, int def_purpose, + int purpose, int trust); +OPENSSL_EXPORT void X509_STORE_CTX_set_flags(X509_STORE_CTX *ctx, unsigned long flags); +OPENSSL_EXPORT void X509_STORE_CTX_set_time(X509_STORE_CTX *ctx, unsigned long flags, + time_t t); +OPENSSL_EXPORT void X509_STORE_CTX_set_verify_cb(X509_STORE_CTX *ctx, + int (*verify_cb)(int, X509_STORE_CTX *)); + +OPENSSL_EXPORT X509_POLICY_TREE *X509_STORE_CTX_get0_policy_tree(X509_STORE_CTX *ctx); +OPENSSL_EXPORT int X509_STORE_CTX_get_explicit_policy(X509_STORE_CTX *ctx); + +OPENSSL_EXPORT X509_VERIFY_PARAM *X509_STORE_CTX_get0_param(X509_STORE_CTX *ctx); +OPENSSL_EXPORT void X509_STORE_CTX_set0_param(X509_STORE_CTX *ctx, X509_VERIFY_PARAM *param); +OPENSSL_EXPORT int X509_STORE_CTX_set_default(X509_STORE_CTX *ctx, const char *name); + +/* X509_VERIFY_PARAM functions */ + +OPENSSL_EXPORT X509_VERIFY_PARAM *X509_VERIFY_PARAM_new(void); +OPENSSL_EXPORT void X509_VERIFY_PARAM_free(X509_VERIFY_PARAM *param); +OPENSSL_EXPORT int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *to, + const X509_VERIFY_PARAM *from); +OPENSSL_EXPORT int X509_VERIFY_PARAM_set1(X509_VERIFY_PARAM *to, + const X509_VERIFY_PARAM *from); +OPENSSL_EXPORT int X509_VERIFY_PARAM_set1_name(X509_VERIFY_PARAM *param, const char *name); +OPENSSL_EXPORT int X509_VERIFY_PARAM_set_flags(X509_VERIFY_PARAM *param, unsigned long flags); +OPENSSL_EXPORT int X509_VERIFY_PARAM_clear_flags(X509_VERIFY_PARAM *param, + unsigned long flags); +OPENSSL_EXPORT unsigned long X509_VERIFY_PARAM_get_flags(X509_VERIFY_PARAM *param); +OPENSSL_EXPORT int X509_VERIFY_PARAM_set_purpose(X509_VERIFY_PARAM *param, int purpose); +OPENSSL_EXPORT int X509_VERIFY_PARAM_set_trust(X509_VERIFY_PARAM *param, int trust); +OPENSSL_EXPORT void X509_VERIFY_PARAM_set_depth(X509_VERIFY_PARAM *param, int depth); +OPENSSL_EXPORT void X509_VERIFY_PARAM_set_time(X509_VERIFY_PARAM *param, time_t t); +OPENSSL_EXPORT int X509_VERIFY_PARAM_add0_policy(X509_VERIFY_PARAM *param, + ASN1_OBJECT *policy); +OPENSSL_EXPORT int X509_VERIFY_PARAM_set1_policies(X509_VERIFY_PARAM *param, + STACK_OF(ASN1_OBJECT) *policies); + +OPENSSL_EXPORT int X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *param, + const char *name, size_t namelen); +OPENSSL_EXPORT int X509_VERIFY_PARAM_add1_host(X509_VERIFY_PARAM *param, + const char *name, + size_t namelen); +OPENSSL_EXPORT void X509_VERIFY_PARAM_set_hostflags(X509_VERIFY_PARAM *param, + unsigned int flags); +OPENSSL_EXPORT char *X509_VERIFY_PARAM_get0_peername(X509_VERIFY_PARAM *); +OPENSSL_EXPORT int X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *param, + const char *email, size_t emaillen); +OPENSSL_EXPORT int X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *param, + const unsigned char *ip, size_t iplen); +OPENSSL_EXPORT int X509_VERIFY_PARAM_set1_ip_asc(X509_VERIFY_PARAM *param, const char *ipasc); + +OPENSSL_EXPORT int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *param); +OPENSSL_EXPORT const char *X509_VERIFY_PARAM_get0_name(const X509_VERIFY_PARAM *param); + +OPENSSL_EXPORT int X509_VERIFY_PARAM_add0_table(X509_VERIFY_PARAM *param); +OPENSSL_EXPORT int X509_VERIFY_PARAM_get_count(void); +OPENSSL_EXPORT const X509_VERIFY_PARAM *X509_VERIFY_PARAM_get0(int id); +OPENSSL_EXPORT const X509_VERIFY_PARAM *X509_VERIFY_PARAM_lookup(const char *name); +OPENSSL_EXPORT void X509_VERIFY_PARAM_table_cleanup(void); + +OPENSSL_EXPORT int X509_policy_check(X509_POLICY_TREE **ptree, int *pexplicit_policy, + STACK_OF(X509) *certs, + STACK_OF(ASN1_OBJECT) *policy_oids, + unsigned int flags); + +OPENSSL_EXPORT void X509_policy_tree_free(X509_POLICY_TREE *tree); + +OPENSSL_EXPORT int X509_policy_tree_level_count(const X509_POLICY_TREE *tree); +OPENSSL_EXPORT X509_POLICY_LEVEL * + X509_policy_tree_get0_level(const X509_POLICY_TREE *tree, int i); + +OPENSSL_EXPORT STACK_OF(X509_POLICY_NODE) * + X509_policy_tree_get0_policies(const X509_POLICY_TREE *tree); + +OPENSSL_EXPORT STACK_OF(X509_POLICY_NODE) * + X509_policy_tree_get0_user_policies(const X509_POLICY_TREE *tree); + +OPENSSL_EXPORT int X509_policy_level_node_count(X509_POLICY_LEVEL *level); + +OPENSSL_EXPORT X509_POLICY_NODE *X509_policy_level_get0_node(X509_POLICY_LEVEL *level, int i); + +OPENSSL_EXPORT const ASN1_OBJECT *X509_policy_node_get0_policy(const X509_POLICY_NODE *node); + +OPENSSL_EXPORT STACK_OF(POLICYQUALINFO) * + X509_policy_node_get0_qualifiers(const X509_POLICY_NODE *node); +OPENSSL_EXPORT const X509_POLICY_NODE * + X509_policy_node_get0_parent(const X509_POLICY_NODE *node); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/TMessagesProj/jni/boringssl/include/openssl/x509v3.h b/TMessagesProj/jni/boringssl/include/openssl/x509v3.h new file mode 100644 index 00000000..b7b8ba71 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/x509v3.h @@ -0,0 +1,798 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. */ +/* ==================================================================== + * Copyright (c) 1999-2004 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef HEADER_X509V3_H +#define HEADER_X509V3_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward reference */ +struct v3_ext_method; +struct v3_ext_ctx; + +/* Useful typedefs */ + +typedef void * (*X509V3_EXT_NEW)(void); +typedef void (*X509V3_EXT_FREE)(void *); +typedef void * (*X509V3_EXT_D2I)(void *, const unsigned char ** , long); +typedef int (*X509V3_EXT_I2D)(void *, unsigned char **); +typedef STACK_OF(CONF_VALUE) * + (*X509V3_EXT_I2V)(const struct v3_ext_method *method, void *ext, + STACK_OF(CONF_VALUE) *extlist); +typedef void * (*X509V3_EXT_V2I)(const struct v3_ext_method *method, + struct v3_ext_ctx *ctx, + STACK_OF(CONF_VALUE) *values); +typedef char * (*X509V3_EXT_I2S)(const struct v3_ext_method *method, void *ext); +typedef void * (*X509V3_EXT_S2I)(const struct v3_ext_method *method, + struct v3_ext_ctx *ctx, const char *str); +typedef int (*X509V3_EXT_I2R)(const struct v3_ext_method *method, void *ext, + BIO *out, int indent); +typedef void * (*X509V3_EXT_R2I)(const struct v3_ext_method *method, + struct v3_ext_ctx *ctx, const char *str); + +/* V3 extension structure */ + +struct v3_ext_method { +int ext_nid; +int ext_flags; +/* If this is set the following four fields are ignored */ +ASN1_ITEM_EXP *it; +/* Old style ASN1 calls */ +X509V3_EXT_NEW ext_new; +X509V3_EXT_FREE ext_free; +X509V3_EXT_D2I d2i; +X509V3_EXT_I2D i2d; + +/* The following pair is used for string extensions */ +X509V3_EXT_I2S i2s; +X509V3_EXT_S2I s2i; + +/* The following pair is used for multi-valued extensions */ +X509V3_EXT_I2V i2v; +X509V3_EXT_V2I v2i; + +/* The following are used for raw extensions */ +X509V3_EXT_I2R i2r; +X509V3_EXT_R2I r2i; + +void *usr_data; /* Any extension specific data */ +}; + +typedef struct X509V3_CONF_METHOD_st { +char * (*get_string)(void *db, char *section, char *value); +STACK_OF(CONF_VALUE) * (*get_section)(void *db, char *section); +void (*free_string)(void *db, char * string); +void (*free_section)(void *db, STACK_OF(CONF_VALUE) *section); +} X509V3_CONF_METHOD; + +/* Context specific info */ +struct v3_ext_ctx { +#define CTX_TEST 0x1 +int flags; +X509 *issuer_cert; +X509 *subject_cert; +X509_REQ *subject_req; +X509_CRL *crl; +const X509V3_CONF_METHOD *db_meth; +void *db; +/* Maybe more here */ +}; + +typedef struct v3_ext_method X509V3_EXT_METHOD; + +DECLARE_STACK_OF(X509V3_EXT_METHOD) + +/* ext_flags values */ +#define X509V3_EXT_DYNAMIC 0x1 +#define X509V3_EXT_CTX_DEP 0x2 +#define X509V3_EXT_MULTILINE 0x4 + +typedef BIT_STRING_BITNAME ENUMERATED_NAMES; + +typedef struct BASIC_CONSTRAINTS_st { +int ca; +ASN1_INTEGER *pathlen; +} BASIC_CONSTRAINTS; + + +typedef struct PKEY_USAGE_PERIOD_st { +ASN1_GENERALIZEDTIME *notBefore; +ASN1_GENERALIZEDTIME *notAfter; +} PKEY_USAGE_PERIOD; + +typedef struct otherName_st { +ASN1_OBJECT *type_id; +ASN1_TYPE *value; +} OTHERNAME; + +typedef struct EDIPartyName_st { + ASN1_STRING *nameAssigner; + ASN1_STRING *partyName; +} EDIPARTYNAME; + +typedef struct GENERAL_NAME_st { + +#define GEN_OTHERNAME 0 +#define GEN_EMAIL 1 +#define GEN_DNS 2 +#define GEN_X400 3 +#define GEN_DIRNAME 4 +#define GEN_EDIPARTY 5 +#define GEN_URI 6 +#define GEN_IPADD 7 +#define GEN_RID 8 + +int type; +union { + char *ptr; + OTHERNAME *otherName; /* otherName */ + ASN1_IA5STRING *rfc822Name; + ASN1_IA5STRING *dNSName; + ASN1_TYPE *x400Address; + X509_NAME *directoryName; + EDIPARTYNAME *ediPartyName; + ASN1_IA5STRING *uniformResourceIdentifier; + ASN1_OCTET_STRING *iPAddress; + ASN1_OBJECT *registeredID; + + /* Old names */ + ASN1_OCTET_STRING *ip; /* iPAddress */ + X509_NAME *dirn; /* dirn */ + ASN1_IA5STRING *ia5;/* rfc822Name, dNSName, uniformResourceIdentifier */ + ASN1_OBJECT *rid; /* registeredID */ + ASN1_TYPE *other; /* x400Address */ +} d; +} GENERAL_NAME; + +typedef STACK_OF(GENERAL_NAME) GENERAL_NAMES; + +typedef struct ACCESS_DESCRIPTION_st { + ASN1_OBJECT *method; + GENERAL_NAME *location; +} ACCESS_DESCRIPTION; + +typedef STACK_OF(ACCESS_DESCRIPTION) AUTHORITY_INFO_ACCESS; + +typedef STACK_OF(ASN1_OBJECT) EXTENDED_KEY_USAGE; + +DECLARE_STACK_OF(GENERAL_NAME) +DECLARE_ASN1_SET_OF(GENERAL_NAME) + +DECLARE_STACK_OF(ACCESS_DESCRIPTION) +DECLARE_ASN1_SET_OF(ACCESS_DESCRIPTION) + +typedef struct DIST_POINT_NAME_st { +int type; +union { + GENERAL_NAMES *fullname; + STACK_OF(X509_NAME_ENTRY) *relativename; +} name; +/* If relativename then this contains the full distribution point name */ +X509_NAME *dpname; +} DIST_POINT_NAME; +/* All existing reasons */ +#define CRLDP_ALL_REASONS 0x807f + +#define CRL_REASON_NONE -1 +#define CRL_REASON_UNSPECIFIED 0 +#define CRL_REASON_KEY_COMPROMISE 1 +#define CRL_REASON_CA_COMPROMISE 2 +#define CRL_REASON_AFFILIATION_CHANGED 3 +#define CRL_REASON_SUPERSEDED 4 +#define CRL_REASON_CESSATION_OF_OPERATION 5 +#define CRL_REASON_CERTIFICATE_HOLD 6 +#define CRL_REASON_REMOVE_FROM_CRL 8 +#define CRL_REASON_PRIVILEGE_WITHDRAWN 9 +#define CRL_REASON_AA_COMPROMISE 10 + +struct DIST_POINT_st { +DIST_POINT_NAME *distpoint; +ASN1_BIT_STRING *reasons; +GENERAL_NAMES *CRLissuer; +int dp_reasons; +}; + +typedef STACK_OF(DIST_POINT) CRL_DIST_POINTS; + +DECLARE_STACK_OF(DIST_POINT) +DECLARE_ASN1_SET_OF(DIST_POINT) + +struct AUTHORITY_KEYID_st { +ASN1_OCTET_STRING *keyid; +GENERAL_NAMES *issuer; +ASN1_INTEGER *serial; +}; + +/* Strong extranet structures */ + +typedef struct SXNET_ID_st { + ASN1_INTEGER *zone; + ASN1_OCTET_STRING *user; +} SXNETID; + +DECLARE_STACK_OF(SXNETID) +DECLARE_ASN1_SET_OF(SXNETID) + +typedef struct SXNET_st { + ASN1_INTEGER *version; + STACK_OF(SXNETID) *ids; +} SXNET; + +typedef struct NOTICEREF_st { + ASN1_STRING *organization; + STACK_OF(ASN1_INTEGER) *noticenos; +} NOTICEREF; + +typedef struct USERNOTICE_st { + NOTICEREF *noticeref; + ASN1_STRING *exptext; +} USERNOTICE; + +typedef struct POLICYQUALINFO_st { + ASN1_OBJECT *pqualid; + union { + ASN1_IA5STRING *cpsuri; + USERNOTICE *usernotice; + ASN1_TYPE *other; + } d; +} POLICYQUALINFO; + +DECLARE_STACK_OF(POLICYQUALINFO) +DECLARE_ASN1_SET_OF(POLICYQUALINFO) + +typedef struct POLICYINFO_st { + ASN1_OBJECT *policyid; + STACK_OF(POLICYQUALINFO) *qualifiers; +} POLICYINFO; + +typedef STACK_OF(POLICYINFO) CERTIFICATEPOLICIES; + +DECLARE_STACK_OF(POLICYINFO) +DECLARE_ASN1_SET_OF(POLICYINFO) + +typedef struct POLICY_MAPPING_st { + ASN1_OBJECT *issuerDomainPolicy; + ASN1_OBJECT *subjectDomainPolicy; +} POLICY_MAPPING; + +DECLARE_STACK_OF(POLICY_MAPPING) + +typedef STACK_OF(POLICY_MAPPING) POLICY_MAPPINGS; + +typedef struct GENERAL_SUBTREE_st { + GENERAL_NAME *base; + ASN1_INTEGER *minimum; + ASN1_INTEGER *maximum; +} GENERAL_SUBTREE; + +DECLARE_STACK_OF(GENERAL_SUBTREE) + +struct NAME_CONSTRAINTS_st { + STACK_OF(GENERAL_SUBTREE) *permittedSubtrees; + STACK_OF(GENERAL_SUBTREE) *excludedSubtrees; +}; + +typedef struct POLICY_CONSTRAINTS_st { + ASN1_INTEGER *requireExplicitPolicy; + ASN1_INTEGER *inhibitPolicyMapping; +} POLICY_CONSTRAINTS; + +/* Proxy certificate structures, see RFC 3820 */ +typedef struct PROXY_POLICY_st + { + ASN1_OBJECT *policyLanguage; + ASN1_OCTET_STRING *policy; + } PROXY_POLICY; + +typedef struct PROXY_CERT_INFO_EXTENSION_st + { + ASN1_INTEGER *pcPathLengthConstraint; + PROXY_POLICY *proxyPolicy; + } PROXY_CERT_INFO_EXTENSION; + +DECLARE_ASN1_FUNCTIONS(PROXY_POLICY) +DECLARE_ASN1_FUNCTIONS(PROXY_CERT_INFO_EXTENSION) + +struct ISSUING_DIST_POINT_st + { + DIST_POINT_NAME *distpoint; + int onlyuser; + int onlyCA; + ASN1_BIT_STRING *onlysomereasons; + int indirectCRL; + int onlyattr; + }; + +/* Values in idp_flags field */ +/* IDP present */ +#define IDP_PRESENT 0x1 +/* IDP values inconsistent */ +#define IDP_INVALID 0x2 +/* onlyuser true */ +#define IDP_ONLYUSER 0x4 +/* onlyCA true */ +#define IDP_ONLYCA 0x8 +/* onlyattr true */ +#define IDP_ONLYATTR 0x10 +/* indirectCRL true */ +#define IDP_INDIRECT 0x20 +/* onlysomereasons present */ +#define IDP_REASONS 0x40 + +#define X509V3_conf_err(val) ERR_add_error_data(6, "section:", val->section, \ +",name:", val->name, ",value:", val->value); + +#define X509V3_set_ctx_test(ctx) \ + X509V3_set_ctx(ctx, NULL, NULL, NULL, NULL, CTX_TEST) +#define X509V3_set_ctx_nodb(ctx) (ctx)->db = NULL; + +#define EXT_BITSTRING(nid, table) { nid, 0, ASN1_ITEM_ref(ASN1_BIT_STRING), \ + 0,0,0,0, \ + 0,0, \ + (X509V3_EXT_I2V)i2v_ASN1_BIT_STRING, \ + (X509V3_EXT_V2I)v2i_ASN1_BIT_STRING, \ + NULL, NULL, \ + (void *)table} + +#define EXT_IA5STRING(nid) { nid, 0, ASN1_ITEM_ref(ASN1_IA5STRING), \ + 0,0,0,0, \ + (X509V3_EXT_I2S)i2s_ASN1_IA5STRING, \ + (X509V3_EXT_S2I)s2i_ASN1_IA5STRING, \ + 0,0,0,0, \ + NULL} + +#define EXT_END { -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + + +/* X509_PURPOSE stuff */ + +#define EXFLAG_BCONS 0x1 +#define EXFLAG_KUSAGE 0x2 +#define EXFLAG_XKUSAGE 0x4 +#define EXFLAG_NSCERT 0x8 + +#define EXFLAG_CA 0x10 +/* Really self issued not necessarily self signed */ +#define EXFLAG_SI 0x20 +#define EXFLAG_V1 0x40 +#define EXFLAG_INVALID 0x80 +#define EXFLAG_SET 0x100 +#define EXFLAG_CRITICAL 0x200 +#define EXFLAG_PROXY 0x400 + +#define EXFLAG_INVALID_POLICY 0x800 +#define EXFLAG_FRESHEST 0x1000 +/* Self signed */ +#define EXFLAG_SS 0x2000 + +#define KU_DIGITAL_SIGNATURE 0x0080 +#define KU_NON_REPUDIATION 0x0040 +#define KU_KEY_ENCIPHERMENT 0x0020 +#define KU_DATA_ENCIPHERMENT 0x0010 +#define KU_KEY_AGREEMENT 0x0008 +#define KU_KEY_CERT_SIGN 0x0004 +#define KU_CRL_SIGN 0x0002 +#define KU_ENCIPHER_ONLY 0x0001 +#define KU_DECIPHER_ONLY 0x8000 + +#define NS_SSL_CLIENT 0x80 +#define NS_SSL_SERVER 0x40 +#define NS_SMIME 0x20 +#define NS_OBJSIGN 0x10 +#define NS_SSL_CA 0x04 +#define NS_SMIME_CA 0x02 +#define NS_OBJSIGN_CA 0x01 +#define NS_ANY_CA (NS_SSL_CA|NS_SMIME_CA|NS_OBJSIGN_CA) + +#define XKU_SSL_SERVER 0x1 +#define XKU_SSL_CLIENT 0x2 +#define XKU_SMIME 0x4 +#define XKU_CODE_SIGN 0x8 +#define XKU_SGC 0x10 +#define XKU_OCSP_SIGN 0x20 +#define XKU_TIMESTAMP 0x40 +#define XKU_DVCS 0x80 +#define XKU_ANYEKU 0x100 + +#define X509_PURPOSE_DYNAMIC 0x1 +#define X509_PURPOSE_DYNAMIC_NAME 0x2 + +typedef struct x509_purpose_st { + int purpose; + int trust; /* Default trust ID */ + int flags; + int (*check_purpose)(const struct x509_purpose_st *, + const X509 *, int); + char *name; + char *sname; + void *usr_data; +} X509_PURPOSE; + +#define X509_PURPOSE_SSL_CLIENT 1 +#define X509_PURPOSE_SSL_SERVER 2 +#define X509_PURPOSE_NS_SSL_SERVER 3 +#define X509_PURPOSE_SMIME_SIGN 4 +#define X509_PURPOSE_SMIME_ENCRYPT 5 +#define X509_PURPOSE_CRL_SIGN 6 +#define X509_PURPOSE_ANY 7 +#define X509_PURPOSE_OCSP_HELPER 8 +#define X509_PURPOSE_TIMESTAMP_SIGN 9 + +#define X509_PURPOSE_MIN 1 +#define X509_PURPOSE_MAX 9 + +/* Flags for X509V3_EXT_print() */ + +#define X509V3_EXT_UNKNOWN_MASK (0xfL << 16) +/* Return error for unknown extensions */ +#define X509V3_EXT_DEFAULT 0 +/* Print error for unknown extensions */ +#define X509V3_EXT_ERROR_UNKNOWN (1L << 16) +/* ASN1 parse unknown extensions */ +#define X509V3_EXT_PARSE_UNKNOWN (2L << 16) +/* BIO_dump unknown extensions */ +#define X509V3_EXT_DUMP_UNKNOWN (3L << 16) + +/* Flags for X509V3_add1_i2d */ + +#define X509V3_ADD_OP_MASK 0xfL +#define X509V3_ADD_DEFAULT 0L +#define X509V3_ADD_APPEND 1L +#define X509V3_ADD_REPLACE 2L +#define X509V3_ADD_REPLACE_EXISTING 3L +#define X509V3_ADD_KEEP_EXISTING 4L +#define X509V3_ADD_DELETE 5L +#define X509V3_ADD_SILENT 0x10 + +DECLARE_STACK_OF(X509_PURPOSE) + +DECLARE_ASN1_FUNCTIONS(BASIC_CONSTRAINTS) + +DECLARE_ASN1_FUNCTIONS(SXNET) +DECLARE_ASN1_FUNCTIONS(SXNETID) + +int SXNET_add_id_asc(SXNET **psx, char *zone, char *user, int userlen); +int SXNET_add_id_ulong(SXNET **psx, unsigned long lzone, char *user, int userlen); +int SXNET_add_id_INTEGER(SXNET **psx, ASN1_INTEGER *izone, char *user, int userlen); + +ASN1_OCTET_STRING *SXNET_get_id_asc(SXNET *sx, char *zone); +ASN1_OCTET_STRING *SXNET_get_id_ulong(SXNET *sx, unsigned long lzone); +ASN1_OCTET_STRING *SXNET_get_id_INTEGER(SXNET *sx, ASN1_INTEGER *zone); + +DECLARE_ASN1_FUNCTIONS(AUTHORITY_KEYID) + +DECLARE_ASN1_FUNCTIONS(PKEY_USAGE_PERIOD) + +DECLARE_ASN1_FUNCTIONS(GENERAL_NAME) +OPENSSL_EXPORT GENERAL_NAME *GENERAL_NAME_dup(GENERAL_NAME *a); +OPENSSL_EXPORT int GENERAL_NAME_cmp(GENERAL_NAME *a, GENERAL_NAME *b); + + + +OPENSSL_EXPORT ASN1_BIT_STRING *v2i_ASN1_BIT_STRING(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval); +OPENSSL_EXPORT STACK_OF(CONF_VALUE) *i2v_ASN1_BIT_STRING(X509V3_EXT_METHOD *method, + ASN1_BIT_STRING *bits, + STACK_OF(CONF_VALUE) *extlist); + +OPENSSL_EXPORT STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method, GENERAL_NAME *gen, STACK_OF(CONF_VALUE) *ret); +OPENSSL_EXPORT int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen); + +DECLARE_ASN1_FUNCTIONS(GENERAL_NAMES) + +OPENSSL_EXPORT STACK_OF(CONF_VALUE) *i2v_GENERAL_NAMES(X509V3_EXT_METHOD *method, + GENERAL_NAMES *gen, STACK_OF(CONF_VALUE) *extlist); +OPENSSL_EXPORT GENERAL_NAMES *v2i_GENERAL_NAMES(const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval); + +DECLARE_ASN1_FUNCTIONS(OTHERNAME) +DECLARE_ASN1_FUNCTIONS(EDIPARTYNAME) +OPENSSL_EXPORT int OTHERNAME_cmp(OTHERNAME *a, OTHERNAME *b); +OPENSSL_EXPORT void GENERAL_NAME_set0_value(GENERAL_NAME *a, int type, void *value); +OPENSSL_EXPORT void *GENERAL_NAME_get0_value(GENERAL_NAME *a, int *ptype); +OPENSSL_EXPORT int GENERAL_NAME_set0_othername(GENERAL_NAME *gen, + ASN1_OBJECT *oid, ASN1_TYPE *value); +OPENSSL_EXPORT int GENERAL_NAME_get0_otherName(GENERAL_NAME *gen, + ASN1_OBJECT **poid, ASN1_TYPE **pvalue); + +OPENSSL_EXPORT char *i2s_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method, ASN1_OCTET_STRING *ia5); +OPENSSL_EXPORT ASN1_OCTET_STRING *s2i_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, char *str); + +DECLARE_ASN1_FUNCTIONS(EXTENDED_KEY_USAGE) +OPENSSL_EXPORT int i2a_ACCESS_DESCRIPTION(BIO *bp, ACCESS_DESCRIPTION* a); + +DECLARE_ASN1_FUNCTIONS(CERTIFICATEPOLICIES) +DECLARE_ASN1_FUNCTIONS(POLICYINFO) +DECLARE_ASN1_FUNCTIONS(POLICYQUALINFO) +DECLARE_ASN1_FUNCTIONS(USERNOTICE) +DECLARE_ASN1_FUNCTIONS(NOTICEREF) + +DECLARE_ASN1_FUNCTIONS(CRL_DIST_POINTS) +DECLARE_ASN1_FUNCTIONS(DIST_POINT) +DECLARE_ASN1_FUNCTIONS(DIST_POINT_NAME) +DECLARE_ASN1_FUNCTIONS(ISSUING_DIST_POINT) + +OPENSSL_EXPORT int DIST_POINT_set_dpname(DIST_POINT_NAME *dpn, X509_NAME *iname); + +OPENSSL_EXPORT int NAME_CONSTRAINTS_check(X509 *x, NAME_CONSTRAINTS *nc); + +DECLARE_ASN1_FUNCTIONS(ACCESS_DESCRIPTION) +DECLARE_ASN1_FUNCTIONS(AUTHORITY_INFO_ACCESS) + +DECLARE_ASN1_ITEM(POLICY_MAPPING) +DECLARE_ASN1_ALLOC_FUNCTIONS(POLICY_MAPPING) +DECLARE_ASN1_ITEM(POLICY_MAPPINGS) + +DECLARE_ASN1_ITEM(GENERAL_SUBTREE) +DECLARE_ASN1_ALLOC_FUNCTIONS(GENERAL_SUBTREE) + +DECLARE_ASN1_ITEM(NAME_CONSTRAINTS) +DECLARE_ASN1_ALLOC_FUNCTIONS(NAME_CONSTRAINTS) + +DECLARE_ASN1_ALLOC_FUNCTIONS(POLICY_CONSTRAINTS) +DECLARE_ASN1_ITEM(POLICY_CONSTRAINTS) + +OPENSSL_EXPORT GENERAL_NAME *a2i_GENERAL_NAME(GENERAL_NAME *out, + const X509V3_EXT_METHOD *method, X509V3_CTX *ctx, + int gen_type, char *value, int is_nc); + +OPENSSL_EXPORT GENERAL_NAME *v2i_GENERAL_NAME(const X509V3_EXT_METHOD *method, X509V3_CTX *ctx, + CONF_VALUE *cnf); +OPENSSL_EXPORT GENERAL_NAME *v2i_GENERAL_NAME_ex(GENERAL_NAME *out, + const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, CONF_VALUE *cnf, int is_nc); +OPENSSL_EXPORT void X509V3_conf_free(CONF_VALUE *val); + +OPENSSL_EXPORT X509_EXTENSION *X509V3_EXT_nconf_nid(CONF *conf, X509V3_CTX *ctx, int ext_nid, char *value); +OPENSSL_EXPORT X509_EXTENSION *X509V3_EXT_nconf(CONF *conf, X509V3_CTX *ctx, char *name, char *value); +OPENSSL_EXPORT int X509V3_EXT_add_nconf_sk(CONF *conf, X509V3_CTX *ctx, char *section, STACK_OF(X509_EXTENSION) **sk); +OPENSSL_EXPORT int X509V3_EXT_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section, X509 *cert); +OPENSSL_EXPORT int X509V3_EXT_REQ_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section, X509_REQ *req); +OPENSSL_EXPORT int X509V3_EXT_CRL_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section, X509_CRL *crl); + +OPENSSL_EXPORT int X509V3_EXT_CRL_add_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx, + char *section, X509_CRL *crl); + +OPENSSL_EXPORT int X509V3_add_value_bool_nf(char *name, int asn1_bool, + STACK_OF(CONF_VALUE) **extlist); +OPENSSL_EXPORT int X509V3_get_value_bool(CONF_VALUE *value, int *asn1_bool); +OPENSSL_EXPORT int X509V3_get_value_int(CONF_VALUE *value, ASN1_INTEGER **aint); +OPENSSL_EXPORT void X509V3_set_nconf(X509V3_CTX *ctx, CONF *conf); + +OPENSSL_EXPORT char * X509V3_get_string(X509V3_CTX *ctx, char *name, char *section); +OPENSSL_EXPORT STACK_OF(CONF_VALUE) * X509V3_get_section(X509V3_CTX *ctx, char *section); +OPENSSL_EXPORT void X509V3_string_free(X509V3_CTX *ctx, char *str); +OPENSSL_EXPORT void X509V3_section_free( X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *section); +OPENSSL_EXPORT void X509V3_set_ctx(X509V3_CTX *ctx, X509 *issuer, X509 *subject, + X509_REQ *req, X509_CRL *crl, int flags); + +OPENSSL_EXPORT int X509V3_add_value(const char *name, const char *value, + STACK_OF(CONF_VALUE) **extlist); +OPENSSL_EXPORT int X509V3_add_value_uchar(const char *name, const unsigned char *value, + STACK_OF(CONF_VALUE) **extlist); +OPENSSL_EXPORT int X509V3_add_value_bool(const char *name, int asn1_bool, + STACK_OF(CONF_VALUE) **extlist); +OPENSSL_EXPORT int X509V3_add_value_int(const char *name, ASN1_INTEGER *aint, + STACK_OF(CONF_VALUE) **extlist); +OPENSSL_EXPORT char * i2s_ASN1_INTEGER(X509V3_EXT_METHOD *meth, ASN1_INTEGER *aint); +OPENSSL_EXPORT ASN1_INTEGER * s2i_ASN1_INTEGER(X509V3_EXT_METHOD *meth, char *value); +OPENSSL_EXPORT char * i2s_ASN1_ENUMERATED(X509V3_EXT_METHOD *meth, ASN1_ENUMERATED *aint); +OPENSSL_EXPORT char * i2s_ASN1_ENUMERATED_TABLE(X509V3_EXT_METHOD *meth, ASN1_ENUMERATED *aint); +OPENSSL_EXPORT int X509V3_EXT_add(X509V3_EXT_METHOD *ext); +OPENSSL_EXPORT int X509V3_EXT_add_list(X509V3_EXT_METHOD *extlist); +OPENSSL_EXPORT int X509V3_EXT_add_alias(int nid_to, int nid_from); +OPENSSL_EXPORT void X509V3_EXT_cleanup(void); + +OPENSSL_EXPORT const X509V3_EXT_METHOD *X509V3_EXT_get(X509_EXTENSION *ext); +OPENSSL_EXPORT const X509V3_EXT_METHOD *X509V3_EXT_get_nid(int nid); +OPENSSL_EXPORT int X509V3_add_standard_extensions(void); +OPENSSL_EXPORT STACK_OF(CONF_VALUE) *X509V3_parse_list(const char *line); +OPENSSL_EXPORT void *X509V3_EXT_d2i(X509_EXTENSION *ext); +OPENSSL_EXPORT void *X509V3_get_d2i(STACK_OF(X509_EXTENSION) *x, int nid, int *crit, int *idx); + + +OPENSSL_EXPORT X509_EXTENSION *X509V3_EXT_i2d(int ext_nid, int crit, void *ext_struc); +OPENSSL_EXPORT int X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid, void *value, int crit, unsigned long flags); + +char *hex_to_string(const unsigned char *buffer, long len); +unsigned char *string_to_hex(const char *str, long *len); +int name_cmp(const char *name, const char *cmp); + +OPENSSL_EXPORT void X509V3_EXT_val_prn(BIO *out, STACK_OF(CONF_VALUE) *val, int indent, + int ml); +OPENSSL_EXPORT int X509V3_EXT_print(BIO *out, X509_EXTENSION *ext, unsigned long flag, int indent); +OPENSSL_EXPORT int X509V3_EXT_print_fp(FILE *out, X509_EXTENSION *ext, int flag, int indent); + +OPENSSL_EXPORT int X509V3_extensions_print(BIO *out, const char *title, STACK_OF(X509_EXTENSION) *exts, unsigned long flag, int indent); + +OPENSSL_EXPORT int X509_check_ca(X509 *x); +OPENSSL_EXPORT int X509_check_purpose(X509 *x, int id, int ca); +OPENSSL_EXPORT int X509_supported_extension(X509_EXTENSION *ex); +OPENSSL_EXPORT int X509_PURPOSE_set(int *p, int purpose); +OPENSSL_EXPORT int X509_check_issued(X509 *issuer, X509 *subject); +OPENSSL_EXPORT int X509_check_akid(X509 *issuer, AUTHORITY_KEYID *akid); +OPENSSL_EXPORT int X509_PURPOSE_get_count(void); +OPENSSL_EXPORT X509_PURPOSE * X509_PURPOSE_get0(int idx); +OPENSSL_EXPORT int X509_PURPOSE_get_by_sname(char *sname); +OPENSSL_EXPORT int X509_PURPOSE_get_by_id(int id); +OPENSSL_EXPORT int X509_PURPOSE_add(int id, int trust, int flags, + int (*ck)(const X509_PURPOSE *, const X509 *, int), + char *name, char *sname, void *arg); +OPENSSL_EXPORT char *X509_PURPOSE_get0_name(X509_PURPOSE *xp); +OPENSSL_EXPORT char *X509_PURPOSE_get0_sname(X509_PURPOSE *xp); +OPENSSL_EXPORT int X509_PURPOSE_get_trust(X509_PURPOSE *xp); +OPENSSL_EXPORT void X509_PURPOSE_cleanup(void); +OPENSSL_EXPORT int X509_PURPOSE_get_id(X509_PURPOSE *); + +OPENSSL_EXPORT STACK_OF(OPENSSL_STRING) *X509_get1_email(X509 *x); +OPENSSL_EXPORT STACK_OF(OPENSSL_STRING) *X509_REQ_get1_email(X509_REQ *x); +OPENSSL_EXPORT void X509_email_free(STACK_OF(OPENSSL_STRING) *sk); +OPENSSL_EXPORT STACK_OF(OPENSSL_STRING) *X509_get1_ocsp(X509 *x); +/* Flags for X509_check_* functions */ + +/* Always check subject name for host match even if subject alt names present */ +#define X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT 0x1 +/* Disable wildcard matching for dnsName fields and common name. */ +#define X509_CHECK_FLAG_NO_WILDCARDS 0x2 +/* Wildcards must not match a partial label. */ +#define X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS 0x4 +/* Allow (non-partial) wildcards to match multiple labels. */ +#define X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS 0x8 +/* Constraint verifier subdomain patterns to match a single labels. */ +#define X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS 0x10 +/* + * Match reference identifiers starting with "." to any sub-domain. + * This is a non-public flag, turned on implicitly when the subject + * reference identity is a DNS name. + */ +#define _X509_CHECK_FLAG_DOT_SUBDOMAINS 0x8000 + +OPENSSL_EXPORT int X509_check_host(X509 *x, const char *chk, size_t chklen, + unsigned int flags, char **peername); +OPENSSL_EXPORT int X509_check_email(X509 *x, const char *chk, size_t chklen, + unsigned int flags); +OPENSSL_EXPORT int X509_check_ip(X509 *x, const unsigned char *chk, size_t chklen, + unsigned int flags); +OPENSSL_EXPORT int X509_check_ip_asc(X509 *x, const char *ipasc, unsigned int flags); + +OPENSSL_EXPORT ASN1_OCTET_STRING *a2i_IPADDRESS(const char *ipasc); +OPENSSL_EXPORT ASN1_OCTET_STRING *a2i_IPADDRESS_NC(const char *ipasc); +OPENSSL_EXPORT int a2i_ipadd(unsigned char *ipout, const char *ipasc); +OPENSSL_EXPORT int X509V3_NAME_from_section(X509_NAME *nm, STACK_OF(CONF_VALUE)*dn_sk, + unsigned long chtype); + +OPENSSL_EXPORT void X509_POLICY_NODE_print(BIO *out, X509_POLICY_NODE *node, int indent); +DECLARE_STACK_OF(X509_POLICY_NODE) + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_X509V3_strings(void); + + +#ifdef __cplusplus +} +#endif +#define X509V3_R_BAD_IP_ADDRESS 100 +#define X509V3_R_BAD_OBJECT 101 +#define X509V3_R_BN_DEC2BN_ERROR 102 +#define X509V3_R_BN_TO_ASN1_INTEGER_ERROR 103 +#define X509V3_R_CANNOT_FIND_FREE_FUNCTION 104 +#define X509V3_R_DIRNAME_ERROR 105 +#define X509V3_R_DISTPOINT_ALREADY_SET 106 +#define X509V3_R_DUPLICATE_ZONE_ID 107 +#define X509V3_R_ERROR_CONVERTING_ZONE 108 +#define X509V3_R_ERROR_CREATING_EXTENSION 109 +#define X509V3_R_ERROR_IN_EXTENSION 110 +#define X509V3_R_EXPECTED_A_SECTION_NAME 111 +#define X509V3_R_EXTENSION_EXISTS 112 +#define X509V3_R_EXTENSION_NAME_ERROR 113 +#define X509V3_R_EXTENSION_NOT_FOUND 114 +#define X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED 115 +#define X509V3_R_EXTENSION_VALUE_ERROR 116 +#define X509V3_R_ILLEGAL_EMPTY_EXTENSION 117 +#define X509V3_R_ILLEGAL_HEX_DIGIT 118 +#define X509V3_R_INCORRECT_POLICY_SYNTAX_TAG 119 +#define X509V3_R_INVALID_BOOLEAN_STRING 120 +#define X509V3_R_INVALID_EXTENSION_STRING 121 +#define X509V3_R_INVALID_MULTIPLE_RDNS 122 +#define X509V3_R_INVALID_NAME 123 +#define X509V3_R_INVALID_NULL_ARGUMENT 124 +#define X509V3_R_INVALID_NULL_NAME 125 +#define X509V3_R_INVALID_NULL_VALUE 126 +#define X509V3_R_INVALID_NUMBER 127 +#define X509V3_R_INVALID_NUMBERS 128 +#define X509V3_R_INVALID_OBJECT_IDENTIFIER 129 +#define X509V3_R_INVALID_OPTION 130 +#define X509V3_R_INVALID_POLICY_IDENTIFIER 131 +#define X509V3_R_INVALID_PROXY_POLICY_SETTING 132 +#define X509V3_R_INVALID_PURPOSE 133 +#define X509V3_R_INVALID_SECTION 134 +#define X509V3_R_INVALID_SYNTAX 135 +#define X509V3_R_ISSUER_DECODE_ERROR 136 +#define X509V3_R_MISSING_VALUE 137 +#define X509V3_R_NEED_ORGANIZATION_AND_NUMBERS 138 +#define X509V3_R_NO_CONFIG_DATABASE 139 +#define X509V3_R_NO_ISSUER_CERTIFICATE 140 +#define X509V3_R_NO_ISSUER_DETAILS 141 +#define X509V3_R_NO_POLICY_IDENTIFIER 142 +#define X509V3_R_NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED 143 +#define X509V3_R_NO_PUBLIC_KEY 144 +#define X509V3_R_NO_SUBJECT_DETAILS 145 +#define X509V3_R_ODD_NUMBER_OF_DIGITS 146 +#define X509V3_R_OPERATION_NOT_DEFINED 147 +#define X509V3_R_OTHERNAME_ERROR 148 +#define X509V3_R_POLICY_LANGUAGE_ALREADY_DEFINED 149 +#define X509V3_R_POLICY_PATH_LENGTH 150 +#define X509V3_R_POLICY_PATH_LENGTH_ALREADY_DEFINED 151 +#define X509V3_R_POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY 152 +#define X509V3_R_SECTION_NOT_FOUND 153 +#define X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS 154 +#define X509V3_R_UNABLE_TO_GET_ISSUER_KEYID 155 +#define X509V3_R_UNKNOWN_BIT_STRING_ARGUMENT 156 +#define X509V3_R_UNKNOWN_EXTENSION 157 +#define X509V3_R_UNKNOWN_EXTENSION_NAME 158 +#define X509V3_R_UNKNOWN_OPTION 159 +#define X509V3_R_UNSUPPORTED_OPTION 160 +#define X509V3_R_UNSUPPORTED_TYPE 161 +#define X509V3_R_USER_TOO_LONG 162 + +#endif diff --git a/TMessagesProj/jni/boringssl/lib/libcrypto_armeabi-v7a.a b/TMessagesProj/jni/boringssl/lib/libcrypto_armeabi-v7a.a new file mode 100644 index 0000000000000000000000000000000000000000..6f7fc05c8100d19cfc4d9902f18f8dec65f878e2 GIT binary patch literal 7232874 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

cLz}}tiTAc6cxTf`MjQcR%8#WtfCN`ADIj%5W z?d#f1=x^Z8E{QYqWgr|ibD)xp|3GFOs@otB8|5*&AeMHea3iY4ady(F`b`~t8t(B; ztzfm!Q;%#=*`5t9FEO#no+-!_RVYLI!eau9ECLJ5z%#;8*z0$A5hvHgFEY_j>&v}8*Xa%kmBfd ze|xOj4=1k}_Xm1>ebxDDZ=R<1=wtcP^&xCALet@tGg&%&nnTxK>d+NFz4H*A^b>|w z4$M+4GEyBD7$fpLbB7v={+F}5ss{>6NV;8dZ|c?LuYC?(oJZTx>sk!C>JSsW{Faa3Fqke z={1^^OA>V)KK4Rws63l@k%iq`~H~77{3;&-&sG2Pq_DDF-cGctAuT z3*`@Vj8?9W!0;676Hnbi6G}ao;PF`X90T@gD}Eg_9yX6vN6>0-&}whf{zeI}6*x#~ zv=()+Iff}Sn3A&-MOuV4c+#wm*x4I#koK!|5P^(L5bc~fr)$!&DF^BLx{HGL@8AJn zf|h{AhY{v5>GR5FrMZTQXA737L*jhRaJByj1nd(f_nTqW&mu+eZnQm8YSrH4Fny1 zVLZB{CIZ!g1qvb!R?R#i8wbOiY7j@@k!qy5#|(E;#MvjbVV6dJ#AlgB57MT^juHkr z0kAlR5=rYfF&CVhQN5~2HAvZSU`2F{E{QrqCLUB^0&`GzK(yI-5I`V{ z#GVPBQk=0klX^yr;6Ym_EW+cn+C2wpxn4WGs&4Jk4&OmqZpVX!?gH#H{W8%AtXC*>(Ld)Wz%XCaV&DY{ZDIS{=s@Pco z#bCVxD8rx+@IZC#p?{gJBxBClVkfrY!C2G*(EMX@{xQmPMia!7DsYlQh$^)U@ugVk zB1uAHLfGFTxIGZ6Ht@ z-OyoiOkdbgF9;)*brE5V_9e7wU;H{I4L0eVYLvB}5XGY=7qql$fBY&l0KbKJkXx$n zCkgGwl)ys2RQPRl7ThXSOBE%Q;X#Wbgp@T(u#tCcuz-lNMhR-6sG1^3w9%Xv#yMS1 zPE~l20R+wIazcgTw2+`VU9NfP-$5!)9f6@}f)w5{%uLjB!V)|Pu3*zzj;9CgY1dj~ z4$`p(50WPE0Nn{Q0x%*a;3>Kj$Ya4ex5pYdD1}1-c8*~ndk8~ByW3DcybyBkAT3PS zV_jyFSN=?&$-&?7fHj!~+ax*MjtAW{ft3^8_Du(A(Nlp2!mD^lPGm|TComm)$J1+w zr$f6C2rf-t6pTyh~H@Ka_re!K9bp=G6?8+OoeF>Xzz=hjEz zK+j5`Sj-=ymaE>#MQ?Ipx}c6{OTEb!QXrl(th8(bm>Z=ZG;P6WZB9RE+La11ElY*i z;2goDLTF)qQz4qCWle{L@tG1Ug3gy~Z#qZ|E4Rm5N+2hn1%Kuj>y>gCIhDh(q@dU1 zK~F>2f(M5 z7hda&HxX~dlP-PA)Dd)T!-JYf*p(1S7b_kDjg+v$LzxJEEAV(xEs0FgN5(+M_+djF z!X#y_cYm>xPDP1PKvhW~!HXuh^@#`3hgiykG zWlfMGU3o1eV8e`rguZyvD8*RsLE4!Lf(XNuHAWbL2SeCRYThzN`{P%c7W{gZEk%3a zH$!Z%2(pu*q0ThS3YtMEPa397vsZ(v9kd#Hs$&e3r@H`85uW*Ys_@j{S%k+JW>7Ak zVm!0(Fl;3rWAb1j4~CWCVR!r}9%IOxap&N%@vsiE(AArJSEJd^YD3y0r%<(2tU@<-)Q4a^DzM+R~iBeO0)bIubMt*`OUTPNDvOY>?APU$F32A}cI23m`Ey4%kM^dx_%w*#Snv$A}R3I>NYT&ZbqelB0vwUOba-4fG@ib3iSm!T zbum8e(RdPB;(OYY=j$l(`SYT_@7k$|sfUct!fX@RnU@0vW{0F!U! zb0=5l7pkIwvyDGJvm3>+USuXRo9R<&Jgt!-5<^=&+rRGE6^P+evy#+?o4QUh4ESQ~kormie>3@3_ZeKWVEZBN~iveUQAd%H(XluS4$kY#;yw)WcAb9?%Z9y`-^ zrQVXV+jlGJI9D}>6UJa)|F)Fvz8wrR6DWpr(#gq}F`Rss_02w?W3X?rJ02%@Zdo}= z4fY+hEp>a!4&P3sQr_O_Y>? z9v?2wU&23^{l$4CHm{52@CB$GDRr0(Ef*3qk>Db7CK6qs9%zEktp~{@$s(%W=5r*} z;h!&HoF<98DZz`1ZU{b?znds2fqzwopI;Aj-neKS?ukRkg|a7!;vxzpQ|a4;NnN$M zM3^*$x$ggc{_Q|y{{=4#QYL+2&|Dvk`~2^(5XR%Eo3sD#-znq*K5noOa~a+#bQ|6w zMRST2ud_N&I;8Fm8O-@Faf2 z6+I93v>9$J3Vqh4N$!zJ{6{8*XC?8^N(vvHj9Gp$kL>{Q{r zu^Kl%wcY1-bNelBd{$}P0h`a7o8)GyapSYf;||z-RyfH$Pw8W1)_ciu5}(>rcDo~S z2W&oUZ?XhfyquE`!2XL{Lh`MbaL%CzV4r8TxH)GYfJ?lafX0yidOYMe3C{pr9^E5u z&OZm>jje}`8$<)V!>wn;tu{HmS?cW_cqv1EzraI&d+`kLW?S!woAclS-idN_ZPJ4_ zBo@Q?ec`4TTfzV@>W8xc%Wk)D={adMOB%(JrmKyOYNp(%Kl#wOs;#ZDZA0L^eD61X#Oz?dEmsSGyKUdOjPcm!#t!I?V(QF3F7q z%(_WtSihuvf@rd{XtVt{o8pPvBz;K#L zrkjVqau3t!&@IAY1`5%Ko$Pc$9z45(Z7=vco=M>ENEEAVGl^}0fNTa#vMBz+pJUNmR6 zJMVnFiZ95lpqnF=7nwSmSZP^P#DA7xP>?N}^f5t-K=%s4HG&%juM@mkkYfkw?-blG z_>kaX!Dj`(Blv5<-wA#w_;F^$oL^$1|6#$W z#s3@P{-NO8;{SUh>eoNTzqeP%_YGuJl$0)&UBEs{;T`E{c1pQJ8Uqu{-LmP2lPXwP^1@9C8M~JBR z&x`*F@&B>7e=hFR;{H#;KZ^f?-&2W;(uKHzb^hi5dU9@|1ZV=cjEuP_;U(Pxq1-C;e}vv2Z)n!fJa2W zT_)Hl;a7=!y|`~8f_^Iz^4=}s4~hRH;(tv1zajpo1pkW&Ijl4w`h{Ucq&rD4pNQ~T z;;s~|5&xy){(`vIiu+o@U4r)tJ|XxN5q!Tc?w18$6YLiJi{LrI-ne8yIe9OKm`Q}* zIm8GKFU3D1?kaI#K}34ZMD%l8B>XPH`y~8Pad!!RjR^XmN%(0Z`os6c{V@^gVv3jc#L3L2b6%G3p-dP|H7DQ80?y-Us1fja}FB0VZhw*}f z6@pcQs-HzTh7d)!TyVAEI>9drs{R)AH;Q|^;4OlxzeV@~aX%*b6~QjS=LBCA{I1|D zg0Bj`E%;l(_XYnX_?aM1J(T>s*+hN&2=d+_-C2UX@=5n(!6HHR?GgCT6?eJd0>N5A zUOZ&{m4a6ZwhC?%yjF0#;4OlC1@{Ra68y5@alx+(eos)14@mcC;^u`b%F#{qnb6Um)&UK{f8c|1xo} z5H#aYySO_9&3Lp`+`NX#^wf7Cfe(rM5y8WPM+A9!lJwsY{I1{+1YZ|CE!ZviuHc^p z&j_k<5B&ZiZXd@NxO)ilDk$B<1bG{jZr(&C76}#$&J`>d7?}+>Nf*%Ne zD98(=?=4xaID}2 zK{amyeWAF^1?LH>`3u5%X@Y!L2sR0}2(}6G$}s7+3hoxXUGN^k`vrNcnDkEz@>((7 zFA2UP_^RORf~N)F5&XU22ZA38{+Hn21o1+z;-4a@=0`|R&5wXt;-4*;D;N;uWoF7( zE;wJXMsTs<<$@~(*9h|dGvj|rkawQxzFqKM!3PA@JPYAZi2JDEal!8i{!sAeg0Bg_ zDfsV#|0(!^Aa71H{m%q>S(@$vg2Mzy3XT_?B*;t8oL8&)8!#;HO2Me0n$ID8jkvE8 z{G#9{!RrM(1$PSGD#%OJOz&aA#|57h>=JxV@I}Gz3Z4{vUGOczZoxBxp9=C4H0RH~ z1qTQY7Q9q&v|x^4u3(|y48b{qWrDm^P5upn%LJDTUMYCB;0D3Xf;R}>EVxT>k038; zlm9`%Cj`GL$XnYC|Bm1f1b-}eO7K^LzZ3jV!9NRrB>0&i=VIjBOR%rtaKTZ6xq<;f z-Wq4TO2LJK4T8Ky&hWK@8w58C-XM6h;BLX&1@95OUy!%Z$?u5ZbAsO#JR$gf!B+)O z3jUkmZv=lY_@3a0f*%Y1UGOu(R4izieosMOgQt6h;5fmFf&sxIL0*(6eWhTX;3C0B z!Bv7+3APGeBlso3ErL4)Zxg&z@BzVx1s@lDQt-Io*9Bh`{I1|Dg0BklVn5}7NAQn= ze-Y$Ge}?xE>?=4xaG2mo!Eu5U1*Zy56D$$51?LGa5ag!>m|mk`vtWzhCc$e3w+QYK zyhHGA!2^Pa1o?3S^8cFPi-O-3{E6Vt1%D;@hT!i6|5NZUf}aTTa|h&)JMaqo2@VwG zSI8NjB{)HFvS6X$48b{qWrFhsYXlnvmkO>BY!X~2_(j1^!EJ)K3f>`jpWuUnj|x5^ zcvSGX;I{-{6#RkUj|KUC2kQHl;JbqF3;sp$6TyE7o)b*N!3E>@669wf=)P2NoZv*k z8G^F~%LF5W^@2+T8wFPh@YC^lOR7g!SHi}{N6v^y#)C&3GVY;Dwr*pBgl_SFnqRPnP5b)T5zG@ z6@n`Sn+010Hws=O*eSS85Ys%%8`AezxgX7UrZ^U55&in+1J_%~VztgGCSty06UWJI zjY*ajr5i*`h|qUAQTF#qk7bIAhiQUBG(Uw%LLtu!NT<>V@*Oa`a|Ck*l^pO_`%^$8 z4^I|JUm;i}sN{lwy||Tpa4!>gvtWy0n_#JR;a7 z_?+NN#DG3eBEBN-R|QWBzAkuL@GZgji72-}37#RM{5};tOZ4L$K+xiT4$70~M{0dd z#QK%zM?{_#2+5%NAq zgq;6PgnVTfh)8#rxc3l|zA8uXQ{@ObUXt*aiIC@{xK+78t~26R`5u5A)C=)d zzM1@h+vEqx|5s)>sKCl%JEbYo;QS(+lo^d*(jj}4Nv2~M%>+E@c>Wa~L_ROw4EPyi z(#?ejc^kKF2n0>KwQ$4UwnhAHAmu=}6zjgJ3U1~B=@{=WJmhWi zr2_U>@EBwGwZg;AZ@-J5NuRh2k6RD61Gh2GBbv_9gLI6~hsLCP7jFD$b62CLx$N1EPXW&MUdBV@cOEVVXh+t)| z)^v^@>7XM&@}e<%T$z;aS(hGY{!Y60NV=vxcwRb4ane6Vj9Z1yxU-E#Xc4T;F-_;l zM>@)9-qbSk@jTa^&*^xThWX2U;n}yzm$QFXjl&f0ql+*q@y0>MPt(K2RgSNwo8wZLdSUQ@5$TfQ2~CKGC9V`QzUf8 zz33wHE!K37eB2LbI$6Te$QJ{hTfV4EzA>OR`NH#Tw|vXNZ?Eto7=D|R_$_zkbGD1$ zUf~B&=FCO(cuvzfdXSEKkQa?fw<{^#T`oP?$CHln{wC>~d_D_)?Nm&R;rDtHzy08s z2^!XyiFgdZzX(5oGA$Tu-NvvUgmhqc^dKGOAuk$}F5d@mmq(XNk6fW+JiZ6uE{}Hb zyHNi!Es5Vt;K%sXBhSUJR`?k`9=?bk{HI!OJr0Q;rRkjV;CB!y4|&lTJx(R1+wIbW za{`m@Uz5^34SqqzN&iqLn!bqOmTxE&?^GfB$I$V;3S(yo_q#hNpcoT24s`B(J_GqG zkT%PA79IpEy{0Ac>yP!$Mw3aPG5q-6hOxuj+SVWMI)K&~6IPy-Zt+~Ki7?18U7nGf zbQdM@8!{S=z%TRM+OF%?^<#-r{#j{iR1z@MS37yX&)D2_EkI!96bfYHg z@hzF|L7_AL`Ji(fBOlMzjGf^D(7E#k!OA=Zi(8LCz5f0H^{Bu@I_mKPED+l%s*c=v z+d#0B7ODs79P-FKa!%#a^Bg+1b@MG9+T3 z<`>GnPxtvKrDta(OMTltypJtx)3%Cdb0VW7S49>m|Ey;?l0Wf`ZI z923|5=^_7FPe~`fHt)#_v<>LC9(*wE-+z@A@!ZdJDnK_ia@~k?fBp73E9bRSo^DT; z)s4d@e!YAvrR{n;O?@l=&aOKnX^~+M^oi_`P-g4n_d4G>`}(o;BYi&d_xeXDAYY-k z&iuMF0J-WSsZTKlD0$|!PAyF;WV6rQ(do_coW$44yS1-3r$^+kr?h=(WR~J{@*}(h zeZtC`cf8**J951H|6=c5;H#*v{qdPICl5$SLU@NjP7(+qkQYRV$TQ&aMG*qX!$%VG zAd!&7JP_2Dpr}|Mg^DdjEVkPE*2GGyEmm7?tG#_dYg=u-y|lH8)>>$_7j1j}f4_UL zJ!fWeLfd(Yk1ovY4LUt-`HGYL!e9Y)*eAk>#W(u^cDkEPEQt$+z>-Qu)@jvCr63o`TQ# zjHBWG>HT>pA|YxmjQ;3x>a9~+s5AMgj~sg#Em#L@$XS_v)#KLfcK(O|dEtk;%y~y1 zK0D_abtNB7eXKBg*Qt!inJRzsQ>DjBF&YwduYDHX-6yJ^`Eu1kwe$p`AkT@E%5s{WE>T4e|Pd@;bSjLOS9L9YoGPcd{-tz-(wlQ zCl1}zmmVD*9dF-hFu;e+6pJF_X`d3?hn4U;#8vDSn(O#*O6oXNQ)O=*IbM_-jwW*iG z3Off!SnGUj!|01S!X^ssQEnBjPat3VyI|Syx69!mTm0g!Y`9ew+%XQ&(uu z(u{L~ze<8*5o8-~uMBO&z8XHGhtv5w_RHb7-O5-Fsgz_Csifdq9ch;#Z5q-p^Q7^K zxP?gLX9AcPa+x1T+Q(rD^y^f5%AXD$6+&XG}mgLnW*OUAeN!5Gn zRabzK7D3vB$f-N5mX0#+?F>5AUhIW20q(ZJPLUWMF^tsbERV>_i%W zrB{82{R-vcI*WtxC2V}aWsJHS*zyfna}89F8H()om8|fmL5^kPb8K_nWnXzK&EaFy z4}xc9eHFWAZ0n#W{cn`muE*@c^uMrx1lV_Vt0B~49M7H=ZwA#w|3$J~jC{R!Ip9+ESwu)7mdIu}dC$h9&zAeo~M z^Uf|eO-u`iV*)0?VLhjQ#$1Tfh*yje57UUyRZ5$lqO8-o5Thl(7yB{wGHyc}>u#fS zq)Rid6QQIjnxe2Fw1|-AKeiGQ9`2v|pt5(4I9J zBY`|rdDbmQz8I``9!IFebvb z&^tx4^2nlmHISrnlpcVO{hpP?2?$k`3U6K3+9$WfvBIp;93jOsaAv}UTXa&IJO zI*%4Ql^G+7mBSmRNrlX`m+aV1u@l04z$Y*N1DKj{mQ67ZjtCEMddG98mH!Y6SfKbE zD4G>3CI5#IN|>Pd><7h1E|iTAb5kqZSLagYPI`_R(rh-d7M}d?EMlw@)`A>65!Gn_ z6X*5x7N3ZZhKtX4G=|@oeb9Nm-?hE@I=I(?z0ZYvsyJeYS9-jSXAKko=_GMTOiO`7 zc>1wV7dPvYo?+a`lQ-PsUp~_?a2oZNsh#GJj1`9SB?z}tqhkck7~?4pi4daDUWSZVszQwDsG8cygF>Qb;&NkqbjSzs%ump^k`jf3mR!#y+%@j#fN!0|+b;s3oB;oLi5LSEc*cJ@zO$KH$fi`DjqlpFB=3?88%>?qv)Y4ug_|MfpuTGv_M zTwK?=xwNONv$UnHzO|);>_P3*9ED)voHcLe8n4`Z(5Os@HSWW>YHcGyZ4fLPReJU ztCZ?jw>fuiU+cVXMM8-lE1t9Mk_w0v%qyRlmy?_Sx$AOr7gFUqW$b^)-yCj7)NE|* zuBmI=R)gE4aOTxkUenmxs6L+Ffo~MS!4_S8DR*BK=FJH#T2>wz{t9sq1Q%+^TMHUWPVA!=Wi%$8E~(+W&gQ`zJl(aoE%~G^mb` zwIzFyLlyVRn$Tlt<~SbjRD+{~yW2a^r&}6Z)d=d^)Y2jS&0%XM0^~ThtOhk$>DPe+ z5Tm}UrM<1Dt+BD8u|efmeaoS!WYlPPyO?GfgVlJ}gLrFqO&6T+wKTQV!}(rIYlClW zsvJ#Fi|ODQf%MJD@u!ET8OUa^DK#?Wy3_&EYVT~>ScCgV9CuLHpk`~(5gyO(UO#vd z&xw*J$t7voJCm+YydmMn@Gj>jczml$tK`Yn1fI|b@l)5FZG?b4;rsm3!H?ad8A$vW z`i`UXCgs%1*8)L*R(>Y)1bn^?6mXU55uuNR@$~xmgQy-LqqN66wgpRwD-)-b_;Sh{ zm)CXH|F8XQ@m@tNgmGJfD_*^D4S5!_l%bz3Z*cI^7p^)z!LJS9H{fewo-joGm+J*_ z2z=&0!2(slT>?*VtP~H$@>2ulaTdpdgT=YOJg(AX!EwD5=`;u4L;UvhSKC-{)P;tZ z9vLGLb9}DFN&B_YkCr#kZ*YHj=CA@r6Vx{G5WpY9X=DN zXQm;5q|XY_O9FIVfWACH?+DPl0`wgL`kny&2xxXckCU09H0v7y{&xfPPXjcUJ6KS| zDUt7RHK{?--eZh=s$zsoJfeFN8+3t4DRruJJpi>`$&-q4VkCja;!JurAbRLbeOGp*ZU#Fn=2n1L)&I9~S&J5ppjPVaHoU=s6|n^Uk*|VuDQ+AS@gVAQVwuz%&rdKE zvC$ZiKM@eZROHbjgog_`%Za=RMC2?D;iR2QoFG1fkUmHFiv(F75$*DZq&vJp0DZ%W&^KF9`C14Rq#uKKNoyQ5Etx9f3{$mpz^^3y`4heAh=&p`P>2jJET$WQ6lE)n?#gO7OZfwWhXvKU z%t-&E(8I7yp9k4eS*As%l!8UJ}CI8;Io3y3;vrRfBa#-UkUzJ@NK~pf*~F+ zAeSh}TfU?-1$mp7bb%m$x*}aJ$UDBI)$t6--_=Pg-#Ea_gx(<7BDh)b8o^#c{z%UJ z$~PL2Ke&=s$3dVv{sF%s={zryua1Mjp9uYm;4#711o`_j<=+?N@1h)^se*hap7a>O ziGq28d^Vr_GC_4*1$~y#XA7PuxLk0RAb)se{>ufg5bP1;FR|qB66E76q;D6*bhG#? zRt6E{4^dU02oZ7&OgG~j(?HRwf+pWcp(8}J$0Wf*K{f7?UMcik!G(fL1kV**D!5kg z62V%*2Eh&@?CTcXD(Tk<_7YK#oq~tiPmupW`m0ykLD`=x^#@gwBpxL4nC=(`(f)W>v|OMQ1@qdrrQ@0keF7|3II1{>mTJt)Wg)Wu-x z@ioM~cKf;%1weY>gIf7cnSKNbX4t)8UF#wt8ZUKpDS1oUeOwT>S-R(CLbTd z^9ECo$+}#(9&;hbdQcaGsYfp4yydYSoF{Ex&?h@$p7EK<*YLU|v&f5?= ziv>t9aw`z=miuzVQht_LU(QKWZe2j%wP@V&#t6t6eO&>$yHL^3$B}Cflv_F3vYv$; z%jIQ=Dfildz6EHEGVo0>ff?0*{@ps>gHAY;g-IZf8?WQM za<4)e=dTGy?mHr9(%)vGozOtuvo(GcpdwY-Llb{|QNr#3)2cMR9`Yt^c{!3E7y`!&Boq}~H?wfTEmbuUq z??CwpcxF4fnfa~!{MwndEzRZqg^G^UX7q1ro>>dKrTo6W2YV|IB|ttkn%vJkci>S} zVx-n8!}INtN+tO~a({2~At!3(TFvXVZpBRoH#v@d$%oKFRY^xJC2OAPhjb+Q>3H%Z z4%vBZIhH)O-@en1jNh8y5$ekjJMVY;dq*4!xiT3_CcoE6kniLnH%~kWY?p9=_V$e~ zV<)Duzb~{*g6h9WKi{&j_tPdL#s0!O8;g3QH{jWL=Y`OtqoUc-8_;G+PlX>V!?W@s zoAOrS!Xu;{q0T&V*Qrn$-XRF(6wN%6&_AvAu2atPqQvk^4`#Q1DTID1I+nUW;l%cY z^ZV~iO!~ZOqGMXrUry+b-09`?R!I5>Db9qH}&^&HNzr z$D||svx}DOuX27osXuhazan9IiY)%xv`Jan-q2*dsxyesi zk+NfV9k(-ZkjsDJO)LK}-n4l4h_f{-@#IT0pE`UJPhr2Z`+d92n)c?;t=yMSg(KFK zmrq$`qth;WD{07o932(P4xRnhh(_c+yXq3VyzcA^PgqXXTj9{+w-Ov`eC;UbwRv~u z5sZ^lhti_sqDj$_(Fw|mh5eOy<3{&iq~FG&=+x6Z8k~|b{t)Ka_CujZQ=_9GXFtf+ zrsczr*>_&h&o^t-h{o80<#&$gKlw&}ZGG)9jD%^>67Dl|`a!f!*`e$ELXV{4{R{iS zscsu&Les@+RO>PN-VtY?nVaEb|Ndrjz8!fUbuqnxd4&Erap*?q8WT;8PK-{4zO!6? z9A0wkcS4*`Qo8su7ShIODbF0v4OCTrE%u4(Rf;6syS9eB@CPI$H$YMH(8(jA zV+h|T99qDrHIz5ihssMGiD5q5mGZb!z%{7j>(pj`UjuOLIvOP}a%(##x%wXJpz|Ap(QE27UO(|5J z(Z$>)%x&}jGoDn2IVDPLIB%TURq7E{I}<&TshCyD?o9PAf{u@!8m2%I<^b1M#kwECdhe}q-vjaY?BYLWjz8hd;JTD^49VA7R$bvJg&pD zRjXdYb_wliosf!T)?y+akM6;KMd+j9iS}~mPxf-wk}5{lfX~1h*axOy42|A|BzyVj zErb=LcMz(roKzY=l`X@Nfz3W}GsLy=Q)xVJ-Dqp4(xSUSW9>Uku+$mEe6K@6J7+rFb%!dpzvVNckzjCHzcCqhzNH;W^K&haC> zYh%wMXDZ42k=LHZ_leE{nagXcmr=D`_W7HvV`4Z5SrgT>|x2AcNgv z)bqZleSmkFwfYwJbPe^XVcNp>=>?g$#j-Cq{p=Zec6p$ebJkE}r_s;DtbO39tG|=_ zKkMr6Bsb@N*99kDXkcw^i#C-I-^v#cO=PJ zdL5P4xk?pzElJg#*RebA2Fd2%shhub5+}8}KVa_)LDwiw5mg*`7s0g7Gs_sZF~tsH{>le?-WFIofV1a+^t9vDsSIH^D02*DQj=l{ntu=gsPSA zfFAUrj6Z#N;;TOsI4an%?Avba^$S7jlx*K^Y&i@e`v6~c(6-!7TUMhqZHpprqAhn* z@NNpy!*FB>#O%*;*1rj|po|s#++@gv_E>r9Oz?T0^g?^8v;Ry{p;l(krJj3UQ@pj= z&v7u^tEt-Ys)A3lzDclq%34G&!gd!5&3caG2rwEQL1Zyc0&5ds#^a za_s}WougZBFI(i(Hr1JY9_PaE}rfXEaY5D1)9y1iyvjzXmu{2dpk^iJXp_&7yUPII>dJj80MJ>EYt0m)sv6$-9 z)cPhxt-z+j>S?MlP4m+h(^ZKnYW1}VbTOL+U96seu~Y35`hB%W4afc_uty~#avvjq zfgBa8^;Z!xluiLFw5PUohQfx@c?z2+^W@4wlmK(kUFa0_R%lOyKE7BJ3c%;$hjWO% zg|fN2veVt_=w;yd-Rh*P>U;~O>*{Fwb8d*Pl&q?QHdPNC*%`Vzma5KVuvK*y zGs5an;TR(<)oGUMv`Te4CU9xO>cpz@QRczNrg+pH;Tp{~seK?3k6GwG7@=0x7a?bv zYV#4wNSyVHxJF<#jD2p#ELB_1ZC%?eo4kI|mPquG|!ZWy{(@PT$P#$&k>75;eS+$%8wI4%d zB$xdR>~;G9-{=^{3o9EUtcJ2|VA4DROk)q6W#8NLSs!5y4T!1-5!o(<++H7Fp)D<$Q?R2j-`nPFSW#4z%mG z)b#71r`J<-nYttiqyE#>OuJBZQXc5?hpBnFv~_d&5YFcnsvwNz3ZC{$pg}e0#r6lR zBhUMbkyV}dRfOmLHAt~0a}=>1^I%%+7^cp`ds4LpUs>0+UX7cZNvpcmtGYb^x{S*&yTNAf;ykRY+UT!pld0-t_90FG zch_{B7|n!MU7<#cGM&ReW;Iq9RuOOL+dZz;t4JQ;%3n{D9%c1UT&sIjkNnxSx<^?( z5He{{tu&q*yRZ}7;m($}3lssz_JM*LVCLdrwnoY@5}Nd?rxiwCV`GN?)=c@}@(Pp(x7 zfl@5I#5g%^M2eF(K5g}w;daItbo3-EC1rk!gM*%f*FV$dq@0D9FEN589V0j)9U`!c zKvt6XHPK}MYobH&Ua07(L>@d|W?sG|nNna;LF&L)HiyMt%*4XkeSZMj$P&D<>3cyFFN*4yJ+XL31S{P!`mIk~=6enH zWx^YxrhrqNEz{H`E5Glk1M|eS%m@(C=CqK&1KmIisl~Qd5Ga6`KCyR$ z&Q8Dn!d>mM5TV5(tLz}rV@U*L0)A1foOF=U0&Fk=dle|G+YL^QEGvS|vAVWa|pV*d<}v#Ah;_CaT-%|t7F`Y zAm;|%5z7e?Y_>I+X3h0=6OQY&il7TwN#NOQU==+zV4rCLGqjaBB~XH6{6 zidddCZU#j1vDsEN;d~WcO`vjiwcjQ!yON+wcdNw1*II1Qv>(8A8Q#YyJg8G21!$Y9 z5mVtZ?7xT&Q<*?P$Ljf*Z)pF|$Ikx~G+Wfv7e8P%N8Opu03`|+@wno zbAzYtijWxacHub?YOe3RuJcwCG&fGKtc-D2n?hOrNvg0oNv@8Vlv`*l$#)#|)PWU0 zZKF}Z)4iZ%a4EMen(JCcu2!z9VU)*aX9)ymU}Kw8n8Bn4O2MTryPi;mZJ?2!2}FTF zc71+OMrutfy_)<76i!l^t8C5F7Da(TQJ$%&xxU6`AK?5z&|J57*gUixE?jC88Cil2 zqJ;BJIwMPUI`%4rals$bF-g(0kOapS0|z1lZDZiHWH4ytA}Up{3>eK8nu`Ypu96sx zK7)pDZULF=e4M*&`~1A=W#zf~J!@ue z%AK?{H+S&_?cFDmI6t@SBMVv*lIXN_I};*%H#%2E;9%%lXGkR1SF3NJkldVk^IGQT<@);Z2O&FuLixI~ zQs?=Pem2+nW+;-&K^Yi`zX{ppO6r+1j#j(eXXtz6F4$OBesED~ZfWTmN+e&2U;?`C ziPX#C#x)V&7Uyf}?H%24y;9dIua393x2kvB!4fwq7T-^gx!sAq-Ok)S<+GHRl@7Qu zf)^q6);nH{@2+cU>#Dh`v9rB~6V#%Ym01;Vvl4S8M6X9kz%Q*e{Go-&-{1Z_E|`#S z<_t^w5-OhsrKWD`b$R8(Wrixiz1#&utwg}Z|ZDpbj$9kj74!**6**$6rf+>S3EkkK_m9Gc3TZSn>TNh`p`Fxk@k0$ z*rlsIa|YzvdN!-(?y}G#8@rpO?c2IqHnuf3M3kc*>gs50+@!nPw0uW*C-bNt_+Q^i z|D^9E&!}RbsIFi$V^q{M!f92j-=Pv^e4`X|hz-vU!!&AY+1jXGAgTFce8AOVMAdAmYwgiPQ#qT6x4tRWr)v85YTq=-kZZ5+#+(-i zeR|-jS*?6D(Gu6;h4$rlut~E$= zoxUh7qc^<6xi%=vYZz}?q`i4{Ss6RS*E=^bua_6mdapA!nClKCtGlC%(vq)Z9&bA9 zVbZ<2cnu^r?hKYgIWNy^FY6kly=|rS`rFFO*Y^1N5$H7GFd|iHV|ONApKwF?MrRjn zt4b>ySZ2_MAnmOyueH4O`A2ybDqpJZ@v5|lw;miL?wGjFQElk8fqgIun+ew-Qk7QN zJ9Nj8Ym@!n#^Q~&>k@Y+Tpzx{xsiPnF-m~*u`NoA^d|2}x;F8;gt+5`*PDyd#BKL7#3^4L5$Sd>Xf_$@fIL|7ni;1o9J%8*8a2ASn8{oo#VcH` zn+7X9#`Gvs$MyKCG;6T>>obBX%T*U=K^jkWJh4HF8BEkIGIs8dSCWT2NC5!}SFakE zm2n%{um;iSW&71(2_Mf$m4Up|DKvb)Myz)S)kxmyG#b8NBbGsfY9#M;8V%p4QLi`# z(<$83X!S@ay=L+U*E+!x29=9b)@fyZr4CsA4OZ+x!PAr*U)a}-Jp&h7!J>Jr(1UNl z!s)c#7DqE}^%oy!={#up@nqxF-nDlydA|j5)`Npu5Ks1W77QluvtVE^#W|3(0|pA7 zrtJ8_0}AHlg730pu)0&Q4TBj`xrDU}XiQPE%SO$-&F3@m+-eLxl&j{G*n{ z$#xpEOl!sIUrs(>9czs6KWvIO!)c7*CFr2D!Eb^V{f7;Ri8nNE=%EMXrgp1D$Llt1 z=xp4gPr^C{xADDXU1wd}#>Osh(!i9~mNvMz*ZFZ_Z$>sXfDJwPegLjFf&o83xFKwv{Lm#3arpCuCphwJp-FNe;SCOc z6~v1!o)GhE%WJfOer@@nNi5LMEq~sO1@mj0PI2Hp$FDzGK24(U3xt$+omg&1JwV{4 zQv&+=G*T=$c*M-FpN|8?0{z^2gM;6w{r2)V>sX+lTfaX3bQ}xxbL-EKXHGrA!QBHt z-+MQK{WChC-~a37K)<+S1NyvI-_(~C&}V*~)kY2UqnjPj=e@e6zKH>S90jr9_^zfY zpBvDZ8xuy%!Gl-+_T*DlvEW#fV+3Ljo)h)AUqOIh7|>T3;1>n*n_q#om}5-~@TUdx z7YFng2l%Cd{G|bYS%8n5FP`Aw5eR>K%>=!*vU=LYEW z0{YGi@Gl7HyTHnU1dpPe86oR}fc!@S^s<2dWdZ*3fd1v^F|GeFFcf5_m1A~}wLYM4y>G>wgmWF1NycG_}c>XRRMih1^Cwl^j#C+e=I<659r$-;O_|N+Y#Vj z7oc|r^z97rZwTnSA;8}ipl=H3yD7lGIiT<60RPqieOo}^Z2|u7fWF-U{wD+U?E!ta z2l#gc=uZdeeF1uZfIbkQKO3O$4$z-h_GGxJ_qZ`e9OXGTmgHEUixGX^ndN@OQ z{7uA`85)LHNHk4eW@xzO9idFyE&Q91m= zd<0u&DBt=P&;;_2Vk4g`x6DwXbsT5{`G3Ghem1tuP_gwlpb6xsfJuH9w#?8BYqZc@ z*=2@it53U;uj@b8DiOY>7g=+J*7>8>xjz1CtKLVix3>G}8s*y;Nor-B8ER0z=3{h= zbyVcJ63Gm;S-%vTE5XcA7ao___H$*M8QQ8IM`C`?{LIib*0_-7>-OGZl?u(3LuTj( zt6JzPMc-_-3%yFwyYcqFdd^C|Q-JGDOFmJcZoIiaY6fpknj4G*ZuSiFH3HrmbARGh zzeB_oELXp+x<3l@hXUqQH~Q5x5`2Wh^Si42jO%-_0`hTgvLjPHep;or*d22JLm2Mu zJJ0hMxJ&IOK_22G@o6+32h|g5F2rwWK-0wj=ikEFc^ZN=6?spfEu4r?q z2%2-%l{1%k{rVZ)B2ILKA|4XY)v%j(LvJ9QrhS-?YKN9 zZ}junGV~idy~r$SkuSn@cpNGb>?NYy$B9P%Vh{|FS9Zw~xTsDi4@hqsB;73iphxwm zENzQAV)DLpvlN58>KB|i@*q02Ps0ge)S9Px`5?hXL&lkbFpKS%hB1fznys-d3sg1kx~-70v6AXk%2=PHo6Tac?9 z(p;?&QKUjtRpFNezb=TTQ|T`Wo)G-2pz^m5J+-!$yHXI36R3QL1bMDxdCEUJZ~_J# z{iQ4a^!HlULejvqC7tI!(iaOh2yP-Gzw$$$Vp+FI`dxw#3-*iL*MxpSkRHgG{})8$ zcN`#&M}8FJLo6t#N$e}#?v!guSJrbu8q2~AQA3xU|!toAolPkF;f~zIHlL-CS z5EtQlF~YxB@Q|dxOoZI8i5TR65&qCb&?rBhi1cD2qd z!*`MJpAdXb@MYn@O8lZ_{Z7)~6;$5~fqo}R>!BMa>YYZ!adrt2{FQ=hg}*`Q9wOvE zC8)k1g8W}0jpMHRjtKJqhseK11pghO|0ML^gbpQZ{zO6by%EUI5xSZPeQSu&-yrF2 zlHMis4&i@R@JYcR3BEzR-?I26_D~&;X+yN$af1BlI@9M8Ar~b!p&x|bCfFtEdx(&` zleh^!MTGyH;0u!eIuUXwh#hbOiUT_9Gggo;rO2Nm^mL(T34In3`C25si-_|K{pV26 zoq~4@|3RT26Z$EkzfMHHwNavv4?2Ek7V?iKza!5DiX+fM*21E%;r*R|Ss=z9INK!4CxgOEAIK`skC7dg-o> zm@PO-uu!m6aHimV!74%e&t?AAf|m%Y^%l}wgx)Mj|Ds&K^a|c6c(WiqnUViF!TSXt z7W|UnR|H=qVx9AS!IuPI7NnnBu6y1Qd{2-*&X`X3wp_=g3yv1d5~ROd@{0v41SG#b)0XxnUcnm$Zx*EESgv zKO(q7kPc(X-zeB7*eOU4vgGd){Dk1`g7gK;_3;COeS%L2(m5>o-xWM6_!B{TizWYe zf`1hJvmo8alCQq22pl2w7(x0~<$AbSutKm>kd9l)UnaO(aGf9>xsu;5sJ_n#`YNI6 z$(8(D1@{W>6TDCGA;HH5zbr^csa$uzD0oEhB|&;(CI2l!b)5zJJ)!BDmHZUJOu^BD zbj?csRKYUA3PE~oCI1{jI#uO*e!XCwV54BWpt@dz+*Lw{v(1<2tFzJjNo&E^j6C2jaLMZ3BD#s@1^8_AZYV?6Er;{6Y0&A zNQceD9Kn1+dN*bIEWvq#iv;N~i~LoBmkQPiHVd{2_6Tkh#9`SAecrM%h&V@$m34lE zh-;ui;%Lh%BWB|~P0YppOk#m$olBgC^%)UDYl&E|)e^DZY9=nS)Ni+37i}ed0nR@} zWZFesE%$G6UfV|+=cl`gP59Ojag+Wu43FDSlE!iKSt5>OFA#A&I6}nyewm2*c8rK| zdz^^zae@ftr-*1T29_TdOcq45sPwT!vThm3-+q|t8bd)jEPa2Pb& zX#x@LQ%*#?v=GrAYW$F#1t8q;Gatx?XXJtYl&zN zn46^%vSveNzLp zy1#(-EVCg8x`K#yT`2St;srSV2)&B99QF#`O+IOiwWOy@)igeHePmHr%dO z!PxgLP~LWF@Yu(DrKX)fMBHoN-JsbYCYW~qH4?n~x;^cT!;`D;J;c5B=mVXK%>-i~ zzoYK0$6*Mty{L=9$fZHZTkbU|cP#kq-;pB6eCopuK-0F*3lE@zsmC;3uG{V}7y&`B zRXA76x#O8~EN8T4yY}&T=e2LIr=4l1X=i?JfVz!+M}#NpTzl$7&e;2s5fG#fhL37F z*FMV8zAQ2kO#5wvoY%g4J@#db9P>Rc^=dL@$Z z1VesH%enPP22Fd+vB=cp8%X!o<9ScHxsW&I{!Qz1+c^Vt#8a+mS3W!E)%TJ|U%p45 zd8W?fD?>hSFk~hK5O?cAIo5-^7)(9VAm=UjHBY$(BFB6@KT)^ok4g|`>>=50SKi0= z>U$UZn4j~b5SwY2WugzD!gA<~H!rtoIkz6X|4)6?#bD~e=OMi1{uSk#c{xqwnD3iX zuBk@@^l{voVC=a&pl{^LSUrj%Z0hl(=rj3x2dT%;wVYdzTcjS;#bE03(?Ge|DA&}Z zOypRPF*u<@h1(xox0tzxWVb&~1@u*T>M;XyrXIsYpQ*>ARPG6eoUY~Edh~%od#H=S z)Pv8Hc>7~6%H?sKu2 z<=lEuj`mO&gQ>^1K)I_t^_U}a%=eU(YsMAVg(gmY#-7gv^fh?uG1sH-G0|u8@%Z2k zhWw$HbL(+T>Oox$rXK$mD7V#9j|C#fdZZu&bsO8co;7hKyY={8K;Jc-(F8W zq8@##MW3k$kFVaqvKX$^a&A3FLXP%O7X#QT@KdSYdK~c7<2;dLzHdmmrXIYGha6V?O?VEeQx8Pla=#?yn*Io59+)`w88dbU^!*h|ST5^<%S~6`1ESC58w!2iVCwO*mUHWo z3OVYdE(TMNmjdO6SH+IIYekOvX2NK1e~cWY9uDNZ{V@{yOg+|n^i36grXE>?)MK5N zbL){U^`I^WQ;*ewafpaOq4HgP5xd#(@Yo9?Mc4dl$YdPww{d_{xQ z;}=@atq0GGw1>JFOg(-UD7V5>j}0Qnd=*Ll{-}VyG%Au{>`8*0w?CG6>d^pMQ;#Ci zXY%p)a&Iu>YK@k2>#;=YL0t@{9(>NvTkcX%JvNFQ>(MXeqS`7f9i$$;0ezQv>d}In zrXKf+K2r}qkLnGk9xrP-w;q>BJ*bPp)Z?WM>8tx%HqNk}T?CF!eYyQ0`7oxmSoB^IfO)xpU%f=rh+c z)MxBjAJDfK`k4PdY+cw)J+_HHlke+;)Z_D7&aKC@QV;54F!kVbnBMj~;Hk$Jk)s{_ zo~pM$UVy%lR3yRJ^Bs{h^s9r|_j@hp+DAE-vsLsN``$#N*S?26_FV;8(=M|i}hAp8-2y1&*ZB$28m8H?pJF$w;q&ZJxtjq8^2@WE%$j(J+^zw zy+_J5^S2oa;$3%d3+Q{vqi=^t-)BUhsmCXcL4kVkd05oRt;b%e2X!%+Y|jMBea%zu zPLX5%Blta$ZDi_k01D=VHo@5QWw4=k$y4raBFB6cDgOT8H*e9@ZZP&FK+dbL!lQ3D zq)k2eP8Dr6`MBQl22+o9TF$Kp$U(#M0kx*VyG2_gcm9r{mMreq&T>hHC3GxDJG z8RqTl>+3yrC^4EGO;>pnq7dlMh^R7i!_nIQgxZX}MYZRoT=z9A2 zi5=Xuj=sK!dovD&qfYbU{@c+enf+s%X-h=yt^EAj3{_fR-~GMCZ=PCA$q{JHr;ney zuD97LTzh2l)mHK9BOA4R;mITQ&815YR{j3Rk><0TpRRiI$9vx&R`&bxo4&Lu`!`1p zo$TG7@}ooV^)6WOqYsN0y}Z46@yj(ITz|?guqKZvGiXi<@WG<~Lh;k!V&erETP*#=gD>d%K`7Evm=Nv;C1~`+=h9;^ulK*V}L97DerS z%u^PX5yP5BX4YEyUxelLU7p`c#*J)nc+;NV!m1D|wN0=UCp#bd!=q`-GVbPJQ zl{q_7kCnlmJZbemAF=mMjcUq{c*|v*m^xIV4&~7zou_Q1TAv0w3Jo&){#PA3r$1MM!IUd zbnEE04wfH^Q+`m!i6c||=7;BujJ8BWdDliKxUE%&v5F@u3nI~}(JGZ%^FimM+%LB0qq2#1Ham;nX3H)wCm{UCT5?8gM zaFTk#(@y*Z_~8qnz$sL(jM&NRL4-mHS3)fOJa&$HEjbiQnu-#_d>_-9u5=_P@JG<_ z^-L+7ELuT?!U<=Akq|~HpJ1|`$fxVWf1}1}OS$J$E#cxuMxSA{RF#IuD6DY#P1q+c zuBx(avqdL;9yl!UkWTZom+UoI2=z;jtRnNQ6poctt3k{2K);oZlv zPfhM&`g;!{J}kMJ@l%YaSwq6iJ(NO8{&SP8E&YNgO2L&9&B{*?N< z4lChx#*>pDu#s5LyjR~nwvTmCfZj`N7Q~5sl#ZpeHBek+k(goU<}&^ z%D$TF(pjQ?4NFXK!FR)%W@S8#9X`mTluShX498iL35;jH4|`2qDY9+m;s4 zhlGELq>()F*%xX(`~gktxlrqQTQgY!YZPB&uvf4^hUM7o1Fs^-Xl4Ei)#6ATgAb5E zjvVS9!#1+3S$s3Lv7e@vl_WopZ5)4>DP%fd{{0?@ZJ*_!E0$zbFD;3#T z>GAlidXG~6(eQYCx&EwrWDdJ!4Amzq_1mF-jB4gFY~`KMkV_6fF$)d$LRe>)x%pE& zAYhMIJ#-jZ(^S^+%$laUbUdq&#&KhhXT|eWLuRXn%wNpHOH6B5DFZ%*G;Kf$wR{2D zN3T_K%>Eq6NlI}k75@s`WSX2w)yzNZ3dm0Q0+RBOd%}K17Ba&3RCXXT&Pe9;A>|-a z3fMjEs2+c+K*j8ZR#q932Gm%0N&(xG;@4~O5T2aeINP)n!OhwYr88){4JSadcU# zMtonqfD2EWI0Yq2jf#-utr02%4xg|>i2M{gTb(r{j2+EGj$|5tm9N% zL8*w9|7!|AU~2ig%DNZ^>#PqjYZza+px!YwX$}B zafj+5&H{v~%+7jR`G3UDzSUIYTv7+_ajS7Ft8obgM@MMGt(^3`Ngh<$DEK_csiQ$s zU)B;t*w<{|Zp4R#X=CP zgjF*&%5Q+M{Q;}R025H7&qAZ__zxK6i!Z49y@(FwLAaQ2g4tu#K^UZDvXk+XR6URC zW7N@@ufvq8BfF;g`b#b~vGsWTDMx?e(6s`l=p$G$-<-3@2lVo_4Xt;)(#zLmv|df~ zwHTk?83XjTvA1&qdi!0yIZ7{IpV4|X&DUjodS?#M`*XI#Tvsm-HTHoEah<5`ovZZn zwVKlV$eL^OjK3RniJB^N)miRQ&}F!kwCs86Ovg^=fr-7uSMAwTIET0cp;Dz)V?4s1 z&_}~o77qw~nVQ2xr*c{pC$iS(xYk9GW*>OoweB2c-S=pnnhodJoDOff)}5oQNk7d7x8a1>Kx3W-zYDF{F ziysHu&Uag+8hrZzAMMrsm9JW4EGntTfu@(T#rVA}cw2$qS8>pl6tN z+sgDyY`(*x+AfpL%(g3Fgo_O}d?CdKX*(W01~%PD4yKxbWqi{@H(iagtR1SgWi|E- zQ1eC5u4TJvS%W@D(3NW&{fCjjn;cEbRc-VA{Zq z%0RvnqYd0>{}>XDpv$<@wwrAp*+P4kSKyS^qK5t%L#gs|rSet?PM-(~E)U*870y^q z<`rs0{1D87C>R_FKLay15I%~wTqPW)@+7uAgjA~_6Fbh2VS47;JZynO{#9UK4mL+v zu41dSEQ}sihEKmW>z61tG4gpZIjm+gGFu(cD=T0mNv(&R0%`EUq$MivwjG^Dp&0kUln56!|lmwBT}5S z@oB5a47W3|J`GK>Qc~t42^U!s#dHpjww$y%DQBgeHv$(U=@5Y-NJ}6!SsirS5Mzh{i$gQ?l zk0F-_0Yq_xg@~o=Rm2oZPNTt?hq~@eDRzxe-Q%+zkH@GkMPJZ}(pW!{EQ|FN+oIfK z1SZ`KFUf*t#w+Mky5lOOwyM+5@aRP`v)p`Y)597;qD)w&Bc~->otYMxCZ1|=-LFZZHWu|q5@a48Q2o7PB`ApJIJ_JzFP6IL&K}3e*%7AFQ0TU z59D-gwsjGq1e{Y15ejzqgRnfA;2x1ap61IWgD94^60Bd{b=c_0a7eo-U>n$HrsL=p3OH>B`qg#6u=q+ z+a`pcKZvC&-mTs_)C%0j<@rVT>l(IIKs~wthtyvbQ}6Z;dscVla)P#F6$RA=w6&a| zOE)uBi_HuN2V=VG)Lfo;O}AWl{BZiQTcu|HNEWK64bn-?jfuA1sJ zcP&#HQnBg6;&E}({y%9-BGe6DZ%!N5412VN>kxATryp8{pc`lvVU$iKoU5X4TY*v!t6_M?@~n>K zSrN%GZ5LYTIhbp%+mJD? zYI)7|HK0dx1k!`|spiHhS83KKSrNvqRUeFHt2Ws*!z~Jte^sC8 zMx8OBv69fJLq9|-nifk!tEvQJmFct7H0%G|XqJuxvM~Zfh9k!e#T5r*L(y$#+NEnX zb3m<5r|O@m7oQWsz##Oh=z8qkz_VqdRegJSno%CM8G=}*lU+SLmN0OVF&NrluS(TB>Y`oj zWwwwBtoVLxKfw07Nd!`k=SPm9ENmwHtJ7J|{~Ox#d~|=v`WkN8gzUeh4YTkl5#ktC z_-(GFw7zp&M|XRv@_3JLrnPOfN*8r>w6@gOb+@#)b(MBCY$|PQ*i^isr>&v2v9ufC zl*7m5TfnL7++2*$wDoK)u4`-PY;S33tlQ91jE|d_;_K=gdRkh$OB?DsuWV^6-dZ`U zW>!UMYs-exjrH~MGnO)AOIv+wPebGBP3UN?>uzfA+zbnJxy6-GS>Id?gGzh4I*pdn z&2{*OJU%0L+6w)n+N@YxAtr{Fws$nPb#=A!lM8shi*4G~-O$k3RMO0;SHn-scOj0O ziAcx835cUNVvP+NOPI}dt@uWs=Hc@P=me3g>uS^zSm~&#>>Rc1NPcN~?#zYfOu6!c z8M*nnOLKEW_?_G~67NHz(AgR(TsW_E;*8u-$io|Lj|hc5bTO1o$e(A0!ggXL(P@ob zFk^CdUQTY_yj*8UWX8NnKF#y&5~nueL?TXY$vh=kenGC270Jmh^_B8%Sdd#fZ~lDz zR3EeJe%mg|FI}L@nwz*VPesmG`-$A=l@*^cJrBi}FIZ4MvpCP`Dk*kGL`qw3&&}DG zud`tvN?gbNy0RIixw*N{;q4J;;@sjH`19Ftiwzr!OLNPYshsC0UYJ{!JHHgB`dh0v zWJeY(gyh0?>n4xSpO~9V`Fx+Q_icNWza2jnLPL5hw?CNh*H_Z0n~5qcTbBp>bMt-Ke>yPxF9#;Q z9uo4VUO zN|$%GU*1^X-Br4woud~s0>_J%)`n8G#}_85YU&yqYI-Uy%oogqjr{np`et}TV^=pP z555Ot>917ObSruO7*=1`R@2$o)pAv%)z#eI*&X5IJtQHc=ZvB_%dED>EBRwP9^BA+ z>$>ZdUX}}88@ropa9C<;+1l7()u>Nb;L{yYgKvm*Y*QuHw>H+b^>nCsQ)^FGv$dtJ zwWm?j_|ORwXkjICsqdEH`;(pB(AL`CwlSi1G|$vkeFs;*yMaQw8oRY1W!jsXNNY2w zj|T*+r>(1HV_RcG1jpA-8n(H8OQWiT`pSxFF?{+mvN(dHWu$oX1{|VW>Jj1bZyt_+ zTV@y6foy7Ruj?+x;dowGdsBB)2a`H_=51-}*fO)Yp?ntT?&hA&8;Gr4#SJZWt?0ga z8{2v!#Tz#^ApOFwNO4o+*80W{bs7NC!GfB4+HgQ`DDJM?(Ar3mmNtH=6X$`=E#32G zRUk!IqL`Hc#qYipcR@K%CZM4}#l2};TDn>`w6wN#Z=2WLf}>{}O~?%oNpNoLT$` zPh(qmm#es|qpn`h5H-K?IUS0rkNtRBL-ACes~S7oRYVPGRR-D$^T=WXhG7jVQ&*3n zU~Rz3&n>4X&bM?-4w>C*4zUhQuhA3TI%o0XIgvt4nW>yHmR>A=h+tcxYtmAOxeHOS z)M9Q?+Suz7cP3mPzQMUMberwtbI}ZbZ{m)GYr{L8>&fRL(*!PB&4QL`RoG6akBjZ9 zw6QxAuTQuke513A`go;iLIjaTX~{d8&bSF&{8pt!u1nsTbbaCt2{(p!IX6*;R~aU7 z!M-RhV<#S4yn#HgU0lRVJzT!G9$bL`v$R(~7ym*1UfUvyAG6KNqaN6OooQb$j~5S1 zJazK&PM0spD}){sdJ(BgE9*_&k#gxS%1zCP)O#2XWKg>P~`&URZg0|Iqi*;+R9 zCCn~fWF-zwT9j-L2@MTrhDX|?>@m(*dz_sW8t+UD=h;?C*S5_#KmxlvH8z_Vzt)V; z8uR2-vY|`9fvi5^?4K?JKHD5*$N5xqJdrr6YkEpLFyTtd{!SSlxxZUjKvup+%Ls>f^f_ z^(rKuKH&_a&BKl9LStYB6IYqA2GizYD|H-b@s?FV-Gj=-DQHmH0bfwBQtP{tI663X zcoI}Rx8myLGw}QuG?tkM6CI?i(~0|wkF$yxwETFor!!zMdA|j5&Yy!?5Ks1W77Qlu zvp}yZ1}jszrzyoF;nS;EAcN@@?rHRTBz$^ttumNWvQDGXuzl*(vTZPhnt2+PF#(@a ztWF0vlDyNXRC&qwYs3m}Fe|YJJH1B3_i3c*=1YNtY4*vS#^wQX4Y<#=5evSicAQjI zyl%sW&c-d;PMv}~D_*j$v#xDpqnvrQ#K06@(-@67b>nfd_RX8I@U=?X+PfP|u%5() zNL~FVuVQtvq8qQS8&@eCdb&|eFyIc68^YGf4_yKg+)(h6phE!~_mMoo!M!9tV-O2r z^}Rc4;f=|V=f*E(9QQUYDbh*mR~k)m@7LzwCkcPb5Vek^ey)W>>L&~4)4@?cb{UHL zQv>?Ft4i|I0{YWpnGti;k2bL+2VMvH+dwSv_IxZj)`);UJf!0Zj{2!Kmf+x)v0oo= zA;*G)6}7+q-W4b9^WJVIJwBk1UPEKS!Pjp5`X9HioiUjmUVoW8U7tog% z;Io%v!LcR>^i7U25p&>`)NkLE0Do$LE(+-5g8{MN;As!PzUlJN2iEZr3#q3;yz(V6 z0x<_qviSR_G{7$p=r0fOxpycgI}Bd<7Guaeq}(P@2M@=@BYH5@;P|0 z%&+gFfWEZ>eQN{!^#S_gfIhwn7z>VdX+YnlF(zV;>qSW?J9vV{Z(nUdenUXth5)}I zKsN^TH3s+_19VG(=5sT#;3zNaUb-ztAm-pXA#ZT-P@p$B_%)yP%WxBW+!!Mce!%ty zM|tFlr8w4=>gQFHLOrVt0VKT%8_#FFcas@PQ~rk$Re}7gv626OvG*2oNwpfN0Uk)*p1nv!{XPBv^E{nrul>$9^UXK&&CHsawbopC z=VS(Z$Ug9}ilP7YYA29hi;Mic(=#!Nl%Io1M}$7cxnF6%!^sThI*$X5Vff9s$j|pT znZf=#*UA0Bni(vX{rc(8cQl#75zZc9oJM;CB2J%z<>4+J75;HfF+J5VzESEQfju*L zhEu9E-=DU~7;B@Ev3H~#kMG5rz&c&dOq5P}WzZUk)AnG3;^zgb<&L;QX zmf}ImJ)+!piN90m=-JS`tZnz$@o4;gqrQIU6P~;g&`$^Q65lxL6Fo`uEKa-oByHZs zi;Md-Oe>!?i5)x#dS2~3p?QAoJUbab_lXB_n-3I>$M?dO$C|qdkVgbVaB%P0F)TMZ zR8_Tt=cUI(n31{k%V{g!lJm~%zQnyR(zKKC&g+JI7_5DGbHEHR!!W~txjXYA4LAt? zY2f4ikah*R!Ec6H;OB^teEo<<-qGZOfj{dI!!d{#J_3RU{(S&xS2?l|7}HrtdKEnp zj~U*8FB3HRN{F@igBf6kEAZ$2Pk)Z^C?}tY^l(JtrOOOIz)v$^go{i^5Y|3A{1{-m zdB3~quKn)g;&S}ykbJq;^&eomQ-n8sd|&L9kLe!a&-Q`(FyFj$#Z7kye+dWw2>H;6 zail~nA)0b9-C0NS&IdD1NB-rmH~qW9ns$Tc>rHNZ%J`gc!XjvA_C_Smtn<#x(`=^(vAk+%ft)r!|C{#5Y} z#d{PVQhZeL8O2u>wpDEs}xLNU!ieD%uqk>Y8 zOvM7lv5IFY&LSo`?l}wKUru_7ySADr=PdyLUHQ4fn(iAl+=J>a=Oe=XX{BFQzF#Zf z`^3&T-$&g;c(kP)?g2zRMlqKNz7itRQ%XePU!eZne~@&o`ai6=S@Bmy+ypTqVC1(|E4teE2X^ah~U3P@gXAG=jYV_HO1d4{!#tqJUxW}Ox-y^ zro1E~!XK%~g}c36- z-&guG#V^%e&X)s!-%f70;}tnonDKv)IN5P7A|kzVE*#ufEB)_^|Dk*jDZWZX|Fcc~ zcPV~IM7{bCB6J+AnMA{V4GdZ-{Z1WhLdyF;Li1gq{pcLX+)%(`{&X9`-%$` ztJMGBh>&-K;_XDp+e9qKzWhXl|CPGGrSu=v|Ib9k^H+6mQw(5W#c;_)_#Z)pyupfc zPB`K@gY*In%ZcExB*J}#(kqp|S#iC(-$_Kcht&O->i&$nZ&m!OBIX?mf3D*3M8q>) zv08Dp;!hNxRz!;;Z6TURL8vL%O%YA8(7hFN6xkH94V7^KaFo&!ROR@|ZZv0|$tCWnbW za?UiuarYSZn>`i#D)M=d?%Y&{c)VhXBKHfTJNKF)o~y{`KGNli+@Q`U0&Giaiv0 zo(BEER4#zjc6;D(=MX^*-CTD|hs?yw~h~c=A4w3r|6S{AFAVyh`2ID$2RlaKBAyIky`0&y|*Q zt3f}k^y7-$@`v%uxz)fol$LX=LI1bXe^T6~DCbziU(T(@`0-1+14BCgOi|=+Ky>e| zn4?&r$W4OiKT1)~tpQgk(=?*|L=-Pom{$;A~)3GxH?-gPqDw^5XGU2@*D#Gla%HLJPa?-CBSo)mgf`D zO}6;LzHu^fyXI*q9PY?(|?BIY{fD~?!v?I{|d!R6|YcS zt$3~CEsFA-gmB!ohvDy2tNqdkwl#X*u^A^wUZ=DRMg?%KM!n_wgqEC&gWgA1LlsJfQeD#e<4y zR-GUoMly)#V|o(d7a?LCUP#1vGD^gFWfU=j_Jdg9eqUn$Hib0$2UKHxVO> z`HGT$#3Rpdz)^Guj#eD6I7w0Tf&UDp%M>dVD;1G-B4;HL>Ap;{RpukqFi27e1(Yod0nxY7}4{bfm=xC< zBJyRO((8%HA9+4U_$Nq1$!7K6LPUPab2$9>l19FzvV1_N6On&k*C1;gh>-7A48wf3 z4aAAb!9V#>Tw?ru^rPvID;3w__|5{4Ki(;DGseU_2o9Zam8eI>SXVwiO-b7p1~R_W za8aHKR|mUoO!_L}2z&he4bTivIWz_QVas~}Oc8Lge0$(BddyOJCLFgRw2dJ-{{lZx54P*ngR*Fh z9?Riw$NM_sHT4S3mKX0Mt~{?i*e{@&@r+3i-}l+_wpsFeTJkojJQHp*XxkX_*Djx@ z2iq^|L0L3L556z7Zf{1`N#-xY+kS*^^OWrYHHu89bQ=SR8 zl7wXp8FBeMJ;+BrD2vAEkqtgO-t<%B zm5a;hF-7H>aD0Dh8>7b(m(SCq5;W73tIS4^MR2$E7;fo-?#+w$9#@{HM>Xj2R>UC1 ztntYkXUSt5Z}hlb<(Y6if7mug4}On^-P417)Pu5Uj2?8i^_XGBi*DJAm*1@^+muHW z!i}RKH6X?Cy{s*-0`em8VR^7`F?xIsKFTxU!jNwp`q31)@p^iYk9trRjnN|q?smL& zr^f3Qh7(@Avd=bXqX)mk8$0Eh^qdKIJAIj;ZDZ2M_q(ur>Ek(?Okc4woAk|tyPdvU zPmQN<7_F<$2L2wX}F?zi1@_BmX zgQh&nqA_~B33of*2TqOaF-rLuj_-wSJq96MdwNi?E$?Z_GkUQ7HG1?@c}9<+kY^jC z2j?lk?&-mEG%3%t<&;M=4Hi4z7ZI=N7fymd`52Dxm2EvZ{%%i?RX%xJAkXN5;i)HY zlgcxCjDWYwmlb$g6 z?0oqM@=SX=&XSj{@=UnPAkQ{NkCRd<=Jm#%s!; z4)P*!H^!ug@6~O2S(dyrz|43luSVsWa2q?&<0mekrw92Mp0a3+9zXWQn{UNCN%MPu~X>5F%q z74KB#W4L@2gsn$2H6}g$E?}3(49JUshwasLT#T3U_?>|AOt@T=Ah^-ckLE;| z&(k9xd<;)nG$z<_zIbcK#p~5M%Exg0j$rG-`B3eZ$4sBRI!oS6OWqQdXY?3v5(FL^ zqsNb2K2HzwF+G$;V}fxWkez?GTJe5Q`52D#fowgdKtOwX+~TDTiy((|QH-iwgOc8&F_ z92bJQ^-ATLa0lpN8KcKom(SCKd`u5z(U@Q-gU{CEz_@t5nx}jWw@Bk(;BCzH zFvi3?-zP788aN<;dMv=jcqxzHeM}gT&YPL2E7rYk{MPvRc&rD{A~eSE)%oK+6M7(h zjCT<(6Yo!b@{Y@OpIQC#Zt=;>I?sJaN_kb5JkBFCX`qb1LLQ%ej4{@q`{X?hc@Y#M z<);Uikfah}Ffu?!^SQn;_g#q?$1V%ltZua{shnh^p& zV_i`>r`SF)@^I%x78j2=erSZ|@aILYEI>r~bnm`9D|Cipon6M`PEJ{F*gcVLBDMu9 z3+-DoY;IY2;$3BT!M39;G%;^Z#^ylYX$$_b?a6g}Ti$wsLfrEac@|?=oT`W83Y*6+ z4DNX`bj#S_TdNiZhOU}(-@*&$1ozBXe&3uA7Y}&!ltD@RvQtv_1fAg4yLz57Fzemt z_m!j;m%g$m94;Ld#Cs%p84oMFR=RYz`pF{*B002@ie|iXH3r?HL&x$ zdwV)L&+j`WNU4R0Ra29fY())xFa;R9{%RV;SgWpqGJO zc7J8>t~-|JE(g6F^zuEVSLCh$y#n-#feS&`V0D<2+;{B`XMOCzpZX_@F0Decv`cXK}$EKKA5J!{8fyyM%^F0)*Zt?;r`7 ziU>iZrf}vK#N19QoW$qGq%i1ybPgn+&R~7;mo$()LWuL;lZxii+6rs(2b*C{z8nl? zDHTOp8${7TwjIP2(cNS7Qmna2W z>2o)(?o4*@0N;Up0$XOa6a3^?AkIYS%ql1NDO10i1VVkrP>mpZu-rJ`huO{at;D|^ z(&Y3&ujBNA*GaBdpcpl3bVMi#h!D!R*h4a)?XaN>tiUAOR42$$6@{5;?Ya&`;z|Hzl2PLQv9-G|k{dQNLQ z3K=*!z#JS3_MVbQg9FSYR?%J$Sq1I+Gz2#EAM&b4qprV2$eJ-{*vOm}+Z0-2ZV z;U&4~^k5L?{!`-QCJ)(Xa{mMk@!NQa8V$i|ZbqSah%U7nf|+WS6-vbEJQi96rcfW6 z(YONZ`IMc(3=2$Qeti$5RJnj`@P7?SIZ081JqohV+?tg*SdkSvbn}`k`^fot(H9W>-vBpO@(3*vmS=>wu+w)E6r&q6+V$k!<$C5UfHiO>qlmBq zMZ}B6;^Z>-Q)js$#KrlFV{b5`2-#=dgyYBIm}74ePr6A-Jj%v@@J%3aMh_lQl9q#0 zMT+p9va@}Ni0@>U^u$wTx|oAlkZ;!MG2P5zI#_~YpGnhQ4>!?6XfpNS6D4~XVN6XH zdzK^Ivv`j55`rQLtpwPo~puRV=f~P^~v$#!m%yxIV`z}PAqpAWVeGon+b(tok3vR&rQFl)WhPL zk+6Z6utBV6dtR`N6Q`*JHs{zfnsAouN~pv|p;PN=t8zUE9CL!5K)EgtES|}L4aYJN z#*1|Zf$ceYr`6NO)&e`g6DY{_pp7?>wKaSy$ipVph@L8~5IRiPgkq_=S=k%CDQ6?dBi0;*VFQtOQhG+@}x_2si)-` zm*`qg%kwVLt)7+_T_U5Nme*XOdp#|`b&1S+THbPr9`&?rafz&iJFPbyvAH~f{@5oT z|6-WsC*VSTBuu~+b}o9`si%#DA5iZ&^|Z}&soy*Gw3WNmyG}iAtS8|7Z%6LMB`);` zr=B)9Mz3P0!YLCMY8@d*tkZJ=LvV4Ic;fM{GyXl}29k4GM!^wvjW8P5p>^g6VUROM zTwXbo$M7beqhYlMF7FHk7DN7^*ut&@{)ek=gCaAKhFa1vj4`#atin}?i)CY*ZzAU! zBqHce7wUKya}KKGo2-H=0#&gP`#sfs^)BH5+SYt2v+9s-&E3}!sAtaN3hV;QZLpRu z86umTdmEi&W`ebHHq(~PL+x#ky-j>&-{3>{_5Ig|(e{SX-0E5OGnN9HfxX{W@Gt@H zx6M7d#kF+dk~vjcq=xr`Q)kRf+%!5~4ZIRyeK323vmVIK~iJEq6BU{=JDQ#~3#GJq-b5)8Em4!|V>mbj^zIsyw#q%75Cvy7Bz=bxw6o`+ z&sX*|6gR!6+m&YgI+ADm$0f!qVY@;t?~dg9SmL7Hn%u5f_3B8Zk_`hkxM$}#OexCU*_H5+nFK)u}yjbWt#D`gQYH!a*K3K+0 zO56$?_iRj*&o2&f)7~D9iSq2bobtN*{g2Wd;o|W?%9|qpR)$zhI=*|joEGnKqvAa6K94kBs&tt zokC6|PKZAT`*9O;^5O(++@sMp+>_BZAvwh|?hwh77Mjd7O{ zo;Z#I$vV!yAQK}TJB5@Rubb{SEY7tdKl_NxU?*oH&=~ShGX#)yB`)%_&)^wn}OC6WlY6&&3( zx9xSUA~4>R3h6e3(wzARZ&L5lqHapPJ+ttkViKIvhGDG{5t&*}1Yec9^HGTI>y!pK z-riaW9|VoJQep;32EYpUJ^;#Lc`*D)rK^>`Olg2KfKPuk2*-!Uv?2{Z6mOYHBQT#a z({Q8kUI|6;2Q$Fj9tg+s3g+V-F7a61a|uY%qMuI2;!kbiNS&`p_7|#zBf2R0b zBILeJM7jTkNV)3%cct-=BmNO0_y-bED4YvN{%MM3ic1t%5K&&&5y3BOVSrC7Eo`0ErmDn6sQiwL>QdtzTjSql!DhJIiZ zWP3}xn<9Gv(uhKkEgbU`w}#+xiYF@aH4gnJE1s=5OR-F`Lh(XHzUgB)&K)4)TZ3So zqSQ;c-=y>{igzpCtJtXcnBr54&nmvE_#4G7idz-8E54`riQ?yqY)qLxSmUXVo2ohQm#BH%ow7b;dO)+q9eBKi3Z zhqzYJ+;6hh2<{E)F83Yi$CQ?%>p(xNw5%Be{kqb>Q~bT+pA@$%?os@!BEL*C9sf|| zdkE5<6f+dF6wUpcr}R)F?$42m{P;8duidQT06FdEX zr1(?C+Y~n{Zc=<$ksqHJ?iodX{Uj}Wt^wardaL3##a)UYC`x++{!f)Ys3?21!JTu% zDK|s0m!j<12KRnS4^SMYc${L1qO@1w=bUoNo2q!8;`bF7C|;;oqqtI$bG{jVwIaW; zlKv0HI~DI%{ea+o1>%^&Ue3NpFhB=w&{MEKcCmk|-~N~JmOGJ3*#Si>g_Bu&OwWTqarLGr}p;GcY` zR$}~o^rPVu0`v56eC!AP@!B$3J~YgSPPj^N(NrSAl+S!24=>UsxG2x0w-R>SnDl)g zj<9=kN6E+VCO(7b!Of1h8u23ACEgU}XSj8^Y(1($Z@^`YNe|1%mRAdT)PWb>jUGRO z-PR-1BpmKEhJ47idwOKSgXy6x8l%U3u-oxAT6&}_AH)3x7iIH)qR9qf?4*qzufcB1 zYqH9tEBuTeJ7A|g6E2s8Wek}N3x1v+91k!(ltp9oz?<-dcwe#f=&pPW$F#7$dL7Coco?j2>)Dj6BW=!Ou(nI8Py0BK>GM{=v`FgM8G3 zvS>`a>%e5!gHe_q$VxBXhr!42raj;cmMjWV18*@ez+&ulARqS+HOBaH+-1i*9`SPQ z!u;bisnPchpS*RrX?GeS;4{`1AKzsV{-#mV;^Q8+cDzl9tO4m`yg639dwufGL`5!v zzcKI@!?o(Rys~^(7UkvPGJ1rdn+d~!H$vWcTGSXnKIhr;)Sk9K z<)PmhKE4d_-D&~>nLe7+z-Q}G2tB62o#|!YV)Qr%e5j+X(n#0e*o;gBdOByavh?6zO$sFuzor9e^zS9|iSu6=ca?*kC<6`&rP3KY&`1=z6O!`*__+` z_2foG?t=F^En5B1f~S`6Uo!fHPtLmg%4uDv-cXrz+x_oe-M80oV&5}z2Y+DC`wlKL z^S;L}3Je`vzG%_Fa?bl+RDRzQciwm5H=6f-?|lEf@B5czk9%N#NAtcPn4h$-u)}%Z zn6b^rZRAH|t$z-98|Hu)CSA9rHZP?#z4U&a1HRju10E?o)|&&)8Q}DD`f(Qc+(q>3 z-L|_+XBo2uWPFi_jz!yYnvZ&XMz8GKIf0SI__AK zJuuiD8JN-BCwAAY-d&$O`^jG6k=aAe`mo2C-&Ieo2Ikycz3{ag6athI@ zT^MPgquE6?>(7N|L8BQ}n_BnR_3@4o>>~pkGS~e2p@raNU;L?jiX41kC zEU{h`#u@0@RAv&?=9?C(z7qfL%=v6S>@0-W-(0UiF?=v{p1Fc*o;@Gl%&^{2MKZ0# z%d{WByIKVgSMM4M#>8kRdyUFH$Mun!^RAzYmih2Z6vdiw;>WRu)8lj`C{SyPgZE!x zJ>P(2$<*yy7RN~-k74}@)UsCbJxvx@8U$)tP*;NN!*DDVM1q;}(~ttrn@2S6y!pO= zhhM@>e7;nU$V`03&;S`Zi~&41gMN-Oc_%Z=AXBm{L1OOFNVhc;|4T3j*7LJW#GQ%H z3cej;7|AfXL-rxcJei3vl^?8m-c0IF8)|p zPk~p8$;oC$Fs=VBPHuWpu*~Nggcz+MxUH%wIo44I;Z~|f#dwe-R%s9xTWU!{kvcv2 z3NTPkHE1Y3u>KRsaZ9P3S(t|Gb4#h5i5p2$Cg)4Aa*zd5!gC*iZ|LT>D+*+Ceg(z2 zlk>Cru(Sc9HcAR*GJSRgZY*eSn98JGEc&<=886JUS*cjIe-eLA&NuZi3Lh@Bq$+F^ ztjYOFNR2deM>{B!aqC#MUyA?NR4oQ(QLV4j;|Z!(SAZnbAd^sPtVda>v4J|OoK8xLrH;47 zV32ZaF-MVa33ouhm%(uZgz)C>PfLG_?#~v@>BpDIbYl&3J$dW8o`q*KAy2a~`ZJpT z;>E0Vj*Z|ib(R}KT>gJr#t`Yu`T5rR1-X07>IA&ez})_>Cv-j$ixJSf#V7is|1zr? zy7z;EneLi|9`Y zu^uE7wISPxqAtfIF0Sa4u-ZY_CO{$onu&;}PS-l*s1zmR%M=jKr&pe}8Um@zH>)HH z;WtC zP*kcy(_|Vr8hdI=*x-4CKE``s+@;7}$*M1MC+JSguwNh*hpEbsXI zbBeagkPO!3e2$ZtrMj5K^*sj;VlbPbofRU59jp*3^cDnUA>0YL5?6>s7?FJSbuNm) zDrNxwC*ew5A+pF*GW)uXpO6^49GJL&7DC~5wI)SiO1pWYH@Z5UZZ^f00NkE|U0#Z^xv0Q@n zqqutS9w6E|EsdD=rbLe;t-)Tu3Hi zn^>n1{)7vMQwHj3`OqaUucu|NOI%S;%cm}JWqlhgU*du!{ClQ1Y`Wsa^_^k7n7^aN z_iO^ISJR)vf}1fHUs+F!%X$uM zo^cZ*t5`kC}AG4c)m-^7DmAfU%< z7;y&wwWg<%XU-RmsjjYCICoCX!lg@A6s@SZuxLreg@em4T2fIpuc*3eP7T*8tSFkZ zq+bw{q~D<%^3hTCvKvUPjN+DTC!j&Wb z38vr4>YziGh`43{uVq4mtCu3v=Pi#6p1)-2;1xB?7uw5&Fyj{)b%89z@s{_P6+606 zhzvTf_yRdd*Q^zy2bT*`2oCraAu2FFz1Wk=qE}ycw((&W7O7N?+5Jd$=sF=+qPz6W zt6|=nBv+FPIl|bR6TNhKO~kBV@>Id;!5X2PxOP@EX%f6uN&W>$>A2@RT7SfD#H>Hc zV&kC3cF#7BKz27@wJwR>7~?aB-JTu(OVDGw_Pjbdz8cAi7-k^5L*H7ZHE1Wl7LOe- z)A7$-+L=S-N?T@fQjb|}Jlc_NUf9jg}i>@YB-^nMRvnk@Hz4c{@^6gfV z>FMf|&(}e5)86{BM0wrg%&>8NSz>zeQq?l;tuITIccjHlc|Cpd@G{gg?X4$El*gG_ zal`dwiRn8g?g?AS>Fc8-zVeCq{BwQsa)p1C$Cc~ZXbHJrwLCYjH%m+}zZt|0*PkV( zx4%z*|2Q*jhptZ>;FCYV$3Ms?e~{0Ah>tGv$>YqPxCvplPll50_XD64^(&4u!xqBs zhg`=*6TuY#oyb3wUY-dh%ur(Z5uP6{A$gSg`5&e zkI@OE3ZK89KE>yMs_fCvHiu&>uJ5yRlyYqiNKe8Q=kFw6(Mfac#r1phfyR)3u_1t@ zSK}f-TOO|OyG3cXJY3(mQE86FGK0rB4=c@_$PDJnnIEuQ%;LufO!@P^5p6xRNDJ3fxkpz*x}F+Z8t{KC1YP;)jZOLm~XKmJ8v=EB$@NyA&TJ;zd5c6$jDO{90-5z{&Xb5mBGg zg08=un+%%Ubn+atvFbiiafYI-X@opkTLHc+)Lpjifjj5LFus2$!heI(_bWc8xLNUe zBKZEO_@&~}cymhk5sEywg7n42v5tFwFzW5kNF%;G)P0lEzfhDlkKo&;{yT`M*RqBO z;n;XlUS}fc3?lr8sQdB62wv8!f0^PE#mf}0B9`Ezhtk}`kn-*&BK*^ee^C6ZVpo(A z{pH+Tq+_}D#C_6N>0^nI zJ4*3%#RWv%S5-vt*D5wBKB?G3gxo#EV%)^W& zr^pULR6)URiYPjvdn*nif+?!V$vLD?RD@`uOBH7lQEz4|&Q)BXc(J0~r{KFv>D7ui zD6Uofsp4&lcPrkj*r>=4RE+m2#b*`YRD4@;n_^7yeZ@VBpD2E=$PSWn!-}%z6LfE- za}>D-gM3`0L5wOMr+A{`X^LkkPEnkp_&vo76qhN=dGL^XnbNh2*C<}E`0t88Q*2P& zsQ8fLBZ|){zNGlNVzZ*G{Y1Q+%}KqsD{@W`>Ai}wCJgl7l;#|M`X>inly(m^=lan- zqS#+?pdx4f(f?${(-b*Jp6;9wNSv)WS8;)2wIU~+lJDOXWi2RZX)l4ds{3tOa}pNgD7NcWc%Usr5aP;{PW|f@rN4pueM zC~G_6&MAwO|Dxh6id>IF_qP@Qq_|y?b0_KliQ<=voJBzQZi+n=dnt{F@?YW3nIas(6GVx0|MWM3Lvnkmhtv z;t7gl6i-u}q&P*9^Et^sUvaVGGDV*2LjTJY<$U;odOkc*&W8ue`S8Fy$p^e!QO<`4 zE$71npI7&n73I8mxXXF*Ku*GB`1cj%ym-)ZUOZ6FiwDYi@jy;|0hikN^!IzqH%(FVC3^7#}Pe=osq9Zv`c(mVS6Iu1+)u%-e7r`5RorBEEb@i4XD0I0Y#2BL3m@2TJ@%2a+u9R0%PH`#@3BgLF+I z4U}{tpE#w2`8tz`bk0_k{t)Td&;AYR;My|keJT<0aqSh`!-d3%<8T5o<-SUUycQzl z@taKWG|fNAlk|g@^h2(s545BY@+*|Tl8AU}lwL_he055%Ax6+%E4_(W;6Cd!zSl`3 z9UrOxULw--bq%6&pt?NYF%0wBHc(GY4*tm(a>+yZ=tt8ZS1PW<@v(gT@v^Lp39E(q z*a=sO(&PKN@}auaG4e6KvA8JDq?h?;8nVULRE@JwUg4CGwwD{!hhP*=X zuwL=azmeAlKFTxUxTefD^rPwJ#_Q=pKI&nxT z5%g&I8)M{+^vR1rp3x&0%tqenDi0v$BV$q8=uz(Sd3unKdgLmfiTC?(xAhor=}`b) z6Ys6AJWr1Upxe{q5}&-8mL9Nr@~%^P05MV1@GEWfxZCCP^dKMgpe!1r$DO`-Yb`wn zC?CV|eHUe$dNm62j0`w?_2X%uytRE3?>Y{DUWBb8Dsng!`-eg zn~=VBaAUpv2bNL(gf zKIa59N)*W#ldM$=eKhl`4y1L zHJrqRQJGnvj4^Ss&jz1ojsxEo%favwt!!}8Bd7;Sj#CQv@wgZ-^=I0w;7(P6J5wFb zVvIa|0vl00^c(C|Fk-~;;Srj{?^UqZ9d~vtbGc}=*CEtuC^-NK$N zIj@(xrFyosyq@Zo?%BHLq49^b3|yIcu(dTuqxjzv4MeI>|IhtSE%!S(|MsVT%{>nW z9Qz;T-1p$Tz^t3O_rcbWijLs^2MhWQTfjXKu9@)IkGKy)mm%qY;9dyFjDP%eW*FE1 zo7Dc#rMn~{-KnoWy`Ot3oOsV`b=+5BVB4+#;NA-RMjmqk_g8px)q4+ekA=QfClBO4 z3m0x4^Ed9ba7oS;J>vT<9J+4-_Fp*ts?zI9*W%p0Gn<<~$XKw&IlJ4&UZ?FzN!mO% z_1VY9CcoAELFR(M$kX>ZDah3Y@3u8No%T&he)WTl(_#-d?W+w>Ep0e0Ixh7s_vAhJ zM^7F1D*g*_+TM$MQd7Cdfs;4Blx{o+Z^JmcJhAV}ZfWmMEj{bQt(oIXpBJ~(y;r8b zvL`L=iG5DDT%IEC*TH~$~1wb%Ib{JkkjZ?-i@YV(qH_l0Vlz~}D1 zaHX8Um$>^vwd}sYROD98t%{U($DRsrV5f!OW^~8i3%`zLV!wsgWv7MLu*ZCLy0sT``_y!+)IJ`qDob&=HIX{q_GeYblvJRu&JwNa+T8pa~4lLxf^Y&4^PdCJ z!1^S_lQ9=gWEl&m%zNqnFx}_E)`M&{_{-wj{4956a+X=`-zD4`eC|PfPcqz7iAmrl z2bBI4rPqNWlWj%dDJr}HwhY-^;3%MSn{_1iC-^NzaO;6y(_py?>E(Mbq&c_}|5JmP!iS?L`n;q*HQXHnZnk#8 zi@`o6cnO?)vB2o}cb7lB(mAd`J$wILW!W*%?_#)jksUO;-3DvmL6aZ6RRZgO$o!BJ ze2_Vk0m*KDKgb*@2I=O=gH&f4$R09Wa1($v;nVyD(2b9|fzM1VV<9E5eklTFaHaWY z%)S+rDsg_sIP>AjtZk!TEeT}b=ZueE5PI?+#7N0$h40ZdP9P`1^4I|{rzbx_(yuEh z`W1=a-{{vXAAb)ZvvNQok%6ewYY3c}eT?Q7*$6>`T?jH;R@|?C1iqo0*Itn=8zKCV zV%*&Vdhv}0-*|i=iIR;AdPU&IlIjFDmN%;icl4klmqU?4__JX1#Gktb(B~r5t|)w7 zg^J`)-KzX<6EFeH(gYMa-D<%WxHVBVel~DbyOpZl3U*huTd7(TNl{ILeFV}~?cWns z`w7KZs&ON{7r|_j9)T>Xwo}|XR_!0+|20)BK%Ao5DNZ*&IR@@6z&{N#6{W@!mg;#g zRb~p^>Ul4#CqIWsrDu-%Yx^-LBCUa+^Cs>?=03b@`Y=PBzBj<@23T07`q1Kf@+Nj< zQxdwdFkDY2sgHO@SeH^}xy~Z%pScmjQGw2#xsO4h2fB~=(U08gSxYrDtee>v7A-e+w6mYW+QP^f^173TC!v8gt|Kp;IksPcxdnN#zbah3C$v0SQAQM zr+MhI)59{Ls#5|1wWS>iF2h%>mgZ{#NFYeZ?aYGBGo`R$@i1YMSkEI&bzKR3lOJ%- zBP?)T3G7+mN-&Bgu92NA4ATg%gqegg*OgEq)|mu$h0GdvD+4!?GvOvC8~@{QB|9^2 z37>sSn0BTsgf_uSCfKZJze-E!%kPIo-TuYu1WQD z8R~OQuBXc=pKD4zUAU8%orctUy2y~oIfptL!wQZ&knp5fXAqij;SkK!dRm^xg_=ZQ zVTwB~l<0195tls!?qa&)->m^>8{TB*e%=%-C1)$Md@#xafra~oJh4vC2Sjo4s7T_8 zt~36{u)gfZmF!HvB|PmGR%tOTgM3_mcY0>x!Yx4Ht@*D-`G4yWpYmS7$HWcOh>EvTK>Hj)7v%`Zk<$Wyf zBc6y^F>gLjy+rl!PRc~?dnaY0nDwMg3>xqZ23AOGW`~{)zLqgS&zC}g3gHOhhnngvS zONR_E${Sb&`|xbI6!(cnhdWqSzng!dP7?$!8A8b8A6MQ7i}-gE|8n`)hksH2#XUkl z7#+%$V4=k>{NKsyK00xgKUVGI+mR{7r|?$JZsH<_HlDh`yqwQw|kASm74WgYH% z@lhAZ%I{&L%v#CsVg~>>erMqlIW>~2Nf@nJgU+~gt?VHOi7Kmld+XC>t@yw83pnh4 z0mxeG6j5gSH$E~{KH?m@w#ZwyAKw{(>-6nK{3tsXtrT*KxPQWJl2PqJ0K5 zz8#CUIgDIpg>gSLGi=}X<@z~{T&AeQ1?`q+`%--jMkpfdptw6)XfGichY`Eq|i^?%Mvi{DL?$Y=@pLTj-O|-Ysr;c5I^j0dY^*4n1pjuutA#AAgZI$0rJ( z08Z&h)Q{f<;wFSw9;Sp!;2Z#*$WJM8!@U4(bLiUr;kGx@&lewY^KI7dGd&re2>)7q zKYfzNNlVBXBPGr@rx90sYxPfqd)z-&UkJNz7BYkBPC5LIVLC3w73c5ntTCQI`pXw# zAjdVCn6Q64ko+7=Wn#kqeXtut{)chVpJS!WVB|1s^$UD!^-*8&c#FOXgG_6!KD!Hi zV;eGJ7Yw}fopEKzS zchfY%Jp!6*>3Mfj4)1@`A_p|hfQSGN^+7qp>aE3xynNDA+_|3}uEjUuCb;uDx#vK; z;f{CX8G!kaVobUrpT=8@4|n!v|BSWxm5gVsyKe=N_XzPSMcyN%Z&qBV$a{nCn-m{a zd`6Ks2K{ACEKtrvMHjw`?k8idqWZ5RqFy|#?!Qp?%|z6TE$aTRy6;eWxB7Pvf)DbK zCZdZQN`(C5)P0Q7QxwlvbwlG7gq&Q(F^V%3D{3Cu%fJe9O*dkkOu#UifJfI z()o%LiI8(P5%pWvB7&B+h>&|Z-GQ?95cmLT+z$^czpN!hxLrygRP2WvfpVk7V$266 zBK*0Ev(^0~BKX!SKB)MbBC4emgiIt~5LHf)qcFPX5aC#$I7l(72+>j>OBLDFuzpTe zoU6zWeRN-01;xDE?gWLB)p^pHO^S@dd?SDgIXREyZ^g|ERcA zakt_ZivLhd;{Am5bW+Sv%u+mBv9Dr3#Q}=L75P<(a!yyAsK{vtbpM`Wg<_>5XDreG zaz)NnAT4X;ft(6^r<5#Wxh+QT%U3&hH}MUPW1R4qDcn1B2`rfU@@skaMcozw}a! zD9W01xXYSzpsYCu%9?YatT_jQ{kvadjkKfqq<=~!c6Q$z6Z!nXeuhu|#GXX7PuYqQ zBHELD#X=$+rC$R|zgFN*PGq@pT+IC7vkb9>2))KB${r+0&#&1IB7QUe`dr(^DBBIh zC*!RMW;cXDL+(%_}LC}&O=q2%k9#41ZSE>G0M8vmJ z>C1=_cWo`huOnT6bIsLX`c0%`o6<2N((`oiI@4(h|3ttpkcX^&!l5F9W7(xodh@7y|r!Rql~cf8XOP06Rr|< zACJ6bojVm5(?ULm#Z!>zl{@G9LHI zYlgfCm{=ZcQ;fXVRh|j=ObDKqF{1zC@_BkRfscAn7LC#41Mt~;?6vghqkIfkfCwqu zl*cQO$3DOqBQFhnwmhd_yk14XZ1mtbnDUGsVIx2V(vOB~sA2c?ARp5cp(l(9#^-rE z-a^D{+Mzts4J$~Jm%FQWGJIMXL@l%)r<$kT&sttk&6X1qy|()6R@djr@#J;*2d z>Uw*6T;z+FdqWsK3c*Y9497JXwjNX9VMlG!v(_iC8uA$aR9t-5W#n;hEL#u02e6IN z;}w_B(}R4JM_Du`*o(e+S6X@uRz8N?1wJCGlbG2M5LG+D#Jj&8zLIwMI3wSLp*Q7i zOO7)dzX15``mzS;<5bpD!OHHQdN5txeey;C%OBjN#+jZ9Cqr z$2v|K_!uw80483JhfEmCD8*-;GFsFaKkgM~%NvEvn*tun9~u_&&={Ur%K2cra1k3Al_rJ_j-kq7yS2lioi> znHxhtUQ2v@qk6mdho6tnktPlF8xKC)7{BY=;oEI7GJQ0B|7Pn^20cu^@C${}gX`w; ztCm3ci=x3DW(c5(m;EC6JTn)3+;7tu!$-8T!Ab9ndXVIfcbSijHv<>bW(9Yu^4nkY zTojEYn8TgVKJxfsL)`#}U-MkYjt^5i+_7vSzI&yJgZWF1p0$1BOZB_bn{IhO)ydxR zT9}iYvv<@6oZfpc82mvn@2Xgvvvzm&>iS(>Vht^$o6p=n?}CPw`AZvG7F^lT5^Q*L zS7_~=FYTRuWdVcS zdG|qmLksh6PyMly*Ng6q=U*D~&JNGKv%@q07@qkT4yD}8&RiG7n!FQPW^UuGSrBAjrz#Ey>QI8tCuN_ zsN2Y2=JAEaZa#0qJwB<{&13A0vSY@w6t~>{kAuDU)^FbJ?2YU&*Uv6lb>5wO-d(co>7#FY=ehFN8qv?-n{9EV zylUy(3nMkl=PX&lv(zH^i(sDE#lwpxpLW*dB3efcikv!a)|44%oj&Hw>5=kFBBSS2 zS1(^$vb1{Mk`*hehAdsa0AFKZtoZzP(+9BaFF~DIS9{j>Zq2{h!9Jl&Q$tIaV9tSm zv`pULWo*uY&9Co1(Bw4ke?HQ<|HYEV{Z*-DtuL1W3(H#{Oq+C|YJ5fOg99cVcyPj` z1J2spca2Tm+Zt|oxrOy9jCxhIX?|-M?!0H0)P35ThW4ytOhZd&_%{bi_JKhlBP-9=N2Oj_;zpnM{7#Mi!H1tyHhJ$Q&4Bp5oTq$ zWk1_DhFP$zq2?Lc_DQG%A8jgY%>pm;fNj^ub$ccK^QM9yJa6TU-EVY#2Wh6hJ;C1!JM}f`H~KQ| zM&I3qm95k_n`zH)@${vhl6L4yJtghXgL<|hz6kiK=NGUWU8!g3_yeuf)#&-rrt;Q& z@KVo@>slqL}@k4%D#?@kPPUGW`N}$~Wa%R{5z{p49Q9O%<)f!Al)Kt~(&xrdQKgu!ESW?2=$-!mSx$Dbh6%3&y~)G{jBTM)6{W>p{^^FHh6W{ zlqc)B(b4EzQWO(-inI%_hBL*X%`EyZsmI zX3dx|%5Xr8={^T`lkO_iU8bA&9orGM4XmF``^u6HQsCDYDw zFm;S+X1=oy`qMjZO)JXLO*8A=#dDJPn{-#hZqiJ{5IrhR47_Wf+zSeHz`n>;u5g!Rau-ZIo9lV;Wk-qwGO}ITW~N>82xY;vuPi`%kT%vMljkPCOjJwJz{&tI-T5D z5c`zv3;e>3oza$*x0*a>+s68l)DT7;+Aj5pb%g0jYRs2$%gWQXBdM31w5u4nEp^hiqtLE^-yDf8G9sy$LO*Xb&UC*(vTcu9b-GjI-k&)4owpQxB;xb!GcTeNEjnI1=~tfR%|Oxdtus2=}*vBQolp`6SkEo8`fFV)|v7#Z5->Wzl~rU zXxa%=$2jKBs2#t(Bx6jF<5<>RwjUhJQZM`dqAncUvi`CCG`bi)j1H`q{&w25bF7d4 zG;^$M(#`QQ>mt+6@iOz@+%G2WtaJW0&g3)eSV!q%-SVf4V|0@?j?r1Km_CltSx@}= z%KGEaSCcN*myXiKdg4zPp9@T$@wtF?gz4k6fhl)0hG2QK5B2Ar$v4)8j?(2%lhbGI zZr+m_YuD~#z2;ak9rsSx=7s>v7Io(cK95D4Zp?h=%R`^X{Le=j*AM>7G_)6gIQgvY zH>O1nbSrE)kl~bU-<-bVz~(`?Cha)zY}JkfT~_5B=<%N9>A}|5;Xmny6Iz?b{&N4K^yJpx!v9BCKe>PM z1EX7Ao^UH=thwvS{o`Lh+2eZ+_y2V-Jh^|uN25Hx*VmM{-mv4z{c(9mLSDH~UKZq) z`{W(jdZ@fCq^+VIc@;i+`H)xPlh+UODtzh7Z%1A~q;GyZ^5*;GF@5uW@|eE)l0G-@ zsOx;qi!9BjBU{H6=C)R)Mq1b5S^dT|2jy0KAmjSYAN4s{)MA(Mn26)8k>mHq#5Hmu zY((%CE8@)hri4{-OP1Em8*=*OvvE}OoVgdeYo6xR;MnH!i)!YrKonnTu=Y8@KjheN znEAdr?BfW?`{)L|H*ihB;TzxxzHfxP@I7|G$pu}~L+90j=KJflpj{IXdFw2i{_8E8 zDcWSw^nbvj>HoAv)4$20>ECS8^xtC9^xtXG^xtjK^l!6h`hRKB^iR*ipBPua42!0J z#G)BK-=gV1+@k3}%A)B%-lFM0$)f2$+oI`TX3_MowrKj-STz0XESmmnESmo7ESmo7 zEt>uhSTy|`Et>vK7ES*bEt>vYESmmXEt>v2Et>wjEt>vq7ES+v_Z`lyUtx=ew`ba0 zJLbN$a_6CCqIS*zH)Znb9&A16koj7c7~#bV&zZbCxf@cvSm--nt3! z%$-wx!4xKt@8UwkX#08wpNZsNGOCtlFV6^7wDl2-yh$f_m}4f%3htNb&KH2&{tSAkD5&h_@vM}GTz z+7|GYAOhyWP+ZhE1DF4MS{CwU9^8#F@fHo$&tnnS9PWGC@gtA_+TYVAXaY9{r&9w*WH)0HSoQwGoM*q zod3e*>1WrR|IG4#Jp8BHdy==^R)!rzWupwuiu%TzjV+CgYT=W znXv8N#@YY9=JSiEO+9(t;+Kmzz0yC__^T^tJ-fei?B&yMzUS?!b6-ndaO|;JtJ8kb ze^k!VL%v)*=*%8nMopiwB5mGNX^So%^6K+ftsb=e$9L|2cEiN^y*E`~Kk@myrdIu` z*X|#`nV{Dk|qPCo0k_21jS zbV%jLt8S`UI`{6CSu08Mc&+%94&~YHw}uVW4sn@ z!na1}&0XpFt6KQ2(J5TjvO8E9OCJR66p4kK?${Y@yguecZrqg?IW|`I==HJGND$w~ zu8*Zfa$`G_@?-R;+@z-bSVdYSmL3ho_>MU#ning37=G{%M%{Qqj3?^G^M0^@EQEO8 zXFO5F({NoZjCeXl3S(t=T^CD1JR!JsLOgqt2I5=cbrMfFIxu!2;t4gS$M~EUhAw4y zUKdM;e|!487wjkcyl3=Tdo6UhaaU@jf2{15Yh%gON8EB_A0`cm1!1Q?otp;47O6fQ zGk2ywH^UG9?dh{CSRnd90au^eHL-NWlM?9{E4zA4EQ$KSEd}~~kaTP;2s`6Riyj+W zsQRR$Owy>&RR|0J_Vn2q%olxj8hw!08Hgu2QV=U!aZM~tec+aicy=ch#)7ajo=#1L zu}ak^1!dBS`YeMV{M*xKPjH~ollsSkurr?2 zX#dy()h8Kcl1hE>U5d{I?dkJjaDeFZq0t9<-4pSIBLib))A3z_`oJxWc-~9u7YoA9 zcv71B#pbI%Nhp&P>Vt1rA^5ka&j-O{MV}9hKFI5A#M3!4AXav29qJkMfm>(9vn#0} z7KEMg@P3)6`h-y?$_fpF%4K3xk zH(OpE6x$GppwGE|SI$d=V)+Q?G~E!Bekrml#(pUP{JMQpD&(+l8Vxz^^-qkSeN@XR zjsN&OiJ$4t8Icz&Wc+x?A^jENWq&2{f6YEC9dg)bIgry{za{#ko%HL^bW{I9s=xGO zh@btKr@!=DUwtoTKo0w|Fyyq?pNamEuZ%zr`^qfH zX|KN&{UOJ%KhsV9S#PPo-1~^1{imn@*XTp@A&2*WPssTu_dnB3{aJ6n>i$1m-&zPc zy#KQyr$WaI_V`rvZ|DAJx~V_w?N{CZhwF0(K@RW#2;_W|`=9Bi{;apuzoYyAaD8zU za(Mr<9sMTvKhsV9S#PO-NB95X`sm@1!~37@=r_6lnQrROdQ1H~y8jQ?caMS`-v4Yz zzsdd2bW?xU+poI+57(!Uh8*7iY)8Mz{m*n$f7aWty8jQ?*Rvnx{m*vvo813QH}z+| z{i^%_aQ*+mXlQ$@GkwS5#sMYK+mrtG_k+DT7Qkw7j9+fqmD+U6E(dfvXpZ|c;Kt{O zEV`r3?n!s_9ock8A2tqY9p8lX@>vk~^xke)?@o87wgf(!y!{k>f0)#K^h5v`WH-W3FTK~rP8Gs{` zfT%d6he1VTQqjy2@Q4#CB92+0fI=Yr9p@owhv zgp5-!mn>?2d{PEYdF{Wnf8;-%m>#Fod0CSooZ(Ja1H*& zpPh}B=|8q`4bHXrLOg#j!}^?KU8VD%EkzjX7`JlVk1Z^FuFES6zG>mu$8|Z^=iEcU zb#-O&H!WN@aE{Zp_8)i`f0J5&e-HlO&vUBvch^<_fJ{td;e%@$yRQ4b#aM^aE_HCe zvUmN&7GquBwf5^4uFJVT@4D*i7OtzgW}u83%MhnO;&T1{Ir0()yIg-eU?U8+%CI)) zxD^Il9Jd&saXBwxUc#WC>vFEixi)9ruq}ka7S{|MuT**vk8AJ#QPIuEkr%GLStneF z7h+v*tiM%U=w|x44rhIF9nST*%ii3~bu`xq9EZ~5zHjFGoNMjRq#n4|=9+sU--Tcu z&M}Aez%hq$Sr43381=w4IM?4?hpT!(yJkIbeZaX!IO_rNxXxxhoIu*S&JIV}aLrwa zHF!A6##nFDF4y3kHyHK6^>;Yy0qbwB!^2q*C^N1ND5K^Sh|?c&xz27vULs(Z>uj#K zBUleugLC|dfGv(6jL*27A22Tw(9iWZ*WO%%t9n5BMZgx<1)Mji^dKJB*!_paHh+n{ zaE<*u>VfO+Lae`ybvD=Cy!W#nxZYOvfb}-l-C6ciUi~36?&R6~!-TlA_6OeEje2OW zKXf`vf9PcD51q{Y0e0CRc>gx)fzPQrnfgPgv-JnWHTpxOsXs)T`a`5of8c$Zd5Jtr ze~3I=f0)z9-5*{&OMl=!xUK$>ZvWn^Ke*zW&)y$O`ku8v@E&W_Lwo(9^I7^sXH$RZ zZ0--R%l^Ros8J8>51mc@q4U}L1L7L}p^K?MbTRdZE~~i8KW)=--tX|0*HN_>!{;7``&4J%r_A>i-c#6b zjr)pmPvQN|xThHR6ONt6{lwgN*yfFUh;jcg?j6Q`!?*P&+}>Es=bjvgRr#3aC1-0tYTvrdNsRWxvBnsG|C9E^@%2A#KgQVkpR^zI z82PWZAI=ed+YiS8V_f`C+7HLQ|Fr!WW7>bxe$pi!yqBBXkEY#robASb;5Mv};19b^ z&Go|=j&>P|aK2xN0?&eZP*3uq!=Aq4GtTwxIV(Qn`yqS5iq9-)i}uPDpJ^Ree1Wko z9Ajc<%%#J!4{h?pydo?S>k8j*K{&s@)#^M|hIeQ^M~*$F=KIzKr$RCpoVs~U;i*RL zWXmz<$(GO3Pqutsa8m6p%00TUnfu&sehmE8CC$fdKegm!IGeG@sHG$^vgPyOq87$I zw&kMc&ti4nMc`coUSr~-7RLJw@jf5x9q(9nfr|Gz;x!g}$NQ{op^Eo^gFSOu8s*3^ zqYQ7A@;jM2_Ly0gnsOf>n=m}v43 zm}v4}G|}WAGSTF}Yof{j&_t8pXrjsg%0!cY%0!djYNE;i#YB_uI0rw<>G=;c(d0*( zXvU8+(d5UOXz~+HH2J9}n*1~qO@6wGCVzs7CO_Lmlb>Uv$)9hc$uBa|Le^2Qr^ zXPap9H=1bj?={gN-L9?uU&a|3c1Ur**9f2!eSH`X-Qj+)8K4WWVdx~zg&?g>#xTkq zVb~XjO<^F;+!m(q{W4C+b?@>zi}+d9sNH3Dn6!;^XQ5qBTl>Q5-Q|J2i3Z<&VXioR zUsrqk!WvDws0ztb&Uatf+2m49aTxJza_Qh<+g2rI=qMMhd)2RDHyjk?+|Ggm$Z=Di z^ikftFDwsowWxHq9~Lj`AJwdAv%Vv-rbK{m*iA|EK4_u6ePQPgmVYhpZ2z1ECoAVS z&RK|gBK{rj4STKlAFSAWAEv1dNG@mlT^8@78w3-^k3JLI>A`^D~^*6m5| z8H>7h$@|_zFd(4VAZo7>8%$8aQ%;jFQ>ppw9 zocqm={G9PD_nhsX5q=%_oo)SO(Kp_i`j7qGhxYufTSjp& zTAxP(Z|8oriWRm-?n$dG4-MqLv|m!*$l~6#zJKmJpZn9kPIz%1_o#ic^Uh7&r}lB- zlQ(g%+Lj%cjpTl{&!6~uJol`P7_uUg`__tV-)3{~nk6;!8SYW^B!v&i!qFIC0A-+~c-o z!o5ei&#iFYpI_o$x4*8*_>}wIsy{8fjC9TK+j#l`20-IF=`ultX@ zl$~&O@h=e8tdV>2e#3EJUZU*Fy`~d91^T*jDe)Wfs z+i|{#E&cFu?#JqocHL16!UKn0chpgT__Lsq*BuRZtvuRc!pft8*(;CsyBpuCLr450 z^+#RM1W#$gS3r}St-j`sr{55ME?{*3{TBs6ZhqkrQgn-dyuxVL}f>a7WQ zzJ0s;#yK#3b7NvX-bI2=Mf_mUX^0<$vo@TS$U{BeQPv`z>pC=QIj~b7h_xN|mVmF} zY!33V=i@l_MOEURBI5U~)%BfT7j%sJY?XI6I-uKLyQT3C?YvLJpx@GXi>=Rn^+)?Y zQGe9`w*HNN44wiTQerM@y2O!js4SN8xvf3k24bA0%ylHJ~}wI z@v*USjcY(}{X_lHZI9L;U3*vm#+x2aXxw&R|HiFPBsAWHJgh|?1|aQ;Nc%FTZ&Uxq z<B@f)tNphI8n zs%>t0Eg<^Tu65tE?5cmK<)c>$PwiUO+_LLV(1(kfcRln@3ug8$d^W%5@XVHm+Rs{^ zzJF57BYUrEZdmtmOT((qS{~bbWphLQdo8sGmp3=u`EkqkqvUchY9p=uVEn&Ld-G}p9 zo)Wtc!|qeC`;^#y3U;rB-KSu;;pq65r)YP9Znxp+^p<`2et2tqm9o2ocKb!2+CjS| zmp1PZyE|Za2kh=Rys&u(>{{`>nEBmxct*<}vHKA0?t$GsVs{Vhu7KS=u=~`}td>2r zJ6*T?)X|)lebdLaY>m1^+1*aN=SH8}PP=oKHg6ZZ+hKP*>~252pm{s&+ER79I}hi! z>=wJ5VRtv|?iRbdVfQ-N-3_~Yj*e^DO}iPo-91NVx9r3B-CG@%%5DSgj*mXoK)Vxa zP)B^2-OXl{UAd%A9S$KmNMyTtB;u)7O(cZuCyu)7j=cfs!Nqpp@+v^!9@ zyZh*@mVE=qwroXRvVNbU-PzHno}yjU`BP%|DcF4qcAq-DxcMpA^~=%iZa6-5s#I^Jr$v4%!XZ?e099 z*Rn4>qh%}Vl6H5~?q$)ZcGE8Ee7D%$4ZFKxclY7q=H0LxP^sH}>hP?V?P9kccDKXs zcCou1c5i^)?XbJ!XhzF++O_C*cO0G3vJYn*Y(-ttuIjrt=zaGI)cM)^ucKDC+g|@& z4ZFX)|K8nx|Lw3&x7%L-y%BbQcmI8){r($RuiI^}|E_`E-`#(oYQO&mHRyKR>%TX_ z?(gouue9HPgAeF-+v~q;VfT0U-*?*YzafWoyY2Pgn_>5N_us#_-+x0Jb-V5L-&%X_c?(gZp_5<~wS`N%V_A%Z?e_a1U3;XcLjX$+~jCatP2TwMC z{Ll+6tvF}um)g@UKN0I&Tgn}&&A&AM*z(J&(=ER|)Y>xXU~4mFI2M$F$NM;CITld1 zt^4_Z`(EDOeVq2%8v}mtJ^T>L>JZBcWBwtO)ghFX>tJ*9p|;8@evnsLWgq-Wl@;d! zW#Dlhz_Q{zpd2*I%6BgC-<}7wHwU1-_QsFjd;fm}W%UNj3ipdQP*!iCtg;TCYJQ`w zvYL?QRaR3E{-Vl?bBHqVIEP?aaSl-qnq}oXk6_x{8-xCpIYfK&2ij|I?D@TOha)Jf zBP=V-8;+o?j-ae29Q?ldNLyu9GSsWA(hvTs%8K)kGVnP6U|DhgQ4X4ATQ%2$Dy~|Dy!AQyvmB>ntQwg&uhE_{qK%f z|H|CuzcF6@-Z{&=D64m6ym}X9^)AYa29O+e79M@P@YPR*{}{Wr#| z-#gEG2>VJnw+g%I&{tmon=r6IGn{xhE&q%Bf7&@KwRlN&wtWfp?iX14d-!LfjEC^DZvkf*=uYSRnP`JUZ0kKJ z{~rn8f$`#dP`=Woy^{#wd(R=D*Ws|2M7(g*--GhMY3uJn+j`T<|39jZmCffranG-) zDk`qxo6fev^>Z{djd`~*A-~hL^{&(D&apTLvlhDO?okl&k^{(?poS~m<7zG-3 zmlO?2E=;aSaf)-l>m25E4oMw|&_U{D=)ly}p?u3ZC@l?Jjp*8c*BLci8FZh4F%+li zhwav)=f~KyPXF-hX}`%9XKaD(+tq^$3v81gEO-#UPYc4HwZx8F{OgDNHZXQW!tZwyrZ`4NA0~ z7&0@$p4k)}6W*HgY7EjcFgvr!UgUSjd)e1PJ^`|k^&=shyu2zs+Z734YT_9C_@>}~ zekV?)4M&Wm<>9RZUd?O@Sp3=~|GNi4B4PQeCYyh*t8e;+>0|5+Ni1WG(U9)H+O{R$|k>nk6NP|x~5m8hqv~7^+MNRNXM6rz;EB>R^&;y^-*ij1B~5gIb-gg z>bQGFlRaROt9Sb1^dYWMkd8qrVo|nnWz3TvE4;P$tBe(`Vm&&w!`+U$k6PnuN4u_T zvIeB2r@3ass$RNuG2-=5@y=24Hckz^8~F*ya`j8kPaotO4(aZ&*0b!R*7$YI z%@})lYp1o$VR&m-6|Z`yd3BggW|koVun{7h@=FmYm2V1MK&aAH$HKzOU)Mq5*0 z;2O~5n>v(Eop!FOE$i}`h-2S2#?E|=Zwl&%Tm+4WWO%D(xnEOI&`qExp{_q^b=?0K zSDx#WR{Q<)UC2YwJ{R+q>#{@Ylh#x9Hz91E3%#O&>3!b?+d(s2K}~+(z6-8B=zMUU z4b~Gah3~WGgJyzj2loKD)}RZ(O>MB9_-^L=N`D@>R&Y0iYYUnWuA{;4#4gwSE|f!1 zF1R*u*MjS(?DmA+L4&;QR)R~r$6Pa!@)Fc_OCc@qLu`9co@+qkvdtI0GwZ2WzWAWh z8TZZW&;IGjj?2GGc=?9$ow8E5SnkaF=erwfOP~C~b<_TL=HD0-zV71NFWK$woV@iaB4kmU|Fx4Z45w`>+#*{CMl$sC36Q`0Bn}bQij| zeOKF)`a3E8w@uQu4svb#{<@L&6V0;p^CaqbphSjWF%K==9@H7(fkCS$G3}8` z|2(AK78Hqazo6?Tu~j=!FKMoMDi^x`pnL9hT{YQ$;>rP?n0o6yD2E^`a%Q{DwQN!l zv}Zzlpe+IUT{?M9Q;=WaiK^TYu9@jQU5T!$$@WcFXdHl8fqup5_qw*a$|qYlQQrX9 z#Z6X(%>Wl8aDC~Npc6X_XSxb8E@kxQY<672(zn=TG@7^RRB5%YNc#UB6@Yl+{gk$5^z~1lLSu0i|9K8;&B^ z>ZTwE#)t!%u443z9l5aJ*osh_BYTPqn&N9|VH_<44{)t*vIdWz@+rnDYDe0G6A)$( z9y_HFvZ)8AxR`!u4oJj(H7H>8l;IeyMQ^}XSAP2NDI;COr_FRxD|Gq~aLr0Tcgjv! z7mfZ2u0`qgO@m!2hA#h+uIrnE{DbNS8Jher#F#!{Ds_ye7QYKo*2ylvk^wGT!MKte zO8U6^xn3;sJMn$r8wz4vSq0A*oc`fYf9%-s>=!3*)t|%89Q^sszkmMP(df4W&VAvAkhe~K9XW5D-etFMY zv3N~(!p&;l^kgXKO&NY!p;?hxT0+(#YpM0bi?-V{t#4$OS_WkST*ar4@Qj{5c%Ho-=;eTW*t0Xw`aLB)qE{J>%1&W3}`($lrAIK1(Z4grS-W)07Z&w9>6>CvvwdZcaNRtyW;z^oW0YjL6+ zuT}Fy%<;C>D!tDcbVF_BZp*h({%e-h#`u{Z}*b`QL$lJOs_JW*L#GT;)>mniy@6PG+#GN1}{m7=RoRDD{~J#awv zMb(O~K2crytg45G$7)aR4#@gL1M4C1X-D>Qm*w$zRR-r}4MG{|dFe0Mt>NUe#x~4` ztx>g?VACttZTPkPh+j*9EEL`ALj+pwex>C#nk@@{+mUlAY!4U#LA%AD|AgH3R|ds% zJz=*vJ|$TFMk)wc#D&?#^e3u_4!?UzI0E=z{-EY*Qg*)vfS(=oLeduhn;7i|1`gmB zOWPpOeksNDev2RfPndiE%?OcT0o}w>;YrN=Lm3#FF0UonHI2s zf?)wuOT-)L_yaTrETp2SfbykFw17gUc8=D8lBoy|yak?)TF^QOT5|e;pi9JM*;oU9 zFjhKX&`TG>#nNaLZm1>K>X;vDnQlo9wd7c95Zuwe1HWNY@MB?NXsK9TSvLL*&EZPR zz0_jKiAYlt45yu7rpt0Ky^Pw4Nw#dXV)b_q$jA)MvWbbEgW$+aA?`xmMvfKYRU{|U zB}5=>MwSUNAqd2rIjNfEKB^dx4a^`13b|M(2MKwDP7W6G5uHpE@)ey#StwP1*U6zm z24L+7&F2c)S0{%FIZh|f6S4?orwPoZQgt0k{_jPd{G4R2oAkp9x6^ErbOzK$ndO3A!8-)@Gw}A3%_0<9R5;;6enmQoEvO_d!NhYS!31M3Rd{*%tK3R{4dqYdq&^F(zB%Y=zyf{b{Ihrywvo!qFm@MBFM+D98*!t;!6u3AF%}LeHzHaj?axgcp_8tNfsKNf8+=%(+lQ zBZHNZ@trm89F+4A#VaO-vK?w+;T{L2#=Cza+Bs#YfEgCnKzBae>l%X}mR%Ust5Vat zG7=M)qJs1UqPUpt8pIebF)}?d5UgS>XfsAgt;ApDjB*|#bP!)u+CXvG8)D_3VJOrwvt$SV*Bui zW2F|yEUGZ|!~UW(G)uUpPiUtgTWF8anO(yzVO>$q$%Xa6&56QAUL6GR#-G^)cQ=ee5QkG3p1n)=SWHqJH!J?z2YjIE<* zf=;;V=*iZJadq_M>csdudRFShggScG=)~kYdiLo=b{#zjbYfZ^J>Tm@P8~hT=-M!v zS4YnrotRTc&xJa1ejPox=*0XwdhXDP{5pDG)`@~TdiYPIp{=lvo?mpLsE!_gbYO56 z*U>XnCraw*8L1N&*U?j?6J>SuT%;2fb@Xh|iOM>99?*&EI(pvKiJCfkKGccJ>ge&u z7zLxt>gWm8i7V^q8L1P?>*z_>iEHXulWIDpO-Iov7mDBIxbQ(1fyEr6Rcq%)M#gpR z9qa59txA3patMhW0E^B?flm}wsg2DR!EzXF(C9|;Dn!v!7p0Uj2KA)a(F z$YEC!T>vq-sKX?|pf_}hM!;8RN-$_R272ZNFb9{94hHSjC0+)+swA$!$@1>W3YxO}WIs8W}x0_d%023m=7Y&{XGZOrNkU>^(7s%2B^VU1YCd-;fO8n8!=!^j8+3`s0DI1qV34NjHP-VeuxoSN#uLkgz?jymVS*rESoDbm5*hhjviK=bP90cHP z)JK9rPv{cQ0A3V{^E~NbP-oQ;`lk-lMV)Ps{?B8F+jta5)3+~OIXnW9I9=2>0nTrY8$yz0l8;NFlePNu^OP? zu{f7hj&sl9xct#5muk^<^k?BhTO&-s)l<79;|`1CboXI#mt-nWdR+7+>B<-Fp0A=X zsdNr5Ll^xEaX}Yhk@C(Yti)y0)^EFpGuL&vj41Tqg9}jzTtPxHVIM9;X}IP9JTK$& zM`6|=#q=M-g;FHEp}ctnj+%(F>l%7martYPAyRam@~aM!>kr^D9LVH!Ba^xAOy)=? zDG{n7%qAq`g5tf`;Db|bxE@Z>=hN$-xrS5dB3v|hDGbtIj?1FWB2?mn!MTRPd2WMq z#2_X3NCdY8!Y#P4^gx-TcyJkd>EDbCdI=BXg5C=Zy%)Om&KJFu*rFoLCh)ESy)I7Q z-@s+)rT;@*&`bCj7xXSL^e%MkEfBqwz^9l@FM)Fy=$*jHe=sgXFa2F`K`$W+7xWez zdKbC%7KvUZp(4!g3E;dLdb39YUAX))S7-UspMwi}2^_2}+I%h}%5WLh>0hQ;vj|t< z>Z&c%(5%bdhReh-nO7^>*@O+aU^s{CkH>KNBOVRYzaJM26W&$cIb4h2<2^`SiUtr} zM?VfUg4ApR=k|!ebx9Xo{@UeAivGTeHJiZk)S}Hz2TZ`lOk4q7^v_YOd4yIqI?N_; zKH68i-5;DQJZd&@P7iJyhIO#N2)+uVGg zPAdEcH{Yj63V)ZI@6)k_zt_$8>0rWt#?ANXC*-4=(v9T%G*%Y|83ZcQ8T9ElxjgukbKtk# zq#CNHE7eRcDv)4GwO$0Xlv4Z*!lh?q_AT() zLf0eQpuD++)wo26UcK<#lVOB_t1?4CH&g}f{VY%ym~IyEeij&|Yapyp-kF5!aUrdi zI(pXVgjGFzTc;DYI(npF?W$n!(m8&0^xUHp{&n=!>qI~uJ)3pHQAf|iI?(pCX9eoRR>TRu#zKe9~9j%VOa-Dit ztD{f1?{2aV1V!LNdm=cq}p&^^GhL)5i3kpk0%l}K-OvQzwl7yyIR2G+4SC?s;+6T=-UQ#r8P<~;>k|h=8$t7$c z)ip&$#f#v_JvYDR^2*|B_)$j)$EFMTF{mwEP+bfkIxqDo4+cd<#_;tw%@UmyozkaA z^r)24SWBZeg>#R^V(T!{c3HA5(1|@9mYBNR66Ynx%ugttGGKC2bW+Ng0VUB%r2}-| z6yT`Y2utl16P+}-cXV|Me2bG(C^RN?+R*$pgtCF*-3j zF?AIAD-#(bCNVW}O41;RqzzND~o0}BfJ7sZiqzXSHQbvhSk?O}5Hqus+OopxF zNL!`ydAQ041=KQkM9So(loBLyM9R|G1Vd{-;+qn8n;K&o*(YV- znY3gf#=+7;csR(6;sJi=CM^KDsH|c^O%leuQPmZTY8F*8sB-D3OBYpMIyk9l;84&t zB}(D=e;5V=ahE8d|ip9HVAYQq6*e zWyKUJEyp-pjKOwEY0apiX$a9Xmc%rJ;%78T)lkk68#ELszd7vE((2NMrDdfxmyaqb z#fVf6xeDk@T2!@QNpVtT1q!K{%E~M7AET>E3z4<5(goG1VbjouI^?}0xzJSp?h<4% zyDQNv6nl+QHT(?Z&mjH`=1&@bhDb~Ciokl9S&4iVYjRg|SI@-q(i)99RzLZwS>az? z*A(aD-ldHnJ9fA;9@W>MwTDL;7(#I**=fApUmhA9qH(TZINn_|LLDoucvcf<1Oj>Y z&J2xP*EIJxy{Cz@Hf!wbFl;-}UwzY^$k<_6*0lSd>8k zU&NIW8n)8D%62_v&AK=v$Ow&G>9@*$z3m2YGeehUaQ-jfs>Q?W{XfC&5%x$+XG>RG zl%<=cyS0a{mp$e;|4VpH@v<7P{}68c+wf$Twkp=-jNB>75L>V?nbIZ(Wp!q0(K27A zPpmdOdU6{Y&MxS-E{&kAgc+Gy4EG;z)yaAfNlrU24FNP%gz4Af{L=D86{v6JU$AgtRq>@}Zdpa4 znOuMY5wkyY(3v3|g$#`tBeZ1BbBfXHlYRf$yeAcEcxnH?&vS}uIJ@@kX~R!E^MBE+ znUPz>#;KLb@qg3fsfNkf)eAdMAIJ2|_8J=y>l|rHheATt-phkPj#!+ z`F!oBJDq%$#~o6ei@Im;jM(X{SXfmJ{$J2nw<^rG`;n4f#Y#D ztk}Huap~r9Hm^~W`aApR!zMhFv*8)7w?3}AJkF+d^APaiUo!jX)G?+O*z2`g&HA;{rV*%}5UeP}CF+Q}XWszai`uOns`Oy7+ z=m9=-k`JAt(&MQ$PtGZ5Q!83e6q{OWo9RKS#M#Gq&x^3yHFFNA*PJ5K>9{D*dtrpN zgT}{lq#wW)VGYp=fQF;|VqE0&o)=+_z>6uJeo@g~H9r0&pZB>4E9y(1Ma0$cJ7Mzx z=DrunlrBGC-2wCUIZ=LLWo3S4RchOlNz<@znnQZVZ1VLHmt&{K?ih$U0$lrySy2;pxSvF>ndSgaF}erPRZF zJM|6~x>D%nLIbn}esoQTc$~uoo-6T3==;?IN9)fuY*Yr95ThgIStnLhd@yk!HaQEj z*OKl=OwrKlfvK9t*2i!rnV2D%CCI%q44)^sKyZ;@wcr(k*9xu{TrbG-qMl8HTLgCs z@`(@meB(eIC^&+M`pP3Bv2%sKQux;rQGc6+euM})ZpR@0QNmvmny=0n{)r%W`H=om zkgvo@cNUBj94weAI9;$nutJb;qZt2Y!Ht6V6Opg2LN^G#Pw3}_{YUB z*9)!@yhrdp!G{DN72F}XNANkp7X)7wJS6y@;75X=3pNS12>u|*8wAs37Yq>$7wj(B zOR%5d0KqiDVS*Wg;{>M)<_exKm@il&SSGks@N&Twg4YY)DtNo#M!|Z)M+F}jRO1iw zw@>I71YZ$6BzQ#dBf+DB+=R&T`9|;u!Jh^3{7CT~g5iQ{+(NuwLdOUW5KIvqCOA@X zoZv*kIfC;A3k4So^3^BPr^Y+rDxq%_RO24P>xF(qP>p{G=etqHe_l|Hd!Szvx>4{m z!4rc25X4h26`wEbsfXV`5W@xI1mgwOcnJPrp|b=h2~HQBDOe&{CRib>D#8twP@}_^=>%)-rwD z1$PS`6y)}6^3{C>_>Ry`g5L;!C-|daFz+jn4-@3KJ*4@;6_K9=5eEsLCpbzlM=(#2 zAN5c^UyxfMNOSux@hZV<1@92#{yOsO1RoT9TJTvxeve4GLxS%JejxabV6)(lg8vi@ z!=jJzxlx$dL$J5tAi<%6qXaVqxe=7{<_P8s77AV}c!l7#f~y2K2yPU7Q1B7KeS+La zN;@wJ{#lUQj~U)5_;F)5-bs{ z5UdvD&Q!)*Be-7hPQfjL+XQzCJ|*}U!Pf=f5`0haE5Vb3KM4LT$WK&hKUA=@U^l@; zL9Rh5cdpR>?Y_Gj1x=}94I(SFhg*HV76enV3pwIf>#M%FStfSPmg2x2E6#QE7 zN5Ovz+OZI3e{cxm!&^mn5*#l$Suj^{mf&K+iv_C$FBQB&@Fv0A1n&}jL~yI%4#7Qw zuL%BC@D0JY1^+I1Laf3gq7)c#Gg|g7*nNAozsf4ndy4!1zsq-wJ*w$RioZ?;sc^7%9jz8pzKU zoFO<{kcT#qf2-hKg7*mW6bJI(5PVPYBS9Y4z~@Vy1$zoQ1$lY{`GWT#xECK zDtNizwSubzc~A!B{~%Z|xLNRV!R>;31)mXoLGTs9LxM*HKN0*?uu1S6!S4ir6tv?( zJJaJ3?7D;FjX*3aD?C(K^`5#=gzr;a|JID zED|gcyh8A5!Bv7c3a%5pLy(7$Q2%3s+XZ(EJ|lQQ5X*MWI)Go$0`bfOT|tfCP9pkI zJQ0DZMC5xI5&G#!Y_99F~P^~NmD*Bbi3`Y7Q05;=R@C% zN|XL$q~{_ZeHvci#Y2Sk(G{0bE?0{_Bc79$Z*pKO$M;J3bLWF{EEnpcGxD(kLgw;| zhh3xHcNaOvdtKM(u7h~!W7-U7=;Qk;v%X=_=Y$YtITjoFcv18j`QY;zvjbZ>ewT_r zcRnb`^iUU_VfS4KneEOo<)gRAG2ThY5smSx2>O^`!-1`w9};Hx89=$EMkRtacoxW+ z?UumqGAL($V{jSy<$ENK zm!VIc&Ij6Xv!E}VOmT*-89w?}L!U8TA&OgHp`?#Ix(8D5P6c6xqds2cK5{b#o!Jg3 zcbUi;@e3hmc1HSc@{uco+%qOYBTF|x&RlPMk&gn%v0RvDqg*yX4$Y_%LCQG?V@+xh zK*KJYk-IIEJp)2p5Z7>q9MKf4{W1grFh)36_o{xtv>AN^UhNm`1-gzNafUwGe&s&K zzx^}(hYtR|XZR;hQO5jOCL9H?z&FuaN#%G_4Gj&owI+YM$zNOQkl#8 zyThD3_0*o_*sh;`8uqNt+fp00+n!}B8N2dP(rCsOFC`uQBq&BVZ2jL zkkw;Rryeg=v_1PpSUT;Q`PI-HlGR~*P|5jEUl!YMl6Lz!&c2h2qOWjW>7sVcnbBx1 zxhHelNzE4cTvkc1tg$%n7yqN++c3)joLM`g6=!m1X5#n9!xxvlxqU#%yQO=#hi+d~ z5ZXw&f`Xi<*T!~IdLt%hxb=2!98gkFQd;tUDW$fQIG(mRgBwqjXajyabUyOppH*L= z#h*H?=P5PI+EDrIIuyojxYBWD;-Y)Zw!L)39&wxK~ymGuPTci8UEs9Ss1`H<|^-Mf5IQ>D1~GI4!p&3(2)+O8x#_b5PTN{7ZNfNGNB@OKLtfZy&RB?##eQUh&0L%6l)oRCz6^a{BHA-zLv@H<03KzKB= zwh>{W-0#?tKL~hU{q6!0+GqrKR6e!R>|p;Kpza?zi)ar40-uLBqBjc5GLgBmyhJgaf@_(m z+IPeW#+|HKjRtG7&f?x3%Q%&6KBiEy#wk`5Md=`c<7T4(-MDi|x$d_z-gq`|I$b0k z(1T{jQ$aKtQIB~kxqwRcAt+NZnNB)A`W0lpg`h%)_527wmZ|h|Zf@Dg&eB7b>Qt8M zN(7!mPCkaHUN|8*y%*2U?q!@0+?{s~OO9#=@I{i^=#Mh$t#nK$;~@k(sbe{Gd0QRH$|z zp#?G<-RB^EmO3MUT@c5z@nbOb{M9jkhasZ!SI7KuzoIHT7Whk$6#eHgF3TA?;u+Ei z*3XcR>aTLGX>*iv9>~@0JOqt_qHZpDE~aN1JRG_D&VxrUr+)E>zy@}S5oNCtg#(F- zLQlLQXNns=67g6}s(j5w^f(x?)XI8}je&>7+J6E(MoD$IB3qWHjY6TYW#f-Xgx(UL zR!s!pJNDb{_N_@1p7cK1+YUVJKJ`Iv;&SH?*IISTG6m zP_CB!98oJl_TVAsmi-)R)`RSi2-J__&OO7zcZg$o!LSgcEIjYF@B%IDpoQnjd4VnV z5Xl3mT+0g-{1)T@rfe?=k9v05*j@-`Ps9+(`)K!OCi6AJSOkJB8`H6{(X;a!jdg@# zHGI8BTS=gFTd&d9RFG<@U>T$!;u*Q3*=W3x_G;PPH!`(v8g@CHSvJl<|JKXxO_m$C zttaec`rc%@-AwYBipF$oC3y=xmLp8ZpFt+7%00r$wXW9^S25}lwW)NyJxPsjZ#@r1 z*7b9es_-$hIaA+9I z(*Cv&{cw63hN3O$Y50~JxRuj84b4ge!=Zssye!`t8dMrL@;;^hCyM1e*4%BBOnDQ& zweYZ`cciByBXzt5KU(S^@#E;lP`2cbtO#vjFBDscxf~&Mc|DZ#K1Z|~xhby=8V<3* zu@(-ux=N*&<~ph$RX&4zh1&_Nz;-Ru9W|X0wE&bH-;2rhj!Nd9@x8V%b&u@=#A6p*8Ag4O}y_4sd zb<6}jhpb~3#$(8N=6Fx^+%Co;@Li2V;Bl1tK<}g9afJFn{qS^eLtf{s_wd-`IqROI z)R87H!E?NhT<>K%JifQ-xOAv+nh$u7HVAaewo-AIeoB2T#5Da_`Z&{R>(JK6$Ti<0 z^-W`r;OQ5HL+m5`S={lu7ej+?3N6=DYRu9AJ)E+MCJwYDnGy~%`5Y<1IYD#L7E`=W zb7%Zi?=0wtzYjDA>Oq6tK{(c44;t*PjSU|Ty;sBeIt2E-Gmr53|3CoaCDTCQ_~D%f zhG1(C1qhtknND5;rJ*sBOGsAUJp8&HhHr8SoT(x%0Y%AB0yXL;=~FW&&v`=#5tBLO z#^Hhn!nw+uL)fN=5;(E+PCo+Fw5?Xb!(fjK-giF&l@1U=eJPqgXgXx`~!p`aWIQ7bp1I5*2Tomv=(99&jJpAtv zunz3s{I8szu!35O@A`{+vlhKza!i#c-q|= zN4OcU!O-nIhqj@GyAN$c1-K7wLralE+pr#xnCd7ub&L`Yt->j8(6eMg84g;3AM!Yo z03L`JS5@gAJeE*B$o8UUu~@D6F#=xp4LIl<@E6~J*BD^OkD-GH$Bj-I!|Pfkfs88gO<{UxFdN{LQV=Z6`3nh_^f;-u6KoN8N|YzubArqoN=sOZ#D(G3?3 zC23ohJZf^vs6JShdJ=M<#o|m!NlEfD^&kRq0$GYu;`C1$9i1{c`uWMxIN0A4bFYdy z$~)$>7UauI*Ygm=(P}Btqvv^rze*c8G|ybJZ{ldRxSr`LbCuzd>UVbP?9pSq%I>Je z(kV9DYCak53!Juhg(bF+m$t7Ec&R1U*1_o&d=kM`2oCWMK4q~)D!FmFx%t@>GxNtz zo0_E=#JI8QMUL^-r>dBzU;R5LuzB7cX$#T%F3#rxY;H3Xrewg7B)~Nz!#H5e2%0e2 zg*2V{`pG!OO|@v8zmdF_$k^vsD$`+}mPd>LfhJb}*hDo&24l9Du4#8UlS zv*Pl_JWk2bKVwF=+b_v8SaXJ?o~P9;smx!vbP)?)uTD=5c@-{&XAL%&1fJ}BQf0g# zG<4^p0iYtin@G;&u`|w9k#Z)Fo2w4QGvuMkolMun@#ALX`JA9f!KpK+uzAmLOXg-w zb(s>O&S2qd%KvxFp81$P^YMm@$`&lHKHDLC(xz0sdmWo648AosH8|Yt(SgFyA6|Afsx5dIM(nRA=+4zV1Gdk!=bMPbIPV(n|K_N_OUo%4&^t z<;BI9`}Xe4iPJO+8I4zO=Q2{E3!|x;GFXJOYO5+deVmPUn0_#z8Z|iPop}tT(T*`5 zlrE_(bGOj3)28Go<0^$FGlgZv3(E0Ewy2vQBh?&)Y33M zWA2PI4ngFs*?b0~F^lFbm^0r0gysy{m>p9e{l=M!=5WsR+Y0AQ-w5vszu~wN$Ow(9 z^}p87eO{um3ZRT0FYG$|O4};mvlO{%khm)hzBw-aIET?4*PKq41=4dJb(-UF#c{Sc zT!k2Uh=bp7T$N;o#@7a3+hK*{x`36xbxx$Y4p^rD3e7sq7=)kyjb}yr9Pud4TXpZY z&L;HYw;fj>ZGI!N2(%qrb*kTptn=HBYaSZgIG0hST)}Hp7?kM|Lpob zIw<3-y-=V2{f2%+;4Va6@;+h)APe9gGGNwr<+ zUOTCN+l*Ti#o97+#u1&SYFG2l-)NXdI`oq^-P-kggE2d6tEhY=&XR>Tq}s62W(GV_ z^|a~b=sxb1c{Gc(QOr8~H_m1C=r9ZUB+xxOJbNj4M1Hdvyv5ow^BV=B->1)3lX_N7 zGCtaWLvcH$+h$Bz6kVVr2yN;z zZRjv9$IezTULqBoy(PD?YE2$8bntm7TwMS&%Yn%Q-DKPHX_Wt;dD<=?EqmO5_+c2B*4l&QJ zuxZjKwhiy`y!C~8jKSCbdAfY`?{Pd|*IS?Q+*+66`MTceGtWqA&v+hg$anS8$CpPQ z$Mbc)_2Heq$=S3XCW`ud`sg#y#L4gFqmR3EJkF*$Jp_E_^K^Aav=2YlM_;TDpPL>$ z&W8Vy=3Rc=Jm7IQd{^L|-*_dz%`Fn|^<5Ai*t$9N*nD$~6U&2K` z%Q?c@OM4e+IP$+R2q5XNaZ#Rk&Il{+FCa+sxl#lU@$E!H9Oa{Z=y;LW<0omugl0>R zuny8D3C(9j5!Q3n8Prt4nMH(kq;?SranygU$n!Z;gf(5eLuj^_2=U1;k^oJt#@DU#i=|`?7XOB&7>+Ov` z4?gRJR~EWzK7N*y*+swWbh;X;mO0oZ+jdDRShyDOes~=&w=D4^@rFvcAts z^*1@5hp)yX1G7%~o{Eo5J&#i5z<3`yWzw_i3JrdV4}Xb=W_@DAxf&DkA&UNg2Y{U!4rCLuUWu`nxLp440Kz%jBtJtC zMWJZkgBU(faDm_=!D_)P1g{lDQK)#RDupNlg_{Jo2<{ZzFZhDs>w@nKelFN7_^V)$ zMc3O!Fh($0aJXQWV6NbWg1l!if0qhgCx}-ODxCi>ocspCF9g34JSF&(Ah%~xUj6?9 zV6e~;f>DCK1mgq~1XBgozwkzUbuKtCQ^F?*P8G}(oF`ZyxJa-}uu5>5;MIaF1=k3! z6TC}MogWVS4+za~;ogx3lEN8$4`S4?Fzb>21fd@A(!g6e#0 z=m|%fIECTZO?&)cg7h%K48dF?G@Fu!H0+#haMGd5ZopB0ukfQD}w5N2>K17j}qf? zewyG{f+q!k5d2vX+v=3OzhIbPq#(b3<#^IhP~AU44-)!3!BK)P!3l!X1ZN2H`&sHM z6|5Aj5xi3H8bS5{Js`hE==Fm9gr0i%0WOiByc2f{J|(FB_cFqt7y2+UP1D{II|xBL(@5Ecv;Da|QX;Kg0Qa6E;w3{pOf-Fk|%h+AdmN8xSChtezBA^aJgWuAU_f1 zed8{{O@j9eVmhPYb6mA9=6sXuG>-F5Vn=PaJiTZmB7Ktw+1m`)V4 zLI)A)4HgU|BHc)`LX{s7T(2`9P9pLVCm2see$;&qm`WP?N)sGLgwROAbRzPJtSFp7 zgmAWC4iWjz6P!at|K{@nVgV76iv&xED33D1N+QaoMsOJs%CIC=SW84XtrT2MM0u?h zTt`H?-66Pv2qPN>>xn4G&4TZ6Tt|7T^&84j{hv9MUm(Y~NPMqMM0q6=Q9kKJlute} z9_b{aJa!Y)H0>`$MRQDjDI2YS48CB!E&udyCk9<;)ISTB5@;yPA8&Vcu)o9=Mzyr zYF+?Z%?ptD4Z`0@M0srydK(etwpZw9h$z2d9zQ~J<--RWaHHK&jHH*~=3PT#{KXOv$KnI>nX?`4FU(?>a`Em&j? z-OqzIr|(r$`uHr6a*X#CE_3?k2oIo~k)C6qC}+?dN6pSiAN$+?V(;7It17Pj_s&kj zNy0O{A;3uj7#?{+M0}tDLI6P^2`DIS67nE{yqW|=t1T+Nsnv@0g#{HWwQ517zN@vi zwXJQ@YPD8dT5YA(TOXw@TCe`T-^Xby z!C%!YAvF zevHIn{MaRU#{bJ8vjfB`{8;OSeo&A05R1Y1@dKyaAy&CrqQ`u^&mguLhptAv0EY?2 zp0^#m@xU7aCHjHOSLjEY;F)~iF+f6D76aEE5fA-%5^1!DSPaGwULWoDILY!OTlAQZ z_btRWemsLXf7dg?*i+@;Ew=D*c?$jL5ImFbHwH+k@q_n8wjT!|r#-}CFn(O?l)Kt0 zccSPqAMcZFKMo@8F&risyhj|o7T|I0V0+}@pdRsF5*pIbd*dEklequ40 zazAv+ea!M>is&&P*J*7(cs)(j9@)^d+xJ-u57U9rj}ryY_`&;bI~cZF>xF(i4FT;T z7K8EQET`O8t#XS*kNNJ9a!tSDb$=y+Bp5v2C)$3z4LsHz+hZCI(;hbqp7De0@pdqN zd{^s*eo&A05R1W-%lk~b+#x5%#+PG7kNHxOf!M|mo>wEln_$d%-N74g;T;EM;|K3g ziD&YanTP-yKgQ{DLqDiTdx*tg{1}ah?MI1KE~+vtcY($W{a6e*>GyFlD}2(Og?^X$_}QUpV4}uAN*Z~`AbEacnnV?V*62V)$?4)smFZygio9wHvo^< zaTAOgZ#j6~7T!E48@v?3Gx_c^5dk!Qa6eDPLqG0@9_=9(1MwIpK+pDLi&gFd$W6KY zMycH%4*+k8LeT$=84De}ZNSTe3flv>5h31Z1<&N;I+Y!aALnbm&=20P(GOxV7(dQ& z%6-i8<22D@zT2c+bN==Po{1CB*mHwpUuG}%J>uBM?_{zZ+#;!9?EAK3-?Nr|T$?ua z{CmefuG10E1Y_UJj(y{MvF{_tKI##VzYjAQ`wlzyy=vLFLiCt#A}Y)72UB~oFH7`{ zy(PWaSFZKK_N5-nIRgiSv2PCa?0)*TW#1~%V?KUi(YEiTUhHde>?`ZVzN;PksK;{7 z!ogtd+v?c&k!9a!M34C%aqL?RJcB_zQ(t==`}jMp9nAUh3&%d{v7BmAHrPLR?CXnx z+0377p-VmHE8-eB-1m~#2MBID*dx*mF?j1nkiJaR8J zelF?{b;WXm0n2MS881cy8E78^_ZPPN%d7Ci)C=!5jUTT-57p42GU4B4 z6F%L(1CK)Q&&X?nF@e^ka*sl|&h8(!V%wak=jsB-U?UTpe#)r-~2v9eCRNuIDe-tZ`Y*Am^KLVd9&&+-O%FCJ}<=N_+^fUKjzX31#z166lC zUw`BsTCVpFn7J4EyyEi7*cqTh?F`WIxUuc7&2HX-`^xaOe|{l9PvuLrXF?)-T^yJH z|2a?OR4;enzH`e)`de3SnG-yhURH(O4hBB%Paint&~qO57QKVr#|!t)lpP4Xy!ZC| zB?FHgIQ5Sx@$lm%XrhU_nY?de-vcv7Fp2R}Mi6)%?1$ra>HNH2ab0Mq@KMB%!Evkb zT<76EB7e(e;62Y=9GzqkI9KI-YYrKN)i~;Le2xqP$5W20JLMGJ!bAkx!LSX-b{wShHj`gY*%r3_FF=~q$n>MY4aT0RJ&QKf(xal*Mj07A; zFv>`Pl#i5R!sRO@eBgp9UVT^X8O_~Ij7n0ml~(LE)IlTvY^Z1ee8VMQ>|#E!^V-x0 zKbqUyJPK7YETUI&%!A%lLbrNViTT>AN~{8Us<3Znp^n{9iUhVD`y%6R*o*|W4g2PJ z9BwE@!ecl{?R8kNDwN`X4UUbNPqBaCzkd+_{oi8JbUX^RgV{7A9ap$;(+o9x@KZA} zNeKQ4h;Y-4i-3@vlyV8uuxZ8=%CA9ExM{}EfD)ARU(tmq1^Z{vN$j67gBg=kZbnA6 ze?~reKlL+I<+u4||BM`J7d9Yk@Ew*>d^V%2p`7xSUm%+LDl=RGt&|sD2j8bJw6K*% z6sJmr&oQRHy$~8+gxhwczH>dIc!~|`sefIL^ho4Pg8YLkSlCLVl{ha>LEb*EB8sgv z_!C)#&lj4lH29mj*-GOi7P$C6!bkF$zLcf+jXcQo$^u#vIgjxbWrz=n{1E@mRvPa! zZno0k0~;x?+>WwR`P*c$6`4|g%g1i|a2tr#k!o(gl{VXp)UY%!ZH~l})8A)?y+|FVEm+SBwzBj$vr$4Hey*(}?N&a( zn%3l{-L?}Vk9cXf6E8|U9UZUm(smIqPvNEALA<62M^znf@q#&EQVyO^>{HP>UQYY{ zvx5ElTOsxvybhNtY!zLQw!up~xCioO8d-gJd%s3j@fW;+4`-zOiA%hF?n3sOw0bsl zT2qmi)}Sk?saT@PX-(548cA!KF44YeO(haVJ;B9BW*ef+P|*?E#kF)XOB>Qe7gu}f z$$X?HgPkm0ZF|y(OYqq1g#9S;9q9C_Ujh5PG`-i!I>eKq${VQ+K7G@dMcsr*zZ(%5 z0MVVGDwS@l)IMJS&1rx53D^PkUfLg3q{B;l^Vdl6`m)Lx6M(+V&l*+y7q$GKhVO$@ z0wxUNKa|C>Bt4nZfybESK`J&C5{URfO=fy>Cdfc`U6pYV?S-&}sq}6T&mbh6iuhp0 z>843M3-KY3`9I(@Gikh__&?l@>cXBjQ1qW+FIepbt>_c}k2;{!huez`^xxu!I%#dq z*sSC22~hVU&p^}vkKZ6UIr4Yr{mUDOM*VSOj$cUMF!4-T0o9cpVKt7@s(NC=03t zFz+j1&JV$l;3uK{O4T?>9HF+!sAO%kIYv@(4W>4u)b0>icN%^*ZBPq&C>J0(AR1%| zK~^GhG|zT_2^*DnFQdC@%o5_=gkvQ0U8peC76_yCCJTV(6w2q^M=h}V+n0sVrxN;6 z2)Ih*-Acvb>~MY~V&cuVP`i=ZuR<^apLFmW=?s5ORnB}n&Y6d4*-OO8!QpRD#*Nu% zK2hesM2r&T(lzoDK~{hrqw4ErD)N__vHg*c74$AjhbP$Y09D23p+`m`kVDwrDqO=Ve2=WE!ZoZyzF(lK@R!OHrwZ55_Wgv` z4!sjPw4cz^ky%6UC-ic%3i>%h^Hl)t-}ChEWw6RWHr6kZFiLG?Krc5cFL67pyi8~b zpL6p+OH1G_s+QZ*XeU2QOOj!zYRta@+#5cHcK?Lhoa6i3+n}u*;wRLe0I|00Sz5+x z`dD^N_Jn$m)(E6&z|XPxbHPgQxGyaJTmp6iLG_Mv*|1;3p?XI;nlskbcM)SF zF|-T)aPO^M*hq{YBbTnsjjT-eM_rj4S(&^Vt9F{KFr9Y#kf&m24En?nx|7fx16A!T zWd9n@?G5}dQ(K?7UktUsOl>}5sGRvSo#6w7%9+o`IWq;V>0cQu@s$wcN@9E+hj!*l zI`c!as%KnDXAXi@&TLBL%*izG(in6ER_c1Xl+bDLRXKCLa%LzE*+p&b3^%OR+PkRD z_b`+*yXeg6;FL3W$2p^ZJlYv6@y-xqCowKWF73=tI&(W&<;+ex^E5HpqR%FB=6PiB zx5uDg457CZ`VYvgoOw$*Lp}dt{@2co%rMS8Ol_X&%9)4h%rtPy8C-O&ZZ-xYe;+Yu zl)t?@#Mnm+E{Q9@*``MwY0$CT92(kn(%v$!_-izCNcTSvVWLobOR{M3|8^<8L3|7a7~v ztfPeSa;UN+drN3367-3-%;PQ-9xcQ8I2q{~&mfxfEmX9h6=E(xn!o+~5a+62w6c6& zeb)k$#*9(MTnlbI+hH<}3F>;Ct<)ZeV8Vq&$Wi=$n!+n=9ZcD!OyQX3O&pK3pgTGB z7~Z8)7#r-)Mv9lmYlVM0CtxW!kZ>kE^4D1joGkcXuoCW|BiC99eDd7iZ6)yR@*lSn z7BI_ev4p;S*mp6;I+<|g@dn?2|1(I@W@Ma%=%n8uHL`+@bRJkWWg5g7>Xp-@>XLKe>zOtL^+2)C9>`0*qye4VvcY+ z=On&XmG)I8a)`1pC-H}Yv}-8g_|pSzKOMY^Vh%Bab{g2UN0|775REZd$lH@i9759e zQO;ptkW#X|u4DH5DCU{2#NMQH(Nof1Vj@pfZK1-P#7D~0o~MN8VGp$XDE>LcJaYu? zuP`IMj*0B1gLr~@lP^UP8OJhl5YG+i1h4|GbS<>ND3OAy`xG@;wPqA%H{5Cb|W*3_by^Bp>vx!VUvx!Xq z;d&z*wH3{PSZ>V2&1N=(^kz1h6XDO`*k(3E23t9Y4)wUB4d&Yg-YFxsBTNW4l)=@r zz&Gh(Dz{h}5x*bJNWFQ>b#q1*LpaLXb%q<)NDXn9mn^-5j3|z=c6NbqtVSsw%o4`g zo3j|3WFMNSl%BFsZJd)WFv7-mu)(%2Cg=6CgN>LYs^iVBG;04EG^C_Y)Mj2g2Xmrh zj8z!0P>^v3l1ZV7YG)w5gUn<%5e>kAF6GIt379+}T1CPEH-7U1Bdr?!*AGUAe^;;kztHkWE#iND(`~Ff%>Ry*N9{2G{n6;C zMGQrg;N&IY8L3ZR#-cbNAj!iKe^w(w{q)9-yExG6GrWrVsEq3*{)a)k!Pnr_w?ukE zSz~4?l&}RD$pRdSby+O)L~&rNtcf6{I*R`)aB?WFNs21E6pSA}IHlk0QF5M|Ixr{0 zf0fc626k=+Lrr>)P7c#uo?{_{(Kq=G{hvx_`!H~B&%j!?!++IpqklB}Tz_5u{|EoM zw4UU>fIG+k-4m&PePLVu`usH;+Ui>x3OibAyBpg(Te}Kt+v+>po9pvu7S?vwHRacK zwia&a>NMLQd9lqQdfyWXkLchm{GZztss32K{}FzY))B11NJ@8SbK6?P)%nez+c2|y z#ly}1q!aZ&R_6&;8@}`^c97@T?r|)9rVvD80c&Im)@FO?j z4?Xhy()Xj;ddsDiYO|rm{694g=65d4er6h%qx4VhE!S&qt{=l*U6RhD_Ew7D%jtt2 z_WjL8dCyI_3KbJy4_9D!q&NpIaTBn+laptMt8%lOfX$wqJP)`kd)$O8lKkOg$4pqY zVBE3sCSIT9XFEGi-JIk{i;JX&qN!|$q|WR$`9XR?c2Wu|Mn9NQ-Ke%W!EbWrULRJ59B0DAbVJdqy{PtaiautlKBtFiNzf>i_jkx@21!cZZzVr~Fi( zV+*3h;@wl#uiger2$_Tc^lp z4N*S3ws;(tsJ`1sbHkmYs;gN`GfI$O@+cj(M^KneU{EBUJkl1%^>kx9K5=NGVu#v( zhb7EJ0XX^iW2dSccUPhK?YU~Z+KTCELml?IQkE4Z8|1sD}=S3E7 z0;ER{11XwQhZ2Q;Jg!AUV;`5u-PVg&QU5Mq`z#(Z`H=c%Y3&XahNbsFF0C+10J*9!p^> zqXg8I`eY?HHmXK%n>Tm4sT--y@LQG078?^)chOc&p9ZtUBK6E2hGH7eBzvq=mZL^k z!GaBr%DNR|GacPVvJDm|H&QpIo{CMi+dFbm2Uxl;bR)&>y(Myk!5R*SXvm6<$%sRy zhGUplY%Uhm*LGs_fx1>a?>2w#+!LaC7_28nOA2OUBE*?{Z~Hh=W@h$?s`$T?=iP&i z&%2%@@zm$trU|^8u=i7P^Cr*@_knVCc{6JQ?@G*GOt#*?Vy~V5)A;v4t#A9qyTG~q zBU`vHm7UJJLbG2LmnBW$T_X0tx+rx^%Eif-1eY@3>}g2+H|`M?w_Og;=0qE~sPtZT zZ3$)JW-2^!62fRfFE}xw4a8?$6IldpCF&h46vx3~Lf9J|MMr=$VjGTEkzU}GsCT$f zY{PMg=><-SdWQ?eAsm`TPd^d?#)Q2<#w#dLCh2k1MYJRd;2dd)C0D~lU`Esnnk^3D z)DWHsObdE}iU}1E`(Q6l+M)ztt~j*I7C3w1m`XM!CV)+(60_7)goCS!G_nMsJ>>Dm znw$=5Xo`_1Ku)L=vo~QIDQjZwpi2!muyUmFmL|jtZRiyXF=!mn*~`_a(TucF%!?Iti@qRWD&lT^eM`UDXQ(+n4`13AZ|e*T>8>mu5lMPQNs@BwJil4hj1d| zwy+lkj?}$N<)l;!&K7Xo;VoftxN|=uAiGBI3gMNbcNG|=?i#g64Qn>6MOSQW_X_G& zymrl+&W4Tl9(1S*o2~7vZCl&WWheDaY2ha1f`~g$ub{5IwY34O4+U-Q-3=1Z( zU&KxTZ-)TS0L9~{Irw}yC>8=on|sW~p-hy{4KC*J-X2jBd@sj~&nn}h+r&K+<61PA{Z2mctf z7=OIhzYr&>w`*fr0&h}`L5zFQ#p6$Quuz42*2UYu+&dpq;&W{;DgLQ6v{&2{c;L@)@XrXb8R4FF@%XE} zE07+mpH+_jSq{J2!C&pjKkMLsR(W5E!$3l=` zkGlB&-xyOyEWlT#G=kV(t``0`2RtLY;djc9U{8mT5-QhbNe5{~b zfqUG=+u!N^1oBw@s8^lB96k5Q+u-1D2z40=umfH^{@LoC^qBo;JNkU@Fct#uTnGQ$ zm=Li5U!#u4KhOIk(qs7NIr?94_%Ay6Uv%UbIQSQM?+d;@zb+9Dgj{ap1f4PHyxg)>Q!N1b$hsuf7&y|k;mmK~o2mdNZezk*twbCCSYF!=1 z7zwBLt-=y?QL#>;_7$brDI!7!i@NRMN zZ;1(&{tidJ!yC!UXHf01L&xQR;N9xz-|7{LepF?-)zQD*(ZAi}H$NDnIDGGRM#B(z zcR2cYc%^arcZ9l(1m2wvzuU>bTkZKsr6>+xeI=iq4uN-RCb_mqh`(r7AcVCP_Eb#7k_G|;$9OcPxEey zo9@&Kkx9DI{Y?==ch)v(T_i=_aJrDoQGA&ITw3KLTc*GwVdDp80= zCZ-myEhb(GlhUz%L{C7Z937+mIwtE-p}RUYd>#Sm*a%krEL^>z?d;|@JX6!rQQgs5 z6np4`%aAM%zo43^JPxPJG^r>`MNL`OLuY(?WJL#7()6=!3;6_`dj6qYJ#MF>B3E&v zKtDniGBG7`p&DvFrUu4R183A&^Pw7M~w#wrWd$i&phDYZmPvu+v}QSC>p64tZc z8@9)jEaou~{osD^eSMlmvpm?0e#Nn#=b4-W_bbW90tbzhom2?Da%#qf01-^dv0*vk@VRyea=JE zfzRh0#u~Y~4K{f1NHo^GwcS+~XE`v$`hh`_6X}H)s_OPUz>9NuO zK+?agX^8Woq+b_HSN8l<(r=EXt9trK(rG#Czr{hY(b{YGz z$jx*F4_9*~ck(`5BS6ywU#)DBmVzfUrzdG{b3oVua@+B(zo!< zC*fO!c9X)MO~Riibc>{4Cj3^R+a#ScdgAXQeM5h{l>FV2{($H`B>ZDSpC*N$JjJR1 ztk4%o;pfZ3zbX{a%1?-t{@X$ik;2cz!ha;RFX_d4j+XRAsqb^7{%1-0agtsv>DNp8 zHIja%q<2YrtE8`$^lwNyrujoy-Yt?|E9omFeW9ddd4_We?(3uU=gK|By5V-x0t;e16wHDFf@3!jC6KCn*&Ec+%k* ze}rE`I>z%>313H=>v?U$Zz7$9Z{rGoIcXt2BtrTMzIiG1+mikaDeU+e>9L;orpVux z^uG)LPvKKiHBLGy^m9p(e-bIKr*lL;UwFR2N%#={T$X}B5-wFRm;olYhZ=}#y z`}U%oA!*=0hw+IN_|t?xi4^iVq-W!M?jl$F_d>5t(l?9VC8X!$o2#Oy_UlFddxgJW z^d1-fDN^YFTGG{iz87JiVUd4A3O)@NcG@w3^m1HZNm2d`p(jfEX{6ArBE`I0{QTzV_FTgoYdm^MrA4Lki zDCw=Z?-u#VlDG)-yrFqC%qHjwiWq}!rw0Pdr2`5dPd~G6#A;j-z3GL z@8g0>`%+24j}}@)3Oi3EeHh>16@CRN^y`E+iTraSKTpyx5Pqxh*N_6|4x#r7{Q)V; zd7kw9IDdqHo%BU~YD@S-q|ajiLg7>Tfqx2fHd5ptM*0lw7ycO1pJSdS{7h2ZN1P`7 zDpJhv>V&^Y=xstD6#A0TzYER40tCyOBJ@AoNY4Zwcis53e7*H6c~= z4A8#5<_8NME_AHW9HAwo^D(~`dWz7wLirIx%2x@k5n3;Fz0h`{8-;SckohhWdZ|#Z z8#4Vmp=!PYez)-75~}ubM*8Eze^)5KcF60}3qpS_^tVE}4oLamgmN8_Ja2GGx$Z~G zFGrD%5t=QOpFHGs>Nue%3!NjB>wJ{26k08`PUt$JZ9+E)JxAz8Lb={Y9DYQR^d_OV z3cW+<-9q;WeNgD5LccHcM?%&740!w|FmYcO`litLg#Jw^Kdi{>ZA9n*p@W6;Q;NL) zP7+!ql>4YKo!?d@Jyj?_AxD0NQ10_ZzD_8=#>MOMMxo~my+G(?LiwRz>hW8Pq_+wE zhR}P2J|OfVq5R4suh0CLGwF*$e7w;MM-kpi7vJ>wTqAwSO~swSO~cy`(n@<>wcv&rbxCs`)eM<-+s(sZ8G{^y{P; zZ0-`eSE!m_BmIZM|3oOiPe}b=3gyS+$iFT0uR{MJlwV)uyrG}aAwu!_E0xYQFU}(h zgdQtY&Bu{mD!iJPgXb3+seh)>TA>X>TZDE9y^!?Fo_C4RFA2Ry=UA@mQVn4kPf=(|D>3FRjkIS*0uc+f$@4;9MqA5tC_%8xXXpCNRX(Ah#4 z2wg0cpJ(JeWsT5gq5Qfq)A_wdQZ@evy+Zh_gzgl&OXxR+eoH97(a3qv_k}(ybidHw zliuTbe-!#3Le>2O(*G&^Cqh&EX#I4d{DLF%M}_7Ioho#?(Bp*iGme}$ohr0K=nA3y zBqQfN>xFg--6-^Yp%)0{M;obsz0e&()%^z2?-KrAq5PI3^}j2W-*P1Xf>5~WC1KG; ztxup2j3A!@|40YPdem^)7kiAXL*=5MQ$9)7pD@2zMjrD7HD5T<^J>V?mi4Cj`kVQ@ z-fUtz#^ueVt2|H56EHqrO};_)TgLdalRUHuy;IgB&~Asxqdhzy6!pNs`)-{6ibhD`Kc~22B6KDx>gyz-rKG60GNB7dQGbhtE+a)fE*H9z6!od* zW1uzUQLptvn@CZ=EkZj;QP15%H<6;g&l9?t6!pGE=w+m+|E)r=CPh1J6M6$F+GD%W zoup`&T|#%0qJ8cbx`!0)^nlQZNHH!wCiF>CwA<4{pCLv2Ju7rSDcbP`p)Zr7Jzo`i zfE4ZehR}ngXy3PmzDtUBJ|y&aY&%DAMX9ZcH!@kY>!`%q8$#CqW;qYP}KWWQq=d!q^M_pwUqT+LyCG; z^8?i9MdU9+y_2H;zD|mIdyo|M^$aQM=@nAckGig-Ubx>S>tkp#DC!}P6#fsP|G$&| z3;)LppGS&%C=q@pDe9w4_ywe>m*v8*Bt`wy3*SVVEBy=jo5-WSwut;PQqcDa2~uJMC* znsTvZ6X(Zj@QM6*)WOTL{J_#hh__$xj2}(l?O^H)T1B7VlaNZg}CjQgKIUW+)Yxh@nZ{QiTvQYgzd*-%a0KjUYp<7(ad}=Qy zi^2H8{R(V9wpe~l5IyGO{KfX;Nu*&(It&o2u-L)dX8FM}p5+p+M(|8NuG`tc_`%=P z5D)!$7D~)dEC%BTH|Mea*lzhTS@f8X>p-?2FCfjd4WeQHxWU1@+wx;7^o$?(2p)(E z91rba{CHODg??}zN_&XKVEo`#IJO@TSbh|W9`kYi$@b$7q$To$>sL13)0Q8_79RJ# zCmx6je->(p@ng6yH}vCeD9|2aF&IC%4rZ78tmOyi0H*#pkG1_c1X-ef#q~2A?^Vl> z85Z6=!83k*44EB_AN5)<^n*sw4`MMGKRCa(%YDQ0<9N|yKCZLbeni0J5J-Zthr37F zc!w;!6QOJByGQCxIbesVEyixXx&on`QYi z7rLh0Wg0KEy$pCcf<=W zIpr?5{J`y2*dB+aTx0uY;EfUt5@Qe7TkZC(xA1VPgm`}uJd=;lQQN_=15@Jr)pqfN zSPXzsp)d68a=Wc^D@Bj~FV%Qq8}NQD(RjsmUK?+V)gGL4vs~iM6FlR`y~c3J7!2E} z^}_bpBYqHz!T7PpDR-;o#~Gr>a_^9GO?x~9JQF9Lv4_un*nVuc{J`yU=*P{1XYzf= z7)~$*!#=L{LO-4qKZwO({CLKd*Io@unk%-^n>dMw1-#>#*bR3+!riA8by!!xV}zo5Eb4AW8zFO_FRZW zyI$U~{AhxnY2TX!&*bC!n;i`MnAQvZ;JOFxAr^!2;~}Tqw=F-goD-J&p_B`v!biRM z@rr}@k>y9Lg~yHSXshuf$wV}K*slg+kpOz3AIZ?8AH-rXe)NT&U4O|HvFmw<=rJFk zM`F3g53c_t>R0?7!p0i{Jm!B22iG7>d(0I)V?KWmwgbyzsMmU-A0wbgJYq2zKWdzE zvn)S0h#vFtcM98&DDaF=#4~2__YT{Ssg@sDjtl+Z^H#(&`6ikO!4Qlek7~Wp53ZBZ z9%3;VKlq%MU2cix$GM`%d>=@;#`YrMnK)kL7f zVEm}ldZ8b@-$ar}EC%C8wNq}r<;ND$W4_xoUg*bi;2EEYXUy2_;B{MmTw>wfAb2L< znI=Lo1mnjeS}*itHT00=5sSh2@olHv^DI9u7d_@XtnotI>w%ZZkCz?1t(G5GT6ljE zJYzoZ|LtJ>;PZTlhkmq(AH-rXexyUs?pNC^Kdurz`cbLzLfgB6mq#E825+*1x6AV5 zYUomrcnbv2m~ZxC7r3xJI<#Ks2lberSPZ7z7N^|1EkCXmJ?48%$~A4U3wUO2l6c0R zZ4TaJ79N)SLqF~lJd^JMMEVj)g0YYLP1^18B=l$xu^5crFP(CqMY&w7dkP2F+D!c& zgOi$VZT#T+!~*ap7`%@iyf=Usg%a^@!eQ{n2p(Wm7>N5rJFqNCI?rzAbM?WSyczoU@ zigXhUUXFwJwuN^Wlnvf|2X6>EcGQ509@)7LUNUa9%=vM*=+VA)4qizwc#RHTmW6k( zg?G8&AxVYhz&m$<;dI@SyV$`i0p0=_#D2O5hw=A12k&P?anG4V1RdCB40k$ugW>G! zm|K`&^!OaG-EQaMW~@}oy&uY^+;2O0e;4fxF$g%R&T3y=G)8XJ)8rRL~o&=_YhvX>mZyVvSxL5RnnOO3yL?wNUta4>Lx zAU=C!0%bhjcl3Ub1z?U>CK$bcI`+K}Jv&g3VE`@yCQkkk^h%Q$(}DIeWI)euw_Q!K zdif6I#*ZxMVQB17neeZq5bqEe2Go=_2yru(QoI&=Q<2vMqep6)<88yjWGNi}9@5{y z!E)(8ZL{%SScGR0tOSEs*WA(6&{*q;L>>EL5#5#w;p{-#P#DN!WP+wc9AydD`VDjX?Js@*c5oR=LaBRr(T@3q+_PuTW-t4) z9LfzpaNlK7@Sh}?NA{9N%LhKLWxF>I+?QM)G@ZEjtaZWO8|LRW?Q9y^Or4!gT2rt- z@uTs1iUjHLg9A&U`Gl6T{N0oWGgdN^8oLiv>Po%6jsydMyK{NTHn7S+@p@bXh$9b7Zy z2|TEw(k^UW_wd}dF>}(Ni{*&yJ+@}afub7bdG&De<~jFQjZAuPrZ;z9`YV&mqh-gJ z)6?5q$CP=wcQj0|nR(!;w<77sLsF?EIpvjyXPy`>Us(Q&!_g<_mLGr(kMIBSTPZ1L zlzq4C2Zz1Q-hpW~b!{ns4kFJW)ywbuT5c2dPf$6gs2scYPj8x1HofMd_waJo{$!MY z&d50m|LMakH*4!rAqac++>5&S>+Ip>sZBxo*7DBg%tM=-`t0{|O4bclHIV=7nKj7= zHZ=M9!E;{ji8X$7!ht!>TUs+y`oHK+{Tq7XS%U|vwi&Q!ooX9;SX!QWVDjj@=OjNr za-?5!!Qq+F!*7l#58j)ZRI;vC)$PE&vueBp9$E=?bpiXo`5okL)jofnpQ74lK>3jJ z8_QoioVOV*R5R?*=EjWuqsmd^%jTBvmKKWE%sUXRnR9^tCcipN+UUds<;^ovQeXTj z@~Tqi!?GuWHndC4qP>ywY2_*JHTlP>KDhKM(@pGp%W;Y$La{326aF3wmr2V-~W6LI@hE!>n!X@us`0|f^ z-o#-wDLAjTmJcsq-8|&b=K9qAS?i{iPgga({FN04RyM6~9-Y$n#c#HHQ{jp1*ZKD@8sFvw}U}E_-qpvx>3{}5B9wKIOpx0A8(d}=UP3E#d3gn z-|VxO<4V)`bvx(V<3iECl;&Xjn7xl5EK*}eu+7Ani+%GOn}g;Ijsa?X(`gvbnqp&H z&@@6gJ=O(HE93Yl<8)t+la*Ss*)=xi%I4_1r+7Lg#BKJRw88Lc@xx0GMY=LoEe=}L zscL!nfnDnsqm3ry_E+is7B#8#i~~F8&&|qsuJrvWxoJw0hI(%fN5P~$10O#LPM(Zo zDvkmiS#p4QyVZH|kGVINXY5EW?^mAwwa;hy&-G~z4tU3nc)~xXPi=0Kmp^U)=)Fih$9@qccuZ(VEq?E7BRm2)!pkK7wHoz;9+YTp-1-=CcuQT5bkQJd-qEDhI?1K+Lj zqrslf98UhH_rwsC%V%o(?Da3$vqwFW2u_04PwhUt*-E$jd8yTVdHpZ7dM^2Y>`N^l zT0Tx)lW9xj#-eiXdR{mEYqC|F^UT&|^V}W0&mZq4tRp;{nIPS+kK%;`_nlLgtWZZh zY-R`f3!~-dsL?Z)HYq{cgfPv^JG4J1R=!G z8jh=QY{AiugJa!t9A!94a4>Mr!!Mf5UASz)yh?6VQ{9E#&(=4b!!6I&b~mYSz07N? z>pZ8UTYWC2x?z*Gp`e~`7Mf|N*I8HM)i-qI*R82jw4uIXx?-jy6&sUucR`{!2)Prcxr;^?@KM zWggO!llq)M`EDcyQ&q-D$_2>~MEdaUcfedk?c|ho&`wDPe=d1HH3Fqz1~sS518gvf z+J(4b^MVKPFXb2P_oSI1vv%LuKw^E<* zw<4Y#`96G1eM&Kr$a7TtfluT5MzAvArT)mD05UK#ip;bAoghQf+M73esXzDU0&PSZ zok;w6=fz*%0 zn}byIlIWUv6Y#lTyb!LcBQ=TDF(Oh;(;`VAsxqmV%ESvUbhPFTP#8$-loqi}R$8gEvXlYpAH9VRAEQrCW@k-L4&YM; z*FOg(r+vkL8C>SIDL4x2dx%y`QCyMEpc>uZkXI3L+KxR6024?;aXoE7ZM@nYq9r!;u^9iI3 z$@~JOLo@l!hGCg}V`zBhe;|EC<}~1p%)AoPQJGw!AD!6^ovh5K@PABZJJQEy4n_L7 z%;R8BG_xPlv%SHmA;}-An%n0Kc|*9791<9Z<9wz+<0(W3pM`(^NUb;yd9~t5tvL98 zSmLLtF67S&rD<9^lyCg|^VAszlm$fEeh0LMvA6p3SnCYKdBr>*|AzDS?lML=24Bm_ zOhmrM$VrHNgOO519$=&lktY!GM(~X*|4hWxx}U%Ok1RtubSAsUeh5aw6z|8-9_3di zMJ^lVSNKJv{AIykeYEt@pP?%K&r+9R2o8VybX3=91yW7Hdq~V8$eRGkfeg6;+RQSuc$2;mDJ!8A zRyk~EEp32eDdeolaW$ft&ALn42!$#rAPd{4!k=lXwJ%RY7O932eC?e^4n53<``B2Y z1k?QO{2fxa{>QZbue4q{^D&2s^Ks`T|Kn4JnIXPv+BO2 z6e?A1RPaTeESgQpogz6`K|?Z@>(oCIz)eW4OzK9>NwMrQV_${FTRn=jG{zhjbmk^T zMatRU1}{f7z)TJbtda?*pql)-`a%OWs8NcgFEqCHyag6CΝHL+RCrmJNwy_Qqe=mz_fb#7vslzB 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 %y(O0dvLqhd^t{=wr#&!41YKLth4qwt~+S& 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

gb@Lus4=2Z5tXA64kk8 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ÐD4{oHM9CJ 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

C@7g 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

XO?#8jRw2e*=RofSRR@P*|d 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׹xZ$z`MgnW6p?gPe&Ng_X^ME|a0cd@r<)|(JM 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
    4;6{X(O5lB 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

    %}E zSxK=4oWJHw4zij#g1Z&#o0Gv$54nD-$Q}N@~Lk$K8WGR-OG^prZE0j(jSkH zWYNCz8~6+2MeIZke0p0P&&hzlaT@&n!$B!M~4u2y4K6%z%0DoD0 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

    w+zNjk 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

    F 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

    A?pC=yH?2*XXZ?G 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 Vm^H49JW|b8!gi-jn+a|M9D*I%&2fKNd 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𝔜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%0D871tfdj8XmaL#A? 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

    mVItt$AByY%>;C&su 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 z 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

    CN5$D9(JE%0PLC!4cnCT@_ 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�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 z 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 (OtDTm^Z z`7P_b4_ae5I-;nLE- z`DLsl(n8-rnE#wd5k4@bxzX~UdoiS7S#vmwk@#s17rsL<-V6-B&sRM|_dtW--%gh0 z$VzmG;NR&_2;GN<5d83F$%^MS!H;-agHarPI{jfN0RJ0YhmSPNzP()bWm--NP5Tcvv{ZiE!MP2=iT|u& zQoeiN9Q=&0K!*4}Ztx$=kzSW|`#sCLf0||8Z)u}1SREm=#QTzcKTT%I;DLJ(J}~tE zvG?ZTRaIyI_u4s!laml4ApyeZVbXvQ5=fX)LXsmPfdrB;2sLCR(U8Op7*H83A_!F! z2UJ?Ykvf7y>#WtPwZ)27eb72kMWxnSuvT%XzTfX!_daKz&53=k-|zY3z25iPS8_gU zxYxbLy{0{}r;q=dZ7DV3KD3VbZ`pwkOt^#Y-_aaM_&FL+{J+=0jG=^O{XNZT34Z47 z2bxF6@p;*JWzmum_YATZZ|MbPR-B&x$LQ(*q_`hgWFD&x>7Ew%9Mk8u*1$3&E|)&t ztj)0G_29z9XI%mFEHmMc)f4`r9+e%PD&BALEyl}KPjA1gtSlrwDF!8FCFytNBqbw{ zo}}AxVtJG9W8ozYhKmoUCze}D7JmInt05nkbUucU_@t$1Ro#=8p}rH6CLj?#l8Vvr z6O*2T`J|)=@Y^$~07agZG#Gj8l{6Z^$w|*cLrM~#QtzGg6=La=^bct0n{)=sCpC$a zynac17eW6d?v4&f;(HkeCPA4Rl=LQC1}6fq$zi_enR{Q<`KE7+|izw`mj-SJJf z(a`+yQsbK^E?ZeOV3OL5za!Dj$Yq z{li=)Kgl0$qGvLHAk7)RE(K2FjdVy5-i1`gK%CYa@B0~=PVhd*_U1%C92!2G>BBfU z(RZYRPRT3^$lPLw=KNpF!0`n;AgBJ0fC;d|`)$DIwNU-BT=eKDIQdT2KTK8^8Rg=^ z=k-BU=cklmw7CAE72cem`@BYv0RZu;9x6+2>skr`Qs0;HXRluW#{P@3VSRcA+GgyRTOpsyi$$@0ExxbapM#$i-)3tV z+OZyNe3$7n9xJ-a<;u53PrkfyJ5k-ft=h*QcbJyTE!J8>+&2j5+h%-D6)vfPUWC_pCw)_vfM}_K?NO9gy7(-hZ)Pq`49&PVDT3%y=5@qBecob53Qfj{r6P;k>0Wxa2jPk*1gn#6r?ith}BG) zL1^x=f3-Sjehyt<>?hU*H0R(viv63lp62gSU9q29m(rYwh93KO>t{6INcYdI?KH2Y zo_|=^(|i~8AGL0x`R_=0>@kaDRDXQg4>e%Yzn(JxGUnarE@Hp5?t%>JlNZf=UT(Ge zy!;T8&&$s>`Mlf-^?5V23qQ!@^YV3pK5u{hdy@X;ex}d6T$_1O&gb>&-%a}WBK^zy z^goNZ{IPFaZ-RPJ9s91H->NvSq+-9a@*(9_smaXNacdvMd|nD8Wf+~1GM!ewm_PMJ z$oO_xT(S9E@RRDh&B_3^D&Os9lHQ}eUHR^?UVuB){sQn_Z%qUIuVL^R=)2LnjX}7V zrMvg(O%W4d^cIYf+ZoY6V>M1rK9N?*UEEpx5Yi^lsMjh z>bqH6QdMFJnugE27d}2OBlCG5$8YSvb*`AOSbnd-=Vd+kylj^~@4Ix~sq@O;_%BfX z{@xXdNQ@q3doN=_s06;Dt9Ru!FnY~7&32W{A1LAK)8}QFfmsgckudA?f06Cz=mhA7 zK-^hCCtyon6q5V^2}`CG-aiFmxd!)nYhd(wxl~58(Joxs$Is^pebS}Bfp2##Y&LQ3 zitb%ZSl_>n+@7>~7o2s9{tQDhf1rk|Kc9C$z4V9JP}<1{89N6STZo!{-j6B70?DF~ z{yBrD{LoJ*Af%_jHP&e7rjyUhRQbFKaMnt=I7~i<%5X%-6llc|oM#K(K}VhBiA+)` z4ii}WN^x?=;`6SCywA&py3ad1fxlc+`n(M7^S%P#SiZ@ppSS1jG5s+S)E!dKJ7U-& z^>1yfR6X|?_Zpgi8N;ai*VLB``1>ho_EDO1wBy51(eTw3e?1&qhsO5vd$kD zP07>`|4g9QXc)`s$R9W^0b)(~ApKdgTtb;r!-OgTGT+)VT%aYhhIOko(rg@%IT>C$ zb6mGMWOQrSKe`ohJp<`nTbgS*qlc+7;iR6=vt_u%bI6<^c#SQ{<)1FThm6?#N}FIsqST0Q|?<`_kFbl*B*&G zF<0_=xzq0Ra#K3-LVbQu))L%N#;~t{)8LZ0QJ=;Ow5L!1ay8`hZr3sJGD%{#j$sw0 z6Lhz=LCf(*5wFE0xvZq|yP(awLuZ!8x{J}<9I zcs^vOH|ww3?;rRbv=y2?^zs+{pk2ESLf_UCKV~}R*}xF92f)GS9fIFp3^B#_Pu_^` z$V~b?d}WTmFked+Qj%3v5t8J5M|qm?mh$jjoBranA%tEXzq$x7 zg27~0n`mZ{ zd;P1ff*IH37}M%K6gP>cxT#KNA(=nO6ZPpTr-raMeE2n&fz%b@dNEz8)woJg?SO;l z8WzqrbqfExEHkrD?SKCeM7#;T8TDcA9AM&&3@iVK-5~GtGL*lS z4*ot?Gc0i_=w$qT^$bzPZ9v!JPqo_N;Z=#}q4<1WN~O+bbM9xI$>4lU&F>#z-OJ#g zcY|f1HmkTzR6I!Q@*?DFhJ2BAFxc7%b3dJ5}<88 z+!AXb8Y#i;%-`yNj|+VGkdM{97Zm_7QybxK(AHG94Ly z9)gViRD9T8S+!Q$W;hK02IreK*;MpMW6RYx=xkF~o=y#u&x-PSxtr#?JHW8^^{)GArBKBT}(H?J{E<1y-vupux0!KnZXQCAJ%QwbHnlY|53QT50}it zF#L;#gD~)<9!I(H-@$e&Y*`twJ&F+HV^Ipc^CxQ&Tz*2A6u8vFWqbezzNkL?X?S&_ zjU~Z*f;BIu18#qW+t1-P+PHbHEb~pUN@CjKbr4>^hSwR|tHjDs*&m5?sd1v%#LwXN zD#TRwCj5K=(?#01H0A=tGC!shzgpqM%i;e6{Il;B!ChL=De|C*O!@`}rc1)AiOf8e zBX|Hm)bpmKVl~{-;l{lEQ@hQJIbVl_&%_DvNtpzZb6}u`fvCd?mYuv+b`;sX#6tfG z+TW3?>~#2KLB(wCqcbyU65N~#oO}q=F>8aabws2e%d>Vio`Uwki-Yi?c{f6h#@%?d zx5CaB$C&nXiEd9^7n}BTiPpq5Guz9hy1j74o&GA6Tbry-gsz1>8yVK6@v$UsCEVC7 zSQ-|DSkvt~lk_{{w1QtNbn!P=@uQR>4av)PW060sgcpnHI7&iVLe6CJ@89YLh#>BHG3 zT#3I5O8C64x(gxHls@Ryt!l<*B75E$S%IxRvP^i(wJEf4xRGh5OwOU<943-wat_Oc zUkxy2at_Oc9|ic&Wx^_%{%v1I6j>S<*%49VC92k?aSlu4Gh21k()b3Wl{?wHpe1ryT$qN`JH`p!Vs95!%`~LPuktmTh)Kl;G=QOlfRnY49rrx}c+$#&39nyOMn^ zw1rFKjKB1R$bOzr)|k<_?4)OE`#Dj|xts;{66a|-dY<+YlQk0~!pjg;Gxf~u04HWM z^{Da+mE`Jq*{f{lW?GhFre)O4sLZsiua$N(9CE)-Kn(xI>82W)tLKHE>otg(W(D|4 zXzLt37+E($e&`jk+MylgFhoz>&e0RMVLB;|dXhLipH;QOOsSC8W<7f8so`BvL6s&A zYb=vMJO`jBdGytjJim%%WO>CgP_&67C6679dgs9`T&B@u>Lw1UGkmBFU1FPAVwJGw zb8pz%d_RI*0aK8lJ+`(`%VV@&$l~5g-)~_(Qy1LNSa4IIKd8&&a+U|*Y7yiPg>?l> zWGk#^>RfJPf!|FlGIu4?slKGBuAr+}LF4?mM#!1)5u~*nG~m_udM^C@OvISA3HG+} z2yrQbS$9(T*$6S4&0-q-9>%|Q|3FA&J`SgA;g`7&hC5*>yd8#dlo5{6{dXf}!Xb46h;~MLs0+6NH-cHC#-RvW~$1R3^j&@VpMb>Rh2c{eO2#2`e4wZiB37~Whq1^?G28;(VaSDH zJPh+}iSbL|5`@cmUYz6&J>%P8*a1V)WiUJpO+{D1a61fhE`q`2B)bN7&Pto1pGjSX zS8@WMZe0=Hz+@oRTJ^1Vq6FD2T`5HV$r+c)@EC3=9tscwqsm z%V;8B($xg7Y(6PP;qN6j|2jxpc@ttTQl9uiOHG^)0VZ+M0T^s;tEemjhC#4NaRG{`Q4f#J)Hr}xSS*ZNd;4P2SYR_!{^d*#DxxrPwmR`^~Ig+DXC z_5uU3X0L|V1Mu2q)LFAt_T_M5eLrZNSijjjMZ?RshFN-vLJgma*C)1DQP@igqdVF# zTZ;c;M`4tqF!&tWi->(9nB%_kF!XQNT^HgP#YbgzERoB5Ytx(b(`_mMWu_3p(pamxx^``rcM~xBA9+m-c{BN zoOoX$%y?eY_%)j3#658CN7?6LU@mlC*E^zn6H;~X2PC%yIn&1Z&lfI;l_sXh;g%mDtj56*f3raF|Jbhl`(b%AB(yU zW{FK^Vkdl^YIBO(CVZ;%;Q$`m8(y%M<(RZ8}~D0)`(0@1Y6 z3i(a?Bm6>T@2u*3n0u&YG3Z4ZrFPnB$$kQme>W^WF-_8uJq`v|C|}Z{D|C-!T216#=KAd8r=4`uJRJu1 zN&6yFP$aG|I9(?#5LcuID_Gef;#jLE58YKP=Ll17L>FLfgtsiMhGb)=fcd?ijB!&& zPue0Tne$Whd<)q&FGsg_cAsFc&|lIk^e+)^%t;vctd}f4V-ZZSSL`q8Nz!uI$JSJ0 zJL+YN&tu#SJ3r&DSKU`41zaVsT*H*N!v`DDdZm4v_AzcaQT0mu5r`7qaVf4>(bHNaG~zZs=)*_#MII`6IoS+geRxqBuYxdTXsI%u znO5y|xEO)hfiRYJ<8-#s5sa6ms~y2APl7;GdpKArgYh8`>%7atuDtMGb|=PXt8G`< zRY&naGF(^x%H{fUKe(>nAL&|N12wUSVt5g}d_Q82{f9BnfsWWDk9MDdjKoec<_VZ_ z#ZK4e1vfHHl@u`c_OI60b-C4+ z%z1AzZv#||A47`z4&j!LzJ8zEgL!6zcWDlEJ9I*kc|psgij&Lh`G9A+>0CDx5#} z(1lB)JqrHPD%w#T>Bb*S9UHMeETt zV!zdQm~u{)T*##GhO}fRS}nRA{{9PMSYYf-P4V5Yy{<*ldd2GX$!L1%AJ!9!fR(c3 zZwct)axL~uTATS{wU~RRP{gQ(95lCHM>q>J8hEu)ElNP+@NbOa{GLOcN$o;@qRjRGYfbNiLl#r z;X0C~tR!nhVsdv+;()~RzDZV3lw-_r)xG=a-95;Pr;qX^PU$|idjSf@EAD7#-A;lC z%9fy4>?w-yCtIGx?%fff8*c`U>tRB7D@dLM>G+UuclvgRuixmVZ-NLzAFcQ#koJ|Z ziOEpKhs{nxiX;>+yLhc|Y)QDkHE|%iwO+lgQ~MPpGmhkLI$bF^&s1-!(Be?v$Fht> z-yx9T_o`AQtB4R)($}H5e>f?)VkODcVgnfy;~CUjF-lyylYlyhCx^3yWlB2Ah9yJ6 zfc78KEtE$r$YIg`R5J`0WSL7H%WzmiJ|p7Af;TeIy#RNo3`C8b3U?iX7ku?I0VBKP z%p4Vt)x>#P*dfX4<(rXu-AtW>(c!ejpbd-(r-s(_a1v<6?7~hStr>%?%;fo2dEZ6d z7wd}8?4~l4=`*f7T+tS@#GXYv3oLu{#TJ@grmm$4mtAbBnA9t0redB24@D2mg>4z7 zCWlj9kQ|ZjDe2Z3{Y)D@wO@qKRLKz<6q7Q|XuD=+KkAI*Y!n^B9y>fz)~TB-He5 zMzjS_~X#je14#t+w`Lgj>Z8%qNWOVyEozh7CF78AZ(|5VR#Gw2tj;?e~;=|dlL=c7ZKc)yLcTeHZ`mB|g-~kS}a%uy!gTsQtw9Hv;pBdM&$vuw^65-^k7n z%a%K3!{rYJ5;5@Q9&Wh1SK3qM4J0q&xRtzJ=^ihXjrUbzWP6|-i#4+PaO)MWr6>txE zpjKW&Fak&8;x7DK#+UG!T;b{j3~@RgC4}Vm!BD}`{{%-q#!p9%&gAp>N3lG-_Am^+ zOj$gP=|eX*zV;27uv^0lBXsT(f9oydA+*n;- z+0fKBwz74_n8t>tj?OWaO*O5}4K=luRSjdZ(kG2=X|1j5XlQK5b)eSs8=A&+PMT0L zA!}@7L)F;j)z#4hj%C1xrs~Fyn%W;vLQ7+1dtGzu3Z%fqJ7yA8R@aX~g2r~Vwc1+7 zuBfc8Z)o}-(&l*mBuY#YI<~o`wyCWRXIc1*11!|G_L`d7y7YSXH5KivT58*1Mw5d( zUM&bSdY`Jwwpy4_F_mpinRFDRF`0K<8gonastOYhy6It@tD1xj&BjpO+{8$srv{%1 z&}^$ThT4@a#(>A-jG?W)vie-{?5w~QJ8^HXZ>_DY5s#+jC_rOwt~$pUR#Y}NHdn)p zOtiJPHZ(0aX58Ro1hCDGe504X)?>~03=Mb|1TsgEX9w`BV!W1TabWr4-PhdYNeXzH z1NhC{J@wwfMN1ZU^=waEI^H@Emj5fvF+PXG`~L$DCn){T4qv&W{XcN{-mT;Rz~K^{ z_YvjspB*+^)-+GtY|r`Wp7_AnKTP*rZ>4)aUXv~ifC0}D*eBoJaN4lZ9ff0ttX%$> zXTay4Vd+Co_T0EOz0easZSnNSQ2m7`4`Ge@0=}#cDAeX@zVjdR_dBbw@NrMNzgNaj z$Br4g{QSZp_br}LFy!Q-U5g*{_bwd!xM$Si`of{RJ@Iu&g=b~JbAG^+9Pl&+CeYp# z=s+7NTzp1t##xJ(4_%&7d)4`1;n;h=FZK*g?^wKiHyTIY8TWbSEn0lWJ)R~0bkC^S zg=25K4=KC>DV&a28}9WKzTufXyYM#8?zN9Dzv;uF(SiE>h%r48(f=(#0mpoQr z$jQTo4?L^ztdo%?kFQ<-?&2@=>p6MIu*n&PQ)7BT4PNt#E(0&fZBsd=b2BRn%JS!^ z{Q2`MiV9{{$28Lz0VU!iLCnHwp%Kvgv?$I~7ayjyU2ZBuP)WqWM}-;3gmFgGW6R=zV} z>9_(T(9%%_VJ4=owYE0&#@CjHrn+X6new>>3-a-1o}$vS`2};&R2}VglS~((%&U7V zR&?M+w^UKxyrKnW9erI#V;2+H3F*VAayvuu^-qA;pNPy`x1{o{RU0+9g$9 zpz;@#RLsc>mm-Rz#Mm0zYgbh8!N1npbMRtdXJ+Q)m(429Ly0YKQjn;K_I6w(@Z65J z%H_48*z$An`Y@(gvRM|KBsr84MTYE@@)C%7IsO!j< zE1o%9XQ8Ape{qFw3X(QkU}kwxUI@&0`=SuetH87Qc?G2Be{?by!qc#wXL?Iu>q=e0?H<2ii*$+l$lk$(z#8Y+t9QUHPKX8q2KTv zZj5>$QjN_`%L9CSZ(Dt3W<`A^a<9iZ$eDB^&-rJfdTN_iR;;LDaNYLj=g+IqZ%}S% zYwO@!laa)h>Xyp(dfq{8PSj9H-ISd#a@PJic{8aF18qeMPZN&n6)S4n>zj2nMzMZl zxIzMJm!nieNn458lOEW$e+AyBLsiYy?X~SNaEQg*s#{H=p&71dZnDcxUVL4_Gcwc! znWeDuGxO)>&(A5UC@r5^Ha|b#`EKa8+S;1X)Fu47YNKst!I^W*=hzXky#*P(gHOPj zddi=JrdXD*s?JBJQ)?V&78e)g=gie-SZz%JbH!F=w}Z&nTQiGo=bCynwU9f%$kak} zQ{$?(W}Gv%m2K=Pt1#=Vt!z>i6(#fY%gPp41k2~&@H;bF#`KU`Y zgR*?-F^hA{^2;hD!RT(A+AAC{4YxDLx2(}zSp!wAtL*wWBQY^4N;H z#>(YwJVQHbl^G_KuK93AO`EE0X)&!BU5Ih1S#e&b)IMHRUXfG2NH35LP4oS8)! z)%Ac_wW38T4yeX>!c{kKy@>97_Q7oslhiZa6uhMD$y zjC$vxqs5q9*U?nn#@Ecxti^%}8MBkBRpgW*O*6}J{x)Hq)QGWl?wJL1^FvbMt_%fi z_hf8SEfKc!OqokBQ*c&(o-TVV7g)aG2B4ZS%5wy>lRUQ=ku^1Ax#v1#D{HFQi1hg1 z$*B;_C)|@7CuESN?`Q^S6h_DqDO(E0(TX{aNmdEWp_0(GB!gF!xd6i>%lv3Sjh^+W zD$H8iLU~|8;*Qw1j+Pdj5^WVV4a;lo=4f(Nq32UfYGY-aJ#1E^V?&3jN2^e0!C^}$ zM^9fOI&|hz)nI^ZX{Hp?TY;CVk3$)|a>7AKw>SHX2&$&7l9Ahm&i8cUWI%1@&eRj2 z$g&b1pMi89xq_6+Ld7o=l%6j6mTt43%xBzCu$BG*N7m=vJzG zPM&dgF=N7rg061vz)0V!&=;fEuC8Lb!*j0+ty#yBi=jX@oQM8^6Qx$1IPA;ZJ2Md< zywImIdXNg9<8#`i)qtok!H(v2U3If&lLl= z1lXOj*xEP`r=#8nkgr&TRs&TXbx2qhukb4Wk+K>`-Etx zo<0NgiYDC1!=;CFPWLcK+Igx(Fz(&|HS2P-s-vx-mOI8nFN7NC;2pImL6!^blv~mOTllSEwjC1?QTnJk}8% zXpAyl(|vVKt(np`*VQro`rJVsuWV>*2q%i24yte*zvjTvQ@6QLVPI+5tOuQn>ME=| zY8z`R^oq_-PH}E&iK?m6MXRdu*&H)Mbu=}s#6%1;dy{ipyreL$Z$e8*p;N)xlEe!Flmx54Kp--!pizu zk2)MiS>Ua;=+}@`ohNo){0@uht^kEvz55 zsmYuGdwV@j9kQ`)ObrGzobl7KkrEiQe0dGri`xQY>afJ9ZQ+NHXlY?Y=$NtjT{Fg< z*|0Y>VI5qHJ#)+|r%%X&i&-X&;Zzwm?!k_c1s%1pXQxJ|n?5HS8nGKRy}kjP%uSGM zhQ2X%oa&Cz^MhI{Yib_DLa0X8ICgOfsf$s1JDHD~lZ6WrmUCnWg%w}^+)^yEbZ2jt zco@~}2BOQ{oVD%xys4?mile5z zalpi}pFm--Pitw$u*U_j&XFwXc?Rl54?0}L%^>FcNRDB~oM19!@!{Rb9Oo3BSv=pg zJQ)S`-i>39DVs3p_4Nm=Oy=a{OuEH7!Z8I{VCCc%D%Y%@KIkkuWtT|@WZ}TstY&$J zv4=5B$55%{7SE9#F02Lh(wjk8C#3~v(rA)UK9d8yHk%yTL#6JUbeUoLSIo1OfhwC; zmFU4Ma?H{SLQ!M?3u{1p{i?aCve9(DZE~t(Jiye3-z1QD^t>`WGDM66vc}-_!LHo4 zh!WTPoq9ktb2ko+b)jUiGs0x7UF&Sqzg*$fo0edDDK42Cs<5|+5dnh|a@ban$$5Zd zrlTr#1L8o|j_n>jJm93#Ns)eczFtpPc7`G^EiDR}^K+p*v^gVHpz>zfX9r6kdYl~- zC%<;@SdB|lj`f&x3KEK9R$*SySMPcg43j`JO6hdV zWP-C@&THE{+x21^xiwoscspR^uADu0qdHtUsLYmn3Uzasf9U;ryfZNTS;#YUbEgE- zFbf&UNr<^cgWq$+QyUj1;=!Hayi6(wZ!?&gIDA9gCH{@Em-;q!+w8r}vnA$oYi8mM zryOt5n3C2t4ezkU3#{lxNcmMd?siCX?Si7oDO4A_MV@;02D#K1cL z`q+zo8@gTM-RQX#wWe}-J832FiBMJ=jNK-V$x*)e*c`tV7ZdO8;R8~qU`qe~t-nzQ#s4LV}DL*Q!V~vte-Br3{?NTmEUVl`!%UGjUWHePq@V^;v zSU6O*;fjx1qfYNAk+34&BBATyhLqE(I4J4!}aEpCxel{h`3REN_$ifUGcTSTi4J4USnw|5lP(L~&;qZYd( zV3$Q6RVGy2p&41!-ofD;CD|-&mqe(n9qv(z+Tj~TFH71bq4kE`qL#DEH;UdU5?XI7 z^1;PEmbWLALWExwohSIaQW~||!U^fJ)}o1M)q3q_P9t--lb+C=knXO;qGX{<(Pqw{ z(xco(ke)ei@}!AoQl(|6wY51N`}UQM>8^8}*C*lmW4iF38$F&ob-A?2df`8b$^P{T zVkTwL##bzQPmnfon|(gBPWcZR$R2;95^U^MbHgN*dCW~S(=$&Lj9O~Zl4S%P=W{fn z=y}8?ChPQ)0*MwUve{6*%CU2JLW!EBhZ}V?En(lTD%+9u2oc;rz1&*N^N1F+|X)Oyu0*uz@3;HzzTxg-9~u|tEnqv!ID5tbe+s;P^ z!p9bs150+uVT*pefsZ(tV~Z+;fsZ?wV~c*ghEJf_cH2aHl+S5}J=PI7z2sRBk@BcG zS9!$g$H|y|?gzxcKLFO_-yCtO5{3@jsTVdiuFyX_4 z2Vx@IQ>sfpAD9Ur9{uo)(>}nZe?Zt1CXX8A(m%+he~?T5WS2eQ(jRd74|VAu>e4^d zCGXtXVERV5^p9}KpX$pws!M*l%YM2` z|LHFO87}=ZT>59Y;vpvt9aUyY$a? z=__*C=eYFGarqa!^cTDI7rW%=x$N^@`uT8V`0(Ia>d5}5%%#69EDV#!@!U8)JZhm! zf9QQBI-CbjphoIn?9v~8=GEv6J&P*gm%8*X)$aC>2TylK>Ob41KRnVI{mbm2njVZs zfe4q%2%AS$yYyGP^jEv&YhCs_m;O4Jf4xh8y-R<1#0MT$lcHUH699dJ}JYv8|XN{1WEBI_&qs{H4PlGQ!}|&-aF1Jb1t~5Vpd^2TsEW zp4WAiPpg&>&mUUD!Z3M4591nVygbLHKRmOcgh!q4(to~|52xaMT^3%;=)-&Y)MGIA zaM*tXdw+-h1=xo;>~=`fqiZYd;!&$rAZ&$cb%f2ME)11D-dBiraiPoqB3Jl})W;$* zP|IHwdMr0X+b`CyA)-i%wqHYI=&u>zv}q@5L_p zi(UR3T>cx>Jke*;x6LKL(Ivl8tq^$=|3;VmCbd@lIcK-jCYS$am%hy|fA{=%t4n^X zOa5|~|K;j>iQlB}Mwk3Hm%KZ_SE;)syh;C6uJGGk;kUc|uW|Xi>-##F|8?p)iO;0> zdY8WIUGi@K8(seH{DylXD)y+GT>5vp>^HmYx4P`%o{JtHwa4Xur%q4Lkn3F`6Ad2a zwzD@2A0G6SZ%BF2m3rQB**|jGKX=*x?Xvq~!uqMNuglKYbl3;|N4xB~uu~<^&t5T! zs?_CQ72%((R=fQ9sn~G%RJF_He{Y2UAoaY<|FsDJq3Z7u_EXh&5%$rlyT=({rs^MI zpP=-cU_<$ts%Av^&rqci_I$NG!aiHAjIbB0OCs!Limwg{=XbHXHNt+jxRQSuXoDm%Z3!U*xj$efsvn^ztns_CfnP zmwlVdzT0KL$7O%kWq-|O{}A?YdAF)B#J&x2_rm*^yLU6G;rNskbDiP~VR#t(ntKs(jJdUg8 z!)sJ}QSLbYOyCdpHH&hw3tEKNQQ`+XiAA~D{J}PHQSK!EOva5X;k!NHkeQ((w$I_B z)nsBj7-pkaN0F(OW@`PJT5YD*o2eC#)3J@yVaI9taawYm4mB=2+JkVih3(p9=3e!Q zPP`-fge}f4w#BiP?NT5+l|QyGd*Xg`7uvDUeBvHx7qZyRJz+=HzQf&qj?j6Rx_t430tU+B7Lirw({yxltM9g zh=uN`;Cs?5>BoA&a<$O)*0o> zFB55`>`SQbM!@JJCBiX>Yt(&bSJ+3#?68JPFjU1lY}ghu>5!~<`*9xLKOBC}gcpBs z=Ou0pvmYwPPB(9cci!m5Ag*T`C0xVC(?bYlm1?}-7AdT}e3CSO<=|2f{gN5Y@i8$4LR@xAb#c)Z$(?2h*U3(H7M=oXPZlv+w+ zYkV1b5?;$fLcX5Fpw>txVYMvo?PM>!<3;Qjk{tYSjIzhGe<~G#o%tP2B7ajzq&ts9 zdW%S;_bd|o5A~p@zj+-L<8Pte)@yH-L$9CiC?pK^YVg1CgJaZSLuLCvE&g8__ff;U z@c&x;M|I)`$#+v&68pXLg0``hu)?84uUf0oPt53c;p?ZV&IU)F`c zt)G>^!%n}g-_GAM?Hl&TCXFtCJAZ8KJnZncza4+0@jk)dj=!}Fe>?t8m;XUm{A;@K zx8vW?g})vDWnq7u3MwA2SJ&+}!P0NrjK?NS72SU@yC!Vc48nGOEtzPkTgj6w{buBN zg!_ngoUCZ_D*g*Of0Hc5{hjz;mV$_OA5OxOPC_5gU+P;xBA%7ve#6J-YishU}B0YSG zp^it`NFu(KWIs#4Xps5j$G#~442jLL{lX*So`61y^-x4Yj&ER$_nMaxdBC#(e zpU3$j_8Jm;>PhHnB%!B;gj_obJ)L5|Q0(i-M=*a7`z8{4wvy1Zjf9@7$uCe|I7V$V z4E3`IrJuC>(VN5my6si-ea6`L&JgM%WE~JkvQ!$nlbPewKp#iSQiZ`9h9s^uJR03*lYDhlS4x zUlqP5JTB~p4w`y;2~QS|7ETrhg{8t3!b^o$3wI0e6Fw?@P58d>@4}H-Ycu{_;ap*< z@ND5Z!j-~{g;xk~5Z*4lU-+c(_rf=X?+ZT@c8fRZND^iWrwj2xA)U^0VWn`r@Mps7 zg|`X!37-`17yg&RD=fdN{?}c70Xqex4VNYQn;XvU~VVW>qm@Ql`Tr1onyiRzF@K?g$ z2=@yQ3;!YfN*I%D($_=yGc077-hIL+g)a(U7rrn2P8f%YKEw494i{z!vxQ59%Y|*i zwZbjJ>x8!m?-M>Id_njp;d{cr3BMBJbCNn;_=uzC0O5Gy8N&O8PYL%6-x7W=jPGmo z^c7|brweBb7Yg~6S(eKh;TGWz;qAgtgkK8zu|0<42T{pqgl`To_78H_%C715R;w(!c&D=!W?0-@GN1SuvK`z@M7W5gx3pi6Ydi}Av_@bR2VnZ zq^GyAShz%3Ej(9vk#LJ}zwkrhF=56qqjw_N4Ih9Z|ANmiiF>8k>%@MZ*jI{uz1Xi1 z?jWIOC;0*P4aNN-;giB=$q%qEDE3#x{;t?R5c^TFe=Yo;g#KQ`4aW%iA_=;e3C|X; z5nd|XExc3snDBYwTf#4d{}v7!Vf0TF77CY=A1bw+L?5(L?CVLCVK|k*C+h|9#;x;g{k+ z^i-p7G&u_E6cYO83m1xe3yFAFlNm~F7H${!>&Xe&HzpDOA+f(8{;!bJkWcadQrIoc z$j6iL&ma-c6mllosrWAw){6TY5^|f!S@@ceaJRVMMb1TkO(H!9gzpIti+}t`qbG$d zQ|dGl@>7Ioi2EWE@l}!73_DMFfw-?HmtmiaMEIYJ{XX%3gsek4#Q$C4--Vxxe=6#L z@eCy!@%dX4`eq5|hjR4;G?u8^eqrB5%+cya%;%Tl=_+QI&r^W_=NCd;pf6{gfXLyo)qB_;do)5 zuwJ-ExKX%WxKH>PxeeFP#m-NsGyNY3kBIx{V*g6)))*t_BayG3Vn10pT-?*eK3?q8 z#a<*_EIeEM>&3o8?B|o%$G@0FIxi(Z!2Z4X-#{Y0w}}58;{Pjge@ghGxW6j)KMM~F z|1SKJL_9wT18^VuC$Q>1aE$%(W8uvcJ0VLu}6MLp`iZECFi-Zfw`*DAR*jt2` z34bo!Cwx@6U--K4UEvQxe}+j%KjBc}1mPLNa$%eBa^Y^_L&5{XzX=mEjsD)k!NQS3 z+;OMNVZN|lxJh`s@IK+wBa>Ct#G^W z4&kH1KMIcsj|qE?H+lyNrwSJe+l3bie=gi7{Dbg4;Sr%P%joSd%n+6c&kP5armDgncLp|B>V#jIZK9OWaGvzDVrVVs8_6k_dN|@OI&& z!ncISg$Wpg8DA=S0M~cKKAC(L@r%8fd;|CMh`oh;663qrH|N zKbypLuxhb4lOrs(O6(m?m9W=jqi?)$ zv9MWqiSP#DgTmhn-w_@co;1bi>o3d_Djb{#dxhPFCkguq`wNE%M+h;@>G0@QG%?lE z3<~E6=Lr`HmkOJNt-@8pi-edeXnmW6Hwb?ryiNE^;a(w{oDPSks`-NOW#ONM?+ZT? z{!93^P+2CtSE#QWqP%cxiPnot#G0oG#|bA0&k*Jc=L;7IYlRKM7Gb;ar@~8x`uZc{ zze?=8NmSBp!n=igh0h3|7rrEXMR-v7w(v9I=fbareCC7kcw-ECKM?Kxg}fh#_7TF7 z!VF=SFev2xLX_9nF~J35uN5{3TZHYxpORRwTq?X=c$M&066=*c!ux~|2%i(aC_Et4 z*F6#LBe8!XJSO~?FxCV8nA`Fh5VDuBk1$O*S~y-fQCL7uP->2_Ot?sR4vF=PzD^2u zh+SVVg?)?IuMl16MioITKI3_N$4oJ z9!eJW7Y-I?2>Hwh<)#YH5Y7{p3zrI)3Hd=-uAg}S6{)Ykg6qY;U8t|a!u=OwzghSo zxeWIi37--^D}0^A`sq#KA)&r*3->R@{*BPWxkmYJ!oI=*!lA-bgp7 z*LUI1XFMoZBdiy$COfhI5ndwPEWDA#dg~_P?ZP{Sj|-m`z99UA@Eze_ghzy*3i-`# zuFvpkJk2;^58=teVM5-YM)`E%3=;FWJYk`*SXe34*N-9BDE1cNDxtof4F4;{zFl~O z@E5|{gufI%CVWcxg76Q*SA}l~^>t^&^B1x6{xPPX_m7d^3V#s#VvRfRC8mFpu(y!+ zh0&e&g^{NUPZLfNo-WK676=y!d4CtfR|}U5n}n^xRl%Ay;X&cs!ViQW3%?Y8BlP%9I%0)Ag(<>8!Xd(O!U@9Dg)@b-g>!{x z3#)_;LVevG`Clpa)x!0{ON7@7ZxG%oyjS>?@LA!0;Q`^B!gqup2|p1Y6aGu+i!x4H7Zx-tN z2N3=~u|FVuRH*MKfd9*4|C8{r@QCoJ@C)I;g;u4al{MUEjw6`&zO8RJc{RO?b2LcA>tn1L5|G9m9@_c~9<3#n_xmJLby) z67%3Ra=6@AI!bXFs`u4rkeFxAA~7E>n}JiqaE|JdJ^-f7V<1}|1IZF>u9et z_uF!wf+nW-hj);jO6?*s57|Rv{NGDnhItnW;ipN|+wVvUkx0K+=occJ+P$YRMVKla zC=3XZRV|+(%o0u#BCFbehA>Y!OIRdaBwQ+7Cae+G3z2oLuSM7{>=a%o+(aVZTZJ%c z`_;l7!kxlh!dr!Vgm()c7CtU~TKHSx?}Yn>2ZXN)4+`HF9ua;jJSzM`cwG3MP_KKD z3BB$G{apWncw|9SuYY03t?k+#5Mm2P+i^>>=4fGtFiSW?m?xYiED|mv(O#Acmyu}q zHNtul?Y~i|*UiImA35z{CyDdnLg6|x1NV^&H<36$whFhA({P`=a0iL=Wv6f#IZLTq zg?mVxKX(iDdbNaQDov@#zHN#=v?_=xnEa6^)`eFn*PB=&j| z`DzzCqSE<86k2{0iF{ry_8lbhd#l(Hm2O85iv3{{k^NTezavo&uZjI2ISchD_9G<9 z_q;>UQeQ2 z+r{2VBJ&%>zKKLRUoG|>B+6U2YozCC+EMPh9mB5M@g8L2zj@$x7X=l{C-PaYa4}*Z z0#XjmLLY89`tdjw|9<@cCpqp%y5n7ED}kRE|2#(HA5&5_1OGg>-e&6LKA0)Pf5vwv z{u$g(?}H9qaMpe#s)pv4i)q0@Ifl36vsn)}XS`S6Zsq`t7fY*9y!XJ&sO<7%y|lw_ zAGW@q!NIBTR_L1rH|nFiosU~!ran6#+`n@k^yBd?{$UQ~gL2FVb@8y{eF|o0yq`Mq zksxvm=YcZnw(~Iw`si;TwmwXSBJ_Rd(3c25J0IM?r9M0PdA0#=Jm|**k7PyUgK|s{ zb@8y{#iM``@h036u8$;s^PQn#ItqAv0=-KB4!LtnB(UxnzilfTF|K!yk7;<3fZ zh3bQHOb>POu=BxvWM_ShcEpQrF;srdtVqsS32`xLt!lpB4a`e=teTD#(YwNu|xhd$i$7SdNJ z`T%{bvkhXm^KrhB3+01y%m;Pxu=By^b)4}wI^qq89K-E5`a=2G1bei6@cAC6z6%}t zhC1{;Bl-Y+Tx}b~Zs+44MlO^O$}v4dMb6I0-{9_ycdH}b5sK}wsSbUaq7Q2H!F_+{VdsPU>@bJ&K{@7wx_H?6C~?Jmw#J`QSUQoaHjmp>L`~AK!JwwA#r(ZX0x}!ufd3$c6Gj zIp%}9c)(j92VC)vcEo$S$T8et%()q_oexgPqMheox%5qQ=$qltmm>P?Sk zA|GBv2)R%`D97|r7Y{ohY$(orY<0xTdkF0M2pWB%b~UYweDL~|Q{PU9zG8>IX`;`r z53XOGhuy9!j9e%mlw&@qi-(<$C9ZhycEmehy`Jf!rLtQ-Vd?Z88*$zH+#Jg1FbU33g)UG%llVdsO-**fcEv?Ja+kz=?x{P5hf^RWy1qUD3v9i957 zIrP;#^!?z<$K74zgV!OQ=LhAO9_r#@=Y!WRo$(eq;yqX77_I_8&U`!weLIjA`>^$$ z;nKGh`gjim*XJwnPdVx<7kzep@VQp!!MJ#I7`ae=P>$iLi-#TWd2n>*Bjw(3yJ`_R zhI`QH3)M#%^hK+WD_#1AJM>{2DwGdiXJuOLd@SoCA1@iXP(COJC%i@59Ckilbj6$H zh_?fxcKP*1W}WrH>sr{(3LUn-PhI-*ppWIj`Zyo|w!R*s&(6p3F7h$S$c6GjIp%}9 zc-Zk~K@NXv1|4xc=*Y)v*zI_EJ=a-&tPF;;54#;)B646Gwh(B?yB=~3KSTU} z>xh^4;@R=uCHn0Ara_;x9oX@{;)<8o)6zsYVaNNDE8f=-Zvg%*=XLnE<2~-uw-ov^ z;BOzcK3+%0Unn16IP_f%cU#}d@uvLja^ZEkXyq~ha!!3INLWwkVfr>W^v!YU+tWpU z`Fy-n-*6}jh`x;ueT|~eF6RT#cM|;V!!BoDf2P^a$05i~vV}mqTrPLTn}>M0r^0+} z7CE-ZJ)&~gutrEe+pMa#!3m%g12eb+ej-Q?2O(nb1ibm_a>q3=3} zzGq$fwnAUD^ZY57zQ>_206l=Z-l6Y9mp(o>A5Gt1T>9R2=)2LO&yVxLt{XV3x1q0a z3Qgv){k)KK*2j0ycLW=Wfd1BmT^}hfeW%Vg_YAuAo#K)kRIJp~aI+6P-l48|5B~wz z)^W};-d*^&Du5gX%U)*x5UFll_Ip<-g?{b&iQpoWdt9>wiJT8NrGarw?tJFHkF&}r~-_FO4 zkVD_x!Z18$ty5~eHklt=HLoGqeK>tCSO+}_Yag~8>8K`^_A}H+FLVFJ-{8l1*}pPv zPJIV&!aIwi)CXTz+uB%@UY*`NHh?2DD{I{3@slP@9v28?XJo=GI6GW|#qsKJ5Woe}0n$gp0%wK=V=^Ip6_7Cn_Yo$U2@^cHBR0`@TuRvf~K@=~J?A@FQu# zoFL6S@_#7)1Ni50 z_euNKjrr@*GrI-fJ6^Ib5x+&-`to-X-}Qws*s2h$fD^lRf zF#mYU^i_F13e~k2&RdrsD^ecq}il~CM)3I+w#Q8o{ROKQW4U?xeNOZd)(c7 zXDsUYc=0CGYx}ko{I={G%-_9V=Y5l>Mtqw$L&tr|%n`2^APy6kakJ`UgZ=gef+lsV z>xaTTFF0PyJXXJCU-!br@CyX(d^{rgu(Ds%?cn$o>ZvNErAGdTgFNo@??ZVc1mo)a z1P398p27ZFXLY?gE%u!e1sTB+g`-g3M(-`!bqHLCI9!J{P^__D&yJ0G(heI9arn9>ycyXq^So?yHsft#FR7GxLi_SzVF6i0j)hyxH?pd zLk~@?U%2nqVFR_#fWmV^K8dCAOUH?Lb1oUCmJj{CR8 z1X-@-uVe)0>DpWuOns#IsPg9pFV*G4o;Le{XHd88rYBgRpN`(am@|VHr;as-BWpPOnao;j<=5cbzd5PC^Z;+JyV$RNJh|h-LyWlR2N=d1OnbnLi2es?UmrZMFD+Q0 z<(Z>d+LWww^x|>sW9`dZriQ+GTxIlMW=(9txH<69x}Y~0gI|UJ8K196?x9;ukHVZ# zi!r%2?ad!*?J5w*c5nsnA*#dwDAY60|Ij#apa1{r9Q>bdFVXa2Y%RWY@8;k(T~6Il zt}O@NJMP`5PQ~x;oWgH0LR^q%w}DG%R=he{+CV|@r}f@ouzo1Uf3L1}l{WY7rD#u! zwXU9z1cD<6^*@vm?568J74~k&{8kcN%m{2;QY`$QSA|xRopaPPFAV>%y1A|k@NFpJL85ped zfH>5OwGI_Uv{h@dpW51LtyZnoR_m;7wbof{ZMDv`_4mGOuXBf!V87q@d!Fz4KmP-{ z?_PVaz4qE`uRWZ7CglDoceu22PEsq|F$j;YNUNG(!(HTCYhMDtkH4+>W4~_4-?93~ zF@G-p*w=a7{9mC{KgB#Bxx<+>{Ux{EIq>r*4sW;P{ncyd{M77c$G5FzBc7bDW8EL$ zb6kvtC3AjlCOC_(*0FWe9X6Elk~8bIzg^vK3h3Wv@{`XYJc;2St~D>E!TO)xWy}6C z=2V70fG_g>s`zhsKS?(J@L%3pJ{1A3iw_1a!(R~LwZQfGV__$hem^ zZac!>;e8+O97K401xQ1Tw+dA9Bst?hjTOz!4x}? z=E3JvhdLNdnLIp`k-i-Xlcw}d>N_MIfN><>%&k~fUAJa_x=CjW{}v5&cIH<#ZfHG3 zqH0<@8~ZypwrUiaYFZony1RtAyrwdLNnhVUYp>;A-qpD!zrL@vH^02Kx4)yUqq(ua zwNC^|QhDj%ge6@q9lfp1{rM1MD;<% zUNwY%#N`k(l`;Vv8#@PpOKNNDmsB0zfDez<;kzjK)`)58=4db>At z^tGDxty_{Pwof9hyfld@ZENf3?0_$HcjcG2^Xu;|rZExcMb!@UwBl1ZElBN41j}3d z`fS$aZTZW=A%to6qL;TNB9lBPe{nZ@Xmi4qgs$%G*x1q8x~?^URY!k&OK;<*F4N=1 zC8A1G>Qb6q7xV@8Pw();?3=$qA6e%m{9j@KosIqZ|MvJ#;|e}mAP2S~;^PWF%OD5G zv5uA=vyScFhmRt4Z)l)Dk|YD!ys?1eEss(7>qG*+3)Db|#D{?3V-1q!Elf1F4nb!v z7W&S%y^P@ltCvYu`x6MJ(S_aFAOlbHHy8|mfE~4<6Iuygmv^AKldGBFMEF|cU?6S6 zNJ99JDBWEFQ@c|oV^4Dm@W2Yhxcfm& zu&5QmP>_4Cp&&~O1@Fgim=W$0FsFTI5`);sG-=yk#BZbv%8UuQ0p7D6orsuFFhF(_ z{TsMKX@Rp44o3M%RVWmwLggdTM{t8@C@d+lXdntA66l6)vZGHy=TKBq@}i%Q0Fl8L zbHKvxb|{#3Q7wu|p8>8>;on||a7JI32|q{{lhNq~gBkdulL`Nhx<+E7AUXVdhGVfe zup1YC=sZjY*|GOwf$+nO&oeGxshD>0EtLKYg4yAh_)-Cz_Z9M(ST)=_{3^piE9bS_ z5sp|ne?N;X#yuGYq^+6l1TD z;0jFKX*(oX#OAwFf_$nz?J5a=mWAL>3BG{x)2@~vACFDjCBes_NZK_L96`;lmEiT1 z`$K-+B=S3$A{KF+r$9vM$dQ1v1&(E+e@Fx2IxPikKE7!<5_HxfC1Tv$&;in}djVO} zpG7b`^3gufDfToxE%Nbo$Y5f8m2>2iKDubE0*)N{l!79$acGRlXEY*=^*cyNyPi*D zMBYXLqauyY=^&yasM!%o(bXs+(&C8SqxVveRv{wMtEpj|!$M-wzr*Px>m(&R$_KS0 z?Lwe!uV*nge4EAWkD5m!hdX>jdvpYe#m=v&aFp*Dk1P=)Xxs}BmG)ovfGhJ9)XJR> zS4{iq;}mfOjTCkQpHjq1@P*w#BUCWa$LUbPz(=gKaW8_vw4b?X*vNQPVRG~mhu?sV zcEIA%%fyr>dfzY*mpkP+`v{7~qu+Nb#vn`dViX&_!kGXf7Ujn}qdSDij{X7-8NJf^ z9a8dOWe`_6?I1>FwRSa|=uYPmlrRP#nxGrpb|w`#3@%+6y~e4BPFYx`ndlFlN0CJp zxK0(A47TX?V$evm44o``gOdY)jYZj4qCZmW_BbGZ?C|ZKd08AQqr07_sX#QJY(EjU zG0|Z#RP?`u$d7U;kKQ7+o*2CphL7GV#N;TA8vUtr69i0+rqMz_bNB+#1%NlVOkOIno+2zH~i$?on)v41TaJ zdfp`Djl?*_M9*g!9>^yl)9$!|ax$SuUi7=~QO;zV_D*Y4MNgOpcZ@xVUJyNzEp1|Fq1fn2ws)*y z-jn&NRP?M*phViQ=72x_0~mfx^xo4D&X9)v4cpbk#DDH*PmIMbK~d4)(qXb=#nkPA zr3mN6a*!JR-AaTpaE8zhX?LAZnQuTscJ$%jQ=iXh-A9fFkBNyJJ}O=q6DN3#x=TLhe?~bG+I%DZ6wlewZkrfJ2Y3z&rQH+6Z{|iMVp9V2 zy?LM`yiq?deVp3}BCExu=eymkTULK}k4Ycz(vZREa;T6#L5N6JSL-^HK2Zqkjp>tw zfV~&74e#ru+&NHjaz?iMC5R};>x>-XLgT=oiWnA2}E}Eujrf^dr3-O^h(q z$4x_ZCYoXRZly{4O&FGrj6rQ?W{h?3rrG%bdB!+5gO!eQTQ8%)T?ir={SNgU&yVv! zwb@k7)-x7e0Gnk@v6Ytom~o&GdC_rHV5$(KvbqK~n2aJJ#z-H|D0bO^`B^IGA=R0^H{6G%&Y;28X79uLjkedyp1ZvdTs6Z%gq zR&y1?F}`&_R!d8o7@I#<$8b;vhFHB=81prnCG8JCVqV?_nVyr5n!?D=W z6!$NNvtuz>Df5Hb$d(s77V55UWWn^o_eh1!^C38uKLl`<&>vwBR{Du*?WWF2p^R!cCJwa#R%kzjU|w$D0B zh`cC`pLMhlPzr{~I#!4=S-mE!L4x_>wONfKe`1u)lGW_6T_#7_E?F%O8)mW?HLF#O zI#rCC)h0$QmPs#bo%1j%I5WByDra>#Pk?~Ap8}*k&WHFjmqW5U1=^)O)k=CV(x*bf zv}XoLzYX==M%Xv)StGpkNI1=qkf*4$Q#}hM6;+%Dnyxg&hdFmD$fb&jF?Fv;UgZ_Sr8cwSD%> z&T8hDw$FY=2)pXfe%;xOlss{S?7unJfv|0#{g(4Ih%wRGs6_U^oJ`!|kRQ!K$=UA- zF)_-Ib7p@i#N_A~T#|k)#MCHX#gLsAn2tQf(SJba>`0&<#LVb5=zs0DLT^bmULKj9W;Az=q zf!mRSp?N*zq`mVgtdRaDf zqn~nS%!_fPkA6m98Wrn9zlnZv7UIXmGGXiJmkj5}!l-%ltCJC)82c%0{cnaR$Ns{) zea-OHXd@Ji8iz!2^cap1j+|i5jLK<5Ku#m(M1M<@xz2gedv5eZ>KAk_0kI(ZKI$1w zb9RAPn8g#EkaIo4i|vU+SWX-&vl<6B}D4(9aIcsX+s6UyQ4c{qp9Tt;&CMhB1PgfVEO=RAp;X5>7E_KxMe0RGIJ*WvhC zIcuTnu$(&lX6H;{AvxE<=EHM%*H>=NT1d#tNk^^`Is9(K$ea$u@0BwE`;5xrmn!zo z;d@j@=iG&ueR6(>vc}|q(d?Tu96F56c@vVyI!WS!W5pTKUj7UC;!kCH6dYgPJb2AFbCwR$R>?U#}<#ML53@-GO zv|v;&O#z;tdbzp&7am0Z$;-&4e^SOVh)4220ij?H(!xCHks`SG&XpgkwTFuG&WblLM;SX77+;{^=41dJZaDF-(%ctab z4AL?`gu9L61K{D4ooYmcpGJnggW(q)p4yM*Nlo}AhmE_>&D7{+=l2Yk!PCO82+uy; z6$roTa9d!XX1HefHQ9RD=NkBA_;qIkeEn=JENgsvBVrIzboXIFFp+ghsiJZH$%a767H4Xp#1V7?NIO}`DJ@Xu0^9n z!p}Q@N11X`9ezR9wqE1|!r6gYkP|hu zd5)|^Otg(g87>>VLD}sM=L!)qqaI+JEiY!q6_s0#}8A&^406;jtBRMvX?Rgsu&+)KHLL&k64kmHC@~0Ww7L8o0qOvu)m5 z*2l!&M0t6Q-$O8Hl|Bd@x%`0;o`r^j%rmAkDY_J4sbG&6nKT$M4w<;a5DM0KoZpLc zegVaDNh0|QK$z#^p&)15P>`oOp`eZ78Gia`*fo-M_OnRMzzNPau3<6EYY6B08)5#e zb8bhpX!HRBx%`0`o&|=2uQ6#9oSlEU@3Qo%NcNa0ITZYwOf*O(ndD~`L&wB_;u*nR zgV?Z@&dsM#kXnU;6A>*!c#@b~#**T>a;0<%24jcE$n!{1BzHDdN^nbNNmX-l;@a(!tjp* zG}P#pb~Eh809$-?YqJ^lCN+W2-lRa*pYx%ho`ILLN#~sG0kSLTZArVWR zk}N9T9ttuRRr50PjLc?~Jn;qqPcD)~ah|Bp1&pWh_}m+coENQ zzAJUrD);u*wvlgG%@KrvtLt5&H$B4X5oSh8jB8~768%p+x- z;z@SqmCz&<@i8LqTp% zXAYO1xh0ZD=#Ct zHsBgs)(yGH$J4jW$7DqLjj-{uM<~eaJ(&ff>T?qP5B!FCvJ?vPDu;Ut2ff7(-W-BT z<9FZlA=#Y>{Ub~ElGuImJ7zL|?7-|g%yGmFNjn(7!qo# z#P^y=&szvj&FE$P@%$)RaqK5BcBGG{nrYl~;0KZA8^MH89lv72?;&8TDjLAtKi^jEVMU5;yD%p0UBmFFps3dybT;kxWif3V{cv!LED^7?W9YzGN1NpJ?)UzTfhq2Np; zrZ0t^Vv)aIfv_#(1>0r0`5$?u0@1NXd{hRwYgJy7YH*D^#Wm_J=4@Wvp^t%K8f&trUW`-%ZLqr=m)vDZM9LZ%P z<7A-DGvSp8AGi#T<;cDc%RC={&W=?RFl30rA5&i*({4d`b3VQs!7`FJ!Ji$uR^Lrh zYViq8cLn|mD_IY@V*en>qMjzy_j5}93S=>gH5(4b!VnSDof`K8r*^ti9T+gv11AO3 zKuriBWDvi?6wd|oIba?q%+-NS5U?0=KS12U61O6-8Df~<6xV3VGUY~G$#EKora1=D zVV+aWSdFRG`NE!)AiV{D&W?j8Vn~#Ff8ns=hd9O@Bu4#0_L6w-??F;ko0Iqc&FV1D zSI$)AzZ+CBB$&IQ+M}w#M#RlT9P9g`#MK72u-1W1f$2`N>hr<%0=Tjuf+_u{uu{yw z2r2x$$#_YTiq5V=98EyZ6TIr18F#W;o8r~V2bZ&BH}W0y_oS2n=!-BvgOjH^1)yhQ zUINLJo-!tX3jt@d?82W2dX~8C337YIm7q)DVTC^XG#bBhZPms73u(GC< zlp*C%h$vo(z~Km7sw^iU4p~hj;%=0<8fUtheG#HgLzL!+k8!*7;QfQp|8h74h86rd zJJ>g7HZqQ(UqSIhU>M)v|A;{GXz`6G8y;MB35=lQpRsJkVwP`UvrG!$PV)`dKwzd0g8r6EOv;+F# zEH?BE87GmZpydlLjU=t zrq~)X&myF-0iTwXBr_M+A!Yq|R7O&2r2)LYOP_2*IvXet74{lvMc`X;+w~xQa5II1 z)4?Bp1q*{2!93J(bljHDBZIS}_5jb8qs5ki5a@pR5;)HX2j3rL$Gp*EOMbt?+HxO} zv=#I$-mv5B8{iE)G6)UZlB^qe~qQMaNxa|_rk2$W7mU{)A`*$C7j za99}vX|NW0T0VZ*)80jql6M;zBrm@?G2crrqmVKRNXk5WCNe%Noqa_hayj~gvru|Z zgtL>_^J}E0LoMks4tvZdq`=}bq>YsnJIR$HZuFthNaAWRqA|}VdWutQ#L*5x@+uX^ zWDz#I2^o_ItMbz@$vNBYO>;<#;m_Ie81iwb+U_vKJHlpmVE*3j@O0`ilHBSAeHPf? z1uY}l3X}+wVqjW-j8k;qQ&9-n?}> zRk;nh3WHb{J7;hLGFDDq6MF~jMo_X2S3Mg@v15uj&`g#^zhS`bHHnlEuae>%?; zqaT{vk-0(AYut1vn+{_AfUBfa!9Wk$q5|R`QhYvAIIVwMQmngOhBz*1c4=HcBwV9$ zwu8qw=G7K4W7=+Z^=Y1JK-mCPAjxIFLxN?g%asqmrL*JB`Lk@ za_L>)^#p%o@8XnJem}-96y|w)3?(`{&WsmEo}W>=^e#w8?|R0QK4kC8K+hheJ-|H>b^ZxIXxp6_cXpNYMp2qdrKApCiRD z18vs>hsXtDzC&bztm_YzdzJ41J!>5YwYkn=1@;>ovqaH(qUhnUCf5t|r3&8ywYZaQ z+v(InpCzJtmvbD#G60+o_3Qv}1akj#`3Mr0(!%T* zSPvR!33@K(7=GjRVXG3cJSUk;thTg_}n%2uRs*yJZwIcxHKB56%r{C%Xe>s@Pey4$NmruYU#^2FkH ziL7?FS0eIO<$T2BtP7dhT*b3Dv!iinDmfNE^vvQe1URyMVP)Vv&dh!sareSm!JP(~ za;{!ng-DKq6JZS%Q~YPdaS)p?ao(8}3MhUJDW4!^wWh=ezLIxUxG9D(vBrtYBeN$~ zTc-GPqzuQveW|9%LfPHEIAltKXyFnh74v~$mhj7zvN4L3fsdIF3}NBpW~TS;kZZXq-{-CT68>bTJO62TL3Vyi%mtA=ORafRBLk z{)i>Wy-YK)c{d{ND8w~t9MqhBD&oAA07gM_;@}3t7!Qn&Hp&J4d!`Q){5#dSH@rNk|mU#uFoUN6w4^8lrbT_7EH`I{$w z$l)E&3J%u(YzR!U%K|tf3Qg4Ru9N~JSX&LA_GX+OK(4#uL$+OWy@vVQp3>bVL-qm4 zYlrN+WXL`Ov>meVma&j`aM{z2d&I)mkd`6&UKx^K0lk2mbk2QpA-@2s&cY*q9zByZ zhV0+Skj*=wX34~IznHKMv>n1fbUsG)>=6F36GL5P2>%f3+9A9IRx~tpaUlZikUu)e zc1ZRuZy5QF#OWfOv?V(bw_z?4Iaaf*=0sxg&k)D)`(!JMgSre*F;n~~k~qrj zv`K-;w~|Jgw=v566AarR_*N^=nT4$vSdMv~^715)OdmOB_HZ!Jy`&K2mxUJ1EF(_X zgy|vWe+QSdG=2)(3r6gn%!aSX2Gmm7Gu?vLJ7|RE$_Iq+Qc6 z1oBy%k=&omoTG+`n&sS{bM6_780(SYuaLL;M2xJ?c@96ntkJI_-$>r&aDjbgL^9s!WlS^GGqH4Xb~(RF zWc)sYE83AG9B_G`#fo#Gf9Mz+UV>JOhHSV4szovaXkTsh!R>=Mmfzv0`dJh71m?VOSRNwaPEam4_vAviS$Q1VD&s^>R2&o%xy;JvF=XUC&H4K&rtk-C`z#>* zTg*l)&q23y zPzdTk^;g}FnIrt3%l*Dw-cBQT%9y%s2u5!fksJuD?$p%Y7;rKKm{k{|79-0YuH|er zm9uxTvF>tXg{ivaX(+i^oGaB|xd{?REM}d#dQ7UfZT@D6$_dMi#TBSEJ^jSgZDD7r z3(yz10!^wn&!o)iDzr>wwAkgy88L`?g6+2I1@s5>F)sgdtsi}j9tcLx3%Rr+tPOXK ztP`a;+c$nKupKc%~qVlZK9RU zQI}!PrVFD`%Rt+rH|98#vT`%rtbMZT_sVgy(ZYd=CL?2hh7137M;bTlkc>k!mSFoR zsPWJ^Z5UYKlLRJ(_cMe@uH$B9WFSMD12URvbEhrIodfRlcxnby@ocV@iNX%? zBOS+b>{S4cBE*c+s-hg+6|`59;L!;UaL=ErDQsg{63f|lgkh1`DbkEm!*QBXOq8z~ zg(xV5p=c)N$`|JGX|`e_cmfDXr_6~N@R~`uTOb~@pJvZUWZz%2i}=Z!U5EoTrw~&} zEXkd@_ZYO|fyrWWoZ+Dbqb@Cz`b4;ZQQOPVxk`{=n1J2#u|~RHCF_ARQ8HjxB3-EEsx~}<_{GYL zaI^&L2^}_;AgfwaPvGDl#Cv?IcOno!&@muk1%Xlm<|ILnc|{5{W@9kd5Uk);$%1QA zcrh`6x0YbFtRZ-EYg2fqA|+s^?<6k9pJP@M>Lj{&C()L-5+OM-OUrAqLPjo_NKUf3 zroUhK$?2Fn0<%gyFn)|h2$myQ)_Ot<{s!B~@~%kmu1w}lHIe15N${>p=1nybnF6MG zClNC!^(D-c;0i(&{-F9PI~lNgvX=2H(Ro_P#RuDXfRDH2ZfP@-C9{wny zW+y{7XH9a>RP8ZeBWEokAAii5XjR5q3AG5t4@|PiQ%$%=f~yF-@i$m?%u?Xxx0B-x zsjA12Lh})=*`+xzlYDiAt0Y)Wu*JoVHwRJk@#pzZCBjGI&oQf;0B71De&v{jUmHap zIar`AiOmu}wjxBGh&H*Nz#1|d5I?ZWqAdul!C(WhlY@bkP@!AhtnOvN7zOYpL#8rBxfdzm%c%0$66ESObx&Bl{=GT_Nbcn1fQ!7>mj2U76K$|zY;$A9|mWNpg=i_g1tu2Fe*As+yHNoRet*Ygf?rM4Kl6ezVf&eYJmRT(C z%4FVD-~aFGFc-oW;13ld(3Xx_gt(fqxAXuZUA{>W5@~+s)&;$5`X$WIf$cmi|jl~}l2%hxR%G!n&Z=51R z>IhTuN9i>(=iA1rBY4tllBCxqOHZ}bL}X#VB2p%roWKe&nyTNgVNYBC2%gM)y7Cgq zkGXuPZ0x}&;t!<}Sb`J(zLKc~x!R@@C?9gD3fC~mLtqJr#jhL-@Vgj)NF~@j^~|$d zV*e)|`2XTR{|hdPb9+{ounndTnC**+J0yG(tq?yf>k5w*-PYr@9vWvv!1D5$PZ8^w zqmp@3y@$R@cOdSEKd3`kEG=J8sFGkcfnpqN@g*I+yvO{+Oi8XLERbLwff>m`#F-=n z#G9OQYVgNo4oIJCnCJ>?H6dGqs|mbzOm3nTM*osy0e+MGXBkMW2j2&LD8XvNXEqkU zawMv{it15n(&)$QlDy*qHX$sK;2JX4*jR$iv&NIi4$LYc4{LOc4HDjvU|ijAPHhMC znw$rc#O=3>=F;8iz;$(1Gv=3DyxFv#|u`4;i^y9AC|CMcl=f1;6p* z|9vd}U+7E!O(p+7J|g_bT41A$?Mm<_o77c>WmrM5zPpCt@up5pmbWIsyE>USb)d+C zKspz3GX9_h;bRHb6A;B%f-N~dP%J>=B4MZ|ER|pl;W7!zInEUltR}G2CJhs1@u>J( zWig_xm|6leVDzj8$dS-2z69lzREIxmm~@0}6d_%Lb%Z<{OX#(+_>CVnkE}$=YzJV5 zuxA7LD+tV%Ix=&?)+r3}S_}u-B~fuT=Yw1zQPqTU39i7e93SF0Afcd*!0-7Q;)KZ~ zUw-YZ$zV+BenpR;D`y^FyvOH9x(*M2yr1T*_21$1=kwEEd9I>MKm3*8 zZvo2l25pdX`1uwgwg!J39p4uY`{UQ2B zMV%c@MeCZIht62Uj2&IgodYec->gCp-V5E<-MaxA*m9@Mfyn0eX;7$Wps&}HQnaD5 zxxE7y!N0LW|6OS&VJC!C(W362)~>$3PF!H~zO+M|_Vu^4w6+ztv#U4sZ|Q06Lm1nG zh{xM&5k}{4YV2!82<_6?*EOAy8nhw%7U@LThMKw*JGyP4xx0(yAZtszVqc>Tv~KLN z0X$S~1AYCC&FeLBb3;pGzsC2s<9*UCn$WclCiD1vJG#~(40Un4pN+&tC>g-qPaLOk z!oCv@o^Z(c8WRXQ?v~Z_+b1mDI<8=TWdsi9@qOVsg%hVtoU-54sT0XJ20wu#`Lm8c z2l8ivkVgg5lk$BUa7OG~Fn(Flgrbr_ASvMy6ujTO`N-n5AGvf~QQ4SzZhxVhQ^=U! z&D-1!N4O&kC#-XuSG!~L1L35sm${CEX8{t*ogH+F#^o1{U$?$!TG7UJM+Jr@CH^dk zg4`1d-Hd#9pwJzb?`|rbbn?fK zEiPC(?+pGcYM*xo^MwjSthp1K8!DQ27B=`3>bzu}{0Rq6D5_jK{;oBL78D%0t{{+X z%M1Pb|L2I0(ZkV9`%c)nbjm?z7Zoop-Z_8WxPp1(#}yT+7RP*d=YGXICoC-p_pSkTzrxhHw)Xgh&?>Oa% zA~$m`Y<(2W3Uw~(IBL~+w=3TrGq+%zyI0}T;`V}ZMUysGE~{*xH~z>1_sAm_jdSx0 z-Qjb8GH>3Rf&d3L&+o4C+vtz{ytLo;|q^m zHg0Ue_-O@2#p91W?8s$DE^F^--*VII?wWje+7UmQR}dJJRH281&O~XlY4Zz~Qb6&M zOIr($tZ*|5X_f-FC*RG@m#)&fxgX;a$8S?wTQ$95NnOPejuToN`ps&*!G7h8hKkj74NFRDBvyDEJJ)sh;>G71Osk9% zsf;U4Q^z{IL8*cFB;&qfzG}U-fp7AnJiLXza!L7`2E5sQaYb^*+L9%fp=Y28%ng10 z=J1NDiki|&dB=PM-ml)(Z`yiWTjlNIsFSTyebthc6?m~+Wo=yzUUhE<`rGF4-Su7T z3?3hE7~&219rBuS`)E${iK$pw-LPz7!uGIbHD3RJ9A1x}T=!)ab&HoT zgn`#}8ECV9ps#UVYg|r6Io^Xw^|Zoui{@xu)zHvB>5csIPW2wCW3mBj@n-hcgwXOO z)r%`?pbNh~(9qV|xULWH{a;gEw;Vb)EG(@nwRNVPhSskBUTG0&ey@JZ%Z`u=Rxhns z(;)7p_3#+V>KDmZF8BbIq%SI4zPz%cw2J1F2)u->p}EP3Vau0Sp<1Q*MnSD<>*(s} zYd6h}ot;gXtA_fH0X(ZO&H!KQ?KJkY1|oQ6X=QzdG;42X1Dvr5pHq-Fl={G6UFaJ1 zJ(&AiO-FTUOG__41YmVi+cq=|z~Sbg8#G~YgZX-0Ujr67_+SBAh;ydbfIW@)+CW1m z-eQl}*`r;1;?=F2HC=^u_qVt9R5ETXLr}Se7b*M zd*k$m_C}b7iv^mlx2<_jNr{MV?b_I|p@n&+rZp8S8kSToT5jxTCHkm$PjgRWe>-o& z6)VBk6^FwMlDtQp1aD8~H!KX64h=o*j8fW$*8cWxk#8k7@UsZ`EJZ&)gwSj7-iDz% zo2)gUQ^Q6q49#Ya0L<3FmWQU@&HeZUfc96c*{o&Z>>JR(Sq+Ro`f-a?|79B1QE(0l z_Z+>pzO1gMqJpb1RHU!H6={4mVqYu122rtaNqmT7*=0)(uc}|>mBLYO5%Y>=Fiuui zmey66rcD^>T5Y6yuk_Q_mV7LKdyVHLcyVz9#*aQot!uEY-hiNZHp=Q-Z(G(j4L-18 zn}(m@NdAsT6IRu&ja{app}MA`u5L}kqWY@xx+Tl28XB}2;qqPRuzbI@jEM621nc;% zn`P15QajMpkFMTlit6zdk-nmZy-O>X7cFe-lD?y} zrAU6`gHG+5TJ@3AgVc!!Fq5q7@+#ia-e4Uf@f{KCQ!pK^Ye)W0ZCY(g8hIrK`j!nn z(~b1mrmlt!aH`hLJ#b|ig+xjPS_Wf(UByBf#S;!{m0Dh2SK*mCt}@>)%Au#R1@d}( zyVaTcx_kT4`Uw#YU9Fo;(-wRd#-OX}*eCtY*ty3@%eGY2O1En4>9Jmk5ySdm%ZB5p zYeQDl)HRgWuTGt+(3km949_X;CsLTZsiWI;c4ItCQbs(axxJxZyDfaf*0H`0Esu|@ zY@S(M>`>fSv4lwy3(>rtR7^_wO_TNQzz=B z(@oQc9`yh~Gp4W}-looT9`;LbWG=18{8zIC{*I{x8YjeXT#S#uiT+M^YN)ALxqK-c z#G7vH^kwLknAeWSXx-M0kM49e_nEHl{<2n_E5ZogkRc*U>rjKTdi3*(s>7F5$-qI2 zCPqG3Lj7F)v?ql+-r7SOddZO$3#G-pukv&^$wcqzSG61kaCY|6;cc>j*es(W%#j#j zZ4_!?2P)6ky&=VP(TvFsW<67TBqrX5WmxGAban6qxu&(Rd!V2YpS6TG}P7 z3`|@~8PtsX4H$u1p`Waf@wKAX-VU^Ce67F=aDphe!y1?Dii*uwu0FOe zdN`NxgO|FLknAM2GIcfJdquYP9J$2Pz{l~4EsU88fS%de$xlwfV=$#H_v~v|MKemU zERr>W9X8`tG>!N`Q=e_n_@V`Fj%_6Ibgv<>q(xIScMo9k&}%RUV76#(qPj_4pO)5P z7V8+(alE$zPHMDu+Gxoi$Fly6!KQ(o-?VhevW!b{u2hqTG+FD=bohRe!S0AOCzZhJ z6DvfV!oWXU*r57lE_^1eE8bmTDP$uTR;k_17&mf?tEhwt_-!m$23ExhSG?e4hQ0wAW1#5qrb)C-=|}WWJ9&AQuPLossHbgIGT!%7 z-2@X=(qJUbixstLl~!avt_o$O#oUdh8b09EAQM|$Ufd<@36ou{G&Xf&SdeqG_%enw z64nxs$t+mzu}Q_P8n_x_e_gh`s!nD*uM!*{#8J_=ZLg`aOMGE+wRQC3mzLqg!nHRB!p;`^(JD`~<>j^2rlm=Y zC!Y6m&&6D*bd zSvEV!un%|jqpQd~rZ(leYa!NMI#Bhtwn^X9b9|YKrBbM1%7@#A7*eFu#6MAobBeA$ zIS-H_8v}~zWSHfST+PxN*7+8v4n5A!EC zmBF)8Jkf%^JKDC$SeK;6l9GjHc^%GtWpKemaX7EF)3FQykR`*Kow+F*rou7`F4d>& zZOe_NBbv~+p|C1LgJRmXE+et?BNP*1w7 zIke9vo7u|22~>W0K6dQ$r)@yb=;~-jfP3)sum`_!_OwQjZJphX{nKzsU|wH$TYp;* zqk0DBZEWk=IAdDN^jV<$+tGcAoqf|LJ1#1;OzW3n1$0Lj&eU6REdtBid9!9B#-6ZD<9Z$x&)TPH#VC@~10^QM$rymo z4EArC*WQ8M`!4X|JB9tz+PLzbCTCi$6xP)}jb>>^)i~#Ize(I!jigKC)bZSYEivBo zbP4XRRaDjD6i=oSd$x(m(VK9kE$oolFMZZ`K4e9zyKu)%gnG+gdN5vuDBtIk{VHvE zbw>40{a_#0O>sABhv%ttL6O!_)w+$Rg_+ z?Uo7m7j;W34_{t0XhFuY0H@NWTa)8Y}sMC*FpDc z?6l)HwyT;N_!%ITET7GcXV4Q6t|vUhax($D3f%Z?li{3(9ip)~gy8dwGWIlf+7B=G z$sov+#dceHJH+sNpYjRQKAFi-k-m1U*kyAGlWqqz-Xb1j&nwkWIDOQ}X?vqx!*DHH zTU(h>zMM;K*hS`cwXIpW*z;mBv3Q%^v}oNdl`rj+4$2i^;|6cGNFIH73V>}rEFZTt zG~+5>()nBRU=-J5@zRB~1gh=-5T!UkV&Q0Q;x(u&iyQj~aDFHqutCnV_3W4DsdSk5 zCsge`izwL;NbFf8q;n+x7#5Kds=<_LGg_Ze67NL;HEvnL*x-~L8`DPag z#ljM&A(F$Inu=}oZ8g*yXs;XjSSes#Bi6@uplo+|1AfxH!#yln(qppord!EF4fMoH zXjzA{OxudG1UJ@K_HLrxG1yJtEDZrX%0Dx5R(NaZ?6hscbKG;u!+UYOBOigXtjHPuyt^fSaNd}g5y&ua zBk>O2{!*HieP-}1cPr$TXBFdqVJ{J=dY_SgX7sGc*6`V(ZE5EO&vnmZ*}P4}J9s-y zlAM$}*)sA^jhq%fJ#=Q;S;4LD+05_P>p#)Sdhs@yxINDdpB37gc6M-^d(QtvuD{&m za(G)$S=PkCwJ*(D?9cbVO(*MV?J=aDd|`L|;4M6*S)Li&(A zBAttAJF)rYCZ!A^(U%&RC5r=}_jn6-@iw2|q@;qt&rGwmxtuPeZ z5S9BT)_9u@C2NRg8;Wg+BH3B?#41G&P8_oR_QWA9+ry_@J$RPynu`R!mS4w4P z9BOWk#}84Jlr)i&G(yODZFi>qJ$MgXLzM6hoLrl%X zp2Qt8gBbk&?(IGl_I8V$A#PDAoL(|#Mu}Y|Czq9^woEkkZihi74$&&Q**J*R)^M{H-f)8+uAC(gllnL^Nf3e+CE%nSq)dltLA1VI;11129Xp3zP|Z??~DCpcXD zjlo0&=sBRMe+&KspqYO){_GKzr^}f8-D?$Q~nR|XAizcAaS^6 zM1nxbH6wlHjr66D@|8DA_#<(yL`yQtl?SBaiJ*B|5{GN{^~vAY9ED`ohdviT zI_q;Z{_L@@S&sl8W3$ID(}Tb?kA(jvAFg<7BF06lq}o3}k%*9M#{2XcZw3%geQbXi zFZoZ5=NfNLL6}d-*<+Wy+GMFm4$>!iw}|CU^64`vo|6IB?C;ZOe{&Avsn7HH3m~2K zxfy@<*xzhNfHt(pE^{dY8$A;GT#4{^lIUv@zB-Bi5yH17(f@_;lSyu9@yD zf4cA|{CT>MpQBacaLr7g{F#YFgj_SrCx4bt{wyCqN2|o)nuC4v4^AW^(bV>;NiZYi;%Va4`Jm1xzs|=Wf9zM~uky){KLf1k zYkcz8n0JxF=Cv<~SR?uQP6m6d5nmVZki*)?&v zW|L3;CZGIG31);`v&BcB;FEuXFa1QH{1bihPxSGh?4wWd$>;2!I9zj@PyT5>`KKkA z5pvBLKKe|b{4;&&TYd7knl$t+b}wFg3Ye{ue+(n!*eWkXDTvd%OfJIHljyw>=9dlZ zvCE7@cuo>M3E_oF^nnQTeIp(}Wwj*Hvk^WfiS{^&u6$G{5#wStlj_f0-6Rgzoad|W zd5J`XT=Q)oeSuHj1-|qPed!mPd8+GXa60BfAOA%@{)>F+7yHsLHbe*sZZXe=0xS6Ec{%}B@WkI?&H7QT$ECu%M;89x%kRss=cr9rC;ewztZeZ zsSj6=iNiHJef&GkJ<2~9Y>v4h!HkeQX#IALFaI?@{vY_#6K6JLbj@|X^y_^2Z}6r2 z^|{eJsrp8c(=j*t^8eWUQ`33o%(XMy$(+H<>)zT8LO=%at-qaOpE(C1k5Y6{(K zK1rdm9!pE+-(d1n=w35Bh2CVUQs@&+YYKguISI6Pus+}Q(bp+IS4zVJ=b2ym(jW5C zFZk$xD$O&;oWOPF1Eo2x=LB}+D-8(Xur$W|6ndwbl0si&<|%FEU1XM}&_6KsN>e85 z)9Rx)`)Gcb+&jph^jeXL-raZJ%_kFE@X6tF>`hme7xM=j@RjA*=&dZDnS7rf=!3kQ z>Uc52%RcB{hsyF<%se~kHc*h*TdpiWIDRuRi0M+=bSZec6gpi>oj#MS(+?W@K1?Rf zlBeJXT?t1DHk9!@Cvm?Z$%7eLQY?|OQw~Z>Es^p{r0fzYwd5e-l?s%I$|bY?&$y>P zrRZJO7vjT zM3Ua(p-%;~Sl`7vDcc|Cqvcw&KTayQhim0~xSl;k-(~%Vh>rUc9GcFP^jsSKM;_=* zJZYZf8cCOX6Rp9gMiZ1|mZw3fW<1`zWqb&2&@cS8M^sX&sgyJ`qWqV7y(^I^jsw29 z3W;}|h+__VYe&-Pf^1_kJ*7t-xn`7}?wEz7@yU!T#Wux$poK5@UEbDKQg2IHq{>cFf*eoQ_wL79*bJ9YV}E>1L#CZfEx zL{DB02p*6(3XslMk>Z%Lw*V%82Uq7nW8&wzO#1Ldxl>7_Jnr`5Q!4U0x^%o*w1+f4 z$i=hd^pTESH)6ebmb6wk?WW{|;DK@}*Zn)M0^%ABHx6)2*;E%gIKNpGDn|2svIoM1RmCALY;=n0|xe%|N#t zA8aK;?(M{d#{5d@dx#bGO~p+A9qC2(?Wiuct{+!EG=Xs!<0HFD1I(1e_>05SZy)so zv~w|{)3NCz?YpmiyJR}v)_g4E(XQ=4_Y<{mwY6`&eJhd3!)xESwSDuoed}!Upmf}S z%wx)tdq~%d1XI=~((@2Z$A(fq5uFT8Zs><%-~Al9cAAcQtz|sw(@Wgnk@jPKwvmS4 zUra=Qx=QgnBK-SqBJ$C0#21JY920`7v;+PNQZ@HDyhD_@9eu3}L5MiI0N^>8K z^jxJED9!z_waC1fcmRHIOyOX`!*55gpLkoXUi#mCcJ{VH{pp^azh%Y8<$L)(JD-+F zk0F>|=*T-#X(zfi?IYt1?8_!gpXSK!GSfF|`sqYC%Oym#%MXa-@hx$se@R5U{ed{j zG4xZm%S*%}$NW>{KPJ+c_@9mqLJX~v&LNBCqG^OilZzbMpY7B}L}Diq_U$E>p#6zx zylp`DJY0(pEv-gF2NcZebBk=Ir!^`j4dxuRP zl`7vdg^n)E-odqWO z!(!5C@0CQfH(i)0;~Eeq7Wy*cq3REaznL`r;vpj1>rLWZ%nvXdzF^c($lNF~b&QzSExIl5C zVx=OhKzY=Mc(fw*BHgYidX(G#95~0mVm|=kF-;f!Fes(aFjBszPb4n!rC0dUv2mTE zH|WKhzmmAriR-tPG}3!CyM8tXTL1gB z{-wV9`|AUJQ|beIh@6)b<%OvCzg3QlFN~1}VhJY5rB%RjOaU?A$bBYEKSa}^g77U; ztX1UrO1?(LHpM>06BJKV+@`o)@iIm3wo}dxitKNspHX~C5mUCrf36sIERC)z@db*Q z5`;!q7KBR()+wH@c!A>g6|YykRq<}chZO&)_=@7c6hBww>sG0Ew&FgD`zcOWoU3@a zVvXW4itUQrBc{BQ70*$;SaGK!_lC)LhvEZ@PbTo$aeu{`ilvHG zibpB7D-I~0p?HBJ_jIY(4T?WkyjSr7#U~VBQ2dADXNo}#RFspWI9BmM#W{)(#t0>whbLlqY*u2gJP+@QEcal7JGia%1k zP4QmEM--n`d|mN<#jg~(CrbTBC>AIdDjuxJ*Qt~57{w070mai5zpZ$=;tv&XQM^m> zA;o7DUsilu@pHwruq~J8E~2O6A&Pa1O^O>7Pf$Et@nXeYia$}jQ}K6-&nUj4_%Fo> z21qGialB%Y;#|cgiYpbH6;D#URPhIjw$zOVRi#S!UNj{?O~#bt_X6k8RKSKO|6rQ(kiZ&SQi z@lnO+75}FAp`w#v%g<8WM{%;^L5gLH%N37S98f%6@jHrlDL$n5C&hm$eyJG61Wtb# zsW?HgSaF`>QpJ^uM=7=`u2ffUMUj#fgf=ic1vh6xS%WDE26xsJKn>V#TW!cPrkm zc)#M~iq9*)sraEH7lhQ0-<~IqR@`54redk$k%}iPo~d}Q;)RNrDDF_aM)3y4pD6xJ z@t2DCC_bS02gN59|E&0e;%ka;DZZ=tvErACf#J4(5ydRUJjKz9`HK4~PE{;XoTE5j zu|jc^;&&9UP`qC8r-~0KKB4%$;)jY~D~7SB$MzVmxUb@sc{cuD#YYvNReW9XeZ?3S z`joS`;(m%V6&EO0D6UuBqY+GA@gT)2#WjlS6*noK zq4*ue9f~(8-mdr?#eXV(rWhV?%O9^eO>vH5x#CjAPQ{HxoC|!1_%-$mHU284uT}ac zrEgXGS4!Wj^utO&r}!cfa$^%L<|`heSf$uZgnxGtG3IU~LXU52{AEgCsq_s>|6K7- zBJw?^_>tnUi8g+M;vqzoQ$fV$MV-HJ! z?r+S?M3nP}(t-UzPcvo&5%FUc_g9>%>GPCcq_|wMPSd*-&r-ZZ@fO8r75_nmJ|7cj z;ax7!iF7s*<&RK0U+H4SgEW4D(iKWqD_yVjTBW-b`-mv#Y{gxQcPc)k_>tm>$(DaM z5qgyo55srdl|GsXJsXwoRQg24(=`5krFSUqB0|ociq9ziOEG$YO`o7RPjNM|(wOx` zl-sX(lHyjy?Zi)TeS!%7>oxvn#oILgQ6l)BQu;l`j43wXIK}yjs}(zlutz_!4%Zoo z(B}%pA1mIh>3<}G|79XJ{XWz5=z%t077_9L6Tw$PT#I-AC@$6bdSV;C!$w4TCn=t< zc!lDPinkHL|4Sm|-cS6(nBQysOGL4eHHtr1 zd`R(cirgTjUU`a>6&EY6P;6D)PK5rK5xemm8xeZnru2iF{v>h0n71_jGsS43<{R@b#y_C=rea2suiA zuU5KV>9tC?D&3>>sfrgWUZr>~5&GRoM0r0~yi?y4^v#D*sOSx;$@1v6z^2LU-1RS_Z7cXOe?YF?5%i+VwGZ(;x;1e{$1jQ#{8HF z`}|VzA;rfu{R<-aLoY-l7b?!s_(~%9RuOj?)27&?@tcU(V0}VF{)?5qPSbB8 z-hlqC>3>#yQ}Jz0&z%WAlrxt26Jur(A#ai5QjKpRg0GwSGhS@^rsw-aB+XC{??RPi~*Hx%Dj{F+#f`;QI=qTV?~ zT#p>7^aLWV&rMePAYvJ=qba?Jc(`MhD!q!h2-h2x?jV+8{jBu4ia%8Rwc?A4pDE@Y zf_%_tKgGFO^TN)-lTYk;6Gwec`S(OTM)ytV430~#bt^s z6xS#oqu8z3r+9+m$%R|Z6~9%qFlR7)fZ||9zGKAjk&3%2j#n&KtW=z>Sgm-l z;tv$%`8nhrsq_lPV--(UJWcUp#mg11Qe3Zilj5z4_bdKU@lnMm6kk<*L-7MezMDin z@x5BPFAz~oDCR5fs5n|tp3Cot{h>{Pl( z@l?e#6wgsSU-2@Qw(I>koCBNW>edlgqIu2DQw@lwULin7n3 z7ItGu1MgD2NAVHG#}%Jdd_nO;#ZMH!RQy&k-+|miF^&|6DW()BDo$41N3mRSK5;Sb z2Pht{*r3>|xJ>Z`#gi4!P&`ZVe8r0uf3A3~;x80$QM_Amqv9VFA5?r^@nyv~72j3- zSn=bp!5-nvJV5{$18o3 z;u(r(DPEv>iQ>-`uU5QW@h-)UiuWl#uJ{+l7ZhJnd`s~?#ZMGJSB&O(^%YYrP#mbZ zoucgXfIg+9v8bJ-xVPediU$&V4P$}gVTy|syA+oz9;diU@m$3V6|YddQt>w8F?fGK z@wbYyc$#5+p(y)EK!|_ z6=mNE@7CD9Sz<SfzNN;sV9P6c;HjQCzAh`*l#h_-CsBBh%Ymn$Bv zxJq%g;+cwPD_*I1jp8p9Z&AEU@gBwd6gMkAqWHMtD~hixzNh$+;^&HADOyQS@2Fy~ zVu9jt#Ziir6w4I%Q=G0iU-4kY#fnELt|UH!=SYgDD9ZjQg#Se8a}_U9yh8Cm6mM3P zeN#wxx6;2?d_eIr#U~ZtP<%)63&n2~Wj__<<>Ouj%UP^AOfh0095-#iF85uEiHJ)P zai5@s2%?lY8qbZ1WAPk@i0h4+M6CO(iL>?n3am>Pk;Xc*g$SaPi1YmlVh8TS5OH2# zL&W*_Y~m`sS4718vW|$r^+b&K4aCd5_xw11H#dSoq>s5;DiD=&&6*mx5-uslqJ4vIx?^fJM zM7!UoxS5Fde@O9BBKpA-icb?~tL;qSOQfOvYl?3Y(Ldf*{E)cFFg{WIoQVGNm7-yS zM!&HY<-Q{N4_>*Fe#BRc*pK8r3?N@kV}HUcQi3TW+JB^C3Gr<2y(nTSY4o#6ihM7M z{SB{L2~H)V-{Drf;7lSaakiq|k3>I|`;owf48INU87VFzqF**Cwh%YsJyFF@BKm2M z;@l8uwBK?f+U*xawAUYqDf}(`(LRMlv`Z-w?a@g@J6uUbz28ejy+2MweZNLrWEiwX z!}^_K15vMYh^WuQiKxF0;wp?&BI@mZBI-%*x1gSqyx)NOk@pX-#Qg)(sE_GH)&mjx zHxr@vaw7EoEfIPa8Ni75UM=;UqV!ZE^j)NM6A^l^Q2JP6O8Yg^uOp3mxRD5Y0}=J{ zkkXG5Q7@k;E&U4hBmD*Z(qB+d((a(8-BDlC&Y-28QE$?&pru_GX*+_Jc0@g%$#w&M zHWBrCnbPZssMi~n-athC-mUaT;wqF^=|_pE?@yHeoQQgt`^1p%u>Dd0MMTiWM6|<5 zrAvrcLLa5eh-jAzrDqb^K1wenqMe$QmiKH>%e;40e@MPzECc=D&?ksK$j<|F+rV3>ksaw2r*e1~A z;h*_c;7@sec{jozbbk5J70B0ll16R>GQFRlj|~V5=DPy^YfiwzHbqL zsI(r7Ku{iK(fNE|!XM1{CFEO-uub@5I!fm|8R_v$>%sAVBWU0G@&+P2DDQK~n+c{( z_!r_&K9+;^ieFlfB3~hd(J_v0w#S#&gM3U+S#*BBoUelUPQ5kLuLdd~)1B$bOY1QV z^7^Yk>KBw(9gxTR@%1=K<@v?uJQQ?@7I%%um)3)PEDvST`FdQLmG7cJzMND1eBai5 z{eH#gV?83tJNWW`pCzvo@~XkI34d%kPRn~q<@v?G%J+EU((Pd*9IRkte;k-|I0C8phgsC*+ z=nnGu(t41O<)JJ(KVQBd8q}i%1K*#oMkycDo$1L->oFDbo}(ajzP!#Xd1a7?)12tR zIo{XfB$WpcH_R8Hw6Dh%9$#7y^07RWMdv5GBrD&|0X=q6KBnXQs+8^btC0}UU%$E| zOWxCvHxubL;Xej{=1X}`syu+Wi~Is9?d$Q4$CuWFd`wSSbbhigvhq#co@tNq%ExrG zQ2#+a)r&)0+RuLhm3N2|w|)`NU34`tE$$(pnBof^n@ zlJYU#?V7LO9=B~nj~{2rs}9J+GBDj9H>f;ckBxqTz(eQj!F4nIX+6lt@=z9?pX`yW zd=~}s-BbCPj?Zf;+t*_==>FP+&wqpM(HW4pcR=0%mFMg6gkK==(D{1otPWR-c^>_|6&r!bf)_cWL`;Xf6B@=@Li@G!Zr zM~PoS2&3~wU+eLu^&lV9PbCu^<G(XEviaiw}?@Yv#kLmb)I;cm* zHuNaVl6O%+-T?u52dX?@kLqpc(c|%@^&lV1Ls@jb9-UeFt`FopNBNlU4$arkZs9ic zI5$h)odJ3C0`hKDdA=S^zF_ds`R(zD$CuWFd@K)T(fN8jn3eD5K)yA~$8>z&9&C@c zZRqiSmb|9}@@fO}qAJhVBWMd0Y-v4cb2Qkm$j94K|Zol7M-6j?F9t& z`23fdaekQcG2O2;Ux2ug2<&g1|1?XUb7w~0;YjK0u|ehedXzGgfb;cu+T%;>K|Zol z7M-uh6IuBd2lA~~KBnV71j+`xxH1Ixr^i=W@=5~o8j;f1V~EQ0^{8Mb0q5&6&Ere! zK|Zol7M-uhzTgYCM_C}>#mdKYXJzRz8-e}lu{cZK%z(U>fV@*wp0CG3W)g6|9yfY? zX+6kCR?4FD^;n;k@4`U7OO=o5{-OE$?Xd`f{ps;&mb{jLyk!A-v=70u`g*i6lYsN} zC`LH^X+6kCR?4FD^(aDMusv1;^6gYUrfb20vVA>zK=-Ey_j?58tqI8M3drNWkDwkW zf(|-gkJCNAv>xOmD`nC7daOoZFyD&;`SvOw)BP2PpdM>L_ov5(EP3k#@{S6~dral| z?QtIHp!49-& z#h>oYfV@?peLe0}dA=TZGn0Vx^?1$WOY1>CvQieEug6PS`Fp?!2hqCB=JtiYOnD0x-*S|hL zUHO>qSWjMBk7CgNSff0@JT+PJK7_n7#Baj?NBH~g!TmQZtDo)+&_UHEOvfnGsD>U??kX2~mqJpVoe(bwbcEO~M4 zPociP^X0vsC2uq26@!WO@>BeMc`>A??zoH-R{^?6{RCfL6yZUAUkd1Zp7K#&?hgvq zGxq^8o$vg5K1liee49X*_)I`Q-x^InRpUNHzA5-O;eR3iz8>61MA^Q)GeP%P&)jzu z)Fb(8!&roLly@=yzP$BW@@z~7!w~N~zkF9^$?JqXzaLx*W?$Z)v*e{9ufKZ!QRS@?9Q~_jQ&$?l0=EeE-OjwJ;f@U256O_-7TA0^= zzGJ}`tmli6uiyW!gdD$KXcvfbeR(~Q*I$1=I7{A!fV`^$@_Mr5-M9^TomuiW2jpE7 zkauR5yw@Oa3gUg|_k%TA@?L_xQZQ}8e?9)bzBi~me;!Jqv#@=A$GV{7{ww-@z7p^a zkQnda^L?CEzNz5ruOEDnRlelinSOdBMEd0$mgt-BVUQQ>r+&WEl+P~`?e4rEs2HD* zc9nwtAccH4qkx-`@TNe%bF<_fJ_pYl{mKQOFOU1Zd_VKvr3T-d;e!u#ejN9Q1@nFL zY3#iy@bbL{yuQ92S@IS%V$Z%W4Cu?_zOtaaJKw>%AMu;;zYTw1-bq>V<}?}dE)Q75 z`SOm>lDF<%>>WX4Qywo#eR=0)$$PljFu0fAcfP!{v*cBO;O%9gygTvt<*ieBr7Ga= zrI>ez_|iOmDf5ObzSmZJ{l(`b5C6AimG2Yq1s!?lHuuAKr{B2|&+^gT2fkoEmwsr- z_oFr;?jHPoJ)Q&~=8R6Jp}TPn-re-Pa`f|M*YM{SM!X2VElBG-pN|+Qj&a`w$QK>| zUWB`dWWMO)QnsMHQ*OY027j@IcwZjO(l@vFE*sZ4u48-(Zo;HV6Y)Ka$$L&rrFJi! zfRKr$5?)$5dD0|Olgr8&kXn>;Lgnlkrs+$f%#yTRWMP~*i$^0oNuUJJKz1<7ZntMR zGZHht{rflHHZG0tHve;H%mFtOi-)b5_V>qztcU{ITc# zw~v@!q>RPD(fG42cgKG^{;aQR{G0G+J@Q)PB>dTpneSEjvkI|v6Z^rO51+;VZT#66 zI3DAu4lHTpTXbXL{}v9UxCQOqoz0D{i(8wUjNX8MR`bf#^p0hnT^-9>yPJ)r%_{@c z^zvZb^zuMd`QpW`ZLRe^tsU*D=`H-Ucau?{3G;*I_jWeps~}B??ap|oH+Oe?N#`w2 z%>#!JMx!4*Z*eAYdUIC~irrY>)0~>w(bfd6bb!z`&C5ELH>YMmgA_iNfRDeBCP}Kg zt95y6Tl13U)WNMiElpkZN44`CIbK*MsJxG+G_yRn*wnNdcak{iVgHUUX zBy_^Vn9zwHf!rX5W-e_z+ye<=8}wcxB=P`+SbU|;-n9}T)~OI;hA$ECr3}4Pyd7b9FB9)hWVl?swe(&g-s>=~!fVCLvV_-(mmj_g z|4h8x4;H>sydzn%pNp5)R>N2C1v&8xF^R^brr7}^u@ss|L*{*jkd=56O%b)sU*Rlo zCr(ELM{V;K#5jia1f^bkG}B*)h~j9y`4rPnBv+&P6_OYUULr-C%u(>$iL)8gEQFKb zhs~mk&EG&+Jkf%V6kQ@Q$pp>VMq7kHo7~E5*1ybb_`Jc1?r-wF%|sQ5=u9)phu?|U zDXdBe+pvy7Q1~Xk&FS#fEbA4h7ru2Q==fSF=S0lVY>Jo;zK9jNQ8X=vyoeo|it_|S z+=Te>Z3i<6-|{GNE-)Wv5}J~9E|MxR61j+RE;gSWNaa{l&L!qwFljo8kCCl&sd+ny zc!K7Toy&wsCeA?vIG3A;4n~KAED%?iUx2MRx4FI1aMqgL=$69_i~G~Uw?EAS@b!t= z&Xp!#XUuKvYBQXx%|%GB1-M2FFqEoYD;4S_3XsNGZ~hXw#S`q~&UIS5da9hunkLa@3nK25UGSk4Q>{#M<&jrv|EHINgT(RTh09-U`*nA z61SO0f|#1vLblt@qd-(7-az|0cbI3Q&@=HV6;R>3_%zkcMUo=t+^^w}?ZK)!|M#d2 zBlcTX;02@LwPXLma$WQgD>n8VYx(j!5gw2Apx--JkSA$aPqB@E?I2V4GR8Vb?+Jg5 zuWC8RvW1M;F7zMA4rj-9W7^|?O_`XSP>Ar|6-+w@Vum@Jehhz(G|2DR9!5;s{XX{m zc=wytqk~+VC9{!>jx9K~Z--N%|u#QCih3~nDGH-{>r1RjDEYI6GI1j%M z9wR2*=TFjmV$yhzuxw6D+U`+lI>SnFaR2rt%DIj8T*KW(yhXWlTMc(t@t5Sbmm2O^YbfMQ5fxoek&4_dFqMi@7_?VHMELi7mC}{_ z!m<4?fnUyzv6)oDkn>@zinVCxEURB(#13FM2H2yh-|$0MGwn=NK`Q=O1jUW*jvf*J z^SPLDjo2dyk3UJxaIOYp{F#Rl9*^CJc8Wju0{qF?#i-Hviw-WGi(>8IjK4~r;@F$? zzdjM+!;HL&nMU|wzA5Rh!eL7MExuJ4<7^avy9_KwPNxxncVGDIoFzv5J^Gy3B4`(X zpZ<6(!Yn_aKN;Hxbs7Jd%blWF83e^YrLo!K*!IvU{#gZhigS)M;{PD`u$&`|_!so0 zVhgC+mvmB9*unMNS+j0x-BL=9e4cM>4`1HMB7jqcHg;4w93Ho!e<74mPQ=lY1oi#2e3DVk8a`Z!*EU zPy9fLq68~HahMRriAGdJ;&35`<#ri~I`O8YmnP~({>TKICDCZIT}l#cmqe4vhAELs zO*BiTj*&`DES5?wm6KCqiTOh)I4LoQMQ$}4L7=+%a!mM9zWV6!eOehK;m7Mqe}tN_ z_yO(klSh(14aKv#LJU8{>BxD4G#_GxpF0P1d>9l<=B^Dr4nhi(yDr38!J8#>uL`m4 z?F7$7xi^MRME*{q8w%uZ2t5D-3(3JO%$64@>^R7so%fu{rK7Zc-t&RB&wDY@_IWRx zG!5&uecmfVBoob$lDEao8N{|{N634_ECb=Secsz9&BG2$JOm~3J}}pUNF^Rd6X$&- z#K^?0C}-X$LX;%{V<-Z(m8-YD@V(FyZ*5^qt0AFIt9EktpG zRv+?8gcz1+L~ZBoEJP|X0d11EYv>AOHB$Of-nbA4r`N;s#!I7)@zg67^-2?5(d11G zu~$w?JjE)R9AdAWl;G~6ygh^{OH3wFCd8D)!OUl$&>qleYT|zCS01`bs$>cqWm@P? z#LP6@;n06r^!O^U%Ony#ksZm1y$i1Bsu`FQ?HD&3M^B>PiEV~5(UV)TAdly8{TMyv zB&^DkvFFjC(bcrNTa?q(U_?*l^ozC2>nMBp!&*pib1}&jId5LhtY`+@c{_}xMvPmj zopu@8pMnqm7r59S>8re(OXb9i|=oSKdlArK82p$ zv3Mj{7?Yd@{zBki-4hIFE38cmBZ+ zR2-|v(fM*U!iU9fVfa_{r(zE?{OjZ49~rA*U4KJ=N$h&+_AUKm68!vtW0)jL6Z|HF zW6D+Aq=c;TL$by%OFYZ0Ept1RdrIO~md`dzKuk?EGbU{A2BIRDS052`PxxngtNN&{ z>SyQjE3uAa&O^*1Tp=w*$)a3hM{FLg9bh z6tNkce3}9IGpr*~ulX~sLXg!2HS(LTMY#1CYB*;Lb&uGO@4v7&Nr+6uvzW6s;C7?}oSubclH5BMu80A(4;C zhkGi`xT*39b++ZoEb=LHL%Sx>og$x21OI@PNE;bqo&mq}Df+~Kop6X8Z_*fi^a-#J zv?DK?*I*)*M&vcQ;w(O% zs%rcN8UD{qQ3=mT;v_| zIr`5C!~d@N3jH52?R(~%^z#Zb^1k^#{d`9^@`3pY{l6p6hvpabKa7G$U|+>CL&g7Yt^=2C40wyx z^SK!ZTf`=F#I8b6{9;sRJdzBpV)}zv=lODCGZLq;QVK#GU3Ov_TcA(~#~84NZB`VT zEn?V1+&ef$71Z5{5Sb1O7BSd}?F=CW_2*ND*N^`IjshM~0A3rQhk_W)b-y3{IQ-J* zLpY5}V4&kO42gK1hr0DSN2fXYNUMM(qQ?TFydpv!!W*%9ArrB^5MF1w4|0}GoW}0~ z7!r_qJ1Vxj@ajr zi52n!ndI;mef(a4cSt7$_iG4^deV6dAY!vr5&I4tMF^Mf1wUqmrBfA1?i370etkd~ z4teeR3N%>osOPsBFsimUc}WVxZm@+xzhIJuvA_;ZReqgk_zAgJixOR<9&f*Ah9^@orUyRU*eZ3q{BFD+X!Iw=V_NnBfeWHlHNjP}( z!g)(N1MhoAY%ZuBe(@_}zbYIuJKMag7P0?KdDqLRFtARE*c*g}%hrfJUZzFfGT3IoFarq>>Y4)Xz(Y$3_kt~_T_;& z6p#eZ5J1GPz%g2dgF6fCWzoaFhClXev`O@b%*BXRLdWRg^xHZ3ymoZa9YY~JMl)a0 zhBYWnJoYqNDcX1i{K*`A`W*NEsb*0Qzb_wcrb@-|cjNy4Sfm}6(@mb%8u(KPUv5O( zsLaS5e7zkjBbJ~9;ax_w^H}hV$?0PFkvG6!8XLnJ?WQ7=4C`B#bDo0;%<4Ew6^@3- zQ&)VdE-xRg?Vw|{rcC(vB|m2?mLpR=hV^5FMd$xem>S8%%vg|sP@V`4YgckEI88Wz zOitDki-fhb?}r~+J;8L`V)%oStcw_|)w zI=XTi{7&o!=6Cc$_~TyD$?i2O6)E5WH9>jO@RX2=MocjR22)m_(1{GC)IR-VCIYM} zY~^F_hQNr;+v5?t7s1iP8OIM!M$cg1v1n^BdM=j@)^C~OA&#)2cJxI)LK^l7i~W*# zPh+2dS?=~n?6VQ+PUONP`us=m%VW0a3#>##uAQQO)CJ$K*s|tfKx@99G zA~sVwQ)GaK@JML8@nAF;N;N>nWce$hQKqzJka{sJP`2!2#wfB zOZl!uqUdUP3wih@D4Az+j8RoA>D0{#@%Cs%uZ4G~_mFp_*y8GW^dsb$_jZPZB1`T? zc_K{~i^mcaPzz({wdf?VA5w3YMlK?ZUDmRFj+GN~0X6q{4Kv>ym0K9Ia);(F7?f}F zG#DCb#A5r#EYz$u(6Dm%itQb%f?!+2(Qm_fU_sUdMn!ir2u>l`r=YRjLet8P#hB7W zI6l^9Ii8p@B*WcIUnT$z`O^kZKuJb=Y)Xv^$N=k3Ngo{sS= zb}!v?`EJJe^3KjS?jXTtmG1G~O-skOH!U68(A(bB);zwaqob{{rM?w0^t!+Kyo9ercYHc68qHJ>A9C2 z;dmx&ZEtMrZEF7KMd)m+?^)c@wG1Wj@*P_Sk&P{5QK0d?-Ce$v@yqHPTUy)yi=-Ku zdV)_2I=-W`xxKr)4Mtx4%~`C|?w+Qm=EdV$*hF9d%lKt#nuk>^inobHnk{r*L$Ak<(-}f*E<@rqOPgFM~R-6uIBnC zjc8wjy7By&O{Ftg&lqNE$L)4BLbf?;7LSnw>Wn={J9hA zs%k6e7z@#P4%)4*a$#*<)x-*;yY=Yix}LtFH4@7DFzVZubaY{d(K4f1%F&ncAfusm z2_9zFHTJA9mNd6>$5V41Z>}+NY?!NiT&=mo!I zytucmt-XF(GsbIgPg93(i;}2rlofgO^mZEcOR?9d@}TOvITe|zL7h}%o7E90MXmNyR@JjA52=%O zP>ERBdUWO71#>EE%4;htjJf4=D(j}tn+vJsRdZ|S8;e`pTf19~#`?ClhWf^(M%DcJ z3s4<(6;<y|b5v~-AQPeL7c(HY1dJL9@Aj8S9AqHZ}RJ%fW*;_GmW znx*Mz>}l>{3D~DFA9)I*Gc7|OOsCzyaxU6tcHR61(`sufD~;}EZ2Fs4wLjV{*h^+G zuHh(*6|K=}^XAR2ET1d=rnxDFxwy;lD|cE|ZJk$vb?{1?`?Z73eO~Q!w70G7?pW50 znV_2^xB(M-bA7v36&k(0qaFK98&PL67dOrCZRo)$>NdtN=tf0v?iODbxts(D>k&(Eko-xujusn1N~gm&zoLb=~sl&u(Ahb#}1>q#clOVx{c-a zZN1HgH$xawd-a{2UK643)^WlxnwA|o!Ru7hD{E@&$`>q@j$PN#+F`VHV6;ew<9PSy19RpQ|R#r#_b~MN&iN=wM)f-vRDKi|sAQXuevvqfuQg>h+ zVG5XolTx~{UcZ=jK;`sW1I6(+_BLR4@8(9^&W^60?z*PdCC!j3dIe80%&M)v+n?7O zF>){%WkO2#XU1FGeqlfIY&^U9I(PGJ2+$%RXJ6Cwsc;+q=0y>St1CM*hs> z^$R(BVV|!zk0F|)puPDhCNH0O~fQFbEG$rq_!vtr}WnPZm(L>lQmir zD@ke0#*SW0pIrt9FUECa151)Q*+?hVVTDQDXgzWnW^bG+x-hwLp!sJy11lS;7N*BJ z45u8d6S%A~x_R<#=v|EHWsJpaj-0%uMy4lZ@4u>3C|<&WX9Jy{E3TP9~DHymUR*RnD!gIfRYb-c#Suh92py zP5gP8^9CkP$V5+>GjDFK%rst4nCqR9yPJ>fMHTA_Lq=9pv!3SIxTvP(t=+8|;VeFf zd0k_J(bOQC$i8uJ?Dw{}F2}@Q?@z?qg}Kr@2rDjhpgJt)jAgxTJ*{;pH&y~#^$km! zF~Is+kJQOjh6Ps}n@-L{0jU*`s;ix@=Ec%+bSWt_oRk#$cQxZe07a8!8P6bCPjvBA z-`*{!>wv_$l?NNTRQKD-J0G(iF-$WBF`7C>9yD%Uyt0l1qpP{63qC2QbU&n#5#UW% z6oF#mgo-Nf_6NAP4xXRsFf!t0{p9z%1(=07MW9J^oTEjj&90hT!F4GY(1Fp^r)M^? zS9Gj2&=;0qmX^Ll6;Kk?czV4nh1C9obwz4=3fEYvvCGih?X8XQ@TzGaTs1AI8pW8u);DHo3*I+@Yp-gaCDHjVW&hRME3?pO#i!Z?%IDZ)Nn1UCguaSeb5{DXhI?EGwZAs&R_q zs!UD?fm0-Etf5~eq1(Xx&t0S{$&ew(iQKP_ZcN)f651_CuB%$SCi2D*SBtF;xH`iM z7PA-f?QX$YTrLq%L9NKpyIRD_mSeF7b4n9;gW@y`Zkbb6d81;c--ewXI9;u*Ys8I% zz)B}L*L!8itUUa#tJNrb(;>u!ER-`gac{#`6z?db8i4?Q7 zG!3qAWEtyEm|XPB*;rz^zSs4H&~kxI2|ZoCIAV6d9($=6uf+4bwNSc;q4?lT=>aag{X=XMIwLP)nbsA_&yX35&zj%r7H>9QX4Ta&DY^|D*9 z1iiXJ#RV?brp>9=5lP+9qJiZT`Ma8zcPzzv$dimEP-FVNfJU4l= zeTua@be3t9^A=$}Z;Tmc3B2Jw#+DnAoM^dYx}hAqz%DWen1ifhbFeuiG}PMO9$^~e zx>qj4ObP7i^03AC;l>2knNt374c*u_rPqO36YvzmtOMSz4a#EVd-P*L` zdvUWUQi!gOahUZ2=TQj_Mq|BG-!?A8!P0jK1GJkkZi1&w6Yd-?@zx#VJb!%y)@I9t zv5*uban*(Q>9jJuG+T%8e1n=3>B!F*$MZjWq%jV?w|N{|7bgkc2=U4-d~zZ&q(%bM zjo;L1hxpati)tR&EyPzWjYlV;OiL6mV7+wb&JvT_bL6bas_yEpW5t;)IUJX87mufgf;tJh9`nwfzn_!0m!N&EirXUuXm#p&}rJ z!z3cQ1bb-+4^AnEC=We=cmON3@Pke%&AE_#e5^qfIY8DS>8XkpinA4~6&ETVrr4y| zqS&cO-6$_Y#70EU-JyYKCq?!?((Gj+6m~cffnzm%FU4}j8H)224^^yJT&&owc(mdw z#WjlOC|;y^x#D`o2Na)Fd`WSO;)jaz4N;VT7t_;YvLZf{D|*dUJXCS9Vwd9aia%1k zK=EgaH!A*8@m|G;6`xjoRq=hre<<2`uE6@0Z+ilVC@tUi1WlX8jNe;vrs4v{21VM; zCEqcMYZT8{yi)Nd#k&>%sQ4GfR}?=`{7Nwg(=g=^P#mH-N^zp%eu{Gx7b-R@b}62q zc%~vZGE)9Einl8MN%0xQj}0nhTuw;zE6l^(7*Ly<52kgr{lwiijCs(7yAI>rA`q)kQg{Xvm7 z3`xJN_`c$oibXgrGk&<@IK{mcXDTjGY*6e_Y>UlbspeCrVS zjnb~;g;y%pDITG?T=68uOBJtCly3||-fxtCK=CQXR}|k@{6aAw`=MB#?G*P>tWsQ{ zSg*KD@yCi6E6O+gAm?VK?@@d}@oB|Z6+cw`S}`ZbE5{(kk%|)(_f?#wxKQy(#p4x! zqlND-<(qQg zr!6C3`4rBmF8=alq25? z1O86w=>=Z+62%_H6BK`>c(&pliuWr1N%2|5*A@S!_>E!?c04ivfr=v($0_cmI76{U z@o>c>6qhTWrFe;A0&7spAEG!~ad*WziiavLQS4DXN%1_zb&5AC&cfQ3^4kZc#q;A6`xdmS@Au^I$Wqw&M}IoDxRZwmEui`n-m{bd`5AL z;@=c4Tw76Yu3|9}Yn9PTPavX??W;Il!{;bnqx4})*AtPxSMhkoJBi5WJ|gC>KPmmJ z;_JlWSRW`I!L=UwhbrQ-LgZqZCy3L5AcnCZSOrn-f+H166vr#>rnr~lzKYd~wTeGb ztW#X9c!Xk);tItR6i-$>L-8!db&6Lh-l(`i@h-)C6o0SyfZ|^jUsQZu@ohyc=Zp~M z9Q;IofS_MrBX~W5cENCyZ+Bt1r1{AET@Kw)?iev2x=9|Sj}R{oO(=Z0To9Mdhs!T< zqjAJiEPa=0TYQIthiQWOP6q8eKi@G3z>>e_Q{g>A>^?i z_|BKNXO_H$0eLv}rRB}bk_W>r#vH%Xg3p&XD@$Gr>^;4EKf@93=S%%r zwxGOY_r~`e5#~Ezp7(@xX|Hb#@jGoH?m2Pt_qBys+akH8Z6Qv@pc?zux8-MxB}CXn zyxG_(_oWke9C3hgZc%E)tn%SUR~%D8D~Wr&wC4 zT0-Z>XYJDBGd_x2m+MT0hc$de}Ah8qT+ zXreqQHBH5d+puB7iRJ-EZyh#s#nxfaIXf-O|L?d?zeD_siTmBFwW5a|3cIRgufbl% z7(RLi;IUyZP@ex+R95hLV%>uI<@;B9nFj4f`o-XRcKO6sK6zSYF_IZPAT4ZPM3XpXei#4iy7tBIFjh{9^(Ow6Lz zOboBI)x>rXFj&BsjA12l2h3)$n)oFoh}A^u2C;v@TE^Osl6GZ?^&6~F|GCw~oxr@c z)x;ekXBdp!$v65&LK1A;oewbFH<58999j*(?ecb0BoaCf%S^{T4U5i5RAS=p->@=? zIH4DzP13yyWsbNKQ{*0rph!$!{)W*IUZ914Iv?F4hxZ7IqxW9}f2_ORhc?LPa-^Le@_F@8FJlmKoz^MeslHB}66TrN}t?AbE-mYZs^=KJR8qKONp=^d;W# z_R_vW9wYu10-~?dZ+miHyAyuLlk?VUvKZF=Eamx>V>N`~y+FKGSjmJh6z>%19==Gt z@3KNK7VqAe8pD@}w~NUx6)(T96TVEmeC;ZHxp*I@_X_de8iRMOcz=id!|TNBFxk(< zdmRcAzEZp$EZNV+%U9IGSM%#~&R&?C%t?9`ikK>>FTxf)G}kC)s>(9a#U%;?_B7`4pk@^ie- zV)Io9i@PtPvpQ;-(H#QaowQ}fG0bLtB_ulwQDVp0-(1FQc#GGWX%rtxzv~>l%vq3zdtSp$!x<7kp7G^cad@xO_1`YKNN9HzA^$t#aG1 zndD}uP~u)-PC$_R92(BONUFea7a_*I*n9(50k+hXdx`nh5F~LE(A2%u`~!%%dmd}` zG9i+#i@xVxZnoh{ponKf!@a_cgYYafx@*mSzyQmP-?9VTK81RHgRVQwr8Kq7=pIWAZWgUax<8_{TZAZaZPw$h=7A6}#@&g;ZRW`!rn=9P?RN8Y z5Ebt2n8n<*WyZsyc=#@w!pxy@t0MQ@didifp>Mk9KaDyw;xw_~UN8z?JAOUObRc@ZIZ~_F}Z}Fn7~O@W;4I-u)fh1GeGV?)S0h$K!>Vk=*;)(8>5lFuK40 z0RE!*8isHF0)9+XSD^mF_k2Z}3sJPB`{16akoa4ym51?^8-D3Nf0Eu4m&SX9Wpm=v zc8^Na8P=CjApBbzbyT4!>wSF;nr;+Y&Xtws%1tuk400OqKQ#vHZGC>rD(5qgFi7#6=~5x!r(mGmKG&CV&YINj1RW6sVNpL@|V zBaBSaE0!5yW0HQc%$PIQ+5$OKyhaXKW`u=F_KTT@^)u97`1cP(W@2}g+`5$={K4lz z=ZM+dcug*f8s`(I`21Ut#)z}|>%(I$6$Z(ALJeuJHkkOL0>BV0#)-Y zHOBX4-e0j=OXBCFV2Q8EGe(vW3C~ia^dY>)$v!m6y`MUp=2Q?c9Vj+m|8x+vaA@4K zBzJG~84xaOFL#P5)#tMMa@A6!^yu8F=H@N%Y{g~YoJ>0bn{-s6uGqLm0M{> zF?q+A+@$vsd6q%AelPM_0-(oD&%HGjpql@n&JT55D_ zQ1aZ2rN-QYO=?U_jkycOOG}Nphln@nvhH(#AViVN%FjJah+_9Smi=%cXsI!`PP{4U zwYh4k(PgvbHkxdg5|{0g+hnp~N~BVAo2636NTud3mP##^lU42#vjYlFau=dya$C(_ z5UB1^&^`R<{cLO4yE80)RxbSblcXPl*4AtkF#O~e(llddeL?z}Pf1q`jTR0+7sjmS z@ab?eZ*7QA)ub?a>q2Z{Z`RCHON}niO?fwlev14ZmlnbDHiVu7frVug25ERp4TV|A ze0K6V^8n04()P*c18tvFOO4X@$(PNqm|ogG`HB$UDm%Hw95$G3&yJ9M!#n_l*Y?S` z%@rVqxig_e@&of`5Gj{Nc#|IqG19#UeZuT53%0B;F!- z4of#$h+_8z5+y-x8p6SHuv38k`=Ej-1m4{5s!b1MDF|BF)P^ZYm@&aw_gv76kFXzneZ3kmMWJ0iU<>plrA>pu0CbvDMX`x%=f?k(~D&at1Av!v@8 zZH#lKcmKh@R2=^m`M+EZ{$cTPsB70V+893&C38Kajqx9|u05lT@j2AZGur4r&GM+x zMt3K)v1`f&-6U`MACl#NnfnE+%reKL+*4dW19fe4FA!7RR>p+QN)TeS(T$k1;GgL& z_@lDm_l!1TiByl6MMlyd_*3&Xq|0wcO_}*Gp>0C>cc7}Qe42B!^FLta<@4EcB%eFR zqWQeMcJi+Szni}jlSWSdozOIv&+jP2^A|u^BL6{j{M`J9;m^z8gkv&42i-3}zXUoK z1!~sG@_+TKFAWb1I6QZvGsEoNOXzh?!Pg(bX?8B0n-kl*^?{Y3IY+RhSrrZtC-z`%^YB0NJ6M-@h2HFTX=89`X&C-@OcRA4x(baOeb< zKOZwe^fPl;@Sv?{pmHKMZ*@j&ZghnKEb;SBWW?r{*NDvxuMzt|IdW5M#O8z-u{q&I z>?Pvwk|Vd!Mr>|)g*jI_vOS$+(dJI{Ir9+YDHqjIHLdCLN-Fwy^L}vIM)4%7^|?6# zY_Jh4$IYBz?NL(J+rSmEPeyojrg*7C#AchqA|-<_6FweuK0?(wMRj5ooHrqg7Ey>1 z-wD-NRDV9awl^N0LBc{FAcR+LFo_9b7_Z9w;4SdW*eSvyM*;%_h+#;?tMZ8bna{ar znsY4$kwo-nUJ_0Q zf5hfRE?R}7-RAX}Z%6aTh>bprfWda&HKC_K$zaa&>}U?59nHM;UN~M*H}b9vG3z0) zqnUSoh%G(@b~N*D2pxlz5Xy@W*qWu#wB7vCowpc#A*5FYrd}-NBNGVmgf2Q-zyP83tCPR=Dnz zb1m&?im}|=Mg9_D<1K!e28Fo9QzGbi3H}L=QC?s~Y~IngxE0lzd9}pRl;U=0Lb7Ed z%BlLbgl@ud*h4rJGRm;dW{Ly;B5}{-C{_$V^WzI?fZ1CxS-YTyomnQHfJf{oj?!vF z;SouNTq_t>9S+W%orGxuj)~<+Rd4`&{1;a9z>Et?LJ*BC!bC2P(I4QDb3WM1oWt_A z!%Y1U+QjkfXvVvE205Ia!j9o3AZHQJ^G=+f)pi;#L2=`8nl*JAH^85a(T=9mL^X?I zw4>=XQ>9|~yYVz;KS&=Iqa97BwF&+d!j~IP8b@H_E4nA6csWcLb9cCR_9LLm>R12L^g zg()EujhK-L7)DurLic4TrFx-SRkaAP4#rS)j-jDPn5#rJWBrTZ=n;%tj@5^A278TV zvl~3b0cE9l{(O=naeLc&k&pUz_?E?fNxb*6x4$e;WnfDhkvVnfSaIk1ui=-+q0S4e zKJRv~^UAddw&SpGXgIIQ!!X0z$h@{Zga{be#W8We49#3Tx=XzZuen?X7G!M1-@I&P z3fEt}TW>C>mu>`Kwl|MDCB-W<{CB~@Jc@cxgKx)Ok%PJN48*pRbfLF-H0$q`67dX0 z0V4JZV2qwBbDy4NC0 z*dko}j;IG0+pQJE@V7B8%oZj(4dlq?rM-rE1lxm)Vpj1|Rx!U4G!kYt46}``@g>Mz zeusm(j2T$xTyz3AL`$XZg8)`qFLZ_&skDP7>_F6mA48!JK-(iV#;Ilu>S$+H{@YRy zHKC)xuT_m|_0+x`DMamg#;*Ldq1nXJ(#7#NFQairs@OyiP2P`aZ3o54eJ@hHSTmbe zgZBp@$DlTGbCE@^fkoCDWPv17lXaT>MQ7z<4M&#gw))5`OJrK>4 z!{xr{-9>a?nY-?8Ze8r7AZ;uQvj8cKaYNbjo8Z&TZU|=f8(;cTk*-DEB{zmNi+IW4 z4TABjP|)ZHAzm|-KEZZwpx28meGz9|vx=Qe1NfPHb3rCx!UWWA{$mle1PCCq<|%v1 z)?{P13o%|Zj2dumXuvD;A8s?!x>Bj=!Ay*xxYk|-w!$!`4OMD%YKug2K6 zg=^r+tQ-o@0%`14j|Pr@ELpKR3&|~u293|bBpdxugs=&{&^;!g`J*3M9=8bkuQtK! zTizA3wr<9fEsg2sq)qLL?OGb*4cO&{IR)PaEtwO(HQ#?~g4Yfh(apy_+1z2!yC7qW zx6rf2Tf{kfK+s8iK>%7|st@Gl+ zhp!SQ&vB?5njzlGHt+Dhws}YNwavR@#%?Zc^Ns`=u-q$FcdH5~4W>oiojmirw9Pv@ zXu`K7V8VB2KLYb>Kr&MAnzpjLbrHw(G4(sv%SR3Wjti#iV{~}DW{|c4T$;(zvjIF| zoDnoxOgq67)8b(4*E0&dTQJDC6g(*%7_bz)doa*T%!^)Qk94>QMF<^c9|J~q2^;a> z+90sUaA1%jW8oJmR6-3I*5Pj&3ke(Xr?8r}@QCAL0T(jNjZh-qTEciQl(5hXCDePN zgmvPr#ZlY=IL^Z#lDq&<8qQq^I+$T(MJ(YWFBC^{%+F(7Pyz1@{J}`@7#F}Nj*Of` zP2(T}(^$sx6V}q>u^t3p+F|WLL4h68;D(@5t;8D1!*>dDzqxx7KbX1LQTj<69d+DA<<{@K0 z9{;b^>7_w4+TYiPb-<|PwyaL;u4OC*{&lm{v_*{-42@2Cz7=A*GUNArTUnrP>}db~ zCaA@(jweWMJbA>ntWjhAuiRZ-o(F43>BiRI4RhS+C06c@*7B52tqnn7a?RR-{G^CF7_=W^F%w_&%*6*yKsGyb6CP^6v$}rqb4C zuq$h7>Sk9>gB|7lVXD=D6|&A|qn%fj|9`fKt(CH%s-I2tVr;Zuo7rNi28NH9)$xAQ z_qCwyw?O4|e1n%Jygf5!3;MIEjjmSL0}emU^s4Hal{LQc$-btxRR+1fSY9oi!W_-GzRUHv*55m@6A`RlD)jYLaHTgG3S~&S!Iguo6rpyF~`8|XzcE+ zt8av<`tDAnkF8b?4bP~#UvD+#b1Tp{_%#@|Xxbud-=_Ue3+G$E=~yRAx1RrgelyXcEso7-R*7H@>6SBvwe&#(R-_R{_0RnM9}e~)xx zQe}b5yA^WfCEpD2-$VT_!|F1hc!qpY*Z!iDXVm{;3+kDPjUNu!+JbuET+eR<{l92X z9TyV)jWSu!Zv90E-_AN)5Z`6th28xAjIR4Fj7jbP8esqa2H16m`A-^K?~y6rx1|4_ zHrLZ_H8(vJaq-FXg>QSDvmifsKvV2EWp#F7*5_AY{<&Fp{Ui{(dYxxEed`&~z}I=o zr_cJgEVcXPo<46*wHoHuD-D)cO_|f%I#oXQlhQxy8p{Y-2DRJsyf?H_*VAZ zw^rS&!amcdele!6*>^t|TKG0_dCsfz|1MMTeqQtEw^@|iOfw=v;1s&yJ-%X2&ZrvYT5|6is5$L!v3;|@)> z(fe(&^<(k=pRuZ`{eD;K*;#I5K`-{@w=%Ndzr?h4|7~2sWM{c8wtlqyXRNAazbmEe zEVr?s>R-$LC8o9PXYg@7nVsdf*!t1(pRtOT{V>S6{(I!<@qNEcGrYksB4qBcZ1u5( z>}$AwKa~*p_Ja3ug?_Zb?B%EJ=g#4{2@`iK+f%=J5D?d|Al!$?#a!U~2=ZmP|1Do> z;IrI}`>*&;LvT*y6IN^xk~}s7L!kMDc^&?qvyGj7ui#F`IACTT-bw6hjY;$Dgm;Uv z-!MR@z3}w+9SG)^aeTC#ar_QM-}1UN6({B8{2!7{3_*VEz6m%Bsr$E}=qtZ4OFp){1e|4XuT{ob#=xxdW2;oaS$KD~ul(XH z`NaWl)<1V}WE{Us(YO5E9+q(yzBo!h!Ic8j_bt6;jLr%fo!&Z81j%OFs+gCJh2GtvIbwej;`{b?3;ca^*hRVh^kcGU zj*g78WQ$CYo{%Bnvt;ySf-L#YcaY}pyo|GqJ*7O!bkJUDA3c^>QOg8bG8%*Q6yx*^ ziPz&`+d7N>c@}*`7JW+={p&3H4_Wl%S@i2!^xw1S+`xp#^6^^{z9T&zG=tbL3t-@S zMpk@npZG#!X;%EoKJmrI*;(;d^oifjxFak6ex*4F=7&Zbe^r|EUVdn#@lGFlgz;%s zdcEWqn{6X;$=?56UVLxm{~_-^!0V{4cHx;bbBc7%ktJKkaz$<+8>`vI7_f~Ni65enxK2wmks5+Y)K7B>IRqP)EWzbZdZi@E)6YC3Xe-$Z@l7;wk@LM;_F{ZL zNV?Yf=qnpv%Pl3n#4wH^g6LEJt;A){Jk4KyTm{<7GK}rOHOsLDA8CZ&q~W&_@x|F4 zL`;!)6WM{_ymNB!Wghz%^Jm*;{`|x&yI%EL0RnD1ndrdJdD5EYe5W;`Q9_OB?i3Y_ z*YD=0yNicl{6U)DodSaKt2LfV(P@0>5a;7L?nBKe{yK|#?J^u4m9t_9h0P)$(xlMg z_==ghzlK+!Ka&P>Rwm*TPa}kd$3)^c^t>H}a}*8%D-}_-MyLY&dMiRjBUIsh8cAGh zICQ__F^VTDo~C$~;suJAC~jALRPh!5s92)7zhbQ-$58U0 zq=;K@p)XRrR`C|aUnoAR_^jfqitj6O6B)|ocTvP#MSfgPdJn~N#d(U06dM!|SL{&i zS3F+vJBr+*j&ixdAn^vpI~9MW__X57itj4^O)+9Q=|?CQDi$kpheOI=sMx5uMzLFQ zv*PiJ-%&hI@rR1s^N8~9R(wS9S;f~BKT!OKVm3aQWV%s`GZp769;Dc=c$DJtir-bd zTJaXedles7lyi2F&!3h4Sdm}lG5;LJ(TY6veX@FH^ih@lM5GDRPH8%6U&Qih+}K zzT!m1QpNogn-p6WHz;1G_<-V*ioaKUN%3vP&lGX|oa8%9ag5>~iZc}tP&`m^m13(R zH;1MErzoDKc(bCMzk~Qklzv9>6-5(sB-1AqM=MTMlyi3wFX!$6mumPyitUPW{tn{h z{2kzTHJm>p3W2^_@fJny@WOEJyhVIN@gv2r6pJx;Gk!lsIe!Oqv(jCPn-#yUc#h)b zia%DoOHt0(ft<&bepc~MihovoNAWYozbneQJ4i3*?f?rhv4((h?ha7S-2pDv@J7Wo ziW?MnC2 zMDc0G9g6QNexYa&bMnbm9IsfUI9stoajD|LitUQMil-@_t9ZHMor(`CKBD-v;ts`k z6~9olu@GZ9#CO%N3gx4^dpBxK^=Cu}^W6;_-?n zE1s^nRq;H%s8D-}BwPf+}U;?0UrD1NRu4)=7FQ>=KHVu#{@;&&C# zSCsRGkS-UG5t+V1F{OB>;x7~*QG7=66~*@y|E9Qpf+O!##j_PJQM^g9 zyhB9ze{Gmy2)^w^wC#I|ko$z<3yQC3d~}k-pGO>r z`+Xw#_fedu;VX%d+f2lNx8f!ZKb}~GXP-o*zewpDH2w}Eo)g@o^dpMT5DzhoKPvra z;$bKcr9USgigkz5$;qIh$1KI=irtE*DPE~~hvH+3?lE)$yj$@x#os7CtN2I7R}|k+{6z5!#jg}C)6qX$kkK+}mC>AMls|dy)pje|=t9Ynl zv*KDso(IKr+z*2NcZ=ewir-bdMDYs6?TYgJ2I;uP1N-kU73I8S&^$eY;kd0fLi_1+ zJ=9wPY1msxME+or{L6@wxF0f*fkg1T{U}Bn>2Mn%2(P5avO!SfLLdBzyh0-6p<4<{ zKDbDK11_b0kbevj!o*JKb0cX8xtBP}FrFfUU-GF^{gG}S<$|stBK=`XuOUKCm(smN z$orWZ6)E1HyHIpj`!jHBBV|1tc39p6FV zVH$tF_kngD>xqu#i(7ap7t)Vo;5rR>0RG9tf9A(=jq+T5IZpVUtKTLB!ryz6Mv{-| z-TYh}K$t(@rUs|YF<(4V@$!8Xe!m@Gf+mmaTzxJ>fL~raPh&VOCI6yd3KPG`cM{~o9`hA_vd?+FJIikc=_Js$n)CO!Jvn-dCCO*o*m?4ddi}6?Wh2s-;URP`EpEg^F3el zb?w*!c|+N;J|OQCpFAx6J$c_#c>r-|xQZ+7l6N|Mo*m?)9h61q+QEIv{dU-m>3&|Q zd`$O-=If4Y=R)3GguBj__ewxsKIF0N*v}{7-z^sokkr+c_xLX4eHoB9!zXWwPu_Ty zHxprW+@y7pYPCVz@F#~-5a;f%}3&(iZj@2p;V#M*i4Q^dM$2{py z2;{p3eECk4T-|(+4dmP8%Xd0B-F$zf@>~(;Lf#2eT*|SP)U^S5?U2W_npqz+@bAj| zSwP+h82N>36!=^__`b&VBN#`mU@bNT-$Q|X$F-wfA&mK!;@{2pxq!U4q10juR_EsR zbU@yWbx!-EymI`z^46c7H=kkqLJ|`4=tAWq&$VXQm z;Cmc=7dTOJMYOnLc>L}D6JNPt+3DGF0Qg{XuO>6vYn*a(X*XZaP2ls~`QTgbW`h3-G_DIHxRxM|4fpLf9mF!_i!EJd-AOPpDbC&@^31)Un9Z6WJSETX{9S^C&Mg&NKe)^B4b{&uRR(^Zhr^eKh}FzW-)B zLJO^0Yw_l4=X6TrUe1@Ccj$PQ<=op73&RT!zInyXMu&4g=UklK+0t>(TXQRTc4gfM zUzN?h$Kk&&cJr3p+l```PZ`t7p0YZ!JI+}!x>0!%r$-<901c1Ut@K|_KJyCE@K#4^)50B z@h^_H_ug(VOfK9_PW~*qdCOaCutVmWHD=-DHNBGSO*dV?#p1Ql*e}b+ne4Wb2 zJXojX+vE$2YS_8Hu$YEju3^6JE&ZRtl<4~Lfa^ljGIRC{NAOW%M?4t960?djXlkm~Ol>}yNawx_xWI`M7Xn>*VLXS-`Z8BMfzZD#OXkF__M+6V}7;@xQCMpCFDqHL~1sHTOXRb2wVUs|ex3 z&~@%vs&+JnHes2O6ClzuWA~sXS)uS3Xn0mA$}05S;MoVvpH_i&9cAo_R2h0dHx?;?87+754wTgr{ItWX{#WnGDI%f{BF za9Ifw;ZQsLb{4-eu_7U!JrqL<5K)OqWUV9-3&~+WS^V_H%95D;Ebj4W#Y3lpp}>gB zQ@XRqA)D+QA*H~6h-dKdP*nTZWHERss^fJIMYZ)%)E}d4Y&{h9EXcPXeHb;7n<#{M zTMtEz79%Kh?lF{p5_od$9Y2FVA!+qc)YFlN{Tl7J6C&sJ6XB0Ja{fXy6WBo%nT57d zPL!t+h0YUi2}92p?_-DxT_E1u7r24W^Y7je)ycL;ZJZc;PAFil&F#T443eE zj)n6P8NQ$g;ju&*B^ADe)+Q3XNe%0Hl+iU*`&T!CHOUiS!uDP8=7jC_6l60&*nSd0 z5vMJ&+=pF@PS||w3;J4TNK7p2 zOhjAXH%|p5vO;WDTg^p~lWPoH0zP|;SpjLueqQvUvqE&gTgs_73w{ z1diN;dB0+wP5;?QXTK^uBiAwYYv#4!AITde`*rij^z$LK{f2of{d=$_{@J{fe(ou6 zziILttC0_r=PmOg`nS`RznG8FKMfcAZS%MEU&_4RG5n4u$(0lw)v1FET@iy6~!8}UocCNXO{Fp_k<7*g!bnqM>qUzWfS2GGYYn_O=d_JEm@mkyAdIg=S2-_ zAGTSW$^FFJE?0Jju$*O*+zoNryoruQF25R)2_8-yxq?+_B$#dF%KZ^+8_^rV8TsKB z5ZR|w(a6=@Y(BA#{MWFF7>O##iCjxR_@4npw%-Jv-R#KEz6Z8ZY(tSd*n|rBJUenH zLksu_Jo0l^aKR%G9Jx!p8yI>w^Df}&vXOfR>3s<$7x~3GO!iyqbFc8S$3^aAGb%Wa z-utQksLoy^@}LCrBeuvx6fml@Wp5+$E2bLNhuJUkYqA#nfMOqJW+)dHL)fNq*?db8 zi(G#<(kECUk)KY*)rceEBfR^7nY^KlJbEEGqCY3cVU*d-58>$e zaL2s35@BPo8Fe!~bYr*~bu)YFL{hRDb#pts3-CV{ea1KgkNn0tn^BK*HlrTrZblup zDSh-Xu$j%GA^4q)wz(ORqYc4hWHah!cK4HA(fpVuD0B2S*kLYa4beH$c=$5aUQEx` z2o|*$Q|(`o615jo?KkoN^=ec4=u;)5OtqK76v>DjG1P*i_F}3%4Wx)3Qth9DBdB%{ zq>X18{+5qTCrl6)_|&Q&`ZGJwmHws_iteF38ul7y9UC5TWhGMj=xVT=b(y7ch?@~Po}_50#5$G+KQP{PX}rg>4XAw_r1?st z0Rl|iCA(Jfi$Sr9nej7ak)Bx^w;(Fmq@NCmwaJne8_RaYN=M*V&O?Y@hF~-G9E7LS zt=DuZdiWKz6mp7%+)qlH9JUNI3_ju#q5rawDSdR5%B3<3nO`E(ZpoihqEpBz7V@*M z=pmcjERmL}_N$QQE95I!$f>kdyTyH(eeO!nEab;nckA47gJZFI@p4Tk!37w4#MU19unUMv3nQl&ODzL$C z;UO@_=#l6EW{)eh4?*U|qtOjmVm;LHQxz)24JeU`BJ?OGIbnR63K~BT9vU%zF+79J zqY0iL(6a^}9wj)w3m#@~Oyb*F^GdS@8BIn;S2Ck1rz6I^l5(d=p$yNYRBxHNGjmL7_n>>VMlO-g@==4Zd}_>ZT5 znkC^pF~r{2@qYq~?fH)Xa%gTH;rLg9Cma)h*$b@M!+O$BQ;8N3VP4@5wO zE7Wq9vi*h}Sa2k{ybHMa{c413#`1Gm&|e7GR&se4aGggku6fHh;}X8YVvaocbGUZ_ z*WKjeiFoBV(=z8Absq9M+`EA5RdW3edKqS(IW=cQ+{zi7vvO3PnTz)z_|;%Men8wp zqqfwG(y@mj6!{WrM$H^@t$Q83&& zqhN&p$btMcH|{e0M-J@fKVV>#vWaatS0`=MXm7*&oj3CzlX<|v*o?jX$NA0*7@x7v z{{+9tjD7xhPjBnbBMJ(gWITpoVmgK=GfeV}D3ntmCa0CbFq}RK0poCqSw12opFP4x z`3N3#fRVv9l^GTx7vGr()5arVgSm3l!SU6S2Y#N1bYR@emkwfPxQ9R#yN5uOr1fP! z|IPshrXFB`g9Y593I62~2ENk@&_>V}@&AAKUh`=y{y)4Sep<<0?3kZs`2U9$|F@fo zxs3gSfRO{<1_C-I?v=4TF;kV8RcI}rp|?G=~NSK&kuT(wtRM&D8=g5avX;xhUUb|MIC@K5blTt;6z{*gJs zReQx{^ifwt;OewjmwM$`O~qm2Df63B2_P83Q&z+;CjKCfZ3-=Jg9EkvkY~_YRR1km8gK z`GzbqNrKDc_zwx;sU(js7(~_S{-=?a(6JNIu^G_O7&=xT9Sx&n^}CLR!#?VkwHr?S zpSB~I-~WkSC!mr-&L^s0d+Z8M6>00++&j=yx{LEgoX;B2B#qXV{uIvRfN-7{!lOgf z>-aWd=gYKj<1EMT9OeN=tiR=Iy<`NA+}J7L*Flc|AmGWMjQ=2DC&hLOcs-cQe-Q8{ zWK0ajadk^*n~9h0II<)ZDTz!vv~0$-y+fui`hCOHSn!x7ktOF^V@j;GB{QwvN~|MG zW?Q)>RxhYTi8W9%bB?vCWaiB2Gc%4oxe{4gW42BXg?w@!G|dqcORbTYmQTva?+vJP zKTx}teIY9 zc_%jX@?nc#w?^)U-aXLL+Lh`bfNx#KOL0#?EhJ!9;d*03Pdi_$xBItR_ib3>WLHjtoZG2{#-oY3OuBlA6pGy{rKmGP8y$IR5g9v%ivg;cYMt?Ufh1$5!dUB`5y8^Qut)0IssD5x zq_>3eZI9|4*O30ofUU?cN{^%PPKNP+3n9DR@{5FK?AC7hKAzy1h0Qvp7BQyr+Y6=A zUt6U08oD-yXuWPD@*OYZ$>ZLjPN6Jss#%0h{)gOK-9Xu;*5R{?bnaAr=iR8;A9`>g z3tK4;nQ2~z;|xT64fdwSmnBU#)ehaXy1qunXtkGmaNj{Wg2?Faz@Zq08CC4%jJ@JJ zx%IJEHvOri2GPP&jM&8|B>tLF;cN}EQ7%>X$2VeoY$^KAV^Zw{o$T%{duugh@X4V- zV%*9moN}_PCbKO`vq_(9FgVaA!thy3Unf4N;ZaM{@6#t_h%9L_=_c1$vtnh<@~RrI zBm29iw4aTg{hdR1exr0HwwUiPt?pa0w63%|)xUnAr?<4euZIIte`#wE8(M#VS8?lL zXIFcvTzxf+a^+@DvJI$gD*Sx?(QYQSyJ(zcz(nYI(X2D@Cf zH>WF?{U}Yf4z6w9fIS`2I3&F@mXh?^#?IqM`=B1Dq}%u*F5Ws_mK)~RH@pssFdP37`*QL;<; z?UYJv?dj=CwRAffXl(5vHPzDKxknfW0+A<$DccXr=VM+Wt*ULTO&cgG(@GY*o@_uB z-S4#+TwU8xQ`J=0u-dVMk}!X)!;1vT$Q!?nUa2?4$Pl38zIiT zTFkl!#WA&5&t{<%u1_e@A0{J6XBS%A{Ep6ce0T@G9>^%RbpUh5KvgGf*9GNh@<= zCkMlMi|U5^%W@LJ{jz!M3fU*yr&!;n3_mY#XaC3c+77P6cG{VFXNDoRM;@BV+jBZ& zmCc_ZoSrt1od1aj$HAHb| zG7OOcOMGW0$-o~xWV!FmFhmAJGwqzgkQI=TI9@!t@(2zoJLfS3#}Ik!f@`O;YW&*TP>vz; z$gtFrk_sHYx3fg%L=B%6lrDpP2Ncp}_!65I>1rd1o_Ahe| z@_t?JLH>VLQh|qEUt3y3@%xWf$fySA##&_hd7Lv7GB~kJ-igi6kiO~Mi7nmk^ghr% zb^&Yh@)B%4&EoQBpD}uSX#z|;>nJzKI|+06(mD)fh{KbSt;d#X9bDJ^|M+HmeCOkHL!G~nDW5Oi(vIgZWXdlH$oJn7(O&ljpCg0k zFJ#K+ul3T7=PzW+A0LoEKFti@Q0FgX$}bG?PYTGN6p+umy0o+8ivT}8HK0E~kxM(C z$B?Q2o&ouLrkUa6c?^EX^A|GppYD$a|BQhA83Fk-0{kTbx-=laG!S1NkY65jL~4UxFZgLqL8*fWIjqze)J{1&HG^KJb7%@1qTgwv2-U@(*$o zYW(VeeD~MO4x4501Lm}|up?Dwe?2T637>_N3^L2(2;onUicb6#FVzvAj~+`tt4Rl0 zMoS>SmUN`>w*~TR6aH+E%ZX1v_iFQE=&|I(opg|8qyqV+(viZyE|A|k;ZN6x6Q8zs zT_Al&fbI`y4NZ9?Li@KyNenYbg`|TqzF6uYLV3ka`@C zf7g-ThW|8wmT`?631qy}&Rlsp#xFDYM;K3K&;`azpk2rG@8Ul#f4uQ`HxkHr{z^R^ zKgk%ILGNkI$e?FA2Be9J$-oS2!ne@x{mSu>96ZZ z7X|18Kr=nZz~P}bW0lgAgkEQKE6w)@!$a$h)0Lhebgyv@XgbE{g-$SjmO*bcew{&o z%lJbEeWLNY(v(5{J`2!Mi!qL4e13qQ7NF+_X#TFubxhAwf%J_rj(eJt`KgY+Js4 zCr|RykwQ|c-vkky5#T38d`5r>@fVe_WCVEm_(L0adXbBLO#Hi=>?B7YGy0k2d7l`> z$A@V{`N%Efoi{&YktcN-sl8X1zE_#vtNQc{^NhEjOp_tR_h2p~-1opNBRudZD$Dr z*4g|%8lT5a`V45 zpuc?mZvI>x&>@~q@ziBB3vJ@Gfr9=j8sGK>z=kV7}U*Fow*H~nY_ zJ^J`G&32gmbBCVpF5ldA?(z&Y*8`!89J@l#8AhSfycY^R@9a6nc&Y5wfZzBDo(|; zDo^x%DG>j1ARaW!C3J3DzR>3f=pUr%2>Gv8xz}UvCk-5_IGVWKkewq!*E#zqGJcN6 z&sSvqGJJ_*gW_t%HHuuhl8;qQWEB&+f+eEq3L+~(G(o`!6wzdaM$rhqt@yd3jYSaU zaIajV>_HA(qO|NK4!TY0Ud3Y-We;)0pQH3;ia%1kL-7Gc?wG)Qo>zQbky|G){J#|W zy*p`cdO#ejxQC*g&4%!KN-t8Bv)K@SxYC`9gNi3Aa&K13y-<bDlS!QQ9McUBE@SI?@@eM@nyxo5Ro^3JQ}(NmFxD#eYWPOtWW)F#5$VoW`YMgTk%;;HA&r+a(7^Yq(r;>fG7Egj zXA}|hdkGPI^A#6p_@PAbrHFfDTvy~)0SrHxxIcE0AR_(cO5dXKcM~gd#+Ra;eTH;@ zBE85kJ|ZIB=SpW~gGT%aBIfn!M8wZkT%;&xpdr4G^!3`dq~^M93{wl(W!4A4nRL zN{@zbCSu*Nm56+|Y4~MIU#;{{h^JtW5)J=@;tLx8XQe+?{3j9op(OsdW8Ne}{uo6$ z3k~!%(%_p#gnn`++UfWyrt%%C;T?)+D_%;(yuDp%IV%nGww#d$Ie%n0))B93{0BtL z`*Kzq;!P~jm|s$HwBl67a>e<^jhLG826PvnuvAOHpq1t%&_Rh*$%rno?Hq2e;d6^d;{ z2wkVxt;pvu3_n@%G{rL&Wu1cft4U*AyiV~Z#oH8rrTD1gZxvCLlI~5#cN9NT{7jMi zQgIwjD2`AZrO1t{7+QOx?FLk;%Y^1DaCP=o6He6DsqcM(q|}cRXksj zyO}YbyG{{rR+M!S=)0Acbx|q$IccD*kAN>KE$buDA1f{EB+&mlEe8T!bH@^bv|3id~BRibpGQ>n6(Mwtqx!)Jfc?c(LN;iq|W0 zCqMGtu6U;+_kLpdoFH*czk^5h99=%QRF2#El zpH%#v;`53xDsqP`rvE_kbH%?a%6c8~IT43X*6pB2E6r`Qn4Y^n5oasTRpf4343~90 zkeh0eUZcnzvqGn1UpYlN+ZgomN}r~9h9Wn}Bmen|03&pjKF0{_{d-*R|1l30F&^_l z84>Ghd7d#D;~{B`%ZrH^U+alj=N?SNc)EsI={$$wIEp4B)DCfI~C|8L`xythul;>X=j&l5pi1N$T z`FSD{YqWtMmm#*ngGM+leTL+myb8SgGX?eIF)`a(P_MT~U4FCgMsy%OQ8-V;tR{_>bZL>-biHCzx*nVXm{) zGXt1~{|cqI9O#Ut=Yu8>|Ct}ENaVTtR)F?9SHCUh+OVa(Lz$fpgD$liJE8_eP(c+$S_&htv zM|~)Z&b8y|K)$)Yd^x6&kLgAuL&|o?mkZz@%8t(h@(O+OFx-3cxB(^QxprIyzuz&A zj`I-wo*m?)K9oi0+ED^Nf4eI4>wZYp)5Mr4!%e5=UeZ~cdGI+9l!seY}bza;2+A4TLSXd_~dbnXTFs8 zgvtYmdtA{4*N%@IKF<#FF+F9`xpw?DkZ-Rq-|5Q7bo|c5Z^zRJ8_JFm;PaQu7N5Ks zK6$(^r##n=9q{{|YX|Sk;rHy=0Ve80S#+))ypQ+iyVaL3mLp#IU8MQC_3;+shO%QI zAn$UYymFtstt!v8;}gXBoomNW9X`(v^3e{;qI2!IC6Mn;zIiLjyU zcrGCCKA*ffK6xJp?BF`e?_9C~iu&t=eAI`s=v+H^Hk!Xap7Q0puktZnvm?*zADkD5 zvSZ(Xyd6GySWbHNyHe%3^)b#>96WR`d91_d)d%^g4`tCITHMird_VBzdw}vW-2qsQd3&gz;OcW$ zK;CwrJlw8&<#L_MbJP9YRa|AdXUE-Y2W8Q@cKkY!?;XB;d5_`N2j6>BHrT~I z2!ii)T<7Y;_vQX_c^LA_z{L7E0{^Z&Tjjaw=C~de=-M&O;q&a63qF=BWzo5IOa-4m z-!FW2v?!m{W5A9I$QvV)oQtc*fdTyvaU+!1)sIJ2!SCsJnCjQ2e6D_d0sUg=wC*^b z0*_ZN zi7DG{2U{U;oXR4&YJ3!sR|I*?m+fFZ{#|(mD$h;FGlu-mwPUfv=an=0D37w}Tsx`} z=(nTHXGgd4G2QWwJkO5XAa4Q%sdLpBP(GLbo$FCPS3iD70l%l;)8J!1y~^k6cR2$6 z`c?S!V}EkXq6I^*u1?1I3-d4o3oClPTdVCR($91T`-duT~1mx}T z>9^4*Z+93$+g<%`fF~cc>s)zb!RNR41E0K2V0P_Y7?5`#2l0}Yigk00~rTj4al2263=*jeU5cTR~+Euq|dq0 zbuQnuK)$hqP|g^enD1%$ck`VWkaryhgQr|!Kvy2WC-U1-fQjfn#8cks_;=;i1>|ks z-7ua*yz5+fO9JwqgS@SXq`Wim@5*Zl$Xiip7~dMATn-P&>saHwGorlj`{ZpvwG&NeP_-tr2G0as}DO!viHuc-V<+a_PITO;etEY zO&)QeaZY~Wh$Y{gcue)N)df3tE5wP)U-7i%LOFAI;=<6vBJuU!>0saFn52m50Q#@XV%SI7OVe%7i#}^ z6Da?I|6#f%|6#hN|6w{zpZ}3t{vV~<^|`@cCvK>nNTnm-*G>J+nZLj>`teh%K+vs) z?pR=(4qh2njgC3lf{KVaw&#QP~U3|}l>K8g=tBHk0| zy;QuMAi|f4m%4;67w_>*c7=HPBp`gHc(+rtABuMh)wy~<$VohamXe5?W)Fzu>##f; zGCR38O%8(|QOlfymkf52huTJM^B}~;P>+;)?J-Q>h=_t{i^)&TlKeh9+Geihdx_)# zDk<7-N_i!VnLZ^%EcqHLIl9(tgRn%BYu@NOiOEe~z&tyI$TuvWg&N+@kJb{ez@%7o zk;$W#lfMBGU2GmD*%UHKtq`_h9m`Vq34hlaI||BJW6^%Yw@v|_D1iO3h#6W+5mn%e zSfLeSDIaG=?9dw^Ac7x-g>U2Zlvo85iel%PY{JQtQBtuBqzH^;K4M}Qng@A@eO*TEYV#Q+Q3bA11-^}Xi(M-P8cTjm)wY|5 z!Q4cWZ8LVAmhKpoXY5Dj8B`#rv%S}d-C+KS3MBafR_sP$8<+f;(taXDVUn+uVmFJ` zQ(gAMnTTV%==p9|?>&Pk@U#=T^sasMiIR2#>{gV<}(4W}b*QqTRc zY4=3^j*H#T-(F-(g*?FeFyd1053=Pa;>RMZ*h8%7+&B&eGh)ALfImO}7{ebv9R32s zdK={zzUKnUd<8OdV~;%pf4qaG@cdl=oKF;V(B)?uSsZ zC_5J?(W6One9X=hE+hFZ2+JOBabUKSKSo>59%0=}ZIjm^O?JNZlC;mINSM8w^#zFB zWGPy1_9%(TPx4#C>;h{X^ejl8MYhpaIf!w|R&nPLoEP+Mn& z9~c4d#IsOfcJ>5|&vcRu$==;sMWd5^JDWYxIunGQ9H5?)tXmKfOU|Qej-83*KM<5X z-7#AFQMPmbA5^2BGbE-Ur+aXNkzFbTx(;K?ELLD)4iAIQF1Oh7rzBURa1MXGm>9oEKs7%u-=5G;Rm0g1s|}{W_5)A0V1cR5B1R*qA=(J;~)2}+IP8~G2O4z_3-wZnI`>3VD_;3FRe|#lsIsUsC?m>-s z8O)78Lv3SmmTLU@1qe^X`Nehog+};u}|&yROA(QD)>h`&YupRa{~oH49= zu@Qdab!N2&X3mTMxveBvK-36mcm1$psLSD>m2;yh+D{@I=2Daby`i2se;C;4@E+%(66m}^)Os1Sbgr?4XN z0m`)~vA?-5G)c1b67x(cz9fq;aexe(POD5*m^>ILkz@fTDuu{R^8H7m%AAUr{Nyka zHRh2Z3X)eKm&9W891!D@Ea=2i^KlS`$<54pg$O{0scx(^!oR780tx<@YF?tr9D_D2 zlU-t^c?zsCl3P*ViB&Qo*g3sM;vkb2$8wG`5(kSnk+aT7tQK!>l4YMbREYc}3qNs~ z5CzHaqaYGT2r(|F&qy?jw@_MMqDACSNwQiJZ6@obD9L(Bw41D$A}Q2FN(yy`6l!9v z6l$4FIEi)U?_l8UBp3aOPV+esC~giJ;ism;rWg-sw)jbF`1gC0ehMXFO^1TvXKG0E zD*@{s($B9X{R!zk!4!TW1v)uXseo5XC`V{%c zl0Sz5$(usoz$}Et;U(Y>zi|tNl|k;(oEOaN6JTK7=e+2v`<$13b)WN!+067(_c^Z$ zk(*qIggI}RCm<$Y8bZ#S=8r)*b)WOL`6m$LlJCNZocGQA0@nS}Xs$UQ3Na;l8T8Eg zM2Mo~PoY!JXF|+KR+23onu|1L$yyX(PAqg7h}lUVd7qOVIvvDZskWRPv3i~~tDM}> zjfkm8j-#~Up+A7APPTCP8Ws8w#A0I@&MPp&f4&{cCtd{C(wyBxJU&;dFsCpST+3l@H^xGVXu{2o(nc)v+L3|d!5y_9e#h*~c%b`K+?PFN> z@o%65#NMIbj^Blb5PSD($%^*|vG;gukcj^PiDG}`*p>?7Z;=1*ryzV>obN$mU(#O~Z$aaU{o{D}r^F9uS^ty%qWH74?JN3cB>B6> zm|>DAOCE^wjhS*&HajUx_>e5&=O*W}N-Xni=shpF5A(ClOF&d4Z=q6Qb32IY9Nt_+ z%p2if>@3=&vS?qL(=xaTqoVmBV%8YB_K361dA$j+_>mjEw??}j>h#R^wFlM-Q3F3!sVIRx-JuddJCk_B) z_pdjGJ;_H3u%Hl1M{EXDOAPBdGT$U*c&ZZy})>C}jM zoiWUV>tvr63>wK!51xOzsW}%44+1B_FA2GF_9a{gW<>9U(1?8)u2J4I2q)LBBjrL( zcVQ@3+7X+LTzNXIo_;5K=f&_kG3N(n@cdBjN!sPvctRufn)jUR^%1)5&D0Ih81~Lc*gz#r4o6~ zDdp&3QqGJD8#G|D^j7juyQ zP0%y)ws|c5H)1Y}yknk7KYtb!dDlFZ{;E9J(G_lAF=JUu?ZX6>o z$@FCFje-p{>kIQ{utjV#N9-b2q|FMB*#AIClsEkmo7b%KIB@1Q7h`CU zK{{^@`Hc9*5SrJr4PM)6m-E0ek{6`p$P%%cW?Z8$crpCahL3gweGQpmNW`1Vh`rk7 zyx8Lm(MJ-|R|2BE4U5>{f;VD!ONLGeZ|<^i9J~=roVo+C*;p5!#-$I2DD~kMZx0k# z;yd>uSTy=Cct-L9VZ3>W*zYiEcPu&iKk{=F%g7msc9|$SVn+}s=^M!;mm}zF_by&S zaIZ#a)RE5T4iTGLMeMy0EJAp1G4ey^2*sr(=xsZ1fN*a$HJYx_gigSHGk~J)?*5PL30M7v~510Ku9%=1zkygaz zFt}S?Zr%zwa;TM)PV0HA%fmYaAJ0yVx4DeGdywKA`L?6fiwG#-ehWF{Llzb=u|cj& zY~Gv2>NsfFIS7r|yUX=+aL2X_#}_gn9YQ{Cdl9kc2nU~-#JG<^#OA|R3@y0Ej+KUg zuyF99BBn06E<#AGL^}VVL{60}7t;~DRE9Y|sg8YH8u10>uHj^0|4{h&uza_AlnR$# zGUtsz99R9Z10=^sg^f?DBQ~GR$NngSUXkFBaE)?}9kKaf+By}sL>I^KVHS+Wb^IBS zY+Zt=Xzc_Eor3GQQe2!RfyLY3=z;r5Tm`QAOtIRHANdOAA!p%Y-A~RX?ZSB^Iax)= zdz_rJ4XX*4=(6t!)490DlBk#bAH&E0k+<@~97d9al4k-U_MNy!e}PNZ46x6Q9@dAS zTEwqKokS03E=K%kD6;4g^xN6kL@v5!FWk_?;-{giqOJcxDJ0^olxW)sNXgCSo`}(Q znwg)?oerZZnp6OPKVB+a3F+gq@$$@wcK#avLWFNLqFpp*O7=#EZ=eQ62=6nZy&u9q zBfF2`M-?L9vN)?F+D}7fnV1=(Ssbp zvoW(~eT6QP8{OEA6!AQ?yXeuU!fV8TgsO;cx&nSXehwO5bo0;PkHvq){Em47{)D4C z*_}$IAtQM~Nl>0tJSC)~5%WC+jH9fK&}$h=sTu9#9t2qTqjyD*Er%D0QOgngZTO?V zXB>a;6g{17$Kq4T=;Q2G6YS{Ad|9>oC)9O^c-OJiUy=6;5&OT8H0vtPq|p}-1*5#s zi@xNvHQvTWUkxMJj{k(IUgzy6mXKdEgEzSQU&Lmr*e2&=BmX%T|PBIr#gC&Lzlg`0N=F$&!=1He>G@(|NJU}v zv`xuG(&gbwUVNKKE({9fLEre!NhWy8rM${cKgl#g1!paQjB-R6jKHrUT^{rj zst3bRJl`12%Ac(PF#8*$LrAxGiTRDu4iAl=C%Vq@0;NQpzH@Sc!GCFeRpOgLM_ zOS45uV05b|AOqY{er(oXM&B4Gg21uWiGas*94bwNozF|TLQ-;kLIlB0x#BVqp2MmL z3=IV4WExEbCs_mGU?-H|N@(yTV04l_3ZV5Acn=ibl?{L<$BU~tj?+V$r}6Ry_>flk z8K_#wDD$#s9L6SST~C;Yf2VBdJHUw`RN&uGk%GW+d*{-`j17hr1PVf#5S(Ny z2n(H1f-50isu+~;eo?X@Oc(DeLb(%4aOAFnPaH==a%Ae_hC%^{%_;1V5LhOvW3|vx z6~7xQyc>x_#tdG~zhe|K;gAOZX7F1vqqMTOx2v!N(X;)`!>AJSIp%a!eVP|(+*I;|-zy9g(i z%OUp719Il~s#(o72RAj>&TL2@ZQs(h4rj~{bZjtidN(VQ`+|Fnt8lh9PQ2dG%#|@V z%}@2U45XU*c1N}kudiELTeZ5msU1fgAnJ|2)R9ogulTZ>rp0yDD4liP2C`m1*x#})<;kh3 z!iNp=73a#Pg>&^pZ7m>Z>1J0|Tfexb!Ki9jUEfrPjGC(}n<@=C2Hj=B2KAy+{gRs1 z&Uc}jv&*nx70tEF7uFe_{r!WfzJ7}CZR>3r=-}G{=Y!ehO*M;9ocOwnt-?S@Z0=>F zVxMl_kQ(Ud5qXY;=C)MdfWgDi*TKyG0TdH5Yu<>F(_q(^_-4FAqY6E31E~RcL|F`K zj#X%E8+y9E+N7QwdAebJ%ihghok-}(bvNa2T)CjBp{B;@Po>(81+_T+e3`#lEo5Bl z(dcJd#0%=`mey1*mxh*VFT`NqXSk&;1yj|q)G3&r?yk-KJsVOOUi#V3TQN7JTDozL zM14a|Q`73^g)5g=HPzNFZ*JB?L>uVt>2BuNa5$WvLw$SWVCw+-U%yehvLB^fTHUu~ zXtR3WFKxw0fLiYF!bH^B)m|!BuOJ#%H)@Sk?yWUGh{0!Fw`)Lq zhgOF{rCSDY2kq3L9yjldA6;7BG*ic!RTwVXH}sYp(r8<|n>V0JQ=5972>HqSwD>&J;&*@V(xR%7(G^tGTdqR}l_-dxpmFe(Er z3-f#1P~Uz#3JwlnINXquR>St*o9f%pIWXX>uiy~CRx29SH=wsyE?9~Y9==6J>xNz} zS5A7(ZRxIFxe`NKLoHeg#+usdbZ1VtVzH>9W>wu1l(9PkIm4I14u*m9DCbnq?w)}K zDXa^iv)i>Kab*+KSg^9G#;94osCIcxx|c#>x0A9~do!q`9AmT>)gDq)EoIr$D&w-N z$?`e~L^aA7zezeV%uDxtCkUsGvUHqa1LJ4>&ra55K3flpuy+9Bg4gsm`^X=(Vkw zVfsDmY1OJ(M*m=MZ%^Mqe{*~1x)h{~vHn?)S$4JbyW?jYx+(g&418Ya;0Wm2va%6F zSv$s%-W~=!*>I4jx-$3R{Rf4*3HYrSS`>ot)7J`dYgCx!xOMPN6pLILG$bD5F+$U(3B?T7#=r+ zFF9Q^oY`a6OiUj#P&=Jb%8x>fmafj0ey5%n#pa_h>;wjy((kh|hNE?Rmql{L`A)`645}lFAHMF5} zd9^OVn7`LnGfN)BlCR;5$(Y`aloT4%ac0y$fKjx2pt-kMhA~f`R|Cy8%bOZjvjuby zw6u1ib;~s9O&%POFrq^yn%}azP9Cx>BsFUowC_H zP`(>G`#aM)(H0&R+}zgcHOjiG#(JZ@Rctgkl{>@EV0Y(6%v&w)+~I0bzoe>hA1^Vf zxon)xs25|yVAnurGtAo{>qb^rE6&*Icl#Vy!qu2~v?KMU)=DeWrLv5mq8$nVM=oO^ z-F$^12Fp~ZvgI`g8G66sR+O`zU_rL`iUgR_xpuR3AYaPbnbpW> zpbrr;)k|YVBI!NOh)5aG6KesKbA}BYRQnQJ%lS==ddWf6X6Hm zD0*-CFD7Yw!&0fRsu1_3g~c1tBDy=<;NhL-eB5bn+^4t&r*N*VI{=(w5SPi9m<%SzX zFEd&@*o|A~_F|_4fbQ(ZQa6P=Zp_2;=gdZkv%o3l@&Oc=y~TPLLy-_5cQpPmY2}?= zodcWacXZ+=wHtgrkXO8xD}-Vh_)`?t-BZj$XoG1S47p;KV$?3LGrL!@cpSy5tybVpq&Wv3%+ee=dmQo3_EYfJ8!v=-gIv|zc{k#Mu*yA$7p*1d67Ddai7 zZo?q#-Vjh0J0|LlW3vo6$dJK310CoiPE$`eP0^%s>7u#@!?_7I0?QL7MaSBtcV3?6 z2zD0uY|5_6Rdvhi4O-t=yNC&eyME;YEOZ>dlao6ZOJ9`|#$;N@rq4u9htR=Nl6mrR zx7X6%-pMA@(&Y>#{RUuR{0Xb#rA!^y+sjDb1jI(j*Elrgnq ziCnpsixmn{eWbir)i&0q7woBS)Hfp6raXHoR3KPwD>DHyao7XP9iDKYZ*?*$EKAz1zRE~hEK9jwoVD*Lr^}* zbsZnGYW&IeDb}|cUpW(jEqv~Y*QfA?_bIM4BH7W(n3)yIwujsK=16mtRbY-b$ArdO z6YNQ*QPRJ80|s^AK%avht`Cot28$g-zdTCUc$hVA%3GAU&n!0ppsKN9!9To7HcJrzoixH-i`iPEJXbzZkW4qQ{@lZIfTkf_8^Fl+VI^TF5+WNSXRZRkw+G$Y=AevyBhGa{WY$kC=VV;$vo?v-qgl z=PW$m&GylJ+kh8~B86=}1iBE&H$9HCjmfT8kZ(59&XRXFemW}Y(;@h1!RIXO){vQh z7QUo+@@Jn4A-)i}82^sLn_-``47||vISakG&__GHIvrr)g;QocUqGduWd!ZX^Y#(M zD>{@5UR(Q|g%1)|D(%GceO207-Y&LIm}QJiN5W^x3;%SGB`@6kG~e%~os}`_Fg@S4 zrJV)q3PGl=n3#@)&oYAa?t%EpMvpIqa!wA=-wn_|2+%hK=${AZ-v;RC0`$vD-)G`8 z+E9+{$L_L-UEYcg$KVbz_DyLwN|siY4fRA}*TcmwVlYg|9H>)^cZYy3%{78Qj?<2x zmdA8l*radAcX5WUt|)a)5g7PHWX6f8Y!TUeI zVW2H^n>9qx?MegE=bX-PdP;V&%0+sSiwpang;(uM{pmPJ&>>w65Gr%tZ-(%Gw2(Bq zd4-1aJtf0AhA@1ShM%F~TQ&S94S!I>AJ*`Y*rK>rv0w2R z#S;}zQ#?!Y0>w)dw<|uX_>AHX#Wxf`P@G^o`tZkv)N77nmEv;6LloC4_9-5(_+7>G z6t7U^FRdx}XNtd6d_wU##n%-7s>t)bna;)(MCAU{#4(Cf70VR&S6r;PQn6LBSMgXy z?w3b-+Z3-<{D~reZO`~e6uEyh=~orsSNu{j8&f0WM=Hwskf5h3E$0q_=8r4Lw@mS1 z#gt;7;t7gpC|;;|jpD6}Pb$i}K#@4cDV$V&nQL4ARM5h(#8MPUssf+8SQY!H$Fkq}}M5bUD3cE#TN+Fh}( zU0LfYy7smfEZFPX+xq{0&zyOgJOZ-6^}oN}&*wLv_vU-gz2}~LZk>Cl+@tgg#gi4! zSG-2?R>d`nPbj{uxL)xK#eXQecs?!VrHGe&gzl@jgW_1leH7~ymna^gc#`5dihoeN zQSlzdzbJ|wO62oRr9V;pUNM3WPyN!0ofL}|D;4J`HYhGvJX(<-@lwvkiq|XNsmOgg z8UCE&n~I+*{-{`pF^GJ{ihQG+^p1*RrxNsZrRORxRy`@}#g-Tzec$?y%6`xdGulR*x8rL4`v8Cd+irXu4 ze*%VADK1jvx8w9*sklntmwieXGR$;VHpiCZi7Q5>tt z_n#O(Tk%B2a~1jWIK%H#T&pN{DB=IE(qAfas!IN(VpqjpirXm;R@_msQgK&B?h`{f zdnwLSY*sv6@kGUQ6|YjfS@C|wClp^%d{6N!MH3fHrk7Ies#vPHz2YdvNs45Q`Q2DekB^PI0>8T*bwT2P+<{c&6fIimMgxRs4(M z^NMdOexmrjBHv`EUfU{`D^@5@P~1bYMzK-x5XEB@PglHH@jAuZ6(3Z5O7VTguM`c; zfv8Ux#S+DB70VSX6elR|p;)8XsCcj1UiQ)WgoS0JVrnrsbPKvuIPEp)Pae?Cd zSb9=U0t-=M7sV3AGR5r`_fnj%*sOS%;_-@SDPE>{gW_F^k0?H?_=e&~ir*?)cy*C_ zbx`c8I7o3P#hVoGQ(UX~ilU1NJLPm#ELOZ<@lD0=iab6W6MIQlv6tcy#c_(W6qhQV zqjZ^cE5%M_1MyhZVD#SayK zQ0$6Z7EG^);y@ziY-5SwnW#8ZagO3bBFeml2>#`Y$7%R!isvg{qTzQE5pRvs&ndpI z$Tc73by6%LVvHX`ggzCD;}xe7u^yg91mAw@->kSy{ZAl*Zl3JD_*Y1?|_(}I~CU`KBTx-@hQbO6yH|- zQ1Memxo-e@w&}@@D{?C%rc& z43zaYaH;z9J0OOipm>_1*d2!dg-TzlDE0&4f4$PTDBiBf&xt7SNyXq*Z9~Ea?@P^ zKmTAk@aTg-mK;U}{yYvI*RK(ta5t{dK=LuZpPrBP z@C&B<;25vYm@bxr*>u^jg88@{^kn?~! zj~C$?%m?`xpR#!P={^g0Fx{V!F54c{W!v)8{RiBX?bq8+aNqAIrhEY72mFKb5@S6Z zu9Sx2loiWix>j(OB4C{KF4BH%H!AGrTc@@;Em5@@~wLcPoT3+&_GI z92bM-lE8&3118F2{rU19$dUI1GJ8fqeD*}&! z5G>{KN)F$e5uQAWq&(z(Tlswdr@NK4Dtz}pDvag*}lf$nc(BK!asaIV!+#|uRwm00GgMKwM>`gN!|Ru z3#W1LXq1Qn&91(5+3WEQI$i*wf_R&(Pqwwdk`i7#z&GE~*bNqdNovdEH`fzhs*-gH!-!2Dk$Tx1;27WA`<5!|DE<7Ym%p>;>{whTbj2N)_2@6W{dWDm>}S8#x|hFm${zj*d*6O% ztTxM>Q{2;{*DhONonxQNbn(6DQ_dHrK{xlqzph8I#LonF*6#rscAi(}k?)+jHkGv3z_ zBLeT+1*PsRpLW$x#A|8zluS~ZJ!b6G(No4x=C>vOTlIK@L%vv4?LFAL4dso4)#~Su zog{~=-$|&qpuc+mD%=Q;|4F<*_V(l1=G9olnfF4__c@aMefEbSEW6J>@9<)u{lmd) zJ&fwh?z2BGjDS%17)%qe&;B29qr^H2cc-)a>|X-{yT|oGYS>plA0spN+0S5bmVNej zV@AvfpPyJKK(_9)|9v5xo7`u=8O$5*v(M*1-LNhCIFzef0@>IVoohmD9t<@i;m}H^ z=l%^^L?WT9F~xA)I4(YssDvckD=?dlIH5SMwR!F~&^h8tNTE9$8H~h3EHLatITra0 zpE?!E#2&&tsVMr;6>!I~mw(jT%Ri32{5_`~=lkB#M>%J35>1d9_4e{l9EJ3wk8Ojz z<|Q6Q2}J$9{QJNwd^#s7G46qu7hT5(pkCa!D91?r2#@I7blaXBZ!dpO&IimUwrlN< z1j1)fj&)TS&NIcy9lOG3iIW@DgwGZyH=+rjBTjA*5?EWdzJaBg{0JkRY*QV+`521GNB*6t8Cp#d zGr$+MLO;XLaQSF3YKK-qABdnq(C{sHG0HDkH3LOIgR|M94kQ{1S83gv*E8?)gIGxzi!vy}&#hY=vL~aiKXBgtwQ!dy#DP zhrRr{S$p`_;mp@^G~EgArDhW4B76C}e=sjZ6jk5~RbUs?n|q}csN+6|a(AyXuV=-& zY~!x(Zj@Y?xZ}}o+?#|b z#Wvv}ZZ^4{Q6IOO#4Y9xASzs1_Hb`CZv`>N{XRl%Kj z1NGpZVIzW(xCiy-p4k&lJ7H6=vt#gg60froyuJJrjcE7oh2+6zvfR==MKE#U7OKd^i9_|WvVPYx$AMFJ<2C92ee&Kt5qRd(u)E*xO*2D!Y zl_&au$4E%?c~V+WLMrdC)Xhmq-905$hh4wfx$hf;xUppnbzABv=Q_$+%JzkPvD^-z z8x8kQ2o2xgf^%{y0go@dolCytMC-OJxCg|N8p*x`Z|09?Zg&@szAtI{xRLlUvd!JFBC={qTVlI zJ9(&{QC>kCo)9aw_%NS)`Ny`k_#OoJ@`qUhI%O|^SS6ra_VSPQwbGC?T(YP}31lyS z*d$=P7-v{bkQRRU37lix94nF7`5$o0wJ|Y{nK0yfm>7Q(oOXN>J_|_fLVt9yPuUqB zcaf`D1br=$oU#MliG6TNP9?vQU{guT{#16N5Nai-(;snJL*cb!8FvO+Lnie!?LZ{L zXiceSo<^5268*rRdj16RCs=!_m*bt`o%kK+}+~)8L1!W$|MFd zYo5)3#M{i8XEPx2G?YpGOrAb6-AH*h1EjsB3>oXo-F3{fY1ShRY-0a4=NV6~U>mv` z*(&X@qZvj4xh%a7!%ZnZm&MmXZ3al|?@(d>1*s%l7GQ^wLgeA11!A=MDMAX}X(Yy) zgK+bv$o&Z!?J&;dPLSPP7IcRR<{2O|?%_zR!|oy=Ycn7Ze$FyzGrYqz^IdAg!L@_h z3~;BRt#oL$8PH*-$sE&WK!-iVNt*#3W{ES;W!ZPwONc_3h2LRsA&OiR4XwkzLeOSF zhuPxHNDJ?vHUnH%ONVNc^-}7xUOLp6te8?M)DE>$sC}eRJIs?pEt3mdhxz7t$Y8lU z2aTdbop}ie6!-qfd-$m@kf&q^NVc9t%LzZrmoAbo!qZv|1;fv$NsobgRs!W4ez}ZpdIdXoR@b|s2PMPlXr25BZ@b|=Bdp9m)Ehp>q7S;eaEduSIJu~Tj668 zx(1hp@Ol~oa>^igLi$y6DJLwf`}Avpx=*Xk0IB=*n`SAlmR{Yb-x9)`k*C+2e7ssH z4I%xW$!Dux-KRe^`Czr1yAqj5e`dZ0BI8a&t4n_&M2Y(*)JT6NM5%ishR*aiLiBNq z$QBNnxO|nl$D#n!PN*k{a+eqIbSyL##89cWwAu`iW|hth9e|Ju_eNwYogcaw#2EK) zXby9BnH^#*Ly*(%XezMN%cwj?(=??3`W; zOZS&b?c-%nZ3eisdYv8^Vyi57|I8v89Ac|1ci*JqLxdRWenw)b5X0T!Oh;`7xOEH} z8G1{KzrE@=Ev@#$hwSIr;=h;aUyZ2!H+ylX@K@3*Gm} z;i8=w#Ocb1qh$(o6gq_a5#4s;aul2U@$Qlo*C6gET!JJLA3#m_)A39S0~(mZf1e6D zv5~0ia`)MHC{w0q&vSZaB-Ws*xi8Rdd()~HImL1kT*|mFaoUzhoQl$NUmi%A-gNF2 z`WMFe<+A%XPUnge`y=b_tDKT`OYog!_cgjRkPi3joU@mBQ^YqoMJzQe?vWe*@-wg| zIp46pg@EwaG>#Obz0ex>i#%i{u{S&6my-}*r+{Atrhs32Q^1{AM&GbH65e$1TlW1t zxk|d8&42_)diQ&_rJ_VkSp|OooKb{XvM$05@VD z0QWd=aS)ZofoC(ob<7hHG6#F$6`g9XLusVDprp)nUv#EW`Z#!4>DS@5(?7BB(r3UY zk}gJ0qiF+YCw)Hn-SlC+MyC^~(RliL)JP(|3zSHv`Cerz&9_-Pr1@@3UV0^pKb_{l zm!Ccg=YsTFNGMD{hKzPh_XSU<^v>|_oUTFn6r~SBx?R!_puV<9^KI#_Y1-8FZ3giD z=&jOQqrSIJ4}uPvbS>l;8x}8W`TKlCb?q;3&S%|)A*&#JLI`hfMC>%qg|SJ9QJ7z~ z7l=4M)->{~`yh%piOR2`x1IPIMUg+B{!U^arm!E~iNqaHBfp;Imj`(#z|X2cg#1PM zI9nehwBYaq;Ea8Xda?_ipv9^<3>OqUc{*GusHf0Iu$?Z5j$4A;D6F)eM0N@*&xM!8 zx8n+HuB6y9IOFRdfN#Y93(ol~;rj&~1#)683wUd$KwJzg;0fGZ4M-_)!tZfs84=9R zA;DY%c)>UMauD1Jz7otuL2GP;@RcXgf{TKH7LqoL0z8xa*jy_J4?Ou!ltkn*ArSF) zXo6tgNQ>Cl;~eDzNjN!CFOZXDFRQ=g(a$Is8WH;@u!_RJFpjXxi6nwKmyg)*f(RHc zC`LPyojF?#7xaaf8ZO}dsn|`Y%AR&%B9CaT# zNp4jpT)z1gImNsT14^Dzv=CHu3-fP~mgF|mMSKw=dZ_s^JfhD*lP=g(*JSIHJ=UXY z6X7muq&5*QK*x!`B|Kg8Q99ALP2Py<`Y4)a^c}gq&~-i9WOTjhBGIl7Gs$=5_D0vw z$n&0zQeEdj<>>onSMr<(0nrc4V!EHgDf*$g4c$w_aDQa>rF$n-SM+0Z5Z&{T!{{gG zFuMPSN{@bO?nL){l=GQ6mhSH;|8sL!y7QUKFHBye#3n-YD^LF?$@8`6J{iMB^c!;~ zcu?20;~24dTNIWD#QnXvdDk*x^K*%a&5tD_Htlp`TXi|}^NNVgdyf&DCVwI}A8JNy zKGs7^l{4?jL~Pclvy!LitL93iDGTtZ+C*@~G*LSE!D2*Z_^hy-2a68cdM> z5XQu%fF}sy$}M6uPPc9W?=;-PTj6^KIuQL3iC0t@AMrW4Z@x$^cpTCSNFsP4Aj(B; z#GU|W#O5+HVtYPZLC4NPKX5wy{%VBAu_!o(^F9oX>cTquX*9DA#~uT3(dYp<3V4DT zuACzFEev`eC;kiWXX@!g^s)bA}kZzcm7szQFy832M*@)oo4&SIJoi}$PHnl?C z_(Hg_D!70tWn&dc>J$vdVE{?(WHO4%L#R?Kw?vjuEzUzF;#}}YY%X$9E0Q~|$6&-o zLhnFml=q*y*m+lk_}ZOx=DdKxguJUfe;Q24yE??AX)q!0nhHYLN-7OrO@ zXvB#=H`gb*+^zAH`(U5@MRHT20&$60spQrYmDcVXOt{96$W@FNQQ~CTk%zZ^9xiSQ zSi{n4J#ID*@I(5u0znM(p?Hd_OrX^fDL$k`byG z`F6%BV*er>ye*Y{7B?m$Ht%S|<`2%v+vF-*jM-tt=E4uHTDn3We3Dm5=l`7q@)cW* zs4{MGqxp!<#{o%xApue3c4fe-7j8b05Q7PvcgnSv1{1jCNj6K0rwJP$2SjW>{z$$l zg02zoyKs(jff2EJ_utx{gWkBOCG16TF3$P%?hc297Yu}|-aNuOo3eN9E1ZMK$tv18%gMQdVa>q2?SpgjQ^d+& z3K#zc2lK=f3P>W!Jpd7V1N81?z}h+CO9?BW?`HL6P#LRsR-_7Jh@p2>D}TqnBdf% z0(S=fOAV)&e8!}q4@ZPs&l|Da2knKs03$O z4cxfZ$($}f5N;>&GE+M66k!*o$?jDrvrxbj%7F5u$|<2W7$KA4(T%d&`0htvO7(oT zs1ApRB^Kfi`bzS~M;@5}!aI5=4c$^6?UM;zO3l6`Tngi9fQHT`6l4!#b73RiA)=E8F?gW8mGI z=ChpJna#|%=!(uA^vw)o5#7moT&5S>;9cVUJ)L(m?aV@^d=D4!ncj%&-1`)xt-zS! z+$X%NDeQjUO~^dSXltnc)^#vr{h)Z#evcy$bhf4~1m|JK+PVo(kDW)zn&B-7=TRnx zB4RN_Y-TPNVefXX`5tb0FznpM#$m(}@h@A#6UDNe%02c12&^H;A#FJ?(UMQ#V+&Bu3FozI;r4X&>{iIF1m~^k@U|02GuAsSL98IwQ_b}UA^^6Oa87nXbw=#F z;VkZi44aFj2^og*DE{X8mv_gA#!Q%t=;YCT5bDfqxCUe&kUg-cm|-qvv^_wUe2aXT z`>#gmSs;7X8DX^eyUS|3&Y$1Oq^K1%Q@-Ra4 zPz2jN07YK~5k~45UQkcQkWyGoDCP^ElS2o>uQ&W=!tYY?qag@CWH3VZN66h0LR$(9 zISAj?{|+Im5K>yHkzdY6HcF?!?@|PQseaC6Mq3VUX7$eqi9#dw>pe&PO6%cx5rHKd zxC{}Fg5SsR8zX+S|A1)bm~F-W!(m40DG1Ns)-d*!@F}5X5WBl1buK~%Ams31h`s8l z!y-)h0LZ>vInE7mNJ#H%5HcBYQN=e&%O0Dddk37wk_byzE}WC#%SS%q%VHMaE=F`M z+}rJm5VICyFxJ6!e#aiD_bPa?n){h(2w*U(kPuX|u<<=U%0H2OA*E%W2iF$wW{ z)HQ&K7fOEo--8QZvvwsStn!5}6QNTebP5UtuzNO%h|T2tzDt#A*{FDU3a<4NBF9Y> zy?6;)X)Q0b&-$V-5YcUA_C1x2Fh}jrAdO2D;~o}eaU&b%iERHocxTBxzoM7lPflb% z`HD$$XEgI9hVUL&_lYdTlh{utfGm+-bPA;`1KG2>VV+^GVtw%Q_+IZ(>MGVqXw`(C zRn^soc`Eb5cbD0xPGg_q3qK_lCHOISrSHHo6ms|m5d@&W;iX0R z&4eG{24dC^5`CD#7>bC|LMS^alv?QH_uiY0(oP89A2GX1_!JZh!v`9r-4MXi>MsFO zT4jCUcNCbJC1e&okIyZnr}fbdd))innQfi?e>~{c8MIddqP@kui5Td z2r(BjH7~JQ!Ne}~rMDeJXuZ~4(^kog7;i2t8Li<>%KNA#%4Q8a$2t&Y4pKPRD_w6S z>csmUHz1bYjq7zm1XAbR4@eav=sfgml#XYbG zk~OR8?J*AQ6@^D#z=I#=n-h!CUNixYy#pUZ7c*zJ`VP7iDds=d2l`F`YXMJa3sV45 zT1p*sIIv}WrAxx)ZiG?3dq=3#ImEGq*RBE%IR%_pcuRxr7sU|s>GKif8C@;E z9P*;G@afE*BCSmkvfan9yWb1>A_8yP8E$dd8zUQ zuy(w=#P`xQ1SezA$xtv+&#dvvOEy?|m*pI2NgI z1}fx7O{&OosDNeZDKm)1j5`gu2_YPZT5pgW<+q37HzUM~7|0+x3dF^WKmiALDKpdx zo57&Z(7ZdzD-|4da*JWm_0YV_DXbt4ErEmve~5&N#+w{Oq`-$7L!N}J{P)@LJzcqC zHHKXrLgr>j=Dl@{RJZXPn^^KKD~Zt~x78dGjU~mhrj*3M5DhH_>@H#VzM$Quq;IY1 ze_&#%)u2*=XHcmSWo~o~8eRIgnOMpiO3Jk653_)vy`?r*lDfB=T?*m$Pmfl^OC-hG zl4q-mWKS%cH35>nT5TJJig1Z1Ny9`WN`0G1CMF5n2J9yFZnc}VUDm)6tRA(|s*e}@ zj8R<%AbQ^*-}tsxp89#>l(WBY5GsueU74=}h62?zYnEwXtLmOvra^7f@XRfhXFXwo z$+y+CeLq7DIH|2ByoMj-%QfBvE;ZhSVljpVSt$~JJQxP!LWH};xfkJ4{M*|0frs+$ z-padYkhj&MP%G~g@(#w|G^P`F5a;9yz*x^oxJ{hXah9VW&Sm&RErJ(kW(AxL;yV-P z?7;+RVyRWBX@1x|I9B6t$|_BK>v3KtUXux4Xja|?cun*|30~+7xUvT>dsK^%z<noF{>X;Im1z+OLAAd?&dXI&2~dOt_c}0yikL49p?v;Jn^44!QdqBz64Lw%vMR+_CQHPg>gE8 zide>y!!Dx3i#5G9R<`-JroYF9V0;dLw7^%gaj1zLt&B77hsRp{p%TH1GlOy7_IwFm zlG*mS0$wM0p=Sav_nd_5@VAV{!!DxZX8a?@s>zW7-7bPNd;C|l)Xh|K6CDy0N|fsE zgarOVTxf{3V^1do-b$hN2ET_SUh8I%3xItZ;VN6Xn@%7^A z*4G}fId;{8=G3w_)?hKglYmv8bQ|k4!?X&9Tgx)ml76GCWX1^LbDHLUvv%FOcvma0 zpSAz+5q*nCTr{HpMP<9rng!Cz%M2jX??QM*D{GAH9k@f0f6e10(;Pn9D%itn*u^To z&YGLCw(``O+i%va2`BG2zxa$k1N!tYK5G6Av-;2Kf6@FAqi0c*V(c5ys>z4Bn*0wu z)|h7TNbFRxdA8)R2Yn;Vf7R4Yu4-yo&aVZiN&H)aP5o%0qOP4lXU4jd>VHfG%p z+ZXuV=K&2xE!uiDXDR$f--ckHa;igrFphcTi3XSaxP zsU@zu3w6oXlNBOi0_-``6M}tGn#(%yUz6Ok;{;mNV?kC_G zQS)u|>4qc*tbEY~-IUtq#Y>v1YsbTMQVVVKHD!&_{BK+Fla>l2o{PK;_~v$g-KbyI z@a=|MD{RW%A4`Z^fKZrg3T*8VFcjz+Z}aRlu}gFC zrfsv)ziJ|IiOd2wG(JlS!7jfELxC9BVJ{HYXzS~7#rTgj8t7g2su#hUDEeHh4MDM8 zfY(ztZc7k`2OF{`uRP0wv98r;~hik^ls{@2V9qA}qk zj?J}3xOmtbVs|nGw^9 z2AbZ3fzRqqnQ6p*G-}=;W_mWrC&w2xy93*RBS-HVC^RuQO`ZNZdyX&i&=)4=TKH190&k%HiA?4~>y=340S8P#c zi)+Jqkb&9F?3QIM1JSmB6C0Iy-6wnSq1vca$x-e~=jiC~Bgce~wU4uohb799sblyY z&3{yD>s+F&`$)&u#qX}$bYLn&5h5UH?()T(M=88HG8>9 zZZWdCVVm*#eQwGda+DUU$tZGfP-3J=ENp9r1hgi+bFLxhbN%&W|TPwBQ*?ex=Qd#YDwv+a+aJSZO z`x0|3({B7$&_?UHeYw=stLFB?W%`?&@Aj{=8?Ee(%l(zKT=lzRKRwz6xn z<5|-Nlidwk_(tab?H73a5~*R(TrcnP!JP00X>+3OnYazu_EqL~%TxF_W!!gYc^M>b zk^?UQ`W#p;c=m#G^le8|y)nOmw(Xa^+)c$jo(ik>S z9mZR{fy0(P_?ZUhF|<3(xeeca^bXtD4i3J3>>VTJ^+lh;ETPp2S9^AdgL5VC4ZqeX zv_srhAI}c4lVx$UE;`z?JKR=&a8^V9RF3?VDV&q=>~PX4;*@CRqZl;1N)e$O2K zZF1yqlOund9DaNq5I8KOcaD6#ksmlLd^6d${`=&}?-SsrzWs9O{yFmd=Y$W)kv||u z{(v0*K{<4Jj(onD*?L%bfw`^zgIfdPvha>*+xE$qMOzQc7?u-0tThlW%h)j|d`DxN za!{_B-6`Mmw2Tos{3GPWXohlqVj5#SMm<}`PV$~8Nw$0wbnvi@3gZg(@WLyC!O(AH z4m~O-{ZTpLV{*cC^{LDWugr-*E+>3kPWUc4^n@IGw;YHa^&OHz1p1cmNwxjgCE=b2j!pBCcFUV5ByM1 z-+SAH7a6n<TftUQhI5kUy0}b6X<+U^qAB_7Bpu3q_G$e!Ck} z+tAw>i`vkAjNiAR2gnDlt?>sNcOcw9D4%wp{e$#6rMtnM4vjFrZ$s~BbifB#JUFtX zLzPBR8+x347Ap)mQC@!yrypqpGe6Gn`c)exn|c7}*{2`i8L8jILTY-P@n8=Y}7s;hZG!$PGW( z^X~0Wk8{Hh)$ojmjL-3r`R_+WzBoQn|KAZ&Uc6GXTqY9_@jl>+9R_>2q!0H#v5Fnx z<(K929Q`3@9dQLdKqnrF4_Gjm(w`gF#g4+4Xhft_N?fU*F-<}Gpjl4CiJ&W#9-}lj zu4DKFr6(&rP3b+9-kaFlFy;^sfD$-*_wq1XZkSd`x%=hHLg3+-n;-6%Yq=M^LAYP8 zJ8UG}uh)v!aHbnO-lKb0s{aX|KD{wrV!H_8JEkJy45jgfluxtX=+A3IXq91PlrABj z>eXvD{3MNkBEHLHI6lfLCE_IMwBsLP_#Bl}i)$8XU`IuMeHf}Xu+u282G?KpXAzKZ zq$0CMdaB}{idBm96w#H0k5xhbBNUHOL>9&WY{d%{uTp$W@p;8{ik~R{pcpkhIfaVF ziu?qP>F%gFUXksJ{wowuQlx!3`d_KY{W?f<9z+y-nZOs6eoOH)#UB*;83y_D6uT<+ zQXHT-TybZ`DT@0jE>LV%JXG;m#nTlpQoK%)^BSiAu;O!yZzz7O$oUNUxLZE4Kry4( zS8+$hO2w&)a}*mCmn$Bsc&y@?ikB(gsK_m#neJZ{Ur>Bo@pHwW6=UdNV{z363Mef}|IcpVPR(x0SOGSPqM81?_7sZ~60~ALnj#r$nI9G9z z;&R26imMbaRJ>Yojp7rEFDtHB{JSDI@}+(*Iy$kVVzFXh#T^v6bvF5SSKLQ&KgA`A z2P&>qyhias#b*>>Q~XfzTSXgV6VsuMA>vkw+bIrJ9IMFBY{@rUahc*u#Zwh8Qlyy@ z^53EOu;R0dpD0E#Fp{rOu~@Oc;tq<_6z3`~QoLI60mUa3Ur~Hl@fXDy<_b)&lVW$p zeu_IPRw_XTILt2j(?tm5v9+)teR z`zbC{JW}x##S0W^42=ALQhZR6CMD?qy5dKQ-zlbXBZuKzDQ>4YOL3lJv*PiJXDj|e z@g~Ll6xS-gtoWYd-xa@A4B^7d^rMRTik%g^D{iAWP;n>435v56=P9-*9;SGL;yH>} zDBi4izv2^$uPDB!_?4oW^z_B%6ry)m#ZtxX6-OyfQskcS%x9hA3dNHZpH*C^$Q`=L z|AS&Q<v6^~OqL-7*D>lN=%qzyLe@tWe-iu|;l{t3k* z#S+Cb#o>zM6{jiAQLI;7rg)U%DT?PS-lBNF;#$S^ik~Zft;mU-=%-kuSfW^_I9zd@ z;xxrMiuH=i6pvCoMe%&as}*lkd_eIj#n%+SQQQI(KienUa zQJkzeLve4#xrz%E8x&g<4^%u{@o2>p6i-z=Tk%50%N4ItT&;MU;@ygWR(w>EThlOK z&neP`5$QJ-3-UdBJH;W2qZKD9&Q)BbxJ>aB#q$&|Q~aai9g4%S)?>Q+DDJ1YMDYm4 zlN7H~yjAhficcxNs`#d26cc*NFHqcCaXZB!ilY@LDek2>U$I&7Fva5)&r-Zh@dm}a z6dzHfsWs~Hk>b9cJbIxbO^q@9XvJp~UswE4@z~BD-!+PBw(#gD6kk&OOpy=$C^xOx zU2!MHxr&PvPglHF@e#$>6u(#Ofg6F8J5F(y;xUS+D_*SlC&dR8`)}#RAFf!hxJvOZ z#Say~Ry4Qr;w2TkDE3r5OYvsKdles3d_nPT#ZMJ~P>kTw7xPu1I6!f@;?9aw6!%eF zpxCT{@iN7G6dzW6Me!>|r@I#~t=Lm>tm16NBNWe5e2a+uyidfn^%r6l?pyTm z=uSk0XNVYMh7b`xR&ko*EDb-52>xS<=#v*~_zjA;sQ(j0@V!Vx8NaLex%&S=?1lAA ziN{w!M7rG-w^9EAN)J}LLg`70)6~CS>E()ts{b)cpQ!X%N}sRv6-r;L^sU4xxDQB# zeh(==srad4sHYd+NwG|EnBr8$MT%!DUZ;4gA`QwiowpS&xJh?YEK{67ti}GD#D0dc zh=}q!NbxwulQsNSBKYqkmgByLhObxrQ2niKJia7x2c)amOa1#0D-2^a5$TOndQT0n zAy&dpyM`aDc#`_BCPI(9iMT)Zu+q;EaewSZrQcTkOz}tJNrv3`V*ErY=o2yS6G3lD zJOx{kDLsgIGVVtzy@z6x;;D+4DL$b1lHw1V^2P*EaI9GAG;)RO$Dn6(9nWEd< zlQT?l55*?Mm5S#nBBwGg*os)b2#x8cATF1J=yHO66w4HcDDJ2@N)c5f{CgZ@ zZr99lRPGA`yDGi4qTC*k z3_nBhe8r0u<^Ccn>o(HBdlc6wa)V&{zo_`SqTF|c|5v2ZN5512MbQd*{s~374+%c* z{!9LzihUHz6o)FxeM#_5P~wf3V_FiZmrd|C1GIP=Pcz7$#n! zc)j9{inlA?t@wcABZ}OEnDJjxd{c3~qTJ_1_~%ME{$*QhZZ!y&|{x<#j~vzXELxJfs~(Zu(1lE5)9Q+bVJw zV21CcSgE*+B6s%Xb!U#^e8q)|-0GL%M<^bnc!DA~>kU<)9VuR|c)gpnCoF;{N5dG1waXFCwDdQ_VhmuD5RuGZzaYX1p znYe?u>0PJ-`6Uf~cyN3|a)J&K@^PC-Fpr3I@Dr5u(eJUGkaROdoJtf$AEYniK2Y?6 z9#BE_5&b|6Ck?D1La#B3qAxrrkOqq0&~qATU_JW{^u3t~Js%_%8piWP==Cl!V;Fuv z8=>uIA`$7$CL%p)?~s24X~=~LBeX!v7xED#wCII&L=S|E9$=oM;Wb30+o*I4F=H5q zD}59Z<#3hK*AY=3w<~=&v0UFDh5WUoq2Egy{wlEo^I{^xKPE!o%{{PeG%zF^5siSP z+8ih@If`*6ABsbcTt0^Jz;wrZwk(uauj&-=`St`wcQD;Y1B|x1`v6`1E0n$*7y4u1 z-Wz}N@bBQy@~1ps-=E+P9)7xq!V~Vs6&grB#`n|n@j&tjqes{D-i9R9(4 z@O`QT{QSe0cNIK>@`eZG(cjO%AN^5qlWz_&Zj8PuMfV*5IlU6 z^C-Bp`5+(jL0LTfd~n_sO!vA#x*SvdbpN2~`uUg!c{P4w0eJ`H$h#Zz-bXn58*VXW z<(;SU0CI5t6+C>=d`}MUY(B`xd{7n-KOYalKbVip>stGHM)?@87y}<=`}w#Z@!G48 zFLUJG5|GzDAg{B^1G^k+eTUM1KE`@{*?f?X`cM`RKOZB(7tF_lfpmK+ALCt+laJ>h zuf2RM&XMSeK{-p6|yfZy{*>?34;0vZZ9O-gQW4gnXk9zE*=|YSgWpH#;H^G-TD@We6K)LYV zg`bb(a^y|eh`gh7a)_k zI;G4cDwc>~Ik>(mRX4#e7rxgKEaw*FBZF|3^C;zGIS+ zlkVx5C^v$S>F$QVpY9_$@(#icJFac~!p-;@m|>^jNu98^Zg$JU+^Fgk4z5Vqu~3=3z9SQ%cC3kg8i)?`S8nS z4}|;W(ieOvhDM2m(}T$5AfEvG>2fX|C@$k$@QpxR|M2;U{usot^1YCED6$XS3-M>V zdH7SepuCzI+-nJV`10g^>Xv@h{TBDn@EA~DK5*Eep@WAF%w)DN8vvhyW#V5}Hn_YT z;ll~%fdZx6kR8T0DxSs8&~v<{ZrjlY z3~RO-IUKy!P~_Gsoy-8!*&6cfQ24_nAzFt!_11B0Eqx@S6J8C%cA_uF0Cx0#bO_rH z9|#Fy8}u|061f3FEbbz2Z^zQM-opaU?q3UM#6CmLOf6zRh;x)4Rx_BxC-|!6U*)S%&S& zdFOVx9Z${&E8$KU*89}*49c+@p>_C7apt3Z!e@!IKPEuov&ET5hI7PuCrj>JaUM?J z^TatV4Cndc>_dhN#JMM(7m9NPdQ$izaXy3e!xxM5b4s{GoJ*ld_)>9ROwBG6=aH2A zhaDg%VWWZ*QPZTE`s7;VJQ^}DD}b!zov4baW$xAu`Av35bw_P;6+&PG^A$?HlC_-} zg@B@HmC0M$Nxn}Rtu{|a6eHOI#U8COrM!~cGJdTPPV!Ppo@ZVFVTt5V44E$>dC4Kr zJi0&#)X5!8<|^JCPgFo-C%UugB5IP;w&*zXTuJ6}3L7s3?1{1wg>MkEvFAV;i*JyH zZ{~gQ1Yf#xB4&t_tt3aJh!r|sa{4n;jo6{BG1Y*G(-9uNWhSG1f#NN7&NO-7Ie8;0 z&N*9(z)0SJ5a%4T8H2tpCFPuJE-8Xv@{dT?InSI5B9SbH?#}r_cgRQNP`sH7CLylL~o&^Ua?6JJ9)OWD4R_`xi<1L#J>$LR<|4TOabks55fn%ykA#$1 zCyOua zCR=YW)6$P(+X+#a+?xvY5uzx?4+&%ah3F=IFIHx;0y8PvYmN=D*z!w~d^JB-ZasiR zOOxH1&h}Oxg!D=7iFT(%nPGhcO~Vg9&m26BljAN3{R~W1HK9K0LKNoZz}+wODRW?0 zT~Tb|haAXE`~|WmxTV&kM~0ahIkV$_%%!^#kM# zmn^zoM#iL?z*HugLZ{{H_2Gx>Ak!(s$tqz3U%MPmw=c4li9gL3$>UrV$DbL%1zVgw zJpMejb>b}5_{$67pNR8Il=!O$!<`rJh*FBbaRuCk@nab2ZSoYwL*#jv?+A7?I*b`- zgr9haNp(avhsQs-77*tM6aVl9u<(1h_{V&a(2mVF;-Apv#QQwHX#P4L#^jc-2!rT@wBPNn8z{E%)@{;pOj5a4Cq%gTHiLvHs zAc~T&BbCHB^KKB`k}T-N1oLYUndFYhc4BuCfDVJ58;$T^$3TI^XV7MNVw$-HCSG!} zOH4OcA~!~oM!FL-@7r5 zvJM52*jI>dsU{;aTbvnbd5J2KUy@|CB&to;OKFnzlBh9RF{M(diCQVtK2oTOc~Yol za=}T=H-AJ1%aik=a-z;OG4P|fw}qVWQ$3L<=N?G5-bU?(pWUAHO459FBK-VV(kDVa z>vGaBPbd9X((G2@S8G8hXfrY|c~R&}5TZ=-;t+efH}WMf=UY=4QFwhxUKiR5={w0s zkb>&;k&c9G<}`*m}P0pGbpiLh4oX8dQ|jed@J9-KX9N)P3qr^BBgLx=+0&L|*b4 z)LCl1c@;tmr6Hu=GhYDV)qUzi)9%c==PL)P&&&}ZGRb)yNxl%GB)K!1VCpL&N|XF@ zBK3_BeUfEl3x}!@rz|-VIZQdBl_1KKwP=^ASmyXbTYIj1JgX(FnhLE1PE>(wvamI&=@qh&?)$2@L?3k!mnf-9v0+ zcBsG2noC!3-R8Mi{p%JEfiL)@d7q#0)h@#}fBua(omi(4E+E$26@_3|| z+AcI4NtH-DO7#n|b9yZ-)n6*LkC(kN$zECVElL|0Vyi4qR);!)Z^Ajv!gvLad^xdL^Y7(JTnxPs zqsN_PMDRKaV=(8FUNGxIfZ3`!7efe^trW?s9XRQ(YJg`cV?=z0D%ZVg{IWdgb ze+3b-S+E5>#n9LbPlCgQ@9o0Z30~33;^fT^cRm_KBJu^hh4hffm*m4O6YOLW`HFeA zW#JY1nyER4RfV<{`KB2B9iKql$QEWD+|G|^6CEpXiX3Vl2#@Gs#xH2*?(M|9E1Tf$Sc4N4{Qw#lV;5g&|3-jM}mQD(@gzc zS`HG;@jp8n0qjz5p4q zxxGxpzF2%p#N9>C`=G!RtJ&!zubKt80LYRn^195Nj3nPCi+pPy1}@v^IGx%0&in|f zMQk!h>{5E!tYCKlN0{{N8St0UEIo(bMx0*=r>o9@)ApKSEjaRdLQKx`BR1o7IXK|G zKitw}FZMkH?UsIs#8p_tUg2{-l;xa+n#(7N;Ku<`u2&-Vb#O*(-kprto)1?+?of_v ziQl`J=wbhc#4(&BU_??E)PhDUJz`UJ7B7~Fh{O#ZuNKR6xU@)HJ zGk!)!QJHgw0JlVzP%Tbg86x(d!H@RC_GtHJ53@OUkJyYIvAf_B8{GjOo$TZlp}C-> zdnT_8v3qugaTFtYmFEw8HAeF45R>j)v%pAR6Jm{buB|qb*M_2q32~gLqDClm7fGcH z`laNLlhb_4NBD9;ngx0RJ$ZuXWq_y`|0IU9WI0v!nu!#pWLVllk^vg=k3Ki&vbo%? z@s#^jpL+mv;2G`na3Y+~8kSb;akFuN zXTHzF`Eh_pTDzR26>;7O?&E!K&Y3+qEEq4I*7F@c52w-ro(&jZ^BFnKmg37VKmj0` z2s}DIjJBWJGSmld=TfOiE@GS^G9V0rZ^Rxa=L|X43kP4$j@WyW?+xjPvxS4V7MxMS z!MlX;B$HR0UAsoE>hAWkv8!4|=dc}njI8n}=b)uWesK$w?Gfq-iLvDVIi_uc} zcvrcAmod&!f-4*93C!-OYcW|xlD23>_ z0TMO@=PgcvWNU8(MaSIWZsg|%hoYVAP;fLpU#Zc?bQ!KWC z=&mOU=V|2Z36CqYoV-LERs)%KyGfYt!Pz+n8l_)=i~syrd14CrB%$@~09;mZj=qPJ zdpp>NM)y7s&-UY!sMzto7oOA^uU{uFhitr&gyzGigv&$urbsQ^c z$_v8(D)~8DQIFQ*F{~@$7oGZ}FqueGgi?`!P|gw!Yb-gZ_e4;{-j19sC92sfu5}J) zSU*FB=uA&=1M1BE7R@Iwy7Vl>h%Zhc@PO5D8gUo>BD(A`xb1iY8eVkyI=G$qLrm|$ zZ{SXNs*~NTRAwZfC#XVsQt_0~8jO(J;L(M$+W0<2UrKG$KHi0g^(uN-^q@WAjM%(+ zjjKJ@ebJv7HXVI9dK}x1wFeu+T6U|hcJvKC)#;XE=sIzRSn6-e4fu%7&qdv%(WVm7 z*N%c)o_s}LXUQ3|-if}|58ifs7sh&r>om+5Ut)VD82i z!2=2#=J~%MV5^&*DExUR+nB^Kb9V~{;ET=4 z0E`Y1y9fdzHg6#@tYe5s&{aZei51I$Vg5S#+Avp>28rj?4v8PkM+EQy;=o|vJC76++PNhY$)VKOH*G(5h5 zq1abJ;wsqz8mTBWVy5RMgQnNf+@{O;0*c5Fi#i3S>CuJ7p!-8uN6im}VGhyRl(>>A zma2X-7&cl}Kog~0O5LKP!35CQG@|6KoAOFIY}pU_W=6@FHuEDDMQ4qY$e5k`c@CkB zw+5-%AelLKg^8LtV^o&`kY9Y<3eyM`t>TT9?ig+;5gPB*g+<##J&@i`T|(d}>1XcL z#p7YB@9~2Wj zf^>Hye`I50eOae@#^rb|&n*Z0O+GgUkEZ*Ujxe zzq-2pi2WI{uA#bqNlophRoGlp>HQZ~RWGP(_>H7(j^TB@Si&Ox=k2b0R?C;cIO@_t zt!~e?fwA??u&lmW=G4)|qzPG17-j)J0NaQ;a5eHmD{|upjtLZlr*41$m74z)tKi(N z5r$%`Tj~}!sF~S`<7bS;ZQ==2r%f3@ac7u@oi`L)P13+~b<^_3mc_FdErAID+ODaF zU2V8$^B&ILK-bg8jY%jcrj$`jLEZi8{?%m9(Jr| zkKJQ3?BMJNEqo(6EI-dij>M(~n}ti7tLE3Lj?*fKs(N!F9Ht|oO}i$$k3^P2CFmn9FX;Y1Pbq#f}TT~7ElXI)87aAKH?#zb4q8aY<%3hr_MoySMR*Ipi zp8J{3g&9^>zgRh>KaKfLZ-ngv)mkrP=9=W~WZyLmY zm?{VZoiuE=xJE3m@+ z4ktA*2;R7uE{d1|6K<0xQjKZjCXF#@R2jli-RQWZM+vRUwlSsLjsa!QW-?7XBHh_7 zO;rueG-KV)ILj3Lae>41CJZFwT@zn5Z$uRfbz%e$mbI7Edd1*b#;dQZYWDJ*9Xe4T zn6^okh%HMD-so%ShShVa#F+6@r_G)`34`Qp5g}zd8ru;Yb^F8EBQ}t(YrRalt^LHH#dTTw*onMP?6yP5Ner?oEwezHX%+|tV*X7>pEIODb!icxDR^~ml488=J z<)yZvnQ8?kZqoK|O`}MF_I2}?&u*$Z0Fqmp;Hs@^#aftx*uWZD zyxhPOtNAd{DGiBb0ZmYP*(qee2&J*}#OayQ8LU(?eHWqX8tSUysKS2cBd{1+I;3wE z$a(dPt6KVEDKw&a@w}FKjr3|b<|zBP4K^~nDS%=t2X z=g+T!|D@(j-+8!z*EVtvOQMkp!6Z4idGFg&#l{4>t^v!hTCBkq)wPTmTn-lO#h0; z$_N_J-H7E|Z{p!i|F}Q8%rP3oST7|kZdrg<>@~*Lwj>FSoUrqxDQrNjdA@nqx;gyj z+p-N)0`6 z*wQ=(Ov-MC0a>Y+QRAn4 zjaSL@G@5taJd>`-VO_(5Iu?CZ!}3OhLUqC-qGpVrI)2oIv09?F4X7Rrm^$0Wa97iU z>wv$o#mLQ3z$?Rz8FlqD+B!8N|G#3!70G(l#fzP2?XS)JD>s(_4Mttn_S(FRokx$} zAybM0c3Y0GypM%jt;R1na5wJYR3a%f{dw@-*2sZ4i2)45EQK>Xr0+;05{r&>Og9v> z^X)>jqluS)%`WB^p{~|ec6Zb0*SvfY#!p~NlZOj@7mWZKVwcb8H@CUjGfpR#0oz=$ zb4?Mp4Q$8w;D!uA+kd&W-Jan)e`snithF=zms-Y?n~SHc5TCP-#c(v(57uTwQD^rep3=SXuB?W zSO%U#1P;sKquVwA z<@5_gAU#%TcIq^2Gfi(pCylvn=(w>+X#(RPl0$p8f_SeLrh?k^u96y|+YUJG+sMi7 zcc5Fl5(vM~1!Zw&fhU@62Q=?K{8m~BS=%RD@d*~fy5p%Bv4>$~h-gl^{<$>Awh*eB z;~yVSumuqLK$yr!3?UH3L{xWQ_1{5pq++GwRK-0Ns}$!cHY*;ec!c6HimMdQR=hy* zD#gbXpI2O`xL)ydMegZB{d+48RvfL!_e2>kd&>d27Ypeo#X}WoyNmv3Dqf;^o#LMq z|E&0g;!BFO)y4RqDt@oXJx=J~L2(Pko{F+J9Kv^0dYs~P#kq=&iU%pmo^ObEhSHZR z-k>OZx*?oa72i_)Op$vwFg%7QkHn6Oe4UMSPsM?X{Qi~xyD9FWSgY8iD0{7e zkDpbNU-nc3UZM2Oicc!OtoWrOhg8N(D#~7Hptn(aq~b(HzEn;A1&T`)S16vWc)sE_ zinl7RQG7yCY*awrdZoWm{D-28M`%p1qhhgQU&S31$0~AfhX2Rjd%#IiWo_eCU7c#W zd#0OdaDV}OV2~jXFa!~F7>1T%$jK~2l0nHyFb;wl6~u_Bm~l;vVHH=*y6PHW4Xdsw zMlgec#kBsP=hUg5nih56_uc)!-}n1{_3NtVo_o(d_uN?bR#%-%e!l8QT%@>6@j}Hb z6>n0kSKO@ltm12m?<#(-_?==99iHhV6q_l^UKQ|9D_x^FTXCu4S&C~E*DKzk_@E-c zsb@N`D88%sh2js2NsLkCD^l#Lc#z@{#qo-h75V-%%2Jakb(#inlBB8wSdMQgN%|+lrqm?o|w6B18Triu)^eR+K#|5I#ofiHa8} zu2sB6@e#%672i<&Nbze$OkpJ5m|{!C0~BRX3Z&ax>4Oy0iq(n}6pvDry(-ptvEw*vEp*Y zRf<#So@&l*dnSiA9S1wt)0OibE8~D^6CNqj-wqxr&!5-k`Wq@nOYh6<<|+ zS5fw=K)T;4%~zkPM+e0+#d5`AiiaysRh+AMs^U3{mng1Ryj}4D#U~ZFDDG7JMv+ro z>cekDh_Xio^;5b`v0QPO;^B%@73V7QlU2$&NAVKH^@_JEKA`xd;ub}ISHbw7DDnj@ z(tb=ni3!DyiW3wkDK1r9p}11eTv+h9&dd1=M5ipMG*uQ*5XQpM{O?@*Mz6Cmd) zrMD_>Q~X%*TSdM-!*pYc%@x}z@}(Ds4^ZSwHl)WZ&Qe^e_?hB&ia{(v$e&c~p?I+3 zP{ofGb1-)$e-V}@#4d_`6-O%8D9%$nL-AV0#}!{t{6;Z?2{PrjR~(>tgyM3=4T_r- zcPf6P$b}K*?5EgP@gl`_iq9+VR&0s)baQE55G&?vM6Hq@s;v6xtdb)M4w zh$+}xQM#JAKWt?xjp@J0!E{Uz!?hr~nIJ?7wo~k^SgKf|m{uIFI9d_Y7Q=@{61thl z0SLP36>#2+e4zP>jZ`#~3?F%a??AO=o*$66EGq)U%fWnLDSiNXUV(wSLE^aU$4BwJ@Rm?&B)shH}!Lm&)}GjzTh5i z*jw=M%BzLEEtpdB>78e2i0ylgE2)uwMi- zq6foxx;AWGzGHg+G9Tm{gA36;W`WOpxM6(G;kp?<7knuXBlY7k8BE@Ce$-PgY+i0Y z7Jv_ZZLUPZWfkOklXlbMb0xP=lJ^NPEq4P!yH28~SdAgQFxJ2W#gnm_%3`8!UU}#A zF^mi0=N_&+JYB<^p#QoJuCmgeG{uFZ=67vyrJMvaHn^ssWm~m5wFR~LwU4%#dnk3G z9j<-(4XXWn$b6Odx*GTv+~-d>8*y4?&)SnWH65~~5}`i_(xo-!n?|>7GSpa;Of{(< zSaee5$(4EAi6`z|rxG*X4z^Qu#A@~Td*^sh43_%pPf%5<+fMesWP3pq; z8KQSV{pOwFa_~L^;|BHSvW**!6%Lnk?Q>sDr25n4o6cw(m;B{b*GdWGZ(mm1yuL)j zt?m99g>bJw)J)}UU)eS!oFSA%ZKfnFXv2FN_2D?dlgF*0`novEy=|@8GqA-ev3Pyo zvOPP@RD83;vvK2wx_{gkN{1!20JK@(c0WmDzv}s-O>}$T6!RQR*KE2mQ&$Z&fi3Ab z?%M26=e>~kqVy1IyCwBE*7|O}p?2V2|A6JSZR^|A8ltte zeejHebeq}@hq9C?!6}z6AMZN!ymZraVY)6|dr#Z?{cFuW?LXOZqOpDdv~fVW$UM8E z>0b{_JMLv^r(Q=5wznqh+t-Xphqt$`f2w{C@|N5_B5n5hV8@91R`sP4v!tdpjoco} z`cKx6-1T$Mwlz%!JJlE|gq%%1Hg3GLuFJu%TzhVMReEhYv@0)Qc4@K2s70I} zQtGX9|L*THYKzfjz?MLlysfF)?vjF0lHLlQ()4z#OAmzjwszYNy7!Ru=yZi}1kyt` zjr`{71+Anu3#(^IZI)~|x<>xqJ?)e*Q=r6-662K}ZBcTm+73d!utP#?jFNA+KD%RX zk+FS#(SEz)q3G7~uZHK_BGpDabo!&Y-AozV4fI9H-6OTg-|;vLapE>B$DQbd`WGqR zyum;7`+Nyn#x#v0fZMqY!W)3waTZ_z9OVvzpxuLf|Bk~Q@Ksmn*?l5E#%ioP-WcMm zV;)c0-X02!>)_l&a5XD10WqiHF4-f{ST)z?UopHhHveA2bP6{AxCw>j$1NaZ^KT7e z!{*Nq`F9Eke2>p31+ek=Ez*O{zceI>%|A|1A$Axhz1CBZtv3IP zA?CMj{;dY{FKzza3uUZ1h^#jM1|!vf-R9qq;C5~P-HjD&@VWc*(Z3@PLA#92zd7(y zn}1(1RBirA-1pkCBqJ?-;D4WPe?;Vb@BrLlN6yD*!VR-7hads9`S&%n4mdXdz74_Y z*!&xX8?M^?TR{fL=HFQ?ImhOo1+~=XA8m`O&A+`!Ty6dxKwih@-y@iGs?9&nN!8}x zC5-0S{CgFxHsIL&<03xb*!-hW7q$7f6myA;%|8c`#yeXa}2r-(Z5`k3Eek z0&M>EMF>9cx|+&3HvjmsSjOgGTXIb?d$a$=?#9eIWApC?hPXEWxK#;k{#8O)H1;k8 zWNiN3#xyfF|F|WO+Wh+fS<2Y_6Vrl2%z=^&{}X`CKN9%ndpS$NvH8b`#n$V{p4$8y zfXroV{tW^jZ2t9-oL&dvu=)2i2#9!%P0+FVcL}nPvH2H=DA@dC5g4(d2!YK%eqrmE zl7h{@LOewX$KFS>u=)2r9z{fBpCbpb`9~riTaK8p`FAbYGB*DX0g?#SfX%<7seo(q z?=~tB>qR!#=3krz<=XrcbMp0)>*81n?FKggSOg`pk!Xgn`L_ZBI>+XbxYzt6i1OG9 zvfXDs1fnwb7Dku`n|}dNfj^4PzvEDG(eO?D?vl)xq$w6wRQTwyPeUl&Jyq`H?zkeCr!PdS&hlepa&_lgAk!;$^K=-Lb9L*k6R zz~|XM{v)Bkrh<>6xOa0;YX<9Q(3nD2p>d;Pvhey=raX*4m?x`e)|P< zYS;_p|3+#rkacN9q|H3Z@`^?(P$A)`*hu1$!PM>PHgG2+7t{ZlE^xyrPY9U_Y<`6@ zFNbQd7s&sXB5PQpFZ2YD5s{|%qO`n-RQyX)?-8l@EmH0HyqN>TBZY`--^|hrFC0iY z>nLY2o1+ooN9f@b=|-c!4WWTYIbMgSAkbRCPVm^#prfCm)zDtxtsrv6Uf@;CTVs2H zPa_liwin12*kCWPnsxX%ZAnLyP?7cmE1^@2V{67<;7|z5*b6)ln!sM*dX`e`S=0;c z1wH~I8skppuow6Sh2+{RE;Q_66CRTTR%xVzfF7dx0cUu*C(U zrNyVH8GC^vp-uE^M5MjIAfm=bF#i5lA7(ms38NHQb3yoH2Z1ePFEB;bTzi3BKxXU( zvIH{r0=rXzecB6T{lQ)!D=^Dm;9?3WvyMliB{7;W%h(I#gX#u*fpaj(2A-rfvFL4V zw6GU=Ac)5H0+|EY3%ry$FsyUgPM)e{lp?e@+6!FED2~0r(MVYB1=8u-3#8k%7kC}y z^p{~~-}VB>Lt5bJn{W+tCv?jOf8hE1K-<@$mS8WC8_P%H90mURI-05xp?KF`AWJp! zMiV?dh(@>rNaU@yaK|Iu#W(WKaJZ9^*^Kl)c?u%!QSgzEPK4XF7np*0n|}zwUf>QU z#nCD9$*Ev*>;*1|%dr;S!TwheAQXULZr%ULc(* zX?YoYfvgtT3uL{N#8@w|7s!e!k((my1+q{(OQFJEAPcorZdR}tcs(*$78{O60egWP zK%ls;--RA{9FTnSs4P62&pv7KOb)5+yP2q6T|`Bs#}-p(VgxU>LWR(%AhdK-dfH z45BQy6Wty50*?gISE?;zFOba&_5x2sNO^1w26EU7q=kvf*u!WKuow6kh>X3!-AFrn zFw&&GK>kxIRS0{5uY*hN1+s0Zy+AtEULc)nFOW{P7f5F^_BOR^?;}wVn}RL`dx0bh zV{b9z9fU~5I-pKqFYtXNRV?iY_5#_CoE8RqfldqKke}h;2lhgo4$uX87lLUtI!L=pVIA*EJj&{KRZj3;$kBFIp=QCNGVhZe=&+l!6q`h z#aH~#*&c}cg^|E2Omm&N(yN>+8IfC2$KluL_B(T&zj3}3j&My9ew}luXoMTmhu=7m zGM%~AoAh^$1afXw5V?WrzQy@bVdM%V7~V!VI|kfubMoyP3FLgO#IU-smwi1B`h>ee zH>)`k34F`{t?h158%6>b@ixHud-&@Kh_CapZ#?s{Z=Lzr4Ca4NJFrBZx!FJ1HsTS^ zZd@aQ9NxploC%AlERBycJH)kxqY^j9N+w1Vy$30%p%sgb}xQ6JYxAWbsCNFYnT zEGBb)pUnCD#tM;17zvyVz5BQEj*|5>=knb);&Br+F-te5bcacyD`gl5USNxMMg@QaPSDV-6;kkxeF zRC@a(MQCw()9D|Mj0At)@pMNcTafjfQODV~LxI>1LDO|(J)4^{ir(itG zN$$scc=FOH6iLnme=NC(eKPqsxbu>K!8M-DLnBEf`RYiMWPe=qlXpQvGWiiQ(KI;{ zJk63nL&AQ^g~&=l@?I#_Jb5V!u|@I;__R#Eg0u>0l+0+A+ykH1$;qg&{ga#_rIKHw z{T3moyAjW8nlTD(<8>j(w;9(Te_?;PX__(qVliCE%iqzQf_{28{gEDtw6zK{6X}ld zvd)0AiK(~1-})N*<$TE38-o5LaE+e{U*3lja$yB09_B?{3{3C>ZqDMR{5er~xHF6h zKAXZAi4$}u_-@9g7lLnggE^URh>Z}wDj{0@lnG%RNjAY&0G@Z;*qqi&YNaDV zkn(+W|`Hg~WSUh{pi@_H3lNlY4wcwa$dW2299kqNW+8 z8AdUMNbrJ~94=sr4RH$Fdb|tZ7T!Z$Pfxq0A0lzV8}xT@IcH`#_n=`WNFsPXAjDNh z&_5PVm;;npjt>`{_G93NX~vBR71NBINI9k%>B6$}b2Oajxfg*Djh=%e!3%_OK@;@< zi9uiD!ZX3~TPz8>Oq3k-({7-|Z;SbILM~nDD$86l5y9O7z9C0CpM?bd)FtTu!4<;w zPU5d9HBWMqIt7EV93ZJ(Mn+M&4+1>g5?MmEI8T#^Gr%A8bL|=Q^G!;a&6F!+2mOyC zG_)8V&1ss^#xzH|r%SBodXXW7T;c|0%;>e*^PCTvW8kdKw77x!a7+1KAT+vAJB_4E?x&s~s z{NoX(8DEAwY@*Ev{ai1GPv#ime;d9*|Ce(8GdYF{hhv)YGV%?Vx({M@7WDHePWW`0 z8u1A$Or8edakJdKN`!+CI&r6xuD}=N!skmj9xQ?1N-~`5H!{t5o;0aia`)w($GdaHD7<39%mkDP- zaWH@OjB_UuRyH$sc`X3Ea!zOBuFC3iGZO0TwFsJ;$qXN985Fv zt-r`t)QM}Fk+=9prWt<#M>x_4BVK6o3&>71awMuFH06D`UDJ%rrfZs!S#nJ?&PQC= zG~?xPyQUeL8P_x;HE>NcJ_fgInsFE0rI8Rz)HTic5?VuOB<=rURL50{knblt*%g;& zmuqfo77KFBslvaU{CA@$s7FKb7}f?B1w#6j_PE0DwP=#Lz5^8%9Dzxgoa>*90QL+%4+0$B7G^fQTw<69#$2` z|Io=MoIyYTC&1kv?$8YkyB;%=(0Ob-7R|kfo@cje4bzPL^KJj04Balyo7m9bmH#?m zM;U?kjc8La&Dg0mGmCEMnr7rGGxXl8VDU$OV5|?gI>x^i_cMVHzefO!U?NtyrwkAM z;Y)>4Z#7B4Lj1>?R1AhB;Z&kTfX+FE-bsd7Jmp z>F9JeQtB#MyN6k;KmeZy7_Hl*C%LvKi%(XiPeF*eE|Ee$&WG1*klinX!?8Ts0~H~! z>%9q~!mt(|^5+gJ&C6*RWoX<+Hzd-lFC0VR_y;1DnxlOS5jYBd)8N;80vs$1sKNlF zPgjhu<}}t7kE3y#>mEoU5437xPGfc5fwR*>*pD%%vu3Q-51if!RaeVM*6NL?cZA&! zkc{;;S!YazJOKmzzmM@hc$abTJU^1!3m1x}|LSA*=w zCj2mBIW^adsWFjL;pJ9)uM&6`;Ii8B^ew`NBR$}UEZ^ARCAns0Iemaar4Qs8A*$79 z4Mrz(jjJ!4h`H`Z1eEY2I&%$M-3}8~9Y+Y;S*EHB*;LoM5$h!4x;BVNlj2SQtp%3w z<3xuX09Qw8%Y&`AuWKJKiBc}h5H(1 z2ZNEB>^m0@=?>E4DN1si#G?zi`*RpD*#eCeUF){Mvy53A%F-Ng4V&*nZk|v8VCnNN zd-fBoDIQ&Mn(K~j>$Z?5*h2W0#DV<7&U}hF<6eKA(7>POo!7T|rqtgPDWs2RT7bPk z8Z}6Dy!egwo$5!3S!x{I5do~sK8LX&x48+|!P{JSNHG#dhuFr4h!sf3X;<5*GoRj- z%x4z1aY?X|q0)PV+yU~yLNsvm9Wu8@?mEse%zUH{(DZcswo+IUlZG z#o#(0+WxbxlY=GjD}^8XQvm`wG@K}TLr5714fc*+$HK85(HNf@UyLd`9)2I9+>JxH z1C<$ZwhjQj6Q{ZEVQ5zlRU#%`cO&s~={gP{9~%thQWoJXnce}=lIN(%;d8cud?IZ| zW$%&)L08N~4V$?V{wC>ZxG|Y|LiYsgAZe3vlX>T-lNBej3?2Gr(x;oC6C#hhz*SD0 zKi@E`%{!64wAd%xWm;?set$%UJHv}3ll?PGW+_U5W%4dU$|Ynpi=x+&@cRLNTwarV z39h4kC*e9u;+%$Xmhi%cIAv$RuVn{BX7;4Fh-C zGjPaw5cIPR$tVzxB8Sb`bZKE(dd&XD;ECwr`NO}2k24H~UW9Wnclt612M%z3F|B}i z`e}&G@5d26U5!Sj&LyZ}b@C%mb=J^%knnQH4Rsz9&N!!_!W`db zQ$VCo4`!T?lefPJ`!mK1b=F{9$sZuT{JKq@kD)*2A1uC;D9mv_MI9XHum;}}CNWTW z*$DG1#MvJOrA~e=l|M*)Uu2He$t1)%qvg-muvR!%|~Si?s3RJ6vXgG}D^JWoy@Mv(JNl#64d>J(H~vuTXMyI;eTXy^F_ zx&bqLiS+--GZAfJ9E=mJL(a#?i()JV2w3LJDrKV!%Oh|Sx{@zBwT3oc{m z0f-y?%A$xf86=m?vdWdp;HvAPQr;`nl;e%)Z4B)KJ;M3&OpBc|!5(f5Jq@FEc$-D_ zU!$*FNJ;TR&9~qi;@Y&zL>=dSMP1oV9o3kIF|-5fIdr~{64@I)HA8NrdIZA5mc=$oG4!cPH_eS1v4Z z8%@0y!JE1EzxQ+Pf8*JqYfT#us=W5UTX^k%xAfZoE_CgGw{q=&xAxlq-rsBgJLR?i zof7-tMGcm|vC7EU>J|&(4u@FuuF5ZK&KVG_d3SGYIlNuK=$_B7->^v|90gd1cvER) zWxS-ZmGKT967f31bhyXpcqb2u(9W$i<-;Rp3YdO>ugpdg2Xr;mih5()?f5XlNedD%!^p%B{KCR}xfTp8wNs0MTJ}m- zsE$ew(y~_)n^ij2=eaZ(?8y$&OgE5@1^7cb=nTnd0)6|7iTNt87Y)HP$3ruoqOs#y z?e%oLhBeNA#)>>{TKJ!56d{W9msaF|mjOd2B@i$osRX(x4*|Gl4s-x|5o*Laj=*JT zhe{-1_}4geVIo4g1dhu-W1%3|lZ^#)Wa)?#%#_dNPnL?fozaVc zn@?8sFnoAZ1OoWO#&|*vPVzPw=x0(?0P+b=4#yFS z9bbZzm2rep$G11&V8@AT=J4c-Wt&y5o;sc>p@$LX;Pm190%9G`U*^TB`q2cJp&IL8x);k1lJbFZa?Wdfq+S~{omB)aNwn#SR{ zW)3IXXo3^%NN=>!*EU2uG7|?5C)${XXyd)n#(1KQ|7A3O*Qu$E^F|x%i8juS##V>n z33?w!V6zDt3yfe}^IACNXb^Xp>&5yg!-+y7P?~8RfotYqB%e`wEwLOY>WIMF11G^L zj|qes;>$*mIUJov5r*MJQznoFX%b#@doHm*;2z@Qj;`5a0m9MK?Qbc2K=yb>DP zH6=JLVhq92;qV3tV;UqJ?v>E6wFV_PI*e`5;m8IFV;dwK>6I|{TE=t_hWL!tl3nK0 z*T{^SAsr6JA{o^X=mOSsVSC0y+I64p7s1ZE8q2-E<>BCc|rhU+q%2z5N1hmuY<#uJ#8 zfN`R6NQ-OfJQ^qB6DUeU=yWt6Pk0Vz5TzGHB)VV3sho7OaNS_H3W6wLvLi^26}bAu z<##-AjjAgfPf>p=#Utr}jQe!5ck!r`t09#~rz^Ru`qwG$RCFObJ(vDZrpx8E&)~E8 z|F`2y<1K9d)%{~UU-@B=9Nn6x+nl-6W@DcOgH{NgPyWpR6Lx$N8??@bF>3SGAr{us z*186WWp$TnAuYp#fcmqrO~{-naHGxOX_&)-U2K>?@q~?T#}nO9I+gV-_Kd0a`3%!^ zecm=qYo=)x3~l6lkBND(4`1>1mmOwY<`)e!RV4mHgNrU%e(iwLB46Ai>_fwB*RoCb zgR6?B3s)-G?Z{fXs$oE~AWexmm;DnHF z1FDdoH_}?uOcfuo=7^j6-nIY!MF$_$DApaOS+vN9HzPB7eaJMEjk5U!;}1AObnO}x zY+O3qOtWiwPbV*OEj`Funxf0HQ%4?gL{Y1cXg@i_SVv_Jv3;5;=zpy zbEVJhdUVfjN0oN(+3j-S=o+*p_qRH9J+j*kD2C&^(ep6t$m6Wsu2$>R0Bh9kR`;$& zz9_PUr=@7nv@_nYeTOl4%$SM8swyT{RvijM!(v5Ut;J91iM?&O6VMp(rSWCQ=>Lp` zwX?AE3T^j$KQ686F#$&IWkVYp_jb$_>jpauPM8QA=4zzbySsx|z?7NOCe2O|~#05i`tR*cR#c?$FJKid5#W60U_b*!3Rp0clvfsm?e1RH5%7YLa2$L1Bk zzg>_P@AxXQY&~c0|7-&xx3&fksvIIa7&$dLzF|utl=SRrC%P4Z@^YgLsv0!}JLVvq zZ@ukvzaiBX8+By%g=n<*kShxNdq{4aLY#uX1ktoyoBZ6lfyVn`wYt#;MJ#BPBJJ&y zd-BqWBVf;e%Kv=ZBK*lP@woYOW;qRoX3^P9{_oho$kY1p5jXBK(ER`JJ&oL2r7rAU zvlmQ+v2I6~OgC}&HF5Vl0w4O{f?8~>Aokf8Oq+(?FJMd;y#!rz&Z61e_s95e?udj2 zB1Hj#+UsUv^B-kPQE`3?IChrkmS!Sen*XaASka~4)i!@fe( zvNx?5hwT(9#*Z6}|L+d18ZlV<*!-DO8+JTH1M^zipWBF<=M=E^-l`)9S4u%U8?nf! z&C%P{al}X@@Za3)33=kqGM<_A5*hHhX`nNCc2gPkFYXNG@;mJuyJ7sBHj0uahYi_g zaRi%|$^7`SxH~r9M2hpD!6U|UwBT)P3bt{>W|=eH2?}m<*&9r`I%5lshRvo>0-0v< zt2<9E#;%$ZCm8~haSvED3tOtOH)=P}*!Xa^B$A!j1`W(;KVp3NU*(nkSq;rl z2G8Hw-itR$&I6r+8k_h1mp1!i1!BWVu5QQfYv(Vwf-#mg+6Am}Q8+sf>DD#>Z&R=- z*zb&1rMRQ6+(>me(LIXL>JWr!0IH5}u%ScGoio>|zsv~40&cjq$~fxmkjjmxbP+Dw zvN_vPK_(jlpD9qhcj$MgPaNR9dxvGJc0{J*VxvReRopooV{pSgJPnaiTJG!n+)K>U z9H7*{xV4z`n9aauSOW)DXHO)VHlExq(M^G+IG7W7J4+I7bccHea-C6s(8%GV43^K> zszb>rk^ZZjkD)fO^T{-9pQ%IstU1^@&3WLGNeK@YFarDwJCeDDtP@k-4&BmSkdel2 z{vX(_%uRdjSZrabk1Yld!f^kKP0Y|_G#T#09qc3C=%E&^ zs%09k_tu#;k!U=Z98z7GcDl!ZZbvj^3_G292X2|p%HC-I^^MZF!|L2Q|MG@uELCTl zNcQkW*u#0@{6%P%xaB}6EX;B5mEl1*ea#f%KKD%%#fAO<|9$$kebpG|{yPPyxU=a( z2I#?mumXSTor#c&+{4{}))-Frz})b1#_`Im z5r2_+hTn;q`9}^x@^2jCtzf(qJ@lvp4$Mu}g_niS2(Ad6=|9Uln>^k$Q^MoK_2!HJ zAF~HniH~7DN6_PDcv#+vZSV~13w+MJ$A@t5!M#7d zhlSXU<>z>VAwQZWKWZER4wjLlzjp>geR8wn=Vi&y%L-3q$xjG>O@=EWFZ*RkdH=G3 zvJAYT>^ZoXXyg2NXHL|wSyp<@gg^7**YEB<+B{2sb5H7&-!e;nV{Nz>X=5LJOyoH% z)L!H8)}BzxPi4tZ34eqBsVx3BS#;Yh`E9ep+hxh;+s+M#B|E=(>5?pYB@KaaS$KiC zaf|9G{Btv09WyREEO{xr!OOzVppDC;OGBXWcgvFBP528kT-`D*IxM4m7TqIDJ}0#e zhlSSHSpTwyK)5WUR~FqnOJ47+@V;5{_Xqwmt_pjl0Ud1Q1}lu4pbkG1SYWq+aW&T)+E z5VVYJ`lzh%iN*sSAIfx}WlM zZQjIJVGPX*ugRj1&!U%R(HCUVw2SN>On-eA{f8`?pUJxi`Jc?9w`S2FWznB!(R;FJ z({iOd<-xs!-Gk|I4`KHp-71T2pGB8t(fnrJJs7__iyoUrADu;W4`TOVe17!q9;7eG zqSt59{3_l($bWwp%|8d67Y(pic;lxa#duu;6K+1ba3|i*^V+V%29+AWzIQ6#| z2j30z#bG;QhyRpXzk?YSQquw&5iTPvTJ2S=waz zISX?AW5g5YuA!ML_pc%irYLV6xNom|Vso9^_=&9sx=T=qhDYY&YIw&Er2D59oDFY^fcWL> zMDXNGQ~>8CSUC7MFSAIeynRO={g=!MmN)a56})i-A7o?UBu0}c4Sy0N$axV84*3(0 z9pM z>Ea#T<=s4|$9KecvT}gt%C7Z%hwPYe(11V3gq(%WM^8D6oNsD!7CU=xfd9r2y197v}P961Q=M}&QdH1Q<;QVw56j{|Mt zLo3cem>!Rg?(zijdB4lSq<|~H)+aI);l&Q}%OQq$#Ntu-5YC{S(={FBXB23wM$>`b zk`8Fj6POPk9o^*u(&NfAM_2G2OC=blYn*b-fqco&8JZu+mvT53rYpcoc~TCbIgcUD z@@nnMbEoxgIxCz{)tK)>@}t~&babcV;1hbFgVaOviODAUbIx}BJF-xDAUp-gIoJ6N zmE~MU8p<3=JkR+^t@T+TaCCI1v4|(~Rx1AmhRhIiE;I~?kor1}coFszCayA!%ZO+< z>xiqJZH2_884hetoM9M6#N+Y(yZZN29H_`9K>o3cM=DNIL=qCdK=CBS zWs0m<#z$2OqNoH>6oOD)@Hxd-6}KyXsJKh9wdwG8RP3!dNO6SXk&4GD&R0B5@qES0 z6t7dfUGaX!#}!{td|mN<#V-`UQ}p{B{qhuBD7I59RXj*>h~jv~$%=CoPgXof@lwU> z74K4fNby-knvG()zo+=6;*W})mol95QDO_lc8Wa|4^bShc(~#;Mb0M~|8&KbidQP$ ztay*&i;8b3eyzv>h;m|zEfm`;4pbbWc$8wT;v&T}6faU-r}ziO`xGBjq`elV`-b92 zin|qmQnYa|BwtfS*trn8i()^;!HT05k5QbVxL9$S;+2XwDb_1)R(wwJRmFD|KUe%t zF%We0X`Z&UoE z;^T@hD!!@sk>Xd1|5VJeo%D+oX;O#fGFJc$4DYirf;A={>JVTj`{~Qsfo{qz7ScOB|(mjNp5m#B=PF*R zc%9;%iklRlQrxPzP4Q#JZxzivN3Z6J?G(E!4pkhlc%!jFS zv5(>a#X*WyiX#=rD;}jdNpZU3EX4(i+=!C-J6-Wi#q$+cD{@;r@?EWXgW|1?4X!doT0c-@hZi;6<<{RK#_k4 zFujh7BNb~DFH*cp@fO906`xb=jfEWL3{qU6c!lEQin|qktsMSb#TJSODE3giQSnj5 zzbL+~__5*-ilNqy+!c(LM5icb=$7qQeZwkf@Xi1a>F|DV)9 z)CT^&Fs~pYUWy35c1m|s`e4OD>OWlRF-jjzJQlAs5+QG~;(3Z|6z?V?od<{q8OEO# zx2pf&i31JeBc*o{)38w976`p^iHKjIbO$2B2PjTZoJa)U3}Urm)DaQ?BE?HI{2Hb2 zP`q3HA5!{R#lI=OrQshb{V5Uhe^zXcwm`a#VsFKABJ`;yjxvlXMCh|Xafya6SNa^K z*C>63(l;o*LFs#xen9Cblzv(9b@hK=>77b{t@O`C=tHBL)GwEKH0(PP;on7ZpyDLO zMT(~>UZHrq;(dzG5h0gGiiw{Rk1&jHl{OCmJsHo1hzQ?Lv5jIE#lDJz6h|l?p*TnJ zB*iloS1Delc(Y=?;zNpmR{X2tHpQKaUn~Ao(QfbPn^fFiu~e~I@i@hmiuWnLqWGO+ z^Abm1Z^dfGNs22KuT#8V@jb;K6$?8!a=I!GS2S>Ny!I_2NC0Oz2XCk4=Fya_?+Ta z#a9)#DZZ=twc4q!D6NCm*JRf;z%Zcya^>`ZU7BL8P6{fy#EiZ3g^sra_yhl(F7 z(nLJ(JM#PzXju*&Qsn-c3~!=H8}g(}6uT+*ROJ8YylEg{FCA%icc#(r}&EE>xw%RKUMrnagX9p zil*O5C!(0ANc;6nzl~xC#V(5SycOYtl^&;fxZ*^`DT?zI7b~8oc!uJ+iWeweqIiYk zwTd?=-c7{)@Q;d{73H}t{GU$&$a=$Mn;=V2aKNjo%j=0|pp+5qVgp9j~6EXjE|BCn9}3b`TW3Fz>)JTJ%W~p$}9M6g@%6{03M`f9O}H zD0;)QKWSh&5%-BoMac*B9!45CiU|G3DN4SO4@{wDyssf5KT{QJiHI~)@kriBkiVHk zE<_qW&{8f)U&;ZrlmqmTe1n#JLm$ZpXvqiks?+!@h{c9+h0^PY(DMPMA0k5E zElR&agx=pMy_X36qb3mY<3!{`=3$^yq>-Qg8eUFBzG{@_*7I(AfvDd-T7m;njG%Hd z-`)eoEJqQpad3MNhVeKD zC)^qR$j5Ye@^JNA0k>DbFcNU}%TYeYc^s!#KlZbI>9-#KUU>zO$M}#RX@Ojfc$CHnw@-f~?j=W4h zzJVX>#64VjW3%L40ePihnuN0%PPbg@#baa;}XbA!QVYxc|)`0ZG=3xopu8=`6zF?%5&Af*LA2sHy;-| ze3^WZkMSvshnp_vIo^CcmL1jD<9+aMg*^Zd_K{Yg7k3J$OoS{zdJqh`hu6~QeJ13=f?AXA3%|A zIgfPsGUd$Y8;nm`JSdMxH5}e__j=OB^evO_YE9QIXHJajC_oQapV?XR!kFuofM*iU z0XPvXdYrBD+<0}6=RMqf@VzRyGx;DN^FdiWD38a@aCq}kigev^s2t(sW4zBDd71XY z=P5hk?;ftaXS3v$LtZVIn2!pauDthEo|})kt^gJ2<|Bl;xi=r=qdt_y!;Qx01>SsY z@Z@8#@-bd}M_#6VFM$BgN8H0rw@UfgXLzvOz2h$Vcpj~MZZ+HpzB>532S_;%2cK8J z2cRDXOafHlBp>xVF-t!_*I<3P2h-%i=L~eau zI*{vzxA7?|<`AsO-NOyD!RJl4?{dQ^N5+`$7@Tgpg<0}C_H*Xw+42gqOqVKFVc4mb@)1(dkv*;U0N> zuaG*F;^Z;r5TxsAFbv~)cotue@xN>@Q&_Ii5kG^>hiKE1L6ow=FaH2k>2txbETd5#2t-uvJKGJr-J% z;hu++`mw)IH?O?XTKs40@o?qggN@lVrqy*y*E!u%sZ{r}vK|Na?A!amo~cx?((dr- zQHo2ddueI!va(dFtY@Fz030Bf z703UzL)vj4SRK4FyxZpkPdX)`-D@MYp-v;WR@bJ|J*r;bYph>dc}*>4J-9oZm%p`s z3H+BVSYoW+y~JGIeW`EtyrtIa`lbHWyO#!5x35|%>Gs(E;O?B)1fw8Ko<8#nLVbfYID?J94(+1h-%zjk=-l-m4FC)A!?ABMI@5#<>r zd)`c>Ht*cKyrjYB?;U5fow2sU_1T5Ww}uMvNJuTgqs#gW^dZIMcMm%JM#$w#`S4AJ(c z3VTb(mdjhNt*Amhbr&f{$)K$>3sED5jt>1r2dj2OZNH)`YVVVLEV*aZcV=m~PMx-{ z`p!4ETetRGpDgTG_bb4hgmfgZbFCjC$`{ zRw`FV?~NO8uQP`%VGTUuj!zpmZmct%p4HgzU*zLhasI~r($*^fYUU$=`agQhJ9~Go zkL@mu99V4}@IA(hfQ}DmRSf%UcO4%BSK4j1?Denmr-z9CrJJt&&Q7(c-;lO<=UCD0 zL(osd(uX%9B%E4XA3$l_yKO7H=7w5(4O27QT2~rtj!OI2`qPG#R?Vgk+s|uTIMi5^ zOtq{&yXd4!quA+Tt+ulrw%o*c&+NrlMmWpsizMw-z1jPY9VO}f?f&#tZF41dZuLOK zcH%azcgi@GPS!KNk&4J@U_8S9{}#@vdSa@PxgT!4D+lf5>w&R!NKy&P)hKDVtrqRe z-}Zu?Lky8t(rxR=T|bwZZH+Z;(2q)`KMyMOr{i0Sv|mYXR}HFd)+xM|v7LB3wlvvp z6z6R3mCD^-lwLBEzD`)_CbP_;S5)kN*+}`Q?=mQd<94gQP8@o9LGfHg-k<*J@#Ect z_etiJ2X3R8W39UAM?S{AUH#g1T+nVoKa6N_7*(VC8SSQab${Jl2Yifnhhxpz4=kyH zQ>Wt7#0CBO&zLPH4G+eEIBMGbSu+;WF!$gkQ)Vuj3I{B`tJgHw3%dwSnZI=I!a3cR zWUQd;UDNo*1{s<7V;43 zoQHes=Ci2HIM=$JjDi1!gXQSTbVacISwD+=%n&=$jrRMv6)ScYJg#O3#5B{0))}+l zzT)XzeEtA-P%*4NAbqd!>i36gpeyzdx(%_dPZ7x~8N~oId@^GDeSuAwUi*EaADbfR zF4UyeSt5o5pMt>H_XyTG5HlN78NWX;7$p$!gB~tIf`@Wqbw6bLI}L`9H6LR9-KN1A z^j|7hrWW)+iED@+)-_-bT-1)v2rhxu@8BA~9?BF3E#DB7j9m<$pr7CAfxzyfMlj$z z6K=o#Ewl&*eNQz*6#ER!)`B4kiQ4aBRv!%e+BZSL+7CkKpe-RudlfPmjQAdgfC9sM z7zze1=JV8?LEtI~Jw+P}kp;7j(4Wa-L}t29e}vYqL(fpxaP%v1hq$@75sf~H^h3`L z!reR`{SqY*`V0M&hIJjh0+-ZNdQT)24{hfcWlr4p$YVs4sDse^bo(7SA3Oke*pc(` znPf4nxkw;zDdkx22H?C*oaJaDfy>3o7r+Boh;t?xt`sLY%{vj21QUpB%n=|8 zat&LkhY4MBTp0ycbbaftyuGZ`IPBfW~0oW}ZL=a%nBszTJF~3fQG&yHnT-?W0go_FY1x?7NwR zddYRMy$A(w-z`LmJ%Z(UkGTc{I@>H^`(E=Y5asqOWV_G&3y4a47Dh4qkLF4!J;boM zgbzGWfb8U$kQ}$q9uIf)DD)5eT&ay{Kk9N`J}VrJ+mKi!MqoTnISpY$Qz(K2S>6xOs6{SL|6r?TPtqx?e1J}r+j4Qm1NA9!dN<8DMd zDYPFu5J^U)VxM5W8c}IKPqGI^qiKw6_ET&y@n|`9d%8Q^$>=Tgf2Kd&81TlR9s-*y z5uCFUs>SWU@TH3A8!X)yD!^kzr5U~`tuQK$;3eu7j!GNYB2B=s?t!9#NB9Cp&I1g! z7uHkGmz1-Z?bL|o!QVcSZgc>?QW1FcAzWkpXU;mF9pbU)L5JT!3rgnfZ#75U+^I%R z%4*NN7c5wUc9mqsZTOq=^v!_ira*Bm;T4PQ-AyD2ovJM|FhNv*V!YYZx zt$V2x$Jt0ixD1>7&qtbA9N_)-<vF=7d*nSmbTExj`)IJbp7U}3@TKZ$8 zlMqR}8x`m*L_scXRz$i9Q7C;lQfjdRQ@L|tt1!~tS_#p`_PMBrNSU<<$(7h|GM!#l zXM}XNC!^gdQEFJPAg6&RmqFif3y!ckwZ2#b%C7zlEoY+ zBbB-H!Bi@lLg#-0q61Gih0ItIm1j+71OH1q&=7=LjE@(cwBGt-$k>822L7a4NR-aYk!{783jG4m4*(V+($jISofyBe6G%@FGVv%D>KH zZ}osX9=#fzv3HJ!I~hG2oU!-GQxGjirNurv3+_TA4>sTfFFenrN>N1pV;`?U%Z+lB zi+!>ZEJkFm5&P_7xcrgnM(lIC!qMf(ZR`uWqtObA`;zW>lwVTCzV3r)$>@5o&kIo^nUPgg2Bo>}{W<5qDrhiU)F?p6|Q!mRy7p3X8A ziTzCfQfWgmL+%4*b^zrYGtG05QeVTG2^9h_UV~hOw;@|4xd)j=kYcm+a{HT7d^U?O z_h1>gofe&2ZoY$5qBaXKcc2h)+-X1zGW`X}k6le-uvrD7z~-l3xkJqPAPQ|3bnY&NXrm zGnwOX?mQ#+aB)U+ryIFPh%;`p>~oJ2B5AYmbB`9Hz&-#4k$bEVg}L*M+==2$NvqAB zB=U=GR!i;_ll4+!vtDwinyi=-Db(C)QmCD!P;-xyLM@e>UhZ_W9vLjNYoK!O4D)^v zC~khk71$DET|b12m0&-3xfSUZr1>sE;8hk%jIS?Qv{4XvgI~7B?k0U5iYD;ZaM0lb zM2+WN>$?bqD3iC|$5Fx=HS=!tvF`mg?@f8P`(8o%Vf!*cR|*De4D54=6{QW`>hhq)4jQ}^*t z%m+af+J8VM;$NCygGkx4(dy#6g($YqN6PVUgeb8i7!Komgy?MdAX~t^lfVnf+P-M2?RiwDpy0i|0zN`%ANm$9)$dq}=X{n?SsY?~foV?LKH%@%?;TKnyYR zxVc;4qpOj2xIfYy7T@1@6X$d6(eadT2e^#f*+#sLk8RAKJI#o<6=xXtym+xVqiBTj zcH)eq5ylS?XVQM2+O-#=z&;LLC|)8&p*NXD555lD$&<4od6cW2-E)zhRN|_OVr#*~M%XeT3+1_aM<%i2n9urZd3T2RSOY zZ({xi`u0kZe2YdFukby95Dd-NaVY*`BT6CXT+Uy@r^Qh+GMzIQn7D>1B- zS+rkApik_4=w`J-B7txD{c+Ce$lFwVcW0D%lplKAUr$4Poz{Khnbv*lOzR$C{`ast zaIa+A|6t#b%U#mmdpG=(QI7QXcWg@q(P_}k{^3mc7e-gn|3|u0(NF3B(`j%QM`@VQ z{wLif(Phlr&vbXTuVjxfOcJH`Zj`TW%EGYBmSu!bmJxmJdB~(~ne(7`fBSCg=QmFQ zQEs2Z!VH*agQ(2q0w-u*0QV4Q;SiFA!?4^*i+lIC`k@7f63uZ9C%y!~op^@#=mcM(k0cI5c}5c_gFlv_ zaf;l;UbyoTpWzx$1W^2mL=t&yl4yf#exd|%lZg{ik4+O}!P6}9H%Qno!4Fyr67?vV z<_SNFp+$n9p0rG~L){f7kYS@$;(hqEPF#Yb*gtU*zFK z3G1#1j{M98A$;@^^moBEnX?lyl8H$tf{1WRn3&QTQ4D$DkeEtuf3z)%A~Bu*;piTw za6H|3xB)d1Gg*Fd$Xf|NYdRt%W_88Y;+s@W>ej%SGZyvlZ}P%za7PxLU^IDgBU~t` z&(TJLetI`eg4@VXTeM@5pZ+7ftQwZn)LYY3ZNhdHL#gG3XKvcpIznr6Us$HyE($h zU=#Y9d`4vEG&}9aM zDp-bA6gtfeqnm_YL4@Z1&^soV_AR)m32ir7xh=n-M(>)>(%lLjGxVPDwB%EP(EBDI z3$%O=23JrQs_%_65ZF6XO}shZkxH> zZSo$~f=?_$-#Gd&AX)q$!K)(AzS}2umHJ5@d=qGc~A4e@fGtrfn4TAo^z&}J|2|+(=Gw6Sd9_xgI*PI72 zI)sxGqbOgwHzjKr-H3jOw33r9h10J+0UY@)ae)x7*@Aw?DeU3#ZV$KgnhCC_r|ZxU zk$8s)`un<^Cuca{g<|<65xfi#;>tDXpA2Wv&jn`C@Az;%obwWTKsfj8M-Uppa^M`! z_%JA{3#;N>};Yv3&!y#Yr)FA&2uQ_%k$gZ_yN&-~YzI)`JIiIOo$l8FV<15@&R zxeTCdQ09_}2=2b{4LQ>Js3z#ARzZIbyhR9?RQa2jQYKcuq)x$L9O*LNL`G4$4^?X5 zmdFyS#mW18(7y!yK|hzbL4T7duUv@*{fr&-zl6|G8+bJL=iTfp!1PJFao#OHcHAuy+q+3j_HS+%8V~w|%HpR%h&9@nHAdbt9puZSmLOmoEe#0mE<5DA^ z@)6z*(4;e*W9i8YJdXf`ocNUtXUTHm;WQJ;res*!!V@e6jX2fi=E@|SyCI%(U+i*! zPHrlcFD?;FojfHftv%?cZ_xj!8NM!C3H0| zIqSjRH+=NyRv4+*qCbX@VJb$HxA5?>bo(RNv^QMCJA62LHb#c<avQxtOe_$uKNA|=bk$=3HZMI zeZTMi=Fb0|=Q+=L&eO|ngP5aTOh~@5A3|*iR2&Hp^y>JREIa{(lU$)Rxm?iNM=>L- z&J+0yDbL=Dc0{ws*w@1?P<@vO-Af@xMnhtha>`@uIh0)X50QL}lFTKV8C4gZMjHDi z%!vYrQ*pv6$itMt`US(0eH&2U0~=O@#3}_9DzNc*(B8zuQ1JqrE&v@!{D3hXe?7$= zqbcqbCzFuIKjZ=RNs&`S)Eho);4qZBdbw_lB&=fb1+L4) zJ7^NiShKF@9MB{dqPGa#KpF$>STZ--kQwd`+`AWe2q%ew`JJe zmJSnmLLA>=n&k4#AuV->n!r;Gbx0?!DF^;c(J(h30#7qCWD&E$=Vjs&?qm}R+?*Un z;&>S&aE~;nAOb!!1p-LsziHgFpMbGfGaH|C`XvTIy5C#`4CgYd_X>GB#ov-ET0ZY! zcqZ`8Q;C6po(kHD;|+;JHUR=}PlU5K(aXGlmpOpB|5&Exy-IkX55<3ADjX66bFDvv zi64bT1m;;|K%4lt7+ZnNvc2(-u+$2L37CvC&^rc-tP3F*;4fxdnapQ09ZHWs74}&#$r5G!O(-hsWuYg) zidP)h4aj=yRcAUp_78~7a`t|$=ct#TCZ_`;b@V#48Sw_Ho+Y;xSV7o#dS>qf$Nih^??AMW z@FE?22}fQh{O4pD^B^21Ta}(}xcwGxE8zBGjN5bS_AhZ;YHzLasrZ!lRYm?!Dx)6I zgipv(RBmd#;VjzajWud)OaU*PBNYz2+Ytx6)}NI;C3+-wTRnN$hqoPsJe4p zb)Lx<%&T}L^X zS{0Vj3*CaNe0JN>Cd=(vS@UzBAXF|0gOpmefTg?xsYNXB6- zUHdDm(&WQOL=Nt4#;%9Ib&}H%PK5Bdwsqv$-ktjD&}Qtb=qs#q9l?hw*x1%Z2li)< zq(eI`=GU?uAJ40s*7-u4u|Kdq|K8D%fh3Jt>55z04~7`;wuom*FXDb5EqgN!h{Dv!2C zufvDd@KsQ*^!IR^2DclIqw5CCZ4YMlB9sDm12;m2)ox8X z0{rK&ZPHp0o;c);>zmyL7rw9~`xFp!NSq6TuVBu;1jKb9@`hVZibkQpB}FsP&ed&p z#Lcz4SbYvxpAD|Ld1dffjuag$KGI!HX@lFbaKka@Vob2CiB1m>{&t+!_9M_s&XwLB zK4Fv!ESihGX$Z1?egbx0S5LjMvMdfp2|ny5obHEiWV|#FTz6xU=dixxUo%Rjj zrVIeVUM>&qTY9N@M95UKH>-pjo6s0>t3-Eq7;8AY!YRkN0a1Vwuuub{7tX&>12R+4 zPq=|h;TojZT1QKHpqoJwPe#C^0LXKg5ydMo)?4d9srOEJv+t5nU&3a-c-icLEVN7S zV+spH2-C(4;o+!#rMKGM?9p0F*&jVY64DXr*9ruA*z?~zjdoX6Lo~>mixGNRh4+!`d zcuwalA*>#2A|3`HE8XyVrfMEEmPj#gVBT#8yYNGZSXcZFic7ym)5>#tjkh3p zkqDyK_!W$_ie+34oMWck14aHEXnYDp28cUVkYhem%D^wWfeT^+Uup6_gFkD-yW-Cp zY4X2?8!I030y;2v;{{brSWz-QFQ9_lQt9|mVCIxtNM&Xb;*>4nO)#_cZWk0zLMzHE6wE4?|EI~R;35#^_% zkLjPc6F%%9qL-3P`R@>0|Ah?0Q7#(Bv9tW2$f*ALRL=oVyiIvMTFZcThGFO5H%!G# zQ0d=icOlc+;itU_!Ytj4s^$N}X2+67FUPs!i#TM&at}vI_6BJr(%46*v1d+WFDv_} zX6Ye`s5M0vI}~R}l?KE_J`Jp?+J=Hm-Q5pDJ}=9l;&N1jRKLX}u!*J7OLino1s~jt ze@t?kt;@-2(aJwOPl_1hpRn0X*~X&&rs6DA+xXY*G$e$rAdNDnf?p4aUum<%*bdUz zwV3J`U{d`35{;-p)l0R;B&7xIq#;Sm2Bumm7+&ylpI~rK(1r$k04@j22+jdDit~6~rq!S{(LHY*a8*p^fH&KP5k1UoJ zcG9dtSQV(4D#3l5ZYcB{UMm_~D(*Z;8XCgRP=9OOpwcwPkrpR*rH@78`%|NcL;V2D zawG8_=|m+s#BQpsz#Uz zsz#WJ*;Za!s@2aoFXOU8NzbG>lb6N|hgm{oU^<(xE;+*>TxBgAxFWbx49^XMK{tH% zX%;F|p5*)Fb5662Cu3_NLQa8)p$GbIR|aoij?IByaZinA1TB~r%?h&9qnSbWFh-P@ zCK1h`WmE;rr2fqe!k~U=S+inn7N6O%qL@0z=3_5o=0>xV(anoy8`*+rmXa;Zw&o6s zmTNCXMNTeUQaFeiQ5-ATOK!fCMJiXK@u5;Mf(0>&N6s!x(29|2VG>8b(zN_R9{AuH z1*ewKXR(tFtfysBgXa!n>sk`kI9EcJ$68jJHcP5QMZ{5Rn&ViBc+ApRAIH5a+r;Jq zW2ugnqEdw9fkDDprjo$7e_7^m0ym1h2HOHxQ^q|U*`qMJw7N=G8aRRI& z#e=@L;)JP$=WyC){mEC8_{4E1Fr>IgRV;^75e0$61WjLhH7S-j zJP0cy9;8;|ga_e5oK6T*+i=2zkb-h?JV*_YQd&wlFXBP!LdOFECCDnrwI0CO;;}>4>13;` zvmDNpM3zw4F|BGnNXMQ?En|QboDd{1E762sz|9Vc|H#2OJtp^RVlGZJ1x8fpkc_C&A+H5cM@(A- zCkg8vei_5pi{vtfWk3XqhF=ynB~n0;!KHLDl#qz?z<%=o6i9Y75PrgG8*GD+;O>%b zPI~YZ(2>ItUg`>a%+`6XtjC-*FCquR5v_7XQF^WO>_Xd9g;=OfN;GP@SH<3KDKm*14ND#P;S9cFRDP)yk%}E zxH2%46VtDP6H6JM7PC`>B*8I25UY|WH1JT zQ=5CW565?D)Hl-BMic#8lT*;qfv+Xkb+_QfIyqg9$L6#(9-CF))7IG9l+)eb z-rCSy*8-oq&UIO>Ep0s;v+CL!JKI|to9gOYvhuU1=X7*7)%UctcIPzKb>chXSsSNM zt(}^mgAbzTtZisGc)%P6Y-y8M4gBvWbhOrWuW9dG2Me5dv!+93Lvt1k%IWFqbhYHH zt7~X(!It9xnxOwyn~CNVC^a;vy#t>C?`p-%2O=*bVy1R=H#Rn{$!=y{tL@&@(bNUn z7I(a805pn&Z%qIdhkf?0wmdp2=}^wA8ltpA)we0Ov^xY|e#CeXw6R&StIi>s)^|7r z?hJGYe7?NlSoPdk+gR7F?%mCuO?8dx(Y6+O=E`@rw5@Cos>BpEbkYlx@dn4{2CD32#5s#`o3%(OSm$~7LZHEz}7RXHSP&dtj? zWOh!jeO$JkmQ9xmcoBWGd~;`yw0pAclx(|o7Pg8qdnx<`%6lc|0EbWeN*v(ug|TK8 z=GY0d?8I!lJ$s0qfXAs3_rz6;OGk(ii+poN%n@phZ%$58PR`*Ysvn!ZSPitB7nRtf z!#hUIIb?*SYlJ5yCe2@3R`!%Rl@mwcJz3+Y9x-gx$i=hgmND#%Nr-Xr?4hD3>{~t3 zVmVQq2gg89`oriB&XG&QzV)^&DoDz97DWV%|8 zZ>sG!G2g5&om?fZB3swGw!O2ZyLp{yl3LhXaJgw~sBLUB^(|}hXhtosQ(=p~sk5%T zi65#L;o8cIveKfJwM7L*3+KlMuby1W;OpwT8=CnY`L(T0PJoV{dVZe1tJ}D*HIY}M zbfD&U8+;7DskW=BfnA}K&}HSN%je?>wzBG)s?zcWrl)(&^sa6;6XU#NrFLCUchg4d zYiM8B0a|QZ)6?3@@6wyD=AQ1x_6=JBmsx7tXITMO7;+Ybp?1ZE-t{ueK%S%VkMbTylXy4KcubYrHpx_TK(0JW{U2E|@l zUK8;{-RNv}lD52{Y}tG%jn39uRGa#y&KTQ~%r;czWgX}Xn@mfkzGKG;syR|y+k>hw z9o4oTqg^9Px~mqW9$tBad}SZ%NY_lw(*W(=%}t$B-H*kqdXUX+YieD&?8)h}@YOc$xZLUM=aLZj&lj&U3Fn#i5QPI@4zII(BL$cA-R?S~pTUuUHfe{8H zUZ-j4>gs9g2=sQu*;>z1o(Jy2eJth5UvIwd*m+8y1y_*W%$Z8rI&>-P8?28Ue;% zCsR~xrjQq!MX1d>T2SPjEYMm{ROobmM$n?wj{P{msHK4FQX^# zPn5Kx^QkN=sDbMSbRSKQV_`)_+5CcXX#!1+VN6;&ja!oLONzRVbxOv`+@h*7Cv)4| zS~qpIuWQ1n*u^fc9+RG?x;9f=TUj-~re%Ev=0?@*l~z>Xp@6oCSxv zJr4TawQX*SoL4k8HfxC*nqJrKW(>P!W}?$iwrUx%ES66}Q?999j&8AWT}Pgg7E|9= zyAHLYX`}WF^O5uOtB|q9@^U4&yrhF{+UOWoQB*U(rdDlpOPi1QcC~l%#Z>j1y73Mv zyzZoSO>5oSE+Z|$IK8fsLTN0oma1OY(cx4bw8&cays+%JJT02}RW-E*%T`3XM6m(4 zMzi_W*0;1fV&b|MwGj;!O`?8NZFy<2X>CV$A{z|52IaS8zS)?co9j0Ej=E0t zXWgj(h2^zHH7iiG$U97f8;oOmXVco2F8DV!LTOJoMg?~0sI+W!2YGMSx>nXuv8kw{ z99dL=Mp@1B5M#t+etAvRO2?*33@9}Pg=H8!WoW5i*P#W5mdJZ8Ib*EFGrn#==9Y)s zehQYM&#x*){Y0k=6C?dqw8=@tRr8luEJm5SrR8+(nBjFdVgqD&R%crS65fEG!!@|P0#Ts~$@sZZ`Xl5@v`=%Kkc>!Pvrgca z6KbyIsAc#LHA!)Mqrp&w(P@e4X=~xSqN=H@y{EIGsk9M8Tg#djR0ucXN=TtFn%32| zv_`W+`XCH=^NVT>63ZZ{_Za)TA_19O%cq#Go{kPQi>}(nmbFc8J&2vM(BRg(E_Xy~ zKo5leOa_V`x7~BZkSNjBt#cZRYu~bJ^!Saaq#f;)a$@EC(3n7HLZFiwJR!um+<<%u z1Zq7>q^Qu)&&f=8)L()kUSSX&S4(^)97a-^cwum8>TE$)Mg~1ia4 zbns{(t*zpysdmQjDU&gX%kbxPLd+g{V_ZyobY?RR?LEl8y4IGuE+_LNLp5q0*2Yrt z+`PkN3b`jiP*u=}qPK0RXDXso6DJxsRqlKaB4R@khIG?%9BO!93F!to>*z$evG;P? z9~wg~8)%H-(vcwQZl@3BG?8Qs=6x+jbF2-etZ6PLSm;nOwdQIN)u^*A zQpZgfr>6A7^s7BKUdAYyX6k#^K-D^GV%DHMYSDMJcN)w(crT62?jssw=WTAwMCW7b zCGuXCopn)Dr7Mi8g7RWrBQUy1r{rdzQ*AIT#B>Uh)0hsLCMiCKlb0YG&WaA~r6uRJ zOTk2@ySAfN#*s)|k=j%1^x-mTs;h5ByLOfX?u>vH76UZmLkn9{QC=g1i}e1n!-7oi zHGOQ}$Z~e{+Q7=4sVhpa2enJ5IMQo2HaQc#_BCtx^s6)pl-2r{u9m1Vu^B^4m^JL? zYa8kfx~tYkr&n~VbVX5hrD?2}+%udSI%5Jl$n}`Y)VUK0JZn@N$%aUCuUuSIJ*^iv zoh=wOXRTS+)7srqi>$)JL90bQYEYNkRdG&Ij5&#}HaeTuNW0QCqYQpxHj>cUguV#& zNO#U22UGG+PK4XKWHKuQ2bvTO)Y(q?{KJjz*tiwLnWi#JqFpLW!hM~k)AHIoo%L&M zHk!r`i5fZ5vSyQXPcc!IPA)bTHCQ;YoM9{1NX~RpnjGSjj>sA87(J4TnFWfrS6-A( zM(^hixzdlzg681wy3}U03`0M*qgWBN7e~D-EGsQ9=7N<=@R&ZWS3_%L-EH3_6OB5j z6=Md-HGQ=~EnbWHffP6AATZgjEqq;<46r)3NXoPoVDcU=3S)0CoV5;>uC1j31b6FZ zW4CVow5&R?Yg*guy0fr(IJ>KTP4}7(I(78SUcaVe{gkZ6ys6;3n^FIXtzB7-7;g~M zZ0rJrv(~O{gnLC-IBN~wQ`*!ao0ecY7!kTiY(F+;bxX4Z-_nL9ToZOJ@ru;hcoBHk z8fPw@#fd05F6Xjzy-$_wW2rILO&V59D|R<#H@9G$uMKkT(3iD_)5k0sd7G%Ltv!pG z(14_IAmJ8))G@6@I?IccuH-E0Kc+ocSx8^&tY$E}xTCk^veUhEJ7bg3O2_nO!;8np9`x~UOK8=RfhEL#9Z zB2F1OW8f^@O=D5Tl1ir-+(jd`F^j897myTfmCFh_cE(uk4pGvzNHJonRKXU-K)uEZ z2^NVE8!cEvx3Ct~wK_dtm%;RaZ-P^$M*0!gLY+x-taY=$%bDO{Sm|C9QOw=|V`{eq z?vj5lUz(lNIo$+Tf-Uvfgu)sYJw7b$YR3FiHXZOR3Nr>%p%$3uY@caAS%n^0HX<6a zP>w{1*?5GWUj&7bMZadBY=XmvT5Nfs=Hns(I`-m)Zsk2-#M7w=O)uz@hS+()bOjZR z(_GWhj%nAX+6HXt$1Fm6^~Y`oE?it(;$%W$X=G*EtH@+RS=Zfz^^7#JT3Pyau?6u7 z9oWt>yU*;6xyL@$SqnB|{6vkV?Y)vKeVm!x>JRE4IEe>7OdgQnM%|yu2!`!mR6TWm$jTM zwxB}lo&<)YMp;Pf_9+@RdtoQHQ7|!ET7^q0wbOJ{7hTv;zO!k4`>|MhIhwK7h^*+b z5G&%M*vVyN0>x$T&fV`gpmL((;aMw;f-uM_a(BwWAZ-RurfPn4Lm#ec78T71XJWV; z&(V(8?|8lNXB@cs@WdqCQ97EAdhi-wVbbU=@n;0i^#96tR@~X%bL?|H=UW9y3o~3H zAg=)yB&BTeo?)K}UlWe;<8{iyr10s1E&elnXU6@?dzO7RWroJc@ET@eQpOhF8F6QN ze`TLVfA=~j#Yq3Z<42(1X`TVe96=ss3KJ6ikLk9WNXji`Pu!rezfv zUxL3NfG8(Nt^U?PJHr}e4fYJNhkHj_CcA6XI*jPR?oJ1rT?#wz-6mTKHoLy7 z%VcAcm`%s*Uudt{EnS^;*|{dWplV4rp@T&G z%YqV_J1Nj>9!`2EACTT(5<5tQ|C?y9D1R{$r&#)ApQ|>e%-r7HT`qH8-Z!5PDsvF4 ze^E|M?&~XyzyB*LN9ezZD=H|F9njSrEL{f|I!I){EO_w94w|$BltfMLQ%wJhq{O%W zU@zhCo0A6@I!NMvS@7VAbEcAgqdUN66+1|T|C=bg73okq+q3&t7@f+9cdXn2`XYku zB8HADFFVhv^ReNu)lk=ZKr9%O4u}B@fCDBW2M9Up4lqXaIffkM(nfaPnx`uh?(E&KobKPnj(kSeDQOH0fB4Su`GDGl_BD0^KOlp!^SNTvEwA~ zmUC`Wb8cevfakqFynEU?ye7{j1!u_f&4Gy93^Nln9{$l|hM5OyyvyR5xcQ**1c@Fq z%py>{@yR)6$amcsr_1x+sYx!2@Vuwhy@!a;*c}a?I-O&NO9ZTj- z1&kgxEbpBk@umUZOg`iEz@OncraMQxJi*MHzMNx*IT^%Kmz8G#BMfq%_nt)$8?p7a zr+4hON$O)ylG%dbw1@K~5BwRvUqq!NADwF@MSMuua-U_?$wtoijz3xwj(l35_|wdl z@L>G6tG1KPd5o=AR3AN_b1 zE9S7xus-^S_0f+v=)@ehIV6Uo{%{}t;XeK&`{*CpNB_t^^0Bi_>L1fb|Cm1V-Elm-n|z+Y_zQ2`9DeTCv|Ri^}t`kv%uw;WbOwxD#!Ns2x#79 z>Krr7lOWc)>;d(^w>37t0@T|jClZo`jozlWeZ6}h+f3;rpWjCx?^28&HhQbx@l7>< zQSVtmOM0_d`RRS+r^_=UlwcoV;YHlBhkZbLXZ8ut-Z6UEW_BO{*-=kWwwc?%_SNGwM08f4A};n-ZUKs1Lw4u(qFt`);l>}?qo{SRC)76JPL+<%TqHmC z`j_rFA7u9(Gh5!Q1!&`*G?4p?F@ljh9Nf5Lm%P0%O!bwJm0DCp*aPx~E6f8NMU(~L zsuT&_*Tap}=+)cUOX{FyckuvS&WcL5BIO!I?5!5!>gbkR1)U2QQC9}&b-zw;FX!TN z)UD5j?gLE0qQ*^-n~QKd*fPl#6BUq=T#UK0fi{(dGoc;t4k30p?oY?tdm6?>xknZ~_A1 znBYz+U3-zw!{N?+E+dX`9v)==BkRPSeKFm6OmL@o2+w)3eFRr&(7`u;;Fyr*AoHV_ z|0$091b2$$`q%aee^{UJuD=_8Zq%P+Si)w_N7y@+Jkr5Ol9)fM6_Eud;Y8`6O@wg?zM2o&2^JAzkF_FoqH_1>v(L_P~jjw znGc>-`qbKQ9R1`+)BOVH*%pt?}S#F*h%(+#s@aH-8*|Wf@&zL$ma(JZ4 zmGe=)QSE7Q*3ljy=YqsR#I?qZAU5Mw1L{6Qu|SdKNBL?+m@a&s;u=LXadAIh@l?gL z6t^mFQ@l#?M#X0pUs2qv_^IOeihOpI_ON`3BNVe0XDXH|)+nB)h|2*I?h3^l6n82< ztoW=V=U|NIZN<+OIrpMFp9mqQC=O8^tC*)aOObOf%2z2KrP!?4rFgR9*@_n{Uafem zBIj7t_mtwxiu`^f-9J(MPSJ-s6W!Ak!-`podVAjL6?d5Wcq%N6Ss*C}pNJVSA-;#G<_EB-<8F~#Q6|Ym=srZoMpA?^0{8BN|@8}<_ zI7V@@B0tE;_{$VmDy~uNQrxWgYsD)RZ%}+x@p;A96+ckqE7%y1g$|RLq&P(JP{j(x zBNbZ|Hz=N_xLxsP#Xl&1p%{#J;u)YgL~*R*WW_m(ixdx6tXJgMb7}AKif1bF9bVp!_b5KE_?qH(ig5`}IKD!e;fE=XS1eUrrdX%APH~gsnTi)HUafem;{A$GDZZq* zSMgKD?-l)+^Uyh6tfklD9%wVQY=?ILa|w~NAWbp3ly(ZyixHFihojkL2-}bM~dGnaxP4}Qxu0O zPEeetSgg2I@n}VUj*8*=jS%7)ioaF7Me%dR|0u>|?oIgtilY>B6=y3hQaoI-QSms% zlNHZZ+@^TF;$4alDL$k4isD;}-zlahJ9Z6K%v8)*oTpf(xI(c>u|x4h#j_MIR@|X@ ztKxl%FDmX){7})tnuPh3sK|G$lOL*>shF=gPq9pKg<_*(hvJEfXDME+xI^()#rqVW zRQ#Lbn~I+(ey7+k)v<4?;w;5N#f6IHiZzO>6jv**QRF8cnchytjfy8LZc#i(@dCw5 z6}Ky1t9Ya0?TWh;|ETz=;!}#xDgI57pX{PNZz%Gc5#&Es+^6`h;*W|sSW8lFfnv2{ zt>UqYCo7(fnv2{t>UqY8x&7h{Egz3iZ>|Ut@w!IUljjG@g2n<6#WAndyZH9mEy&U z*D8Lf$nOo(elyU)s}&zr{GY*&`#XxCDaK)K&u{}2$0<%%T&B2D@pQ$T6(3Xlr{Y(N z$=IZ%-oq4+R%}=Nt>Vp!_b5KE_?qH;Tvnoj#A7~oT+%5 z;xmdbEACbNMDaUC?;(!<6vd&6;}sVuRw*8(*sR#4c(UTziWe(ht+-3^6~#{#zf(*J zJ9Z3F%vYSNxK!~d#TLaL#nTioQrw||=>dXpf516$=!XE7mGD6A`YJxYn2x)P0NM+3J3w@>eSU zUhyU(!atlJq@KBBls@k7P070nopPjMI#buX9Lg!Pf~ zE0wQTT&wPz6)#u3LGb}%lQB;yKBMlhD*vY9yXyXx;=hR~PrS2J!lx+qC&GQW^5Yb9 z6%SLKLxlY+6gw5qRJ=*?NyS%)O&A9i-%OfG zMC@;FC&HdBRZ?6o>LzM99rjEKv8w z%CAs7O5J;uKVJDQ%Ac+LMao~Rc!Rp%Mnt?jm4A>}XUw0~{W--~6hBh5C#b!Og^G(6 zyA>~1yh`yd#odbUDGr+meJ#d}BUa#zM?|E*OmU^+8pSTfQx(r7BHTqp=($Gu`_%s- z<^QSpZ$;kd!*Bx?vlUB-h<~y2wTc~zTNJk`@>?&A_X%PR+J*8T6S05#wes8$rCg$7 z2JzQeKPx|;cplz&r2Gux`FOj(@+%d46faS{L-AR~_Y}R^PJF`^rz;+=*s6H0;x&r* zDZZ^3$Z_-xQp{JZQEXQ{L-9&QgM;IRS23uVtcb2z{4vcEL^cWLDo#_JsaU93qPRqH zsp1O7BNf{eI~8%sK=hxaxJB_S#VZtlt9YH_O^SCa?oxb8@ma;)imxc{QQWKex#Cxf z-z)y4DErXJub`#*qR96EG9UQ~9Acg#uV0bp^($hL;sV9ximMd)tsKhn?SsT_#f^%; zQao2t?)ie;rOIEe_&dd$6>nGMM}?{P0Y%yGMj`)|Jn$98*A)MyDEr^=|5ka~2M2F? zoN%%q4xS&Tp&r=}2aZ%;_QkGde53NRZw|g) zdD%Y)e+GGsU$TD=yg+%`M+eV)73hDh;!TRTDc-C2fa0GNWuG14UQ}N8+rj@sdD(Xd z|B>>aDt@iFUlA`AlK5pm9`gLU4DA`D$dAmBpQI@J^5EwxFZ=W07b(9?aitcPR3^Gt{?B@d3q06#2aw`u|PwHN}4_exfM*{E+*%@;@lb zem~rk&;e0Te?@+Yk37FuL!6{IMRA&9iQ*zfegcm2M=LfdwkUQgu2(!sk)QHnxC<38 zRlG{^8pRtGZ&l>ia~MvpF94rX{#nJ{imxc{QQWJ@FWfM^Tz>$vZIbsX@-sK&k>GakXNLqFlE?xNhY)DxRWvy5c#C=PO>Pc$4Ctin|ma zP<%x3uSCrC{-!9`Il%u@d43v){`(aFt@wi?Kb1rOBt^Ln0)CM4Va3sk6BTn5`EebF zFH|g5T%uT`xI&R1-=X}mid~8u6i-%^>nM;rTY0&j0{&vmSf_)6vL6q^)V6+09+DxRo#p5g_HmnmMUc&*~~iv0Wz?Rij#Q}4@+$TfaNFM1sQE@X7>D;2Yg7YERcOwyYJ*e}eahw;xj*UdbEB6;5-Ydu> zzFUaUFZUHd{}3;D=#_kdF&WhFrW^b`^3X5o0Wax6dc`jAo9U1EwiChcAR^vdmA{jS z_#agMQ6lVkPWcy!uxF3*dx@~i%Xu>N@jfNm_un4ab~XqSc}gX}Pe5do93${gIb??% zedXxK14(0-_kYUOLZ)xLym!q#kj-*T!atgVXE}7oX=HFvj^W+-T-*Y;*m(CK-W0eoUcbsS++LiFitUug7BIOEDgUm%d%?x( z`vm&JaHBrDQ;zyx#Yuf`I(CtXIb8NzPB$I%A;;iuxN^7Rz>SBin)klr7fDAY}83Zd9|&x=V1E~!Q0Wj^2+Ne4fccRLm7;o5UqAAQ@QkLAX6q~Uba!SyWlx#4`S zL2%zO6uSl~@22BtM=p{M%F!O`;^7AS0dleNPKt?l zjLI<_+hJ^Zl>I_FMnf)E->evY?Bf|P^%bi=HytZngW$)*O$YDi106{RP+r#_N{HYADEXBa6{@aUXq0LfEnVZ5~CZq?_egX_`Q!&SY< zk&C2*atu#hJlu5ry-&Pf$D|`i6%v2RXPdrCsjf>iemWz9*nB z142y4Y@Dt>eEF@HzFogyAHFTu%f3A^_F?)M(O0he-1_n&^!10od(d_s+^2DA@?7uU z#)_(|jI-cJy3E(SKHqY$T?4%Txw3{_k>&6rJYW`KA7F6<*0M5X$O8Lx*c$Niz$ z@)&vn;>E=U#ycOU8}BuJ^nDG_W>*=|)yMm0WA&9?>CEY=Z$XSc?mM|*sOHEL>;aR| z!}a4nRjj_>L*G8gP+uud*S@Fv==%ivDi4w`f9j*};_cD?U~!B-?t9S&wlN;F;F&tm zq4`fgp4<(TP zmr9&&zWC8z(S|zUB*&Hpd~?ucfUauJ1>Lqr?|UIP5MkZJl_PpwN8pPsNG}ZGI-(sX z<4wUy+hXp;gtDhCC+C<5E%{&J)NtU{EesZ-^Aq$WMZrtZ?ZnxS8-O!g67-4 zO%J`fzb4&VvbAJb$@G#<#XtZ1r=NW#CbMYw-}jr`ckWs>>dpPrN1Kb%!*A}-&%b2E z@x>>IOhfaV`!myh;gQYeqD{qb?hogmP;6cFyJpWtZ|=_k9p1a6Ij@A;p5Bj$Gw1F5 z;?&j9g)IQ+`g!rGF`9lXb@lwP*wykqD29IZt^K93cFoxR8ti)Du9i_>EuyBc7GD;l zX760TY0qZ z^pdCVn%I0;$+p#w-?ru<%^8xn!lz6x8Qh#uJQ%)Lz{j)SzJQ?yy)|8InAm*BqV#aV zh{yK_?mWJDV)Nts&7HWr=Av5=8|50BZ;IG*W5ky0K~3CyJ<=98(y3FMCEvGhzP5DZ zFvsQ8l8n0+lpwvqIeTv%b(N%Y`{LA?R9+F$ye*>nGL83-UzlXG@9E8%&9uUdnz;Hg zq@C$5&~*Dt0(VbrURhEoDUVIH88NuIFp}ckH495tmQ;Lg>Z$3@FHGR|J>K05CG{qA zpHlZBzJaelIclTWxuKVxJrO&*B6fCyy7>c>)3f`dQ5_Pdy;rSR7YTE0B+N0OF8H9O zPp-|{y>XcL4%#-c*?YmDW~+Exvs1DYnlD(r4P|>x^9-arE-zZHhc)*p)6IE%Cp7OF zRWKrDb$Zxbv~*F`;%G~*jM!2hv1JLUMIXE~s!VKOym&)Qxs*oa7ewSsKu!L@8k<`Z zLZ9-`hx>lB5S`!zoV*q`94FU;={Ube|MxAP$a(Rfa6Ww%}?T!r&UoLuko#V2Y(o2%yaU!m z5B9<5-kDNj#++5+za(%;=!>E8@t3fiLtlgw{OFBIpHXrKKfRCGoe=&B{N$Bz%|S zx~1^5m*$l?Bf$e`L+QJ#_C_U}?{8@Kh3Ayg?%5ITvqbv~A6SQ;_I$cqePVd4zjk7vnrfPd?XIhO-=Jv7Wrg;!9Kqo*(0U87KGecHz7S z=e2sS0`j=?j)cuwAAMDjRFYnjg3)?#$*|I4i#O?boYx#KNfmqTy@N`f9`?=st2c*B z23G7ZKBd?hQTmroD4B^-J}f2Hg)oEEa>u```H1GlcU{>$^RC3waEZBS0%T{3tQGb! zZKs+?+F%POQmb(;$GHM$InJ>-dE9E>wYd|IuVX@kcjmXP?co=0qF?FSh&N!apOWLw zc<>%=d6n-BGl}oZ0^qfcJwW#rlg=APO>@)68F(djD||Zf#`}%kGt8I?U6ptbWw=aU zfgCQ1yxnw07*}4}_+c8nq(4FAWwM z5B|R#aoB7?SBJxEJ(+|#89OC>FuT{}-s6qq*8uF%5c9l@6^!wE{nc1?;L}y-A+)^< zvD=w4kF^3PAhg#LcUV7yKP??zd^*aWBmo0)6=1vpe;Hzfnsm%Oz23MPh&Ij(eukLh zTg`d!Ht6bDBW2mPX@yntB4kEwItYTTxA7@Kq$l z_w0>Ol@fdd*7^QI_jF_b4-y)8@e*i^UqWBsUN$Bt?Aw$vLGFh7-XZOE^t^i?=zyc= zqccD!B8i9~?h@*;--!cxsgPV<$6Y4mOUWR&3E4`4%Z0p*Id_GSU(xkSA^E&u+;$;3 zq{Lk%B=4Sy`>l|C@G93T%@s zFrhb*@qx>&U&i*dtkdTDWMxs0D-Hl3m}#b#bADG z<$}pb;s=8QS6d&$!lA~#jm7r|?#U(c!LYKxwbo6DAqns9HG%7_OA$m3xLytT36(c+ zgJftR^fhz`ZnU!DmKb6k58R}=%PB(O7HbI&NW!;xOyE{)I}Hd;r`YWxHZ*iBGwKdu z!XZvo0(VKOM~CLI6m|-e87hK-fxE39D3}y#BD2f70nEJ6H5B`UbsL!C&}y{fz&+M^ zFnXb}=c2UZ?%##v#B*~zJ#f*Fpo2@8HJAJcd1ivVNFTUVs!eb*?b?RV0-~9vqM!p; zv6?3azo*jQQYOXNB`o6y0`QKdJfHttGZRwm0Bj1ee@sXfDHGx&X$k#ocFf)o_gfRv?5)hD&=Q16NVo5l`uQLVJ7Iv$ z2f2UA&`U^nLWcbrd@@2IbRP+WY#T-o4K<)qBn%cN94bUDN*H2~gwJS` z%x@6HJ(r(HvrDGSQ*_3^Ky51LFAZ@d{ILGAnI-v*$-JNqkW}nhcdWDTqJD zb0$+@>=3do?#Td>n8@!*m&Iq=M}tYKsxtB8ZQcWBlFCi|1R>Lt%3DnQM4>a2+Hy^N zmVF`g%#tL=I|(UH!gr?Pb0tw|v~|!H_Y@xj5BO1d_6Equ{bdvQc;2a*7_8z0;K53m z9;{|gnjnimSVP(yEQAHYWs<|jJ_lJ7_Z%M-k3SnF98TQLhr@%sQz7wh&!7>QAS-F& zD@&BmT=VlWBimbfP!bV~3JRQ$v@=YUQRwm~xS9m-?`KP3HrGw7iv886+B zdp->H@qT2{ti+E#U{vg#5zp*hmwIyE{p&w328B!-xQp#ou2LdPI!p(5*j_@sxD$;`JV zVy`tLv7Fso6hK88Yp)%{&V8Wp=k{wzq3eed2y`#7nHZvJ~Kz~-K##&ARc9@}M z))`2R2?bDBLd#_^@g{Yc(BT$S97sCOgjNWdn6%b}RtlLCV%~?25GFmu%nuzYOh(8; zMGGA*%+RDx6RH(5EVVXNC;CT+SS+Cii{+9TV!4DGEf!3sWNN5MGIf$ zC*A4cl@&}Zb7;(apHbQK&|8+g$9f;NTFO58pD|^h{ANtqC%>>|dmNYq&tfpsrPz{_B-OK|S|z7=+Tk-V z^Z`}(^K1iC9NLZgkUY?{6U;)B%|w3U5Al)Y(yoN7l z@SkxV+|v^p>y7`+^PmOOnk`61+`e{3#XYt3z=!uSs$H-k@bOHU*33l%2>gq*H&}{n z3w**SrvpK*D*~T#S&Fjmv?&mjN%!A56-x{jA!`G#O`uL^iuO9)(-ZhfufRVzMau{dL(&6#IL#Uw z9Ek`6|0K;G4fGqFhmUrqeQ$Ewmuc*CnYCZl!k)kk*k+#%1##cBgOB&a?8d+sn~{{@ zHrn^q0)*FT-PbYGx^J9m-J?wZw=9lCXNvc4w*3?tB?J3+!aY66o<8s$>rzH=11d@2 zhcnOnOpi1zJSFSY&cT`&bB;Ea>t> zGX3|+^nZHj24;IrD;e?UAbN1coO@Oii5KZR+%4n%6?4?eeu|6Ta+7yki5q^H#V049M`sFa3D z2x4Smozh5WZ;-dCr>vzrikmSULpm{dCX$}g%G^(Z*7M+I^GyyZ>vrNl&D;M%YY#Fc zop&W$>8s;q3(*LZ(p!-^$?2={pOStJYEf$XPRR62e-!^|>3@QT^z>s;r~0Qqf=~m} zPlx-!^h2OOBRv}~gVLLkkiqGj;4&or0mL;loz;9;`gL#_p3aHzA?bWSPB?u7^p8LS z-$pn;S2jK`|Lt9nOx?U6uJKK%5Z=`1QxGbl>sXWe*Z!c8miJLD|2rM}mDra+ zXTOpmaIz0U73tS_1KjNmurJ}gVz~Oei}0Vqiq;7tRsL9vsSoo{D0-&y57M0SOEGg+ z??^`k;k}W{80gN3_fCeU6TB~Ty_w)>X!zViAI9-n#D`%d+SK!$&@Z~7xge0x2>7)d zkZXY$^SOlu?|8WSyxI8obA}{Qa5kPQe-cH+ekU>-fgoH>_`FjfD(TtGFd{C0WZ}&T zyU)88jL*xA9l*b9!45nhgauc2*go&=aPn6Q$xW#EV^E5TzAxD2NblqOigMV>!ka;T zU(*7wEQo#IFt&iP_aQaDZ|{eE#!!-jEsLE(C3=sHJX8$d$yPr&_+N(jAg}LDYZ$86 zU@k>`d##;t9P%Qnw(l+L8PfNoiuv9anIZjAd42C#+!7h`2J6qevd|xLEh>)hJ&W(m z7_xy;zAqaML*l6C1L<3ae2gmZ`_L+&Ogy6ZePr>S8bf^e^L=bBABqZVY)BCFA?dY9h^-f%rbR_zsRCM^R>^IcgG_&$`Qm+7=*NV8@i;y`>uhadqtT4t6Dvib%54OC<~M27sUINT0VDq|eLcp3m#J zaCI6#6ViduudabF-e(#*i}NqO;nbn9Mm-G`Cv^5^IEzIOfJo&Z)Nlpk^WI9Yz4+sq z%Kkfb61-g@YW8{mOd)1SIwr`e@^=WSF_FJWKu8aUtKZSij^F2{RX*=0t`aVAQXgkN zMna`Z>{JZFJb=XZD+-Fq(`ZsuS^|r&W+z8opLZ4HeO@j$ecm-}8D6f7d|rn3dGCU+ ze?1%qd6Ta9d=E~VXVMKGHqXKMu%=16(Q(Hocumqx9!5R5vDqZu>|u!yZfY<|w|K5b zNT}l?z~}X0PUJsRV&TJ*Vm2rKsnieuRM08R&_n6SKRC_=_?_@$>Cc?yGQg=OlFVsv zN|m~B9Td3%OI&HL6Z%R=!)Y|#uJj9(ra`GfiCQV-XpTy4_j&2+^Iq!)FiZ1!xhsm1O8x_I37jU)c&d25 z??l7#z?&nz8n@a5d;^`&yOPqo*!O!IMVh<)12~Lv{wG6R8vPJDz3!R>S;WOg*0{(}c2hDaf?Dvs#XfBq$lM2PP~ z3M3&VDQ%#5rgrm>F{F}(qDp|zdp!RAr{FI>3*yuLM@|`vo_bj#T#sTbCYS^5{-a5I z6Yyqf|LRX55eO!u$Me@e4C@nv>(Mj$8(s#TlF&H01y@X%%=84jR2&yfn4}EQUAQXJ zfUrXox+v3f7U(eC*BgH;6EiviZ}7&%h8ASPz0>$Rc7mRifJ>vsf81N3bA$buqg_l$ zzOnB`J@8k|fd_hZ{7V)d1;Rfcxo+8g9$ApfR~paa2M7~k>dgHCizr?^w7Oh_vKkQ3A=1y2o8Z}^nM zVJLO=a&4w7wK}evVJE}Eo{j$Bf5MlNLS9tBXb)%q#q=vd8}^^Wx?}I7*mG=F!@d4D zdA043uW9REAq$!7Z^?xbpZ5WH#t%iEO7#D8=x`*KJMR8Bm~+mKtN-n%AmR<)$x!cd z4U8G%Ijn8({RLmX_-~E5A0Q7M;(g-w`!>L8Jwfv zV&X<&frqj;W(+<(ZmiG$+gg2hd9UmjQp`SoB`6_`uFy+VGutb z07U$b)X<7f~%3V=`ive z7(NLfUpLkbL8PB)$!as!jm(+*U_n;Bv2Nm`j^<=;fw~K!ZazXuI^s;`?=^}>aa(G| z#&WBfz)ZXiK_>B zCIp_;_~|woZa>5AwW!-fjv$)sUiLf*J9u|XY9<15E1N>YM;s)7PBNLiHD(wDr-^@+ zl`knqz)mE99+m2GsOzy=qwP4D#*a+qjqqo{v-<>`a1T6Y!DGTxAec!LxRhchWhSC# z(#j_ergM*(I7|Jdgg3;L@H+^M=3|yZ?>7?IsV0SRqr(0pHQATM1X^V>Tj75!!i-n{ z_0Yrqm|;rYFsH_ZS#2iV41X4K<~<-7;TjQiB79W?pXmm^EGBS^$^0JvXCTZD_1`4L z-3@I6EGODW-H?~YglspNyg7-ny&R2g!iyegf*X30wgCURGWB`66NsrR{s&w_&rv!7 zNj3g&5n5&?L*bZxK74=nn{X3GSZn`HYzH_dL94Z$+(=#&wD#Wtl2-&r@Z;ImcYgpo z73@f^+N|$5EYyR|;_XG&4-9uY*m11-)_>UDTZfO6{_01X=h<2|PP(g~Xr^at&>9|p0UhBmZ)pT%C3?=c_S0gtyv;~|+3X=}1YWBCGilL&Y6({vlIGTsNWEfit-|e=Mnl6mFyNBtZT2s=XzA! zd&H;O-dgM%Z&i7Yhrm(~8~pna_!2>%)rb*j;+Jsqk9R8cde>5W3H3LqaavyC;kltUuMQ^g%(uYD`1Jwd#8-Xym%p% zn8hr!Xut9E9eUw!5YCzdN{$`)x3<3pvz$6RhjsQ&6x|4^m2+4tcav@J={D9}cJe=h z9XXIA+gxf{|% zW<3>NDn8XnVQ;l7;Qs~uZ;q!k=&Nnw@v4pG)JKzMy6XV;Pxvil7DAKDKqkp4v$JLQ;tkcZ*r$W8-grt*=N^f0^0 zMhcRUjR-UCFielgaR7QH3nK~4~6OLg?aZq$7z7jQ^%v8P)D&aQLU(=g^NY(cMKeu5I9S=hiCRrQ| zo!!tGE8-zB-e$iubu+8kLWbtZ6t%=j*VO(<*MR&<@MaGz-e&4yP&?pIhT#Yj4P&Oh zla9K20XsW(^^T8Nng1VDGJmsN^kU^tWlxmKX`4BeFXn(b>}67Elga0+f&Hx>c1r9$ zQrYi1lkllrzNYM9@;{)D{Lwrl`BOOfEldEXj!lHn%XDUMAwuR*K2PXx^RPiX3S~Z? z&(*5`Oo@w4Sd(}xGz@H@>7{h!A7ZEg_}>LNqn?xKT8oYA&l`P{Kcm}fCEwlk-ISsM;B`G18SzACxbg3ZkF z6O~hUAUz2uG8CIpG?bZnDw5<|E`c0pvC3Gf)|jNUpq(@%Y1zP3D`g;tozW&3oD;MI z7*z%sJ84F6X0Q}R?p60BG^1pQKp%l#cnv23m+tMPS=bkdPqXZ#V2~j#xF>{gCxWA9 zI)Vkks#daz5#cxrhtxN&G>yJV8dlk4Sfr|udHt<%gG$pFDm6|l=!Z6r3p$p>E$Y&7 zVJ>MXN(QyowFx!VvYc=OM<84d;>pmYA|7nC4UEw+IBEellcUyQ1Y!J)eOP}(LohOE zKuI>Pnz-pi51oxHVIEL0)#~S)mvLF41RfC=Ns15fEgNP5Hgw=R9}j&NKzSpWpZO zd;R|SoL4gMvpnZH`*Y5@_nhaJLi!(GX!T5HX6AWffN1^&=U8avI$cdieBvB@R({GQ zjR;tP0L1`IJ1z~DJBTe6%p|HjPUNOqS63bu58{vNVlHbXCwa^XKD?&0EMbc>&f})C zcPthUbe-dLIhIsg$4xa+SUW3pwJh~|8n0z(FI|hq^C;uVh)ckpHBj%RGhRodENXeR z%1%eAW74E~CTWn-kla!ogeb<8rMd~+f%?^}RtNS_8G~UAg5wFib785?gnkS-(jLE` zwiNymKyaBHpTz_-5(uczS}Py4)RxbJiA&o#4s91{P3C&Mnd{1;Jr7)bs&+qdvo6Vr zh^9?5ytubxF!4Y5N0|wHSz)P<5RA%%4gw1TUjh#mFdnyduW9cN0`Id}>Vzu++|Q7L z_($#C!BYVLF;)Vq2NVgdl#W>=wPa0k^L&fR58+{LJ%RAF@g5amDTMgjd(~yn+p7z&>rJq zzBu70Ym zD>Y#U;pf`AiBV04Ho>ON>G)-+Pu1;z82C8;J(+_Gw%QH@S({GNr-mUubYb`9fO5?j;6Dp~9L^jwuHkunm!2Cv*RZazXw%<< z#_mHcz(3p0HM!wzA2ylSP;$|Xm)~z9EuZ28DxdWZCU|UO$sPYz?mZk;(=a+Z81IXu z;Kz-74#sLyBO`--1CcmFB8j0Yd=-9dS5;&kW0Br?)spJ^ zn$ZM46CWQ;)kGtS)8fNbyXu#Pmo2FojQ7@T>+2goVhtn4hx-P{qOteS!suWm)jyIL zLJmy2RrO%mH&BHP)r=(*E|;32NZ$azTK~QU`mo$Q_mxm%lF^!x(b#Y@If$K?T-Rom zCR5R9tiO7IJt~~qJsL~Gjs}1~Zuh{Bj?x=R#$ZE}MUumH#%At8W$eb*J1iIU^0=MH{xCS{(r-R9d+)LPAKJVB;mhrl zD(pEGvzFSst1D;if8^?T?f!==kExt_Y;EPt%Dr~c3OiY`(hhC5cda;f*7Dk!E4MxJ zl`W0+`|V$-r`uNAjVnMl^SHXos>*@NnJbmgZ`nK6T|x|01niQ{#~!=iu6(d|zrFRr zOV`hwRdv!~voGB;2=b3Vy5BB%aJ~;WYtYRln{Qc`?X0j*ub45r(wyKO zYBH=masAB7S>L4fe!K9T^~>yC70veP)!%%xbrU>&ffa#M)^Cj4Cp~B%SzY_(8l8#$ zKvaiIF5rX!cD3-z740k!hEK-EjAoWL{hOZPvem++_AB(wP{PZ zsiA3Yi#KA|qEZ-sf|HrpBCkjzH8!du+wl;N zAHHQx^t7s$O&#G4&6!$4MRce{>{MJL^k#fROZVE1&Es6?BWs1sY#&SVTB6Ijr3pvV znL8;`_v(5njno@5@6tB4cC2mbR85^*I=VL^{cv+bcZ1T6;F4@?T&Hu|vA$(XSbx4& zGUO68_N>+)Y3Adi+%M(gmg8_dIiUJ5ID0XkRclvQ4=NTNp{pBBg)iYMeiS)5Ffuk6 z4JTr$#O^dP8W<->b&{JJ+Im`attSSy*7vG8CVDYD-f zCf&>Ggb!XdCDr!$@J`hKaKE{CndxX+7I~zxk(!y?qk|*E+bVdAGC2^b3lBt4Z?WN> z;h`v5=)T?Aa(uY8ef35aPbSA=iKOc2+_)Kiy`>W)2>u*OE$v;c8{5NpBaFO{_PJM2 zy&oP1Tiu)am1vYTjBbr9sR}YUJj$U#!5$upr3OZH(k8KRUo4TrRn$~$8!BH*XXGoq z6Vs<+NpyG^CpVefk-ikZxGW*?`aSjG1DTA8#lJKG_*saY#WY6D=_URl-t7WZWy>pmHsNX zuG*%~HdD1D!-Kn%BSSIFGD!-tUaT8pk>Sks-*LYDE$!jviC>%6H-FKIASfckBg0`{ z`ikw+i-c&`SZ@lVC#hv#EM6R@;5n4JMx?4noZEWgp=?+Uy+~(w=dfFpV#7rbcq$4Cp z5-GH#S$e46-6_-st_+6z2P4~(N>`mSV%lWcjAYYObYr@AvLpCPx*nex{w6p&w4=@p z7CkB&dNym>5blkSC=_VB7B~1-d6@UFg|M^DB-7K~)ZMzF1=qC`5GyHk^TzgYQ}<>x zFDeYn%06XsIF`aaZ;E^LM;@jejU|TSDHJK)vblng6|QT)1M^CELt`7JK|RCt4vk6+ z0Qlv0uCKy4GVhAHh8~Fj&erZNVF=(>ce-frZdudPX^NbdS($;OyL4yErj6^-JZ@tc zDX%!N(Y`y-Ir~S{@JOmLhD9j~!vz=e8P<^-x{<%ep6(Xa(!Qp(y(J?ZP!d--utSVy zxptUR%D`bf0F}fq-;DbcM?-VCAI*R_93`gVJ zV#tQB9`7oHc^ix*-T4PM?|1Ds_wli4h;d5Nl6}k_ofHag8a-W@exsOAMn~vvk_hqYjfglL>wU+H*6c{}{v@@)bn~PQ-CM zf&!w+j8v{o)^2EM(kmD)tWt@{aFV;0aprC&?aFBO_%1DR!->dgW=cRX2PQL$X*Grd zvIj`P%%r<`5oTRI;h15sYnQyR3XDgRrs~o&Bf1JUc)GW^MaFUmh3*>}!_1UWkW!Fq zeZ9|>$RCS zSPRTFzjV`tTiUxjx3Gr{ry{+B7!;hSG7}xkkJ$%2(HA#tZ12`W)XgqOA}3$ene@MQ zv!F}Hc8sCzWDeJIBN{Uc72S(a&pYGEcqTy%?Jy+EBEH;a@hH&3eZA??u(7GDLq&Ua zu@#puM&ykR$9H1d#ahke+s#;q3VJ~jmKz4#CKjRzuI7f5 zdJT5)MIQ$m3N_4m#FK7&%Lz*M`)(I7OEET4bX2E<8j1Js)| zdO#qO9X70SW zMf42*tRWC(j~m%-_HUw7g^h?63HMfA3LS78COO?EmB&Et!qWqwrx@PZ%kHH^ z5J7nM6sCY$7?}-^RIw8JP&5i)4s1PliZqdBOS)Zk9jCV)S`eCrIHa;G z>2)oeu_g`9tvjazy#t5fG)?6$O4wd{11;_74$wxd=*RkuTAOq;LRM4iyNe*k<>+RM zLdcAcK%`@>omRo4m$49T$N@=5QUe%Urt@byt1eVS+nSA?@3X@~Y%F&hn%1kFB^vo+ zwC<99xn{*5GmW3QSO1Y$X+@N#6Vyrb^2Jx2|Q?$BE6Y+N5qWE%p1;j5)3k zUP+kdQkpH-(*vd>86m*^NW2#hP_V;-=tl1G3?PxJ;3^1nXdHPp4|GI!c0zVWha$Vu z33qk1rR^0N z#00plpw~Z<)EJi2dK859RswrXJjuWek(uT7q|8$5jf>v)V71UUy4#2$K7nDVma|4C z(TRx$Q=RS)cod+wOhzszl}EmEr>mD$nvfe?S#fE%ez-HfT_wW~F= zJHnDN5l0u1y(;E}sNQ(V!#H_5W9kugof=>*Yd(z|Iz&{t<;<+9NuP-A9NCT)u;Gk# zZhF&~R4q;1YngiHdJg1zlj-h%x$a2qN-e?!$boM5gzn5rqG1(}ES18mHBC*+E9PTH zIf4@k&qd?tAPiovpHUnt!foJ;;hT`g;yHVrbA#vQpC8zlcY*&C_9uN8S@SX{9ucy|8Yz`1$n`Omlafum|zgn$TNeJG20$UCa4K?Mr( z8-kYOEAUVBms^vp$@Ua$sx{4bsC}3puXU=EyN56>0aFQs1FnsF%v80mr|RBhQdMIa zQ%%q6167e#H*{{OMo^^ppcIU4sN&IG?@OiANQjcQT+V6#arkA0X)d_ipjEx)a!LD- z!zB|o!opXN^LVJbZqd@EwWtw8ff}o;u1h-)5@FF&Q-zu-(@l(2WA@}zR$aAGys6q| z7PQsI9_ht)VW&5gPjEcMc&ssuEv(n;Kp!qO(2klra;mDiROHsJ8e=wAjed;v0Uzah z80$5J(zWK1>*!Ot#`9tj?`d9n&l_&@4V1^&@?O*RviT;;V{CBXJKT)%^TvVZ!g1t7 z_)NHY-oY5Zn&nzGmaBO{C+%0RuLR8Yxa(kF>~ZtmHs81!Q?8DIh5yEst5vWxiHq+= zTVP-3anruh|A0JqoJDxk}g@x!?>kFiyLPB>1Hd5n#cX4jXaPDD6s zowCG-aMstO>1N2(4B6NUN1r^#h9o0>#!#|ljEygsWT#iGdJ#?pt>3YG-8kOp zF?RZk9>&wo;clx+4>kE`dO8DaHCM;T)C!L;WQ?8GifR1ptl5b1=j)RfZVd9d%XI+h z{!@v z*N}cwj(b~<`^+5o1v&076sG5$13Un5)8cPE=L5HDM-g zYr_25*0hK}OZc;xKbSGwnwIhBDE`#*=V<=a)hc(gPfyqI)jaAnlRC|yPV=hMeCn2| zgUrmB$`2BPIU7?ZpT2M#m3ijpT`)2v=XHpzP`N$9a&s((SzX>19Pqps?Df+fpy$mU zHUau=jcg(GhL_vx^m`7yB+g=%rqNFrNu2c#HfwW^#JH{whxKYPY#vX9`|$2%G+|!0 zU~}btH7XDHwwvO(I}PvlONyNJ4$%8J@BN=~nd0czyJmN(Ic@$v5cB{BU@R+oF+ zlGJ*)x9OM2?sGp@h<-be4w2oFtjP|ZVLUa~lDptIe7ha}zF?Ko-`OZ=z!g_M?WL4P+9^!E}$|3@MO?tc?O|0ogkj}t-vG!gXA z5kda~5p*vTLH8OFbZ-(t_bw51Di4Tdi=T)^N05kkAtK_H5D~AOh z?S*JpBFe>+$SfDfCCkO5)GXJ_M9{rP1l^lN(7j6po$>)e=O@BHNQ8e#{7Z<4Urt2) zDdL_k?h0}9R42pd1Gjzzd|?($F~|>e>UzWiyaHYYry$gzRoEng-2 z9o^G#i-fquJVW8PK)FIEa%D}NN<2#Gm97tqj4JV8F4!Ol5vl3X^cvAr8Y6=Jf=R*C z1c#Pm$!5+b0!BN4F z3hop9jNn%Uzb*J9!Mg1G@KLp-Ny-T5Zo*n6HEx6 zC3vCW=LNqe$ZzG5-|qw;5`0xq`Av9{;55N`f(?T0f*%na5F8UcNAS~voUfSf*9E^T zc)Q>|f)5EkBlwCSzp=*n4rD2Dk|6FEX?K<2a={kClLg~~V}fT3UL^Q=LH&(-@V{By zKNh@8@Ik>R1YZ<TyO2O5FTLp&&cMF~;c$whUg5MPUf#9zM^*7#; z&J*H(N$?%Pa?AzHN2Or3;4y-01$zX01xExg5d5m(O@cob{H>t=wmQ;zS=|2-bRZa+ zev4pO@KnJO!P5oL6TDRLOM>4J{GK3n3zF~e1RoastDyb{Il})V?gFgMbUg@G32qSF zA{Z0gA^0)Ds|5A8z`^&s;=Wz*9zp%>Z-hT5?pFo*V2SA$2~HE7CrA}-3~vx@7yO7I z^&~RvOxJ@u2NR7XYcaGrs zf|m+@PVg&&)EG?q9|_(i_@Lm^g8vYFSJ1(lf$RnT0!cqr2D6WcMCow_)o$21e>t7A$^D7$%3Z}o+h|g@Djl<34TNHHo-dt?-P7X z@CCuQ1@o{MV7jG(GX#$iTq?LhFeW%Ec!uCU!OI1&7Q9iAst}pZF9q)vd{po`!Pf-w zJupol5}YGgE4V_iM{uiPOmI~248eVZmkVAkc%$HLg1;2JSMX86=LBC9P(lV|s@OP8XadIA4%jP)WB$aJk?rL4M7F z;cbHaf(PB31y2!-3Q~h6!$$>o3Z5Z&j^I8)YJVmD<$_-jyjt*Uf;S5ClMkf7P4Fjz zzZCq9;Jtzm3ce)xmS8FNdgMc`oy0kUHG<0psf(B4e-Zq<;2VOzauc2}SS5J0V2j}K zf+q{c1;+%>7W|ap=LN47yjk$af_Di%Aozsfi-LJr;4|N)f_nuo5&V+ije@@sd{FR7 z!LzZ!A)l`Zet)WQ-ywLf;Io2n3Od+(Fy1u5qXbVBj0s*S_*KE53O*qCir}GmbWeV( z1dkWoBY2_U6@uRu{Gs5y=_dXX!KmN`g5ME*Qt(y5_XG=PnD~L1HfA~-{^TJUJW)q-7u5y2tB(*@5L{G#A>f;SVfHvA27sZzfe|A)l= z7jZu)?ia=VFLA#s?f~|hj9*AZz9$iDu;|6C&Wk<}7jPXzr+akoi$kGR7U9wj3F znSx&uyiV|kg1;AhN>Ejp^eTu*r%G@U5&TvQ#sr52PZPXE@D{;41s@iCL-0MpnU#ib zz2NbJI|M%=c$wgpg4YV(A^4==8-j<-GJF>Zt`qDM+$MOw;Fkq&7kof)#%%CGyUZiv z`NT4DuOgy;HVSr&|0&`g5=@ByS%RMu{G#A3MDY2U;JtzmNcdyKg-ZRMi1hy@_%0Fs zqGXPVKZywUVMOHj2=T8L_tD}$mIywbf=R(M1V1bIUxL3Cd{XdT!5MQ6pXGuZ1^WaC z1;+%>6g*$>V!_V~{(*>mKSD%bd|uqI5m7&UW<#W|4B})W=qts2I1%wy3G&7>-6sp4 zCipqQZwTHY_#_ehUJ`tp7{PO{dB%UP;CjKB;5mYq34TlPcEQI5dANrBCkh@WxKglF za8U3(!7mGbNAP!ouL=f_FnnhUE*0z%j0h$L&lUW#;Ex6WTkxNP3Wnp|FNkHkc4OJ4 z5!04NOd}f6MK#t6qAP0mF@lYPs|7m*y9GZY7#7?iI3{?8;2y#A1wScxmEe~JuNS;g z@H>M4C3u(MJ%SGiJ|y^@;0uDU3BD=#o}g`+aux^{3qpCAF8@@)3c)#o3k7Qh`M#L- zeT-nEAm0c%7gR|Ij0LA(8eWrC9h4-=dvc!Xe;;1a=lLH(Q&{P{UMrn644U9d-R ziy$>CkZw>gDR`RTnS$pCQpFzWKO=aR;Fkrd$Bpv%R>2<%{#1~P-5CCW;G=?%3qC9O zcR^}?BfSLyMGOjt1j_^`3-VjZq?;vpgkY8662W@Gb%OeNDB|^qdyC*!!KmPN!4bg# z<-=lgR)qZ;Rio>tf(U*z^ar`dpkPQ4+fD6{ZHLAR!8w8u|JvV`yY=E;A-GDgSy0Pc zWJ1eZ;AZ**PZHcJ7!@29ObPB1)N&Z{_K170;Kf9g=W@X-#Q#dctBEN0HG(IwpM(BC z(%(NJ?WxO)LLdnpzKRHUGZCHx;vOVQJ;M5d2HO<{QKQ%{G)oMme~}GsD)CD?WJjA^ zI)>3;TG#J}K8UUpbh+t{qTH_Wi-qmz;D434|9h)>cf9~^((s>sWG(*5&&}^O;Ke@U z8kgTNJU};kjs)BUI>vXyT|57mb@P ziM;8)=_v;uv82M`{fcWxw>|it(B(}Amm`wHN*3dWou9+60{k9F z21!a;;qv=j4!^4)gUj8_g3jf~b&YFhQa3NdGk7=i9y+dryyZ~4F-G%Dx|Atyx?CT5 z`7JueyelSe8aIsR?!5d~ovBm>!dVVH!btP`E$G}h@K(LxcM~mQ+%T@cy!^I;A0v_< z#iN@)uEX3oWHAvk_2zNvh3mE~erILct5%E7#{UJl2Kfx6Ob;1&5`g&73p+KfXthhpE?C+ zQauq}e&$eDq`I$qq^1I*q7c$25Wxurw1-1C`Q+Kj(Be~zY_vi0MU$U)0E7;ps za5f^?zPwjKXZ!LmXILg`VC>7+A)!DMLxR3<14;t7F~rd! z=YhU;l5oK`n8(t?^UeG>*dO|B+t)$GP=25uRj#axP+or)c+^$WL=t2%5-$ zW7$H={{rjl3(SuHEn2@wYk~h7{1&n<3jE9U?|0!5D)5s-fuE;Z3XMPWgLiz0KG~vh z%}b%I<-Q9no_q@E?bj!)lSxpVifmI*xW$D10ev9mLLCweJO?k_lwwtc0(JQHU2Jhj zTY@jmf}MYwwFIsS=OKed+gbE8EpCJhFtCL@EM#g0 z{*$x^W9B^xw!yqk>pD0BH-cqex24Z$2Y6y5ugBs6ZCrEV`JlW_)>(}6dyob5Hd~J{ z&KV3i5emVPc;E*7s`&Zyr&dl&ciJHXvwrXLM#NP2H zb}hU$_ZKvG$!f`O;BD2P0_HR(lXNkY_1tjY32$8+^{kC&>C&~q#Wp^K`C)3~36!d*C@+~m1^rF!uHUXti zC$`eD@u!GJ7-Q?}aqot<&n8_@tg^$sWUPvZW_&rN&(dum9sbR$R|HH?AJ@vbY z?k}~q{ok}7q3zQO8M9h9>glXB3I8gR@xQE@uzbdMMjfd9uh@oKGx{JE*BPzWey_Icylk!1 zfsEc~YNgIkhiXmFK~WJ6jm8XhGK!z+EO6Ci7aBF$Aubk*y!xhdm0Y`ev`f<3i4Rm8 zU7D>ndZJO`{F%n7ROnph(eqqx^gK(*BrnS>J=Ejq#Lg&c<^zMNxr&^pWx|aj=R?!X zMVm6UF;6$Dxo3F8s0Laa?p2}6mB1c+px#zPaJ-iwTUo0i==2g~D_}JQ|L>FdKn@>B z@c-jdaF4)Y$0l$M8-(V6iYE5|JiePQ`MigJA9su&LS-y8qMEzpHLx8-H!8LPTtM;T&`9-? zET2|SmC;c(zP?HCPRCqPO2;^O<>}i>BmMpS6m5BH)q;| z-)cN)W0J2Xb+4&uhqv!%b!v9jjKnh%OZ1OY$h}W8P+yahq>TO+T^k3M)|ENT*umLR zPgSObbfvU5ETi?w#B()hnUu5q7$M8Utp&M~Cl3zB^g#bW{Ttq?gZBTg-T$BI;W$8I zx~@0 z{trq$PCiU?zi*5W$jAG1gz?yB+B>IbA3P_SC|-3hP~Q?6tUh=wO7mQuGEfxbWs%j_ zpH{Rr88UhdsCVYn9lqETo9Qpjaq|>q#@JbJ+DXq>3>jnV+tFV4u^9(!wpx|rZq)g4 z-&J`vMv>4~O*!-pIqnv`F=RcOwdzEl-=i}MPnO{y^TeS04E$&49rdZ4@GoYC7wdB; zE(zoRAS=8~-R%Yf8U9FC_!RY4mV1VpjKnkP&r(aX-1Ag717W7)zZ3_rcVxNi)Y;-D z4b!_g$ITaNu3@<7k>REWie#WR=HQd4%w6M6l$n*(xLfRlXc5V*dk%<&pzMvyfg7Q$ zeCTCCW}~E?nM{o{6GLCIy96IE^x(CS*;0)Y&pfU;cw{UVva$`g*@vc|kQ}frCZk$d^depeCEb?(|5(0g!>>qI73l?0cU0+`?T*PN>zxP65n@{sSloS zAD14lH?!zZ#4AC@YY@H=BCHx8aFQS&wfmaQt3F=~KHVt(IHsfNRtkbdyVnb{sN}On zaI4@p!C}EM!P5oL6}(h%zu=96-xs`7@P5I^1z!?;OK=|K0Q0d}kov#qZWG)rsLyS~ zU!T_o^0g`HE)cw2P@k`c|HI;bR?x!ZUD6i|9x8Z*;8H<-P8xK3#QiBjeXbe)*NgjB z!P^CYC-|h`OM=w9!}FUH@WRX2h_g$A3kBc^o!-;eX2)>}lx|BtvUP-ccNBp!`(>f&xBVm!5poBC!*NBuHH zo(UzMLB#mbdJN$H6y4~|mrD453I0h?>nQ*o4eJ}(&`43F+effcaIWA&!CFBSLDQ2J z<5A=hj~DDCf~g)yKs}Ct3Gv@6xKHrYf|m(iOGNwKAb6ADt%7$F(SCgQP5gu41A@;A z{$22&f^P`&tvBO^1j__D-_xJ(u-UFvf=dK>HkJN-sZDGb)Mr}Y*7q!cd@arP=D9}V zPQlX!1I))Nk&mc1EeBCQ6$<|7&s;CE{JOr8ABa+&-YO#c*IFX@(s#J!7nggKzW`1|OV`h)cY4R=y#Iu#H~=F4k*;;00Y&K7qr9m8n2Qwie#gXoS2 zO>VkuTi5u-!uE3Tze?OIW}3EN12<{-&-CafKR3UtVD}m~e}nLZJ$?Ro72J&Prsv`S z{JiP%ekuDL)5#Zl#=8ao-g2ykd%SXReedOWl7}Dt-Ev$n{M>S|A9#&hj(gzgEeGkC zAM&Dc%W)U%-gE~&=`x>gx|9>%a$qSlZaFx=d-2i>c`5`YFw;T@WyydvtlP+b7TYp1_U%DJuAZ)yH9FxQEQ4c?e zzcjx-;Rn#>8bKG_a!`Mjw;ZHnImnB~EypD}>Av7ew?gO`?{!Jn?N>L#Z@hB+B8T6* z9)7bt{QfTd0NUIp=z?1gt|z_aARY5VUNmkwrh?Af9-)eiyqYU?jK}+G&!M<9{nHVi?AMuB*N2cEB;;B?7wX zPKCwW9&Hs$;ZM&WoSsR?bQ^Q{?E=5?%5iKCzrl)3IqE$8;yL`dZyGOuu^fJ9fFJ&J z{uX=qaX$bSX~Sc@>COYI8}_*zepgoD96IWr^ChGEEe%MX+3=UpZqe%yC>yj2e> z^Foh@Yo(qwZ#};-TWMX8Ot;>X?yqzBJyBrp{((drm)|dQ`0@V!T2PSRa{MD$w;PXg zx^dv8j>ejfbgps3{*=S-R`A;cBJx{-f0y5jIsDEBKi;W!jcff|4!Re9*m=Maz~gU4&aHALd@lyJ4Mt z`d-QsJXb&JyS^KPYl~Jlzv-`7TN@vkwc6ONE9{$Usm3QQ*Kf$bd5`rW z@2OP%?d6T<-ZXhN?!LU|U%mF`$KJgAVs$uvuU4=43*TyfyLrar$=S8*)Me!rHR~HH zPjA-uWZv8Gc-`uH9jkTqy>I&W#}bQ_%1tS{el6LYSH6;10VnX z?1AL>&z(I{$1PnymX2Ft(ydUBSFFyv>BrB#{Au;mpP*iThW}gf&%Im}|NZzsN&dNx z=D6foqPgkY{yjT+;!Qqcy|Eo1v1!0F(k?ukG9>zUz1Zo;zQKMJ5kI=!G3EBXAp9=E ze!D0+mzc24RNEN>?e<4=a_FfECd!ddP%=AAE*E~~st9>Z_227IOmY~NZmurmif0l$yr%2|eN1oC|6!tQroLoNaV z-^Z}L4?24$z>%**Le7GGID)>%D07{kBF_Owhm<=f!z)neV{e_J?3a+iyi2=~Oab-q zP07FGYp@sMT2TJ4NTLdHEy!5?g}fG&Z>|M}UIul(xfT=(KqTb<<{ea7NoaEbcDWX0 zA42Yz-%Rdfu$JUM{u1mauDKx;`XfB@pJMs_hR@S_9cuXejl~S%Mi5x%eTIDOVbo0C zXSMZglrisf+PV~F&$~if-(!V-UR(L3H17-AdM2ZNQClxZ4)d#Ew-hShY^z*LPR$ej8`?9uPiHziZMO(X=v#)CFZ%A&q!&{FrtGos-D9-+BtnLXIE3Jh)AVlsJc@?7;!;C|5Ssf8<@?0?xrb z$Z;^Z#u{QWRHqtTYv~*R&bP>{RXhC3KAW}hZ9Z2nT8+%u*PwWL-`PhNzhL3=E#FOK z(F(eJ+xG`u(v{$s@At*fH^G8R9`bJGm9*gPD8hW_vsN9voCnZw&K0@}lyeqBoX=ZN zOkw4)rkpQWPfbG<=Oakg`J#0@93h9-shlgdqr~|W8o;^A>c`Ho9Mu8Gm#hFBQ;PW& zZfC!>5}k88YL~6^-4!g?ztDBtoUd41cogG9Xv(?P8syH>WZ-L(fh8!KbDgfxpfiX# z&h^&W@C!NY{&-?xqBv%kY{Bq~A2<)MLR?TPbL!GJ66jtD8=fdg_@otTC#ecJ6L)WmDui}sk zg?iENoiCB5MA=ucjej@@(t@ur)H(es*h8OY!e_9BROmJ&>wJtI&L65|+%tbgp2~KR z@4O#f&$ySOeWyFOzXE%qZjfKFJyb}y`!Ct^Lm@vTl5+DTO>ZZd7 z0XVpS+KjjbZ=-&KPAX15wdAvt{Y!<8W4)b5J38(fgy#J$h2Nq$0_~Ssw%hl@9lQ}O zUtTcN{sSDvQB_c3KZcmNWH>Ua3TD}JVfQ=NqYwqNwIf(O9NVS}=4glMMFn%U1NFU| zZTRy?$(JWK<`N6^6wr)fup!&g~_huUKZ znWHA)a~LY`7pEaN!LyKoC54CC)$C69!KZMh{ZUXUhqt^7EA3n1@H_uT3l+|?Z$UuN zX=T<-IYUkbi?hHKT92c`BekR4X=Mf$YR8mfelNJNMmwhKu~%4YvjHoLNAa1m!aAEh ze~vR1)m6B}{uUCQ?@;e=;ZkbG$IzjYRB_ZQ`+j6M@0Um8H~0|hIan~@i@;ILFJczN zePm`zP;jd6A(lYdW9%n)3^K}#;MGkeAV1c%l7q`b%!I9cN zzj(M-6;#>JfX@nD!~#>0=Hdj1YIUJ7XdgoD<=uG?covNy=k|Vf@ZbI!?t=SJm!VK+ zF|r!E4IZH`)+D@8`=M^y{h>S2lA#{jG2s4$fV{h>g1!K^s#HbMA5Lf7ub{6M-M60) z|3a_9zvuy$G#Fxw6g~71{6nG1NUP}4=V31ivHKQ1R*roO1|KMko+8bZ(Cf7S^;q~% zR}-4os=Rx+GAbBB6|E@x+j?*dQ92bp-wYB}II4kNO1_E3l~ zii-Y0dr9c4sN14fk3zKa(Ba@$^!iTJ!<5iH=s`tqbbw|`;SN>w7OAHfo~nx8rmZ5x zi?BuSP;Si$^`kM0-kl5k{Lmkev7&#IW}#j}6un3PTHS|=l$PI1oc%1bWvxO=^~ydK zS;+g{CX^!hC@On?@iEpza5${J;uV&zK8Mv;e5@9@rbidAvOb4YLJljixIsHgoR6Yt z#ZA_a5K`_eqNByKAS|aiJ`|{Ut;G*8Om|q(#cfs}92L$!BvyR9W`Mzl51OjH-#^XV z{0zBSQQU3)0QI6L%HkgDT$DyR$0Fy&oAhMjFCJCJCs-_Tuy}_m-mI;m;%%yUi?)_H zto!1RXh*rj$}c`iJEl1IFz=^m$MoWaDh_LFh3>V*5zT*&!)7V&v)C^49kxqx)MCTT z*Ogiv)0MhVS88#;uGCsRSru=y;waz}rwdswj$0#ept@g0+4JtbgKa$-KQ?dZ<=y`P z-H)Nv_6B4y?}2CNeh=BR`M5goq1WkdK#SNjL6rAsUI^vgf~X}E_WRbrp))h#Y9FP9 zk(v{(@v-gw4(Fx`H~KC_`a!1;LuJBEz6asJ!g4J$^Gqk1tpwk;l1Hs|oax#2C4cs` zeaT~ko2{f+mwJWnRwX6A7KE&F&PNGLCi;fqXm*yNUzJSu?So^jnt+e8s=UAUAi3Zs z{Ir$K^qq_ym2Se43g3QEsp4T(GRwz4<}Z$^lG)lC#GF?$M_WVage7yewFI58Z4#; z?mRagDTW?J4xHyp5mkkH(UqLP)9w#lgKBeLn5&cGzQTEt+lo-=T|{zTn#`n>{W^&9 z{y7g`1$UtMOPu?u^4l!A9^jHog}#BV<~&Hd-z=5>#AQ=3q!-=)&81im}O5^e->Ohl!Q*2$yJ6LNOHGd6dhn>7g%h;QX2P3KSOhzi=Hs$1M9ESRQfi$Tyg35VV_X?P5hRW@+(=TrF|&l#8PVgFDspgxaFnyp`epWOF?r;=@R%) zE~U=QDWxMwcWUV`&|cF@KLMXZODDrVoeI0vj8fjkKdjV2>1UQ+1U?m|PoZa2D!T;i zN>BbN*aiG|;CCY1?jcyp(mx2{Ba49l8T^(PoPZeRr4ed2FXWQ2v~MAzKtTtZtTak* zj6PIF={EWYLoudsD(#^V)l`)Zvi?fI??U+5Gm!7nAvThI2SO+ASq}~cXQE&DC*H%y zx`oN@YU1w(U_(W5R~+!ud(t!XC|hkmi{g~69)_3w?GUWd>)>w(VJ&>-bMOuLufp%d zbK!djEM@wKr7Zgif3%H(W&8m(SNOUXxQI8@X+i}5mdqH5%X$-h3uDs@!Oy$FTQ&ex#`hKaPeKH zf5_}01?A=;;6D$fI?4MPN0aLxIuXqEdB9J#^#MOC_7MKO4(H^HV6os!`5f?DX#M;S zZRInkf*+w-L;0^z!f0WW|0?NJAr*GyzjiLHe!c(Af1RmexqLWElmA8t^i%RNsPZRU z-LMDG0H5-}1=d&L(34Hz6MDoOwK0KD>cyAexgTRGaG?$fI!B=G0~c9rwUF}!yY9u- zX%NpPYDyfg{At#=!L4X5qt)Iao|Br|;)t~>E^;-;@Y24K0KW?#c4;^HV zp0Mts{ZI_d{3kWdp`S$+=09ce;mV;gbj|#y^&^8r`I(mdXRJTdpPv%Q|EqpvaVU@d zvh@}Fe}en@6f&?5B9%X7BYY64QSl_7p#2RyHLXX z7cJ|YYdE_&& z`eh`5qU?VBfC=|(cr*;hbneGo@5f-*qox?k8|~>CI`l&%?#BcEmtD%mY0A%&5uFG= z8j#POYrsDZ)_|WI%z)qca6eq|DU5(%@%g7A6q=Wc_i@Dsp(r-&ihqv|R(!!Gc4R=1O z3HX_-fdA+C)l9ghD%-)7(y_{P>SPSUe1vPllS!zvd=#^kq1KUgs8lECdGtKc2mIXL z2K>L_p!ahp7VtB6z<)kM^B;!CRR4sp`R;{F590~f`8bTHC6W;};dd*Ei};2=;J-&x@F7#tTFrycrvrXI$}L*1 z=g)s=3OP$@p+T;OEPXqQ7ZIyR`QO_|50mBH-t+~ej0?fp{ud$#TfeJ)`AL)McjBjvLCU_GG1mP-hy4k^6Y2f38(zj`o>?l{%PCOT zzoRLw>C$SGV9}h)xJpp=iTDX_sDN+4el7koWA&%_e$?OO!bPDH=Q)u@W;_gatD`)s%h#xu&_Fj%Wg+l*EqXhfD z4tq%hIo_9W(^qrrW8VUjfQQ(&)v|4wM%V`1hL;)SpZ4lxJw z;h#{!(S5KlEW{_RRdC0D!Co8sJZm(`fQv zTEWg{O}~!xlvd0~rh1fp8T^7>aZNNrA|}R+c$jj@qwG3T_FSeZKTk^560@0Mmsv(C z`}630!4t^1;C3`wNpRLyx1&1$VE7Js7%~DV=@_ z>>-nBlAGpa5z6?3Iv_vY^P(<_QMd ztXdofbe@2e2yT#b^20J0Sl-06E`yd z1BB-9(dA%%=Us>9wN4@v8dMZA@*G_AQSoXy;~()d%4eMfn*>jPziX)*wUfgtPK5__2mq!e?PKB^+Vq zc!2px9Ai+{=(Ql`j{nHGvUV&489&atkoqQnh>$$A3+_L}5(#B};%->0S*AO{Vop6Q z+mOq9E11*ceZdCg*J_^Y`9 z?(Rm&oPJndgr!oGm}qDL9qky2cDfsF&cz5}Rz4yj!H;^fa+aF&ErjzPz_8(FEmLz? z7Dlc)r*5v{cP8 z==|0RPr%1iV*bxyt^G6PLVl^uHFn*7>~Sa3YAEUoEO@lBPZ^Iz<*4o8F8zFP2{LQ8 zqI||xMklhvwp}z0Lo5Gfn|lv-o3efEyNl04PV--}S;#U5iTCLkM3b5e4yEonjfmp*zStk;oH|14xk!2eBn z8N^OjMjPTY`%A9DASnGKIkH_ef3@^V)W@V&tBhG#hMFj~<`$O~+Qo+!_e?IeO0Wp> zi3&p$&GxD=^k-BX=1~P9(s4Br<{M3f!L%B~JPX3Y)mxZn)EE||L$#8_!fYjnp=>3G zMXt`mTwR99QE++TF;I<&dBATK7Q&%ZE5&2N;^}CmiIc2(Q(McJgEFHlu>5cob`m*i za^!p*<%C`Zic=?h7^CHNk|+lDsgh0Yn9h`#&WuTlNkWuML|wv}nIb`aR$F#4Gfu)R zMTwQryr@H3%Xp7xR<*%_sX44q^2GS=zh&Go2dJlqX{fK01KJTS5OS=t+q@KR=F zYJp)VS{{!?CZyJxiG|ElYuS>iRO47xAYr8#Sk;C-bw<{BG7hp@aiZdmn@W9+b(wIZ z?Qu~$GahY^i@lyJbY(9|d+FjC&!uTkL?-)XNYfY$AO)R}1WsB9>V$;c2f^`#`P$k; zaA~vELqa}*wv&J%rhF=)kr8~j0_8^ZsgDi9D{U}CG7p3h{twIp`XmVmoOupLaJ-iw zJ7cGWKnFI!SG81Jpw*4HC%1!@fJA4v=$ z2PWOBda&#ps6vKn#*zt_OU+QEZy-J#`@h4@b8_>bdM(W{PE=|#6^+LFjpoWQb*3d@ z$Fc?fP;du3T3Iw+Vt#SeV2TyNu%(q>irx734hzOdjHPd6nCXBhIv|*g7)xyDsIlN7 ziLoS8k-qH`xGSuc8tJI1fkZ44m4M-Gs57xA5^lr<4zI$ld#7mPd_q|jvkp7<#JDdX z{mIqO`3US;3OWz)cu`p^=5*MnSKCfS&4StXuIiiCA5*!$&OUve^5M{EMPU1u6-?wv0bUyaFU%;^c+Alo@(jr47as5hMQa0v~+cgCQ9nU45!p)=nvhr z7)k`Y!>x-twI)2HsB&=INFtsZ7*a7^*lfa0suvn6$A-dOxNeIL#}ZIb8RqLa@=Kp1 zZfIKD;*Hp~sMQdRj`f0=+WM$mA}l9$O_qDwTQ{}fRd5^5Ah))!QDdq8`ecfAtMmch zq%x{g!$V_GphX^iBSWLG>-77_1_!k&L!MdJr;NjBe#FOcOhK{cz*s6ea@w#OO~iNV z2voI+45Y?JRb)F(mAaMH)2doFb%ZxGXDU*wT1>=FjrC>K+lH3zwHuqY&Q664Z68ZU zw#CwXTAFZ7g*lYcb+4|Mf=Lyk0B)L1tsQGyI#pBWmX7X?NG;sl(A{A4n7Sm;HK_B| zvA$(XSgW#-OtM2M|5?gwQ$lq z9fl^w%VNzrtwR#8kHcu~-dMskA1jy@KaB3yGm0@1GZCa<;qVwLyB@u(7qSndd0R3J z8JLW*dN`uSIfAXVuIW^}m(>ZM?eXEAsJh|)ux|KFcQL&ot;jSv5UC3fL{Pxk@Xqj1 zl!Uq;cD5WJZf#$^QN@$Vu~;I>^hf(fBdGztknt)4K}_AN6a+$elzmg{Jspar21YbL z!y()kOQaME7u$xq(4qo~g?B=*Yhk3r!+3YfER6J}Vkua3*M-bAMMqZ{8W~PEIrEue zw5FxKrL&3WxqysrjetKt;36&(hY6R}+~qFc}aXteGYkrY{KP~FV&XbbI;C}JiOBhnd?BZ(ARxOX?z z`{KlI*yw!Kb%pPku$B+Jtw1F6)w4J~RklEA=Dp=UR?hnu=LqZQG8vBv3BCSPNzzEpfDrn@Ca z&}b|%6i=Z9=?2V|JRAqQk~<*FyBiwYFac?)-a9lZ6%FWvbmUYY_6VAW9!S;BR&*;! zy4L25D9MZ#U5d_@O&iyv?%kR;!c(!Od07O4r+;LeN>oPC^6*HiF@}W_%EWme*$r#1 z4c*9QV^4RBYH457+TN0p3n-9uBi#)~vs^n&VPzP%p4if?E7mA{PG_-wBN(Cu_58Do z6DG@@ku}B(8E5TDmxWjlZ@^qW{{0uX@ExE?7ev>)=%z)FjYDfSx*BH6WI87->!!sj zIW{_qo|p_rVyBZHBoEA0Cq0w7QhqKsE7gVsu;+-&u9VOEPm#Egzm z0GL!cL9t9`^2D5qRg1#=DW>H{6WK;egU>1;rSVkUEf0 zeZ9<5X4VdChMIK~COQ@0fsw>1H-Y-(_%@vZ<15Vmo?bbCM&G>3zA%L~u>0X}QK9F#pfut)2s~8p2Rm*ss+ht5){0^tWqhT!( z)BMuy6mDtn?%cxOGMtL^4q{yBi99`fQ2=5}0Z;VM4IA6Lwa9cwO=j`sRu20gha~Ed ziz(@$?Pgg8b#P;7UYVq|(1^y&ibV9V>yC!X-x*KFGr1WjIX&`N50rf2zFv2@aq7uT z!X6d&ZVhj2>grI@UR{5R3mqdn$A;rOv382M6QfJsvA(J6sPssstDeIHJ!6|18XHW- z!>Br}6QwKkViAyZ^TO>$GiFs8$B9_K?&q=}(c)0&9+eAav6z8&#`L0|!x`(y1Q&9{ zNxc|jd&xZA-g1H(8O8o5nUX6|*k zDf38%tRWF)4;=foHsew-Y2K0TTX^-2^X49SpeBsGAM0b+FNOc&JYH?*zU*r~!@-3?9a zRnE#vr!fBIUyQO{vYkyA0|}YE5PPzl|E7%_I!yMwn)q2oU9D@FfR5hL(}=a4v6~#Z zvw$ASx_FrBH*zR2k{KW(rggM*g4k0-p2fLlhzuG*gXaRhVP2yVrb>@+H;1x}*SdX;5=^-dHt_7uvvBp!glT?j*Eg>=nQd(C zMhDP~@2r~EYnn)E3~ONBv%`8Dkj!0Wuv~hBF&NpFG@_8JCVG1$3!M=7n5T4$V*{?Y zHAapml}8?Ov#Hlenvk1JSqf^mUO12$U8pziMpB6}ctFbGW}~iGQ!ZKIrbjHcTHI!3 z^$qEpTRK`)YFV8K!EwHff$cy;KQ};RBKgskwW+nMHM4n%4Wq@;+_GbY(2nYTkvy1^ zryQonP@SH~4UHQ*qz!P?BK@2!vsg%%H?uY-n?!8q$abvWO@dgvrnhS7#7*2GnfgYx zkX%1waW|>RjoH1q3nK;$t9WFo)WZRvs?bl---EG~?~G!+MZ?R=wBeKVhTlaz+r|u-;lX&-Oyz8Drix|E=Xe^$y*Eu(MUjF%keR&u7KVg3oTpEh&8y0~m z!bjxF;%kq*qpBKIpdh~?XgR(D|3rVeHOZQ6PqC(2(|m{8hxzgS$m-wI8SlFW+5EG) z@w*1uKE*lw`QkTY#`~^8Hh-K?@fd#BAe(=gT8wbkCuOY<;f(({{*5V9d<(nYb)x<@ z!XELs`MS2oBe59rE6;IbT232=ADQFkb!68td`*tKJ;xmpH`gJhzC+b%;;z^3!xZ&Rx`zCW z9)9zN1d8|%GB?k`tChBev~l|k)Dw=RNBdnQ0Dnu`V|k>N__e*xypV~BM+(=liBsWw-_f) zOpD`BdpaMUT`QUghtO2PN*rwx)$^XN7CT75y&^|hpoa7%mPE9oWqiE9>yVEgCMF(ySoH={FC7k!G6J{;OT;A3+@xVMDPm1s|2qX z{EgrPf{zPQ9x=VQ1@kTArW~SwrC_z-F@mjvy#7YIa|E%4(e5t@UMF~q;7@f}a(n-c$PDEcheAy9BAn zl;KYaQo{}1{}wFp8~0?vMS@gwM!FLO`Pp>3cL<&-_({QQ1#c0gx;E0^E%=b&Uj_Aj zXN2HG0A;H~(=L%jT_$9#`1aB9-NAMxRX9WK#$g3aB zmxF;$oFrH&SS7ezuto5A!IK3~6&w>hUGQANuM7TC@IJvm3qCLSFF`+K5c5+ic$nak zg7tzef>gvo`mo?G!E*&K72Gd)qu}=i?-aaW@I}FV2uAYd=jn-+f;EE61-k`%1&0K0 z5d4MU?*ysThy4B`_`Kj7f>=`N@Cky`1P>QnBzUagI>AkXy@JDn=L%jTc(dS-1@97k zK=27c3v(;;StK}BaIRpT;IV>jg1r3Bcu~O}f@cbTQt%4FYXxr+{HfsGg3k#4Q}8{( zszQ^_a=|r%VZlMc-Gb){UM6_8;5P+-D0rtJ)tayz4+=ga_*cQd|3B<~349bq+J5)U zBtow%s~zTgf)AJ$&<=MSWaT?G3I4i_9JST1;wV4dJn z!D9u_5WHA$z2KvQF9>cE{8(_OU;r-?n4gf~UV?do1%icwWrA}As|6bcPZm61aIN4b z!3PB&6?{Q(o8ZTSI|Tz+z^VKRb`i`IED$UdEEAj~SS{Enc$DC&f`1U?u82%$z2IYl zp9+30_`M((g49nIY7wsMkTThv0C*BEd4jYQYA< z!vv2LJVP*uXA#;RBDk+$so+e(1%gKko+5am;GYE73En37s^E6PuLOSRucMCox_=e!;fv9PidRgGKT5Dt@D#y21RoH5TJTlD?Sfwk*5H|w_Kp=iU2u)y^@4W^ZWeq& zaGT&Kf`1pZ@eE75?FD-X4iOw9IG%{L<}8ut5%JP-iC~lXA1U&&BA+Jm*+j(uli!?=G{HH72MAUR)(SQXwg{d;MEjmBc$VOKf>#mI9@h!36Wl2Hu;62Y&kAl4 z+%EW$;Fp5m2>v8!nr=G$*)7vk{9?dvBKHvNC#c>xAe_I;rGAkhHnqnd6GYXs(0OP7G>yRS*S2Xgg*WhDmzFA(~?SW zst*YJHAKW)MuhT7MChq_qa=Ok6)+y;kwoYhi#&k{xNa(KcW;~%0Pe1ePIKAaye!Yh-2gi@M9Mofc+Tx+p<#_X^JHwMM^QqI_7shB? zx5rAj+bTyUl)Uz;J@(KoWA+Nfo^FrR5#~LZ7LR$ZUaUQ+$8yjX4_%G}64Gt)q>CkF zEZtirU0sgz5yt<;=|kH)IlmSC}Te{k)^`t!ArJ19%;1)@4~kukdUxV#TSo`ex}x_d#-n{F}E zjUb%m<-2EH-m(OH@53JFEPZHu+{?^sui8@%&MDg7QnAN$cyME`Ke|qJg?W{KZq-G% zF2}WyM|$*hx+lQjn{Erz&4C{6V<{C&_ZG3IO>BdliF>X-m==#466~E$duR~ai{RAd zxHG}tm%Xr7f}cLLJ#MC}-3)scjj_Vxp`DK=r2D4>U5;y}%WUd&w_2BEQHhR4{zR&~i?P=>XOP%hK z=!#-80!5;IYl(-{_Fo??jYNIjUH?OBC#_F~oF;N4TBr2P$jG~mdr?I7%l1Ox0Gtt= zJg&3AO9WOQSiD!)-MV$_R+sq`HNV8tY;qDCg=HFoW1%r8^)A|mWcbircn`N zKt##v!$yeem!mT)ipG~zmX}N~#V=RmKZ1&V|LCseX#bx*PVq!wzu-YX=9&G2{e;K; z5m(05z0YuUNSp!hM~oN0(1@FkIf1-v=WqlWz4zbD3< zGX(;8bAH0(4R~^TU=G=pX zW4t-1P)PQ@iP^=n*9IYI-kh#jJ%BgoGNd1}cOuU*-W&%7jPvGP00rUAIRaXH&YRN( zwXS({HemUZ@>pdi(sJfurJtgCbM8i3!kfdll_BBHQE}hmoNhR$p=ndzR`a`~?7VXa zye-$x2dk)J_{))i@aEisni1X{{)0()bGYrd@aB*%PWfD(yqKYBN@%*%~^mv3vUizf(mcW<5X~Ya|UAV7vs(84;Ap{Oy(`X zehbYF-khm>p^!tW2H*KZkfj-W#P^F z5q0iA1;rEIoTV&W0&mXVs-z{b2i}}VA;1LxSu4CbpQ3tWygB@*0C;m)1%`biLcp6d z39H0_swwd1OvcjAviZM1@aFV~;Mn{}ICyg?gzV$dHNczm41^eOP9uaEZ_XdlEy0^Z zCMx00>4C1B$eZ&bqDTg=mJGa#&I{fgR;Xp4ih2ic&buhCW3!LPcyl7CPw?iP!3=2L zoUP1&y$$sq3BF&zGLRrBV&!hBsc7XFs=0oq0L<~&8C znm6Ytw(+jKIoptweI#4Ra1NmRDArHFsbSoshtQ_sUyn=(Z_Wm^Z)@Hhwuj-Uc7Kq~ z?l`X_Df=NdbjbOfd3(45?rf(A8({N6aASk{A*es$&6xy!&6~r2Qrk~fL&tDb_jyY7 z9!E9a)2i(p)ppOQrZdzocfy-*^gjQfj5UC+4i-lUhw8z1tG`of+Jx*dlvB%IIa4mq!&ejMSxS;;)_cm++B<7_}LaK8BqbjW?$z` z(S-Ykba>8>y^wUCvxr6ei8=$+GQbh;8}V#5Q zhoY_Xg8P`4@n*u>3ywBb_1Ubxpys||{RIovHsOxV3Jex0A!PIYYH*y{8}Bl*?RFGO zOp;>c*qJC$aDvHAvb)%<=wO-oB!r0lGObNh24dVd*D^Qrk(<%M8RpTve{j+ZYVMnN z(cZy0_f2rN$r6+MCOAhq$$b-?tDGU5bszk_60&Vpe((S#6uedrr_^k*&k(Je*R+0Jt+4=29vg2N11zL`p>5P@+Qh3P`(<~m9+Iy$kt>; z4W+N~rD6V2nMq&k<48Ab&V1>b`-bpxp zz;0Q_RulVgxow~Eny2kEH1`eLKI2Vu9^IH{Fu>+#Mj1)I-yu%E z{by8QhUMd4-39hd=$9F(zSAI#RLz#5xo_C5GD5yv5K?Gwr0GoGOAw0fk5O$I9eiIx zh;iR^M5(P7q*<2H&6kTtR!x`@@!7nsf%_(-yN`X0+&39Ll#|>y89kMg+&3A$l#|>y z8NHP=+rE;y>!XAmo8PWwGrUU!KzUQ zxW&`lH~dOBW2le4vcTTVDjDu$uPm_VvUnquFw$N`VWbj9+aEC<&3*GK4HWr0A<<%+ z-$7<*?weG8odUueejK7E5lwi*w>{RePpd`C`3SU*quX-6M`5hvU&f0t0Bz=B5Ea2|W-tztyCUrc@Vt;r9E8H1{4s3r!cfgqd^Y+L5m%Qch zfx!NR&jXl85y}4aSSDroPlHm@m;62@^+uE#gg1wxr@L#VEozDEBq2NYi*yIvHO}9- z-mx4$SJ*Fc4dpodA(H*_!L;eFtzMzOCcNR=D#w}4bhmPS)WsnYg#8-b5ey=@U*`f^ z6W(yWhMg>Hkm;naj^w0uG4kfW4+fHUoDMlP8QBKm4WBig<8eCFmKN@a7Tv3*pVZ^#AE-*y-uaVOq`4$wRNIz7Ts|B;v{!qMm8<==|R3|C(Re?LE-OMCYR_<}bC#uQ~qUpTVVg_Y@U z#j0GZDDndB#jux2UoI3~?RywZF9Z*!F}k@xbb~i|g89*n3g%)m9vcytFobDvG3m(# zz0@Am&^bxR=CV@h!1D$jQL*L3v;R4(Bsp*&f?eL6I5!Iycv`}? zqtw-fBJ8@{EL|bE+$`Cw-MJ9koe4*ro23R`Ddj2(-)p4)5q%2WEF28Gc zM*AG5(#gz%wIE;SwI6^!2X2<0@JM+9+3!GZmcdZY@o=+re1$o3xmh~ygE61-meT2X zDogOT$p`q3e2ty*j(RNZcpmyt%DZL}{SRQ0@2SV)js?`&t_D=c8*zsQH%kR|9z|1v zn`JKDFQP%f%~DDCF}Rncd}P+py*>%3$w112+q&(;VSuVHrDSQfG%-mSGs|;AS}s{%GqcD(64R&BFGyGEi)Cv)qj| z)$%3A&GI1&{;k;;S^=Z|y{w*{<^@no4p13fL~Paodunok)Gf(@?eI^z5q%~(z%nEU z*rv&WztelQ(&IIC5GFV)vvLq_n`$!6oJS*uGYi$2>1Ajc1C1eXyQHqaHQDu1q z0zBF(vI>>z`fzXu8;n5+Gezk8Dm!lla=`KS{ z4)&KZ(yw*>u>+Qoew~j==YXLl{dyl;JO>Od={NXDzyqUP9AiMhOv=qFl^8<{7sOe# zkML;##n7^pp1i>G2tbM(e<8!!)wn!%yNRll5%9`Vec@eJfuN|YDhjf1^!$$^Nv?u2%*BSx8KXt@V5gXgJ%KSF6JhL&1o zBbY?J`M3rL;T8bGD5Y_k@^%?oCcr1SSp_arfxXq0i{4fYE$^xM;bLlEqvo_fDLpc@ zWS65>xI|L-S~9e7bspsJP{0wV)I1C=165YvQr;xfN#R;p7+SiaEY<`Y9|@t*xOP4r zmi^0+hE>{4`S!xKQ$8;4QpEox#+Eg49~D-FYbImtufwwr#ysmTnAl&y&{Cr`520o+ zcpMYcchrL8B%!*js%%)%3@t3CW@urNG(*dku&x|@}%TG$vkKCztVK(FD;;T@@ zKLNePnoYy0T&aSgr4G8z1?cbAVaLH~ID;Lym#>C9;P6Ls)`|^qYlfE1RChB?b+2Vysu(nonW#qoFwl1Ta|7pRvu`b`isIO4}2@b$6V07XCoc8)2`qnn( zX)c9FuI&b`+WPN8D02bX1$dU?|?Itt@;ihDDk5I2=>c&XCeTk zh`0u)p~EBx{s3p!D7vyalY@sxBTjSmab5BGBVQYvGwI~ftpSOevrdMX3o+8Lv;`uc z3MMnOJyI}d(aH%pb2$_4=!SZSdUtcW|0}biyUW#)+Z#dQ2!1Z^2AQLEz#s(VBVa!j zpol$k_Z8(iqC8Y9PmzE_C14*3=rK#Ih>TKxsG5t7(eq%`xmm$7@IbdhS-*f30rgA; z9qZr~sjG*?ndVta+yT(6SOw>oID4U-#;k}g)%5P>G!$+cQUjE;Qfa;CF|4c#U8!zD zC8!UT5H+&UY;GM^aHirnY|8Wz%5-a+Jh;8i#@r{I9Y#9AXJ(BXUpW%~Y;dG&9 zrvdPvN+d7>-7e)zKiAu=u&j^ah~FEszT{}@UrD8}lquFx7PYfj*%Hp*oq?Ez-mDkb zchKH^g!;noYAZwkdJV$wqgVDQBlJ$7X= z>D7vzgw!WS*c7gkR_rIOI8E~6j3Xp2>6^$%(k~wFGLrONpG5}GHfw2$|2g#tA zr*M!!k@pCUEu);!s6%aNz{I1UK3YZ?x8Y z9~j8ctsuD3rW14$6|J&^fkV3lCbKIOiK{TptI#@=t^$7-9JA0mJFddNpTuq~j7Gwk zUU0C|-GgQ2!6Nb49lD`z-TWgx9iKYKAu*rPp4Z>FNDlFmtL!PWiD%pV-Eood(?j%2 z?3MXH#YD0P{3Eh?pvx(;JJJ!{WmRwVzi61b-3Bimyl9d^T984>wSyN;_K~|rYdi;c zE3T1$!UOx~?aC%1TgAAHA;tg2Y$CE-<3FYm*#p9me}^SRZH_auEl!X&NkEX)F2o;+ zTkh}rfv4Wb^#2+Qh$?&n-3Rw7!WNcltL-)jK6d$dm1GG2J**$GO-l7%t*wYYeibqg zP2#~}TFGry6#>fbxI5gfeE$(82RF8NcRU_E6FYA=4=!$+R5o>RaZU3fEe(x>%bOaw zk9+gr1)vK8(M$7Uuwd0Kt{$we?p9T$zX~D8u1&8t^8VL&Id;Rip=gQzzhKq)cj+|L zr}?14QDjDyAo{3ls7@f&_+Mbq_!mhtV#7|&IBip6{HHiD{vqv!&|Ul*6c^l9{NHA^ z*maCyH{s=+Nr2q_nL`fz64(IwS7f~SH#sgy)5VOdZTb~)1TvezUqRXm4_U>pM^E9h zqp^BoolMW|E@Q}^F;al2+r6{5`e8<^4bcBdo{C+XGCs+-&0L|zhU8r{*YNJ@GO7HV zJQaxqii*QZt-rlY6&_NGU*@6ktV2oA^j}Op@o#ZWwApNmv?SgmJ=?DTYBUtWV4#*6 z!aVUC+r+?yWY8L@XpU-{A_EuJHw@%r_J5CUVwY*aWeD?Ed+(pe}?>_4VDL&IMT!QFtoajo5G$lK&ZO? zzd-s>H?*mZV(cOR!+#^`gQ|J8KQC_Uq$=7C1w>r0Zm3I`F$+u=|BK8Id;{s_ec)?p zeei8(QF`e3J>`7xzRjdNQT`v~dT6WrCDIYJ-AUD!{YBF!52{&SSG|0Ya7VOhkGusc zyzQl2VtTvLYJ>gYA81N`+L|R2(?btyV-U7ozTIl7^me_YDAozLmcYQ_*1~SI+9=;Y z(A-UWF5$#4Cg`f|QHpU@#VElzO$~!U3^#xApk4E~hYS#S$Y}le>=HnDI3{*A-HMIk zzm6&b@6uyO!1&_lm;i^LZ`wVFU;dw>z5K0q44{6%;Qz1UM*ttl^8ZNge^SU3(F5)S zVhS#AL`*cg8T}!||6kKh@k`*}(sFdejsW-$L5t8I1vmeT`( zevnt9b^dLYU;bm>J@DUi&(RjIL~Hxr8I<*to?t&c!9M>r7eCtKm1u1r{}lHe-i9a`JRheDo%ybi6y_cHdA z@I0VtboXe}USfMk65>Y^^t&g7C)(?opwEA|$B%!72O=Ju`5o*PArDdc3B`Pe#$0sx zjYK&=A-uqt$nbAmb>P&4HgN!K&$k=d~%-?@NsuFcXyImZ3K(UQ6^z8oTAU~=xIJW+7E_;Y?IH^e+5CX8w#zC)=cqN6P) z^2UH8#u-t_Z`#* zBDh`fYe5rh6y~dwU?0Il1eXi052y!Q%uIxf!k!f6dWwx5%2S;YE?(6#PVxUw|_|N%#()7#7rA4Shu}5}YhJ zSFlO&D8b_d&k(#=@G8Oeg51cA>1nQpEh4`u_=(_mg8Uti%Aep~f_(*t3yu>k7d%k# zV8P=BuM%7*xLJ_f)G?h`1-W$*g6lHhE?D!~T9BLq(pJWp_q;0=O*7JNYPX~94KdFdkg+fuvl=G-~z#V!NUbl61+(8O2M0mSexA?^25YohVi(_ zTSR_G@B{Hz+y~IxNg468@KYJ$0Kr1Rxq?lCXAx097ZdRiwT=io_Xs{I_?(3ABtqYZ z*FnAxc+Mh1KTmL=_(zG*D<>jPm4bER-$2Ck;E6=USKJ4XZ<6p$#KDH~fXGh^zDg_w zx1h)$6DJzRHzH?7AS2x&g0lsW6kIL1LD0a#dI|{QHmPJxa|&|>dkGE@%ojvbN^c** z$%4}a`Ob*;4-l*pTqIa8*d%y@Am1G^-dTd@30@+2x!^h?+HIrYor3oYJ}bCIaI4@p z!7l~B5&TIIUq~yv{J9m|S?%o)>?$(fEzzI9zaowl+)r?vAb&x{cAhIZPq120J;x8h zyu)-+UiCfz<%v*+-8>@tkE(Cj;o)sBzQ>wVdK^0%wLwpQlWhX*}9rYdo z*uw`I>6Q>-XBH9h7ZDL}IT3ow-YCf*^i_T!7tkK!6%rvA6A`~$9L-8Fg@>q?5QIcS5zt9W4cG89>aL_!O1%NB|ZKcka4`}HbT}%KpY$oSdy#q z)9a2BL%k;*4mWjpGQBdKw5Rj?C%C*rPx7n2)<~ddqPKWbdKN@g6+A<)9wp(-se%?ptts z)6Ms!%Y5o|hr<|cC*$OCAI`SQ!JX5*_6j}ru(XWX<2EX^r`zKRxV;C%c+7J3V(mda zmV>r<=yFVlo;TfcPr4W$v2?F??ZwLR0>auV2e%gT+MDOGm*ugyTI}g^Y(tp$K(IO< zcJ*TA*alyggSL3+a{M(R-9}Hk?M09AIv_#XPR7aOeVlETDPJbR*E$<=}qyw5!W;5rn)p z?A@1O?>^Y09nKrwacX;?iamI#<38AXC?W!YY4P|l!QM95n}ESVdp&V#d*3J6TZP2< zlYD(>dkzYq-3;3aBg;G<+G#=0+a7r{4Pzw&nJ(veoo?p@d-c8Jb2aU2dmR$&T|3LY z$I)J2kG(+&_HKqf-V61i?e$Br_Y&;!o=AKBaq9dPCfIu&_D*c0UPdR_%bV@CFYOKV z*eerzI#1Qe{5DQNaxi~9XD8?tV*wY^N}@x(c?tQO0X^@b%iGe1-eQj;%gdt?dfs*` zM>%x8aLnj>ITm{OYgCbNxew_M(*jVZ%c4Oqc6PJkgEfV)RpO1Yz3AA3!Xb-`K3#31Zv?!y=Kr^M^ztk)ipxM26(&4=*TyG_v4# z!|AaH+yrMYL_&BZb=NR1H^IOUJ|B0(I^WIhZwY=8u!B*fr+IE(lsp6{jP3ATZq#*` z=b8m8qxsR7b{Y|emFK>+GY}c6^zx&>i%wLox3-%X^uMI?h*tBM?9$cEmXE*xaF$w3Vvb{L*CjttcK0js)|( zD{Fn{4Vu)wR`DhLY(&OwE37s0wmxIzG7TelWpu6LTsSs*#}`IMmuGv%te?@NyI9Zl zSnnp*yT+_{QP!W{ZscuyhBgCHBk$s8b7FSR@6le_DavgZv-6kjdC?@dKJVrIaFB^3o~e zD-3d;{Hq7Q-AjziKE^)HzRyFO=RFl&-}5tB{?23BF!g1=+wt+~e^pCeL;WaYKs`Qd z1}vMucquS3&#h&{{ZUzQ!;<-R_2mtV>#9~5^4WPSKjtQWRK%Ui#qsJ66L;+DV0X+I z#zj4~f504r`;plNFRX82EYG3&Bk-JU_+H>t0OE%qporhf_JFQ`Evh5NAMtnifIs3! zOgZ3>sKm<2e*>nA7=Hv`*@HiVnQ%GLX1CR3>3g0F$~!e z{)iyDZX$ogVnmS)TrC;kzMYnz!w6;MBdG>bqgIDf?bD7f%PEJ1wDA8|4IrhUP4s3yaSumUga1!ur{iut;TubwUEe6)+^ zkGO(HHGjm@Y-5){;u;#T59e-j&eP~v_K|EM>{5?p?W0&f0cSqr9{mVy;)5KHySuK1 ze(GHqn63FE*dB(X+WkQ`yW{MG8OeT#4IOgcVcs780Pbw(68dlc8gB4M+=luS{)m;x zn&ywlVy!&+J#-95b)TnH?{QS)J+0c#QEm5(YC3Gy#ld}VG3q>ZHgcl*Bf8VhGIlA$ zX=1${MmIYy`;E&VQIA0Xhb)`RA8|ffzBPZu8;F^}AMq3l(Kdesdr_P}VlCUy<&P*t z7GwMooF8NS5#wMi#vhS^rUQS(JE$1T-hp-je}o?yaO}QlZ16|y1tDaUULO1r49T_^ zpnAa{Q3L@y&r_|Ve-?x;_7~{j;E$jXvANqS_#>7=Xw4tNy@F%>5nEAb;E&+{h77wO zqvZNGLI~Ie%%|p$IE7j35wD`8!XLrUPTS^>UFat&|*Zi zxZn3b&mZwF?2J}ZMce!l-=g+}KjIeT$^RHT_~VK{;zi`dai;Sl1m`~Fz^T}P$}=1` zzcYjGfb%+9(wRv&2HZ~wNP2>#GN}&yBf)16XWXmNSA);3!3=CTpTj>W+!Jh(;LGF! za2&oN4sQJr?vOJY10wiFb_Wi=6^Imkn>snpS9HI(FZ?z4#0gA_|EwP!{9qESIh>t> z9~MJ}+!Mi%C&ESUiQp%6S5(U30 zhYq54e-vS`9R(S%+Q6z++g$XM_v>I_gzk)Uu-a1Ox6DC|Q8_Fq_L z(=3DlGK7^}J3KXu{o-3xc3%2E=F1Rl)?WH(Q&peM>Py$$6Rf}VLh}zu#j#m|=|xHi z*;Oc7`Z)70gk;;DD3q8cCd(YV5S=J}g4qv37n>EGUS@LR(TKg7)}|=~G46?Xn48VW z&FJ(QCO?L-Ibo)2?uk0&JUz}mkv`jGiOD^YK1VspJ&`_FIYTz6&|j&5~YavR(3Qwo7`o$%e^O12erwRq6m$sp$(P?y$Y9czcPabP0{(53 zU*?)DSVFl4Rg<(eiR++Ah#JaR<0FHd%1p*uA6wXPNg*`%1n*55H~LOT`j&kP3XrkR z_aX#vPjK!^dY9W@Sx3QcS!k;{k#~Bwedsk$+lMsw1lvCJruhxytF{llr381C9eUSn zkADegtBw%bZWcpu+dlN6*#x1BJ%*+~GjD(pv5!D^4Sk`6p7zhkXXtAs_zC8p;TWkZdM~zvxPMG1iMuzZP3Io(T0;&TRWY=B|$ta%>-lX(&$#U2J~16zZ#lh}|7+66)`}9!d37{U|iZ z$HD3Lu+U)Dr~};MY3>OU%AhT=>t*h0<(cCl4U;oq8uA_cif`uuq&bqq{`hN25nbTW_w`@=Azf`(Yu;W(o(JJ_FgU{Z#EB=V5-Wgpl{eHz6F4aFU_sg_(@ z)JofV16|F2k?w%IRQem2O_syQ6Z<7D#T@5$)Rz4+erSR0t0mei^w%^LT%zSTr!(EH zTxNA~)^XsxMt1~-h5L1`!!->BmwkDL|8-8l5jpWt1{n?DnYB<*;fdF4F?G!*Z^ zq*D$H_E&o$zAWp$X8t6vJKSYmXV%d-y{O_Y@xJBQ52?GPrlH_WZ-2+Wl;dor{tv65 z-^J;Hy4ExlMwb9gA+UBajkW3TY#@aY;ZKvi@LUkE#q@OS7LxmZf0-ogjo3vNH22b#ZI+zRncx*(p;h}QDg}x^js~DSA0i7Pyp>Zzx zl@2_|>xf+Xdm^5Wq!4@ne6i~{u5oS;F21wWg~oPMP?y_-FH2OC&ohovR~L$~>vDVi z1%k`%(f%5E?||6hOgQ4)9wr8CO1X-{cTTBap;^K0!5L<^+#Y=Xjd6QSLupdJaiE`L zVo-tGV+P#Tm9Rr@4}Nr}ZZ>Umd!(SbW85D36g0Po1H0h%I1JNs$jCVh{S4e5x4>F( z2Iirh(dcvF_P7roDK8-V9m(zSI0j8854T6>LzyF&+oSUk3`}r)P^a_B7}VhQ;LDZH zb?BPl_Tc>8nX7(qd%Q+B$y31X!TGWC+0@ytW~t8SVjzRt<1_ltM3sTtV+Y;mF)JUM zq#NiwAPMe|6a`x6+b~6d+k@;2o%crx!R-;G`(XNiYG%>>N80(!>_|7syTI+yjqaCF zGH`qF9@R;>Jyia=^F6pdl>2t(`5Uu8bkNrSX>Jd;r*$6MhTI-=k)~Q6#<)HBBn57d zhoBWOa`+`AxIKnI4cq9e>t;@{!tJpUTFHUq;h!==IoX=Y0WwQ?Sv@*%Ih9@cAiUMR zDO*@Q_D2O~ds#im&X&asjPRK)Ilwqw_&lb)-+)_DJsGUmE{r4QY;NOvI>>zJX%G}N5td+ zA8(Tb`~V#U0P4!v;6_4d$}8~b7|6KV_Y5R8j5AzTk4|Lu$hg+^C#y%sbv`ED39KF& z*ZbJwoocF#j2nDQ5fkS4*pVFAN~0gDRAQ_ieALLIeS~iZC{~X&tp2ljfoB+y;>Q1x z;jCFcc(~m}6;l;h^@Ss7O(J%IlG5grNuqW%epy@*c%(Ed(q^9jhc z!(6%Xq@DX9NL2tIj66EKC{EIfd}vbDmvyY$A}#R9c@&Ko+RJwd+(8Rt2scv9h{1uF zOOgXu!8bW@ySko9jqyt30NfIi1K*>qgDX^nKdCentH(iV#__Ov48Y`{9N<^N7(Ge6 zx~v|r(_R{eZgRlEqA@vemr~&~L@QR0Evgd_hDy-o&Kjk($?DO*9JRs~r@G6M)q@W^ z!4KS7L8*CIJ^HGwE?3^C;F`im3t{!JIO$DTqr$Gjb+6N5+5ZL7uu5-JzIWo< zIEbAhkcMBeTJv~^x17^4eOe37N1hz#J2Z+_bv@jg)q};cPTjRuAStvwEBiw`TSDGu-*kWvtO=76ki?k7B}8vk{OSAeVuv!eMZ@#Z@jTE+1(9 zXRsot^E+_(JIqJCdJO+X@UtrFlu`qgm>4tSG0KIi;U7-Tndd3Zi>b+4Vm9OE z;>$?G&&9trn}$;@G%i>@eumpQ4V}n3EC)}=hSLkVw3ZKrJK(&7F=DNl0Jr7b&Xf*6 z2yS8Zpt{?fEJ7A9C=>0eCZ~mXFhaV*qYG`d@*PQET6KM;s;0ohe-p-)b;Ms`P_ud* z0q>M*hE2m-&N`L7#=nH!;0X?>u3+ilfA+fZ|M1o}<$Rz0=uP!cnB>4|2u$TG3$S#2 z47Xzb)hr!+yKB95A-n_5zHFs;)c?K=zk|VRy?ZADz?y}twSXShaI+WwS7*P&T#iud zLc=a)Zy2crtYucQ`hI8rgg7}pFrKY3<`_f?uEuNiMPIAbMbbgPiVFtExH@@K^9V@~(2Q1%W}_7Dp-QVIQ( zm8dezYRCc>ez>;30AVW;q9)0yM&Aq3V@;M6y%Da}8xh9(IfzAm7GC|(EXHdp6`=s> z&mYIQ3J8*Te~VyrQ}t`88j-hI;mxdL9{h^jT>Wr&-4e}gi7ye*y{cuoVYV=YU$E!) zgP+;Lw%`ZrZd)v4Tg;=V+Tt)~>}ZNlVG1{w^EqMzMY4yw;;RsQ;v)~kT=4`fck;On zclZEUp8{dv3Ot&;g%FqIV-QQ8+7nfs2S;Z(Zpw9=$0|Z2n8kg3M;SirD5LjCgcl+F z5ebhs-@XW8W523G%6({_-V@=+#@->?%T(hqWPgMl06RAFpu0vr{FruM;vaH7UCbOZ8E}P}7G& z+~n(psDESlJ#e@eib#Zgc-To85a3$jkjUaQV%EvH7(??hDT0`VKJ0d`Z^8MPe#6hU zgGX|Jxf}Ku%#Q8Gne1?$2c>vQBVfxI`Xf}sDJBca_RgXKbqg@|?uPYQ_HCase z)?_g~;`QhtiPJfS%l)S5ts72LMs8#DwN7%Z7XUG3MAZJ8g>txGX8#G9AWtkE5r@1ZeI5AVz{ zucxb5Fv!@iqhjt678=9YJEjFMS8F)(WQ_3oGadNxz>vT+$ba&wg~YCGFRsEgtza56 z8BHH<=yV7r$MqTcYiL{DFpU|6GMs*+<(M^e z%))6JGjNR^xFgdj!NIv}fiSeFK;R8~cM8+I3a$BVTnp0)`~jM2%qD1KajF}pkNJ_Q z5nSC^^|3HR-B7|v<($Er)Az0~p}n#nDzigVV&c?C`wC%B5S3XChxy%wPxTt&kB z$~l+tnd?h%qtAs)9c+$roG?x}T{&l*4LH~JC4A}n;;IfNS%A|tW)YZ8zp?C?HFUV< z*;?vgIPNSs0_w_(4rHbA(8y}_9($t4|C9TS{doP2kmo-|$RnQ}qj~=4D0!+H>KD3X zJ9|LRqxN`rwfBgpr>3dN)oxgDu1SSQFYQ(0HPw7G^g%AH!>+Do7i;)r&O6Ynj% zB^3Ja;SSR6#?g?_85B)J%lxWCP~b{UKk@5R3-KpW>gODln5Y}s8isD4=0l_dsj>Qt zv_qAZ<OEm5svEjYPkpgp0I3l$b=-`S8I>{)bRjUs8FX{J z;?~m8Wz>Uj&TH@U=U zoKN0^mYOC5R5s&g%t2$KE6#7Jt1{fYEN#Jby`%=eD5|L@{Rjw!mejQ%*RjS;oOw8Q zRZWy*N}o|QwhT8THMuWX(kOHLzsqr?tJR%G|M%IAbbh8xol+7f?`Yiu#y?4c)YebT zF!NVVE}5*l67TfoaL3qd+}<~KV#&A}#*&8WI&iX}Yc(!yX^!c;ogcsHYHUQ$Yp$%W zTU3MAQbS*ItM21$!o~BOTV^(5uC6hvnraA&)op1#Z;W_ZTn8p0m89A)Uu`m~t6^pZ z?t1@_K1nYEghok61c?OuAtu6cW83;M8r5BD9eoF#Jab0L9HXUX3E3qvh-$D1RL-6dF15+nBMWqQk_WMzQFkbo zFuXN4Vfy2=;P#`cC76Vk)>kFor%(-h!qz0WGNYNaOZXY8I+)Ee|M_ZdCS`fg5k(3N@BJ zIV&AnjAUDy5KuF}xuIT>lflIN=K3L(XekUAH)jiLn$WzMb6Q2Nh~ZjG%^De8krC#m%}ja3f79}oGg5NgjRDf=CfEQZyl`yBc*0ZWlM{?OI1o6$J%vDYz$&PHg>}Rg=wU* z0TVeE-&DaMP)W1jHnh}Y1i4*5-c?neips`Moo-<1S~PBw@vo3V=}eBBI=S2(a(K!v zFDsf+!jy6Us;np-PiNiGmP*guAPbP0W61^R$%_2;yiyHyrH_Td)MDPDVWidUtfIxL z29M}_MjoYeTry>RDVA=$W5pg=W7as1V{B5G0V-RTG-9e&a|jpDwQgBw6_w2_G3K}6 ziFLtJu0=QjBcIK+SZk@}64v!~)##)uv$KZb{lkpP>6i$sm&{)tORb`!Eaom52P2$r z6sxXOpb_Vp;yxF6&r`F+kjJ~K`Bk-8t0z8Da^(^;I$=_A)Xnk#1&%4tB)NygQtaGI zn`?C?@}cGbKG&4mktA_Z#e0#w=91SU>@RTchIWcG$l^MvNGBW;tAn=enoK(O z3NQBThX;glm9ephUdn8!RTZ8iFmE*)cqdiavb<#|5@!C~M?-y^rBc07H-B&Gr^fhk z<3>gDaGUANy9{60^98<_p9=qojU9Z6KQ_I~2`Q_RPfR)~aI*gt-X*jN=B@6Bn!p-r29UT?^Zx}y*4L&OGyup7o;-edt2In5~QF)Jlg)geL{a>Fi zsHSfgYaqr4Rc{w01!$bW0QM>n-U(Eu$XycBMJ zIOHDqD9>~JEBsUZpEQqboMvo?LFI*iGX; zPk6e)FZcAp@I=0;K?&jfd6zz@Uz{M9C&=6@Kp)g^5Se2j?CWeC*Gk^YIA3HghQhv% ziu=YJU-4PVJ37T^wd*PYd{%AV*~-S{8=$wsy`yZLqPH4q?EWs-`gRh3)NJjqSBm;= zl>Qe{TaRscjEVmfayN8X3D(teCH_W6i3uuP9mF*#F)#Y(ta8yR{c@&220IJkPAuz_%UQZe}+EP5vs zCt?pa;w1N@A>u~S+bnt?6N?SwNAVA#|1zBj(2v6QB;wP`JmOe<1}*;i;$J|-VBp@{ z{=M*vYGPNzC?rCkdzoTe-07)2N0n@kH}9tarDCnf9fc5>(f`} z)(1Jd@(_Swrs{bYF0X<3q@LlpL2*7Iat!;XqI@E=UMaT5u0LY0=NbnoM9|V(e!(@6{f)T-if};ev)eiM41m_7Z5jnao2yPU-U+^ixR|Ve}+#%>ockN~f zb`k6=I9za?V7cHyf^~vR1& zV42_?!D_)q!IK5g7hEg2N$^2I&F%Gq$lC-z7ThTqz(P&sPq2$%o?wAspXw-wSdf$b2OWI)dCHiT*i)T?Kmza!t?he8J&@qXowb zavvY+O%a?SxWC{$!G(g01-W$*<1H6FTJQwHQw7f!yijnp;1z<`3f?Suo8WfAp9Rx0 z-Sj#L_7EH{SR_~`SS{Efc$naEf@cT@@nVMM7$Uf@V5#6t!3Bcc7mE6)2x?BUKZ(3f z@HW9$1-A=+CHS*o8W#Ap*Fms{;9$Xh1jh?j2v!OnB6yhK@q%XwUMhI2;Jt!F@qo#6 z_Y*7=++T35;EjTJ2+r={##=6URwq}!RPbuSy9J*Td_(Ya!62Tsn0~(CK7tDbR|sAp zc!S_0f?o)>$Fm*n^bwpTxInO8aFyUWf7X-Hnej@mH!8E+uq}?3B-hx8~_Z1u`I7M&{5kFE~ zB=VueVffLn;PK*rhRElNyjtWxihP5}cL?4s{!a)hjxwb48D*dyaj}Qs7{OzSD91@e z+`}&?B0pD(e4B*dOT^fJO7JD|e~Z`wT!m~I!rv4RH*HVd98Xy9P~2neDJC>gh5g{UTly#xmc<_qp8I8Jb)AhNFF z9VECwuugD^;E{qW1y2$@P4E)I%LT6%yk2m<;BA8U2>w;@St1IxMR2R&Ho-56X#Z~n ze-h+-X8QlT+;iL)l6IyD^1T-2YQaMU`Cgg+{P90gy>9`YBJvr6=L=pWxJK|wLGBj7 z__qt*EqK2m|Jly)Cj_~j0OdCX-xK^$@C!liTu8ki1@X@!C8r3c335LI>U9Om zUy$5T)Z0f;{cI01w=kgpbiuiT2MR6}JXjEq&4zD?yw^iNR`2`J-Vyp^zRHvK1gQR~ z`#By*RlmSvfkG_rls=XL3Y8t?1GgoWpE9Ng`{YYve>#B(`xi()RJ>7=KJ-R29^^tI z^f9!RTuwy114N!jL^^wV;5KWZ3Do;Z#wp;%b09nF$i^91ebc&EbcJ#_w>;0br*aT0hsknw4U zhsJuiz3JiyU+P^i)5R-|Sh}1ayyZ9_GW&o&w7m=A;k8%mu}6Phj*W18%dr-+_t53w zyyGp$TF5L1ZSm0Qz67^7-Q}KinNOW=9~h%;_J1DN;%uuNRPx$8*<%lnf-!r0i9OvO zESL9ST0HnZAAhm-pdQOXTRe0*3Zdjp_aaZa=>D;E&vNa>%5fLMI5+A;+gp@i?^@Vn zM%cbtICZ_O5_`HF5$zCz+O*nV!&46Gu^hC;L#KOPV!G4f{i?m_G2XKY>E^*+HVw(4 z)BRTT^mrQ$y^&f8sMGx_A>BKWF6Shcm;Zavi&|wuiR2Ho;zKdc1wRd+a?a_TZ(CYS>%dQ%i0cC_S2BF9Lh- zhur*8UFYxR1bZy(_wdsP>x9Qg33}i6GYr;&KD6F;_<7scsxplG;KzF59Iw-58afVb zG-Ivm?SDG#n*@8CYvS{GUynVqi0C-9cLVHs+f9er(DUZ+bJ#0{KJ(Wfr_Nuu1bffJ z-WKFVAKIQ`U4dtz1mrJ__X9+U+3PR%@{JVCFd#O((XP3cf?zl8kZ zL*Q12&R<1>-W=#1>Ct3)c}#_#w_eIojzajeUN~lSz089i{u<$>ju&7Lk6E!pryGV3 z^kPR!6p=h0T94?dR%3Z7Jd%Eyi*Gp=_FP-)Lp%9D^rm{v#0Sp3f`XyH8#Z$I?{>q* zH*Dx|`~-lZ!A2gHj`|0_YPVgEbSBxPFewOyudaGZb!Mv zFK2H{t)2S$&qD&|cw?B6#=DJs2O#M|IN7H$^whC#-SsO6ez0?DAbNJRTQogt^eunp zv`u|WBhkK-#)3)DWyZ@_41499dcj}u`u!Z(W+^`-@BL@q*tzm-qZh7gajyHW`1|4? zirpBi#`b+~#QI2dT6Apm_ewvoZ7;~B%AFtWt8i?sKbpBI61}+AzwP+iNVM~&u=4kB z3%V?VKlfRm7E9UO`$YMdY`5NJX8dDq$MuCOH@>I$P5jUO2ekTdWkjKdb+W2hLLi%M)-`ZqG7HpfcerRdG=+H@#sBxj{Q+qS)jh%O`HG03X^Nw|c zCb312DE6P{rg-Amx1TE%*2R?Ql1(lbqZy5;{J7G*P2DFRUYxou67^r)FIu5OjJyxF z8j*h6_K$XnwWg7`Uq-r4p{$_W# zCmMM#yk-txzg;mVp2am6*TpyET!(W5&J%DRjB_l`Vw?pyd91r7uyW^Z;J(c55bdgR z7>Jgy?;9Nz9j2rtDN$Z@=iNK+cH`WD{?w~q^XT&VP0clt68qEQ5cB1;sMRS0XT5gxS>p0c;D)U?-SySqA-z zkWg*??h+3AbMS}%EZ6JZB0O-QYO)f?I)2^N?9*B1K3Wj z9GLPW@-QRi;J;%MwJRHqltYxJUD;%$ELMtkgbf?>u z3l)!8esr znN>HKk`5lqV5)N6>IN&9#BPMIbAd864bC9zo_S3_6Aqs%U#ev^=G&~5Qv=A7{~7cI z>nz&w!_%Twuo6#ab0>x>jrk4 zx2Yd+?YyJG-b0$h?U8bC;(0RFX-ibb8tx?X$kiNB6IWK0kKPo3*kXctK=L4+2 zE0uEqvvXAkBp>2`Je^e2EQ1jK1SL=PnYHa^*#gh~9E zx=5*o!hdB*trE~C4>6f*?_n|@ut=%n&G(qh-yoz;FdJ1eqZp-B3E0$qC2Qf9FW{GP z1Ty2FfXT_a)kK8QFqYpoeSIN>CqU2k`^r^GuZE8u@Vx^8Cj5wOZ7g7v1{5JL?LzZ< zM!5hrm3EP;0wc^13(_t&OFOc1SW{`2DBcq*d^VCzyHxR}IN^b4s=z@HE)H10pa&4Y&746P#8Xd zYPXpmK`0JyNBgGTZk~=zPcZybAz8Pd1BH}RP-{-wRey!sdWA8rQLSNJ#(KW?Y8VVy zY=yMz*dNjBNCIPRdXjM?2+dAAuRZG8dXd?^fO{4j)&Z>i3wyyCuzE7?MTPLUtbDf6 zWgM=KMbfP_O$|Ak{o~GDL`%7bp=pQnQz7dLX8K6Bu3>$GWYdmfXAM}x824!IJ&ydm zfJ|6-9mu#NkmoLG_g@XSts3(Iwk0M4mgPZ?8ppZ}Nu@nRHq4O4ovza!o(6ZewUz#x z4}crgko*U_b@zJOOoe|a?eR~UpZTnxC;4AS!%|)EDb@2V)$mU+!7Tqh=+0L71?UE|{jaIMO+Kt( zd;hl(Lg5J*kiiZrBs=^Onmd@|?~HurgfFF9M}IzqF5%-bID(y&04^UU+Sxx9Aw7*O z{zTk*U;t7GZAS(Qf?fS@Gi&^&EZEJ@f2kYc*BB+&eVYtyZd?Lw8957YeEef z&Y+r5L#iG~UvT`5%lqKNPvgOqJ+M|*)=Qp7}>U=cjmcTjKcPmR^ z_)lj)c_4H zz0nyTaLr+HX3O~SMyMEeqml9P2Dk$DA|vAyx-83&(q?>0w`1ip$S6L?1PPr@9BzIH?e3xaNg=^Jy;!mPc} zXj4^RnAH~&YDm?iLxtwgNW}@W0z*Yg2!-n@j5B-URcp55(F&C)e#D&cV@M@5!8{is zUBayBP?`BSgh=>OcFSqX00tX3Z?T@fn7IicH={!{%m(yjb(0MVHDs7yABBV(^8c~- zCE!(6SKH^@@!TQd-XubR02c@trX&nPP{1&SQ3zp16hab67(z?{0V|?{v#n^IsW{Y% zXf0r|S|_U3soH`q)>#~IK&v>9)&G6hUgzGMfNj5i{l4evldyg*+RzR^nL6^VRGVher&EVx$&#uh}g-(RN`-s05QLUC%bTH@?C-%y-)Fs?*7sQ&8dCZ`>oxmi=9j+DdR>@Ud=dIA>wvuuDLFC_ zvfj3D2V?p^>!AGtn7nvfG$QLmJG&kG{>SLztdE4rkN+O^%=%QAg7`Z)!?HdXrgwZ6 z)%>18$Wt7@01nJ@JSTz~5I=;|JuB=vA54jKTb71~lwp+>^ZXJirSW5EEz9#Pm{IX1 z7!O%(JpAd-SSy=f9CO~1YwB0fnwZtelZD|WU6_^d1bIo!s<*PbcsRy5OiBDVWJ-h? z65qyhG&E$Kq29BGdvZ}IT!N97HNwOBWULj;#}LR1uWRJ2%5`FReK#Z^$^yDBd?v#- z`JAb+6+Vl!<2;VWgwKAtBZfqXYtitA&tWy@e2xwcZ+rvtoKW=wD}2sHu!6M=BW5~> z_>;omi7=THdFN3UHJs~?gZ!lwqHSQ*N8TgtbDl@G_!?9Hab@QG91I}lsgAZPbT-A|}e#}YXJJ#=$jmWQSxlhy9a-W&C+zH4O`JCMm zHS4-Bc*4iz(io8kMmY|r_sCZqK)FsP3`a~nNauUXzukzu3FjKh|Go}%zSBfsn|P28 z&;H2wl=qHbfzu(P@gU=8!oLw)?f?hG<$l2<_X{QQW7#EMdlTwCBtC}q^Vyrhl*SnW zGvc>z0W&I#cQOI{m!QX*JA|OzAxzAwT)EncIQGLxnQwUqp`7fKu156&zAZS)(}X)& z+vEW$_elDKIOYUbBS%hlWeDvJaov<%)f?4EAX21eS5xeBI$*?QOK=XyIfo^f_=(Qx zXnOWidOsOI@c=xKy=*r`-pxqOS>Fv7f*+t=zMQ9rvJk{i%=zO8Q0UJSFn$9*ijO)- z!BJ)2e(2Jp%Em(EJqaE>%EV7Rh|bM8a0;XW->Eo;*$-PlMC8C8jU*qHM3^WCXmc4X zUf@dCXeSksd^3$PJJ-G@nX4lAiOeHzGFQW?+{pL_Q&k3Uq6mJ7*;I>GrEi_y?WJR{}g41Gd9JQ~7R)k2@L z%|5wF41LDZa1*x-!#ec&TgcmbFY+SLbs_S$;tzIOkHNqQt+S7ZAi4vBHonlS_IOMJ zxm=!y_S@`%ww*EihhDRJ!`gNm=84ejqSKc5w4pa_-qf}ojqwwDQ*NBw9uIGY4%l-k zKZ>QlB{%MEms00#IrZA|e-WW~?0V{4gfSU<*Iq$-2gYmYpuLv#b1e5gdp+qami4}U z4rvFYG4wb4BGL>f8v4M#l=LgK^Pzne>6d8#kbNELSLvURY)-tn400Iy)YN|`bv`rn zBdqi1_BQCi^$*I~@H;d(;JZ%fMmh3%T)=m$9DgmxC*^pV9M6*@pQ;6X`{nqa92p!g z;A8O0fbVmmyTIWw&hbv@CHpy)DYu8ASLFGG73V{N&=>Y7X!)$xXR%pd+S{QP@KHJ7 zH1QbFqPxl!rVV7ukcqdD0pBcF^V+1QO^Pg%ZvaGjvt@z~27J6Haw8$~7A~0J zwIp`#t56JK1$!PBDVU;^!i`)4?uwoN0K`(GuRuh2fEh0H13pF&40puhkbC5FxFymX z$*vMD2Yh~{N&X5d$$_y1BaH5D4#|wro&{;tSm)D)fRD8b_!z`cjPNcXa)>1*b48?d z8ipdHsEgw7sVG$*#44qq>4Pf{IiXp1DNI9K8k_OOgv zqs_qqouRG{7wBm^GTP-JqlgPvXji)0T(lcItd+^9{mdWeOQ~GTr|BG~c&Dq#b-uVS z@~)}WOAxd^5o08)g9o1=uv(oX9m%_>R`Xp(by-G(66Xx0%jf~ z8hkF&>J1qId}bN&@#$l$bwbV*4L&-=rAv-wkhB^hj>~9JAc?$bMWe z&BDctSr~tvuM*8VYO;$?Pipd-ZFy%?>4ft{=`tK!6{26lw}avy*~tS-h>%4ke+&rt z?#3~CKMuhYpk5N5drAk)f`36jgiSOcqto`AHv5b ztnf0{paAklE8K7hbnj3j<)?H)xy8;JdQ?K5A(Tx=x^VK3poCc+M{(h`AWU6~B-wfd<{AWJ}YTmjG7 zx6y$80QgSJSFQlhdx1{;Zkl}?rHL~!r0v_*K`U_!YHKni7@^vbFw8eVomWAb+iL9g z=3WWQ>T-^Xy6~?rOCj%a3y6zJ>;%Ez3w7NDBJeejTk<(926e~p3MPV>3!?i15UW8P z?b&2`Lf>P2^WV(&IEbz1u-lv0bw*q$srfk8dRBAeigol$EaKZdW0Nwd!`GW-h!#B`h0x(SPTni;H?;2-)*wI6?R=c6;-NuC8lmj0@1AZn7Q^k)J9tNkJ;#uj?%v!5I zha`hy4w%baE3LcKT51r`dF+nAN{Web$*dBOkvTV*@;=vecFL5rL39n0d7iXJqf;?5 zO&G?t$i9u)PqmJdWVe{OLuEFJR} zWNaUOV3%3Nahp=6bL_7NEz@=SUcZZs^HBpxWniMsFb7BTAOf zp7?s$42<(RFkT}oC!yHP2$<9E!rn+LA+y-BFX{$nCYXUh>u7Mj`29-zD&C^5q*4tc zabC?~cNw@ov!KNRKQW(8n1Wu_hV)s0lrz!L`H~``F8eHo>`KU1s0=;Vrvb8^ke!#N zw*fNt=&wXJRZhJM^gT-OZkiTg5zNYSifRw1ncEK82AqBGYSxv$RF|5tr_A}N=KOnF z&Obu-I4TlHqqT&>7a;opGT5;Ds?h2KSIDe$oNA)q`t(zaTy#L&yUEgO$|zigpFU31 zT_?$5TTdMA&3)0F9t+XEkCJ*U;GXD@(&O)dHT@~MItAVS6m}@s-bK8Y zJkFtUBG_K|D7R%l!6G(*?Sn)s19RrrQpqWHG3w&|#4fk`-~<=9B~a?o_EhP|-1tt<`ELng=7maHH8W=Q73s5#Y zJx*v28s8%RXL_{HHtEqmb5nM3HBOa*MXDR^v%MSbGcP^bX9v}l$fO<9qkSeM-f5>) zTu-b5Q!ziW>MOMSW;ct(*~M@5&F0_Xx(bnt+mmJyH@l^RY--5Q%SW_j$jxRkKhuL= zHZzZ#O1CpuNY7Md$o9gmO{A$A@6t;f*StB!X%^8I zd^5%r5XVUDXPR=^2qg4p#L~Xmn@A5ZrXlAbImU3fvPJCaZ74~F^h}EqT7rz$;N~?k zVL*>f7aGxVNf9g<(U7Dl8B!DmaWjb>(I5#taZS`rQbi_#P@GI4HNhkhCM6R{Rhk6C z>SO|lYYMC;prk6Q&3(G9QZd+3c!-T9Lj51P!sZ>RJrKWC4RcdN_ zrKWB{hUCV!dhqczBBm42r^kpa7PR0Dm2>T|P-!AtL7nss6BQjw7%1d4f@wfG;Zh?d zTq$HZfr~vvJSE&x`7Zs@v8q!i`2sxX(xlyM-(#ydxxSCAYbt7}=Ltj~&GlOj*+jbOAMp zY&A3pyRlPDGy)jllb&!-pVNWYC>L$Q5!1ArCusr)(ir zViE|hk>+F57^xs=H>4NXeB2mae#Ay~B}A}mxB0kXRX7*25_BOzno3RjAQLL>v7=4| zTE_rQ6;cj?Y^+5BI}`~kWw!+=mQvH9loT-z zQy;`(Dq7jpSX77bVF;vY6%B7_Sc*S6NhGDBrhm^$QDxJz|B$7oHHdprSY%?C6oJx; z7HI%3{CQCS_=z!!a5M;Qw`%jK?^ye!h@uwtXsy6wf^U$RoC^aY!-8@ zS&TpVu=~FpyL#Tjx~1BE{}U0c=P_KnhCgk>$NZPnG}hNFowt19LWD?Ubf~Ik@u3i< zbo3YmT*d!z8rL*HV^zbv21Z<$h=m#@tqDQbnwnPDG@4*)n0IRyAr4$JQrIe7eN04C z23wnlA1^Wn)bgqoj3Kx}!jIvCWTF;xr14w)c(iLGET+u3Q8xdT5Y`LQ&Vmt>Cr=zb ze3ArRuc=N{A@pA|LN$w%D7N^(Ki#)vuXb~$CZ{~er{++H%xL3BH1oqF`@=5wY1QBCQRWpM7AD*5X6=S5KNwX7!B#+ z(Hfd@rx;)9$ue%v=ur}j8!x92L(@Xo(&bC)bd=+YHhR)j##v`HPu2J@Mv~^t!5=!h z(W8?meOfpRi{U9-hK>H8iWA*DG&I8?rnNEoe|~y+M*n#dAn=6I)5cC7g}Jb)Y}~}r zT)FXlONNS8RbKuXy$+uo5fwA{xp8JqsOTRI5Pf(|=>JwUXv8?JsYewt#Uv}A3~(qj zbJ|=c@fi^uva-np*_KG#46u!!#=2jw=2gpAV$yD8JWoXMt6D$@qyi<+6B9BhNB%3} zos+?wB}=jgB-kz8M(cI;_=yoiV#@l)9X0snpQEJkyq{BO>l31jyw@w&s+T=rMQ2 zFzy5l;2LwS)<}w+VEGSziDQefxTaLb50ya3RSW)wK+R@(z?R^o;h8W4kwvitLSP4a=(&1-f&@#Bq}tU>2Uk8cfc^!^7TJvxk+> zET^7mtd>U#MahR4E9;lkFFzIG++kD(>kkE9PF}o@7mlvYQ`y)L?gvVuIc_VH9cY-CSLbpwuT|U}c zF|e;*t5(#lz%8)}b-fagXBO4tHjXP8ES-lhbMaTN9#>D)=G_a zh?#AI6EB7Ds#oA*b%gN9l37Be^ViKk94wiQZoYhE<5h}I(1%Fck&QL0mM_6d|KACY z%pQds{++LT@Y$ga&c@(5fph)m`Of!V(9$N~1&qkdKiuN* z%#u9UAdv40hG*uU9oXRC=sU-IF75oU#aKRUCN8XNYOE|o2*lwPClsP5Di;(=MByJ+ zJVMCef2=I_bl{}lVzeysNGeAt?1$7^7GtLDe^7`j{Np0hl+p`0>;(9Mat_z~;o^?0 zn_eotCl%si?*~e3uJgmCwa`0480G)_!XEQ&Npky7#61ott&#BQt4Z@dka3T@Lt2~E z@mW2RG>H!KjZ6M|z-%4l+oD-6i}dvENO6;CKegeVOWNkeH(Q$5FC_K3JE;?rcaZ#P zp4mEBLqVkK*g<}%!1tAA>tKxmag58NeiK3S*Cb|ZS>K48An3&(Ihxm(vvX?m;%nB; z>zgV1hmtCp7T-y;j%I6FUd&Ap^de|b^YT)jrh*q=oo-&9iOc*>(n_|)cgJj_**eH; z@R2Ty_E&=D&sEIUvOavjpW3|mIaBlcv`!_0^5Vw_&FhnXwPJd^7W(a5*yCI6)aE^G z{P4YYYV%r&6a&g@b#B3TZNaBT3KP8Yh2xZpH*MsY^j=cGRIl_-DNFvAe9so?h1Q}p z3GFns;McX_f82t<89dKQ@lWRTDBK?ULeCj?WOJ4jMe<=|YPXiHC_6p^Bc6P*%T}~zr!vPz9yKA=N%};h{hwJ9>aP#BL z@Cfs}7V?}si7bbDv`hRE5tHaoiO|1J<=d3!IqJnl@IE5ywVQ~a;66gkG3O}LpVIU_ zL`=1RA?lRcvlSR_s3(8+6CQ1TvBsFr6UpOJ$@a27R}f2$UB+OhJ;r)|fjAETh6FNZ z@~1@9=S$%H@i<`X=}yTghu3Ykw~z?CFd_UjBHBwohEe!J;t9s@;YpUYo;>t_s(3qb z6#fCG{FB7Vmh~*L-27t93#Y#ip7oLX0i}MJqFF!shjSLwdBS^f;gRp5Lhg`vjvZpA++KCAee z;`@qUD0+OxUWQ_>VmHNpipMLSpg2phMzK-x48@BSuU7np;;$7SRD4SDdBwLCKUVxg z(Sx~;?QW%*r^q>w@?#W7C{9+Kt5~PFO7U#POB8QYyi0M9;>(H$6~9pQ;e=zk9Tj^i z^6z+*k5;TuoTs={agE}+ikB*0rzkO#VdpO8A6ERMBELVwa^6z>Sn)eW&Z$gqqu52U zP?2A5WO|w6RK=4OS1F#Q_+!Ou6mL=7srZ26lZwwOzOMM8;@64+$CRI?*h#UcqQqE6 z{UpXRaGuK7D4wf$sUklL!1mm($ZwUCe^gOoE`#5%{NEJ6Rt)0WOZ^(H)d&%|F9!UjAh`n%D<`jp<)OVJ@wisc2PW8akb*visva_rnp7% zHpSm4KBD+1#TOOdR{TU!Vk)Ej2-X}@55=yE$10X7E>vt(T&H+}BELIEJ9jBQr1(e0 z7ZfFyGW7WEbn4rE>vt(T&H+};uVTFD&C>^Tg68epHX~8@u1@8ik{Z$SH*UU67v}K z8m9aX#RnAsp!mF^)5h4zQA{X4sJLJ8i*`oOi^ovXpNicS2P%$HoTa!@@hZie6rWUl zP4VxF*?Go(k>YH{b&5Yxd_eI@#b*`&ruda&4esq&-$un76(3XlNHNjT==D_`syI%O ze_o-TO2t1beyI4hVn!#UCoznn-&6U4iX#*yb}`aVRDP-Asfs^S+^Tq|;uA!y8DApy zv#bM(A1HpI=p>9@T(O;EZz9U=N5mXAfe1Tu6z6Gro${wDZcsd5(=Sv0DkALcRD4wN z1;q~(J)MnSf#L|oxr#N4^@n{`8Sn+SNTtr z_jNJ$Gl{U9t$YXNdnpbiqWt3&Co9$}HYi@F_#4IN6u(ex)799K*u=0`u6(uPYQ;;4 zX!kWl)O9D3?N<5klz&wDJ<9J>{#E7QRQ?0yzfpAZjlB#a?%xy27b^BAqTCY{D-~BN zp0BuF@e##?ir*<_bu)Gf6o)AC^INpPoQQU=A@;PaO+>Wwdc~VH{a4EWTKNZ*e^~ja zm48X`H6rYNqu9B-;Y)}p?}ftoX9x7m682n|#9*=O`{wJWKH^#XA+BQ2bCa zv%uKtp=e>_dF)ffa#eVoN`mry1?iZcgoj%NkzEk35=4^(hbj(NoS-;aafad?#ifc3 zil-``rg*X9CPjJfg8FP${uhed6n7}@QoK)bx8h@pe^7iz@maQdFBp7kNB4eeJm)O$4 zM&(y2p00SN;(3Y}DPE>{rJ_7Hf}Iu^o0OO5XW;KpUY?_Y=a;ZJPyb$#k)O!#QT(goi;DbI z7Slgc{8I5-MX%SS%kwwr@mpHd@1U5kSfE&>*k5s|;&8>WiW3!QD9%x=RIE{4t|-s# zQ0`jg<@p`>^OV0x@iN6L75T9*)|W9Mi2TAX@oq(a_l5k!iu@WF`R5ho`5yQK%FA;; z@Q0L_=Y8P6QC^<=fe&CpqaAtv2aGE(&jG>bDc@D`XvIQBc|Hie!O9O+oTyl?D9;O_ zH&^*8#YKwsit-#0dTW(mr?^p(afMjlO^TN*@|$OrZ&m!2B0sfB`EL~&Z;Jfy6`xRi zPVpthHx=Je{7~@|#jh2=Qw(5^qTR4!T=6JHes+!N{H7YX(C_?m5ZP{At z(FV7pvD3%@Om8-HT9&&SGIxVpWTW5lXxb_j4(~CMkv^w?sKcG*O~y`pZhh&G^v$i` zk01oyaF!-gkNMs5Tx4C+%PpQ`#vIGVP)wHl6zKGJ{2Kgo*xk*wcQXX(_DW&zD#&P$ zagc@X7+$I{mWIL$G`p_0Px7@KU$}K%H)gO3d zm@M~dE!S-a*MsT5uW{`yYhkY(_U?uqwgZpylJ)?crA)V#6Rz2p6pg`Jo+p!(?(obu*K5w+JmkWEj$VYobmP>nF$J3sh z?}Z;|M-QWyY{yI54%*`8wxb*L(#Jt@T01zWxaFRp*0w13 z`ejgn16Xcn>~4E6Zeg!vP-^a?N!K3lSJM4={VHRN_PVCoyS|0J)v#AiL%O;4c)ycw zZx8IPhYsy^!|v9P_dRYNh^@zAZ!!~gbJKXAly0vaH~Q=j+T$GW+Iv9lQO>Q+5X-tZ z%g{X19``3&=sh#ZjC<;EbM>BSQNP!rm%h36d#i=so6vhaP0?-A>(EPY$7-~L{$qVH zB$Dm;1bP@A4X%mXaY5z0v?OLMEf}~v(VeS4CkCxwD(+e;U?y|hK;o98V?AqP!8pbej z`}XbYy|qqlZW~PBNehF6tpxM8v{SMxT6UDwxOB(Rd#V;+8}#kF z2{{t29ONjG@@_@E^(@qp^|KQxU#8P+_v#&I*S-*pqE!DrtBw)m=gTpXY+b7U)E~K+ zE!dCN`mDBlDtDOJ_1D95S>icQ(sOOmj;>3t3Hbk#eQ3S3#e=q_`=ex+Qx+|YAF(aF zTeRgL>9%aQv#XzJ`S+dzdc?VZ0(?~V;CYL8e^P4M;Bjr*VV}8uyDVqfJ+j5%*Ytj! zu=wg=VBZak`ySeDwci`(aSz4@M%x>UOMB()UDr8LHu=!^{pdBjqw}Ki1v#rY7hX55 zW$$t1nKHI--@4w}<)3icsNCAz9n=jKJNJiJrw4gn9;se-$BY-99{!gC6Y>(Ljk3P6 ziyOxHCWHpl1}vb34P$bUm+LBSJZDOF`OB<)+TSoD^n$5bkFrwJw>#_sAH9v57nk5X zNR5|~9i3j*uJgCs&*hf2+8>%=U&0b%_fRvqzpl*QCT%PDe2;Zis5rF!q%VEn@Y*Na z250>sl*t~YmR%g#dv@30c@Wo#<7> zKv{;Mzbvrh?t7l<+Fx?@OUu=IN3oP})Q$pE-$CQ|8ZVXYzp0jILn7^LxT)42)Vt_TTqb!Rvbub&ZQgY{J@6!#f*anfh1>@AmuOIrJ0j z!4KfCL)dp?e+YXu_W9U(sVc`l5&N;a1FT=crzN`(-D5&{+-al2C#*qlo-TDNXqz{H ze)_ieS9|>vtS+aGYBwKa0eRd#6Eru@BUWu{{;=v&bZI)BrqgK`ZFBctGJl6N!MoKN z7eN`;Wot(Hx>9b=55J5c>%rD2hdZ~et#+($z&MJQjl0vq*t@BA!ac3_*DbMne6>e% z7JRm+W1``H(`z?y{C}T&&%#CU)g~ZP9J4Ts9K!;>H1ano`SO9zQ(fpm-#-L=yCIQ z#kI=Rplb2RL#5uT1y+|t+04$_QYy}dJH55-cQ7r6wA$L$J4V*t`PrFg*n4`__QK3P z^3Zzb>FSr!yT8)2ALm;CH!9t-M`FYoo24ILnY3DRXVu~t1HOH3{#N@FWz##mGm%yB zG0yiHY5c(#3UsbXEHEW>U63r{)Ad!RgsEzO>keX8RMU9J6A*P9lwTo39c{n0H^c3{D}&OOU|Nt**@R>6!tRf~(tNj2ai1D zgRbe5b4L`Hjd*6TXfpT4g1&oVFP&A;agYC{GYk6feFK(lZ{hy43)=44P|!ye z^lPeJX8b!JeViz}Vadot3AK^SUjNjZN}o?pS}Xndn$Gq%tLyw~wO3tykA1D(-wRLb z7(pEuX&tTZV?RE_NmM76(ue1a82U_NX(O%Kn^K*56UHM=RSUfP*=GB)=id&Fty;W#6#LeUGMNF-z61-_?O0B_bHy()zct93 zB%`c#*^7SrFD$<#+#%_{hGkFP9i|24tbzT2=qTaUGo zm49@8X#cgrph&pRwDR#zdw+-gM471>%igx0i{Gi(r(>UqozJb-Vc&%IUx@|&HQ3+7 z{yuj3mqz*Yit@=*N6*8*^_vU$F`y%U>_C?F*3_vJ6IDy=`1zWqrlm?zh_9O9s~i+6 zH3^>(sj6(KNu;ILH>J|27M*~voh0~o@Vfd%R?{;4rJIbU3Hr%0e9X_Jxt}n@f7g?l z5P4U!46k34C`SePMXJjBHP+;jQ_B;zHA@>%qvcgi4N6W!5s9fQDwj1RE%1-z_@uQp%2A$v4^#~PI8CEGJ#932_5nBE8l`}5|ok~__NnePc*$F((d`|c;&<;pMk!bkLqd-4-8ziyt<)}^I57f!Aysx2Q{-5$? zyK^gQ6$|X=A1O@U*QsNLKY$?c25FzM^XA>49b@O+ji3>eyb}uWUrsw-zB%$=AtYZa z_^%W)8UuNikbLFkzgoy@dg>Y>U!?R}A)i7G{hNj4YiIw@gnWeLbwcjI%HO|5$Olor z|9T-Sne7H4e}szoZxr&c^xsWF@*Ru+=AN(<`3}{I25oyDnCL@jdC+4Y4Ve|)57!61 z_MkRsZ}c_{x1i5vU{{0&+n<5_zhER3=PQu0;Aec>9sUfx9{hX_GFaiCqln-aouTgw zkHMe{en~@4_(ixr_*FL+V0n*0F8@|OA&T(zk`o+bzW^rsM+~OmSbGC4ML%La#tDOf zpd1zcUmbu}#?>g!%P+S3@BEA=yl9{kuswY99bF2&fY;MXnzEKX?epBk+Ti3yb^Lb~ zK+72jUq_vrXM+ykjv70+NQN*qovly6hA$jo&2FVn&~iqw_20wZa_UfKj&m8`TZa#_ z=*wTm5rOqkE$0fh&==;J?_Bi;Q^Wj&hx0QInP|8c{pMUp9R&X#%_iK-_ubAdOm)`2 zOPe>Nn$C~j=Y3N6EEMaUZoJ7Kh&$_^p-s!npzr<%KV{yP7zoKPq4nP4)jtx&?t@Z(nIiscPfsEbz` z6rGOhgt`jjWY*U#vO@X7M58>LLfwQxn@+-b@jr4A?cT(?hiX0i159RRBeK+aE`nhz z%15=K#h#y_7*y>vw9Ef{{yir0YdCvisKCp2$e9%tR;Y)!2jo`fBrDWY$ehecbyldC z&;^!HK0ydp`xGfqUGX=Dq;^DEqStB{E z!{c^>^o5pHuC~JCDTkjg;Pmhm|5M{^!XXjadq4Aj2**dB*@fy_;RGBI*~gYS;eN0m zdHzGlqv0}+&6oJUv{-l|`Y7^hPtZBx^Pm}dgF3n4Fnk|*YZ~NvR;y8CE&tPxv8a`B z$&kpqKZa$*xrEBWIZ&}e4TvbuXVAXTBE*v?<%C~g`Uj+=;Z8L7A?a9n5(mn z!g1J(e8yki=Z5*a>B#2`am)>!f-tqz&I>KJB43kAg!wy$$Tu9W`Qhzs+PB?67lf}x zcSinBo!&C@MZTxJI64{LN4$0ZoPR*{KDODmM?h9$c}JoO{y$z#BWp1(3Zlo^d8loa z-ir>g#eGq_FFMQ?|3&G)XsP{6loE~7fzjc@#G)snY0;53f6bi}Eg&=6ZiCLrjq-=y z(Xne0h5ScM{85WKt9|%b-3mK)6sO-K-6YPbejEl*5+FF)^vL#T7y{I zm zjaGD?kO>*3(MqwOA7!^ht8Dg5L6rRxt+v@Q1>)3bjX1TpI5oOZoLU^^aELCl&p-nQ zL|3uOb@oOuaCbf0?%(5Jv}br=**hPq{y*oE{}7(=mZ5_FeFfx?MGtttC;xm2`D@63 z$T{w%vEU<%kTsUE#d84|sZ7T89`-Pzy&+S^&pqOxD5s>1+dWsJd?(r$$BgYBUQjW` zbKdbExSYniqwtBDFWDEv>(cj`FQ@f==BsIapZS{2a5tv!GhY`b7QGb1Df58c87Vn3 z5HjDkCxbD4pLx(e9ZX*I6f`39L;Ef;iD&|i$^1x|{OG-?XXdBE6hzNNJ2F2PrgxP8 zM#}ViUO=AW=s9p;rsMez%z)@_KbWwmH`-Am-IkdttsWx7Dl_IOM@ngQGOcBK)_@rm zJs-`@Y~#5M%vh@xK8a-c-?|DVMEary6Eiz`u1Bq;3o{cQ&d*k6y_MO;!vW;Wtg$k? z3h7`P&de7wib0s!O~@DqVPGAyyz2bcn@I`(O<)GW-re! z6qPUID6`PRlhcf_%p&R3-lloQ(!Ap6cv|b{;iw!Cy@xIt=;5dw5N*P!$Q&e0N%TxI zCBh7ezQ%HfdN|vZMvIs-+;gwE8Cx&Z}?J$(Hx$$l(9%TGYqs z0j+B1quWuHFrs-`&L?f8y<Ad(d zNCNR3)FT-Gg!PY4!&w%JPr-Q=jvvLVRs38yH5&gA`Wf-T9DVVHs8Fl;92{fuw_rIQ z?}ehW;)8L_j<1D*_&czZh~EMGow3e53$}wDAPV>{Cb=2<0UwW9U*mvK*WQgV)T-<% zq6JFv88vxP7GErg3S8`d>mW$4n*E(ks4or z0xUQl^ph|CbPWq>T4KfjxEK^%{9BB!fRAFS==mUWSYvY_OS|ZpfRBH&3;5W`);#e3 ztIdx=*pTv%b-{8l&N4VW8u*CkjGR7!PdHuRz7F3p4Sc#0q)%4YfzMbBR%QGzRp9fx zpr1R4WIMUr%{UQ*q^&RTsvSam+BM*tZGrvvPGo6+H*52n{RC zTcPi)+-f%KOM5xg0zN7Se4L{L5)9J$Eu7(G&3gfInd!3Tvzx8(g|LxTc{xa*8ENlA zBZmj%w@G$}(S-sl8;0WhLDE~$AbDw0DM$&&#=-h2dn z#UKMd-ZKPzM#5Vf=U9lH=(!gILRjIQ$BQ^l6s2%u^CJwL==n<_mU3?&MV?fTx~3@{T3o%aA#ci|c@o zx!d|Oe&Kl$3UW?n+~U~@VLL=)u`;$AIllO9W!&mvdF`ret&D9Rc5}O$Dl6kQ&xObd zOI$t%d~bsZ_K^Y(VjxOgxn#_teWZU3$fg%tQ^*5^d4QnF9|S3xxPUZcL)s>-lmV~_ z7TkGk_$Uqd&UQ0$9cnU4o}@Z-?sIjx zJk4RZ%1|}h91+mj@9J>Xnx-Q|Tn;jHxSE5u4@%++u4IiJ*2?75&h6*waDkhqbC}`` zSCNZfabFHE?kMIA2y)NCbdlM?b2I3Si_o=*9gRNB7z94x+b+l7$?n=A89*D~AhSpAN54OZ|G5l(@xgTJSNj&+sCSiwh`t79Xc)CM1; zY9}t|gO9T?IFoJ&_}Dn-W%Rle-1ZS@c?cW4i^I+eA>$KAL5OAs>6Rz|2*#U5*F9zW zky*Si)9gMD1GwN-K8Ebn8bd0$U&!m&tk>kxUBLG(^qtvoSv2@^JrqrGuSjvS;tsx^ z3$ZVp!}8u_Td)lI6-zuY6bS(zb7l0GDfbMJkyBva30BxU!9=G+KR8X68CJAA&c5Ju zSwrB`I2gk_IK#exc@QcVd1l#fF%K8k!8x)Vv7%2>>qJTLp)eZF4YBLz+7B@2Ahx`Fiy0LHlMaHVV3CAtkj=mu@sB;qUAlpbN*egU0tL$^pPWuXzDbbdh5P$p%k0D7V^BX12 zf3@Zh__`xg@Cp>txgY9b-(gIh>YBPEY3h!Ysb7gwK0icc?-06cH+*6Z(aJr{$QJX_ zbN4@@_w7rrhREjO=(=h&=@NAh%j`Y^jkj;4#NG>y0``>Qd+;OX_Rp!+L-O6sD}&YZ z4s?b6jj1KS_SI`Y3;D)#D{}VY%^7IkoOR8gK_>3y*zU#v0Ctu)NV1^YDHz7|I5`qONh?6#oEvQHObw}vX{ud{D}LjDF;;|y5?cSB?@d%ckP z>)D<&?OUJ%k689uHXXup&bC=jx5bvd!3;#iA4fFWZ>9m8cs%gvG@nNIM*$E z^Q$mbi0)rZf?Lr7W$Y=)&5kba&wQPYS!iGwBV!5P^Yy(HGbvIyH+P1#-_` zDR7QyOF7!&XPGxA%QSOmjM z2vlF1(J`EkWb4Eh*PSD2!Wu=3JjI6gB8%;0?Dpp238)T%h_4rijRCLf^B8oONywSzL#?qsO#(%-1-x>M-dvr)(4`x? z!jLuebd=1E6TH3omINw&F+>fh%y7(PGLehqentgDgZl#^TqH49KbSJCkFUlQJ z8q^(Xr%DMG5Yw@IuWDIi=JLY2-ff#H?@N@&DPcWtp1*?Kv2x`Xt!|isCUQn}Fn0Yo zAJ8ODZ>;f)$mcdGAF|EbBxfU}_NWq+>2c1+Ez9LdWPZ72iD4avjALxL$ll@BME?J@ z`HQZo30B@lJ_Tiu0~Wukp2`zMU6pXn}Pdx9^ND+>|*(g!H(aRfxLII{~jj$vIp#MXv%|njz1Y~HZ0FWaY$>Fst&=h z5Qn^vHqs$$;Uvr?)Q3RmcZaH*PXJd(+$tg;nI=ahbq$>doD>pxN%Kas-PVg#0*qp~|xhI~VQ zsE5Ib0v*q_4`^-!d9b zNYLN>I0Y=x_~tptz@=Ky9z+>0Qh6wG5dEswgDdefr!Et5HceWHKC?5Di!Ps-*Z>o9 z>Bx{3?-KN!HK`TX=vi|202ViCEbI^3blpK~?ah~_Uv)5bYt=d~!E z7X>LjPc-@C5o^+%OlTG)HO=|Ak(ykf7RUmXFFGgl`*n6d`*I|iK{h$ckzXoVJ)2gP zfwTI-A(ha8r!hg6n^|Wpy@Ww$)q*Ior`iLsX0eZBZ=8-%+#328&C1Cbwt_5uDA)Vk z*kAVMb=@(^ybe(e&KmXsh(Zv@=Td=5lr%7jI@_4U%fSpJjs6Cb(jZ*-XNXI)L3~T1 zBZzh=U9Jb5sM|o9RpNl;$mS&6S7f@fl9Yu=*@R|{R&5N`LG_T`B26>HtE?vkPeZUc zr8I=~c>^-Ds0oqn&7UXQi*5UQ=<%LnvAL(f7+Wg016J=7*pK6F`)$=2FB)B{F*lAE zVg9EuWKXo+`;`+UV^?!WGuP%F4euiOtEHjt*N?Y)>C(Gdk*pt%P~(BxhcH2WqAn&wv% zOKE;0hzTqLSBG+TH~$}c4IB5Ry{Q0Iy%4f_P#W$glwJ-=BP3JkKQ0`{Qhm8yLG|B2 zwh@WLehK0x5EV=^T*wLwpc$ zn3N?za0HBjzD_7Z3Lz_Ems({%M?J=aTqVg_b};y0$h+dHWSIk@u!WivL9oPk4li-0TjGyg<%>Y7H8@|$`7Rnxik{6X4FG>|2T^vn!)1T4w#m&=axHWhM=~CSfKs<&ToSRky z52jf*;kK4F@HkUl1I5sJ9y(>Es{DdcmL;@%3zS@}m7NSN`uGDahNm@OPSV{DPEhv9 zsp3qe45>#7r>P;Ig5a!PW}$0XrBczI+Psu8Zl&^|C6y{r_2oxWuW+3-P_-^UlGYqo zYZ$cNL(#X2mdq(-{A~|M-Ti4YexZl+&R&(VFXuzXsq;XZ9v^$KDIuJ*oPN`WWU~9t zQJtbR9na}Lc*z^SCOHU3V4T~1;Y86gHJbz(*V8l8WYZwyrC^E5P_rSkAft=R7K7ko z`@B?QStDe;JZ(^bl-WWB3BWZsdi7+W_qL<`a8kI>9X3$Okh8 znP9kX6Qwe8yeku~8k|{dt)PXo$Rbd*y^^be>%sBejC?D;7fian!a0s>%;QzYHsR7M z>!YcVL9s&4QeG}_Vcm@jx!pf`JI70vz4=xs@@BEWJdnDRWnq`Hu1u9Rn98X;t8!SI z96R^Kr=K$A{zT48=W7OE^G4rOz9_`aCwj>JKwNZ@dB z9a|QLfMc&4v{fkH;Mg0iGM-A9sAcS(pfWVMjNafirZSax5Qd@1XbbtQjHe>F;$MLV zo(nCx;yc!~TKa0vsgRhZ#k3tqK~Q^ZQV{U5t&<;Tx39KuM0TS%eWiof`<*%d%)5jc z-(tn>yzk|6H4d^I`oTPMo$)<%oosoB%9$)j9!Aa>8iMp)`Rya;i&O@aYvxa*xIX+v zI+)2NIN*Xh3=rha^~}pq_t;ApLCPB_Ntd^h*34X7ymOA>5aW$c&I2IiV9ktUXvgID zfLAa@4)W%UW?-F$XRV>9M%rAmOI6GvX(flNP;2HPwC|{n%*XY)mMp*1J!vO|TpVkm z{18R#X_m!>at^P8){J-#gh5#}aN09fky=dW2XSNX@H943zQ(a;>_(%UxR384cs3g+ z&g6x?O%z^KJyqi?-C=n$;FrgJ0Xc zi01Hdv^A^I56L{6SE3v~f3{|=Mx_ECFHhwh{u0BQ!SAa(v&FNV!qq!#kmkH2?dDu- zq_f(?8`<~SJt*M;PT)B==X1C@`)=FFEIV#@%gl~=GuvlQZxgp;aE2!z-v=KS@uG&_ z)|NN(*vN5_aX4vxD#tMJw~|kY2MA0GcDD#lw(ZS~M3{lEr$ZT**D<+Ea2|xgsxh*W zq_UsNQBC!a%VuguHkA2TDN~K8ycKGsHZih&wv;9Y;`r%VW*(fM#jK_lXz5Y*(QU_N z%iD6lRPrb+53Sa=ZG>$)Ls*0YbG4}`2mRY7&2YO^4e+a!R5h{4pmCb+p!(A6j;b%7 z>7@F?B$72lUw1Bqv)~;+>z9z6UHqnTQirY#WRyR^_)H|-z_9JYbT71zZ)^OSGH|pS zkkSgkBs;H%=9QG5$-HTW_fmDS-aAz}Q?))Sh_JA@ofRm}y>f)Ky)ad#2cxGbjm2;) zP8n*EuWzb6=IfWnB47VhTbVi_jYaA)S_taO)PYD9R~mNE`DfV}*L~43B^R7!Tb|ra zBamsZ5nn!{EmMw7Gl9h8QtfNjx*^D98CydOVX|4`Fu&DTDsX(np5BH7p>%*shDT6? zEKFu248g>aRL{d$!)M@-52cQ#IRskv}KVeB+aAmo3&Ehpa;3M$|PS5QHZ;Lm-g zWr*08RyP=!o-7NE93tarMp7h$(gD(gx6b8m_ndMDooizit0$fF}WGtigewIG~H%3P4h%44Ez@grux5Hu+eQ+ zFs@5%F(HBd@Pds3f9om=X+DHRzUg9H6{*zelyc*`mk;thHQlH*iAN41ttN< zJ7;f*#`=Hq#b%UYB|pl%CGCbc4!nj8T>S_9>bp2gVg`0bunEd zqlwu~Wl3=!f-%C$$pjF|traK?D1w`F$`(>wa3g`hoGrT8WUENeRw3C+M7M%413PO{ zv4xZ|l5A;lnnG%VcctmW)s>~yfHUg|>}VNbw2)J1n`aTE1Qv=0;3!)ej^nVWxt4NH zED#aWTAb##1X7GYNtwPaCzvxWX`i{%vf(AJ<+V-;Z6T4se)s@N8+yi8@-%_ETnOm~ zYMEpHEn*6h6PU+p6l6y>ulj%6 zWZ_{ZAxOXQv&U^~I^po*sf#5V6!;T9oe-y`>rP3|bkvQDZaJYN7VNe)hrkz)&6}0d z<-d4UcXqmNbGzo0s~}LxZ=GiK>%7I)4{_XwzHJ8)4ZEAE%+yo?v)l}<%+zMOOhJ!` zbynA7nU}e)Elu~i7Ld*fG`VTIla|iP%EqyfHmM8)Yg;o3!-Xs-tTR%=dDy+ysb_2< zah;J9_|i}0pk?cbV^8cjr3makoVSEwMmh?>QxOUTRxa(to(Rz-lS+6<$Qh3U9ycUm zA9jzmA_kC+=f!;NFiBt)F?tA>2w6^GO(6x9+&rL=hd{?2J{*}WY znY~^rspXuWjiPkZ0wcvywmCSO)M@iUnzl}pBphgl8fim?Nv8QSd2hy36QmOO>aBTa z=0W#Tqrhz3CSpGsJA6y{xsXZU-U#+~lS;VDq!R8nQUd?AlGaqdUnvq%ITFo=5!4<# z3UMW+(3oYk2-QN)Ak-Nt;h>Qc`1>(rC-Ci?EtfShR*nYow^T?aoFini1vJk0EI6&* zqWMm*g%|io$bph^hO6}uMBhnC<%E9C%`(-9l6^x_F0^>DBDRwpQ}}nkd?CvT1=y)U z>?7hSZiy_0FZa@_$~S|?PBL?v51G--q%y4!0NY|hyklqF`?+@b1fC9oJDe@6S%q9#jtWR zk#z0%R=JCu-nhBQOBy$~9&UL*gl@hSCYzk)B-w-9=wxp6mb?(Vi z(@@KAKUqb?8yc3@RaLIQmzbK0nyQx+)mJa+vtVU?_0pQ670Z_|t*Wi8LrP`ivOY`e z>Q}DrQ(0f#xV)~qrgA}Dp8MGcKL3s%-GT~SnB*?4MQeV^4O1LqAKP_(peLD8bB zsv~DCV#d1qs--KdYyNQ+8kSbBSh&1#8ERn4?Nb7iRkeLkp`w*djjolVWtCO6b@l%t zYiZxeg2%L?Mavs%@QJIXX^E>5JbhLFqC$-7yi z(WoOtydlsc^t4H>u3Ln!Z5cV1;%GaTr3WoLdxFPf(bcx=h3^i zuvpV3Dvln|xtW3If5^bmVqi_uz)&^NFraxA51@+0MM(4n5&_eqA%Qu~%DCBY{~y-g z1U{`KvV)`0|Ft5Stz&-StiLymN7FyK&!Z5-K$nB zwOVPbb*7W9(zg?1Dw3409HWyQ+Sw&+jVg`FP6*m9_$9f!^+EzARVVC6*PLX0i;d zs$4U7)hKB{wyZs8&Ye=R@033DLcdi$D(zOJowDzgRaeZ}cPehJ&a|;xEo&Ycik-Wt zVxOr~*4p@UwsRwPGBRzp9gWxrl+CW%r@VZcofol3*euzI zdoMcm3cGWWJuQOIWMrgo^I5vKuITk~RCYSVxjs+LU+4|E#2av#H{cqdW$zU^TpQ#O zA70pymi{TKX6oFz)NCPtbbXXo*!xE8?nrF<3Om27Z`I=I(`MmbTURQd1uH}jZPiqZ;rM=C2T*OjlTfE`brGG#^Os(q(Cyu!|1X>VLVGiJ2sp?uNgU`y5r3q!>P@UT-J{V8-sV>Z{otTRdb zeK+0^8t;k6@J7%LQIw`z^$!j9M)>YXcLjnRQ_mPRi} z;4wyoS?g-r6pV+UVdm~G5}JM&8{V#KuFQHX9_164SOP^8Z0}r6MF(Q3z9F3(7dE|A zl#3wdx)F<4#f4V1D>j^p;>9ymYN#uPCL`Sd>q=uPw7UVkp;X#OYg<)YeNA+AdmCB` z)RM#(W zY+tQ5LES+tsJo3ds+*b`>Z%$sHuMh0x+7SV4=bmdQ3D%0`bWGYjeg^5)G=QtR`O_! zMmsYkVK^`YhrBD6W0o@g9xZclXpo6foqCbp-8#~l8ji)1s=OU<;}xG?8?dVPK;P+amjvcA>#er<@(p;lO8%*OjE~I^Q8@rU`)-FY*QlD(b*r1 z_8>#m+|slb!&+TSTeQA$89QlPU1KZzt&Z;Qle$*bRjsHTcQ-SGWWQ8u_dsHf>Ku#? zpk2i9WS~}|4#q~MwAIxbx~ZnEt}QBBIX#~*>q-s{r%+v;n^UlXu{T;eUn#09qr0(H zxAKle!n7QICxZjNt_IaTaO@mo1znJ;_O<9R==izOLe!mVPsler#8*2sBk)c zqGK3+6pM6K-59NDTZ^iKA+c}kQa$}0y-AFwz40XCW8L+&7}L8r)#x_Hj_4hN(sj^` zDWI*Yx&c#|o(!}`oB>eF@s9q+k%3NR*@-vk>Mg-8O(vQe9?^Yzm}7iZJ4VEodW^0Z zB%wxn2ucrn(3KjO*EiN>Ix|E&eVO%^7)2dx>P-4o{o!@B z+G^PNBsoE2kHYE2sl~=72-d~RG$9sL*f3k_nQN0C8RCOIG*QMHBU+f55c$sGsJwKT zw=el^mDRavAU{e*WRz!BwWvM zm6aOq7)){o9IaXhUa#$p>g-{ydVr1&cN}LX7*xUThc7m5Jy#z%7n8M~wamDpjZAS^ z0meI$rgqZvE7~dQOgB}h09YcydR;>!+{1H-!@$?o$@02ZL|UL0U4wB{#g9dI#S63t z;wg-4>CxTHlIY6Oo)L`xT&QuqqgO(#h0zUQv^6+^m=1zd2whiH0ZSb$@z|--Lt+Xw z*dQ}acYGLc0GGKLs|n=6HLgB$P@N+^kTXCrEGyQVQJg>w4SO0k)+lBP*G7?HRF~mbM)Gotozy z#w8d`Chc7Y>}2fN5j29BQAQ7o-7&M0+89s9Gg)H!#Sw5WXEJwFc5Kca4&S%FOI1g8 zdsBK1h0$_|YebAI$qr|}b#!cARnvM*nN| z95rrICu9-t*{r*mtjdOCJz5oXqTv`$3!w!UvRsG`CaIoE@C6!jc<0O}W@Sf-qiWyP zR?spreGCno%~>XbY221lo_$8^x>nWHhOLI~aqJ36pu4x3X-Fo`bOMEYFkz#fl17b8 z;nS-n)tQX(z|%?7jzJSmp}L{Iv6j0x?iyV~#Hbd|D!>AV+tgN1pE1ir_6CI}){EJ= zI}vqePN(Xs>zj<`(mt^?jnqVNb{i=j=)@*C-USbptHf#S#)C>bK=$+xb)-shI9!<= z>Pht^7?c>P+}M-YcwlMwoCTm$eOOfx`;(>J7^7k4O6+VSrM8N6{r?35-UoZEHK9MR}^hw07` z?~kW8SN6qmW;+PJA;>H3;cBZ?&w4Qm8yqU75xP(`4$AzdfnGpLOOVwQx?*AoV<#7` zqkDaN(o`6$v0~6WN4;GZ^QUdzsAQl__Zf`Brg?BGzyhYnvtCrWv;jhAqxTx?=w+K^ z$8JV+w$FrFRyakfXydrgzGi?c>mFGj<0Zo6>sVdm3qfT@6k*(z{YN z99U49^O4#WPAg(=RY~3Uv8>akHzqR1HH$!fgph8MqsA|%npUi;U1l_`u21iQWS3;> zKre4PQX^QX>z!{@Z%SnB8nxK;jy9Qf=crnyHL(!H+~XQw^#qC99%I*y=9V(W*8?ig zXLP&JBRsd#RV{7n^th|z&9FrdC@QCHm}Zb&Z>c6Bmo|CZx@MdZ;1DX>*8%Z5 zEK@CJgh?%!<18F>qZ&2#V^3Ap!}Z{(deJ+8F7t&K>LLS?7Qd#xwLY^E#0k%E9P^TF zqA|;K>m8+DL=2(#>3uFu0IxID7&TWn%W#~(nlX&Z%=8JCvxOh4Etzfyoy@LS&JsrL8wVBMH7Ax+%WG;5iIiYw zo56|AT(IZ2S1jc_Asli z{7YTo&INS@sR;h6@(WJ&pJs1k9&TN{y7|HD)~!UR-BmZY&hEUXd-D3SICnl%O+Kf3 zZNS@m#w?%*FVlb!78%$vWu;W)+FEF_CEfpmMTkb z9>9_fm>M?N=lF0X0SCLfN0)WtT)V8QWpx?CIy%c3RVEh(%CM}LD7-dibd)EBbFE>l zBZ@yef~597FM48C*isJ7gYEm_d5%48~&IZDzY;-c81G zKJ?WYJB(i|V>j~{8IL}j`trOzykD9982nlT_c5L~$5C-(?-_cbhSG z&gSBfrv}Cnm*yR#uwThPh6d?Fr!OyfhV3i!9nCsMmY$2pU!Jj-`75&@D}h#GmsOV8 zetNUt9orZge;MnTSyt@Qg1sWZ@ij6Mt}*lAM#L;0zp`W*&aaWDOD?&0n>ThPUngU- zea&1Q)?KsY?)pnJ(+ppgO`2)f40tmBr5R|3ugW0Jv}*>=we>H}B+c|y8KoIL1Bthl zai{vVtp7DCQ_jl2jyQ+)E3|WNIr(}bzh+xE8{4lVQZ5B*)=Y(sb)-3FrH#qByNcT_ zb0%XmsOxi&G4pfB?=BlJkCwh^H>XhETz1PhMs8oq>n)Q^s$+MsQFGbu8|xTs-fXxe z9;?Nfq`O%#>mDOnNv2$*jHyyU2(A!chF|;-O#yz=~0vJEZw+)x)(R; z;37(y@pp7~4#zf%bR7%PZW1>G4B}>6chIgOJRWx>LSMWV3b(WH+rDKu9Ez3U%mZiI zy#L6hg+BK-_1=-f2~a2Q@k(N=w~NEpIqm%F-(RE&cx>g4C9UrTPP5p&7uw})+-JU4nm^I?^Yvr*d7^7Av1@Y#4Mc(nWiH3Q+4 z&vOKyerOmTakhS}!l9UcyhlD>py6^hVn@p_lE=`@gCRaoYFj^6lM!IUnxpl1pCT~- zNgnx=R1=a@|E2iz>8Bv!5of0#Uoio;`i4h7-f-%2w%XSte_#DsW6F=<&xd%ov(*$g z3H_#eP>`GK3kd(@os0U8jrjhcQoYHdg5z6 z@yk5gm8Os`*+VTR9Et3C2od*T~C z@r|DNW>0?2nm^O)($C=Obhc{oq;K`eZ}r5td*ru!;?qxWiu|=6d22oVhkN85uK9Te zYaE}V%{W^>?&hYC^2k3b6A7QKq8|BC&7bL&QS}X0cG~So`{=P%hllR;7Jn|Br z_+gJco|I>ttwt}IY&^y|dVWl0nBlY4MvuIWp7`TD^d^tIO`iBI9(h|l@yC1U6Fl-x z@Wh|!k$0lz&$PD_J^Wie^vNFiCwt;g^~gWf6Ti(vpYD-&x+ne&kGwM!E=B0^me)&s zcsl{>gO8~jcZTE9Xsfe4^x2;L&i2Hg>&fq2PyBa0^!Xln=X>HW^vJu=6MvD1zStx0 zVo&@f9(k8|;<*~gI2&)H9^GCq%|yaytIIs`m#IT!EMT9t5bt)jy4=HmxoQ%AzvjQ( z%?|lLRQ$jUoq2}*hlY?}TV0`!9Th+7l^saG!^8h0PyRnrXG{9ez-g%;dH8>#E|z#k zSn4O9_$xg$S34PJtE)2ve73sQLtpQqf99cY^3XSH{R`5ex1@da*vd=q^u*t$ZgG`| za(?HbAM?@Hw&Ol|@rQlVvjg#`#vMgFW#}C7$hLoUd86c;fkiR;D-c z?P|mme}cp>)aegb-}S`*U{rim@tq2eqyGOV@x10c&eyFT@x=epL-QLHj$``QJoHc8B@lSc^e|YFmJ#+yJB98g*+K?i4A3~mcCH+>rMqb)B_^0;qlcW$26 zVoa0OR|NEpYVL=<^y40yi|V8AWgdRgyzcw?(`@FBSM$t+4ou&BW8&9&M9$olm%gRb+&h>qgWQU43gNm76Ya)%f;P=d zJxn7Wt95GkuJ)bR3hld(ObjkcZ~tkPh)2-gD(x zbLL(;REKl?-iL4Sgq!Ic8-jmS_%stwIRSWc_cJuV5~7{R-^Y>f9FHNKZsvT0Og|3Z z+~!ABpea?Ow!p zVNWa`n0_3w5_$sd-@r~p=vN~2Y@zv$7nXA#F&p(H@rxvWsl?Yx_zDR}c53EH{Dng~ zb$feH%87irex}?CB51B>SWj#RX}fL%L5K8oGtV}drde1zC*IjkI<&JL1nmP`?kCa? z|ARI_`oEHYSn|IQfp9aOZ5q-QgUbc2MiC)VQ~OG0y8ApZ%(CZ)CteVX8QVmr=~ zgx(=|8}T6Xrb4E_Tf(0p&Qa}ap3e|DwfP`y z3h_^PtDl4)B3LE3OpsFq(;Y6@A=o3B6xJ zzGdi1g8K{di_Mg~Sa7A_8o^G%LBZn%PZzvE@G`-x1$o{1G@3xaP7@-2B!;E3SKg69f;U+^lyn*|>dd`j>GK`zXwH@_T7EEb$DSS!eHEHM5^!9Ky1;K_pD z5xi9JYQftC?-zVb@L9n(1V0q?VXeXZ_7LO;b4kw^tQJfNeoOEy!5<6WBzU*r?*#uW z_^RN$f}acK1WkVVg8ae{^WR5shG3Z>Kg`Ye#e(&MYXrLl6N3CuE&0zD{GQ-X1a}JF zBlxi3Uj$zh{I}ref}tEEw^(pL!MTD<1RDg`3G(Bp)F&ypRgmAGXZTMA{~`FXpg-5d z7YgnpI7@J$V4Yx#U{tVQaI@g)g5MSVk>Cx2cM3iz_=Mndf^P_ZD98&6)IU$KSa7;v zh2SE=6@u#p`vo@%ULbgx;5CA`3En5jkE$`>rv+aVd{>ZPJY{?k3j*Qw<3yz9;yJ;OByVteu%ZJ_n_- zKyXh%e!_|IQw2)|`IS+I&l5aEaH-%j!3IHoAAjm2dI|K&= zHw$hPyg=}B!D|I?7rbBaQNd>f|1J1G!9;=4>sx|n32qm>L-1FEj|mPGnsnz0UOK_h zKNY-L@FBrx1pgtJjRhj@K2vbM;I{>TD0sc#9fH3Sd`$3J!Pf=f6Z~8-w5Q2uhTuHG zC4wsj+XdGPZV=okc(UO41b;60xZtyb?+N}-Fdt_8X>=Yal+$wms z;C8{Q1aB4mrQq)cpAmdp@IQiqVx!M^!H8g~;30y`1=|EK5&VhZ4T4V!zAQK%3x1Y& zw%}2MCkpNm+$s1+!B+*}5&TSW)+8fuonS)nM!`FYSkpXC#G%LQ68>)@##*(vNgpC2 zzCh>$gsv63iHNq`E8znYzKICioiE`ROZX0aBjHHbD6$4lEKJ`XxF zzr6(`M8wY}g1?eDAKyoj_z?*|o_MHI7fSdgLhlf~R`8d^DtwQYhwi8z?b+g3(Qt&as7X)7= zg70%8Hlc;st5c6jg3|;`h=@N}=*2=e3mzrmBgDh;oe7~Y5WH0IN{PQ+=z9f!EBJef ze@5sRgnmcp4}=azOg`fTD+H^FD1QTSy;4UA#)-W+FCe0PCkuU^(BBpM8Y0r)LL5-) zexV;BBHh!1&rA5m>X(q3;s<0pdgW0tgZO&k5#F1r0gH#FKEoLWG?8623&}TA>?-<|l5**CF8>giZ*( zMd&jHw+mh_@mC9dgV1*f{R^RgE%d`eKSlfvK4DFSo^J~(j18nCf-?jc3$_X-1-~u$ z1HqdF?-aaW@L|Ch1ph8Lc{=igy`~Yj;r;=^I>93(zK3|WQYR5%r)?5`KJk2fFYyf*S-!1WzKOJUR39b-q6+BLGtKfx#KM=fI@YjNG3ce>8z+A@i z%o1EBxIr)_c!uB&g0~AkEBKCJ&P*e3oZ#MqRe~!86N29pyiV|5!9NPVE|@#Z$gL2p z6cJX&y*;N^l32tF&|H5ct`_<*!SzI}hr0zg2o4FJD0qtC1w^dz zF!XD@OmK(bErNFl-XnOwAew+q_qgB-g0Bd^DfqVF$AX^<;u4cyU+eRI%yC6RPZXRb z$Zs-n9lk)2_luIQ62|h0Pq~I%puM6ty9q82mAfr984 z+*43r|3LT@q4jkT(6fcE5L_ZyBe+tqQSd0i4#5Nw`zL+f1bDpACkdV@sIQ|S{vx5b z3-UforoT~8Uta-zm(ULg{#NkMf`1i!S@3Uy?+Csx$gz|11A;|@ydRU{5y9z#3y9d~ z;X~vas|4!=n*>`04;MUIFd>){JYMi5!7~N*bspq%kz2epwv5p9|`_fFelr@ zhXsoSCkpE8S4clw=tGIaN-YswCb&|tRZxE<3w%cl-6?pC;Gp0p!4m{e6Ffuke8GzZ ze=2yL;LU=!3*IAmzu+T+j|=`q@L5599SwT^UFiQ1vH$*`pg(Bnpx_>Y;|2E<)YsLJ zu0rT}f`2hTu7Z-xa(>@LIv23En1nr{DvE zzZHBz@D;%~1>Y9@K=2d6+#I8SzTlpMlLTi9mI*EpJVbD%V58s~!NUcQ5gZg85!@`O zukXPgrwM(w;CBSSCwQsgPXwg$ZqyIAPSg3|;K5IjimP{C@!WrC{(4-;G~c%z$C(By_9b;etmCCInN0#|xe$c)H+Of)@#H7rajJM#0+!?-JD4 zO`*qwLO&_^7r_?1!5xBE3SKXGli25L4BPTawiDAx8S~l`uZ&5=L&tWV5OkGE{phPp`(Ibg2RIPIxP6M z34NyE`GOY-{zUL=x`391=_lo+5a<;JJbq2<{NPQt(zHHplupGw@!a zeG?!+Ae(hTP9sj`l+u`@pqC?BmuGu}|tFE;si%b6rUQ&Xah^U_v1h*1VPp1iBX~X$^>&fq zb|UKUGQk~0)Z>+c*AP*kHwf+|qF!$kypsrf-7R<@5%v6_;6p^z_wNOtAY#Aul;G1u z)c+{xkte_h-eRQ3BF52yZAux6C&EjXM(yuH=+JmpFmx&XfL?6Sht%3BHE4q zXfm*vG}_N(!3YsXnl4yEM0?_W*u)AV+7<7gC-VMzwlChFO=rzO=NYK~ONprW8;GdyKN3;T`rHHcJCFN*)awWl^|_shder9% zsJ~y4M!o%&SOt6dfvBgsMAXk(BI;$3i2AshxL&DW6JdY7zlPnvAPswe13J;ZdY=sY z>isM1srRd}=iQ8l9UmpaZZ8mFuXl*BQx5l8S1G0Uk+9Euq+yr*Y#{70od`QjV7)#g z;}OzM7rKN9d(0DhArW?I5W1NN`*aK4M}(bD5PBGMJ4H-YVE8`?DybOjOhrq2UG zFC~roYmoS6BI@x-q1O{ppZ!87h^W_dgg&2$`n^Wz8;GdqCxm{Ai28m@=y!>zcR$-F z@(&VG|6kYb4Mr4^x4&w~cHwpquiX^y z0P;EXQinm%$rnwAe2G&ed?}E6pxbHZU=64o{4Ld?s6W(20sJtbwgLH=t`C21{Z>dg zKs!gDqd~d#YnFHi9R0Q!zO;ViV?O+&bM)H?zgxehF8y+ak7+K$pIg7RpsAzd9Q`gt zfLp&E4uhbh-%W-utsnWAk5ea(e%B++tzWZCKP;hiIhgKE{JHhJ2J~e7InL4VAq2SP zt%p3OXMM02i>d@+gbWDF^30cfNhDa*P)~rsMMsl_Se$x3aL57s=)CboA5zvlv^w|R*x4dgy<=7X@PC4d_JSW{I3U@h&j2XUk zImpLyP!^q2jt)=0J6+|NDtt`G>o}C{lw&Ihr>`M6J>Fg5k$0b~9Mi$)l;diV2hi>u zM{%JYlGlgePnUyy)Q7U@oN_$i$@d{wIXK2U`MxdrI_2Q}>d2rxN1s=P&!M+F3Xuse zO=9AJKdm46sNW3Dm681!1i9@4J^A5->5m^LBpNZge%XWags^;bXeB+a)RSqow()qqG z`8wr@K;CpM$^1BK{Kg}%#8r-iT=L!&c}}`o$0IVGa_~AH{ONL#kL92&I;R}t;Bnip z!c~q#gpcWljJ$NaYJj}y6eP}3gVzJy@|L>F!FdGHT925>bJB5L=ypyyE;fAWa*&Vu zICB!^(Om$KJKq(qax6hS`Izo4BQIT!O^`Pg;f{0ExZfjht*abWV0PraBJ!Mcm%-y6 z*T_c~#-7AoA6)NJAIhS0_;SGKF2{Q0>-5W7;bXd(k(VyVPRQfh%yEuB^E~o4L0$w* z>>tbU$9yU82$AQc%SStNJLs<6IfgG?AAGKl=_!lODaRR}e7C#mqh9!!?lsBR=^w?A zH<^OOIr8rE$h*cRZxwi*a{N`~IpyGfcdYuzLWb`8;B|cJLs@iAz83i0^>L@GJ{pCO z=~|4ubbYLVyx9~a&XG6UBku{9Jg$+Qa;y+}PB~JL=XOqg3>v<4eUOj(P!^q&?=hZy z-*DLv+skym_e#D1?N0EN!_nt_kGxM@eykhv$425Io{Y!Io2A! zbUDb!^pr*CW zEqs*ssizz#px?WlBRXR8O_zgwOix*KPB|tc(A^GJT%KuHy~4+I#~69(a-0TvizrB( zBd^LMZ!P3;eZz9Z@kc(&TQBmQ`r!Qm=BJ^v~%>E0zS8X*SPdcfs=ep$LsEH{a)IQeth1R ze2)D%-?<&*=r$R?w0`7cJ{xsx#(pXA;lElc;di?9+k`Mjzw0Dlr@!&O9;b{<>gcmW z_#B$|{kWZ@-y?=EtsnWQ-xgtZWb-}%{7>umkW0T45bo%=FAjIy_WK0##u}gB^T>M| z@=73w{fPIPI`WD{o>Ptrr{LhBbIQT{0pL%UgM2IpWzjk1SPVXQIru`B0>m@llZB7z zzT+te?|Wi9ah#(M?<;W2D}X$fm-0@H_TgM8G7vgn+0T;<7k zg{vH=3m?<*xoLNOaNc&$)sDR1dE~8yyaW=m9A~)X{Zr&Q<>37lZpXan_6m)z5AsnT z%A#}f9S=UY{T{j^Qy*swAJg?1dFk=F8}i&|w~jtbJo27~ykewhInH&-J5uC1>9+5t z9H$z-bbXMI`cM{~Qx4uY;V#F!u5z3&d`$O{B)Byfsg!HrfJs)J|~U=j{h8wJo4ePRN6V^xY5J6c{hAd2;W?h!25Cj zla^*|Mwzb)pQGPtpg(i*Ir_bbaJOC7@5rpfeguBcz=sK z--qtR+6)6e$Aha~`SQLOM>eIr+Jb)R3UIub{X-=+kg$!5m+lb&XISlN8WwE2L~c4?`QaPJ7lMM3~5kALTQ_%1;w=X~inhwozHbHcB74+aP%AKkSczH7k8cZWHS`q5nl zKDS-&dlZ3Ums{X<%E9}JkUYUObPtXwb)fO;UngJoL02~FWAO3bBgZ*>L}v_Q+2;7``^X49W;KBt59~gumt1Q40T3d zPTv!yWQs_#yS-xSU?%FbKs^*%y z>U^!)?3ecLJ0fo3_XqJK`fBbvb=qVdKUv}@zjQ^P|7ZKKv|p%cGnZN4wXdJEOr5__ z=fCOZ2z0S8Wo+WEv#0H$)9$fqOKsH@Q)*L66;UrmmKE)M_a61j2T``m@Q0<3UN>$9 z_TaA%f3&f)-q?BlgssWB@u+#_XiZyP`m^j07*V@X{)vxsT)N!5!IsacA z^J7EeD{fz&V%i~oE#B{EU5gfbxzlq*y3e1*kDlApLHnLM2)}-R_W#gq{Z^n9y!N+| z$S!GSgcaoRso$4XjHd1PW&aut-saBFo~;uGvpxgi4`yG6Spi~R$H3$FXT1gqS$@!m zXd!`1(Eja%DQQ+6LhKrd@t4Qo4frqCzsxP*e-OXf46q|$&ic-N^kQC9Sr@#B-yqLa z?QbJ-)`jnY&Y6!~ivz!|Mo-914ywR!??tG}?RUKXT)h2S1sXKmNs=ULeAYi|XHj;u?y_eduD zf%YzfhFOk@fw3l1ntRHDFzaEhFW9@y5_WOzU z4pZ(`eDh=8=TIjv+p>m0giFAZ?X$K`fUGbd*vYo7>EA$k!yTyZY`>L6Oie`b1~{bYApJxHR$zeWXScU$|x?+^DeCZ>sCxQUW`tdk%tFUYRVcAq9tCqZU&&CATD1R4jkms>foQ<#sYWUsJ})!CdwVfC8uEBkchmUYtva0Pj= zWv{^sAnVrYp!1GI;er9n*FX_9;0xHk0bSC+A=iN4XB9zHWmmCQZsTKJc~_$dCBg4m zk21+`V5#7CZ2}dJAtv~Ji!XKYYfA+$wHhWOEc_I*4gSEI2_i47FJfG#iGuJtG>zcp z*5im_Ck63CYY0SfK3;LIf>&7caD9HVviZbL*6mMIfydEw8-hQ!u7ytdc;&eYUS<6W zNkoC4iULog@dmHf1`UR5ktTSJwF$+|3$twouNCVaipCJU-a3a00m8|1m1i_kfHDiNY4u(JU2Q;kU39KO% z%BBBXY;gWi7t@|tL7B=9L+`A+Ynk>`)bHfr{pZ4;t1ILI)`tq|dVi2DKQD9#vI_p1 z6ds=##)CVr5T%)yyN~@aRqJ5-eeGdzsc?izrr6hm z@P}`ro>T2x5D^TYOVvy{^TPYEI5SP5bwA3TrHKjQDO6y#CW`Y1M+Q`Gxh5v-zL#5J zvjQXe34H1@caF`LKRtXui!;x@3YnIKFJwOR?b(Q#9bS!gCq#v^=hL_k{)r`+#YUUc z=i?Jr`5nWkkGPM*ObK$1@jby3DEsGZC%@)%S9y;?RzpsSeKd&tmKK#W!!ANSsr*Kj zGgEsfbo;-84DNtVb{wY7 z`u%3mIsZk?MnZr1EBv8fpuL6uI3A;@3SEZchW+xDBkT(_DEXr%MCZQMV$u6(m+J@4o@GGeAyfu14@aHE~-Zw3l zIGBH|%3G_wdHKC6Z=LoQglYS{BQ!A~OylPrsfpt7lhplaO-#-oR(VnFjp&w_*P-Q4 z53^eGx-8a9NtpGL*KM(4O0-e)V%n&)wNdkWv{5Vcgp=26J&yv;3$KRCd2#Di5HR-$ z%AWPaew?n?L9+caYA@@_`J|_iUIhiS{!~ZWMh)11C;d!2>BC8P!dzL;alFps8%ztr zSNOOp(8`2&_}J6U$QQnnZ+FIs!uch9gYQG+9}Itp0)%(^mS7gb;_zi~XZ`IK3OgBc z8}gsCuFC@h>puT^SKa5o=&Jktm#rw%>$=Z>MH2<#OOP=CZ`MhOnV=g&{@<;ifiQKS z{}1a~5R=1|6#b4hp_p}l3#vH(-0(#6Udh3TZl9j;d5cY z{Gjhh5c9%(=s7>vcNU0+y4v#db*UHWW|d#yyAd%f44$wq#_(l>XnwT6u4A#z{p@~SCZ&J*k<>L$Nrt5Z;U*==y zG%YN@TvzIBQ@jdYyo&I{ls4DLRyi+xBTcfv$5uHn`~g};{y~~p81}KO3pKGQ{72?f z$#-wVB&U$A$~O_2)`ofSTYk0gPQ+k%J%+8~Uk||wIRognle16cvq^e9$=!D*N*i0^O>{+WKiS?>IWOP^qf zTa4h-Tu$YMrecr@J`<-*v&{M{!zbioi>rdqa+y^eDuLkOb6hG-4h^IA1fQorg2KZ8 z0@u>h&C=~fF5OD71*2)-pT=ZW(9J#|N??m{ghfbueKc~MWR7g2r&_6r;81+#WiHh(KVBesnH)Zp}dI|5-OZbK1 z6KFEqx)6FV3Lj7X{MO|lmWJP^uq^8u5ViT-Tm-Be;a_1E?b&+K-jLrhvI(n7>p{e< z#|CI6#AP3XtPA|(F0}TAyh1+AZWaCk)#NMW18a8SAX<>W@IuJXD!d*cfx^#Fi0r~= zS(HM)tU0G}227h<$OlY9g%6;r|Xkj);2OYmDz_%153u&^F^jw}2o ze#aN?fP@K!6OgK?@ByUSvyk)AUWH2`zqoKNLM9d#!6K6i&p^oDg+s_|av?f{`bHsN zsj^Su&meinZS0michd1|cd`oJ;e-VBsu)6Pt zr%3E}kbalJj&m{6tIG5I%2Z4*7gj`j-5}t~z5Z#KzpS+G?X=^qN) zO+mRX5BR?YR-NU;OrzQL4@pFG=^OCh3?ksCVfWg+AB@uU~I110OQCpt2uEI|+PbgTMGwqzz26R>2?S z`)-O`&@cigT1O%v`zf$b^aozFdNI~a;-WtAl64CL_l}}p1YWj&M}H8*cis??xE||FABhe^M6w|FkZr|1i`*;4SMX^z#w$z}wcf^z$_yfqz*y(VxwMDBMbP?gE!zG)ESx(?(=e%paj9ZZ~qgqxmY5f!Br4OB=KRl*MWwU zcjm(g)*5ADnOVdi2;)8?;QxqGGZDhSA`at4vk~nuQF6dvh&Y}8Xfo-aIDJFupL9ZS zcOx|0Naqnmz)!6L{sjouLb%N+3M0&woz9(t!FasG_y;m-mANW%aqGl7R?Nw{FW|ot z`~g3=d;vc{x`hEt|1$MNfB2`qgRzd#eKLHtk9~5|aI!;%uQB1>^k3^^ev`WURQNg{ zt9eqaONFoZy@^oBF~+lf zaRqMLhPK~92rAMI;2oA+5^i(2xkUGJXVM8bU;M0P=NE&U3KeOe7OQJET~%5ZG-D`c z1}7mG@+P59lV%6cBt&W9T;CV5T6I%3+-woxS?us|+3(`fO|AfKDZjKN<2T@DQX ze1r!4`|971!5!oi@|ZXDpmR9+j@SKVf#%?eNpQaA;9+aP&vVJ(?{sTlt2ub6i0MiH zE=Nd^Z{i8~M|9+V`j?C8fWKT1Wjv`4{zbRk?c_d_1HS(!nvaL&dp4sSTzctwZ9L+* z>JOfyb9`8{@uWK7=gE9`NAwt>~XMg_Ns2pc?>yOMJJ{? zIWH@_4L{kd&(us8;Wv0RQcd_7eEciAl|Rg(h$NK!4j|ya3%}X-;wR@@U|*Ph54=XT?I1B+A)e-alJehlf8b8*#7WygODe+1zhRdzoMGd*`B!w0BA3Brd}cH-ag z&(0lY_^}b>TM@d27EQ7s^ORk}jGMj%rhxxc{Av?k29GJO_DONMv$LB}#_X1#Y5rTu z&(Vr{WXz-N?Fh?m{i9}jnoP`$inxSwX{hX3}Wgqu#cyX>pH8=eTe(coH@Ul1aJ>$X99n5dbqwwb$)yZxu zl?5r{4=h1>y5cDz6OEX25ipsuMulF@P)Z%uKJGz)&G$!TA3q0PB!;mA{(r!q{Uqah z(TB6oV%xE=B-`)Vt@iO}zsQSK`+h-PU(((?+0b9s*A)W({~~G5JFrAv_VY)8QD4x@ zeu3>v>1|y0D_IEkhfqe9{TjEQSSB8XE}Z>0ez7s&XR07yych8I!yDnd1+6~riLEz4 zPvJ4M)kp8tuGA)F#s5VwK9&kEEi`SYE2XRrOfW66L0SFWT24oaceFitVxq?nKN$4*u|(~8F;X#srbD<|2mb*ZpuN?g zYX{M=m9j2791$g2)ds3cH$yA7nu<*UIg^b4jNs=0-pXRNFoKR_mUY?8eH{TU6i|)8 z8M?f!EN>S{UFKHidm8>`Y4PopvJ>QNUXiudY=hT#L4PSrdI&^jq40R$BH~m4TD%A~ z%dKW>o+_J;pvegOLI)k@3sy0rw%qqEc}aQlL5 zPMXII>0nC!6@t$bZN#` z=2337z;3kRMs2g>6pZY*DpVOub0e6)rI`=YT-v6GP$lM9@en+2W2-VYo5v7!gHEK` zE8taZg3KzVvtowL$WW<6`F6^{44WITMVl}#S+%c&-&i)Ajlc2=^p@=N^kR?YF5>3T zOjec8<{|ONKJL?~k68^Z=IU`=jm7q1)>`cFW`}w&ee7+jl5=hLcl43mQRLK7^r6$S zp)S6QQ~3uz8m@>rs3nhDI21UH>yf2{pvV7&f@z|niu9s8v-Trj5f7zR<;74r@Topo zq;a%3lZFyh)e%?&Oqf4fO_-w4+An{6$j;w8zkRPls{pGz-*goUEe_e}uJ)cdf;c2} zXsDi>BMFBAv-SWBvLi4mdw)d;jtBc9jBq*QEgW5hn9@QxzVc%SjhKZ<76K_!N#>=Q zv&bBl*sS{TjLny{Lhb>LL=<|E-_n`rbcHyX%jb84#_f;dj;AU{0~EW+I$&b`cuFtI z(wgpRS%%(g3TU3x6-!Z(54!wbF2R#B8en^y(GKl_aw+v2MT!|Y zGMI!mAY(+wPswt{PX&=K*fgvK(!_KS=}Op-ME&@A6DOk@_RkeI45?+-l8KoN3axR0 zrNx(2YwfVAa0KvOB{MQPk(_zvDV8d4+AVc*CsBrkXg+ha zUCYmc6kqWL)rhEYA}|P+A%2uHbFJ6Z&wLusFXl(7)DDl z3@wBT&D&0Jcw5rBVNlaIghO9gNU_UUs*O;hz0HIbCKSJE$8<zr4nszr5=fYb zKNOQtt-Wo8!%Zlm+k_Ifm{7uLCX{fl2_-NK7#F|VCGeZVpQTzejIAaPJq{k9Cj3s2 zZY(5NjdV1N+XaOfE1pjj`;>k!xAiFoQ{3r^{)5bw<-Ltil~*Ma{qe4jRD5VKS)T0P zP(Ikbp|o>ku)9B2o*EkJ@9OJ_Bc@|`ptL_eII^j;$0 z#QRg_-5tZn#Rp3_EnE;?Ft5Bn-dWz;)irj)awd!qcJ+^R$G%*JM1M!BXJ~i;8kl@b z7eZuLUnvwSA4v{7QpyK9y87aS|368?O3=C85l z%KBJ^(bVQdED1jr0SL!!lJKKaJ3Epw__FYInB?Fb<1_bhX8gw2IVcz(GM?@}!DNT= z#5N|32Pae#vMJi#krE=+HyrEemWaV#m_+=;!^YDc?~Ns?7qr3ZIzHG7zixP0x)Ius zDr>yYk5;23;7MgopB$OKYUfDhoC@XhTT^`jSM;08nrCl`ME1A0lee(z zYjv4bZ)`9&+>we!c`cBlqs>hX^)>6FHB~h$>fAC~=hhpB#7HOajZLOh&u}ajO~$&| zQ;gp2jrD8la2>j#wXLPTak&~v^(-_NRpwsZ=)g!Swuyx_Fw`uhhv24ZUL zJAIRVBdPA8;|5h?IKELQNTM*vIW>|{9UE{zs$;75dR@5HwHY(QQq5{Ob_~>X7iV={ z+lr=In6GzGL7@#J$&TJwT25UJZjRA4(cZRfp%g|e2;H6RYU-O;)U~LZmUYc-O~@!( zTh&&jHAwb#%u%{t9Nwntl{%(*RoyysH?yeVFjTiMQ;k)t>!LMHjmWX8zOk)U^~49` z$v)N9(cj76ki?;hl>)7DN=s-7>)6KA@?yzWm5^n9_+^E7mcnqS5A-y0*4;(Piz8HEs1x zjnSys7p-V;XfVo~Gh>_dB-GtH(wRaBPpb0vBr2f1c6e1oQ+aJHxdFE}mNyR%u}dY( zJ2C2@oh17)MaKKP%k^*C9IfkGrLwB#OT!q!K-W9y6rj6LDn(K0juZ}bOyyz(q|wa) z)h||OF=g;ugYl?)ATdYjX5Tp&9YDp#HYH5*I#?K%Z>y7$z-`yGa=c-tb8`ws#2vfQ zp8k&Bq}tfgKN3@Bj8odg9f^dgY4n*Whdg9^>>SfdYwB9sqE+o{b%%;}#)r_#(Mz4$ zFuJt2!PcwmRH9=T-7kfPR^1q_XH5R(DA1`>L{jdo>*gQ|9ne=YTB3mA{;Ycm}_(|C0$ zTI$v`t%4Pu_HD*G#g2qg^;irKJws}6C{-Q9ngpslT}UUcYJ)b_?QM0cu5o#NV_l{< zLT{%tvfdJ-sAEl;r1R7tURSH_H`J*IaYvKJCJ01D=?P(z?yM+YriYs#=tm=&V1+R@ zy4p3hHp8D**>u3_m31|33QEO$;^?fMn52^F(z8@+4phmJL}F+-m5iE|gQ;)##K|oC zJCe>A+l7vZUaUvJbo1v>=#-_s72{ZUJef)iG1z3oiGb?ri3%6oDAY;7n+ws3V4|98 z#W*RTOhv0<^R*ZlM=%B;=WaBq;dn>C?qfBWp=4#TVs%xGo>aL4NDX%kCb_U2W0GOk z&RE7a*s2Gi=y1nzW|%}Yd&gkxIE-#hj?QK}IdCrK6FvHxzQw{tDFjQFct_G$B|SNy zLb3SPb?Rt|$rz>W8XCbcJ*?2vF(!0%Ql-o+Xas7}HJCP3{8+SkPGQ3sq%ba~r(T6i z7Gpe2gq5QJyxaVrRybH*Vxvwj_qPF)zR6HrLmsz(lZ2yCJft;2x1`YJ$l@l1&O2b^L3?}u;!X>e>?wd-sOHM_Zr2`Gw zozN0clz7i(-K|_H>*v-Yqtq}W^n9+^SdmEgDKjXNgr1o2Vdqf=sh^9!>I}+yK+%gs zrx~_m=-+rC=FOBS#X7BSsBf(0@|{}_SN|N^bjtH^&sI?6CWyo>C>ACT_kC5SR_SiBG?v3N(ay)2IF1uaHCs^jqb*SN;^RI z^bd8UO0n;*Ob+#=dJ+suj8tyyNo+i@w0q71(5XJOLSlciv>Rg}#)C@igd(NAz1;|J zN=8b1u;hs)^nM>if*JLU3}WZrU1~Z2==dO3#4&96F(X$ln1>LviYet90TfrqrLq^I zNC?pTB6pZ>1x&H#)h!2u@!4NJ#?96BgRcCKi@Xu7@{(|rn? zNRGwMMu92V6S)=Ci!qEa$brE_sXlZH)3!5hQRi3Hu)L{7dDbFKgD$j5_GD?r5NuZM zY_yI>HBGCV70cOLznlp*cXN9+RyD?NvT#OS-7B>%F>^Mtku#Aj8qBb$lcnWjAK1~| z9cSa{=r@B#QepPtLn9(o>AveIBr6@xAC7G@>j!o~%nd1>f{VdEQ?aH`a`hYU#HJW4 zb_{_~EZK);hTb$`?uJFuab`Mk9i6P@_$Y9J)NT@eeZ+7(WN(3>Kx zUsPfU6Yl0{7fy>@>o@o8qOg(Teo8u~lf#Ntwabk9)%EG8a!1)#uM#>^BUl*f1{u{$ z;G}onW=ZwpTCc$M7@$WA1iJ(dcR zAO-Vr`JEabK>&s+Jg%qBYYKynI#+<{-i2L4)Y}9MXWP2wI+a>5N9h96 zS1lAG`e+NSsc)^%tkz?LsCd-6Y<4i}cI%CRoSDG-9A1o>U_;j)xO#Q7j0R4@GHXWi z563nRZNU1^NX9BJy$M01tl`?<~bn+E(S~on~+Ioo7|&^L~r8<4JE- z{)E%Aw)s!TqtxeFHTiv2a}n6VBUfedtUBwU(kd0m&8`YsIlf%~IR6Bz$lA*;wkBGW ze0$sb_@`Q`EV+3A13EA@Y_QMq;ZQ22%FGc*XELeEFte92ux#x0Vp&zo>azcby*Gi6 zqDt5QtGartq?2?=#IV{SiG(DCKv=?}h7g)n**BL-ki{SfD2uo;pr|-*D5!|2j4KL` z3F?fDBJSfpiOUR(s8Lbe1r?1tBmd_)=dJGQ21f6l-<^B^_jAuDmG4>J^PaV;PAy$8 zlBb^fPo=0uOU|0UeC{X6qmDNUk=ximXYg9rF>pexIoo6-Ya~x8F!X? z;^_|O#{=+Lcno?H$noIux)q**oC!LPdVlQ%K!&f!M)}d$T6t{srVhNyG5rbg6Ab@3 zDg0Ja_=}|Q{-p3vNnx9Xi=%$pD5k5xmWgLA`AO-{61a4lk-yN$pKg?n98{*BL&Oej zBL{Uq)SXi~svZ6ib?7rk;##VvMxDcI^yNm)G~8>Pf0iy^trHUNTdJ5tT}s98N8o6M zs|Dxgw>yKnbBSc$4CDhK^@PIpB*-nxv%TwRd{9kzXBv)2n~q)S!_#IwJ5#Py&lTG0 zjvykXyM7X#g7bB6hRgL6b-q|U5@8GPs?ZgsXd1}RaZBlmH%rKFcz2J4z5yik@zHlm zFa7v8yo)$)f~`CiA@_wb$|$C3YR-`w0gMqr!2*6NOWS zGldI;eCSR+%Y`e2*9g}NZx*t@DF1@+4PmqJ10nl?a{ReIStRT&93(tJc%o3*@rL|a z66SC5nE!I&^}^o@Hw*tDd{W4_z?g4`@O|MI!taG%KHY~L?KhBZg$2SgVSnLJ;RNBS zLVi+&`T0Q@a;5M(;cdeEg^voK7yecFp72ZI--XIPHuNgH*sLc`=Pai{*h6@n@Oa^5 z;S3>vvdVnF7G5E|QFxc|0pTmcokD(3pZU21lW9U_uNvXb66WVxn6B(lgC|M2PPjivjyv_@bu~r2DyG;~*iSfE$ZvvCewJ{N zaJld*;f+GR;ZFGm;Wpv(!oLXL6@D)KUdSJUF@L5|*>y%ZSHe+Yt&ratr~Em>ON6V1 z8-(`>|0w*E@O2@7Xiq&~2!9l2V>!q8Tw$rOzi_B7B*hWtDUUnaa=ST9uej3KA& z7=wS2_`SlPgmzGuKUi2J}g#1n~!zIGO z!m+{{;g!O5!n=jrg)a$r3i*jD>Q#1bK`y2lP7^A-wg?|B;bLKLVSiy%I6^p4c#?3Y zaDi}{@Jiu2;YQ&D!pDU#3;!nM?+01WZ-gdJm<*>2+X)MW{3aRGtAzZ)2g4@|X9*Vz zFA}a2-YopR@F`&c=YHx@c3i<+2`l@p2=|xpP~imOsls`}^M%SjEAm}0;oF7v!pDTq z3*QjFEBsvey)ZLf*RPAPr?65uQaD+t?53jp`4YZBxKhYZw6MJ!gqwvA3!fG?3O^El zBQ)^CDCTb?%olbM_7qkMM+zqkrwiu`&lj!~t`Tk!ZWcZ)d|KEjd`tL=@H?Rw3rN_P|A26-aJ%ps;fum1 z;a`Ps3EvlfEaVSusCU2cN1=%YC*uRcG+~yIU*BVTg^=G2WcVcEOyOMNIl>h}FV?t} zFBJ9?RtiT7#|Y0BUL?F)c$4sM;RC|$!WV^q6}~V0Quw1Vkge;JB|J)4EbJp3B|J&^ zittV0N5XG~*;uf%oe^P)@I~Qg!j>E@=f%RF@)^RTg?)rWg;Ru!g*OWC5WXmUPxzBC z8@CClzf5?d@Yljs!tKHrg?|-(A^br&6SoTgt@o?qg)T+vBKfPiNaHb zuM77Ie-x(UHU{;y5f%&k2nPvA2~QTDAzUI{DSS-$yzq75E@4|->#@9i5^J?`2_Hjt z!gZ%`jHI6==`%>2Qx{5jDGB*2h3kczg!LrKc}(~mi7|Vbgq~(0Z`&~3R#;79pPEEM zf30wqa3zVn*OHLCUE((j9}@mi(*GpkM&YLt|1AkUKT0?~qV<&u`v|8CmkKWx-YC3J z_yURc{zdp6S%FVTNH~zI(>n+U38xDe3zrM;7yemjz;V2={8z;CKoN&^MTjXD2up-z z!YUH|92Fif93z}2JWV)Pc$RR5aHa5S;cDSJ;Vr^?;e*0QgxiJB3SSU53EvRzCNaJr z3BMG6E&M_FlaRlaqkOioo$x5((L!~d4mtj$j`EelAwqtbi}Cyv2RTv5AJQ>AN4P+E zwvfNCWBQds+U;YQ_V!5r?2i1M@F5}XJ~Ey^!Xy7I{EP5!!gqxq2tO0<6@DlDQRwk# zeSTq@FjGjob1bjDkiY$7xSO!IkY8(Myr2CX(f6M?4{>-`^9fNZ9Z>VnnV-1)Q0Z7s zD&jP(G_mLxKQ*|O1PRty?&{~VcS60sCF<I;Y(C;CGjMzN;OagHE|6P)6OH z&vdMBi}LAzj=m6t-1@G7zEu!mJFw)B>BFPb#CA}*%Q?X+Ef*UP9v|2a>Y{VXJr?oq za@!A$j|Zo_(~e(heX)749^uwXlm3UGa?3=HkA&&AARJLX{f~0oR^uP(%;(n;!09XI zocdjjcz69uP(L0E*e_W6#p<_7^f~i11P{l-aV(3jN#t}0x*+#Kt`pLAVu<%U-R0ul z6NA@MESKdw{qk0lzJKK5p1RX0$RSy|FO%d3cQ%Y+PGwzkpC*;NVv=DjgB;7{F~uqO zrzCw>b=r5w-g7kXIp7M|1*snkMnN1>f`i$rVO1U zH%R1kEbP!j&h02iH|Y>^C+j5j-{$_^`+2(!E!U$UydI*@afQYbW0BGIS{PW3x2b@e|~|5!b!y|FrHgt@9Lsx27QDcc7ts@lDp8`XZZ=d!2~+0kNzY4>1E zv|se3=yKRZC{sFzs{dut9W7p!{`MX-V%2Z^Xz$g=_ES-zT5KeSOu7354a>|Cs;uo! z-_oXpIs9DOjYy0ey5!)vVdoqi_y1U5%R|0sM%2i6`XVjX7k#7tsG)i&xOIMA%Qmy; zXM2oD%QoG%O~Hm`=<`9BMOQ^TMgviN^t_>J>yvrq%1%W2i1U>Vij3wH+gnYQs^9$4 z%F@)g{*>2MNtD2n#BE|p!iWrM9#A)OEBo9Vt$hFnBXa2<`oI8K&lsk1S2i@}MO4nn zh}lZ_yL%|(i$2`2z*R3$a7z7jLYB_@9}!}t*A=J*l52M zEsRd7TUR$~?}2ib7j7_ne!9n8>#3hF<8!aY@%egSAnJ*%jJA$;kb2cN3{<|#h6>cL zN3=NV;S3(g`rV%wRQ(cg^^4OZN@}^Wo#$$9bemB|AJuN%=E++>&P!1(Oi5^A5cW}W zRjIzH)(3kju!(}pSR+D3aQCP-`%v3-spO+EppM)=n3tm*je*fdqJ>)&YcJI7*jvc&1UcxRA#7xAYJMnV*Rs-u3m z#^WE4lXT8L&-D_I^}P0Ubi@0LT|&Ke*#$)lCh9kH`$Y=oOpg?nEh(5Y8Ry0nq?|Z! z?hHgPD2eb_Ui~76{)L}DI_p-%Uh|zbeSwa_>$vAa4So}cHyxAQ^rSG`G)v+VIz{^U zaD6fydH#+QjP4V!$$Qr(4b(oC)Ju*nmTt%pv&F)1Tku!7khSX3)iGNvX}J9IdVKs= zCv36&12-0}&v4p`*<#5_K|(OVJMXZ)vK*rWTP!@ODO)T!pHb}xP+|>*Zn4EO7i#{w zEtYN&KG+t^anREqrZa}36YPBGhUJXw0K>ikb@KZ>7qdLOI|F{t1=zKM_7Rvs{(wpe z*%{~$f6(&|PUK;`8|v)0RZ6zK4^jS9&tp)4Zx#O$74%&@4#lLrjAsowfoJZ5KNa>~ z0@~h7D(t;zuQ!$UUINb*AZIXC3!MRN?SWA8IUa!0tqK&>A zl=qKV8~fHOFCQ8EZdBe%j?OyeeP0ITl)X=wHc~@fs_-^xbi93|xd$t7uj(m#o%wNF zWU=|Y*uKg969OTdFJsv2RUm9{#{k$jn{#k=l8x>_;1)B4fVTHy-)bHM0oZ%#fa>@j z;%*;24O4fdeVfTWUfFxG?=<;QI;p^2Qi0u=y!PFyLxc7%RNCHXE=OF*<{Y=h-iuv; z$zX3XyRZVv-iy82T*3<2TcO_;doT7Rbd)XjUTnTzVmGK(=i6JTZHo#N+WerQ{eU?J z3QAx=0)Yoje)+D_HZj}nhs?_msJ3Y@(T>@B31YN;TXRrc3SU^swpUMuKg5R~_H{eZ zXGW-m9e8~KyxtJMPj0V$n;jck$3f8cUP6DN(pxBl503NeO1?+tKs4oUDzMMJ8UE1s zD9S#cBV>f|xgC5~kQ2@u;y0S@r7u$_`Wp52J-U&3J7av?+fVF+Kb1czwx8m77$G(8 zPjlvnLhDhK{R{^>9C{mq_OoBYpB)Nv0G{Kc3LL0TK>zu+{hd1ZL1);0u`l{9_2R!ILHg@ZJ2Bi1iLCsqMYM+DQTYUV8u< zk>a-Zl9I1d^ehrPDCqBZF?oGY?xNm>sA6Gi*qXyS@%Wf3_Fn8e&{L^m@5QDK@zgAf zEe+aTkS8_U;)j+)HqD!)wzfJT5Vn89PL+D3O3Ak8avXB3fk?@*`SL|-8*3s0?d=iR zDN@_2K*S!8S(Mt&T7;CCy_d65n_w0S>zUfoD&=(g1~I8eS?58@uq&7)*Ln~EuYDcs zDfV9M+b~U1#omj}FWsezy%)6~rHZ{5dn@*^RJXmCRI&G>_Px|Hivy_by`+l07dr#p zmDw-8SG5Pca6jZMdt2)%=dkov}- z5#sQN#&1D>Z|EtEWM~5Y*x_cQYkV)YfqY5{;v;EI=Q8i_F;~-Gy^{;?&?ksbd*ceq zhd3f>JKsTkDAXNgrR~}ae>n6fO#HNW+TvB^?9e%oOnaX)IiauV|F9bIj;)v#Eb4u9 z(SWp%M?hPMN2jz;v>mAVM%rimmajMUG$ZYE`huZ{nf?X+`0_O7K-!n|heH+U+ca$} zCd8LV()KS#TXI7D@O#>~6Csn6dZv-~J*C^Ho^GW5Kwl*EF`K4s#e_~qucv8SF`?tw zw0}^hL@goGw5=F5hw!l<&Y_<63v9D#Rw4l7B?q{6cx56o1}!wJFulLY*J^C`Uitu2 zb)U`dOBY))YDTA5nm41Akj)NEAE*Lho6kkk2boVICEISxz+f|ggJq7r5e-crYL+3; z-eyOqk2Gf?5V5~PVd-O(f|#wC-K@eLd|sp&ISrJT$PUJsHy{eU`Zh0dzMXwfh>M z;aFdef7Uqe2d}-s@HmE}sG#qS4;aqE2w3>d5NyTlXLtg`d^O6q%ZH;{@I+({XWZ%; zf`F<_#s&{ZSRXYr#8!;Wb5q7<&$TE&Xn%(WWYl|hA%KNt8&>9nu~c?F^o|VgGKcd_ z&#@1`-4E3Wf1?70_G(lk{H+R<*nBN5?DNnlU77tg>KqPwzDJ;^ zy#VtvoZ{(>lU0Qpwy@ZWQPV0M_KZMErTr;YxAH7RpxPdec@;j=a}@$HTQPj0DM-t# zBg02|PQkfA4PiLqxf4>f6%+2{;T)r_m~fu*(pF43UwLUOCS0Jrv=tLRT6wc=zJ3|* ztO7YU&)wld6=-jtf!+>xQGtj}lLz5qPd$ptSMw-b>fz3*XIQwK8q^ZqJh2sH=U}G~ z_waC5_Ov_VJRk1u;jHXw&*ZG=qXHH7LIx^SV1WG;%Mn{K_N!Dd(DQrMC4a<@5RTc3 zxtWLJFY3?>DebY_whu0S4t{k!2`(!@e;6SynS;w`=a+K3w1 zpB#y-2JA1v|0(_6P%Cts{aJx3iq{qP=e(>4g>FMN?Jqj8D8r&{B;Qw^p(o`%G{2|) z8ef~zORhJ#SJ$FPvJL8?Y~VGie*gmpKYC{>*H& zG?4i<>L1MHr%LV2FYrGla~oQkn(0S>hB9|SJ}vVrOu6(-nj*=_9LOHaKP$68@@8l9ZO|h!??JBCnQIY$WG3Gy$jRheWoN&ri z&{LUbe26IP9aOT_vJudb!gs>FtzMqSLSU4p)hl)Ip`(_g=lotqAMrjTvZ7WFnwb@y zizq7#Ga_sH-H5lAhmiAw8xZUFve~UT$DV;FOZ{UjvmWC=I2pP0 zcV)Z+MIo7A4EB4M<9~n`J*o&!^DOm`$_~>|UOf1{mq1h%`5N;marKWuBy)Z4_wtUE z%P7r$1l4Dx<3?#r444?D;XS96@fgrhU>}b#>R=PlMrl&{b&`NKN~5lS1N&JTmdk%c zYXaYfAfLk@Is}e1$HO1Y=A83irp&ykla2p3$~qLT=%$`#_%AmvMs}}Vh2i#Jp;ChO zl?+^Ea@0aL&EWZ0nP=nh95!{ho7+V#hr418d|#rVl=*oW$t zMY|1@*`tn9?ViPs9Qermk}_YT%K{&p`|0QFjDb(gAL$?Iga1?0MCIGviop$hW(Mg0 z16mmP+)Sf?JmbGGv*@|;~e+OC?*k|$_rR?1VzR~sXOqu=K{~hc6 ztyv5ijCB;9@8vxrSV2<%X|^Yrk7fr0yUZylQ(aUC#NLg~E2+SD<};9jy_=8OJuPN;i21z~ z_Isbh*-6{G@p~VH6l@V7J}^{y*#^ItW9s*=V>Dl}&<3zlW^hrJUGoB>)fp6e|1 zXjP*d;K|}YDC3nAdY?&;;vcuHH7vaZ$&L^;!%7E**dco2Hw~ z(As&!Mq7))*f>gfVU=|zON!;nQl(Qd#M6+jN}EPORpmacQe0YPR;kjROI60+koS9e zk&98meuN{G`p?`jnt;^6-w@Hpn{k)tF9@lfIm2ZrCu5_I$G5qRjC(vRnuc;R?)7lQ zX(%USljl6-ggRb)zyK7Lexgdb0DG~jHZM4`s2}N{1FhJhnYaeX;y*+l2?TV0zIm!L z@$y4Y6V*)BU^N$(Q=4S$$ov4~`5kZn8M<)U4IgoE(s$Ep62}Uh}wQ)NEJ()GXq)0HhB%(!37RdRQx+ zPsX_`l9WbX9=T)=5**_Q^3q9lU)H61M9xJ-P9Bcd;SQb+@Tbk;qRh(+)3j%CM1grF z#QMFDs{b_Kl6Jq6I9VN`e!y6#-KPfpH6_7YO=H0D z;8B{gxK=Q%8vF|$f3y;!Ws|gTk*gKoROgm8n*Ufr7K2b!0{FdrgFSE({-qp&hF1hn z&cORgpF`Gozt{-QVPo=B7c>40)}RpaXBoly zSHWMBdKTl)q|J)5(0%OD1#Aeu?|vc+9@Q2JII82n>cYP8=;kV)G?$mP)*g1`*x^ck zH08HI59<-{9>ZFTxZt>XN@x*11}|}k>gWx=!{>X-L{6|-d3&?J-&K!d{N8Jjm=eHj3I*T#3V!tr zH260AOyA=TzQ^Aectck(*KYL$4EM>f^9Db70ttREa|Lfk*9C*NS&S!k_Ln#`1XJWW z+K=qtRJHWOiYCf=8!|131^N5iU@+6HVIDq%3AWOC@Z<{9GRvHf1h0`+tJVaR%6WnF zEZgh@e_EqD1T2O(@*K)A&ro$nwO3&?*Ed9PoyVsF<{9+Tby@%mJ!kwO!V5rz<}HG0 zo-=q^bUcE&e?u|mTq-#STi#;BoPRMqcQUXLUnelnKARaxNXKjlZ#(OGcmPYD+4!$ap5*sKO1KCjQFzMW8L33ZcorgVJmQ8U zu13X;Hp`5H>4>7HD^%1t&v`L@V?5`I)}v_{2lXyE9l|q^e}m4?xX#dPEJmDE0AqHE z8oATacYZI2tnfaJt~s4eqQij(J$N*Fsnb+M(^HJbb(%F7AszxpGQ>+7b2|HoQ;#NK zjrFROvDVk-*rUxcz!;PXjAlX9UicbB&FSoAI$hAYxl#}%c-KP@&2%0@?{`!`p;Ra8 zEG*!dB~|-oXjA5l-bD_hcp=I#*@aSAle@4+NBeiWdvsL``AaKvHYW<5u4KXiZH>w(Q&Uz>+|ad$evTK)kUbGg@> z2Y4Ir4FpTLkC-M$^lKF~OpjTDyqVZ-^Kn4cy8zY(Y8My|=El_Dk-KXm0)rq;L-?xE3DjK1qp;_CR;REr|Oy;ufj6 zu`rp$USi5dq}+;>%S7QK#Jz+#*5n?E3l2mfX0@Y7oLRUnt8J`1Z=Unz8*n61UGXC{@`_n;AZxDz~>Bs3etL>9s>1H ze+h!!Xxi4?!0~zxLDlPz7dX9Mz&Y|b8Z#eJ@q-EavJ4e6I009ylyTT;$KePI;Gm0vdmr=OrAYsbLA8tA%i-#dy;qOVCTdxZpdO$5I6h4Xs`0rL zI`v+m+VCd2*hUmPxQ9`IUQqKsPepN_va*=uWo1a=kVRF>p@yuW8X_FBnUXnS^4@QB z9**>VYDkqzJ&df68pc*IXb68{Z`9V@?HsJA(_BBk5FNpx*v+BHL|5rU#cnqI7zA}o zKV(a36;vDT+e0NQ5mXJQ4rw^LP)$r5Q3(^X0KKf5&_$;t&b*KH(SrwpL6WYAcoFu( z-pJ{0oSKt`$8%2Za~d-lGUoa!tOQhJ_OUT{1)V|N$3f*>(2e<;jrj>d-I#BvGx7)e?D zhkfl!Ai&##y_%pWwbJCi!W~&(Q9OoFZ=+8ZIyLik?&|ETEY)FHXTcxng+0FyZAfMA zx&rB3>8W&eOUmfg&WH8wxgO3-F57`adF<%Q$seVDx$wsshicH#n|g zth&EXAL@AnfY+u`p7;46!F2DxU)S_x15DmLpX1dU#oQRr)>ii@T!N~;T4NneW9 zVPLOP!li+Z?YkPYE3nVvsaogI%3j9hcc6tIl2T{0ELAyGuRaFa(7Go(hVx6^o;Uiw zmVzN4WODYn?jo`)_5J%k@EN_{g;d~Is){@xs!q`t;=O)k?X__|o)EKm7dwkjZj?Hs z*L5g0GoTh9e`LD)$KFRraXfnU!ipkzo`?O+T|xIc$H3^d0EgJXcOI(b?x{8Q;|l??rj9K+3a2?1|NawZ`r=0U zvb0gYY@C&hBix4j{+rG8B^a*DO|+udDbb3a%VHmm+vUgY(-k<@@J!5+qg`h5Iy(tC zr6gLEODMOC78Cn?N!I$@`4V!K;3f%&4Oa13pG3obj@dxI8`CXrEsug?yHAzI3U?Ph zF!Sii!J*M5jUa6Jso4;-y$5T4&h*f>_j<)@=(4@XTg*nESc=QEUWGeSTifd!i-HCn z)h{uMdl4KC6}UVeO{~I}Xci6;1`Zk!7(?(xW*QR+M>cK%4v``|HZD8SEgQEc7ndCu zm!0I69d|2b=y0CkH~v^jq8yvYxBv%g?YN?<#fD^JvGPvAf8~bb|43{|C3GrJ*UI(8 zf1dGRW{y~h%`z7L`c`^$TgSr}b2z_I5fQ?6a93%8F>Zmx{?P(s-2#c7q6Pl-B7RoG z&kFnxZ-r~x_E5tz0smu8r;Z_X>Le$rBRmmo7)L@+tcmc&95Z>0vRmVs6D9$#i;j#*hRFoa1BfNG zhRJRXiSsO5$&MqmhKcbyjEmPHp<}8c%#PuX#4e$qJP{k(PVm%>or(CpjwN>KSp1K< z74R`Xc@;L~Cv<-GzUspwL23mFBaF2nGZ7Kxoj~9^hOq?Oqx+t|V^zWgVrVP@o|wZr z3OUCRjzD6cYk{#uM9EGfbb({t1&+NnUf?8mfr%ra^^J?`n;6$O&aH2pOW#DdzW5;$ z6;Z$MV~?i8&tXM35E11aPw2XiVeLv(>}W#w%y>sJvLQ0&c$`BN(GT0flUWP!$$m^A zvEQ`7SVzD#Vsk2jJe{yXKcRP_aqz_)cR{2QCCWRA=%!;slL(#_4z4U# zp3paj(E275j*>CA#+6KVD@kmSRx&oOWMaHhW8IY+>(V#TtuJvRXno`2`XE~d$U+{CWf zx1~W9ZRvIiETJqekNdUnAZxqR=FO!kU)(SG1$K9pRRk?9MoV(1&_-`2h<;MQ0xc;%=2>Onh z<)P7MN7?)ECm8JgPego@tm8isalkYq-BCZ&AMsBaaTMEN`iJ{VdgOXcS9Q0UX6bP% zt<>LbwRlE!yS1#_h$)?>tYHgHf2n`uX;ZpcGfS-w18zO$m@-ecOT#TFs8h$X6Grqe zzReSKC0u5jojP`+f@7ylSyoO@EmL``4b^#5 zZY`T~Om0G#?qht1yb-q^!@R|(Fg<{LFq-nSrjB9fX#NaiE{xJB6J%m}4Q6}(6|2WF z6F7X8T^R*(TWoX;1F?jEkE!GTh*9I15f|sv0sL_P@yS+>_3!D`hyD+1@E9+p)F?S+ zn~64k4rTfn_D;l*>MyZ>9Mg#p0VLT%{{Ni`WM%6>dYPYpfaM3r#%|1<7c9=;QwQuj zWiUu(NiuxQqh<}}?;>SxnL`5eO3I94%+h7t4D!Ej`uM-a%CSr%$GD(lG3-BW>sa^W z;NwS+gx%g>Z25S>Y~9a#m;Ns@fvoo|7|8lBwS^or7~<^Z|J}xs7r^@53|K!sq>W_V zC-RjOr^f$_3@1BZrTVWmolHBC3x0tCWh@D`HMnki-PX;iUg@;|GULiJ>tW@2A#Y5U_R^L6V;hUccmYba(r9oxXiOEsYsXCK|2E^$Y7Z03Rcd|e>=#Tx&(`pFemD}qKJN)XYczV^%$eF8B@B+^<+nuJ z(FuEmb5?S8CsnlDx-?9@&w&j~SYnOsssFnTO~(&)oNhmBb{em<>#GHXei_hm)O@5vp;KDDZ~bA-l^ zI{u^fs&zTYSTk|$7*?_n!^ z?!uX|V`zez>jnPO89_ z^}pXlwklVx=J{hR+@v{-!R)vkf2cJ}ElTyC%}bfMrSN})LG9RS);OGLZCx?<=SY9X z)^?%m0TG`MRi&3L3oTE*FlB{(aqyDBrT&$^%e=p_E{8Sk*mEmp;WI4fIo7``+@1xA z0TqT@oZwqBl) z&S!PWWej8^{~fl=_0=VhQ3qM}jvc*}3F{;q<*s}*v#soe$L1)Og2~zv(wHMj-$ChO zSzT^LA3~%1mhz!$cu>01=$xatwoR^MLfRqfcu;zRMs-9xoJyVePjtow61(!CO2#@$ zTNXcDH|o^HPCQ6gtcwn*D=9VJ*qXz3o=!PjGvlc)U5D>BeXHeAL#q#UNnNHR<@o1Z z)*W&@oNqSAgbrKbWNj35)jjFX=AjEq7CLNUhY~!vFfLmEX+cWh=L(4lsRH7+n36TS zQVyXqDfQsW>ibQ}O7%!db4BD3+7Bn@D#mrTJ9Hs#fx{M&EOc-I|EwL7`{&w`BsP!F zg-Q=?8N8yrx85O@46A+Cyi(m8a{m+&|15v^zR3SiC3;jGTml}mPo1O7!SV)+c(v=f z>)_l_{yFVE%VQE)%XTmAey}RlocImlpQLuhbSH(uEpr!G1T&)#OvGfJl`|I|}Y zJ!{5dDPP4PpF249tf_NP!<|#zSS4|A%$!+sXE++sBBK;fKhNNu%+k5@7S1Rga>9hJ z>blmgW#(DDXQZa()P;Dkcj_YEpgn}cawX=x#=Zlw06Z4nHF7&k-Y|0FEJ(PWh1Vq9 zYcsx!lmP*1;Tq3_a2s$LHtoC#YZ3hD%E(0mWwiU1ddoD&2_oI?EQ2qP#hnFfN%6dl z=ljiZXW?sUiS@IUJYV?Jj&GL5on`Q)uDG+1J5hh4HVbb>CdQ;E=}(U#>CcJ_!)GaLK=CLG@5CkQ=gV<%XW`p_iTZPr^v6enxh$h? zJhKY7OVZCb0presb)7{09g_6pdj>9N(J-OQSwKz%Ilky-ao0l{z|?wCe=UYqsKCiNeUmEq@S-L$DL(VCh4zKZ|m~-#cMGS z(%sH7s@y@8Hz-N}prrJ{N%{vX`PeI-#^5CRAxYt(N&1~PF}0Y5mqHWg&u}F_Af|;c zjmDj&eyidRAD^WE_;@0GmN6AV__JIk1oRNfThI!V^$)x?G2 zvy79H0Vn4O= z^ftmCCsp^?kx60x2HJ7VPn)HVW0=1^b{xZe1DpDJlLr{AM!qb5CyN8D+dI^1LUO={eQ-OG0>x!H5}u`sH2P8X&#h* zlceV+r7uk?-&yuM`ki#A{H}+|@04GDm~^LnXBiCr=pxm>ymDjzM#$gdA6(IKnrsKJ zEK+Va)NgW9?vQb~MITpF?lfSQ5a}Cq|EH|gzlx;%I>z5+sC5c$>^#RX^1nhN@pbZ6 z!`Ka4^R;bo3(M5cB)peInCD@pw@CQ!66V2~>2yWanyjyC*FF4fpf0Zxw9eP{r+ftA zjB2U`0%3RIF~VWO3Bpr_X9&*`UM##uc#H5J;S<7_g*$~G2)`2kLumVT zJ&zFP3cCvX2?q(!V2MF zAwPaW`5NI8;l;vhg|`Yf3%3fN74jQY)bqJ8fCDMR*}`05H(@{Fc;TtSGlcgDpAxFRG)^E6QqVQDVTp^A4Q0^LGgK(ShdEpyET7;v# zi4!)NCTt@t5Ox%wN?XTlbt7Yjc2 zTUbbwPz)CedkQOsBZZTN(}nYe7YKhNyg_(}utE5O@C)HL!XJcO2(li2VMy3Ym?P{c z%oi33Y2lOkdkbmRmEkJkP~izenpt7`iNadpOyL~iSwdPTqWn_f3gK^rtAy7JX=94= zw+S~2e@6H994VYGoF_b6c%kr0VOqA<+g*69aF}p{@KoXX zLVnqg?YLfehp=AwkdTJ(D7QyQyKW305YjFc!$%79gx!Swg+qkngf+t1!n1`J39lC3 zBz!=)UDyK`ye#)P;Yi_$!n=f9gpUbNIa23aD!i_(4*yoTS@@Ljb>RoXZ-rU7N5JxX z3kM48gufQvBy14AEc{N`zP;AdRd}+nPPkBbx$p*|)j{VA3oC^)gjWk66Fx6|L-?-n zbK&>G*|?BpyDk-8E4))!FMLw?itum34~1U~y+>(%nZl035@CgKu&`D*TX?qcLg5u8 z)}l8__)hXd!+1dWr0`FY-X!6-g`W$56b2(Ye;NtBt%YU6zQW^$wZbcfzZE`BqTgO2 zaZLVzM7_QidUAC*Kq9>>3Hd%G=JW}Yev0r^i9e5o+{Gm3%o^b>5`PDY?GX~?Jucx_ zN#xr_c1ArU-Rz|0!onj+r1vKwKbY)_`$CdFTR30hFC!thnk>h0P`Fv*w~&1e<9YHz z^oN9-N#y&4JPuo)P7jcX&y;XPSSlA_|al)a(lZA_gzY*Rmd`!5TM0>s< zN8nAB0ub#9k%(_C;dT-(kZ_TNdrG*kga=7@sD#Io=i@uNB=nytTqAszL^+M*7<`{s z!XJ~UM~mVcbBT0y6?6>hqw)KPKU)B>b|3cM0E> z_)p1MFbhROPfDR?k+52LB8l>*lhX|2d=lj?m-x#iyh_6BBz%wXcM|_Fc{aY#PC`$k zaIetYMaSm|dk80!ET25rFy>15Tyi${8wsxxt`}}3?>CJ5B)pZZ$Nee^zd$zN{;!1h z3p0xlkMg<;M+j#M&lcV+d{X$Hutk_rto0NLj}y)iE)#ALJ|WyC{7PuR@wo04rV4Qg zR`ED2Dq>nImI%v)eT4mm#|tslmHcGk$wCZ`ia$+=TdXR4fpCRzrSNLuYT=#2dxYq6 zmH$EE)57P3e-^$bd{6kH@N?llpi#Isf7db$-YC3Tc)#!g;U9(SzA5BssDtOf*M)BiX*!ef z`$+7g`-OiO;^iF`PZJ$XZ!PQ~%oWmR2h;lqj}=x4X@`U7%gI7Mzh-!vaFOsF;WFV0 zAx&%We7R2eTj8BTTF~J6?h)aW!e@nV2zLsbg}a5cvBCV`34aoLEFDj)8%#e!*g=>p zEF-J&97d?_*CKqJgw=gpgojIbjF48aneSwwx}S?M4RA1ivG4-na^Xth6~fiR8-%wA zZxhmj2lYKH+%9}dNW(x(e?|C)aHp_YxLZgQAe8?>XnJ+nCkzS0LUq5m8u#HPOrs&p zUn=Y^>?f=eMuo=<#|S42PZmxSo+hLj66!x!c%kqT;g!N`glmQCg?9)y3jaWk!2A+E zDSTG=vam_GL%2(*?qehWClcN#+%KfH59&`9wi31$()m$^^SE%muBmAR;`D~Ku zeqmUcEo>*G6++5&7xoek5LOC@2uBFj^8w_WDB)V+bm45_JmGSodVYX>S4eo3kOpyC zkDG+I3GWit3m+6dBHS))622jPOZcwvBjIPluZ71f@EqYv;T1yKieUa5gtS}2_3gdF2H``(M}?0I zY1oAFe-XYVd{_99@G~JTpHN;sHvv;@9j28Z#vdVUBa8_1g~h^dLiJn)`Kly5Oh^kY z)Q4$nc$UfYc^R;PGNU!`N?^keF}FNc8JU67`^SuY=JIsvaR>m_&VWTTfBd6ZOLFCRM)(iTdRW zRlQM9wO$5Q{ZZeZOb07S)O&!il0^McWkuC4v|}X0plTly$1@D7cA{NsT@BVU9_^bh ztRvCRIYQNbw09xHpy~&-`+SDMleq3d|8FGG|LQq5+WP{-Xy=6 zK(ym167^T>A=Gyg!>H$tBjeZG>P^!OL#X~ zjrTiD5aoqPw2$w-GF(QYood~Wuv+({z4Ik~A&GXclJFW5?f<0?P30wu+HaVrC;zz| zhDEtt{HGkcS-E66rqQ8m)H^OeCpR2&$>p+79p@Df=ev!qQo_v`m|FN3W1|c=?pu}E zsL!eI)9|~UQ@>v!68`xYN+RW$pL*yVo(R9Y+{!ccF@@y@M2`8^Vsp3SC4@uR9Ovlc z{^8a)+NF>2l%u|@u({i@17Wvw+VML?y4yiH=BF+?r`&ttcb8l1Dwp+i%KZd>cRQL9 zK2$qiK)hSue3w2vx{K*!es?=QL)h({c2Ed^vGJfB+d*A)PCNb%zq{OJu5vR)j`;>? zeX;rc4dM>f4qk7&^{sO0%W~=KA^Mzor5c5F$01p{v05(H4$84U)J5mC;{?RJ%iZ8A z7mrM0{dcw27i$NP4~J^U+$4SVE`2#JeHV*9rybb{yPXrfOUuRDK{>XAy6BvC+=h5} zJ05qH%VUZ&uin-AV(nnRAF3TsCFyH)>FeOq_gB&9w4)GVw{wEL|A4<(J1EC?P#2xk z4&JYDx1-rrZbammuPX|KXsjJPE+48L8IW`9+w0QT$)zt(^a09o-nyL=9H`}D?Vud% zLtS)EJC1>zyIlU1BaCz&uL?wt`FLN1y17oGt482Z?cn*_tuO4-$78%RzVk#Mpd8On zZs!EA)N-+QP>%JXE;^?jd>_tTZp2k?k;pM0@5fNL(~ijq9I736C+RD5=__&RdsOrR z%1w7FE@3CgbqoBlc2JJ>p)NY79e+(Kx6)N^H<4pLu5+l{X~!G{dLZmLr#{~%=^G7w z+$TA{-LX02!TUv&KVEhKXbRE5^~I6DZk) zp|2Y8j&tI2QPe_ z^T+Wb$9!{=+R*}ilc`9Yqi=AMzA*GvLWb=ah0SRP?;pC`L6e+r$27Xjv|Owmlw*CU zi_Xc$_ix?p80~7uSdnAC%}M3*K5!-#iF3+*RpgxRoddZ-M+kJveI=>fT9g|>I@>!z zmO9k?SdPPW>K*T>F?*ynbbnbN99Z1r*1Nzox>v=WZr7t5{A5P>EXHvNIlvKYUcSe_U>UY^8uW^kX1F38efSyVqJ?uxr2}XC%_M zPxrD4Mnq~;em!_()HEGUY)fIRJt*GDpQzG&JsCjS7sjVX_#tm}Swm%Au;IXWKONX0 zj5v&L`zTzAl6b@)Csxyj?Z8W;H zduw*xja9vyT6YOHWkz3aF*a01`$snn@pcUC>e~FrsxD0fRV@l1G4o3w*jU$v^*>Nn zdsK6msI`%PU&n{HkJ@{n$B}O`H)7X18hmdZ-C(WlqVkv3T5Bn7HG86-W?YyycZ!Ci zzWQw+?Y&r6xMqcy^&NFt{px7mH%4`EMo&>z(y)yBrPV3Tz2Ntz81Q?W%aO{Iv;w13VC{t5ELD?b(Xy?9 zwWx6))@NC?vf1doHCn0CmJiN(wK6(P`CF~C>Q+~!HTiEE6U|y@cCM_u@}podFY39r zhf24iIa}?0rv2_7Bd;>*Tdn%yrqoB$Fos7p8{J-Nd_VBQ>n(fwif*R+Z^~MSlDj8r zs@&QSGP<7v9Y6fr+k0}NHhbpkzoBbh#r6WW=X5t2_4fytaUNb$AB={Fc{h3PHCCTf z?b~Fowl=X0Z((MWXYGN)^c~iX2fC#0@UA;h6x`vv=|Hh>M`XSknL7Wr`R~s+nvICR z9`kg2g`;<)Z&}MjfoRsO>}a^yY%(G(+s14iJ8MjPvuWB?vw2UP0cxdRgV~jyBqUndCNOB!;*UR%Bq~krKhwq@7h;p)cmmQ?~m@Y zGt3>HL8;Am?Hg$L3e6pTj`hMn75?XTOggs5AhXx*J((%*j?b$;aem$`PkG){6Lnzq zHeoLBeW;_?R~M>l^@g=KY^|y47WM8}Q?<{@s;UMW-A-(Z1SY?}b)S(jp{ea& zZ$_YLU_<_1(|c6Z>@{QXuGa=N8(oGr8b#kU4Q{p{=oH9${h3cg9;+y0XHL|6qqmc_ z`sJ43e=Mv(@TVy*KE6XHUB&)RVV2;u+YlP0?R>mi4!bU*FlOxzpZ=HL!o1 zVr%DZ`^qf4*t5e6`9JL`E%G;I@AYM5HgO*?^B>#OwJ5b|TEKq2dau{}hdoI1T1{KA z*BWn4+WIp3pfWl&+9P^WG{BiX3U$~X{4``g_i4cQr%!F$-gls{jrQL(c*tu!j&OhI z5iOQ^bxh;)pQZ*GUtc{edT#p>vQMpi!2hYwK4$BA=tXbS6N9@nzVP+qW=iuT`>YKA z&Lf7EMZKNQsb+hd8;o4k)LJ{()3o4}qT;N^;nAwW;YN&e|JyM`?ZWSNqV>kWiZ+E` z?d)2-x3Nt_Y4PWcMzfh8(RIGs*#0n13C{7g{(gVbyqXpD-^8+vb+=Uon@lQvSG$kuRkIpRNW z`f87NYf03|tB3|y=c0G=q89s7opGpJ&-hK4gWo-r7CkcRkLIZJlt21WLqS8K(&mdc zHiROqr8ipN(7$e6!=1H8UT$>7M?;MYb!?y9U`8U%l&GjR3cqZ!ntf4k)M)lbXXd32 zH&$myQb!ETJ-7Ni)vwtN`YhGDp-ky7j2@xN)b;6veK%i@FRT}|#?FPA4c4%8s?BB( z{xhD}6&tpVcOJ8*I)-_VI6jd`LU)Rm6T7kM3 ze$l8~A3={{Pu(7Y9&U8pXOs19_!sq+J#=xsQ4oq+*A3jdIj^hgwUQA_Rj*a4TJenC zwb;8IN1X!t%Zja4*2ZI-)_iZ4VIEqOiz}KuJ#$r`1{?AwF2I?Tt=*p2Zg_UYSUoeh z?FeTKjL6Z=y(As8&4<}mV6D}?8+#6mMD_mpQA3ZI|KWzRn15wMY0N*lp(N%nY$%HP zgIf>e{)Zd#V*Zs4xiSCbhNEKs!iEkpf6i7Tue{cbv}yh{uZ`-joDoZ6 zvwe15>tX%~)=oI%a^+^O-c;vVodqBJz=(M3=Wlxn{q!`pN3lJKZ8NqzuJKRz%JbK^SJ)*mfv!0d>cx!s~^`$EB1&6QuJW{ps7 z9xi+MlIF@SX@z!UN@1YUgB4;)VR>VAi|xegJv*^hYPRmBPMu<{_43HOJc9EKA-5V`zXfw=;8lC!eKBqdhdDJ)C z7qnKjYwbGbwr#$*D*U(lldWRTeN!!8ahn~Jj`?UyIpP|1##P&Eg zjyd;PjxCRm`g#%X=%YX9WB(0e4`y$5kNTpKXp!*9i@%j?=bkXo1efK`{bHFM|^b<`=WEv&1@xp0d*MtGyEw$>{jX8+bg z7r29y_l1p%>mRG*C@S=yy_P3F-6geXqi6Gc1(M- z3qouQHxsQPjl$2cMn1CHywAwjd&i2Zj91H|`ds3v!x5&)*HjptqU%!lQKQ-OlRf5I z_j<+XG$FU*p)B+eHDWJN)Ed0#6T6Om$FxFR;TqeW=l;CLW&fypKt~qlF8#%I-e}G& zoj;I}--k6J^=Vyfe_OQQ(Wm>sC}_wn!rIeR$4PIrrNO*kmws_ot5>^7P5e!H34fqYzrq+hA;Qizm? zSAlRFEp_cOFcAGseF(F*pBi=U;g}8O!PVVH7zGh^rs$W8mH4tE?Dc``Z0RGTaCl>I zec+a9?LAH5(u$^{=5T4RM*AkKxW_I}lTq4jSFqVrY&8vNco6p#Jk9GLc(AIV(I{#C z=D=ttnN<~SjNE7Ug*|M+T~)b_-hE*s_^H=i)~-jp3N_b{Yz`uQP&C-bdU18tkd|O* zZFESBxBdR6l;)DCjrEJ3pGIN!c5gnGp3Pyb-c!`Enrj)l`pq`xj33v}M?^EXvWGL8 zJ)8A-d9YU8--urWVl1xwD8niWPKAe-yXr1b1e>8||{d9Fi^dVZ!??c^kFRRz{Rp;)8vzX3d6n@vZ2rK^~ZE~Z7Cg>7;(H#xv zw69Zb4>|u0jgL@%kqi?qa)w#dyn#-y?Xbl z=sU1#Q1#%bQ82yK`7@Tx?b_945PgZVRZg3i>ZYMFe(Z$7Ms(oFaf6M8XDyn6?}(mb zOc^}RI0ql$o;h_6jPss=rwb>Hf?-XVm7BJ3*1Wm>j1n3m0#qIPIks-*Pd#hFjG8&K zVDTmP-MzslOgMhkD)twV#@E_|16*4)#K4kPugPy9De$8!&J1m1-l=g05+ z*jeH{ULVZx7#5G$*6V%n-|G$VLkKY2eLtQvSeM`iske})bFUe^4Y|D@-|`gY|lS8D3aQ_ae+SDb)Ud?7ew(9L3c>Ts=J+&1f{T zBnwN}#va+Sk&U%^w~;JMmTb$GWv$+@J!ly%AWK4aiSVBlb2uUCT z0tqC%$;-YZVTZ5Ql+Ty9Zd6(rbg>6#gY&@`L2#4=#X4lK+cvYVd7%>*U`r z%EC5ru*whk55#9FGdBm^FW&%;fnNhmPk!k_z&h_Mq*1{hjH=0hA?($BUcCdbU-S9v zIe=4@Ifep!SCEgn0JZmBDd4xUA?^FRfMY1zca?ybp<2GH1ssIteBTg|XA{0}3V019 z^c@iJWHgTN8UguZ7~i!59-j{IpnxBteBX5f{)-&GB_Lm9@_k#tnUw510=`AQ*DptX zQa?BX55HmX4V%zkQFFh?cn~-hnh5Fqrg20V^$iWCBH}fEh7`XtQz^lXCo}(JNXYTG z8vNpBh@V^Ww;P+0MTKt0roO+!5PgNNWd5i`{GnHp5a~32&7wp91w-<8NlJQ%za#K> zO9XB540!r(dYQ%WMRUJ@jS)b}p)N+&8f{WcC9~8>#H-A2p=95WvOwjZ1Yt~mIKcOl zJj7GmU_bt3!&6HZt)NRbJ-13tbHOj!>!|`QSn#(VzT5dGaOy><=A_Vguha&POCQ6h+3s0g0rC?gA=sjZrWK28T)` za;@h^!2iz}f>p zHP#_g6-t6D3jEBt2tuz_=2yYNcgO9d-h_5d51jV_;NZ`h;{s`o;8!Tig*QXn-V}aC zGw>CfkU#hj*6Sj|=w@4?K;NDJBA+dgFe`8wUj+y*ri!n)8c!9(@T&q>lHMCUg*>l1 z2)sX71cM1&!>*eeMyzjCV1NS`zI7J%vH*8lG6#KcKJt#H!I*JNBK!ZsS?x$?O zy%lg)@L0Ipz=OX8oTJRoP^9nfm&kJh=+gs#I0~W%7gJXc-3J;K6f=BStS~4>@Caq| z2gL>+6%$Zq6oUGGmCtIwh+O`_@CNc(Pd=lxQx%+mXJ9vBbO8QH#CPu&(D=_pqPY(e z`0ndQJQb52m6bBx{3#-79V#Vk&O=8~X~X>kDrJT_3$QnIIx3MeQzHJfzG#<9$&-k- z#*|qSfxhRm4S#(v`IbS%{9w9S4_$=lXM-6+r9$tb=D|#p4&EF3CL{??G`FHx_(RX3 zU4mKW7$T{m575}bN#>=9q=&XZreLE`>OQX&56GMH=5LF;-$ zFH+7K=50vuhxl2epsr_Xs2(~C&efHc{un$)B3YpZSafinL~_#j-?PCYiAGo73lGZwi_UQ4DnXW;~37*-|7ur3KgUJK+%<^?uQEf`T$=~gyH8!f0Ipz+ulS->o zDRTwPN~`NpDaQz$pVn8bQVPuZ;8QA9OwkpoN*e@Gu~Z73e+b(1{g%J|33Nm9)YLVv z0G2T}buBBQWL!N?`l!RB)G|HC`X%a`X;Lygm5zrnAgnxQ7rs~}A! z)GT?$iG*4RBkwQJgueftLwn~B*1~CzUC6wA`6KP|PUKR->!H@Pr>GTwkgb>Y=j(t^ z4e|%JY0v!_aC-25bdR(bp9P#1BxTxPNRty>hz3r3Jqd+ORTHY#D&Iqwv#1GBXKC7B zkE6-ZBc{C-1c^!+P-*{@0mz%urPAIZkP;lBO*`UcuIZ37cgVa+~PEcu|5ef(US+#%C$K?ehY{P%CYvu z#tEBb0Q05|s0o`5*4UqRlA5qZz|^!ZHDRlO=^^TV!f_JG3Q_qJwo4=@^gI+XVW&i< zrVXkI5dp(u;S*Yge_n{qGNIjIyX1%1E)zNoHcY-KbwX5>I!}~3p;MGvECb|(E~6N7 zE)1Orktg&RixGjk|Ae~x9(@XR^7nzWIRxo^PrSzXRL0MTfWD_bW_$t09P>ix*Z1cn zw2c1;j3+@|zUPiWJoRK`O;11Q*^Gz?lYX6t9z}cD^zVAu_TCW3vGiL!O(@?VnhVL( zZ}nV*2u9f)3iDbUnH>ebwHePD+h9S`_8HH++CJk&SKDX2Y~0QK()JmzNF+VP;XC6s z<9VcHi6LaXVFb~sb=zmWWh_HvYUp%SBI7+{5Rq``W0ainfkg5`{DxV^M-s^o6_DE} z5}6nJ8Of47S0Ybw=zYkX;rILkk%ggr*kwkF=S@VGO0#98Nv%u8tTNI)si0mNs)pmr z$n-2iq$=ctZZony8xdKnCN$FEUXP;IsXI|-ZN_xZE~rA9FeB{g1eHqbQyDWnv@vg5 z6yLlN(2wykBTv9o7-7aN0n=fG8M6h<3h}F!8AnSbC-ieh@+C4gbPvkQm?M#J=ph(Y z#xb6gP*k4SQAVMMol{#_Mv*k?JYBtFsa|pDU2>c6p;aynHDDr^vDibaTo^hRR*|tp zB1=PbR2fSpQX29gJ)_LC1T|V2;x8#PDm=SIC6}NhWK??YK+0Mb_zgV5RR7+GpayXw z{xfJuD)<1J&VS}QNb3#u;psn%us`@H2>oYQPJ;?lIEVG`Yk@%N!A~Ka|D3hJXQgzs zDgU__feYq6cR_aF`+q{Nz&l`>6?iijCK@~&jTm@~{X+%$9f`o(guTIb=qm6(UMY$T zn7}(+zoZ6#h-cv47eIr#20vKn``bM53CxD`SQvQXZt|2l*;Aa8p(+q3@HAnso=g3a z^D2Lk>!84&I9E#zZib2ifBqeL>N(sq#Al_P7~P`+&vFiz6PyJ}0?%wgo@4^qp4&k4^9{e;{MumF z#Q?BL`V=%hamNNBXu?x?bpgn99>}^&(ueRoB2bDdXH9Iq8<7-F-X^xs11lv{n28-k zdxOI;<%wOy`-AI1Kk)>@slmrljfuT1KOI~z0?vF3Mlx~NFi_?vcuf2`TPtuLJHW&{ z{{~F(F~Ae={0%@H%6TVWYWx~)nEe7es*!yjjMS5TBzTzFd>PT3{cAK;QuZ8ReA)cm zb8_|&p8o6`U}Ayn7hsMl+5F^wFuNF9OwCS5YlO0AfLmJjC4eVn@53`ado|{|8QGIj zYG!sm1Ih1WM>beQaRa+fjKh!EU0sG_5;97$-X8P=EW}w zs-v<)kYQSO7CP4SY<{FQoP8Ad=Rye&qB6-m_wsr9H1k23b;b+829ATdc(We*1aQjG zi7M;ie*!{XUW7t?UZPEYurl~sDtP(4nUt7z%++(IJj5RE0ZJPM6Epb$HJ2RH*j!a; zYKIWXE6I%6xz5nZw=p+SNRHUaTzSNDBV{jBSO!-fE-8r0WQ&95Dmyn9Btiq^U3NyU zMO+yTM3MX$0#q8$WUj)b2(AV)k>c15|G@p=C#+3CrB-eZw1xn4l-hy_kT z)1@YVK({0wD)~dwVP6gZ6rTJM1^3FTI{9N3-w zPuaEez9TT_%s%h;<;g8cpVvgs@OjhZd7WVL1U^!pXF=hq-$ujulbQp@LMo~c|$+2|VpOTT)`M!K9famd6ax6k`? zoANV<@*#BjOh%EcXa!uH`n)d#hK>H`0w*rJIn8lyZi5eV<1!3WP z0}vA~I0{dZXbXT$KEQ@c9iO*`NvGk#JCklVa~_gyB69Y5J4i%@{Fp@YxJ$@m4?82M ze-3Q2=FZ(1pO;ekycggpOg><)de%5roRm(+Abi*+%tKR)Ael=jQjA(MORA+#j?_Ny z-;vSh<*L-@eFh%b=j8&*=Vfl6w~jrUdk05)({J#69Wm*y={NFUC)DJ@p;ncClg4)t z{+@@5n%vQ?(r@;##V1GGRr>cmrN{|(TrK##-yze_q?98$lcbWkLdYb4r2h~>1{L}^ zk$eF8Cj`kl|8JPiOk6K$Gm&aag~b*sT^avkQ*%L)NFB>(6_WuX;oVDW3Y003u$4xR zX;iG;=OxzXuaq7WIPA(d3o;PpDmor1znG4G8YHPA`~=y^8vcPwY@?yi04rk z5&IR^qUJ2Yo{#6$%ka>HyLlpWth-jyzKdrDbKGsGXRd@Y^vG;3g`WNE9~8=mNy&zK z#i1+$rQ)9T|{kO1nGN$5zJ2RUPmXOIPWdBeok3uAQ1|ESwfPATc`_q7f zV;G$LJ6MVe?ni_BcM|rd;GdrS$MX}z{vbaL?{8}b6D*`KWcb^615Quj|9AO2Sk0^y z{$rOv$|~gm9>T$m4|%7i;9yqydyWAd27Xleds&&h6#hM$e-|al2Yyib2Ul9F1Ym@#&->6tPIV1oY5n(<|5 zv%n27%yj?gIa^0w` zNG2bs8Tm=WlS3>SDIXwZDtX0WgFs9r*Esvg1;X41pX@*73S{$nd0qkk4|MVprhOMZ z*?*zf&IPFe{nwohbTEzG=v%Rq8vnPgW3x3>{&#kQCNRuK^k4rI(%(<5+`xIC3cg5N zyOA&k-5)V>)5V~f=Jo%aABLXJiJ|`vRx`{G`}yxAHk?lt{erW$@HI4uUkb=CUHR`~ z+2JIXd^Z>3;YG;nzvm=oy9oZn|0|&#AhUb9D-d4CZ1++8={*C=f4?A?uugIsGrgyE zk@EkRxuy@|2-*KTl7_jJ;D3;XK}A%9&&$dMzQK;k${rjH7Y!N2(Z4?o3>JX7#LqBUAfl1GX5q73pif5{fz{D8>^X z0Q7Uw486U0L>S_&VN<;%;5GC*FUtX#&&#i92lhhGss86{L8xVXL1dII0skwXfW#XN zQ^;4TK}_nu%dY?06wv#;%;n!Cmazk14*y@mSm7C##FO!qK5-3zOs*jGtSAO8QMhua z8lB!}L6SC%zt=Omy_=}V&H57aW5(NX z*2XH2u_hNk-2|^y9=g%I*Ps``9Jljc2Xmv!LmBeQ;q3v>LveXL2sNr@b8FUjKxnKH znproqMr(ye&HfBTo{Om;vlT@g-EPHH{#2HHiEOSJKV|8yj7llnDBvZ+VP=~$_G|2K zphdt^_A9VI<5DSmPLDD!w@OY%a9u|jdxZF?8C^HNgJ9m56M37pJ5wwXS2T5qFkeyx!$92)!sX(q}$P1 z0p9~y9g|0PBLwFXI&eLx=iTZdk|3`FbR3nr1^}B>09d^Mh4~gxWYn7<8ub)_r#;1Q z7~qf#Hnef_{R^0t@E`AieHbEE0?Y4g3L7W){NJIQ7?0>x3=+W#d1uZUo9%&p!se z+}J7yWr(U9a2p45U;(V%R+B#S0_0q{3=<@a?qSAv(Zsi!-C>lAS}hba-)6Go@mnLy zp^a^Fc_t*41v!(PNs zXZ=qTzAG3PRqhp4?nJzdFPs=>m`8;17bJ{}U7cyt!#;`lB6xwbg!_yn#7#Ni+|}Q6?5~zF5R*h?nkz9_WRx zoDJG8?Bp0Xn;c*+A#pP0{JxmicMvbX2!uC4b8R4|HuvCJPn|Bi1u5(zMMe{vgAF+< z6ep`9&uM;hzt@M*>p6u{W$v#Bx6&t(ClB|LQ23(0s4{+MQuq9b=pyOx4@$}Z#gd-` z-5*f$b5_YT7Ad*lC8WHLlx3d)7*B-2=Z6(REc0K;yaMGybfXxO^U>h(x6rrjZ}zG3 zK`_o;i#O(k$U>e0X`0Z_1l{bGYwq{8jc2)O`HxOc{4N)w~=WP|Z2$9-qNZk-~9h zAu3kF4MmG`FXJOa@cwtoKKNURFB($DFTKpk>Dp3isuo#Skl{1lIlwPz1MX%dF4+vg zfL~j(9spmBS!I(}^#QXJn5r=VJobVOk;k=1YvbMx*e5fS>NmoGam~kV9JqK6{xS5U zFu?lN|7OszdQvWe#w9ZlTn|pGQvmorb?x-8a@nhS;X zV#4IX7^~g})gmafUt%*bs;FgXVYL!fg8iHOm5=to9^9a<0v1xkdcbMJ9Jpg)ye0w| z4}ddgSvopX8tpYbqY*h?*R!cU`ocFQ3uiZf6^dCuU;C{v-1KfyRsWeyH)H zxgWZu{gIZoDi!oU7MfXg935^Gcn<3M6ODZmJ<+&b3wRsnc0bhu&d;J1uM|%UDb%Y5 zq6hXC*v-1qq@Y`&a^0*e#le4%aS^OS(zy+$o3%pH*FhdVyj05Yax3CxqS7j%e-rV= zv>mqMQryORvwNOW>j!{a-@(T=JZhO#bt<4tOgyX32e6vJr2skzTnpf00Bg5^a19t# zeIJ-xnDlc1zXza}-GIl{YsHrt3t=Jj<8T~FV`@arK-yxO1m`znh!`8qodxK4)6i7> zzqcis0Fp5yT;c9qJPqIgfLgMu;{QS1jab!U051`!1n?n& zS^yK#;8j}ytN>8n2m#ndC!=%@N1Scg!;zkOV2)wW5BQ}s60fm{IikT)8?=9WbhC+< zT?t}W{p&Ht;VPVK@n8q~&}ae!1dZCGqSMVk4e7={%Z$;SRL+5;3js-g-zRo;0z}t_ zu}`e>3dY4S&XM$c85gTPN77$FT=(~L?f%Yx#gd*p3B13&H_I%Ob0a+{;R{t<)bMJ? zZ5;R?a9J`4R5Gl5$*BNp2%Hb#N&=Sx;2*#(xfZ|#%tESewrFZE0R#L53lFBPXBPa* z3lFlBRH0piOyzLC(gJ_bLMM%=VKo&xOd16+1F~5dw3tz>3hO}5P8F}^BDg!G;@a?2 z`kT$O2;-t8#(}v=nkSR2%^YN+D0d!DIt+>KXY`lsy<155G@^BWI-6}=$avsc>W-#+ zIqo*(-O4Eck5NajMsy?o?;Q?(6H@Cx2b+~(l7yKPDwl@G9q2J%EuzF?Fy-(ng8P<* zgJUh{H0UAF-L7#)sVXl8>J^|K6jTFzvMN{&9QU2dPXLex-~%hsUjgn$l~}63Q%_kq zK~91wEEk!}PevZ%j0iiK;2 zV!w|Bt=L^uEDv6_Vt3KmO~tZZE4Gh{EkjgRZnP|?{TgK6VXp!={9yw4?zKzFky8HY zl(Ltl@E~yBT8>0Qce+!`=`7_=L>HukjHRdz7ok%a=h*xp6r|o(VoQAvoAeonpU`E2 zNK1V#`Ed)OFva5MNNp`zH~f~?_EmD>h2{eL^!Z@GZ5!jO1be}t0n4KGxh}2!j zf#qx5@4u7LOMo{nA&-9`Dkd}=`79HHsi}o%>Zc(zdIM*tGF4OMvynn0_(Z38;*8*O zRRAxpHX?o5QUFl^u~u%HX0vSWo}zQ}LmTMzw;??X#?jb@$>xoe9aEjUBVakkP2|ypw7OSmW#6OqoXY5% zXdfND3(=-Qoah=iGxa${rJgKL*Rue=Lmfap%jvRi1aQ>?sW3Vt8)AR2D%ge;HcWXR z05;`)7Ky(TBzAxPl`3H0{WS?M1n?&S&uc>XJXs8rNx@APlV$8A9|A+iJ`7l^=V?~$ z5xXa_a~KD1r+UOOKEg~qPnstxc!Vk_g;I1+c$7V16j9x_k5hR!BdS&K1ex-PMf}|{ z(DT{gi_)#G4JpgH=wOfhj-=S*u~x+hY?L05-ifNA%o`pILcnKjaq|p{yKu4He9zJ~ z|BLd8BY2jlnfdS*b-&<}^?AzIjHq_aZ&5SSJXK&|nISUB)=&N-r_gdX8MlKrsz!1t_matgI8myI~6L z$BfHJuj5xu#uSp@nl`*rre}Xg+5ckdY9tByD@ZPrg^N$`Gs549Rjq+U+NxS)DzMd{ zxt7y&bMXJl5~(ISL%k|E9!UPpVZr$pP)_4y&-l5J**jpnLGm-3O@MV16Ue~9 z58&p{v!RetQ3%SG&#D;*vX`Mv?g>Z=NB$0|Mla(>jdMVC1LBKhe}7DJzRfsVNyh?k z4s5|a2J_Z2hLz&UqU27*R`77qIK^NoTF;{Pc}}z(*<}9o52;SQZ$vGaHq%hcmIF^^ z&=b0bM>AzF>MCwg?3|pWk|C8m6>#%Gt~@U>?m%{4)QoZ918~zj(U*wf?T2W(l9w1v zxS+^T6 zAn&G74hp%`_yq7`o((Jpa4T-(+s0=Qf60r$Z3GXsn1>P2iG1A)sX5@cMy6~W|j->ESI{n z;49G1B=lM#&=b>-tW3YMGsPyeW(wYKD*qP zQMdbbhXryrZsWie$HHD^+`C_zvJpF;CG9+a((wVr7s-ysZzbo&jLUGZZm za4qyBl^qrw#eb-3p7`+Uz-=7ZQHl~i1M2UfUXp}tGs8Ht$N;d4ouUf2pf>_7gu4JZ zNmV5L3NQt@)h2odw&jTgz!|O183qlAj;x>(0998|2Y`zcT=N$l2|$IJK1vt;Ky-Sib4aD6RuXafKxo&0)8K+k3L~x${se zx0A~k0-&zf3W>JV)xdGnce{myOD*RZ&pq)`i@5LAD>RrXf|I%7vbo@88JNtwn)#nw#;1;uY-HoW$Ci+v8hlURiwbBVKNBH~8NZSJ z?4R*Xho>sFlZ?Bqe3G>i;Ys~S1n${ z&^CO7QxW8Y59b8(MW-TLfHMxfQm(cAqG~vV$dp{ zMB>_)09*;mMXep!zck(i_y%j24?L~lR3PXp^+prqD&WlK0m!PXuKGk|cwjDP!F1xr-%C_SO;`%`FN$WsR$(Z|h$S@4f zP9KxyDMb>);t3_U;Pla+u9@9Guvg)g{bp|L%!k-tgIOETJ7NO`v8yYz*w2gD{C{UH z_VXh4j~%g}7qOpl#C}1<{uFUX&Z%HEj+|_{FOgFjSYbDh(w^RMD%V2)C0BG>o_MyFcq7_hCP%U>Y+1&Y$VPr7| z^|4G+C7k}~V#e=4nw-iE%3;c^^QqEdIm1xZb77~vUczl0SiK6a>{y`w4H=fK0k8^< zwUqUN8TY*+@O4`j0LAC5UiwVk+Jwj4o z3tBb{>r;dX*=DkLmEMa7^;^W+vXcCvqg4ASOazuah$Q>CN82Ta0No;2K@91LRvlmf zOFU5AdyWCff?FvW@i6Zlo>4SOOUrak-+rd~b=Dmhq}8TPh`X@xCL4 zN8Yx96xv;zl5y(M@QNapS1fEf;^h!hq}mBy(2E!)oX=_SaI}Wopf1_Pya&K}LSwJ- zPm@|;Oj=e5!WTrZ)_`~ftDfUX3lo85zF%!inl9WR?GMT;3Vuk)(P!F7Fa3=t2 z@DGyM=p9idd6Y!!5TxbZpr8(4jAdUoXtA`cMZevuR$FVD>8klW$Zvcu3IM6vhub*t zItWVoa6tRHmov2VIZ*rE=rxFQ!ClDsVlI|d68mi};*0PufhUQp{1Xr><2NV_Gier5 zFJmf(N^cT}%3m>tHb_chi#$$R{%YTf`{$w_+mY}->hViRL63nK1)ys=nep=Eg|2Ro zRbP&Nj|iR2-j+cRGT2fxv2MFa(_i$dsN%+^238IVpTYa*T0b=E46($Y-`d&R;$rYQ9E9PS4sYX_yWF4lF7Gl zGvzhL?E!E~?PSGyxS}~Rx7uEWo-!$)WpJvH$zO}YezF&dfz8`o--kIREB9k*|wPOjm2Hum;18_c=$yug; z?OlEWz=ztg039)a_lUrZ$`&Hba$yYlIdoS(IWN_nE|J3BTn~D7qceX9EhhY=Rt-@hH zvGO24$n`qu-DsU6poSB_-huAYn6&Q`S7;#ec_zNerK;8(-&t4N z`6IZt{x>X^b6dsj!u9lRtCi z#6OeE3AN)s=)ixze073Tgdq7D10Qj z^_yq~LY%qim#C#@UksFL?Sy8T$Z~Hsf6}T@2@3bvTECrf@;k%Igao6 zFbG(G2ZWwKlSutOtL)QhA}H`V$e*R zlGc))Veq$}o;(!{t_YfboH$NWX4>-LvB8>&So>Lcv=~0!6NG3!224txtr++xg1i)s z5twM0X~7_K^2doOA!YhCo2AGWMAYKSXsSb;MB{@iXhRsqhdvR#j0B98W`tU9Aqd%BfTR1~%{N+frpi~o#5C=1$2I{L`4 zSRKi0evGVUVjSTDU5dqeVN4s$wkTE`Mi(CiX&Q}|>@C5q(z+M{OGMVCOd(%8Wto+fOw7209YGD9m%bRnl70rnqC)#Q^tFutWqrraA@Oh$^^aES<+jL zxiQ7+R~g_^&$OC}3y<`mum(##7Ga}R0Y;J96P<1!s!sG(VvvFTNV8IS(MGX}~hb$L&>E@E;^J zS0~`#l}=z_mlfYAQ-z?BL8*Yv z3|8VM_eLqUPA4$f?j#V}s}mU5#WqT@S4u)7g9Dm|fh|F!qgNpH!HH^`4UjwywT(f$ zfK3d@8rWEMn(XQTi!|q24#=a54>DYd8?DZOauaRKkKVx&PPNbs_u&RL16^7(g9Esk zk>Rztkr7Y1I`ACDjZ6$q5wL-Q&ffyaxwZoWA%k@IBahnO%rGqQX%0`)vjx$@3@p-m z7pY_UBux|2Mg}A?)NwYYZaLD}S1JHQ@$E8;Hm*>sBuTP_vNK9(rF(7u9(9`6O+aN( zPYk8dYoUE}7eyg#+NARQu{g6IIYOnR%02|YAgfl-%xRy)tnk^PTDP#*(9NDV33bnClFe$6Bv-aP9U^TCoo_^Ist%l z>9QK_vfz?fP!?{CO$^8$SO$9JYh*y)z%r;6u#thTOEVz3ymlyGJeF|BBkkB?s*uvmdC&6I`K=W&0!1uv?m`cQ_AF#$Kl1Z;E**yyk|)FzuFC6AwtO#*YY3WGuck7H1*u?(~tj*FGjN6EAPHG-%qXP(%t5@JlX&;Vmvh*|7*c0&#LP}|mrtfL251kOc6@QhmunB*-AcqSI#xTSdCOIPQzY+ zbU2vp;VBo#ex2GFOKr3g<@YbTqT9w(&vKNclMkc!7{Othp9F*P@)Fg7+f=)ag9J{L z^hO3OOz?*a=;)34w@H@6^odPKWSKrx91i;+;m0L|GbuaXL9vg@bu&=62~{J5M{&cw zobEVN7K^P5F%^dUa6``wzG0zlRwUhP;TV#JO*E<_RxH_pkX1BX%>(6f0k zvN5zs59ef=?3ytmW{nF?wzsxCr6z19fql7z;~WY0&tQXq^$hB8Yi~t}d0pKGF?>l_ zWM-fTn-&JTs0Id_ZwmvPS%XYvH8ZE>k*>nHAuI#UY*UPxtfMtEo&i`wHoApubn)E; z66ey@l!26`#*Y!CB15_nTS~eSO3S_kILweaNn>ARs^yXSrB<5LHAxl1jj@1%ZrV)@ zF2Su;3c$HEZ36?X(iR5s8mk8eEzQ7Y5y`F*2AJ(UwLiRVOgWauNVImrE!+ zXTw24BzKKE%%DqYbeGcTqGf+^F3q=|!CKsh+CD1|{tR#^Ld`L-Y2)ip@!9$e(={=J zd;wb+9HX%exLitbjq`wFeuncUSvLAKB~8k?{tp#fHZb{ws3Lb_gn z28U)~Kzj7|ShfacyGUd2Kya@H@sx`x7vlzh2HzF1`DO&SYYSUh%x@>NIf0UkX_iwM1UQNtGD(v4pg{x0K-aQ`0S!m1iqKr# zpkY8E6HLhEs_kqIvP;g&L4kH1$uHh`UH+LlF|THzvo+e;fCW;nG(6cHkcENXq2Ncd z?L~Vmk5fn1CX5?-80c~w{Q=|dHZLKH+A+v8Yz-jdT$BJ+V(^lHn;6)%vD$Gp$`lw4 zp3db51VI>-3MiY!YXKhW1$4v6R*a_I#K5MF6-8Ml2{U@9@J_f`w0nB+#h&5kfoa*^NhxY61S z1_Z2UKtX|JaHYmFxK6+p1~&>=&w%2CmH}(Qp2v_?K{GS>NWc~b|JGOr{7n$@F_7{3Pcvzf&DN*1t%lCz$H7Q^YG>^dtYwTVF$ zZc_~z(kr&>$liklj@OaX54Hj5#_cjxrV-5r*`RA5jLg^J#(bW^@wjElMPLv&@OU~G zC52iT=v*?%XCr8}5c))DHZfR>COuSN+E>a5mM64Z7#uBN1A}Q|30oN09Ae6%hIHBW z3|J!k0t2=+gkz8+92^z?7O00MwUGfWG;U!@LN*=Oa(fY;VZjX9Tpl&Lm*Ed_L#YgI z#qCu?e^dtvk)vzL#n!k=P%R8@!krA(C3$<)3`QtVni@S_4jN|~f+z0xxKRVD?w{k3 z03}x~o)j5I$3PdpiGkKe0~t&b6>I_|*SUDI3ihEW;fp1H(&;=BCHydMKdP$FKW!;u z7$nO@75#t3i+rdfANC0-hpn%WtuHMMwMOx>60{aC>iDV1=3G8N&@hA90y;KA5|N@wooGCs$+*FXK`QP;JIG{Bz+k6< zEetwvA4)r22pSk@+D&fSShvXnfs1yFWOJ&=R9C4w)v4Z6q|#A9=(Px3y>EkHh zO9PS`cc!9KWrtd)IwItQn5zL4f~Q=CcoyRZiopT_ox+%t9Sx}rS_O1QW){RYz<9=h zO#wm%E=R+PfuIz@N&%gs8SNERoPmTi6$8z&g~3AH@hy`Mj7t%$h-=QpJlcZl8R*m& z2IS;Y0Ag-yp^6|b1GYnakvYJ)ns9~CI>J*RJx?iW5bVPzgNcVzKjZqYwtG1>D4T(1ebRz_@qmw5H-xSvFi^LRB>( znK_qM1izbWDcq5UBs#SzmKtZkX`q0t4CV{?ABdm{4<~|7J)8(SHBN*KEdqlq+`0h> z(F7nH1KNCi%K)Kt&IWhRhJ&%3G9=qMW3D5Xv(cTi(Ur5&U1t1Fhc1)M0FV4AmC;Ocj4AGBlNgVVDJ*|L#wRYOO{4jl6nTqal4vp8V(YA z6gLtWyo6gP0FaC3J8n)E|0M21$qy^|y&%Vo!JRX9=FLQxBqWMwO#)(Fa}LDZuPLz? zV2#Rv4GcXpSg5ghI#&uH^cn^v*5we&)(H%lEnWa1tkN3ooaofCY>jp{S663CYp*GO zxCqgN>7`FlGCJ$6s|E&k=`sDVA!ce?2E_t8J%|Fix@o4QZennRfb|T<(S&P3%8FR^ z$pXl_*Nf54&^WN8PLg89CF&l#T^(0e&%VA!9v_}kRB_v2`IUkYYT3yI~Zu`8pa{qjtRd< zvUugm$6O1tF}8T*#Eb5UR~UJD*;TzvbB|1Py(N~TYW?3Pp z5xng1IUSX$4?%9-@UqjnA;jw<9mq0}AkCClstz2v2CTR(m(9nnr;VR)(M`3&mlE>X zbW|^|eL9dQ>qghYUc>%qUts`j#A4i~xL4xdiQB$NUx=H%Diig(3OA1{?Td9{`fA*x zxM?-#E6)D=)+TPuRFF(ih1js6)sDB{Z zH#F3XPP8C0GTd8;&#mBn5)J95h`}0a>$Ae1ehU~OZ{%$6@3WweZjHfT8)+aqI-mjk@sS3Gy9cAK9U2}Q zZf!r&A{>i!v<}<3`nphQn`W@5uM03Lw5zqZx4&J(tONxiI=V~K;%CYl=x;kg1K5rL z0mhn-m62PdJYK_B=sP6LE%2DIN}KjuUSp!i<3c=Q0^xNbUiKJXkNLyBgQ>L9)KS6dlu3IWMMH=w^}JT?kyE^kNIb#bA8#ixH6yh85@r3u>@REyrSrYQ%{9luW+3cIauMGdFv2sBnpspdvrPCEZ!9TU z(G9W8aA9$7?nu%4qV;t}W?Nx-E;i3&ZSreq8I{@{&dr}S&rB&T&NYV$YgfkU@C~mK zUf*Tn5A6emGw_cNsEyedF3v5OiK?0@g)0ima?4ib#x?D)ea0elPdL2GtPYz;hRv>Z z@(i1uq7CyYwa&ch^mXTaclXMfW>+cnQBrYq*Il_4(~Gxm+*(^+TwYL8TnvHA%*@i< z6PJ_}6q#@AU03_9qJrGP#kD0X%gkrhFj#~yDEi^NnXKrUMi_q%8>`y6Nfdj<*Ji{C zc4?B4H7&ei!Hl967dM&%VKXz_b!<^wegCA4aEU0q&?i>n3;VWiEtxiRTCqguv`sft zOAiV~*lHR(EEH@}uE*z+kXqQZ)#rdWkqF0XsptOR-s*a>J%$mir?MZ4Pvrnd>}hu3{cF zpq1RMU1f6@#97d@z{4tZ=kN4&2?tjw=IC=FY=WYagRkX!@?1r{4_3upufbm9lyZj0 zD4Abm9u4~on~m&qp6?2iQeUw-MKo@<7n;TE%;wVKqO!7Y7Zp_$eajqMXHFZ5(DFyuDY3l%A;whasW7-O>=XJi4tti9r0XR;8QeXW&Wj|Qq z$#GTVep5Sz>A71)O4#v=xVF2K9@%ZFH=wK2jZl7i^pWDOvZAu(ZO6b##M$F{@SW2a zn|rkO1Er(u%T6{&rEkyPwtjkUQJdIWyi<76G$zf3J(hJHo4X>8-KUUrR?)G!MbmTF zADdg&9cSP#n#PQo%Vxq^>eBXvw{6{4yQ2)Aid8q$3gdeClgUQ7ta#h^=Eq@Q(AaOr zW8X|Ra%Y@b97p+p-&i-(Ea7yXe?3ra7Drs*0w%l1NQ+^#)bl*chp;sf<+Btf_8lR$DN6+_WIV ziAbb#Fd9|Sj-L9~!Qnl1t-GRXsORKpWY{LE-qIYYncpZ_PKs1(Z&&|d&v5rH6_t5M zJmDtQ*3*T*X^6BBk1729M|7}tI2z&qRS%sQ>Fnw25b{X<#@d=yTO+F~R;{hpnD*{y z`-ze6{-L;%o95T(KxfMG8`Qvr<0?D{gL**Va&*O4FGA2*%#fdI!AhY`$QYv zBf}m2yZh9@V9%(gKm}3s@W_B_JrRG}Wh=L(Mnz8=Y3+@)W0I(Qj*F#F3%aE@Zaat9n({T9MAGV)N>yR_#zT-E@|^QJpo_ zb=8d(wUN4t4b@FL(dM(NrhaX8qa~hJ;Ht*0_01b0Rivt-xx(EBJp+-}p>|Ar2LTNY zw6;Taw3rC>5sCH<4@x_TFPiL#HYuSKWHCICu++g`)iX3QFc2Nodfrq~+fq#n z!QaP6V9aeuh-m=$KJ>Dd0nEUos;9o9qhl~SWOX;Ic_NV!tQnS~8?|A54Q=|p{e4|wh@ytNTT3F{tW>bWCBr6B%H?=4vXkD>~fWFLLN|BJI&Z2tE*P??JB; zjxoNYSkL0y$S_M%Mew)ntU!PJaCDf`vfE>ct97lrE30rk2X)#_DP{6pg|IRMj}{lTuXHtby6uO-v8EnzU`Z z;WwjNUzHm-)>c>4Nym?Ngt5RLgjR>e5Ny+d$JD(+nq^gEt!|e7zTQ1U{kx)A7!J|R zw_$-EZH4>jjqXyBNPS~Xy1y%{3eAA`z?AY;jmgZ7MX2_SU}sK6L7Kg|C&$ zsuyC&u0TiANZT;H?2syI8A78MRSmAM-B?r=9XfHif1s#-u%EtcsHhF20nB@-7uycd zaFIM6`FU59lcX5sH5951jUNB4x=A)9lINTyLY(9VunGD ziq->6uhrg;^`eR;5$)!P!%)XI*o3j9W7j|l*8J%3ZGDklFt+HJ)#qG}Mhtr6s^;ou z+iGo7!SEtAqocy=x!Pm_gf~VQ8zTW5DX0y7BbL1;>aM?x<^$9@jcBU|A-t zO-A63T_=@jBV1M8*c_>7*&?j(c=Bsc5o-?er-!U}Y>l;AH!aO* z_YKu{x9wxU9a~sjY`ZCV9Qg5JxU|Z;$g1WoFb}8_J4o&D4D{!4AmUmEqg`-IFtZL6 zG%}2#mXib6J3Bpm<*uG#)Y`FbmB}ty;i(4A0FKm9?0O$Uxn;Yrtwi z1pH<$H(4SHt`}`crE9|-5oK1iVCZbDfvsbZfrxM#9IRpZkJ4q|S@*_3ds;i{6um!`JLEA`YCtAjKnovj|XA`0oie$@Pw-E)R|3}R-$RymFGZjO&0q4Wj3Q( zY0=$1Bf_~72Z#-rWs1wBRl%Y-x57x(!~Ms`=urR2V0*Nt1CxiI&K`(t*P|ZU9OdeM zSGlfwRWoOcmNgvG8+C_)X2}Y@4pX-whanqi(*iW(zyLbsP^6=$D{32}d(z2zcVPA> zvrfzWdNCofM)h_$SGZ~!Jsp2Ve`yQe(uBdT1N~#5pJ=fQ&8%lYVlY_DRj3#}!9(kE zsw#xypZeQ};CfcAVvAH&H?3-{si(hI*bKBA1w7a++UV)#o#LzDh@fa#(W=UES_QLH zg?UF*7smmed|XQd8br?kdK5i~>>f+GRx{fpCFGzx7}k!=nlWyG;cvk>KY|emI_iK+ z7{vIjixQ`+8_1cuur_q%tF-UrI%MsJid72p2Y8o0>1v!@gIQ#Fu(fZ9He;DzXWuxJ zI5M=yVLBJg1UV%iY~AfruXg{^7eLNYou&%2LV!74Z!bpajdttA^$(1p9Dx_i$Lvk! zCA#|3ax4zRQBUiTwhd=`h0ce4cLMJWJ4Y~7JEBCytxDs{q>^n87b1%fPQ4W;;t@=ghK4ZE zcPeZvi&vl!m@s1^iCwe7p16*oTLiN`=s~X{odVr6bXLwXe9pscp9BxB+C)@w2(jUsbIHm&_!?_g!R|;q z)&s2F7>yNmRn~%)B0D}O-i|QZy1ZuW6oF?wlUeQ%h72r#oQWKV z3A905-~5hfyTWV=!r}C0Sk=^TT8s%zMKhB(Y^-aR(ce}OwJO~Mf3c{0be&%K3}N;R z!^Og1%u=*3L)LKrFuFYo;fa*)VX&Ifo}r$Ya99#XFtp9@LyB9~6be$v)JMkc*s$K*(R+o7spg>2C`u4<}R9c|KbN>&3hlw5raz>xSY(e)`y+irdac9pKAv-3^=4(AT-m0n*Dunpy~BFW zZciAjDV6pd{eyZ#$E|qPF(8Ex%M<$P>D=RZP8gfs?x|86o3UXa-VPs&$AVukHpGF@ zp154oQx=MWDr1@m8^P?ClPL0zB-Ep3ev>s(5i^2A9*Xrs87XDeZTI&UOz6)4{N;esxS^Q!v(uwt9?D~0C>JyhI7)+a(fQ+e7Sr;w#S4Ma{;+^^WyCl>6j;?DOAaLD z=*CIk?dk0q-c#1ygTv51(Dj2~K_{0C1v1r%l38DW0hQ2>s&OpjVq2QTvNX#I;~g6; z3p)Xv;c(E=OJNL<_7E&u)*j7jckUnxS8HWxIePqeGF=>Yd$55ZZDvp2*>D31B+h>>q_CS_BN?es|*N$4T{AQzUFtm<20%70FfvZ=6 zsk1d@shDldJ;VWSxK^#T`vMKPVo3TgR(JiFSnk25GL{!Hn~3x2dI}(Z6%EXOV!5cc z)(-X(yLH#DuUf4uTv_AnZJ;d|!c_Zr$*yl)8_K-8b$A3TVCke4eZf_hYX`g<egX^QV4~X=CgIuzuG~;>`F^Wgi1(Dnvq#W2_tZ(6Kubk- zgVE9c6S1PyQeZjg>{X#3ui`e3Ze-}1|{w4Aej`;yM_o@<^*IqX*_NyFFRD$=rCsqy(c zbpA7ZXC|Fx*TXI2tA~@ZGHs>19KLo}k(Lw3Ck&i@H3NX~XZX)dKFcj@*d{>8S5zy; zp|M{jC23-tusz)AS%|yk;%lafa(!94yN#cd{HeNyA)Gs{P}0)(dCxJ=O>F->=*_9i z*-7KlXxS{CxM5@lOt?1Mz{s{ zc)Z;-+9nUxiJM0Ek3(tPa?oC&k2Abyn&Kne`Cmd>Wm=BAUC=Y)ZBWbM)B{bRU*Sbo zx#Hw>*@4?m$3Pj^k1Nxbf{k*_)x3$0-%_GUw2MdOA-q_nmjj(~YJQBTL%7ZFJT5JAr#5*f!5 z#$gzrs2MpM+=p%E1-o}s~3y!Se8 zyTo2^h$9nu^pUo8I+G|=eBwBg9ZKM0YR~x&sjJQvOFk^)coG+DIZGN}TAg%Qma$|P zyQoar$LD9I9hRXhT{v2vgDZW#-=E0#P=axIk54pi0TF$Q`DMk}WdA{7Zqo6Kl=aM) zmZ+)zlLBLuhcA!o{r{*)A^cBEb%>>4=Ou#JvA`i^j!QF6afhXgFUfvgA+c&sc8B1L z%7`P90uEV!Bo=Te!8iqsPc(ibaVtHskVHGiMm&hdDd_No?!vgfmR=S4A`48UI(%{C zQI22U7gR3BT9eoJ9T!spIe-heG&r(2u=`mB=?C zbsWCqPzYaV>pziYEMXjO@rjOd^*cP{&$noJap~i*9hXM9yS9xI1$8Hl!!t2i*wI49 zABErMnmnO#DdLiHoOGu4#&UNR!BY{5BQs>a4C=M8d3ke4@kx@UqAk2+!0n7Tu;0 zzOk1&5_!5(#^INcdZ>)DGn~lNRY5EtxPkqpvc{+!d7ZbC4$(vWI~n8g9*5#kzI@v$ zQS`WsLU0(ZIMO*pj&iW)f9U3BVnNi=_=MvW_yxrMT0qFB6m z!Iw}hS+eZQC`w`!dasj3FOC(B0imR@Vwan2mq5mS#@0|f6wW#+R34eT+o!(R<={Gbz9O!vTy>N#H*v#vG8Tj!NKvlv)Wq^%cg$ zgLKx1f7PO|qvR6+jB@W3Ujwl|7@_OzQRS)&c&2k-(1Y(@3|evS#e38u#A25zpA2)y z!wK?+V~K!F{HsO0K4z#hfoFL{<{50hwsecz%n7{y8>?T#M9?5XO3G zqW+gybUHBc@rd~HmL{YxPbiNcREb@td?3ReFH7K87E1(V!d~O$FHcCXNQhS^@T*Kn zuS(!oCG_VzR8{gRF-)~4p}aK?CjzFbNhq%-A$@&9yf%Sftfy#xbqW0H zgg)ja>(ref%(3dyG(o6_-{$zzeVU*I#fKFiCt#=AH_kw;}ZDub2+ig#Ale|<=>IOpWkPSU8a07 z*d0GUf&cNbL_j9Ku^P|6P3Z4;sM;Kefa!d|Mx#v?P2e9*pzliHPj4Q(Ow|*M05a7H z3H(k-NbgPH*DLfdIaIysH-Pym8GSt^AN)Pmj^abV4*`z#+Nadxh{t;AQ|gb1uX54z z%rn+Yo>H$MzQL9LCg6>(_`85(R``^Bx;Qp|KczlHdhA0_uy6Rbm{y)rKE#iA@pC`` zrhJVmhA~xtg1-7=i9&x;g1$}?`cjALBnKjZ@AM|bhZFb@C!~)i@E;X=ei~U{qc$L+ zDIXz=p-i<{D@HOGSwLg{Qn=q z&IQh@>HYuvoHLhm_MEviond6ubTv&=rVA!2qo&hU7eWz@E=;7R8L3`~UM<`?F_u=ga@MUbE-Dp0%F!to5wR-us-hFJ(rb=PFJp zb0dZU^N{SSq=0pAjQxA7G7$?{_r=)1FDCy#G4iAsdsTaSDh8}6G4`eyeV&UtVTv0u z3{*al%1I7bQ)BE;jnSVLV}F_zMqjWyob$73rhIW_sngGf0-hI{P$ghJ5>wwJl_j10 znKAXvw9Zt0rBLvjv!SXY0rMVV$a5R=cdwW<)nW2jGGkL6XFhy|>dV(h&XlmAMLyfVh#%9#Au zV(h(U^tn%W!fS5CFksF`s*(cM>oN9UugXL$fTw$&-k)n?@_9B>6#{s*<>~&ft;$3! zV7(n<@9miUcVp!BG4`sC+*AzU$=#>7@BNta8)D>*G4?jb-TbRR~zStPf7BZ&y_&VgYNn zdBYwP9e;Mmv82PIh`H&gEw93@Ol`%#F<{9=?Ndfb& z3$OgG^%wl5%emOn@x-fCe^oy1Mq=bfF>>^3$a_yKf1UMROgtrSKn#6Sf5NmXd{v_o){tmYulgw)m)BU$u zFUIJl>K#V*hM!sL=`AIh2|CBW=CjZG8d5!d)_AItG$K-#c z{AR}93)YvCvyA+bbwYB5kzcd^h$$aPK!yVQqk4>7BSx+bxvGEGSj|t9-?lD|(Z4!I zzBNXksPbb_ce?+5YnJ4RM&4vCkI}DsykoslRz2MM>Rz!|bxS#ayso??F7_HV$YZK5 zBtPv+DMxUA^K;_nvZR>nqGB!~>)I~A@>=tMy7H@QJN# z9e&2>+U`RB!;d0e+u;`&DC1%={5NHqnnF!Ysivk_Q&X;~Dbw@<@7)pj9aTS3|I3di z_!;S+bNKVoKj-jgqkqZ4&qb&GO!O~m_&w;KbND;ZzvSTepMTD|5WoBAN3^O7K+R29 z{rZ`UPy0DH&Gj3A$8VI5$mi7H%};>2pGx<3>Xs-y_QpIv!`u)MbH5>La&N2e$2*lP z6Wp7kcvVB?Ew%2mT)a2#=qXL6p!qS;43fFMx+*Q^7VoMIDxdZ+5Z&bM-U|x1Djy!f zQrwhymxA-)c;)igu>=26_t0tA;En@1){NcG9gL#ru~l# zyiQ1o?0nA^P3$OMI_P;Q%>O8QN_#H#@!l(V`o%ijOI2N>bNcNjl^4vILBEEB=?uB8s$|peZ5%nbZB_arMC}WGRyP!}(XJBl5fbVA{VdQK zuLu#@MKz(vklVo_>vQdABZ>XYklW3`w3FjZ`!HqUQKcs2x<8?yJcrnB=`)XIC$lNz zdGG}!KFG7lb}OHGcbVN<X(`YYF|GmndzKL zft#E+hy+TU-w7-A2L7)ePt_{(hg9VU5w+X;@ar##c4CMvyPeORW7|bOs}ORay3Z;i z-S&-uz<_p`^3ngJd`3+9F-~!ouZgIQ8f6ovim}%4m=2FT63*%=<2y_sD-* z`TUm3?&`DFgMkE}`3;2a+$?z;33;dFU6KJSmxI87c9`*OulbAq&PHZw~Ar2*XF9Jr zAfKj;et${nJ0yQA*+x64SC2&haF@yP!7j_PFZWq(NR-FaFzNhVCQuFgPZEChmfTlz zvE+f0OC%4GTq=2#*%4iQm z?qY}Rmn=l7UysCb!OSbzDOLJyB>d%gQ}2{ym^QK*Cv+0~hxRe0%yA`;#21G+1Xuy& zv%i>+t}-%qQARG5%>Juv-*QyK;Eo&G6@h494JCx!R}3oi17YX8mYNt3lg}T#8C?JR z$ggX(f5ALxgKQgv)0xD6vlt9;ks;)+b;$A zX5As3A@_ZUv|}U6<0Gr!@zL1b;Jm(s^N99}IY|(5xf5YPxj4YS-r4Wk{WM-EXT}NT z%y@%^&|~=`l9LP}my?+RcF;wpep4^nYy3fb^O)Y>DNlboQXZi4yC5*2d>UX6@|oAI z*!4}SmFs>L>d7~D-TVWN9?Pe&yqkU~CVjBRp4-C&*PAdeAEBKw4cRdGyOPR{{B*>AEZ9obq0y~V(g+ktEQbo z66>NX347O&us4u|y`jnntlU5N9|7&`4cJ)RMi1jqN*Uw8kn3|uJ+{|h!x=Y!EuZ=B zp3Go6coun%&#F!0wWy7i&hs4RUn)jLoQ#teiN{1V)#P(ONC5+4xxTLJZ-6qkvwiSLM8 z#9iV+@q6)C5wD^!_V^t-?bZr{V$e z2k{Tl4mkDlyKK`=vA)<$yhOZA>@5xwM~D-|2gSMKv*OF*R&lrZqsSc<+mS5R5YH7a z6}ySoiX|eyBWC$~#A)IJ@p*Bj__nx3`eZsIlKjp7LLE^(Ilr1-YD zMcgfZB_0>6;e>(ypCdLD&lfKhyNP|po5WG#-Qq*yd~vb3QhZ1JP~0p2B;tiO&b$y? zi=D-*#bM%jakBWR_>@>KzA0`JKM_9@zZQ>(Ka0PM31O#QN#Yq|T`^y5Ep`@rivz?` z@lJ7yI9q<p_+CZW4EiUx_EgzePL(#`ND=Vgs?cSSVg5-YAX~UlZ4h+r`htBjPDB z9w%I!Kj~sEF;8qMM#U?{VsWTAPP|`yM0{L)Rop7>7QYgYi+_rtRHt1TVjZ!u*ivjS z_7txZ2aBV{sp4Gm8SyP~qqtSvEq)~)7ylGPIMHRlWr(%K#$rpcy~uY9Q~x?~usB-0 zN1P@u5SNIriXV#KiYLTB#df%OgY}FSr;2mMXT%ladhtVXkNCCthv>%%G3^G$6fq*! z5VOSwVxHJcED+m>MPg@>??`7oeCaCLSL`pAh(pCu;yAHPykC4!d_KDw)>Bh#B(@Z95=V*?#F}S11U2+p*J7EEM~TW5k)_TjD|Sq*xbUV9>Ag#EZqt#p}fn#81UUe0R-qdE!;# zed43yB5}F+y7<0WfG^}|r-hVCtfUe6#I*JiZjF~#8<^_;?mF-UQ6Pf{$|Oe z$g_RcSf$@1J|NB%mysC9mr0y!Z6Q%^hvYAn{{x9*L1JAeKSQiRBKcS+tS`LN{gB%hL;*uZITn1ml^O3otT zPYcN{m0u*elkx|Mv&H4ge@lE<>HEa5#Tw^2_Ae28i6!EA@d*;`dY)`zS?`jZzhY{R zlYTJ?y#eC=;=|+xmbFmwQWE9g5I2dt#RDYtf0q2W7;Na2OD2(DLvmd)SLyA^R(K_< z((e(ck!asMvaMw;k^GACS4&gi0P-r?e% z;tcT#ahbSEd|&)jJShGk{w^jqa_m0p=lHZWLPVy$n+a!M``AZV@9466Ufjoy{67^+>HN|tqJQDgXCASqjlCXEHIGlvu z-O8UL&JY)f&xp&#*Tgj>%D*RhtN5u{A$}u%Pon;_8$0YM_7f+N822e;H_MtU`DqgV zE|L6-H;m0o|zTC#UgN>Xl3Y)66Uogbx0c*ia#zVcC0{G~MiTYhqV&;Z5WgEJ z{ULFYxKi9G?hsFi3Hgq_8e)`$KRw8Pmeo)4U=scel{`lBos$0}`9TupmMQ&Ja-e0s zC;3AXc6LhsT=GH5-$_0}qTC-!PiP8xh-GDvXkRT7cIrvSgBXn5TryrBY2>yf%3Z7U zLF5R_8YTHI5_TRCrz?G)WV}??)VD=Vm{67CC345Q4zlgjondx~X+Is;x#&SHNOFBGqc{LW6Iz6s)7agq3rxJmq6JR}|y6IwX!O(Q2-RxQa5 zNwmL-^t8n zmq5Z!8X3m=S9(LSwb)Y}B#srQicg9w#f{=V@wga|V?EnjU+hex{$At)yn0>ott9*y zA$h#yyCpv$c{+)5Pl>CQzn)xVSszLMoP@oj;%{Q`LMJ_$L_0DipCdU(a%0J@#12aD zD*0;3eI?&WRzv$qwBvU1L2;J&xVTDuTl`G?Qv6Q*S+olryVb>W#mh+e(VJY1`)DPP zAmRT#;v?chak;oge4B)wtz-)B5|X@+#PtaWNZ9{PY}V4zZ%r=8{k$aVyGb0P{M#kp zC(aa~5?6??lBjANKF7r!EL{QHSSy?-k`aFLTwiPcIi^V}C%8eBtB~kt{a zO2WA-<~gw5_%`aU>iry5*w4SS3vH-Gfqg@yHe@Jk_SmHm0Tv?N21(Z@lA2N_?7rGiF$mO zfV(W~EE4t9B$3`wa#ZX>Vm@Clc>sxWcZ&Cmv&FZ>9pVop?EXgXLq8XSsIQKAE{XhR zk}s6pR&oc)SCJ?`T6|XNE64+uwULC~-QwrU|3>onl7E%_7m0G`TcNKdoy}vkFTq152e-o41 zId&uBStRPq7dw#f>vHl0zGouQj$uk4CwYS8DUzp2eq3Cl^yMV%ydxe_{?FtucwToA zi2Bk<)RQ6kJjpF2Un04PM7e%qi8x7|OTymMn#ae_EcTrF-D4~lV}96PDv`CF>$f@uDDw~DW-OI?A8$r#H+<2;sfH7 z;``#);wkaWE{?r^;&^ec__DZG{6ah~S_u5UH%?3vQ^hmH8e(m+zKD;XraVsf4Y3lK(4i5_gE7i2KC-;$iWq_@nrXm=JL4HP^YJo^;7)i06p4#fD;Iv4zNcx7q$e zu}JJ9b{DS_dG9v$`-?YxqrT^Tak{Td}ifuGfRT>m~OWZx)A&cZufuJ?Kx7{E#?H zoGUIApB9&jy!V^!e^q>4G}rqf{XNM$#a&{B_@#J6{6YLh{9O!S-_3dw#S}4JtRprM z8;ecF0L+>lNWohU9u;j+igD5HA)l5j%)o#LLC2L~~su?Dv;^ zvp7_|Q@mT8F3uF65}y-a6<-%Oid)3JWE0D(5D$q*#1rDrVldIs4~x~sGsT)>9kB&@ z0q%bgFA>dklt}L^xtn;U*hefD2a30d!^FG9d&J4&RB^UAUtA%Q^hmH8e(m+zL+QGix-L)i=D-8;+0|_u~-}^-XabY zZxhFfcZ>Il4~o;p+2VZhd2zY8Qd}**FMc3?BJL3niAO|V$my?mF)XHuHN`rjxjq&B zdy(X**jc<@>@VIb4j1nir-+Y;kBZNbt#JM*mW!{5?~5OZ+r^K?y<&xUNIW8*5Pufq zZPeG+vO;2-7!k9?Y%yPKAzmzAB6bkFh}Vk!#2dw%#o^*;alBY2P8O$%GsQXL6XH|i zE8;3~t@y6^fw)!tSllfh5q}VW5q}p0_yEHGN)%JY>S7(Sf!IWBCSD}A5u;*fu@Bk7 zvaS;ciY21C?icwZC65#D5+{idiZjI7;u7%%@fC5ExL({K?hwuO!l?IvoA(OiEG{lSuN6-S9<#L41Rae=r{ zd`?^{zA3&fZV|VO72=oTkK!-lU!oshaBx3RT|85)CDs*l#U^4Kv8~uy>?U3%UL)R2 zcEk4^qPgB1@>t1ti}#7ML~|WD^cG5fT3jZUi|fSo;wJG!@pJKj_>K6Tcv3tiCgM98 zUKf!hri*8Y=ZNNda_Hqq&J!;XFA_V6mx;Z^-eNy-fOxYwR5aJ0qn@#n?-lC=Wxh@}ay5zIObHsXLj(DEfT)ap$*XP4dRI<4~A95eb*NKC~ z!D6XsuFHr19g-)A=DK{OPmw%Vd`x^sTq2t5@uB~Uai6$fJS-j+ ze<%A{*56`6bw{?vEHPU=S8OD<7B3Y$ie1I)$$|KMDh?KJ6(@-Iic`dg#5v*u@hR~+ zakcoSxL({K?jeU**5~3^;y2=t;xFP~qCeu4i-?(GEwQfHSZpd5ibY}@Hp*UL#&FmWrdq@nV_yAMpXv+|Pk}9+mu<_@r1a zz9Oy>*NOiXH;H@5yD)#muf%V}AH`q9zeIiq&vFqlQ>-P{75Pjd>NOG17tQ@9NH3IJ zBwit2EnYA77YB>CisQvHagz9;I76H*J}xd2mxwQjYs7Wp263~vSF8{ZiATiW$ccD< zkr;obBZtH^F(R7#YM@_7aznAP*h(xEJBVGxE5$xyu{cn?O&llQE#42*-W#uy|DbOZ1=R=p~7% z;u&HMv95To*hFk5UMyZB_7HoC*NXkb8^xQ&;o@j#Vz8;;%;%j_?7sR_^ZeVrLlkG#3V6QJVUG@))woFd1AhJp?I;_R*Z_>#LLA# z;&tLcu|ymujugji#^3F#ew8v{N5`L6Gw{U#Jj}%#L41x(cC`> zJI_jfUR)ur6xWFB#1F)+;>Y4{@rd|?__O$%7|L?mpDaeiOtH3DUu+^a6U}{$X!j+O zyNTw$Mx@^;`DSsrI9j|*yhnVPTy9yj#0BC)@i}p+xKdm#t`pabpNMGV%6v4NN?HWkkoTZx5Yckv3*+?R^}9w2#` zI8wY@yiYXur$YY;$xFo-#W%#Y;udkcct|`V{v!S^rqpu$OBeIReDQMf70bFxyiUA9 zEEPwIcZd_jhr~z3x#DBuGO=7-E50j!Law%~J>q`xEAba{t!4c#`m-H5K};5_iFL(u z#U^4iv8C8r>@Hp*UL#&F-YO0k$B5&_2gGUOqvAaAN%0x+74m({S|zR(-xYU=pNRX! z{o*n4q!_5}*h>^s#B{N?SYON&^TkWVc4B9-n|P(zM=TZxinoZv#Jj|M#D~ev*dK}u z#D(H>;!^QV@ojN~xLN#6{6hR%{8l_J{v^iLLH#@MTtqQdtS;6NYl`_|3-My{60w_j zx!6a%P8=eZinoh*i01xewC8@wv&dbz4q03%J}tf~zAnBkz9;S!cZr9@BjO41XYo(b zhu{2JZyLD|pEJd?#adz$v6UUi-*Od;$P%Z zZ1o+6#AGodW{P#h24Z8esn|~JAa)Zk7yF3Ui37zFafEoAc&B)`I76H*J}xd2&Hdu= zr(E(o;``zjal81L_=Whj_^tSdXf<&9$J|E_`$>||5o?S2eeoFqOdJ}xd2mxwQjuZXL}wW7Iy9qrvA`4iFH&yMu{l8=$U;Jyv< zckypA;an%5&t9fpmY6M`D>f1@65ELF#ZF=m(cCu=d)G?tCk`e5u&fc{Sn*DAqBu!> zM0`|yOng#&S$s`gE1LW9QO_pHABvxdd&K?XSK?3Nuc9xYukELIaU#VoO|c&^w) zY$jeLwh=EAdy2iqzM^?<0Q|T~@=$Svc!xMaykDFm&JbsdOT-t%x5RhEjp7z@r?^Y} zLOdv*5Y2N5(9S<4`x-j^mPX?G{)l+CSW9doHWOQlt;Mcl5Aka8TJdIas5n|2E0&29 z#TnvkaiRFMxKw;mTr0jS?hro__lf((!{Sl#C-GM?nCtXMSgbCdDb^J0hzS<-&vKqa z%j@p(b(y(N9;ch;x_ETAxgI>9#Am1i635O$vWfFtTV8+GgK{gq`@5}W6;tkj?-|H$ z_`QO>0{5qpy)CPZ>}Q$hC-e87>6C|9)*NyKerG13yqLTT`)_h0&ZEi6mbH#tU|Ac; zMV5K{8o$@rMR~bpRgn0cbC|^EjbkJ}SDYf>$3Gvq*?E38&lk=0^eCLkbetb$lQ?h4 zArIkxArkxf0uuYbLK6F*jwI$~4-)f`f#2oFi9s?;0D#tHq8t~cYbN?apu z5I2k4#GPUVxyyMzI(b;~QSlUsdHRQF#?eN9v;RRnvcSw+bDu<-#ueicVLE8W7xUQM zHvyV)#(b{Fe9(+H=5-!r(2P6gcMHm(8UI!o56YmK2N=&H%AlDK7_Y9BK{GG9;hpf5 z!QLeLv9DN6_SStEUkuiNPBsjv+C4t&)ii5z2D4~o-Cte=_U91?@O zKwL;-Jv}WhCKp)NGO?Uogz*$tk&7*Bjku0nZdvQa4I~DCv$&1K`r9e)BC!tliWMZ* z2lGixwiaRmiFMveoIqkeE+sMl){vNYTS&~eS^*IA%-r{Y`L%~K=2c=G zi1~C0iFq`DY>Ur9B<4*G*yMc4Cox~HATd9lCNV!&k^}KP0TT1UTyKtf;KvS~<9`l` zaW~JeooHF+dTxyKW~O6&50Z;4%UlnQ@if;dV;r-BNXPiKCNXa2x?haf?UdigydW_? z=DJ&qi+S!V#v?t1bo74?dBC#Tkm&czN%Z$r68*cFM8E!*M8Ez`^7zg5T*rBSJNq+F zaz2TEMHiX;LK6MkRdNp!{ahk>2#NlFQ1WyV{SKE*`BfzPf1Bi;B*x*G&APxinsor#tOGb< z<~?LH?=h}s9z!jCMq*y2#ewvnJb?8mxq!qx>mj)pc@+Cg$zw>&yP1;bkeGj~B(EVc4|hr4OX@g| zsqlXW{48N%s4Xlf6IzHa(2XY4#((O;9TQ^pn8$D~HY~CKQ?Dm9Qy-?ZvFDb%9lJbvKPxXOClIrb{&^F-uf_f;8OdsvF6+3V%8R~_1}A9%&X zX@2ajwB$sPZ35p*fWJyVs7F6&i@~k;DkypV80e`Nhk?p^=R5W){rD1j&(e^BJ07>k z*c%0VInd#}%EadS@v!W<<)%RP23K6^=vDf`^Dz2BTMVuryg%0K#{!QZ+^4wp{^HoH z^kXLEY;10D?R^|$ZyD^BLWzFha9C;YJK1ync*Tv#plh1<(;{B!2leO&Z85m@^8Q<| zA6Y+Ct@CW@v0Qh@UZo#APwIhmH@Nm1$JopB*sB9&w_n=J9$-S)-LXn`{kX}|tMr3< zY!7WQxb+Tzp4X37o_gy`kL8|p>{a>^fxVeDq=0M_?u)V474}%3&I-_bIUFM z7e8Kh^eX+J9_`Te1f4vgi8I$~BBU2G{hnj$Wl7)MI(tVsPu_ebnCmTkr9M^}F?QJiX&l z1bg0d7`Hv|#n{{Fv3HTj9zO@so?C9rzxeU1qgUw%_2>s}F}QyG6jSe)o_bqLkL7sY z==Gxv_IlBfg4>=5^t}CY(qr!u=(_!qD|>Fao&Vwo@B2o*m3~lajd+G0+~vB1F7?4DtBU0r}KpIlfoMJ07E8&$WT<%K7o%7<=PkkLBq{Cv2|0 z!?Nd&$C!WdqdGogddGu$v`1SEZW~ge=k;Tv$B(YkW4VEjy~^<@gFW|{@3nVPjJ=t# zM?Lz{4V&x7HL~aWG3Q_WnCR$LjtBMF9@=7X{V0p6cbUfzewJ|S<^Am5@mL6Z5o5{u z=h}Nd#@-r_J$(GFw6{g}Tt9dpv^Ti(>NiKP(hus<587gI>-{;V-p!tRuaX|i@&0$O zA8TN*BMm9I_Ub~m3wR zZ}@oCI=@zWEccS?1xyGdv7_RIYj0|dy)4*s{kTqgw6|FHTt9j-(Gy%hc>liF59(2s zwiw)cH^$W4)#FF8^jMDf@zXZcP3Vh6?`Hwm-uE%~`oi8Al;C*u$3{Kc3(21AM*#=X z6I?%&H;pbIT3=7eDx%0q=N}$`9INaQ&D8J+B{sc>K6odi3LK)$5MO7!<1KcACc?*NxX+ z7~iFwLO#c1i1cW0uk5*gEU=O239jh`D0}^&9?R1fgX@PMiQanSeymy_!=%S@d>#R9 zyM8!?C&J(M9%LKaT#3AEO+-%6UaSBpF*kr5~k8^!m}t z&Hpho9K3$$KKo+dtG5~8}jMLZ614kP6CU&evAo2@C4WNXO3Q_AJjvV zu|;*a|2~bWH|u28c#M@E%klkQ-tj1dy$5MX!L|2ijJ-VA%Yn{OY%Cp|y5kXny^d~W(qs86W9$ut zz3E7&A7$8FKloe-7I*#NeaYV7nx5w9Rr*0a`cWoj*N+Ec>OJZ4<6h{x_42t9wC(ya z5cV3#7U8z%g&2ErKUIzIeb965t&=^s+?0RuW1pi}>BocegSHr4Klq+D{8f%e#8dAi z>CyihSPx!5X2Kq(R%LMQ@i`Y>d-Xi_ra;^EgU`M2j>p1(@q^F3fL^5^)MI;Si@~jz z&&lxC+rm>Xzq@qn9jSWV@mLId1C1r;pKGsIjJ+b*bC2iKJoX05o;x1lRF5%4=_A7= zN3YTk>d_C{VsPu77*p>kj~|ankLBK0y{;b-*ej(W1-CtXPKUQ&Cc<6;bhtidVsrcD zHQ95^P5c)>`1}sTt6O!y%vz&;M(K!LA-u! zhP@mp(T};;l05fkH(H(<#j$4V;vEm_u|2fK;MO}WrruVlmnPYN zPfCyF_NZQWJTjrw8|iLv+w)qCy{@pA4<*`r3Y+W4HraE_m9kP#aQ*nv(W@K}>ajhv z#o+q!LrlHnJ$^hZJ(jy5eEPf^1AE?i<+djsdfxGU&|`10$6lW7x#jpA0dH{q=;7#9 z`awOmhqf48Kf1=$yTDWLQt7eWEY<6d$1AY+Pu~-k#@JitvG;<<-UG7d`tkL@_`&C} zc<0q&`9WI@t{=-{>Rschw_JMk<44u&`f&{QvS>)bZO`@?dz)d8<&R=}37b2wzL7n* zT)3JH3GR3#;k?1?2lZ%=wisML5~1gv2Rl7}tdt(hb#Uxe?yn-SSAldlxb_;x*!vRp z-2LurPj&T0_)mWD`8VG2?FxI@u)}_N+hgyz?74mn`4>N`!rtXS2^}7=M|qvF@}Z|-1an$u{R#}IzoqjypN6b(q32DbIbAh5#E5dn=stbtDINV zV|m(QaQ)!(dc1zD_xQ0JDzHilQZzt?!LWh2A!shz1Quf?( zW2(!L;QDdE(W~@>dTbAEF}Qww9#ij8j~`p5$8t$He$%#FZyD@)m!?}U-|yKWkGj9gc%s^05j>Ro_$5|p0j)Vt49 zFVAaS+q81&bjvFCB)HKbG4{fj;o2f(a(#T^v3GBby(b^W{=l8I&~xogh_Tlf51{6? zJ+!yqV{cZBy>DjVS~8q_yTP^haE!gKm*X8=YTrSRy(eWaUk1*_iRncCz^*`h+<2Zu zx_V1-;Rli`gR8evdTz!W(DMfBF>H*{TSL8glV$$7`-AtO=bbMzufRLt(0}Zg!`R&U z@(J|NU8SytHE)?$FS%l6KXZ;luQL1qJ?}Y|+dk4WOxCUs@q7H4mh~Od>m!r(qDs>? zuf3c@@Xg)1BHy)Fddq;31x*Gt8FpT_2~AtHXx6fM!38awXJ?zKmURj zEwZx+RUl6iz=)&4NYEr3kt})*DA9be{-zEWm#p>hoiSz z^P*GR;u^B-HxD2CPfqmjU;g?#E^6icyv?fpV$G!J>bBjFSqX_dItB;y>YwRvnt2MI zmi~BXz*%2k>B|nB@(uaml+|P7DXWm>SwngG@-o=({ziG`3klH&qK`y#qI06rCusT6 z!)g9(Q^%~Fgl*HYJ(3e#>#y5tyT8J!i_7@x_U}5rDDFrgGN5F@ia8w;qCHj@p6F2h zy3W>&>e<(I8B=>)(H%u~Dr!a-mh@gx)}bSEdsgplab#oZsbA(_ZE@uPB?!s1v?HX)-u`!gtc#)YO50{6R&yU*ECq?t4Nsq7>YR++bNu2I@ADkX%(&MKW zXEDEaG+}zu@xSx4opJfy`fb&5D>b++h_u?#%G6)2inpWokx(EsBh&O|qWK^1#HR=6 zU@06sQWihgYG@rhRF*K$%C(LiEVItDj#XfRSjYC2CC;}RS;uylS#_Uk8@H#%yx^R7 zdik24I%L(oqP@K*GukH_n86k$%?ZqJ+xIu*ojCM5+Ollz>qUvjEgLH*X%jSiM=v$C z+VigHYoAKWPde^PI&mmre&D#z&X3ldYt^9@w&$s`{Ah5lGs`H?hukt6n&;-vfQ%Mb z>OWA{{g^L!_WU{R&)nm+bk{cO#i`uwMsiD)qNjYpFAv4d&zg76oOx|?*4BV7YlxeZ zHGfXqAv?~lku~F-`DlGGP;}0Wh3%8}6h`BWM*N(1eG}&TP6hL6QQecP`s8L;~6x|fwDLIvhF8ohsky|;zVuYD#x+VzKSv8!e^>WH zqkUnQ60`OW9V#rzT*2Jr%f{wBdaFg|^YathgB$d&-rr?tZdtq`MCo zS2R?ucGg`+g~QzWR-K%=)-2zQ=254A3Tww<&9bdI(X`r6nON^=E$ugcLqBobfo&(Y z2eCbbjqAT^A5gO_f92%zb|qH*tdhViYi9g1-^|2i{+U+EeDx9cm5)_F!}yia<)+F# zRLzR``N1VQm_e7G3bsz`a!1kGrbOc0xTrI_z2Mi5k+vymtA9<;nm);nhRXBbwAOY- zd%9uc*w)0Bjg6svNf2$juiUB|kE2HzYkcF1E3yLHgT_yP6!Rh)Sn7Y?8A-NsW%XoJ zSF)$BWXwqa+<;jdaZ&%AoD~5x&;4pcylDeZMe|IptT&ExtHb@}@lnpMnx?+ED35W; zb&E_5?R3nzy`mY8s;P5R=Cc(EMyGn+)<&mQm$2!pK^57iUy4f_6q~kYTXo~i{whAo zR)1W*xzTUtISyS?k>5FPN!pxoMd{8cJW&?C3BCE<$VNstx65GIZXI>jQ%;37J^pww zkRSEU=oyV)+8OLUvJ*Jd{=?%=f{s1kq7T<$dk5PpYzwsw1-TV!1FZ7p@fhF#lv}mq zqj3*MqVW%Zu;LnwuQS^N7~iv^anHvuts38-s;3zr(mdlEsYsfigS}$>JZnaHzHdhI zeE$sFj7D5E4x{bvQE4SRnuyW90Cg9z0SM(w63~XZrVZ9~I~rJ=Wctj?>A9_{-sW1> z4Ll=MSP?KY$cJ`Pa}`D>WhDDJ?uD9Ns%MX{Tql8fJY%8GS)TKivnvjkoPF~xE3&Z< zp3`9iN~eu<_m!he*&xn{s*S{(jc~@5g5Dn%)B6_o3unO}uIcI6hG1hKb8T}iwZX>E ztK1mMmt>lKW}x9S<=7v_Cq^enBhk>Tq}_!l?yvjBsTTEE(-)`mTZ}aIr&WZO*k*Ob zM@ujhra>oDI*}IRiUz7Zr}l^DrYx_vB0p-+3spFK@%X62hEc!vQ2EiO(R_2fbY}g$ zx+jfiC%X)+?5S=0BQK;aO_-6sG;xNrU*oa&y}R?HX-k~4T!T;6J#0!IQpw5t(-x;M zNiepVzqalHlfPg2W0Bu5x=_dJ@3*Bd=2+CoDLl5g?2H$4(5jYZ1X=d8x*waeJ5~1D z{RPn)OZ=5(laH4M3sAy2kFavS+LnBLOj2Pqp-vyoo4wnzUo5P&Y31yM#w5EiT2`m0 zG&XJPZDJWYp>5qy7L0t|)cCq;tb-bpk53P>jU7)7Om_P5QuL#h&9pLnCa{jRygO-r zK{Vd%MebE!$ItIwbZ^`6wnAgQ@Whe2&zdvPfwiA8XP`e-JXz8sy7N@HJpN%?N{l+k zt?<(Lxz}LNk-XGD!!mmfYr112bG1X?{!IA9GU2&so!OTbL_^2@KAsVL{8wT$Y}UfJ z6&X31+v}iD<2-%(cisDqhxf_D6__J#+1F6^!;0BCeYQKt{kkP}rq?RzzM}idb|c4` zQscS|H}m6Bo!{44;+MaP*xPnL*?!~*qc=jwNF7`M@J4e zx`U<5Jg0xBqfJki95DOZGTGp$FD}2WVouJ4lS`Lp z#mu2*%`Z2#^i(Y^D=BIiG11A4d)2mV0MJ z&Ogiu9z`x{?tGfL0Aua0%=++Z->H&?^wXUsy^HQ?pR}#;M4RS$rj>b~zDTGjE^%k} zgp+NSJO1Jm;dv8IUbx(<&-0;>8R?v8eRGyk4IDS-Mdkfn-Z1b@3-m_NN+F;v;{TH`qu`R~NQ2t`Q zvI|!_pCjUMB<+4OV`P@`Da*5;&co-~K=F~1cUN3{^MDoH*Jk1q=$RuUMzeaC(Pnm~ zV_%y&vYJUt>oUxwasPYP$P|;7j9wl85BuK$_P_Wl%iOnD1V*v(*m4oJCfWdNN#Y8# z@7-RW5DiApj3!6tMw6F@u-=l*8csf55KLauHkvfunUD0R@Wl1a51QH!dd6t={^Yrl zWoO~IvFntT?e1^gIm`V-b~NwBqfq9%D&xYkm;#vnBgVRclV1< z>&G^C_H3&?GqP~Mv(ItPrtWI~va$1Wmr`TryF;1FXr;Dk$vx(5>fYwdjLtH(^J3Ih z>e=IRA249#Ge+kb=`7%i!#=laeH}e*pF3#ee4{_V%Lr5NMCg~H{c&2M_e6`)`*WMm zG+Hw}?e7)+qM~Co@6pDy*t?0xgZ{+h;ebz{sqQxAo@_qJl>3i4OX;dJt#?t!q);}z zb3Pxj-M5aMU^FMF-G$JZp41UK?$LyMiaB;~>^rLV6uC<~qNVnXvrI2pIeVb95SHU) z*~;0zEj#L~W7XaAO?q9na}{Pw`Vz+SSL{O?NAjiPR`(=)Px5B-V$+6VkC#I#oKfNt z@xA8PnEY$H++q6a`$M$DS#oS!lldK^=gm!=5j4k>d({j3PIa7qkIsq`=LhP<&768T z&YygIT_}j-%$8H(>Hg`N(JR#Y3((f&pUUo_)#T%?Y=5*c8Z_TR1Q1I!t7FTlxbjXY z8C)2ghwlRPeZ+!H+QevfakjpvDu|wXGdJ4Qcs8iGdC56N=i_Yt z)SHftrNI?tzpPA*rpQ9+%iT{}J?ZV36;}PYip*`bOX7>BwzYTMP*M=BQ_`^L^0S$1 zuP?3EIf-F7Gp+!BQTd5v>)y?d29F17GI%8Og_kp;?C$ ztd6F9Z}VN9GoRw4`Kx){&cm#tZG1ASn;pHlnDI=k0-%Zs$Iy;qmVg{)Yl63SMWQYb%%1I@n$Y?KVL%|d$#<=xU#gBSQ*A*cJ$4| zX@#)KpIPx;?BX(hx7@T@zrmvh-P&*9paCPsmX7K-u-Ra%N0)Y26u2o?`>T5NGbzn_ zbZOs5V*5Ujpk;Jn?Br`2aP3I7rw{*C{6O@5#SnwR*9ja^CbHT;;88GP?L#6u&8 zTEYLO;m1oWG{lX@g@z6uXazUWPSBo$HU~E{9=2b`FHFG?{zhZc>}o;8H!(e81^7CX z#2F>9nD_;91CdO`W^xA>T!Uy@u!1*`I<^k5jAeJh-Y$5M@i@osmtD||pkwzN`WLnW z7ox(%S+o;)3tl8XYNEaI%TnTO6Fq`5iE~V}85QQ5Xb1FB;ye@G%GCKL+7T^ITwtQz z(DjLrndl3QK5nA_O-1wx6Fq?X6BnB3Cm5E*Cry-hqb4pg(M{~nr%aUZcuRa{5d2Bx z%4%Fa7NC}6=mCSE~p>X2bH>m#{r(I}N1@*r|kA`kbGVOnszTD0@{N)=2 z6W1MqPGTV%5;&9fz5P4nBpy&BcCA21bY=2D%gzoQL~mQkqlT4QcAY?d#N)yjA<3?5 zgkbW}K{r`;JtKs}oauIbBcKoNWxu|21xzKqjwa?Lr3DT`2y;FsRWn*vco{k>DLuf2 z6&G%ZmLydV97b9&dS7Z5F zfeA>n!XL0m?Z7GsapCD~XPv-D$OwiPW9X6`Kf~by^jT7_JoJj1}(8^q`f}uI&|8 z;)XJojYHXBa{Xsmmiy7<1_LmCvD?LwEcsmO!R*e0*(uwrq37&xF{CLw z_$+qI?tz4qkJ%GJn#@jqgBfo94<>SWqAF{mkD zk3c-jN-64SC2lzz)`GX83tOdpbAVNCz+_MPb_`UkP^p!2ln+dg3*BU;e8*VO<^yh0 zzGpmacc!@?7*DgOU>s9^yb#4AHed3U^3ym>gG~EM{7?Cr4ay7+w^Dwkc2?+SE9E!F zvTeRVH|2NkYwFpxST~(k%`*@p5n7xhuMLtml`20 zya=wPw(}iBP9%(L7p&CwzVoxV82N^f)Q-OEA!LQ=S87+^YzW!m%Q3>KJ&ge@#-b}O zwGuzP0}V*3h1Rr6?d9u(5pIcQrVjQ!1p(bX2SpRN z_2sd6KRged#n?wf_N!8xbm=8p=tG(~zObv&7!CpSpSYW^_Y7W#gZq&5tLKL?f?MHcdT-8O>|)_WIv;$C z(fk=6r(ZJ}@t}Q>I(>O84BNaL z2&T8N4`9^OM>1YuH>b|%Lx{JscdZ+jElIg$4J+B2wgKkXOWJu&d9)AkeWhfm*wj%9P{rSIm-b55($KQpIQHs8~g zzK`*+&3AvK^8vr;TOMK3_s>Q=VvZQ;2N}<_0*|w<&-i-I;2lWmk^XfAgYJyuA!i(U zzLS2~8Al#r(!bq?HU#Y_*yl(1gz~V>nUa3=cf`}|Tp!}!Qzv52r|&;x)ZsYZg}Ir2 zoatFM_l@Z%n4WFdV>?eWy`IheZ2C`ake*{FV{)aRVtSs7W`V;;eAejAO^@V;OWSkSb>QDPke}s8TTYZ_Iud@h-zeRraa(^~X ze6gRJj}|0W456`1tc0NNM8Mq5g;{9%ehfSUudVPRDEUsBa~~Y;M<6e8{}U|I4@DxO zGyLDP{=H~SDAQEw956yPolgegZ1icUmY?U#LDQH}wmIPshkr+7Lbd&ExU{Um>!>a9 zt6yn(0i5g_+3P!ws?D)5vd?oYjC|oa7Do2_3h9hF7Df&jAuW6X`aklOuNXNIb6|`d z@;wB>ITl8~_3>pES!Q1v`N8)SgzRu@j7{XY5$c(-iJUY-PBujbC`{!`KKYLF#I7-nj`7{RS=58 zi`j=~`gcI+Xr)|!1rESp{{gR)%28+6NG*RHXbx$SZ2vdV!fw`z)baC}8<#u?505v| zAU-2R>X~R52jxh86HUWGInuyHBjJ76RYcA;LS~rnT#w`!AuG%m*G3u|Av=5*#w60n ze-c&IGso3P6F*N@oFi`JJTt@c9QX2#d--9$Nj=ic&!cpU@K5ZL3;aAvw+OewtcYA_ zgo1Eq3I#@J75*>lX>E4=h2e!*zL87)znLx>jr~ugt)J&tIF-E~wiA!>-I>9sv5+F6 z!@Uu=Kf|I8eS0Nlj%D)!Q=ub_$JyUw5JN}bL2l6g1Utmgcl>M?w)s-K(D&CmGp!ZZ z(1`)G`61fWBJ>gOp|E+H6Z)7RXK~2K7=%7CA8l>Ecq{a&nZNetc*J)#hMlmT!->7S zh&Ju_VIZ`J>5&k=?Xg0iHAg(t=F8?nd->Ti%l2VXhW0U@jZsJZ^Ulzz7sB^QR_KdM zQ40=Q1JEytKmE z=I5HwFWeiX+5BV|I`t9KBQ{SzL%(uBGwnPKQRw&SNYAnp(6^yK7|*tkGX2lVh}W}M zvv2=mJjdpX^g@3#o)^A=_AMWU{O}?4XUOMcPqzs3YvqvNcN3ag5Z=Kq3ixh?&?;P$ z?Thn`flwGez(&RU?uAg4%nnHKO-8(9cr>*VebXRxO}=6D7%LR?JprK@Uml%-u1H;o zIs<#rTN#(`Ml?7J(O^br&KG+khA^WGqn6zaE@gBz`#==!LDhJy-Ch|t^UaQ-ex+8% zEk-lcZ-kXG#3+XP-EL*v%4pE$_3ar$uSPsvKhmv zpJ_iDLVVP0#Ix+-n6(+BuR%T8b}3RaZX1huJv+gV`0acXWRAU&>0@3)JkP!c6C&dd z+RP928;zFT$(9u$j;7s3`>pIrY|q_%J7l4KKZYgao-K&C3-ue)-^#d;WsB@?NXeK) z{jT-_3{l49vytAzN@Eh6Q;qFIcd!dgBHLvWt9^uwYScq^F|%2eO?9#DvU@rZ8~CRfH}bfGV!0rsQ*j8)JL zWKOzM100}q$FhAg)U6Y=z;&ijBe<*P(}lcs-4jnDM=X*p_9THA7gSQXRO9v zB_-pMGcji}o`z0Z#u}`^Y8eaD(7cT0_+LF^E-XYc9>PH4yIjU2((0Y;5D z3k5uS#K%a~m=S|v-eX5R1kSh-FGA1w5lJwIV@B}7?}QQkVFD9JybV3cBep_+isiH* zz{pb{Lg2XIW4KE}{~eA*?*^YY#Gf6+$k59OF??jrEH(=6PmHXa!HSSM(a3tTgYjHe zk6cfFD4xIBJ@RzA2gN^)gpF)r`3;3u*01w0mA1Z(yOWDVj@q#j8bX86u7jigu%3}b zHdv$n*a8;{vj+_&E=cyMA<$)wUhMEU?ME-}1j`wVdKz8-ORCLB(G2{@Pr!`}{tWk_ zmw@{i9EozH?Ie13kVsFtF|UY1N`X5{M%ojE_fu5H;M`*}-p?|$TI2h!H+P+)p%IW9 z*^-K4&qq=rabE!ykeNama=95Lp}|~6CZ)I!WmKAghzj28z>N!@i+cih;6#!;L5Xq` zNiY4qGRmE-xFGjLB+9=qjEKvPB)kvynIJ{yYr=noM#G}h*iMfMNE zd=ox^$e3X06}t)D_E>Ixgf|7zt9Kv?R5Wx`aiVqq5E@Y z{v(@{fU%K=E)T0LxFCh&f}Ebj1zD+aLH@jB0(TFRZUD_Sy;x0xp-*t>iN*l= zV~vS&lXbt`s0WH3Lv_Xlo2ibP;(`n-R?B(62_!BFB>hob&`5ScU_6)HB88w=xk0(~ zHbEJSG5sq{eC)(SE0B}WnD7^H%N%9QI!R6ZVHClbn!S(=nl$uBXO+ksw6o`n3o^|3 z2|o5PxFx+sF4Nc4$U`7*CdUOQyOQfYNy!;Wc((!)xa}GjEQJ%HV2N=-!{KIbD2}Zs z;ryH7I{cL@JUNx@zvtIPy*INJ}$_;*SKJfSP{1gQD=bzB+71&@Q81nxb>1@A>elgw~6m`MF#W&(!Na;wPX4NU%CVuA_3nEotpt__Xx zNKr{Kh=u$d(YXN|U1=^JW2K|vG#dV_qUipB(o9gIxI`_}NB^sIx^ze5TMTQGfpNt5~O>Bz`HApXXrMXBou`*RAoYwvs zt_;_%KA9r~f8+{sT`R?xD7&W^^uQQ>3?+-Ty64>Vn)t=wAR+jSGGNE>4MKtKmv1*_U#I#Q%EFLXdD=#xPm@1Clha}AMy~IkI>_Sb6m*?B_#=T!H4@lalx?b ze<}S%NaNV<`s}BVGJotcA9R^+ec$T(yhb01NL*_1Y&CJgM_nO1MRg|91s@uIT<|^D zKZX9HL?a#yhUAz(o@jC`t}2rLY?pzNz&--)pH4I4Pl0nhcR)oc{2JjFeV33aH?Ff? z?=z%V+eD#1p%xDI5<+nP#G(Y}4rn4D41oCr+zH$r#USANb4ODAU7_c}7|*>)m+_%1 z$_+>(%8Wya4TeO*jYH!j{e$!_UQZ9fajqcuB#ofw9qoJ|xX2achGUFIc(=OV+=4XT zQnYfr0%?NG_uw`9ASN*OK>HrJ(T%yGK47Tm6hyi{KJZWEV-K+tsVQqs;--*=BM2t)UQgbTGIcYDPbzxRuyjvC9J8 za8Epu)jL_zZGVYGB)2f}lVv%RELC=_uRM;GOeK#Q2$|z-nrlj3*JjI}V$+h7dBzcL zW^EE5;@MN>Azo^0y=5P7)Amx4mTC4p3JgQ9Vb73ACy80lwBwG$ZV+pA92`v9%t`z# zf<4bp27`5M0~6SE5*SI+Ufd|FbNvMV$e}R#tA@f{X{BYb_QR&lK%Q$Ad(UOZW0fG5 z8n)RtegdC#$?rPJZ#lA(E@rw;^1Kan2J5>%c3SrLZ63FuOY35<`!xRT4K{xYZ{C&QJ%@1fegMZO zbesc6E&|Wn2uA}Qr^9g`9jC!@1030|migC%^9VTee+dV_fj$3TIQY`Q{NKaTMaQ#n z@KI9^A7zSR><#pt*bn4C+1YGhS9T)EDR`Q0%dYfBdY;7YLCDKVN{efy?Cq452HDC^@jd$T zr!MR^c0*(0V1-2(@#x3Na={`c8cCEWaVZImLn8JI5{2l$gi1j7HkIGlw>yqSbh#v7 zO>jwmTzBeij81%8Nj`$840$EU0w_9zArFzj@FK+E5QvRR%q7u{@s{}slaMYU!cgBM zS%P3)T;<#jYU(%+yF$JVa+-7(-JF^QdX^SSZ}9j!R6$`w8%ppGXTm96#(z*Drfue8 zI$@Qg+FPfaMgarQWrME+?;OK(dWOQnCWE;d%q#p%rjq7-vxY{K%AKve-x^-9Xa9Bt z&sFZ9T}hZYq$Tt_uH-$C%s&&{?<1o89qPy(jzZlH&M}A%jlj-;Ju*>j#7ysG_}>Bl z6O6y<4uU;*ZucZ+t3-{F2=*W*8ucdVGddPQ;(6#e#}`Mi=Ri~iJ8~vspHIM_2!79j ziTIrx1+tAOdg(Y*Bl(w4M=ycPA@C`bB+rzbj_wJ?B^4~2oXRpBIh?MUQ*CSHFrQ*} zP3S8TFliOKSQ9YVbDPN^d&aV0&p}qf%aF;0Oju-A*_q-6K`Zya8hpD6E}f>^&1^vl zhhRC&5%gy<>ZNn#q#`#75-pIp*C>}LS+?{W3%~Q=_b2f)ys0YxULW$a;m1-K3^R>( z@9dS!&;eSx+)4Zi^rajBeqH#W?syal4MQaIxr}9MayP=k9&ELUVvvb;vw_ePR_+e? zvnOm5f0Ptz+{!&qxw~Ahlpo*xpzM_{7Y1hK{!qEM8ZJ!A%H0j#orwNH<*^X1Qr-)0 zXcqkRYr%aCl1w;E*>tLGp3@va zZJ)*`#P(|&q1ox#y?q+aYT2*x*p}0C!FK7ZE{B)ttMZu>R%UJy951he?hKY3`hs2C zQGj-amA?)?!E#nS9LK`3SVYPk86__P^Ty+G>P(mw()`P1WL+gAYgqtB7T7w}=?QYU zAA~9a1a+jfGp*bM(69h%f9hBJsH%P8|EpRva${1G|2l$7mfnP86%>DJ6mxQt`=Rm% zpa^In^AJLe@dRU>tPi1wSqbzj>PbX}K4eFd5f0a7__z0bnuX>m%bbU7 zy7{GAGu3`b=F&r9(Ppasu*{`1K`*>`5@JShjtll9_M!uz=RJj6Ieh0m1V;lMcffHT z9ed%p0gh}pP|n}L3G~$G{7bND{zt&OA(8WyFj{g3U>MVpkIN!18FnFgC`0FCyPUT4 zvAs&F-c0;Bme2xv>aE;t1YliVCjn4~>uGd4Vf`t_voZ+WP>z|O3iLFwkWrrbC&Pz@ zoZG27-cpeeMO+=%+E)H%2(XjE6&Kv$pnTay*f)9Q+W{YY&;Mq*<$IHqFCWIH4@T>S zBo~wY27!K&HFLA9E;2zE%M|Q@tUUrfO~ukZ+##~#Qq}wC^3I-@w6zn6aqhi5xt{I{beO> zS&BktnoNq=-C!$$xi6|qLhgbAS{JW%uw#4AzPZS^tSp0aBIi7ogXFtkfPKy{NlV82 z$&SX$q@{<7lkJZ9!JwskixdC3q@{oBFZ!xU@4#Hk?jMLGW3~)>me_enQgS)yOzABL z$T2TIotBdPB@$)~&#clW1;!%5bF)x-ry%v$fj+5cYb_34e1`fYPnR5{wfu7a#e+0aPjGqbPl$=|DYWIzZ>R+hH)89*&J7SHZ!7hRePbg9-Y6ZMKz=D}`J>OL`q06QGT0 zna(+9CpZ*^shhr$l`J-zXeH1RiylI^XTK#a6f)M?__y~QpA8!l8+}XK<~yjUbQz7` zlC2Y-^fqnzEosZyq@^vtE%NoG#b)1@w#=i8#%AA^#(XzvvDtS-{%@qkX5W$4{UvDA z7rfiMFLkA$f-qHJlH^e`tFZdL8!ZIF)Mm`ep zV8LrDh21C3LKooPpvGFV@|zHZ^_|}ahg7oZ8vcRGv8M)Pml!^W@Ne(gJs)=1kxh?C zGFE`d*DM|gwT~CUD?k@d;N)bQypiSf?Ac!YKPs9Y;7*j&v)4>W_Ct>;hsAsP!TZF( zLFmsNj@vF6#2-xZITtl66`7S%n;3LAQac`^cR^I_kk<6Mgo$Z)vjSFrJ|wwik-Hd< zM-XH;pWTh+MZji|Ah#MqL;uGB@S+Wa3wyC(8 z+{3u@nL)Ao+u?X6*6LXxV)a9;1Qznd$Y>PH9nxRg^B15W(tG7(E<30&%w z9L#~%)6f^&k4p@x4Ru(H8~3Cqv6^=IHBt6KCP+or&`zF^9zC_W4Z8zR%4lNtuKyq- zhuNk6ql_9>$%Bk=F$Nd=ONr1bc^4cLw!g!XD79k);tDym#YuNja)2Xa+002lMJe0U z9Vv=h*p=&!^SMVdMMh?(Q9Do6PLkgO%69nt4Od){TH=CBF#nNZltm+zH5M<$zN;_&8f?Z!PHJE*98UDGaCQ z-EGC)=x^<9QXo#xhugBale%3>1N(p5&3t2rMEp|(mr*hk@%l%}gMlKXXBiXLg2_a& z7}C|M(FfqbRD_;f(reo8h<-WMy!Ke{>aLc`+)Rc+ABQw4vjx&N%UW@;pbAl z+3DO2_1rQ{sI;u}dj&VUB=kQ=gWur#?_hW{iqoIFZD|O9xA>PqGbRY&m4f$_@-~5Y zCwO(>z2W0M2;OG!4hwIUEX%m2%Y9B23`KFf`FKecO!o2KrX2E?tvn`(2NN0ja^;-~ z-f-|3`8pquhn6@=xm|{E3C8(V?WOm0r&DMe|;dvVrt}B4T-y4PVp9SuPbqB1-3u|6-31bb z*|y;qF<5qce7q;Y`xSV%3vU%t=ho8us^M{;^k=H!Wgm}+NIAZItr|l0(BQ6$MmyMN zhX7|=!;oTE`DF08c9`Ph@ds5Yx4_5aG$>H=*o;4j3#4#y{j zD3bS30uHthbN(Y`Q;^dSC5au?oJ7I01-CP}4v}^(@Y_zF!Md--RXP5e4Yy55LJfeLIzYxXX54*wl zMmq;u{PpVph6eYU?3qXoPp70IUtV%vwT!+|MP!ysbitlO*xleR$E(}0_^@mvGT(>< zLK3A+T#Ur@cu1&L2@9RmA5g_!2P?9ScO!gcR+f))xxgsp*oBO6NVD>hK2tNCda`D& z6Cu;Nc7Vs4`Aw83yV-2|xx3)W(s|uYs`Tt!a+nS1t5mbIkhzViLbTXiPQs{tln6+m z{H3Tu=_Hc&!k43`jP2vB1diZEdpVt5DbrneTi4>>-g5{(=`!(MDHGp(m~1BJ#bqLR zI!GCdDd(T(HV2r$d`#c0Q&BqdIE^-U8{{Ox(XCY{zA|7fnGMOu)iXMm>;jj;rlZci zHb|z-9g8M&CR8qOZ-Zxk8F$Zy6OrWSIeja4cy!@$q%mDiER;JuvG5t`Q!q!tvVoJ# z)Zw7z5JQE$#m{#E%=DyE-sEz6p4@7tCspz?7oM$dmFY>fOuC$&H@9YWG~yYzOMkev z_#+gxM}M)kcoXNbuK$j0#WH_&=?k_M^ZBjkf62Du8JJdh^zLoNe8t8-$+;Jqbb4Oc zYNkW0CF5tp%RKsB<19gTot{Ux&00GG@+Uhiii7Z%D%t_UKV5pwxxhhZW+Cb>*!{yx zpr^H_&a!XNeC^#?fo;XIu-vcdes$}t z>sVnoO1k+@Lnil;Z*sVi{3XcZ5>5(lcFYFv3)_l2MuI+|^zQA&ud~)}app-eJhwG> z2-41GGGMVZdYu4qx4>*UWvT!1z5LBUy#-duX9Ens)cBh|%1ltsf;UH9dN->#`=DUY z16yUu&+ttuaDh)i_lCRR&23RO!ad?`lC%rFX0(Vqgolpe)vcP^{F~q<9r-WeU^n!f zhJ*3vbKJa;E$LM_*q3~yo=nG^;4z|ps6%Qa?-TI&2yTq>y1?U4y>m-@iSR09E>_MN z9k#IpvUxd($;V!bJqv9X($uilry&D8#@?uV^OCCijIWtlQ&1Y%_G{~fNlei z1C)6p8CQ+oZK){@_~y=l2fOJx!qaVhJlQjK$pHt&DWzX65;0vWk||pb%=+o7mVxRK zh*{qj<>hyQC!P2XIQZo0Iuj>1%=M`ggI)w*8rLJnS8dlAA5`RC4}YqDQB{+7CwMfT zkAC~Hqp=xoX+A-;aIr1!?Ne=r2=W<*IbOh|l=TYCnV|8nMi~0H z8-LSG-03dNT)i)LgYRW+M(6pv;7@bDMx$iY;_(=&d{9-&@E%R>!|;~m@=+x>l3&rV zwCvZx<3{q=!o&1?5OcgK|JFz9gVZ)aIf6Q?Vb-IkJ%vp?L9>k z$obsKlNBoFg2E-0-ok$Gb7vvkGe&^MKk3(!F^?y`FF|NVwgGfzM`o5~e<7N#0iDZ+ z!YAuND!^no+mc81WQ{f~d9ITRF=lLr@?cWa)4=27Qx;)2)dcxkbX<_>D&nIQJ3-v= zlArFd_p~pE_0%@E(}!nef6Ej~4ibXQ!7HF=ZG^ZzR8D4p1=^fsN(}O&LsJl@*uu?D z3UY4)k4wrE_%6%FZ7kA|i5-H8@^VK#MC2sF zan%?L;Kk}e8^iaq5fyl(ky-OIEMYLDc<7Ta(yN?!D_Mnd*Fo?Kggi~W%y!o*^jGxX z2&GN%Ki#La=#2qL`~t6(SjzUE!7ETojoAEI5TtYWNVkv{NFn_Obfy$yt`s6)Gcvi( z6GdZ2A(8RWbQWTI-6YcN4SsBwnf=2Ol=WfbgPPOSPv>^wX^fcrD;P z172~IC*Amez?*&vJlUN{SK^9eHX)nZ?A?XYTSqWR=UiH8@I4KrsNW+ zv0@%n45*ibu9ZEgiE$IIfGVawaRwY#6`vA~U1;;9oH^%xEV$<7L)N&w$YNE_M9}f_ zkt6O1n>Sp=Ta;8Mj>MkR8kxm$UpV>(Y@&Rftm@r3L{egNFIp6yWL18gfLf?yWc$hG z4P|#LAmM8`S3B@e+{%-1=GCZ54u6SX&cpphGI>LQR{#k-;8=MxZi%l`Aq&c!ljgAj z--|o+v{s)6=C~9dZ8PuiR`Ll-qI~m$C)i>_T9t2O>YaEl!}6q)NzLjm)X31&dCW-; zw_BC_Q9?uSWN~nYWKQi@u0+0v{+i71d(1UCh%SCV4`EdfLQ;l)hpKt@#~hRA+&7UQ z`>-m1FbLik(VJ(Bj5l9)HC0!+Y%sj#6K?FUjkn~O@7h==??G!~W%FQyS%1iRgXg~@mp+0&4WAU<&|GDWOWz9#GfHvJR=kHK8#ga7lQv6 z%rg(|n73(|DyuRb9Yy@JtU*qK#K$`Mbrd91$pbGYm5ek|Qn~u;1cdlGPq>(LRoZA3 zLpv$K101I4t8c*YKA_oT|5~ucL9y7w#<XoqeiL#CyYPTwzp(2qdWaW{PF(Nsa&#E-# z%dyRz&|f_R#yVjQpZ1$Pv$(A42`Jjoza73y`6RvM=4B+2XX24!dRMj}d*f#_7$3$; zd$p=>NJ99}15FU%<5m+_bv3nqERBg!%{gL^F|+R#hQ6p9HvfmdMzxs;kf=Kq((-CCYP&>cvRLfHoO$ zZY5W4k~w)f?l$rw$p{-4WTz1)iCEK^h>o+GkK!t442AR8EMd;P%-buZtktigYKNW7 z*`s;Cq_O~^27iy9+>TDkOa(3`W+BfM{gAsn-w-V5o?8!kd$jHcn^7aKsd#c@uh*k8V9qPM&?pDW;bTq& z%}Y=$8BOK~Namnw2Iqt^kuz7*5wA%^t_GEou{s-*pFyk6as{mFCr}~-U$Hqa<}56c zb3avBh%RH`$;WhByt%)Ad6 z&q<0I+SarVg4mx}#}?lK8ZvC4Gi2P5s!@sdP_*a3WNYBS{DBUv)EQ|xLvjW#7+5k4 z^KIp$RrgDP2s9Ju)qfb|a$$9$VYV}5;6Mhk!5=W#azZA2Hso;-##KjhpeNjq!h_Ve zU&%1~;>hqimF1*9A`1wp(E@mV@ifGaAH5<;CoMo9+m<+9cqRLZAp(rF#=zJ z88RMLGV(a&eH2q|5{m_pW);z4Gh~!6(Aa1~U?b5)qD&b-V?RbCkxWk*VKG%`9cd^G z5?<3Llr-9VM4S<|};W;)8BNLI&xCoEu0;7A1z@9k}rkUo? zlu5wlCIRWuyfFb8(cF>D)F_Zyl36|ys%L3>)OR*XW|^s(6R#zci0J1YgJdz<)dSZ^ zmCoyDWs1h^fk<)^dgA%Bm6Ib5Xn--&i#3(&W{pIiAucT%O)4LhWpaJOk)^DeEYNgo zITmW#1~P3$Y4!@p~Qeg?4Z`8(nR|M`cg;%a->cTM?CA?U$|SB}<=x)guXD%mHhwKU(3#Kj>M$N|9)s3a zh(Ss&>fu9A7;6$B+c@1s`b^kOkZm2MZleN6F%$~q;va=@0KkO$40=q^*%^3aVYQnt>{|K`UaFKBmdhqX9J)d~yk_rZA2CNz4G;wEMO`I+6tgDIH;?B65 zm?Q4YtKHNFtgK$;R;04TOYrZ@7^4A4E=G;V6inqhK&^37>FvgeyLb88^nn1A+fzWi zP25`xJUKWpBZSUX1XF{n36wmt!!okv1Xa7pr*;w8-ep892yf#b?VjMO?cF|Am*~_a zdV1(k|DZ3fUhQ)q5{xW{h{k9u2pTNp3)ZXI9x%ZM5mk1OPj-+$4eCGC=g%^hs{nWA z9W_Is2#n_7c30N1wjSIL54qBC&%i%~2`YT2U-(W>cq1gX7-0g1ZR;esLmN>XF$Esi$m(K_>VI(SHBN;0Qn7BXX5=Oh9MQif1KfX_BI!iG+!i?pb0(T zPv`+Jp{0=crwDrkPd&&+VXa{U)7}9tx!Q1#;NP|?2&(-azxI1P?GupiRLOf8fd`;q zPXvBl4GAQa8!n;Ja0%-SSK`F&ApTioh?Zq#EVF`O(zg~axp<^)KmIWTpm`WIt2aX% zAI5^~3UYi+#y?U);0Y--;HaQC)UvynY6J6s)_r&z9X|Wu z8Fk^)Q6R+D!|YDIiv@s=hQP2G0SGiRa0v_vuB+h4?q{gTmJ^KZ8ozAs`N2q$tsoRY zFO~J~bQqMA0#`-sq(J?HKK~$;d6)W!eEweVQUobB2^27a#sZ@tuz7$>h?DGk_R#@W zH~s@?7er1Re2tw==}!EkatXi3KZ^U1SHjd5k|1RS6S|jj!(t-5YcyO)4dF8UA31yD zgc7wwa0Pl#*^GcpR$YN;J;Wi{SkX{{yIf>_YnX40l^WPJ2jnrLD3$qaHJr!`VY4{B z%u~jgLm7c3iBcr6%#X}87X!#NVVXEA39fAK{2SSF0w*R^R(>^Ilksm`<%B8XT!p(_ zWw@8)ABiQb6KAi)VlR%q1a_TBEMXn0^~l5;*;RxYQvD|rT-n}P07_3+mzHFPd<%?*!i{kYvDr+A0gh_BG;~!;1 z@KsKl;Sx+Es3dSI3RwbG`=*I=A-KqdA(*yWOFv4sej1l?^PpZ)PIoA-z|=A@K-693dm z{44$;NjN0VlL-GbTtc>l_ZAjBBL2Ft$_UH}v@;|BHe3Sp;)|21#6t|mL)azGD#Eq+ z?`=?QcfRgtvdC5vW{I`gsw;;_;e5i>z3WROdET%H zJ9hN2HARf?s;FC9r5rO6iJ-M;YNF zaaIw2h<_tP*KXrMIN*7};ay|lf=Lmm6LYMn>Qz*|*Ki50hTiShXef_rSR2()9@Vhc zuOVuHQ0uN}q8d($YLLwg21O4~aMKWN>tISEIhAoGVy7}xO#_NXQOPK}lubMb|ELcF z3l6+wcrHsPriGt zR>x@LAw3XT1?UEOU1mV)lFoI?KU?{S6gi{d#W;Ae3+1J1r6VBC?C?r8AjMB7Q|n%P z;kXI^x8t8V;}yn$3Oj_$3Mq7_hQq{#y=ZtnafoC|6@M;g;+l4px+MIUk({; z*|?Bg{M#|V;%lWBc678f*VS}2x3@*oBlR27+v+#WtnKEH^QL#Tx3|{8*00oTe{NgYdSYIx6Ry~JvTgec6v*5ZTkAU zy1oOZGhlODT}yX;!#5|Pqot;+vAweuDKPQQ%!bOkrkO}kdUvGL)sl|aPMVtA{*Sc% zAEl`#()xd-DY7Nv`vGQDq846ydq+cCB+}yZG{4Rak%o;OeX(n|bTve}I-A?pqtW0u zrL)uOXc>{N`uc{(v?eyJaMzZOh6voSAn@@c$8e)PbhJmBH+!D_&@HJPI*ZzxNCTuW z0j!C%Wg6G!IT`bftF}$Cxm_LIj0@7yNXf|!{%^(O_z#vHFY-B)T>9^dYF&8J3Eb|wWg(|y$)_s z!ZI`N_S(}`prO?`e5t{J-2`hie4K}op2~UJva`l#jXyR$KW~K5a|FbikqO=oEN}rkUB%YX=l76K#AUQK7<(gZa zb$8vJvhidmt1Cax={(>hrKP9ecT3*SQfH(t%lp}~^htTnX=%4OsmXyfpXT>0+ZmAS zY)W?T$?3~*paY1(pIi+j5Pf9JBoIfEoWo=W+&b3bK zYG-VkvwwS+^MaM^tU1w{mYgTo34xF=BY(4PoZeuOy#& zf#E)}FN3JlG}LLz%)F^753c`fUjDt^&ZN7Xx@2cOjm~yz)0);htPG$Y0aFEOX<&otXvWC#PS#GyP|G-%`3h zuXIiRDJN{XGLjL=Y?!^iduRH+ci-RbyteH`QNK3VNlT-x*!h71U&{U%w38>HG&0iD z^Y-ogWnNwYzsKiU`7?2L?i6QBa$Z^Hl1Xds&0D^2va>lY6U9}~yk|i^;@Q`8-3=FR&qi*L=NXebC>=4qBA{tiNp^$Cj9$wI(Gm zb6JYho$Cxq?j`eskexgyJ=2NrI(9;;voWpP=}L3Pq~({qQ<>7ZCP1W4V$|# zJaA~Y3M)!8!zGo)E3Ddv&am{lR;2mNhH#evdvdF$Wqo^Rb5~QV)gZm0RolECKZz9P zhd0(Yv^8|rbTx$e0X-Qvtkvk=!(}U%mn>WpURbzrX|WY%e`<9{8tU00hdUq}Zf)pl zYOfDRx{Q2BcP+Uf>l!+{!nHN)@p?^JcwtG|(&F;)!pha*T6DP^!c3cmh>at>3F&IE z5I9`d+JPaauDLnP-`)b%>KRMw-`4gq>SDy4u67 z-CY<3n1J@y4!BK@YC3CLk;iaz8$KrtQq$NFvG8Np zQiGE8aD9U*$kM_U#o>i3OOdz2lG4fws}U6vX|n1t64zoBx9}QQn3iKLT~WBuVqy%`FX9drN&-j0vVAQNT7qw{@9>R?f}T7^Lw;x;r}BJG&y`dYJ`j>evJ}G`DSx z7Q5JJ?{;Lhw70EKreY+ZqpqW-t4S=&)H|{(vm)f%)ETO@cwr@Mh3zg3Q}1kRXbHDB zHX=v<%))R?O-Uw9%8%#>Sei6y@u(3s7I?_Qd+gbG&?jLya`!r`WMM)(aM#}iwjGoX*Sd+V*%7@xpix*A-u7nv$=7L z^cCnH+FQfXo|EQ0CyX!hv6G6*|jpkMd8fVy@VLt9rQYQ5TDNE@zg z3%6ppXxOYBT`_8^xV*5kc#(-{<-*G1%CIKSZO#1gR=QDyVJTN*1RR6RlELlgB4|u7 z0Mo;<(qM%fYg)Q7)UcY-XBcDCjzpT3)L~c#HS}RdpuY8tOjGC!i_0s+g;lGq4tDb4 zx|Vh{dD^t;scOWuBUT%R;xJ#uxL5@O&MkD8#=n07+Y;yRxQ4@RomL3 z)$VrkR!4SoTcb(06lGx*28Qwy7&gX=l10(3GTK`dE?=^;+%rit2w9v%=)fs?Go7^d zpl$74MGe>^Kz_K+L*h-pQ&@>~7FAWEjHFLDeO08J6N%!|B_*ZB(Mbw2yt1sgw4!1; zY7ngxb?8o9XpI;{bs9tJ3{xIUic4Xb%S%o!UL-Yv;g%yhJ1Ut5Ne8Lr?iy<8O2itj zYj5As43jer0o_PryX0=6%pj^dV1r1aH!G3~MBQsw32|0XZD;!i)Sb*7Oecb_k%7$6 z7DjJS8kW*5sa(1uj1-_;O)g~qhF%9+bjUPy#5Ft(%nZq>?`qalxTJLPO7x^&rIcY3 zi3ZvwYO>8}CZ>seP$$Z$xv`ne4AUz!&`Vd%i6`b?ux3vc2Z-ufR_rim2GhB-G4`0W zxPwj|N)}}!Lz~w(ag1{dxT>PKT&IVKs=F?dg~2ScxMX>;<6|K(eBt5)`Rv>5}e*7RM=iS0^l(yJkKkVyqNekCvp9Ei>2E z5r_jSMX=4LU6#yr(NpyrkfRCPu%c#j1t$wKfTI{OS>gcQ*4=^;4-<9M-q;-6`5=u` z<}qsG9n!9wY9dWxeq9k$kZ@gXB#UmXa2S!Xg;`m!1+gO2UDI&F?6;%?YDN##hUH6h zO~lxSH}^q8u)Qf&=av~}(x~XV_HJ$3lFXGtl~0EWE6uj+RWZJ+x6X zX6i6wtb$7c6oPd8roT7qAjC_{mHCdB0CYJOl~@U4e6XbZ#Nw#dECt>9gTIZI7nUwU z1#`cR$%%G!VXU##MA5k1E*BzFG18ZrR0xeZz11L9>uHhx)2knjmwxSBTuMoMeR&(2 zY*G@X=V8uF8tcMYHC~DJyW(>jM0(kM2sV-HX;l(7&$OCLYh&6D^`|P z%6Jv-=H$RNKo+Woki|F^u<>-aVnpt2u4yUlZbe@S0uzC@x&~7VGRA1j#acoJ@-hb9 z*c@q&rjLyXBat*BB*6^3T>F=CQsAzTShw0ENxy>5+%-(jTg^(9b-=L+jne97Ol}5N zF03e%lw;KIYpkGlc1mW6FT-1R8)h&td3R=L78b5TDw*f07nLxO?pE1xsOLkT(2gM2k zn<&vWlfReY@Frc4Ya19qOo8a+5=*z_g~@n;lsvN)7TVTa2L~Ss<>8Ug#(6VqKsL6t z*L2Oq6RNyOdt+B)2U#86c^ex$HqM$^pE(zFR}&f;u_ZFI9&HX&w>)fiCC^;Hz8?IQ zk>r_;4V&vQ$L01Jhz>@C9R)n&s-J0k1klZGSnW69(O7G9SKi#&;Ftx|Os*$DaXB$F z0_CcOTM~5pdD4KJTbjGJY2*g+Gny5>X0=Kb$oZn= ziJ;7Uf@b$e_F^h33-L{)n57eQiGFIc?h=~K0XB2Dgchz`fgkh$Q0p~%N+_1Ilrei_%iGCB`8Lx^P)O2e!&+*? zHJ$6VM>Y{MVG@?Ra9-+leP-%UY}2h?^zm5eb7vL1go`l|>5_m5jESwJTlV^_nl7}I zT5Rt|up=tVl1LL4|FR+G?#IZghXV`dl+8%%7TM>KWk-E$O>}Bryb!DV26rn#`p8=B z@@j{q#VaCab!kl9GDDP^ax7ZvwkfxGOsf}xDHRd zv0u*(Ffk%lEoZY{>(-vYOp)CZTe@t~VpB#%CEgy2mmcWoRqwI^R@2pug|&1HVOd5; ztZ+*$Iyvsn`_`{)B%SQ_*#NM#Y{ELC1x4l)!7Nvr2-ah=AKuW))+Tu{T}+o-Vq#|E zVTza*Xx8wuV~BFa0Mv-5(HOQ(n`y0yY>?L8jlE)NJ7$8U4a+|y9zB5=R$0rkq0fO^ zH~V@IRv4-yn1&!`Z)}&8YO6p>-7eY8#<7Co=Ao=#q!ZMcz2t{eX=!#c7BZWC^dH7h zynSQcQRwRIW~rD}B}#;=815^%EZO;N&cc3}?-7MreU<1Vin`90`VOgOW24dvj1A~+ zuxC!#U}JaLt2tYyTgAG9^)9AUxu&cb4^L_`QU9ojuDO}oMoio5wPMF~$_yeFHgF0X zX}zwU;z7M@Tl8Tb(1{Bspoy}<9$T?KCz$EKsTT5Gu?Btng4Hby19qTsP z!DCrVlBJxuGt6Cb-6I!|q7`L2j+#0VtHRte!xs+aOPiGfpzUA`K`&|&c(77n^16$6Xx-vZARWxMst^wzU&g*}E+y(tE3|{1X7gB{oF5%IK$*v%f z$54+V+cecD$3tRAk=qL|Ig;p#^B`H_kU_hgb0yA<(XI!Ohr)b*$^NvglQ@pZTj3BC zieCp0r1^AA_4^&_?bqSY0}rnCnTMhwcQOw=ROVjS!cjP6^p3di^gAbLa?-1edFZWA zU4=vV-BzhXR~Ko&?i{0gXWXuS=LXMn&S(84yTU+IM#(!u-|2sjU&f!$RM9bXr<=CP zzVJNfc$Bnd`w!pIT{tAPi}4p`fvDjTGRtO}^_w@d(29%iUl_6n1mc59!Qu7@dz3TU z9)sT~8s|(1rrK6oWJ@ci-N3F+gH5gr&vU!1G-)|$wJ`Fu&W4sWGSke1Vs|Gnt+0GW z8rU_peflz#k!Y^pd{hb18yzTOb^3hz&==!tbRF4;AEC4lk-oGaMa&-!Q@{aKHXx4@ zPj8u{M|7l|#ANzQ{~|Xwo<1b{h~+3!N5)}&qkdx!F%{cOx6fb<-(3zPgGbTbOX8?$ zKSIivc6VIvJMEtDx9Rq!os%6&zc~mHt2oxX56yjvcuDSiR)^LW)2f(+qssOX>9@*D z3QW?9*XX0N*hpi&`-rD65r5{mZ^Xeox&s~?iKes--RD<8EkL1OA$EcHMm9hDchB4mXs5UARs~XR#zCkm6zge*>;jcVQuCU7x zt5)kkJ^Rplq<~+k%)5@F)A$`-rTVvXR7&gPd45`ER>thP$m%yr%$f5o5}6s_rXv&2 zq`o=W?Ci!V6>FX(b3tS=0A?`E%D8YYU{IPGUw0zwtQz~&il4B zXMbDCWX=9o9kXVAb1a$jv%f_mD`S54H|xmCoXzrQapENXdf9TvY)0HQwRn!Q(eI1B zBtMBK+if@>?Pndy;TEN<5!GjlG3pBYDmLk0Q-tOT;)rJ>^+(W<=aZZTrKwE zT-LpU)<<8vZlc4J<-W_|>2lxY@PxVVa&XX^?>j}Wpv-NlWi|c-Jc#YP9C=$M%5ZR^ zoUgh>FPt#S@n)@w8-!9r2MN6 z%J)vagZDLibNDi5^m0&}z4ad>@=cxyzb_HJ9BX2ffXlIxWArD-_@~C`PZfE7V!&Kn zDMc@**Xo!0kB!lPY*ZL72iDd*{ZmA~%afYox#)1L<74P)G5V*)_|J&ZKSSgn@T7WM zwXYp`7j4zoBM>@nyv5<;ZJXetLe4{`pZ)xEyOijQ#~8&-ZN2wZL@RgAt>G4d5L`YJ?zuP0UEx#)1B-_8)egBNal_b1gc@~dO?a})G5Xd7pnEcjTBiPt+W#Heo>c#Ee z9DIQ%Mg6%)Wy=?NTwlh&-ddpk9BFLO{>#Ce|5fTgRQ#hoJLMd!*=kpRQ-00<;P5}) zx={V`rC;bjJ;r~7b&dMRi~oig{}$_B_2+(;EiZXTMI5Wu`iuG}iGOR<6D|ke5BW&_ zIda+ZJ&~x0W3@*Kkv}7b?u?8E?#LzFr z&~L}kU&hb_y|KXL|Ckv1_!v4PhAxVsD`M!z7`iov-V{UcjG-@zq4|qM?#2A$*NnW2 z^!^x{pMY>L`acvyKOIBA7DIm?Ll43{z`dw%Yz#dkhBhBfF)xfK1x8z?G5)8-&=JsV zVjcKT!V7laiSfTc{ntS#DUfPi8RLIL4E^gE`jHs=`55}082Udkbbl-sm_9yNND54` zMkswq=o!}J=wd=<^Rr{M)W9S!S z=zqu1U&hc5zdWE9;~NZ`<#jFolLB)ses|iv=s#Qi`HUnfu)tao<6jv=H^tCr$I#!2 zp)Zc1F9*%^up3AU6j;|Oog?%j>!8xc{z|O-W5PcXL%$G1zZOHk51R3%ivCjTaEyO{ z-x8PQF%&fA4~Tq)bxe%^u`zU744o50F9uD09Pg3>tF7`F|C$*3^ccD`hL#7^eCd2L z54!O^KKJp=WIWFF9>Aw9Ux;0zdadn)T@;n`M3aWO0-1C_dO6>)VH$VtxB$ zU^A>wAK3)!(?>SH`u5?bm!5_ShviXV*qp5k*Wo3bj?RqOBaQMf-G923rv;*im$9!U zr?+BHI8llRy?n0)@j*b}@0*H`|0N9B#f@^kqs1{Q+~byBPH>uNBMM9NMG8;jk2o4f zExnI@DMyai;2;4Hl#aSdY;eCraT95-&d8x5;*zoy$Q+WY4PgW2%h}(aib>zy|YJNOy(6B_k>F9 zJ2`CL+3vfda@e%@84lxr#EUDvg82_BWxJL(6g`$@jjE z_ZlS~JaR&m7DWdiXfZ^uH!%DjVfWPo)_k-qyu;2sUU>AQOKu?VfR5hE>|)bRm3+}DTDmDPR|gKH}j0jJxB>OFCLrZ85@I}f#n4o zO|Msoopo8^*%>&gUnd#o87y&h)|ryPaqVzJeZwq~kTqZY&oH3ln&!^G_L(t0{u+E@ z8T@!mxUMH&XIT#@{*eggUx_!E?|#Sc#}CSrz7hYJC{UiCU8R2Ri;^xP-h>bP5pTw) z(TJF!@JFLb?;&Di<8~tCx&Q9$z@8!Te07JTgcFvlSN;Z?)uGvcwMMa}^)|E3-x*K2G}Q_y(gQzZ@BV8}t)@4ZVs5 z#M|+;O7(A2{zm2hka!24B@m&HpPG!n6ZJ{_4SqsGY34uvF3aMNW5?f(FE$eI!C5Y) zGl$&j{!H$%EnTT+Qh+w{}_&?$!=EK49zf-#f zvRs{ukzXRxF;!{WGijDL{bwtkt#q!^P-{(d4`CtQV;Rq2^R+{!V>#(Z&FB6YZyRaw zxtqiC+5vPT=Hr%(?*h>49y9qP{}TFx&uiKwgDjtsaK=Aj&fLXg-Yw+>y(g0Y`)GWp zkVZUBK&RV$s?gJSJea(oZwMg%59U*?@qaWQKZ}3LJd2Be+I$}|{!ePBh)2r*8S@b} z<_B4nd`r25ew#Gn{ep;mOZkK5ca$m5a*u!3^czl(mNW7x?hqng~6oD2-%T)6#jz^$q2>8s70wTC$tTbe~Qd>1KU77n+a#dgV6< zOkU786cGQs_6L8_azsA4R%HKLM0`Q*82m=kH>f@DH)}YS3%U?1{zcOdJDZGMGd`9t zX(UbT0aYUX+;hr@YT>`6^s7n(tZ55)$Axre0piiAmk|+PJ@IeGF5(eb`lG)ayNpL; zx>Ds15aE9h5q!o&Jgmqs)5pJp{1d@v{Sjpx0J0uPw-8^&Z=frE0TJPDA|f5qUqShO zq+c`R0QoPF2LGSLr%ZoMKKp6%rxDTavWW1{Ra{I&e)u_G)?*71>EPZW!{0|lcz!Q6 z{&m=`^8c;;A=uMmISnVmUXzJvU;H31X?|2U{?D*a;v2{(5&Cy1{!nqB;sGM^%g?+r z{@)Q1Klj$+(Rlb7UdH#C`u|V;xpzkXWa2;2UWos+tVKlRi_h7do%o6_5%#iLY3`Yk zUZ-@u(oIUYDBVH46n3ukW~I+odWX`xl;++V<-e!&B}!kW^lqj1D7{zdYn9%w^Z}(0 zDt(*McPf34(hn&8u+lI)Yg!@ixb~UPQO3Wi^BI&=2iPnxvFA6mf5iit3&3Z2u>W#E zU!wG7O7B*BkJ5XU23XUU@{SAfjRwS{lbcFJdnzI#zSTt3>pCLpRnh_bJDc>q_}yC~ z>;o#q|2E<~I==$nqJ2Y8NbQ~D5ar7iWqhZ7k%k>zulxsy2q)wG6Zi>S(ij*1tNi$Y z(UYbq<2m&zU9Y&2h;;8DB3;)Lq4!oI;*)mrF4{k7c@3q#VqBg;1U-WY zxw%BhEhoN*_DFmmzkfnph_A&GVaJy!?k1ui+)G3`OS}01^99ndd-)LZSx66P*5{K% z&}>Jf`E_g3FDU(z(yuCgNa;6~epl%amHtHOFO)v4w59eJBtm~k=|M^lReHG6qm>@7 zbh6Tum7c2f45c%ah9y|jN_oe%&%m@wgQP=na(MKiTTBh0B{8P zz%j%hTUH7YgXK)+=O`8`vYaVjp?I=ljbfu>L~*m?xr*$s7#>}&;2y_taAJ;Pv0|CxTE#}i4T|jV815{^^As;t z+^fj`k8;0JZyic1wM71t@YC~j8Vt$3~CLB)F%A65Lb;v0(ZD}JdM!ob3Gj8IHfOjpcREK#gh ztW!K&@j}JR6(3golj6&YpD8*6OuR!Ck5QbaI8SkrV!7g}inWTZik*sE6)#l$k>bx3 zZ&AEU@e#$x75}XGy5a|lhZP6Jn{uI#&v5HxW1&YfQPg1N?Y*#!>@qEQg6|YvjS@90VhZLVu{F~yx6hBt{T5%u- zUZ!)D;v~g%#RZB>6e|?NiW?L+DehFfSaFZy4T`@~ykGGN#lI-Nq4{*9huHy ziW3#5E6!6~sJK#bt>Svch~jp|?mg8{66vZ^f1&T`* zs}yS$+ZE4NyioCS#cLD~D&DL3xZ+|h}(^aatR(KvR{TQoe~LjY z2pB$Iaj4=*#qo-%ic=NS6lW{uC>AI#R$Q*gpXFsds})aEtXDi;u|sjA;@OJlC|;oW z1I5b}uTUzP{-`?rH!JQ^yhL%2;(o>36dzE0Qt<`FLy8|N9##xt!N+)pD<&(>P|Q{= zQ#?iSDaDr*-%|Ws@wu@^@2iUMDt>pI;U7@^Jr=Bt|3$22iT_aiP_h3+!ym19ykd^x zD#b3v?TXhc-mmzG;uDI`DE=bV=>JghE5-OphCfPivf@(3D#cpGcEz(5FH!uN;+={Q zEB;S0ezJ)tNpY6qBE_|e>lH6o+^2Y};_ZsRReXYoHNan$K1962vffhqW2FPf8h(Ew z%0E%*kxC~keXP=X#C{lelnyIyP~4=rQ}HK?Hz+=;_?+Uaif<~uub6q9Nlz{jbFXDe zR}+zswMsWCy+P@XN}sEEk@A0}^mU3iDgW0>-=*{;O8;5$W5v)Elb&Hj#6Mc;RO0vX z>wrY0bDrWdBIGI+PgQJGY**Z@xRr?T7b$(I;vU886mM1h4e@;J_Y)EBImJ&E6Q&w| zx?-{78pZD`?p8dY_<-VLiq9y1teA4V(K|ZnFcEr3DLr24u+bX2tUqze|MvA1QsM z($^||qtd@p`c9=ERQf5!mlWSp{7kXmbd!%^ild2$FIDLUM3mQJ#bxSWMLZY#%*t<5 z+^M)*@qprkiq9*)tN5wn{}d<8F!2>A)++8)yhic&if=07XHX=a#fs|`cPQ>tyif5N z#rGA5q?zy;it`ou3!Th=yW+WuKT-U-;zNorDt=8wISxn%VoXUT!p^1;!Ov8BuF?fc z7c0F|=}M(fQ@Ta*4CSAt^hJsnEC0tzU#0YZrSDL@NBO@~`U#~!SF|&b&Wo|HO+@+= z6pvTTQe2{Vq2g7FFDkyS_?cpSrqNfZxK?ow5#@3N5o6KqO8=IKa{Haqe^UB+rC(F} zZ6d;bt#l~MgiBN$t2mJexm=}J5+mprm4B|{^@8q5!QR&|(-lzOWi9Hw}h)Cbx6+a^) zeP1hv<`_CraU>D)la!vVxP-VB&p*^Zthht*CyMtdex*2JuF*F|ae?Au#g&Si6n7|I zsQ5$0JBg_GhltSqjM9H6B0sMy{hreQR{ATY1M^Jy!9>U>DSeF6sY=gOI!oz1rHhna zp>(;@HHv2`e}~c+5ihi?i-}0@HHr@@9#R~YZTyoJ(}~Du4sijVvknF3Rq=hr|0>2IuS`#p;&jEeijBlV%j#Bo2NC6a zuF{t%y;t!%<^Njo73CjN`hDU~Jf9{)@7Kg1i?F~1M-aA@rosiO^O#N?pM4=@oB|FieD)v<{N#-D$ZA2p;)7M zh2qVM_bWcD__5+wib*FJy_t%oitC9ehYrPV{^AxXBd_?ik|6}hxz_Y5-wg0`} z9tbai&_WG8w1g566_5Z4pp;Mrbqs+75(!Br2?$nD#NM!XEMu8b2gh>6-p6s&!E$Wl zjM!#$Mn~+9I^+Mo*S^>L?spT^GvEBb@0{y8>&lzoD$jaW*?X_u)_S)1x!7%rr*A)T zj<`lVRop6GFWw_QD!wg7rh59iiTjY)@1~G59A}=whmmOaYOzuAN0A#G=Xiy;kjQts zc)ob2_*?Ns@h>FG`<$GE_tn$9aC;KvbyB#G!UGg8Qn*;*0~DU7@IvuK@jUTb@pkc1 z@dfd3B+3n!di6+>2R1SX?b0FPtYIZlze^NWL7tBJiX`f>Q~W|~gMEkby~WXDnK)NG zk3|1mO4j2!2Z{FVQ1}t?9TIXMlN%l98-?R@z4)Hu6tPm=B%UwcAwDj?D<;c5J$=MU zB0h6q%B>PNh-ZnHh%}G!ml{UySaGv>ig>noo_LLTy?Bdw zn|QZ)pZKWwYw;!VHStaHUGXy#o${6Voro!PCZ6kqn4T0lFP!0?Vt;Y4I7%EVa^64X zCySi_%J5?GCt{^oBXWK@ zGj9##{B(xD5IO&r;ZVq9OyoKn#&;L{iG##(qM6SIxhV>liHpTU#7ePR-)-W<;^X3r;w$1Vk@JI@?=$f$@jEdb_R`yl9mH;8 zPjQeqRGc7A7N?5`iSxz9VzpQ+Hi~9G9qPA5Va`Klea{sy5N{BFA^u9dOMG1XjmUY( z)MMt`fxlPy4e?JR=lfIc@8Um1&M#&>=NFUh#axl|hZ)cL!zAYolf~i$ak4l=oF$rh ze2`zF@G`MVY!TOs8^z7y>EhYqRpPbc&&69s+SXwGc8E`soiT4)d_jC!d_#O&{8ao> z{HMqOf>ThA-7K9qr?-$E#igZ zrQ$W>_2OOPJ>nzc6XG-CbK{}7`w^^2G%_7Vq*L&SZ>iQ+VIhG^zL zqTP!WUMU_S{#0Bm9w(k4o+n-;UMXH9nt7AZf2YEaioX`k{7Iz0s_?tw`{I}4H)8v^ z*Zy3wyVzSCEDjSVh?B*+;sWsy@o;gC_*2o$!$kd#QTQbBRPj>rO7UmnO`@5viTrmc ze6RSR_=NbB_?&3wb0Xh63cn|QBz`J>E&fw%m+<c(izic#e3nc)573c!PMCc#rt7__+AAxKn&t{Jr=W@o(bi;@`zk zme)Tqu`AgV^Mk~G;vlg|93$>0P7yP$gSFwjUOe_-j z5%(7l66cC$zAVZ)MBz%YTC5Wr#pA^j#nZ*J#Vf^Y#GAxh#0SJj#NUX|h_8#g#E;1S zj`OMbwP@z!B0dM_Hl}wHdx(9+QQ}x}f@tRHBHw(47mL+mt=K5Gh+D+d#B;?9#2Z92 ze;4}iRro>i3GpfMRdNWPXNm8K?};CYW_~Z^qS>B&mY5@U5_^b!#8Ki{ae_EmJW!k? zE)tiDHDaCEESh=2sLvLLi*Q{lo-1A;nt8%V-=^@d#Jj}%#fQZw#izwTif@VUiyw-g ziC>9ai^}>W#m-`$m@f_x$BFxiQ^YcHv3Q8MTwE!x6OR&45VwdIikFJlh}Vm^h_{J% zi}#6-ie{cN+V!l$&x@~$e-J+qcZ*+&--w~4*FQ0_o!CLl7YB&N;&{=_Z$>>1Quq+@ zaM8?jM*2?`UN0Uao+z66&yYJy;jQ8&;uYd`;*H{ei1&(*h);;mh|h_yh_8!(CC6gj zi};0T=20WwZSSQ=#jauxv7b0d94}4~r;5|XIpTb=N~{shyla%(tnjhoCh-*U4DmAY zD)9#K7vjC*gW|8n--^E%-w^*S{#E=&{7#JLc>U2<>>>6M2Z=+)eaZbDXQDVwoFUE? z7l=O*D@8Le9Qo@MUMC(UZW2!tFA^^kuN7|)Zxw$f?hx-69}}MxUnWa%-zdH%{z?2$ z{8;=-{8pq56y}eMd15bdfN18SL#{~SG2(vWB(YSSDIO|Th%3b-#Gi_5MKf<5WKJg*(H{vtmAH}!C_r(vz&&039@5FFNub(=KUBupEKXHgSLM#@? zi<8A^;z8nE@nG>#afP@_TqhnSo*-@!&lJxUw~5z@H;dcF{}AsLpAw%HUlLyv-xS{! zKM;3|Uy9#|ZF0SSONyPvJTYG!APy6Y#7X1~Jl7IuinGOq;u7%)v0hv&ZV)$$n?EmuSK_$mp>|Ii#cLH zagaDd93_qyCx~;z`QlRXCt{UYBOWClCvFi>6VDYd5U&ug7PpIci1&&QicgA9i+>Q` z6yFm+5Wf+>6JxkXWdEA=6JVagy~N=p-Vcrx_YwCOXN&Vhvpxdyhbg>TY!J=52&5mS z@Fwvj@l5et@mlc)@mA5Shk%}k8OD3W$Hk|`o#Gqf+u~ouzlr}4UA$PJo-DDQ*h%ar znspVB8>aARahzz@Ss;C;!t=yMVwGstUqG%wVY3bc;iD8jPCQ9GRlJy70Xr(YxJ|rH{Dt^S@hJ_pJCAS1KM{v!{9b@hG%btypds?e{L4Hlc@Y1;@u?r`9AR>677CW ze3C@JKP~PgYw#XOe1*hzcwIa@j4=A=DH8o*-s_-0K8zsT6ZWi-#&(= zh0gH`Pasi0vz?HREM~izen!~zGwN&l2jTmej(VGRBW&7@`tO#$&q%bxycb5gc`uCi z(Ec0CA5WrPwClz&?Ygmj$0)p!L_056cpHiKKB=&=D}r{vqVVe^+W(cp-;#%;T)u~d z{(KVsF<#*bBpSI);VKgS^J85P2%-pMcZYe3`OoK|&bYq#Pr0xc+(V9Obc69r;P*pv z=z=}UU4l64Y`Mb`k%ix6CDgs->EDDfc0KcBdDHM?9c(^sZ@;tkTZu^c8&6Oo<(Qwk z=q#7R?=QCn<>nxc@nt2Y;#^lw*GCqO;}x3VwgNcf6c#N4Dgc?@Ros+qUBl=;O~itB>P^ zU*BWU$9;bj;*^_7!C$H!lw*CUi_Vst10jF8onB411GmVj zaw|N2sdh9%-(_se z&X!C2L;iL=?Q2ID$uZxrJ$Y}sd?hiSCxto3M$d?@Rov3ncJD!HV zWo($7)%TNtzVo4P7i8Fue)!pTY>+;{xZ$jX&so)1d2*?CP>%JXE;?K8Wsvi?qviMM z?J-bt%tyOV)NR{Qj7-NMY@OA|c{6@}o1t$qgxHS3_}O;6Dt&-)+nLGdY&*X3utI4Bn2e0GcPql+`YzKAG*>axbUS#hV9U*e$KQ?? z=)2Bn^8Q(UUj+0mguZ1EVLQg*XZ3L&5%t-2bmQRSb4;Tf?a8IuK{>XAy69}Vh4A?M z?+#x(_LUs-9j9{b@sSUGoU3G=_09|EdyMVS_Shf7l%qb*Px7~8VJEA}qix64o?NOO zlw*GCqN6^#E8y|BW58SK?J)`Ilw-aZJ$yr&RzrJbEmk*&$_)Wvl z>gy|gHs3XSX~$$wF4d0f)DG&RqdvL`fpV)*E_XqeI~_k;F73Ga+i^4WH6q@_Ikuw+4e)P|a_GC6isY=mB;@?w5`vIfWB!yeQb|y#|G)M`S^U+@7PAV zOFX$$J1EEcP#2wT#|43M7y8OQRC3J6d2;^#%ZEPhFV@*|Uk=EPhn&3!psbbqdqA!X za{g1CmFp4DESJxdTa%j@kmK{_JX<+mxfKDqV=m3v&MB!^&M2 zkXr^hyc$e7D|dfDt_gBIQc~%Dd0TQe=}gE)54NGS+#8VdZ?~JV-M$*=ZMO!9+wJyI zK;PDS*jBe2A9A*SE|gh6OFO0+Ym9w6s!jVxpxo=STxT+NgiXlPgr6;!_A6~3>bv(0 z@BWv5I-8aaIe$Ce8R(|2pIabj_4NVdXdXZ4K==*upEJ_u3Ydi-qtN~F&oV+$|De&9PmsE@x{0lAfUfD+vADYqz4 zzjcuFJIc`22ISU5uEicKNVl818glq^CgVqUIogpAC7a;qS{mC9&a=dr(MTD(5AJX> zzEEw;8p-&;{&Jz8hircuf~t%vi;2J*Z1DDI7eZOu+Hjh z9ACkYL=~0?F~n~3~nZH_OU zRpz=@6Sqe}YCmK-BZr#OqQwRUc;-9S2^A#nOgz`N=Jz$jZacK5$88taP<#@Rh~jw%5MS+O;Buo#B+5NG8i4{XtAT=Fp!itic*w*erRM*| z_#bCP*nDB(Yz&o7cmc%1=iUx)f_991M#7<<(3Ev7;vC#~mil8M zT3=3Nl`ti4QnItCFp>zp4}qMleJPe@QaWW-LO9Ykv=su~9L}?G!dtoAs}0x4bc;TI z6#Q+Q>z(MYDdM!Pv))MC`r0Zd`Xp5+vIjv;^f&ZpXY(ml^rf2&whJK^xeKs@O32y_!7f?_5Gyc2K zc;97zUF5}5;9}!F5e0=WG2Uk=d#Ul>LxIbTw}#m+H{P}A=I|B9%e%?&mBxD^1-2P4 z?TUx5HeNnb3}0isd@~fj)_9T23E#d7Vu^dve~G9YIvatkGKfUOp>v?h$?C~KBs2hs z;Bzrl^d?tyCAhq-Q>=^GOj&r1Bap?e zj-2M!Al+%-Qn|{BobG!2S7)Z2VNw!V^N}1m%jI5?opl^EM$U1$ekaFC@)N4j?ruG_ zh~w^V~WV6aBM$BmE~(<~^4SoN`aZzv%n! z9rUlEp1-*F(0>vAe{~yPe0bc>VqGh~Q<>28Kp#7VNa=vVG;R6iD>a4gb{lvrdO{PDQ)vfdcF;7@WbXynom zKX=@T>V67OXL>sCPhScD@tVd-aP?NF$Q7Z7z$`wpid-2oDc-JjmD$H5S)HkHn+YVc zhA?oo$&#HlgL$qoDcr56Lr?Nd#$6j?sj(D8KUUVaCXdVXr7{s~WC zrez^|3O%{-tbm7$xXjhI5#DTNIMy4P9rQ3ePZ}xV-hGhm8^rYC4b}lTS;6JUSiwbJ zr8oq#9$j$((zg=P^l%^QTU(D1_h1gRefe2QcM*?Veh#7^H7&xw{_gznr|$gz?mS># zf43YcXH%&?|8L0cE*c0~IlZo0^hX(0@wQfabx>g*2Ao0-d!aq^+UE`_Kq zE5P`CQ>U&`Uwbid*$U!l=7&HXfB5LJ#(8i*D_R zU8{GoV)~qVg6niZ1{@fL?g4q}f-^MqO&3W${g4ZqE|`+XjQvl8j!?IAr{HiN;OSG! zK)=cig@aIIZNLz+4R&3x3kv$83yRRsLnMGcIv|hTIW(Q)fIQ|I=2t$!G<0|>D$2g| zB1iZmsmZvG`0qO91joFHgCXK7lcImTz;>N^gcX>VA%K2>z7e?Fph&AOfh_G)6 z4v%~GjVCbAFOV*RYCM7Yet~o=(gOeIMeIex1eAe62M*(p9Jc`-n?$!ada2$v`#w3F zpE8X&2t%HY3HKW;wZdI4V$g|>TUc1MqG>~8OG8oP>J`o7ouZP)#=6=Sl`XjAYc6W8 zT3u9MwR*(zwe?kX)kQ504RtGODr=Ea*|cUvU2Xl^^&=|ltC|{WtEwxP*N!MI9ADJf zRK0v{ZCy)IRb|tWwe=&`j~`btuDGbKc6rgN6)RfLSj3FA^(*SuR#iLcD#547qK3xm z`sU_3w8h@xv--^~RaMn13v1Y$%PX6!;lo(XFE_WOy`FFV*pd5sK78uf^I$+WTOs_A z<96!ZuiwNz{pN=7H7wW0zX*RQ_OC_wJ_^0OsbMuP1$ZHFJwc2?F_*Hu;2SFWj6a_Q{yStScgow|nl zRr%)M+WO|&RrS?X`Mh^-Y{LJ_<#pBg5`1m_DlgN_g{8AAN|%&-p((S=RYEmBcV698 z*-~BQrOchWuykRC64RgU=C`NQ#jz9>h~1*e%Q?MtPU-xTS<0I32DYxLdSyk!%9Xq} zH(IE`e3^U2axZh`+V%J#vnn?;RRK@S!iDo^PFb|Dl$z32;+Mp0E61vltv$dnB`AGW zbv>F{r_j2}y0z6#X0P$`(`a9`uxz})1N2FE2bHc~Ro&#ZAS18IRyt?VY;?fF(rKQW zg-gpzy+(S4Ry4ObRh2E3c#eVtt^!+WT?NX-$H!MTFwK1GzPYBMsU<%{`P%wgK8Z=y zy&0eD#@EuT9UL0iaC}1JuzR9(NSrN--H)|vfaT7=4) zKH*lVZK+w~tgNeC)$A;O69GZIdpvnYRRK29I`Bi7(+^!2qX;Hhj{Q8N)|sCD~{ zs6=pOT|;Hd2%MiLHaDznS=q>_#SrCSAoZ+fQc%v-Bwe>hBR^!CDrnY6`xMIY3 z!{Z2cF+$wDBbuR{XIF$d{?qS|GlxfQ9X8>_np&LR>LJ$veIr(~(?&ElaQvaN`i2qQ zyerVOy4uR-)DWLBW^uSjpQg{LX4EN4pG8|61uzQZ)LOY>HL_M@j=kR2G5airf|cX_ zI~d9`CnOf=OrJV+zx)Dho*~>i_DbbDI9!b%lf-=sFZ8VA)z6e<;>6Hd-Zv<1Jg;K> zS28~)TrwJ&DtSHPxCQV=_Zd;*#M;D55^h$gO{8O_liS(t8t&%ix!prO!o4H?T&J*k z!y0Twu%*dkjrFxuuSfrx1G8{>bF)*}R9#od$U?iL7naPQU5JRv<$-ugdTF&)>sv`P zS}-)VI&=iJ?p3apQodK#l)AS8D_H7YUI896zUIRu&!T)GruqYo-rKvtVT4(DO}O8W=%EDUxoDz zE!Bk>2QXM+MDc4e1Ddz(eXo=3p`RjeRji9RAAe{4WSDmWJ{RVlfX{__Kj3p=+;QRd z-RJP!6(MTj7!>l|kx?j&$5379Njcu4rd=5Kl9}nesZ6^t-dtvumu2L6o9sE?OHo9G z1JYrPewq6Hqao#!fgH(zezq>{!sczNKinappKor{E{xe3nf1>N=*JTlp9`BW{-z_s zkj|`sW+;rO44L}71@!YFLE43#?&$!0Va$@q)aaiz!Sr5%^j@j?HF)NV?QUmeduqc@ zpMd`SK>qyH+7s_dM!$f3zkqx&eLz5dP#`=w5Vmh-z38wrERa4T5H1RYN16KA_p_L> z8b}X@M+VZ1omsvZ>NzYBZbq2L5BJQDp{&$CBL5wema_r==Kb ztsUumCQ}m=Y)#JIr3devaG}CuurD(VatbKPXT_mW zj(PbN!ePvjfbr-eLpF(F6lFM9TrB=XtP)p?P2$nw3F4LFP2wHm!{W2z@5T4T&&81I z)uX-GOT<(oQ$J&~7WG}OaJ_i6xJBG5UMU)zw8(dt!jFp2im!_Ah#!f@<}C8@At3uH zN9-XE5=V(kCWGnMi^e7^!Vf5H*3=^WlEQC^d=trhUyFPN%5X=K?`#1c;w9qs;_c$E#aG35#LvX<#7;QCSl&J) z;tnKn`dlC$CRU5ah9~5XRCuF!s%X{}BmYGVL+(1o-=r|-BD1^)NgU)aDg7PsQ}HXM z8ylREFThw3!nkz+3H@_KV{;Snbqqsp9f?82*wh5iR{RAd#;u!4wu#%3kbIR}>cZxb;bnEt_LH*71m z7yF6>#o^*eaf(Yjxp=L3gSbPyUwlk_QsnFb zmitHXUGaU9a|xKv8yAu2qzzN9z=W0c?{*| zGals@kcc$f5BccWZoB=lTbOzxi=okje7wG9exncncs)lw`6ToV5PPs5&^LyJl4&IJ zaqTSSSCWu7`o>8gWf#jczc0?6V(|n*o_%x$HyhY`N?Q-i1z9!a1l2^`k4yHsW?- zcoKfpXY;XN&}}J4Il4pegIsD22m6irZMx-R#QDp;80DgyO}Q9)j6CyQi66`5enwY? zUu)$yA>OZVJM?j1Vmlbma;fip{HV{iqY-|;V;bE<_`#oQ2j!Tby69{>?t|Z7?nAzE zSx;N8)|#i&jE0=Q z9lQFb`;XV2wjCTl@Rw@G8SuB(4vtHHeY<`7a(((XN}t^x7bDH@SQg#Qo?NOOlw&)n zi_W&=M#%ZgAfO@k^b?;mU~K|+(wkkwzAxO{A{`R1oSP0zD`KD&g#1> zpzjpuWB*YfyeWO0Yt4FESA)P~6qK`R?*{ap10|eVN__+Hv-SHtpl>)9265h_bygpz z!C61kPQgy~mM_A3!;tfD-x>_;Jg2f;j`6nKE&+W<;J}@XbnC3Xjsbn+hj`~U>Vr3> zZ%9Dj&!KOmRR&sp0|WYMpoIGs_2F_crH}U`HV>km*PyS(7h%2o1oYhveFc!GKHj_9 z_D+{RTc zLoN%P%mCajU%&8}vF$hpa`k9!uY1ZmdWIJTm3d39>3OnR-%n7yo(*=MA;c;-i}mHBKu z3c{_mH*OT*amjxF_O&k~-v4g;rn1w@&ME6%mVJdYID8RT-bBjEcP#B+e4uk)ZhrAW zC4G;YW>(yMSH5d<&D|e6?Vo(8vssOpjgpW{uCF+eS$yylaS&9eI1tnfYbmpPO|$-<9uZ>YrzF<{fm@w35DF zJv!~mH?rmCe@?&fWp3FF<1g3|zIeuMEYr!yjQsqtBtQLgWc&T^?LPSlbm)`#U5DTG z_??2^Y4{z1AFr|aqr0{JZ5v0t|7l6QELqmM>|&!kQnqBrnf=?D+GP8BCBH0t*RZl@ zzH&D1TQ=HAM$7WcI`3dD3d%w(cN34%p++;#!QtCBa{sZ%ncW`~h~x7pJ_j_rRR!kw zjI1z|DE55$tR2rOpHf<0GQVWDgIO(R&Pr3J0u?Is%M6XsLd`5-k zMUPM<66e==u)OGZh&0QK`l3MSdI34Zx1tu2VWkj^MYxs1oEIPU78cE;_uRV?8!tf5 z^^Ao>eW4?9E8=635XGIudx(ieLr1|MNzfieEEf6*0*S;Vip5Pzc7k`ku|()bR3#^| z3jbqSCZ$v21JoeaHuP)M91DwvLoT{?IFx4n9m=}JALo5x8!Rk}|C%CB8!RmHypc9s zSQPgb7PVapHF0lYQQL!|KmOF6EUWE9jJFGmn%ScBd1aWz$5J`*UB8Ck%lp5q7N-gzFyCOkdwvzb^}bTX7iFQA@qA@oEqG+utiC3=zZ^5I|fV&lD=0+$#s z*L6iNHQwG7xXgIZW46nUHyhm?y~22FP*U_t<9&bv+l)7aK8ap!yzf!jHOAYX)w$Mq z`K6cWE&N_oJRceo2`6+u>(7BM;fA=7%}KnCDkVapMF?PF5n`O^?KGhi|0~od;;z{k ziMyaG9uCblS@vTf65Y!}Je>T=sAry=AfKY?^8c`g2jlj|WG zNxsKkNFK=?$zQ`CPx9M9iR5g^WF-snzfE!!l($XN21Is}Pc_>mUxj=!$u%nNlOxe% zImx3T*&)e=i5-)yL~im^XzP@mfYi>(lc2LpG7s@xlbnCwEjbhMdC9-wfA{2t$lD{y z=dV4JTwl{G$z?sglN}J#C&|@7`NK#poeo?Q6+7Maj*NaxIm4tR5~onrSuXeI?8NQR5=7{7v^7 z`puSn%gA)DL`3{;m)o#2*CoW?ak^P8wz{7-Hr{pX{Y_@B*s$IkCD z?|beV#@~T|@%LRGKb<$D+VQ`*8|eQ9{eN}&%(F8eu*N@dPon=Emi3`~I{h?y6aSlg zF8wbs{v(%mIXX{e{BHLO`penukKJqG@5E`B@z1>aZ=?L@p8smff8pK)8El9?C^;74 zcod8L)BJzl{O52H!>UF8?_~ZDHUB>~@n*D&@Su-H#+vxa=Kmi|%wpp|$o%K_jMt-U z67kpFmr-WoMD~Z4L?yVwFaD*=Hbk79Nv!5q?k^!0i%>Wg;rgXmUT+;*|n2|)JBhaN09pD~#49cU!r8pMuFw_+bcMd#3(OtQ4=fH=ct}g_-nuR+D za{rowAHVtIjBkV8-CMYm=PlgHOE281L_x6#wRXXDVQ3nN9CTiBe9&u(qr?hCcQwm* z4*Vs`+l-(o;3uX4vwSC|xl0!`Em(P)pyukr z8SPrW(}ho5-MO}sov?}A%l`_MJ#S=rbF)#x6ArJ%!lk9-&S#6cgY~UC1$jdq)0okoX4WdkcK} zRyQ>{?lJwkKoz^Le<3_SM+3e^)6n^$LPXE*3=?l-&43Tw6*@~1&NLk}4 zM`ox0HpDGK+{uzY_b^l_)B=TfA%#`#{{TGPQr8&~li2?;#2trhcPkD%SpS`fyApBF zd8*vW)U*MbUPHp8NEq;*G^q$@AnVHB8gwE&ot$iLxh_wjEO!gH9Nj|v+{<6Yoq)Fu zw{WwxpsT%YXoA}qG~4iGZo{V;G~4iG3iFKGs|f>!dn%O_1V% z{sr)`(U&7_kL`1&(|iiTfuC`^(bN*#NLFyjE1s2)6jNKHrq3h z$Nb-Ir0euHmOV<_pm?uZ+3zE9@O97??-1soF!)gPPke~+7nEWLbZ0QylOFOLc;lah zIfn2E9QrjpLpcx(<>5cnVTTUk>czOXY>WrpP)ZNw(W~@jkc#g%N_e1ovBQd~`r|Nr z#>-)p4dY^rtf?+{*r5YihWW=+)==}0w{y-AesD5=c$jJ2b%*lgVyff}IT7CYHz6i* z-yO<>YACM}j3#FY7nR1HFpn!C5U zXDBZiogrb?V^^4EtWV`+LxwVlQI8isBlya-?a}8UhCiNvyBgTDA@A?{LMoeTS*QSo?)(nVZb3%|*VZTRn5f0tTXXBOTi(hJ|l zqY_!ERI|tppDMEJ+L+39cv>RHV79lEuU*8qsxDaok)G{vy)y_+%ki(u>mX%XmDka( z%FFey%IlOC!kJv+`${jxuWuxj+xwmhl7a zqPszM(cNI_PA$4CNEhZUx*L*egl~l%=8kaPVtPRy(lQq0aWP)8qSDLp%=$)8uCNfs zZcHns7W<>Wq|~xK406u@?4@aFfSF)|R&bulZquNp1TPczTx&-mtV2x89^#kHTz2Ql z&L>8iY)c5fR%#DpIsS9@Rg5e#GV_S%Ta)=CBLC7_0^(B6D|11*evAF}OD|1i20lOu zIp-Sw3VzpFbT`1l;bn1ed0zZaIbNlNoRL?N{qRG_5nclq5~ICX;sN7bNKh;DS+(?2 zJzM0O6F5AMvk|{j@q^kk0AAn1i~lLd*XD>KW*P6n1g`-0+*+ROytM3Mzij5#@?`lT zEc0d*JutziH*>wDC%Yi6cZpwbx|egHp(lQ*FEQD87ZOvAx18`=!3G#N4gW*Nhx4gi z_79NzDqTv67c`g1^zJQxYx$O<@Q`C(djAhtJo&xrH@SpsWkb^%EZ_7NZH^d^^_VMa zMqsT>(c0#w)N0E$l`CpEq5I#W&G-DT)dijQX&|V_1RWI;k7tlIS zTy}6}79-{LeCxe+o`}P3gcpU`>Q$Z(%eXubuK&zF75~-4@xUQ%uyrFRP9DKFGO)V%r*>wwN6^*=V)YV0OLvbW{(;hh?GV{r& zeROJ{ka9_lnVD(VkMe=37Lk_DpIfG7ozB;ig{uQds-?+A=0{cco6DH7>&o5oLaA`%^qB&UaICoA( zg;!?g8dlR_^$3?+qzaocyJV_^EmDE!rK8c)=|!#S?dtWRx1`V3zI5ue1tkvFA+KoE zT2nKVwvp>2sv6c}ab&89xlTvcl{|JN7P`noYSH~B}eueFt1G}BvCn+h)| zou8`fw3*YfXwtlZ;8UNyF0%dprL|V|ltpDuaG5RoyeVDWjFgvcTRg_w-|TYRJ(t=3 z-&js-YhOBN`b-QVds|JL8jH-RU^7jfSv~{(nclrPGuGPKxPaNzbV_<{xe4p&=00!2!3DM6 zi>y|c)h_zct7(nq;A&YjTi?D1GZL*XnQdkl+9q-INUx!_%}*tlqxD)?YZRKJo?U4U zXS>YSDw{HMuKFZp48SH~oJ#MnQ|37Kq+)u*w<GZhRewJSd!~ET$5;-+|8rK2mTS1T) z@>7!e8xx!2n`0+Mw?s}3pF)}cYioToIxe_wG&8Z4wW50pq!;1Ztr1k3F)*05mw~0k zdkT1~U8S&sM|@CeYS%G|t<-c+flQ@l?BArX^BKbN8Gt5Li#0F}&C-I$u0C_qm9%_l@V!a_NT&jNm$7 zzvH@IJh=5aKH5t=uItUzpB2!Lw-7$p+PdCM{r-`Z^+^WwCj%; zj_Z0e>z^CYk0+)+*V?+?O#OWRm3Ca$o2kE>(Z4$-(k(TI$cq}7N};Et@F*)pPv?nFN|k(k=}BndJ{oC&Cv_S#b8E_gp7DJRr}Ps%aO_m;p+Cd|a7! z;fxu;Odn_J!v}hvGq0^|0O`T-*i;%lVa!-u3i6oep5GDkZ&rfVQE!V4fDE6GUs^uP z*nzhqOus%OJ?Y$T6G5gwoROaE{4S8rC$ZGe>ynOG@bPIN9glHRj`}(V!u-^O6T*z*wNb}VFX!w)`jvt3tqSwWYll!j=bk`1r?FW_{f?a= z>R{P3mOB^DnmTfiYtOx$sc>rBOA5|m8COH;I}}8J?~-PFp_IbV$M~H`t ztHfq;qjB8>{1|bmSS|ik_B$01CiSf~VQyXC#;-%a&v08Es z3b!bHoWdt6e5S&ei&rcDm*Nh^KcMiFBnG<|NtFKw@gHI@477~jN1QAkBG!wii06tw z6L*Nui@z6L-0HF2ZOH*R50Gf@5XFyCc)Y?>6rQf|JcXBu{1y-OHIO)Ow2;tytayd^ znD{jb`B)ne=aC!|;htiFSWF&_wL%IXE*>YIFaAP&PW(X3#y&&6{lo*rrQ-48RpMjf zOX6E1hWU*3--tHh_F`Xgpg3GaR~We|VwpHw#Hrt;uOOjxl~^w}iJQe!#Iwco#GjGa zzi$$^i+6}mkl2r&5}y@!yJJp5G9Ti%HR(&k=9V-(Z2_i^MVFej?}6Q%|WlQ^c_Dgo<^&iSvlL z4#n}4&v=ag1tg9KbNrznacODv0Ooj$h!_sdac8bekw1rFD*KV{|CPN5j)Ul;)RRoMm)pX+h&=3HoHCrr3O_c?+gAG{ zOd0;TEvMo~eduQ6CW{tKqpQLX{>Bqb$kWUGwmi#ai1U~GqOV+>qEqEw1HZo=+&-9g(NcJ@2l4&JBu+d(IevZ9pzm%7aeH*bk8;#^jr7@eT!xp>N7?zg^na7?k~a#<6L;4FUf?ZT0OA=*z~nF~@MW1H)TN zUqbq9J9yvgcQ!cGlS{ROa%=~6(b;mj!qDH22`Ja@&-s#LKHeWwH%>#wafJfU4c1wG zGXnZ%`SkUJuWi>al6~vP`cbV0{V`DzK5_= zP~Q;ztiF!|`Zl5w=ONBI+YWv#$@-a=i$P$CZ4|;b?H_@1C*VZGdv=z~ezfK01oW-$ z`IAb2Rl8;%D{s59qrc`o?>zGW2oPh+kg>LdzgQecb=8zOey) ze}z8U^0Us?Z&W~E74+HTi2IP$S0a5(qnm+iinF+*%TXVHvjTE2!Q?ED59_SlqCoxr z1UbL6^{WlYy$88%K0(%xt{QUwemURQFX-}AJJvxCe~l&+{+*KlFZW!+5prK*Jl$DKN&yPkL_pOeA%6MhB(d}RteIq*Ly9oZnU*rk^08#nAYu9j2=I7 zd~rVA4}atJx(XD8$-&sA;R;~O>fnF7-HLzrH(+7w!Pvp*T-K-T4__5*r0s@CnNx7Y z&PYD}G5D)?_OJ0QTSWRTSyoWizoz>#rfpy56fE93cG*3!j1k#6PxdS#vS;BG%-FfC zW{0twF*9W~!zq}!la@3>uRBHAulLv$GNo*Trcpafj138=;N$0p?Yg$8-A6-=18oBwNWev}+hNl}hjmBoiWNgLW`T@?ZuwOCa{oQkau{~CH zdfC>p@Oi~oupXPrmhCvc|KY|y#!n7f39BKq%8s5k+tl;gU6j~p{Ong}_gNdK*Zdkb zGZ?=f?RIvbv~grvyN`1cj5+1Dk!2H&9giVpp|Z&)U)<<$6~Y(tb|!97P5aUMMnRdo zbyQidk#!1ccNUZ#Z)}W&$|Cupt<)O2bYoe~ZPAarxeRsN;pvU+8ebOaJH_N1dzm|? z?Q;cX@xD&KvA>`cZV6u}ukAnfJg>AJ9}jFFd2XbUkCwT+=I;J(tY^){xnN1zyt446 zV=rTl{AI707DUVLHmq5;?Y67)nQ}x;mzmr)1JbuS>yWg=6_IksPX*^Agl8}wdMwsU;I@`|GRVz(P8AmyL-k?r8hI`=W zPqSk$%QyhP`*2a@$w%BvG3dIV;Q=2%df5$$)>&IAJi(>DzxkrqAoS;WR4Ky7G2WgnE0xEt}Xph9scu?hvi zg33woM-msJ5Li&*Cnyt%DHMyFlMC32jZ@w+157X?rIA#brUo=y~T}NG3cz@3YFVpz;Yj=>qBr&q8YSLgSsu z*o%z!b0kGCHr`&SM)VTn{RcKz^it!UMS;tV_fmHA<;Hs>x;c7<@iw8P=#|Dxo3YVt z#(OH2U2VJ{QrR`e%bSbnwZ?k~HQamxBI5i=W+D*}{TzV=UQr?tGN#!Qf8_SbG67gn zIh@tL^-gB_3hHwb*`Y6)1y{OGqFv}|2s?=xNJ%6^lMsj`_;MuC-UJfaJWLZgMj3hr zvQG5&5Ey@#QZUEDS6+#}+zjCmUt2hd3s54=u~0M0&t+GmE13O~6O`S@*dg85P6vKkGsF49G?jeCd$&hzTSTd}5dNgv)~>J24Fzvwq_a zL?9=@T_Njf_XY$yWjA0L%le)BHS~1LrvG{4FUVfLcBPZ`lG_G4$0r^~-LhUY`Iltl z>upY!XF}t!#LK8!)|)0}S>g@!PS(37P?gxss{Pq0z?bqyvvsfJq8{PeBbPgG zHm(0;eQdHgiMLqi&rO{pUIYGa0*S;ZHtk!rW(74nAvR5|35QH;5~e$1A$CW%#8&*z zN`z=;p{LhtZ9^v_ke{f*Cduj$Iv;@niFH(+8=|3v0vykGp;k#A)1FbB_K|j5U30jW zAkNJ>6uU$yCy6c$=kQ`UlCuEKiRNr#j-27}$8-42;6%>ztYywEkZF@M7XG$5b@-p1 z^9eMx%Xt~{$(-&;ZJ%>E`X(pmPpCkLoE?bin8VkOxj9EcTc?~OklH!tDWrDEq4~hB zIY*(2-Ew$qpO?cIyxnv7TBt`(5BPiL+MCh&Du8pUBpZy%E(hips$#&R|3&A4NW66lXM2 ztWg|Rrt=V}kH6{OP5+tbmiSvPWje1$1dQVFNb1}JZHd3*@~G_Gom$^@r_sLwm4;EA z1L;2=#lR>IzmnPcPt5zCyO@5y$%9dx!{}d2{eN+n(|-y5e|2lG)-<{3=*gXS&YZS-S|2^vY+-u7jl>frr3K?vZ zvDl2U2v0HA_|1F9&oh8EnZxHJvB+fe-!qf*Pm}7Iz&Xgo^Ib$N!Z#wZNS*QXZA2`> z?HPX+-Abc4524J28SJf5oEzBiFU_a4BTmP|Sk158iy;<^P&gLpf&8(^AK_1WwsKhS zScKaVwsIKFajMJZXbeY>u4lp1-V4)~j0yK~x^S->YQycFZUYgXfpDJrH-|p+kMU5< zHw&@ILPRI2ITm4FlZnQgyiCStGMQ_hSj3a8fIxR1>_!S%PqkT%bre$`OUX0;ICwyY z-)u%9rc|B>VB_a@phsO4!@#U!>{)c#__>!e)Dt#-X6>iwp0x2Zi>5pJLZGLy@iXfr zc&FgUVcPkmBVWFmk8}6-Z2a_2+xR)sY$s~%akwdNAac-o#hqn~qr?hC_cS(sW?c-~ z%?O$Ty5iAgP;-yJ7;TxAzYR+IuuA*zVP`&eS5zJURM@-z!hVKmqkXo~E*n2RW@4ke zi)P?dK<8DGA@<3lIq*DzXwxT)*e8Ex$n?pgli=k$$sg_$p1xxdYVC0vsucWe`8BpU zO7JbF*C&hECkNUBTJ4jIu(Jj$|2UNR`lO8!K~>eZzxxYYZMA3i$#`_B`-ZgvTL2;V z^1OD~A$SSlzA+HW&Ol^eUS7Cwa5VligAcGMlbVYL_dSRCc2W311}kxldBJrE_T$xz z`xeW%5W)VqV0YZN*#W<0>TDMD4hOu?5gZU>aESW}@(lbv)DA&qqS(D*^9B#29CqN~ ze0Zv`X&=U3fc?=eb_Vmw$x(=+sT4%fCeh&eh&vl`ADK8BIl`VsOMrt9LCVcY31cT< z9Hko(_XOhldvVDPm_41?kTRJxcni{5=s1&J?v8c_Z&j89rDi=Uxeak|LTvEO@O%i* zDo;LiB;t5_2%#A#nYab+NE}=4Sk-sXeKsriLuS23Sretspr;Wx7+D8%PVN|Z9#mor z;yyqecZL^yaok^*LhdsYM-x%(s;RwUA}ZWwC}wB#r3f>@#*67PC@ScLxZ{yYRdTxU z5`&w-42L;RlKaLGetF)l=H_+}M|kK8gg876JCjk>Ph(pS=cSOliWfi55WZ%04>s}_ zQy$0L!4w+COLq5Q?o~t0fo5bzG&DQzQl5RB9xqX#$?l#vqIT}(ci|yyUtV6iO}x6~ zvrTVrZDI*WGB^Srx0!mcWzg)c%}o6rf;}s70qM3d^;@QzowtRlJrUJ!4)d;KkqZ$l zJc|3W2|E3a@h9Uyj*`3vbB|=krx-MQy$Svk!J-u{>m7GJ&j;aicOF;7GB@zV5pZqkfYe;xKP?Xnhh&M(CqimA>i%zBaQK|-yMa*{cuHY5K zJ!*EZ`3OVaEv7gQ4J6)-e{YyXbNE690=P86v@EH>qm02L5yjp5DHWJl$(oqmI+Qrx z88i;*Jaz_gMBpiC5I3kfa+bl<1?v9pQ+I^o+U0mVJ&R~T9LJ5pCXScpUZfVC#!Yp*nPI1mge=w^7MokYP14 z+~Q>jog3j0!5r>BUIu3n$HsFYGx%G0E{5kRUx_^IZ$aE26^8~5>Vh~P)q@AX!?QvT zb}s0RoO|DKF;?a%Q<bcJN2N8Cs zZ$gZBj3-$wBXyyb3OnOZ;3zTYhP2ccc=s*9X%c3?cp2@7I?4 z52V-Azu(cw-FQa&f<;CGPF-8^^ge?B+Et}vUk zfEi3R+0r})aS_N%nhDQf=WI9C{ZB(?S+wII zn#W?iPB7gzVH9?4Scc(<$&2{)HV zfoJQjJ7XBmuxd9mcMrREK0|rEJkxU*Ov$75x!yiQd3`)%bxO%kS$>0sxD17TGY#eS zOIxSo^s@d4`idI>V|cV580~-^Y9K|enY=+>ajeB)YYvZXDX;-tWEQ%f(LJ_1-S-(SOVQ5Xl$1=$79bB|2Sb1Zvt~p# zetX(p^8`2ac;L@G3#0D>x zIN#K6F~R%cJ&!6+uh|}+?4f?yy>1Ur_7J~p=CS762owrCxO=eDVdvQUjzi^AjtSff zRv@?){sc*+N67b$zu8dvBEEdM2uZs#BRldc@<#kz=iv1yiZ{pbrsXikn;ML~iX3B- z%ZX*iyNI{Y%!uu5^K+|F4~zC~es1!7Q&KrG+IW`|V~w|*@bWB$&p6H_%{FSvxkR$i zcr$jW36NufU4s9{vHi=8>QuuS#llg4TZf2)#}8Mr zHmnK~2xjvVJXPLvf$a#ODB@1zo$pUop7)MR9h!VXz*t|;--W10P2O_COHI`nF&J-5 zAq2a2&;8dEFcvwjK;};C2^ce+Rv>dv^#qLVO)HQdBRIT;@MF=|@$^LZuabiu9S=x4 zmTKK~@LZ1{H_ahY5Rn%8PnNblm*Jq8E`7C{=EC~Jx>!UDxTH)C( zteCoRiO;xN=@J;*^sFH6%_eC&uaoxD0I0g^$5|`Qr~sy|Rir1D8C|wpTQO&9N;SvK zOmtO6^?C=>LYUte-b-7rXvO}9tizfvZN_SS^uWj^i6KvXw6)jD5 zDZ7Y2%9bj2>{Mscs&462?ayOI!<=rqZnQmOLJOCcmzv3k#%?AIdDYgh(k?Y;Vd?bJ z`AkgJA=BWhG2&R!(ojLmj6d4iD$PII-sQx=@3p+T90Tg=3Yro1Dz!Hwtp3emwjZ`> z^(vSyH5)kN=<;o8S|ZW3M^F8~$2zOOGAzQjR@Pc!f6^Q!{A?U|{GioVJ6p0kH7gXx z(bl4#u&bNiZPG{G8oqQ&&FAFa$lXsHv1F`glOcpSUYce zo@>#f=IW;AqG?SB&6-;@t-5)2OG9H(c~ip?)hk+>iaN5Pn=}Z>DB#=lq~?S#tzh6Ft~&CM+8|#?UG2VD?vIvy^>ijG%fa zBL*{$;k40WV~5tHrA*IOHa1pdn17~TYlGI?xanELUd3pK7OzIV!_PK~Nq&R0D{Jd3 z>oRJ-S2MIcubOelvqW26zY12`*@~8Nqtvgq6dHl`O-MHNY1LG%Zy!=`Oqn}(R%yu` zNBfy+^YVrUj9?erUI@;b>34k@Fznd6Ut%;7o7T;VLosaspD*<9y%V?}xg z`d{0)d$Wz3+F`w8##+Von|U{fRK?on>MF-KV45QlRyhlc%sl;uBEN}rb8lm|t~ucS zmUMmRJM6+T#%nJ@dGtBcr%v53zW|$TNPcl4pJVWz_1|eX*WLs3R+|3*YIp!M%JDvW zO0r;Mn@xM#+%2#|An)&|BnNEHIw`Rwesb)T=&6y@!l%RPZb@<{k}{SH@EJf!GG}9C zQ+V_L3%k5JsRj+xW}b3eGa1{8gs~NydFl@84WzbW@U|5RYe?6t>)y=s`cqrco7(xk z{FDgjH7EXHh11!*mY2HhR z2hv-qyZ;Qu%L!A1J+$wo+tcdPy&5ztoL+3?-Fo{9kWJ#$vY%k@*fUL9ptT0f0)k?9}By?IAu2D@3c~NCNO$~)sO6$pZ|KZ70FJHR~ zmka-ctT^+$VBNpNhO_@X$7k4l*qyKi_?~Gqsx=$VlutXpKutT^aL&}970{2lA3oQb z4d+b#nc8T>IWs01(4X{aXZ>>m;SNSV9f=7#K1UnQnfh}B`uP$o?OL&Fie_){goSKt%w8@;Qe{ewm;IuG&d)jCo8qm+Fs%aO-D$z{+!;L)O!+LJG zv7u^1o(0u(C~Q{J`ol$m@`}=l@P)AgHM6`?MxL+fJU7aE48zWtK)5)dzc`RSE}(y0 zAe~pvX-6B;ncH{YbRv9Vye-6B6XQDKznfYu>&1m(VIVXAgwz^aUgx^T0)Z#X|6%hf zLVx&xK>h>FS`kW=J6%q3p;&pP-KUY^Yw+Xl#{IA(UXE-Btz-HF_@&d6&eJyW|6}h>;OnZYw()cBy&0RP zNjd@@ZrZd>rzD*RC?shcJ2xFE2&QS0Hi0&YNeV54q)?zT$S77QFDQsb8Cro?K#)2B zDxgJi;zccr0xzg24mk2X&)RFBv+v1G+t)vz@BjP#SigJjv)A5huRWZ7&e>-V>i`-4 zVoG>_nPs;k41Xsje2DCG3H1&0hJXqAk+QHO}*hV1)l_gnvH5yY@7g9``;|gztJqvB{n<(`qJ13@?cAqa*z6 z2+y^hmKeV=!godZOC!8%mxl2_8wvkng#UJge+4|t!}rl57~y4}CfUfPRv-zL;6ZEWdKroNrZ=!6XJ!v83y z()EQnjDmNh$QW=KW=4c<_fuX}!a!l8?{CpJF1J)hTiE3l1@;9Ycu|oAq9e6B>DY@I zbvw?>aYScKhUvL8QcjRFT*Fx!N`?g!gX|nO4Cl<8s42M)Uu&EZNzVB>Y&f0Zcn0Hr z;+HaO7nKU;0Nt8lQC&VfH+I^|%|gnImpf+`Nz0DLJKoOlsy$Vv&?!>|crytbG#ID8 zz)41RwpZNtgdq&XetR5`49x9&!yD*>%{dtcX+$t3e3S7H?9E5Rn>E~aiKF4%>H->X zI|w!$kEjIvgY<0|Ga7EwA0=vVBh&oZ_%{74;21`6d5&fKLQVJyVECPs*_w z8)L{LT`t_p#ril_ArVE8@?!( z5cv`!_&nuV@3E^R;b;`oG@SJx1HVvtsF3*CM0ELvsK4;&B3eF^{#Z;W>ENXCQi=fw zDjr8X-IMLou@CBZ1Q0$)!>bf)6jv)Eis-3V+@y$8F8-)u!JUdYWx`*lxJU6;#eIs8 zD1Ke>JBlwUzOMKu#kg>Rm_bUIk9sL`K0m_6uD!Eda4v@Cz1TAiW?PaW`h1=w-_k)ih;Bj zNdH?EKd<u{(@-Vs98o`+d~IJ`r((qI?$s{E5ofD6UrAptx1>JjKfu zZ&ai~4eEVa@i&TpQ_M-2aIxbLIkDf*bk%>M;#$RxifxJ)D2g3_#JfrPI~1Q$6ubQh z|Dp0?zaRWBlovbx;D4+99~J+mD0cl3o`q)_%Om#vf&G=oo)qyPp*UI*n>56Kvf@m| zxr*}?7b&h#T&ws&#d^ifidz*s6?Z6Jq~m5TDc0p#~F<-e);3&pn-|Do6iHx8C_ zu;Ng~YQ^P>rz>t!>`?rO;uVTFDSle@so;o zDL$b16~*UpV`MzB>koX1Jj(huaXsEAatszI4kRMHiU|27L~NhgsNo-0JV*VnAwuqx zMBHTeDSkoyA10!o@*N`5dqMeMY4}@2^i#5OP53}X>>v{PaYTf#B_f?V;wY@B*YHaf zuTcLxh>*LNI1cAs@hSCxmWY1KFNny`Ys&vs!xJbgzdzHT2tC7ykQ=G|MCB(df1>i0 z$}d)ah4S+K0L1^0^3584uHpsif0^=EDt|o@`S^tLpCZ;`{jvJrulQ9(`3?c(X-k#y z5_s?tOB81+E>T>g*sOS&;x&qQDBh!ZQ1J!DKPu+*HR+TSQC|xcS1Z;jZdd%I;vK}3 z&>vF%F(T^eE6P8k{2}FERQ_kmzpnf{ivLjmtbC&eKcqyC>HegORV3kPb>ah@i&U`0Y+b`;xxt66}uI$SNwwF*A)*d`U8!g z!HSa7E zX2n*;4#i!HyA`idyg~6ZL_CM?R@|@npyE?RJZHY8_`Krx6<<|+L-F^D(jP~>Z1#VF z+?_-0uQ*t791+j0Ns7}HrJoLezOONyh8T!z6;D&7(H}my+7xMsfjqZ45w9XnNB>yy z6NM^Mfpw`ul%w$=;$X$$iX#=rDbgM} zFl_D)1F<*aC^y7x7kp}w9cgcYAo<78{YRuDa!ZAz?UgcGmH$Mtyrlz zUvY`z3dMDbrz_SgHYw704)vX{c(EdFSks@D?TFVY-l0fiZ1lfR@e7JH6G;EZ6={Bl zynLq&_@eSZReV+P4Mp1Lp*#nuh_u*7%u}Sn9`Z@WQpJgi(-dbZRw~laB;(P-4{^QX z2E|6jvlZq2334?1L-~spuTcD$;>Q&~sd&5Mor<4VykGH)inKLCy|g1l{I=rv6@RRF zSn(CbHx%VP4Do1qi1FDMC*~;1`xp43$|n^|6=@KX^4PR4DDPe1X^n{fixpQY%KH}l zX>5q$&5E=+ME-omixn?ZyjJl>#ak3_Q>2w5#(zjr-oL;fRGtQk82&v)+9@Lcy5c*E ze^-q2JqY1hinR8^=k@W5#fqa9Y5s-b^4&O~yuSf!)L*_I2mTD@8x%Jy(m)L3U#PfC zaknDCi>=e~E#z?sc|4zzMD#sMiFn?~^9|2~S>#7~UL_IlB@2nTZ`TrWe?XT-%C~`t zbV)2Pnt>o**96h+7L@dm?ojf;BoXPCC`$UshdgJ2k`Lr(8pDB-ALI*3$n&a_i2Ti0 zl>8x|OUVNzpUCeT@<7Qi@_hz*;07X;H7Yg}QI0K&Z}WM9d?sQ*6qSQXZr)`3EogM?Sh#|8^qsvrGBiMC9v6<@XSgzsHn6NJKtgQ~pgN@_Vdw0t8WI z9@`m-X-=3!BMIF1$Y-KfSdJ5 z86He;J`U=$`K^T8C7ZuZ@Ps?~{z@fy#<%HN+z3B6-K(5*vs9k(?!w`gVzgcWXr+%2)7*1I_cta3(`H+=nL9& zJHpbHgZ*Mx-%E}@yz&J4mZ?5ljtdax5`u-=ja*O;%CQ{OMY84C5=r+>C*46R$9NBD zy7s!<1;2FVxF(|S?~cA9j=sB9pDo9=2y+R+LeCkwpd6HAeyEFN%kj-fx_Jx3>yq~r z$}wIc5~OZh4&J}gmE+eDeM236xLpSNvQ(cf$DIgsiD{8I4*+*i4$3h<)J3x87z;VK z9ZYo6O{yH@wQ0Jx9QVL4T{)IS^qu7B8|mn4QhflShZQZ@a(vXt1?8X|^Fv)ETMn)P zam%sPNq4l$F&@`?P`53|LAcYEB2(8C45r-|uXw_%S@pnfT zby{|@kqgQ}Ip&ADNH$&0=eX%kTohg(c$^36^1X<^a!gY>#{0d|7nI{c@B^qw z$>xXebFRKF=wp1AV+Iaej@MM5jrR@kF4=PQK?JuPl%qcCBH42Ad)98c7dYjZt#XVv z-slVJ?-2B1NG%|nZmr7MY`p?UX&@D*%g;x+>0X6&laOP1Pr`v<$#1Lbn*yH1_ti6u zQ~sGQkDV%K(`^P{>&Sr>;`g`RbnijBl?Y+Fr{JI*%lj!fsMpr>!{GTmwZt&e(<*1v zeHQ#s6D0p&g}w%do9>%VJy%15a!mKva8S3^_Zs+g`Z#as>ifH+Z@#0i5Pg1|S9p5~ z@COIdWypr{z1G#2w*(gf`tPil8XQPY@;5A^@9W2V-t{)Kkg@v8BXaA8d*03VVs_*> zPwA$60p98OO>m~W2!~DgA6A`&)%Gp3TSzgi&kaN%5A5f0{@Mk&J z;IQ>_C*)8K?eG$6#yi?n%K)uvURzFedAC6BLBzFW<%ss0WEibEy@d z|Nd@bJNl(0^8Ui@^T9u1%O^4m;gd9{RCpAyTDHcoUcFRSov_3xx8D~<^4G%oWAO<8 z?AMkOS?uJ+{me2X5cjhmBp1t=LoSxZZ;2$v!z(tC&+K@%RDL`=tC?IPYo0*HA;ZlV z6`5ZJmw1|9y56hPGl)C;wUyEQ#4>0(b(2p zBo-}m`ym5Nv5&E4n&+x?EQ(^?N7Q0vzAH-GkwU0oTvD|J)@G_nFt$U6n6o1eIZt#M ze-n#5>(wRG%8o2I5hpq3{Q}W?x0B_SSGBiqX=$kEm&`iLI~&jbR}4y(Z>?`=hINAX zMw{o^y8v%Tbu{hJ2{Tcs64;`GQ3SZrsA#gJ1I84YLN>|h_SPpG<4ei@n8fixc7H%5b>bA6O?5OY9VJrz)nfi{c4fXAHwPCizhK2kE zb|ZqK{416{-Zx3$nj|m=i&9RPYl0xOXGGgOY_Q(ERj1XiS&@47dYTT9yFzca19*+| zu3^dEMJ&%SH=Or~Dt654o9Z{Vcz!9I88atUd6~IcRoQ+{EH_b<7~l`|2gir_$N9&{ zPKXarjP$*-&K+C3>Nf(rIt(^j7x(mfWnvVhY-4Aq*{UiVeLK7AJJ3SQqAfJKrMOqQ zG<%niC`(Hkb@d$`^*eg(Do$6|>9!X4Dkmk1T=3C?M1#}hKPqDOexpjw{%aF#>M*h` z+y==`;T{)xSx1`v%kS?O&PDqUDdAzslROG|-Nb??sgX#xUzpvmkg`H2T--058qOYU zNZcQsn!fWg0I_(=l}WyDL?3e-QXISQQuXx{`S7{l&r62laM><~@rNP6z* z0K*4F(i}?soHw( z4=#3MQ+`y04?3^n&;7jA$afP%yjzA8PZ=elzA<4STycDA#??qYvmFWYwK&){;eERZ zlYEWJ^PXK4>*sYU&vRT98{nM>B=H;+#!z2Dj{&>SqW9U7Mz3t?yb90WEZkm0U7b7u z>bA9>+tS*I4n=!idq+juM^faLrS~DLH0WkXzJ`|xg!_0nKnUVmT+(>kq~Xsp#kI+d zw@pvw$J?e0oX|Nn}(aMPsOXp5543jHjwU$ITc%S8=`~#}w$#x+k8g z$hs$gwql3k4#jT8OBJtGyos2BkF_Y?ul^4aQQm{fe~XB6{#beGb(i29RmyYTDu%-3 zpg}Mn1Bp{HU#~oZB|gtR_3&;&?58O8G}5$J=7(1k(@$zRREmCpnO9cKCPGf?7sz%= zy#o|Q5Aww^E#~hnBJ`vGEb$77kViK`!X@5>$ow*RNgw*H5&IRLzMulgFe>%X}Dc|T~0aZZ}mL}w_7js!P_#y z8MwcoayG1nfezX7z6d|JylfvVZy%Ml`TGHQH-8s6<%KiIUon)q`Q!D^HgC!5<8|oj zyUHmquQgjGNWAXxJMkjhbpbTJN|OH0;y01h{Q5AwXhkL{j42bP2R`wIMQ9I)OU zVBVxd$%cI|B6kf=bg>lzTDkAQ;ik*=>q&$&UG^Vrx<7}UjRS9QKlHiRx((xgF<0M9 z&{qn1>KlQ>>ic6v-)qoEIZIaG?;`pVXn2(nqP}7rR-c`ZhL;f6VOCfr@UhM~(sA=Q zANrCAr#?KU1AScI$~YA`NR>#a9)6Y>#)Io#UAa%;LB?m0B`e4IZMrQT-~-Pg8+Kwu zj-PtwwQh;!C2{?fTaHGjURaN|UbwyrRnaby=#QHy9?JpQbfe?pGa3g`i+5cSjnhZ~Xgwj`&;*y(Fk|^Rxex5X(3du@kW@ z?yQWj=3iM81G3GC{bu@9oGU(A85B)qeVtq)qZ*Kr06&r5ekRv=BWrM1oR0svjEzs; zLMLxw8RaZNCUX|e5(wWW9Yv!!g_%FzQh5oY_z+EICXwRI(sQta1kHd=}OUwNj9PfI4<}X_1 zWzJm)pFBGICK#AM9)bScN+d+O0*AksTtE3J=v*!06udhv>Fa>bmd&iAbjf?p@Z;ENSvgBixD&sC!t(|YVpxZZ}4{baUD8D@s&f2 z@h55!I)oL|H?b1VzKJi0n{}T*6dpdODTONV@9$-*rY1J9CO!?%B0lx_g!%$Jj>B2p z$S7=%19%_c`t<=U4vXpyV0oy-JH7+|*%P0}f8WG&_&B)2D5-7H;j>o@x*$=@55i_DQrqC>o7T$!*|oOno^7C$KssEIJ3id@FMdKGrvEYsuO~E1I+9bKixLaeyxpSgPgC)4YmPjM`lXt zI4E(x40pUcZM3LA%W%SUk5f=X-4dAZlVP%-A;aAe#$l=>jHmn2vy_k58QnZ4#QiB~P5M4W2~V~sCCF1Ij;Met&Nkbi=SvlcEPvS_-Xg#7c5Ss_u8 zOX>Xog2o>6ZsUKi-&`_cc`+&RzF3u??9Seqb#dmdj7t-j#V@DrZ#*Fb;=L4h z!7oYdieLI~wF_=5i047Byy)CrPk}VEcj<*>YS0bhi9V8k2|tSZK&J8ky;(dyWkY%| z?Ea$n;!yaErf0f&yFre$8TAZ3IB%D#k8j!`rL*gss*hJeNVMzgQaZc6so|-q_nbFl zXDOtf^I#`nX3dNd7^$J5FkC(7#rSR!QrsIZb0$1Tyk=>Kb9@*qV-I{kvcz|g*_Hv4 zuZ-{uBmA-me` z%zC*>dEEuKRT+=WMfI}FNGu^@P_In+lZnI4dfQyQrmj+dzO?5iJ#T~ZUBqJifdU(M zBhC18E|iM?r0UnxIX+j!WrGBUu)G*5o-HqiF&UWy1L7w<-U+-IniZ44G@*toTF4R}_Dz_zy*y^Flsk z&I?%Vn|!TN{17q2^Ufur@U+Rsd|#$K$DGN3k_b83vk!j1hI0&={$EynT2X9t!T&|& zf1$|H9m>mIeIVcD$yX?ThzR}7M4YFcMC9u-nxlK2Ah@zMB(YQIx&$ z;0NKIn*L&A3s|c>s!Q_0J0SCe_g+B^T?+EPK!0BG#A3zKiqjNlDW0M@PjRv0a>ccZ zrzvhwY*gfR%yc>wcPL({$nhG6-=O$uBI@BT#d{SGC_b$CnBvzIpH}>V;){weEB;bZ zt`k%S?@>&beGjHbB5&(0n>_sGdIH{~=lf+McwUcuwU_vaH%s}GG#=oX=mbbXWiVI6 z`gaMZU8orUl*4HjipnvJ#1~uU{b+J4Arnpa3iw&F=}v@)I|iOa8?J?45(n#w2h;li z4(hY^S1?_a0hcq2f;Hw^^hz!!|kTqj&ym>k~p$(*mT)0sGH}N^bH&p;xd0W zKUafw^>srZ&s|det-jBKr#>6+9k^X$80i@ta0lg}9Lr&Q3bq_it6wFMw8tq2+m=oD zw{TnClp{m?6P9e)8}M+;u@CyPk=Z2t^Kn>xe}mh`fzzu;0QXs1vd+G6SU1B4pd$ZZ zg@87U_g^>N{dkrn;g^IAvJj*@6n^*xl#P>B8gOCQ5D2;Y4&j2b=L4z(edQ5-70^dH zOE#?u5q+;gUlKw*aC;2&RY4BFfEGd@?XFm|P7YMN`OAh9+y2=5vh~bCOvbToZUG{_ zXd4gw8OCFML~aC5KJ{6$a`h@_{ma=%9HJa)TSTq`aL{XfCv`ixptbR_WP zTzz}sc{%(nS$*YGX3t1EbhJ6FDHT&HjQG*#uuj7L8x+i872-0HTzIcvYcE+OuS?ma6%SB&-3{F^pJ3#O=dDC(S!lQ%W z;kdVX?oeEFCreBT>;6;{T52+{ZEoQI8LFZ*Ic+ZzGHW>?Z5R zQgN@Wp>69{49|LHt!-URWjLpku$H^wY%@?&--YkwZrs*|_&vzpBN*^rj3u}Uq#HX( z4d)#!qn^i%Q2+dp1^&HEgX&oc6Iy`#f1R{1i; z>59@1h1@*l7b~t*T(4NCxJhxVqNH!`i|{!*{crVSE08t!{Ig%ocMVH6Y$7~R9bTmd zJcyfnH{5s?kUJ^w^{7tSr)=YZmG_V_bST-d<>0NGLC@ky*DqncyXj6toiZJ!%cqA; z_e{85eXoEYhQpE#Yk>#dEH}vq^BWsTUXLzCEB9MGd+}%u$jb4N=0x}2bsySJ*wt{m z{R7G!OaEXBBHbFK8m7fG-K4np{1E(@M?NE2FLbl+5ERhu2w)$?lFfV5cKOt9u<7$? z{e#J~Cs$094#Ls<2c?ygTF^h3=T&;04|${VYT_F*YO-r&?TM@=$*ke}6Y`}SlH%Wb zU}EzbkNkX8=3?)L{AA{ms^atJpFdw>)Od&eWNd%?|45D>-I0%kaJ7CKKGWdVO0!uPiXEhYi3F}ls30N za@(l>60^vOX>tcswug%)hFAK=q0(l*L}KsoPaHD8LUko;V*4L|?X8{O6TGh2t}1a< z;~?Fm`AyWsoBP#VTXVLg%auKqk3296OC(V00h;ch!=`RBS@IcQu1+==zT_1%#f%!S z^pDR!KB|w%=Po&KepRulrP7)N)&*5d9$8z=$wH*d>uRJP0LjO!hoGl9uV(!LZ(PoQ zQSYwmjPI5<7uP)g+N?_OPuP_`uvv+Hgg{UP*l4fDMyT-;8zmKzxsh z9pBUcyQY2)y_0?LvEO<9at_6sz2d1myz58JuWqia@vom#bNB=Pv|ql;7=AJXIXtwJ zIl}e3D}glLnwL@2znQ5Fs_`aFJ`~$GPHTMPp}xP%%kfHLnp$j6Qd1kZqj-K+O@+w) z@STE#@oP=mbCBYM9g}OA`gzU%^^1}AxE+->@tce1`_q_%A36DW>k^ZX{r55-?^b2i z?5>ILn_V+d^p-w=QU~Q6tSNu3IkV>c1G9IO))Y%Cozi@wl(hq?jj#DrvtLtLvmfPs zS<)%hHB=KeBupET1n=p0pxfO89rhH1tJLlz*xb}r2Ty!w1@l>rP1~(MhG^+8o5m=! zXJollW{M>oGvX%#<`Lz zURsM_tj{_K2J5rFO)i$Ti(=Us-^JY}k)1V!Tq3IkiC`tx7s1I&tY1mYOj>h{Kg+NQ z3*Zyq3unfepM^6saWDR}M&s`*II@F3ggh7E$ju;O;6-G9>(l0rH;_;Dtl#_BQK{GO zL#($1qxAngEAMTenaE7A4P_>F$v;p1AR74hpC64_{d~>NWgx za8T!nhv4AVpZqc$#$G^i8F-!>e%C>w@M4iDJR2iz@F>Q0;+0e*l(z9lW1U}i)o8!g zKY4WQLNAv6a|DcGujG7$UJI=Vi{XhlmZR!7z;A34jtAfnAFXc%eg^C|1=lxQi_Z4L2 zbYI5P-9}bg!sToUyh_JEh(CY#XlTA4t_dBO1@k}346*+>ktcZ1&?93qXd2#$RSS)E4>?jtn`wP!C~tfDWNfqmjAMys>8>j8$6F496)58;upD+oiDQ z!bi$Mol=e>FQ3^hJfU>;2J{#=H!)cV^=|BJJfkoY4aAg8*GU_0zZH69K2OblM=;z7U?M* z)4SRz$U@M*)wC7JnjiOBhnW8MW=NqDa-WP{w|*u{mEkkjNd!)2mij{JEGbrz&vGq6 z!0dJmZ1@9wR#fb|GsesSvY5|m*4ebH;m1+(!{R5ai05pC-`|B_72Dwy66G&xM_48F z2la70JXjxNkpb4nHVL|Jy*G9|LZm);YyOM@rp%2CS)zQCb&`tcwz|+rB5Og0PpS`fkQ_&DJ`uX342M;U2u#-Os*{sKW-eir= zQ+@`YoZ&n1&)aA=)p{p$jyLOJpEpq>R`mjvK2LqsbCLU;V%}6tFRikT8OoCL!rMu< zq)Lt6DL3IS<1pQ zmmkAC5tkdNlE)IkmTW_@%&EalGUGU$SY--kLf7+6>e z-=XN%6*1WO<4L0{%rltufc}pBKurW8vrrF%LIXmJ`X^<*`QUI7IC>i45^!{O!WG)+ z@NmudqW;s48=8+Bxm|@m)UHAwR_0IcpJGvHc!oDwYzd8+rjDdIaGNO(my(Y(PILtr zh$|ypCqCL)K0d~Jvku0B@d}Y1?)9lFz*90XE-VXIw~tRGKgU`S=x_tL(S7QA!TQ% zYO+v0Q}e5#vz$=Go$Z7|c#cV)IXThIKuYo_8KE1h5n*ny`X1Q~q;R>qvCaDWQvxrs zB4s=)15YWY@vI7zswA%PKn`9;YF?@rE*nxF4lH6PEEVTk!WtZ@rla5?!;n~#-w)1- zIIxVLU}aabM=CT3|Gb+*FTv>LT~&xZ=^7lqx7K*z)T>wOQhkQvu|_on-iHu}un$Mi z?D2&R*&`U)b*^lfJ%r1spzo~;WlwcwR|Q20Wmku?>s{H^DY6WSdDlq>n9EqoH>pj= z5T39a5RM00NE$!e31``b*fSiC1NA|0P64M2;Y-*e&NZ!o3yc&00quq>=2hHA{1^_L z!XOL|Q-iexb{r5&=*Drx+BUMMy0X32wvk=$%7(Q)1u0F#fwJIV$nj#xdK}ogu>o+F zapFH9Jk=PNU@B@YVI&Tdf4ca*aGD-CEw(fq6KxHlSOixRtcI1hg&I;SE?;D83DONt z-CV*GhlWWop)5r}xT_#^6~Tm_YJ=EUV=~TJ;z^$`UO^3klZjpwd;pvuk&s(=O#|HK9TASf&jUAvhls!LrpLF~UM|24z|dcBu&^EEDHS z{0mV@OkCkrX%+7?B62y<$%aJYNh7iHNX#M0=rL|K8`dV{Fb9@~!@)4-xeP}I4z}wp zI9P|4D3`=R+2uG~dN1-f23@t7_c)%yJr)E6GrL2OhmtO+(YZNlCmw2i>ZAgVsFGKf|u)7TI}x7x-PMnw_3^ zF*5GXBy_i-7#HdDzCUW%s9~jZ=aw%$8E>S1W-_z<%f&I*2;pVEUsf`-vb_8YBg%`* zD^4yyrQ)`D%SrJeNk$mPzZ0jA9DerP;#i*N2gVKWL9|iBCKoR${`fM{Tqggrk!eKn z=G&%V7gHZc{z>0Y7LPFdoRXO><&(-&_CUSv`-@9P4j&mmFFA&aD*3mBe<5_0GywJJ)1B;d~ z_?LEGsj;}#YpT{Pnpd}M?V1JaVNhvH8&)-7wL`m?I;~;TUbw7kp4WLc%{K;_n7_Kp z&W%8atXh|5#Z5dxye0E%yl~x)?k>}H@4=E9ZGv?TTk2tq&&FN80!7s9x|1*Jg*4|^ zt*P?rP?UK~f>`qw)h=AH%En76CJSjc(%2-7D%jlQJde$M-8tC480f2B?sc|xbTu_v zm7Ex|^FUV5it5Euah)C}OX}*kASEk~Y$ArU)rzZzvW_b6NKl6k9V29Z|G zTV1OLysV^qzUMFcz=G9lBFn9q;PSQ0*rHblidI!EpC45uZ4a%7mDthL+0=0ks@+`y z7OuSt7Id*X+4f{U&a3a(yd_MXVen~BSBZ7f8qV!#>1txbZr|3~Oq6E4wW$kCGfsOl zB^`uwGEC2&q-tA&tOJwmF;TgkY&};mT9I;91y!(MUg{;(2+OE85^H^yCoSXsrDX0> zGE|Z|)l%6hr^nXa{DnM|7#iQ!6x8Ru70YVr%Q_A&^wc{^UCr9%^Hw|i5ABn&A<(j5 z9h7hdSY5+b%|=AWyrosE!$w}cw#MUDS6-cLJh*kVZrifOwxHgonpsBMuzF54V=7B$ zrm2tDOpw2-)ypT#)e!igjV**v+g9;uM^rr2+d6R9s9m*S&6?As&}$a0SYB5b#94jX zYMVp7$!gU^m+_ewdv|Xo-^4Ak%UG2^q&stG#;(Mr@yob(GHC;W?CMsVy_dT(FU`0t zad~`qRHnNZnIZ7E#O|)UKhwFWHUyRt6Lye#AL#P0Y< zk%M{p73@Y^Vpki{x^s8tT%3JLR!Uy;tPqgBqJPK2M%lXAvspwpZ>Et*vwgD{DM=&s zDaFQS9+c6PdX-C)-VtTpRNW_jFA1iI^qy7^F*g~O-(G6HB$Fc2don%5++}u*A(l3zbo;E6VK7`Ag$gN- z{S&GBF$v&M&wbc~BKhUmRYdoT_hF7zkHS zd&bF#zGOsxWJDhaqe6;j_4a52Es*q$f@}o8woFs@Z%!-#zn#>MEHrpUNY9C zFN18MNF2MGtCZ!L^JSN_8(tO+?G;Hl2k1hIi)CP!pByr9#bppO^oq;Kw#&~58IhkA z;pas7lcf9wf$!YFMMqpL6Ng@L@5GRi@KeP8v-PB&>nsB#A6|Qgcc(TO{%A!08xj6z z;C&qIKXM=bpCjS_jPRV#wnY8oB79kdp8=j;-8hP3`QD;Pc&&!B-&uqW>IXUcc1d?PZrTQbod?udjdT>Y}RCUug|jd0eFU` z55TiapS$j$gLz*T^9A}EtZ!54WOYD^FJ$g3$C1o;YxgPaW$GYNI`yfq?u;UDRqRUe zHA~**HJ;n~Ll9V7IJdus5c9gIvD{7;!bGtKxg8_*O6kI=U%EaB&L`g&au?vd5^Kx^ zX6^^fuzl`AGrN(y$UG0@GtK_VxIUr+8w?oR=TjvY4^6f~%AZWcGy_z6xywD7t)M^K zRPG8htCCx5X6u;l74%1XycXkA&3A8^&h5(INwn#5*(u4U3;h$pQjeqyz3a&%y+-0H zoyD1M*5*^scKFA^bG9(hYaeA+FZ2yZ_;8(T2<)jNd;s-gEe_x9m~JT%a>$C8tJ5yy z8JPrmKJ_R+h6wp7M952iSDUGiTujJx(BH-%1%_nvgZM+hGCto28GjlP@liyHC*`*B znJE(Dlg3XnNInzJ7;d#Z|FKidQ=T|bdCrT)aH}mQB9n~DaNeDXRf@=p@W_H7?=cLo zS8P^nQ#?oULdDAzuU5QX@m9s}D88!rw&J^reQQ)mHU{*3O8L(!-m54!G7$cV@=qu}srZcI^NK%Gd|C0=ihoh$GEL^Y zP;r>zIK@*Gmnxp7xLL77@mj^tD?Xw4wBqlHm;}m50P!f#R~)Q3l8F1zSR&+RsehGX zjryNXgj}8STyH@6>lANRyhD+D-B`Xa6LEiePWc}ak&l;@|CRD@DE~+0|EfH{GfDXz zBJ}lF9xI=OAF2FUQ$kQM{dq_@5)BGR3sc#8Vd_5j0ACnB9jBJQi5%3nxCysH#%R=iEaA5#8NBJO8jQ~&4G z|GPx!`<3E96^CRS|6;`nM5I51ILh-DD9<%IOutUCQT^ML?^6CM<*y?mA2+N2XVm`@ zBJ@6|__E?Z6!Y=SVtA?IWW^JS$X7M7)bmyG=MBHumee~sb| zinl1oSY zb0;E^+ZTBM{FWj&A&~#R;wy^WSw;WfD!#4A{SEZbROFUQ@`Z{?#S+B{isg#ZPl5bN z%5&!fNAX?7IPP)u$79`#%{JpFyf5-Sh1X+}i1rB)X-{&0#rc>; z9_6egB5)yb68?w?hkC(mMR`wwzvx9gzIQQxQn5r)(t*F+&w-L2knc%udh^NKbb(8i zkKWfe&>!V!RBR@qJX;joiD>U#irb0EC*LcH-9)6nOK~?5>0PCGEfM9uQSn>6AEEy2 z{c1F?N2Iq_uS>aKK=0k;q4y0U^htjldInHWwbm2#NV&mFeWM&wKJfC~f?mld_-@8S zIreD$y+ow*u=0-)k={$nA0{H*1oMmd*+is&taJhd5k=Y!<1n8t#gr)qQZBB1RE}Y! zu{g4E98Hez$QTaGWl zO?|c;v&cAP*`LA>?w}l$V>zgcWYcB8#7%cM(k*~r6^=ZWW4uX-k6%!ZN-*8vEm?i+ zx48QDK;J?LRpH3TVavgO41Pg54w7-mvWtyeP!7s5Kh#CC>DIvCP4}=<4$h3&bZ<2J zf^vKV{20+>{%pN&jp%#J(TB@1(07IEv+;O8aLKXbopK~qj`6-_^abU31^g!XTLLTe>4?5= zryL_8Vast4a?GoZ$Nrd0wjA71@0Nq(I?NAsk!(4bAGaL)opOv;ImV+cR_eC*t2N+l z9^f6g^Hk1;tpo3p&EJVeE@&_7!808`2S_%5?0>rXJLu$ZoXRoYCZjKyz1jeN02L`Q zT^`$1&gQQRyltZtwfVa#B6k&ddri7>?4L4@)yG}?MHEo7`d(5w>wf_JWqhesvU0Qr z;Fk9g%6k}ZZLV6cBsZZF806g=@V?jjj zrjh3Uj36N^w>*-+yCCNh=9xM>j&Ma9~&{C`TLQPz~+y z5_)*lvDvnI19BJH#1PYFffzHYoFRu)HgRK&TStq_J z5!kg#f{tq2YTDFU$7o%dkYLy6C? zekU=(zk#-t;``5hC-DX>bbUa!eDBOVAg?;60Qh&~u0y*wO(Eg`0b%|w{GAkt8izGW z#7;?Il4u8-3bu1lBF^4pV3LT_C@@L%TY)T2Ld2KA9iPbYJ6I>;GzY8`(V{r46LHW6 z)``YY?AuiHp-+)!44m!UG zvHta*f8MhYVqbg6M$bQ=jK8u!41-+oWeDYg#YttGIxaiG56R`wyYNT&^Dq4-{z)Y` z{Jreom`8TmOk$8>ydpRmkwRr4E1zTpb`ZV7&*9(SZ_j{9csL**b-AAkvZxJpDNHFC z$;G>p3o)o-+66Py4srj%R9zoYT@O;%BGo0#S!7U24>B`XTE)lV9$^~&Dzqxo_SqPz zKgPU1YW17eG8GxgmuvA+*4{m;^ie8(4$L6ACLd+$vFo-E8!p%7mwqYimLYNtJVuRv z?Ff#v=i!h_IG7xdMpQfkf4_m6;z4k5$PlIpu;mesegzPnCAnQ4yKW2fd|h*9G|%2h zY9)!*y}YJH1&0kqX*(TEh7+5`O!NzINF^KXyaDv6i&0Zh7rb_Pb(YXk!cvs%$DcQP z6>^*@-!J5KTEe>UM)7=8kQbnd!FFw8jCl&q%wo1J3GzmBIwR{uRw++)3G2@r%{lh$ zDWl=!X%bHjDMX6dQyIcchao2Iv3z;T>E|=NggV9BNL>XM)&H-V*+{jYkx5$?v|}+1 z<6v3l{(j zC~)jj6uR*v<{i)rw_k3g27WZr`Q9NvnuuBvI}%JU^~;G))FHUQoxFe@;%EYU+!$1_ znCGCOkwyK7;tZXj<{`*pP;sb}7+!S|$r~O@V8xj?Vwl?RSl{O~ytO20yaVmk+VB|J z!@S2RQ*!q+i?A)oIvt%_C&tRd7}wKyjSaliW&|4wh%ZgpBu&T{=NkM6gu)?oCBX=; zvVuLWG~|k`?Cn-f1l~o>zI(dlHsjS2=HS5IaRNI%$OGYI<4dR%XDy*doGCdg6t9&8 zo5af7=;GCZEE7x;YYElHmtd5wg)1PVOtzL=Wvd)ztE@5>WYuk=~@R4NO2WxR^JhR#*@Q$59h70xR7dq?)&QuQc#+ z6BIJEiowicP=d8U;OXgE3r0X}vsi&JlYAN*fmK!mjF2?LS11fVYWySQ;NMUSCW)X0 zH6r&ssixAz5e!@NQYW!8NNiaowjmN50?G0gt-R%pl(|FF{a)&oscP@@=&HPLbz$SS z*2XPOGJ!Ir$;Dsu{A9_{l4&u#v;@`>o`vVA^7x=+{H(Ic zW2VfVvSdlTeQ~^KeTvkd8FeJ>4rC_rAImJ~|0MnuSEfkr^8I*Da<~{O7|w8!93hhO zHzk(kB>!>W_tCiz^YaPc9|$?5lUY7#dP>m!zTZE^8a7l3gAOL1 zyZbxb>8^GJ&gpDzN7Z(1;x6yb;De&F_PP@v4ql5bc>JqZU}Jk-;IcZJ>pPpLPVvrOv1t?5rdQW@wsd;$Z}@gM ze6vD>^K2^;m2J-s*Xpx9cxTskv|xjqe(tvC_HfgDrcS|LY+a-eQJ!Dk3hKK;vjMV~ zKV@fmFLnp))^2>FvE6MsHfw=_3)w&rDxrx0Nu;HNYah4edJ|QyFbr8cnfm zOVRe_HcX~3Ik=T7x!nge`bjfD(t-u_IJBs ze8}|{Rw7|}`bAyyCU14}p~%jHB|b!5J{nFwX@!9%-Rz5Fm-xE<{NlvN@KBHHsG0&{ z*^=VAL1Y9A0Im*K0Gnf_sTkVZ0)Mw2<+-G z*lb-oBO-N#lp>Pp zcjoF9bcD^gRw5GLmPhY@=@g_BNhz^j5xo`F1|Ok}R-~8AAy}@WBjqkdCYn8aBRE19 z1Cb+VGes<#O!%ZaLP1hA7&#bWF6&(vGbEuYci?DIQUlWzqNhNhG<;5`)9QrwqBbJ& z|KMh8^eh8jex?wwBc$q7Z_O1D=!RiAsurF?!wAD=2A z#pUhMaSR-!=GT4VF~5T%`Z?$k68BQO z#BW}w>chaML)=T9nqRJ<3908du!lwTahND1?yXMMHzEv#EAACX_>mEPBO~D@5q%|* z@G%j7Y((GKNcgyjJ`PZY6vy8F)cTqb2ErA`s?yZ(iIMQKi2kxjctwPt9MLy95Vc8Mxw+$=0|GK87N3uTt_8w(6=dP~u1VQzGH>CH zI!QQ%sE<>&jL$2xD0YJPS>=uVh#q^tpG*la@qP^667~HON0^^+-tTQ7kl}xi@cki7 zd6OR63%VzG!B728yX~hTjQfR;@&WeLev#O756CKsrZ26 zql!-`eoOJc6n~}2YlG<}aX}C#D9%)ry+=6T>&WBA(WH155&pDez>&crHM-REL&cYfh{rXn#7qo%5yvQ2Dy}3V{s)O@H)ko|MT9=CR$=%p%FCV| z_#aeW_TnJ?=j74O{-*wY@lMEiLlvhJ5wBWth2rTNE_-Is9?w_*ZX)>WHGD5|g!y_1 z^>9L)_&p8(2@&n|59;sZCd6>r;{yK?_NBATJJCuB#EGk|PgyhRXYrVBVyd0x`==Q1%OFID0!#l=LlqveX6 zi6eiS;s(V=#a2Z=%P6-)@j}I2igNuS{2JwNP`p|3KNLTsc(>xiijOINP4Q{P=M}%N z_>$sb#a9*IP~f#*$2$8gBAC6uEkc{56VPyG{OPMXn0seQ3X;>?s8QCFSM53jTTJxdxl^T(eE&3LxU| z75}364@KEah;Z3U2;^F2%5xPDk?VzsQxs<_&Q+8>gws54HF==imw{Z{OP*_lh_Z(e zc)s#-zXmTh5r7|8|GkR0D{@5<pkps(dpMk-L@OMMS#SDt{vp<-J|` zJBcMoSNR8t$j?FLzfMHHUQzxv;xzmnBb@*_RE6|Q86_GO#T6>XKjqNug`#o{BaOw8 zjpJx?wUCLXn-4!rHeJ?h4vtC<*pG}*{{kEdJ;>MKpgtR~8g7?t{?39Y+`-74UHNeFOSR;YWS+XS&q)IULky z<6RH8OAI5ufCKKJ95;ezeCi_EavXx&P4_LNYs-y(+7CO_&1^J^K^H*eogZeuSa&G<#ocs-dEYoGY+caHUe{X6SK*;9jf{4B(^f5l$ z0Y?O_KKW1~cpL96xLtx8A>P;U3(7$`>Z2|a^^qQoq+9BggCmPJ-ItBNpq}4Bn5`4) zvH9V97k&YsOU5C~>Yl_Pe|ZRC{&?RZ+5G(({%$?ba`MM z9LZkFadAZ71}L%RC~@@N4msu(AXH*AuDoTxVdR2xP>%Yji)733b;!BpXdW4sgZFsK zF&^K0soR!gBA9gd4fY>hecPeWmSdcwFRuC^F0>H(c%QOl^H*Zzf^w|Ua!?n^$|WJ^ zrrV8l+4tb}Hc{o6kA_G&_!nQNV>NpU3;J8$TQ^_?^aD0P9eTmoo-JKd~CX(jOg1BeH-A%df~{m)pvJ9 z-&gVQD~*Y2`Lp`ipSErW{5LB7Nt=1_HjMpm_k0wL@wlQ`(wzZ0o9?$F`tHYrqnV18 ztUlTXarIST*nd4_SdLjZtUivH*f>-%7=1FzS+Ze2j_BJBeYZo1`sU!U`eOV#$WR5z$wQMpp|V>SN#4>ie7Ot55}#aMNWQvP6A6IKD%)a+eJ>?I0@GPvxxt zO^|cR=5JI)ZV%+%as-(_(g--*dgdma+u_f0RNFIup)2Ful;&5(~CT*#rlAzz?iuOUA0?X|+g6f5EX3~qlK{w}~lvis!{ z>`{7gKeJRIn~~zNjAa5@&l0jT9udgG7_%2oWc3xu;Nu6}euAI*G{D_YQGmS#czNj4 z=j1+doSe8iaVeSi7m91{#EC!l1!6L{*<*nxHc+?f3OcS1>bWK=SUBXavkSj9)zP%6 zp>11hS6##8$z=`B>ZEWjQ%V8>BdeSKmGyVQlBqC-V6{}5#Z2!nm2;QMMb~syO+nN6 zzr4cfSQcFbChd*zu^X@FGL?U;t$KS+5!0=gNDb#5ETnj3b~&EX3!*-bY=;!*>}})< z<6}RDzdRz;^PWrOqkt&aI_?YX&yg=voUSNiEAXGE{9?tGihO=DUY+75#jT2xzPTsD z=jimmH5O5Uthx7b-l994?AkCq@=~6Gw9C~EKRo*7F3S5npMk758wXDBE*xX%P_kjm z!CNgZ#dZc>LJcL;vW zBcG3~7rI$@2ny(S1Vqch!1Ae6r#fAOquL>uK5d3ELy$ar-{3G$meV&FjwY+GPwQI;5?4C=}_1= znFL>SE@ZKZ_l3e;A#l>^%H&Tqvgm4!*E? zxruA=-=`CQ{^-&8C&}fwcPhe-g3(k!t$DHscnsxuD+}~xb6}?x^4S$|h~mDtAdmhD zH-o1&Wt_W|O zzvZ48Y>UJvvQxICW;we;(do;^rcV6~dX91GN6B;Tp4dLFs>trtJZBRrl=V&B4w@gt z#NJG^U9+Fr-C5v%)SI8D7vfU@`@jfEajqe-{(Ei-b7V&vSprXBsw`vkE{!dj1arf! zg-eLd0d)>Ct(-2#AW_t%bp9Oki+S9b-J=g2^k$FzY1w1l6I8ynzM;9L6}wBS+S|9Z zG}L#sw6%7YcQ&3~-r9IJ_LBV1b{GY@OZ#2dpm)G89-sq`@&#XXMRf&VbVd8_YQ{pO zMzgO7J?5s4;47|>+S0NSA#xSy#-gEqvUtg;VZ{~0Cr?6$1J4r;D8b&MCFK<*! zEJyV7F>Q#w@sN7H$L5KAD8VZ&B(D2MpClkZ=p7rcp6mWoOUrfsE^*zyOI)Y#QqOhy z$GgF(pP`~5e4lXNxLAKt-p+g(HC%Vk_ivtK-ZzS3iIlHkQSa$EERo-486f$qa4>oM5MXhWGI z#DR+J#nMCzlZ@fzyj=Y`S3$YCit`nhDAp>Tso1D^wql3k4#jT8OBJtGyhZU&#m^Bl zupUazCiZ5&U8$^`%ugWKUBhR(#jK_IQh8HW2SDZ#f`6`L1lm*Ij-kkoj zP7g?8eiDjMB|Kku>CdZ)$g76P^TPBh6lW@)s93F7qsSLC%AcXwptxC4&R>6X9Z)|` zk;nriJ)1AK59*Qg4CFi|<)vKUc^8Nc)%Z4_;B7vs?^uXeH&h4np=^IHp`$HSjDN~W zHyRj~V;G6|2Il=}a%&(HO_z0TiSZgk!}I}m~NKJGv2c}sGH}N)Qp4oHA`0CP4IB_bwgh%{HTxq zwj5uDoBC`y?u6SVhLPUE0e4Ui$}vCGMY8Gs0d6 zy6<4zqZ{GHIQS&B>9$AoT?KtSAC|1XEfIa&k$GOT)HeW!)ptom--FOcIZIaGMG<}1 zLSGU>#W;BHvHI+K8h8mk3wCq3UZ9Y`vYkl?iml-Mh2c? zJno6e{REAj`Yc(whg8n`|C$$tLzE-YeyVkoe+zPzbSN=@q$eTdmgAsPFYJ-na{K^t zsET%pguesxnhZR=?AhM+#p=}-7ve(%4D z`mA^Al+JKi_p``8hILOxEDYc7p>e2Ym(W$p8Ta( zOW&*nBln|)S-+NPlF%%XY4&yszDj2;C53Q7fnQ^JQ@TAAl)|jJ8_r_N^tl7BJpLhx z^W~pnIj^$J>nH&S68R}S3tJlDM_IqN5ML1m!ycr+(#tuK`C1=}^Q%W9zFx(}tnB); zRlJ+p<;}rp=LQ53Ki!CXIr4~Sze>}md4E%NXPnB&wO$d^&Pp&KM;2y%D3qrDT#oDe zbvGL6{3{Vkcb2^ zxy}$ho+Nz+`eTptp$kSQ#oVMZQkhThMg1Aj&sF6l!mt8I8Qx9`Q>{Q24fLpll?6iW z;gP`&CeoTyN75q#Y{jVpyw(`i-dkLk@weed{gJ|>^1boYL1J!5Q8`|eq~5}#^1boY z!FjKk+0NkqEx)ga1wQcMGu97AlpUi@@WTk&mTiqqI;QgU_cW53} zZcfamZLJNQEe$pcZY$Sp2Q5dV^Bdr%xz)pRSUR2UZ8DjLiG|IrO^r#J!Adh% z!K$%WQnYSt+cjSp?>RBSTcbNKVQ-bZ)$w-e^1MkMiD#G_{y&X>H2udC{(pO(Bx2*J zM+;16t*NI_dM#`-J?<1oP?%o6cilbjc1Ka(O9XfJCbbdwGGP-D>V1wTBAC7?!PU+3 z2N%^5iqcDjW6*9d>SI+N$RC4ldvPDD?m+%1y6rvhSo8+6>2 zzow1bHrLf}+}P1{jvI;`yKJ!VmE|>YI_g_DH>q{N|LJnrP|KzcKCt9k|F^D>#n6yL zwlidCVL#}InOyb zqR*XWW%@_6N5&bRkZ7MQwLUmA5)$V{Q}bsA5qu$<7i??v`_Yb+WQvx zx{7M=z0Wy$G)dFY^i3bWBMk=^i7I| zPmb|ZV)~}U!YgC?Dr4bQF}^ycuR0dq-+E@#WAZa%`eww!V17YlDNW59eDz?O;Q^2a$6)O!*RhO-|# zIFaw28{v!0cnZVWatuzCcziV#>KkhId=2A|^d67IALAX0@EIMWlJq8coP!(2pJeuX z5BW-OMI?Nh^P<8|0H|8JFc^>zpSg}aaL*fEuRg7Gh#A(qiz$K8uAq2k@5yBg)Sg(j zFzrdj!?ZUf{xr|+{W#v*M~HV}vWP^x5m^L!-TrYFow*9j3>&Utro4Hbj4<%LCnTl$ zoyZeo$G&xzCU){#7rcNQYv zka~&5_N{l~RGBLQe_r_v=k-G5l}B76xLlCe5B-}3*9mfPivAZ1zDMxAf*%&#O+>fh z)53q2Sm1eI68=@e*NG@^ezQ)!rwA@1qP&}hzmVAAc^uoMoLP$q<^Mk6Z; z|11&b>1E-OJ(CZ%Tg*?PAgdVp3=#QYRUu9ltPwQl87GNtTrj7i!1L1Np`?NcJu1(Z zocXRLLMf_%$!8-G`QxAk^V3X({cS|4SJZFp1m@Ep>9D;dn)Hz#lInZS7}!6a;Xq?o zTJi%l_Q4(`ZR|33PPX$2cphr$5Brc+gT`(MFC`B&_QT$lyY>;&o_Bx}VCfjhOblZsE5QVb>1fcM@UWjl$ndgq?eZzl%82 zj@L5%hsne4$0humMA(0{1k=oYjP;HL)e%CqHpF_1BJz@!?Ip)B(nK8jIQo-gyTmwd zx+(BVnl7&o$|*lb1q3x+HkojDT`B&QqaCVK5k(dmo8LLY*7e2kr!ACYJhpSLeYN1# z1~>!vCb(Vu>KN#d+V=_gx%SnAXF5DcYTxZ}^J%FT2kBF5)p+V@1vzJrc^?4GE7J`A94wQnojY7?A+n`^vK zPQ$h{&>@DACR%+#`SCiSeIpqNQv1pw=a%0g$3C_xY9H71a_!rJFtvgD)V)IFl)r|7 z4yk?oUJdTRzMYVvefk8e_FWD+*S^D!eSCUV`yP>WwfwF}nA!km;J#1fG>rWom(;!= zTe-kKw&S!fBf@GQhumHJSir2Ki*c0WQ2Pd=A*F7$Z#Ud(1Dt_7zIF@S5tr1yDyuKB z?+ysjKHP!~seO|n=h|1|*vB?r?Q4qJcNfC4*>{%6Y1rL1x!_mrj41N-iU1nrw7 zl4{@1n0;x-K0d9heNV>h+mA4{fhyJgXw1F`8R(GO$2DJF`yPf2?W+`7weN7uz8c3q z+|C30su6*@_52=yTWx|fa8D394f`4c9a8(ww{k)GJq{V#H%(*_Z0KA#-1A%O*vGdC zlw&-uaY)_Mage@^qujXc55suu6*&$1Jsez*S4r)=BbII>(&c)giy_E9fu_svyEP7V z6oP+^4j~QuT1+m9K4F~-0aflRkaP3<8eW;zBAn^Y#erax-|xrtErPzS2vbsh--+p) zgGR3nLezI64%PQ;Odr?OrJR!LI~3D*2lO3)5cTodP4#ijUyTEAZvraL7{^1MFU9mV zkM_J~$WtHR-l#tIp&6$J2dOR(Ys-~;Lm*2_3K1usL7UHR(A3e{v8IX>D*K;HIeT_Z zn$-VX%4^3WAxs3cefJ8?q^$S;-Z_qcuYCRk$+pr*{PJY;&QtQgjBDq9|B8M4qI=jU zmRwT5;>!q?IzKIVJ6{(nJ%+w-3C*?#yZ!lTOME&K^5QSL`5=0I}g z0ZgLgV!N0`xt3fak4wm=u7p?cZTtiV-VYhSAOm-z zpo`kPy!njwr2hzl^B$!8JO0aX7pDG%-y(h)GVmg}yyC0y!&zpw`uV#jB52TG@#B}$ z$+>o^k5TXf3Yu;s)5KQvf#6UPEdDwJ%*!k*vN;eLt|Ht-)E@~sQ``OBHw7XiRb(Hv zpgB^JM*@*!Rpc4y_e~efCiIg)WDK3gXsRj3TrAIL|4WkNG%cIEaUxj!5d`{~P=qU< zS&@v2m<7PfDZ)n%fA<=Qlx(B3oK8~7W%%*SH-e?EWBBaBZOu`7d*K{hnA(7#(m&wG zuQVkOUtZAuZocv+b&vnI_%$-+YJHH|7JQz&!Hgh_W9g8?bu z2<5Pj6;xnyB{!lj)TIfEbY>*ld&UhH9EeY;#JU5)HrgXl4i1YNcZ^;6;D$N`nHiBN z!Xr$n9OCqz<^!=;(PQWf~^d-~;D zvO2=sy4FJER*SRwCRSR&C20yUIXF67bV!sP7G+07*-=q;bd((%Wz$i%%=a_Xs?l2d z!Fmo;F)=mY;ivhfOA{%0tZR}SV|b)xV=!@#LoRNBXQ!?GU(EVE{j8OXR@rHGT%yA3 z>{z`9n_jLDw&An_u21CSRrxwq#%-*y*`f!#twub}IFDV0;+@Hzl`_PZu3X#EiH}e) zF|xa|W#fA6Fx#;Xt7n9>fg^?Ol%Z}bWJmm(mY%tA!P2Ici&m_3=2k~9n$?@Ob#-?( zwQs@nv?gqKD`&?|z%yfQTUK{>ZoWw{k9ZrRwxsY2ndvbKgwt+jJSIc@cfvrccymdzExrmc~J zUcTUrdM_v+V+XakM%x*urYwAp(dzHFP$|9W%i7gv+}uT`X#P`8`b5_?ptoY} znL&XzI>Kida@pp54rV|=`liNuaL#8`A0Mhh$~NaSsxSItkaIqx`rNw!?ZacLL!9#& z)u&H7R)}*xqxzyxR>{~(Ih^Ae)feTsR!vl&dpDzfI)bO^4~yv==2%bp5ixyuQg(=Q zK3z&;6_2Pz@j0KPWBTx-)S=#M;f#&xvo8@fO43Wm^rbb(V75JJqxO}>TC5o7d`9&j7mHsJ(_dla!&<~QGa)6t$sq$5_ppuXpArkNjOnk8>DLh;8!c&8 zs|i&k@rFIBza|WXD~S=7X!!J?Mllb5Fal$vB_nUQ8Glwx-|QGaC&r%;NQQ^&v@HpRco3StTgO#14Hy`P) zJN?8XPx6d+7bEeVhq{QrbSff#+N~1LNUtL7V)hwodo+UUuAFM5Pru7K+oK;>MV&%0dR$iM<<+W*3-n=@7ZsoOUP+l+PRrW49x!OLHB&AAE zo*{-pp4VpJKR5K}-7>Mzh9?%|g(!I-?-E3sm}o#9Bc3AjHQ~>zmf!CF(oR|%T6 ztZ=JeD7=~H3Hfu#5AwXV;?H?I)MMs(;(VHUp5Q+!{U9NrvH7x-wVD@lzNsxIw_VjkngmKC^CZ?LAI&% zpDI`*SVx3isA2|B7hEQ|nh3kr33dpY`U8Jcf1!kJAI~d$C!A-QCc=mcBF>XZ59ft< z7oLY&BFY_EGv#dRE9}FiWb9}rLO+RmP5yxSZgNunVWc;9?@mYpI~I8+NWF4>WtP!p=(8C)hWS z2)j5hjrP2Y2z%BOk^WX9(tR%x>2X|*>3xQXbU27cy@={1aB-XbLBGilctkPj82iB+ z`;nfp7re0-kylFmRYauUDtsFec61BBl?Z!w2)~nvL~a!RW+LpnSNMHI*!d;l4-jGR z(GtfCkwsIF7-uGb97>2g1EgG1__!RyNE317apx(#Fv8a1MeygfL^;O042Nr9EqJv7&cMy{=Gs@sK!+Gc z;`kTbfqnJhnGO$<+IK75u6=)T>_c@9>^lgzYoECu;HRXvJ^>HcKIY#gweKZ(y7uw9 zqHRSYtoHp5ylY<(>T(JESboJgwEVbd8g;WwNvm+EP2|8;$_3?j z9{gw@(>DO>jQ16*FR-r*erf}pfqTEmX&CPdE+NpKb_VvJz>5Rrf zQu`J{&b4o;V;`E)z`h)}Y+K2|t&#oZkg~ za0mII9OGAru;%0JSi09b6KCX=E+wJ57x7$D;CmqpNJs*eQ zc1iQW*-mag4nc_aP!~z_@$Fc;d!2mLh#cd+200?Y&~y0BRu8zxw%R~J$_0_&)G+SJ z?Vh*&NVgW5;(0@NBFOKUxIP##T9r8Zbbc(n45e~xA4YkNG9{MoE9ijqK#1w`-i~0C z&-t-*cS2tm!jx3s2{C=$XfT=~M16B`sJ>+}eXl_u<&;$4=`npzLEkx65d9Vu<%SqfU64zdF>8SQLlsDSprDpqYSSQiG zuR#*#{U*@7-vr{e?_s){d2YwH2=DA~D1|-~=srtn-Ixl06q8qrgT#AQ4-l_>%o*od z=Y5d(c8vq)TfV>HOx$aj4%5xUq3QB{vzzX-;Bl)CNW<2{hwd5)@xlCF10{?spA%g< zK4~aWf`XB@%{R1%UZz@q2iS^XIpL53lZ6?J2s2tI~64~!Q2tV4$ zyCTblZk{t&-yI0x`v4`?CzsI0>pRTnAN{VSjlGYhKhgj9A3SHEKKlnhMWA1SpY0R_ z_39s-3Qv4Pv5}C-;p=Dg557gn&w0o|-dTkB-p8M#r=RLKI=Pu171s({+ap)_DXxFUvRYJ z6g4=-dT-#_KH7f4y|};hK>qFS7fk&J^b4MM3V==?@qPi{EAl?8q;m0o0lyt|Nma-D z1(Z9QenIt7_6zu)?I04SjYsMi?8bR>-@~eX)iaL&yWSg2n>Ksq9P^5y|9-(8$C(ld z`UO+*6@BHe|9ECjLvce%!>m(>H261gpW+!y=4I|~OTO;aZ)nS{U$XGbS6W*9*AvsH zw3XJ6uCH9OyDsOadtbe4rayb{s|UJs4|!8lKT46Gp925%YbE=NGM(%1d2wJt;frsa z*w{dwd9QwddC~OF!-am{t52PCMMI*#_N50J>lQA4G&#Mo;mqHBBA-%48UJ5>rcsbMaxxc+}xxA#gFYo>y=zWwW!EaA1fBnXS#68{( z$$L`9POswpgUQ=!PR)7s>RCB2{nyaDJX$gJw5g}oEzD~;^Ofz*(@y@u=*5rTFy>Rw ze==vo=v50Dj=Zd>{lj&~EM$IW89HuOn+Yw<^cdZ(<;mCc)-L$NCpYKT-}%zU zi*Bzw?irLwvh(nnK1#c1ZHr%%Zh;=;KHub?C0|jWxb0ALh0!oCb4TD}x)lvA&GRyJ z`RRGuLEo<8KY!`MF=B zCiAIhQSKk;Kb`(1x!2Qw2Hit)FQorWx<}*|QqL^9N9Vqq?%8ywa~C7Q)EpW!K9^Tw zYA#Kvz@{D(fcY$t0Z&4we-35LZq^0cz%h0~yE?EZiSh9Y3n|skP|^!H{M{!bei8EL zx6?%$_&@luVtl4#n*^3A@b&P(HYDwLoCe_?WYe(M?`Q;jAK2n5{P>+r;(KJ-=eO)I zL@QoE;V!D0Nw%4x|4Ly_<|#gjnhkpi*@ZzUr|JxvjGwdNMe=u+ECoyd63z>ve8~y; zp&mSTrWV1T{OgR9siDB|d(55q@t1Hy4Jn1g-%V~H=hFB~?#1u3P%v;deykin;u}oC zi8=WG)L+IAfJ^;GKqIx<6#flD`8yyqd){PuopY z#hFIK&9L`JsU)$h*_OQFZbYChdBbv+ku7<{a+jOo=B(XJO^IEtBOZd+5V%L+@IU@n zWVPhy@M66!`5_$K)urS+aD0f4$KbdVj*%1}^&B{^r!wkAI2d)*pW&!LUPdLsHNb(1 zRlF0PjZ;wSuSi^4RO&BBaW4-GKhf=#CNA|7m*OqMF@HpSf4`QEx%cnpxw6%CKMT1P zT5UBo?3HBCMQZ+j)_6W{7j<`f{sZK`4Q}`kk-q<+6xHzOnSyYw#aslya=)SIa@LfG zS`i_!t8I8G1BKgI+#ZC@fI*`t~TV%uR*@}!z#7hWNTNmcWjMQ0=qUw ziuNC{ruZ6MdLOw_&R$I z+Kq7Y9J|vEcFM6IZ*!}fbRlDKi=2FZJsB0!yU7rXoPDP^FFc=Hlh~K6#I^~Hqe04>ZIJ5Xd0ZuFxGx2 z&lBfgivr}%4YK_% z_*{S^i5tltI@aOH^|qAcmiv3?zR?CI_Rzt*NYdM09Enb;gtw*W3&3yV@VymmMxL=w z{04+J0-=orv;U}qWMFgjo6i&UG3Max0vD-8q2fPR~jq@A= zjZS(OPYcwa4UbhOypgcUIO%Cfix-Mmq>SwwaT|=^V&m0F=r&IF(E`ec%lDQMZ0O1$ z2#&!fbUA^;Gf0F$LDsym-oV2=&*Ca55dr6_t%uhcI1ox;3OU~99y9=SHse4DVJ(h4 z?_a%L&AFrZkmhESi~3M z;MLHBgBAY6IBv)B2^@QIxO6n>O@)yOuNwVxcn#$PjdpSFWp`x@BDTXUEpuRy{U3Yu@y-v6<>)kHgGs3@C{X zY~?mGvO>m3e1FFA6Os#0%Zyuca%S9^@iUX#(&sLzt~{}9+)4AtmenLrn3rs*N}iBT zE;?;$P4cT=RVMkR%d3*#@YW_DF_<1(cG9@ax^WqZCpV-qQsO6vr7@5hCcEGFtHzI> zepSsUs>fx@#@0|KH=PUn=ZDT|nX*hd*^IHUbM0Dw?6P^yYVX1=Sh}GDYqej9WfL~6 z+0?OSW0NUPED6xwv>oe%c_Q7`zS$YNFfy$z+q`w{#<@ww=x2Pkt!ddr9T(H*&CG7l zMGb5Uc4|W~9Ks)c{&X~%A3;Xq4lj3!!% zj1rbmFk-T4&E_o|Q7n{$qV6_ohH*&8rj3WRz&sSp}(N{pMCIQxYFMLQ7MG!(9WTg3XT*Tl%`2K zG2rU_Yx3TkyEEr~srM&85MP&qjn{aM2t0(NuDGJ7;EDlP=3kY!Blqf@Yf|q`?qs~t zjvVh&3yMp2q^?e0gRlj~FyQT&?_$2ZciNix$M$YemhbE1!A4#5y!2W%ARe4WZ8niC zs!i({w>TQtiu9XAD3&c5Qz83F$IA4dP$*|NgZighX@LE*klu>52H0^7DP?Bm;NkN+TMBkLw|2TT39SZ&)Y{7uOPSiE9P8#QmUL z>b(}gI5!yjGBLh9#!oQ$3-fSXEIiJ;Ehp`*h@?P0RgMPoi*T^Mux1R#1hSPtC5E4` z43K;~4$2?GF*s4|^#IAU{T-Y@`P%M9&}GFgJWd-oz7?G@GXoL3)U3ZKV77E%TpL^F zc6Bv%ZK{dgn8Kcz8@Ii)H6~};pjhi=S_|5ZB^b>&d&Kt(zgzHLL4a8=m#7P2kDX#T zZ?ab1N%me>fJ>tcLDW|#*euv4$j5Sq-z~Ub@C(GLb}tDcX|h&b=x42?eg+Xqlkwin z5W;!YCdODh5-`Hd2?P$MKafwGiL__VeF9aiTKs1Vo+MZ=xI~bThm3!&V6)&l!4APK zg4+eJ7Q9vP(}JHDd{pq?1^-jm-!1%|5`K^H4+zfz5~laK@J|Z=1L2<$p5In6z5f;dMdAM-JQ`dR&gUlT z8zlS)BJ3SaOxv~psi#K5=L(u{pUaRx@~CfJMDW{*kiT5`_X+ZY!KuNEXwnB8F96sxh}z*>k`N}Fbv-zxKr>t!5ak4bqYDYETjB=g64V!|3%@= zbqoG`!v8?u@RNdO4F&jf&klxvOYpmb9PXq)$NY$Y6HLhUI#iGY z{|v7XoGNJAA^0y8o`a&4yFhR~5f679Bc;D-e}GqrziD^Ce^|mlCjNH{f4AVj33459 z>fx9w@jHS~2|gqEbHQH<{zlNWONhszSjP9+4gmRm7qLjNRB*T;M{F5BRd9yj@q!%4 zW%y}={Kk#^S%MsrWjoU*$ZyQZZx-YjE%|E%KPb3M@D4%KzCrFD;qMcCQ1AObd<|k%D`n&XCLGBc%ol`c7!UGLW#Xj;#|s)g2%jpvX@|kj6n>82Ji*08*t1lyk%+`r z3YzvA@y{a>6r8oZqh@%trGqo zBH|w{9ScDu89endzb@f2Hk83HSjG9Re(_)LRHPynnmt z@&eF&pc)0~{uOTO)_m}OdkDOe>iZ!)Tzw_b$GXUT@X1{B@iN@hr}^N0%_WABc)!Pg zkPpf+AJj$CblE>}(`|P0f$ATm%lkh5gM6@m-AzS8Y6fRax%#>seWj4qe6T-3eH!n2 zb%;KOk*>0GK|UzQd{7rj^TGayn{JPjF8hRboBL_92}5_{K%c#q90@ zUTHh@)i~!^_5CTPul6|4OCu8XWpJoI_U9O<1_$YGRL*tU7=mXQ57u*6?if6%m%v|1 z<;IAd`e*n+?-1ok>>sL|{CLQ*Em5L54kfCS4riFj<+`tmGdw>rof-)nf5XNw9VBw6_v@&hw5A1wWYFUQ@j13 zE1mB5o37($*4U}rNAb;f+Lm!JcY8YCmL#!n&arJH+PuTQ*;A(gc9J-+Id6$yc1iuH zu3RHCs;%Vyy2IE~;7}QUM>Thy!t0RNHi_~%qO0~Lf8mJQ$40HHTeX1u^bEElj*QXu zO3ww*g+KTl24Cnt2>;A zdx5y~;ZBIV1a9mn^k^gOn1>_VzCypn39xl3<-Z6SpAWEWakv!DFXm&3Oc2I5ZeNBF z<`+Lf&qN*{5mI^h3HAxPivjt0O@vh5&ncbC`7g`y#RfDz2uK~I+w2mQvk*@IVqDyw zpUas6{`gD9k|Ffloo5z8lt(^qGX7jqm&aFHzR}i9*KR&C7M)M$2k0yr_yWbRZG#V~ z;EQChV~|%;^b0aKkr`F=Rl0Ab+b=p5p;lF*$lUvHqkpRC4Tj!McYZOipP$3^IUIxh zM!(i8;n|@V+0!tuh>0F^3w2e{Lc96R;Ey7qR0s1{I+$seQEZ4c@J&vMtdhBjc9J9R z$5r0RBjfWLKU#;^l6mgLK0DtL{+#lMXNF*cBd#G#oXo0%q6OhB!_l}4722tmMUF3C zzzhsoc9DzS>4k%w$&Mu&fUu-71yjT5WQ`;>o8R!~?~ym}N4#ed`5!)OroCl#+j>l;cuQu^;LVn{ z^t`{hvs^ZJw_?B?lUs1Vz^$OEWz*_5aF9a9Hf5VE_cJHqOL;$-w=xMEw_uXV{K%}5 z8GhNiM4lrx$1gQPZp^=Ues!{VUhS;pu+!#`J$ZihQv8`YF|wlS`pr#eEIRXyrnOr- zR(G%O>}c8Od=ndH!dZVcF214h^s|;O^*Yvcb~LSS>1w%P;~Ho$8ERxDmHEu3x;nKS@%*S9hCOWo zuf#UY<=OVRJlnoFuk9XnG~>{{Oy0J+9etd|_-uy0#Ij6iIFhKDJ<-?c?jucJ_ojK# zYH@_^BeKi7sb*{1vTur!O|t*&Iv0qs(@i_D&K1g@cvjKAQ}0teGF`=O3gd;Xmsmt5 zOM+SD>~0w}!fl{U{{IPQv6#CqFG$c^F^2`+HHT8>eGq$8mcl+0`D}Am^!<^Q=Nr3_ zxIacz{{W*u9f@8MD?-58xrThM8o-pC?w8_(HycK`QW4S zV?trLlCc>+NiQ7>&&2rh7|-X$kdo%DwaZTm8MwGV1?>sz-_%%moHx&#flLxJY-j=V z#(Nj{UpOHMwR)Gt_zS>Op7%q}!Pzc6?}waYb7O=rHRH9EZ#Lm0yvKk_X*j;44AA5Q zZI*q366~E2Z;JZ3Cuw6A^ec1*PHe(XUw5pSTBli$$8dr)QMaWHds$g6m}c_XJkw@8 z*w@!IK2*1zCp}zftgf!B)Wyf@V$t`hMa0{vlClzxH5yPl>-7`$r~zD?BSO!*hu!uc5-13r-@UT+En0 zRw+ikMyk5|Z-9z7fM0rSa2-ke_`uRF$L8$e_|V|-rI#556l zV5-3viO`dvy@)@Y$aIO2H)Dv9H~L_N(Fb`GAH1;-@puU&z|SEfe!cLEiO{oBc-C9Z z2b}#9TXC2YjI}Twm+bouTYo8+l)$(g!$>Gh3 zPEZu)98r$^={TrQ?Pa;Rr1ouvC)~jp59JtN(^Kq*AA1nBI7o+)ZV8a-vL~YH{yW@m zJ{rMS;80S1oRj0~<7*|=M}O7#Rk*27^Fe!EVi@VSIN%QQK{@7wx=5PtuiK|Ux)ecE@> zbXUjHt#I;zQxl|nK+@HG>_u3%d~mGZ&Bq)kAMAN)J~+OH|KNNafZHX8k$z?6f_xl+ zAM>HTIL*g@L(WaN*2xF&J(}(u6dZMHKE4TeGY%!yR{}X#UnBITA;j}B0*C6W5`B6; z*#7YRE2%!tJwi~B4~`)-AJj!sISvZA>2@Jq$}nBFDVi?lI5NJr2W;=~ACS5~V$%)$ zDaU!3O6uGdOLr&I?Li>Z#gxGy-H*rgRl)$)NhNiDJ|?#ohEtD{%5jkuH^2F4tkMu- zx)~gr->=2=?La^+!j)9tS7Q1qppUwEl;co+Psj8R|6L{$ex5<38Oi`PUA8rl z3#br-h+LCjN#%&hazOP1J?{YIroo4LnJ)8B+nnfL3JE+5KPA;CUHwXY&RVsisJG3a_BC9e2y>4fac@ zmTqj#eF1jN-mH1=3y)@9KP@+_Bg*w&131T=50x6s&Kf>&kY^c=OPJR?<_&LOMrHBO z*0*9?sHAl?0}rOH^*g<8bXqC$wwhT3c=hzuA$VSB;|vaTU$z@<#j?zfdX#|g%sMCra*xLh424AbLR3q zyGjgAY5V)V&rhQ>=Q3x`+~=8@XLjYY@>4^_tLHa0B%hW|n_92jxOL0s%?%CB!ixVl zG;H3uWy>a^56m~_jCIC*;ayLw%QP)DPw8IxeUteway5G!jdyQZWNJ>={rn>)dqwMS z#{E&Z$^HjjZR1W;;huBU)IOCvajB_&D)*&Nn_9XbF7# zzxmTi_s=`c{L^p?K6J>W-NLKCZp4+2nuT<)zRN6p*H?o3D)^`A&OCOXsc^U7WzKZ& z6+6wDv3t)4%$amw`)P$+G_T!MxQ6eVMX}p?m048HJ@*l_=rr6}g+oT%eSlBl7I%Ko zEWYVRv-pL-2<}VYGmF)oeQB=|*EDF(J{@<_^4F5LSubK%U2({lB5*O~guuC;D(zNwGh-ETJar{g}|XzHE&*PZ5~ z>_>hrx8kRRhVJ5vep=lf_=dTdZe}F72fk}Aj@`d4F&D!%EFVw0YhPp<((bM;rXhA8 z?==li;Z|Na*N7{9->iHp_g6nME1mn+)n+B#&!%Q|t2%1TX}fzrZC1tZ6Z6fgDsFYn z2aLE?UpK3tZuhqDo7K+!+o#QHxHZe(Ug_>SYSw&ag>^rEzF7lz$z|WQ?gsdsyY;8$ zk~iI6;V!*tg{g2qpKC6S+-18zYZC6{A#>TU>DG21HUHQB&&Y$zUwxH1E%(14F_*)w zJL`+qb$!IF`&Hbl?lbFtRrkGjnJZczsdP7g#9TplVkEdfUuv#+8r}M9zhTyY{@cHn z+t75i`AxdUCB3HcJ2#!SYr5eobGoj1;gosW+{YG~=Ksd7<{Id%;w&I zt$7CBFV|IdTe}yT|Bmj;^*=J+z3fxw%BR^~weIWYnR6d8&wTk8&9laC{FU9d&F?c; zU-~2Kt{X8|Kbd>&J?82U-}pb;J^LFs8t1kTf7|>zu5DnyY5T2fpBC4?X})<<_ZRn= z_Q>tH;4br|?nU>Q9dvJ9WZe%RF*{PON#69s1b8QuO-GWb< z-qq9a-5bARy8rUizqZ@6?#<@E zv)eoOkok?e4_;;V&gTC4?Pl-O;ChelH{Si;_f2o?e!SH5HGlqBcelRC^!;D=q4_Z1^<`f9WPKj3b-;HVLI!>7y*|55kzd(91}=?)ya zz*M*wA2kO~$DL|72h#3|`^u*dhq9L%?}ol%4$&h)Z^#V}KV$|!b^EXEh7PnF@80o!Gjy76xNWC-Qup0MrcnOa z>A81*-V`D?viL=&s=N6|W+d(Y?u%w5a)$>Nng56@b}u#FJy2tc|3Oze_)7DeayLD4 zpZQhY=%OX2!nJ+MjLzon=r*Ijs{28W8I9c7{1GE=!z<0$Z0_i%%-HF;Km4v4qx-AD zU(NmKAv1QGZoK&`#=9FIGUI7?>yq-3+<4&@V?l0wW^`2iGh+nLFHB7k9?g%=6zC}z zrU^!-3W82fOnQH5yj++P?r>qWFfDxR%S}#CN#J5>LV0Um@7|D74uLDFVg}b1`?ea%ax`JV`UPj z3e!`i!qEc#YAt+fEqxPtq~3XQ`KiOEv$r>Q7*Q9drY5G6SZ=g5UZ_IK4dbp?O&6yM`C;T{ z9;N3}K3+JcF+%&`RDSBXurx@JwK~hk%gF6WHNseog;W~1Im&cZQW1H1V!V9p(vTSJT z_#}uniDi*v4NMS3u)S+fC6QU}f*#p3Ss3r@+ubXf(I}P{4?=Fm2rJK(E zJ-N>Dp^4!_*LZ0#&##ZmArn1Lo zw$cdXP;PRnFj6{(-pcE3*)lt?bcSDvwC8ZJx+d9VyRBeO$<%L9Bt551LmGgYi@92g4y40#}|6EjIAf< z^07U~US(Vgv^_U6%3*`j7$HjPwKbqU$97w_ERPQPbu+!`X=+|ueJqd%dLgb*Kt1&q8{BVz%LfP$7)F6Pnf z**D1`m7ADiaTzbA|So31aj{XC- z;ixq6A&jEhp(DIdvm7LmeKDpxp`CJEkAI*b6Uc1|KtA^}Y=m0G@} zGa1AtJ&45djSa_GI-%8*?{kjre^~4kB`6eutXR&&n$DPQ<#1k9Lg!_*qyS6Q2V}=< z6%QUCFIf{~+Qi^Z5-6sP=f`ZZkvLSEEEc9h;2m8(*L3zu(V!c%gL6dV1eQibB-aV1 z$TG)G(PTzU8irQRNun}QO0rN2X(WYwR-YXIaodSst2u_YZWOEsg?q#?UD&m@&u34CODg+E%aP|w3N3U zS)vuVrqRx6RR6?v1=|g^b+&cnQWgtsd}4g45Eryi$MVN=cx9O?;)O*b_EgMoC>@Bd zm(1N#!YpmLG*!@dDrB~VastU9aijBM<$_L*J!JyZ^<+S%c4}x7rbn(LF5qoPUaZ+L zr-oW{o0{>CG92EXl!@_Y-U3U)-(qc#)KXL~{V3&VwtLO42^2g+)Mc-VHCjV4fs zZHtbmDyK5aR}8i|JqCKmODQZJkCj1#*x2eM?PzGNrfDs$TfOBT$BF=R!{G(KvqkvC zND@ChG#2<*hAflt#AAKH6Z(M1;W=Y)Su}{M7I*`6=6zNvNS>9)GRPScDlp z-mg$MTRG72rK$$DgOitRB8>Y|6*ijU!DH>8P zZH4nc$OWp)QyRmu_^G+M(%9r^X$X@PeB6@ASFM1Wag~~w@3Y5~=FT2ZBuQ^YdLllj zz6pNZq^l&jD!aNRuHz_|M>mFi@VT5MS7dV~JF>bZmtGzK2`wXpz-IJQ=m6!WJuCVIvwcb(dt}!A7Sf&d$^TrJzGZeM{2v z7?hHfR3>QHR3<3Zb>oTTCPO5%LU|*wmv6-hgXMKUL7BqJ0hVwKLgfx~*)+Fl5Tm=G zV>6@E0cHB_%T8d*8&nADQIS2mHB#dci2_JlXP?i1`d#AbPmd~&rZO^ik%kF=LdRgK zf`nX)>jguhGf#wKTXzLQeyS>wG?c7I`SKX%3c-Gdr|pjEY1>t{6?93DlXdwpSY~64 zZBt6MvDLDUO=BKl2YnMLP9fDD-CB{i5ji$d$xfZ3DP6I3Dj~JhS>cBM4&)Wn%bAGt zPhe^|nV%|6Tare!QTQ5-MdIRO;PE(C5+JbA#VEnuTqsSHc|wAyM&+;oT`UY8!D?Oa zj!ksl-0mHFx_8Ppg7wK;mM22Y&K@m=bG<4QyVA|Mu&$9=X|4d9;LQz|CXB>}Y$;=o zTPkC%&$d-NI_FxOD+snhs+b$Q6J3=j&e+A>v~04U@Y12Rrvq3$)g!jbERS zkg}DQo50o)5P2oBFJHj8S%t2+95gF|qQaD=XCSgK2Z$}Q@xtLeMj%ng+U@bd@!Tzi zW0QGora@8`1^_jslyqsKEf7{&_%J`?OA^-Lk%!%~M(%B7K#vR!mRo1W%caBPXh@J8 z9B&;Ol$@KvUY$e>K#kbBV{~PQpvGGR%9P3vmYEc15WGls}2!6J8XCYr1wb>4( zc_Ikoyaihh!ots+oFoH_w!?M*|@ewC<@l$wRyGVmD7Y?`WCZtVu~r zOG>n)&=3MP`jj$amul1y7Y1IKhb=ekvXrN%OIYtxgB>T0do9$M)YK}fST&F$S;_Zx zg#?e3Z=MQ>Gg7J)yV@Y8?Nm5aFf=hXnBVI33$}?E^#z{CHqrFMLsG$LY-t<|4VW;2 zdSnW<5yOUL_Vs(Z`@=FGxSpU@!{e@gc!FzD47Uu1+d*ASv^@U%nVQD97;&! zuw;D13`8H_a5;}OVV#KTLtVE%spnJDD9E-xA+j&y)E88{d#wo42cJv(SRQ8)*ez3z z*^Ug7Faj$!6EvGy42HYCQWpSi9e`(M60g7`!aM4T^kBsd*$WBo!ixvp2Vw=~7EGIv zIQS-Kl!SSgmA2br!ov!ICv!jCBU1$_NQ7sawf_btg%{9rabji^x$fduJjCt=rdbQA z&W0#q?|ZT^R6;c)m0cwdTO6kMHG*0 z3D62zsF33eB59349uMZR&E&HNa~4^9l@Q3&TuitnMrhs8=mdKLrkt2+t02hP5tkEA z$`dh^a~s!Zv*JwiG^a4oE+=Hf!!Z~Hrb9fKa7AeZ!X09fjE+FqlL|3`5{%Gp>spPs z$Y%H;zE3A!CMG^^k#qMPnr-!C8IUOZ?v!-|9_*2@D&Tb~UYHnRfzC|XRE^{yFv8xG z@j*r`vNXHbw{2jSAG<+om`{!afBmr$ph!reH=K z3{#rn8P2s387ED)*3%f5w@<>ti6_oOD}wsme=?p8%sgawIU%Ab+cXl%JSGd(fvG)lE+z$C%ksJ3WtTXzSlGG8R= z;~Rq|VfBBeZ2k5Sfsl0^izsp|NUDek6b`EbyqAsI;Mf8$7oC{mfQwF9{9vd*?5Yd+%uQg4@a+ zP)gI!>A&-rvDL2RQR|&PHtnV9ce)uTa2qG;Eyg;Al&%hM7bWysqu3Nr(FSo$hUB)s z?v`A8SAVXrzqhM<7dsYHY8}d@=w_(3R6$G0NT{Zv^j&tFrIl$(uBmc2pO%Ub4S0)r|?qibb?=M z%_s0Etjt+sT&AhM`Dg?_#frxP^c0FE?db3HZPVxOo|wuku9Wq8)`Mo<-`2jn)6VTg za$k4X{?6XMw%yw3kymlu30(nR@JI4o*5*9k#-dEN=~1QrlCY=YY>Z3?1>^o zztr8;ksw=P4i2%frMlkR=O^1q=o|!-P||)drdb_=Nx=lBZz00;`6pP^@B~MOrJ8M| zm#L4lQ$h@vMn)nT*Gu*v?CInnt}J39X2n_}CJS47jhSgIr6zleef>Mq#yV2kBuDpY zb_5@}BOt<@jmYfl-?^2x4p|>wrnFEcckrgqKi>!i2UUbE-Uy%MAhcC4O z3pz6{1WpJ?!ds2xChLkljw|y;p|PyeG^tZ~BPn5Z5NfRkXQKHG=l)z$!Fyf>3k$@)V~T<>VV;f^i6}I)oHH3o zY~ffA-MUpPnF<2>p@`ryjF*$6T-+hW1;)4-$s#aDp@@K&(~%U(3wV8=!j+;Dm$L0z ziLD?m)=)pi&J>E6110G3mE1?>DK521g2#H?3a?lpScpJS)+f965JZ^mX&U9mF%_3% zok`IuWJ(X=Gn%UMRT&I1ff;hO2&&O3k0w`DKG3CreXdFM!8_TpsBCSOazo@KnSKO| z2lp_NC8&}UF(sOG#8U&wb+0%yA)V|vf~Zp@XmW(4l0;)wJrPY*1w3erXi0^k;f2IT zG*KAvpfI8(6>^x;&cILWBAO@+cu*M8k_!C{Dy=om5Y;JS(4S@`BkAALl2#u`qS&KB zWgsP$b+v6yD+?r1=Fy-mkdn&uO(U%^NfxCEQc#>ECzb0oBNV+Oh(b3B@jZ(pB$a3c z?lmbWOEY3Copgnro{@}Xe^*}@X3^wD+E z&b|AvYt)%*>pmD#n4m_o{b?~vkZkC~8zYq9(@i_##5z1NF?w*0<~cjt?Xrs}^rs0C zo=zv?jPuNy5Q@Q3yitx2TWnv7y#Z2-oLs1oj*@C4K3KBBIq6iN;H6#Hl9ID!?4?2{ z>EuEm>?l65sj$%i<3yuD%#osj(vjRq?C?a{f#|2+L&b>_&U=?}NNs2upWF(A^Qx*0 zY@`iM%wVUB5?sp`aZknGzO3)cHkTYJ5I)|i>}d^;NyG41IgjHM9>d-l3{e7SPa~xQ zHp#g4Au`yr%nuLZ>#wd|SXyH?2j8LHd$1r0l7pSyySlnNr7fvfqEQc^{>l1kam9UWDr6ZGpl`>)y4fi?RPqu!ZuBCr%apo`05BuX*? z{hlq}_V8YV9ReI-J4Ol5kwatGU?XD;@6!c)hU^;q-b{V&ObqBWqdC*N$$9?zdTPA|cB#tMzB=QWJOq*R2YEOu8mhA4iZbu)! z?%=jqOM+>$cvd!xDq^-u*s(&noW~h)>Gmtx`Z6qU&_ zTYB1h+ph0(dSVj7M5v5vDU$06y*V;#NW|qRu_ko9m`vgXGCEMU!pr*w}-^jay51$lh*W%q89bX+GRrUsSV#_;;b@<(v$4(tDD z>yC(HP*tchGqIAGn4&0gO$y#BTq#*YXyNQKwz@F)utAtCOdA|c-&>Iz9>f>ME+1?+ z?{S!jW1F5!1i3jm!6SdP;o8Zm32sVpDZPrZ)(|n4x2%5wr;h?MFgolZ08WW zF3_c&r$|ZEsfq&GvC}Hc;dORDPCQ)KX_qCKbAgh;d^7NTtB5a>%q-~uS|^XlC@*g> z%z9zP#8#1$`6nz*c5BrL;cY>a9|#jRKcdcag8Ad|r1|KkQdwgu>@aPv13z$OZcA%! z$G+bEot#@*bZ1xR?vAbw5}*=U#jJ4eae?BPuAw`@iaJe(YufZ{Tc%g%psF-X<&PSQELv?vElJ+Z=}?{`X)tX-Wy3tJ(m6el^VUf946O6j~nBx z>nSof%(01G$~;g*QF~0AlXh@`ny(KfaG+S`PnfStXLPuP|)Ra0e2vTF@oyC_)uLYIgUVktHhIv z!_Ge9g3!oqCtQVLLnO;65vD53hN@P8iLg&1U^TFP=aXq6JF3HX0VgEN)-- z&;fAyMpjHv9x|+vpsQ|YLpkiH^DV*Z6K z7CL4xQ_&P))y_^(bUjL^W)8dN`nDb6iztt=qu}{uA$0MhawJO-y+}y>JLTp8|D zdUyg~XB6!vB$mEkmOZI=Ctkj*Nid|u%iAc@fl@K3DQU?HGId&0)1rae!?^|Xfg*y~ z*_y-L{LA6d49t2wjDYX@<>0{K@&zG zRLU%sN*E?m35rUkjTON((P@m*U=>CLlvLIH$Fv#miFTG5(yCNDcdj7YHBFyiY;}lF zx-{7ez)eLV47nWUm^GfO*P6>ju_Xa zus4d{uZXtIOix54uIxu|ORnT-WTJ^EAs1Ic(vnSw6nT@0^&qjhMn`7iF_}4(xN1zQ z5H&D&s&nMCG@s8>xk~Kp5~P6XdSX( znLcD0w`b)?r+IroLN!ZCLeD1PG-#rdU0H0L3ZTvL!{LFUVZ?P|14TkxGzxDCR>L*0&h+4Z3HxCjJ_tLox%tXmZ|B}X zO;GeJxU`@pKZRtjyYmK7o0RtCqzyZIcc*M{l#~rgve@8AUSnb@JE*NB2i>#rD(Q(> z{2G+cRR%~MEjv zcuY&^uVkd8Me~zKC=;u4$QVdRq(pQT^rWm$Mq*tunJKfdD#($pIFUl;Do7~JU|}_S zlBU6DFEV#rA{gxsPJ|5NXPZ&{qBFvSJr%@=APugod#8R%%}>o3XOf&EdCfxSfq3^l zxDc>ZKV&~^qNZW|U;q{ytXeqm)w|mlaC=9)c0emY(lIC8W1gzP*zf8ODRHp}c0L6ek%WK-kGh1xPY%;Utx4T9QPsxw4H{QrPO* zIzyfESSYL%$)i3dQgUtk4kWdBN>WpbTp8Bcl-tqS+mEg6uHKa1Bt50Q8dKs33~7({ zWhwezqkA{)tVMJR+SUDmqNrBInnN68Tng1eyxo)aZJtZyRf=mpRC($8E`C1uP68l08{A{hR*<7EY0?pB;qt;wQ`0(pMvW%@KaT|tVsF~v6d|k2S28V ziWX&QtGJxFkqAk|eQZ2hkxNlUUANrpV-;|nR02tj^jM_{X_kEL>4|Z4a@0t4(pWDd z5wIh)@kLfg$xG-7!ai(nVsyBA_`s>q5m+Nwre$@iNS@W{*s8%2nVVPjR?!1*DfZD_XNOUqu?l`A>tce@9^RuvK4-^KX3Vj^m3gh@KQ4V(% zTp6D{n;Ah7{(e{Jv!tRsGD^(1+GnO(`i<0 za21|6yb3RwfRunuh$E&GLyn_dl(aBVK^qZ+nN$m zvd$e#A#)PFgQ^Ev`xM(_CzODRp5<_1Dw+UDoK2b>sPStcUuyT40Jf#Bfr@w6wZ9{B0|4at%xiL zdkGduJV-IrECUi*=(lhMGLJ#>jXR+w!P4?#5a!)%JZ-a9C9e97btZYqxHx}|Yb@ho zN`#L3D^j-Ny_*YMKFthVNn zV7rKT7Dj3`A&NvRrg0P$w|bLOY;0X zLqrenKfZ>BK!NF!6oq7gSGR+lYH>*wNzAC^q9WXBgml^>b_9!I)-QJ%Su857z{Zif zDcsx{i5(tGD&d4oE_0IHvZH`@nuu1;{mKV4R%hTdpWQ*y>On&qLnx-v-j$dNBkJUL zbyExgvH@jeC3MI zR#WjNI-w9IJ`vRg|U1|`-Dm+ezv&M+(i4W2va41#KTK$ zaT8&sIu_(?SuQD<#d^u}>HMHu4^LP^rO^~7&C{7of*ij>B^VNi{lyNqK+l1Qxu0ku zj#x2oa}55hxt{TmY;bg5kzGOOrOzVe-fS7)RN<(u>U3b4zLH-#k(BobbnR34bStb{ z3YB?ezc-DhKepMel6u@EiKa!WWTup&b$0jn9;}!wiT=O} zBY4CJvmQSs60VP>(qgMI1oSia%795$I$$!ni5QbC8<3?D&%vTpkQI{0_mPUa=ZNuA zr>h=TTxb8?o&9|~+HlonU(a=2qNgf@QC4LPZrOy^DxabxRgs||x=6L@flE zuM4Mb_pUv?vK<_u!7Ha5BUA?BWMKORZIJ1+NfpI%$}zB*L~ZSsjg%#DW+jfVMIrnG zwFJO#cWFbk;T>j2?~una9=0R>UZv=lQu14s4hyp`=@2~MVZu*lwnUI5Y5YE;u*bx$ zK8Y88Pv=Pq&miJCj4uwQc!Hk@O@V|4rYP2+xYs~Dp}`R-kvOyE)Kn0iq&tyCL8a+2 znK)=H#YBgLRZ+MezZ>d}OGfL`NUGNu5naSCX%%v*s9n&+NhxP`1(B%((M6*9o1~~r zm6RmaMKL>l&ge*?lk%sToNWmLg8-tl;ddkftu2new4RJ=AOq za$ZJGq7f4lk{Hk9B+vi&3SG^jM6yCuVv^?tn|!*HB-U+v(#-b-DOAeDZ~BJLCy#{>oUeg9D^HAc}IaaXE5n^tz%T39GRgS_V_FgON zp&a7!{jH~nUWWz6o{}8&Kn|u6@xlEY7efYfh|v@;CzEB)9{Iyeo*Iu?48pOIGopCQ zBBqCR08%+}x=lmx5AYM_DJ^NG48J%wA5CyHMma#ABD<2Lh#Y5h1egDDq58$I zkavM3mU=XlKp-WHz|*6-M?_1h^LZac{4~OoJVjFCvr4d#NzptoX;EN=^hGqWDBvN5 z5iL<$Nl$9B6-DH|b%Ld=^QjdkN;C?H0y)M#UpXCsYuJNXyjiceyKT461_{l{a2LL1 za|P>(a;Kt%makEQ34+o--|qC_t8aCR+rYNV^y$&QDpF?!d@57`O(W`ZC7)C+qYd*4 z;Y298VQ3X@gp%t=LSY6hHW$_;R%U`x)yQ!p;MkY!gFHnda9F4xo|3F?Ad7)6lr2dL z`@AF)GLo3D8AM!>((f9tFEe-3nW!h?JVCwvBGm2L64Qjn6JdM-$#PGTlBlRmk$hrf zdRK+6E|cI_XzH>VkQ9QMF#(^N#wE1BE$ZBfNXp>}DJK##mRPJ{2Qo7hjbNgJzMw-e zpGpe&Fg8YCj3FjpeDV1cz8Y38wzD5kEU~MYytn#N=2=wVEQyGrGVJ)%d7c)1hvzpC zk?xSTL?-BYxu9OomHIdw7G;P#VHeUXJMSFVT5K#hvx6gq0k?db8}kE>Q5H9XagR9h zDlg=zf*ik!U-7M^EOT0YDq|@=)4~B+pLKy`bHg3TO{I=!bfb#nL;0rYa|Kyx7m{(v zA6t1gP=bP7NQv<1loYSZ(Vqw?1YfOGiVNEKH2Y|QKX2&{B=VPc-Dl$t2^vQz)jB3bhbok8Rr?(VrOH;W z;jSgWn!^S!Yhv3z+^E#s)qjvLJ2)81s+gvwaIrp36RXlh)V@;dQT}o#e{xBdAS(!c zCT8og*gPzY$>wN^fIg{$Rzc{K#Nx&=CbYe+uM2kp?CHi?@HWg*?0m11T0xQIR#GLw zm1HCtIXsACIAuwy97YaT5{r!$w2i!S2S4(Rn*tenyzD3B`!{ksmp`(k2hC%GKYyV_ zl$}&yMWyyIU=9_G{Yjc06FKwt0b&M6^$G@>jQcqrRV)-<@ulY<5El+i@>_i04U=Rg zQZ$@%h||Z0!wt)xJ-fSh9F!S_=wKm z(BKsofIjFO28D!$Goo()8;+>T|4Y-Jwk(56hx>GYyUXCutBjt&YryF^O@6O*BEExqJGr;Tx;gy?}Y2*c32d)}0+)xD~MfpbwiM#E4B* zByPLF*c1^-5PUo_)mG6YC4p7w>8lbK-vB~_xHA&#khA;=0{Z0U+|m3f?l(@*W$sjk zF7gx8I1nPWv@(qFx^X3WLZ7S;B!p4CiF^be?6ze;Ue1;Bn{%TjY_zxS*wKmmSUWoV zcJy}j^z$&5&&5ifw9G2xN|IzM>q?m7NS|jVtsXyJ_8#S&tF zYO*0ElcI&g(5fdst^*RM9RBk9)Dce&f#Ps6)2;|bU>p_3Y{*rmzJ2Zey`A=F4$?HS zSbD!`awsKKL98xn=hYR$D1mfTT3`9|X`CS98g6{gSZ4W54wa;{>gnBc0Ecm8<|DN# zL5LBtFhLOOSVt|DW3gS2kzSJr6C;h)xU+_f;;ItPwy@a)Bh?8ziAw_G*|?3Ok}Qd; zB5t$Nz1c*WDH*`~rexg7_278Z9{XA&3yKM91;tvC4y_5SAgc|2?vATwrb-j|^x7ul z`nH}Pe`$J(#_30rBwb&U#MgP&4f_tQ?~?WvRGR>LUc52cbA?Kpl;7pk))pF0^uc5- z$Q>s;4cyn;v!_pfH#2^R?g?aF8;K~gr6B!#g^K6|u?v79AsLnHTd>V!1i4(@py*(jUL}TegFbt#VfL(Z{)mgt;)w%imNcZ_P+3gQ1w|92_@`t{ znPUcj4?00bsg|Rc@V*0BN7R>Z=T|5-()oQ07lO2A>y!UM)K*wawE2gQKz>cwSR#8@ ztbkP|@-$aMYG!l-OBe}lK}OZbGN`p8Z13)6Qjd*?K|)?gB_UczX^WjfqzSnhoQ<^y z-BD+~TyAh;!k%oapyu$FTxFsfXfDORSRA1uZuHFY=pq&-VrI%MH4?@7OI%zp16~o! zruc-zz6Be783qA#!#Wy1n3SV>w#=j9^xYpGun=hUQD7y(qp;q9WFa$q?7yo^>tpqT6Xt!O%B>0D%i>cMN`Ko z(cQ}qw!8K#@RL`5VVAp=J+i<037Fisf&VS7%mG;@;n%WUAF*GrgVEF8$;x5JPmzth zVe{H*L4QZB2qs145Z|(@Y^d8&6M<5j@S3dTaRBMqD`njfQlZ4H_#+W=!MKggA&zRt zC8Y*kn{&uZz700p>+8fKPc%L>TBHn%?VYWONECyd^|@#i3z;GpX~jW#v6jW{C0pXx z;GUN>^vLi?D{T!%3Yse&O;KQXPyy3}c|dmb9_;DggBCV8mB-mfITen(`U?5u{?MjH zjl1$aKQ%U#pUm}m0)AgjZg@!$_yfzTn-wjw5u$Y1PP#0OCq-itDnMEaFI#C6vo=lB z;ZLp{bn&=E2oK+_IUFzBqxcZmo?dl^j}^xFCg)`MRrSVJkD>>Xx4s^Hq|%37{^_Z4 z-Z1B+fe+=;pd$qoaWwuMad})O7bEi9#78}*dEtNLtTaC4Eb=t;1gRfB(@^~NEF|Pe z*#%)Plfb1ze=$*10vra&uVAv+gdr0E4bgv1Z)Y2Ck*C_UxVD{!MPw?cPUwm?v zR;nLpI6C9NsG5$3WaoGwx? zOBLUDE1fx!pt}leKPvL|Ir_#ZDPg}fQf;_tw!0IH1n42;#Ca4+HM$cYnHiU*?xa}~ zB4W9ChbCw2b|V&DGy-%==q>SCCa&AUaM{$<@GCtVuWVNNf%*7dot6#IcXZQ+(frim zLStX!L=&m4o3~iHr)+L%jVY*yMeGXZTbuEUalBjmB_rElhpdDpnpBl44oobn{{T{a@+)99rh6#)h_}I5}EKR(nG;T@0dm3tKNm1B3 zEJ-UHJ|<>mR2qMUOy46cMLt0iuPvCCO`BS;+_-hirYjp7HaE9`*eXTV(%igd(GO@jd12{60p`_@6c?0a8CWX4Zr;HFMe6OV#z79 z^4wMQFBZzcfLU7y+G3&AuD&Gy&4Gsc>|+h}lrark|JcU#-ns{Ft9#H$m^#qv9>~1- zk zeo?(yyXcg;WOeaP?eiWPEZ%Qke}ERB+?Cn*_|4jHof;VU z*1)P_zIbnY%@^)5ztc1SvB~<|%$$qwxv*~8J*I0p?HnxLu(zRTR=;B))7&ud6N&wP z=u;N9)nhnGtk*F2Wl`2ELS zNozSvS(q!bs2NgTk1eaO`{Qb5UiV;)q<6MDfjR?SnWDKodn$9K)m1l(uC1sm4W~?r zQgc=;J@w7v_Tn2PeYC$gu)25!T)udp(B6SG-#_rp;y(_oDXq`fKDJhC>@OdW>#VJR zFDaTU<~_W+w7s~pSSvL>gB*|R-xCksd6G3Gdyg&cXFQfIW$!arocVC3_=@%)ohlSx zZ?+$N6>`lqu06GJ;8L4w>%Mb});5%~zn3qXSFM6gwX17hC+S@Kx2J}Re|EuwYkqHW z)3T2nv*8Tj+4p>T`RdZ^chx?d@np9B;BnJvPHi5@G|V~qL{x4k@2{0QpE-3~(L9#X zmSF3-c`#dVN-u5CoHDEK8(5x?+uM&HG_TIw!}x1gtU_I1ReW9h3e@!vnBQH#waEHp z-uU`mTL%V<_Z~EjXFdFZ_PSGp#XpdikU5nBFSEt91=E1KvH5Fg8Naaga^3^CwVq*2 zt>IHE-A-m()|hkS9tf5CKkpL!yC1I3{{!a% z;r}82pE3VA2z_og&#rR;7p}8I>p?dQKTUPRB-bvym0AyzUbpb`pk!~Nf8oMw=pVfc z{>9LG6fpabB#nI--ZSf^wE^~s|A_mLsU@$&s;bsey=^%$%7vr;HlR3bC z`t14mcSD^qhrwHt>B)4MvzLN23eufI>dka4$?VNEgIP0;0QDN+^%`KiIeVQ3IH>`) zO8|4uRiM8NiZm$fp9hIE|CvTV&lybvGAEt@;~a=W*4ohw!S_-yCwT>q6G{aU%m}F~;4&xnJMj_5cLcO^T=J}u=FFc#Bs0OB<+BVfbK(^) z*aTx?DW6+{5KVa)&YXFK@f>x5E&wTW;;&qwql{|-90MI?piUs?-;aMbOs3Z?eI=uP zA(fpgq31)RBG~P|t>tc~b_&vmw0fS)kv? z%CKx0|2{1z;uf0?w$C1o*#t`iBG!giNA z@lzLcU53qMF3^jmr@2A|uOnVIne{ShECFkfj;ABTj!J4bTl+Fr6c+a~7S9*pIi~|2 zS3hUqU%8plcR|>->u1l^Th>>wInaK5TvTSbwauzz&zyBFL zj}Sq<_!dj;TR`f?tZy^o>^vlrX=lcr-3!lR3~7&pvn11(*~Hd})UKWcgN63$0dVHl zQqkPn48opA!!LR^YsLPIvvv_^nG?-mORd^3MbQY=qZ|!-^+skKAthFmB%Tce6G_&se zAdSI639*53u)a|;X}s*von`0I%h$4(S?iloqu*_ z@%fk+tuYH0T)lwVo?U9Pi>_Mm%mrQNAO%WCm6~%FM4+93ta;~UE?eGpP6pn(Ifj%o zn9cLg$z&HTSU?42EjZI;>#Vk|2)z)fDkpkoW9He*ErGhu&McX`ecA7}FK5U_bG&E` zEIezIS44F2d_~Vjj-36n+cQX1ix{)y<+o={&9Yawqp_dk7-*YNr-m^6d6$aGOJf5P z(Vrhh4^7LU$uJ6ImRE+k*P46*vxK%^xB%uXnM-dy?A8=B-iv(TITa~hp(f7hI)|bc zYl;{+Sf1-*MGfV;5eT#`v}-8)?!5Nc?&%9EX4ow z;2=w2W&4Gt|4@C&CE(DQ3{IKFa1bD<7jHiS$LUI0=^RZD!MR?5zNK(bLV*0K64J)9 zm%xSG`<4)LZya*3PadRghiv1dkTuGQBTmN0!LicXC{7o0?^{C1y>ZB7oKdFPB=;wi zjOhHsB7hkLYsK47z&Tx|MOJoikli241{;FFKIrj}4K7jHwDl8gg@XYEQ{wF>n1*{& z1FVJ{2v$k3y#!Xn4Y7t`7Wl^6&`V%7>?c?PmodErR>S^SL$5DTRxQq3P@(Z(9+H~j z=9n4Ny5=qPJ`*lu_Ts-h&%%Ejs7EORSbSRkHVgU*C=4or_4d2qmAPT9-b=7Sg7pzl z3uX7dCFt85D+w9GdS~PI$pOV&1P2=k8sKci^l>x*gMbBJX%Q77-hzVTt>xr7*lQdk+K^T&tdjDYs_QnFiGK4a}e%y67Zi1`C z+fNXBLHe$-41#Onl3B`WAJdBj5Lj7XRLo^t?umM}*aje|7w;?`qH6**W^yrwF-Rby zM7GPc)ASJ7x+eXI)!IX_MZ)wGY!hz}!5x-La5r2sO&}PncW=OEGnzF*XgY>uO6mi_L*qi1nqDn6CM)(jKJIA&l*g|>7mgS0+6Q{|DOwoVz2~j zE3HF@-3V}-czwyRV0XgRnCZoYELj95V6RYPUWotUVFdx3AkjctvS$1#4u7w(TXi`+s_5;nBe#^5QB2hQl43xQ-F_e|( zL-=1KKCf092T4pl9|u=hR7PidS@-#{S@2nBfeah;b|}79;WC9zpTnOF?%q#tjYXr(U}Hs=G04{^?*$bh#mUT8GH&COoC5|O%wR_ z!*Y4lJgI$?qxosvOF9PgtWg`bBEF#__Y9k6%2Q68!NDhNQ8x}T3(C{OxL2UD$Qo$L zMRWjWOpY>uj4FwpZEXBI|1gqb{TS<|+GamxG7YP*TfO_b*6S}`xvFK`%9;!^*>S%L zZcS}O_`1ogY)Q&|3o>v^>eCRy=_}U z{*Fwhp@q7(Z#%eRW0Ln8@U}Iz9J+-3b^Nzx+a(rm-`2Wv^>tToyZBJc$_=dvjh}ED z=QhsW-n^o@scA#^%8Q$_GmY7W4T)qwlF6)YrCLZf9lYj>?EHp=rq|RUTb|u{X@dBs znpEb!rJB@xA+=`Bb!!f`tZF*A`l6LhO{=#xCG>m-600ThhPmyBle}+aGL3CbExVQ7 zbg=1)?1IMDEpL&WLd~eHfypmvZd$dnW=>R&e@#=?Cv*L)h-c-hrsgE|A3$x|M*SPN zl?3i?I=Fu0wrsg^U3RI>hF#tJ8g?|GB{Xap!}TZQr6G7&eYc_d9^E`$06IN0Uf6c5 zjFSh%MsW51^aeD%ZRLrPX|jv>Z3QwWXSN+3nIvVjykQu>;eegzZHLEa8a5n0JPe6F z<%SI-g=0gwjT$i#nPhZ0CV(b8yg@FZBegWntDw=+$4b-Nwrm20UrrZ>H=rAs0>(2& z8}z^(<=r`hn0B;O#_9gi()96d#S+@uIOHavZ^H;KvMy}UV=N$!Pi$aI8$yysOL_ie zu4&qb&uhy~9aGos-qX}kC?A=gm~85qn&8*X<)%UWHtP6cbPMR9N~6O~^55_Wr_Ie} zUTIf8!mH1RZM(+dB2zAc+`ug({=RN*TAR6G@{<`ntu%RDbmW*AV^1{6ukrE_m7vC+ z425>RS8fu&!Z0zT7u*>+p~fRbR#?>Vv}%L=W8^s;H`#HWL1Z{MVm$d4e3??9(LApQ zz*8kS`eY56!HwC>`UYk_xi)Sp8JoZ_mxF?XAWSwcU5Q0Q)LsQ`ki%YLTY@}T#yyz$ zeGjOUbl4nAh=9d?EoVo$SQ?o&IEKKpUq()yL1J>ITtqhF*NsE^E3_a($7e=I8JW-0 z$q6KwUkQWAqhSEgFHB7kf~7_2a|Ki>=`d(WA8to8bnsMCz;A}iPro0zzBJy4awnA; z4}h_Z7rkq?nO!?}T-C4^E%9pB*0xgW!lLu>MoZHut*3FYTsDnU zh0#V58&ONyA2hc0Uf&2jKbRy_&a&`>3YDx#g>7rq^(b#vWwVDxPaw8dvB9yN4bqOQ z#Bb@<dz9GNff?PbYA*W}eKG z0);E6;mJZ06WHUz)-%OX<5T#lJkI@A4G?iWI&+ zrEh(T-U~$6#0!Q{ToyK%_)3KN*|Y#!;{6vOtSuL z4NUm5*iuN==c`iuXQuevl?qQ53-(FXm`gf)HT`Bz9ls>*)gePlur}XU(O!%^D!ay?@j63 zEAlV(Qrrm$Pd2&pg82GV`ul@0d|9lcC(F;TtBYLL+>nw#kkZFDoA6|@4U*J%C@|s6 zn&+hO=ce>=ha@~%b7M;1je!YY)(oWZd`e$F#UD!Hg%m!L!iy>VrW8J!!pBqiq}UTi ziJMdWG(M5ymt_RvD9km3C0G+(8c9%Z+#?f@drab&r{uQ-r@r}cOKQ$QjSUawnL~lU z$S}pk`L4XAW{GZX+anH3a319a%ICVml9~(6?TYh#c}dO1=H-g76MT)iS8=W#EUCHN zycN(rjQ>3j0VIABj`6c)FR5uXA5olZ2TN);n$IZCcm5?cTjkVkuz#ERa)RG(9#i~U zk>6z=2XqhP`yO0K?{4!W#{?w*=gPkua7oQxJz)+65BUobnBf<}EveaWmMhMgz>=Cn z=5oc^a+cJfKD+&dHPdDdR^RL!yWK)?t9EbA* z_?nSiV~rLL!%Ux|@ywoz{BoQ<9W?(|*iZ%UTo>>7Fv8A3z84yoqnS0-1H1|!CC3~IQ(LZ60d`o@v|OyJ6z)gpWgX* zS^0IYk%GRJ^p_dw+2*tH;91vbA@#BydAge(fKF59zrxC`yE4d2{EmLL(p`GDYks^` z!?BU^ar~WXzYEVs!^iQ_c}O~upX`@tx7hb;gOMG$OJ5HVKCqMh!u;0=X4bjQZqTnH z{T?GDy>%I|wE?DzlWzRSGcy9{wh*fXw-91D;RghSJ<8vwu&D4Zg>O*E)9lpq8A90g2;qEV{!Zb)DE()I zXcyM`G=G~Oo)EtR^`7~>90`y^$Opq@Pi8fkPv!5sraV}q33@o{0D{e=2^KV zgafdH5O%dF{aJ(sWA-WikkW5acsn8br8g@7txCUN@so;wRPoO#{IbHY6C(T%75_KI zYtRvs&W}0>*DBmah;$uLIHvIB3g4*kL4}Vh{1=61pJBtJ8|c&5e7?dLE4)+T?-C;NH!6I) z!gnb=sqjMzKdSKK3LjSZ*9yO?@G*toRro!H|Eloc6!I%B_G4!$T&nN_g=-Y9RoJ9( zqeAJo5uV?!P>=NAfc=W!sBlnWN#U46eh0?>@g)jhu8&p-|=vkUvAm>oXPdLp;W}TH!i{jS4p_yi(zIg&hj7Q@BUr zeuXmcfZn{~1%>?9kMX@g;q40VQus=R_b7aW!Z#_D`3b_mSMdiFKB(|x3O}WgpA#~^ zFDm?&!tW@2Lg5b;@)JYK%X|j#EXB`Jc!9zd3i+X6%>ce&Rd}VsZ3=fOyiQ@S!u<;Q z`5@;-qYBFkWnKh2KMdr&<>d-rt?+dU->p#QNs#-X;twh0hl33NS%nWP{A-2$kdXZE zD11Vp%%ec(H*Vz5Q^@ZLiC>@)*=A}m8Cgt-y2kYez9%&hg1DCOJo_03=OKKL=QzHd zaE*O0<#>oDCF8&WLiC#hgy^S=gy^3p2|J8AMtCjS8zBO{lo0LdRfH(7*Aot4o=u4S zdk-P(Z3wI*gq>X4AY4p{e|!%oTt*1H>lHQ-!hV=6a4jLyA@e!FX5wIOQn-~6 z>3WvJ?SvS|Iuu?*h;(A9Kwu9c(%Y}_03p)-T!jOK2t2H?NQitGRX9lqCDRIz5h7o1 zRd^dA^5+hPFC`q%^Z0G>rg(s3cjKiJ<# zIDqRG2x0FF31R2Cv=fP5MhH8b72iY%dnLcYm;8p^1Im~Dg#BPic*!rM<5h}Fejq*X zQT+XcNY^J6|5HMw@2iSGMu>9$x#EWTf%MiBB9aC|q0cXsFPX!{07UpFZ&&6tAj4A^9|!y4kK?@?@uHeZyy#Lzj^Ta> zE=~vQ8>**&oIQNMi}js=K89yHNN2pn?}Urf@lxOm;oRfwdnX8SI$jH$;i-#{lY1Nd zalHR8;#~$B?tB-{$|*?-QS9{`Q@{biKTT;q27=BPdw?(>l@dKnj=l~&HD z;}mF22X*mr>EJqL9Pgu1I?hu$hTEa>x^yu8ED!fMd#+SDhd<#26oM_!ek6S^nY17 zpAO2=9_r%b((yUa<8+)G#k)%77>?@&)a~+_EJp^oQ~a5yc}CxyzkI>T{`{&`Z`3D z{pa-EnbP-M=yT?4>qH+w! zbrDUB(EpYb$mFMAeAQz|O z)+ilYRF2_xT75np!_Zf)pXB~Wtncn99a|%P&r*HP{9ECvHm)ADa=tvcZbo~ki;qjk zzEr%gMZC0c2JV?E$8cO%ip%3w&{u6-<^57|I^G|pgL50kOMQ2!K9`OYv!vs#R?es6 zJ(>>c;^WeBA{Fn4qI7ImImY`1jn~yHt`k-(j}NEx{biJn_DCPs&6qDxBM;vbs+9-# zmEwB!DCB4lb@6fOcq|p~qft6KRgU47B0yXoUxmJFsYoB7^875N@1LNr0h}2)&Rt!3 zEL43i+@%N?Ka7jdWme9Y2iH4k4|VaOK0d4AiR-~aG>XNbGhW(BIfgrA_4)SE41Lw+ zLszHt)k7b{Q{Qelr;qD~wAH1fdzN&JS~;H%uD?#~$!0$8c}8 z`g}SLK;PY7X3#p)Nku$L9m^#OdgW z;_U~Yat!yV)#uakPtfP)x?uZ!{jAD4`+ho$egA0XynS3RW<2|;3=iYw^Ef=QeY{`5 z)t3X{Q;y-5%t_Y!S}@!k7Hn@HE;CBh1Gbm=arw92%6a>iL5}g@RaG7rjQgsweZ!G` z&xIuA7>?_&)b0A01~6#9dt82TUpCe^9qGFf!cO0i>T}_^z8ya<9d}qcpAO2=9_r%b zf^j`Kj`xlz-n_~&+&eX1hUIe`6l`HYeO$b6OX+(p^lb-??Q#f?@lxLdDSZ!}Y0ngZ zC6CkhCn>phRD#Q?Kp!Xf@l?Eza99D#!JV0oH9VC@9$FjZtX`kNia`xgR#z_Qo)LC_{I?%8|yWcBO^xKV|rEf8Y6u zQ;ug&+{66ia~b5~bUYUW$94o{I&Ow@`Mec!Fnf|=_^e%xIILIxySUB<7A4R0LGBua zb&r!HjLb17F2`CL3^@w=3*ZsybB-xj9?Jm($d9p%5uecR0~ty>%TJoSCs zb!~_UpBLiQ5zktj>g_i_!F}6DN{j0k)}LSh`dwJwJ=HMqUb!XtNb!~C&C53x&HB1i z4aF<#ufR>fW^K)>OD`HO{_yeU`f&gAj~~3-yrXVTy?MfBTA?_A_Ytg(R^BUg$`!aL$vIWJVfrSIO)%EerGydUmxsmvd z;{*2({P>S)>HYH_z@6CH6&K+S;oJ9{hTGehow{vhmpN-q!zC9SGwT+eS~7RZ()l~? zt=qr-((NC(@QJpi^;0`CEx&B(*`C?>e;&^+Jh1(jkK5a_Po8`q?wJ0QVr{*-;=G6N zESlow_Gam|*)NyOd)pU$dER3_G4z{c9FO&ZYlP7PRUtjm2-oK5Tn|ZT( z^*gwqc+jlA^W=hov+A?&t*y7WKhG_q?ljIhwWXN3@9KeU@q&THk1cGFTCjE@?s?AM zw{svnaQnbo+^F49pV_!tav;;dTd0v7!~3VVJ~+SLtgMwh%i;#@Gm-Z-1Iy|!l5|M8 zXWDRU>kV!QkMG@v<*Uw-kkxHo{NTd+bD-VUW_uGi?`c1QMs53_+RReek*PxqU*}pf zEyLsPmzITWcfYh;|CpKk0`wfUnYwO*nmOER!2QyX0?WP|{_J`lmcdoiJX3+Irhl7a zweuzsNp0<%8enqO^gZNe=03q-yg;_LiF1s(TnJh?XZ)|=pSKP{=1ja8UNi4&^iPsp zJC84+bEaMmf1RnT<&tKW=Pl-x#mggpbB=$9+}eM}|1&P30MyR+|G+r|gauhHyU%&y zdH7#fdm;XxL8Z(Jku`Jqy0C1{Z}D`>yql@_#p@wp<}INAPLgZqy%GQCyp;61dAHNb zyP5ul^LXTC&MUtT|6*(L@5~3~T*P!IU|sDOz{&F5-JDl3#)Xf-n`z6?g3MPzI1`t& zw25z#TsGU8DTB3W++=oUo=@LVli6iyxRmvp43i19JlS&A%i&$jvx}KO&0Gd>_Gl4a z`j)(z(fk?BJ%@`yOFl&W6t5jN=UU`%B#ltT&7-r3oCjwzw==zbo&|^dw-ID1_1;b& zpYyp3l)3#c@t>j2XZdAb!d&N+ZyAd%bH^k2e+SUz__Y>X+|0b-;iu)2M#<9m0lk2e z><>ZoLR=Pm3-)EWaB^X0Fa5CW&%rs1=GE0Qzs};ni&jzpJK?i8Rh@W0q89_-$%KCf z^z$XL?_^?s2z1#vG-TezWU&fZi{3?xc&up|t6WCV=aGxA+~3V)-AdjE@z0_x{uQmD zvnfp=$g&~w9%3XPgU?*dzH0z&j`I#CXBxBy&}Kk;yU=<;L*g>cWMc?!=m+~Au+7SQ zsRB<2T;>FiS*~IuW5r#~!>?uyTg;k2=f8*X?-Itw%n~tfA9>29ls_MoOBsYGUoT}a z9zD90L0=3Hp35GGpU+mf%!#)#${&FA0N88(9iB_(gTb5-GIszyd33?vL1l9&NesYbz})>aVfh;?j> zRxMV&wY}Kl&^pw%(5o%2)?)RwRy)|q+SXg&?|1EWhUf4^y`SH`?;pSS-JhI%_u6~y zwfA0oIQ#79oVBs8lnMJHBp=@wA=#*@8CQsZY})aBktz>Cg)>3@6ohI9l$p2`5zbI4 z#(L1s{v~NBF#Fn2>CV#;KdAzVK(9tr9qC__&T%$_z6Nv=4qqXCDFkr$Vlvuqn8RZ8 zU7pF(`-VGg?6*Nrk;b<4AQX87E6F9(kUomr*059}3 z1e81t>CSTYK)Oa;&i=7jk>$v6Sk5_NIWo-Qbm1)LbkPOU4u=&?#s(OZg>d$v??EI= z;4Cv^MvxUjZ%EJ@XPMuF*ue@k!TUBrETi0v;Ubv5Dht_bH3~VFDP^Ry20S7HtK}ms z%qBz`_H1YWUZjwrw239+OSl{kV#eP=2E#EaZJ{b*k5Jv zG2%Z-%1rkf3pNqOE|aGH6(^&%}k@nL-B%z2&K+5}Q&2Nvf+$YPQ9o|TRw zA)RVx3R!$DyCjHr+*7Hp$R&WawOuJSRzU9fum? zi#bz7LotU%`~_(#VoU}HZGBIcx!Ka$D24P!mbo6XBWmRA<~MmEn><|5X~k48e*{A> z#O3U#wP-2cNm9H#h@ZqwdN6T-Re+Wj<0u#j>*1Ip*YKa1e20o`vrXH}s?QU-d~9*{ z&xOWB?mUsZ(U&_mq+z5jH+Z0Rha zKQ>)9n3vM;%;1eFee|V}#*vjN{d(p<5y&781v^WylV$G0KQrt5Op#~j4fFral6A7B z>R!pFsWUt~*S!Nf*LWq5cCP!3M?tcDW5#00IU&}r`vw-AF?k0jmT}*;_NMz6!#Xz2 zVNV!tQw-1)Vp4lxU}_m_jy?|UM-T3U3J(dAc~-L3u#c{^dPM$<-iUNKB%C)=e?Gi8!% z{&aX~NxFa@+~}+{+~`QNToZ!Cnq#4t4Q3536ttdHD7*$K_Py2a^(2r~w33s9wqOoZ zR4*D^?Ah%u@f%f)TPIbZG#r-{Qx?)PZst>c#uH6^PYcH-37H-Up>k&Uj3G1IGi_kl z%=WA>pKnncGlfwbp>xE$j=&q(iDo^qod(|3gt6jXOYnG;O{QAjH3Td7w6NU3@-e3e z{-%yH;J-KuwQ0CK5SPGz8?@dN6G}i9nV_t>?lVBbLMY)ZTqo88U5WJ|cnm?|x#Hvx z)sRoH!nj}($NR=ITrf&XsKN#7rg5U&*5n;F5VpAd0ST5|2_7e-=n}YC(U>W{ooMqp z4L)(aT{9T@5LnD~+FphwXn4i(PDIHWrZXe`(Cy99}Jyu z8Sq~mgUWG*G|Zss611AY<)v%RyX1CyZ2Ov@XtRaviWU1AQ z&BQ0fQ^&QN2@6Kt?y+TJ+idE%?Gh%U^dCD6N=9JrP!M4@uH=ewMRFo90>ur+e_JlU z+l@d_0#~T?ywlD|4gw|bc%TSOz#fVs5Z2>LE&>9SS1eas-qXUoLAN9CU|g^#Ot8G` z!@R+mA+PQ4H3VkNPRL-opj_*0047X$X5m6Nm;>NGHoWBk_6T_KUtB5vTgEj6GShl* zkZ29lmTNG;cUaOukeKG*Al~(aMqDQ<1+x}-R}(DnX<^<#DQrKT90+S9*;;~4R!y*8 zYRY$^NsSdk0}s*W$-mc<&VOJs&I|X!G{h@pbim=|Kg}+jnxo=82*Eczy?Xq zj~rO3kb%IwPGqo(TurdNYr?#Na@fIjl*8vcJGoU8R^dY32`u)BS=r=bci-}!7Um7I zLSkd(t|3qu>{xSB5;qM0IaE+Bf)(X!v=~7ZHkPmiS4_6z;ZbM%Lp8xRM-S~q_KY!r1DVBM4S*O;~O)N9+UxJ0VN#InKUxUc+(h)6KTv|6a;L zOGl;Bc@o%P={zlZ@vJr-OB{CpC-dXG88LGkR=^)&lv;jJ`Dmlh|7VO+|F_tkF4=~I zZDCLMqbu}@tyl*(Pg5AmHu_r>`W~!P1SYO)Y38;A_N$?Ogu@c7wPkJDw-`KahD~2% zUsgJ$i&JdMW>p z;lC2!Ct+lYFPT?jW40ySzQwQr zJ#Tul=x2?Sfb4l?Re59bR_4tst;$;od)MW$^pF;4$-97(r-o}Ub>H+QP$Fm z(lL3^Ye}gZAX*+#K3t!3uG zJhN|yI%=2N%gZM9Z7)M2ZT(C6;csk30Zi4hg*D4+m#o+$o;)w)RO)Z-{w-{d+Nv5W8#9ghm zOD*QVlj8gmZlqallu1qI(44mvGni$i`X%xomZe$arsk&3CTsGVwxw5fZL1J9%*c8wr_3P-b6nWTK(I0M#uR$d)T?5#RJz4Q9IFzP(0T# zsq80nE$TV0Z(vK>w^JRCmF#f&xJHVWFD##Hqj28d8VSL&p7PdG zr0K6v``+O^xXwzlIbD%mm?DpqHp7`;Dx2Y4qj@&H7jm`!KWS?^^`sv)s@elr3hSyL z!6~*|r3>m563rzkE`{u*_=rVW#Ccs^tf|^)-#~UW+AB-ae3YU*$?>VnbRv%@T_(t2 z9!McS%8@#UR9s#jsVs$~wi29Lnjhtfkh?{S!rAcDLV8LQ%qcxILxjOAgFi2&C`S;N zx-7}@o~lDlS#YTDar4{8fVCJEvV_XN|@ zXn)&fB(jI1$vw(vur`dhwrpyJO?t71{C~X-WX{icmXaOOnE!;00Ju~(k;mF7{f{5k zLN1j}Wd06D`MgiYWD_GuKpV+nN1MpW^22v4mgm226FFI4^3Fgio5*D-5X;N^axCd> zYvv!mTaq3UDesVQbr64|jpT(Y-)@%XMEJS87&sSuLCNLkW?$fF6Pdd{fy)(s>e{;S zU7Y3RR$|~>{J@YbpT9H&&NX=v`FTMke6Gol&;=2B1(Epi5qaYy@e?9+VMJbGB)%vj zj|+*wxp(o2q?5{WN~$S;Y+v$q7!#ZFbSJa1>p^0@fzBDuY$2Z`Zx z<(GsY$i)_TvOMmE2hKGoMdY0nM8fA{gFQJtH_Zd*V$>(c&kZ8sbMcEza(Vd+P2gNp z9uV-kW?@7gdwbwqvnU|oqYdP+b7fOD2yx{nt}wkKAmF1-%*l>VBc z*kA*{*j@wj+cT#ByQ0`i11&bvke;t%#tN~AM15RGo?-T1J2(iMtg+Z8n5sA2e8MSfsGdb47SV!Ps{inKvOzAq@! z)(B~Sc)@vJ?sLFHN*`8yMv?ENlTU220bf)4Eydp|%KZ@WVzUj%FEf~KpdvrZAU#fz zUt4hgo~~cX;0hW+?JA8q$Ll`E599S$6=ZC_P<~-*7XYUx5&- z6l)YuQ{-nMjF)u@@I0lv6!{4U@3)^(+@pBC;;o9eEAkT$@{8?N;31_CD?X$6eMNo( zLVj7t0N+yjw~G8Egz>VD0rHa&(gPLw4F~V{;}j<=mMZd_4#qE0JVkM}BEQw(eSNcH zi(C4%7Q% zf{6LJkcjzF)&rO)&_psG%ZZ4D24iH5k!GvAra$U)-6COCj#+EE#;H)V*Je|4J;?3oRx|!lJrkS zsRzovmNZc6gYut68dyg}qDDozFQYy`;QbZ#7!w1c+%-g$yN!tQK1du38$?8uPoB?E zo}rwVQJx|q3VQ|-`Cd${(E9}P6Md{#eIP%nA84r`@|ALemU1HhPL>b!4&qR?9SZt- z(kRa(8vhs(<$6)+V?>niU8Vm*L^%!XhxBnG$~#QyT;gn$L+QCh>QCtnMASppKS)k0gXT#pU5YL>s70T$GP-bQ5r8;QBZ|6jkJLe9%$eT=Cg|UcT&i zSZbSc8*JVxw({43W*_Ip{Hk!V3|_i6_`}XC-*yDT@7r=AAJbC~ormr4hx2_G`SwQ` z^Tkm2^F0JVWqb8te_$W+oL8Rx2nfqFCB`HWMtKbP>hX2>DbGvyBK%>;IJzI>g5R$P z`B)FiqVwwUL-@n_CXlaJ56%f*zVE|N*n#Dl5+~Um<7=3*UL=V|Z9zc}U*CkUTzL;Lq1{9f^?h z$W4~duLt>956YtR>d}DkaK6={e1|9>)7@|7`SsxQ3&(=zym~}!UDiP!)3d+i;PUix zm&)_f@%bg}Jn~t~=hx#fXv(83IEunhw8P>~}@3T_2*Iy{Vk%H8D^4^Zf z+W~oOH`XH;mnV;3G*X^dkDhEH^6U)o`StK@AyO8dm+wIEh3j!JR1f~@=;gaSQjh7N zr-~%|52QGLj2V`981jZ8hV{t9<;h#1^1O7LJda4Rb)@%9%jef)3uv|nWzl){I1S<9 ze2<0dQJ{QG_h~E7Zx7xVJsFe-QXKa~!+P%YA~c?Hbk|!xzkK9lKI0`eki7@t;qtu| zDqkUZJ-r;Y^8E7c1U*<~5kQLL^J!S#`;fiskNw)K$2QH^tH%eBm#W{N8j)8Xst51c zp1h4J&ntd0=&ro1t^`I;|uO6R9cvycMLiL!Xd`!pZ_i%e~Um@HNyz=n* zKP+zxrX-Iyz;yek#|+79`nJ=d?}B{W+=}~w*_?AF^-OB$As%aKBlKEIt$9yjxXXDTTr9!3~vrSe|2EyuKXayFQWJPd&b`DW8}A9`J>oSN5k;@O68U zNZ=LWJMe_-F}pm_%WCCgf8m)zP=l}9g0c8*65*cnMB@?8e@0>4so*>AWd_>gBYIy4zEgO*krMkO2!?w!$Ke}sYJeM5Z z!g2S`{$owvzD0L}FOfUgT8TscbhJ@68}{A$!@gVHaOOOC#vS=*n%gS=b~HctgK5W_ z85Xu~hu_p=pij+n{rQD<7ev4hIZ zK64ApJ$d-+TVM~bB>PD0W;3x5Ec}^C@uPVwF07nW*Qd@sesW#@)v;R!)n(plCXG9C zH)1o6j#!a-^M#d}b$xCzMI(<4svCYh^X5Lc^r~nL!{6XbNdy8|EDH?v{ z?wvnNkH7S;l=-eLe`+-OccaekarailPwIWd*2CQV!3^i7dmEkO<~V*hg@w4oOS++p zMk)l3w&Hrh2A$dG>~j*sb4Q5ovmfu3qP==O+6PwOu%ofp+3QFzNzFG4?V6Qqu5M{O_bdnA_o!PI@tYnt~} zq#x-w)|ob_eDK(sMZ-2wH>qvidAb>v>*Rg3ZlIS0^s~p=y%Gd+L4vEvM~3e%G@mtxg+Xq zkDvWG*SDOz=plX7k)_0P87zExhuQPMU{s|y9WJ^b21(08E4s!%C@D4 z`O}s-+DyFUQM{CvX8Oj8;zutoTzrfrSaO__@>SA;;~NWy9&>XSo@^5FNwbd)la_X; zr}xe>BO$Tm_z3);EdM7S9}fTc{mT-zGyxu&Go(XlJi zzcwj*c5Zo|omJzQ7h*?8qwMj0ra0qh?utoiLmwR3w=~2tY(-wKv+u&nNxA06*bQkn zQL6pFaWraqG(LIg&(dx(;}(s{9X?0;{(+ZE+HxoNj1Xt}lU2d~6e-d4%^?!|w6_#xY4 zGB2zvpZ_}VMPK!9!>pdkc+|;_p?z7B45UeCSc*CDZ?Hw$7k2_{t2I74|46Jje$-5f z$=FNVG8QvTP4k}SetFKcKIJuyxYHipkn5E1ZRAYz#xPsXDQV8F88=PoJ2Sm_(S*8< zb&1Q~4B2+=_sF}CUU@L?UiQ=QD;+|EVUxGVO)~&Zyj6d>K^XCn?zf2l) z#Eya3txpbj_n7N$sp$W+A=7&Q*xX`n#{F;Vkh0iyR=ciRN9}t&o_l<_bF+Jkgx~JW zcZNjyos6^XtH7 zZJXAQ^Uf#nuUd$8VfErwH8oYi_eS=u(8Q+tt<7ESO@`lnc5ZELNpx&!?P_jJw6u06 zw$yKLN;EVzwIulMVN;`NtMBM&YE0B8TDqE>6K(bF_1o~pW4rNQNljo?*xGJd@g?S_ z=GOB~^VWvKaa|KldsBT!Ym0b=W6rqJ**oTp>#%=jTyvL4G{Tb!dE4uow>Bn_zP-Nv zf<$5IMAOxBZcFR=Enb-ExS#{yIQnD*J`(NPmT1R^n)sx?!>p-U7!Z|PH*MP5G-X*+ zbMvBZz7X)GW+O-u~Hgs*;)YKjXw>F&9w6Qa>wXvzCb1Q^}qN*34 z67W@q^W9K9qx7W2#-?^A*;wD%6!0yqSyfz?XlmKmijVF$2jLrATQ+Uo+|^z$jj?HK zb12Qm)@|F+LeR>__6yoNTZ2@n*w(gAR0S3s(Pq9D(Bc76vHaA4s9w3KW>zveJ0Lf( z-0P&m0LGAb#x}Y4%%TBZEf3vLIeTJR#q+vk?T4T+t{=T{h%=vZ1*G| z!f^gBu9tAVf$J~09L%PCuV)IbN?f(L_&d}ExUR>=y>9Lc{|eVXaP`8Ce=x3mT(tPN z2p9K3&&72CF21v}57%9|4&tJP;2+^Sj*DjoXW+-GIP%4RhwlqH`$0W|h&lM;p;=e))ED(Pe3Db_!-&{Qoy9eh;(_f zXne}q^xlZ_$4lDieVokCaCgi7GQ^|}+yie${2L6o73E1^^ftYHQR`lXH`4n6wX*P^ z@TTl3vsMZH8BkgEtOYtajQ?RAFt#ISY|Ev$oA-oGYA}we2RO zSr{{G&o>#{=*{T;P5y5=4ga%xkEPsJ`m-}@8#bAYHvT->zxP4%oJam)y;rhGom4?? z@2{l6-&Ku}L~nMKjP0%P7xW&1A5=5W|2+JKy=ihYW5;9gPwqX1{1;JXX=ZH~O7>}% zY&QHT+QpPVxAzRDy_8*}y!X4T+hsq5e^F*_bA!paoM|h2KLSN&Tt)t>-jAcQ8J`(| z@M_bCK`c&|G*L#JDv&^yO9He03YIMLL0jt?&7>@qa629w056A@b#*UIDgcZ;*N$V zOY-9S#@43)1?a7V`<(9ZRj2`1far6kLmo5We5U)95b*(xX&~wx)-z*3FS2cPUZj)( z*OF**o&(W;z#jbXv)TDJV4xYe6p5;wKD(U56n-1!T_JumsI#@r^!bc43ykH?;Brd; ztWcHC;0_A8)}gkSIVPLMK7vbX+|LYo2JO^mj}&-lyw7zGUp~tD9_sGo$or@{vp6nu zo<_OiIroA&E$1vWe|kkN%&J?;DkK{-W8W^(uni<2`LS;lgBo{mCKd|!IsTs^T9t3FlrexcIso~88rw6avEZMP0I9LhyNLI zwn#>tZ8N$O89LvUj^aFn$T7HQGJySK3~u+HKlcw5|2^T!{XH0+XB_s#+>y-cSrIVm zpQxSlGf6wD9MYYi3qSJu0aEm(%)}$)`8Q`A{B-<<(b+!^dd#b5INv^_8;ep{%2}O1 zhE@26Lm^I0K{j)IOsG7vjyulqud-@%<+z;vUxCE&qK5k!QH#I{P^%d^+?YDV6~YQ~ zshKbsL1hTy%TWk&GpigkVLSqtAdqiH6~d-20t;bNw-fJX@dpz;ULkmOtcxiaY7)N( zr&A-k2Wf3v?VpHN&fC@jGtxCNj>>xxQ*ae@J6v?MZyI(HNUd;YOHwPEa zn?Q64U%TUNymS^kr_-|tp7Y@;gPl+_U@G?ts4>3hRKlRE5huyM2+uSxdOFijXWEIQ z!F`()t{TdLn^A(a)MgegXItz|iaHtpn9WS;lI&(Cvtbu7v(~e1KM$WIbM~)8)NHBA z=UJ17knSW3MPK>b2G^zTxih^=Nr^clJNY zOt2+^K(@m#Ajo!|{p>m<=fGU`U7YVGWaA(8cK~T1Fs%~?-o~1lV-d`JCl;#5%WT|Y zc8x>q`gF%|Is183%E?<>V4?reI0W=YZBFK-YRN*7vpIn~hsd~%BqwU;&<*&{*Lvs5 zxPP3nvAt%ljQqzL8QUA5hoXL)Mdc0FR^vOY24CA9FPc0|O)i7{dH6cbI8U%_XMz;v zu^DFGg%GLDA$V9@uQnNRcI1pWOFjP{7SWN>4pM&Gb@so8QcN5Ol1eS4#bq`C{@Dg_ z$_itjj)RVU+F<;d`LBT0Ns9+Xdg9QawwMi24w)Ik z^+myISYzNC)cHZ^-^uoiGFXbj6;ilPQN>YZVZ|*2zcVl*WETRh;s#22A7*()aRa5i zzhrqst&>V|(TvoZzSo1T;<7QKZAL>SqdusT&1k4(#7V&_E=S@wk`~3~Nc3hzlb^-t~1*D0O@pIawVPN*%c-4`&ilcFK&lvb2-^jI6RR!Y`m!*^?!sX%K8P znk*UdO<$|*DH4AJX;JnRiGPX(>8Y0n#Yk56f?r~wIc1pq@G7<_`Xv;@DtfA{KKNl$ zIcA$_vi9>;K7svBL~{DV4QV2N;WXcqdxE_| zE#S98&N?Xxd??Aa;LdAfN!B@^LCBdb3F>J}vS0`Kd9&18+WxPBU*eBJteO8W{BwHA z-JU$m&)NSrc#8go(j$hWh>O)pvdqeeaY=IW2xP;xOmyXa|$=Kws@yhIh8%VK*wOTPvDK4K~s@G3+W4Plghn8`%1$it44an6?K8Lp@E zV9AU0WU%qhk9$Ksc?qb+9Loj2M5{R0 zNZ@@4EGT5wpA-5e&=alz(-NpD4sl##X3Q}YZ$em|sBTSsdY8$y;lap4G7dR*#giqO zbnXdAVc3684TY5=>=HzrCt)@5F0*W$h%0AHoexQCl;aDQBfZP8sREwu;Mt-)KeRmd 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

    u0)e+Ef4N?{3OpEd(ep;w0oyL=vTWV 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 z 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 {Vl0< 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%0D7AJ{c5x*){h^L5) z#3f>**dlg_UE*1ydHx3NvPJS%@pAEM@pkf3$GJ;b2pF=mpoKFK`audh$oAc;(W1ITqZV)tHn-nt$4P$LEIv46)zXB z7H<@95$_Pq^ExR1fH+=?dIG7mpN=77N4@ajG~? zTtH$!x<*_seqC%AqPTB5yJ16{Gj-_xJ!JAyw!1jC7S1qApcSF z-^EYF&qcgGz@!^Y-hum#;s|k+I9WVNoGH#0my+1WULl(2kswDUXL4WiN&CGp?wbzL zK4q9hAB-iBbev)m`&U!ReC&Ua$Jy_PaX+M*@&x<6Enb(eqKxa@7P8cSpN`i(J(Q~) z=RC3o$0LdL?luzZ*d1gY&VMAR9o_}{y#(8KriTQO831hF47>9dF zjGK2z^#48*{k5M&`#T{J?V3&AgZh)-NBzl%5f8`w(#32M%Lx-cghYFxNesgz)?lN> zu_W4WyjV=49dX;ha4Lz!)5Mu%zWsg_IhQip7foeYO`@G^#bqSgd!@LFM7uYNEhLP$ zil~a|hc2;)M1Pzmo<}0HP2v_3{j*ivMxvk4q=q|4WPZJPGg*gqzqpe`|J^O#N1`8p zAU;f@P>+kdNc8KI;%*X!drsU#Zm{p{AYY}7LjF$NOQPT36yG6H*!RVKB*wwV;(ik2 z;ZxC!2NWJ(Z8GD-j0=p9Jj$RM9~dWtDT8L5V7v^Y42DTm%Ix2RdE9Tr_!v)OT+Ajh z9=4Mh2R|lqrY?0LG*K&ME{!oM)d0n%G0pFN|tKB5dHTMj3ctnah8+l53|pPelYuFX#amR9PK_K6Fdv!hunbg2a;&t$4RtnMiz+n zH2XSe$FY>rekYN);`?(X+R5zGpnX~?qg~D>(H?`@&d+OpL7w9!7n5us$#Y4xQ>$bY z(X9L2gvUg%4kp1|By}pqg_qELN@)1_8lLx>5Iu} zIPN4@lcgw+a zl#BcN(C0ftXqkqF3 ze~?F$=x6giBgm5|qrc7fj38H0M!zqUzPTTOPH2(bN@5)JNIr|ic-SI&D~WNjL-O?` zJMX`AcZ?bd^q6ixKK^>#3>m{X;k@$fL5SbpJFpi<80*mwAFm!Cz)yQ#xAZUIdzQ54rE8_&bDr2^^%C`<9_v9{bY4BW5bm$XSYN(JNRR1$WbGyD!F0oDNX{$I zj)1+Xu*dZ54~{Rd9^aQeFWolCe&>m=TD?R)s7HIWMd#Jy6@>fiG1FHM&M98LE;6L; zOeTh7d09`-dFA1KYU+9NeGoW4J?G^++}cZ&?{Vm{e0Yr8I8W~===sZ6jq)c&~i? z{w-~LUQ#fB7asX8Deno>#tqBivuUZNBoI09~(q zMK}@p%g6J+HR~5*hXHluJAm{ z*K0pMCjfuPMuk(4<-_Ay#(C|>=L-Dox64;PEH4x7x4_ym`JpOuwZ%-aa(-2QRrn}SH zOVlGB?b(QM&ry$VGdzBK#jv*w;j9Or`Jx`}-3*VvKe(RsJFgy3TD?R)sK@lQMMryd zyWsKXyTwH1~Zd^6#v>wvu~>oxzq=6o|?ZwKs+g$CWWpS=%d z&#OnGK+vJ{>M;Tt!k?%I^;jO-qVwv(@AdoJj~i6pd4|WQ*B?FBUZNh^i16w}dtP}e z1NH{M9`oh6!ewN_UYqQB>G*C(zw_#GgVjsaV*vDMkGAN%WY+}p9pbCU66rDBr^**F zj?YW=wyxV9us7Cc50}4*dVC~%UOgsx1(JQQ9>->-_6PM?9@?Vwl8uC(zdxq>@?9Z4 zrrTugCHjE-Dw}9X&MVK-fW5h}Hx)YUkCpf^U)ozQdtSO-UV#ut=hb7U)l2jT^_ZTv z=)7dN2J$@*`Fi6jB0Z-2RQY=Su^R?nr6D=b-b(>{+hA`SbXbo%e5glzAIY9q4<4s} z=hb5vl;Ka*gL+I)TXbH&LlEfikMJGIdNfLp=~i2NiT>boT(8iOoM&%Vz+N%zdG%<5 zu2+vb+4Jggme)YC=hfq4tCy$;^$_IH7M+*x=0Lu?eD#P)kLiAI?Ir553HCPAkepYZ zdjt0Nz@9g*u)UM0$1AeurOQSC_?=e|Hz&0}@}S4^&=#Fnk1qoGX5X3Yk2dKs-BN2W zQIEl}x08nCJbQ)E!=E!#;X`1r1AdMx((8{Z+4Ji0_yOwCW%UyMK|Pj-w&=WkI|BJ` z@zo@i=~ z<6L|^dpF3Qm#*yq^?2IqCF;TPLwmGE=hfqN)c)v!J^%HzSDyC* z_ICN|vB_sISN6Pgn*#Q{@=dgQiF#~PJ!p&0(<_1=qMVrwgxigLhk$Iq3-O^I>v6vF z_4yUSC5+m z`M!gE2OysH*eX4y`&jvUW#0*Vo*&VPdORDjw;%SrdR*$W$LFd1^|^k`xx1L^Kg)?+(Ful@KO74!AV{_p|nF*RUs0PK17xZG!Nne2Jv>c

HXjI;re929rTq!i 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%0D*A44;G3tN0hWT-fIC zaSq>M_BaRIom1s=A6U{kxa&=oKVI=a zkV)rYTYswk+~1#cj@mrurAvMCN|TZBIoO4mDv#R{lg@F!w57uw?6*(Vk2lvz=iqea zRC#lgk?=WclYTPD!6w#JdGnKzioen)uhJKPnvXu+C+~D$e3egLl`sAbAAP1z-kHAm zYM;DnUwn;^uJy^Q^~KlwT!4L*6?>6dhl z`=uit=3r}VYW+4Pnc;KrMoDUWY4*jh_0cUpdC8uUjE=S5CvUwkJy#Bs&cT;}QuRyO zgbR6}@X7mx;_r8drB5V+lfPN<&vLmoyFPjxtH(!g^~vAri|_Nv@AJi<f+kXSQ3W$0$_%+kN~ytX2s*5olXGeDOPd`tG!hg*l3Ur;qk0`OrQ$F3 z#qY9ikr2*IY~K<5j&+%j|8gI_$46i3qxbsg&-&=AeDvp)eaTtW7ku%4`f6YNwbr)~ z!tP)n{tK~f?nfRD%6-vC|ISDM$wy;vrR$iU@4FaBda{q6;|OZ2=sbfu4837T1Q=2nQ0sIM2A?Xxgriq+xcAM(+kOW~hx-6V8CrJt$3 z8Bh6qZc&Jju74*bey;UPp>=$v^)_hZXx~3m_^aG+)$-X+VMeueilg<{`PEyer_d{` zrWCrtil)%b>Ra{HkK=4%#(L{d%_?-qVO-zm)ag!L_7ygC6&5|E#Vs2fN64Iix@ zehCBP^QpKv(&K&fWFI}tM^}QT{;%M_Fr(Fq_~Ltf^i@9kK}mmDrH@+A_~L)*qyOZi zc}6nxFIVX|Te;X!ZXE3?0?l|ndn(N6v*!BZm!`xgQogst^jjsK&7u&8z{n;RJolZN zu%>ocWvgn+(>-_As~72)HLz-tHiF9&=_9Z#;a`y$fpKAa30#2~{sc@mBJwG5az}~T zm85pM4&OoJ*{C2-$GLiDma`;CZ3{ACDSLp_1F3LWJ@Lb~AnryDw_^`W|3JA%LE}~2 zBJ*gw4b1*C#qaJRP*myzeg7^cPno1X=R$S$G}*cvzE91w5R|b$buzut5JhI(T(OrHNpfCKtrPsjCO2<=qAk z1G!g-wdAs-5G-A@DILrp^&S@^j~fFK&W(1i0MD*F(DJ&y8-ct<$3qv7!LHwd0*$@u)qU)49Gi(gH%Z0Z{cne_yA7ZBR+_e`H2td zH#YMg*6WVWb^66x9+h$p;+-4t1BcTzwEKpBH*nIunw-Ij2_3>Y$Iknvo?B4v6w;V* zDt#W+ZxQD`rq4TI{4vc5uu z-ggt9)-V1#U)FC@GvC7qcgt%c2s)4c1t9aD)O&5HH{Fb4jV|90G(CfbM)yN)|BM-$ zoKdEc{B$$sXe3S3X`jjm_R-C#)ade8C27Tv`cV8-9&W}GjV`~rAv5w(USq(*@}ir; zLZthDn0piOs){@Q`<&b?mm30s5D1EJSposc!X6MTn-OFS2_T!2KmtSq!6YE4wLwKu zsYS7sDi-QityaOU;EHvrRcmo+Yt`Clt-+uAeCOVCF9H1jpZ9&9cb=U4 zndLXX`OTa;bLK2L9i2;GWP`DARXoi7-17|^9#k8T?*lLQADbZZCe~qB z*zCWzwEr;STFLm|V+9HF9jrr4{=x1a=KCANt@a=JsgK_pX8L&YUC%q4d=LM=Pokc@ zZxY&x)htLf)_R36Qn*Fo%M{+M@D_!)Dtx`d+ZEoS@GgaKQ}|AW?@@TS!VfA8^Swdm z@D~p4X^sQbqX@wW+F>M#cHl0Iyl?-vm0Za1pYVMH@&nX|Y_-Qb+X07;3ExJ(s&@OG z=RLwO+G9V7_IL>l;gZtybF|0n3UimSedq?Qv7~)&JTi9T_!*2O+F3>-%&rkR=y_En zE-Y7)*l+7d)Z;1=`{x$&FLqrj+VQZ$@EZG`2Sd2@HTF3>sDuu7oB%{Vw≪&x=f| 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 z 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

<=Dk{B=`UE+$AX_R(yLCjBK`VmJ(P}4;@6b zxoT_q_8U*3Pj3fO?QA1|0?CfklY0M`QZ=&wYTCB^f979>eDkIBp6eXl@H{$xkM$($ zOyYnp*|$r0vX6iKd@Ma=H2QISXgTi5ZadD;!sA-Y@g^wlI6o^TPQquO`OF_~GcCvY zT8aAj#vtxEe=AWRpEAeY@$N=(gjY=e9e35Az(G z4SRD{ezLq!yGLVr`00V3Bt1dgZP+2yGY$va1N+Ucfef|o25I(>T`|#TE&Rr*bkXNv zyoLE>R=<>2V_g!yVmevkWvku(L(XBj{^``cIcGzJ=7bhZ9Q=k5%n@v@N~g>f-3}T1oMPl z@@WV4JtO#2!IuSpA^4`?uLOT9__5$$1^+4Nx>|2okndQTPItlHf)T+y!Qp~Mf~A6G zf~vhkkD0s4cbU|?Ot4C@RkU-?mvPuYpr2;LybPs)#^mhfhHY4e0 z1z!=|C#cRF@c&Eb_XQ6M9uZV?)gZ^m^3<0i$miT_k9@#PU=}^IH4yB z^1(Re%LNw;@+}9$R|>8YY!u{sXY$n?G@zP;22^vW7gYTU;$0$iGTS?b0OtJXXo2TzM9zbJBIN0as^0*H zg;xCsXcZ6r11?djpNJ5lCr?o6K|2{v8dyX`yb?h(C+ItDUx@djw6nodj%sWOWhNb^ z7e7ib4&}l)LLz5y8fcDyOC@{>-eIsUuw2t3=M^uLiX3O#U_@5PmOzlw&$P=$I~D8xA{vYpncnWKKE8c>#x=zk2da zV(^>%@Uf|_ZzJ@vP37ZYTQ>TB2tT8ncukfr1S=l#koJ3aP>%VbE;?h!2k_hJZn5m( z9f3)gbDfzK%brfn<+su{`RR->Tiql$BkN_ipw9q66gLc#(}Ne7N5QsppSF9SRd#fJbk-;`rbkTjWJ3f zXT0n`jGqZ)!iek5$!Ezu1R>jwtUhS>$RE??SlZaZ>!hvkcJwvuV~jIAURP~>k(0D8 z>SLc`^zHZQ`z7?18f8GEZ=X-!bm&_FKJ{VP=jr44*2F=u(;W@(Jd~ethWA^azI&lB z0wL<-n9tpgi4daYlGUC#2+%(gmB*5_03uz++ zoDR7*i)Q}lIKHsU`32Zfig4PIhr`%01ahc$c3aB50DU730W|3{J67{>{*Hh#h-;jY zBU-^u2^#wz1e}a;_VG-Y_A_s`z7Nodn-ON5(bu?Y<^R&0u2CaKj*ckz)oYk_(-q;( z>FS3T&AC}u?71!07R%g`8S8v|j~HiWEqY`qW@hP`NP13Hikg`<{lk>tFf}tPd^kDy zNG#=Waz=1lFV4(LePrs4eR+HHV<%%(u`I0hr8T6=oUD{%sYR(r-PFSe@5Aa_PTq@{ zleHIfvT)^OPp8OK7HSEc7-4aQuo9!D~hx0ekl z>#~pXSvx8)3u{o>?lP|B^#_@I#MQ4Jo%|W*U}a(sR+2RbE7ZoxExO%=+_zByE?Wa{ zC~Rlu9q|I}t%1d7ICwe2!EKONG;a;8>&XZtMZmxsSVx$EH`!<|d7+ev3X*sO1B&Bj zXyUw>;ARHtsYaQglTKq^lCTOHy8CDFlcIiJrtdZU{6FlycYGC9{{KI7=jNsoA|PFI zlh6dx14IP53E@(O(5nlPA}C-a0Vx(hbg_JPK@<_uV0Twn!M0ddv+5$&54hONvVLp? z*9FBjTm8LWXI^vfBw+dN=kfXewUeCtJnvK9r_7l%GiPSbf!7}VHktV9O*kZ{gz;;e zUg&e$w!e-+6UHc6wO;Zr!kQ~!laptp3@i@Z|$@& z@9CUIoq&PeL#n;{v~VR1GknHiay zO?PFr+A7aS5i&lfReV0ISDQz6Hd&lkiD0F4ga7~L{SUt3@x9X>edjA2slInMaGq-Z zCWy}$mlWwuUkqs(f59U@?GY-#_j*Uu7e81^y?s&1Giw+IZ!QpdFy^T|E$m(3PAoUp z85@8PT`PWL8gW8vJ=Ml76hZX`JM)w*_cYe*xXKoR_4jS`DMPG_@Aff|94N(%_$Q5?B9Nh zewsb7#90;QbQkuCpNmg-AB(5!vG|IC%a$>4v!~+M&eKEj_%lpCacuG&(?5j*GTvkg z1$Pb&6S+y8xVk3J@!2=xZyC7LZn!n#Ju;0&iqDh5Z2dcr%l|W_hX1KICq1cMSv^nB zn`8CN+VwwNHqWfxsY~3sOyZMem|fERA#xge68|&guD+gy9m{t-`z`%{{OniHKbp1T z6FtrSo{;}}&UyTEPT%gvc?pAMzU{}%GvN!4_#FL+Z;tsI-7n*zl5hKW=8a$q88IEW zk@0QEKWF6mI==C_BXfZ6+nhvCG%tkZ_GeAzfoRt1zT?52n@;Tc8?ME0WoX6?d5m$c z2j16_=J^=Nd-_1So{wR`C0G6f#4<4|P7rxHLOoUD0?|CzfIF`_=+BEIa=m!9xKX@G zm@X%G|4DM=?j_JuThy#3J!Dk#{-tA1zjjQ^XnK+2VZB)EnZ}NM0pgB3>b0C2kXM z5$_a#A?_3(7M~EG7WaxTi+>b97C#q{h`h03xg6D>HwOpD+vwg->?C#U_4utC~ zd5~Bp@;gN886)y`iE@=_+A$71>~iA{7<&898z<+{#eXYhb)Mu$t$= z|3iy5&yVfev(t-fZF3CS+dM0e1An@G(3kCmC)4FI?UmzKuzPV}wYU~^m=8jeP?297-by>yum=FP8fZ<_ng2%OF4sh;!ybG)*!xVW(BM~+uk z=bEHq8%OWBG8)9{1@}d}M++7t^}{L#owt;K621R3 z$2u1MdVj|#*H>tB%g$kcJLR>c$B$Yq?fny?Z4O#Fo6D2mImpq%jIzjQ?eVQ*hFxse ze)Z|!lG+_fOl-UV*Ksn~huRmMjt5|#q zdNazh@!du=h~BmP=HhG6-e=ioU<9`Jgh+3!*TC^tj>I1Q)E$G}hOc9HcfcsDT^tQ= zOxV;8C3>jbI`Yt(K9AX(-Eq{t!|a<*J%TW-`qNGpfuldtbtyihtSbe$UFW^ecC^INCXNEmq0c7`3{NJz}SAi-zt^ z*jzC*ci+cJpAJbx+p@DeG$s^;?wMx3vpv16^%1*e+S69fnwoA8bD zO@Yl5%y+u{?zZNv;E}|DU6S^<#BXvM5)*H3>|Bs@})nC;j(v>pZyQ`fHh)O3I!QwM+P=@6k`2j*-v9Nzm=9g7zb5 zy7sd;;=938>9%9@>y43{iwUtA0s~(vF%%IUN4)W@muQQ;0}x5@)E3RIDsNS zf4Z9C@VfnU<@*M99RsA|HFj887ikJNkT_cp95HTc#_b;RO#ugQhc=92`LWbuDAhVJK<5n zASN&s4YTuKVBrbt38dBuJ7h6ybtju_=R9PuD=c5gYZ=?@f5YpP0q{YA@dYc(yUdh# z8KdwN$Q_@|bg*#6dZu&KXyersy}Hs132kIT!36wtVOxs8`2;Gv+y%dx-{Hqyv&!$s zM;NGk^CY9oawNFL?;FqPDfjye;E$!}AMFxQW_vI6n~${Z?L5NFj@w%gx9*h8j@!$9 zQ2{ZNZ(P}XS>ChhYj)fV+;M9lx;yTLCOhthCOhuMZU`FNaWDFI+)LDX3zURWYcDe+ zflZa+xiS01EH-@ahQt27X}-TfFw>y-)50eHF)eKLf2DgZ*A=fX3vke3%UDObN4%&Mu*x4E>7Zy-C&SUr$8JcZqCfX z+8!yJgBACAyrDNw4b5epy?qLjHWmCfZR07K3V!=+SgT<&&tV0>!^-#>eN6?w!wS9+ zqFcf5GH~q3c(+LfzuOH#V-@_KuY%vF&KD8WRAfg8r7-sYn2NMCQralXyTT1kI`BfAPWgk9c6`eW@Kz<@eCO=X7XAcq|wD7Tou>w)=!G z=F`$!rcW0_hkcQuE9(@LYdjV{nVLE+ z70tk110{zg!9nDGS8jGAQUdW=F!8vtPL+p&>pL#)%U(UUAuYr;pZP8@)+xkN7%q}9 zzK*u5Tn~c!T@P4d+i9@j0U_Z9m{1q}Ez@{{>Ow4Rako0!cfg=Z2$sh4 zf;G0We?yHEdB$o!R;OO`$d{INuKO0?PGg<<4Dh~dJqG;ESf>(vaoI$qWjqX?6%!L- zP;H~O=kUaa2Cyr$@3ivSb1LOg@%bv z3-c0-j@YrS6>Nw=m`k(xq8(k}RAPK55(8oMES%PxI%8gqIWPLIbU(aK$hrs72+*|(^dbW6~rA9Q_9FX{SDK0fYv z26BB_C9$m|Y$yZa`c98|!NN$afq3MJo_7?Mi;VZCv=g|+xVjkWE`wP4+g5TKY`kJXaT;C?;b$!j$8?JAYx^jKZ zIz_JUjF?(j=*zkyc|nB+Nff}CwoQv0EmnuD^&%Kw{~mXm3=gx#ohBXc6w87aDqxky zDv)m3Fr04!msWMO=fj|HB$#xP>s8pfNhEdwAP1 zxGd~mxUqe4VRxqr%_AqR0Jz;vm@C?-thWmXgjJL65^k)sT82;_Yr2A`R z_CN2|{NKG>V}^6l&i?IpYi`DHV%k8bHteL$e`{L)g8Z5+CnYaykh5ZB{@Q+*_bQrK z9&ju>wo=Xjd!Um%)wwV{u7GdYmGZ;&tOe7%WanZki5$vU#pg2j zZ5*@MO~^#489!}(4SWL?*#%uj@ueQSe_s>3AZx+2?941=%8kAJ1hF|Ig}b7Tv2g~B zz$s43$Z3~P>pi5fNq%3j?WseYl}y?mlAm<{pk6tnrVMTp8)cn0G_h@NSVe!4(#Myf{tLc6y^!Cz;=C^PgNNkxMqqzB-MkiQ42jg(( z)GmlkV$t-Kv-7#2PxIH0%r`0D_5Kk%TZ?6UOX?iicb zf%9bX9q%bcx_W^?o=mp5h`mR|kjtloaGgh21>sxRCRrrIp*f8HHC z{@pQNgz-9!$LWumBg21;@mkTp{X1(GHPy%5#J7KEPK>7dTE>;Z_V3Jz(NtfXX8L&P z8sGk3%!$GLWW=w|V8Ct(e~`r;%a3;|DSb0hGZqF)DIofbP@9Dv=|6bU$BQ zE}D1z;J#k+)#66+Ch=|YZ(;^^6!mo%Ic!3?noO{)%ShZ+T_avE-Xh*D?i3#r%{Ug~ zy(Ia7_#p|s-;zj&&x-g>HJ`IG9rF!7c)DaW*9GLUlo6ia50XEZzxh@k{FO!7aO>&uNzFCJ}^KClFhk#6HH;H^aMWTJYK_dRgqFJ{D z{$|}0xI01DKZ%5Uk!aQ%f&W6v(6g9CJ6S=(eXVHL5rMo}vROX_@|}|J7at-K|78;T zFm!Ly!?3$qPpUtOcxF8haFqNf$$hS9*6~0-H_QJQa(|FSqkfb`I=_|si{kIa_e4H9 zV|rhR--!Pp5&vWyIMm0D?E=|0L=_vd_oX|68fJ^9ihMnX{sYB`I7}QRju$73v&FgM zd7?S4pl_|@%f)L%b3DQSHpzF1kBa6T2>%x)zbbwpekdLi|0Et08$~`aXSq_vwj!Ui z(>+V%<95m=VyQS-93t`|B*RS*r;BDz8@Ml}j7sN&U-Dvct++un{Q&$;KLFk+_Z{LL z;=SSn;-ex5DXIUr;_pPBJLvwJ__p}I__1i#r9!wPl8=f15IK@WJ&9tf$oB*2o+oF>i|=ZcHOYVksGwRoBMQ}Jiwwc<@8Co*P!?h=0~ zJ}8?04*tK9{9Dn?4FY#FHwbt@?r(`^ZV8ACVjq?zJZ{`vL%^V@1*RKv&_|f77af&!woGbDT4yJ#xxL({Kdj0ZEl5Z2ux>Sf~ z9%qAQJu1+wn+Mh_++Oiz@pbWS@u2vTcv$?i_&3qaZ3Mju?0>;zv6a|X%o4kaeZ&H> zR2(P{6-S7C|AhKyigU#U;`w5YxJtZ4H0x6#zB#XeW_>E~dik643*;S=`Bn?ldsuu@ ztQYxe3;lmDejt7*@;w&%e=YLm70Tw746wE2b|T*r;rWZ-QILgVUy-kk(0#Z#R-7Q7 zEzTDgix-G%#P#CU;?G6CGeZ5hiN6%@7x|6|{muCg;pyj0|CAoRahyivSa_=WhT$X7!cKSAUhB9z;Ud{KmQZ;|hdP(DNCYa^7$ ziF|v6@;vbZahZ6LxJKklCJet#yi5G0xJ!IQM7FI!NB4e*=h60*(Qd;e_7fjEP#-tS zXy%4VqPZ{N{+7(UK!!7VKwKgjIV^S+jb8ZkzJuX;55;uM^$r-3Tp?DH$RF=t$f+dq zIa8cXLeE^$+)qHyBFdom4adtmpK`7hhBxOS_?vv^DBsX;@&P%*_(;d-g>3X9p1E#< zyixjrAGP6D%G^V;-no^yi2Wj4X3N4avT8Z5cw9L8aq9uYeepx#`XLPC_|xSzows@E za(^(KCx77u5WRG#yWwKrf*gU&d;}HFBd<&OzI#OOjkrfd^_h0Xyf7T&{S3yRzedR3 zLo!%n`B|@UUjFuY76!uRBh=25#d+{>f+{=qYJ|M z(+!8?<>0-BmoBe^@gHjke2tRFp0|1V;VTG!eFfooIWW=@)3-?aym;4rM>)2-;bP@r zIF^IDxOwHcu35UJ;dnWCjC$pGPU$i(x9!lk&}-a~;cd41X8MMQ(H0Sw`=c$4r*B^~ zeF@n44|z%u&a?79-?PKn+Ks;9CG@4<=J|a9i@*Lh`5S7M$!`m2! zrk}!j?muPa`Zk8)#_<-pd1mnvm9Mvyn2~}aA-!=a57sd z&Y{Jg0D5V$eIs0KI}hRb(yF(4;YgpebpR*M9dI}m?%iRSF3Zon`SsPJa@WJn+dO^e z%vpTmxsFQ1;l2fh;c&R906*cvf`Wb}CE;*MK|u+;u>J5{M@gGZYO!yJM&MNheiIRj zhK^Pyw}`fh-n`Sw8hh-?rTqG#S9DKfb=h$I){Ywy-7#!S@AJcaUZdz z@vKN$gHyGoaYn(G#_(>9%->B#x-#FCfUMu^JLv4pzIeQMZhv}Fzw&BH^g-K%@N-UHqIe5gjBMoUu zBg$Vn6uickU z4nW6^W3`G}^!|N%5$^2ySgn zxXQ>h=%?-y=xdL3gSP7yfLlMfb+p$tq(E1y6Z(2h^`1imO?qcX&O<9WBWDBrt~7q@ zSJp!h(|P|;hE4w$Acwx*u=4#wX*p{eQc%9sm@e1v8u(c`@vs{qhjP61+%VU{E$9og zwdUDFmL2+fd(HcYTGs&mfHSt~f9?0!;);A;tFKIC~T7duaWk089odYRsV94yN z7d%sQ+3c|gU+G{Sot-i;+Op4chZ6#6Z(BM0W*)^?fJe=@eU1AIqT}$bT*kmJK5ciT zWuOOUC)-+)w$FS6XL;c^V;-^s^gFZdy~9?w{BqT|R^jUDkuR4HNH2(%H#pfNBNwbL zsu_?5d-=%7(wYG&3=8S(hY;?o)eqLpihNVEcUbM};?-S)6%EeZuU2;+^3ZD7y1vm^ zU04u(qp>zCbTn*l9X6-)S6H2~2&*$L#p;X?)_7kY?%a7l>ZfsJDB3c*59LOE6mE*{ zYn;1l-=TE7vcV1v+27`Ha&YKTE8&r&)~uwb?LGrud!unt)*gg@aMxq_a6sCe#h zax(R#qJF+?|JRvz@wJFIYUr8<+g{fg$vC!uPvfFZ!Gl)#H=i|L1$&llY)QN9wL5n{ z;6H_!zWnN)`x>h+xDn+^AA0_g%n-}8CYo>q%dxMq_5zmWs_5ouaC7Jel=Onc8(Q{w zpgig6yUOd23|za9dmS-P-xa(mQjlcwZRPBR>sx3GTN~3NTN_(cZf#7Ty|uAr_1{em zSVywgCLMMH9Z?5%F-w0fzRhcmy^fM(pntPc;e+y6D3A5={v?#2nuC}RFE=<6$Ij4( z;M|)MEAR#1u!c}~2O%TiPs}^LXRloIZ2yG5AC(@r;pkFxSD6;jiGH@ zhZU!9XlyxqLt|P&aoUE)76rvA8yeFKk`5<29r1;x-M{@sXoZQJ8zW)XX)4^-HU#X; zkT;~X_0%ZyVVAu2>E6Z#7d&+^csSL;mw;)ZZINhTv)z|#q6TkFFe`ng)dz0sh1Al* zy_izC7gGvb*+{=K>2SbKS~#;YfG=lntPB=q^!j>#M#;lpN6vqJ|MX}Mb8kwWxV^sL zj$tWZN6!7l*O7&(U!#lr%eVa>8+ukW@OEE(9r@I!Y$w4jW1}PYq5Ns7hm(Lq=h$5 zEsOj@Ipn;9oN;jfTX*BT-r&uNM_MK`r=60Qbna4N7jr)))^)N|4?79lDtdLw!OE#@ ztvUPbeykzn&`#LC1N)#n+I$aKIovO!h6aw>fz*8+8=c7h)z>x-wyGkBCYD9);&qLK zGycq4-{hcm2M)qkXopi{vl8Mu?|~HdU-*6$ZMy0v)23VYP>bHu=5Q)obQN3lmCFGbMI4Ejq!uegRu_$m$W? zf_e=NGA%lB^DMOJ%OA5#Sf6NV(2>m+9br4mHhVGK>_x2j8|cuOm~mcbla~ZHFNu~v zFV6nNt%XtM!|rcd^tjyzQ!pQ8!cDI<2J0hH=SI74Xj}5(P~uj!mSBBvwv~e3=D6u? zjvKSr(3+jVNellrb!238qZ1AmXY@vE?)NBK^PBtYOW1mo(R%N7TW{Zcho-(AyxD8v zBXM4e%(1%PGpt**{?pS@YtD6NMThPS-VzV7b6E1>)U*^FYpjvr=EN=NZ`iI&n9r9E zJBf)mzJ%E@6K)A?-f40gxQVsWv_{O47jcg~w(7@BtNzRWdyi(MK7m$!;H^8+s-0V~ zZg6U+t#!xTh+1$+wPhuTW-RpkgvU7i?dJd zCbsbUBQLB$Z=A*6xO`V|v)3C3Z?dw{A7`PhhS49R&9?M1rF%9<8>{)uJgl=J9&Gy2*oKb(^(~=`CQ?mDsZRpsk zFggnBK~Fcjb`LwNBB8D*%J$l_l5KWMMenqP8(dA89w3GKsB1zrRQKZHU~u=a$rW86 zvirV;Yk`qbx2M{Qytw_;@h$%La<`vKsB?R%f6iQp>zO9~R9S2f;~X5{!|bQreH@IQ zf-l^0=FP$NL}RV})13zz=bkja!;qtvbD(i{Rd6GECM#i6%d8u5#@&cB?jviSL+ArI zzv7IGnhBy5J26|pb8tC;{_r~V=ve7`=XH(g8?S3@x#O!{n2hPj_B9{2#}x;9CVNo4 zU&1=!P5Pxn*rzym#kBJ5Ft#Bz8f{3M&(*`D4Jo0-!wD(ThUD(QJDigEyTfTo*sleb zmp>Z~-0)bm%iHz+{2JWjI-%~)uOstz4?{b=Zg_NBv_3ln=f>jnPq3DDaT?Q@Q&Wuf zv|sQO z)u+8?jcyos(VLA6PD;cz$w`mB*|_MWal4#rd983NT57OH>)Edovs(puJzU<<`fNx;V9yze*F4_D9i4l}7qp*; z{Y~7_QI15PhwW6{$s@$jH*t@}dnWh}bwi~XnPKMRx-O$->RXX$VRWRqr`UNo#hF?@ zwJdP3AZi_~jK*t_YnE3(k{-3P+C)>L2_|$wG~sB(&gfI}bapf&`!}CeM{qa(bo`zq zeSRB1h(v%+FtG`xZa&I)>lmyN%WTO+acXL7QntPr`2~$mz5a`{BnIdjMh> z6~@g9W+M*?v&#@Dbq2gv*rA&^0+}{#p%uEV9jh*F=qS&g0egYm!)ctXzztK7Hq{Ff zNgFQ5$`(&Rcj&J5P%=CH5$5#nM`*XxVYfo}ybfWmoqjHbds&wY>~xNzxxyklozty_ z?%NBeYTGQ}9s1P`5Nd5JBO`QU8ltByK)N@YR*<&nd|8vM;AFEsHxmKudB3h869@%&LP%!VP>`V$SrhSK?%twm_;U#M9sADdiJ503fIV_UZaiGL`t~g5K zIY#W%;atmJ#nes;+N*2f*XsNw^DO(Kjd1GxFl77U9k5!b`~|A*OSs%gGS^69hM8KI zCt$U2MfKxc$Kc!fR#xVm+7)!Aom-~)i2qib`?LTi%>502?r=Ws%L>}J*~bt)+oXQG z&E#`T@^{!fV7I!O^zXEJ;3vO^kUah@uEx~8+Oi+AdAw|Z>5gV%KWww|AE$_>B9X_g z)r0Snu;e{q>^JS6??QeHcJ?RsyEb2KJM}%-A8U=DUSGqPM_&ZSK4>3-Z|^iDUIksf zZCEaZr4M~`Plm+4q}x@iTOLo1?&krBB2*dCMsD5tC$752EHhia=qN-x)$zT z#-e)c!^j0%IezW!-=e>CTh?Kt_kR#GbK!CZ`T~J$gwHh7svNd?NR5PyhV{99CgQmb z>rcLh^@Y6yfvmo!Vg1?WO9^}dCAl{&-LU|kWgoHGRc(S}zqUxq{?cZrW>4!s8P2!B ze9oX~Z%%;eJ%NCI-(iSgfbH*X$fc`b`7MI6epi{YVTYC80avcP0as`FLC^WLgK%!@ zWStg7(HVJpSbN(l`3Eyo8sJgOZ8wa){pCcja!La{?D#-Ev#JWyhm;0bJ7LPEc1lfd z7eQv;Pczb0lrVYBfB=j99HhQiGnLa#NkYhKUsDBx0<40Okoz5BvV#Nc(Citd?Aq@| z7UJ1=me=Eh<4fRPhr$isW<0Rz`wXjRjj5iOD4QN_ZD21Hw?vk@n;vgnfIZ$4X3ZwBI#p z+Y`H$!tu^n${(1N7a=7#C6mi=O-+~x4E5}F@M@cJeHW% z&yZ9z&mwlz^b4Yp&Hesj{3=4-jbFUbqrE~G4L|`HyUdMkvWWR>Dnr(QRm_`dlB%r0 ziVUx=LczI+kjyK>P|*G5(H#n|rZcT2?Dg&Tj&}g^{cTKa)52@B?HwL~yHPi$&9-;g zWd?Zg17eiMQF#&JF}pn?1!zL=#AU8zI?d zyEuK|^(hp%ZPt}9#VZ1AvzbQyoDA$a(`LgCJEvPIn>L%}u<5-3*=@7g4%_T0xIA;) zY*&Ye{6&H30`&@{x`wtd;@iGH<*-@bczs_$4_wVcAc| zn)N%-YHy#9X5^l9pEk|!%%_R&J+gnsvRyYp~up#kf7aj1pL70%K*>+zhpqf~rj@7Qy)L(vyYdvuXytoMYF|Ne zTlw>*mA7q+PR;bhdrhmhr@3wVMboCI!`E%oFPk>K0&@Q%WHO3^{Fa9k+HWApqw{Ha z6;&|*7g{&NhrJpb-FVE3rG~;uo6y$|Snh^m2%hlAo2JlYUs|Q3q4I5`rin-CgK$53 zynE5V;Et5LU|+;jPOA4cQ5-DFK#}=8X1R5y8(4=(GG|8UjKigQ4}98H$ZxE%_?rVK z-?RG!i;*_B2Ptmfh2!3B4t;{`zZjjAkO*^kSb7C$HvXgsf;PpzM>x*%2Jc$O!yV?Rs*|hFMMLnz&k6~9)w$^Q(KRwQtpOB7`LZTM`qd- zx*haM+^4)4?!OK}nQTkcKXbChcO^IEsz5Q8q^}10s zO=%MflUZAJ4nwjnJwVx3yD}%j7WtJu4*B|o`FhRd3w4Ej-5<->YbIa!F~)_Ksp-K0Cty&*MI zVGhCpXstDgQe`EMk>{Z@dC7xtA3O)vl({=#jYLs9JO+7VnnX)dF@J8vk5$G?H+!Mo zNI#BpB+-UTuzvx`ynHFk#E)HT^N!LNqMQe0Vi&4o%_j|j#VRkQhS^ll+Hi-&IJD+^ zM_z@MF<2lsC&ts{WXNDtMbb1D$n`QBEB=AtiCM-4**MAWmfkwmN$-?CsohC-Mmro@ zU9HsAGvI_v30ZLmfuXu-I5A)1$##zpHZ1tcfO2wogB0$>)Yi6>o|-Tq z^>i~WUs?;xo5ZdZDq29)^m`Q3eIh#OmcGCcGg{lJsh*;f+WCZ5@qic}^JejDiSy8lrP?fJCw?u~Ii6Qs zaw1f08o@5H`Tme#lgR@)DIcfsOBi9M5X610i6t>hMM_{A*(wtJa7s~HM(C=vjL?lU z_c45TqCocVOYqP%3E0gF6hwIdgEHHMoP< zI7YOlQ^d_Q8&3(sFx@hLIb5gmm=jtRBQo3&zoY9^(bNft2sb2SVMZ*1OO@KzWP+oT zN!G;}?Mj**pZ$s9(PJafIN~~EokTD^r%xPL2O+lMx&~p*j9KhsFzFTHg&iLY+Y7E{ zNW+>&Fatqr`97=8%SxijN+g~W#<&D#Hs+za&QAKa21DQV zdBSS8WB6ScD~%k@;HX>=TCoHg;r%a|By0NS;Ec_|%}JCNp+3^&GI4Wo(&ivt*2AP) zo7P;qIce(V;Iz#_I`9k56xVUn2KZ3E#{_i47)Lrh4wGiNj&5P-vezGUBjVG6Z-b|* z#GB|y2Y!-?gpORYImx(Do{I}UFY!irP>!JFP4i9{j@YKEM5wyWNqp?H1SUo4)Fy3C zqRc8vliT>s!3mqq36_<}Dxj)VT%H$p%p5zsYi7qfPj?IMkWkE-;khvm?=n)+Vq%_j z;0-n=xg(fj3u{y3CC5kK3U6M_r(z1xSadpk27~B?qHnnL_~=uinFZ$@a3q7;W)$De z9e#1HgHt8Z#aJifH@4w^4!+|E*LRZV#mfrcLG1cY^nA&gFwji!`WuHhUA@iq9d|b5 zl`uG7iB&Km%ZxtNT>|?$*Ngbj=LKtQ>kJ!W6RyrF1Vj6#UyMRz<`9qv$G==Fe$9p} zANRv1O!P-@-t8bV;pTjT8_u%k!{TOl!Zono4&$3`ktzHVCK0oy^1!d7Z~!J`O=;4S z;AHL)P(8eI+YQsKdIlP&al}YtokFk%9Sd`T(sGaMPTX&-;|N#R6xd>$yKlx5uJ1I@ z>s(ltz;IqYj6>AXeiaM~Pq2t=I^=D}IaU$v!Hl27121yfc#-<~&*v5koHAuJ_m=Vvw zgm?yOt<{)Vkr{Z#q&kV%W2`d>uJL1AlZb<^D|5(fIo76!FO6quQanrJnWbk;?q51WescGS*MrOX9BSi#<6NHt=j|3M=)%5q>H@Q-2ty3r+y$l zvaP%bX^y-NPre9z|_VSBoAE^iWX`$p=jZ8!%&D|wgUW?z(74A^~e0`kNMRP_o+V? z@Tor*@TnhebmNEW-HvbqA@v7i>d~l}_g7(%tH?f()l0iqAqYavZ0dAI2(z*NN@0+3 zLYhB{X-0`ZG8umhzKA%QdR0fGeTDeQUx<%PA(Yf;L^K<_5q4gQxEe~s*kc`qYh8yU zsdS)lmp=rBUw95R2;tY|_KBuTV#E-R7j{XWk|bA-bguKXBv~~K0hi;|n6A}T<4zeH zS7YQRYF0s!Uk#5M9wnw{^K>`skogT;tV5>2zA0Hfv@c7H&b^@X$$bcg^9gaku~rgn zFmUyfA}5+S=6u5I8+3KVIvB@7A4$tj*Zn!5963gisQ`z2vG<8CA7Qcn$B{Sm~2mpmuq^wT;t>AYI0g_YYJoLP<|0AFtsz`DxE|OH%ezv>3Y{n zTmxgyRczW!#XX0_PLI`4yWUkz@VscwRkZvJCIL+qCnZ{Wd4#>eYWom|Cnd6t$;~99 zBa9-@>Nb)|1hc{j~P(QBgQ(BFm2DOy|gZfjEy#VoXC3p ziEAbJ+{+|Hi(8C|UNL?s&&ZnDKE$t^$0_wl^*NXjIv8H#(*7n4>WSd~pU zuq&W5S#6xB5KNxVBT1qT?q11rxNE)n8Ia+eId|NyJq!rbnlRIY9(3 z=^v90w3&_jp#X+gg6wH&cS{mG6Q>|xTNtmCrJcKiw-V$MpC6+#8(vs=nT_E_!Jw|Z zAh5cAt~Pd8=!icG(84fiZI$H9Fvf!x>Nc0xw5UzSy3l@bTLFW1;Atk?z@W_&4;tTz zboI85u%L|-wZ=MyxB|wE=g{($>;4+R^DPd0;?Kr9o(LGV)7W$LGS(?XB@7BNoSf`B z6Sv8k{H5y*6|pTHHXKxho9!vW3DGV@irV{1GI)iXa)})&V8%-04FN}2(K}~2; zI3#F`7!8w{#Z|7ASO;T{j%7GHZiC?FlebG|n~&e+FxZ8}3K(+%Mav~Hx*nqSRu}|h z8K{}Z4Y?f#&II+N@!kcv$;6rklerb93zqIM*F&py)T|_NJ+z9R0gSmJr^U^|WG@FllpNHXjXR?)jCYYjyQ?a8=x{G~h6!2jfHm!X zU;l-T+eKU;jc*6CKrOnzu6UM7; zwzYF%rdbyjsE@v|&{%l=U1V$=M=Eyv>Dbew3roDvePf~f#X|Rwht8_o3H2ZR-zEX= zW-Gw2TRJ>Dnz=d1q+f;c9#+xL3h_4)#yJM#8$^PHPjyZ86WPW(iRcF7SQkXhill5@ zeArhRyFP;h(lUF7a3fCkB4Tecz89_OGr|-TZ9L&dn@D(Je_!e%y}mIKBXbRF=^XOY~xxG+x{Xx%NDV_4jHbHME#R3bMXZ`@d^ z+?Zc(Ow!wW!NS%#6=pWf*)R{nJPhOMhqZ~@Q*_YAo#Q<>TA_T>D+y^b-3UyD(x>}C zxs3+ThM5b)?rssx5}2hh8(_T63v&(Jcr0#(sfXdk&0ZL9+Y8G+80!5A4D~LDSpoAX zjJJJXxNCjk_R)^|48ic@vyL$HVZ7}`{{4LZs}S%in4iJi=0yVcz_6i5p??R=Juobf zxB2~fPGDK8VOTG$18<`ao?;HbyaV$d%!e?azU|F-3fOEQ%3X8ub#K0re=}PbMg6e=hfurWb`0F+EnQNz2ofSMu3EI{{5c9V zZ?PK$C7s10L&AQYQ@zY}##z)fHD`xoJ1GO5<$2{ZPbutD;H2igp6{GD-#Iz#oHr7` z^YU{GhdH}0O{#VFTVdycOY@wg*1$odMmaaY+F<47!@Bn3ygoU-2NfqR%kPsv>i#ah z3r{KhRetWMq(Qm)`8Vem^ckI$^=9s}3VGxY0-;5aL=(ff0kx;POp)X%jzF29NIPtOz^F;mmyeK+mAetZ6-* zm3gBwvr2OAxGX!6>`U&~K|8Oo;M5+)Ge@1(r;rM=24#0a;c`cGpFL<9R&L6p;|%^} z8gKsO#%v?HIpYR8tq0}@9G}+4pk0BLqIw`U;4I7Q>7*blc}{Ykvm_6@qD$BEMSTjg zr#Z<3Pu*aYjT)Vqo11@gcc*4Pi@z9^kmoE8JFQ1Lr-YsPBYWpKsbObno|7I%c-yHN zn4g_FW7nw6>^?iPoSKo&Nzhw6DAQRv)$I0-NRf)i@@Jm2Y@pL>;IB-~b4P}zhMe{T zXT5Ox1N3~?geXRBJFV6^?Y=xCb0NdMJnFK{GUsoX40Jl?Kz?m5oN@XXF#JNJct zw#mMI3bL?YvokMbM7PTCyVR}n)0@`#uafLph=In5tMa;^TX2T2A)S#~ zl-b2pv&qW^ZkF19d0`hP%vMza*{_5Ds)<`8b@rlpj7ybs&PV^d0%56G3yH{U$-E1#e`lSva~3aKRNG7!b7?J} zw|GwVN~;?Fi(>hh!*`RtWxH4)Q|4LK*8HXO=2`fb&MkP&!gH3)n;SOEr!~!{w>nCE zMKD%DtZJ5*GTj<{RT^8_YZ+8F%ir92bC#~GuAPPSii=L{=UY9_UF*$VO|G~IH61@& zx+g@Wj+0?*WipfN|19z5U*ZjWy};cgX1Bzuiu-P14c2R$yRgb_7p8)n_?uS3Mut{0 zY{;2xAVbEEnK*RnL|kMnomaKk+ktFwi>q~DG*Pi|3HF-5F(J({L&uJZHA{Spf)MU5 zHpf~O+iBC5$8Qdf&;6o>wY50DhS!?IY%!yatsFXL!i3Sdh*^xoZ&qczb(UcDxn^3i zTGza)nt9D!`9*Hi)aT=vLg&!bQ3r$Cv6n86v8pAVd;_fzH)Sj-CtL{tM@kEQJ1ABt!LTGiXc?+-ovuFUlRJ~mRX^c#Ihti zIgk=;6>MXlY`1gT+a2tVflf}BV76`L)vR2M)(F-vb-BQ^nZ7@7ZdGlSm3MYcjl0sG zf7Ll0YdpS8|NR{c&NT`0-D}Mq7wiPd@RalYshAKyn8*+7aU1{lECQ(PD%^>e6jT@< zn?J0{g!*1R-kI!&b;Uw{uRfjBenj44A-`8&)6V5b=Te=~_wU!HC*U8}eS+{OXiw@R zzdva&&=0mMf4~zY#?!&~r({C>U^1~#CrAU4&B@{W(}{)p!L*u${Li|NCtmk)V{GIx z=yl14jv4TcJ2~ble_ZAhCI9B&-Jzx~n7hEYIe4|+zj0kh4hqLNo|)sDgGT{P^`*x> zVROt#cHGIq!-1yyGUA>le5+>qS~c@;-7J3VX8vuO`TNge%um~9`r9^(&jIZC#&sf_ z=GTA5q`r>L^zlp?-yEw`T!78NgQ=$a_;4z|IT!hnwjO$30iX{Zxv{3UfW|3Uaz+bbTm(GDD%3!6&6$E160bq{%#e>Hjj@f^E$g#pu6=1 z1#Q&-0%SVzNNE-5ZN1yf|3mq+=V%ouuo|2BCm|o+Mt!_>!>xVSS_`YUHof=q#yB|E zfKcwp42B;Rs`(veEQlGrnKf+m*z&T`v&KfF6NXNlHL}E;5D^Il$w^?y+m&6#*5t(YAy7tLt4En*{0FG z>(QpJO|L(j`Zc{CZ0gtaPFaHjO@r{7OT$x5J-iE~=C{&jbPCOZXRs8!J-{b_DWlyv z;ZpD%`XkC?@Kh1k4jsngDL>e;5>FUOybi}TYC4X`Q#ul_f80S%#1lIbZ=Kvn^3f?a zt`BFnDbNW^3Lfd3bk$kJ*7Suxx7b>~o_wOKlBKuS7VLwW47PpJHi|j|~ z|B(2U_=0HGHidtG)Dy$8pELTzI`Ka7F>#Ohd$9%jAI5u6JS6@_#4xe(UnnjU|4U@M ztdaf2X z%Kb*kw@AKM@-E3wNq$c9e#vi=NdF_rM#KF;xM1DA>9XV8-AXbU}?eJ5{ zpG*FlL_ToqW%8RqLe7wUGKumOi{nV>nJ=DCBK#^cg6l2GS4sXkiTHPkuZV}l1ax@x z?;)0pYf0$6h72P<3H^_VzY|{<|4btMKg70Zn+)GwED=v55w1e=2+0#A&lMNSy;kx{ z$?GLwNunNZl6#~NTc$%NIp-kb^(P~EV~2$MPsHW& zzm$aDt4M_Vx#Vq<>qx}=jre=Hzb*M|@uU`RxYNa{B=pW9yJ4+e68f(Zw~P0QyGVq8 zUHnk|hy2rU%gy*5#Y__6dr2N7dAQ^=B~O)n7Kwb+NM0fN7V#PJ9q~&sv!xqvjCc-- zbeEF7P#zNbx=FlOd_t@z5&k3bsF;dAhw(azr;2$b!k;F2gg8d-(# zxGrM8IDka>!IDQx9xHjez1ycWP+4aNci^@XOf6F zhs5>J#U#S5lYF!I0Euvqi@y^;6oYMC|4w3oI96OFt`jY6JYNPy9Ii%2b1>v}CjEJT zWX`K%iFmq*OE%*l6-SD=u#>|;LkVc7%p2Z7W<3C#8Ki5ah7<2xJYZa>(5x@3$$Nwba4=l0O%Z zh@8Bd;Sxm7YE3yqt?ufa%t)tBTf>hiL=GIBBz#S_zOj|wmD>TJq>P>yIIp5^39TO74H%66FJ#5 z^*t@_5nmKJ`856C7qPISk-reRPk3Dz5?hGox*P6c$z4UvXJx{3j&a88Ck_yYh{MD& z;&^eIc$UcNr>Un}yii;%azbkQ|4iH_nzhd1ey8MLh`U5{y$^p*Va@n^#s3z6FTN)p z6h9L`7rzp}5ktIQhrSfCt=Lh_7Q2f@Vn2~nW;4FIp8zLGHun{fIm0!tFBggC{sQua zk}nb0iC2pMC7SyVgx?|A+ z{JY3G+F6b?-Ctyg?Zi%Ew%A=X_dAGpn&gOBA&wHqij&3ZqPZVJ{BtFn`y$B8B%3wW zA+M4AQ}Jr?TG6bvj&OC7Zx_v4>u|qc@+0D7BBvZ@xj79x`FrtA@dNQg@v!)3@h{@v zL~}m|Jqf(;0n@|`v7OjS>?!sU&3zl<4VD}gM~a;EoO-8-v&1>#x#ALWrFgNpUfdv> z`#$KqPV!A+op_h{OOZ3GGyUI)e-u9!&3zyIk4XNj_)jsY`?4glrPx~REQZA%VsDXi zsx$q5;$U%zI8q!VP7wGUQk*Kz6wUoQ^evElfw)Y(L|i9w@_(kkMZ8_STYOkF_wNYzJIODI zTqA(-KNJs%e-i&H{!>ileKx|k6wUoT?n2- zyNRcY1!9R&2_ZpNm_>ZQ`xsog$YLV0m_noHd>Dv*L^5 ztKysDyP_EnLHJK3bLw@*KPongX1oOMNgTfb&A16@#!bL3ayR29kn<#)@e{~plFj%D zWPbigJ!TvQoGE#Zc#gP4Tq>>wuaaUDgpwD_#}qR8pkspoa^ZSh0#6Y)=?8J|M@s~=zL|i9cDgKve#z?+hOm$B5&_ z8R9H)fw)NI`W}qGM*OLGwRoLq#_15QPV(*Iz2XDnuf-?CXT&`s*AHQO?}&dCKNi0b zzZ5x>JHvk~CUP7Oa;n%`Y$t}ru41lOC~~0^#vdx4DRMSoy3ZEpiWi8>#C75o;%4y% zk?WdJ&#%OX#oeMAUxfc&$#017h+GGS@&6*4@kYqW93KSRi0wtr08jVcB3B}ze1^yc zMktRH%{V3G*^;@ehZ(;XSBaO1my1`58^!Cy+r_&@P8&~s4~k}-6Y^7%pBG;eUlZRD zKM>7$DB>NG{3r2i@vkDkqGoz#+!RccoFTRo&3G#OxlRegbDDUvpEy7)6NieUMb5>+ z@KeMYA}5ch`}yK>ah14Myjwiero zUBqnhR54d95lh9v;t+A9I7XZ-P8X}hdE#R60+9>HF#qettHqy-Tf}YRt>T^Hed12> z*Wwc*7ows5SH;)Gx5b0vN8%Uam*QW=e~Ll8(n@_v;>ltMkqgz(zmHff_80jP3H>X? zu_9-|rTcX8C*pkZT=4>NnRt=7M&!ac)U#RqwfKbijJQYKCms;r75^Z9A~uL$iQkC- z5(9YAhv{-D9Q(@+ zJ>#~)JWs>nWuBMe63#r==}F>TS3sifO35&umy$Sd3@6cEDoNDqR1)QxO(LJ%_)G|o zhYT^yYKY+yLoeMnl1=&ukL($LlRo4=l1)A!BMIXl5i3NKANY@!Z1MwnrsUb;T(MfL z6<3HCiEG65;s)^=aie&hxI?@{yhprG+$laR?iQaE_mZgRm&JYJ0r4&IJ@KIUk$6Nr zCN_%y5c#q*^#{cyF-_!q+4Se!RAgA}D)to3b9DIgy=sOt&(Xn%*()0g2qX)rmJ9j4k}~qSgGByX zIw0~jk3_o|76g%x9E4^1kC8~%JikPGH}m-(^qc31(BH;_Jk0%GnEE4Q}S#Q z>8+8xoL1*Y6$?>fUxq&u^0b!b_yVHvVzaR{^ zJ}`LnW9pl7c#dVw22nL848t+K5ir!}<@Y0>E;t)Mvf8y*ucLsC;TYdb&*LJv`O{s4 zbg^4ax`_(Uc#pyO%keq%b%C3=dHLB42fx0JK7Dle%JBf~{&J*v8InT!aeEyG_E?~3=t6#6GTKn1w};` z39f*s0TEGA1EM0L21G-(Co#4V7}r%ikN}zrVc~Vs0}#(&+dq zEBO8Tk&pUeTP&Q?&jLQPen(CEH3Fy7uahCquip~LQ*Z90K&4+R$*013cwS?6N2f(3O-_lX{T%%Ma*&VmD2tBr=$eDiTn-oVRr6^J&{e*)r=x6Dj%i?0vM5LC zlO7;1(Il^xN!|o0Po;b266JWz;PaQGNS1@L=u|l#3CP!N$~QssvHai5d{sGCL!KHN zl&AFB7$7g*Brnkm#%RyOmsvKtm^362m+d=ZN9Pvn?+M4Ni zLEfXB_@q;`IPjUDSAFN^eqW-&?q% z%$&cYq;)!VKzTAyo{UhW{r>#a1 z&!0cvAg=V`^2$fwJz9yjh%PCuc>MhNV;8M^&{+R0fAzY5Ow_%q zH*>vH4(p2T_|NM6F%XhtzpLASw_aJFTBYldx<0!r z#y249BkvbuV|?rD{Gk_XTfNt}KJR_9Xsb8R^@+Z3bfKXwRo%-6IXY^8w+dHS< zc0Jg(Nk0{n>?PlN#JyW1Ne|9BrN552_uBOo{G~~~yrePi4fx+5&|CLJSL$zOrFau( zmgwaPy3Y7Hkn!V$Q~Kc>eJsEC6yk6n!Haub-YcNjI?Gu@ub55xtb_&nx>$t$dhOEJ z^*pQZQF=8o^djHI_1dNH`KNk8#szxCSiSkUUbg(HKZv>tNqSSC-EY4BaxB8oDJ1)M zl>Jlv<(_})d!f^VsH>2kZ;HAipVBEL=XXcR_^U3k^i)Q)ZW(!bU&<2V1;C*3&Em3_CXdsc34-ek9Y z+i}9=ys_8`U>qd5ut>;vukqYi{oQM}h=1)(Ym+ADk50f#A=^yJ&l+{R@#d(k{QSJ} z*>~pSU7VM3ctdS94qLTVm}_knhYOq*{0pm=!Xn;PLK@d+yqH+*rx`Y!!G9R%copV; zyODp%49wrOIRKwc3(~M{6#JmXV6ADjhd*MRQArhxlO()$225ssH(?!y)$ zJP7*)(zU$N6Gw^{R>bA_{UgWXbsKS6rk7zkojUy6wVLVMJS;WAA;j3JG#IWBHdF2~mzJSq*m+NI=iKMYy^y&n0fi*iav z;9ifvP4BCifQpZ3+Olb-;Bz99I`f{;rS^KB5WF@8bmf%1wq4qDE9ZBY-Rrgc=X$Bb;9X@>@{CTc2y)vnnSkn%tig{hn z&uXUU7N&SVo9Ff&b)42$N3GURV~$+YZ;f7*P^9;Yuha)6xxIOEj&0V@qt{AmqC4BU z^n8oe>rSoIn?)6gxiWvN+j~6ztbP`2OZn#1~;Mp9^!Rv!v+IXULcJ z^Tp0ApH@<2W17#xvV|_0TBVTV8CR?);_E!ST4wu%en&UxT!$ZdWVQZ1bbR#lH9Feh z81qO;J*89joTzm=FZu!!f5bzhS6DbA2)o=F7E< z^~(HI-IgO?>cTo^-h-fns_T6CsSEX@J_paAZ^^ZW{I0~u%eiLY9%UH$$>WQ`{@{PH zj-B)06?>rS>rR({wB)F^Atv!gn_PQ%yCA63px#=r9dG@#g#9O1o~l&^O2GZyx?^xy z#JteU2;eVQBIA5$rdQ2327Qo;pYuwNDa`aZgGpz|pQeIR{tQ!?={K9gOuxkxCcVTI zCVht~O!|IPnDm3DFzLrlVbUv2VbX^)QaGc0nWix5Ii@hZ<4j@Fr_@2`sCzQ|ab@GKkAHPK&d0gG_4Pc!TSa$U{D#W1%w*zs`JBK9!V-u9&e zd{aDM3idC!i|t>E{pB$Bg%lTq3tDh5AzY=2hY_UFHOIxhz~%T_gGZ%-SG$zF!2JvP zu3`e|l#Iar3!hC_%_miPk>9NPaPV<|Nu4|6Vmop#9C)wlIQBVh5U-rdHw&LO8HIaP zY6Ek*{ma$uukLK{UjAOyf;u8M|Nf;l-sO1y_jB(vwz#;s;Gg*GqHHV^{#rPHSz_?# zMutt!Y7gQ&*KPI?4l$c0cpbpbE^3X(Jzc~&iU`)A@uXWrHk1Ar>cHBX4QX=(4Isf0 z(t=B9Khu$#Gh+4JBNhaKwF^zOCc24dT9ls`5p&LM|)H7(itV?Lq0=N zN0Ae&-kD=?vf_>~ya<1glDrNmCUW`?flC&Zg^G4iO4oq=SVKmBT}6H^AkWCJtDX6= zx{dt0iu`U@`Tce2{AzIYT3Xmy_?i?@lZ{l9Eu+;aBrU;CbpvU&_!Pv_L1;+v2Ax{e zWKp%+uae$H&;x0jrG}+xRIPAZRKuvjSJbdLX^b1Eg@<1kZo_0?lU_Vqx7XEdQQg9? z3GahRI;fV#78M@Opantv1W?hsgu{ZK2O0I|A77eYKcT_V7MZ1_q z_Ni4(s1rh|s}x$p%-UUKTQf)qsb!}0sb$b=2S%d$=rD(1vgYGK(djPy=$*kZz|2tn z^L7S9hMA%IH|-3D|7P*G6~%`Z?AJy!2#=iHt760)RE^`G^YN2$R`DU>zxiYuR=oe6 z?~DB>zgC806V_?&IQ*X@Lq+;OM}}G_gZM5P#<-|s+ZuCK_=J>y=L0-SmU@dSa-c#~ z;fCHf2Yi-BF*9TJ5>;|v_+gX(e!#~30UL9JqJr62Bd4e@#)xm$kRz~Gt9^t7hd8W_gaHl4|T7%EVOfh}%iCL-E&YOJaq?{?DwF5g7B@5L=rW9uWtdjBl zsA?Ks_;HvB%qZq>!!WEIr=Nc{oYWqP{uAFbF}GLX*AuGIF7nNU3+Up@4CYF|m_*ee z7yFn+wY1F9FEOyqE++W`o=fO_QNC(9nMeGka;nDjH#uFv_uubHT=+c+HCBlK-~WCD zPs3Hth98}WRR!VW-o47%a3@3E+c09WV>LOOc#CsY1iuGSU7oVWGq2`QnwVIT!N%|Mg8Al-nX8>_!+n z6S0-!`}F$;(1%x}M^!z{K|JNntwyhNHI^0FQgs{^-^!r3gq@~vDqh~W zX~~=BbchcI;L`$Pt-_~HMK31umJ5+>W<^(GZ^0)AjCYG8p7)4I=W|P9szjKAiSQ7K zw@4f(ak9jz67Q8bTjG3)3nea-_@cxO65o^ft;8QCo*<&0g3*!qTa3CAn@Qw17f2sV zgx-^gsJ{m#{V9nrNn9uCyNKZbnuvNmDe0$VJZ+JgAHQNvz8W%Imk55|b7j1EXC>-C zOVatJYsTLp!&7CrP=>`jE5ZMwjNc~ldx_^HqS&Hb9BV8ej@$x~wZIsOO(nLLm?$w> zVv0oG8l#*65=RkHPh%xcl9(q^v>)gkgXDWu;^Puukhn%-vBZrMKO#ceof3CT{7T{x zi9bu!C7zPV+c``hA+eUkD zE-{#TV6bqWVZCv-W<9uw&?}yZ^mL@Fc5*NbKJFEXB0c!Y%5*{w0*x33hB7~-Z$JdU z=+EHmF7*)UVr4q;#W5YiB7g9Al;JK?elHnLB{K0pbm;10u4cLEDA(-JErpB0U#RB4 z4<5)z8Xc!7)&aBcXYw(<%3I+G#F_JrL%wWN<{KjUneG`}=5n|t4IrG-XC^{sc^ysVV7w~F zV))JF=q037{ZZxEXz=;VK|bn3S#+u#9G~WVyPL|vzN+#)4Zpb@Y#${9UVpuo!f%$> z*HjMNTlCBO1%7im(h)X0RSwSU`0p(4jakmv7LLrpR$ zPqjz40C_p4a&U*I>Sd^ur_yonVs;=4S77k@%RxStL+ut-IrxmzTn@f-$O%67tGc*U zzN=-vh!QRbe;cSl1;5Jo`2cx*chL^SQC>YXzG zvwp`R&kZ`|VVU;JI};#p5#*^SEMW7?422A9&0`v$Q3ZRNkkWbvu$ zJcuWa7xxurK7K2K{XjXz*Ff^A_)Xw5JMz&b1n_MJpLxttKf0FSGnb<;%Hd`_u4cGY zIj#X8x=1dfgyTCRJE#Cq<;$^W>XzCy;NyF|l~a5~Q?xcWQqw$$XodKuxR@`?PuUMJKF!O(*K;Y%f)T#+qJ*ClkuSP^3N$}bJ4+V(~bh-wOI6+Ha}JN zf1)@jB_hT8_!Xg7E&J~Dv|>xE@RQD9cjfy9bCWxlCLIg6*?KMwX}7yLWmw7&>$N7O zLw_2YHt+~tDy`|jA3)hU)9&W_GbV-#>OcPCBhUQwE;4H+(!f1%Ln8omv)oGBNCyl)WkS#yL8G(&+W% z>=fI!#VMzDN1k+t2A^~~I;8CKQ+xKVqBgy{k}W(Z`xpWic7XZ*%9b&Nlp>1aD!-t8~)g>p%rY^THyiD|DY8dTH6~-joSa{ zBK6N2iahBOZM6V?t;xmeIj|krR{u&num#ZX&<3o3wgdBJJG}NUw?my`{8Hgj4w>TD zY8P<4EGk}-GB2gkvN|aZmp@p~(rWr{J9-=HEIc+PDy1;xlb=Iu(XCp4gOM`4J~U5q zpB!XC|M`7)VoJM|?d8;rM(h6+FwJ?p+i!3{v2fM&?~x?Ti;Xg;z?)t z7PNEKDEcwwReUzem-5?gt;xxHrNb>9YMgc+ceZ-u80Ngw&IsS`p(!^*H)9;@^~%6e z6YuF~r-|nYSe|=L%q_7@`rF?W`Z7=)DL@UNpD0Hz|AHOE$rWD7kmM5W! zrE9O~7QMcC3G;~U$>;EQSIX-tiQ^odhoD5yBv)y}zA)mV6s-yCu5@^kI~2(JJB5C3 zds^veedbI(YIqWwR%z+oZF$DF@=0hI@v8O7Ilx;|x~05vq*bW16Iw}VyY^>W1B}Mt z!M$E?h?)wCZq?(%v(x+X<8)uba@<;c{Z?H%GM(_O#RAPz~6KmYnk2hBKn$TJ643Y@Nl!EoU;GmLT}xBHU8S|AxFSy zw*>Q`YvWxJTRhiCyTvhwU=8AmXSaqd0@!HjWos=GI*=g_K9!w1?DV zB1>>HCJLv&Rd3L3v{$gV9Sv^~Kce9aO6B=Cn48+5KJ;qA1HclL#w=h8@&cd&mtz6` zT%*}|S_tY}jK85yOE-RhGI$gMmTTz60fh8A@CtsI#TP)BrF$h}!^DrD`;#jk>!@Wp zA7Y2oa-_d_oQ?Q!VK~xXSPCH+L9;JQI@dfGM27Q0nI%0N$)+F}5ku+#GSjFf9JkgG zoQNQI5|NNQkSVhnm@pc_K@4s{Fp8cWT(wCXKQ&jgWaS}UDT2`p@W+zPU=3VOuC$$T z)fhhsY-1Q-vldy#(p#%9NItZBZA*rI(Zc(JYg-0b^ASqNU%04+_`@3p(~+c3{zQnl zo3&$GwB)|J<3Llv)%VpIKUK3#H;9`VYOh)DVbHoLwN^b~U^df4Hq)5PT97Be^9yn@ z%Cm&p^~PnC=V=D-#s%{SrN{~?+$h;IRV7;~N>&P)uAqyR>~6|%^0pI8W|V4u^-{^8 zEY*hUrFvbJst6(iv#2T+K8AM_G_KFFP|t4s9mfcE$NEi0EG30agcytHy6N;S=SS*9 zzxs;(>J?l@zxs+@Wgdt|zuL!M&>ST+`qe)6tEmV!5C@X48MH3a8i-!@H6>XW*&B*Z zwx6BMy2!ykc7ReABbm|1zGW~qSXIkG>S9~8S~m7~MsV|ebti(&@;!rS-nuVS?;m6c z4X9Z>%cC%rsqpgeRlUhOI*{*j)MXxj$-LOS!Y}hGXRh@zsqf5jE zgCs(Z@D3($>auBfI#<%O(1<525#Dsda&$C{HkeQ>yy*nvkUW@h9G8$m4`&l_6ZlOg z==tOSaC?eKHG6ZfCt=R&jx7kLU$ zle2KqUj%$s`VDEuUv6d4A_SxV+@z?Sn-c}~7DB4J#%n@$+?mq_5h1^ za|AMMB=Sxt#Ni4?Ro$t@uB1N!SEP2AHeG833*J~pZ${LX3!@pu@X?mUKD}5az$CF8~FDEQbf)ByA^WNT)0q|1S99cgqk8v27%>9 zV-qL|6JPF1dbnk|a0-YJ;sz4Lo<_VR0|C@Dt{ZS!w1IsA8MrtYh(|zQvS|o ziek;PkFkFld7#rFU*ULv+fZu|p%*SFn+=#Pyh8{c;mtS;pd#p9jR5>KH>!Zp9Tz%J z(S01W?EmPC1ZFGZ>2Zs?8N@!6W_Te_xCZ!ZH0^K>PmVt1L10x`wBZD+5IcxfV<>Sm zm6$DJ#bRURdlR9=h-I!k2BJh&x%zuA%L^i$UHs)A&YN`Xd&;o~yozfRu3vDO-NpF1 z*|utrg7bf3;hH~r@&uURjh_U|&Af?iCXAnS=d?CilXCJVkIxyMl|8;q$Am6zbMr=L z-#LCle%qX^yt~FvYBQ}%=aHQ|ww*9OyY1Lfqb{DXEfbEPG-|?~IivsIG_o~rGNV;# zT$?j`3~XxATz;clRKMTo7A;G|lyMq%+NQc}VF|-DtKHI;f39hN z6`@J63t$ay#=kcu@-M{Ot)qLy#9q~I(TkrPMaYtxxW6@HWBF%A6<1-RH}R^(m_}`H z{p5Y}8Io<03AVcus)=vTgrlnxj!sO3_?1$8>%>n;e~f<$tC%P~CZ^F1w|?@P6+e)) zr~>V`Si0My5^Q-cTU7T>w$KFI)C6i~2~JC(h~Ostd((CNTO_JuB=_}Z&%)4Jm>X?vzwp7_q!qy{GGbKTfZqSRI9th6k>zzUk?tT2Z5 zo1XqVmd!a?`B@rnTD0e%4%MtzX<&4rb@PSRwg0tZHd`^{23C8HL}k95kkD4xs86O@ zIxjh<4P$m;J6z2`xT?*oMJp3#+&#-hD@i-%@l!{SGR&9RSa>3(EZr|}$*io@{1(iV zkUhSd5New}Ve+Wk(aUg;0vV5+oR{yarWkI!jm;mYVSdJ~iR*jz?B7N4 zQ<2%WnG2C}Tu_pu;%0|F;FuHgVDQ|ahwSrg^R16qlA@-W`M5w`f^Xb^)YjQty%)3W ztwz6uRqq8ne%s-Is=rtUfh?EE<6><84;l`e_aAochk#HxXRfAs5Xp*>hd@;s+=u=Y7;jI%yd5K zu5z>sHoFV$fN=-ON^<{mN+eZ|rOXhJv^q5Qd`GM#jWl zL>PE1hYmzKzkO_DfI9z+zfpTvQZeya>mka&lTzek3}u@mW@l3^b0DCcD&-KE#1Qmt%4<(V zJRh$xd>;|*{uB{%Uz8}mnGX6JGQ3@)_*OdNzh)Ttr;O*jvzfjz5%Fy#UL!F>(z7Iv zAtGPCJCpdL#2pfUBSKCLbS2VJZ$t~^oW*doM4pKm=CPF6L}GJ^yc5Cr_7XXU8NOCx zFNvuV`Q(pu(QkpG-vUR-_^}dimzXCJTL+QuUWtVg7fM_#QS@KPutRc}Qk+(0%r|ibt z%5YbS*GlXqF;!xQ#32&JxPqK48Rj!m%DqeCOo_83&X*{T=-_)=hF3@w;|}pW_*2eC ziM+GG@K%W*O8i3Nml6+3^hneto|1S@qE(KkFp1*+66Ev#Ci9`48Id=chzSxqOY9~w zSt9RokguP_42jti$4HzcF;5~N(K6jkiE|{*lPKm1(4UmyXC#Vy(1_n4!BsQ1GcU-evYM$yW!+bi-_&yT( zi*SYqNxVhkNQq-4-X>AZci_KQhG$EhEAdf@k4s!C@fnGHFw1#ry~NEDw@Caz;>Qv{ zm$*mbw-SGl_@l&Q61@_Cm&l2Z`Pn7%)eHM!F-$^_y@uE zmB^bylou*7Qeth1^(699Ir&;iY%j61#A_ucNlca4SK>g4H%ZKtm?M$T-YI{pP= zNaRCy(w9hFDe*apFH3w);wFi2OWY>$BZ;3$+%54NiQh@&yBL|@QHhljeG>nacwS;i zu)!ZLv8Kej5*tg5mDoaJ8;PAHc9lpg0_NXW;y{TvNgN?DTO#d^$v;uz42cC2X+KQ* z6B3t8ERy(=#Fr($E%7~xpGn*;k=6;6_lv~eB>o{$!?B2TzTJixE-_kSU5O1O#z<@` zv9-iRiCraLE3ucvREYy54wg7vVx~lzPf(935~oX?De(b`4@q1oak0c@5?4xmQQ}&O z>m|M+af`$fi62Y+RN@|q`y`^;#P4xnYX~lg7Uvo!=*T}NhwOxl!C&%W8Wt{)k2JdG zxLCH!@u{;R>x+)^c+ON#<=Yw&JbAk%Va8RO=7OIW>yj7qOTk4QR60JmFgvB+ZHR=w z>UR|2V|vP=Q#b~GbH2-wFWc0G3r+3McRl=+t;&%DdFBT$N}qY)G0R(LDhK0LIbM?T zRJx65TeDN;_}t+0mxFvP2W8Qza_ofPobN7EIoS79zQ4h*WW%d%fxIrJycO*vXl8i_ zA#Wj+bs?VjKa@NR5~wtY)_mx*OHC2VTPuL?5hzu`3YJdsMZ;sxcS0=kMT84{I9~bl zjSY}D1p_5s$|5Lve9~u@cea%=mR#V$anUcYQ-Hi>ke3L$a!Ovi0C~01aou2Y;o>n( z)ywq(@;-&UOjBP~^7suQvwk#tRQ->4ev~|($C*ay)CzM#vFbdCCym#L0KRW=Af!Cy z6yI3Mr{ekTNwXs#9nbm7&+u{ZWzr)Z^`qmt#axaYl*5I1UYzSxIp%^7)sTxQ;re1? z>YxHZkcDGgo2pB@4}41$5j5o`nyNvohkH7VhyifUW4DCawEzd?M9l<^R#NSZ61!=-~hb>(EiJ^}-*g)cQ|A?i+ zYy9O8k0YacLJ>mST%TFRUnpW0bD1k0oSXpH3HI4WC z)wJFl0qbah!?wr~47A%8*@>`}S)nLX z50>dL;*B!(pkADxjY9NbA%-$2%y!*O_85Y-xZHgWHSa{kMRn9_bCl>{(IVJ$qMpGY z%Z>OWwi}k^38)64!Hv{_w~7r7ZlngmR8Q3EjjUBSgQ8aZQ6b)EFlx0QnKzOu^y^3c zJh*Cc>&IhQ9CG>ls$8U@y98^sTO!5PNTEe_#ve--{%9`xmLE`>W{LJ^NVIE54mz{;wW1I#I_*NTxc!<;h1lrqDdvU+tHDF>QU4m714 zXiizZ9=XFtaR{8njdIf0!XOZMV!g1Djg$k-DF>{qN;$xsvU)jX6yA^HoEO0vHYxdVWoP3d<|_-GAIdaUr@%P7AS%e$6NaN)YJ zY7B+}W`^oDU@&Bu8LAi5U>Im-s9qjJZ~WdzDiPTKCEaeKSL^@A0Q>*%7#4SlP&aHI z45)Hr^_ukD>v^4cns)+*C7_+(^T`HdyqBc7ZydgNVs`0~=|Jo&cPf60iH z=>zRayINwl;6A0rZ;#o-QnziQ6`wlt$9$$)VjIWC^lOWX)->yl{emO0%Xl)nXr$`N{brIEF5U*&i-s&ce><^A<47h2_o z?_xHu)#a%@q>+p^uhr#634L4prSgeUmAjZtY<2n7rO`&VdQ2@LziMvclbkAdp$%Itq7TwiDt%v+Yq zQLbABfDHEy2#-RT>Dg0g6Fen=exIaw6!a+Zeo)0ic`v8{kl}Z5QJxD|O&EIexu|la zAI4RsZ$0gIMFf(5!6v%OGC5!^P|I@l9f*0g{~I%9^R#c?LeOuXv{fe6_bb(7%^Qt? z$yhQ5#EML+Ps~bU^;lE~M?e^!zqo*ziTDHOx0h~boEsY>p0{oqcMxQ)C2yqAfzGkb zbWEBFI{Sa)PR6_68uP9;TuY~cDSQlfz;m=PEL(qjj-2(Jc0~~Zdcege%`ja)@ zcot0LJpv+6^i~Xu7-Dm2kBxYU6!avCDG~=t940YK;uwkSuarAoVxh#j5+9ZLq{L+s zUzE6B;=2+*k@%y;lM;pfDDvU+XB?@t8;KZn!zJD>ak|9&h~R%nhPjDjn9oL;?j?!q zh>&OF$sF`hBHAy82);y#JtPYIOT-V9d{ZSpKt%faM6~B~MDPjwN#Ir)E|vHd5&S>M z@Gla*M5J$u+tI|fMDTSYqVaDeLZ0{`DlkjZZ_Ibc4)HTDjr66WY zTqF_AE!qRg1ac^`eWE4CNNg&R(d3Vi$mf6z)2@Rk z-p>pa?`H;HE#t3|m@F|xA|D(woftR3Q8G+B2gcta@lJ^|Bo;{IlScAADN)!}BfLt6 zUzYfq#7z?4mdJ;S?ALt%1@UW%-%6~I_>;s+i9U(q4jR&h$#GIcqWC=o;;)k7CK6jp zOpxf7*h}IK68lTMS>mk{b0m(FDD0_`kFci(ig6EoNYWpdD1LW=cwtWs6!z3WJ{V=W zH%ly$D1MKD_+2tA<_Uy7GJII#afy`@u?Z35*)B0$BEMhAan5I4|DTKpzmV5T$^(B#rbifC5s|K! z45t#2Z>9|A5Fw{PhG!FHIpDpl;|TyNho8XdMYVlQ?% zKJIG*^Nphb>Fg4@zVOuNmf>{`j5ffQP_z;G*hYPDQJ&IwDEwxp^vgvg{C+z{@-e;2 zPvHc_ne*LZ%9p29mG7JIo6C`jF#C#fN}tCOVV1YcB#-e*-Yf8%%RxQNPL*RfBF*I> zAIm{mbgCTu-H|!pgQk3`r^>eugi$uf3tc`ga~msp+z*=N(az3=IJO5*&q`jnl&8wS z8Z@(GUUb}7;=jK=$j5T1leo&a6`0KVMxf(zEHd93xKzGV4SD`@6ocl%rJR!2KR{k1 zle}7BR`MoDd8!b#iup}BMY|GwW_iOQqy%wn-z#yca;F{>12<_ z{dhI0gOBof%?se`jRQ3MfpUtE`!b~iX@hytHaSImDS&S%_?Daas2?5AcjkIoY^oP5 zoBnca1RvDS6^Zc22YDS-0I2fi9AYY-)*J(udqU+DAJG)89mm0*dn(pb0xs&u@>4gn zyyZCfM=BwpDK8%Q@G0xmjtK+BSEw&%$J@D6qG87S5A1k_X#{M(jCnjBI;q(N3c$TE zYSc%wXUsVL^j&xT^6)+PoQl--^Y7k%`@Z#)Cx1Wa!w(mwCnjdv@RH{>W5<4eZ>v^A z>YqDzB>U^H-}v$6mv3A;b?WinJ9j?1V%Dsy+@E~%(1Z8hd#28rGr#_P^UWJRx&Hb` z!YeEPJpRfnNn`i!ef_UzpB;JZwby#TzkGR<-=BYe;FEcIhi@q4|lcUb4n6OwxLm}&j}_uu;O+I9c%jvdGOUU*?Z$BGKP6aM5MkKb`e`IP