summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorforsyth <forsyth@vitanuova.com>2010-08-10 23:06:28 +0100
committerforsyth <forsyth@vitanuova.com>2010-08-10 23:06:28 +0100
commit7de2b42d50e3c05cc143e7b51284009b5e185581 (patch)
tree42fffe0c9804551c120ef89c3f505059bbd31cfb
parent99c84fef96ccd10bb6cabb823384c033090293e9 (diff)
20100810-2306
-rw-r--r--CHANGES3
-rw-r--r--appl/cmd/randpass.b14
-rw-r--r--dis/randpass.disbin523 -> 525 bytes
-rw-r--r--emu/DragonFly/emu2
-rw-r--r--emu/DragonFly/emu-g2
-rw-r--r--emu/FreeBSD/emu2
-rw-r--r--emu/Hp/emu2
-rw-r--r--emu/Irix/emu2
-rw-r--r--emu/Linux/emu2
-rw-r--r--emu/Linux/emu-g2
-rw-r--r--emu/Linux/emu-wrt2
-rw-r--r--emu/MacOSX/emu2
-rw-r--r--emu/MacOSX/emu-g2
-rw-r--r--emu/NetBSD/emu2
-rw-r--r--emu/Nt/emu2
-rw-r--r--emu/Nt/ie2
-rw-r--r--emu/OpenBSD/emu2
-rw-r--r--emu/Plan9/emu2
-rw-r--r--emu/Plan9/emusig5
-rw-r--r--emu/Solaris/emu2
-rw-r--r--emu/Unixware/emu2
-rw-r--r--include/interp.h5
-rw-r--r--include/version.h2
-rw-r--r--libinterp/crypt.c1350
-rw-r--r--libinterp/heap.c34
-rw-r--r--libinterp/ipint.c150
-rw-r--r--libinterp/ipint.h12
-rw-r--r--libinterp/keyring.c162
-rw-r--r--libinterp/keyringif.m4
-rw-r--r--libinterp/load.c17
-rw-r--r--libinterp/mkfile28
-rw-r--r--libkeyring/dsaalg.c2
-rw-r--r--libkeyring/egalg.c2
-rw-r--r--libkeyring/keys.h11
-rw-r--r--libkeyring/rsaalg.c2
-rw-r--r--libmp/port/mpextendedgcd.c2
-rw-r--r--man/2/crypt-0intro98
-rw-r--r--man/2/crypt-crypt142
-rw-r--r--man/2/crypt-dsagen94
-rw-r--r--man/2/crypt-gensk159
-rw-r--r--man/2/crypt-rc449
-rw-r--r--man/2/crypt-sha1144
-rw-r--r--man/2/ipints193
-rw-r--r--man/2/ipints-genprime112
-rw-r--r--module/crypt.m191
-rw-r--r--module/ipints.m57
-rw-r--r--module/runt.m4
-rw-r--r--os/cerf1110/cerf4
-rw-r--r--os/cerf250/cerf4
-rw-r--r--os/cerf405/cerf4
-rw-r--r--os/fads/fads4
-rw-r--r--os/gum/gum6
-rw-r--r--os/ipaq1110/ipaq4
-rw-r--r--os/ipengine/ipe4
-rw-r--r--os/js/js4
-rw-r--r--os/manga/manga4
-rw-r--r--os/pc/pc4e4
-rw-r--r--os/pc/pcdisk4
-rw-r--r--os/pc/pix4
-rw-r--r--os/rpcg/rpcg4
60 files changed, 2979 insertions, 157 deletions
diff --git a/CHANGES b/CHANGES
index fad2cac0..ecfa3592 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+20100810
+ initial introduction of crypt-*(2) and ipints(2)
+ replace keyring.m in module/runt.m by ipints.m and crypt.m; compensate in libinterp and libkeyring by using keyringif.m to generate Keyring's interface
20100802
various changes held back by accident, notably stackv in stack(1), better diagnostics by cat(1)
20100801
diff --git a/appl/cmd/randpass.b b/appl/cmd/randpass.b
index 074b21ac..ddfa8e09 100644
--- a/appl/cmd/randpass.b
+++ b/appl/cmd/randpass.b
@@ -6,9 +6,9 @@ include "sys.m";
include "draw.m";
-include "keyring.m";
- kr : Keyring;
- IPint: import kr;
+include "ipints.m";
+ ipints: IPints;
+ IPint: import ipints;
Randpass: module
{
@@ -18,7 +18,7 @@ Randpass: module
init(nil: ref Draw->Context, args: list of string)
{
sys = load Sys Sys->PATH;
- kr = load Keyring Keyring->PATH;
+ ipints = load IPints IPints->PATH;
if(args != nil)
args = tl args;
@@ -29,11 +29,7 @@ init(nil: ref Draw->Context, args: list of string)
raise "fail:usage";
}
}
-
- rbig := IPint.random(pwlen*8, pwlen*16);
- rstr := rbig.iptob64();
-
- sys->print("%s\n", rstr[0:pwlen]);
+ sys->print("%s\n", IPint.random(pwlen*8).iptob64()[0: pwlen]);
}
isnumeric(s: string): int
diff --git a/dis/randpass.dis b/dis/randpass.dis
index 333f6c04..7ebd35e6 100644
--- a/dis/randpass.dis
+++ b/dis/randpass.dis
Binary files differ
diff --git a/emu/DragonFly/emu b/emu/DragonFly/emu
index eb461164..e4fbc42a 100644
--- a/emu/DragonFly/emu
+++ b/emu/DragonFly/emu
@@ -48,6 +48,8 @@ mod
math
srv srv
keyring
+ crypt
+ ipints
loader
freetype
diff --git a/emu/DragonFly/emu-g b/emu/DragonFly/emu-g
index 98a1ff89..0667fd62 100644
--- a/emu/DragonFly/emu-g
+++ b/emu/DragonFly/emu-g
@@ -33,6 +33,8 @@ mod
math
srv srv
keyring
+ crypt
+ ipints
loader
port
diff --git a/emu/FreeBSD/emu b/emu/FreeBSD/emu
index eb461164..e4fbc42a 100644
--- a/emu/FreeBSD/emu
+++ b/emu/FreeBSD/emu
@@ -48,6 +48,8 @@ mod
math
srv srv
keyring
+ crypt
+ ipints
loader
freetype
diff --git a/emu/Hp/emu b/emu/Hp/emu
index 0992a819..be898d74 100644
--- a/emu/Hp/emu
+++ b/emu/Hp/emu
@@ -49,6 +49,8 @@ mod
math
srv srv
keyring
+ crypt
+ ipints
loader
freetype
diff --git a/emu/Irix/emu b/emu/Irix/emu
index 407b754b..a76441d3 100644
--- a/emu/Irix/emu
+++ b/emu/Irix/emu
@@ -48,6 +48,8 @@ mod
math
srv srv
keyring
+ crypt
+ ipints
loader
freetype
diff --git a/emu/Linux/emu b/emu/Linux/emu
index be653b4b..e41ed6ad 100644
--- a/emu/Linux/emu
+++ b/emu/Linux/emu
@@ -48,6 +48,8 @@ mod
math
srv srv
keyring
+ crypt
+ ipints
loader
freetype
diff --git a/emu/Linux/emu-g b/emu/Linux/emu-g
index 2ac1e46a..3d45c288 100644
--- a/emu/Linux/emu-g
+++ b/emu/Linux/emu-g
@@ -37,6 +37,8 @@ mod
math
srv srv
keyring
+ crypt
+ ipints
loader
port
diff --git a/emu/Linux/emu-wrt b/emu/Linux/emu-wrt
index b53714bb..4f7f6fc6 100644
--- a/emu/Linux/emu-wrt
+++ b/emu/Linux/emu-wrt
@@ -48,6 +48,8 @@ mod
math
srv srv
keyring
+ crypt
+ ipints
loader
# freetype
diff --git a/emu/MacOSX/emu b/emu/MacOSX/emu
index 4ace5188..a1a9666f 100644
--- a/emu/MacOSX/emu
+++ b/emu/MacOSX/emu
@@ -48,6 +48,8 @@ mod
math
srv srv
keyring
+ crypt
+ ipints
loader
freetype
diff --git a/emu/MacOSX/emu-g b/emu/MacOSX/emu-g
index fc0ff87a..d196f5ce 100644
--- a/emu/MacOSX/emu-g
+++ b/emu/MacOSX/emu-g
@@ -35,6 +35,8 @@ mod
math
srv srv
keyring
+ crypt
+ ipints
loader
port
diff --git a/emu/NetBSD/emu b/emu/NetBSD/emu
index eb461164..e4fbc42a 100644
--- a/emu/NetBSD/emu
+++ b/emu/NetBSD/emu
@@ -48,6 +48,8 @@ mod
math
srv srv
keyring
+ crypt
+ ipints
loader
freetype
diff --git a/emu/Nt/emu b/emu/Nt/emu
index 7c92dee6..7a864d48 100644
--- a/emu/Nt/emu
+++ b/emu/Nt/emu
@@ -49,6 +49,8 @@ mod
math
srv srv
keyring
+ crypt
+ ipints
loader
freetype
diff --git a/emu/Nt/ie b/emu/Nt/ie
index 1942f591..5963345a 100644
--- a/emu/Nt/ie
+++ b/emu/Nt/ie
@@ -48,6 +48,8 @@ mod
math
srv srv
keyring
+ crypt
+ ipints
loader
freetype
diff --git a/emu/OpenBSD/emu b/emu/OpenBSD/emu
index 93dd36ea..4d9a7d0b 100644
--- a/emu/OpenBSD/emu
+++ b/emu/OpenBSD/emu
@@ -48,6 +48,8 @@ mod
math
srv srv
keyring
+ crypt
+ ipints
loader
freetype
diff --git a/emu/Plan9/emu b/emu/Plan9/emu
index 2807c7c5..71390426 100644
--- a/emu/Plan9/emu
+++ b/emu/Plan9/emu
@@ -49,6 +49,8 @@ mod
math
# srv not used on Plan 9
keyring
+ crypt
+ ipints
loader
freetype
diff --git a/emu/Plan9/emusig b/emu/Plan9/emusig
index 1975a4cc..c08bda95 100644
--- a/emu/Plan9/emusig
+++ b/emu/Plan9/emusig
@@ -39,6 +39,8 @@ mod
math
# srv not used on Plan 9
keyring
+ crypt
+ ipints
loader
freetype
@@ -47,6 +49,8 @@ port
cache
chan
dev
+ devtab
+
dial
dis
discall
@@ -74,6 +78,7 @@ init
root
/dev /
/prog /
+ /prof /
/net /
/net.alt /
/chan /
diff --git a/emu/Solaris/emu b/emu/Solaris/emu
index a887a102..55705a2b 100644
--- a/emu/Solaris/emu
+++ b/emu/Solaris/emu
@@ -48,6 +48,8 @@ mod
math
srv srv
keyring
+ crypt
+ ipints
loader
freetype
diff --git a/emu/Unixware/emu b/emu/Unixware/emu
index 9c92b0a8..92fc91bd 100644
--- a/emu/Unixware/emu
+++ b/emu/Unixware/emu
@@ -48,6 +48,8 @@ mod
math
srv srv
keyring
+ crypt
+ ipints
loader
freetype
diff --git a/include/interp.h b/include/interp.h
index 15b7068c..abbe764b 100644
--- a/include/interp.h
+++ b/include/interp.h
@@ -389,6 +389,7 @@ extern void altgone(Prog*);
extern Array* allocimgarray(Heap*, Heap*);
extern Module* builtinmod(char*, void*, int);
extern void cblock(Prog*);
+extern void* checktype(void*, Type*, char*, int);
extern void cmovw(void*, void*);
extern Channel* cnewc(Type*, void (*)(void), int);
extern int compile(Module*, int, Modlink*);
@@ -410,12 +411,12 @@ extern void destroyimage(ulong);
extern void destroylinks(Module*);
extern void destroystack(REG*);
extern void drawmodinit(void);
+extern Type* dtype(void (*)(Heap*, int), int, uchar*, int);
+extern Module* dupmod(Module*);
extern int dynldable(int);
extern void iqlock(ILock*);
extern void iqunlock(ILock*);
extern void loadermodinit(void);
-extern Type* dtype(void (*)(Heap*, int), int, uchar*, int);
-extern Module* dupmod(Module*);
extern void error(char*);
extern void errorf(char*, ...);
extern void extend(void);
diff --git a/include/version.h b/include/version.h
index e9eae7b8..80208e8e 100644
--- a/include/version.h
+++ b/include/version.h
@@ -1 +1 @@
-#define VERSION "Fourth Edition (20100802)"
+#define VERSION "Fourth Edition (20100810)"
diff --git a/libinterp/crypt.c b/libinterp/crypt.c
new file mode 100644
index 00000000..998e6d91
--- /dev/null
+++ b/libinterp/crypt.c
@@ -0,0 +1,1350 @@
+#include "lib9.h"
+#include "kernel.h"
+#include <isa.h>
+#include "interp.h"
+#include "runt.h"
+#include "cryptmod.h"
+#include <mp.h>
+#include <libsec.h>
+#include "pool.h"
+#include "raise.h"
+#include "ipint.h"
+
+#define MPX(x) checkIPint((void*)(x))
+
+static Type* TDigestState;
+static Type* TAESstate;
+static Type* TDESstate;
+static Type* TIDEAstate;
+static Type* TBFstate;
+static Type* TRC4state;
+
+static Type* TSKdsa;
+static Type* TPKdsa;
+static Type* TPKsigdsa;
+static Type* TSKeg;
+static Type* TPKeg;
+static Type* TPKsigeg;
+static Type* TSKrsa;
+static Type* TPKrsa;
+static Type* TPKsigrsa;
+
+static uchar DigestStatemap[] = Crypt_DigestState_map;
+static uchar AESstatemap[] = Crypt_AESstate_map;
+static uchar DESstatemap[] = Crypt_DESstate_map;
+static uchar IDEAstatemap[] = Crypt_IDEAstate_map;
+static uchar BFstatemap[] = Crypt_BFstate_map;
+static uchar RC4statemap[] = Crypt_RC4state_map;
+
+static uchar DSAskmap[] = Crypt_SK_DSA_map;
+static uchar DSApkmap[] = Crypt_PK_DSA_map;
+static uchar DSAsigmap[] = Crypt_PKsig_DSA_map;
+static uchar EGskmap[] = Crypt_SK_Elgamal_map;
+static uchar EGpkmap[] = Crypt_PK_Elgamal_map;
+static uchar EGsigmap[] = Crypt_PKsig_Elgamal_map;
+static uchar RSAskmap[] = Crypt_SK_RSA_map;
+static uchar RSApkmap[] = Crypt_PK_RSA_map;
+static uchar RSAsigmap[] = Crypt_PKsig_RSA_map;
+
+static char exBadSK[] = "bad secret key";
+static char exBadPK[] = "bad public key";
+static char exBadBsize[] = "data not multiple of block size";
+static char exBadKey[] = "bad encryption key";
+static char exBadDigest[] = "bad digest value";
+static char exBadIvec[] = "bad ivec";
+static char exBadState[] = "bad encryption state";
+
+/*
+ * these structures reveal the C state of Limbo adts in crypt.m
+ */
+
+typedef struct XDigestState XDigestState;
+typedef struct XAESstate XAESstate;
+typedef struct XDESstate XDESstate;
+typedef struct XIDEAstate XIDEAstate;
+typedef struct XBFstate XBFstate;
+typedef struct XRC4state XRC4state;
+
+/* digest state */
+struct XDigestState
+{
+ Crypt_DigestState x;
+ DigestState state;
+};
+
+/* AES state */
+struct XAESstate
+{
+ Crypt_AESstate x;
+ AESstate state;
+};
+
+/* DES state */
+struct XDESstate
+{
+ Crypt_DESstate x;
+ DESstate state;
+};
+
+/* IDEA state */
+struct XIDEAstate
+{
+ Crypt_IDEAstate x;
+ IDEAstate state;
+};
+
+/* BF state */
+struct XBFstate
+{
+ Crypt_BFstate x;
+ BFstate state;
+};
+
+/* RC4 state */
+struct XRC4state
+{
+ Crypt_RC4state x;
+ RC4state state;
+};
+
+static Crypt_PK*
+newPK(Type *t, int pick)
+{
+ Heap *h;
+ Crypt_PK *sk;
+
+ h = heap(t);
+ sk = H2D(Crypt_PK*, h);
+ sk->pick = pick;
+ return sk;
+}
+
+static Crypt_SK*
+newSK(Crypt_SK** ret, Type *t, int pick)
+{
+ Heap *h;
+ Crypt_SK *sk;
+
+ h = heap(t);
+ sk = H2D(Crypt_SK*, h);
+ sk->pick = pick;
+ if(ret != nil)
+ *ret = sk;
+ switch(pick){
+ case Crypt_PK_RSA:
+ sk->u.RSA.pk = newPK(TPKrsa, Crypt_PK_RSA);
+ break;
+ case Crypt_PK_Elgamal:
+ sk->u.Elgamal.pk = newPK(TPKeg, Crypt_PK_Elgamal);
+ break;
+ case Crypt_PK_DSA:
+ sk->u.DSA.pk = newPK(TPKdsa, Crypt_PK_DSA);
+ break;
+ default:
+ error(exType);
+ }
+ return sk;
+}
+
+static Crypt_PKsig*
+newPKsig(Type *t, int pick)
+{
+ Heap *h;
+ Crypt_PKsig *s;
+
+ h = heap(t);
+ s = H2D(Crypt_PKsig*, h);
+ s->pick = pick;
+ return s;
+}
+
+static IPints_IPint*
+ipcopymp(mpint* b)
+{
+ if(b == nil)
+ return H;
+ return newIPint(mpcopy(b));
+}
+
+/*
+ * digests
+ */
+void
+DigestState_copy(void *fp)
+{
+ F_DigestState_copy *f;
+ Heap *h;
+ XDigestState *ds, *ods;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ if(f->d != H){
+ ods = checktype(f->d, TDigestState, "DigestState", 0);
+ h = heap(TDigestState);
+ ds = H2D(XDigestState*, h);
+ memmove(&ds->state, &ods->state, sizeof(ds->state));
+ *f->ret = (Crypt_DigestState*)ds;
+ }
+}
+
+static Crypt_DigestState*
+crypt_digest_x(Array *buf, int n, Array *digest, int dlen, Crypt_DigestState *state, DigestState* (*fn)(uchar*, ulong, uchar*, DigestState*))
+{
+ Heap *h;
+ XDigestState *ds;
+ uchar *cbuf, *cdigest;
+
+ if(buf != H){
+ if(n > buf->len)
+ n = buf->len;
+ cbuf = buf->data;
+ }else{
+ if(n != 0)
+ error(exInval);
+ cbuf = nil;
+ }
+
+ if(digest != H){
+ if(digest->len < dlen)
+ error(exBadDigest);
+ cdigest = digest->data;
+ } else
+ cdigest = nil;
+
+ if(state == H){
+ h = heap(TDigestState);
+ ds = H2D(XDigestState*, h);
+ memset(&ds->state, 0, sizeof(ds->state));
+ } else
+ ds = checktype(state, TDigestState, "DigestState", 1);
+
+ (*fn)(cbuf, n, cdigest, &ds->state);
+
+ return (Crypt_DigestState*)ds;
+}
+
+void
+Crypt_sha1(void *fp)
+{
+ F_Crypt_sha1 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ *f->ret = crypt_digest_x(f->buf, f->n, f->digest, SHA1dlen, f->state, sha1);
+}
+
+void
+Crypt_sha224(void *fp)
+{
+ F_Crypt_sha224 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ *f->ret = crypt_digest_x(f->buf, f->n, f->digest, SHA224dlen, f->state, sha224);
+}
+
+void
+Crypt_sha256(void *fp)
+{
+ F_Crypt_sha256 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ *f->ret = crypt_digest_x(f->buf, f->n, f->digest, SHA256dlen, f->state, sha256);
+}
+
+void
+Crypt_sha384(void *fp)
+{
+ F_Crypt_sha384 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ *f->ret = crypt_digest_x(f->buf, f->n, f->digest, SHA384dlen, f->state, sha384);
+}
+
+void
+Crypt_sha512(void *fp)
+{
+ F_Crypt_sha512 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ *f->ret = crypt_digest_x(f->buf, f->n, f->digest, SHA512dlen, f->state, sha512);
+}
+
+void
+Crypt_md5(void *fp)
+{
+ F_Crypt_md5 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ *f->ret = crypt_digest_x(f->buf, f->n, f->digest, MD5dlen, f->state, md5);
+}
+
+void
+Crypt_md4(void *fp)
+{
+ F_Crypt_md4 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ *f->ret = crypt_digest_x(f->buf, f->n, f->digest, MD4dlen, f->state, md4);
+}
+
+static Crypt_DigestState*
+crypt_hmac_x(Array *data, int n, Array *key, Array *digest, int dlen, Crypt_DigestState *state, DigestState* (*fn)(uchar*, ulong, uchar*, ulong, uchar*, DigestState*))
+{
+ Heap *h;
+ XDigestState *ds;
+ uchar *cdata, *cdigest;
+
+ if(data != H){
+ if(n > data->len)
+ n = data->len;
+ cdata = data->data;
+ }else{
+ if(n != 0)
+ error(exInval);
+ cdata = nil;
+ }
+
+ if(key == H || key->len > 64)
+ error(exBadKey);
+
+ if(digest != H){
+ if(digest->len < dlen)
+ error(exBadDigest);
+ cdigest = digest->data;
+ } else
+ cdigest = nil;
+
+ if(state == H){
+ h = heap(TDigestState);
+ ds = H2D(XDigestState*, h);
+ memset(&ds->state, 0, sizeof(ds->state));
+ } else
+ ds = checktype(state, TDigestState, "DigestState", 1);
+
+ (*fn)(cdata, n, key->data, key->len, cdigest, &ds->state);
+
+ return (Crypt_DigestState*)ds;
+}
+
+void
+Crypt_hmac_sha1(void *fp)
+{
+ F_Crypt_hmac_sha1 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+ *f->ret = crypt_hmac_x(f->data, f->n, f->key, f->digest, SHA1dlen, f->state, hmac_sha1);
+}
+
+void
+Crypt_hmac_md5(void *fp)
+{
+ F_Crypt_hmac_md5 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+ *f->ret = crypt_hmac_x(f->data, f->n, f->key, f->digest, MD5dlen, f->state, hmac_md5);
+}
+
+void
+Crypt_dhparams(void *fp)
+{
+ F_Crypt_dhparams *f;
+ mpint *p, *alpha;
+ void *v;
+
+ f = fp;
+ v = f->ret->t0;
+ f->ret->t0 = H;
+ destroy(v);
+ v = f->ret->t1;
+ f->ret->t1 = H;
+ destroy(v);
+
+ p = mpnew(0);
+ alpha = mpnew(0);
+ release();
+ if(f->nbits == 1024)
+ DSAprimes(alpha, p, nil);
+ else
+ gensafeprime(p, alpha, f->nbits, 0);
+ acquire();
+ f->ret->t0 = newIPint(alpha);
+ f->ret->t1 = newIPint(p);
+}
+
+void
+cryptmodinit(void)
+{
+ ipintsmodinit(); /* TIPint */
+
+ TDigestState = dtype(freeheap, sizeof(XDigestState), DigestStatemap, sizeof(DigestStatemap));
+ TAESstate = dtype(freeheap, sizeof(XAESstate), AESstatemap, sizeof(AESstatemap));
+ TDESstate = dtype(freeheap, sizeof(XDESstate), DESstatemap, sizeof(DESstatemap));
+ TIDEAstate = dtype(freeheap, sizeof(XIDEAstate), IDEAstatemap, sizeof(IDEAstatemap));
+ TBFstate = dtype(freeheap, sizeof(XBFstate), BFstatemap, sizeof(BFstatemap));
+ TRC4state = dtype(freeheap, sizeof(XRC4state), RC4statemap, sizeof(RC4statemap));
+
+ TSKdsa = dtype(freeheap, Crypt_SK_DSA_size, DSAskmap, sizeof(DSAskmap));
+ TPKdsa = dtype(freeheap, Crypt_PK_DSA_size, DSApkmap, sizeof(DSApkmap));
+ TPKsigdsa = dtype(freeheap, Crypt_PKsig_DSA_size, DSAsigmap, sizeof(DSAsigmap));
+ TSKeg = dtype(freeheap, Crypt_SK_Elgamal_size, EGskmap, sizeof(EGskmap));
+ TPKeg = dtype(freeheap, Crypt_PK_Elgamal_size, EGpkmap, sizeof(EGpkmap));
+ TPKsigeg = dtype(freeheap, Crypt_PKsig_Elgamal_size, EGsigmap, sizeof(EGsigmap));
+ TSKrsa = dtype(freeheap, Crypt_SK_RSA_size, RSAskmap, sizeof(RSAskmap));
+ TPKrsa = dtype(freeheap, Crypt_PK_RSA_size, RSApkmap, sizeof(RSApkmap));
+ TPKsigrsa = dtype(freeheap, Crypt_PKsig_RSA_size, RSAsigmap, sizeof(RSAsigmap));
+
+ builtinmod("$Crypt", Cryptmodtab, Cryptmodlen);
+}
+
+void
+Crypt_dessetup(void *fp)
+{
+ F_Crypt_dessetup *f;
+ Heap *h;
+ XDESstate *ds;
+ uchar *ivec;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ if(f->key == H)
+ error(exNilref);
+ if(f->key->len < 8)
+ error(exBadKey);
+ if(f->ivec != H){
+ if(f->ivec->len < 8)
+ error(exBadIvec);
+ ivec = f->ivec->data;
+ }else
+ ivec = nil;
+
+ h = heap(TDESstate);
+ ds = H2D(XDESstate*, h);
+ setupDESstate(&ds->state, f->key->data, ivec);
+
+ *f->ret = (Crypt_DESstate*)ds;
+}
+
+void
+Crypt_desecb(void *fp)
+{
+ F_Crypt_desecb *f;
+ XDESstate *ds;
+ int i;
+ uchar *p;
+
+ f = fp;
+
+ if(f->buf == H)
+ return;
+ if(f->n < 0 || f->n > f->buf->len)
+ error(exBounds);
+ if(f->n & 7)
+ error(exBadBsize);
+
+ ds = checktype(f->state, TDESstate, exBadState, 0);
+ p = f->buf->data;
+
+ for(i = 8; i <= f->n; i += 8, p += 8)
+ block_cipher(ds->state.expanded, p, f->direction);
+}
+
+void
+Crypt_descbc(void *fp)
+{
+ F_Crypt_descbc *f;
+ XDESstate *ds;
+ uchar *p, *ep, *ip, *p2, *eip;
+ uchar tmp[8];
+
+ f = fp;
+
+ if(f->buf == H)
+ return;
+ if(f->n < 0 || f->n > f->buf->len)
+ error(exBounds);
+ if(f->n & 7)
+ error(exBadBsize);
+
+ ds = checktype(f->state, TDESstate, exBadState, 0);
+ p = f->buf->data;
+
+ if(f->direction == 0){
+ for(ep = p + f->n; p < ep; p += 8){
+ p2 = p;
+ ip = ds->state.ivec;
+ for(eip = ip+8; ip < eip; )
+ *p2++ ^= *ip++;
+ block_cipher(ds->state.expanded, p, 0);
+ memmove(ds->state.ivec, p, 8);
+ }
+ } else {
+ for(ep = p + f->n; p < ep; ){
+ memmove(tmp, p, 8);
+ block_cipher(ds->state.expanded, p, 1);
+ p2 = tmp;
+ ip = ds->state.ivec;
+ for(eip = ip+8; ip < eip; ){
+ *p++ ^= *ip;
+ *ip++ = *p2++;
+ }
+ }
+ }
+}
+
+void
+Crypt_ideasetup(void *fp)
+{
+ F_Crypt_ideasetup *f;
+ Heap *h;
+ XIDEAstate *is;
+ uchar *ivec;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ if(f->key == H)
+ error(exNilref);
+ if(f->key->len < 16)
+ error(exBadKey);
+ if(f->ivec != H){
+ if(f->ivec->len < 8)
+ error(exBadIvec);
+ ivec = f->ivec->data;
+ }else
+ ivec = nil;
+
+ h = heap(TIDEAstate);
+ is = H2D(XIDEAstate*, h);
+
+ setupIDEAstate(&is->state, f->key->data, ivec);
+
+ *f->ret = (Crypt_IDEAstate*)is;
+}
+
+void
+Crypt_ideaecb(void *fp)
+{
+ F_Crypt_ideaecb *f;
+ XIDEAstate *is;
+ int i;
+ uchar *p;
+
+ f = fp;
+
+ if(f->buf == H)
+ return;
+ if(f->n < 0 || f->n > f->buf->len)
+ error(exBounds);
+ if(f->n & 7)
+ error(exBadBsize);
+
+ is = checktype(f->state, TIDEAstate, exBadState, 0);
+ p = f->buf->data;
+
+ for(i = 8; i <= f->n; i += 8, p += 8)
+ idea_cipher(is->state.edkey, p, f->direction);
+}
+
+void
+Crypt_ideacbc(void *fp)
+{
+ F_Crypt_ideacbc *f;
+ XIDEAstate *is;
+ uchar *p, *ep, *ip, *p2, *eip;
+ uchar tmp[8];
+
+ f = fp;
+
+ if(f->buf == H)
+ return;
+ if(f->n < 0 || f->n > f->buf->len)
+ error(exBounds);
+ if(f->n & 7)
+ error(exBadBsize);
+
+ is = checktype(f->state, TIDEAstate, exBadState, 0);
+ p = f->buf->data;
+
+ if(f->direction == 0){
+ for(ep = p + f->n; p < ep; p += 8){
+ p2 = p;
+ ip = is->state.ivec;
+ for(eip = ip+8; ip < eip; )
+ *p2++ ^= *ip++;
+ idea_cipher(is->state.edkey, p, 0);
+ memmove(is->state.ivec, p, 8);
+ }
+ } else {
+ for(ep = p + f->n; p < ep; ){
+ memmove(tmp, p, 8);
+ idea_cipher(is->state.edkey, p, 1);
+ p2 = tmp;
+ ip = is->state.ivec;
+ for(eip = ip+8; ip < eip; ){
+ *p++ ^= *ip;
+ *ip++ = *p2++;
+ }
+ }
+ }
+}
+
+void
+Crypt_aessetup(void *fp)
+{
+ F_Crypt_aessetup *f;
+ Heap *h;
+ XAESstate *is;
+ uchar *ivec;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ if(f->key == H)
+ error(exNilref);
+ if(f->key->len != 16 && f->key->len != 24 && f->key->len != 32)
+ error(exBadKey);
+ if(f->ivec != H){
+ if(f->ivec->len < AESbsize)
+ error(exBadIvec);
+ ivec = f->ivec->data;
+ }else
+ ivec = nil;
+
+ h = heap(TAESstate);
+ is = H2D(XAESstate*, h);
+
+ setupAESstate(&is->state, f->key->data, f->key->len, ivec);
+
+ *f->ret = (Crypt_AESstate*)is;
+}
+
+void
+Crypt_aescbc(void *fp)
+{
+ F_Crypt_aescbc *f;
+ XAESstate *is;
+ uchar *p;
+
+ f = fp;
+
+ if(f->buf == H)
+ return;
+ if(f->n < 0 || f->n > f->buf->len)
+ error(exBounds);
+
+ is = checktype(f->state, TAESstate, exBadState, 0);
+ p = f->buf->data;
+
+ if(f->direction == 0)
+ aesCBCencrypt(p, f->n, &is->state);
+ else
+ aesCBCdecrypt(p, f->n, &is->state);
+}
+
+void
+Crypt_blowfishsetup(void *fp)
+{
+ F_Crypt_blowfishsetup *f;
+ Heap *h;
+ XBFstate *is;
+ uchar *ivec;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ if(f->key == H)
+ error(exNilref);
+ if(f->key->len <= 0)
+ error(exBadKey);
+ if(f->ivec != H){
+ if(f->ivec->len != BFbsize)
+ error(exBadIvec);
+ ivec = f->ivec->data;
+ }else
+ ivec = nil;
+
+ h = heap(TBFstate);
+ is = H2D(XBFstate*, h);
+
+ setupBFstate(&is->state, f->key->data, f->key->len, ivec);
+
+ *f->ret = (Crypt_BFstate*)is;
+}
+
+void
+Crypt_blowfishcbc(void *fp)
+{
+ F_Crypt_blowfishcbc *f;
+ XBFstate *is;
+ uchar *p;
+
+ f = fp;
+
+ if(f->state == H)
+ return;
+ if(f->n < 0 || f->n > f->buf->len)
+ error(exBounds);
+ if(f->n & 7)
+ error(exBadBsize);
+
+ is = checktype(f->state, TBFstate, exBadState, 0);
+ p = f->buf->data;
+
+ if(f->direction == 0)
+ bfCBCencrypt(p, f->n, &is->state);
+ else
+ bfCBCdecrypt(p, f->n, &is->state);
+}
+
+void
+Crypt_rc4setup(void *fp)
+{
+ F_Crypt_rc4setup *f;
+ Heap *h;
+ XRC4state *is;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ if(f->seed == H)
+ error(exNilref);
+
+ h = heap(TRC4state);
+ is = H2D(XRC4state*, h);
+
+ setupRC4state(&is->state, f->seed->data, f->seed->len);
+
+ *f->ret = (Crypt_RC4state*)is;
+}
+
+void
+Crypt_rc4(void *fp)
+{
+ F_Crypt_rc4 *f;
+ XRC4state *is;
+ uchar *p;
+
+ f = fp;
+ if(f->buf == H)
+ return;
+ if(f->n < 0 || f->n > f->buf->len)
+ error(exBounds);
+ is = checktype(f->state, TRC4state, exBadState, 0);
+ p = f->buf->data;
+ rc4(&is->state, p, f->n);
+}
+
+void
+Crypt_rc4skip(void *fp)
+{
+ F_Crypt_rc4skip *f;
+ XRC4state *is;
+
+ f = fp;
+ is = checktype(f->state, TRC4state, exBadState, 0);
+ rc4skip(&is->state, f->n);
+}
+
+void
+Crypt_rc4back(void *fp)
+{
+ F_Crypt_rc4back *f;
+ XRC4state *is;
+
+ f = fp;
+ is = checktype(f->state, TRC4state, exBadState, 0);
+ rc4back(&is->state, f->n);
+}
+
+/*
+ * public/secret keys, signing and verifying
+ */
+
+/*
+ * DSA
+ */
+
+static void
+dsapk2pub(DSApub* p, Crypt_PK* pk)
+{
+ if(pk == H)
+ error(exNilref);
+ if(pk->pick != Crypt_PK_DSA)
+ error(exType);
+ p->p = MPX(pk->u.DSA.p);
+ p->q = MPX(pk->u.DSA.q);
+ p->alpha = MPX(pk->u.DSA.alpha);
+ p->key = MPX(pk->u.DSA.key);
+}
+
+static void
+dsask2priv(DSApriv* p, Crypt_SK* sk)
+{
+ if(sk == H)
+ error(exNilref);
+ if(sk->pick != Crypt_SK_DSA)
+ error(exType);
+ dsapk2pub(&p->pub, sk->u.DSA.pk);
+ p->secret = MPX(sk->u.DSA.secret);
+}
+
+static void
+dsapriv2sk(Crypt_SK* sk, DSApriv* p)
+{
+ Crypt_PK *pk;
+
+ pk = sk->u.DSA.pk;
+ pk->u.DSA.p = ipcopymp(p->pub.p);
+ pk->u.DSA.q = ipcopymp(p->pub.q);
+ pk->u.DSA.alpha = ipcopymp(p->pub.alpha);
+ pk->u.DSA.key = ipcopymp(p->pub.key);
+ sk->u.DSA.secret = ipcopymp(p->secret);
+}
+
+static void
+dsaxgen(Crypt_SK* sk, DSApub* oldpk)
+{
+ DSApriv *p;
+
+ release();
+ p = dsagen(oldpk);
+ acquire();
+ dsapriv2sk(sk, p);
+ dsaprivfree(p);
+}
+
+void
+Crypt_dsagen(void *fp)
+{
+ F_Crypt_dsagen *f;
+ Crypt_SK *sk;
+ DSApub pub, *oldpk;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ sk = newSK(f->ret, TSKdsa, Crypt_SK_DSA);
+ oldpk = nil;
+ if(f->oldpk != H && f->oldpk->pick == Crypt_PK_DSA){
+ dsapk2pub(&pub, f->oldpk);
+ oldpk = &pub;
+ }
+ dsaxgen(sk, oldpk);
+}
+
+/*
+ * Elgamal
+ */
+
+static void
+egpk2pub(EGpub* p, Crypt_PK* pk)
+{
+ if(pk == H)
+ error(exNilref);
+ if(pk->pick != Crypt_PK_Elgamal)
+ error(exType);
+ p->p = MPX(pk->u.Elgamal.p);
+ p->alpha = MPX(pk->u.Elgamal.alpha);
+ p->key = MPX(pk->u.Elgamal.key);
+}
+
+static void
+egsk2priv(EGpriv* p, Crypt_SK* sk)
+{
+ if(sk == H)
+ error(exNilref);
+ if(sk->pick != Crypt_SK_Elgamal)
+ error(exType);
+ egpk2pub(&p->pub, sk->u.Elgamal.pk);
+ p->secret = MPX(sk->u.Elgamal.secret);
+}
+
+static void
+egpriv2sk(Crypt_SK* sk, EGpriv* p)
+{
+ Crypt_PK* pk;
+
+ pk = sk->u.Elgamal.pk;
+ pk->u.Elgamal.p = ipcopymp(p->pub.p);
+ pk->u.Elgamal.alpha = ipcopymp(p->pub.alpha);
+ pk->u.Elgamal.key = ipcopymp(p->pub.key);
+ sk->u.Elgamal.secret = ipcopymp(p->secret);
+}
+
+static void
+egxgen(Crypt_SK* sk, int nlen, int nrep)
+{
+ EGpriv *p;
+
+ release();
+ for(;;){
+ p = eggen(nlen, nrep);
+ if(mpsignif(p->pub.p) == nlen)
+ break;
+ egprivfree(p);
+ }
+ acquire();
+ egpriv2sk(sk, p);
+ egprivfree(p);
+}
+
+
+void
+Crypt_eggen(void *fp)
+{
+ F_Crypt_eggen *f;
+ Crypt_SK *sk;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ sk = newSK(f->ret, TSKeg, Crypt_SK_Elgamal);
+ egxgen(sk, f->nlen, f->nrep);
+}
+
+/*
+ * RSA
+ */
+
+static void
+rsapk2pub(RSApub* p, Crypt_PK* pk)
+{
+ if(pk == H)
+ error(exNilref);
+ if(pk->pick != Crypt_PK_RSA)
+ error(exType);
+ p->n = MPX(pk->u.RSA.n);
+ p->ek = MPX(pk->u.RSA.ek);
+}
+
+static void
+rsask2priv(RSApriv* p, Crypt_SK* sk)
+{
+ if(sk == H)
+ error(exNilref);
+ if(sk->pick != Crypt_SK_RSA)
+ error(exType);
+ rsapk2pub(&p->pub, sk->u.RSA.pk);
+ p->dk = MPX(sk->u.RSA.dk);
+ p->p = MPX(sk->u.RSA.p);
+ p->q = MPX(sk->u.RSA.q);
+ p->kp = MPX(sk->u.RSA.kp);
+ p->kq = MPX(sk->u.RSA.kq);
+ p->c2 = MPX(sk->u.RSA.c2);
+}
+
+static void
+rsapriv2sk(Crypt_SK* sk, RSApriv* p)
+{
+ Crypt_PK *pk;
+
+ pk = sk->u.RSA.pk;
+ pk->u.RSA.n = ipcopymp(p->pub.n);
+ pk->u.RSA.ek = ipcopymp(p->pub.ek);
+ sk->u.RSA.dk = ipcopymp(p->dk);
+ sk->u.RSA.p = ipcopymp(p->p);
+ sk->u.RSA.q = ipcopymp(p->q);
+ sk->u.RSA.kp = ipcopymp(p->kp);
+ sk->u.RSA.kq = ipcopymp(p->kq);
+ sk->u.RSA.c2 = ipcopymp(p->c2);
+}
+
+static void
+rsaxgen(Crypt_SK *sk, int nlen, int elen, int nrep)
+{
+ RSApriv *p;
+
+ release();
+ for(;;){
+ p = rsagen(nlen, elen, nrep);
+ if(mpsignif(p->pub.n) == nlen)
+ break;
+ rsaprivfree(p);
+ }
+ acquire();
+ rsapriv2sk(sk, p);
+ rsaprivfree(p);
+}
+
+void
+Crypt_rsagen(void *fp)
+{
+ F_Crypt_rsagen *f;
+ Crypt_SK *sk;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ sk = newSK(f->ret, TSKrsa, Crypt_SK_RSA);
+ rsaxgen(sk, f->nlen, f->elen, f->nrep);
+}
+
+void
+Crypt_rsafill(void *fp)
+{
+ F_Crypt_rsafill *f;
+ Crypt_SK *sk;
+ RSApriv *p;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ sk = newSK(f->ret, TSKrsa, Crypt_SK_RSA);
+ release();
+ p = rsafill(MPX(f->n), MPX(f->ek), MPX(f->dk),
+ MPX(f->p), MPX(f->q));
+ acquire();
+ if(p == nil) {
+ *f->ret = H;
+ destroy(sk);
+ }else{
+ rsapriv2sk(sk, p);
+ rsaprivfree(p);
+ }
+}
+
+void
+Crypt_rsaencrypt(void *fp)
+{
+ F_Crypt_rsaencrypt *f;
+ RSApub p;
+ mpint *m, *o;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ rsapk2pub(&p, f->k);
+ m = MPX(f->m);
+ release();
+ o = rsaencrypt(&p, m, nil);
+ acquire();
+ *f->ret = newIPint(o);
+}
+
+void
+Crypt_rsadecrypt(void *fp)
+{
+ F_Crypt_rsadecrypt *f;
+ RSApriv p;
+ mpint *m, *o;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ rsask2priv(&p, f->k);
+ m = MPX(f->m);
+ release();
+ o = rsadecrypt(&p, m, nil);
+ acquire();
+ *f->ret = newIPint(o);
+}
+
+/*
+ * generic key functions
+ */
+
+void
+Crypt_genSK(void *fp)
+{
+ F_Crypt_genSK *f;
+ Crypt_SK *sk;
+ char *sa;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ sa = string2c(f->algname);
+ if(strcmp(sa, "rsa") == 0){
+ sk = newSK(f->ret, TSKrsa, Crypt_SK_RSA);
+ rsaxgen(sk, f->length, 6, 0);
+ }else if(strcmp(sa, "dsa") == 0){
+ sk = newSK(f->ret, TSKdsa, Crypt_SK_DSA);
+ dsaxgen(sk, nil);
+ }else if(strcmp(sa, "elgamal") == 0){
+ sk = newSK(f->ret, TSKeg, Crypt_SK_Elgamal);
+ egxgen(sk, f->length, 0);
+ }
+ /* genSK returns nil for unknown algorithm */
+}
+
+void
+Crypt_genSKfromPK(void *fp)
+{
+ F_Crypt_genSKfromPK *f;
+ Crypt_SK *sk;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ if(f->pk == H)
+ error(exNilref);
+ switch(f->pk->pick){
+ case Crypt_PK_RSA: {
+ RSApub p;
+
+ rsapk2pub(&p, f->pk);
+ sk = newSK(f->ret, TSKrsa, Crypt_SK_RSA);
+ rsaxgen(sk, mpsignif(p.n), mpsignif(p.ek), 0);
+ }
+ break;
+ case Crypt_PK_Elgamal: {
+ EGpub p;
+
+ egpk2pub(&p, f->pk);
+ sk = newSK(f->ret, TSKeg, Crypt_SK_Elgamal);
+ egxgen(sk, mpsignif(p.p), 0);
+ }
+ break;
+ case Crypt_PK_DSA: {
+ DSApub p;
+
+ dsapk2pub(&p, f->pk);
+ sk = newSK(f->ret, TSKdsa, Crypt_SK_DSA);
+ dsaxgen(sk, &p);
+ }
+ break;
+ default:
+ /* shouldn't happen */
+ error(exType);
+ }
+}
+
+void
+Crypt_sktopk(void *fp)
+{
+ F_Crypt_sktopk *f;
+ Crypt_PK *pk;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+ if(f->sk == H)
+ error(exNilref);
+ switch(f->sk->pick){
+ case Crypt_PK_RSA:
+ pk = f->sk->u.RSA.pk;
+ break;
+ case Crypt_PK_Elgamal:
+ pk = f->sk->u.Elgamal.pk;
+ break;
+ case Crypt_PK_DSA:
+ pk = f->sk->u.DSA.pk;
+ break;
+ default:
+ pk = H;
+ error(exType);
+ }
+ if(pk == H)
+ return;
+ D2H(pk)->ref++;
+ *f->ret = pk;
+}
+
+void
+Crypt_sign(void *fp)
+{
+ F_Crypt_sign *f;
+ Crypt_PKsig *sig;
+ mpint *m;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ if(f->m == H || f->sk == H)
+ error(exNilref);
+ m = MPX(f->m);
+ switch(f->sk->pick){
+ case Crypt_SK_RSA: {
+ RSApriv p;
+ mpint *s;
+
+ rsask2priv(&p, f->sk);
+ release();
+ s = rsadecrypt(&p, m, nil);
+ acquire();
+ sig = newPKsig(TPKsigrsa, Crypt_PKsig_RSA);
+ sig->u.RSA.n = newIPint(s);
+ }
+ break;
+ case Crypt_SK_Elgamal: {
+ EGpriv p;
+ EGsig *s;
+
+ egsk2priv(&p, f->sk);
+ release();
+ s = egsign(&p, m);
+ acquire();
+ sig = newPKsig(TPKsigeg, Crypt_PKsig_Elgamal);
+ sig->u.Elgamal.r = ipcopymp(s->r);
+ sig->u.Elgamal.s = ipcopymp(s->s);
+ egsigfree(s);
+ }
+ break;
+ case Crypt_SK_DSA: {
+ DSApriv p;
+ DSAsig *s;
+
+ dsask2priv(&p, f->sk);
+ m = MPX(f->m);
+ release();
+ s = dsasign(&p, m);
+ acquire();
+ sig = newPKsig(TPKsigdsa, Crypt_PKsig_DSA);
+ sig->u.DSA.r = ipcopymp(s->r);
+ sig->u.DSA.s = ipcopymp(s->s);
+ dsasigfree(s);
+ }
+ break;
+ default:
+ sig = H;
+ error(exType);
+ }
+ *f->ret = sig;
+}
+
+void
+Crypt_verify(void *fp)
+{
+ F_Crypt_verify *f;
+ mpint *m;
+
+ f = fp;
+ *f->ret = 0;
+ if(f->sig == H || f->pk == H)
+ error(exNilref);
+ if(f->sig->pick != f->pk->pick)
+ return; /* key type and signature mismatch, doesn't validate */
+ m = MPX(f->m);
+ switch(f->pk->pick){
+ case Crypt_PK_RSA: {
+ RSApub p;
+ mpint *sig, *t;
+
+ rsapk2pub(&p, f->pk);
+ sig = MPX(f->sig->u.RSA.n);
+ release();
+ t = rsaencrypt(&p, sig, nil);
+ *f->ret = mpcmp(t, m) == 0;
+ mpfree(t);
+ acquire();
+ }
+ break;
+ case Crypt_PK_Elgamal: {
+ EGpub p;
+ EGsig sig;
+
+ egpk2pub(&p, f->pk);
+ sig.r = MPX(f->sig->u.Elgamal.r);
+ sig.s = MPX(f->sig->u.Elgamal.s);
+ release();
+ *f->ret = egverify(&p, &sig, m) == 0;
+ acquire();
+ }
+ break;
+ case Crypt_PK_DSA: {
+ DSApub p;
+ DSAsig sig;
+
+ dsapk2pub(&p, f->pk);
+ sig.r = MPX(f->sig->u.DSA.r);
+ sig.s = MPX(f->sig->u.DSA.s);
+ release();
+ *f->ret = dsaverify(&p, &sig, m) == 0;
+ acquire();
+ }
+ break;
+ default:
+ error(exType);
+ }
+}
diff --git a/libinterp/heap.c b/libinterp/heap.c
index 5eff79a5..1ac715f7 100644
--- a/libinterp/heap.c
+++ b/libinterp/heap.c
@@ -237,6 +237,40 @@ destroy(void *v)
poolfree(heapmem, h);
}
+Type*
+dtype(void (*destroy)(Heap*, int), int size, uchar *map, int mapsize)
+{
+ Type *t;
+
+ t = malloc(sizeof(Type)+mapsize);
+ if(t != nil) {
+ t->ref = 1;
+ t->free = destroy;
+ t->mark = markheap;
+ t->size = size;
+ t->np = mapsize;
+ memmove(t->map, map, mapsize);
+ }
+ return t;
+}
+
+void*
+checktype(void *v, Type *t, char *name, int newref)
+{
+ Heap *h;
+
+ if(v == H || v == nil)
+ error(exNilref);
+ h = D2H(v);
+ if(t == nil || h->t != t)
+ errorf("%s: %s", exType, name);
+ if(newref){
+ h->ref++;
+ Setmark(h);
+ }
+ return v;
+}
+
void
freetype(Type *t)
{
diff --git a/libinterp/ipint.c b/libinterp/ipint.c
index b4967843..5728420c 100644
--- a/libinterp/ipint.c
+++ b/libinterp/ipint.c
@@ -6,13 +6,39 @@
#include <mp.h>
#include <libsec.h>
#include "pool.h"
-#include "../libkeyring/keys.h"
+#include "ipint.h"
#include "raise.h"
-extern Type *TIPint;
+#include "ipintsmod.h"
+
+enum
+{
+ MaxBigBytes = 1024
+};
+
+/* infinite precision integer */
+struct IPint
+{
+ IPints_IPint x;
+ mpint* b;
+};
+
+Type *TIPint;
+static uchar IPintmap[] = IPints_IPint_map;
+
#define MP(x) checkIPint((x))
-Keyring_IPint*
+void
+ipintsmodinit(void)
+{
+ /* can be called from modinit, Keyring or Crypt */
+ if(TIPint == nil)
+ TIPint = dtype(freeIPint, sizeof(IPint), IPintmap, sizeof(IPintmap));
+ builtinmod("$IPints", IPintsmodtab, IPintsmodlen);
+}
+
+//IPints_IPint*
+void*
newIPint(mpint* b)
{
Heap *h;
@@ -23,20 +49,22 @@ newIPint(mpint* b)
h = heap(TIPint); /* TO DO: caller might lose other values if heap raises error here */
ip = H2D(IPint*, h);
ip->b = b;
- return (Keyring_IPint*)ip;
+ return (IPints_IPint*)ip;
}
mpint*
-checkIPint(Keyring_IPint *v)
+checkIPint(void *a)
{
+ IPints_IPint *v;
IPint *ip;
+ v = a;
ip = (IPint*)v;
if(ip == H || ip == nil)
error(exNilref);
if(D2H(ip)->t != TIPint)
error(exType);
- return ip->b;
+ return ip->b; /* non-nil by construction */
}
void
@@ -151,7 +179,7 @@ IPint_iptostr(void *fp)
retstr(buf, f->ret);
}
-static Keyring_IPint*
+static IPints_IPint*
strtoipint(String *s, int base)
{
char *p, *q;
@@ -250,7 +278,7 @@ IPint_random(void *fp)
destroy(v);
release();
- b = mprand(f->maxbits, genrandom, nil);
+ b = mprand(f->nbits, genrandom, nil);
acquire();
*f->ret = newIPint(b);
}
@@ -712,3 +740,109 @@ IPint_not(void *fp)
mpnot(i1, ret);
*f->ret = newIPint(ret);
}
+
+/*
+ * primes
+ */
+
+void
+IPints_probably_prime(void *fp)
+{
+ F_IPints_probably_prime *f;
+
+ f = fp;
+ release();
+ *f->ret = probably_prime(checkIPint(f->n), f->nrep);
+ acquire();
+}
+
+void
+IPints_genprime(void *fp)
+{
+ F_IPints_genprime *f;
+ mpint *p;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+ p = mpnew(0);
+ release();
+ genprime(p, f->nbits, f->nrep);
+ acquire();
+ *f->ret = newIPint(p);
+}
+
+void
+IPints_genstrongprime(void *fp)
+{
+ F_IPints_genstrongprime *f;
+ mpint *p;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+ p = mpnew(0);
+ release();
+ genstrongprime(p, f->nbits, f->nrep);
+ acquire();
+ *f->ret = newIPint(p);
+}
+
+void
+IPints_gensafeprime(void *fp)
+{
+ F_IPints_gensafeprime *f;
+ mpint *p, *alpha;
+ void *v;
+
+ f = fp;
+ v = f->ret->t0;
+ f->ret->t0 = H;
+ destroy(v);
+ v = f->ret->t1;
+ f->ret->t1 = H;
+ destroy(v);
+
+ p = mpnew(0);
+ alpha = mpnew(0);
+ release();
+ gensafeprime(p, alpha, f->nbits, f->nrep);
+ acquire();
+ f->ret->t0 = newIPint(p);
+ f->ret->t1 = newIPint(alpha);
+}
+
+void
+IPints_DSAprimes(void *fp)
+{
+ F_IPints_DSAprimes *f;
+ mpint *p, *q;
+ Heap *h;
+ void *v;
+
+ f = fp;
+ v = f->ret->t0;
+ f->ret->t0 = H;
+ destroy(v);
+ v = f->ret->t1;
+ f->ret->t1 = H;
+ destroy(v);
+ v = f->ret->t2;
+ f->ret->t2 = H;
+ destroy(v);
+
+ h = heaparray(&Tbyte, SHA1dlen);
+ f->ret->t2 = H2D(Array*, h);
+
+ p = mpnew(0);
+ q = mpnew(0);
+ release();
+ DSAprimes(q, p, f->ret->t2->data);
+ acquire();
+ f->ret->t0 = newIPint(q);
+ f->ret->t1 = newIPint(p);
+}
diff --git a/libinterp/ipint.h b/libinterp/ipint.h
new file mode 100644
index 00000000..a730f4f2
--- /dev/null
+++ b/libinterp/ipint.h
@@ -0,0 +1,12 @@
+typedef struct IPint IPint;
+
+#pragma incomplete IPint
+
+//Keyring_IPint* newIPint(mpint*);
+void* newIPint(mpint*);
+//mpint* checkIPint(Keyring_IPint*);
+mpint* checkIPint(void*);
+void freeIPint(Heap*, int);
+void ipintsmodinit(void);
+
+extern Type* TIPint;
diff --git a/libinterp/keyring.c b/libinterp/keyring.c
index 7bc5b5d3..8b7fd406 100644
--- a/libinterp/keyring.c
+++ b/libinterp/keyring.c
@@ -2,69 +2,73 @@
#include "kernel.h"
#include <isa.h>
#include "interp.h"
-#include "runt.h"
-#include "keyring.h"
#include <mp.h>
#include <libsec.h>
#include "pool.h"
#include "raise.h"
-#include "../libkeyring/keys.h"
+/* arguably limbo -t should qualify type name */
+#define DigestState_copy Keyring_DigestState_copy
+#define IPint_random Keyring_IPint_random
+#include "keyringif.h"
+#include "keyring.h"
+
+#include "ipint.h"
+#include "../libkeyring/keys.h"
-Type *TSigAlg;
-Type *TCertificate;
-Type *TSK;
-Type *TPK;
-Type *TDigestState;
-Type *TAuthinfo;
-Type *TAESstate;
-Type *TDESstate;
-Type *TIDEAstate;
-Type *TBFstate;
-Type *TRC4state;
-Type *TIPint;
-Type *TDSAsk;
-Type *TDSApk;
-Type *TDSAsig;
-Type *TEGsk;
-Type *TEGpk;
-Type *TEGsig;
-Type *TRSAsk;
-Type *TRSApk;
-Type *TRSAsig;
+static Type* TDigestState;
+static Type* TAESstate;
+static Type* TDESstate;
+static Type* TIDEAstate;
+static Type* TBFstate;
+static Type* TRC4state;
+
+static Type* TSigAlg;
+static Type* TCertificate;
+static Type* TSK;
+static Type* TPK;
+static Type* TAuthinfo;
+
+static Type* TDSAsk;
+static Type* TDSApk;
+static Type* TDSAsig;
+static Type* TEGsk;
+static Type* TEGpk;
+static Type* TEGsig;
+static Type* TRSAsk;
+static Type* TRSApk;
+static Type* TRSAsig;
enum {
Maxmsg= 4096
};
-uchar IPintmap[] = Keyring_IPint_map;
-uchar SigAlgmap[] = Keyring_SigAlg_map;
-uchar SKmap[] = Keyring_SK_map;
-uchar PKmap[] = Keyring_PK_map;
-uchar Certificatemap[] = Keyring_Certificate_map;
-uchar DigestStatemap[] = Keyring_DigestState_map;
-uchar Authinfomap[] = Keyring_Authinfo_map;
-uchar AESstatemap[] = Keyring_AESstate_map;
-uchar DESstatemap[] = Keyring_DESstate_map;
-uchar IDEAstatemap[] = Keyring_IDEAstate_map;
-uchar BFstatemap[] = Keyring_BFstate_map;
-uchar RC4statemap[] = Keyring_RC4state_map;
-uchar DSAskmap[] = Keyring_DSAsk_map;
-uchar DSApkmap[] = Keyring_DSApk_map;
-uchar DSAsigmap[] = Keyring_DSAsig_map;
-uchar EGskmap[] = Keyring_EGsk_map;
-uchar EGpkmap[] = Keyring_EGpk_map;
-uchar EGsigmap[] = Keyring_EGsig_map;
-uchar RSAskmap[] = Keyring_RSAsk_map;
-uchar RSApkmap[] = Keyring_RSApk_map;
-uchar RSAsigmap[] = Keyring_RSAsig_map;
-
-PK* checkPK(Keyring_PK *k);
+static uchar DigestStatemap[] = Keyring_DigestState_map;
+static uchar AESstatemap[] = Keyring_AESstate_map;
+static uchar DESstatemap[] = Keyring_DESstate_map;
+static uchar IDEAstatemap[] = Keyring_IDEAstate_map;
+static uchar BFstatemap[] = Keyring_BFstate_map;
+static uchar RC4statemap[] = Keyring_RC4state_map;
+
+static uchar SigAlgmap[] = Keyring_SigAlg_map;
+static uchar SKmap[] = Keyring_SK_map;
+static uchar PKmap[] = Keyring_PK_map;
+static uchar Certificatemap[] = Keyring_Certificate_map;
+static uchar Authinfomap[] = Keyring_Authinfo_map;
+static uchar DSAskmap[] = Keyring_DSAsk_map;
+static uchar DSApkmap[] = Keyring_DSApk_map;
+static uchar DSAsigmap[] = Keyring_DSAsig_map;
+static uchar EGskmap[] = Keyring_EGsk_map;
+static uchar EGpkmap[] = Keyring_EGpk_map;
+static uchar EGsigmap[] = Keyring_EGsig_map;
+static uchar RSAskmap[] = Keyring_RSAsk_map;
+static uchar RSApkmap[] = Keyring_RSApk_map;
+static uchar RSAsigmap[] = Keyring_RSAsig_map;
+
+static PK* checkPK(Keyring_PK *k);
extern void setid(char*, int);
extern vlong osusectime(void);
-extern Keyring_IPint* newIPint(mpint*);
-extern mpint* checkIPint(Keyring_IPint*);
extern void freeIPint(Heap*, int);
static char exBadSA[] = "bad signature algorithm";
@@ -86,10 +90,6 @@ struct XBFstate
BFstate state;
};
-/*
- * Infinite (actually kind of big) precision integers
- */
-
/* convert a Big to base64 ascii */
int
bigtobase64(mpint* b, char *buf, int len)
@@ -567,7 +567,7 @@ freePK(Heap *h, int swept)
freeheap(h, swept);
}
-PK*
+static PK*
checkPK(Keyring_PK *k)
{
PK *pk;
@@ -1170,28 +1170,11 @@ Keyring_verifym(void *fp)
acquire();
}
-static void*
-checktype(void *v, Type *t, char *name, int newref)
-{
- Heap *h;
-
- if(v == H || v == nil)
- error(exNilref);
- h = D2H(v);
- if(h->t != t)
- errorf("%s: %s", exType, name);
- if(newref){
- h->ref++;
- Setmark(h);
- }
- return v;
-}
-
/*
* digests
*/
void
-DigestState_copy(void *fp)
+Keyring_DigestState_copy(void *fp)
{
F_DigestState_copy *f;
Heap *h;
@@ -1933,18 +1916,17 @@ Keyring_writeauthinfo(void *fp)
PK *spk;
SK *mysk;
Certificate *c;
+ mpint *p, *alpha;
f = fp;
*f->ret = -1;
if(f->filename == H)
- return;
+ error(exNilref);
if(f->info == H)
- return;
- if(f->info->alpha == H || f->info->p == H)
- return;
- if(((IPint*)f->info->alpha)->b == 0 || ((IPint*)f->info->p)->b == H)
- return;
+ error(exNilref);
+ alpha = checkIPint(f->info->alpha);
+ p = checkIPint(f->info->p);
spk = checkPK(f->info->spk);
mysk = checkSK(f->info->mysk);
c = checkCertificate(f->info->cert);
@@ -1985,12 +1967,12 @@ Keyring_writeauthinfo(void *fp)
goto out;
/* diffie hellman base */
- n = bigtobase64(((IPint*)f->info->alpha)->b, buf, Maxbuf);
+ n = bigtobase64(alpha, buf, Maxbuf);
if(sendmsg(fd, buf, n) <= 0)
goto out;
/* diffie hellman modulus */
- n = bigtobase64(((IPint*)f->info->p)->b, buf, Maxbuf);
+ n = bigtobase64(p, buf, Maxbuf);
if(sendmsg(fd, buf, n) <= 0)
goto out;
@@ -2108,7 +2090,7 @@ keyringmodinit(void)
extern SigAlgVec* rsainit(void);
extern SigAlgVec* dsainit(void);
- TIPint = dtype(freeIPint, sizeof(IPint), IPintmap, sizeof(IPintmap));
+ ipintsmodinit(); /* in case only Keyring is configured */
TSigAlg = dtype(freeSigAlg, sizeof(SigAlg), SigAlgmap, sizeof(SigAlgmap));
TSK = dtype(freeSK, sizeof(SK), SKmap, sizeof(SKmap));
TPK = dtype(freePK, sizeof(PK), PKmap, sizeof(PKmap));
@@ -3081,3 +3063,21 @@ RSApk_verify(void *fp)
mpfree(t);
acquire();
}
+
+void
+Keyring_IPint_random(void *fp)
+{
+ F_IPint_random *f;
+ mpint *b;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ release();
+ b = mprand(f->maxbits, genrandom, nil);
+ acquire();
+ *f->ret = newIPint(b);
+}
diff --git a/libinterp/keyringif.m b/libinterp/keyringif.m
new file mode 100644
index 00000000..8eed5143
--- /dev/null
+++ b/libinterp/keyringif.m
@@ -0,0 +1,4 @@
+# temporary hack to prevent clashes with DigestState
+include "sys.m";
+
+include "keyring.m";
diff --git a/libinterp/load.c b/libinterp/load.c
index 8645338a..2e3aa216 100644
--- a/libinterp/load.c
+++ b/libinterp/load.c
@@ -79,23 +79,6 @@ load(char *path)
return readmod(path, nil, 0);
}
-Type*
-dtype(void (*destroy)(Heap*, int), int size, uchar *map, int mapsize)
-{
- Type *t;
-
- t = malloc(sizeof(Type)+mapsize);
- if(t != nil) {
- t->ref = 1;
- t->free = destroy;
- t->mark = markheap;
- t->size = size;
- t->np = mapsize;
- memmove(t->map, map, mapsize);
- }
- return t;
-}
-
int
brpatch(Inst *ip, Module *m)
{
diff --git a/libinterp/mkfile b/libinterp/mkfile
index 50d86f5d..81f39198 100644
--- a/libinterp/mkfile
+++ b/libinterp/mkfile
@@ -6,6 +6,7 @@ OFILES=\
alt.$O\
comp-$OBJTYPE.$O\
conv.$O\
+ crypt.$O\
dec.$O\
dlm-$TARGMODEL.$O\
draw.$O\
@@ -48,6 +49,9 @@ MODULES=\
../module/keyring.m\
../module/loader.m\
../module/freetype.m\
+ ../module/ipints.m\
+ ../module/crypt.m\
+ keyringif.m\
<$ROOT/mkfiles/mksyslib-$SHELLTYPE
@@ -58,7 +62,7 @@ sysmod.h:D: $MODULES
rm -f $target && limbo -t Sys -I../module ../module/runt.m > $target
keyring.h:D: $MODULES
- rm -f $target && limbo -t Keyring -I../module ../module/runt.m > $target
+ rm -f $target && limbo -t Keyring -I../module keyringif.m > $target
drawmod.h:D: $MODULES
rm -f $target && limbo -t Draw -I../module ../module/runt.m > $target
@@ -78,9 +82,19 @@ loadermod.h:D: $MODULES
freetypemod.h:D: $MODULES
rm -f $target && limbo -t Freetype -I../module ../module/runt.m > $target
+ipintsmod.h:D: $MODULES
+ rm -f $target && limbo -t IPints -I../module ../module/ipints.m > $target
+
benchmod.h:D: ../module/bench.m
rm -f $target && limbo -t Bench -I../module ../module/bench.m > $target
+cryptmod.h:D: $MODULES
+ rm -f $target && limbo -t Crypt -I../module ../module/runt.m > $target
+
+keyringif.h:D: $MODULES keyringif.m
+ rm -f $target && limbo -a -I../module keyringif.m > $target
+
+
bench.h:D:../module/bench.m
rm -f $target && limbo -a -I../module ../module/bench.m > $target
@@ -95,8 +109,9 @@ prefab.$O: prefabmod.h
draw.$O: drawmod.h
tk.$O: $ROOT/include/draw.h tkmod.h
math.$O: mathmod.h
-keyring.$O: keyring.h $ROOT/libkeyring/keys.h
-ipint.$O: keyring.h
+keyring.$O: keyring.h ipint.h keyringif.h
+crypt.$O: ipint.h runt.h cryptmod.h
+ipint.$O: ipint.h ipintsmod.h
loader.$O: loadermod.h
freetype.$O: freetypemod.h $ROOT/include/freetype.h
math.$O: $ROOT/include/mathi.h
@@ -105,11 +120,6 @@ das-spim.c:N: das-mips.c
das-68000.c:N: das-68020.c
comp-spim.c:N: comp-mips.c
-kif.c: kif.h
- rm -f $target && kif -t $SYSTARG kif.h > $target
-kif.$O: kif.c
- $CC $CFLAGS kif.c && rm -f kif.c
-
# optab.h: $ROOT/include/isa.h mkoptab
# $SHELLNAME mkoptab > $target
@@ -117,4 +127,4 @@ kif.$O: kif.c
# it works only on UNIX and Plan 9.
nuke:EV: nuke-std
- rm -f runt.h sysmod.h drawmod.h prefabmod.h tkmod.h mathmod.h keyring.h readimagemod.h loadermod.h freetypemod.h kif.c
+ rm -f runt.h sysmod.h drawmod.h prefabmod.h tkmod.h mathmod.h keyring.h readimagemod.h loadermod.h freetypemod.h cryptmod.h keyringif.h ipintsmod.h
diff --git a/libkeyring/dsaalg.c b/libkeyring/dsaalg.c
index 9845d5f0..2bf659f7 100644
--- a/libkeyring/dsaalg.c
+++ b/libkeyring/dsaalg.c
@@ -2,7 +2,7 @@
#include <kernel.h>
#include <isa.h>
#include "interp.h"
-#include "../libinterp/runt.h"
+#include "../libinterp/keyringif.h"
#include "mp.h"
#include "libsec.h"
#include "keys.h"
diff --git a/libkeyring/egalg.c b/libkeyring/egalg.c
index 0c6b88d1..28202c1c 100644
--- a/libkeyring/egalg.c
+++ b/libkeyring/egalg.c
@@ -2,7 +2,7 @@
#include <kernel.h>
#include <isa.h>
#include "interp.h"
-#include "../libinterp/runt.h"
+#include "../libinterp/keyringif.h"
#include "mp.h"
#include "libsec.h"
#include "keys.h"
diff --git a/libkeyring/keys.h b/libkeyring/keys.h
index ff1eb149..4071ca02 100644
--- a/libkeyring/keys.h
+++ b/libkeyring/keys.h
@@ -1,4 +1,3 @@
-typedef struct IPint IPint;
typedef struct SigAlg SigAlg;
typedef struct SigAlgVec SigAlgVec;
typedef struct SK SK;
@@ -16,13 +15,6 @@ enum
MaxBigBytes = 1024
};
-/* infininite precision integer */
-struct IPint
-{
- Keyring_IPint x;
- mpint* b;
-};
-
/* generic certificate */
struct Certificate
{
@@ -115,4 +107,5 @@ struct SigAlg
int bigtobase64(mpint* b, char *buf, int blen);
mpint* base64tobig(char *str, char **strp);
SigAlgVec* findsigalg(char*);
-Keyring_IPint* newIPint(mpint*);
+//Keyring_IPint* newIPint(mpint*);
+void* newIPint(mpint*);
diff --git a/libkeyring/rsaalg.c b/libkeyring/rsaalg.c
index f522f485..46df7e50 100644
--- a/libkeyring/rsaalg.c
+++ b/libkeyring/rsaalg.c
@@ -2,7 +2,7 @@
#include <kernel.h>
#include <isa.h>
#include "interp.h"
-#include "../libinterp/runt.h"
+#include "../libinterp/keyringif.h"
#include "mp.h"
#include "libsec.h"
#include "keys.h"
diff --git a/libmp/port/mpextendedgcd.c b/libmp/port/mpextendedgcd.c
index 413a05c2..ba7365bf 100644
--- a/libmp/port/mpextendedgcd.c
+++ b/libmp/port/mpextendedgcd.c
@@ -101,6 +101,4 @@ mpextendedgcd(mpint *a, mpint *b, mpint *v, mpint *x, mpint *y)
mpfree(u);
mpfree(a);
mpfree(b);
-
- return;
}
diff --git a/man/2/crypt-0intro b/man/2/crypt-0intro
new file mode 100644
index 00000000..3add273e
--- /dev/null
+++ b/man/2/crypt-0intro
@@ -0,0 +1,98 @@
+.TH CRYPT-INTRO 2
+.SH NAME
+Crypt intro \- introduction to the
+.B Crypt
+cryptography
+module
+.SH SYNOPSIS
+.EX
+include "ipints.m";
+ipints := load IPints IPints->PATH;
+IPint: import ipints;
+
+include "crypt.m";
+crypt := load Crypt Crypt->PATH;
+.EE
+.SH DESCRIPTION
+.B Crypt
+contains a mixed set of functions that variously:
+.IP \(bu
+form cryptographically secure digests; see
+.IR crypt-sha1 (2)
+.IP \(bu
+generate public/private key pairs; see
+.IR crypt-gensk (2)
+.IP \(bu
+encrypt data, using AES, DES, or IDEA; see
+.IR crypt-crypt (2)
+.IP \(bu
+create and verify cryptographic signatures using the
+public keys; see
+.IR crypt-sign (2)
+.SS "Public Key Cryptography"
+Public key cryptography has many uses.
+Inferno relies on it only for digital signatures.
+The private key may be used to digitally
+sign data, the public one to verify the signature.
+.PP
+Inferno provides three data types to represent the different components of the public key signature scheme.
+The
+.B PK
+adt contains the data necessary to construct a public key;
+the
+.B SK
+adt contains the data necessary to construct a secret key.
+A key contains the public or secret parameters for the signature algorithm specified by the adt's pick tag.
+Ownership of a key is not recorded in the key value itself but in a separate certificate.
+Finally,
+the
+.B PKsig
+adt contains one or more values representing a given form of digital signature.
+.PP
+Certificates and indeed signature representations are varied, and implemented by other modules.
+.SS "Large Precision Arithmetic"
+Many
+.B Crypt
+operations require integers much larger than
+.B int
+or
+.BR big .
+It therefore uses the multiple-precision package
+.IR ipints (2).
+That module's
+.B IPint
+adt
+stands for infinite precision integer, though, for
+space considerations, our
+implementation limits the maximum integer to
+2\u\s-2\&8192\s0\d-1.
+.PP
+An
+.B IPint
+can be converted into two external formats.
+The first is
+an array of bytes in which the first byte is the highest order
+byte of the integer. This format is useful when
+communicating with the
+.IR ssl (3)
+device.
+The second is similar but represents the array of bytes as text, using either base 16 or a MIME base 64 format,
+allowing
+.BR IPint s
+to be stored in files or transmitted across
+networks in a human readable form.
+.SH SOURCE
+.br
+.B /libinterp/crypt.c
+.br
+.B /libinterp/ipint.c
+.br
+.B /libmp
+.br
+.B /libsec
+.SH SEE ALSO
+.IR security-intro (2)
+.br
+B. Schneier,
+.IR "Applied Cryptography" ,
+1996, J. Wiley & Sons, Inc.
diff --git a/man/2/crypt-crypt b/man/2/crypt-crypt
new file mode 100644
index 00000000..5d079ca4
--- /dev/null
+++ b/man/2/crypt-crypt
@@ -0,0 +1,142 @@
+.TH CRYPT-CRYPT 2
+.SH NAME
+crypt: aessetup, aescbc, dessetup, descbc, desecb, ideasetup, ideacbc, ideaecb \- data encryption
+.SH SYNOPSIS
+.EX
+include "ipints.m";
+include "crypt.m";
+crypt := load Crypt Crypt->PATH;
+
+Encrypt: con 0;
+Decrypt: con 1;
+
+AESbsize: con 16;
+
+aessetup: fn(key: array of byte, ivec: array of byte): ref AESstate;
+aescbc: fn(state: ref AESstate, buf: array of byte,
+ n: int, direction: int);
+
+BFbsize: con 8;
+
+blowfishsetup: fn(key: array of byte, ivec: array of byte): ref BFstate;
+blowfishcbc: fn(state: ref BFstate, buf: array of byte,
+ n: int, direction: int);
+
+DESbsize: con 8;
+
+dessetup: fn(key: array of byte, ivec: array of byte): ref DESstate;
+descbc: fn(state: ref DESstate, buf: array of byte,
+ n: int, direction: int);
+desecb: fn(state: ref DESstate, buf: array of byte,
+ n: int, direction: int);
+
+IDEAbsize: con 8;
+
+ideasetup: fn(key: array of byte, ivec: array of byte): ref IDEAstate;
+ideacbc: fn(state: ref IDEAstate, buf: array of byte,
+ n: int, direction: int);
+ideaecb: fn(state: ref IDEAstate, buf: array of byte,
+ n: int, direction: int);
+.EE
+.SH DESCRIPTION
+These functions encrypt and decrypt blocks of data using different
+encryption algorithms.
+The interfaces are similar.
+.PP
+Each algorithm has an adt that holds the current state for a given encryption.
+It is produced by the setup function for the algorithm,
+.IB alg setup ,
+which is given a secret
+.I key
+and an initialisation vector
+.IR ivec .
+A sequence of blocks of data can then be encrypted or decrypted by repeatedly calling
+.IB alg cbc
+(for `cipher block chaining'), or
+.IB alg ebc
+(the less secure `electronic code book', if provided).
+On each call,
+.I buf
+provides
+.I n
+bytes of the data to encrypt or decrypt.
+.I N
+must be a multiple of the encryption block size
+.IB ALG bsize .
+Exceptionally,
+.B aescbc
+allows
+.I n
+to be other than a multiple of
+.B AESbsize
+in length, but then
+for successful decryption, the decryptor must use the same
+sequence of buffer sizes as the encryptor.
+.I Direction
+is the constant
+.B Encrypt
+or
+.B Decrypt
+as required.
+.I State
+maintains the encryption state, initially produced by the setup function,
+and updated as each buffer is encrypted or decrypted.
+.PP
+The algorithms currently available are:
+.TP
+.B aes
+The Advanced Encryption Standard, AES (also known as Rijndael).
+The
+.I key
+should be 16, 24 or 32 bytes long (128, 192 or 256 bits).
+.I Ivec
+should be
+.B AESbsize
+bytes of random data: random enough to be unlikely to be reused but
+not cryptographically strongly unpredictable.
+.TP
+.B blowfish
+Bruce Schneier's symmetric block cipher.
+The
+.I key
+is any length from 4 to 56 bytes.
+.I Ivec
+if non-nil is
+.B BFbsize
+bytes of random data.
+For
+.BR blowfishcbc ,
+.I n
+must be a multiple of
+.BR BFbsize .
+.TP
+.B des
+The older Data Encryption Standard, DES.
+.I Key
+is 8 bytes (64 bits), containing a 56-bit key
+encoded into 64 bits where every eighth bit is parity.
+.I Ivec
+is
+.B DESbsize
+bytes of random data.
+.TP
+.B idea
+The International Data Encryption Standard, IDEA™.
+The
+.I key
+is 16 bytes long (128 bits).
+.I Ivec
+is
+.B IDEAbsize
+bytes of random data.
+.SH SEE ALSO
+.IR crypt-intro (2),
+.IR crypt-rc4 (2),
+.IR security-random (2)
+.PP
+IDEA was patented by Ascom-Tech AG (EP 0 482 154 B1, US005214703),
+currently held by iT_SEC Systec Ltd.
+At time of writing, there was no licence fee required for noncommercial use
+but check
+the current licensing policy of iT_SEC Systec Ltd,
+especially for commercial use.
diff --git a/man/2/crypt-dsagen b/man/2/crypt-dsagen
new file mode 100644
index 00000000..7ccedc16
--- /dev/null
+++ b/man/2/crypt-dsagen
@@ -0,0 +1,94 @@
+.TH CRYPT-DSAGEN 2
+.SH NAME
+crypt: dsagen, eggen, rsagen, rsafill, rsaencrypt, rsadecrypt \- specific public key systems
+.SH SYNOPSIS
+.EX
+include "ipints.m";
+ipints := load IPints IPints->PATH;
+IPint: import ipints;
+
+include "crypt.m";
+crypt := load Crypt Crypt->PATH;
+
+dsagen: fn(oldpk: ref PK.DSA): ref SK.DSA;
+
+eggen: fn(nlen: int, nrep: int): ref SK.Elgamal;
+
+rsagen: fn(nlen: int, elen: int, nrep: int): ref SK.RSA;
+rsafill: fn(n: ref IPint, ek: ref IPint, dk: ref IPint,
+ p: ref IPint, q: ref IPint): ref SK.RSA;
+rsaencrypt: fn(k: ref PK.RSA, m: ref IPint): ref IPint;
+rsadecrypt: fn(k: ref SK.RSA, m: ref IPint): ref IPint;
+.EE
+.SH DESCRIPTION
+.IR Crypt-gensk (2)
+describes a set of functions that generate public/private key pairs given an algorithm name
+and a key length.
+Some key types allow further parameters for key generation or support further operations.
+.PP
+.B Dsagen
+generates a DSA public/private key pair, represented by the pick adt
+.BR SK.DSA ,
+and compatible with the containing type
+.BR SK .
+If the parameter
+.B oldpk
+is not nil,
+.B dsagen
+takes the new key's modulus and group order from the existing key;
+otherwise it generates a new pair of primes.
+.PP
+.B Eggen
+generates a new El-Gamal key pair, represented by the pick adt
+.BR SK.Elgamal .
+.I Nlen
+is the length of the modulus;
+.I nrep
+is the number of repetitions of the Miller-Rabin primality test (0 gives the default, currently 18).
+.PP
+.B Rsagen
+generates an RSA public/private key pair, represented by the pick adt
+.BR SK.RSA ,
+and compatible with the containing type
+.BR SK .
+.I Nlen
+gives the length of the key modulus in bits;
+.I elen
+gives the exponent length in bits; and
+.I nrep
+is as above.
+.PP
+The RSA private key representation used by Inferno includes some extra values to speed computation.
+.B Rsagen
+provides those values but keys imported from other systems might not.
+Given the essential set of RSA private key parameters for a given key, represented as IPints,
+.B rsafill
+returns a suitable
+.B SK.RSA
+for that key, including the extra values.
+.PP
+The public key of type
+.B PK.RSA
+can be extracted from a given private key value
+.I sk
+by referencing the field
+.BI sk .pk .
+.PP
+.B Rsaencrypt
+encrypts a message
+.IR m ,
+represented by an IPint,
+using the public key
+.IR pk .
+.PP
+.B Rsadecrypt
+decrypts
+.I m
+using private key
+.IR sk .
+The result is again returned as an IPint.
+.SH SEE ALSO
+.IR crypt-gensk (2),
+.IR crypt-sha1 (2),
+.IR security-auth (2),
+.IR security-oldauth (2)
diff --git a/man/2/crypt-gensk b/man/2/crypt-gensk
new file mode 100644
index 00000000..df51b4ee
--- /dev/null
+++ b/man/2/crypt-gensk
@@ -0,0 +1,159 @@
+.TH CRYPT-GENSK 2
+.SH NAME
+crypt: genSK, genSKfromPK, sktopk, dhparams, sign, verify \- generate keys and digital signatures
+.SH SYNOPSIS
+.EX
+include "ipints.m";
+ipints := load IPints IPints->PATH;
+IPint: import ipints;
+
+include "crypt.m";
+crypt := load Crypt Crypt->PATH;
+
+PK: adt
+{
+ pick {
+ RSA =>
+ n: ref IPint; # modulus
+ ek: ref IPint; # exp (encryption key)
+ Elgamal =>
+ p: ref IPint; # modulus
+ alpha: ref IPint; # generator
+ key: ref IPint; # encryption key (alpha**secret mod p)
+ DSA =>
+ p: ref IPint; # modulus
+ q: ref IPint; # group order, q divides p-1
+ alpha: ref IPint; # group generator
+ key: ref IPint; # encryption key (alpha**secret mod p)
+ }
+};
+
+SK: adt
+{
+ pick {
+ RSA =>
+ pk: ref PK.RSA;
+ dk: ref IPint; # exp (decryption key)
+ p: ref IPint; # q in pkcs
+ q: ref IPint; # p in pkcs
+ # precomputed crt values
+ kp: ref IPint; # k mod p-1
+ kq: ref IPint; # k mod q-1
+ c2: ref IPint; # for converting residues to number
+ Elgamal =>
+ pk: ref PK.Elgamal;
+ secret: ref IPint; # decryption key
+ DSA =>
+ pk: ref PK.DSA;
+ secret: ref IPint; # decryption key
+ }
+};
+
+PKsig: adt
+{
+ pick {
+ RSA =>
+ n: ref IPint;
+ Elgamal =>
+ r: ref IPint;
+ s: ref IPint;
+ DSA =>
+ r: ref IPint;
+ s: ref IPint;
+ }
+};
+
+genSK: fn(algname: string, length: int): ref SK;
+genSKfromPK: fn(pk: ref PK): ref SK;
+sktopk: fn(sk: ref SK): ref PK;
+
+sign: fn(sk: ref SK, m: ref IPint): ref PKsig;
+verify: fn(pk: ref PK, sig: ref PKsig, m: ref IPint): int;
+
+dhparams: fn(nbits: int): (ref IPint, ref IPint);
+.EE
+.SH DESCRIPTION
+.B Crypt
+implements a set of public-key signature algorithms.
+The public/private key pairs are represented by values of the adt
+.BR SK ,
+containing both the private (secret) and public parts of the pair,
+and
+.BR PK ,
+containing only the public part.
+The several algorithms are represented by different pick variants.
+.PP
+.B GenSK
+generates a new public/private key pair, represented by
+.BR SK .
+.I Algname
+is the name of the algorithm to use; in the current implementation,
+.BR dsa ,
+.B elgamal
+and
+.B rsa
+are possible.
+.I Length
+gives the length of the key modulus in bits.
+.B GenSK
+returns nil if an unknown algorithm has been specified.
+.PP
+.B GenSKfromPK
+generates a private key that has the system parameters as the public key
+.IR pk .
+It is used to generate new keys that are of the same complexity as old keys.
+.PP
+.B Sktopk
+returns a reference to the public part of private key
+.IR sk .
+.PP
+.B Sign
+creates a digital signature of a message
+.IR m ,
+represented by an IPint,
+using the private key
+.IR sk .
+Typically
+.I m
+represents a secure hash (eg, using
+.IR crypt-sha1 (2))
+of a much larger message.
+.PP
+.B Verify
+uses public key
+.I pk
+to verify that the value
+.I sig
+is a digital signature of the message
+.I m
+using the private key corresponding to
+.IR pk .
+It returns non-zero (true) if the signature is valid; zero (false) otherwise.
+.PP
+Most applications use generic operations on public and private keys,
+referring to
+.B PK
+and
+.BR SK ,
+but specific variants can be named, such as
+.BR PK.RSA
+for RSA keys, allowing use of RSA-specific operations.
+.IR Crypt-dsagen (2)
+describes functions for key generation that are specific to various algorithms,
+using algorithm-specific parameters.
+.PP
+.B Dhparams
+creates Diffie-Hellman parameters. It returns
+a tuple of IPints
+.RI ( alpha , p ).
+.I P
+is an
+.I nbits
+long prime number that serves as the modulus.
+.I Alpha
+is a primitive root in the integer field defined by that modulus.
+.SH SEE ALSO
+.IR crypt-dsagen (2),
+.IR crypt-sha1 (2),
+.IR security-auth (2),
+.IR security-oldauth (2)
diff --git a/man/2/crypt-rc4 b/man/2/crypt-rc4
new file mode 100644
index 00000000..8f04705e
--- /dev/null
+++ b/man/2/crypt-rc4
@@ -0,0 +1,49 @@
+.TH CRYPT-RC4 2
+.SH NAME
+crypt: rc4setup, rc4, rc4skip, rc4back \- RC4 encryption
+.SH SYNOPSIS
+.EX
+include "ipints.m";
+ipints := load IPints IPints->PATH;
+IPint: import ipints;
+
+include "crypt.m";
+crypt := load Crypt Crypt->PATH;
+
+rc4setup: fn(seed: array of byte): ref RC4state;
+rc4: fn(state: ref RC4state, buf: array of byte, n: int);
+rc4skip: fn(state: ref RC4state, n: int);
+rc4back: fn(state: ref RC4state, n: int);
+.EE
+.SH DESCRIPTION
+These functions implement the stream encryption algorithm that is claimed to
+be equivalent to RSA Security's RC4.
+It is a pseudo-random number generator with a 256
+byte state and a long cycle.
+.PP
+.B Rc4setup
+sets the initial
+.IR seed ,
+which can be any non-zero length, and
+returns a representation of the initial state of the algorithm,
+which is used in subsequent calls.
+.PP
+.B Rc4
+runs the generator starting with the given
+.IR state ,
+and XORs the output of the generator with
+the first
+.I n
+bytes of
+.IR buf ,
+updating the
+.IR state .
+.B Rc4
+is symmetric and is used both to encrypt and decrypt.
+.B Rc4skip
+skips over bytes (eg, to account for lost transmissions);
+.B rc4back
+runs the generator backwards (eg, to account for retransmissions).
+.SH SEE ALSO
+.IR crypt-intro (2),
+.IR crypt-crypt (2)
diff --git a/man/2/crypt-sha1 b/man/2/crypt-sha1
new file mode 100644
index 00000000..adfe763a
--- /dev/null
+++ b/man/2/crypt-sha1
@@ -0,0 +1,144 @@
+.TH CRYPT-SHA1 2
+.SH NAME
+crypt: sha1, sha224, sha256, sha384, sha512, md4, md5, hmac_sha1, hmac_md5 \- cryptographic digests
+.SH SYNOPSIS
+.EX
+include "ipints.m";
+ipints := load IPints IPints->PATH;
+IPint: import ipints;
+
+include "crypt.m";
+crypt := load Crypt Crypt->PATH;
+
+DigestState: adt
+{
+ # hidden state
+ copy: fn(d: self ref DigestState): ref DigestState;
+};
+
+.ta \w'verify:\ 'u +\w'fn(\ \ \ 'u
+sha1: fn(buf: array of byte, n: int, digest: array of byte,
+ state: ref DigestState): ref DigestState;
+sha224: fn(buf: array of byte, n: int, digest: array of byte,
+ state: ref DigestState): ref DigestState;
+sha256: fn(buf: array of byte, n: int, digest: array of byte,
+ state: ref DigestState): ref DigestState;
+sha384: fn(buf: array of byte, n: int, digest: array of byte,
+ state: ref DigestState): ref DigestState;
+sha512: fn(buf: array of byte, n: int, digest: array of byte,
+ state: ref DigestState): ref DigestState;
+md4: fn(buf: array of byte, n: int, digest: array of byte,
+ state: ref DigestState): ref DigestState;
+md5: fn(buf: array of byte, n: int, digest: array of byte,
+ state: ref DigestState): ref DigestState;
+
+SHA1dlen, SHA224dlen, SHA256dlen, SHA384dlen, SHA512dlen, MD4dlen, MD5dlen: con ...;
+
+hmac_sha1: fn(buf: array of byte, n: int, key: array of byte,
+ digest: array of byte,
+ state: ref DigestState): ref DigestState;
+hmac_md5: fn(buf: array of byte, n: int, key: array of byte,
+ digest: array of byte,
+ state: ref DigestState): ref DigestState;
+.EE
+.SH DESCRIPTION
+.BR Sha1 ,
+.BR sha224 ,
+.BR sha256 ,
+.BR sha384 ,
+.BR sha512 ,
+.B md4
+and
+.B md5
+are cryptographically secure hash functions that produce output called a message digest.
+Each function computes a hash of
+.I n
+bytes of the data in
+.IR buf ,
+using the named algorithm,
+and updates the current
+.IR state .
+They can be called iteratively to form a single digest for many data blocks.
+The state is kept in the
+.B DigestState
+value referenced by
+.I state
+between calls.
+.I State
+should be
+.B nil
+on the first call, and a newly allocated
+.B DigestState
+will be returned for use in subsequent calls.
+On a call in which
+.I digest
+is not
+.BR nil ,
+the hash is completed and copied into the
+.I digest
+array.
+.B Sha1
+produces a 20-byte hash
+.RB ( SHA1dlen ),
+.B sha224
+a 28-byte hash
+.RB ( SHA224dlen ),
+.B sha256
+a 32-byte hash
+.RB ( SHA256dlen ),
+.B sha384
+a 48-byte hash
+.RB ( SHA384dlen ),
+.B sha256
+a 64-byte hash
+.RB ( SHA512dlen ),
+.B md4
+and
+.B md5
+a 16-byte one
+.RB ( MD4len
+and
+.BR MD5len ).
+.PP
+.B Hmac_sha1
+and
+.B hmac_md5
+are keyed versions of the hashing functions, following Internet RFC2104.
+The
+.I key
+must be provided in each call, but otherwise
+the calling conventions are those of
+.BR sha1 .
+The
+.I key
+must currently be no more than 64 bytes.
+.PP
+.B DigestState
+hides the state of partially completed hash functions during processing.
+Its
+.B copy
+operation returns a reference to a new copy of a given state.
+.SH EXAMPLES
+A program to read a file and hash it using SHA might contain the following inner loop:
+.IP
+.EX
+state: ref DigestState = nil;
+while((n := sys->read(fd, buf, len buf)) > 0)
+ state = kr->sha1(buf, n, nil, state);
+digest := array[kr->SHA1dlen] of byte;
+kr->sha1(buf, 0, digest, state);
+.EE
+.SH SOURCE
+.B /libinterp/crypt.c
+.br
+.B /libsec/port/hmac.c
+.br
+.B /libsec/port/md4.c
+.br
+.B /libsec/port/md5.c
+.br
+.B /libsec/port/sha1.c
+.SH BUGS
+The MD4 algorithm is included only to allow communication with software
+that might still use it; it should not otherwise be used now, because it
+is easily broken.
diff --git a/man/2/ipints b/man/2/ipints
new file mode 100644
index 00000000..2d4bdb8b
--- /dev/null
+++ b/man/2/ipints
@@ -0,0 +1,193 @@
+.TH IPINTS 2
+.SH NAME
+ipints: IPint \- `infinite' precision integer utility functions
+.SH SYNOPSIS
+.EX
+include "ipints.m"
+ipints:= load IPints IPints->PATH;
+
+IPint: adt
+{
+ iptob64: fn(i: self ref IPint): string;
+ iptob64z: fn(i: self ref IPint): string;
+ b64toip: fn(str: string) : ref IPint;
+ iptobytes: fn(i: self ref IPint): array of byte;
+ bytestoip: fn(buf: array of byte): ref IPint;
+ iptobebytes: fn(i: self ref IPint): array of byte;
+ bebytestoip: fn(buf: array of byte): ref IPint;
+ inttoip: fn(i: int): ref IPint;
+ iptoint: fn(i: self ref IPint): int;
+ iptostr: fn(i: self ref IPint, base: int): string;
+ strtoip: fn(str: string, base: int): ref IPint;
+ random: fn(nbits: int): ref IPint;
+ copy: fn(i: self ref IPint): ref IPint;
+ bits: fn(i: self ref IPint): int;
+ expmod: fn(base: self ref IPint, exp, mod: ref IPint):ref IPint;
+ add: fn(i1: self ref IPint, i2: ref IPint): ref IPint;
+ sub: fn(i1: self ref IPint, i2: ref IPint): ref IPint;
+ neg: fn(i: self ref IPint): ref IPint;
+ mul: fn(i1: self ref IPint, i2: ref IPint): ref IPint;
+ div: fn(i1: self ref IPint, i2: ref IPint): (ref IPint, ref IPint);
+ mod: fn(i1: self ref IPint, i2: ref IPint): ref IPint;
+ eq: fn(i1: self ref IPint, i2: ref IPint): int;
+ cmp: fn(i1: self ref IPint, i2: ref IPint): int;
+ shl: fn(i: self ref IPint, n: int): ref IPint;
+ shr: fn(i: self ref IPint, n: int): ref IPint;
+ and: fn(i1: self ref IPint, i2: ref IPint): ref IPint;
+ ori: fn(i1: self ref IPint, i2: ref IPint): ref IPint;
+ not: fn(i: self ref IPint): ref IPint;
+ xor: fn(i1: self ref IPint, i2: ref IPint): ref IPint;
+};
+.EE
+.SH DESCRIPTION
+.B IPint
+provides the following arbitrary-length integer manipulation functions required for cryptographic support in Limbo:
+.TP
+.IB i .iptob64()
+Returns a string that represents a large integer textually in base 64 for convenient transmission over a network connection.
+.TP
+.IB i .iptob64z()
+Returns a similar representation to
+.B iptob64
+but ensures that the top bit of the received value is zero.
+.TP
+.BI b64toip( str )
+Returns the
+.B IPint
+represented by the base-64 encoded
+.IR str .
+.TP
+.IB i .iptobytes()
+Returns an array of bytes representing a large integer. The representation includes both positive and negative numbers.
+.TP
+.BI bytestoip( buf )
+The inverse operation of
+.BR iptobytes .
+.TP
+.IB i .iptobebytes()
+Returns an array of bytes in big-endian format representing the magnitude of a large integer; used for instance to pass a value to
+.IR ssl (3).
+Only non-negative numbers are represented.
+.TP
+.BI bebytestoip( buf )
+The inverse operation of
+.BR iptobebytes .
+.TP
+.BI inttoip( i )
+Creates a new large integer from integer
+.IR i .
+.TP
+.IB i .iptoint()
+Converts a large integer
+.I i
+to an
+.BR int ;
+returns 0 on error.
+.TP
+.IB i .iptostr( base )
+Converts a large integer to a string in base
+.IR base ;
+returns nil on error.
+Only the bases 10, 16, 32, and 64 are
+supported. Anything else defaults to 16.
+.TP
+.BI strtoip( str , base )
+Converts a string
+.I str
+representing a number in in base
+.I base
+to a large integer; returns nil on error.
+Only the bases 10, 16, 32, and 64 are
+supported.
+.TP
+.BI random( nbits )
+Returns a large random number of length at most
+.IR minbits .
+The largest number allowed in the current implementation is
+2^8192-1 .
+The seed for the generator is obtained by duelling clocks.
+.TP
+.IB i .copy()
+Returns a reference to the same value as
+.IR i .
+.TP
+.IB i .bits()
+Returns the number of bits of precision of
+.IR i .
+.TP
+.IB base .expmod( "exp , mod" )
+Returns
+.BI ( base ** exp ") mod " mod.
+.TP
+.IB i1 .add( i2 )
+Returns
+.RI ( i1 + i2 ).
+.TP
+.IB i1 .sub( i2 )
+Returns
+.RI ( i1 - i2 ).
+.TP
+.IB i1 .mul ( i2 )
+Returns
+.IR i1*i2 .
+.TP
+.IB i1 .div ( i2 )
+Returns
+.RI ( i1 / i2,
+.IR i1 rem i2 ).
+.TP
+.IB i1 .mod ( i2 )
+Returns
+.RI ( i1 mod i2 ).
+.TP
+.IB i1 .eq( i2 )
+Returns 1 if
+.I i1
+and
+.I i2
+are equal; 0 otherwise.
+.TP
+.IB i1 .cmp( i2 )
+Compares two large integers, returning 1 if
+.I i1
+is larger,
+-1 if
+.I i2
+is larger, and 0 if they are equal.
+.TP
+.IB i .shl( n )
+Returns
+.IR i << n
+.TP
+.IB i .shr( n )
+Returns
+.IR i >> n
+.TP
+.IB i1 .and( i2 )
+Returns
+.IR i & n ,
+bitwise AND
+.TP
+.IB i1 .ori( i2 )
+Returns
+.IR i | n ,
+bitwise inclusive-OR
+(it is
+.B ori
+because plain
+.B or
+is a Limbo keyword)
+.TP
+.IB i .not()
+Returns
+.RI ~ i ,
+bitwise ones-complement
+.TP
+.IB i1 .xor( i2 )
+Returns
+.IR i ^ n ,
+bitwise exclusive-OR
+.SH SOURCE
+.B /libinterp/ipint.c
+.br
+.B /libmp
diff --git a/man/2/ipints-genprime b/man/2/ipints-genprime
new file mode 100644
index 00000000..5ec5f66c
--- /dev/null
+++ b/man/2/ipints-genprime
@@ -0,0 +1,112 @@
+.TH IPINTS-GENPRIME 2
+.SH NAME
+ipints: genprime, gensafeprime, genstrongprime, DSAprimes, probably_prime \- prime number generation
+.SH SYNOPSIS
+.EX
+include "ipints.m";
+ipints := load IPints IPints->PATH;
+IPint: import ipints;
+
+probably_prime: fn(n: ref IPint, nrep: int): int;
+
+genprime: fn(nbits: int, nrep: int): ref IPint;
+gensafeprime: fn(nbits: int, nrep: int): (ref IPint, ref IPint); # p, alpha
+genstrongprime: fn(nbits: int, nrep: int): ref IPint;
+DSAprimes: fn(): (ref IPint, ref IPint, array of byte); # q, p, seed
+.EE
+.SH DESCRIPTION
+This set of functions in
+.B IPints
+(see
+.IR ipints (2))
+helps Limbo applications
+generate and test large prime numbers with relative efficiency.
+The numbers are all represented by
+.BR IPint .
+.PP
+.I Probably_prime
+uses the Miller-Rabin test to test
+.IR n .
+It returns true (non-zero) if
+.I P
+is probably prime. The probability of
+.I n
+not being prime is
+1/4**\fInrep\fR.
+If
+.I probably_prime
+returns false (zero),
+.I n
+is certainly not prime.
+.PP
+.I Genprime
+returns a random prime of length
+.IR nbits .
+Since it uses the Miller-Rabin test,
+.I nrep
+is the repetition count passed to
+.IR probably_prime .
+.PP
+.I Gensafeprime
+returns a tuple
+.BI ( p,\ alpha ),
+where
+.I p
+is a prime of length
+.I nbits
+and
+.I alpha
+is a generator of the multiplicative group of integers mod \fIp\fR;
+there is a prime \fIq\fR such that \fIp-1=2*q\fR.
+.PP
+.I Genstrongprime
+returns a prime
+.I p
+with the following properties:
+.IP \-
+(\fIp\fR-1)/2 is prime. Therefore
+.IR p -1
+has a large prime factor,
+.IR p '.
+.IP \-
+.IR p '-1
+has a large prime factor
+.IP \-
+.IR p +1
+has a large prime factor
+.PP
+.I DSAprimes
+uses the NIST recommended algorithm for generating DSA primes and
+returns a tuple
+.BI ( q,\ p,\ seed ) ,
+where
+.I p
+and
+.I q
+are primes, and
+.I q
+divides
+.IR p -1.
+The random
+.I seed
+used is also returned, so that sceptics
+can later confirm the computation.
+.SH SOURCE
+.B /libinterp/ipint.c
+.br
+.B /libsec/port/probably_prime.c
+.br
+.B /libsec/port/dsaprimes.c
+.br
+.B /libsec/port/genprime.c
+.br
+.B /libsec/port/gensafeprime.c
+.br
+.B /libsec/port/genstrongprime.c
+.br
+.SH SEE ALSO
+.IR crypt-intro (2),
+.IR crypt-crypt (2),
+.IR crypt-dsagen (2),
+.IR crypt-gensk (2),
+.IR ipints (2)
diff --git a/module/crypt.m b/module/crypt.m
new file mode 100644
index 00000000..db344d08
--- /dev/null
+++ b/module/crypt.m
@@ -0,0 +1,191 @@
+#
+# basic cryptography routines implemented in C
+#
+Crypt: module
+{
+ PATH: con "$Crypt";
+
+ # state held while creating digests
+ DigestState: adt
+ {
+ x: int; # dummy for C compiler for runt.h
+ # all the state is hidden
+
+ copy: fn(d: self ref DigestState): ref DigestState;
+ };
+
+ # expanded AES key + state for chaining
+ AESstate: adt
+ {
+ x: int; # dummy for C compiler for runt.h
+ # all the state is hidden
+ };
+
+ # expanded DES key + state for chaining
+ DESstate: adt
+ {
+ x: int; # dummy for C compiler for runt.h
+ # all the state is hidden
+ };
+
+ # expanded IDEA key + state for chaining
+ IDEAstate: adt
+ {
+ x: int; # dummy for C compiler for runt.h
+ # all the state is hidden
+ };
+
+ # expanded RC4 key + encryption state
+ RC4state: adt
+ {
+ x: int; # dummy for C compiler for runt.h
+ # all the state is hidden
+ };
+
+ # expanded Blowfish key + state for chaining
+ BFstate: adt
+ {
+ x: int; # dummy for C compiler for runt.h
+ # all the state is hidden
+ };
+
+ # digests
+ sha1: fn(buf: array of byte, n: int, digest: array of byte, state: ref DigestState):
+ ref DigestState;
+ sha224: fn(buf: array of byte, n: int, digest: array of byte, state: ref DigestState):
+ ref DigestState;
+ sha256: fn(buf: array of byte, n: int, digest: array of byte, state: ref DigestState):
+ ref DigestState;
+ sha384: fn(buf: array of byte, n: int, digest: array of byte, state: ref DigestState):
+ ref DigestState;
+ sha512: fn(buf: array of byte, n: int, digest: array of byte, state: ref DigestState):
+ ref DigestState;
+ md4: fn(buf: array of byte, n: int, digest: array of byte, state: ref DigestState):
+ ref DigestState;
+ md5: fn(buf: array of byte, n: int, digest: array of byte, state: ref DigestState):
+ ref DigestState;
+
+ hmac_sha1: fn(data: array of byte, n: int, key: array of byte, digest: array of byte, state: ref DigestState):
+ ref DigestState;
+ hmac_md5: fn(data: array of byte, n: int, key: array of byte, digest: array of byte, state: ref DigestState):
+ ref DigestState;
+
+ SHA1dlen: con 20;
+ SHA224dlen: con 28;
+ SHA256dlen: con 32;
+ SHA384dlen: con 48;
+ SHA512dlen: con 64;
+ MD5dlen: con 16;
+ MD4dlen: con 16;
+
+ # encryption interfaces
+ Encrypt: con 0;
+ Decrypt: con 1;
+
+ AESbsize: con 16;
+
+ aessetup: fn(key: array of byte, ivec: array of byte): ref AESstate;
+ aescbc: fn(state: ref AESstate, buf: array of byte, n: int, direction: int);
+
+ DESbsize: con 8;
+
+ dessetup: fn(key: array of byte, ivec: array of byte): ref DESstate;
+ desecb: fn(state: ref DESstate, buf: array of byte, n: int, direction: int);
+ descbc: fn(state: ref DESstate, buf: array of byte, n: int, direction: int);
+
+ IDEAbsize: con 8;
+
+ ideasetup: fn(key: array of byte, ivec: array of byte): ref IDEAstate;
+ ideaecb: fn(state: ref IDEAstate, buf: array of byte, n: int, direction: int);
+ ideacbc: fn(state: ref IDEAstate, buf: array of byte, n: int, direction: int);
+
+ BFbsize: con 8;
+
+ blowfishsetup: fn(key: array of byte, ivec: array of byte): ref BFstate;
+# blowfishecb: fn(state: ref BFstate, buf: array of byte, n: int, direction: int);
+ blowfishcbc: fn(state: ref BFstate, buf: array of byte, n: int, direction: int);
+
+ rc4setup: fn(seed: array of byte): ref RC4state;
+ rc4: fn(state: ref RC4state, buf: array of byte, n: int);
+ rc4skip: fn(state: ref RC4state, n: int);
+ rc4back: fn(state: ref RC4state, n: int);
+
+ # create an alpha and p for diffie helman exchanges
+ dhparams: fn(nbits: int): (ref IPints->IPint, ref IPints->IPint);
+
+ # public key
+ PK: adt
+ {
+ pick {
+ RSA =>
+ n: ref IPints->IPint; # modulus
+ ek: ref IPints->IPint; # exp (encryption key)
+ Elgamal =>
+ p: ref IPints->IPint; # modulus
+ alpha: ref IPints->IPint; # generator
+ key: ref IPints->IPint; # encryption key (alpha**secret mod p)
+ DSA =>
+ p: ref IPints->IPint; # modulus
+ q: ref IPints->IPint; # group order, q divides p-1
+ alpha: ref IPints->IPint; # group generator
+ key: ref IPints->IPint; # encryption key (alpha**secret mod p)
+ }
+ };
+
+ # secret key (private/public key pair)
+ SK: adt
+ {
+ pick {
+ RSA =>
+ pk: ref PK.RSA;
+ dk: ref IPints->IPint; # exp (decryption key)
+ p: ref IPints->IPint; # q in pkcs
+ q: ref IPints->IPint; # p in pkcs
+ # precomputed crt values
+ kp: ref IPints->IPint; # k mod p-1
+ kq: ref IPints->IPint; # k mod q-1
+ c2: ref IPints->IPint; # for converting residues to number
+ Elgamal =>
+ pk: ref PK.Elgamal;
+ secret: ref IPints->IPint; # decryption key
+ DSA =>
+ pk: ref PK.DSA;
+ secret: ref IPints->IPint; # decryption key
+ }
+ };
+
+ # public key signature
+ PKsig: adt
+ {
+ # could just have list or array of ref IPints->IPint
+ pick {
+ RSA =>
+ n: ref IPints->IPint;
+ Elgamal =>
+ r: ref IPints->IPint;
+ s: ref IPints->IPint;
+ DSA =>
+ r: ref IPints->IPint;
+ s: ref IPints->IPint;
+ }
+ };
+
+ # RSA keys
+ rsagen: fn(nlen: int, elen: int, nrep: int): ref SK.RSA;
+ rsafill: fn(n: ref IPints->IPint, ek: ref IPints->IPint, dk: ref IPints->IPint, p: ref IPints->IPint, q: ref IPints->IPint): ref SK.RSA;
+ rsadecrypt: fn(k: ref SK.RSA, m: ref IPints->IPint): ref IPints->IPint;
+ rsaencrypt: fn(k: ref PK.RSA, m: ref IPints->IPint): ref IPints->IPint;
+
+ # Elgamal
+ eggen: fn(nlen: int, nrep: int): ref SK.Elgamal;
+
+ # DSA
+ dsagen: fn(oldpk: ref PK.DSA): ref SK.DSA;
+
+ # generic signature functions
+ genSK: fn(algname: string, length: int): ref SK;
+ genSKfromPK: fn(pk: ref PK): ref SK;
+ sign: fn(sk: ref SK, m: ref IPints->IPint): ref PKsig;
+ verify: fn(pk: ref PK, sig: ref PKsig, m: ref IPints->IPint): int;
+ sktopk: fn(sk: ref SK): ref PK;
+};
diff --git a/module/ipints.m b/module/ipints.m
new file mode 100644
index 00000000..443b9f4e
--- /dev/null
+++ b/module/ipints.m
@@ -0,0 +1,57 @@
+IPints: module
+{
+ PATH: con "$IPints";
+
+ # infinite precision integers
+ IPint: adt
+ {
+ x: int; # dummy for C compiler for runt.h
+
+ # conversions
+ iptob64: fn(i: self ref IPint): string;
+ iptob64z: fn(i: self ref IPint): string;
+ b64toip: fn(str: string): ref IPint;
+ iptobytes: fn(i: self ref IPint): array of byte;
+ iptobebytes: fn(i: self ref IPint): array of byte;
+ bytestoip: fn(buf: array of byte): ref IPint;
+ bebytestoip: fn(mag: array of byte): ref IPint;
+ inttoip: fn(i: int): ref IPint;
+ iptoint: fn(i: self ref IPint): int;
+ iptostr: fn(i: self ref IPint, base: int): string;
+ strtoip: fn(str: string, base: int): ref IPint;
+
+ # create a random large integer
+ random: fn(nbits: int): ref IPint;
+
+ # operations
+ bits: fn(i: self ref IPint): int;
+ expmod: fn(base: self ref IPint, exp, mod: ref IPint): ref IPint;
+ invert: fn(base: self ref IPint, mod: ref IPint): ref IPint;
+ add: fn(i1: self ref IPint, i2: ref IPint): ref IPint;
+ sub: fn(i1: self ref IPint, i2: ref IPint): ref IPint;
+ neg: fn(i: self ref IPint): ref IPint;
+ mul: fn(i1: self ref IPint, i2: ref IPint): ref IPint;
+ div: fn(i1: self ref IPint, i2: ref IPint): (ref IPint, ref IPint);
+ mod: fn(i1: self ref IPint, i2: ref IPint): ref IPint;
+ eq: fn(i1: self ref IPint, i2: ref IPint): int;
+ cmp: fn(i1: self ref IPint, i2: ref IPint): int;
+ copy: fn(i: self ref IPint): ref IPint;
+
+ # shifts
+ shl: fn(i: self ref IPint, n: int): ref IPint;
+ shr: fn(i: self ref IPint, n: int): ref IPint;
+
+ # bitwise
+ and: fn(i1: self ref IPint, i2: ref IPint): ref IPint;
+ ori: fn(i1: self ref IPint, i2: ref IPint): ref IPint;
+ xor: fn(i1: self ref IPint, i2: ref IPint): ref IPint;
+ not: fn(i1: self ref IPint): ref IPint;
+ };
+
+ # primes
+ probably_prime: fn(n: ref IPint, nrep: int): int;
+ genprime: fn(nbits: int, nrep: int): ref IPint;
+ genstrongprime: fn(nbits: int, nrep: int): ref IPint;
+ gensafeprime: fn(nbits: int, nrep: int): (ref IPint, ref IPint);
+ DSAprimes: fn(): (ref IPint, ref IPint, array of byte);
+};
diff --git a/module/runt.m b/module/runt.m
index 1021041a..e9d290a3 100644
--- a/module/runt.m
+++ b/module/runt.m
@@ -5,7 +5,7 @@ include "draw.m";
include "prefab.m";
include "tk.m";
include "math.m";
-include "keyring.m";
+include "ipints.m";
+include "crypt.m";
include "loader.m";
-# include "readimage.m";
include "freetype.m";
diff --git a/os/cerf1110/cerf b/os/cerf1110/cerf
index 24002405..2ef05c37 100644
--- a/os/cerf1110/cerf
+++ b/os/cerf1110/cerf
@@ -57,7 +57,9 @@ mod
sys
# draw
# tk
- keyring
+ keyring crypt
+ ipints
+
port
alarm
diff --git a/os/cerf250/cerf b/os/cerf250/cerf
index 820fba8d..57a6ed1b 100644
--- a/os/cerf250/cerf
+++ b/os/cerf250/cerf
@@ -60,7 +60,9 @@ mod
sys
# draw
# tk
- keyring
+ keyring crypt
+ ipints
+
port
alarm
diff --git a/os/cerf405/cerf b/os/cerf405/cerf
index 87e475b2..2673ed7f 100644
--- a/os/cerf405/cerf
+++ b/os/cerf405/cerf
@@ -53,7 +53,9 @@ link
mod
math
sys
- keyring
+ keyring crypt
+ ipints
+
port
alarm
diff --git a/os/fads/fads b/os/fads/fads
index 1f1a2959..ef63ee47 100644
--- a/os/fads/fads
+++ b/os/fads/fads
@@ -63,7 +63,9 @@ mod
draw
tk
math
- keyring
+ keyring crypt
+ ipints
+
port
alarm
diff --git a/os/gum/gum b/os/gum/gum
index 81748ce8..4bac086d 100644
--- a/os/gum/gum
+++ b/os/gum/gum
@@ -10,7 +10,7 @@ dev
dup
ssl
cap
- sign
+# sign
# draw screen
# pointer
@@ -59,7 +59,9 @@ mod
sys
# draw
# tk
- keyring
+ keyring crypt
+ ipints
+
port
alarm
diff --git a/os/ipaq1110/ipaq b/os/ipaq1110/ipaq
index 19559326..7fe4648e 100644
--- a/os/ipaq1110/ipaq
+++ b/os/ipaq1110/ipaq
@@ -58,7 +58,9 @@ mod
sys
draw
tk
- keyring
+ keyring crypt
+ ipints
+
port
alarm
diff --git a/os/ipengine/ipe b/os/ipengine/ipe
index 8e00c855..44b9a1d1 100644
--- a/os/ipengine/ipe
+++ b/os/ipengine/ipe
@@ -50,7 +50,9 @@ link
mod
math
sys
- keyring
+ keyring crypt
+ ipints
+
port
alarm
diff --git a/os/js/js b/os/js/js
index 16e2ff64..1e5feb6e 100644
--- a/os/js/js
+++ b/os/js/js
@@ -49,7 +49,9 @@ mod
draw
prefab
tk
- keyring
+ keyring crypt
+ ipints
+
link
pppmedium ppp compress
diff --git a/os/manga/manga b/os/manga/manga
index 725e275e..0e6a24ad 100644
--- a/os/manga/manga
+++ b/os/manga/manga
@@ -40,7 +40,9 @@ lib
mod
math
sys
- keyring
+ keyring crypt
+ ipints
+
port
alarm
diff --git a/os/pc/pc4e b/os/pc/pc4e
index 0507118c..a223eced 100644
--- a/os/pc/pc4e
+++ b/os/pc/pc4e
@@ -64,7 +64,9 @@ mod
sys
draw
tk
- keyring
+ keyring crypt
+ ipints
+
math
init
diff --git a/os/pc/pcdisk b/os/pc/pcdisk
index 4ae6338a..470a6e8e 100644
--- a/os/pc/pcdisk
+++ b/os/pc/pcdisk
@@ -73,7 +73,9 @@ mod
sys
draw
tk
- keyring
+ keyring crypt
+ ipints
+
math
init
diff --git a/os/pc/pix b/os/pc/pix
index d856cfdb..b1e0f112 100644
--- a/os/pc/pix
+++ b/os/pc/pix
@@ -68,7 +68,9 @@ mod
sys
# draw
# tk
- keyring
+ keyring crypt
+ ipints
+
math
init
diff --git a/os/rpcg/rpcg b/os/rpcg/rpcg
index c5c90ece..c2198be9 100644
--- a/os/rpcg/rpcg
+++ b/os/rpcg/rpcg
@@ -61,7 +61,9 @@ mod
# draw
# tk
math
- keyring
+ keyring crypt
+ ipints
+
port
alarm