From 4c945eb174419f72d04bd70a883308cd24cd9ac4 Mon Sep 17 00:00:00 2001 From: Adrian Grigore Date: Sun, 23 Jun 2024 01:15:51 +0300 Subject: [PATCH 1/8] Make.win32: add -fcommon --- Make.win32 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Make.win32 b/Make.win32 index c032b33..8a217d2 100644 --- a/Make.win32 +++ b/Make.win32 @@ -10,7 +10,7 @@ CC=$(MING)gcc AS=$(MING)as RANLIB=$(MING)ranlib WINDRES=$(MING)windres -CFLAGS=-Wall -Wno-missing-braces -I$(ROOT)/include -I$(ROOT) -I$(ROOT)/kern -c -D_X86_ -DIS_32 -DWINDOWS -DUNICODE -O2 +CFLAGS=-Wall -Wno-missing-braces -I$(ROOT)/include -I$(ROOT) -I$(ROOT)/kern -c -D_X86_ -DIS_32 -DWINDOWS -DUNICODE -O2 -fcommon O=o FS=fs-win32 IP=win32 From bb00700fc815c1acc92742a59b58be75dfb8f41e Mon Sep 17 00:00:00 2001 From: Adrian Grigore Date: Sun, 23 Jun 2024 01:21:28 +0300 Subject: [PATCH 2/8] include/lib.h: define u64int --- include/lib.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/lib.h b/include/lib.h index ad5c24a..9a50aae 100644 --- a/include/lib.h +++ b/include/lib.h @@ -35,6 +35,7 @@ typedef signed char p9_schar; typedef unsigned short p9_ushort; typedef unsigned int Rune; typedef unsigned int p9_u32int; +typedef unsigned long long p9_u64int; typedef p9_u32int mpdigit; /* make sure we don't conflict with predefined types */ @@ -43,6 +44,7 @@ typedef p9_u32int mpdigit; #define ushort p9_ushort #define uint p9_uint #define u32int p9_u32int +#define u64int p9_u64int /* #define long int rather than p9_long so that "unsigned long" is valid */ #define long int From 15a79f4db957e04ddb129723d0bc7767da6f13c5 Mon Sep 17 00:00:00 2001 From: Adrian Grigore Date: Sun, 23 Jun 2024 01:35:26 +0300 Subject: [PATCH 3/8] libsec: sync with Plan 9 --- include/libsec.h | 282 ++++++++++------ libsec/Makefile | 4 + libsec/aes.c | 727 ++++++++++++++++++++++++++++------------ libsec/decodepem.c | 32 +- libsec/dsaalloc.c | 3 + libsec/dsagen.c | 3 - libsec/dsasign.c | 6 +- libsec/dsaverify.c | 4 +- libsec/egalloc.c | 3 + libsec/hmac.c | 39 +-- libsec/md5.c | 7 + libsec/md5pickle.c | 6 +- libsec/nfastrand.c | 2 +- libsec/probably_prime.c | 69 ++-- libsec/readcert.c | 22 +- libsec/rsagen.c | 34 +- libsec/rsatest.c | 13 +- libsec/sha1.c | 7 + libsec/sha2_128.c | 191 +++++++++++ libsec/sha2_64.c | 187 +++++++++++ libsec/sha2block128.c | 101 ++++++ libsec/sha2block64.c | 92 +++++ libsec/sha2test.c | 63 ++++ libsec/tlshand.c | 75 +++-- libsec/x509.c | 350 ++++++++++++++++--- 25 files changed, 1820 insertions(+), 502 deletions(-) create mode 100644 libsec/sha2_128.c create mode 100644 libsec/sha2_64.c create mode 100644 libsec/sha2block128.c create mode 100644 libsec/sha2block64.c create mode 100644 libsec/sha2test.c diff --git a/include/libsec.h b/include/libsec.h index 7c187fa..04ca62a 100644 --- a/include/libsec.h +++ b/include/libsec.h @@ -1,11 +1,16 @@ +#ifdef PLAN9 +#pragma lib "libsec.a" +#pragma src "/sys/src/libsec" +#endif + #ifndef _MPINT typedef struct mpint mpint; #endif -///////////////////////////////////////////////////////// -// AES definitions -///////////////////////////////////////////////////////// +/* + * AES definitions + */ enum { @@ -20,27 +25,38 @@ struct AESstate ulong setup; int rounds; int keybytes; - uchar key[AESmaxkey]; /* unexpanded key */ - u32int ekey[4*(AESmaxrounds + 1)]; /* encryption key */ - u32int dkey[4*(AESmaxrounds + 1)]; /* decryption key */ - uchar ivec[AESbsize]; /* initialization vector */ + uint ctrsz; + uchar key[AESmaxkey]; /* unexpanded key */ + ulong ekey[4*(AESmaxrounds + 1)]; /* encryption key */ + ulong dkey[4*(AESmaxrounds + 1)]; /* decryption key */ + uchar ivec[AESbsize]; /* initialization vector */ + uchar mackey[3 * AESbsize]; /* 3 XCBC mac 96 keys */ }; +/* block ciphers */ +void aes_encrypt(ulong rk[], int Nr, uchar pt[16], uchar ct[16]); +void aes_decrypt(ulong rk[], int Nr, uchar ct[16], uchar pt[16]); + void setupAESstate(AESstate *s, uchar key[], int keybytes, uchar *ivec); void aesCBCencrypt(uchar *p, int len, AESstate *s); void aesCBCdecrypt(uchar *p, int len, AESstate *s); +void aesCTRdecrypt(uchar *p, int len, AESstate *s); +void aesCTRencrypt(uchar *p, int len, AESstate *s); -///////////////////////////////////////////////////////// -// Blowfish Definitions -///////////////////////////////////////////////////////// +void setupAESXCBCstate(AESstate *s); +uchar* aesXCBCmac(uchar *p, int len, AESstate *s); + +/* + * Blowfish Definitions + */ enum { BFbsize = 8, - BFrounds = 16 + BFrounds= 16 }; -// 16-round Blowfish +/* 16-round Blowfish */ typedef struct BFstate BFstate; struct BFstate { @@ -59,16 +75,16 @@ void bfCBCdecrypt(uchar*, int, BFstate*); void bfECBencrypt(uchar*, int, BFstate*); void bfECBdecrypt(uchar*, int, BFstate*); -///////////////////////////////////////////////////////// -// DES definitions -///////////////////////////////////////////////////////// +/* + * DES definitions + */ enum { DESbsize= 8 }; -// single des +/* single des */ typedef struct DESstate DESstate; struct DESstate { @@ -86,12 +102,12 @@ void desCBCdecrypt(uchar*, int, DESstate*); void desECBencrypt(uchar*, int, DESstate*); void desECBdecrypt(uchar*, int, DESstate*); -// for backward compatibility with 7 byte DES key format +/* for backward compatibility with 7-byte DES key format */ void des56to64(uchar *k56, uchar *k64); void des64to56(uchar *k64, uchar *k56); void key_setup(uchar[7], ulong[32]); -// triple des encrypt/decrypt orderings +/* triple des encrypt/decrypt orderings */ enum { DES3E= 0, DES3D= 1, @@ -117,67 +133,98 @@ void des3CBCdecrypt(uchar*, int, DES3state*); void des3ECBencrypt(uchar*, int, DES3state*); void des3ECBdecrypt(uchar*, int, DES3state*); -///////////////////////////////////////////////////////// -// digests -///////////////////////////////////////////////////////// +/* + * digests + */ enum { SHA1dlen= 20, /* SHA digest length */ + SHA2_224dlen= 28, /* SHA-224 digest length */ + SHA2_256dlen= 32, /* SHA-256 digest length */ + SHA2_384dlen= 48, /* SHA-384 digest length */ + SHA2_512dlen= 64, /* SHA-512 digest length */ MD4dlen= 16, /* MD4 digest length */ - MD5dlen= 16 /* MD5 digest length */ + MD5dlen= 16, /* MD5 digest length */ + AESdlen= 16, /* TODO: see rfc */ + + Hmacblksz = 64, /* in bytes; from rfc2104 */ }; typedef struct DigestState DigestState; struct DigestState { - ulong len; - u32int state[5]; - uchar buf[128]; - int blen; - char malloced; - char seeded; + uvlong len; + union { + u32int state[8]; + u64int bstate[8]; + }; + uchar buf[256]; + int blen; + char malloced; + char seeded; }; typedef struct DigestState SHAstate; /* obsolete name */ typedef struct DigestState SHA1state; +typedef struct DigestState SHA2_224state; +typedef struct DigestState SHA2_256state; +typedef struct DigestState SHA2_384state; +typedef struct DigestState SHA2_512state; typedef struct DigestState MD5state; typedef struct DigestState MD4state; - -DigestState* md4(uchar*, ulong, uchar*, DigestState*); -DigestState* md5(uchar*, ulong, uchar*, DigestState*); -DigestState* sha1(uchar*, ulong, uchar*, DigestState*); -DigestState* hmac_md5(uchar*, ulong, uchar*, ulong, uchar*, DigestState*); -DigestState* hmac_sha1(uchar*, ulong, uchar*, ulong, uchar*, DigestState*); -char* sha1pickle(SHA1state*); -SHA1state* sha1unpickle(char*); - -///////////////////////////////////////////////////////// -// random number generation -///////////////////////////////////////////////////////// +typedef struct DigestState AEShstate; + +DigestState* md4(uchar*, ulong, uchar*, DigestState*); +DigestState* md5(uchar*, ulong, uchar*, DigestState*); +DigestState* sha1(uchar*, ulong, uchar*, DigestState*); +DigestState* sha2_224(uchar*, ulong, uchar*, DigestState*); +DigestState* sha2_256(uchar*, ulong, uchar*, DigestState*); +DigestState* sha2_384(uchar*, ulong, uchar*, DigestState*); +DigestState* sha2_512(uchar*, ulong, uchar*, DigestState*); +DigestState* aes(uchar*, ulong, uchar*, DigestState*); +DigestState* hmac_x(uchar *p, ulong len, uchar *key, ulong klen, + uchar *digest, DigestState *s, + DigestState*(*x)(uchar*, ulong, uchar*, DigestState*), + int xlen); +DigestState* hmac_md5(uchar*, ulong, uchar*, ulong, uchar*, DigestState*); +DigestState* hmac_sha1(uchar*, ulong, uchar*, ulong, uchar*, DigestState*); +DigestState* hmac_sha2_224(uchar*, ulong, uchar*, ulong, uchar*, DigestState*); +DigestState* hmac_sha2_256(uchar*, ulong, uchar*, ulong, uchar*, DigestState*); +DigestState* hmac_sha2_384(uchar*, ulong, uchar*, ulong, uchar*, DigestState*); +DigestState* hmac_sha2_512(uchar*, ulong, uchar*, ulong, uchar*, DigestState*); +DigestState* hmac_aes(uchar*, ulong, uchar*, ulong, uchar*, DigestState*); +char* md5pickle(MD5state*); +MD5state* md5unpickle(char*); +char* sha1pickle(SHA1state*); +SHA1state* sha1unpickle(char*); + +/* + * random number generation + */ void genrandom(uchar *buf, int nbytes); void prng(uchar *buf, int nbytes); ulong fastrand(void); ulong nfastrand(ulong); -///////////////////////////////////////////////////////// -// primes -///////////////////////////////////////////////////////// -void genprime(mpint *p, int n, int accuracy); // generate an n bit probable prime -void gensafeprime(mpint *p, mpint *alpha, int n, int accuracy); // prime and generator -void genstrongprime(mpint *p, int n, int accuracy); // generate an n bit strong prime +/* + * primes + */ +void genprime(mpint *p, int n, int accuracy); /* generate n-bit probable prime */ +void gensafeprime(mpint *p, mpint *alpha, int n, int accuracy); /* prime & generator */ +void genstrongprime(mpint *p, int n, int accuracy); /* generate n-bit strong prime */ void DSAprimes(mpint *q, mpint *p, uchar seed[SHA1dlen]); -int probably_prime(mpint *n, int nrep); // miller-rabin test -int smallprimetest(mpint *p); // returns -1 if not prime, 0 otherwise +int probably_prime(mpint *n, int nrep); /* miller-rabin test */ +int smallprimetest(mpint *p); /* returns -1 if not prime, 0 otherwise */ -///////////////////////////////////////////////////////// -// rc4 -///////////////////////////////////////////////////////// +/* + * rc4 + */ typedef struct RC4state RC4state; struct RC4state { - uchar state[256]; - uchar x; - uchar y; + uchar state[256]; + uchar x; + uchar y; }; void setupRC4state(RC4state*, uchar*, int); @@ -185,32 +232,39 @@ void rc4(RC4state*, uchar*, int); void rc4skip(RC4state*, int); void rc4back(RC4state*, int); -///////////////////////////////////////////////////////// -// rsa -///////////////////////////////////////////////////////// +/* + * rsa + */ typedef struct RSApub RSApub; typedef struct RSApriv RSApriv; +typedef struct PEMChain PEMChain; -// public/encryption key +/* public/encryption key */ struct RSApub { - mpint *n; // modulus - mpint *ek; // exp (encryption key) + mpint *n; /* modulus */ + mpint *ek; /* exp (encryption key) */ }; -// private/decryption key +/* private/decryption key */ struct RSApriv { RSApub pub; - mpint *dk; // exp (decryption key) + mpint *dk; /* exp (decryption key) */ - // precomputed values to help with chinese remainder theorem calc + /* precomputed values to help with chinese remainder theorem calc */ mpint *p; mpint *q; - mpint *kp; // dk mod p-1 - mpint *kq; // dk mod q-1 - mpint *c2; // (inv p) mod q + mpint *kp; /* dk mod p-1 */ + mpint *kq; /* dk mod q-1 */ + mpint *c2; /* (inv p) mod q */ +}; + +struct PEMChain{ + PEMChain*next; + uchar *pem; + int pemlen; }; RSApriv* rsagen(int nlen, int elen, int rounds); @@ -223,43 +277,47 @@ RSApriv* rsaprivalloc(void); void rsaprivfree(RSApriv*); RSApub* rsaprivtopub(RSApriv*); RSApub* X509toRSApub(uchar*, int, char*, int); +uchar* RSApubtoasn1(RSApub*, int*); +RSApub* asn1toRSApub(uchar*, int); RSApriv* asn1toRSApriv(uchar*, int); void asn1dump(uchar *der, int len); -uchar* decodepem(char *s, char *type, int *len); +uchar* decodePEM(char *s, char *type, int *len, char **new_s); +PEMChain* decodepemchain(char *s, char *type); uchar* X509gen(RSApriv *priv, char *subj, ulong valid[2], int *certlen); uchar* X509req(RSApriv *priv, char *subj, int *certlen); char* X509verify(uchar *cert, int ncert, RSApub *pk); void X509dump(uchar *cert, int ncert); -///////////////////////////////////////////////////////// -// elgamal -///////////////////////////////////////////////////////// + +/* + * elgamal + */ typedef struct EGpub EGpub; typedef struct EGpriv EGpriv; typedef struct EGsig EGsig; -// public/encryption key +/* public/encryption key */ struct EGpub { - mpint *p; // modulus - mpint *alpha; // generator - mpint *key; // (encryption key) alpha**secret mod p + mpint *p; /* modulus */ + mpint *alpha; /* generator */ + mpint *key; /* (encryption key) alpha**secret mod p */ }; -// private/decryption key +/* private/decryption key */ struct EGpriv { EGpub pub; - mpint *secret; // (decryption key) + mpint *secret; /* (decryption key) */ }; -// signature +/* signature */ struct EGsig { mpint *r, *s; }; EGpriv* eggen(int nlen, int rounds); -mpint* egencrypt(EGpub *k, mpint *in, mpint *out); +mpint* egencrypt(EGpub *k, mpint *in, mpint *out); /* deprecated */ mpint* egdecrypt(EGpriv *k, mpint *in, mpint *out); EGsig* egsign(EGpriv *k, mpint *m); int egverify(EGpub *k, EGsig *sig, mpint *m); @@ -271,36 +329,36 @@ EGsig* egsigalloc(void); void egsigfree(EGsig*); EGpub* egprivtopub(EGpriv*); -///////////////////////////////////////////////////////// -// dsa -///////////////////////////////////////////////////////// +/* + * dsa + */ typedef struct DSApub DSApub; typedef struct DSApriv DSApriv; typedef struct DSAsig DSAsig; -// public/encryption key +/* public/encryption key */ struct DSApub { - mpint *p; // modulus - mpint *q; // group order, q divides p-1 - mpint *alpha; // group generator - mpint *key; // (encryption key) alpha**secret mod p + mpint *p; /* modulus */ + mpint *q; /* group order, q divides p-1 */ + mpint *alpha; /* group generator */ + mpint *key; /* (encryption key) alpha**secret mod p */ }; -// private/decryption key +/* private/decryption key */ struct DSApriv { DSApub pub; - mpint *secret; // (decryption key) + mpint *secret; /* (decryption key) */ }; -// signature +/* signature */ struct DSAsig { mpint *r, *s; }; -DSApriv* dsagen(DSApub *opub); +DSApriv* dsagen(DSApub *opub); /* opub not checked for consistency! */ DSAsig* dsasign(DSApriv *k, mpint *m); int dsaverify(DSApub *k, DSAsig *sig, mpint *m); DSApub* dsapuballoc(void); @@ -310,31 +368,39 @@ void dsaprivfree(DSApriv*); DSAsig* dsasigalloc(void); void dsasigfree(DSAsig*); DSApub* dsaprivtopub(DSApriv*); +DSApriv* asn1toDSApriv(uchar*, int); -///////////////////////////////////////////////////////// -// TLS -///////////////////////////////////////////////////////// +/* + * TLS + */ typedef struct Thumbprint{ struct Thumbprint *next; - uchar sha1[SHA1dlen]; + uchar sha1[SHA1dlen]; } Thumbprint; typedef struct TLSconn{ - char dir[40]; // connection directory - uchar *cert; // certificate (local on input, remote on output) - uchar *sessionID; - int certlen, sessionIDlen; - int (*trace)(char*fmt, ...); + char dir[40]; /* connection directory */ + uchar *cert; /* certificate (local on input, remote on output) */ + uchar *sessionID; + int certlen; + int sessionIDlen; + int (*trace)(char*fmt, ...); + PEMChain*chain; /* optional extra certificate evidence for servers to present */ + char *sessionType; + uchar *sessionKey; + int sessionKeylen; + char *sessionConst; } TLSconn; -// tlshand.c -extern int tlsClient(int fd, TLSconn *c); -extern int tlsServer(int fd, TLSconn *c); +/* tlshand.c */ +int tlsClient(int fd, TLSconn *c); +int tlsServer(int fd, TLSconn *c); -// thumb.c -extern Thumbprint* initThumbprints(char *ok, char *crl); -extern void freeThumbprints(Thumbprint *ok); -extern int okThumbprint(uchar *sha1, Thumbprint *ok); +/* thumb.c */ +Thumbprint* initThumbprints(char *ok, char *crl); +void freeThumbprints(Thumbprint *ok); +int okThumbprint(uchar *sha1, Thumbprint *ok); -// readcert.c -extern uchar *readcert(char *filename, int *pcertlen); +/* readcert.c */ +uchar *readcert(char *filename, int *pcertlen); +PEMChain*readcertchain(char *filename); diff --git a/libsec/Makefile b/libsec/Makefile index 0afa2a9..622defa 100644 --- a/libsec/Makefile +++ b/libsec/Makefile @@ -46,6 +46,10 @@ OFILES=\ rsaprivtopub.$O\ sha1.$O\ sha1pickle.$O\ + sha2_64.$O\ + sha2block64.$O\ + sha2_128.$O\ + sha2block128.$O\ smallprimes.$O default: $(LIB) diff --git a/libsec/aes.c b/libsec/aes.c index 02aeaae..3999c23 100644 --- a/libsec/aes.c +++ b/libsec/aes.c @@ -30,26 +30,44 @@ */ #include #include +#include #include typedef uchar u8; -typedef u32int u32; +typedef ulong u32; + #define FULL_UNROLL +#define const static const u32 Td0[256]; static const u32 Td1[256]; static const u32 Td2[256]; static const u32 Td3[256]; static const u8 Te4[256]; +static uchar basekey[3][16] = { + { + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + }, + { + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + }, + { + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + }, +}; -static int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits); +static int aes_setupEnc(ulong rk[/*4*(Nr + 1)*/], const uchar cipherKey[], + int keyBits); +static int aes_setupDec(ulong rk[/*4*(Nr + 1)*/], const uchar cipherKey[], + int keyBits); +static int aes_setup(ulong erk[/*4*(Nr + 1)*/], ulong drk[/*4*(Nr + 1)*/], + const uchar cipherKey[], int keyBits); -#ifdef NOT -static int rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits); -#endif -static int rijndaelKeySetup(u32 erk[/*4*(Nr + 1)*/], u32 drk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits); -static void rijndaelEncrypt(const u32int rk[], int Nr, const uchar pt[16], uchar ct[16]); -static void rijndaelDecrypt(const u32int rk[], int Nr, const uchar ct[16], uchar pt[16]); +void aes_encrypt(const ulong rk[], int Nr, const uchar pt[16], uchar ct[16]); +void aes_decrypt(const ulong rk[], int Nr, const uchar ct[16], uchar pt[16]); void setupAESstate(AESstate *s, uchar key[], int keybytes, uchar *ivec) @@ -59,17 +77,96 @@ setupAESstate(AESstate *s, uchar key[], int keybytes, uchar *ivec) keybytes = AESmaxkey; memmove(s->key, key, keybytes); s->keybytes = keybytes; - s->rounds = rijndaelKeySetup(s->ekey, s->dkey, s->key, keybytes * 8); + s->rounds = aes_setup(s->ekey, s->dkey, s->key, keybytes * 8); if(ivec != nil) memmove(s->ivec, ivec, AESbsize); if(keybytes==16 || keybytes==24 || keybytes==32) s->setup = 0xcafebabe; - // else rijndaelKeySetup was invalid + /* else aes_setup was invalid */ } -// Define by analogy with desCBCencrypt; AES modes are not standardized yet. -// Because of the way that non-multiple-of-16 buffers are handled, -// the decryptor must be fed buffers of the same size as the encryptor. +/* + * AES-XCBC-MAC-96 message authentication, per rfc3566. + */ + +void +setupAESXCBCstate(AESstate *s) /* was setupmac96 */ +{ + int i, j; + uint q[16 / sizeof(uint)]; + uchar *p; + + assert(s->keybytes == 16); + for(i = 0; i < 3; i++) + aes_encrypt(s->ekey, s->rounds, basekey[i], + s->mackey + AESbsize*i); + + p = s->mackey; + memset(q, 0, AESbsize); + + /* + * put the in the right endian. once figured, probably better + * to use some fcall macros. + * keys for encryption in local endianness for the algorithm... + * only key1 is used for encryption; + * BUG!!: I think this is what I got wrong. + */ + for(i = 0; i < 16 / sizeof(uint); i ++){ + for(j = 0; j < sizeof(uint); j++) + q[i] |= p[sizeof(uint)-j-1] << 8*j; + p += sizeof(uint); + } + memmove(s->mackey, q, 16); +} + +/* + * Not dealing with > 128-bit keys, not dealing with strange corner cases like + * empty message. Should be fine for AES-XCBC-MAC-96. + */ +uchar* +aesXCBCmac(uchar *p, int len, AESstate *s) +{ + uchar *p2, *ip, *eip, *mackey; + uchar q[AESbsize]; + + assert(s->keybytes == 16); /* more complicated for bigger */ + memset(s->ivec, 0, AESbsize); /* E[0] is 0+ */ + + for(; len > AESbsize; len -= AESbsize){ + memmove(q, p, AESbsize); + p2 = q; + ip = s->ivec; + for(eip = ip + AESbsize; ip < eip; ) + *p2++ ^= *ip++; + aes_encrypt((ulong *)s->mackey, s->rounds, q, s->ivec); + p += AESbsize; + } + /* the last one */ + + memmove(q, p, len); + p2 = q+len; + if(len == AESbsize) + mackey = s->mackey + AESbsize; /* k2 */ + else{ + mackey = s->mackey+2*AESbsize; /* k3 */ + *p2++ = 1 << 7; /* padding */ + len = AESbsize - len - 1; + memset(p2, 0, len); + } + + ip = s->ivec; + p2 = q; + for(eip = ip + AESbsize; ip < eip; ) + *p2++ ^= *ip++ ^ *mackey++; + aes_encrypt((ulong *)s->mackey, s->rounds, q, s->ivec); + return s->ivec; /* only the 12 bytes leftmost */ +} + +/* + * Define by analogy with desCBCencrypt; AES modes are not standardized yet. + * Because of the way that non-multiple-of-16 buffers are handled, + * the decryptor must be fed buffers of the same size as the encryptor. + */ void aesCBCencrypt(uchar *p, int len, AESstate *s) { @@ -81,7 +178,7 @@ aesCBCencrypt(uchar *p, int len, AESstate *s) ip = s->ivec; for(eip = ip+AESbsize; ip < eip; ) *p2++ ^= *ip++; - rijndaelEncrypt(s->ekey, s->rounds, p, q); + aes_encrypt(s->ekey, s->rounds, p, q); memmove(s->ivec, q, AESbsize); memmove(p, q, AESbsize); p += AESbsize; @@ -89,7 +186,7 @@ aesCBCencrypt(uchar *p, int len, AESstate *s) if(len > 0){ ip = s->ivec; - rijndaelEncrypt(s->ekey, s->rounds, ip, q); + aes_encrypt(s->ekey, s->rounds, ip, q); memmove(s->ivec, q, AESbsize); for(eip = ip+len; ip < eip; ) *p++ ^= *ip++; @@ -104,7 +201,7 @@ aesCBCdecrypt(uchar *p, int len, AESstate *s) for(; len >= AESbsize; len -= AESbsize){ memmove(tmp, p, AESbsize); - rijndaelDecrypt(s->dkey, s->rounds, p, q); + aes_decrypt(s->dkey, s->rounds, p, q); memmove(p, q, AESbsize); tp = tmp; ip = s->ivec; @@ -116,36 +213,228 @@ aesCBCdecrypt(uchar *p, int len, AESstate *s) if(len > 0){ ip = s->ivec; - rijndaelEncrypt(s->ekey, s->rounds, ip, q); + aes_encrypt(s->ekey, s->rounds, ip, q); memmove(s->ivec, q, AESbsize); for(eip = ip+len; ip < eip; ) *p++ ^= *ip++; } } +/* + * AES-CTR mode, per rfc3686. + * CTRs could be precalculated for efficiency + * and there would also be less back and forth mp + */ + +static void +incrementCTR(uchar *p, uint ctrsz) +{ + int len; + uchar *ctr; + mpint *mpctr, *mpctrsz; + + ctr = p + AESbsize - ctrsz; + mpctr = betomp(ctr, ctrsz, nil); + mpctrsz = itomp(1 << (ctrsz*8), nil); + mpadd(mpctr, mpone, mpctr); + mpmod(mpctr, mpctrsz, mpctr); + len = mptobe(mpctr, ctr, ctrsz, nil); + assert(len == ctrsz); + mpfree(mpctrsz); + mpfree(mpctr); +} + +void +aesCTRencrypt(uchar *p, int len, AESstate *s) +{ + uchar q[AESbsize]; + uchar *ip, *eip, *ctr; + + ctr = s->ivec; + for(; len >= AESbsize; len -= AESbsize){ + ip = q; + aes_encrypt(s->ekey, s->rounds, ctr, q); + for(eip = p + AESbsize; p < eip; ) + *p++ ^= *ip++; + incrementCTR(ctr, s->ctrsz); + } + + if(len > 0){ + ip = q; + aes_encrypt(s->ekey, s->rounds, ctr, q); + for(eip = p + len; p < eip; ) + *p++ ^= *ip++; + incrementCTR(ctr, s->ctrsz); + } +} + +void +aesCTRdecrypt(uchar *p, int len, AESstate *s) +{ + aesCTRencrypt(p, len, s); +} + + +/* taken from sha1; TODO: verify suitability (esp. byte order) for aes */ +/* + * encodes input (ulong) into output (uchar). Assumes len is + * a multiple of 4. + */ +static void +encode(uchar *output, ulong *input, ulong len) +{ + ulong x; + uchar *e; + + for(e = output + len; output < e;) { + x = *input++; + *output++ = x >> 24; + *output++ = x >> 16; + *output++ = x >> 8; + *output++ = x; + } +} + +/* TODO: verify use of aes_encrypt here */ +AEShstate* +aes(uchar *p, ulong len, uchar *digest, AEShstate *s) +{ + uchar buf[128]; + ulong x[16]; + int i; + uchar *e; + + if(s == nil){ + s = malloc(sizeof(*s)); + if(s == nil) + return nil; + memset(s, 0, sizeof(*s)); + s->malloced = 1; + } + + if(s->seeded == 0){ + /* seed the state, these constants would look nicer big-endian */ + s->state[0] = 0x67452301; + s->state[1] = 0xefcdab89; + s->state[2] = 0x98badcfe; + s->state[3] = 0x10325476; + /* in sha1 (20-byte digest), but not md5 (16 bytes)*/ + s->state[4] = 0xc3d2e1f0; + s->seeded = 1; + } + + /* fill out the partial 64 byte block from previous calls */ + if(s->blen){ + i = 64 - s->blen; + if(len < i) + i = len; + memmove(s->buf + s->blen, p, i); + len -= i; + s->blen += i; + p += i; + if(s->blen == 64){ + /* encrypt s->buf into s->state */ + // _sha1block(s->buf, s->blen, s->state); + aes_encrypt((ulong *)s->buf, 1, s->buf, (uchar *)s->state); + s->len += s->blen; + s->blen = 0; + } + } + + /* do 64 byte blocks */ + i = len & ~0x3f; + if(i){ + /* encrypt p into s->state */ + // _sha1block(p, i, s->state); + aes_encrypt((ulong *)s->buf, 1, p, (uchar *)s->state); + s->len += i; + len -= i; + p += i; + } + + /* save the left overs if not last call */ + if(digest == 0){ + if(len){ + memmove(s->buf, p, len); + s->blen += len; + } + return s; + } + + /* + * this is the last time through, pad what's left with 0x80, + * 0's, and the input count to create a multiple of 64 bytes + */ + if(s->blen){ + p = s->buf; + len = s->blen; + } else { + memmove(buf, p, len); + p = buf; + } + s->len += len; + e = p + len; + if(len < 56) + i = 56 - len; + else + i = 120 - len; + memset(e, 0, i); + *e = 0x80; + len += i; + + /* append the count */ + x[0] = s->len>>29; /* byte-order dependent */ + x[1] = s->len<<3; + encode(p+len, x, 8); + + /* digest the last part */ + /* encrypt p into s->state */ + // _sha1block(p, len+8, s->state); + aes_encrypt((ulong *)s->buf, 1, p, (uchar *)s->state); + s->len += len+8; /* sha1: +8 */ + + /* return result and free state */ + encode((uchar *)digest, (ulong *)s->state, AESdlen); + if(s->malloced == 1) + free(s); + return nil; +} + +DigestState* +hmac_aes(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, + DigestState *s) +{ + return hmac_x(p, len, key, klen, digest, s, aes, AESdlen); +} + + + /* * this function has been changed for plan 9. * Expand the cipher key into the encryption and decryption key schedules. * * @return the number of rounds for the given cipher key size. */ -static int rijndaelKeySetup(u32 erk[/*4*(Nr + 1)*/], u32 drk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) { +static int +aes_setup(ulong erk[/* 4*(Nr + 1) */], ulong drk[/* 4*(Nr + 1) */], + const uchar cipherKey[], int keyBits) +{ int Nr, i; /* expand the cipher key: */ - Nr = rijndaelKeySetupEnc(erk, cipherKey, keyBits); + Nr = aes_setupEnc(erk, cipherKey, keyBits); /* - * invert the order of the round keys and - * apply the inverse MixColumn transform to all round keys but the first and the last + * invert the order of the round keys and apply the inverse MixColumn + * transform to all round keys but the first and the last */ - drk[0 ] = erk[4*Nr ]; + drk[0 ] = erk[4*Nr ]; drk[1 ] = erk[4*Nr + 1]; - drk[2 ] = erk[4*Nr + 2]; + drk[2 ] = erk[4*Nr + 2]; drk[3 ] = erk[4*Nr + 3]; - drk[4*Nr ] = erk[0 ]; + drk[4*Nr ] = erk[0 ]; drk[4*Nr + 1] = erk[1 ]; - drk[4*Nr + 2] = erk[2 ]; + drk[4*Nr + 2] = erk[2 ]; drk[4*Nr + 3] = erk[3 ]; erk += 4 * Nr; for (i = 1; i < Nr; i++) { @@ -175,6 +464,7 @@ static int rijndaelKeySetup(u32 erk[/*4*(Nr + 1)*/], u32 drk[/*4*(Nr + 1)*/], co return Nr; } + /* Te0[x] = S [x].[02, 01, 01, 03]; Te1[x] = S [x].[03, 02, 01, 01]; @@ -854,26 +1144,24 @@ static const u8 Td4[256] = { static const u32 rcon[] = { 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, - 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ + 0x1B000000, 0x36000000, + /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ }; -#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00) - -#ifdef _MSC_VER -#define GETU32(p) SWAP(*((u32 *)(p))) -#define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); } -#else -#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3])) -#define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); } -#endif +#define GETU32(pt) (((u32)(pt)[0]<<24) ^ ((u32)(pt)[1]<<16) ^ \ + ((u32)(pt)[2]<< 8) ^ ((u32)(pt)[3])) +#define PUTU32(ct, st) { (ct)[0] = (u8)((st)>>24); (ct)[1] = (u8)((st)>>16); \ + (ct)[2] = (u8)((st)>> 8); (ct)[3] = (u8)(st); } -/** +/* * Expand the cipher key into the encryption key schedule. * * @return the number of rounds for the given cipher key size. */ -static int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) { - int i = 0; +static int +aes_setupEnc(ulong rk[/*4*(Nr + 1)*/], const uchar cipherKey[], int keyBits) +{ + int i = 0; u32 temp; rk[0] = GETU32(cipherKey ); @@ -923,32 +1211,31 @@ static int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int rk[6] = GETU32(cipherKey + 24); rk[7] = GETU32(cipherKey + 28); if (keyBits == 256) { - for (;;) { - temp = rk[ 7]; - rk[ 8] = rk[ 0] ^ - (Te4[(temp >> 16) & 0xff] << 24) ^ - (Te4[(temp >> 8) & 0xff] << 16) ^ - (Te4[(temp ) & 0xff] << 8) ^ - (Te4[(temp >> 24) ] ) ^ - rcon[i]; - rk[ 9] = rk[ 1] ^ rk[ 8]; - rk[10] = rk[ 2] ^ rk[ 9]; - rk[11] = rk[ 3] ^ rk[10]; + for (;;) { + temp = rk[ 7]; + rk[ 8] = rk[ 0] ^ + (Te4[(temp >> 16) & 0xff] << 24) ^ + (Te4[(temp >> 8) & 0xff] << 16) ^ + (Te4[(temp ) & 0xff] << 8) ^ + (Te4[(temp >> 24) ] ) ^ + rcon[i]; + rk[ 9] = rk[ 1] ^ rk[ 8]; + rk[10] = rk[ 2] ^ rk[ 9]; + rk[11] = rk[ 3] ^ rk[10]; if (++i == 7) { return 14; } - temp = rk[11]; - rk[12] = rk[ 4] ^ - (Te4[(temp >> 24) ] << 24) ^ - (Te4[(temp >> 16) & 0xff] << 16) ^ - (Te4[(temp >> 8) & 0xff] << 8) ^ - (Te4[(temp ) & 0xff] ); - rk[13] = rk[ 5] ^ rk[12]; - rk[14] = rk[ 6] ^ rk[13]; - rk[15] = rk[ 7] ^ rk[14]; - + temp = rk[11]; + rk[12] = rk[ 4] ^ + (Te4[(temp >> 24) ] << 24) ^ + (Te4[(temp >> 16) & 0xff] << 16) ^ + (Te4[(temp >> 8) & 0xff] << 8) ^ + (Te4[(temp ) & 0xff] ); + rk[13] = rk[ 5] ^ rk[12]; + rk[14] = rk[ 6] ^ rk[13]; + rk[15] = rk[ 7] ^ rk[14]; rk += 8; - } + } } return 0; } @@ -958,13 +1245,14 @@ static int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int * * @return the number of rounds for the given cipher key size. */ -#ifdef NOTUSED -static int rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) { +static int +aes_setupDec(ulong rk[/* 4*(Nr + 1) */], const uchar cipherKey[], int keyBits) +{ int Nr, i, j; - u32 temp; + ulong temp; /* expand the cipher key: */ - Nr = rijndaelKeySetupEnc(rk, cipherKey, keyBits); + Nr = aes_setupEnc(rk, cipherKey, keyBits); /* invert the order of the round keys: */ for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) { temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp; @@ -972,7 +1260,10 @@ static int rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int 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: */ + /* + * apply the inverse MixColumn transform to all round keys + * but the first and the last: + */ for (i = 1; i < Nr; i++) { rk += 4; rk[0] = @@ -998,15 +1289,18 @@ static int rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int } return Nr; } -#endif -static void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16], u8 ct[16]) { - u32 s0, s1, s2, s3, t0, t1, t2, t3; +/* using round keys in rk, perform Nr rounds of encrypting pt into ct */ +void +aes_encrypt(const ulong rk[/* 4*(Nr + 1) */], int Nr, const uchar pt[16], + uchar ct[16]) +{ + ulong s0, s1, s2, s3, t0, t1, t2, t3; #ifndef FULL_UNROLL - int r; + int r; #endif /* ?FULL_UNROLL */ - /* + /* * map byte array block to cipher state * and add initial round key: */ @@ -1015,7 +1309,7 @@ static void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16 s2 = GETU32(pt + 8) ^ rk[2]; s3 = GETU32(pt + 12) ^ rk[3]; #ifdef FULL_UNROLL - /* round 1: */ + /* 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]; @@ -1025,7 +1319,7 @@ static void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16 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: */ + /* 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]; @@ -1035,7 +1329,7 @@ static void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[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: */ + /* 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]; @@ -1045,7 +1339,7 @@ static void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16 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: */ + /* 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]; @@ -1055,99 +1349,98 @@ static void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16 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: */ + /* 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 (Nr > 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 (Nr > 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 += Nr << 2; -#else /* !FULL_UNROLL */ - /* + if (Nr > 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 (Nr > 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 += Nr << 2; +#else /* !FULL_UNROLL */ + /* * Nr - 1 full rounds: */ - r = Nr >> 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]; + r = Nr >> 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; - } + 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 */ - /* + 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: */ @@ -1181,13 +1474,16 @@ static void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16 PUTU32(ct + 12, s3); } -static void rijndaelDecrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 ct[16], u8 pt[16]) { - u32 s0, s1, s2, s3, t0, t1, t2, t3; +void +aes_decrypt(const ulong rk[/* 4*(Nr + 1) */], int Nr, const uchar ct[16], + uchar pt[16]) +{ + ulong s0, s1, s2, s3, t0, t1, t2, t3; #ifndef FULL_UNROLL - int r; -#endif /* ?FULL_UNROLL */ + int r; +#endif /* ?FULL_UNROLL */ - /* + /* * map byte array block to cipher state * and add initial round key: */ @@ -1265,8 +1561,8 @@ static void rijndaelDecrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 ct[16 t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[55]; } } - rk += Nr << 2; -#else /* !FULL_UNROLL */ + rk += Nr << 2; +#else /* !FULL_UNROLL */ /* * Nr - 1 full rounds: */ @@ -1298,9 +1594,8 @@ static void rijndaelDecrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 ct[16 rk[7]; rk += 8; - if (--r == 0) { + if (--r == 0) break; - } s0 = Td0[(t0 >> 24) ] ^ @@ -1327,8 +1622,8 @@ static void rijndaelDecrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 ct[16 Td3[(t0 ) & 0xff] ^ rk[3]; } -#endif /* ?FULL_UNROLL */ - /* +#endif /* ?FULL_UNROLL */ + /* * apply last round and * map cipher state to byte array block: */ @@ -1364,11 +1659,14 @@ static void rijndaelDecrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 ct[16 #ifdef INTERMEDIATE_VALUE_KAT -static void rijndaelEncryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[16], int rounds) { +static void +aes_encryptRound(const u32 rk[/* 4*(Nr + 1) */], int Nr, u8 block[16], + int rounds) +{ int r; u32 s0, s1, s2, s3, t0, t1, t2, t3; - /* + /* * map byte array block to cipher state * and add initial round key: */ @@ -1376,9 +1674,9 @@ static void rijndaelEncryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[ s1 = GETU32(block + 4) ^ rk[1]; s2 = GETU32(block + 8) ^ rk[2]; s3 = GETU32(block + 12) ^ rk[3]; - rk += 4; + rk += 4; - /* + /* * Nr - 1 full rounds: */ for (r = (rounds < Nr ? rounds : Nr - 1); r > 0; r--) { @@ -1406,45 +1704,42 @@ static void rijndaelEncryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[ Te2[(s1 >> 8) & 0xff] ^ Te3[(s2 ) & 0xff] ^ rk[3]; - s0 = t0; s1 = t1; s2 = t2; s3 = t3; rk += 4; + } - } - - /* + /* * apply last round and * map cipher state to byte array block: */ if (rounds == Nr) { - t0 = - (Te4[(s0 >> 24) ] << 24) ^ - (Te4[(s1 >> 16) & 0xff] << 16) ^ - (Te4[(s2 >> 8) & 0xff] << 8) ^ - (Te4[(s3 ) & 0xff] ) ^ - rk[0]; - t1 = - (Te4[(s1 >> 24) ] << 24) ^ - (Te4[(s2 >> 16) & 0xff] << 16) ^ - (Te4[(s3 >> 8) & 0xff] << 8) ^ - (Te4[(s0 ) & 0xff] ) ^ - rk[1]; - t2 = - (Te4[(s2 >> 24) ] << 24) ^ - (Te4[(s3 >> 16) & 0xff] << 16) ^ - (Te4[(s0 >> 8) & 0xff] << 8) ^ - (Te4[(s1 ) & 0xff] ) ^ - rk[2]; - t3 = - (Te4[(s3 >> 24) ] << 24) ^ - (Te4[(s0 >> 16) & 0xff] << 16) ^ - (Te4[(s1 >> 8) & 0xff] << 8) ^ - (Te4[(s2 ) & 0xff] ) ^ - rk[3]; - + t0 = + (Te4[(s0 >> 24) ] << 24) ^ + (Te4[(s1 >> 16) & 0xff] << 16) ^ + (Te4[(s2 >> 8) & 0xff] << 8) ^ + (Te4[(s3 ) & 0xff] ) ^ + rk[0]; + t1 = + (Te4[(s1 >> 24) ] << 24) ^ + (Te4[(s2 >> 16) & 0xff] << 16) ^ + (Te4[(s3 >> 8) & 0xff] << 8) ^ + (Te4[(s0 ) & 0xff] ) ^ + rk[1]; + t2 = + (Te4[(s2 >> 24) ] << 24) ^ + (Te4[(s3 >> 16) & 0xff] << 16) ^ + (Te4[(s0 >> 8) & 0xff] << 8) ^ + (Te4[(s1 ) & 0xff] ) ^ + rk[2]; + t3 = + (Te4[(s3 >> 24) ] << 24) ^ + (Te4[(s0 >> 16) & 0xff] << 16) ^ + (Te4[(s1 >> 8) & 0xff] << 8) ^ + (Te4[(s2 ) & 0xff] ) ^ + rk[3]; s0 = t0; s1 = t1; s2 = t2; @@ -1457,11 +1752,14 @@ static void rijndaelEncryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[ PUTU32(block + 12, s3); } -static void rijndaelDecryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[16], int rounds) { +static void +aes_decryptRound(const u32 rk[/* 4*(Nr + 1) */], int Nr, u8 block[16], + int rounds) +{ int r; u32 s0, s1, s2, s3, t0, t1, t2, t3; - /* + /* * map byte array block to cipher state * and add initial round key: */ @@ -1469,9 +1767,9 @@ static void rijndaelDecryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[ s1 = GETU32(block + 4) ^ rk[1]; s2 = GETU32(block + 8) ^ rk[2]; s3 = GETU32(block + 12) ^ rk[3]; - rk += 4; + rk += 4; - /* + /* * Nr - 1 full rounds: */ for (r = (rounds < Nr ? rounds : Nr) - 1; r > 0; r--) { @@ -1505,10 +1803,9 @@ static void rijndaelDecryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[ s2 = t2; s3 = t3; rk += 4; + } - } - - /* + /* * complete the last round and * map cipher state to byte array block: */ @@ -1534,10 +1831,10 @@ static void rijndaelDecryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[ (Td4[(s0 ) & 0xff] ); if (rounds == Nr) { - t0 ^= rk[0]; - t1 ^= rk[1]; - t2 ^= rk[2]; - t3 ^= rk[3]; + t0 ^= rk[0]; + t1 ^= rk[1]; + t2 ^= rk[2]; + t3 ^= rk[3]; } PUTU32(block , t0); @@ -1546,4 +1843,4 @@ static void rijndaelDecryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[ PUTU32(block + 12, t3); } -#endif /* INTERMEDIATE_VALUE_KAT */ +#endif /* INTERMEDIATE_VALUE_KAT */ diff --git a/libsec/decodepem.c b/libsec/decodepem.c index 7e8f83b..d732b0a 100644 --- a/libsec/decodepem.c +++ b/libsec/decodepem.c @@ -6,12 +6,14 @@ #define STRLEN(s) (sizeof(s)-1) uchar* -decodepem(char *s, char *type, int *len) +decodePEM(char *s, char *type, int *len, char **new_s) { uchar *d; char *t, *e, *tt; int n; + *len = 0; + /* * find the correct section of the file, stripping garbage at the beginning and end. * the data is delimited by -----BEGIN -----\n and -----END -----\n @@ -42,6 +44,8 @@ decodepem(char *s, char *type, int *len) return nil; } + if(new_s) + *new_s = tt+1; n = ((tt - t) * 6 + 7) / 8; d = malloc(n); if(d == nil){ @@ -57,3 +61,29 @@ decodepem(char *s, char *type, int *len) *len = n; return d; } + +PEMChain* +decodepemchain(char *s, char *type) +{ + PEMChain *first = nil, *last = nil, *chp; + uchar *d; + char *e; + int n; + + e = strchr(s, '\0'); + while (s < e) { + d = decodePEM(s, type, &n, &s); + if(d == nil) + break; + chp = malloc(sizeof(PEMChain)); + chp->next = nil; + chp->pem = d; + chp->pemlen = n; + if (first == nil) + first = chp; + else + last->next = chp; + last = chp; + } + return first; +} diff --git a/libsec/dsaalloc.c b/libsec/dsaalloc.c index 6a48f03..d82ab3d 100644 --- a/libsec/dsaalloc.c +++ b/libsec/dsaalloc.c @@ -22,6 +22,7 @@ dsapubfree(DSApub *dsa) mpfree(dsa->q); mpfree(dsa->alpha); mpfree(dsa->key); + free(dsa); } @@ -46,6 +47,7 @@ dsaprivfree(DSApriv *dsa) mpfree(dsa->pub.alpha); mpfree(dsa->pub.key); mpfree(dsa->secret); + free(dsa); } DSAsig* @@ -66,4 +68,5 @@ dsasigfree(DSAsig *dsa) return; mpfree(dsa->r); mpfree(dsa->s); + free(dsa); } diff --git a/libsec/dsagen.c b/libsec/dsagen.c index ccdd918..46c369e 100644 --- a/libsec/dsagen.c +++ b/libsec/dsagen.c @@ -32,9 +32,6 @@ dsagen(DSApub *opub) // find a generator alpha of the multiplicative // group Z*p, i.e., of order n = p-1. We use the // fact that q divides p-1 to reduce the exponent. - // - // This isn't very efficient. If anyone has a better - // idea, mail presotto@closedmind.org exp = mpnew(0); g = mpnew(0); r = mpnew(0); diff --git a/libsec/dsasign.c b/libsec/dsasign.c index abca3eb..137134b 100644 --- a/libsec/dsasign.c +++ b/libsec/dsasign.c @@ -21,16 +21,16 @@ dsasign(DSApriv *priv, mpint *m) // find a k that has an inverse mod q while(1){ mprand(qlen, genrandom, k); - if((mpcmp(mpone, k) > 0) || (mpcmp(k, qm1) >= 0)) + if((mpcmp(mpone, k) > 0) || (mpcmp(k, pub->q) >= 0)) continue; mpextendedgcd(k, q, r, kinv, s); if(mpcmp(r, mpone) != 0) - continue; + sysfatal("dsasign: pub->q not prime"); break; } // make kinv positive - mpmod(kinv, qm1, kinv); + mpmod(kinv, pub->q, kinv); // r = ((alpha**k) mod p) mod q mpexp(alpha, k, p, r); diff --git a/libsec/dsaverify.c b/libsec/dsaverify.c index 23cee50..70e7f3c 100644 --- a/libsec/dsaverify.c +++ b/libsec/dsaverify.c @@ -8,9 +8,9 @@ dsaverify(DSApub *pub, DSAsig *sig, mpint *m) int rv = -1; mpint *u1, *u2, *v, *sinv; - if(sig->r->sign < 0 || mpcmp(sig->r, pub->q) >= 0) + if(mpcmp(sig->r, mpone) < 0 || mpcmp(sig->r, pub->q) >= 0) return rv; - if(sig->s->sign < 0 || mpcmp(sig->s, pub->q) >= 0) + if(mpcmp(sig->s, mpone) < 0 || mpcmp(sig->s, pub->q) >= 0) return rv; u1 = mpnew(0); u2 = mpnew(0); diff --git a/libsec/egalloc.c b/libsec/egalloc.c index d7c940a..3f0753d 100644 --- a/libsec/egalloc.c +++ b/libsec/egalloc.c @@ -21,6 +21,7 @@ egpubfree(EGpub *eg) mpfree(eg->p); mpfree(eg->alpha); mpfree(eg->key); + free(eg); } @@ -44,6 +45,7 @@ egprivfree(EGpriv *eg) mpfree(eg->pub.alpha); mpfree(eg->pub.key); mpfree(eg->secret); + free(eg); } EGsig* @@ -64,4 +66,5 @@ egsigfree(EGsig *eg) return; mpfree(eg->r); mpfree(eg->s); + free(eg); } diff --git a/libsec/hmac.c b/libsec/hmac.c index c723973..aa2fa03 100644 --- a/libsec/hmac.c +++ b/libsec/hmac.c @@ -2,27 +2,25 @@ #include /* rfc2104 */ -static DigestState* +DigestState* hmac_x(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s, DigestState*(*x)(uchar*, ulong, uchar*, DigestState*), int xlen) { int i; - uchar pad[65], innerdigest[256]; + uchar pad[Hmacblksz+1], innerdigest[256]; if(xlen > sizeof(innerdigest)) return nil; - - if(klen>64) + if(klen > Hmacblksz) return nil; /* first time through */ - if(s == nil){ - for(i=0; i<64; i++) - pad[i] = 0x36; - pad[64] = 0; - for(i=0; iseeded == 0){ + memset(pad, 0x36, Hmacblksz); + pad[Hmacblksz] = 0; + for(i = 0; i < klen; i++) pad[i] ^= key[i]; - s = (*x)(pad, 64, nil, nil); + s = (*x)(pad, Hmacblksz, nil, s); if(s == nil) return nil; } @@ -32,25 +30,12 @@ hmac_x(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState * return s; /* last time through */ - for(i=0; i<64; i++) - pad[i] = 0x5c; - pad[64] = 0; - for(i=0; i> 24; } } + +DigestState* +hmac_md5(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, + DigestState *s) +{ + return hmac_x(p, len, key, klen, digest, s, md5, MD5dlen); +} diff --git a/libsec/md5pickle.c b/libsec/md5pickle.c index 5b353b5..a3adb51 100644 --- a/libsec/md5pickle.c +++ b/libsec/md5pickle.c @@ -7,11 +7,12 @@ md5pickle(MD5state *s) char *p; int m, n; - m = 4*9+4*((s->blen+3)/3); + m = 17+4*9+4*((s->blen+3)/3 + 1); p = malloc(m); if(p == nil) return p; - n = sprint(p, "%8.8ux %8.8ux %8.8ux %8.8ux ", + n = sprint(p, "%16.16llux %8.8ux %8.8ux %8.8ux %8.8ux ", + s->len, s->state[0], s->state[1], s->state[2], s->state[3]); enc64(p+n, m-n, s->buf, s->blen); @@ -26,6 +27,7 @@ md5unpickle(char *p) s = malloc(sizeof(*s)); if(s == nil) return nil; + s->len = strtoull(p, &p, 16); s->state[0] = strtoul(p, &p, 16); s->state[1] = strtoul(p, &p, 16); s->state[2] = strtoul(p, &p, 16); diff --git a/libsec/nfastrand.c b/libsec/nfastrand.c index fa042b0..3ba7700 100644 --- a/libsec/nfastrand.c +++ b/libsec/nfastrand.c @@ -14,7 +14,7 @@ nfastrand(ulong n) * so we want a random number < m. */ if(n > Maxrand) - abort(); + sysfatal("nfastrand: n too large"); m = Maxrand - Maxrand % n; while((r = fastrand()) >= m) diff --git a/libsec/probably_prime.c b/libsec/probably_prime.c index 4eaccba..d9c57d3 100644 --- a/libsec/probably_prime.c +++ b/libsec/probably_prime.c @@ -2,14 +2,16 @@ #include #include -// Miller-Rabin probabilistic primality testing -// Knuth (1981) Seminumerical Algorithms, p.379 -// Menezes et al () Handbook, p.39 -// 0 if composite; 1 if almost surely prime, Pr(err)<1/4**nrep +/* + * Miller-Rabin probabilistic primality testing + * Knuth (1981) Seminumerical Algorithms, p.379 + * Menezes et al () Handbook, p.39 + * 0 if composite; 1 if almost surely prime, Pr(err)<1/4**nrep + */ int probably_prime(mpint *n, int nrep) { - int j, k, rep, nbits, isprime = 1; + int j, k, rep, nbits, isprime; mpint *nm1, *q, *x, *y, *r; if(n->sign < 0) @@ -19,18 +21,18 @@ probably_prime(mpint *n, int nrep) nrep = 18; k = mptoi(n); - if(k == 2) // 2 is prime + if(k == 2) /* 2 is prime */ return 1; - if(k < 2) // 1 is not prime + if(k < 2) /* 1 is not prime */ return 0; - if((n->p[0] & 1) == 0) // even is not prime + if((n->p[0] & 1) == 0) /* even is not prime */ return 0; - // test against small prime numbers + /* test against small prime numbers */ if(smallprimetest(n) < 0) return 0; - // fermat test, 2^n mod n == 2 if p is prime + /* fermat test, 2^n mod n == 2 if p is prime */ x = uitomp(2, nil); y = mpnew(0); mpexp(x, n, n, y); @@ -43,38 +45,43 @@ probably_prime(mpint *n, int nrep) nbits = mpsignif(n); nm1 = mpnew(nbits); - mpsub(n, mpone, nm1); // nm1 = n - 1 */ + mpsub(n, mpone, nm1); /* nm1 = n - 1 */ k = mplowbits0(nm1); q = mpnew(0); - mpright(nm1, k, q); // q = (n-1)/2**k + mpright(nm1, k, q); /* q = (n-1)/2**k */ for(rep = 0; rep < nrep; rep++){ - - // x = random in [2, n-2] - r = mprand(nbits, prng, nil); - mpmod(r, nm1, x); - mpfree(r); - if(mpcmp(x, mpone) <= 0) - continue; + for(;;){ + /* find x = random in [2, n-2] */ + r = mprand(nbits, prng, nil); + mpmod(r, nm1, x); + mpfree(r); + if(mpcmp(x, mpone) > 0) + break; + } - // y = x**q mod n + /* y = x**q mod n */ mpexp(x, q, n, y); if(mpcmp(y, mpone) == 0 || mpcmp(y, nm1) == 0) - goto done; + continue; - for(j = 1; j < k; j++){ - mpmul(y, y, x); - mpmod(x, n, y); // y = y*y mod n - if(mpcmp(y, nm1) == 0) - goto done; - if(mpcmp(y, mpone) == 0){ - isprime = 0; - goto done; - } + for(j = 1;; j++){ + if(j >= k) { + isprime = 0; + goto done; + } + mpmul(y, y, x); + mpmod(x, n, y); /* y = y*y mod n */ + if(mpcmp(y, nm1) == 0) + break; + if(mpcmp(y, mpone) == 0){ + isprime = 0; + goto done; + } } - isprime = 0; } + isprime = 1; done: mpfree(y); mpfree(x); diff --git a/libsec/readcert.c b/libsec/readcert.c index 9fe5d73..6fdb456 100644 --- a/libsec/readcert.c +++ b/libsec/readcert.c @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -13,8 +14,10 @@ readfile(char *name) fd = open(name, OREAD); if(fd < 0) return nil; - if((d = dirfstat(fd)) == nil) + if((d = dirfstat(fd)) == nil) { + close(fd); return nil; + } s = malloc(d->length + 1); if(s == nil || readn(fd, s, d->length) != d->length){ free(s); @@ -36,10 +39,10 @@ readcert(char *filename, int *pcertlen) pem = readfile(filename); if(pem == nil){ - werrstr("can't read %s", filename); + werrstr("can't read %s: %r", filename); return nil; } - binary = decodepem(pem, "CERTIFICATE", pcertlen); + binary = decodePEM(pem, "CERTIFICATE", pcertlen, nil); free(pem); if(binary == nil){ werrstr("can't parse %s", filename); @@ -48,3 +51,16 @@ readcert(char *filename, int *pcertlen) return binary; } +PEMChain * +readcertchain(char *filename) +{ + char *chfile; + + chfile = readfile(filename); + if (chfile == nil) { + werrstr("can't read %s: %r", filename); + return nil; + } + return decodepemchain(chfile, "CERTIFICATE"); +} + diff --git a/libsec/rsagen.c b/libsec/rsagen.c index bdfc37f..ebe1079 100644 --- a/libsec/rsagen.c +++ b/libsec/rsagen.c @@ -2,21 +2,6 @@ #include #include -static void -genrand(mpint *p, int n) -{ - mpdigit x; - - // generate n random bits with high set - mpbits(p, n); - genrandom((uchar*)p->p, (n+7)/8); - p->top = (n+Dbits-1)/Dbits; - x = 1; - x <<= ((n-1)%Dbits); - p->p[p->top-1] &= (x-1); - p->p[p->top-1] |= x; -} - RSApriv* rsagen(int nlen, int elen, int rounds) { @@ -31,8 +16,8 @@ rsagen(int nlen, int elen, int rounds) phi = mpnew(nlen); // create the prime factors and euclid's function - genstrongprime(p, nlen/2, rounds); - genstrongprime(q, nlen - mpsignif(p) + 1, rounds); + genprime(p, nlen/2, rounds); + genprime(q, nlen - mpsignif(p) + 1, rounds); mpmul(p, q, n); mpsub(p, mpone, e); mpsub(q, mpone, d); @@ -41,19 +26,22 @@ rsagen(int nlen, int elen, int rounds) // find an e relatively prime to phi t1 = mpnew(0); t2 = mpnew(0); - genrand(e, elen); + mprand(elen, genrandom, e); + if(mpcmp(e,mptwo) <= 0) + itomp(3, e); + // See Menezes et al. p.291 "8.8 Note (selecting primes)" for discussion + // of the merits of various choices of primes and exponents. e=3 is a + // common and recommended exponent, but doesn't necessarily work here + // because we chose strong rather than safe primes. for(;;){ - mpextendedgcd(e, phi, d, t1, t2); - if(mpcmp(d, mpone) == 0) + mpextendedgcd(e, phi, t1, d, t2); + if(mpcmp(t1, mpone) == 0) break; mpadd(mpone, e, e); } mpfree(t1); mpfree(t2); - // d = e**-1 mod phi - mpinvert(e, phi, d); - // compute chinese remainder coefficient c2 = mpnew(0); mpinvert(p, q, c2); diff --git a/libsec/rsatest.c b/libsec/rsatest.c index 9ff66b5..c7b2e33 100644 --- a/libsec/rsatest.c +++ b/libsec/rsatest.c @@ -6,16 +6,15 @@ void main(void) { - RSApriv *rsa; - Biobuf b; - char *p; int n; - mpint *clr, *enc, *clr2; - uchar buf[4096]; - uchar *e; vlong start; + char *p; + uchar buf[4096]; + Biobuf b; + RSApriv *rsa; + mpint *clr, *enc, *clr2; - fmtinstall('B', mpconv); + fmtinstall('B', mpfmt); rsa = rsagen(1024, 16, 0); if(rsa == nil) diff --git a/libsec/sha1.c b/libsec/sha1.c index 946f028..cd16b2e 100644 --- a/libsec/sha1.c +++ b/libsec/sha1.c @@ -125,3 +125,10 @@ encode(uchar *output, u32int *input, ulong len) *output++ = x; } } + +DigestState* +hmac_sha1(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, + DigestState *s) +{ + return hmac_x(p, len, key, klen, digest, s, sha1, SHA1dlen); +} diff --git a/libsec/sha2_128.c b/libsec/sha2_128.c new file mode 100644 index 0000000..65b93be --- /dev/null +++ b/libsec/sha2_128.c @@ -0,0 +1,191 @@ +/* + * sha2 128-bit + */ +#include +#include +#include + +static void encode64(uchar*, u64int*, ulong); +static DigestState* sha2_128(uchar *, ulong, uchar *, SHA2_256state *, int); + +extern void _sha2block128(uchar*, ulong, u64int*); + +/* + * for sha2_384 and sha2_512, len must be multiple of 128 for all but + * the last call. There must be room in the input buffer to pad. + * + * Note: sha2_384 calls sha2_512block as sha2_384; it just uses a different + * initial seed to produce a truncated 384b hash result. otherwise + * it's the same as sha2_512. + */ +SHA2_384state* +sha2_384(uchar *p, ulong len, uchar *digest, SHA2_384state *s) +{ + if(s == nil) { + s = mallocz(sizeof(*s), 1); + if(s == nil) + return nil; + s->malloced = 1; + } + if(s->seeded == 0){ + /* + * seed the state with the first 64 bits of the fractional + * parts of the square roots of the 9th thru 16th primes. + */ + s->bstate[0] = 0xcbbb9d5dc1059ed8LL; + s->bstate[1] = 0x629a292a367cd507LL; + s->bstate[2] = 0x9159015a3070dd17LL; + s->bstate[3] = 0x152fecd8f70e5939LL; + s->bstate[4] = 0x67332667ffc00b31LL; + s->bstate[5] = 0x8eb44a8768581511LL; + s->bstate[6] = 0xdb0c2e0d64f98fa7LL; + s->bstate[7] = 0x47b5481dbefa4fa4LL; + s->seeded = 1; + } + return sha2_128(p, len, digest, s, SHA2_384dlen); +} + +SHA2_512state* +sha2_512(uchar *p, ulong len, uchar *digest, SHA2_512state *s) +{ + + if(s == nil) { + s = mallocz(sizeof(*s), 1); + if(s == nil) + return nil; + s->malloced = 1; + } + if(s->seeded == 0){ + /* + * seed the state with the first 64 bits of the fractional + * parts of the square roots of the first 8 primes 2..19). + */ + s->bstate[0] = 0x6a09e667f3bcc908LL; + s->bstate[1] = 0xbb67ae8584caa73bLL; + s->bstate[2] = 0x3c6ef372fe94f82bLL; + s->bstate[3] = 0xa54ff53a5f1d36f1LL; + s->bstate[4] = 0x510e527fade682d1LL; + s->bstate[5] = 0x9b05688c2b3e6c1fLL; + s->bstate[6] = 0x1f83d9abfb41bd6bLL; + s->bstate[7] = 0x5be0cd19137e2179LL; + s->seeded = 1; + } + return sha2_128(p, len, digest, s, SHA2_512dlen); +} + +/* common 128 byte block padding and count code for SHA2_384 and SHA2_512 */ +static DigestState* +sha2_128(uchar *p, ulong len, uchar *digest, SHA2_512state *s, int dlen) +{ + int i; + u64int x[16]; + uchar buf[256]; + uchar *e; + + /* fill out the partial 128 byte block from previous calls */ + if(s->blen){ + i = 128 - s->blen; + if(len < i) + i = len; + memmove(s->buf + s->blen, p, i); + len -= i; + s->blen += i; + p += i; + if(s->blen == 128){ + _sha2block128(s->buf, s->blen, s->bstate); + s->len += s->blen; + s->blen = 0; + } + } + + /* do 128 byte blocks */ + i = len & ~(128-1); + if(i){ + _sha2block128(p, i, s->bstate); + s->len += i; + len -= i; + p += i; + } + + /* save the left overs if not last call */ + if(digest == 0){ + if(len){ + memmove(s->buf, p, len); + s->blen += len; + } + return s; + } + + /* + * this is the last time through, pad what's left with 0x80, + * 0's, and the input count to create a multiple of 128 bytes. + */ + if(s->blen){ + p = s->buf; + len = s->blen; + } else { + memmove(buf, p, len); + p = buf; + } + s->len += len; + e = p + len; + if(len < 112) + i = 112 - len; + else + i = 240 - len; + memset(e, 0, i); + *e = 0x80; + len += i; + + /* append the count */ + x[0] = 0; /* assume 32b length, i.e. < 4GB */ + x[1] = s->len<<3; + encode64(p+len, x, 16); + + /* digest the last part */ + _sha2block128(p, len+16, s->bstate); + s->len += len+16; + + /* return result and free state */ + encode64(digest, s->bstate, dlen); + if(s->malloced == 1) + free(s); + return nil; +} + +/* + * Encodes input (ulong long) into output (uchar). + * Assumes len is a multiple of 8. + */ +static void +encode64(uchar *output, u64int *input, ulong len) +{ + u64int x; + uchar *e; + + for(e = output + len; output < e;) { + x = *input++; + *output++ = x >> 56; + *output++ = x >> 48; + *output++ = x >> 40; + *output++ = x >> 32; + *output++ = x >> 24; + *output++ = x >> 16; + *output++ = x >> 8; + *output++ = x; + } +} + +DigestState* +hmac_sha2_384(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, + DigestState *s) +{ + return hmac_x(p, len, key, klen, digest, s, sha2_384, SHA2_384dlen); +} + +DigestState* +hmac_sha2_512(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, + DigestState *s) +{ + return hmac_x(p, len, key, klen, digest, s, sha2_512, SHA2_512dlen); +} diff --git a/libsec/sha2_64.c b/libsec/sha2_64.c new file mode 100644 index 0000000..15559cd --- /dev/null +++ b/libsec/sha2_64.c @@ -0,0 +1,187 @@ +/* + * sha2 64-bit + */ +#include +#include +#include + +static void encode32(uchar*, u32int*, ulong); +static DigestState* sha2_64(uchar *, ulong, uchar *, SHA2_256state *, int); + +extern void _sha2block64(uchar*, ulong, u32int*); + +/* + * for sha2_224 and sha2_256, len must be multiple of 64 for all but + * the last call. There must be room in the input buffer to pad. + * + * Note: sha2_224 calls sha2_256block as sha2_224, just uses different + * initial seed and produces a 224b hash result. otherwise it's + * the same as sha2_256. + */ + +SHA2_224state* +sha2_224(uchar *p, ulong len, uchar *digest, SHA2_224state *s) +{ + if(s == nil) { + s = mallocz(sizeof(*s), 1); + if(s == nil) + return nil; + s->malloced = 1; + } + if(s->seeded == 0){ + /* + * seed the state with the first 32 bits of the fractional + * parts of the square roots of the first 8 primes 2..19). + */ + s->state[0] = 0xc1059ed8; + s->state[1] = 0x367cd507; + s->state[2] = 0x3070dd17; + s->state[3] = 0xf70e5939; + s->state[4] = 0xffc00b31; + s->state[5] = 0x68581511; + s->state[6] = 0x64f98fa7; + s->state[7] = 0xbefa4fa4; + s->seeded = 1; + } + return sha2_64(p, len, digest, s, SHA2_224dlen); +} + +SHA2_256state* +sha2_256(uchar *p, ulong len, uchar *digest, SHA2_256state *s) +{ + if(s == nil) { + s = mallocz(sizeof(*s), 1); + if(s == nil) + return nil; + s->malloced = 1; + } + if(s->seeded == 0){ + /* + * seed the state with the first 32 bits of the fractional + * parts of the square roots of the first 8 primes 2..19). + */ + s->state[0] = 0x6a09e667; + s->state[1] = 0xbb67ae85; + s->state[2] = 0x3c6ef372; + s->state[3] = 0xa54ff53a; + s->state[4] = 0x510e527f; + s->state[5] = 0x9b05688c; + s->state[6] = 0x1f83d9ab; + s->state[7] = 0x5be0cd19; + s->seeded = 1; + } + return sha2_64(p, len, digest, s, SHA2_256dlen); +} + +/* common 64 byte block padding and count code for SHA2_224 and SHA2_256 */ +static DigestState* +sha2_64(uchar *p, ulong len, uchar *digest, SHA2_256state *s, int dlen) +{ + int i; + u32int x[16]; + uchar buf[128]; + uchar *e; + + /* fill out the partial 64 byte block from previous calls */ + if(s->blen){ + i = 64 - s->blen; + if(len < i) + i = len; + memmove(s->buf + s->blen, p, i); + len -= i; + s->blen += i; + p += i; + if(s->blen == 64){ + _sha2block64(s->buf, s->blen, s->state); + s->len += s->blen; + s->blen = 0; + } + } + + /* do 64 byte blocks */ + i = len & ~(64-1); + if(i){ + _sha2block64(p, i, s->state); + s->len += i; + len -= i; + p += i; + } + + /* save the left overs if not last call */ + if(digest == 0){ + if(len){ + memmove(s->buf, p, len); + s->blen += len; + } + return s; + } + + /* + * this is the last time through, pad what's left with 0x80, + * 0's, and the input count to create a multiple of 64 bytes. + */ + if(s->blen){ + p = s->buf; + len = s->blen; + } else { + memmove(buf, p, len); + p = buf; + } + s->len += len; + e = p + len; + if(len < 56) + i = 56 - len; + else + i = 120 - len; + memset(e, 0, i); + *e = 0x80; + len += i; + + /* append the count */ + x[0] = s->len>>29; + x[1] = s->len<<3; + encode32(p+len, x, 8); + + /* digest the last part */ + _sha2block64(p, len+8, s->state); + s->len += len+8; + + /* return result and free state */ + encode32(digest, s->state, dlen); + if(s->malloced == 1) + free(s); + return nil; +} + +/* + * Encodes input (ulong) into output (uchar). + * Assumes len is a multiple of 4. + */ +static void +encode32(uchar *output, u32int *input, ulong len) +{ + u32int x; + uchar *e; + + for(e = output + len; output < e;) { + x = *input++; + *output++ = x >> 24; + *output++ = x >> 16; + *output++ = x >> 8; + *output++ = x; + } +} + +DigestState* +hmac_sha2_224(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, + DigestState *s) +{ + return hmac_x(p, len, key, klen, digest, s, sha2_224, SHA2_224dlen); +} + +DigestState* +hmac_sha2_256(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, + DigestState *s) +{ + return hmac_x(p, len, key, klen, digest, s, sha2_256, SHA2_256dlen); +} diff --git a/libsec/sha2block128.c b/libsec/sha2block128.c new file mode 100644 index 0000000..0ed0368 --- /dev/null +++ b/libsec/sha2block128.c @@ -0,0 +1,101 @@ +/* + * sha2_512 block cipher + * + * Implementation straight from Federal Information Processing Standards + * publication 180-2 (+Change Notice to include SHA-224) August 1, 2002 + * note: the following upper and lower case macro names are distinct + * and reflect the functions defined in FIPS pub. 180-2. + */ +#include +#include + +#define ROTR(x,n) (((x) >> (n)) | ((x) << (64-(n)))) +#define sigma0(x) (ROTR((x),1) ^ ROTR((x),8) ^ ((x) >> 7)) +#define sigma1(x) (ROTR((x),19) ^ ROTR((x),61) ^ ((x) >> 6)) +#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 Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) +#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + +/* + * first 64 bits of the fractional parts of cube roots of + * first 80 primes (2..311). + */ +static u64int K512[80] = { + 0x428a2f98d728ae22LL, 0x7137449123ef65cdLL, 0xb5c0fbcfec4d3b2fLL, 0xe9b5dba58189dbbcLL, + 0x3956c25bf348b538LL, 0x59f111f1b605d019LL, 0x923f82a4af194f9bLL, 0xab1c5ed5da6d8118LL, + 0xd807aa98a3030242LL, 0x12835b0145706fbeLL, 0x243185be4ee4b28cLL, 0x550c7dc3d5ffb4e2LL, + 0x72be5d74f27b896fLL, 0x80deb1fe3b1696b1LL, 0x9bdc06a725c71235LL, 0xc19bf174cf692694LL, + 0xe49b69c19ef14ad2LL, 0xefbe4786384f25e3LL, 0x0fc19dc68b8cd5b5LL, 0x240ca1cc77ac9c65LL, + 0x2de92c6f592b0275LL, 0x4a7484aa6ea6e483LL, 0x5cb0a9dcbd41fbd4LL, 0x76f988da831153b5LL, + 0x983e5152ee66dfabLL, 0xa831c66d2db43210LL, 0xb00327c898fb213fLL, 0xbf597fc7beef0ee4LL, + 0xc6e00bf33da88fc2LL, 0xd5a79147930aa725LL, 0x06ca6351e003826fLL, 0x142929670a0e6e70LL, + 0x27b70a8546d22ffcLL, 0x2e1b21385c26c926LL, 0x4d2c6dfc5ac42aedLL, 0x53380d139d95b3dfLL, + 0x650a73548baf63deLL, 0x766a0abb3c77b2a8LL, 0x81c2c92e47edaee6LL, 0x92722c851482353bLL, + 0xa2bfe8a14cf10364LL, 0xa81a664bbc423001LL, 0xc24b8b70d0f89791LL, 0xc76c51a30654be30LL, + 0xd192e819d6ef5218LL, 0xd69906245565a910LL, 0xf40e35855771202aLL, 0x106aa07032bbd1b8LL, + 0x19a4c116b8d2d0c8LL, 0x1e376c085141ab53LL, 0x2748774cdf8eeb99LL, 0x34b0bcb5e19b48a8LL, + 0x391c0cb3c5c95a63LL, 0x4ed8aa4ae3418acbLL, 0x5b9cca4f7763e373LL, 0x682e6ff3d6b2b8a3LL, + 0x748f82ee5defb2fcLL, 0x78a5636f43172f60LL, 0x84c87814a1f0ab72LL, 0x8cc702081a6439ecLL, + 0x90befffa23631e28LL, 0xa4506cebde82bde9LL, 0xbef9a3f7b2c67915LL, 0xc67178f2e372532bLL, + 0xca273eceea26619cLL, 0xd186b8c721c0c207LL, 0xeada7dd6cde0eb1eLL, 0xf57d4f7fee6ed178LL, + 0x06f067aa72176fbaLL, 0x0a637dc5a2c898a6LL, 0x113f9804bef90daeLL, 0x1b710b35131c471bLL, + 0x28db77f523047d84LL, 0x32caab7b40c72493LL, 0x3c9ebe0a15c9bebcLL, 0x431d67c49c100d4cLL, + 0x4cc5d4becb3e42b6LL, 0x597f299cfc657e2aLL, 0x5fcb6fab3ad6faecLL, 0x6c44198c4a475817LL }; + +void +_sha2block128(uchar *p, ulong len, u64int *s) +{ + u64int a, b, c, d, e, f, g, h, t1, t2; + u64int *kp, *wp; + u64int w[80]; + uchar *end; + + /* at this point, we have a multiple of 64 bytes */ + for(end = p+len; p < end;){ + a = s[0]; + b = s[1]; + c = s[2]; + d = s[3]; + e = s[4]; + f = s[5]; + g = s[6]; + h = s[7]; + + for(wp = w; wp < &w[16]; wp++, p += 8) + wp[0] = ((vlong)p[0])<<56 | ((vlong)p[1])<<48 | + ((vlong)p[2])<<40 | ((vlong)p[3])<<32 | + p[4] << 24 | p[5] << 16 | p[6] << 8 | p[7]; + for(; wp < &w[80]; wp++) { + u64int s0, s1; + + s0 = sigma0(wp[-15]); + s1 = sigma1(wp[-2]); +// wp[0] = sigma1(wp[-2]) + wp[-7] + sigma0(wp[-15]) + wp[-16]; + wp[0] = s1 + wp[-7] + s0 + wp[-16]; + } + + for(kp = K512, wp = w; wp < &w[80]; ) { + t1 = h + SIGMA1(e) + Ch(e,f,g) + *kp++ + *wp++; + t2 = SIGMA0(a) + Maj(a,b,c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + + /* save state */ + s[0] += a; + s[1] += b; + s[2] += c; + s[3] += d; + s[4] += e; + s[5] += f; + s[6] += g; + s[7] += h; + } +} diff --git a/libsec/sha2block64.c b/libsec/sha2block64.c new file mode 100644 index 0000000..0b3a1b9 --- /dev/null +++ b/libsec/sha2block64.c @@ -0,0 +1,92 @@ +/* + * sha2_256 block cipher + * + * Implementation straight from Federal Information Processing Standards + * publication 180-2 (+Change Notice to include SHA-224) August 1, 2002 + * note: the following upper and lower case macro names are distinct + * and reflect the functions defined in FIPS pub. 180-2. + */ + +#include +#include + +#define ROTR(x,n) (((x) >> (n)) | ((x) << (32-(n)))) +#define sigma0(x) (ROTR((x),7) ^ ROTR((x),18) ^ ((x) >> 3)) +#define sigma1(x) (ROTR((x),17) ^ ROTR((x),19) ^ ((x) >> 10)) +#define SIGMA0(x) (ROTR((x),2) ^ ROTR((x),13) ^ ROTR((x),22)) +#define SIGMA1(x) (ROTR((x),6) ^ ROTR((x),11) ^ ROTR((x),25)) +#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) +#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + +/* + * first 32 bits of the fractional parts of cube roots of + * first 64 primes (2..311). + */ +static u32int K256[64] = { + 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, +}; + +void +_sha2block64(uchar *p, ulong len, u32int *s) +{ + u32int a, b, c, d, e, f, g, h, t1, t2; + u32int *kp, *wp; + u32int w[64]; + uchar *end; + + /* at this point, we have a multiple of 64 bytes */ + for(end = p+len; p < end;){ + a = s[0]; + b = s[1]; + c = s[2]; + d = s[3]; + e = s[4]; + f = s[5]; + g = s[6]; + h = s[7]; + + for(wp = w; wp < &w[16]; wp++, p += 4) + wp[0] = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; + for(; wp < &w[64]; wp++) + wp[0] = sigma1(wp[-2]) + wp[-7] + + sigma0(wp[-15]) + wp[-16]; + + for(kp = K256, wp = w; wp < &w[64]; ) { + t1 = h + SIGMA1(e) + Ch(e,f,g) + *kp++ + *wp++; + t2 = SIGMA0(a) + Maj(a,b,c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + + /* save state */ + s[0] += a; + s[1] += b; + s[2] += c; + s[3] += d; + s[4] += e; + s[5] += f; + s[6] += g; + s[7] += h; + } +} diff --git a/libsec/sha2test.c b/libsec/sha2test.c new file mode 100644 index 0000000..94b5646 --- /dev/null +++ b/libsec/sha2test.c @@ -0,0 +1,63 @@ +#include +#include +#include "libsec.h" + +char *tests[] = { + "", + "a", + "abc", + "message digest", + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "123456789012345678901234567890123456789012345678901234567890" + "12345678901234567890", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhi" + "jklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", + 0 +}; + +void +main(void) +{ + int i; + char **pp; + uchar *p; + uchar digest[SHA2_512dlen]; + + print("SHA2_224 tests:\n"); + for(pp = tests; *pp; pp++){ + p = (uchar*)*pp; + sha2_224(p, strlen(*pp), digest, 0); + for(i = 0; i < SHA2_224dlen; i++) + print("%2.2ux", digest[i]); + print("\n"); + } + + print("\nSHA256 tests:\n"); + for(pp = tests; *pp; pp++){ + p = (uchar*)*pp; + sha2_256(p, strlen(*pp), digest, 0); + for(i = 0; i < SHA2_256dlen; i++) + print("%2.2ux", digest[i]); + print("\n"); + } + + print("\nSHA384 tests:\n"); + for(pp = tests; *pp; pp++){ + p = (uchar*)*pp; + sha2_384(p, strlen(*pp), digest, 0); + for(i = 0; i < SHA2_384dlen; i++) + print("%2.2ux", digest[i]); + print("\n"); + } + + print("\nSHA512 tests:\n"); + for(pp = tests; *pp; pp++){ + p = (uchar*)*pp; + sha2_512(p, strlen(*pp), digest, 0); + for(i = 0; i < SHA2_512dlen; i++) + print("%2.2ux", digest[i]); + print("\n"); + } +} diff --git a/libsec/tlshand.c b/libsec/tlshand.c index 0d04a66..a7d38b6 100644 --- a/libsec/tlshand.c +++ b/libsec/tlshand.c @@ -17,7 +17,7 @@ enum { TLSFinishedLen = 12, SSL3FinishedLen = MD5dlen+SHA1dlen, - MaxKeyData = 104, // amount of secret we may need + MaxKeyData = 136, // amount of secret we may need MaxChunk = 1<<14, RandomSize = 32, SidSize = 32, @@ -118,7 +118,7 @@ typedef struct Msg{ typedef struct TlsSec{ char *server; // name of remote; nil for server - int ok; // <0 killed; ==0 in progress; >0 reusable + int ok; // <0 killed; == 0 in progress; >0 reusable RSApub *rsapub; AuthRpc *rpc; // factotum for rsa private key uchar sec[MasterSecretSize]; // master secret @@ -239,16 +239,18 @@ enum { }; static Algs cipherAlgs[] = { - {"rc4_128", "md5", 2 * (16 + MD5dlen), TLS_RSA_WITH_RC4_128_MD5}, - {"rc4_128", "sha1", 2 * (16 + SHA1dlen), TLS_RSA_WITH_RC4_128_SHA}, - {"3des_ede_cbc","sha1",2*(4*8+SHA1dlen), TLS_RSA_WITH_3DES_EDE_CBC_SHA}, + {"rc4_128", "md5", 2*(16+MD5dlen), TLS_RSA_WITH_RC4_128_MD5}, + {"rc4_128", "sha1", 2*(16+SHA1dlen), TLS_RSA_WITH_RC4_128_SHA}, + {"3des_ede_cbc", "sha1", 2*(4*8+SHA1dlen), TLS_RSA_WITH_3DES_EDE_CBC_SHA}, + {"aes_128_cbc", "sha1", 2*(16+16+SHA1dlen), TLS_RSA_WITH_AES_128_CBC_SHA}, + {"aes_256_cbc", "sha1", 2*(32+16+SHA1dlen), TLS_RSA_WITH_AES_256_CBC_SHA} }; static uchar compressors[] = { CompressionNull, }; -static TlsConnection *tlsServer2(int ctl, int hand, uchar *cert, int ncert, int (*trace)(char*fmt, ...)); +static TlsConnection *tlsServer2(int ctl, int hand, uchar *cert, int ncert, int (*trace)(char*fmt, ...), PEMChain *chain); static TlsConnection *tlsClient2(int ctl, int hand, uchar *csid, int ncsid, int (*trace)(char*fmt, ...)); static void msgClear(Msg *m); @@ -337,7 +339,7 @@ tlsServer(int fd, TLSconn *conn) return -1; } fprint(ctl, "fd %d 0x%x", fd, ProtocolVersion); - tls = tlsServer2(ctl, hand, conn->cert, conn->certlen, conn->trace); + tls = tlsServer2(ctl, hand, conn->cert, conn->certlen, conn->trace, conn->chain); sprint(dname, "#a/tls/%s/data", buf); data = open(dname, ORDWR); close(fd); @@ -357,6 +359,8 @@ tlsServer(int fd, TLSconn *conn) conn->sessionIDlen = tls->sid->len; conn->sessionID = emalloc(conn->sessionIDlen); memcpy(conn->sessionID, tls->sid->data, conn->sessionIDlen); + if(conn->sessionKey != nil && conn->sessionType != nil && strcmp(conn->sessionType, "ttls") == 0) + tls->sec->prf(conn->sessionKey, conn->sessionKeylen, tls->sec->sec, MasterSecretSize, conn->sessionConst, tls->sec->crandom, RandomSize, tls->sec->srandom, RandomSize); tlsConnectionFree(tls); return data; } @@ -408,19 +412,33 @@ tlsClient(int fd, TLSconn *conn) conn->sessionIDlen = tls->sid->len; conn->sessionID = emalloc(conn->sessionIDlen); memcpy(conn->sessionID, tls->sid->data, conn->sessionIDlen); + if(conn->sessionKey != nil && conn->sessionType != nil && strcmp(conn->sessionType, "ttls") == 0) + tls->sec->prf(conn->sessionKey, conn->sessionKeylen, tls->sec->sec, MasterSecretSize, conn->sessionConst, tls->sec->crandom, RandomSize, tls->sec->srandom, RandomSize); tlsConnectionFree(tls); return data; } +static int +countchain(PEMChain *p) +{ + int i = 0; + + while (p) { + i++; + p = p->next; + } + return i; +} + static TlsConnection * -tlsServer2(int ctl, int hand, uchar *cert, int ncert, int (*trace)(char*fmt, ...)) +tlsServer2(int ctl, int hand, uchar *cert, int ncert, int (*trace)(char*fmt, ...), PEMChain *chp) { TlsConnection *c; Msg m; Bytes *csid; uchar sid[SidSize], kd[MaxKeyData]; char *secrets; - int cipher, compressor, nsid, rv; + int cipher, compressor, nsid, rv, numcerts, i; if(trace) trace("tlsServer2\n"); @@ -498,9 +516,12 @@ tlsServer2(int ctl, int hand, uchar *cert, int ncert, int (*trace)(char*fmt, ... msgClear(&m); m.tag = HCertificate; - m.u.certificate.ncert = 1; + numcerts = countchain(chp); + m.u.certificate.ncert = 1 + numcerts; m.u.certificate.certs = emalloc(m.u.certificate.ncert * sizeof(Bytes)); m.u.certificate.certs[0] = makebytes(cert, ncert); + for (i = 0; i < numcerts && chp; i++, chp = chp->next) + m.u.certificate.certs[i+1] = makebytes(chp->pem, chp->pemlen); if(!msgSend(c, &m, AQueue)) goto Err; msgClear(&m); @@ -1116,18 +1137,23 @@ msgRecv(TlsConnection *c, Msg *m) } break; case HCertificateRequest: + if(n < 1) + goto Short; + nn = p[0]; + p += 1; + n -= 1; + if(nn < 1 || nn > n) + goto Short; + m->u.certificateRequest.types = makebytes(p, nn); + p += nn; + n -= nn; if(n < 2) goto Short; nn = get16(p); p += 2; n -= 2; - if(nn < 1 || nn > n) - goto Short; - m->u.certificateRequest.types = makebytes(p, nn); - nn = get24(p); - p += 3; - n -= 3; - if(nn == 0 || n != nn) + /* nn == 0 can happen; yahoo's servers do it */ + if(nn != n) goto Short; /* cas */ i = 0; @@ -1140,7 +1166,8 @@ msgRecv(TlsConnection *c, Msg *m) if(nn < 1 || nn > n) goto Short; m->u.certificateRequest.nca = i+1; - m->u.certificateRequest.cas = erealloc(m->u.certificateRequest.cas, (i+1)*sizeof(Bytes)); + m->u.certificateRequest.cas = erealloc( + m->u.certificateRequest.cas, (i+1)*sizeof(Bytes)); m->u.certificateRequest.cas[i] = makebytes(p, nn); p += nn; n -= nn; @@ -1181,8 +1208,10 @@ msgRecv(TlsConnection *c, Msg *m) goto Short; Ok: if(c->trace){ - char buf[8000]; - c->trace("recv %s", msgPrint(buf, sizeof buf, m)); + char *buf; + buf = emalloc(8000); + c->trace("recv %s", msgPrint(buf, 8000, m)); + free(buf); } return 1; Short: @@ -2043,9 +2072,12 @@ mptobytes(mpint* big) uchar *a; Bytes* ans; + a = nil; n = (mpsignif(big)+7)/8; m = mptobe(big, nil, n, &a); ans = makebytes(a, m); + if(a != nil) + free(a); return ans; } @@ -2223,8 +2255,7 @@ get16(uchar *p) return (p[0]<<8)|p[1]; } -/* ANSI offsetof() */ -#define OFFSET(x, s) ((int)(&(((s*)0)->x))) +#define OFFSET(x, s) offsetof(s, x) /* * malloc and return a new Bytes structure capable of diff --git a/libsec/x509.c b/libsec/x509.c index 081dd8f..8d7dae1 100644 --- a/libsec/x509.c +++ b/libsec/x509.c @@ -40,6 +40,7 @@ typedef struct Elist Elist; #define REAL 9 #define ENUMERATED 10 #define EMBEDDED_PDV 11 +#define UTF8String 12 #define SEQUENCE 16 /* also SEQUENCE OF */ #define SETOF 17 /* also SETOF OF */ #define NumericString 18 @@ -172,6 +173,7 @@ emalloc(int n) exits("out of memory"); } memset(p, 0, n); + setmalloctag(p, getcallerpc(&n)); return p; } @@ -259,9 +261,11 @@ ber_decode(uchar** pp, uchar* pend, Elem* pelem) if(err == ASN_OK) { err = length_decode(pp, pend, &length); if(err == ASN_OK) { - if(tag.class == Universal) + if(tag.class == Universal) { err = value_decode(pp, pend, length, tag.num, isconstr, &val); - else + if(val.tag == VSeq || val.tag == VSet) + setmalloctag(val.u.seqval, getcallerpc(&pp)); + }else err = value_decode(pp, pend, length, OCTET_STRING, 0, &val); if(err == ASN_OK) { pelem->tag = tag; @@ -316,8 +320,6 @@ length_decode(uchar** pp, uchar* pend, int* plength) v = *p++; if(v&0x80) err = int_decode(&p, pend, v&0x7F, 1, &num); - else if(v == 0x80) - num = -1; else num = v; } @@ -500,6 +502,7 @@ value_decode(uchar** pp, uchar* pend, int length, int kind, int isconstr, Value* case SEQUENCE: err = seq_decode(&p, pend, length, isconstr, &vl); + setmalloctag(vl, getcallerpc(&pp)); if(err == ASN_OK) { pval->tag = VSeq ; pval->u.seqval = vl; @@ -508,12 +511,13 @@ value_decode(uchar** pp, uchar* pend, int length, int kind, int isconstr, Value* case SETOF: err = seq_decode(&p, pend, length, isconstr, &vl); + setmalloctag(vl, getcallerpc(&pp)); if(err == ASN_OK) { pval->tag = VSet; pval->u.setval = vl; } break; - + case UTF8String: case NumericString: case PrintableString: case TeletexString: @@ -573,7 +577,7 @@ int_decode(uchar** pp, uchar* pend, int count, int unsgned, int* pint) err = ASN_ETOOBIG; else { if(!unsgned && count > 0 && count < 4 && (*p&0x80)) - num = -1; // set all bits, initially + num = -1; /* set all bits, initially */ while(count--) num = (num << 8)|(*p++); } @@ -744,6 +748,7 @@ seq_decode(uchar** pp, uchar* pend, int length, int isconstr, Elist** pelist) } *pp = p; *pelist = ans; + setmalloctag(ans, getcallerpc(&pp)); return err; } @@ -1014,6 +1019,7 @@ val_enc(uchar** pp, Elem e, int *pconstr, int lenonly) } break; + case UTF8String: case NumericString: case PrintableString: case TeletexString: @@ -1244,6 +1250,7 @@ is_string(Elem* pe, char** pstring) { if(pe->tag.class == Universal) { switch(pe->tag.num) { + case UTF8String: case NumericString: case PrintableString: case TeletexString: @@ -1404,6 +1411,7 @@ mkel(Elem e, Elist* tail) Elist* el; el = (Elist*)emalloc(sizeof(Elist)); + setmalloctag(el, getcallerpc(&e)); el->hd = e; el->tl = tail; return el; @@ -1461,21 +1469,21 @@ freevalfields(Value* v) freeints(v->u.objidval); break; case VString: - if (v->u.stringval) + if(v->u.stringval) free(v->u.stringval); break; case VSeq: el = v->u.seqval; for(l = el; l != nil; l = l->tl) freevalfields(&l->hd.val); - if (el) + if(el) freeelist(el); break; case VSet: el = v->u.setval; for(l = el; l != nil; l = l->tl) freevalfields(&l->hd.val); - if (el) + if(el) freeelist(el); break; } @@ -1573,6 +1581,7 @@ enum { ALG_md4WithRSAEncryption, ALG_md5WithRSAEncryption, ALG_sha1WithRSAEncryption, + ALG_sha1WithRSAEncryptionOiw, ALG_md5, NUMALGS }; @@ -1585,6 +1594,7 @@ static Ints7 oid_md2WithRSAEncryption = {7, 1, 2, 840, 113549, 1, 1, 2 }; static Ints7 oid_md4WithRSAEncryption = {7, 1, 2, 840, 113549, 1, 1, 3 }; static Ints7 oid_md5WithRSAEncryption = {7, 1, 2, 840, 113549, 1, 1, 4 }; static Ints7 oid_sha1WithRSAEncryption ={7, 1, 2, 840, 113549, 1, 1, 5 }; +static Ints7 oid_sha1WithRSAEncryptionOiw ={6, 1, 3, 14, 3, 2, 29 }; static Ints7 oid_md5 ={6, 1, 2, 840, 113549, 2, 5, 0 }; static Ints *alg_oid_tab[NUMALGS+1] = { (Ints*)&oid_rsaEncryption, @@ -1592,15 +1602,16 @@ static Ints *alg_oid_tab[NUMALGS+1] = { (Ints*)&oid_md4WithRSAEncryption, (Ints*)&oid_md5WithRSAEncryption, (Ints*)&oid_sha1WithRSAEncryption, + (Ints*)&oid_sha1WithRSAEncryptionOiw, (Ints*)&oid_md5, nil }; -static DigestFun digestalg[NUMALGS+1] = { md5, md5, md5, md5, sha1, md5, nil }; +static DigestFun digestalg[NUMALGS+1] = { md5, md5, md5, md5, sha1, sha1, md5, nil }; static void freecert(CertX509* c) { - if (!c) return; + if(!c) return; if(c->issuer != nil) free(c->issuer); if(c->validity_start != nil) @@ -1611,6 +1622,7 @@ freecert(CertX509* c) free(c->subject); freebytes(c->publickey); freebytes(c->signature); + free(c); } /* @@ -1833,16 +1845,19 @@ static RSApub* decode_rsapubkey(Bytes* a) { Elem e; - Elist *el; + Elist *el, *l; mpint *mp; RSApub* key; + l = nil; key = rsapuballoc(); if(decode(a->data, a->len, &e) != ASN_OK) goto errret; if(!is_seq(&e, &el) || elistlen(el) != 2) goto errret; + l = el; + key->n = mp = asn1mpint(&el->hd); if(mp == nil) goto errret; @@ -1851,8 +1866,13 @@ decode_rsapubkey(Bytes* a) key->ek = mp = asn1mpint(&el->hd); if(mp == nil) goto errret; + + if(l != nil) + freeelist(l); return key; errret: + if(l != nil) + freeelist(l); rsapubfree(key); return nil; } @@ -1932,6 +1952,68 @@ decode_rsaprivkey(Bytes* a) return nil; } +/* + * DSAPrivateKey ::= SEQUENCE{ + * version Version, + * p INTEGER, + * q INTEGER, + * g INTEGER, -- alpha + * pub_key INTEGER, -- key + * priv_key INTEGER, -- secret + * } + */ +static DSApriv* +decode_dsaprivkey(Bytes* a) +{ + int version; + Elem e; + Elist *el; + mpint *mp; + DSApriv* key; + + key = dsaprivalloc(); + if(decode(a->data, a->len, &e) != ASN_OK) + goto errret; + if(!is_seq(&e, &el) || elistlen(el) != 6) + goto errret; +version = -1; + if(!is_int(&el->hd, &version) || version != 0) +{ +fprint(2, "version %d\n", version); + goto errret; +} + + el = el->tl; + key->pub.p = mp = asn1mpint(&el->hd); + if(mp == nil) + goto errret; + + el = el->tl; + key->pub.q = mp = asn1mpint(&el->hd); + if(mp == nil) + goto errret; + + el = el->tl; + key->pub.alpha = mp = asn1mpint(&el->hd); + if(mp == nil) + goto errret; + + el = el->tl; + key->pub.key = mp = asn1mpint(&el->hd); + if(mp == nil) + goto errret; + + el = el->tl; + key->secret = mp = asn1mpint(&el->hd); + if(mp == nil) + goto errret; + + return key; +errret: + dsaprivfree(key); + return nil; +} + static mpint* asn1mpint(Elem *e) { @@ -1982,6 +2064,18 @@ asn1toRSApriv(uchar *kd, int kn) return key; } +DSApriv* +asn1toDSApriv(uchar *kd, int kn) +{ + Bytes *b; + DSApriv *key; + + b = makebytes(kd, kn); + key = decode_dsaprivkey(b); + freebytes(b); + return key; +} + /* * digest(CertificateInfo) * Our ASN.1 library doesn't return pointers into the original @@ -1999,12 +2093,16 @@ digest_certinfo(Bytes *cert, DigestFun digestfun, uchar *digest) p = cert->data; pend = cert->data + cert->len; if(tag_decode(&p, pend, &tag, &isconstr) != ASN_OK || - tag.class != Universal || tag.num != SEQUENCE || - length_decode(&p, pend, &length) != ASN_OK || - p+length > pend) + tag.class != Universal || tag.num != SEQUENCE || + length_decode(&p, pend, &length) != ASN_OK || + p+length > pend || + p+length < p) return; info = p; - if(ber_decode(&p, pend, &elem) != ASN_OK || elem.tag.num != SEQUENCE) + if(ber_decode(&p, pend, &elem) != ASN_OK) + return; + freevalfields(&elem.val); + if(elem.tag.num != SEQUENCE) return; infolen = p - info; (*digestfun)(info, infolen, digest, nil); @@ -2019,30 +2117,51 @@ verify_signature(Bytes* signature, RSApub *pk, uchar *edigest, Elem **psigalg) uchar *pkcs1buf, *buf; int buflen; mpint *pkcs1; + int nlen; + char *err; + + err = nil; + pkcs1buf = nil; + + /* one less than the byte length of the modulus */ + nlen = (mpsignif(pk->n)-1)/8; /* see 9.2.1 of rfc2437 */ pkcs1 = betomp(signature->data, signature->len, nil); mpexp(pkcs1, pk->ek, pk->n, pkcs1); buflen = mptobe(pkcs1, nil, 0, &pkcs1buf); buf = pkcs1buf; - if(buflen < 4 || buf[0] != 1) - return "expected 1"; + if(buflen != nlen || buf[0] != 1) { + err = "expected 1"; + goto end; + } buf++; while(buf[0] == 0xff) buf++; - if(buf[0] != 0) - return "expected 0"; + if(buf[0] != 0) { + err = "expected 0"; + goto end; + } buf++; buflen -= buf-pkcs1buf; if(decode(buf, buflen, &e) != ASN_OK || !is_seq(&e, &el) || elistlen(el) != 2 || - !is_octetstring(&el->tl->hd, &digest)) - return "signature parse error"; + !is_octetstring(&el->tl->hd, &digest)) { + err = "signature parse error"; + goto end; + } *psigalg = &el->hd; if(memcmp(digest->data, edigest, digest->len) == 0) - return nil; - return "digests did not match"; + goto end; + err = "digests did not match"; + +end: + if(pkcs1 != nil) + mpfree(pkcs1); + if(pkcs1buf != nil) + free(pkcs1buf); + return err; } - + RSApub* X509toRSApub(uchar *cert, int ncert, char *name, int nname) { @@ -2059,7 +2178,7 @@ X509toRSApub(uchar *cert, int ncert, char *name, int nname) if(name != nil && c->subject != nil){ e = strchr(c->subject, ','); if(e != nil) - *e = 0; // take just CN part of Distinguished Name + *e = 0; /* take just CN part of Distinguished Name */ strncpy(name, c->subject, nname); } pk = decode_rsapubkey(c->publickey); @@ -2067,6 +2186,97 @@ X509toRSApub(uchar *cert, int ncert, char *name, int nname) return pk; } +int +getalgo(Elem *e) +{ + Value *v; + Elist *el; + int a; + + if((a = parse_alg(e)) >= 0) + return a; + v = &e->val; + if(v->tag == VSeq){ + print("Seq\n"); + for(el = v->u.seqval; el!=nil; el = el->tl){ + if((a = getalgo(&el->hd)) >= 0) + return a; + } + } + return -1; +} + +static void edump(Elem e); + +RSApub* +asn1toRSApub(uchar *der, int nder) +{ + Elem e; + Elist *el, *l; + int n; + Bits *b; + RSApub *key; + mpint *mp; + + if(decode(der, nder, &e) != ASN_OK){ + print("didn't parse\n"); + return nil; + } + if(!is_seq(&e, &el)){ + print("no seq"); + return nil; + } + if((n = elistlen(el)) != 2){ + print("bad length %d\n", n); + return nil; + } + if((n = getalgo(&el->hd)) < 0){ + print("no algo\n"); + return nil; + } + if(n != 0){ + print("cant do algorithm %d\n", n); + return nil; + } + if(!is_bitstring(&el->tl->hd, &b)){ + print("no bits\n"); + return nil; + } + if(decode(b->data, b->len, &e) != ASN_OK){ + print("no second decode\n"); + return nil; + } + if(!is_seq(&e, &el)){ + print("no second seq\n"); + return nil; + } + if(elistlen(el) != 2){ + print("no second length\n"); + return nil; + } + key = rsapuballoc(); + + l = el; + + key->n = mp = asn1mpint(&el->hd); + if(mp == nil) + goto errret; + + el = el->tl; + key->ek = mp = asn1mpint(&el->hd); + if(mp == nil) + goto errret; + + if(l != nil) + freeelist(l); + return key; +errret: + if(l != nil) + freeelist(l); + rsapubfree(key); + return nil; +} + char* X509verify(uchar *cert, int ncert, RSApub *pk) { @@ -2264,6 +2474,34 @@ mkDN(char *dn) return mkseq(el); } +uchar* +RSApubtoasn1(RSApub *pub, int *keylen) +{ + Elem pubkey; + Bytes *pkbytes; + uchar *key; + + key = nil; + pubkey = mkseq(mkel(mkbigint(pub->n),mkel(mkint(mptoi(pub->ek)),nil))); + if(encode(pubkey, &pkbytes) != ASN_OK) + goto errret; + freevalfields(&pubkey.val); + pubkey = mkseq( + mkel(mkalg(ALG_rsaEncryption), + mkel(mkbits(pkbytes->data, pkbytes->len), + nil))); + freebytes(pkbytes); + if(encode(pubkey, &pkbytes) != ASN_OK) + goto errret; + if(keylen) + *keylen = pkbytes->len; + key = malloc(pkbytes->len); + memmove(key, pkbytes->data, pkbytes->len); + free(pkbytes); +errret: + freevalfields(&pubkey.val); + return key; +} uchar* X509gen(RSApriv *priv, char *subj, ulong valid[2], int *certlen) @@ -2398,33 +2636,34 @@ tagdump(Tag tag) if(tag.class != Universal) return smprint("class%d,num%d", tag.class, tag.num); switch(tag.num){ - case BOOLEAN: return "BOOLEAN"; break; - case INTEGER: return "INTEGER"; break; - case BIT_STRING: return "BIT STRING"; break; - case OCTET_STRING: return "OCTET STRING"; break; - case NULLTAG: return "NULLTAG"; break; - case OBJECT_ID: return "OID"; break; - case ObjectDescriptor: return "OBJECT_DES"; break; - case EXTERNAL: return "EXTERNAL"; break; - case REAL: return "REAL"; break; - case ENUMERATED: return "ENUMERATED"; break; - case EMBEDDED_PDV: return "EMBEDDED PDV"; break; - case SEQUENCE: return "SEQUENCE"; break; - case SETOF: return "SETOF"; break; - case NumericString: return "NumericString"; break; - case PrintableString: return "PrintableString"; break; - case TeletexString: return "TeletexString"; break; - case VideotexString: return "VideotexString"; break; - case IA5String: return "IA5String"; break; - case UTCTime: return "UTCTime"; break; - case GeneralizedTime: return "GeneralizedTime"; break; - case GraphicString: return "GraphicString"; break; - case VisibleString: return "VisibleString"; break; - case GeneralString: return "GeneralString"; break; - case UniversalString: return "UniversalString"; break; - case BMPString: return "BMPString"; break; - default: - return smprint("Universal,num%d", tag.num); + case BOOLEAN: return "BOOLEAN"; + case INTEGER: return "INTEGER"; + case BIT_STRING: return "BIT STRING"; + case OCTET_STRING: return "OCTET STRING"; + case NULLTAG: return "NULLTAG"; + case OBJECT_ID: return "OID"; + case ObjectDescriptor: return "OBJECT_DES"; + case EXTERNAL: return "EXTERNAL"; + case REAL: return "REAL"; + case ENUMERATED: return "ENUMERATED"; + case EMBEDDED_PDV: return "EMBEDDED PDV"; + case SEQUENCE: return "SEQUENCE"; + case SETOF: return "SETOF"; + case UTF8String: return "UTF8String"; + case NumericString: return "NumericString"; + case PrintableString: return "PrintableString"; + case TeletexString: return "TeletexString"; + case VideotexString: return "VideotexString"; + case IA5String: return "IA5String"; + case UTCTime: return "UTCTime"; + case GeneralizedTime: return "GeneralizedTime"; + case GraphicString: return "GraphicString"; + case VisibleString: return "VisibleString"; + case GeneralString: return "GeneralString"; + case UniversalString: return "UniversalString"; + case BMPString: return "BMPString"; + default: + return smprint("Universal,num%d", tag.num); } } @@ -2444,7 +2683,10 @@ edump(Elem e) case VBigInt: print("BigInt[%d] %.2x%.2x...",v.u.bigintval->len,v.u.bigintval->data[0],v.u.bigintval->data[1]); break; case VReal: print("Real..."); break; case VOther: print("Other..."); break; - case VBitString: print("BitString..."); break; + case VBitString: print("BitString"); + for(i = 0; ilen; i++) + print(" %02x", v.u.bitstringval->data[i]); + break; case VNull: print("Null"); break; case VEOC: print("EOC..."); break; case VObjId: print("ObjId"); From 947a96a923ef171647b224cc8c03e00cf848b705 Mon Sep 17 00:00:00 2001 From: Adrian Grigore Date: Sun, 23 Jun 2024 03:29:12 +0300 Subject: [PATCH 4/8] libmp: sync with Plan 9 --- include/mp.h | 147 +++++++++++++++++++++++------------------- libmp/Makefile | 1 + libmp/betomp.c | 4 +- libmp/crttest.c | 5 +- libmp/dat.h | 7 +- libmp/letomp.c | 1 - libmp/mpaux.c | 8 ++- libmp/mpcmp.c | 2 +- libmp/mpeuclid.c | 3 + libmp/mpexp.c | 8 +++ libmp/mpextendedgcd.c | 9 +++ libmp/mpfactorial.c | 75 +++++++++++++++++++++ libmp/mpleft.c | 6 ++ libmp/mpright.c | 14 ++++ libmp/mptobe.c | 1 + libmp/mptoi.c | 2 + libmp/mptoui.c | 8 +-- libmp/mptouv.c | 6 +- libmp/mptov.c | 4 +- libmp/mpveccmp.c | 1 - libmp/strtomp.c | 17 +++-- 21 files changed, 233 insertions(+), 96 deletions(-) create mode 100644 libmp/mpfactorial.c diff --git a/include/mp.h b/include/mp.h index fa912ca..c81c76d 100644 --- a/include/mp.h +++ b/include/mp.h @@ -1,16 +1,23 @@ +#ifdef PLAN9 +#pragma src "/sys/src/libmp" +#pragma lib "libmp.a" +#endif + #define _MPINT 1 -// the code assumes mpdigit to be at least an int -// mpdigit must be an atomic type. mpdigit is defined -// in the architecture specific u.h +/* + * the code assumes mpdigit to be at least an int + * mpdigit must be an atomic type. mpdigit is defined + * in the architecture specific u.h + */ typedef struct mpint mpint; struct mpint { - int sign; // +1 or -1 - int size; // allocated digits - int top; // significant digits + int sign; /* +1 or -1 */ + int size; /* allocated digits */ + int top; /* significant digits */ mpdigit *p; char flags; }; @@ -18,117 +25,125 @@ struct mpint enum { MPstatic= 0x01, - Dbytes= sizeof(mpdigit), // bytes per digit - Dbits= Dbytes*8 // bits per digit + Dbytes= sizeof(mpdigit), /* bytes per digit */ + Dbits= Dbytes*8 /* bits per digit */ }; -// allocation -void mpsetminbits(int n); // newly created mpint's get at least n bits -mpint* mpnew(int n); // create a new mpint with at least n bits +/* allocation */ +void mpsetminbits(int n); /* newly created mpint's get at least n bits */ +mpint* mpnew(int n); /* create a new mpint with at least n bits */ void mpfree(mpint *b); -void mpbits(mpint *b, int n); // ensure that b has at least n bits -void mpnorm(mpint *b); // dump leading zeros +void mpbits(mpint *b, int n); /* ensure that b has at least n bits */ +void mpnorm(mpint *b); /* dump leading zeros */ mpint* mpcopy(mpint *b); void mpassign(mpint *old, mpint *new); -// random bits +/* random bits */ mpint* mprand(int bits, void (*gen)(uchar*, int), mpint *b); -// conversion -mpint* strtomp(char*, char**, int, mpint*); // ascii +/* conversion */ +mpint* strtomp(char*, char**, int, mpint*); /* ascii */ int mpfmt(Fmt*); char* mptoa(mpint*, int, char*, int); -mpint* letomp(uchar*, uint, mpint*); // byte array, little-endian +mpint* letomp(uchar*, uint, mpint*); /* byte array, little-endian */ int mptole(mpint*, uchar*, uint, uchar**); -mpint* betomp(uchar*, uint, mpint*); // byte array, little-endian +mpint* betomp(uchar*, uint, mpint*); /* byte array, little-endian */ int mptobe(mpint*, uchar*, uint, uchar**); -uint mptoui(mpint*); // unsigned int +uint mptoui(mpint*); /* unsigned int */ mpint* uitomp(uint, mpint*); -int mptoi(mpint*); // int +int mptoi(mpint*); /* int */ mpint* itomp(int, mpint*); -uvlong mptouv(mpint*); // unsigned vlong +uvlong mptouv(mpint*); /* unsigned vlong */ mpint* uvtomp(uvlong, mpint*); -vlong mptov(mpint*); // vlong +vlong mptov(mpint*); /* vlong */ mpint* vtomp(vlong, mpint*); -// divide 2 digits by one +/* divide 2 digits by one */ void mpdigdiv(mpdigit *dividend, mpdigit divisor, mpdigit *quotient); -// in the following, the result mpint may be -// the same as one of the inputs. -void mpadd(mpint *b1, mpint *b2, mpint *sum); // sum = b1+b2 -void mpsub(mpint *b1, mpint *b2, mpint *diff); // diff = b1-b2 -void mpleft(mpint *b, int shift, mpint *res); // res = b<>shift -void mpmul(mpint *b1, mpint *b2, mpint *prod); // prod = b1*b2 -void mpexp(mpint *b, mpint *e, mpint *m, mpint *res); // res = b**e mod m -void mpmod(mpint *b, mpint *m, mpint *remainder); // remainder = b mod m - -// quotient = dividend/divisor, remainder = dividend % divisor +/* in the following, the result mpint may be */ +/* the same as one of the inputs. */ +void mpadd(mpint *b1, mpint *b2, mpint *sum); /* sum = b1+b2 */ +void mpsub(mpint *b1, mpint *b2, mpint *diff); /* diff = b1-b2 */ +void mpleft(mpint *b, int shift, mpint *res); /* res = b<>shift */ +void mpmul(mpint *b1, mpint *b2, mpint *prod); /* prod = b1*b2 */ +void mpexp(mpint *b, mpint *e, mpint *m, mpint *res); /* res = b**e mod m */ +void mpmod(mpint *b, mpint *m, mpint *remainder); /* remainder = b mod m */ + +/* quotient = dividend/divisor, remainder = dividend % divisor */ void mpdiv(mpint *dividend, mpint *divisor, mpint *quotient, mpint *remainder); -// return neg, 0, pos as b1-b2 is neg, 0, pos +/* return neg, 0, pos as b1-b2 is neg, 0, pos */ int mpcmp(mpint *b1, mpint *b2); -// extended gcd return d, x, and y, s.t. d = gcd(a,b) and ax+by = d +/* extended gcd return d, x, and y, s.t. d = gcd(a,b) and ax+by = d */ void mpextendedgcd(mpint *a, mpint *b, mpint *d, mpint *x, mpint *y); -// res = b**-1 mod m +/* res = b**-1 mod m */ void mpinvert(mpint *b, mpint *m, mpint *res); -// bit counting -int mpsignif(mpint*); // number of sigificant bits in mantissa -int mplowbits0(mpint*); // k, where n = 2**k * q for odd q +/* bit counting */ +int mpsignif(mpint*); /* number of sigificant bits in mantissa */ +int mplowbits0(mpint*); /* k, where n = 2**k * q for odd q */ -// well known constants +/* well known constants */ extern mpint *mpzero, *mpone, *mptwo; -// sum[0:alen] = a[0:alen-1] + b[0:blen-1] -// prereq: alen >= blen, sum has room for alen+1 digits +/* sum[0:alen] = a[0:alen-1] + b[0:blen-1] */ +/* prereq: alen >= blen, sum has room for alen+1 digits */ void mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum); -// diff[0:alen-1] = a[0:alen-1] - b[0:blen-1] -// prereq: alen >= blen, diff has room for alen digits +/* diff[0:alen-1] = a[0:alen-1] - b[0:blen-1] */ +/* prereq: alen >= blen, diff has room for alen digits */ void mpvecsub(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *diff); -// p[0:n] += m * b[0:n-1] -// prereq: p has room for n+1 digits +/* p[0:n] += m * b[0:n-1] */ +/* prereq: p has room for n+1 digits */ void mpvecdigmuladd(mpdigit *b, int n, mpdigit m, mpdigit *p); -// p[0:n] -= m * b[0:n-1] -// prereq: p has room for n+1 digits +/* p[0:n] -= m * b[0:n-1] */ +/* prereq: p has room for n+1 digits */ int mpvecdigmulsub(mpdigit *b, int n, mpdigit m, mpdigit *p); -// p[0:alen*blen-1] = a[0:alen-1] * b[0:blen-1] -// prereq: alen >= blen, p has room for m*n digits +/* p[0:alen*blen-1] = a[0:alen-1] * b[0:blen-1] */ +/* prereq: alen >= blen, p has room for m*n digits */ void mpvecmul(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *p); -// sign of a - b or zero if the same +/* sign of a - b or zero if the same */ int mpveccmp(mpdigit *a, int alen, mpdigit *b, int blen); -// divide the 2 digit dividend by the one digit divisor and stick in quotient -// we assume that the result is one digit - overflow is all 1's +/* divide the 2 digit dividend by the one digit divisor and stick in quotient */ +/* we assume that the result is one digit - overflow is all 1's */ void mpdigdiv(mpdigit *dividend, mpdigit divisor, mpdigit *quotient); -// playing with magnitudes +/* playing with magnitudes */ int mpmagcmp(mpint *b1, mpint *b2); -void mpmagadd(mpint *b1, mpint *b2, mpint *sum); // sum = b1+b2 -void mpmagsub(mpint *b1, mpint *b2, mpint *sum); // sum = b1+b2 +void mpmagadd(mpint *b1, mpint *b2, mpint *sum); /* sum = b1+b2 */ +void mpmagsub(mpint *b1, mpint *b2, mpint *sum); /* sum = b1+b2 */ + +/* chinese remainder theorem */ +typedef struct CRTpre CRTpre; /* precomputed values for converting */ + /* twixt residues and mpint */ +typedef struct CRTres CRTres; /* residue form of an mpint */ -// chinese remainder theorem -typedef struct CRTpre CRTpre; // precomputed values for converting - // twixt residues and mpint -typedef struct CRTres CRTres; // residue form of an mpint +#ifdef PLAN9 +#pragma incomplete CRTpre +#endif struct CRTres { - int n; // number of residues - mpint *r[1]; // residues + int n; /* number of residues */ + mpint *r[1]; /* residues */ }; -CRTpre* crtpre(int, mpint**); // precompute conversion values -CRTres* crtin(CRTpre*, mpint*); // convert mpint to residues -void crtout(CRTpre*, CRTres*, mpint*); // convert residues to mpint +CRTpre* crtpre(int, mpint**); /* precompute conversion values */ +CRTres* crtin(CRTpre*, mpint*); /* convert mpint to residues */ +void crtout(CRTpre*, CRTres*, mpint*); /* convert residues to mpint */ void crtprefree(CRTpre*); void crtresfree(CRTres*); + +#ifdef VARARGCK +#pragma varargck type "B" mpint* +#endif diff --git a/libmp/Makefile b/libmp/Makefile index 402d39d..d62a1c2 100644 --- a/libmp/Makefile +++ b/libmp/Makefile @@ -11,6 +11,7 @@ OFILES=\ mpadd.$O\ mpaux.$O\ mpcmp.$O\ + mpfactorial.$O\ mpdigdiv.$O\ mpdiv.$O\ mpeuclid.$O\ diff --git a/libmp/betomp.c b/libmp/betomp.c index 95935fc..9197f3a 100644 --- a/libmp/betomp.c +++ b/libmp/betomp.c @@ -9,8 +9,10 @@ betomp(uchar *p, uint n, mpint *b) int m, s; mpdigit x; - if(b == nil) + if(b == nil){ b = mpnew(0); + setmalloctag(b, getcallerpc(&p)); + } // dump leading zeros while(*p == 0 && n > 1){ diff --git a/libmp/crttest.c b/libmp/crttest.c index b58e173..ef3d18e 100644 --- a/libmp/crttest.c +++ b/libmp/crttest.c @@ -8,9 +8,8 @@ testcrt(mpint **p) CRTpre *crt; CRTres *res; mpint *m, *x, *y; - int i; - fmtinstall('B', mpconv); + fmtinstall('B', mpfmt); // get a modulus and a test number m = mpnew(1024+160); @@ -49,6 +48,6 @@ main(void) mpfree(p[0]); mpfree(p[1]); } - print("%d secs with more\n", time(0)-start); + print("%ld secs with more\n", time(0)-start); exits(0); } diff --git a/libmp/dat.h b/libmp/dat.h index f935fa3..8542909 100644 --- a/libmp/dat.h +++ b/libmp/dat.h @@ -7,9 +7,6 @@ #define MININT (MAXINT+1) // for converting between vlongs's and mpint's -// #define MAXUVLONG (~0ULL) -// #define MAXVLONG (MAXUVLONG>>1) -// #define MINVLONG (MAXVLONG+1ULL) -#define MAXUVLONG ((uvlong) ~0) +#define MAXUVLONG (~0ULL) #define MAXVLONG (MAXUVLONG>>1) -#define MINVLONG (MAXVLONG+((uvlong) 1)) +#define MINVLONG (MAXVLONG+1ULL) diff --git a/libmp/letomp.c b/libmp/letomp.c index 5b8ee92..e23fed2 100644 --- a/libmp/letomp.c +++ b/libmp/letomp.c @@ -12,7 +12,6 @@ letomp(uchar *s, uint n, mpint *b) if(b == nil) b = mpnew(0); mpbits(b, 8*n); - b->top = DIGITS(8*n); for(; n > 0; n--){ x |= ((mpdigit)(*s++)) << i; i += 8; diff --git a/libmp/mpaux.c b/libmp/mpaux.c index 38fc53d..66f1524 100644 --- a/libmp/mpaux.c +++ b/libmp/mpaux.c @@ -41,6 +41,8 @@ static int mpmindigits = 33; void mpsetminbits(int n) { + if(n < 0) + sysfatal("mpsetminbits: n < 0"); if(n == 0) n = 1; mpmindigits = DIGITS(n); @@ -52,7 +54,11 @@ mpnew(int n) { mpint *b; + if(n < 0) + sysfatal("mpsetminbits: n < 0"); + b = mallocz(sizeof(mpint), 1); + setmalloctag(b, getcallerpc(&n)); if(b == nil) sysfatal("mpnew: %r"); n = DIGITS(n); @@ -96,7 +102,7 @@ mpfree(mpint *b) return; if(b->flags & MPstatic) sysfatal("freeing mp constant"); - memset(b->p, 0, b->top*Dbytes); // information hiding + memset(b->p, 0, b->size*Dbytes); // information hiding free(b->p); free(b); } diff --git a/libmp/mpcmp.c b/libmp/mpcmp.c index 38af081..a2e3cf7 100644 --- a/libmp/mpcmp.c +++ b/libmp/mpcmp.c @@ -2,7 +2,7 @@ #include #include "dat.h" -// return 1, 0, -1 as abs(b1)-abs(b2) is neg, 0, pos +// return neg, 0, pos as abs(b1)-abs(b2) is neg, 0, pos int mpmagcmp(mpint *b1, mpint *b2) { diff --git a/libmp/mpeuclid.c b/libmp/mpeuclid.c index b44e8ae..80b5983 100644 --- a/libmp/mpeuclid.c +++ b/libmp/mpeuclid.c @@ -13,6 +13,9 @@ mpeuclid(mpint *a, mpint *b, mpint *d, mpint *x, mpint *y) { mpint *tmp, *x0, *x1, *x2, *y0, *y1, *y2, *q, *r; + if(a->sign<0 || b->sign<0) + sysfatal("mpeuclid: negative arg"); + if(mpcmp(a, b) < 0){ tmp = a; a = b; diff --git a/libmp/mpexp.c b/libmp/mpexp.c index 7450572..9ec067c 100644 --- a/libmp/mpexp.c +++ b/libmp/mpexp.c @@ -22,6 +22,14 @@ mpexp(mpint *b, mpint *e, mpint *m, mpint *res) mpdigit d, bit; int i, j; + i = mpcmp(e,mpzero); + if(i==0){ + mpassign(mpone, res); + return; + } + if(i<0) + sysfatal("mpexp: negative exponent"); + t[0] = mpcopy(b); t[1] = res; diff --git a/libmp/mpextendedgcd.c b/libmp/mpextendedgcd.c index 9d1557e..413a05c 100644 --- a/libmp/mpextendedgcd.c +++ b/libmp/mpextendedgcd.c @@ -15,6 +15,13 @@ mpextendedgcd(mpint *a, mpint *b, mpint *v, mpint *x, mpint *y) mpint *u, *A, *B, *C, *D; int g; + if(a->sign < 0 || b->sign < 0){ + mpassign(mpzero, v); + mpassign(mpzero, y); + mpassign(mpzero, x); + return; + } + if(a->top == 0){ mpassign(b, v); mpassign(mpone, y); @@ -94,4 +101,6 @@ mpextendedgcd(mpint *a, mpint *b, mpint *v, mpint *x, mpint *y) mpfree(u); mpfree(a); mpfree(b); + + return; } diff --git a/libmp/mpfactorial.c b/libmp/mpfactorial.c new file mode 100644 index 0000000..9d980c3 --- /dev/null +++ b/libmp/mpfactorial.c @@ -0,0 +1,75 @@ +#include "os.h" +#include +#include +#include "dat.h" + +mpint* +mpfactorial(ulong n) +{ + int i; + ulong k; + unsigned cnt; + int max, mmax; + mpdigit p, pp[2]; + mpint *r, *s, *stk[31]; + + cnt = 0; + max = mmax = -1; + p = 1; + r = mpnew(0); + for(k=2; k<=n; k++){ + pp[0] = 0; + pp[1] = 0; + mpvecdigmuladd(&p, 1, (mpdigit)k, pp); + if(pp[1] == 0) /* !overflow */ + p = pp[0]; + else{ + cnt++; + if((cnt & 1) == 0){ + s = stk[max]; + mpbits(r, Dbits*(s->top+1+1)); + memset(r->p, 0, Dbytes*(s->top+1+1)); + mpvecmul(s->p, s->top, &p, 1, r->p); + r->sign = 1; + r->top = s->top+1+1; /* XXX: norm */ + mpassign(r, s); + for(i=4; (cnt & (i-1)) == 0; i=i<<1){ + mpmul(stk[max], stk[max-1], r); + mpassign(r, stk[max-1]); + max--; + } + }else{ + max++; + if(max > mmax){ + mmax++; + if(max >= nelem(stk)) + abort(); + stk[max] = mpnew(Dbits); + } + stk[max]->top = 1; + stk[max]->p[0] = p; + } + p = (mpdigit)k; + } + } + if(max < 0){ + mpbits(r, Dbits); + r->top = 1; + r->sign = 1; + r->p[0] = p; + }else{ + s = stk[max--]; + mpbits(r, Dbits*(s->top+1+1)); + memset(r->p, 0, Dbytes*(s->top+1+1)); + mpvecmul(s->p, s->top, &p, 1, r->p); + r->sign = 1; + r->top = s->top+1+1; /* XXX: norm */ + } + + while(max >= 0) + mpmul(r, stk[max--], r); + for(max=mmax; max>=0; max--) + mpfree(stk[max]); + mpnorm(r); + return r; +} diff --git a/libmp/mpleft.c b/libmp/mpleft.c index 23ff9da..cdcdff7 100644 --- a/libmp/mpleft.c +++ b/libmp/mpleft.c @@ -9,6 +9,12 @@ mpleft(mpint *b, int shift, mpint *res) int d, l, r, i, otop; mpdigit this, last; + res->sign = b->sign; + if(b->top==0){ + res->top = 0; + return; + } + // a negative left shift is a right shift if(shift < 0){ mpright(b, -shift, res); diff --git a/libmp/mpright.c b/libmp/mpright.c index 6c42de1..0303917 100644 --- a/libmp/mpright.c +++ b/libmp/mpright.c @@ -9,6 +9,12 @@ mpright(mpint *b, int shift, mpint *res) int d, l, r, i; mpdigit this, last; + res->sign = b->sign; + if(b->top==0){ + res->top = 0; + return; + } + // a negative right shift is a left shift if(shift < 0){ mpleft(b, -shift, res); @@ -21,6 +27,12 @@ mpright(mpint *b, int shift, mpint *res) r = shift - d*Dbits; l = Dbits - r; + // shift all the bits out == zero + if(d>=b->top){ + res->top = 0; + return; + } + // special case digit shifts if(r == 0){ for(i = 0; i < b->top-d; i++) @@ -37,4 +49,6 @@ mpright(mpint *b, int shift, mpint *res) while(i > 0 && res->p[i-1] == 0) i--; res->top = i; + if(i==0) + res->sign = 1; } diff --git a/libmp/mptobe.c b/libmp/mptobe.c index e08ae56..ed527cc 100644 --- a/libmp/mptobe.c +++ b/libmp/mptobe.c @@ -15,6 +15,7 @@ mptobe(mpint *b, uchar *p, uint n, uchar **pp) if(p == nil){ n = (b->top+1)*Dbytes; p = malloc(n); + setmalloctag(p, getcallerpc(&b)); } if(p == nil) return -1; diff --git a/libmp/mptoi.c b/libmp/mptoi.c index e636e24..b3f22b4 100644 --- a/libmp/mptoi.c +++ b/libmp/mptoi.c @@ -28,6 +28,8 @@ mptoi(mpint *b) { uint x; + if(b->top==0) + return 0; x = *b->p; if(b->sign > 0){ if(b->top > 1 || (x > MAXINT)) diff --git a/libmp/mptoui.c b/libmp/mptoui.c index 9d80c1d..41c0b0b 100644 --- a/libmp/mptoui.c +++ b/libmp/mptoui.c @@ -25,11 +25,9 @@ mptoui(mpint *b) uint x; x = *b->p; - if(b->sign < 0){ + if(b->sign < 0) x = 0; - } else { - if(b->top > 1 || x > MAXUINT) - x = MAXUINT; - } + else if(b->top > 1 || (sizeof(mpdigit) > sizeof(uint) && x > MAXUINT)) + x = MAXUINT; return x; } diff --git a/libmp/mptouv.c b/libmp/mptouv.c index 76f93dd..b2a7632 100644 --- a/libmp/mptouv.c +++ b/libmp/mptouv.c @@ -35,15 +35,15 @@ mptouv(mpint *b) int s; if(b->top == 0) - return (vlong) 0; + return 0LL; mpnorm(b); if(b->top > VLDIGITS) return MAXVLONG; - v = (uvlong) 0; + v = 0ULL; for(s = 0; s < b->top; s++) - v |= b->p[s]<<(s*sizeof(mpdigit)*8); + v |= (uvlong)b->p[s]<<(s*sizeof(mpdigit)*8); return v; } diff --git a/libmp/mptov.c b/libmp/mptov.c index fd371d8..b09718e 100644 --- a/libmp/mptov.c +++ b/libmp/mptov.c @@ -41,7 +41,7 @@ mptov(mpint *b) int s; if(b->top == 0) - return (vlong) 0; + return 0LL; mpnorm(b); if(b->top > VLDIGITS){ @@ -51,7 +51,7 @@ mptov(mpint *b) return (vlong)MINVLONG; } - v = (uvlong) 0; + v = 0ULL; for(s = 0; s < b->top; s++) v |= b->p[s]<<(s*sizeof(mpdigit)*8); diff --git a/libmp/mpveccmp.c b/libmp/mpveccmp.c index 9dcc598..a462b1b 100644 --- a/libmp/mpveccmp.c +++ b/libmp/mpveccmp.c @@ -2,7 +2,6 @@ #include #include "dat.h" -// prereq: alen >= blen int mpveccmp(mpdigit *a, int alen, mpdigit *b, int blen) { diff --git a/libmp/strtomp.c b/libmp/strtomp.c index bc1de22..26e3751 100644 --- a/libmp/strtomp.c +++ b/libmp/strtomp.c @@ -52,7 +52,7 @@ from16(char *a, mpint *b) b->top = 0; for(p = a; *p; p++) - if(tab.t16[(uchar)*p] == INVAL) + if(tab.t16[*(uchar*)p] == INVAL) break; mpbits(b, (p-a)*4); b->top = 0; @@ -62,7 +62,7 @@ from16(char *a, mpint *b) for(i = 0; i < Dbits; i += 4){ if(p <= a) break; - x |= tab.t16[(uchar)*--p]<p[b->top++] = x; } @@ -88,7 +88,7 @@ from10(char *a, mpint *b) // do a billion at a time in native arithmetic x = 0; for(i = 0; i < 9; i++){ - y = tab.t10[(uchar)*a]; + y = tab.t10[*(uchar*)a]; if(y == INVAL) break; a++; @@ -118,7 +118,7 @@ from64(char *a, mpint *b) uchar *p; int n, m; - for(; tab.t64[(uchar)*a] != INVAL; a++) + for(; tab.t64[*(uchar*)a] != INVAL; a++) ; n = a-buf; mpbits(b, n*6); @@ -138,15 +138,18 @@ from32(char *a, mpint *b) uchar *p; int n, m; - for(; tab.t64[(uchar)*a] != INVAL; a++) + for(; tab.t64[*(uchar*)a] != INVAL; a++) ; n = a-buf; mpbits(b, n*5); p = malloc(n); if(p == nil) - return a; + return buf; m = dec32(p, n, buf, n); - betomp(p, m, b); + if(m == -1) + a = buf; + else + betomp(p, m, b); free(p); return a; } From e67eaf09f50f9cdd2d72f08ee472682a9edbdd6f Mon Sep 17 00:00:00 2001 From: Adrian Grigore Date: Sun, 23 Jun 2024 03:49:05 +0300 Subject: [PATCH 5/8] libauthsrv: sync with Plan 9 --- include/authsrv.h | 39 ++++--- libauthsrv/authdial.c | 39 ++++--- libauthsrv/passtokey.c | 1 - libauthsrv/readnvram.c | 236 ++++++++++++++++++++++++++++++----------- 4 files changed, 218 insertions(+), 97 deletions(-) diff --git a/include/authsrv.h b/include/authsrv.h index 4a486e9..971a513 100644 --- a/include/authsrv.h +++ b/include/authsrv.h @@ -16,18 +16,18 @@ typedef struct OMSchapreply OMSchapreply; enum { - ANAMELEN= 28, /* maximum size of name in previous proto */ - AERRLEN= 64, /* maximum size of errstr in previous proto */ - DOMLEN= 48, /* length of an authentication domain name */ - DESKEYLEN= 7, /* length of a des key for encrypt/decrypt */ - CHALLEN= 8, /* length of a plan9 sk1 challenge */ - NETCHLEN= 16, /* max network challenge length (used in AS protocol) */ + ANAMELEN= 28, /* name max size in previous proto */ + AERRLEN= 64, /* errstr max size in previous proto */ + DOMLEN= 48, /* authentication domain name length */ + DESKEYLEN= 7, /* encrypt/decrypt des key length */ + CHALLEN= 8, /* plan9 sk1 challenge length */ + NETCHLEN= 16, /* max network challenge length (used in AS protocol) */ CONFIGLEN= 14, - SECRETLEN= 32, /* max length of a secret */ + SECRETLEN= 32, /* secret max size */ - KEYDBOFF= 8, /* length of random data at the start of key file */ - OKEYDBLEN= ANAMELEN+DESKEYLEN+4+2, /* length of an entry in old key file */ - KEYDBLEN= OKEYDBLEN+SECRETLEN, /* length of an entry in key file */ + KEYDBOFF= 8, /* bytes of random data at key file's start */ + OKEYDBLEN= ANAMELEN+DESKEYLEN+4+2, /* old key file entry length */ + KEYDBLEN= OKEYDBLEN+SECRETLEN, /* key file entry length */ OMD5LEN= 16, }; @@ -133,21 +133,28 @@ extern int passtokey(char*, char*); * Nvram interface */ enum { - NVwrite = 1<<0, /* always prompt and rewrite nvram */ - NVwriteonerr = 1<<1, /* prompt and rewrite nvram when corrupt */ + NVread = 0, /* just read */ + NVwrite = 1<<0, /* always prompt and rewrite nvram */ + NVwriteonerr = 1<<1, /* prompt and rewrite nvram when corrupt */ + NVwritemem = 1<<2, /* don't prompt, write nvram from argument */ }; +/* storage layout */ struct Nvrsafe { - char machkey[DESKEYLEN]; + char machkey[DESKEYLEN]; /* was file server's authid's des key */ uchar machsum; - char authkey[DESKEYLEN]; + char authkey[DESKEYLEN]; /* authid's des key from password */ uchar authsum; + /* + * file server config string of device holding full configuration; + * secstore key on non-file-servers. + */ char config[CONFIGLEN]; uchar configsum; - char authid[ANAMELEN]; + char authid[ANAMELEN]; /* auth userid, e.g., bootes */ uchar authidsum; - char authdom[DOMLEN]; + char authdom[DOMLEN]; /* auth domain, e.g., cs.bell-labs.com */ uchar authdomsum; }; diff --git a/libauthsrv/authdial.c b/libauthsrv/authdial.c index c2463a1..c54803b 100644 --- a/libauthsrv/authdial.c +++ b/libauthsrv/authdial.c @@ -7,25 +7,30 @@ int authdial(char *netroot, char *dom) { - char server[Ndbvlen]; - Ndbtuple *nt; + char *p; + int rv; - - if(dom != nil){ - /* look up an auth server in an authentication domain */ - nt = csgetval(netroot, "authdom", dom, "auth", server); - - /* if that didn't work, just try the IP domain */ - if(nt == nil) - nt = csgetval(netroot, "dom", dom, "auth", server); - if(nt == nil){ - werrstr("no auth server found for %s", dom); - return -1; - } - ndbfree(nt); - return dial(netmkaddr(server, netroot, "ticket"), 0, 0, 0); - } else { + if(dom == nil) /* look for one relative to my machine */ return dial(netmkaddr("$auth", netroot, "ticket"), 0, 0, 0); + + /* look up an auth server in an authentication domain */ + p = csgetvalue(netroot, "authdom", dom, "auth", nil); + + /* if that didn't work, just try the IP domain */ + if(p == nil) + p = csgetvalue(netroot, "dom", dom, "auth", nil); + /* + * if that didn't work, try p9auth.$dom. this is very helpful if + * you can't edit /lib/ndb. + */ + if(p == nil) + p = smprint("p9auth.%s", dom); + if(p == nil){ /* should no longer ever happen */ + werrstr("no auth server found for %s", dom); + return -1; } + rv = dial(netmkaddr(p, netroot, "ticket"), 0, 0, 0); + free(p); + return rv; } diff --git a/libauthsrv/passtokey.c b/libauthsrv/passtokey.c index 8e267ce..cde9a24 100644 --- a/libauthsrv/passtokey.c +++ b/libauthsrv/passtokey.c @@ -29,5 +29,4 @@ passtokey(char *key, char *p) } encrypt(key, t, 8); } - return 1; /* not reached */ } diff --git a/libauthsrv/readnvram.c b/libauthsrv/readnvram.c index 4c92efc..e991599 100644 --- a/libauthsrv/readnvram.c +++ b/libauthsrv/readnvram.c @@ -4,6 +4,8 @@ static long finddosfile(int, char*); +static int nvramdebug; + static int check(void *x, int len, uchar sum, char *msg) { @@ -27,15 +29,29 @@ static struct { "sparc", "#r/nvram", 1024+850, sizeof(Nvrsafe), "pc", "#S/sdC0/nvram", 0, sizeof(Nvrsafe), "pc", "#S/sdC0/9fat", -1, sizeof(Nvrsafe), + "pc", "#S/sdC1/nvram", 0, sizeof(Nvrsafe), + "pc", "#S/sdC1/9fat", -1, sizeof(Nvrsafe), + "pc", "#S/sdD0/nvram", 0, sizeof(Nvrsafe), + "pc", "#S/sdD0/9fat", -1, sizeof(Nvrsafe), + "pc", "#S/sdE0/nvram", 0, sizeof(Nvrsafe), + "pc", "#S/sdE0/9fat", -1, sizeof(Nvrsafe), + "pc", "#S/sdF0/nvram", 0, sizeof(Nvrsafe), + "pc", "#S/sdF0/9fat", -1, sizeof(Nvrsafe), "pc", "#S/sd00/nvram", 0, sizeof(Nvrsafe), "pc", "#S/sd00/9fat", -1, sizeof(Nvrsafe), "pc", "#S/sd01/nvram", 0, sizeof(Nvrsafe), "pc", "#S/sd01/9fat", -1, sizeof(Nvrsafe), + "pc", "#S/sd10/nvram", 0, sizeof(Nvrsafe), + "pc", "#S/sd10/9fat", -1, sizeof(Nvrsafe), "pc", "#f/fd0disk", -1, 512, /* 512: #f requires whole sector reads */ "pc", "#f/fd1disk", -1, 512, "mips", "#r/nvram", 1024+900, sizeof(Nvrsafe), - "power", "#F/flash/flash0", 0x300000, sizeof(Nvrsafe), + "power", "#F/flash/flash0", 0x440000, sizeof(Nvrsafe), + "power", "#F/flash/flash", 0x440000, sizeof(Nvrsafe), "power", "#r/nvram", 4352, sizeof(Nvrsafe), /* OK for MTX-604e */ + "power", "/nvram", 0, sizeof(Nvrsafe), /* OK for Ucu */ + "arm", "#F/flash/flash0", 0x100000, sizeof(Nvrsafe), + "arm", "#F/flash/flash", 0x100000, sizeof(Nvrsafe), "debug", "/tmp/nvram", 0, sizeof(Nvrsafe), }; @@ -109,40 +125,55 @@ readcons(char *prompt, char *def, int raw, char *buf, int nbuf) buf[m++] = line[0]; } } - return buf; /* how does this happen */ } +typedef struct { + int fd; + int safeoff; + int safelen; +} Nvrwhere; -/* - * get key info out of nvram. since there isn't room in the PC's nvram use - * a disk partition there. - */ -int -readnvram(Nvrsafe *safep, int flag) -{ - char buf[1024], in[128], *cputype, *nvrfile, *nvrlen, *nvroff, *v[2]; - int fd, err, i, safeoff, safelen; - Nvrsafe *safe; +static char *nvrfile = nil, *cputype = nil; - err = 0; - memset(safep, 0, sizeof(*safep)); +/* returns with *locp filled in and locp->fd open, if possible */ +static void +findnvram(Nvrwhere *locp) +{ + char *nvrlen, *nvroff, *nvrcopy, *db, *v[2]; + int fd, i, safeoff, safelen; - nvrfile = getenv("nvram"); - cputype = getenv("cputype"); + if (nvrfile == nil) { + nvrfile = getenv("nvram"); + db = getenv("nvramdebug"); + nvramdebug = db != nil; + free(db); + } + if (cputype == nil) + cputype = getenv("cputype"); if(cputype == nil) - cputype = "mips"; - if(strcmp(cputype, "386")==0 || strcmp(cputype, "alpha")==0) - cputype = "pc"; - - safe = (Nvrsafe*)buf; + cputype = strdup("mips"); + if(strcmp(cputype, "386")==0 || strcmp(cputype, "alpha")==0) { + free(cputype); + cputype = strdup("pc"); + } fd = -1; safeoff = -1; safelen = -1; - if(nvrfile != nil){ + if(nvrfile != nil && *nvrfile != '\0'){ /* accept device and device!file */ - i = gettokens(nvrfile, v, nelem(v), "!"); + nvrcopy = strdup(nvrfile); + i = gettokens(nvrcopy, v, nelem(v), "!"); + if (i < 1) { + i = 1; + v[0] = ""; + v[1] = nil; + } + if(nvramdebug) + fprint(2, "nvram at %s?...", v[0]); fd = open(v[0], ORDWR); + if (fd < 0) + fd = open(v[0], OREAD); safelen = sizeof(Nvrsafe); if(strstr(v[0], "/9fat") == nil) safeoff = 0; @@ -150,88 +181,167 @@ readnvram(Nvrsafe *safep, int flag) if(nvrlen != nil) safelen = atoi(nvrlen); nvroff = getenv("nvroff"); - if(nvroff != nil){ + if(nvroff != nil) if(strcmp(nvroff, "dos") == 0) safeoff = -1; else safeoff = atoi(nvroff); - } if(safeoff < 0 && fd >= 0){ safelen = 512; - safeoff = finddosfile(fd, i == 2 ? v[1] : "plan9.nvr"); - if(safeoff < 0){ + safeoff = finddosfile(fd, i == 2? v[1]: "plan9.nvr"); + if(safeoff < 0){ /* didn't find plan9.nvr? */ close(fd); fd = -1; } } - free(nvrfile); - if(nvrlen != nil) - free(nvrlen); - if(nvroff != nil) - free(nvroff); + free(nvrcopy); + free(nvroff); + free(nvrlen); }else{ for(i=0; i= nelem(nvtab)) /* tried them all? */ + werrstr(""); /* ignore failed opens */ } + locp->fd = fd; + locp->safelen = safelen; + locp->safeoff = safeoff; +} - if(fd < 0 - || seek(fd, safeoff, 0) < 0 - || read(fd, buf, safelen) != safelen){ - err = 1; - if(flag&(NVwrite|NVwriteonerr)) - fprint(2, "can't read nvram: %r\n"); - memset(safep, 0, sizeof(*safep)); +/* + * get key info out of nvram. since there isn't room in the PC's nvram use + * a disk partition there. + */ +int +readnvram(Nvrsafe *safep, int flag) +{ + int err; + char buf[512], in[128]; /* 512 for floppy i/o */ + Nvrsafe *safe; + Nvrwhere loc; + + err = 0; + safe = (Nvrsafe*)buf; + memset(&loc, 0, sizeof loc); + findnvram(&loc); + if (loc.safelen < 0) + loc.safelen = sizeof *safe; + else if (loc.safelen > sizeof buf) + loc.safelen = sizeof buf; + if (loc.safeoff < 0) { + fprint(2, "readnvram: can't find nvram\n"); + if(!(flag&NVwritemem)) + memset(safep, 0, sizeof(*safep)); safe = safep; - }else{ - *safep = *safe; + /* + * allow user to type the data for authentication, + * even if there's no nvram to store it in. + */ + } + + if(flag&NVwritemem) safe = safep; + else { + memset(safep, 0, sizeof(*safep)); + if(loc.fd >= 0) + werrstr(""); + if(loc.fd < 0 + || seek(loc.fd, loc.safeoff, 0) < 0 + || read(loc.fd, buf, loc.safelen) != loc.safelen){ + err = 1; + if(flag&(NVwrite|NVwriteonerr)) + if(loc.fd < 0 && nvrfile != nil) + fprint(2, "can't open %s: %r\n", nvrfile); + else if(loc.fd < 0){ + /* this will have been printed above */ + // fprint(2, "can't find nvram: %r\n"); + }else if (seek(loc.fd, loc.safeoff, 0) < 0) + fprint(2, "can't seek %s to %d: %r\n", + nvrfile, loc.safeoff); + else + fprint(2, "can't read %d bytes from %s: %r\n", + loc.safelen, nvrfile); + /* start from scratch */ + memset(safep, 0, sizeof(*safep)); + safe = safep; + }else{ + *safep = *safe; /* overwrite arg with data read */ + safe = safep; - err |= check(safe->machkey, DESKEYLEN, safe->machsum, "bad nvram key"); -// err |= check(safe->config, CONFIGLEN, safe->configsum, "bad secstore key"); - err |= check(safe->authid, ANAMELEN, safe->authidsum, "bad authentication id"); - err |= check(safe->authdom, DOMLEN, safe->authdomsum, "bad authentication domain"); + /* verify data read */ + err |= check(safe->machkey, DESKEYLEN, safe->machsum, + "bad authentication password"); +// err |= check(safe->config, CONFIGLEN, safe->configsum, +// "bad secstore password"); + err |= check(safe->authid, ANAMELEN, safe->authidsum, + "bad authentication id"); + err |= check(safe->authdom, DOMLEN, safe->authdomsum, + "bad authentication domain"); + if(err == 0) + if(safe->authid[0]==0 || safe->authdom[0]==0){ + fprint(2, "empty nvram authid or authdom\n"); + err = 1; + } + } } - if((flag&NVwrite) || (err && (flag&NVwriteonerr))){ - readcons("authid", nil, 0, safe->authid, sizeof(safe->authid)); - readcons("authdom", nil, 0, safe->authdom, sizeof(safe->authdom)); - readcons("secstore key", nil, 1, safe->config, sizeof(safe->config)); - for(;;){ - if(readcons("password", nil, 1, in, sizeof in) == nil) - goto Out; - if(passtokey(safe->machkey, in)) - break; + if((flag&(NVwrite|NVwritemem)) || (err && (flag&NVwriteonerr))){ + if (!(flag&NVwritemem)) { + readcons("authid", nil, 0, safe->authid, + sizeof safe->authid); + readcons("authdom", nil, 0, safe->authdom, + sizeof safe->authdom); + for(;;){ + if(readcons("auth password", nil, 1, in, + sizeof in) == nil) + goto Out; + if(passtokey(safe->machkey, in)) + break; + } + readcons("secstore password", nil, 1, safe->config, + sizeof safe->config); } + + // safe->authsum = nvcsum(safe->authkey, DESKEYLEN); safe->machsum = nvcsum(safe->machkey, DESKEYLEN); safe->configsum = nvcsum(safe->config, CONFIGLEN); - safe->authidsum = nvcsum(safe->authid, sizeof(safe->authid)); - safe->authdomsum = nvcsum(safe->authdom, sizeof(safe->authdom)); + safe->authidsum = nvcsum(safe->authid, sizeof safe->authid); + safe->authdomsum = nvcsum(safe->authdom, sizeof safe->authdom); + *(Nvrsafe*)buf = *safe; - if(seek(fd, safeoff, 0) < 0 - || write(fd, buf, safelen) != safelen){ + if(loc.fd >= 0) + werrstr(""); + if(loc.fd < 0 + || seek(loc.fd, loc.safeoff, 0) < 0 + || write(loc.fd, buf, loc.safelen) != loc.safelen){ fprint(2, "can't write key to nvram: %r\n"); err = 1; }else err = 0; } Out: - close(fd); - return err ? -1 : 0; + if (loc.fd >= 0) + close(loc.fd); + return err? -1: 0; } typedef struct Dosboot Dosboot; @@ -340,7 +450,7 @@ finddosfile(int fd, char *file) if(rootsects <= 0 || rootsects > 64) return -1; - /* + /* * read root. it is contiguous to make stuff like * this easier */ From 00be3a3806d9a5f849da470c4dc3e3403c3a2bf4 Mon Sep 17 00:00:00 2001 From: Adrian Grigore Date: Sun, 23 Jun 2024 04:33:54 +0300 Subject: [PATCH 6/8] include/lib.h: define usize --- include/lib.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/lib.h b/include/lib.h index 9a50aae..0d814e5 100644 --- a/include/lib.h +++ b/include/lib.h @@ -30,6 +30,7 @@ typedef unsigned char p9_uchar; typedef unsigned int p9_uint; typedef unsigned int p9_ulong; +typedef unsigned long p9_usize; typedef int p9_long; typedef signed char p9_schar; typedef unsigned short p9_ushort; @@ -49,6 +50,7 @@ typedef p9_u32int mpdigit; /* #define long int rather than p9_long so that "unsigned long" is valid */ #define long int #define ulong p9_ulong +#define usize p9_usize #define vlong p9_vlong #define uvlong p9_uvlong From 9f1b25cc14c526c0109ac8eee25417e8ec88ca5a Mon Sep 17 00:00:00 2001 From: Adrian Grigore Date: Sun, 23 Jun 2024 04:57:10 +0300 Subject: [PATCH 7/8] libsec: add chacha20 Add ChaCha20 stream cipher (RFC7539). http://9legacy.org/9legacy/patch/libsec-chacha.diff --- include/libsec.h | 36 +++++++++ libsec/Makefile | 1 + libsec/chacha.c | 175 ++++++++++++++++++++++++++++++++++++++++++++ libsec/chachatest.c | 70 ++++++++++++++++++ 4 files changed, 282 insertions(+) create mode 100644 libsec/chacha.c create mode 100644 libsec/chachatest.c diff --git a/include/libsec.h b/include/libsec.h index 04ca62a..96d4811 100644 --- a/include/libsec.h +++ b/include/libsec.h @@ -75,6 +75,42 @@ void bfCBCdecrypt(uchar*, int, BFstate*); void bfECBencrypt(uchar*, int, BFstate*); void bfECBdecrypt(uchar*, int, BFstate*); +/* + * Chacha definitions + */ + +enum{ + ChachaBsize= 64, + ChachaKeylen= 256/8, + ChachaIVlen= 96/8 +}; + +typedef struct Chachastate Chachastate; +struct Chachastate +{ + /* + * 0-3: a constant (sigma or tau) + * 4-11: the key + * 12: block counter + * 13-15: IV + */ + union{ + u32int input[16]; + struct{ + u32int constant[4]; + u32int key[8]; + u32int counter; + u32int iv[3]; + }; + }; + int rounds; +}; + +void setupChachastate(Chachastate*, uchar*, usize, uchar*, int); +void chacha_setblock(Chachastate*, u32int); +void chacha_encrypt(uchar*, usize, Chachastate*); +void chacha_encrypt2(uchar*, uchar*, usize, Chachastate*); + /* * DES definitions */ diff --git a/libsec/Makefile b/libsec/Makefile index 622defa..551db83 100644 --- a/libsec/Makefile +++ b/libsec/Makefile @@ -5,6 +5,7 @@ LIB=libsec.a OFILES=\ aes.$O\ blowfish.$O\ + chacha.$O\ decodepem.$O\ des.$O\ des3CBC.$O\ diff --git a/libsec/chacha.c b/libsec/chacha.c new file mode 100644 index 0000000..3f7b9f5 --- /dev/null +++ b/libsec/chacha.c @@ -0,0 +1,175 @@ +/* +Adapted from chacha-merged.c version 20080118 +D. J. Bernstein +Public domain. + +modified for use in Plan 9 and Inferno (no algorithmic changes), +and including the changes to block number and nonce defined in RFC7539 +*/ + +#include +#include +#include + +enum{ + Blockwords= ChachaBsize/sizeof(u32int) +}; + +/* little-endian data order */ +#define GET4(p) ((((((p)[3]<<8) | (p)[2])<<8) | (p)[1])<<8 | (p)[0]) +#define PUT4(p, v) (((p)[0]=v), (v>>=8), ((p)[1]=v), (v>>=8), ((p)[2]=v), (v>>=8), ((p)[3]=v)) + +#define ROTATE(v,c) ((u32int)((v) << (c)) | ((v) >> (32 - (c)))) + +#define QUARTERROUND(ia,ib,ic,id) { \ + u32int a, b, c, d, t;\ + a = x[ia]; b = x[ib]; c = x[ic]; d = x[id]; \ + a += b; t = d^a; d = ROTATE(t,16); \ + c += d; t = b^c; b = ROTATE(t,12); \ + a += b; t = d^a; d = ROTATE(t, 8); \ + c += d; t = b^c; b = ROTATE(t, 7); \ + x[ia] = a; x[ib] = b; x[ic] = c; x[id] = d; \ +} + +#define ENCRYPT(s, x, y, d) {\ + u32int v; \ + uchar *sp, *dp; \ + sp = (s); \ + v = GET4(sp); \ + v ^= (x)+(y); \ + dp = (d); \ + PUT4(dp, v); \ +} + +static uchar sigma[16] = "expand 32-byte k"; +static uchar tau[16] = "expand 16-byte k"; + +static void +load(u32int *d, uchar *s, int nw) +{ + int i; + + for(i = 0; i < nw; i++, s+=4) + d[i] = GET4(s); +} + +void +setupChachastate(Chachastate *s, uchar *key, usize keylen, uchar *iv, int rounds) +{ + if(keylen != 256/8 && keylen != 128/8) + sysfatal("invalid chacha key length"); + if(rounds == 0) + rounds = 20; + s->rounds = rounds; + if(keylen == 256/8) { /* recommended */ + load(&s->input[0], sigma, 4); + load(&s->input[4], key, 8); + }else{ + load(&s->input[0], tau, 4); + load(&s->input[4], key, 4); + load(&s->input[8], key, 4); + } + s->input[12] = 0; + if(iv == nil){ + s->input[13] = 0; + s->input[14] = 0; + s->input[15] = 0; + }else + load(&s->input[13], iv, 3); +} + +void +chacha_setblock(Chachastate *s, u32int blockno) +{ + s->input[12] = blockno; +} + +static void +encryptblock(Chachastate *s, uchar *src, uchar *dst) +{ + u32int x[Blockwords]; + int i, rounds; + + rounds = s->rounds; + x[0] = s->input[0]; + x[1] = s->input[1]; + x[2] = s->input[2]; + x[3] = s->input[3]; + x[4] = s->input[4]; + x[5] = s->input[5]; + x[6] = s->input[6]; + x[7] = s->input[7]; + x[8] = s->input[8]; + x[9] = s->input[9]; + x[10] = s->input[10]; + x[11] = s->input[11]; + x[12] = s->input[12]; + x[13] = s->input[13]; + x[14] = s->input[14]; + x[15] = s->input[15]; + + for(i = rounds; 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) + } + +#ifdef FULL_UNROLL + ENCRYPT(src+0*4, x[0], s->input[0], dst+0*4); + ENCRYPT(src+1*4, x[1], s->input[1], dst+1*4); + ENCRYPT(src+2*4, x[2], s->input[2], dst+2*4); + ENCRYPT(src+3*4, x[3], s->input[3], dst+3*4); + ENCRYPT(src+4*4, x[4], s->input[4], dst+4*4); + ENCRYPT(src+5*4, x[5], s->input[5], dst+5*4); + ENCRYPT(src+6*4, x[6], s->input[6], dst+6*4); + ENCRYPT(src+7*4, x[7], s->input[7], dst+7*4); + ENCRYPT(src+8*4, x[8], s->input[8], dst+8*4); + ENCRYPT(src+9*4, x[9], s->input[9], dst+9*4); + ENCRYPT(src+10*4, x[10], s->input[10], dst+10*4); + ENCRYPT(src+11*4, x[11], s->input[11], dst+11*4); + ENCRYPT(src+12*4, x[12], s->input[12], dst+12*4); + ENCRYPT(src+13*4, x[13], s->input[13], dst+13*4); + ENCRYPT(src+14*4, x[14], s->input[14], dst+14*4); + ENCRYPT(src+15*4, x[15], s->input[15], dst+15*4); +#else + for(i=0; iinput[i], dst); + ENCRYPT(src+4, x[i+1], s->input[i+1], dst+4); + ENCRYPT(src+8, x[i+2], s->input[i+2], dst+8); + ENCRYPT(src+12, x[i+3], s->input[i+3], dst+12); + src += 16; + dst += 16; + } +#endif + + s->input[12]++; +} + +void +chacha_encrypt2(uchar *src, uchar *dst, usize bytes, Chachastate *s) +{ + uchar tmp[ChachaBsize]; + + for(; bytes >= ChachaBsize; bytes -= ChachaBsize){ + encryptblock(s, src, dst); + src += ChachaBsize; + dst += ChachaBsize; + } + if(bytes > 0){ + memmove(tmp, src, bytes); + encryptblock(s, tmp, tmp); + memmove(dst, tmp, bytes); + } +} + +void +chacha_encrypt(uchar *buf, usize bytes, Chachastate *s) +{ + chacha_encrypt2(buf, buf, bytes, s); +} diff --git a/libsec/chachatest.c b/libsec/chachatest.c new file mode 100644 index 0000000..7949c6f --- /dev/null +++ b/libsec/chachatest.c @@ -0,0 +1,70 @@ +#include +#include +#include + +static void +printblock(uchar *b, usize n) +{ + int i; + + for(i=0; i+8<=n; i+=8){ + print("%#.2ux %#.2ux %#.2ux %#.2ux %#.2ux %#.2ux %#.2ux %#.2ux\n", + b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]); + b += 8; + } + if(i < n){ + print("%#.2ux", *b++); + while(++i < n) + print(" %#.2ux", *b++); + print("\n"); + } +} + +/* test vector from RFC7539 */ +uchar rfckey[] = { + 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, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}; +uchar rfcnonce[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00}; +u32int rfccount = 1; +char rfctext[] = "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, " + "sunscreen would be it."; +uchar rfcout[3*ChachaBsize]; +uchar rfcref[3*ChachaBsize] = { + 0x6e, 0x2e, 0x35, 0x9a, 0x25, 0x68, 0xf9, 0x80, 0x41, 0xba, 0x07, 0x28, 0xdd, 0x0d, 0x69, 0x81, + 0xe9, 0x7e, 0x7a, 0xec, 0x1d, 0x43, 0x60, 0xc2, 0x0a, 0x27, 0xaf, 0xcc, 0xfd, 0x9f, 0xae, 0x0b, + 0xf9, 0x1b, 0x65, 0xc5, 0x52, 0x47, 0x33, 0xab, 0x8f, 0x59, 0x3d, 0xab, 0xcd, 0x62, 0xb3, 0x57, + 0x16, 0x39, 0xd6, 0x24, 0xe6, 0x51, 0x52, 0xab, 0x8f, 0x53, 0x0c, 0x35, 0x9f, 0x08, 0x61, 0xd8, + 0x07, 0xca, 0x0d, 0xbf, 0x50, 0x0d, 0x6a, 0x61, 0x56, 0xa3, 0x8e, 0x08, 0x8a, 0x22, 0xb6, 0x5e, + 0x52, 0xbc, 0x51, 0x4d, 0x16, 0xcc, 0xf8, 0x06, 0x81, 0x8c, 0xe9, 0x1a, 0xb7, 0x79, 0x37, 0x36, + 0x5a, 0xf9, 0x0b, 0xbf, 0x74, 0xa3, 0x5b, 0xe6, 0xb4, 0x0b, 0x8e, 0xed, 0xf2, 0x78, 0x5e, 0x42, + 0x87, 0x4d +}; + +void +main(int argc, char **argv) +{ + Chachastate s; + int n; + + ARGBEGIN{ + }ARGEND + print("rfc7539:\n"); + print("key:\n"); + printblock(rfckey, sizeof(rfckey)); + n = strlen(rfctext); + setupChachastate(&s, rfckey, sizeof(rfckey), rfcnonce, 0); + chacha_setblock(&s, rfccount); + print("rfc in:\n"); + printblock((uchar*)rfctext, n); + chacha_encrypt2((uchar*)rfctext, rfcout, n, &s); + print("rfc out:\n"); + printblock(rfcout, n); + if(memcmp(rfcout, rfcref, sizeof(rfcout)) != 0){ + print("failure of vision\n"); + exits("wrong"); + } + print("passed\n"); + exits(nil); +} From 693ebe2a441f6fb54bb038742a6d7a58a14d3d48 Mon Sep 17 00:00:00 2001 From: Adrian Grigore Date: Mon, 24 Jun 2024 00:10:00 +0300 Subject: [PATCH 8/8] libsec: add missing \ in Makefile --- libsec/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsec/Makefile b/libsec/Makefile index 551db83..7ba537d 100644 --- a/libsec/Makefile +++ b/libsec/Makefile @@ -51,7 +51,7 @@ OFILES=\ sha2block64.$O\ sha2_128.$O\ sha2block128.$O\ - smallprimes.$O + smallprimes.$O\ default: $(LIB) $(LIB): $(OFILES)