Conversation
This adds a cipher suite interface that will be used instead of Kyber abstractions to allow any kind of asymmetric cryptography. It also implements the interface by using the Ed25519 scheme provided by the language. Related to #579
|
First reduced PR for #587 |
| } | ||
|
|
||
| // NewRawPublicKey returns an instance of a public key. | ||
| func NewRawPublicKey(name Name, data []byte) *RawPublicKey { |
There was a problem hiding this comment.
As every call on RawPublicKey do not modify it, you can use a value receiver.
There was a problem hiding this comment.
I'll see with the other engineers but some guidelines tell you to use the pointer receiver everywhere when some need for consistency.
There was a problem hiding this comment.
That was my guideline - but I have been proven wrong ;) We were trying to get away from this for v3, but then couldn't. So if you still think it's wrong to always use pointer structs in New methods, please go ahead and open an issue for v4 to actually return the more appropriate structures.
One place where it will collide with a lot of code is the 'old' protobuf-structures, where the pointer indicates an optional value.
81867ec to
7b7d7d3
Compare
nkcr
left a comment
There was a problem hiding this comment.
I like this ciphersuite package, thanks for the nice job! :)
Nice unit tests too 👍
| // registered using the name of the suite. | ||
| // | ||
| // Public keys and signatures may need to be transmitted over the network and | ||
| // interfaces cannot be used as is. That is why every the different elements |
There was a problem hiding this comment.
| // interfaces cannot be used as is. That is why every the different elements | |
| // interfaces cannot be used as is. That is why every different elements |
|
|
||
| // encodedNameLengthSize defines the size in bytes of the name length | ||
| // when marshaling cipher data. | ||
| const encodedNameLengthSize = 32 / 8 |
There was a problem hiding this comment.
Something I wanted to discuss. 8 or 16 bits integer is probably big enough for a cipher name.
There was a problem hiding this comment.
We'll see tomorrow morning
There was a problem hiding this comment.
Or you can use binary.Uvarint, to pack tighter, reduce code complexitiy and have unlimited size.
| size, err = w.Write([]byte(d.Name())) | ||
| n += int64(size) | ||
| if err != nil { | ||
| return n, xerrors.Errorf("writing name: %v", err) |
There was a problem hiding this comment.
Not fan of those shortened error messages... Makes our program stammers the error message instead of having a comprehensive-nicely-readable description. :/
There was a problem hiding this comment.
it's only an opinion, nothing has to be changed
There was a problem hiding this comment.
Well the fact that we are wrapping the errors create a chain that should explain what happened. Like here a calling function would have something like marshaling cipher data: writing name: ... so you know what went wrong.
But I'm curious to know what you would have written.
There was a problem hiding this comment.
I look where the error comes from and explain it:
"failed to write Name as bytes: %v", err
| "golang.org/x/xerrors" | ||
| ) | ||
|
|
||
| const errNotEd25519CipherSuite = "invalid cipher suite" |
There was a problem hiding this comment.
Shouldn't those be public? like this an external package can assert for this type of error
There was a problem hiding this comment.
No it was only to avoid repetitive string values but for the moment I don't think it's necessary. We can always change that later.
There was a problem hiding this comment.
btw, if you want to have it public, have it as an error, so that errors.Is can be used directly.
| } | ||
|
|
||
| func (s *Ed25519CipherSuite) unpackSecretKey(sk SecretKey) (*Ed25519SecretKey, error) { | ||
| if data, ok := sk.(*RawSecretKey); ok { |
There was a problem hiding this comment.
a personal opinion that I wanted to express for a moment: I don't like those if with short statement. IMO each line of code should do one thing, otherwise that makes the code harder to read. (same for the named return)
There was a problem hiding this comment.
I think this kind of ok conversion is quite frequent in Go
There was a problem hiding this comment.
I had to get used to them, too... But I saw even worse (don't remember where):
if ok := some_method; !ok {
}
| return signature, nil | ||
| } | ||
|
|
||
| return nil, xerrors.New("wrong type of signature") |
There was a problem hiding this comment.
that breaks our philosophy of "fail first" that we tend to use
| return nil, xerrors.Errorf("cipher suite: %v", err) | ||
| } | ||
|
|
||
| pk, err := c.PublicKey(raw) |
There was a problem hiding this comment.
Can't we pass only raw.Data? At this stage we are sure to have the correct cipher suite, so the check raw.Name() != s.Name() inside the PublicKey() function looks superfluous. Or I am missing a case?
| // Verify takes a public key, a signature and a message and performs a verification | ||
| // that will return an error if the signature does not match the message. It | ||
| // will also return an error if the cipher suite is unknown. | ||
| func (cr *Registry) Verify(pk PublicKey, sig Signature, msg []byte) error { |
There was a problem hiding this comment.
just a thought, shouldn't we differentiate the case where the signature is incorrect from the one where an error occurred in the program? It feels a bit strange that the verification outputs an error while it only says that a signature is invalid.
Maybe it's better to rename the function IsValid(...) and return a (bool, error). IDK
|
On hold during the TLS related investigation. |
| } | ||
| } | ||
|
|
||
| // RegisterCipherSuite stores the cipher if it does not exist. It returns the |
There was a problem hiding this comment.
| // RegisterCipherSuite stores the cipher if it does not exist. It returns the | |
| // RegisterCipherSuite stores the cipher if it does not exist. It returns |
| func (cr *Registry) RegisterCipherSuite(suite CipherSuite) CipherSuite { | ||
| name := suite.Name() | ||
| if suite := cr.ciphers[name]; suite != nil { | ||
| // Cipher suite already registered so we return it so it can be reused. |
There was a problem hiding this comment.
Isn't it surprising for the caller to receive a suite different that the provided one, with no error?
|
This PR is celebrating it's first year tomorrow 🎂 😰 |
|
I propose to close this issue without merging for the following reasons:
|
This adds a cipher suite interface that will be used instead of
Kyber abstractions to allow any kind of asymmetric cryptography.
It also implements the interface by using the Ed25519 scheme
provided by the language.
Related to #579