whspbrd-final/owner/owner.go
2026-05-02 22:09:19 +02:00

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
}