From 7f5ef6c78f856ae5edaeb0f2dfe6f5cce81cb4f1 Mon Sep 17 00:00:00 2001 From: tfn18001 Date: Mon, 25 Apr 2022 21:26:34 -0400 Subject: [PATCH] Improved Documentation of crypto library, added code owners to each file --- CTng/crypto/Readme.md | 6 + CTng/crypto/bls.go | 20 ++-- CTng/crypto/crypto_config.go | 5 + CTng/crypto/crypto_test.go | 13 +- CTng/crypto/generate_crypto.go | 31 +++-- CTng/crypto/hash.go | 15 ++- CTng/crypto/rsa.go | 15 ++- CTng/crypto/types.go | 211 ++++++++++++++++----------------- 8 files changed, 178 insertions(+), 138 deletions(-) diff --git a/CTng/crypto/Readme.md b/CTng/crypto/Readme.md index 360833e..7a0f6df 100644 --- a/CTng/crypto/Readme.md +++ b/CTng/crypto/Readme.md @@ -22,3 +22,9 @@ 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 + + +## Code Owners +- Finn is responsible for designing and programming all the code in this package. + +##### Readme written by Finn \ No newline at end of file diff --git a/CTng/crypto/bls.go b/CTng/crypto/bls.go index c82c312..f83cb0e 100644 --- a/CTng/crypto/bls.go +++ b/CTng/crypto/bls.go @@ -16,16 +16,17 @@ import ( View The Go function translations here: https://github.com/herumi/bls-go-binary/blob/master/bls/bls.go*/ type BLSThresholdSignatures interface { - GenerateThresholdKeypairs([]CTngID, int) ([]bls.ID, BlsPublicMap, BlsPrivateMap, error) + GenerateThresholdKeypairs([]CTngID, int) (BlsPublicMap, BlsPrivateMap, error) ThresholdSign(msg string, secret bls.SecretKey) (SigFragment, error) ThresholdAggregate([]SigFragment, int) (ThresholdSig, error) VerifyAggregate(msg string, fragments []SigFragment, config *CryptoConfig) error } -// Generate mappings of IDs to Private Keys and Public Keys Based on a config's parameters -func GenerateThresholdKeypairs(entities []CTngID, threshold int) ([]bls.ID, BlsPublicMap, BlsPrivateMap, error) { +// Generate mappings of IDs to Private Keys and Public Keys Based on a config's parameters. +// threshold is used to determine the "k" in "k of n" threshold signatures. +func GenerateThresholdKeypairs(entities []CTngID, threshold int) (BlsPublicMap, BlsPrivateMap, error) { if threshold < 2 { - return nil, nil, nil, errors.New("Threshold must be greater than 1") + return nil, nil, errors.New("Threshold must be greater than 1") } //ids for n entities n := len(entities) @@ -55,7 +56,7 @@ func GenerateThresholdKeypairs(entities []CTngID, threshold int) ([]bls.ID, BlsP } // None of the above functions return errors. Instead they panic. // If cryptography information fails to generate then we cannot proceed. - return ids, pubs, privs, nil + return pubs, privs, nil } // ThresholdSign will generate a signature fragment for the given message. @@ -68,7 +69,7 @@ func ThresholdSign(msg string, sec *bls.SecretKey, SelfID CTngID) SigFragment { } } -// Aggregate signature Fragments into a ThresholdSig. +// Aggregate [threshold] Signature fragments into a ThresholdSig. func ThresholdAggregate(sigs []SigFragment, threshold int) (ThresholdSig, error) { var aggregate = ThresholdSig{ IDs: make([]CTngID, threshold), @@ -89,7 +90,8 @@ func ThresholdAggregate(sigs []SigFragment, threshold int) (ThresholdSig, error) return aggregate, nil } -// Verify an aggregated threshold signature against the message and the public keys +// Verify an aggregated threshold signature against the message and public key mapping. +// Note that the public keys of all signers must be contained in the public map. func (sig ThresholdSig) Verify(msg string, pubs *BlsPublicMap) bool { // Construct the list of public keys pubList := make([]bls.PublicKey, len(sig.IDs)) @@ -100,13 +102,15 @@ func (sig ThresholdSig) Verify(msg string, pubs *BlsPublicMap) bool { return sig.Sign.FastAggregateVerify(pubList, []byte(msg)) } -// Given a message and a public key mapping, verify the signature runs. +// Given a message and a public key mapping, verify the signature is valid. func (f SigFragment) Verify(msg string, pubs *BlsPublicMap) bool { pub := (*pubs)[f.ID] return (f.Sign).Verify(&pub, msg) } +//init runs when the package is imported to other functions. func init() { // The init function needs to be immediately called upon import. + //This sets up global variables and random number generators I believe. bls.Init(bls.BLS12_381) } diff --git a/CTng/crypto/crypto_config.go b/CTng/crypto/crypto_config.go index 4931c1e..cd0c617 100644 --- a/CTng/crypto/crypto_config.go +++ b/CTng/crypto/crypto_config.go @@ -1,5 +1,10 @@ package crypto +/* +Code Ownership: +Finn - Created all Methods +*/ + import "errors" // CryptoConfig Method Versions of all crypto functions. diff --git a/CTng/crypto/crypto_test.go b/CTng/crypto/crypto_test.go index b06c53a..d678d41 100644 --- a/CTng/crypto/crypto_test.go +++ b/CTng/crypto/crypto_test.go @@ -1,5 +1,9 @@ package crypto +/* +Code Ownership: +Finn - All Tests+Functions +*/ import ( "encoding/hex" "fmt" @@ -15,6 +19,7 @@ func shuffleSigs(sigs *[]SigFragment) { }) } +// Shortened version of a repeated block of code. func confirmNil(t *testing.T, err error) { if err != nil { t.Errorf("%s", err.Error()) @@ -23,6 +28,7 @@ func confirmNil(t *testing.T, err error) { /* Referenced test certificate-transparency-go/tls/hash_test.go +This test was used when learning how to use the tests and go. */ func TestMD5(t *testing.T) { // Our tests are a list of structs with the following properties: @@ -85,20 +91,21 @@ func TestBLSFunctionality(T *testing.T) { threshold := 2 // First term is list of BLS ids. We now derive the BLS ids from the CTngIDs, so it can be ignored. - _, pubs, privs, err := GenerateThresholdKeypairs(entities, threshold) + pubs, privs, err := GenerateThresholdKeypairs(entities, threshold) confirmNil(T, err) + // get space for all the signatures sigs := make([]SigFragment, n) data := "Test information for signing" wrongData := "Incorrect Information" - // Have all entities sign the message + // Have all entities sign the data message for i := 0; i < n; i++ { priv := privs[entities[i]] sigs[i] = ThresholdSign(data, &priv, entities[i]) - //secret.Sign will panic() if it fails, not return an error. + //This code will panic() if it fails, not return an error. } // Verify individual signatures validate diff --git a/CTng/crypto/generate_crypto.go b/CTng/crypto/generate_crypto.go index 7eeedf2..7fd399c 100644 --- a/CTng/crypto/generate_crypto.go +++ b/CTng/crypto/generate_crypto.go @@ -1,5 +1,10 @@ package crypto +/* +Code Ownership: +Finn - All Functions +*/ + import ( "CTng/util" "crypto/rsa" @@ -15,21 +20,23 @@ type CryptoStorage interface { // Generate a list of cryptoconfigs from a list of entity names. // The threshold determines the k value in "k-of-n" threshold signing. +// Every entity configuration is given a bls keypair and an rsa keypair. +// Currently, entities such as Loggers and CAs (which only sign with rsa) +// need to have their keypairs manually copy-pasted into the config mappings. func GenerateEntityCryptoConfigs(entityIDs []CTngID, threshold int) ([]CryptoConfig, error) { + // Define some CTng Constant values ThresholdScheme := "bls" SignScheme := "rsa" HashScheme := SHA256 configs := make([]CryptoConfig, len(entityIDs)) // Generate Threshold Keys - _, blsPubMap, blsPrivMap, err := GenerateThresholdKeypairs(entityIDs, threshold) + blsPubMap, blsPrivMap, err := GenerateThresholdKeypairs(entityIDs, threshold) if err != nil { panic(err) } - // Map entity identifiers to given BLS IDs - - // Generate RSA Keys + // Generate RSA Keys for each entity and populate the mappings with them. rsaPrivMap := make(map[CTngID]rsa.PrivateKey) rsaPubMap := make(RSAPublicMap) for _, entity := range entityIDs { @@ -42,7 +49,7 @@ func GenerateEntityCryptoConfigs(entityIDs []CTngID, threshold int) ([]CryptoCon rsaPubMap[entity] = pub } - //Generate configs without individual information + //Generate configs, assigning a different entityId to each config. for i := range configs { configs[i] = CryptoConfig{ ThresholdScheme: ThresholdScheme, @@ -60,11 +67,11 @@ 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. +// Saves a list of cryptoconfigs to files in a given. +// Each file is named the SelfID of the corresponding config. func SaveCryptoFiles(directory string, configs []CryptoConfig) error { for _, config := range configs { - // fmt.Print(config) + // Sets the name to the ID of the entity using C-like printf. file := fmt.Sprintf("%s/%s.test.json", directory, config.SelfID) err := util.WriteData(file, *NewStoredCryptoConfig(&config)) if err != nil { @@ -74,7 +81,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. +// Read a Storedcryptoconfig from a file, convert it to a usable cryptoconfig and return a pointer to it. func ReadCryptoConfig(file string) (*CryptoConfig, error) { scc := new(StoredCryptoConfig) bytes, err := util.ReadByte(file) @@ -87,6 +94,7 @@ func ReadCryptoConfig(file string) (*CryptoConfig, error) { } // Converts a CryptoConfig to a marshal-able format. +// This serializes any neccessary fields in the process. func NewStoredCryptoConfig(c *CryptoConfig) *StoredCryptoConfig { scc := new(StoredCryptoConfig) scc = &StoredCryptoConfig{ @@ -104,8 +112,9 @@ func NewStoredCryptoConfig(c *CryptoConfig) *StoredCryptoConfig { 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. +// Creates a cryptoconfig from a stored one. +// This is used for reading a stored file cryptoconfig. +// Deserializes any neccessary fields. func NewCryptoConfig(scc *StoredCryptoConfig) (*CryptoConfig, error) { c := new(CryptoConfig) c = &CryptoConfig{ diff --git a/CTng/crypto/hash.go b/CTng/crypto/hash.go index 3d6a739..d7f02f1 100644 --- a/CTng/crypto/hash.go +++ b/CTng/crypto/hash.go @@ -1,5 +1,13 @@ package crypto +/* +Code Ownership: +Finn - Copied functions from certificate-transparency-go/tls + +This was the first code made in the project, so note that we were still +learning go at the time of writing. :-) +*/ + import ( "crypto" _ "crypto/md5" // For registration side-effect @@ -14,7 +22,8 @@ type HashInterface interface { GenerateSHA256(msg []byte) ([]byte, error) } -// Function pulled from certificate-transparency-go/tls. Copied because it isn't defined as external in their repo. +// Function pulled from certificate-transparency-go/tls. +// Copied here instead of imported because it isn't defined as "external" in their repo (it is a lowercase function). func generateHash(algo HashAlgorithm, data []byte) ([]byte, crypto.Hash, error) { var hashType crypto.Hash switch algo { @@ -41,13 +50,13 @@ func generateHash(algo HashAlgorithm, data []byte) ([]byte, crypto.Hash, error) return hasher.Sum([]byte{}), hashType, nil } -// Generates the MD5 hash for the given bits. +// Generates the MD5 hash for the given byte array. func GenerateMD5(data []byte) ([]byte, error) { hash, _, err := generateHash(MD5, data) return hash, err } -// Generates the SHA256 hash for the given bits. +// Generates the SHA256 hash for the given byte array. func GenerateSHA256(data []byte) ([]byte, error) { hash, _, err := generateHash(SHA256, data) return hash, err diff --git a/CTng/crypto/rsa.go b/CTng/crypto/rsa.go index 2358d6e..c124c67 100644 --- a/CTng/crypto/rsa.go +++ b/CTng/crypto/rsa.go @@ -1,5 +1,10 @@ package crypto +/* +Code Ownership: +Finn - Created all Functions +*/ + import ( "crypto" "crypto/rand" @@ -14,15 +19,21 @@ type RsaSignatures interface { Verify(msg []byte, signature []byte, publicKey []byte, config *CryptoConfig) error } +// Generates a new RSA private key of length 2048 bits +// This is the length required by the CT standard, and has been adopted in our specification. func NewRSAPrivateKey() (*rsa.PrivateKey, error) { - // 2048 = Specification requirement for RSA keys return rsa.GenerateKey(rand.Reader, 2048) } +// Although unsued, this function has been left for clarity +// of where the public key is located for an RSA private key. func GetPublicKey(privateKey *rsa.PrivateKey) (*rsa.PublicKey, error) { return &privateKey.PublicKey, nil } +// Sign message msg using the private key. +// Returns an RSA signature, which is an object containing the passed id +// and the signature itself. id should ALWAYS be the same as the CTngID of the signer. func RSASign(msg []byte, privateKey *rsa.PrivateKey, id CTngID) (RSASig, error) { // SHA256 = Specification Requirement for RSA signatures hash, err := GenerateSHA256(msg) @@ -35,6 +46,8 @@ func RSASign(msg []byte, privateKey *rsa.PrivateKey, id CTngID) (RSASig, error) ID: id}, err } +// Verifies the signature of the message against the given public key. +// Returns nil if the signature is valid. func RSAVerify(msg []byte, signature RSASig, pub *rsa.PublicKey) error { hash, err := GenerateSHA256(msg) if err != nil { diff --git a/CTng/crypto/types.go b/CTng/crypto/types.go index d2bdbe5..e77665a 100644 --- a/CTng/crypto/types.go +++ b/CTng/crypto/types.go @@ -1,7 +1,9 @@ package crypto -//This file is for the various types we use in our cryptography. -// Some hashing portions have been pulled from certificate-transparency-go/tls/types. +/* +Code Ownership: +Finn - Created all Functions +*/ import ( "crypto/rsa" @@ -12,15 +14,17 @@ import ( "github.com/herumi/bls-go-binary/bls" ) -// Generic Ids are URLS. +// CTngIDs are URLS, but are abstracted to this type in case they are changed in the future. type CTngID string +// Simple String conversion of an ID func (id CTngID) String() string { return string(id) } // BLS IDs should be derived directly from the CTngID. // This essentially maps every CTngID to a unique BLS ID. +// BLS IDs are used when generating bls private keys. func (id CTngID) BlsID() *bls.ID { b := new(bls.ID) err := b.SetHexString(hex.EncodeToString([]byte(id))) @@ -31,16 +35,16 @@ func (id CTngID) BlsID() *bls.ID { return b } -// The reverse of CTngID.BlsID(). +// The inverse of CTngID.BlsID(). Note that this is a function, +// while CTngID.BlsID() is a method. func CTngIDfromBlsID(blsid *bls.ID) (CTngID, error) { id, err := hex.DecodeString(blsid.SerializeToHexStr()) return CTngID(id), err } -// Implemented functions for sorting -// The following types are neccessary for the sorting of CTng IDs. -// We sort CTngIds in aggregated signatures for consistency when transporting. -// Otherwise, payloads which contain the CTng IDs may not be consistent. +// The following types are neccessary for the sorting of CTng IDs and utilized by sort functions. +// Aggregated signatures generated by different entites should be identical when converted to a string. +// This can be done by sorting the list of IDs, making all ThresholdSig string representations identical. type CTngIDs []CTngID func (ids CTngIDs) Less(i, j int) bool { @@ -53,11 +57,10 @@ func (ids CTngIDs) Swap(i, j int) { ids[i], ids[j] = ids[j], ids[i] } -// Enum is an unsigned integer. -type Enum uint64 - +// Note that the following hash algorithms are not currently supported. This section of the code was +// derived from google/certificate-transparency-go, in clase many hash types should be supported in the future. // HashAlgorithm enum from RFC 5246 s7.4.1.4.1. -type HashAlgorithm Enum +type HashAlgorithm uint64 // HashAlgorithm constants from RFC 5246 s7.4.1.4.1. const ( @@ -70,6 +73,7 @@ const ( SHA512 HashAlgorithm = 6 ) +// String conversion method for hash types. func (h HashAlgorithm) String() string { switch h { case None: @@ -91,95 +95,6 @@ func (h HashAlgorithm) String() string { } } -// RSASig contains the ID of the signer and the rsa signature. -type RSASig struct { - Sig []byte - ID CTngID -} - -//String -> RSASig conversion -func (s RSASig) String() string { - return fmt.Sprintf(`{"sig":"%s","id":"%s"}`, hex.EncodeToString(s.Sig), s.ID.String()) -} - -//RSASig -> String conversion -func RSASigFromString(str string) (RSASig, error) { - stringmap := make(map[string]string) - sig := new(RSASig) - err := json.Unmarshal([]byte(str), &stringmap) - if err != nil { - return *sig, err - } - sig.Sig = make([]byte, hex.DecodedLen(len(stringmap["sig"]))) - _, err = hex.Decode(sig.Sig, []byte(stringmap["sig"])) - if err != nil { - return *sig, err - } - sig.ID = CTngID(stringmap["id"]) - return *sig, err -} - -// Public key maps for the configuration files. -// Follows the security assumption that "All public keys are known to all parties." -type RSAPublicMap map[CTngID]rsa.PublicKey - -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 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 { - serialized[id.String()] = (&key).Serialize() - } - 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) - for key, val := range serialized { - err = blsPub.Deserialize(val) - if err != nil { - return err - } - (*p)[CTngID(key)] = *blsPub - } - 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. -// type BlsIDMap map[CTngID]bls.ID - -// func (idMap *BlsIDMap) Serialize() map[CTngID]string { -// serIDMap := make(map[CTngID]string) -// for key, val := range *idMap { -// serIDMap[key] = (&val).SerializeToHexStr() -// } -// return serIDMap -// } -// func (idMap *BlsIDMap) Deserialize(serIDMap map[CTngID]string) error { -// b := bls.ID{} -// for key, val := range serIDMap { -// err := (&b).DeserializeHexStr(val) -// if err != nil { -// // return err -// } -// (*idMap)[key] = b -// } -// return nil -// } - // Signature Fragments store the signer and the signature. // This information can safely be sent, as it does not contain the private key. // This information may be too much here: the gossiper should be able to deduce the @@ -197,7 +112,7 @@ func (s SigFragment) String() string { return fmt.Sprintf(`{"sign":"%s","id":"%s"}`, s.Sign.SerializeToHexStr(), s.ID.String()) } -// Returns a signature fragment generated from a string. +// Convert a string signature to a SigFragment representation of that string. func SigFragmentFromString(str string) (SigFragment, error) { s := new(SigFragment) s.Sign = new(bls.Sign) @@ -252,22 +167,94 @@ func ThresholdSigFromString(str string) (ThresholdSig, error) { return *t, err } -// +// RSASig contains the ID of the signer and the rsa signature. +// while RSA signatures don't necessarily need this storage in the context of CTng, +// this consistency reduces complexity of the code. +type RSASig struct { + Sig []byte + ID CTngID +} + +//String -> RSASig conversion +func (s RSASig) String() string { + return fmt.Sprintf(`{"sig":"%s","id":"%s"}`, hex.EncodeToString(s.Sig), s.ID.String()) +} + +//RSASig -> String conversion +func RSASigFromString(str string) (RSASig, error) { + stringmap := make(map[string]string) + sig := new(RSASig) + err := json.Unmarshal([]byte(str), &stringmap) + if err != nil { + return *sig, err + } + sig.Sig = make([]byte, hex.DecodedLen(len(stringmap["sig"]))) + _, err = hex.Decode(sig.Sig, []byte(stringmap["sig"])) + if err != nil { + return *sig, err + } + sig.ID = CTngID(stringmap["id"]) + return *sig, err +} + +// Public key maps for the configuration files. +// Maps a CTngID to its given public key for bls or rsa, respectively.. +// Given one of these maps and a ThresholdSig, SigFragment, or RSASig, +// it is always possible to verify the signature. +// This follows the security assumption that "All public keys are known to all parties." +type BlsPublicMap map[CTngID]bls.PublicKey + +type RSAPublicMap map[CTngID]rsa.PublicKey + +// Serialization of these fields for transportation. +// Note that this is an inconvenience of this specific C-BLS library. +// Normally, we would be able to just Marshal/Unmarshal a mapping, +// but data is lost if we try to do this without serializing Keys. +func (p *BlsPublicMap) Serialize() map[string][]byte { + serialized := make(map[string][]byte) + for id, key := range *p { + serialized[id.String()] = (&key).Serialize() + } + return serialized +} + +// Deserialize takes the serialized version of the public map, deserializes it, and puts it in p. +// p should be a pre-allocated space for the BLSPublicMap to be stored. +// this can be done with new(BlsPublicMap). +func (p *BlsPublicMap) Deserialize(serialized map[string][]byte) error { + var err error + blsPub := new(bls.PublicKey) + for key, val := range serialized { + err = blsPub.Deserialize(val) + if err != nil { + return err + } + (*p)[CTngID(key)] = *blsPub + } + 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 + +// The CryptoConfig is a struct that contains all cryptography details for use in CTng. +// This object has methods associated with it in crypto_config.go, which allow the user to complete +// neccessary cryptographic tasks of ctng. type CryptoConfig struct { - Threshold int //f+1 is the threshold for signing - N int //n is the number of participants - HashScheme HashAlgorithm - SignScheme string // "rsa" is the only valid value currently. - ThresholdScheme string // "bls" is the only valid value currently. - //entityIDs []CTngID // id of each entity (DNS string), should really exist outside of this struct. - SelfID CTngID // id of the current entity + Threshold int // The threshold for aggregating to a threshold signature. + N int // The total number of participants of the "threshold network" + HashScheme HashAlgorithm // The hash algorithm to be used for any hashing. + SignScheme string // "rsa" is the only valid value currently. + ThresholdScheme string // "bls" is the only valid value currently. SignaturePublicMap RSAPublicMap // map of entityID to RSA public key + ThresholdPublicMap BlsPublicMap // mapping of CTngIds to public keys + SelfID CTngID // id of the current entity RSAPrivateKey rsa.PrivateKey // RSA private key - ThresholdPublicMap BlsPublicMap // mapping of BLS IDs to public keys ThresholdSecretKey bls.SecretKey // secret key for the current entity } -// This is the serialized version of CryptoConfig. +// 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 {