From ef15d9b4267d60072bcd955e5dbc97f2744a3e18 Mon Sep 17 00:00:00 2001 From: tfn18001 Date: Tue, 19 Apr 2022 22:25:30 -0400 Subject: [PATCH] Added Crypto Readme --- CTng/crypto/Readme.md | 24 ++++++++++++++++++++++++ CTng/crypto/bls.go | 3 +-- CTng/crypto/crypto_config.go | 10 ++++++++++ CTng/crypto/crypto_test.go | 1 - CTng/crypto/generate_crypto.go | 16 +++++++++------- CTng/crypto/hash.go | 1 + CTng/crypto/types.go | 29 +++++++++++++++++------------ 7 files changed, 62 insertions(+), 22 deletions(-) create mode 100644 CTng/crypto/Readme.md diff --git a/CTng/crypto/Readme.md b/CTng/crypto/Readme.md new file mode 100644 index 0000000..360833e --- /dev/null +++ b/CTng/crypto/Readme.md @@ -0,0 +1,24 @@ +# Cryptography Implementations + +## Contents: +- `types.go`: type declarations with descriptions for all the files below. +- `bls.go`: implementation of k-of-n threshold signatures using a BLS library. +- `rsa.go`: Creates slightly simplified+application specific RSA functions from go's "crypto/rsa" library. +- `hash.go`: functions for hashing of data using a variety of schemes. +- `generate_crypto.go`: Given security constraints/requirements and the names of each entity in the network, generate BLS and RSA keys, and create and store CryptoConfig files for each entity. + +## crypto_config.go: +- `CryptoConfig` is an object that contains all the cryptographic information for an entity to use + - e.x: Mappings to public keys, Private keys, signature schemes being utilized, etc. +- For convenience, methods are defined for this object which use the information stored within the config to Hash, Sign, and Verify signatures. +- Thus, all cryptographic actions are condensed to a single object. + +## Signature Object Format: +- `RSASig`, `ThresholdSig`, and `SigFragment` are objects of signatures bundled with the signing entity. (BLS for the latter two). +- While this information is typically contained within a gossip object's Signer Field, there currently isn't a way to store multiple signers of data in a gossip object. Thus, this implementation is integral to the `ThresholdSig` Type. + +## cyrpto_test.go +The following tests are included: +1. Hash function test +2. K-of-n BLS key generation + signing/verifying with different subsets +3. IO function tests: Writes and then reads a cryptoconfig and verifies functionality diff --git a/CTng/crypto/bls.go b/CTng/crypto/bls.go index ab5521b..c82c312 100644 --- a/CTng/crypto/bls.go +++ b/CTng/crypto/bls.go @@ -89,9 +89,8 @@ func ThresholdAggregate(sigs []SigFragment, threshold int) (ThresholdSig, error) return aggregate, nil } -// Verify a threshold signature. +// Verify an aggregated threshold signature against the message and the public keys func (sig ThresholdSig) Verify(msg string, pubs *BlsPublicMap) bool { - // Verify the aggregated signature against the message and the public keys // Construct the list of public keys pubList := make([]bls.PublicKey, len(sig.IDs)) for i := range sig.IDs { diff --git a/CTng/crypto/crypto_config.go b/CTng/crypto/crypto_config.go index ca9977b..4931c1e 100644 --- a/CTng/crypto/crypto_config.go +++ b/CTng/crypto/crypto_config.go @@ -17,6 +17,7 @@ type CryptoConfigInterface interface { FragmentVerify(string, SigFragment) error } +// Hash a message using the configured hash scheme. func (c *CryptoConfig) Hash(msg []byte) ([]byte, error) { if c.HashScheme == SHA256 { return GenerateSHA256(msg) @@ -26,6 +27,8 @@ func (c *CryptoConfig) Hash(msg []byte) ([]byte, error) { return nil, errors.New("Hash Scheme not supported") } +// Sign a message using the configured "normal signature" scheme. +// Note: This is not a threshold signature/threshold signature fragment. func (c *CryptoConfig) Sign(msg []byte) (RSASig, error) { if c.SignScheme == "rsa" { return RSASign(msg, &c.RSAPrivateKey, c.SelfID) @@ -33,6 +36,7 @@ func (c *CryptoConfig) Sign(msg []byte) (RSASig, error) { return RSASig{}, errors.New("Sign Scheme not supported") } +// Verify a message using the configured "normal signature" scheme, and the stored public keys. func (c *CryptoConfig) Verify(msg []byte, sig RSASig) error { if c.SignScheme == "rsa" { pub := c.SignaturePublicMap[sig.ID] @@ -41,6 +45,7 @@ func (c *CryptoConfig) Verify(msg []byte, sig RSASig) error { return errors.New("Sign Scheme not supported") } +// Sign a message to make a keyfragment using the configured "threshold signature" scheme. func (c *CryptoConfig) ThresholdSign(msg string) (SigFragment, error) { if c.ThresholdScheme == "bls" { return ThresholdSign(msg, &c.ThresholdSecretKey, c.SelfID), nil @@ -49,6 +54,7 @@ func (c *CryptoConfig) ThresholdSign(msg string) (SigFragment, error) { return SigFragment{}, errors.New("Threshold Scheme not supported") } +// Aggregate a list of threshold signature fragments to make a threshold signature. func (c *CryptoConfig) ThresholdAggregate(sigs []SigFragment) (ThresholdSig, error) { if c.ThresholdScheme == "bls" { sig, err := ThresholdAggregate(sigs, c.Threshold) @@ -61,6 +67,8 @@ func (c *CryptoConfig) ThresholdAggregate(sigs []SigFragment) (ThresholdSig, err return ThresholdSig{}, errors.New("Threshold Scheme not supported") } +// Verify a threshold signature using the configured "threshold signature" scheme, and the stored public keys. +// Uses the keys stored in the CryptoConfig struct to verify the signature. func (c *CryptoConfig) ThresholdVerify(msg string, sig ThresholdSig) error { if c.ThresholdScheme == "bls" { if sig.Verify(msg, &c.ThresholdPublicMap) { @@ -72,6 +80,8 @@ func (c *CryptoConfig) ThresholdVerify(msg string, sig ThresholdSig) error { return errors.New("Threshold Scheme not supported") } +// Verify the validity of a single signature fragment using the configured "threshold signature" scheme. +// Uses the keys stored in the CryptoConfig struct to verify the signature. func (c *CryptoConfig) FragmentVerify(msg string, sig SigFragment) error { if c.ThresholdScheme == "bls" { if sig.Verify(msg, &c.ThresholdPublicMap) { diff --git a/CTng/crypto/crypto_test.go b/CTng/crypto/crypto_test.go index 59ed586..8de798a 100644 --- a/CTng/crypto/crypto_test.go +++ b/CTng/crypto/crypto_test.go @@ -74,7 +74,6 @@ func TestSHA256(t *testing.T) { } func TestBLSFunctionality(T *testing.T) { - // Just entities := []CTngID{ "a", "b", diff --git a/CTng/crypto/generate_crypto.go b/CTng/crypto/generate_crypto.go index b285aa5..dad6eb4 100644 --- a/CTng/crypto/generate_crypto.go +++ b/CTng/crypto/generate_crypto.go @@ -13,6 +13,8 @@ type CryptoStorage interface { ReadCryptoConfig(file string) (*CryptoConfig, error) } +// Generate a list of cryptoconfigs from a list of entity names. +// The threshold determines the k value in "k-of-n" threshold signing. func GenerateEntityCryptoConfigs(entityIDs []CTngID, threshold int) ([]CryptoConfig, error) { ThresholdScheme := "bls" SignScheme := "rsa" @@ -41,7 +43,7 @@ func GenerateEntityCryptoConfigs(entityIDs []CTngID, threshold int) ([]CryptoCon } //Generate configs without individual information - for i, _ := range configs { + for i := range configs { configs[i] = CryptoConfig{ ThresholdScheme: ThresholdScheme, SignScheme: SignScheme, @@ -58,6 +60,8 @@ func GenerateEntityCryptoConfigs(entityIDs []CTngID, threshold int) ([]CryptoCon return configs, nil } +// Saves a list of cryptoconfigs to files in a directory. +// Each file is named the ID of the corresponding entity. func SaveCryptoFiles(directory string, configs []CryptoConfig) error { for _, config := range configs { // fmt.Print(config) @@ -70,6 +74,7 @@ func SaveCryptoFiles(directory string, configs []CryptoConfig) error { return nil } +// Read a storedcryptoconfig from a file, convert it to a cryptoconfig and return a pointer to it. func ReadCryptoConfig(file string) (*CryptoConfig, error) { scc := new(StoredCryptoConfig) bytes, err := util.ReadByte(file) @@ -81,6 +86,7 @@ func ReadCryptoConfig(file string) (*CryptoConfig, error) { return cc, err } +// Converts a CryptoConfig to a marshal-able format. func NewStoredCryptoConfig(c *CryptoConfig) *StoredCryptoConfig { scc := new(StoredCryptoConfig) scc = &StoredCryptoConfig{ @@ -93,17 +99,13 @@ func NewStoredCryptoConfig(c *CryptoConfig) *StoredCryptoConfig { SignaturePublicMap: c.SignaturePublicMap, RSAPrivateKey: c.RSAPrivateKey, } - // p, err := json.Marshal(c.RSAPrivateKey) - // if err != nil { - // panic(err) - // } - // scc.RSAPrivateKey = p - // scc.SignaturePublicMap = (&c.SignaturePublicMap).Serialize() scc.ThresholdPublicMap = (&c.ThresholdPublicMap).Serialize() scc.ThresholdSecretKey = (&c.ThresholdSecretKey).Serialize() return scc } +// Creates a cryptoconfig from a stored one. This is used for reading a stored file cryptoconfig. +// Returns a pointer to the new config. func NewCryptoConfig(scc *StoredCryptoConfig) (*CryptoConfig, error) { c := new(CryptoConfig) c = &CryptoConfig{ diff --git a/CTng/crypto/hash.go b/CTng/crypto/hash.go index e352c9c..3d6a739 100644 --- a/CTng/crypto/hash.go +++ b/CTng/crypto/hash.go @@ -47,6 +47,7 @@ func GenerateMD5(data []byte) ([]byte, error) { return hash, err } +// Generates the SHA256 hash for the given bits. func GenerateSHA256(data []byte) ([]byte, error) { hash, _, err := generateHash(SHA256, data) return hash, err diff --git a/CTng/crypto/types.go b/CTng/crypto/types.go index e818669..d2bdbe5 100644 --- a/CTng/crypto/types.go +++ b/CTng/crypto/types.go @@ -91,6 +91,7 @@ func (h HashAlgorithm) String() string { } } +// RSASig contains the ID of the signer and the rsa signature. type RSASig struct { Sig []byte ID CTngID @@ -122,14 +123,12 @@ func RSASigFromString(str string) (RSASig, error) { // Follows the security assumption that "All public keys are known to all parties." type RSAPublicMap map[CTngID]rsa.PublicKey -type BlsPrivateMap map[CTngID]bls.SecretKey - type BlsPublicMap map[CTngID]bls.PublicKey // Serialization of these fields for transportation. // Note that this is an inconvenience of this specific BLS library. -// Normally we would be able to just Marshal/Unmarshal. -// This could be an inconvenience of using the C implementation +// Normally, we would be able to just Marshal/Unmarshal a mapping. +// This is likely an inconvenience of using the C implementation of BLS. func (p *BlsPublicMap) Serialize() map[string][]byte { serialized := make(map[string][]byte) for id, key := range *p { @@ -138,6 +137,8 @@ func (p *BlsPublicMap) Serialize() map[string][]byte { return serialized } +// Deserialize takes the serialized version of the public map, deserializes it, and puts it in p. +// p should be allocated space for the BLSPublicMap to be stored. func (p *BlsPublicMap) Deserialize(serialized map[string][]byte) error { var err error blsPub := new(bls.PublicKey) @@ -151,6 +152,10 @@ func (p *BlsPublicMap) Deserialize(serialized map[string][]byte) error { return nil } +// This privatekey map is returned by the key generator. Individual private keys should be +// stored in the crypto configuration file of each entity. +type BlsPrivateMap map[CTngID]bls.SecretKey + // As of April 2022, the code is refactored so that storing blsIDs is no longer necessary. // BLS ids are required for signing and verifying functions // Thus, we give each Entity a BLS ID. @@ -185,11 +190,14 @@ type SigFragment struct { ID CTngID } +// Convert a SigFragment to a string. +// Signatures need to be turned into strings to be stored in Gossip Objects. +// To convert back, use SigFragmentFromString(). func (s SigFragment) String() string { return fmt.Sprintf(`{"sign":"%s","id":"%s"}`, s.Sign.SerializeToHexStr(), s.ID.String()) } -// Writes data into the signature fragment pointer. +// Returns a signature fragment generated from a string. func SigFragmentFromString(str string) (SigFragment, error) { s := new(SigFragment) s.Sign = new(bls.Sign) @@ -244,11 +252,7 @@ func ThresholdSigFromString(str string) (ThresholdSig, error) { return *t, err } -/* -2 options for the below: Package the cryptography information here, or -simply pass a "global config object" as the parameter -and let the individual functions parse it. -*/ +// type CryptoConfig struct { Threshold int //f+1 is the threshold for signing N int //n is the number of participants @@ -263,8 +267,9 @@ type CryptoConfig struct { ThresholdSecretKey bls.SecretKey // secret key for the current entity } -// The below version is the serialized version of CryptoConfig. -// Again, this is because we're using the bls C implementation. +// This is the serialized version of CryptoConfig. +// Again, this is required because we're using the bls C implementation which can't be +// stored without serialization. type StoredCryptoConfig struct { SelfID CTngID // id of the current entity Threshold int //f+1 is the threshold for signing