215 lines
4.4 KiB
Go
215 lines
4.4 KiB
Go
package owner
|
|
|
|
// 5% of AI generated code
|
|
// human made; AI details
|
|
// FINAL-FINAL
|
|
|
|
import (
|
|
"WhspBrd/typio/bit"
|
|
"WhspBrd/typio/yum"
|
|
"bytes"
|
|
"crypto/mlkem"
|
|
"crypto/sha256"
|
|
"errors"
|
|
|
|
"github.com/AeonDave/cryptonite-go/sig"
|
|
)
|
|
|
|
var mldsa87 = sig.NewDeterministicMLDSA87()
|
|
|
|
var (
|
|
ErrInvalidSignature = errors.New("invalid signature")
|
|
ErrDestroyedSecret = errors.New("secret has been destroyed")
|
|
)
|
|
|
|
const requiredSeedSizeForMLDSA87 = 32
|
|
|
|
const signaturePubPartSize = sig.MLDSA87PublicKeySize
|
|
const signatureSignSize = sig.MLDSA87SignatureSize
|
|
const SignatureSize = signaturePubPartSize + signatureSignSize
|
|
|
|
const IdentitySize = bit.Size256b_B
|
|
|
|
type Identity = bit.Sha256
|
|
|
|
func IdentityEq(id, other Identity) bool {
|
|
return bytes.Equal(id[:], other[:])
|
|
}
|
|
|
|
func pubHash(pubKey []byte) Identity {
|
|
return sha256.Sum256(pubKey)
|
|
}
|
|
|
|
type Secret interface {
|
|
Identity() Identity
|
|
PulicKey() []byte
|
|
EncapKey() []byte
|
|
Decapsulate(ciphertext []byte) ([]byte, error)
|
|
Sign(data []byte) (signedData []byte, err error)
|
|
Save(path string, password []byte) error
|
|
Destroy()
|
|
SaveAndDestroy(path string, password []byte) error
|
|
}
|
|
|
|
type secret struct {
|
|
seed []byte
|
|
pubKey []byte
|
|
encap []byte
|
|
identity Identity
|
|
decap *mlkem.DecapsulationKey1024
|
|
privKey []byte
|
|
destroyed bool
|
|
}
|
|
|
|
func Encapsulate(secret Secret, encapKey []byte) (sharedkey []byte, ciphertext []byte, err error) {
|
|
encap, err := mlkem.NewEncapsulationKey1024(encapKey)
|
|
if err != nil {
|
|
return
|
|
}
|
|
sharedkey, ciphertext = encap.Encapsulate()
|
|
return
|
|
}
|
|
|
|
func NewSecret() (Secret, error) {
|
|
seed := make([]byte, requiredSeedSizeForMLDSA87)
|
|
if err := yum.YumSeed(seed); err != nil {
|
|
return nil, err
|
|
}
|
|
pubKey, privKey, err := sig.GenerateDeterministicKeyMLDSA87(seed)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
decap, err := mlkem.NewDecapsulationKey1024(append(seed, seed...))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
encap := decap.EncapsulationKey().Bytes()
|
|
return &secret{
|
|
seed: seed,
|
|
encap: encap,
|
|
decap: decap,
|
|
pubKey: pubKey,
|
|
identity: pubHash(pubKey),
|
|
privKey: privKey,
|
|
}, nil
|
|
}
|
|
|
|
func LoadSecret(path string, password []byte) (Secret, error) {
|
|
seed, err := yum.YumLoad(path, password)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
pubKey, privKey, err := sig.GenerateDeterministicKeyMLDSA87(seed)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
decap, err := mlkem.NewDecapsulationKey1024(append(seed, seed...))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
encap := decap.EncapsulationKey().Bytes()
|
|
return &secret{
|
|
seed: seed,
|
|
encap: encap,
|
|
decap: decap,
|
|
pubKey: pubKey,
|
|
identity: pubHash(pubKey),
|
|
privKey: privKey,
|
|
}, nil
|
|
}
|
|
|
|
func (s *secret) Identity() Identity {
|
|
return s.identity
|
|
}
|
|
|
|
func (s *secret) PulicKey() []byte {
|
|
pubCopy := make([]byte, len(s.pubKey))
|
|
copy(pubCopy, s.pubKey)
|
|
return pubCopy
|
|
}
|
|
|
|
func (s *secret) EncapKey() []byte {
|
|
encapCopy := make([]byte, len(s.encap))
|
|
copy(encapCopy, s.encap)
|
|
return encapCopy
|
|
}
|
|
|
|
func (s *secret) Decapsulate(ciphertext []byte) ([]byte, error) {
|
|
if s.destroyed {
|
|
return nil, ErrDestroyedSecret
|
|
}
|
|
return s.decap.Decapsulate(ciphertext)
|
|
}
|
|
|
|
func (s *secret) Sign(data []byte) (sign []byte, err error) {
|
|
if s.destroyed {
|
|
err = ErrDestroyedSecret
|
|
return
|
|
}
|
|
|
|
signPart, err := mldsa87.Sign(s.privKey, data)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
sign = append(s.pubKey, signPart...)
|
|
return
|
|
}
|
|
|
|
func (s *secret) Save(path string, password []byte) error {
|
|
if s.destroyed {
|
|
return ErrDestroyedSecret
|
|
}
|
|
return yum.YumSave(path, s.seed, password)
|
|
}
|
|
|
|
func Verify(data []byte, sign []byte) (Identity, error) {
|
|
if len(sign) < SignatureSize {
|
|
return Identity{}, ErrInvalidSignature
|
|
}
|
|
|
|
pubPart := sign[:signaturePubPartSize]
|
|
signPart := sign[signaturePubPartSize:]
|
|
|
|
ok := mldsa87.Verify(pubPart, data, signPart)
|
|
if !ok {
|
|
return Identity{}, ErrInvalidSignature
|
|
}
|
|
|
|
return pubHash(pubPart), nil
|
|
}
|
|
|
|
// Destroy zeroes out the secret's sensitive data and marks it as destroyed.
|
|
func (s *secret) Destroy() {
|
|
if s.destroyed {
|
|
return
|
|
}
|
|
for i := range s.seed {
|
|
s.seed[i] = 0
|
|
}
|
|
for i := range s.privKey {
|
|
s.privKey[i] = 0
|
|
}
|
|
for i := range s.encap {
|
|
s.encap[i] = 0
|
|
}
|
|
s.destroyed = true
|
|
/*for i := range s.pubKey {
|
|
s.pubKey[i] = 0
|
|
}
|
|
for i := range s.identity {
|
|
s.identity[i] = 0
|
|
}*/ // not needed for added security, but could be done if desired
|
|
}
|
|
|
|
func (s *secret) SaveAndDestroy(path string, password []byte) error {
|
|
if s.destroyed {
|
|
return ErrDestroyedSecret
|
|
}
|
|
if err := s.Save(path, password); err != nil {
|
|
return err
|
|
}
|
|
s.Destroy()
|
|
return nil
|
|
}
|