#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #define NEED_sv_2pvbyte_GLOBAL #define NEED_sv_2pv_flags_GLOBAL #define NEED_newRV_noinc_GLOBAL #include "ppport.h" #undef LTC_SOURCE #include "tomcrypt.h" #include "tommath.h" typedef adler32_state *Crypt__Checksum__Adler32; typedef crc32_state *Crypt__Checksum__CRC32; typedef struct cipher_struct { /* used by Crypt::Cipher */ symmetric_key skey; int id; struct ltc_cipher_descriptor *desc; } *Crypt__Cipher; typedef struct digest_struct { /* used by Crypt::Digest */ hash_state state; int id; struct ltc_hash_descriptor *desc; } *Crypt__Digest; typedef struct digest_shake_struct { /* used by Crypt::Digest::SHAKE */ hash_state state; int num; } *Crypt__Digest__SHAKE; typedef struct ccm_struct { /* used by Crypt::AuthEnc::CCM */ ccm_state state; int id; } *Crypt__AuthEnc__CCM; typedef struct eax_struct { /* used by Crypt::AuthEnc::EAX */ eax_state state; int id; } *Crypt__AuthEnc__EAX; typedef struct gcm_struct { /* used by Crypt::AuthEnc::GCM */ gcm_state state; int id; } *Crypt__AuthEnc__GCM; typedef struct chacha20poly1305_struct {/* used by Crypt::AuthEnc::ChaCha20Poly1305 */ chacha20poly1305_state state; int id; } *Crypt__AuthEnc__ChaCha20Poly1305; typedef struct ocb_struct { /* used by Crypt::AuthEnc::OCB */ ocb3_state state; int id; } *Crypt__AuthEnc__OCB; typedef struct chacha_struct { /* used by Crypt::Stream::ChaCha */ chacha_state state; int id; } *Crypt__Stream__ChaCha; typedef struct rc4_struct { /* used by Crypt::Stream::RC4 */ rc4_state state; int id; } *Crypt__Stream__RC4; typedef struct sober128_struct { /* used by Crypt::Stream::Sober128 */ sober128_state state; int id; } *Crypt__Stream__Sober128; typedef struct f9_struct { /* used by Crypt::Mac::F9 */ f9_state state; int id; } *Crypt__Mac__F9; typedef struct hmac_struct { /* used by Crypt::Mac::HMAC */ hmac_state state; int id; } *Crypt__Mac__HMAC; typedef struct omac_struct { /* used by Crypt::Mac::OMAC */ omac_state state; int id; } *Crypt__Mac__OMAC; typedef struct pelican_struct { /* used by Crypt::Mac::Pelican */ pelican_state state; int id; } *Crypt__Mac__Pelican; typedef struct pmac_struct { /* used by Crypt::Mac::PMAC */ pmac_state state; int id; } *Crypt__Mac__PMAC; typedef struct xcbc_struct { /* used by Crypt::Mac::XCBC */ xcbc_state state; int id; } *Crypt__Mac__XCBC; typedef struct poly1305_struct { /* used by Crypt::Mac::Poly1305 */ poly1305_state state; int id; } *Crypt__Mac__Poly1305; typedef struct blake2s_struct { /* used by Crypt::Mac::BLAKE2s */ blake2smac_state state; int id; } *Crypt__Mac__BLAKE2s; typedef struct blake2b_struct { /* used by Crypt::Mac::BLAKE2b */ blake2bmac_state state; int id; } *Crypt__Mac__BLAKE2b; typedef struct cbc_struct { /* used by Crypt::Mode::CBC */ int cipher_id, cipher_rounds; symmetric_CBC state; unsigned char pad[MAXBLOCKSIZE]; int padlen; int padding_mode; int direction; int id; } *Crypt__Mode__CBC; typedef struct ecb_struct { /* used by Crypt::Mode::ECB */ int cipher_id, cipher_rounds; symmetric_ECB state; unsigned char pad[MAXBLOCKSIZE]; int padlen; int padding_mode; int direction; int id; } *Crypt__Mode__ECB; typedef struct cfb_struct { /* used by Crypt::Mode::CFB */ int cipher_id, cipher_rounds; symmetric_CFB state; int direction; int id; } *Crypt__Mode__CFB; typedef struct ctr_struct { /* used by Crypt::Mode::CTR */ int cipher_id, cipher_rounds; int ctr_mode_param; symmetric_CTR state; int direction; int id; } *Crypt__Mode__CTR; typedef struct f8_struct { /* used by Crypt::Mode::F8 */ int cipher_id, cipher_rounds; symmetric_F8 state; int direction; int id; } *Crypt__Mode__F8; typedef struct lrw_struct { /* used by Crypt::Mode::LRW */ int cipher_id, cipher_rounds; symmetric_LRW state; int direction; int id; } *Crypt__Mode__LRW; typedef struct ofb_struct { /* used by Crypt::Mode::OFB */ int cipher_id, cipher_rounds; symmetric_OFB state; int direction; int id; } *Crypt__Mode__OFB; typedef struct xts_struct { /* used by Crypt::Mode::XTS */ int cipher_id, cipher_rounds; symmetric_xts state; int direction; int id; } *Crypt__Mode__XTS; typedef struct prng_struct { /* used by Crypt::PRNG */ prng_state state; struct ltc_prng_descriptor *desc; IV last_pid; int id; } *Crypt__PRNG; typedef struct rsa_struct { /* used by Crypt::PK::RSA */ prng_state pstate; int pindex; rsa_key key; int id; } *Crypt__PK__RSA; typedef struct dsa_struct { /* used by Crypt::PK::DSA */ prng_state pstate; int pindex; dsa_key key; int id; } *Crypt__PK__DSA; typedef struct dh_struct { /* used by Crypt::PK::DH */ prng_state pstate; int pindex; dh_key key; int id; } *Crypt__PK__DH; typedef struct ecc_struct { /* used by Crypt::PK::ECC */ prng_state pstate; int pindex; ecc_key key; ltc_ecc_set_type dp; int id; } *Crypt__PK__ECC; int str_add_leading_zero(char *str, int maxlen, int minlen) { int len; len = (int)strlen(str); if (len > 0 && len % 2 && len < maxlen-2) { memmove(str+1, str, len+1); /* incl. NUL byte */ *str = '0'; /* add leading zero */ } len = (int)strlen(str); if (len < minlen && minlen < maxlen-1) { memmove(str+(minlen-len), str, len+1); /* incl. NUL byte */ memset(str, '0', minlen-len); /* add leading zero */ } return MP_OKAY; } int mp_tohex_with_leading_zero(mp_int * a, char *str, int maxlen, int minlen) { int rv; if (mp_isneg(a) == MP_YES) { *str = '\0'; return MP_VAL; } rv = mp_toradix_n(a, str, 16, maxlen); if (rv != MP_OKAY) { *str = '\0'; return rv; } return str_add_leading_zero(str, maxlen, minlen); } /* Math::BigInt::LTM related */ typedef mp_int * Math__BigInt__LTM; STATIC SV * sv_from_mpi(mp_int *mpi) { SV *obj = newSV(0); sv_setref_pv(obj, "Math::BigInt::LTM", (void*)mpi); return obj; } ltc_ecc_set_type* _ecc_set_dp_from_SV(ltc_ecc_set_type *dp, SV *curve) { HV *h; SV *param, **pref; SV **sv_cofactor, **sv_prime, **sv_A, **sv_B, **sv_order, **sv_Gx, **sv_Gy; int err; char *ch_name; STRLEN l_name; if (SvPOK(curve)) { ch_name = SvPV(curve, l_name); if ((h = get_hv("Crypt::PK::ECC::curve", 0)) == NULL) croak("FATAL: generate_key_ex: no curve register"); if ((pref = hv_fetch(h, ch_name, (U32)l_name, 0)) == NULL) croak("FATAL: generate_key_ex: unknown curve/1 '%s'", ch_name); if (!SvOK(*pref)) croak("FATAL: generate_key_ex: unknown curve/2 '%s'", ch_name); param = *pref; } else if (SvROK(curve)) { param = curve; } else { croak("FATAL: curve has to be a string or a hashref"); } if ((h = (HV*)(SvRV(param))) == NULL) croak("FATAL: ecparams: param is not valid hashref"); if ((sv_prime = hv_fetchs(h, "prime", 0)) == NULL) croak("FATAL: ecparams: missing param prime"); if ((sv_A = hv_fetchs(h, "A", 0)) == NULL) croak("FATAL: ecparams: missing param A"); if ((sv_B = hv_fetchs(h, "B", 0)) == NULL) croak("FATAL: ecparams: missing param B"); if ((sv_order = hv_fetchs(h, "order", 0)) == NULL) croak("FATAL: ecparams: missing param order"); if ((sv_Gx = hv_fetchs(h, "Gx", 0)) == NULL) croak("FATAL: ecparams: missing param Gx"); if ((sv_Gy = hv_fetchs(h, "Gy", 0)) == NULL) croak("FATAL: ecparams: missing param Gy"); if ((sv_cofactor = hv_fetchs(h, "cofactor", 0)) == NULL) croak("FATAL: ecparams: missing param cofactor"); if (!SvOK(*sv_prime )) croak("FATAL: ecparams: undefined param prime"); if (!SvOK(*sv_A )) croak("FATAL: ecparams: undefined param A"); if (!SvOK(*sv_B )) croak("FATAL: ecparams: undefined param B"); if (!SvOK(*sv_order )) croak("FATAL: ecparams: undefined param order"); if (!SvOK(*sv_Gx )) croak("FATAL: ecparams: undefined param Gx"); if (!SvOK(*sv_Gy )) croak("FATAL: ecparams: undefined param Gy"); if (!SvOK(*sv_cofactor)) croak("FATAL: ecparams: undefined param cofactor"); err = ecc_dp_set( dp, SvPV_nolen(*sv_prime), SvPV_nolen(*sv_A), SvPV_nolen(*sv_B), SvPV_nolen(*sv_order), SvPV_nolen(*sv_Gx), SvPV_nolen(*sv_Gy), (unsigned long)SvUV(*sv_cofactor), NULL, /* we intentionally don't allow setting custom names */ NULL /* we intentionally don't allow setting custom OIDs */ ); return err == CRYPT_OK ? dp : NULL; } void _ecc_free_key(ecc_key *key, ltc_ecc_set_type *dp) { if(dp) { ecc_dp_clear(dp); } if (key->type != -1) { ecc_free(key); key->type = -1; key->dp = NULL; } } MODULE = CryptX PACKAGE = CryptX PREFIX = CryptX_ PROTOTYPES: DISABLE BOOT: if(register_cipher(&blowfish_desc)==-1) { croak("FATAL: cannot register_cipher blowfish"); } if(register_cipher(&rc5_desc)==-1) { croak("FATAL: cannot register_cipher rc5"); } if(register_cipher(&rc6_desc)==-1) { croak("FATAL: cannot register_cipher rc6"); } if(register_cipher(&rc2_desc)==-1) { croak("FATAL: cannot register_cipher rc2"); } if(register_cipher(&saferp_desc)==-1) { croak("FATAL: cannot register_cipher saferp"); } if(register_cipher(&safer_k64_desc)==-1) { croak("FATAL: cannot register_cipher safer_k64"); } if(register_cipher(&safer_k128_desc)==-1) { croak("FATAL: cannot register_cipher safer_k128"); } if(register_cipher(&safer_sk64_desc)==-1) { croak("FATAL: cannot register_cipher safer_sk64"); } if(register_cipher(&safer_sk128_desc)==-1) { croak("FATAL: cannot register_cipher safer_sk128"); } if(register_cipher(&aes_desc)==-1) { croak("FATAL: cannot register_cipher aes"); } if(register_cipher(&xtea_desc)==-1) { croak("FATAL: cannot register_cipher xtea"); } if(register_cipher(&twofish_desc)==-1) { croak("FATAL: cannot register_cipher twofish"); } if(register_cipher(&des_desc)==-1) { croak("FATAL: cannot register_cipher des"); } if(register_cipher(&des3_desc)==-1) { croak("FATAL: cannot register_cipher des3"); } if(register_cipher(&cast5_desc)==-1) { croak("FATAL: cannot register_cipher cast5"); } if(register_cipher(&noekeon_desc)==-1) { croak("FATAL: cannot register_cipher noekeon"); } if(register_cipher(&skipjack_desc)==-1) { croak("FATAL: cannot register_cipher skipjack"); } if(register_cipher(&khazad_desc)==-1) { croak("FATAL: cannot register_cipher khazad"); } if(register_cipher(&anubis_desc)==-1) { croak("FATAL: cannot register_cipher anubis"); } if(register_cipher(&kseed_desc)==-1) { croak("FATAL: cannot register_cipher kseed"); } if(register_cipher(&kasumi_desc)==-1) { croak("FATAL: cannot register_cipher kasumi"); } if(register_cipher(&multi2_desc)==-1) { croak("FATAL: cannot register_cipher multi2"); } if(register_cipher(&camellia_desc)==-1) { croak("FATAL: cannot register_cipher camellia"); } /* --- */ if(register_hash(&chc_desc)==-1) { croak("FATAL: cannot register_hash chc_hash"); } if(register_hash(&md2_desc)==-1) { croak("FATAL: cannot register_hash md2"); } if(register_hash(&md4_desc)==-1) { croak("FATAL: cannot register_hash md4"); } if(register_hash(&md5_desc)==-1) { croak("FATAL: cannot register_hash md5"); } if(register_hash(&rmd128_desc)==-1) { croak("FATAL: cannot register_hash rmd128"); } if(register_hash(&rmd160_desc)==-1) { croak("FATAL: cannot register_hash rmd160"); } if(register_hash(&rmd256_desc)==-1) { croak("FATAL: cannot register_hash rmd256"); } if(register_hash(&rmd320_desc)==-1) { croak("FATAL: cannot register_hash rmd320"); } if(register_hash(&sha1_desc)==-1) { croak("FATAL: cannot register_hash sha1"); } if(register_hash(&sha224_desc)==-1) { croak("FATAL: cannot register_hash sha224"); } if(register_hash(&sha256_desc)==-1) { croak("FATAL: cannot register_hash sha256"); } if(register_hash(&sha384_desc)==-1) { croak("FATAL: cannot register_hash sha384"); } if(register_hash(&sha512_desc)==-1) { croak("FATAL: cannot register_hash sha512"); } if(register_hash(&sha512_224_desc)==-1) { croak("FATAL: cannot register_hash sha512_224"); } if(register_hash(&sha512_256_desc)==-1) { croak("FATAL: cannot register_hash sha512_256"); } if(register_hash(&sha3_224_desc)==-1) { croak("FATAL: cannot register_hash sha3_224"); } if(register_hash(&sha3_256_desc)==-1) { croak("FATAL: cannot register_hash sha3_256"); } if(register_hash(&sha3_384_desc)==-1) { croak("FATAL: cannot register_hash sha3_384"); } if(register_hash(&sha3_512_desc)==-1) { croak("FATAL: cannot register_hash sha3_512"); } if(register_hash(&tiger_desc)==-1) { croak("FATAL: cannot register_hash tiger"); } if(register_hash(&whirlpool_desc)==-1) { croak("FATAL: cannot register_hash whirlpool"); } if(register_hash(&blake2b_160_desc)==-1) { croak("FATAL: cannot register_hash blake2b_160"); } if(register_hash(&blake2b_256_desc)==-1) { croak("FATAL: cannot register_hash blake2b_256"); } if(register_hash(&blake2b_384_desc)==-1) { croak("FATAL: cannot register_hash blake2b_384"); } if(register_hash(&blake2b_512_desc)==-1) { croak("FATAL: cannot register_hash blake2b_512"); } if(register_hash(&blake2s_128_desc)==-1) { croak("FATAL: cannot register_hash blake2s_128"); } if(register_hash(&blake2s_160_desc)==-1) { croak("FATAL: cannot register_hash blake2s_160"); } if(register_hash(&blake2s_224_desc)==-1) { croak("FATAL: cannot register_hash blake2s_224"); } if(register_hash(&blake2s_256_desc)==-1) { croak("FATAL: cannot register_hash blake2s_256"); } /* --- */ if(chc_register(find_cipher("aes"))==-1) { croak("FATAL: chc_register failed"); } /* --- */ if(register_prng(&fortuna_desc)==-1) { croak("FATAL: cannot register_prng fortuna"); } if(register_prng(&yarrow_desc)==-1) { croak("FATAL: cannot register_prng yarrow"); } if(register_prng(&rc4_desc)==-1) { croak("FATAL: cannot register_prng rc4"); } if(register_prng(&sober128_desc)==-1) { croak("FATAL: cannot register_prng sober128"); } if(register_prng(&chacha20_prng_desc)==-1) { croak("FATAL: cannot register_prng chacha20"); } /* --- */ #ifdef TFM_DESC ltc_mp = tfm_desc; #else ltc_mp = ltm_desc; #endif SV * CryptX__encode_base64url(SV * in) CODE: { STRLEN in_len; unsigned long out_len; unsigned char *out_data, *in_data; int rv; if (!SvPOK(in)) XSRETURN_UNDEF; in_data = (unsigned char *) SvPVbyte(in, in_len); out_len = (unsigned long)(4 * ((in_len + 2) / 3) + 1); Newz(0, out_data, out_len, unsigned char); if (!out_data) croak("FATAL: Newz failed [%ld]", out_len); rv = base64url_encode(in_data, (unsigned long)in_len, out_data, &out_len); RETVAL = (rv == CRYPT_OK) ? newSVpvn((char *)out_data, out_len) : newSVpvn(NULL, 0); Safefree(out_data); } OUTPUT: RETVAL SV * CryptX__decode_base64url(SV * in) CODE: { STRLEN in_len; unsigned long out_len; unsigned char *out_data, *in_data; int rv; if (!SvPOK(in)) XSRETURN_UNDEF; in_data = (unsigned char *) SvPVbyte(in, in_len); out_len = (unsigned long)in_len; Newz(0, out_data, out_len, unsigned char); if (!out_data) croak("FATAL: Newz failed [%ld]", out_len); rv = base64url_decode(in_data, (unsigned long)in_len, out_data, &out_len); RETVAL = (rv == CRYPT_OK) ? newSVpvn((char *)out_data, out_len) : newSVpvn(NULL, 0); Safefree(out_data); } OUTPUT: RETVAL SV * CryptX__encode_base64(SV * in) CODE: { STRLEN in_len; unsigned long out_len; unsigned char *out_data, *in_data; int rv; if (!SvPOK(in)) XSRETURN_UNDEF; in_data = (unsigned char *) SvPVbyte(in, in_len); out_len = (unsigned long)(4 * ((in_len + 2) / 3) + 1); Newz(0, out_data, out_len, unsigned char); if (!out_data) croak("FATAL: Newz failed [%ld]", out_len); rv = base64_encode(in_data, (unsigned long)in_len, out_data, &out_len); RETVAL = (rv == CRYPT_OK) ? newSVpvn((char *)out_data, out_len) : newSVpvn(NULL, 0); Safefree(out_data); } OUTPUT: RETVAL SV * CryptX__decode_base64(SV * in) CODE: { STRLEN in_len; unsigned long out_len; unsigned char *out_data, *in_data; int rv; if (!SvPOK(in)) XSRETURN_UNDEF; in_data = (unsigned char *) SvPVbyte(in, in_len); out_len = (unsigned long)in_len; Newz(0, out_data, out_len, unsigned char); if (!out_data) croak("FATAL: Newz failed [%ld]", out_len); rv = base64_decode(in_data, (unsigned long)in_len, out_data, &out_len); RETVAL = (rv == CRYPT_OK) ? newSVpvn((char *)out_data, out_len) : newSVpvn(NULL, 0); Safefree(out_data); } OUTPUT: RETVAL SV * CryptX__increment_octets_le(SV * in) CODE: { STRLEN len, i = 0; unsigned char *out_data, *in_data; int rv; if (!SvPOK(in)) XSRETURN_UNDEF; in_data = (unsigned char *) SvPVbyte(in, len); if (len == 0) XSRETURN_UNDEF; RETVAL = NEWSV(0, len); SvPOK_only(RETVAL); SvCUR_set(RETVAL, len); out_data = (unsigned char *)SvPV_nolen(RETVAL); Copy(in_data, out_data, len, unsigned char); while (i < len) { out_data[i]++; if (0 != out_data[i]) break; i++; } if (i == len) croak("FATAL: increment_octets_le overflow"); } OUTPUT: RETVAL SV * CryptX__increment_octets_be(SV * in) CODE: { STRLEN len, i = 0; unsigned char *out_data, *in_data; int rv; if (!SvPOK(in)) XSRETURN_UNDEF; in_data = (unsigned char *) SvPVbyte(in, len); if (len == 0) XSRETURN_UNDEF; RETVAL = NEWSV(0, len); SvPOK_only(RETVAL); SvCUR_set(RETVAL, len); out_data = (unsigned char *)SvPV_nolen(RETVAL); Copy(in_data, out_data, len, unsigned char); while (i < len) { out_data[len - 1 - i]++; if (0 != out_data[len - 1 - i]) break; i++; } if (i == len) croak("FATAL: increment_octets_le overflow"); } OUTPUT: RETVAL ############################################################################### INCLUDE: inc/CryptX_Digest.xs.inc INCLUDE: inc/CryptX_Digest_SHAKE.xs.inc INCLUDE: inc/CryptX_Cipher.xs.inc INCLUDE: inc/CryptX_Checksum_Adler32.xs.inc INCLUDE: inc/CryptX_Checksum_CRC32.xs.inc INCLUDE: inc/CryptX_AuthEnc_EAX.xs.inc INCLUDE: inc/CryptX_AuthEnc_GCM.xs.inc INCLUDE: inc/CryptX_AuthEnc_OCB.xs.inc INCLUDE: inc/CryptX_AuthEnc_CCM.xs.inc INCLUDE: inc/CryptX_AuthEnc_ChaCha20Poly1305.xs.inc INCLUDE: inc/CryptX_Stream_ChaCha.xs.inc INCLUDE: inc/CryptX_Stream_RC4.xs.inc INCLUDE: inc/CryptX_Stream_Sober128.xs.inc INCLUDE: inc/CryptX_Mac_F9.xs.inc INCLUDE: inc/CryptX_Mac_HMAC.xs.inc INCLUDE: inc/CryptX_Mac_OMAC.xs.inc INCLUDE: inc/CryptX_Mac_Pelican.xs.inc INCLUDE: inc/CryptX_Mac_PMAC.xs.inc INCLUDE: inc/CryptX_Mac_XCBC.xs.inc INCLUDE: inc/CryptX_Mac_Poly1305.xs.inc INCLUDE: inc/CryptX_Mac_BLAKE2s.xs.inc INCLUDE: inc/CryptX_Mac_BLAKE2b.xs.inc INCLUDE: inc/CryptX_Mode_CBC.xs.inc INCLUDE: inc/CryptX_Mode_ECB.xs.inc INCLUDE: inc/CryptX_Mode_CFB.xs.inc INCLUDE: inc/CryptX_Mode_OFB.xs.inc INCLUDE: inc/CryptX_Mode_CTR.xs.inc #INCLUDE: inc/CryptX_Mode_F8.xs.inc #INCLUDE: inc/CryptX_Mode_LRW.xs.inc #INCLUDE: inc/CryptX_Mode_XTS.xs.inc INCLUDE: inc/CryptX_PRNG.xs.inc INCLUDE: inc/CryptX_PK_RSA.xs.inc INCLUDE: inc/CryptX_PK_DSA.xs.inc INCLUDE: inc/CryptX_PK_DH.xs.inc INCLUDE: inc/CryptX_PK_ECC.xs.inc INCLUDE: inc/CryptX_KeyDerivation.xs.inc INCLUDE: inc/CryptX_BigInt_LTM.xs.inc