Skip to content

Commit

Permalink
Improved Documentation of crypto library, added code owners to each file
Browse files Browse the repository at this point in the history
  • Loading branch information
tfn18001 committed Apr 26, 2022
1 parent 6fdca9d commit 7f5ef6c
Show file tree
Hide file tree
Showing 8 changed files with 178 additions and 138 deletions.
6 changes: 6 additions & 0 deletions CTng/crypto/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
20 changes: 12 additions & 8 deletions CTng/crypto/bls.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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.
Expand All @@ -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),
Expand All @@ -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))
Expand All @@ -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)
}
5 changes: 5 additions & 0 deletions CTng/crypto/crypto_config.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package crypto

/*
Code Ownership:
Finn - Created all Methods
*/

import "errors"

// CryptoConfig Method Versions of all crypto functions.
Expand Down
13 changes: 10 additions & 3 deletions CTng/crypto/crypto_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package crypto

/*
Code Ownership:
Finn - All Tests+Functions
*/
import (
"encoding/hex"
"fmt"
Expand All @@ -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())
Expand All @@ -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:
Expand Down Expand Up @@ -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
Expand Down
31 changes: 20 additions & 11 deletions CTng/crypto/generate_crypto.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package crypto

/*
Code Ownership:
Finn - All Functions
*/

import (
"CTng/util"
"crypto/rsa"
Expand All @@ -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 {
Expand All @@ -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,
Expand All @@ -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 {
Expand All @@ -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)
Expand All @@ -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{
Expand All @@ -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{
Expand Down
15 changes: 12 additions & 3 deletions CTng/crypto/hash.go
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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 {
Expand All @@ -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
Expand Down
15 changes: 14 additions & 1 deletion CTng/crypto/rsa.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package crypto

/*
Code Ownership:
Finn - Created all Functions
*/

import (
"crypto"
"crypto/rand"
Expand All @@ -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)
Expand All @@ -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 {
Expand Down
Loading

0 comments on commit 7f5ef6c

Please sign in to comment.