+/* hash password into 32 bytes for chacha encryption */
+int collect_key(unsigned char *key, const char *pass) {
+ struct blake2b_state__ h;
+ if (!pass) {
+ pass = readpass("Passphrase: ");
+ }
+
+ if (!pass) {
+ return 0;
+ }
+
+ blake2b_init(&h, 32);
+ blake2b_update(&h, pass, strlen(pass));
+ blake2b_final(&h, key, 32);
+ return 1;
+}
+
+int encrypt_key(struct secret_key *sk, unsigned char *key) {
+ int i;
+
+ if (sk->encryption) {
+ return 1;
+ }
+
+ /* TODO chacha encrypt sk->key */
+ for (i=0; i < 32; i++) {
+ sk->key[i] ^= key[i];
+ }
+
+ sk->encryption = 1;
+ return 1;
+}
+
+int encrypt_sk(struct secret_key *sk, unsigned char *pass) {
+ unsigned char key[32];
+
+ if (sk->encryption == 1) {
+ return 1;
+ }
+
+ collect_key(key, pass);
+ encrypt_key(sk, key);
+
+ memset(key, 0, 32);
+ memset(pass, 0, strlen(pass));
+
+ return 1;
+}
+
+int decrypt_sk(struct secret_key *sk, unsigned char *pass) {
+ unsigned char key[32];
+ int i;
+
+ if (sk->encryption == 0) {
+ return 1;
+ }
+
+ collect_key(key, pass);
+
+ for (i=0; i < 32; i++) {
+ sk->key[i] ^= key[i];
+ }
+
+ memset(key, 0, 32);
+ memset(pass, 0, strlen(pass));
+
+ sk->encryption = 0;
+
+ return 1;
+}
+
+int decrypt_key(struct secret_key *sk, unsigned char *key) {
+ int i;
+
+ if (sk->encryption == 0) {
+ return 1;
+ }
+
+ /* TODO chacha decrypt sk->key */
+ for (i=0; i < 32; i++) {
+ sk->key[i] ^= key[i];
+ }
+
+ sk->encryption = 0;
+ return 1;
+}
+
+void pubkey_init(struct public_key *pk) {
+ memcpy(pk->magic, "ZPMS", 4);
+ pk->version = VERSION;
+ pk->type = PUBLIC_KEY;
+ pk->reserved0 = 0;
+ pk->reserved1 = 0;
+ memset(pk->key, 0, sizeof pk->key);
+ pk->created = 0;
+ pk->expires = 0;
+ memset(pk->reserved2, 0, 8);
+ memset(pk->signature, 0, 64);
+ memset(pk->id, 0, 120);
+ memset(pk->trailer, 0, 8);
+}
+
+void pubkey_bytea(unsigned char *bytes, struct public_key *pk) {
+ memset(bytes, 0, 256);
+ memcpy(bytes, "ZPMS", 4);
+ bytes[4] = pk->version;
+ bytes[5] = pk->type;
+ /* 6 7 reserved */
+ memcpy(bytes + 8, pk->key, 32);
+ putsle8(bytes+40, pk->created);
+ putsle8(bytes+48, pk->expires);
+ /* @56 8 reserved */
+ memcpy(bytes + 64, pk->signature, 64);
+ memcpy(bytes + 128, pk->id, 120);
+ /* 8 reserved */
+}
+
+void bytea_pubkey(struct public_key *pk, unsigned char *bytes) {
+ memcpy(pk->magic, bytes, 4);
+ pk->version = bytes[4];
+ pk->type = bytes[5];
+ pk->reserved0 = 0;
+ pk->reserved1 = 0;
+ memcpy(pk->key, bytes + 8, 32);
+ pk->created = getsle8(bytes+40);
+ pk->expires = getsle8(bytes+48);
+ memset(pk->reserved2, 0, 8);
+ memcpy(pk->signature, bytes + 64, 64);
+ memcpy(pk->id, bytes + 128, 120);
+ memset(pk->trailer, 0, 8);
+}
+
+int derive_pubkey(struct public_key *pk, struct secret_key *sk) {
+ char bytes[256];
+
+ memcpy(pk->magic, "ZPMS", 4);
+ pk->version = VERSION;
+ pk->type = PUBLIC_KEY;
+ pk->reserved0 = 0;
+ pk->reserved1 = 0;
+ ed25519_genpub(pk->key, sk->key);
+ pk->created = sk->created;
+ pk->expires = sk->expires;
+ memset(pk->reserved2, 0, 8);
+ memset(pk->signature, 0, 64);
+ memset(pk->id, 0, 120);
+ strncpy(pk->id, sk->id, 119);
+ memset(pk->trailer, 0, 8);
+
+ /* serialize and sign */
+ pubkey_bytea(bytes, pk);
+ ed25519_sign(pk->signature, sk->key, pk->key, bytes, 256);
+
+ return 1;
+}
+
+void bytea_signature(struct signature *sig, unsigned char *bytes) {
+ memcpy(sig->magic, bytes, 4);
+ sig->version = bytes[4];
+ sig->type = bytes[5];
+ sig->reserved0 = 0;
+ sig->reserved1 = 0;
+ memcpy(sig->key, bytes + 8, 32);
+ sig->signtime = getsle8(bytes+40);
+ sig->expires = getsle8(bytes+48);
+ memset(sig->reserved2, 0, 8);
+ memcpy(sig->signature, bytes + 64, 64);
+ memcpy(sig->reserved3, bytes + 128, 120);
+ memset(sig->trailer, 0, 8);
+}
+
+void signature_bytea(unsigned char *bytes, struct signature *sig) {
+ memset(bytes, 0, 256);
+ memcpy(bytes, "ZPMS", 4);
+ bytes[4] = sig->version;
+ bytes[5] = sig->type;
+ /* 6 7 reserved */
+ memcpy(bytes + 8, sig->key, 32);
+ putsle8(bytes+40, sig->signtime);
+ putsle8(bytes+48, sig->expires);
+ /* @56 8 reserved */
+ memcpy(bytes + 64, sig->signature, 64);
+ /* 120 reserved */
+ /* 8 reserved */
+}
+
+union signobject {
+ struct signature sig;
+ struct public_key pk;
+ struct secret_key sk;
+ char bytes[256];
+};
+
+int object_type(union signobject *obj) {
+ return obj ? obj->sk.type : 0;
+}
+
+void sighash(unsigned char *dst, struct signature *sig, unsigned char *data,
+ size_t len) {
+ unsigned char signtime[8], expires[8];
+ struct sha512 hash;
+
+ /* need to put these in as little endian */
+ putsle8(signtime, sig->signtime);
+ putsle8(expires, sig->expires);
+
+ sha512_init(&hash);
+ sha512_add(&hash, signtime, sizeof signtime);
+ sha512_add(&hash, expires, sizeof expires);
+ sha512_add(&hash, data, len);
+ sha512_final(&hash, dst);
+}
+
+void init_signature(struct signature *sig) {
+ memcpy(sig->magic, "ZPMS", 4);
+ sig->version = VERSION;
+ sig->type = SIGNATURE;
+ sig->reserved0 = 0;
+ sig->reserved1 = 0;
+ memset(sig->key, 0, sizeof sig->key);
+ sig->signtime = 0;
+ sig->expires = 0;
+ memset(sig->reserved2, 0, 8);
+ memset(sig->signature, 0, 64);
+ memset(sig->reserved3, 0, 120);
+ memset(sig->trailer, 0, 8);
+}
+
+int create_signature(struct signature *sig, struct secret_key *sk,
+ int baresign, unsigned char *data, size_t len) {
+ unsigned char messagehash[64];
+
+ if (!sk || !data || !sig) {
+ return 0;
+ }
+
+ memcpy(sig->magic, "ZPMS", 4);
+ sig->version = VERSION;
+ sig->type = SIGNATURE;
+ sig->reserved0 = 0;
+ sig->reserved1 = 0;
+ ed25519_genpub(sig->key, sk->key);
+#if 0
+ sig->signtime = 0;
+ sig->expires = 0;
+#endif
+ memset(sig->reserved2, 0, 8);
+ memset(sig->signature, 0, 64);
+ memset(sig->reserved3, 0, 120);
+ memset(sig->trailer, 0, 8);
+
+ if (!baresign) {
+ sighash(messagehash, sig, data, len);
+ data = messagehash;
+ len = sizeof messagehash;
+ }
+
+ ed25519_sign(sig->signature, sk->key, sig->key, data, len);
+
+ return 1;
+}
+
+//#define MARK do { fprintf(stderr, "%s %s:%d\n", __FILE__, __func__, __LINE__); } while (0)
+