all repos — honk @ 92e32cf7e1ebdec5de9f369e0e1d988e783c2f1a

my fork of honk

encrypt.go (view raw)

  1package main
  2
  3import (
  4	"bytes"
  5	"crypto/rand"
  6	"encoding/base64"
  7	"fmt"
  8	"io"
  9	"strings"
 10	"time"
 11
 12	"golang.org/x/crypto/nacl/box"
 13	"humungus.tedunangst.com/r/webs/gencache"
 14)
 15
 16type boxSecKey struct {
 17	key *[32]byte
 18}
 19type boxPubKey struct {
 20	key *[32]byte
 21}
 22
 23func encryptString(plain string, seckey boxSecKey, pubkey boxPubKey) (string, error) {
 24	var nonce [24]byte
 25	rand.Read(nonce[:])
 26	out := box.Seal(nil, []byte(plain), &nonce, pubkey.key, seckey.key)
 27
 28	var sb strings.Builder
 29	b64 := base64.NewEncoder(base64.StdEncoding, &sb)
 30	b64.Write(nonce[:])
 31	b64.Write(out)
 32	b64.Close()
 33	return sb.String(), nil
 34}
 35
 36func decryptString(encmsg string, seckey boxSecKey, pubkey boxPubKey) (string, error) {
 37	var buf bytes.Buffer
 38	b64 := base64.NewDecoder(base64.StdEncoding, strings.NewReader(encmsg))
 39	io.Copy(&buf, b64)
 40	data := buf.Bytes()
 41	if len(data) < 24 {
 42		return "", fmt.Errorf("not enough data")
 43	}
 44	var nonce [24]byte
 45	copy(nonce[:], data)
 46	data = data[24:]
 47	out, ok := box.Open(nil, data, &nonce, pubkey.key, seckey.key)
 48	if !ok {
 49		return "", fmt.Errorf("error decrypting chonk")
 50	}
 51	return string(out), nil
 52}
 53
 54func b64tokey(s string) (*[32]byte, error) {
 55	var buf bytes.Buffer
 56	b64 := base64.NewDecoder(base64.StdEncoding, strings.NewReader(s))
 57	n, _ := io.Copy(&buf, b64)
 58	if n != 32 {
 59		return nil, fmt.Errorf("bad key size")
 60	}
 61	var key [32]byte
 62	copy(key[:], buf.Bytes())
 63	return &key, nil
 64}
 65
 66func tob64(data []byte) string {
 67	var sb strings.Builder
 68	b64 := base64.NewEncoder(base64.StdEncoding, &sb)
 69	b64.Write(data)
 70	b64.Close()
 71	return sb.String()
 72}
 73
 74func newChatKeys() (boxPubKey, boxSecKey) {
 75	pub, sec, _ := box.GenerateKey(rand.Reader)
 76	return boxPubKey{pub}, boxSecKey{sec}
 77}
 78
 79var chatkeys = gencache.New(gencache.Options[string, boxPubKey]{Fill: func(xonker string) (boxPubKey, bool) {
 80	data := getxonker(xonker, chatKeyProp)
 81	if data == "" {
 82		dlog.Printf("hitting the webs for missing chatkey: %s", xonker)
 83		j, err := GetJunk(readyLuserOne, xonker)
 84		if err != nil {
 85			ilog.Printf("error getting %s: %s", xonker, err)
 86			when := time.Now().UTC().Format(dbtimeformat)
 87			stmtSaveXonker.Exec(xonker, "failed", chatKeyProp, when)
 88			return boxPubKey{}, true
 89		}
 90		allinjest(originate(xonker), j)
 91		data = getxonker(xonker, chatKeyProp)
 92		if data == "" {
 93			ilog.Printf("key not found after ingesting")
 94			when := time.Now().UTC().Format(dbtimeformat)
 95			stmtSaveXonker.Exec(xonker, "failed", chatKeyProp, when)
 96			return boxPubKey{}, true
 97		}
 98	}
 99	if data == "failed" {
100		ilog.Printf("lookup previously failed chatkey %s", xonker)
101		return boxPubKey{}, true
102	}
103	var pubkey boxPubKey
104	var err error
105	pubkey.key, err = b64tokey(data)
106	if err != nil {
107		ilog.Printf("error decoding %s pubkey: %s", xonker, err)
108	}
109	return pubkey, true
110}, Limit: 512})
111
112func getchatkey(xonker string) (boxPubKey, bool) {
113	pubkey, _ := chatkeys.Get(xonker)
114	return pubkey, pubkey.key != nil
115}