doDecrypt := flag.Bool("d", false, "Decrypt")
parallel := flag.Int("parallel", runtime.NumCPU(), "Parallel cryptors")
noblob := flag.Bool("no-stream", false, "Include payload into container")
- var pubs []*sign.Pub
+ var pubs []cm.AV
+ var pubIds []uuid.UUID
flag.Func("pub", "Path to public key to encrypt to", func(v string) error {
signed, err := sign.PubParse(mustReadFile(v))
if err != nil {
if len(load.Pub) != 1 {
return errors.New("expected single public key")
}
- pubs = append(pubs, &load.Pub[0])
+ pubs = append(pubs, load.Pub[0])
+ pubIds = append(pubIds, load.Id)
return err
})
var prvs []*cm.AV
}
kems = append(kems, kem)
}
- for _, pub := range pubs {
+ for pubId, pub := range pubs {
switch pub.A {
case sntrup4591761x25519.SNTRUP4591761X25519:
if len(pub.V) != sntrup4591761.PublicKeySize+32 {
kem.CEK = cekp.Bytes()
}
if *includeTo {
- kem.To = &pub.Id
+ kem.To = &pubIds[pubId]
}
kems = append(kems, kem)
case mceliece6960119x25519.ClassicMcEliece6960119X25519:
kem.CEK = cekp.Bytes()
}
if *includeTo {
- kem.To = &pub.Id
+ kem.To = &pubIds[pubId]
}
kems = append(kems, kem)
default:
-prv $TMPDIR/enc.prv -pub $TMPDIR/enc.pub
dd if=/dev/urandom of=$TMPDIR/enc.data bs=12K count=1 2>/dev/null
export ENCTOOL_PASSPHRASE=$(dd if=/dev/urandom bs=32 count=1 2>/dev/null | xxd -p)
-test_expect_success "key encrypting" "cmenctool -p -no-blob \
+test_expect_success "key encrypting" "cmenctool -p -no-stream \
<$TMPDIR/enc.prv >$TMPDIR/enc.prv.enc"
test_expect_success "data encrypting" "cmenctool -pub $TMPDIR/enc.pub \
<$TMPDIR/enc.data >$TMPDIR/enc.enc"
}
}
{
- pubMap := sign.Pub{A: *algo, V: pub}
- {
- av := cm.AV{A: *algo, V: pub}
- var hasher hash.Hash
- switch av.A {
- case ed25519blake2b.Ed25519BLAKE2b, sntrup4591761x25519.SNTRUP4591761X25519:
- hasher = cmhash.ByName(cmhash.BLAKE2b256)
- case gost.GOST3410256A, gost.GOST3410512C:
- hasher = cmhash.ByName(cmhash.Streebog256)
- case mceliece6960119x25519.ClassicMcEliece6960119X25519:
- hasher = cmhash.ByName(cmhash.SHAKE128)
- default:
- log.Fatal("unsupported algorithm")
- }
- _, err = keks.Encode(hasher, av, nil)
- if err != nil {
- log.Fatal(err)
- }
- pubMap.Id, err = uuid.NewRandomFromReader(bytes.NewReader(hasher.Sum(nil)))
- if err != nil {
- log.Fatal(err)
- }
+ pubLoad = &sign.PubLoad{Subj: subj, Pub: []cm.AV{{A: *algo, V: pub}}}
+ var hasher hash.Hash
+ switch *algo {
+ case ed25519blake2b.Ed25519BLAKE2b, sntrup4591761x25519.SNTRUP4591761X25519:
+ hasher = cmhash.ByName(cmhash.BLAKE2b256)
+ case gost.GOST3410256A, gost.GOST3410512C:
+ hasher = cmhash.ByName(cmhash.Streebog256)
+ case mceliece6960119x25519.ClassicMcEliece6960119X25519:
+ hasher = cmhash.ByName(cmhash.SHAKE128)
+ default:
+ log.Fatal("unsupported algorithm")
+ }
+ _, err = keks.Encode(hasher, pubLoad.Pub, nil)
+ if err != nil {
+ log.Fatal(err)
+ }
+ pubLoad.Id, err = uuid.NewRandomFromReader(bytes.NewReader(hasher.Sum(nil)))
+ if err != nil {
+ log.Fatal(err)
}
- pubLoad = &sign.PubLoad{Subj: subj, Pub: []sign.Pub{pubMap}}
}
if len(ku) > 0 {
pubLoad.KU = &ku
const (
BalloonBLAKE2bHKDF = "balloon-blake2b-hkdf"
- SaltLen = 8
+ SaltLen = 16
HKDFInfo = "keks/cm/encrypted/balloon-blake2b-hkdf"
)
"github.com/google/uuid"
"go.cypherpunks.su/keks"
+ "go.cypherpunks.su/keks/cm"
ed25519blake2b "go.cypherpunks.su/keks/cm/sign/ed25519-blake2b"
"go.cypherpunks.su/keks/cm/sign/gost"
)
ErrBadSigAlgo = errors.New("bad signature algo")
)
-// Public key.
-type Pub struct {
- A string `keks:"a"`
- V []byte `keks:"v"`
- Id uuid.UUID `keks:"id"`
-}
-
// Public key load.
type PubLoad struct {
KU *map[string]*struct{} `keks:"ku,omitempty"`
Subj map[string]string `keks:"sub"`
Crit *[]map[string]any `keks:"crit,omitempty"`
- Pub []Pub `keks:"pub"`
+ Pub []cm.AV `keks:"pub"`
+ Id uuid.UUID `keks:"id"`
}
// Parse Signed contents as PubLoad (certificate) and check its
if len(load.Pub) == 0 {
return errors.New("PubParse: empty pub")
}
+ if load.Id == uuid.Nil {
+ return errors.New("PubParse: empty id")
+ }
for _, pub := range load.Pub {
- if len(pub.A) == 0 || len(pub.V) == 0 || pub.Id == uuid.Nil {
+ if len(pub.A) == 0 || len(pub.V) == 0 {
return errors.New("PubParse: non-filled pub")
}
}
return
}
sig := signed.Sigs[0]
- if sig.TBS.SID != parent.Pub[0].Id {
+ if sig.TBS.SID != parent.Id {
err = errors.New("sid != parent pub id")
return
}
}
}
sid := signed.Sigs[0].TBS.SID
- if sid == signed.PubLoad().Pub[0].Id {
+ if sid == signed.PubLoad().Id {
return signed.CertificationCheckSignatureFrom(signed.PubLoad(), nil)
}
idToPub := make(map[uuid.UUID]*Signed, len(pubs))
err = errors.New("pub can not sign")
return
}
- idToPub[pubLoad.Pub[0].Id] = cer
+ idToPub[pubLoad.Id] = cer
}
signer := idToPub[sid]
if signer == nil {
if !parent.Can(KUSig) || len(parent.Pub) != 1 {
return errors.New("parent can not sign")
}
- sigTBS.SID = parent.Pub[0].Id
+ sigTBS.SID = parent.Id
var tbs []byte
if prv.Mode() == mode.Pure {
var b bytes.Buffer
cm-pub-load = {
? ku: set,
- pub: [+ {av, id: uuid}],
+ id: uuid,
+ pub: [+ av],
sub: {text => text}, ; subject
? crit: {+ crit-ext-type => any},
* text => any
identifier, that @strong{should} be generated as an UUIDv4 based on the
hash of the key.
+@item id
+
+Public key(s)'s identifier @strong{should} be generated as an UUIDv4
+based on the hash of the encoded @code{pub} field.
+
@item ku
Intended public key(s) usage.
Application-specific example with multiple public keys is described
@end table
-Example minimal public key may look like:
+Example minimal certified public key may look like:
@verbatim
{
"load": {
"t": "pub",
"v": {
- "pub": [{"a": "gost3410-256A", "v": 'pubkey', "id": UUID(hash(pub))}],
- "sub": {"CN": "Test", "O": "Testers"},
+ "id": UUID(hash(pub)),
+ "pub": [{"a": "gost3410-256A", "v"}],
+ "sub": {"n": "test"},
},
},
"sigs": [{