Documentation ¶
Index ¶
- Constants
- Variables
- func AllNeedlesInHaystack(needles *[][]rune, haystack *[][]rune, caseInsensitive ...bool) bool
- func AnyNeedleInHaystack(needles *[][]rune, haystack *[][]rune) bool
- func AnyOfThem(haystack *[][]rune, needle *[]rune) bool
- func AskAndConfirmPassword(prompt string, minimumEntropyBits float64) (*[]byte, error)
- func AskForPassword(prompt string, minimumLength int) *[]byte
- func ByteCopy(src *[]byte) []byte
- func BytePtr(s []byte) *[]byte
- func ColumnSizes(rs [][][]rune, headerFields ...string) (columnSizes []int)
- func EqualRunes(a *[]rune, b *[]rune) bool
- func EqualRunesFold(a *[]rune, b *[]rune) bool
- func GeneratePFK() string
- func GenerateSalt() string
- func HighestInt(number ...int) (highest int)
- func IsTerminal() bool
- func JoinRunesToString(runes *[][]rune, separator string) string
- func LowestInt(number ...int) (lowest int)
- func OldAskAndConfirmPassword(prompt string, minimumLength int) (*[]byte, error)
- func RandomAlnumRunes(n int) []rune
- func RandomWipe(b *[]rune) error
- func RandomWipeBytes(b *[]byte) error
- func RuneCopy(src *[]rune) []rune
- func RunePtr(s []rune) *[]rune
- func RunesToStrings(runes *[][]rune) (stringSlice []string)
- func SetMinimumPasswordEntropyBits(entropy float64)
- func TrimRightRuneFunc(s []rune, f func(rune) bool) []rune
- func VettedCallSigns(callsigns ...string) [][]rune
- func VettedKeepers(keepers ...string) (vettedKeepers [][]rune)
- func VettedKeys(keys ...string) [][]rune
- func VettedMessageIds(ids ...string) [][]rune
- func VettedRecipients(recipients ...string) [][]rune
- func Wipe(b *[]rune) error
- func WipeBytes(b *[]byte) error
- func ZeroWipe(b *[]rune) error
- func ZeroWipeBytes(b *[]byte) error
- type GroupFormatter
- type Key
- func (k *Key) AddKeeper(keepers ...[]rune) *Key
- func (k *Key) CommentString() string
- func (k *Key) CompromisedString() string
- func (k *Key) ContainsKeeper(keepers ...[]rune) bool
- func (k *Key) GetCallSign() []rune
- func (k *Key) GetInstance() *Krypto431
- func (k Key) GoString() string
- func (k *Key) Groups() (*[]rune, error)
- func (k *Key) GroupsBlock() (*[]rune, error)
- func (k *Key) IdString() string
- func (k *Key) IsExpired() bool
- func (k *Key) IsValid(d time.Duration) bool
- func (k *Key) IsValidOneDay() bool
- func (k *Key) IsValidOneMonth() bool
- func (k *Key) IsValidOneYear() bool
- func (k *Key) JoinKeepers(separator string) string
- func (k *Key) KeyLength() int
- func (k *Key) RandomWipe() error
- func (k *Key) RemoveKeeper(keepers ...[]rune) *Key
- func (k *Key) SetInstance(instance *Krypto431) *Key
- func (k *Key) String() string
- func (k *Key) UsedOrNotString(used string, notUsed string) string
- func (k *Key) UsedString(rightSpacing ...int) string
- func (k *Key) Wipe() error
- func (k *Key) ZeroWipe() error
- type Krypto431
- func (k *Krypto431) Assert() error
- func (k *Krypto431) CallSignString() string
- func (k *Krypto431) Close()
- func (k *Krypto431) ContainsKeyId(keyId *[]rune) bool
- func (k *Krypto431) ContainsMessageId(msgId *[]rune) bool
- func (k *Krypto431) DeleteKey(keyIds ...[]rune) (int, error)
- func (k *Krypto431) DeleteKeyByString(keyIds ...string) (int, error)
- func (k *Krypto431) DeleteKeysBySummaryString(summaryStrings ...string) (int, error)
- func (k *Krypto431) DeleteMessage(messageIds ...[]rune) (int, error)
- func (k *Krypto431) DeleteMessageByString(messageIds ...string) (int, error)
- func (k *Krypto431) DeleteMessagesBySummaryString(summaryStrings ...string) (int, error)
- func (k *Krypto431) DerivePFKFromPassword(password *[]byte) error
- func (k *Krypto431) DerivePFKFromPasswordWithValidation(password *[]byte) error
- func (k *Krypto431) ExportKeys(filterFunction func(key *Key) bool, opts ...Option) Krypto431
- func (r *Krypto431) FindKey(recipients ...[]rune) *Key
- func (k *Krypto431) GenerateKeys(n int, expire *string, keepers ...string) error
- func (k *Krypto431) GetCallSign() []rune
- func (r *Krypto431) GetKey(keyId []rune) (*Key, error)
- func (k *Krypto431) GetPFK() *[]byte
- func (k *Krypto431) GetPFKString() string
- func (k *Krypto431) GetPersistence() string
- func (k *Krypto431) GetSalt() *[]byte
- func (k *Krypto431) GetSaltString() string
- func (k *Krypto431) ImportKeys(filterFunction func(key *Key) bool, opts ...Option) (int, error)
- func (k *Krypto431) IsInteractive() bool
- func (k *Krypto431) IsOverwriteExistingKeysOnImport() bool
- func (k *Krypto431) KeysAsText(filter func(key *Key) bool) string
- func (k *Krypto431) KeysPDF(filter func(key *Key) bool, filename string) error
- func (k *Krypto431) KeysTextFile(filter func(key *Key) bool, filename string) error
- func (k *Krypto431) Load() error
- func (r *Krypto431) MarkKeyUsed(keyId []rune, used bool) error
- func (k *Krypto431) MessagesAsText(filter func(msg *Message) bool) string
- func (k *Krypto431) MessagesPDF(filter func(msg *Message) bool, filename string) error
- func (k *Krypto431) MessagesTextFile(filter func(msg *Message) bool, filename string) error
- func (k *Krypto431) NewKey(expire time.Time, keepers ...string) *Key
- func (k *Krypto431) NewTextMessage(msg ...string) (*Message, error)
- func (k *Krypto431) NewTextMessageFromReader(r io.Reader) (*Message, error)
- func (k *Krypto431) NewUniqueMessageId() []rune
- func (k *Krypto431) ParseRadiogram(radiogram string) (*Message, error)
- func (k *Krypto431) PromptNewTextMessage() (*Message, error)
- func (k *Krypto431) Save() error
- func (k *Krypto431) SetCallSign(callsign string) error
- func (k *Krypto431) SetInteractive(state bool) *Krypto431
- func (k *Krypto431) SetOverwriteExistingKeysOnImport(state bool) *Krypto431
- func (k *Krypto431) SetPFKFromPassword(password string) error
- func (k *Krypto431) SetPFKFromString(key string) error
- func (k *Krypto431) SetPersistence(filename string)
- func (k *Krypto431) SetSaltFromString(salt string) error
- func (k *Krypto431) SummaryOfKeys(filter func(key *Key) bool) (header []rune, lines [][]rune)
- func (k *Krypto431) SummaryOfMessages(filter func(msg *Message) bool) (header []rune, lines [][]rune)
- func (k *Krypto431) Wipe()
- type Message
- func (m *Message) AddRecipient(recipients ...[]rune) *Message
- func (m *Message) ContainsRecipient(recipients ...[]rune) bool
- func (m *Message) Decipher() error
- func (m *Message) Encipher() error
- func (m *Message) EnrichWithKey() error
- func (m *Message) GetInstance() *Krypto431
- func (m Message) GoString() string
- func (m *Message) Groups() (*[]rune, error)
- func (m *Message) GroupsBlock() (*[]rune, error)
- func (m *Message) IdString() string
- func (m *Message) IsMyCall() bool
- func (m *Message) JoinRecipients(separator string) string
- func (m *Message) QRZ() []rune
- func (m *Message) QRZString() string
- func (m *Message) RandomWipe()
- func (m *Message) RemoveRecipient(recipients ...[]rune) *Message
- func (m *Message) SetInstance(instance *Krypto431)
- func (m *Message) String(width ...int) string
- func (m *Message) TryDecipherPlainText(dryrun ...bool) error
- func (m *Message) Wipe()
- func (m *Message) ZeroWipe()
- type Option
- func WithCallSign(cs string) Option
- func WithColumns(n int) Option
- func WithGroupSize(n int) Option
- func WithInteractive(b bool) Option
- func WithKeyColumns(n int) Option
- func WithKeyLength(n int) Option
- func WithMutex(mu *sync.Mutex) Option
- func WithOverwriteExistingKeysOnImport(b bool) Option
- func WithOverwritePersistenceIfExists(b bool) Option
- func WithPFK(key *[]byte) Option
- func WithPFKString(hexEncodedString string) Option
- func WithPersistence(savefile string) Option
- func WithSalt(salt *[]byte) Option
- func WithSaltString(salt string) Option
- type Wiper
- Bugs
Constants ¶
const ( MinimumCallSignLength int = 2 DefaultGroupSize int = 5 DefaultKeyLength int = 350 // 70 groups, 5 groups per row is 14 rows total DefaultColumns int = 110 DefaultKeyColumns int = 30 DefaultPersistence string = "~/.krypto431.gob" DefaultKeyCapacity int = 50000 // 50k keys DefaultChunkCapacity int = 20 // 20 chunks DefaultEncodedTextCapacity int = DefaultKeyLength * 2 // 700 DefaultMessageCapacity int = 10000 // 10k messages DefaultPlainTextCapacity int = DefaultKeyLength * DefaultChunkCapacity // 7000 DefaultPBKDF2Iteration int = 310000 // https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html DefaultMinimumPasswordEntropyBits float64 = 60 MinimumSupportedKeyLength int = 20 MinimumColumnWidth int = 85 // Trigraph table is 80 characters wide MinimumSaltLength int = 32 // Fixed salt for pbkdf2 derived keys. Can be changed using // krypto431.New(krypto431.WithSalt(hexEncodedSaltString)) when initiating a // new instance. You can use GenerateSalt() to generate a new salt for use in // WithSalt() and your UI program. DefaultSalt string = "d14461856f830fc5a1f9ba1b845fae5f61c54767ded39cf943174e6869b44476" )
defaults, most are exported
const ( // How many control runes/characters are required to change key at most? // (change table, then changeKeyChar = 2) ControlCharactersNeededToChangeKey int = 2 )
const LineBreak string = "\n"
Variables ¶
var ( CharacterTablePrimary []rune = []rune(`ABCDEFGHIJKLMNOP RSTUVWXY¤`) CharacterTableSecondary []rune = []rune(`0123456789?-ÅÄÖ.Q,Z:+/¤¤¤¤`) // Encoding uses two character tables (primary and secondary). NB! Any changes // to the control characters in these tables need to be reflected in functions // encodeCharacter() and decodeCharacter(). // CharacterTablePrimary = `ABCDEFGHIJKLMNOP RSTUVWXY¤`, // CharacterTableSecondary = `0123456789?-ÅÄÖ.Q,Z:+/¤¤¤¤` // // CODING LEGEND ⎘ Switch table (Z) // IDX ABCDEFGHIJKLMNOPQRSTUVWXYZ ⬔ Toggle binary mode (W) // CT1 ABCDEFGHIJKLMNOP RSTUVWXY⎘ ↕ Toggle case (X) // CT2 0123456789?-ÅÄÖ.Q,Z:+/⬔↕⌥⎘ ⌥ Change key (Y) CharacterTables [][]rune = [][]rune{ CharacterTablePrimary, CharacterTableSecondary, } )
var ( ErrNilPointer = errors.New("received a nil pointer") ErrCipherTextTooShort = errors.New("message cipher text is too short to decipher") ErrNoKey = errors.New("message has an invalid or no key") ErrKeyNotFound = errors.New("key not found") ErrInvalidCoding = errors.New("invalid character in encoded text (must be between A-Z)") ErrInvalidControlChar = errors.New("invalid control character") ErrTableTooShort = errors.New("out-of-bounds, character table is too short") ErrUnsupportedTable = errors.New("character table not supported") ErrOutOfKeys = errors.New("can not encipher multi-key message, unable to find additional key(s)") ErrNoCallSign = errors.New("need to specify your call-sign") ErrInvalidCallSign = fmt.Errorf("invalid call-sign, should be at least %d characters long", MinimumCallSignLength) ErrNoPersistence = errors.New("missing file name for persisting keys, messages and settings") ErrInvalidGroupSize = errors.New("group size must be 1 or longer") ErrKeyTooShort = fmt.Errorf("key length must be %d characters or longer", MinimumSupportedKeyLength) ErrTooNarrow = fmt.Errorf("column width must be at least %d characters wide", MinimumColumnWidth) ErrKeyColumnsTooShort = errors.New("key column width less than group size") ErrFormatting = errors.New("formatting error") ErrNotCipherText = errors.New("plaintext not identified as ciphertext") )
var ( ErrNoRadiogramProvided = errors.New("no radiogram provided") ErrParsingRadiogram = errors.New("unable to parse radiogram") )
var ( NilRunes []rune = []rune("NIL") HelpTextRadiogram string = `` /* 610-byte string literal not displayed */ // Full message format (012345 = Date-Time Group, abbreviated or full e.g // 012345AJAN23). Action addressees (adressmening), precedence or message // instructions (tjänsteanmärkning) are all non-capturing groups. // AA BB CC DE DD 012345 == XY ZZ/P == COL 3 = ABCDE FGHIJ KLMNO = K // DE VP 012345 == BA == COL 3 = ABCDE FGHIJ KLMNO = K // Group 1 = TO (can be empty), // Group 2 = FROM, // Group 3 = DTG (optional, can be empty!), // Group 4 = Message text (will include trailing = K, K, +, etc) MessageRegexpFull *regexp.Regexp = regexp.MustCompile(`(?i)([A-Z0-9/,\s]*)(?:\s+|^)DE\s+([A-Z0-9/]+)\s*([0-9]{6}[A-Z]{0,1}(?:JAN|FEB|MAR|APR|MAY|MAJ|JUN|JUL|AUG|SEP|OCT|OKT|NOV|DEC){0,1}(?:[0-9]{2}){0,1}){0,1}\s*==\s*(?:[A-Z0-9/,\s]*)\s*==\s*(?:[A-Z\s]*\s*[\d]*)\s*=\s*(.*)`) // Semi-full message format, without message instructions (tjänsteanmärkning), // optional group count (both are non-capturing groups). // AA DE BB 012345 == VJ QJ 3 = ABCDE FGHIJ KLMNO = K // AA DE BB 012345 == VJ QJ = HELLO WORLD = K // Group 1 = TO (can be empty), // Group 2 = FROM, // Group 3 = DTG (optional, can be empty!), // Group 4 = Message text (will include trailing = K, K, +, etc) MessageRegexpSemi *regexp.Regexp = regexp.MustCompile(`(?i)([A-Z0-9/,\s]*)(?:\s+|^)DE\s+([A-Z0-9/]+)\s*([0-9]{6}[A-Z]{0,1}(?:JAN|FEB|MAR|APR|MAY|MAJ|JUN|JUL|AUG|SEP|OCT|OKT|NOV|DEC){0,1}(?:[0-9]{2}){0,1}){0,1}\s*==\s*(?:[A-Z0-9/,\s]*\s*[\d]*)\s*=\s*(.*)`) // Short message format. // AA BB CC DE VJ 012345 COL = HELLO WORLD = SECTION 2 GOES HERE, INCLUDED IN TXT = K // AA BB CC DE VJ 012345 = HELLO WORLD // AA DE VJ = HELLO WORLD // DE VJ = HELLO WORLD = K // Group 1 = TO (can be empty), // Group 2 = FROM, // Group 3 = DTG (optional, can be empty!), // Group 4 = Message text (will include trailing = K, K, +, etc) MessageRegexpShort *regexp.Regexp = regexp.MustCompile(`(?i)([A-Z0-9/,\s]*)(?:\s+|^)DE\s+([A-Z0-9/]+)\s*([0-9]{6}[A-Z]{0,1}(?:JAN|FEB|MAR|APR|MAY|MAJ|JUN|JUL|AUG|SEP|OCT|OKT|NOV|DEC){0,1}(?:[0-9]{2}){0,1}){0,1}\s*(?:[A-Z]{0,4}\s*[\d]{0,4})\s*=\s*(.*)`) // Even shorter format. // DE SA6MWA HELLO WORLD // AB DE ZY 012345 WELL, HELLO THERE = K // Group 1 = TO (can be empty), // Group 2 = FROM, // Group 3 = DTG (optional, can be empty!), // Group 4 = Message text (will include trailing = K, K, +, etc) MessageRegexpMini *regexp.Regexp = regexp.MustCompile(`(?i)([A-Z0-9/,\s]*)(?:\s+|^)DE\s+([A-Z0-9/]+)\s*([0-9]{6}[A-Z]{0,1}(?:JAN|FEB|MAR|APR|MAY|MAJ|JUN|JUL|AUG|SEP|OCT|OKT|NOV|DEC){0,1}(?:[0-9]{2}){0,1}){0,1}\s*=*\s*(.*)`) // Regexp to match trailing = K, K, +, [AR], AR, etc in a string (e.g to clean // up the message text). // MessageTrailRegexp.ReplaceAllString(messageText, "") MessageTrailRegexp *regexp.Regexp = regexp.MustCompile(`(?i)(\s*=\s*[K+]|\s[K+]|\s*\[AR\]|\s*=\s*AR)\s*$`) )
var ( RepeatPromptSuffix string = "(repeat) " EncryptionPrompt string = "Enter encryption key: " DecryptionPrompt string = "Enter decryption key: " NewEncryptionPrompt string = "Enter new encryption key: " )
var ( ErrNoSalt = errors.New(errUnableToDerivePFK + "instance is missing salt") ErrTooShortSalt = errors.New(errUnableToDerivePFK + "salt is too short") //ErrPasswordTooShort = fmt.Errorf(errUnableToDerivePFK+"too short, must be at least %d characters long", MinimumPasswordLength) ErrNilPFK = errors.New("instance is missing key needed to encrypt or decrypt persistence") ErrInvalidPFK = errors.New("persistence file key is invalid, must be 32 bytes long") ErrPasswordInput = errors.New("password input error") ErrCopyKeyFailure = errors.New("copy key failure") )
var (
CustomMultilineQuestionTemplate string = `` /* 457-byte string literal not displayed */
)
var ( LineBreak + `IDX A B C D E F G H I J K L M N O P Q R S T U V W X Y Z ¤ Toggle binary mode (W)` + LineBreak + `CT1 A B C D E F G H I J K L M N O P R S T U V W X Y > ↕ Toggle case (X)` + LineBreak + `CT2 0 1 2 3 4 5 6 7 8 9 ? - Å Ä Ö . Q , Z : + / ¤ ↕ → > → Change key (Y)` + LineBreak )`CODING LEGEND > Switch table (Z)` +
var (
MinimumPasswordEntropyBits float64 = DefaultMinimumPasswordEntropyBits
)
var Version string
var (
Words = map[string]string{
"No": "No",
"Yes": "Yes",
}
)
Functions ¶
func AllNeedlesInHaystack ¶
AllNeedlesInHaystack returns true is all needles can be found in the haystack. Final variadic is optional, first true will match case-insensitive instead of matching case. Intended to find Keepers of Keys where needles are Message.Recipients and haystack is Key.Keepers.
func AnyNeedleInHaystack ¶
func AskAndConfirmPassword ¶
func AskForPassword ¶
AskForPassword prompts the user for a password/passphrase and returns a byte slice pointer or nil on error. The byte slice should be wiped with WipeBytes() as soon as a key has been derived from it.
func ColumnSizes ¶
ColumnSizes calculates max length of each []rune in a slice of []rune slices. If optional column headers are provided (as a string slice), their length will be taken into account as well. Left for legacy, replaced by predictColumnSizes().
func EqualRunes ¶
Compare two rune slices. Returns true if they are equal, false if not.
func EqualRunesFold ¶
Same as EqualRunes, except EqualRunesFold is case-insensitive. Returns true if they are equal fold, false if not.
func GeneratePFK ¶
func GeneratePFK() string
Generate a random 32 byte persistence file key for use when loading/saving the persistence file. Returns a hex encoded string of 64 characters that you can use as e.g environment variable and is compatible with SetPFKFromString(). Beware that strings are immutable in Go - the internal wipe functions can not be used to clear this sensitive data. The default password-based method in Load() and Save() use byte or rune slices which are (or can be) wiped in an attempt not to leave sensitive data around in memory after the program exits. Function will panic if there is an error.
func GenerateSalt ¶
func GenerateSalt() string
Generate a hex string compatible with WithSaltString() and SetSaltFromString(). The hex string is MinimumSaltLength*2 (default 64) characters long which can be decoded into a MinimumSaltLength byte long byte slice using hex.DecodeString(). The salt is not a secret and should be shared with whoever is supposed to decrypt a Krypto431 persistence file (when, for example, exporting keys, messages or even main persistence files). Function will panic if there is an error.
func HighestInt ¶
Maximum int in int slice. Alternative MaxInt function.
func IsTerminal ¶
func IsTerminal() bool
IsTerminal returns true if os.Stdin is a terminal, false if not.
func JoinRunesToString ¶
Wrapper to strings.Join for a pointer to slices of rune slices. Returns a string with 'separator' as delimiter between items.
func OldAskAndConfirmPassword ¶
Asks for password confirmation. Returns error if passwords don't match or a byte slice pointer if they do.
func RandomAlnumRunes ¶
RandomAlnumRunes generates a case-sensitive alpha-numeric string as a rune slice of the length n. Returns a rune slice.
func RandomWipeBytes ¶
RandomWipeBytes wipes a byte slice with random bytes.
func RunesToStrings ¶
Generic function to convert an array of rune slices (runes) into a string slice.
func SetMinimumPasswordEntropyBits ¶
func SetMinimumPasswordEntropyBits(entropy float64)
Configure go-password-validator minimum entropy for the entire krypto431 package. Entropy limit is not instance-scoped (yet).
func VettedCallSigns ¶
VettedCallSigns is an alias for VettedKeepers.
func VettedKeepers ¶
Generic function to vet one or more keeper strings, comma/space-separated or not. Returns a slice of rune slices with the keepers for use in e.g Key.Keepers.
func VettedKeys ¶
VettedKeys is an alias for VettedKeepers.
func VettedMessageIds ¶
VettedMessageIds is NOT an alias for VettedKeepers :). Returns a slice of rune slices where case is preserved from the input (message IDs are case-sensitive). As with keepers, IDs can be space or comma separated.
func VettedRecipients ¶
VettedRecipients is an alias for VettedKeepers.
func ZeroWipeBytes ¶
ZeroWipeBytes wipes a byte slice with zeroes.
Types ¶
type GroupFormatter ¶
Returns a grouped string according to GroupSize set in the instance (Krypto431). Keys and Messages implement this interface.
type Key ¶
type Key struct { Id []rune Runes []rune Keepers [][]rune Created dtg.DTG Expires dtg.DTG Used bool Compromised bool Comment []rune // contains filtered or unexported fields }
Key struct holds a key. Keepers is a list of call-signs or other identifiers that have access to this key (and can use it for encryption/decryption). The proper procedure is to share the key with it's respective keeper(s).
func (*Key) AddKeeper ¶
AddKeeper adds keeper(s) to the Keepers slice if not already there. Can be chained.
func (*Key) CommentString ¶
func (*Key) CompromisedString ¶
Returns Yes if key is marked compromised, No if not.
func (*Key) ContainsKeeper ¶
func (*Key) GetCallSign ¶
func (*Key) GetInstance ¶
Return the Krypto431 instance (non-exported field) of a key.
func (*Key) Groups ¶
Groups for keys return a rune slice where each number of GroupSize runes are separated by a space. Don't forget to Wipe() this slice when you are done!
func (*Key) GroupsBlock ¶
GroupsBlock returns a string-as-rune-slice representation of the key where each group is separated by a space or new line if a line becomes longer than Krypto431.KeyColumns (e.g DefaultKeyColumns). Don't forget to Wipe(b []rune) this slice when you are done!
func (*Key) IsExpired ¶
Check if key is still valid or has expired, returns true if still valid, false if not.
func (*Key) IsValid ¶
Check if key is valid d amount of time before expiring (e.g 24*time.Hour for one day). Returns true if key does not expire within d time or false if it does.
func (*Key) IsValidOneDay ¶
Check if key is valid at least one day before expiring. Returns true if key does not expire within that time, false if not.
func (*Key) IsValidOneMonth ¶
Check if key is valid at least 30 days before expiring. Returns true if key does not expire within that time, false if not.
func (*Key) IsValidOneYear ¶
Check if key is valid at least one year (365 days) before expiring. Returns true if key does not expire within that time, false if not.
func (*Key) JoinKeepers ¶
func (*Key) RandomWipe ¶
RandomWipe overwrites key with random runes.
func (*Key) RemoveKeeper ¶
RemoveKeeper removes keeper(s) from the Keepers slice if found. Can be chained.
func (*Key) SetInstance ¶
Set instance of Krypto431 (non-exported field) for a key. Can be chained.
func (*Key) String ¶
Key_String returns a fully printable key with the DIANA reciprocal table and coding legend. Instructions are not included in the output.
func (*Key) UsedOrNotString ¶
Returns string used if key is marked used or string notUsed if not marked used.
func (*Key) UsedString ¶
Returns Yes if key is marked used, No if not. Optional rightSpacing pads the output string with trailing spaces.
type Krypto431 ¶
type Krypto431 struct { GroupSize int KeyLength int Columns int KeyColumns int Keys []Key Messages []Message CallSign []rune // contains filtered or unexported fields }
Krypto431 store generated keys, plaintext, ciphertext, callsign(s) and configuration items. CallSign is mandatory (something identifying yourself in message handling). It will be converted to upper case. Mutex and persistance file (persistence) are not exported meaning values will not be persisted to disk.
func (*Krypto431) Assert ¶
Asserts that settings in the instance are valid. Function is intended to be executed after New() to assert that settings are valid.
func (*Krypto431) CallSignString ¶
func (*Krypto431) ContainsKeyId ¶
ContainsKeyId checks if the Krypto431.Keys slice already contains Id and return true if it does, false if it does not.
func (*Krypto431) ContainsMessageId ¶
ContainsMessageId checks if the Krypto431.Messages slice already contains Id and return true if it does, false if it does not.
func (*Krypto431) DeleteKey ¶
DeleteKey removes one or more keys from the instance's Keys slice wiping the key before deleting it. Returns number of keys deleted or error on failure.
func (*Krypto431) DeleteKeyByString ¶
DeleteKeyByString is an alias for DeleteKey where key IDs are issued as strings instead of rune slices.
func (*Krypto431) DeleteKeysBySummaryString ¶
func (*Krypto431) DeleteMessage ¶
DeleteMessage removes one or more messages from the instance's Messages slice wiping the message before deleting it. Returns number of messages deleted or error on failure.
func (*Krypto431) DeleteMessageByString ¶
DeleteMessageByString is an alias for DeleteMessage where message IDs are issued as strings instead of rune slices.
func (*Krypto431) DeleteMessagesBySummaryString ¶
func (*Krypto431) DerivePFKFromPassword ¶
DerivePFKFromPassword uses PBKDF2 to produce the 32 byte long key used to encrypt/decrypt the persistence file. The salt in the Krypto431 instance is used to derive the key, either the default fixed salt or one that you provided earlier (e.g krypto431.New(krypto431.WithSalt(my64charHexString))).
func (*Krypto431) DerivePFKFromPasswordWithValidation ¶
Same as DerivePFKFromPassword, but validates the password against go-password-validator according to set minimum entropy bits.
func (*Krypto431) ExportKeys ¶
Krypto431.ExportKeys() returns a new instance based on the current instance where only the keys that pass the filterFunction are copied over (entirely w/o messages). The filterFunction must return true for each key to to export (copy to the new instance) and false to not copy the key. The new instance's persistence field (filename of the save-file) will be empty unless option function WithPersistence(filename) is specified (can also be configured afterwards with SetPersistence()). Any Option function (With*) can be used to override any copied field.
func (*Krypto431) FindKey ¶
FindKey returns the first un-used key of the configured group size where all recipients are keepers of that key. If the recipient slice is empty, it will find the first un-used anonymous key (a key without any keepers). Function returns a pointer to the key. FindKey will not mark the key as used.
func (*Krypto431) GenerateKeys ¶
GenerateKeys creates n amount of keys. The expire argument is a Date-Time Group when the key(s) is/are to expire (DDHHMMZmmmYY). If expire is nil, keys will expire one year from current time. If no keepers are provided, keys will be considered anonymous.
func (*Krypto431) GetCallSign ¶
func (*Krypto431) GetKey ¶
GetKey() searches for a Key object with an Id of keyId and returns a pointer to this Key or error if not found.
func (*Krypto431) GetPFK ¶
GetPFK returns a byte slice pointer to the instance persistence file key (PFK). Function exists as the persistenceKey field is not exported.
func (*Krypto431) GetPFKString ¶
GetPFKString (yes, it's Pascal-case) returns a hex-encoded string representation of the persistence file key (or empty if there is no PFK in this instance). Function exists as the persistenceKey field is not exported.
func (*Krypto431) GetPersistence ¶
GetPersistence returns the non-exported persistence string (save-file) from an instance.
func (*Krypto431) GetSaltString ¶
Similar to GetPFKString, but return a hex-encoded string of the salt.
func (*Krypto431) ImportKeys ¶
Krypto431_ImportKeys() does the opposite of ExportKeys(). The filterFunction runs on each key from the persistence file specified in the opts variadic WithPersistence(filename), for example:
ImportKeys(myFilter, krypto431.WithPersistence(filename), krypto431.WithInteractive(true))
The default salt is used when loading the file and the PFK is empty. Load() will interactively ask for password only if WithInteractive(true) is provided as an option or it will return an error. To override PFK and/or salt, use WithPFK() or WithPFKString(), WithSalt() or WithSaltString(). To use the key and salt from the current instance for the imported instance, you can do the following:
k.ImportKeys(f, WithPersistence(file), WithPFK(k.GetPFK()), WithSalt(k.GetSalt()))
If an imported key ID already exists in the receiving instance and interactive mode is enabled, function will ask for confirmation before overwriting. To force overwriting without asking, add WithOverwriteExistingKeysOnImport(true).
func (*Krypto431) IsInteractive ¶
IsInteractive returns true if instance functions can work in interactive mode.
func (*Krypto431) IsOverwriteExistingKeysOnImport ¶
func (*Krypto431) KeysAsText ¶
KeysAsText returns a formatted multi-line string with all keys according to filter function. For example, to return all keys not marked `used` as one big printable string...
s := krypto431.KeysAsText(func(k *krypto431.Key) bool { return !k.Used })
func (*Krypto431) KeysTextFile ¶
func (*Krypto431) Load ¶
Krypto431_Load() loads a Krypto431 instance from the configured persistence file (k.persistence). Only exported fields will be populated.
func (*Krypto431) MarkKeyUsed ¶
MarkKeyUsed() looks for the keyId among the instance's Keys and sets the Used property to true or false depending on what the "used" variable is set to.
func (*Krypto431) MessagesAsText ¶
MessagesAsText returns a formatted multi-line string with all messages according to filter function. For example, to return all messages as one big printable string...
s := krypto431.MessagesAsText(func(k *krypto431.Message) bool { return true })
func (*Krypto431) MessagesPDF ¶
func (*Krypto431) MessagesTextFile ¶
func (*Krypto431) NewKey ¶
NewKey generates a new key. The current implementation generates a random group not yet in the Krypto431 construct. Keepers can be one call-sign per variadic, comma-separated call-signs or a combination of both.
func (*Krypto431) NewTextMessage ¶
NewTextMessage creates a new message from a radiogram (Swedish Armed Forces telegraphy radiogram which can be thought of as simplified ACP 124). First argument is the radiogram, optional second argument is a key ID which - if specified - will override the key finder function if message is an outgoing message (a used or compromised key will not be allowed). If the From field (after DE in the radiogram) has the same call-sign as the instance's CallSign the message is considered an outgoing message. If From (DE) field is not your call-sign the message is considered an incoming message.
Outgoing messages (DE yourCallSign) will be enciphered with a key found automatically or with key specified as an optional second argument.
Incoming messages (DE notYourCallSign) will be attempted to be deciphered. If deciphering fails and it is still a valid incoming enciphered message, the cipher-text will stay in the PlainText field. The message function TryDecipherPlainText can safely be run prior to future presentation of the message, perhaps when the key - if initially missing in your store - has been obtained, deciphering may succeed (for example).
func (*Krypto431) NewTextMessageFromReader ¶
NewTextMessageFromReader is similar to PromptNewTextMessage except radiogram is read from an io.Reader (until EOF). There is no output except warnings/errors. BUG(sa6mwa): NewTextMessage and ParseRadiogram need to implement io.Reader instead.
func (*Krypto431) NewUniqueMessageId ¶
NewUniqueMessageId generates an alpha-numeric ID that is unique among the instance's messages. Returns a rune slice of length 4.
func (*Krypto431) ParseRadiogram ¶
ParseRadiogram attempts to break out the Recipients, From (DE), Date-Time Group and PlainText from a Swedish Armed Forces radiotelegraphy message formatted as transmitted/received. Function returns a pointer to a new Message object. If DTG is empty, Message time will be set to current local system time. ParseRadiogram will always put the radiogram text in the PlainText field and leave KeyId empty. TryDecipherPlainText can be safely called on the return message object (especially with dryrun==true) to automatically attempt to identify the PlainText as CipherText with prepended KeyId. By default, TryDecipherPlainText will attempt to decipher the PlainText which will result in a populated KeyId and CipherText field as well as the actual (deciphered) PlainText.
func (*Krypto431) PromptNewTextMessage ¶
PromptNewTextMessage prompts the user to enter a a new text message as a radiogram. If os.Stdin is not a terminal, radiogram is read from stdin without prompt. Returns a pointer to the new message or error on failure.
func (*Krypto431) Save ¶
Krypto431_Save persists a Krypto431 instance to file. The output file is a gzipped GOB (Go Binary) which is XSalsa20Poly1305 encrypted using a 32 byte key set via DerivePFKFromPassword(), SetPFKFromString() or WithPFK().
func (*Krypto431) SetCallSign ¶
Validates and sets the instance's call-sign.
func (*Krypto431) SetInteractive ¶
SetInteractive is provided to set the interactive non-exported field in an instance (true=on, false=off).
func (*Krypto431) SetOverwriteExistingKeysOnImport ¶
SetOverwriteExistingKeysOnImport answers
func (*Krypto431) SetPFKFromPassword ¶
Similar to SetPFKFromString() except it derives the key from a passphrase via the PBKDF2 function DerivePFKFromPassword. The instance's configured salt is used and need to be set before calling this function.
func (*Krypto431) SetPFKFromString ¶
Takes persistence file key (PFK) from a hex encoded string (from perhaps GeneratePFK()), converts it into a byte slice and sets it as the instance's PFK which will override the password-based key derivative function and the use of a salt. The key must be 32 bytes long (64 character long hex encoded string). GeneratePFK() is available to generate a new random persistence file key and return a hex encoded string. Beware that strings are immutable in Go which means the internal wipe functions can not be used to clear this sensitive string after closing or wiping the instance. The default password-based method use byte or rune slices which are (or can be) wiped in an attempt not to leave sensitive data around in memory after the program exits.
func (*Krypto431) SetPersistence ¶
SetPersistence sets the non-exported persistence property in the instance to filename.
func (*Krypto431) SetSaltFromString ¶
Takes salt from a hex encoded string, converts it into a byte slice and sets it as the instance's salt for the password-based key derivative function used in Load() and Save(). Beware! If you loose the salt you used for encrypting your persistance-file it will be practically impossible to decrypt it even if you know the password.
func (*Krypto431) SummaryOfKeys ¶
continue here TODO add sort function to list (for list, delete, etc). idea: let digest be pointer slice with keys, sort pointers based on date, etc...
sort.Slice(dateSlice, func(i, j int) bool { return dateSlice[i].sortByThis.Before(dateSlice[j].sortByThis) })
func (*Krypto431) SummaryOfMessages ¶
func (*Krypto431) Wipe ¶
func (k *Krypto431) Wipe()
Wipe instance assigned method wipes all in-memory keys and texts (plaintext and ciphertext) with random runes or zeroes in an attempt to keep sensitive information for as short time as possible in memory. Whenever keys or ciphertexts are written to the database they are wiped automatically, respectively, but it is up to the user of the API to call Wipe() or Close() when using the methods to read keys and ciphertext from database, file or stdin when done processing them.
type Message ¶
type Message struct { Id []rune Recipients [][]rune From []rune DTG dtg.DTG KeyId []rune PlainText []rune Binary []byte CipherText []rune Radiogram []rune // Raw radiogram // contains filtered or unexported fields }
Message holds plaintext and ciphertext. To encipher, you need to populate the PlainText (OR Binary) field, the rest will be updated by the Encipher function which will choose the next available key. If PlainText is longer than the key, the Encrypt function will use another key where the key's Keepers field matches all of the Recipients. If there are not enough keys to encrypt the message, Encrypt will fail. Encrypt will cache all non-used keys from the database matching the Recipients into the instance Keys slice before enciphering. To decrypt you need to have ciphertext in the CipherText field and the start KeyId. All binary data in the message will be appended to the Binary field. There is no method (yet) to figure out which of your keys can be used to decipher the message. If the KeyId is not already in your instace's Keys slice it will be fetched from the database or fail. The KeyId should be the first group in your received message.
func (*Message) AddRecipient ¶
AddRecipient adds recipient(s) to the Recipients slice if not already there. Can be chained.
func (*Message) ContainsRecipient ¶
ContainsRecipient returns true if all recipients are recipients of this message.
func (*Message) Decipher ¶
Decipher deciphers the CipherText field into the PlainText field of a Message object. PlainText will be replaced with deciphered text if text already exists. Decipher does not use a separate decoding function as simultaneous decoding is needed to support CipherText enciphered with multiple keys. If deciphering succeeds, all keys used in the message will be marked `used`.
func (*Message) Encipher ¶
Encipher() enciphers the PlainText field into the CipherText field of a Message object. Verbs encrypt and decrypt are only used for AES encryption/decryption of the persistance file, while words encipher and decipher are used for message ciphering in Krypto431.
func (*Message) EnrichWithKey ¶
EnrichWithKey finds the first appropriate key for this Message structure where each of the Messages Recipients are Keepers of the same key. If CipherText and KeyId already appear to be present, function will just return. If CipherText appear to be present, but message KeyId is empty it will return an error. If there is no CipherText or KeyId, the function will try to find one where all recipients are keepers of this key. The message KeyId will be used by diana.Trigraph during encryption/decryption.
func (*Message) GetInstance ¶
Return the Krypto431 instance (non-exported field) of a message.
func (*Message) Groups ¶
Groups for messages return a rune slice where each group (GroupSize) is separated by space. Don't forget to Wipe() this slice when you are done!
func (*Message) GroupsBlock ¶
GroupsBlock returns a string-as-rune-slice representation of the message cipher text where each group is separated by a space or new line if a line becomes longer than Krypto431.Columns (or DefaultColumns). Don't forget to Wipe() this slice when you are done!
func (*Message) IsMyCall ¶
IsMyCall returns true if From field is the same as the instance's call-sign, false if not.
func (*Message) JoinRecipients ¶
func (*Message) RandomWipe ¶
func (m *Message) RandomWipe()
RandomWipe assigned method for Text wipes PlainText, CipherText and KeyId fields.
func (*Message) RemoveRecipient ¶
RemoveRecipient removes recipient(s) from the Recipients slice if found. Can be chained.
func (*Message) SetInstance ¶
Set instance of Krypto431 (non-exported field) for a message.
func (*Message) String ¶
Message_String returns a formatted output intended to print. By default the width is 80 to fit consoles, but can be changed with the optional width variadic (first item in slice is used for column width).
func (*Message) TryDecipherPlainText ¶
TryDecipherPlainText attempts to identify PlainText that is actually CipherText prepended with a key. If optional dryrun is not true, function will copy possible key ID and ciphertext to the message and attempt to decipher it. On failure to decipher, the message object (KeyId and PlainText) is restored. Function will not run if the message has the KeyId filled in or the first group of the PlainText (key ID) can not be found in the key store. Returns error if CipherText detection/decipher was unsuccessful, nil if successful.
type Option ¶
type Option func(k *Krypto431)
Option fn type for the New() construct.
func WithCallSign ¶
func WithColumns ¶
func WithGroupSize ¶
func WithInteractive ¶
func WithKeyColumns ¶
func WithKeyLength ¶
func WithPFK ¶
WithPFK overrides deriving the encryption key for the persistance-file from a password by using the key directly. Must be 32 bytes long. Beware! Underlying byte slice will be wiped when closing or wiping the Krypto431 instance, but the New() function returns a reference not a pointer meaning there could still be a copy of this key in memory after wiping.
func WithPFKString ¶
As WithPFK, but takes a string and attempts to hex decode it into a byte slice. Not recommended to use as it doesn't fail on error just nils the key and leaves memory traces that can not be wiped. Use SetPFKFromString() on the instance after New() instead.
func WithPersistence ¶
func WithSalt ¶
WithSalt() can be used to override the default fixed salt with a custom salt. Beware that the underlying byte slice will be wiped when closing or wiping the Krypto431 instance. Use hex.DecodeString() to generate a 32 byte slice from a 64 byte hex string produced by for example GenerateSalt().
func WithSaltString ¶
WithSaltString() runs the salt string through hex.DecodeString() to derive a byte slice that, if at least 32 bytes long, is used instead of the default internal fixed salt. Not recommended as it just nils the salt on error, use WithSalt() and solve decoding with e.g hex.DecodeString() prior to instance creation. You can also use SetSaltFromString() on the instance after New().
Notes ¶
Bugs ¶
NewTextMessage and ParseRadiogram need to implement io.Reader instead.