Documentation
¶
Overview ¶
Package keychain provides secure local secret storage with minimal memory exposure.
Design principles:
- Each secret stored separately (not one big blob)
- Keys loaded into memory only when needed
- Age encryption for at-rest storage
- Symmetric keys derived via ECDH + HKDF
- Protected memory via memguard for sensitive material
Index ¶
- Constants
- func DecryptWith(key *memguard.LockedBuffer, ciphertext, nonce []byte, cs CipherSuite) ([]byte, error)
- func EcdhPublicKeyToKeychain(pubKey *ecdh.PublicKey) (string, error)
- func Ed25519PrivateKeyToX25519(ed25519Seed []byte) ([]byte, error)
- func Ed25519PublicKeyToX25519(publicKey ed25519.PublicKey) (*ecdh.PublicKey, error)
- func EncryptWith(key *memguard.LockedBuffer, plaintext []byte, cs CipherSuite) (ciphertext, nonce []byte, err error)
- func NaClBoxDecrypt(message, peerPublicKey, privateKey []byte) ([]byte, error)
- func NaClBoxEncrypt(plaintext, peerPublicKey, privateKey []byte) ([]byte, error)
- func P256KeychainToPublicKey(keychainFormat string) (*ecdh.PublicKey, error)
- func P256PublicKeyToKeychain(pubKey []byte) (string, error)
- func VerifySignature(publicKey ed25519.PublicKey, signature []byte, data []byte) bool
- type AddressBook
- func (ab *AddressBook) AddContact(contact *Contact) error
- func (ab *AddressBook) AssociateOTPPad(contactID string, otpID SecretID) error
- func (ab *AddressBook) AssociateP256Key(contactID string, keyID SecretID) error
- func (ab *AddressBook) AssociateX25519Key(contactID string, keyID SecretID) error
- func (ab *AddressBook) CanDecryptWith(contactID string, keyType KeyExchangeType) (bool, error)
- func (ab *AddressBook) CanEncryptWith(contactID string, keyType KeyExchangeType) (bool, error)
- func (ab *AddressBook) DecryptFromContact(myPrivKeyID SecretID, contactID string, ciphertext, nonce []byte, ...) ([]byte, error)
- func (ab *AddressBook) DecryptFromContactWithIdentity(store *Store, identityID string, contactID string, ciphertext, nonce []byte, ...) ([]byte, error)
- func (ab *AddressBook) DeleteContact(id string) error
- func (ab *AddressBook) DeleteContactWithKeys(id string) error
- func (ab *AddressBook) DisassociateOTPPad(contactID string) error
- func (ab *AddressBook) EncryptForContact(myPrivKeyID SecretID, contactID string, plaintext []byte, keyType KeyType, ...) (ciphertext, nonce []byte, err error)
- func (ab *AddressBook) EncryptForContactWithIdentity(store *Store, identityID string, contactID string, plaintext []byte, ...) (ciphertext, nonce []byte, err error)
- func (ab *AddressBook) GetContact(id string) (*Contact, error)
- func (ab *AddressBook) GetContactPublicKeys(id string) (*ContactPublicKeys, error)
- func (ab *AddressBook) GetKeyStatus(contactID string, keyType KeyExchangeType) (FriendStatus, error)
- func (ab *AddressBook) IsKeyVerified(contactID string, keyType KeyExchangeType) (bool, error)
- func (ab *AddressBook) ListContacts() ([]*Contact, error)
- func (ab *AddressBook) MarkInvited(contactID string, keyType KeyExchangeType) error
- func (ab *AddressBook) MarkRequested(contactID string, keyType KeyExchangeType) error
- func (ab *AddressBook) MarkVerified(contactID string, keyType KeyExchangeType) error
- func (ab *AddressBook) NaClBoxDecryptFromContact(myPrivKeyID SecretID, contactID string, message []byte) ([]byte, error)
- func (ab *AddressBook) NaClBoxDecryptFromContactWithIdentity(store *Store, identityID string, contactID string, message []byte) ([]byte, error)
- func (ab *AddressBook) NaClBoxDecryptWithDefaultIdentity(store *Store, contactID string, message []byte) ([]byte, error)
- func (ab *AddressBook) NaClBoxEncryptForContact(myPrivKeyID SecretID, contactID string, plaintext []byte) ([]byte, error)
- func (ab *AddressBook) NaClBoxEncryptForContactWithIdentity(store *Store, identityID string, contactID string, plaintext []byte) ([]byte, error)
- func (ab *AddressBook) NaClBoxEncryptWithDefaultIdentity(store *Store, contactID string, plaintext []byte) ([]byte, error)
- func (ab *AddressBook) SetKeyStatus(contactID string, keyType KeyExchangeType, status FriendStatus) error
- func (ab *AddressBook) UpdateContact(contact *Contact) error
- type CipherSuite
- type Contact
- type ContactPublicKeys
- type FriendStatus
- type Identity
- type IdentityPublicKeys
- type KeyExchangeType
- type KeyType
- type OTPPad
- type OTPResult
- type SecretID
- type SecretMetadata
- type Store
- func (s *Store) AddEd25519KeyToIdentity(id string) (ed25519.PublicKey, error)
- func (s *Store) AddP256KeyToIdentity(id string) (*ecdh.PublicKey, error)
- func (s *Store) AddX25519KeyToIdentity(id string) (*ecdh.PublicKey, error)
- func (s *Store) Close()
- func (s *Store) CreateDefaultIdentity(name string) (*Identity, error)
- func (s *Store) CreateFullIdentity(name string) (*Identity, error)
- func (s *Store) CreateIdentity(id string, name string, generateP256, generateX25519, generateEd25519 bool) (*Identity, error)
- func (s *Store) CreateNahoftIdentity(name string) (*Identity, error)
- func (s *Store) CreateSigningIdentity(id string, name string) (*Identity, error)
- func (s *Store) DecryptWithDerivedKey(privateKeyID SecretID, peerPublicKey []byte, info []byte, ...) ([]byte, error)
- func (s *Store) DefaultIdentityExists() bool
- func (s *Store) DeleteIdentity(id string) error
- func (s *Store) DeleteOTPPad(id SecretID) error
- func (s *Store) DeleteSecret(id SecretID) error
- func (s *Store) DeriveSharedKey(privateKeyID SecretID, peerPublicKey []byte, info []byte, keyLen int) (*memguard.LockedBuffer, error)
- func (s *Store) DeriveSharedKeyP256(privateKeyID SecretID, peerPublicKey *ecdh.PublicKey, info []byte, keyLen int) (*memguard.LockedBuffer, error)
- func (s *Store) DeriveSharedKeyX25519(privateKeyID SecretID, peerPublicKey *ecdh.PublicKey, info []byte, keyLen int) (*memguard.LockedBuffer, error)
- func (s *Store) Ed25519PublicToX25519(id SecretID) (*ecdh.PublicKey, error)
- func (s *Store) Ed25519ToX25519(id SecretID) ([]byte, error)
- func (s *Store) EncryptWithDerivedKey(privateKeyID SecretID, peerPublicKey []byte, info []byte, plaintext []byte, ...) (ciphertext, nonce []byte, err error)
- func (s *Store) ExportP256PublicKey(keyID SecretID) (string, error)
- func (s *Store) GenerateEd25519(id SecretID, label string) (ed25519.PublicKey, error)
- func (s *Store) GenerateP256(id SecretID, label string) (*ecdh.PublicKey, error)
- func (s *Store) GenerateSymmetricKey(id SecretID, label string, keyLen int) error
- func (s *Store) GenerateX25519(id SecretID, label string) (*ecdh.PublicKey, error)
- func (s *Store) GetDefaultIdentity() (*Identity, error)
- func (s *Store) GetDefaultIdentityPublicKeys() (*IdentityPublicKeys, error)
- func (s *Store) GetIdentity(id string) (*Identity, error)
- func (s *Store) GetIdentityPublicKeys(id string) (*IdentityPublicKeys, error)
- func (s *Store) GetMetadata(id SecretID) (*SecretMetadata, error)
- func (s *Store) GetOTPPadInfo(id SecretID) (*OTPPad, error)
- func (s *Store) IdentityExists(id string) bool
- func (s *Store) ImportEd25519KeyToIdentity(id string, privateKey []byte) error
- func (s *Store) ImportP256KeyToIdentity(id string, privateKey []byte) error
- func (s *Store) ImportP256PublicKey(keyID SecretID, keychainFormat string, label string) error
- func (s *Store) ImportX25519KeyToIdentity(id string, privateKey []byte) error
- func (s *Store) ListIdentities() ([]*Identity, error)
- func (s *Store) ListOTPPads() ([]OTPPad, error)
- func (s *Store) ListSecrets() ([]SecretMetadata, error)
- func (s *Store) LoadEd25519PublicKey(id SecretID) (ed25519.PublicKey, error)
- func (s *Store) LoadP256PublicKey(id SecretID) (*ecdh.PublicKey, error)
- func (s *Store) LoadPublicKey(id SecretID) ([]byte, KeyType, error)
- func (s *Store) LoadSecret(id SecretID) (*memguard.LockedBuffer, *SecretMetadata, error)
- func (s *Store) LoadSymmetricKey(id SecretID) (*memguard.LockedBuffer, error)
- func (s *Store) LoadX25519PublicKey(id SecretID) (*ecdh.PublicKey, error)
- func (s *Store) NaClBoxDecryptWithStore(privateKeyID SecretID, peerPublicKey []byte, message []byte) ([]byte, error)
- func (s *Store) NaClBoxEncryptWithStore(privateKeyID SecretID, peerPublicKey []byte, plaintext []byte) ([]byte, error)
- func (s *Store) OTPBytesRemaining(id SecretID) (int, error)
- func (s *Store) OTPDecrypt(id SecretID, ciphertext []byte) (*OTPResult, error)
- func (s *Store) OTPDecryptBits(id SecretID, data []byte, numBits int) (*OTPResult, error)
- func (s *Store) OTPDecryptWSPR(id SecretID, data [11]byte) (*OTPResult, [11]byte, error)
- func (s *Store) OTPEncrypt(id SecretID, plaintext []byte) (*OTPResult, error)
- func (s *Store) OTPEncryptBits(id SecretID, data []byte, numBits int) (*OTPResult, error)
- func (s *Store) OTPEncryptWSPR(id SecretID, data [11]byte) (*OTPResult, [11]byte, error)
- func (s *Store) OTPPeek(id SecretID, length int) ([]byte, error)
- func (s *Store) OTPSetOffset(id SecretID, offset int) error
- func (s *Store) OTPSkip(id SecretID, numBytes int) error
- func (s *Store) SecretExists(id SecretID) bool
- func (s *Store) Sign(id SecretID, data []byte) ([]byte, error)
- func (s *Store) StoreEd25519PublicKey(id SecretID, publicKey ed25519.PublicKey, label string) error
- func (s *Store) StoreOTPPad(id SecretID, pad []byte, label string) error
- func (s *Store) StoreP256PublicKey(id SecretID, publicKey *ecdh.PublicKey, label string) error
- func (s *Store) StoreSecret(id SecretID, keyType KeyType, secret []byte, label string) error
- func (s *Store) StoreX25519PublicKey(id SecretID, publicKey *ecdh.PublicKey, label string) error
- func (s *Store) UpdateIdentity(identity *Identity) error
- func (s *Store) Verify(publicKeyID SecretID, signature []byte, data []byte) (bool, error)
Constants ¶
const ( NaClBoxNonceSize = 24 NaClBoxKeySize = 32 NaClBoxOverhead = box.Overhead // 16 bytes (Poly1305 tag) )
NaCl box constants
const ( P256KeychainTypeByte = 0x02 P256KeychainFormatByte = 0x04 P256KeychainSize = 66 // type + format + X + Y )
P-256 Keychain format constants. The Keychain format is a JSON string containing base64-encoded data. For P-256 public keys, the encoded data is 66 bytes:
- 1 byte: type (0x02 for P-256)
- 1 byte: format (0x04 for uncompressed)
- 32 bytes: X coordinate
- 32 bytes: Y coordinate
const DefaultIdentityID = "default"
DefaultIdentityID is the ID used for the default/primary identity.
Variables ¶
This section is empty.
Functions ¶
func DecryptWith ¶
func DecryptWith(key *memguard.LockedBuffer, ciphertext, nonce []byte, cs CipherSuite) ([]byte, error)
DecryptWith decrypts data using a provided symmetric key. Not applicable for CipherNaClBox - use NaClBoxDecrypt instead.
func EcdhPublicKeyToKeychain ¶ added in v0.0.6
EcdhPublicKeyToKeychain converts a P-256 *ecdh.PublicKey to Keychain format. Output: JSON string containing base64-encoded 66-byte Keychain format
func Ed25519PrivateKeyToX25519 ¶ added in v0.0.4
Ed25519PrivateKeyToX25519 converts an Ed25519 private key seed to an X25519 private key. The Ed25519 private key seed is the 32-byte value returned by ed25519.PrivateKey.Seed(). This is compatible with libsodium's crypto_sign_ed25519_sk_to_curve25519.
func Ed25519PublicKeyToX25519 ¶ added in v0.0.4
Ed25519PublicKeyToX25519 converts an Ed25519 public key to an X25519 public key. This allows using the same key for both signing (Ed25519) and encryption (X25519). Returns the X25519 public key as *ecdh.PublicKey.
func EncryptWith ¶
func EncryptWith(key *memguard.LockedBuffer, plaintext []byte, cs CipherSuite) (ciphertext, nonce []byte, err error)
EncryptWith encrypts data using a provided symmetric key. Not applicable for CipherNaClBox - use NaClBoxEncrypt instead.
func NaClBoxDecrypt ¶ added in v0.0.2
NaClBoxDecrypt decrypts a message using NaCl box (X25519 + XSalsa20-Poly1305). This is compatible with libsodium's crypto_box_open_easy. Expects: nonce (24 bytes) || ciphertext (MAC + encrypted message)
func NaClBoxEncrypt ¶ added in v0.0.2
NaClBoxEncrypt encrypts a message using NaCl box (X25519 + XSalsa20-Poly1305). This is compatible with libsodium's crypto_box_easy. Returns: nonce (24 bytes) || ciphertext (MAC + encrypted message)
func P256KeychainToPublicKey ¶ added in v0.0.5
P256KeychainToPublicKey converts a Keychain format string to a P-256 public key. Input: JSON string containing base64-encoded 66-byte Keychain format Output: *ecdh.PublicKey for use with P-256 ECDH
func P256PublicKeyToKeychain ¶ added in v0.0.5
P256PublicKeyToKeychain converts a P-256 public key to Keychain format. This version accepts raw bytes. For *ecdh.PublicKey, use EcdhPublicKeyToKeychain. Input: 65-byte uncompressed X9.62 public key (0x04 || X || Y) Output: JSON string containing base64-encoded 66-byte Keychain format
func VerifySignature ¶ added in v0.0.4
VerifySignature verifies an Ed25519 signature. publicKey should be an Ed25519 public key. signature should be a 64-byte Ed25519 signature. data is the original data that was signed.
Types ¶
type AddressBook ¶
type AddressBook struct {
// contains filtered or unexported fields
}
AddressBook manages contacts stored individually for minimal exposure.
func NewAddressBook ¶
func NewAddressBook(store *Store) *AddressBook
NewAddressBook creates an address book backed by the secret store.
func (*AddressBook) AddContact ¶
func (ab *AddressBook) AddContact(contact *Contact) error
AddContact stores a new contact with StatusDefault.
func (*AddressBook) AssociateOTPPad ¶
func (ab *AddressBook) AssociateOTPPad(contactID string, otpID SecretID) error
AssociateOTPPad links a one-time pad to a contact (replaces any existing pad).
func (*AddressBook) AssociateP256Key ¶
func (ab *AddressBook) AssociateP256Key(contactID string, keyID SecretID) error
AssociateP256Key links a P-256 public key to a contact.
func (*AddressBook) AssociateX25519Key ¶
func (ab *AddressBook) AssociateX25519Key(contactID string, keyID SecretID) error
AssociateX25519Key links an X25519 public key to a contact.
func (*AddressBook) CanDecryptWith ¶
func (ab *AddressBook) CanDecryptWith(contactID string, keyType KeyExchangeType) (bool, error)
CanDecryptWith returns true if decryption is possible with the specified key type. Requires the contact's public key and status >= StatusInvited.
func (*AddressBook) CanEncryptWith ¶
func (ab *AddressBook) CanEncryptWith(contactID string, keyType KeyExchangeType) (bool, error)
CanEncryptWith returns true if encryption is possible with the specified key type. Requires the contact's public key and status >= StatusRequested.
func (*AddressBook) DecryptFromContact ¶
func (ab *AddressBook) DecryptFromContact( myPrivKeyID SecretID, contactID string, ciphertext, nonce []byte, keyType KeyType, cs CipherSuite, ) ([]byte, error)
DecryptFromContact derives a shared key with a contact and decrypts data.
func (*AddressBook) DecryptFromContactWithIdentity ¶
func (ab *AddressBook) DecryptFromContactWithIdentity( store *Store, identityID string, contactID string, ciphertext, nonce []byte, keyType KeyType, cs CipherSuite, ) ([]byte, error)
DecryptFromContactWithIdentity decrypts data from a contact using the identity's key.
func (*AddressBook) DeleteContact ¶
func (ab *AddressBook) DeleteContact(id string) error
DeleteContact removes a contact (does not delete associated keys).
func (*AddressBook) DeleteContactWithKeys ¶
func (ab *AddressBook) DeleteContactWithKeys(id string) error
DeleteContactWithKeys removes a contact and all associated keys.
func (*AddressBook) DisassociateOTPPad ¶
func (ab *AddressBook) DisassociateOTPPad(contactID string) error
DisassociateOTPPad removes the OTP pad association from a contact (does not delete the pad).
func (*AddressBook) EncryptForContact ¶
func (ab *AddressBook) EncryptForContact( myPrivKeyID SecretID, contactID string, plaintext []byte, keyType KeyType, cs CipherSuite, ) (ciphertext, nonce []byte, err error)
EncryptForContact derives a shared key with a contact and encrypts data. keyType specifies which key type to use (KeyTypeP256 or KeyTypeX25519).
func (*AddressBook) EncryptForContactWithIdentity ¶
func (ab *AddressBook) EncryptForContactWithIdentity( store *Store, identityID string, contactID string, plaintext []byte, keyType KeyType, cs CipherSuite, ) (ciphertext, nonce []byte, err error)
EncryptForContactWithIdentity encrypts data for a contact using the identity's key.
func (*AddressBook) GetContact ¶
func (ab *AddressBook) GetContact(id string) (*Contact, error)
GetContact retrieves a contact (without loading any key material).
func (*AddressBook) GetContactPublicKeys ¶
func (ab *AddressBook) GetContactPublicKeys(id string) (*ContactPublicKeys, error)
GetContactPublicKeys loads the actual public key bytes for a contact. For contacts, we store the public key directly as the secret (not a private key).
func (*AddressBook) GetKeyStatus ¶
func (ab *AddressBook) GetKeyStatus(contactID string, keyType KeyExchangeType) (FriendStatus, error)
GetKeyStatus returns the friend status for a specific key type.
func (*AddressBook) IsKeyVerified ¶
func (ab *AddressBook) IsKeyVerified(contactID string, keyType KeyExchangeType) (bool, error)
IsKeyVerified returns true if the specified key type has been verified.
func (*AddressBook) ListContacts ¶
func (ab *AddressBook) ListContacts() ([]*Contact, error)
ListContacts returns all contacts (without loading any key material).
func (*AddressBook) MarkInvited ¶
func (ab *AddressBook) MarkInvited(contactID string, keyType KeyExchangeType) error
MarkInvited transitions a key's status from Default to Invited. Call this after sending your public key/pad to the contact.
func (*AddressBook) MarkRequested ¶
func (ab *AddressBook) MarkRequested(contactID string, keyType KeyExchangeType) error
MarkRequested transitions a key's status from Default to Requested. Call this after receiving the contact's public key/pad.
func (*AddressBook) MarkVerified ¶
func (ab *AddressBook) MarkVerified(contactID string, keyType KeyExchangeType) error
MarkVerified transitions a key's status to Verified. Call this after out-of-band key verification.
func (*AddressBook) NaClBoxDecryptFromContact ¶ added in v0.0.2
func (ab *AddressBook) NaClBoxDecryptFromContact( myPrivKeyID SecretID, contactID string, message []byte, ) ([]byte, error)
NaClBoxDecryptFromContact decrypts a message from a contact using NaCl box. This is compatible with Nahoft's encryption format. Expects: nonce (24 bytes) || ciphertext (MAC + encrypted message)
func (*AddressBook) NaClBoxDecryptFromContactWithIdentity ¶ added in v0.0.2
func (ab *AddressBook) NaClBoxDecryptFromContactWithIdentity( store *Store, identityID string, contactID string, message []byte, ) ([]byte, error)
NaClBoxDecryptFromContactWithIdentity decrypts from a contact using Nahoft-compatible NaCl box. Uses the default identity's X25519 key. Expects: nonce (24 bytes) || ciphertext (MAC + encrypted message)
func (*AddressBook) NaClBoxDecryptWithDefaultIdentity ¶ added in v0.0.2
func (ab *AddressBook) NaClBoxDecryptWithDefaultIdentity( store *Store, contactID string, message []byte, ) ([]byte, error)
NaClBoxDecryptWithDefaultIdentity is a convenience function for Nahoft decryption. Decrypts from a contact using the default identity.
func (*AddressBook) NaClBoxEncryptForContact ¶ added in v0.0.2
func (ab *AddressBook) NaClBoxEncryptForContact( myPrivKeyID SecretID, contactID string, plaintext []byte, ) ([]byte, error)
NaClBoxEncryptForContact encrypts a message for a contact using NaCl box. This is compatible with Nahoft's encryption format. Returns: nonce (24 bytes) || ciphertext (MAC + encrypted message)
func (*AddressBook) NaClBoxEncryptForContactWithIdentity ¶ added in v0.0.2
func (ab *AddressBook) NaClBoxEncryptForContactWithIdentity( store *Store, identityID string, contactID string, plaintext []byte, ) ([]byte, error)
NaClBoxEncryptForContactWithIdentity encrypts for a contact using Nahoft-compatible NaCl box. Uses the default identity's X25519 key. Returns: nonce (24 bytes) || ciphertext (MAC + encrypted message)
func (*AddressBook) NaClBoxEncryptWithDefaultIdentity ¶ added in v0.0.2
func (ab *AddressBook) NaClBoxEncryptWithDefaultIdentity( store *Store, contactID string, plaintext []byte, ) ([]byte, error)
NaClBoxEncryptWithDefaultIdentity is a convenience function for Nahoft encryption. Encrypts for a contact using the default identity.
func (*AddressBook) SetKeyStatus ¶
func (ab *AddressBook) SetKeyStatus(contactID string, keyType KeyExchangeType, status FriendStatus) error
SetKeyStatus directly sets the friend status for a key type (use with caution).
func (*AddressBook) UpdateContact ¶
func (ab *AddressBook) UpdateContact(contact *Contact) error
UpdateContact updates an existing contact.
type CipherSuite ¶
type CipherSuite string
CipherSuite identifies the symmetric cipher used for encryption.
const ( CipherAES256GCM CipherSuite = "aes-256-gcm" CipherChaCha20Poly1305 CipherSuite = "chacha20-poly1305" // CipherNaClBox uses X25519 + XSalsa20-Poly1305 (libsodium crypto_box compatible) CipherNaClBox CipherSuite = "nacl-box" )
func (CipherSuite) KeyLength ¶
func (cs CipherSuite) KeyLength() int
KeyLength returns the required key length in bytes for the cipher suite.
func (CipherSuite) NonceLength ¶ added in v0.0.2
func (cs CipherSuite) NonceLength() int
NonceLength returns the nonce length in bytes for the cipher suite.
type Contact ¶
type Contact struct {
ID string `json:"id"`
Name string `json:"name"`
Notes string `json:"notes,omitempty"`
CreatedAt int64 `json:"created_at"`
UpdatedAt int64 `json:"updated_at"`
// P-256 key reference and exchange status
P256KeyID SecretID `json:"p256_key_id,omitempty"`
P256Status FriendStatus `json:"p256_status"`
// X25519 key reference and exchange status
X25519KeyID SecretID `json:"x25519_key_id,omitempty"`
X25519Status FriendStatus `json:"x25519_status"`
// OTP pad reference and exchange status (at most one pad per contact)
OTPPadID SecretID `json:"otp_pad_id,omitempty"`
OTPStatus FriendStatus `json:"otp_status"`
}
Contact represents an entry in the address book. Keys are stored separately in the keychain; contacts only hold references. Each key type has its own exchange status since key exchange is per-key-type.
type ContactPublicKeys ¶
ContactPublicKeys holds the actual public key bytes for a contact. This is returned only when explicitly requested.
type FriendStatus ¶
type FriendStatus int
FriendStatus tracks the key exchange state with a contact.
const ( // StatusDefault - Contact added, no key exchange yet StatusDefault FriendStatus = iota // StatusInvited - User sent their public key to this contact StatusInvited // StatusRequested - Contact sent their public key to user StatusRequested // StatusApproved - Bidirectional key exchange complete, unverified StatusApproved // StatusVerified - Keys verified out-of-band (e.g., in person) StatusVerified )
func (FriendStatus) String ¶
func (s FriendStatus) String() string
String returns a human-readable status name.
type Identity ¶
type Identity struct {
ID string `json:"id"`
Name string `json:"name"`
CreatedAt int64 `json:"created_at"`
UpdatedAt int64 `json:"updated_at"`
P256KeyID SecretID `json:"p256_key_id,omitempty"`
X25519KeyID SecretID `json:"x25519_key_id,omitempty"`
Ed25519KeyID SecretID `json:"ed25519_key_id,omitempty"` // Ed25519 signing key
}
Identity represents the local user's identity with their private keys.
type IdentityPublicKeys ¶
type IdentityPublicKeys struct {
P256PublicKey []byte
X25519PublicKey []byte
Ed25519PublicKey []byte
}
IdentityPublicKeys holds the public keys for an identity.
func (*IdentityPublicKeys) Ed25519PublicKeyTyped ¶ added in v0.0.6
func (k *IdentityPublicKeys) Ed25519PublicKeyTyped() (ed25519.PublicKey, error)
Ed25519PublicKeyTyped returns the Ed25519 public key as ed25519.PublicKey.
func (*IdentityPublicKeys) P256EcdhPublicKey ¶ added in v0.0.6
func (k *IdentityPublicKeys) P256EcdhPublicKey() (*ecdh.PublicKey, error)
P256EcdhPublicKey returns the P-256 public key as *ecdh.PublicKey.
func (*IdentityPublicKeys) X25519EcdhPublicKey ¶ added in v0.0.6
func (k *IdentityPublicKeys) X25519EcdhPublicKey() (*ecdh.PublicKey, error)
X25519EcdhPublicKey returns the X25519 public key as *ecdh.PublicKey.
type KeyExchangeType ¶
type KeyExchangeType int
KeyExchangeType specifies which key type a status operation applies to.
const ( KeyExchangeP256 KeyExchangeType = iota KeyExchangeX25519 KeyExchangeOTP )
type KeyType ¶
type KeyType string
KeyType identifies the type of key stored.
const ( KeyTypeP256 KeyType = "p256" KeyTypeX25519 KeyType = "x25519" KeyTypeP256Public KeyType = "p256-public" KeyTypeX25519Public KeyType = "x25519-public" KeyTypeAES256 KeyType = "aes256" KeyTypeChaCha20 KeyType = "chacha20" KeyTypeContact KeyType = "contact" KeyTypeEd25519 KeyType = "ed25519" // Ed25519 signing key (private) KeyTypeEd25519Public KeyType = "ed25519-public" // Ed25519 public key (for contacts) )
const KeyTypeIdentity KeyType = "identity"
KeyTypeIdentity is the key type for identity metadata.
const KeyTypeOTP KeyType = "otp"
KeyTypeOTP is the key type for one-time pad secrets.
const KeyTypeOTPMeta KeyType = "otp-meta"
KeyTypeOTPMeta is the key type for one-time pad metadata.
type OTPPad ¶
type OTPPad struct {
ID SecretID `json:"id"`
Label string `json:"label,omitempty"`
Length int `json:"length"` // Total length of the pad in bytes
Offset int `json:"offset"` // Current offset - bytes before this are consumed
CreatedAt int64 `json:"created_at"`
}
OTPPad represents a one-time pad for XOR-based encryption. The pad is consumed sequentially and bytes are never reused.
type OTPResult ¶
type OTPResult struct {
Data []byte // The XOR'd output
BytesUsed int // Number of pad bytes consumed
BytesLeft int // Remaining bytes in the pad
StartOffset int // Offset where this operation started
}
OTPResult contains the result of an OTP encryption/decryption operation.
type SecretMetadata ¶
type SecretMetadata struct {
ID SecretID `json:"id"`
KeyType KeyType `json:"key_type"`
Label string `json:"label,omitempty"`
CreatedAt int64 `json:"created_at"`
PublicKey []byte `json:"public_key,omitempty"`
}
SecretMetadata is stored inside the encrypted envelope.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store manages secrets on disk using age encryption.
func OpenStore ¶
OpenStore opens or creates a secret store at the given path. The password is used with age's scrypt-based encryption.
func (*Store) AddEd25519KeyToIdentity ¶ added in v0.0.4
AddEd25519KeyToIdentity generates and adds an Ed25519 key to an existing identity.
func (*Store) AddP256KeyToIdentity ¶
AddP256KeyToIdentity generates and adds a P-256 key to an existing identity.
func (*Store) AddX25519KeyToIdentity ¶
AddX25519KeyToIdentity generates and adds an X25519 key to an existing identity.
func (*Store) CreateDefaultIdentity ¶
CreateDefaultIdentity creates the default identity with all key types.
func (*Store) CreateFullIdentity ¶ added in v0.0.4
CreateFullIdentity creates an identity with all key types (P-256, X25519, Ed25519).
func (*Store) CreateIdentity ¶
func (s *Store) CreateIdentity(id string, name string, generateP256, generateX25519, generateEd25519 bool) (*Identity, error)
CreateIdentity creates a new identity with the specified key types. If generateP256 is true, a P-256 keypair is generated. If generateX25519 is true, an X25519 keypair is generated. If generateEd25519 is true, an Ed25519 keypair is generated.
func (*Store) CreateNahoftIdentity ¶ added in v0.0.2
CreateNahoftIdentity creates an identity with only X25519 key (Nahoft-compatible).
func (*Store) CreateSigningIdentity ¶ added in v0.0.4
CreateSigningIdentity creates an identity with Ed25519 key for signing.
func (*Store) DecryptWithDerivedKey ¶
func (s *Store) DecryptWithDerivedKey( privateKeyID SecretID, peerPublicKey []byte, info []byte, ciphertext, nonce []byte, cs CipherSuite, ) ([]byte, error)
DecryptWithDerivedKey derives a shared key via ECDH and decrypts data. This is a convenience function that combines DeriveSharedKey and DecryptWith. Not applicable for CipherNaClBox - use NaClBoxDecryptWithStore instead.
func (*Store) DefaultIdentityExists ¶
DefaultIdentityExists checks if the default identity exists.
func (*Store) DeleteIdentity ¶
DeleteIdentity removes an identity and its associated keys.
func (*Store) DeleteOTPPad ¶
DeleteOTPPad removes an OTP pad and its metadata.
func (*Store) DeleteSecret ¶
DeleteSecret securely removes a secret.
func (*Store) DeriveSharedKey ¶
func (s *Store) DeriveSharedKey( privateKeyID SecretID, peerPublicKey []byte, info []byte, keyLen int, ) (*memguard.LockedBuffer, error)
DeriveSharedKey performs ECDH with a peer's public key and derives a symmetric key using HKDF. The private key is loaded only for this operation.
func (*Store) DeriveSharedKeyP256 ¶ added in v0.0.6
func (s *Store) DeriveSharedKeyP256( privateKeyID SecretID, peerPublicKey *ecdh.PublicKey, info []byte, keyLen int, ) (*memguard.LockedBuffer, error)
DeriveSharedKeyP256 performs ECDH with a peer's P-256 public key. This is a convenience wrapper that extracts bytes from *ecdh.PublicKey.
func (*Store) DeriveSharedKeyX25519 ¶ added in v0.0.6
func (s *Store) DeriveSharedKeyX25519( privateKeyID SecretID, peerPublicKey *ecdh.PublicKey, info []byte, keyLen int, ) (*memguard.LockedBuffer, error)
DeriveSharedKeyX25519 performs ECDH with a peer's X25519 public key. This is a convenience wrapper that extracts bytes from *ecdh.PublicKey.
func (*Store) Ed25519PublicToX25519 ¶ added in v0.0.4
Ed25519PublicToX25519 converts a stored Ed25519 public key to an X25519 public key. Returns the X25519 public key as *ecdh.PublicKey.
func (*Store) Ed25519ToX25519 ¶ added in v0.0.4
Ed25519ToX25519 converts a stored Ed25519 private key to an X25519 private key. The returned key is suitable for X25519 key exchange and NaCl box encryption.
func (*Store) EncryptWithDerivedKey ¶
func (s *Store) EncryptWithDerivedKey( privateKeyID SecretID, peerPublicKey []byte, info []byte, plaintext []byte, cs CipherSuite, ) (ciphertext, nonce []byte, err error)
EncryptWithDerivedKey derives a shared key via ECDH and encrypts data. This is a convenience function that combines DeriveSharedKey and EncryptWith. Not applicable for CipherNaClBox - use NaClBoxEncryptWithStore instead.
func (*Store) ExportP256PublicKey ¶ added in v0.0.5
ExportP256PublicKey exports a P-256 public key in Keychain format. The keychain format is a JSON string containing base64-encoded data:
"AgRLwusU2xH3whuHbLUPAKw/tgnqZkuu28c5hWQaD/VPgCJmn0C4g+7UUMNSqFHBw3ItFLj0dMdVYuA64kBCFtbE"
The encoded data is 66 bytes:
- 1 byte: type (0x02 for P-256)
- 1 byte: format (0x00)
- 32 bytes: X coordinate
- 32 bytes: Y coordinate
This format is compatible with DarkStar's NewDarkStarClient function.
keyID can be either a P-256 private key (KeyTypeP256) or a P-256 public key (KeyTypeP256Public). For private keys, the public key is extracted from metadata.
func (*Store) GenerateEd25519 ¶ added in v0.0.4
GenerateEd25519 creates a new Ed25519 keypair and stores the private key seed. Returns the public key as ed25519.PublicKey for use with signature verification.
func (*Store) GenerateP256 ¶
GenerateP256 creates a new P-256 keypair and stores the private key. Returns the public key as *ecdh.PublicKey for use with ECDH key agreement.
func (*Store) GenerateSymmetricKey ¶
GenerateSymmetricKey creates a random symmetric key of the specified length.
func (*Store) GenerateX25519 ¶
GenerateX25519 creates a new X25519 keypair and stores the private key. Returns the public key as *ecdh.PublicKey for use with ECDH key agreement.
func (*Store) GetDefaultIdentity ¶
GetDefaultIdentity retrieves the default identity.
func (*Store) GetDefaultIdentityPublicKeys ¶
func (s *Store) GetDefaultIdentityPublicKeys() (*IdentityPublicKeys, error)
GetDefaultIdentityPublicKeys retrieves the public keys for the default identity.
func (*Store) GetIdentity ¶
GetIdentity retrieves an identity by ID.
func (*Store) GetIdentityPublicKeys ¶
func (s *Store) GetIdentityPublicKeys(id string) (*IdentityPublicKeys, error)
GetIdentityPublicKeys retrieves the public keys for an identity.
func (*Store) GetMetadata ¶
func (s *Store) GetMetadata(id SecretID) (*SecretMetadata, error)
GetMetadata returns metadata for a secret without decrypting the secret itself. Note: This still requires decryption since metadata is inside the age envelope.
func (*Store) GetOTPPadInfo ¶
GetOTPPadInfo retrieves metadata about an OTP pad without loading the pad itself.
func (*Store) IdentityExists ¶
IdentityExists checks if an identity exists.
func (*Store) ImportEd25519KeyToIdentity ¶ added in v0.0.4
ImportEd25519KeyToIdentity imports an existing Ed25519 private key seed to an identity. The privateKey should be a 32-byte Ed25519 seed.
func (*Store) ImportP256KeyToIdentity ¶
ImportP256KeyToIdentity imports an existing P-256 private key to an identity.
func (*Store) ImportP256PublicKey ¶ added in v0.0.5
ImportP256PublicKey imports a P-256 public key from Keychain format. The keychainFormat should be a JSON string like: "AgRLwusU2xH3whuHbLUPAKw/tgn..." (including the quotes). The imported key can be used for ECDH key derivation with a P-256 private key.
func (*Store) ImportX25519KeyToIdentity ¶
ImportX25519KeyToIdentity imports an existing X25519 private key to an identity.
func (*Store) ListIdentities ¶
ListIdentities returns all stored identities.
func (*Store) ListOTPPads ¶
ListOTPPads returns metadata for all stored OTP pads.
func (*Store) ListSecrets ¶
func (s *Store) ListSecrets() ([]SecretMetadata, error)
ListSecrets returns metadata for all stored secrets.
func (*Store) LoadEd25519PublicKey ¶ added in v0.0.6
LoadEd25519PublicKey loads an Ed25519 public key from the store.
func (*Store) LoadP256PublicKey ¶ added in v0.0.6
LoadP256PublicKey loads a P-256 public key from the store.
func (*Store) LoadPublicKey ¶
LoadPublicKey loads a public key from the store. Returns the raw bytes and key type. For typed methods, use LoadEd25519PublicKey, LoadX25519PublicKey, or LoadP256PublicKey.
func (*Store) LoadSecret ¶
func (s *Store) LoadSecret(id SecretID) (*memguard.LockedBuffer, *SecretMetadata, error)
LoadSecret decrypts and returns a secret in protected memory. The caller MUST call Destroy() on the returned LockedBuffer when done.
func (*Store) LoadSymmetricKey ¶
func (s *Store) LoadSymmetricKey(id SecretID) (*memguard.LockedBuffer, error)
LoadSymmetricKey loads a symmetric key into protected memory. The caller MUST call Destroy() on the returned LockedBuffer when done.
func (*Store) LoadX25519PublicKey ¶ added in v0.0.6
LoadX25519PublicKey loads an X25519 public key from the store.
func (*Store) NaClBoxDecryptWithStore ¶ added in v0.0.2
func (s *Store) NaClBoxDecryptWithStore( privateKeyID SecretID, peerPublicKey []byte, message []byte, ) ([]byte, error)
NaClBoxDecryptWithStore decrypts using a private key from the store. The private key is loaded only for this operation.
func (*Store) NaClBoxEncryptWithStore ¶ added in v0.0.2
func (s *Store) NaClBoxEncryptWithStore( privateKeyID SecretID, peerPublicKey []byte, plaintext []byte, ) ([]byte, error)
NaClBoxEncryptWithStore encrypts using a private key from the store. The private key is loaded only for this operation.
func (*Store) OTPBytesRemaining ¶
OTPBytesRemaining returns how many unused bytes remain in the pad.
func (*Store) OTPDecrypt ¶
OTPDecrypt XORs data with the next unused bytes from the pad. This is identical to OTPEncrypt (XOR is symmetric) but provided for clarity.
func (*Store) OTPDecryptBits ¶
OTPDecryptBits XORs a specific number of bits with the pad.
func (*Store) OTPDecryptWSPR ¶
OTPDecryptWSPR decrypts a PackedWSPRMessage-format 11-byte array.
func (*Store) OTPEncrypt ¶
OTPEncrypt XORs data with the next unused bytes from the pad. The pad offset is advanced to prevent reuse.
func (*Store) OTPEncryptBits ¶
OTPEncryptBits XORs a specific number of bits with the pad. This is useful for the 50-bit packed format you mentioned. The bits are taken from the least significant bits of the input bytes.
func (*Store) OTPEncryptWSPR ¶
OTPEncryptWSPR encrypts a PackedWSPRMessage-format 11-byte array. This XORs the 50 data bits (B0-B5 full bytes + B6 low 2 bits) while preserving B6 high bits and B7-B10 as zero.
Format from codex.go:
- B0-B5: Full octets (8 bits each = 48 bits)
- B6: Quartet (2 bits, values 0-3)
- B7-B10: Always zero
func (*Store) OTPSetOffset ¶
OTPSetOffset manually sets the pad offset. Use with caution.
func (*Store) OTPSkip ¶
OTPSkip advances the pad offset without using the bytes for encryption. Use when synchronizing with a remote party that has already consumed bytes.
func (*Store) SecretExists ¶
SecretExists checks if a secret exists without decrypting it.
func (*Store) Sign ¶ added in v0.0.4
Sign signs data with the Ed25519 private key identified by id. Returns a 64-byte signature.
func (*Store) StoreEd25519PublicKey ¶ added in v0.0.4
StoreEd25519PublicKey stores an Ed25519 public key (for a contact).
func (*Store) StoreOTPPad ¶
StoreOTPPad stores a new one-time pad.
func (*Store) StoreP256PublicKey ¶
StoreP256PublicKey stores a P-256 public key (for a contact). Accepts *ecdh.PublicKey from ecdh.P256().
func (*Store) StoreSecret ¶
StoreSecret encrypts and persists a secret using age.
func (*Store) StoreX25519PublicKey ¶
StoreX25519PublicKey stores an X25519 public key (for a contact). Accepts *ecdh.PublicKey from ecdh.X25519().
func (*Store) UpdateIdentity ¶
UpdateIdentity updates an identity's metadata (name, etc.).