initial release. tests pass at least.
This commit is contained in:
parent
7b000530f3
commit
29dea9ae1f
2
.gitignore
vendored
2
.gitignore
vendored
@ -19,4 +19,4 @@
|
|||||||
.idea/
|
.idea/
|
||||||
|
|
||||||
# Dependency directories (remove the comment below to include it)
|
# Dependency directories (remove the comment below to include it)
|
||||||
# vendor/
|
!/vendor/
|
||||||
|
21
README.adoc
21
README.adoc
@ -18,33 +18,42 @@ Last updated {localdatetime}
|
|||||||
|
|
||||||
A Golang library variant of ChaCha20-Poly1305 that OpenSSH uses (`chacha20-poly1305@openssh.com`).
|
A Golang library variant of ChaCha20-Poly1305 that OpenSSH uses (`chacha20-poly1305@openssh.com`).
|
||||||
|
|
||||||
Note that this module *only* supports the OpenSSH variant, and should only be used for key generation/parsing/modification/manipulation, not actual connection/stream encryption.
|
WARNING: Note that this module *only* supports the OpenSSH variant, and should only be used for key generation/parsing/modification/manipulation, not actual connection/stream encryption.
|
||||||
|
|
||||||
== Why is this necessary?
|
== Usage
|
||||||
|
The usage of this library is *very* limited in scope; it's only intended for low-level OpenSSH key operations.
|
||||||
|
|
||||||
|
Primarily, for use with https://git.r00t2.io/r00t2/go_sshkeys/src/branch/master[go_sshkeys^].
|
||||||
|
|
||||||
|
== FAQ
|
||||||
|
|
||||||
|
=== Why is this necessary?
|
||||||
|
|
||||||
Because Golang.org/x/crypto https://github.com/golang/go/issues/36646[removes functionality^] (even for https://github.com/golang/go/issues/44226[very common tech^]) and thinks OpenSSH is a "weird" use case. That's a direct reference; they called it "weird".
|
Because Golang.org/x/crypto https://github.com/golang/go/issues/36646[removes functionality^] (even for https://github.com/golang/go/issues/44226[very common tech^]) and thinks OpenSSH is a "weird" use case. That's a direct reference; they called it "weird".
|
||||||
|
|
||||||
I *really, really* hope this library is https://github.com/golang/go/issues/57699[no longer necessary^] by the time I'm done writing it but based on my past experiences with core Golang devs, my expectations are extremely low.
|
I *really, really* hope this library is https://github.com/golang/go/issues/57699[no longer necessary^] by the time I'm done writing it but based on my past experiences with core Golang devs, my expectations are extremely low.
|
||||||
|
|
||||||
|
_Narrator: It was still necessary ._
|
||||||
|
|
||||||
They have no decent support for OpenSSH keys or lower-level operations. And guess what -- sometimes you *need* lower-level functionality. Who knew?
|
They have no decent support for OpenSSH keys or lower-level operations. And guess what -- sometimes you *need* lower-level functionality. Who knew?
|
||||||
|
|
||||||
So now because I'm just a single individual, bug fixes will probably lag behind upstream. All because Golang devs decided the OpenSSH variant was "too weird".
|
So now because I'm just a single individual, bug fixes will probably lag behind upstream if I have to re-vendor because I'm not maintaining an entire fork of golang.org/x/crypto. All because Golang devs decided the OpenSSH variant was "too weird".
|
||||||
|
|
||||||
But, of course, not "weird" enough to https://github.com/golang/crypto/blob/3d872d042823aed41f28af3b13beb27c0c9b1e35/ssh/cipher.go#L652[not support the *wire* protocol^] for SSH. Just the key encryption. Because of course. And not publicly exposed either. Because *of course*.
|
But, of course, not "weird" enough to https://github.com/golang/crypto/blob/3d872d042823aed41f28af3b13beb27c0c9b1e35/ssh/cipher.go#L652[not support the *wire* protocol^] for SSH. Just the key encryption. Because of course. And not publicly exposed either. Because *of course*.
|
||||||
|
|
||||||
Assholes.
|
Assholes.
|
||||||
|
|
||||||
== Why is the name so ugly?
|
=== Why is the name so ugly?
|
||||||
|
|
||||||
I couldn't think of a better one and I wanted something notably distinct from the stdlib-x naming.
|
I couldn't think of a better one and I wanted something notably distinct from the stdlib-x naming.
|
||||||
|
|
||||||
And module names can't include the `@` symbol.
|
And module names can't include the `@` symbol.
|
||||||
|
|
||||||
== Why don't you expose the rest of ChaCha20/Poly1305/ChaCha20-Poly1305?
|
=== Why don't you expose the rest of low-level ChaCha20/Poly1305/ChaCha20-Poly1305?
|
||||||
|
|
||||||
* To keep code changes from upstream light (and thus easier to debug, audit, etc.)
|
* To keep code changes from upstream light (and thus easier to debug, audit, etc.)
|
||||||
* Because otherwise the module name is inaccurate
|
* Because otherwise the module name is inaccurate
|
||||||
** Because OpenSSH has their own specific variant
|
** Because OpenSSH has their own specific variant
|
||||||
** Which means we can handle SSH-specific functionality if needed
|
** Which means we can handle SSH-specific functionality if needed
|
||||||
* Because golang/x/crypto has made it painfully clear that if you want something that deviates from what they *think* is "best practice", you need to do it yourself
|
* Because golang.org/x/crypto has made it painfully clear that if you want something that deviates from what they *think* is "best practice", you need to do it yourself
|
||||||
** Which ironically is something they also brand an "anti-pattern" which is just \*chef's kiss*
|
** Which ironically is something they also brand an "anti-pattern" which is just \*chef's kiss*
|
||||||
|
13
_patches/chacha20_nonce.patch
Normal file
13
_patches/chacha20_nonce.patch
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
--- a/vendor/golang.org/x/crypto/chacha20/chacha_generic.go 2023-01-09 05:16:30.912219212 -0500
|
||||||
|
+++ b/vendor/golang.org/x/crypto/chacha20/chacha_generic.go 2023-01-10 02:20:55.150612278 -0500
|
||||||
|
@@ -24,7 +24,9 @@
|
||||||
|
//
|
||||||
|
// Note that this is too short to be safely generated at random if the same
|
||||||
|
// key is reused more than 2³² times.
|
||||||
|
- NonceSize = 12
|
||||||
|
+ //NonceSize = 12
|
||||||
|
+ // BITE ME, GOLANG DEVS.
|
||||||
|
+ NonceSize = 16
|
||||||
|
|
||||||
|
// NonceSizeX is the size of the nonce used with the XChaCha20 variant of
|
||||||
|
// this cipher, in bytes.
|
13
_patches/chacha20poly1305_nonce.patch
Normal file
13
_patches/chacha20poly1305_nonce.patch
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
--- a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go 2023-01-09 05:16:30.912219212 -0500
|
||||||
|
+++ b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go 2023-01-10 02:58:31.006536303 -0500
|
||||||
|
@@ -21,7 +21,9 @@
|
||||||
|
//
|
||||||
|
// Note that this is too short to be safely generated at random if the same
|
||||||
|
// key is reused more than 2³² times.
|
||||||
|
- NonceSize = 12
|
||||||
|
+ // NonceSize = 12
|
||||||
|
+ // BITE ME, GOLANG DEVS.
|
||||||
|
+ NonceSize = 16
|
||||||
|
|
||||||
|
// NonceSizeX is the size of the nonce used with the XChaCha20-Poly1305
|
||||||
|
// variant of this AEAD, in bytes.
|
34
algos_test.go
Normal file
34
algos_test.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package cc20p1305ssh
|
||||||
|
|
||||||
|
import (
|
||||||
|
`testing`
|
||||||
|
|
||||||
|
`golang.org/x/crypto/chacha20`
|
||||||
|
`golang.org/x/crypto/chacha20poly1305`
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestChaCha20FixedNonceSize(t *testing.T) {
|
||||||
|
|
||||||
|
if NonceSize != chacha20.NonceSize {
|
||||||
|
t.Fatal(
|
||||||
|
"Mismatched ChaCha20 nonce sizes;\n" +
|
||||||
|
"\tgolang.org/x/crypto/chacha20 only supports 12 or 24 bytes nonce size,\n\t" +
|
||||||
|
"the chacha20poly1305@openssh.com variant only supports a nonce of 16 bytes.\n\t" +
|
||||||
|
"vendor/golang.org/x/crypto/chacha20/chacha_generic.go:NonceSize must be modified.",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
t.Log("The nonce size modification for chacha20 is correct.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestChaCha20Poly1305FixedNonceSize(t *testing.T) {
|
||||||
|
|
||||||
|
if NonceSize != chacha20poly1305.NonceSize {
|
||||||
|
t.Fatal(
|
||||||
|
"Mismatched ChaCha20Poly1305 nonce sizes;\n" +
|
||||||
|
"\tgolang.org/x/crypto/chacha20poly1305 only supports 12 or 24 bytes nonce size,\n\t" +
|
||||||
|
"the chacha20poly1305@openssh.com variant only supports a nonce of 16 bytes.\n\t" +
|
||||||
|
"vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go:NonceSize must be modified.",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
t.Log("The nonce size modification for chacha20poly1305 is correct.")
|
||||||
|
}
|
21
consts.go
21
consts.go
@ -35,14 +35,27 @@ const (
|
|||||||
*/
|
*/
|
||||||
NonceSize int = 16
|
NonceSize int = 16
|
||||||
|
|
||||||
// TagLen is the length of the Poly1305 tag.
|
// PolyKeySize is the amount of the cipher result of chacha20.
|
||||||
TagLen int = poly1305.TagSize
|
PolyKeySize int = 32
|
||||||
|
|
||||||
// DefaultRounds specifies the number of default rounds to use if using the provided KDF derivation and the specified rounds are 0 or negative.
|
// TagSize is the length of the Poly1305 tag.
|
||||||
DefaultRounds int = 16
|
TagSize int = poly1305.TagSize
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
// initBlock is used at counter 0 in chacha20 to get the poly1305 key.
|
||||||
|
initBlock []byte = []byte{
|
||||||
|
// 64 bytes
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
}
|
||||||
|
|
||||||
// iv is the constant fixed IV.
|
// iv is the constant fixed IV.
|
||||||
iv []byte = []byte{
|
iv []byte = []byte{
|
||||||
0x0, 0x0, 0x0, 0x0,
|
0x0, 0x0, 0x0, 0x0,
|
||||||
|
@ -1,20 +1,79 @@
|
|||||||
package cc20p1305ssh
|
package cc20p1305ssh
|
||||||
|
|
||||||
import (
|
var (
|
||||||
`testing`
|
/*
|
||||||
|
testKdfKey is the key that would be returned by bcrypt_pbkdf.
|
||||||
|
|
||||||
`golang.org/x/crypto/chacha20`
|
It would be created using the passphrase (seed) "test", with 16 rounds,
|
||||||
)
|
and 64 bytes keysize.
|
||||||
|
*/
|
||||||
func TestFixedNonceSize(t *testing.T) {
|
testKdfKey []byte = []byte{
|
||||||
|
// 64 bytes
|
||||||
if NonceSize != chacha20.NonceSize {
|
0xd7, 0xe4, 0x7e, 0xf3, 0x7c, 0xfd, 0x80, 0x6d,
|
||||||
t.Error(
|
0x48, 0xfd, 0x8b, 0x46, 0xec, 0x53, 0x51, 0xef,
|
||||||
"Mismatched ChaCha20 nonce sizes;\n" +
|
0x3f, 0x15, 0xf8, 0xb0, 0xa2, 0x30, 0xcf, 0x60,
|
||||||
"\tgolang.org/x/crypto/chacha20 only supports 12 or 24 bytes nonce size,\n\t" +
|
0x2c, 0x09, 0xdd, 0x44, 0x91, 0xe9, 0x54, 0xc8,
|
||||||
"the chacha20poly1305@openssh.com variant only supports a nonce of 16 bytes.",
|
0x72, 0x03, 0x15, 0xe4, 0x83, 0x54, 0x30, 0xca,
|
||||||
)
|
0x8a, 0xe1, 0x9b, 0x15, 0x3f, 0xbc, 0xbe, 0x45,
|
||||||
t.Fail()
|
0x17, 0xc5, 0x03, 0xe0, 0xc9, 0xda, 0x77, 0xff,
|
||||||
|
0xe5, 0x95, 0xa3, 0x33, 0x17, 0xad, 0x4d, 0xe7,
|
||||||
}
|
}
|
||||||
t.Log("The nonce size modification is correct.")
|
|
||||||
}
|
// testPoly1305Tag is the poly1305 tag.
|
||||||
|
testPoly1305Tag []byte = []byte{
|
||||||
|
// 16 bytes
|
||||||
|
0x7d, 0x98, 0x49, 0xd7,
|
||||||
|
0x60, 0x2b, 0x49, 0xf9,
|
||||||
|
0xcf, 0xa0, 0x2d, 0x9f,
|
||||||
|
0x39, 0x66, 0x2c, 0x66,
|
||||||
|
}
|
||||||
|
|
||||||
|
// testEncBlock is the encrypted private key of an example ssh-ed25519 private key, encrypted with the passphrase "test" (block "4.0.1" in go_sshkeys).
|
||||||
|
// We skip the KDF for tests, though (see testKdfKey).
|
||||||
|
testEncBlock []byte = []byte{
|
||||||
|
// 152 bytes
|
||||||
|
0x9b, 0x24, 0x63, 0x64, 0xe7, 0xbe, 0xf7, 0xc1,
|
||||||
|
0xc7, 0x20, 0xe1, 0x0e, 0xce, 0x79, 0x3b, 0x7c,
|
||||||
|
0xe0, 0x61, 0xa4, 0xa8, 0xf3, 0x2c, 0x18, 0x36,
|
||||||
|
0x3b, 0xb3, 0x85, 0x82, 0xfd, 0xed, 0x5d, 0xb6,
|
||||||
|
0xd3, 0xb5, 0x93, 0x16, 0x3c, 0x5d, 0x06, 0xaa,
|
||||||
|
0xb4, 0x9f, 0xc4, 0x6a, 0x87, 0xa1, 0xcb, 0x29,
|
||||||
|
0xa0, 0x8f, 0x53, 0x99, 0x2b, 0x86, 0x56, 0xc5,
|
||||||
|
0xf5, 0xaf, 0xeb, 0x1b, 0x86, 0x5c, 0x0e, 0x21,
|
||||||
|
0x52, 0x4f, 0xf4, 0x76, 0xb8, 0x1d, 0x8a, 0x8b,
|
||||||
|
0xaa, 0xda, 0x2a, 0xed, 0x08, 0xc1, 0xcb, 0x21,
|
||||||
|
0x8a, 0x6a, 0x2e, 0xa5, 0x2d, 0x9d, 0x01, 0xe7,
|
||||||
|
0x4c, 0x7b, 0x2e, 0x42, 0x30, 0x51, 0x64, 0x5f,
|
||||||
|
0x9f, 0x46, 0xa6, 0x2b, 0x15, 0x73, 0xd2, 0xfa,
|
||||||
|
0xa4, 0xf4, 0xdc, 0xe9, 0xfd, 0xf8, 0x91, 0xa3,
|
||||||
|
0x11, 0xb5, 0xce, 0x18, 0xd7, 0x4a, 0xff, 0xa9,
|
||||||
|
0xea, 0xd3, 0x7d, 0x44, 0xd0, 0xba, 0xec, 0x16,
|
||||||
|
0xc3, 0xc6, 0xcd, 0x1d, 0xa2, 0x2d, 0x25, 0x17,
|
||||||
|
0x45, 0x98, 0x9b, 0x7d, 0x06, 0xf2, 0x77, 0x17,
|
||||||
|
0x54, 0xd2, 0xee, 0xc6, 0xa6, 0x64, 0xbc, 0x9a,
|
||||||
|
}
|
||||||
|
|
||||||
|
// testPlainBlock should match the decrypted block of testEncBlock.
|
||||||
|
testPlainBlock []byte = []byte{
|
||||||
|
// 152 bytes
|
||||||
|
0x09, 0xf4, 0xb5, 0x8f, 0x09, 0xf4, 0xb5, 0x8f,
|
||||||
|
0x00, 0x00, 0x00, 0x0b, 0x73, 0x73, 0x68, 0x2d,
|
||||||
|
0x65, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x00,
|
||||||
|
0x00, 0x00, 0x20, 0xb8, 0xd3, 0x93, 0x30, 0x65,
|
||||||
|
0x72, 0xa6, 0xe5, 0x7e, 0x22, 0xa1, 0x64, 0x5b,
|
||||||
|
0x97, 0x9b, 0x01, 0x60, 0x7b, 0xdb, 0x1d, 0xcd,
|
||||||
|
0xcf, 0x92, 0x01, 0xd4, 0x80, 0xc3, 0xa9, 0x0a,
|
||||||
|
0xbd, 0xad, 0x20, 0x00, 0x00, 0x00, 0x40, 0x2d,
|
||||||
|
0xad, 0x50, 0x3f, 0x38, 0x88, 0xe2, 0xc1, 0x57,
|
||||||
|
0x0b, 0x1c, 0xa4, 0xcf, 0xbc, 0x7c, 0x39, 0xac,
|
||||||
|
0x19, 0xf2, 0x7b, 0x02, 0xac, 0x91, 0x1b, 0xd6,
|
||||||
|
0x05, 0x06, 0x00, 0xff, 0xe9, 0xb6, 0x83, 0xb8,
|
||||||
|
0xd3, 0x93, 0x30, 0x65, 0x72, 0xa6, 0xe5, 0x7e,
|
||||||
|
0x22, 0xa1, 0x64, 0x5b, 0x97, 0x9b, 0x01, 0x60,
|
||||||
|
0x7b, 0xdb, 0x1d, 0xcd, 0xcf, 0x92, 0x01, 0xd4,
|
||||||
|
0x80, 0xc3, 0xa9, 0x0a, 0xbd, 0xad, 0x20, 0x00,
|
||||||
|
0x00, 0x00, 0x14, 0x62, 0x74, 0x73, 0x40, 0x64,
|
||||||
|
0x61, 0x77, 0x69, 0x64, 0x2e, 0x72, 0x30, 0x30,
|
||||||
|
0x74, 0x2e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x01,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
11
errs.go
Normal file
11
errs.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package cc20p1305ssh
|
||||||
|
|
||||||
|
import (
|
||||||
|
`errors`
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrInvalidKeySize error = errors.New("a key of invalid size was provided; it must be at least 32 bytes")
|
||||||
|
ErrInvalidTag = errors.New("the provided tag does not match the ciphertext")
|
||||||
|
ErrInvalidTagSize = errors.New("a tag of invalid size was provided; it must be at least 16 bytes")
|
||||||
|
)
|
33
funcs.go
Normal file
33
funcs.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package cc20p1305ssh
|
||||||
|
|
||||||
|
/*
|
||||||
|
New returns a cipher.AEAD from KDF-derived key.
|
||||||
|
|
||||||
|
Currently, key should be KDFKeySize bytes and returned by bcrypt_pbkdf as it's currently the
|
||||||
|
only OpenSSH-supported KDF. It is up to the caller to perform the appropriate KDF.
|
||||||
|
|
||||||
|
Per the chacha20polycom1305@openssh.com specification, only the first KeySize bytes of key
|
||||||
|
is used for encrypting the private key. The second half (the canonical key is 64 bytes)
|
||||||
|
would be used for traffic purposes, but since this is a static blob it is not used.
|
||||||
|
|
||||||
|
If key is nil or <KDFKeySize bytes in length, an error ErrInvalidKeySize will be returned.
|
||||||
|
|
||||||
|
*DO NOT USE crypter FOR STREAMS. THIS SHOULD ONLY BE USED TO ENCRYPT AN OPENSSH PRIVATE KEY.*
|
||||||
|
*/
|
||||||
|
func New(key []byte) (crypter *ChaCha20Poly1305OpenSSH, err error) {
|
||||||
|
|
||||||
|
var crypterReal ChaCha20Poly1305OpenSSH
|
||||||
|
|
||||||
|
if key == nil || len(key) < KDFKeySize {
|
||||||
|
err = ErrInvalidKeySize
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
crypterReal = ChaCha20Poly1305OpenSSH{}
|
||||||
|
copy(crypterReal.kdfKey[:], key[:KDFKeySize])
|
||||||
|
copy(crypterReal.realKey[:], key[:KeySize])
|
||||||
|
|
||||||
|
crypter = &crypterReal
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
100
funcs_chacha20poly1305_ssh.go
Normal file
100
funcs_chacha20poly1305_ssh.go
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
package cc20p1305ssh
|
||||||
|
|
||||||
|
import (
|
||||||
|
`golang.org/x/crypto/chacha20`
|
||||||
|
`golang.org/x/crypto/poly1305`
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
Decrypt decrypts and authenticates ciphertext returning the decrypted format of ciphertext.
|
||||||
|
|
||||||
|
If tag is nil or empty, it will be assumed that the tag is appended to the end of ciphertext.
|
||||||
|
|
||||||
|
If tag is specified but is <TagSize, an error ErrInvalidTagSize will be returned.
|
||||||
|
*/
|
||||||
|
func (c *ChaCha20Poly1305OpenSSH) Decrypt(ciphertext, tag []byte) (decrypted []byte, err error) {
|
||||||
|
|
||||||
|
var tagIdx int
|
||||||
|
var firstBlock []byte
|
||||||
|
var polyKey [PolyKeySize]byte
|
||||||
|
var realTag [TagSize]byte
|
||||||
|
var cc20 *chacha20.Cipher
|
||||||
|
|
||||||
|
if tag == nil || len(tag) == 0 {
|
||||||
|
tagIdx = len(ciphertext) - TagSize
|
||||||
|
tag = ciphertext[tagIdx:]
|
||||||
|
ciphertext = ciphertext[:tagIdx]
|
||||||
|
}
|
||||||
|
if tag == nil || len(tag) != TagSize {
|
||||||
|
err = ErrInvalidTagSize
|
||||||
|
return
|
||||||
|
}
|
||||||
|
copy(realTag[:], tag)
|
||||||
|
|
||||||
|
// We need the crypter.
|
||||||
|
if cc20, err = chacha20.NewUnauthenticatedCipher(c.realKey[:], iv); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// First we need the poly1305 key. This also sets the counter to 1.
|
||||||
|
firstBlock = make([]byte, len(initBlock))
|
||||||
|
cc20.XORKeyStream(firstBlock, initBlock)
|
||||||
|
copy(polyKey[:], firstBlock[:PolyKeySize])
|
||||||
|
// We explicitly set the counter to 1, just in case.
|
||||||
|
cc20.SetCounter(1)
|
||||||
|
|
||||||
|
// And verify against the tag.
|
||||||
|
if !poly1305.Verify(&realTag, ciphertext, &polyKey) {
|
||||||
|
err = ErrInvalidTag
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, decrypt.
|
||||||
|
decrypted = make([]byte, len(ciphertext))
|
||||||
|
cc20.XORKeyStream(decrypted, ciphertext)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Encrypt encrypts and authenticates plaintext returning the encrypted format of plaintext.
|
||||||
|
|
||||||
|
If polyTag is nil or <TagSize bytes in length, an error ErrInvalidTagSize will be returned.
|
||||||
|
*/
|
||||||
|
func (c *ChaCha20Poly1305OpenSSH) Encrypt(plaintext []byte) (encrypted, tag []byte, err error) {
|
||||||
|
|
||||||
|
var polyKey [PolyKeySize]byte
|
||||||
|
var firstBlock []byte
|
||||||
|
var cc20 *chacha20.Cipher
|
||||||
|
var poly *poly1305.MAC
|
||||||
|
var tagTmp []byte
|
||||||
|
|
||||||
|
// TODO: check size of plaintext?
|
||||||
|
/*
|
||||||
|
if uint64(len(plaintext)) > (1<<38)-64 {
|
||||||
|
panic("chacha20poly1305: plaintext too large")
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// We need the crypter.
|
||||||
|
if cc20, err = chacha20.NewUnauthenticatedCipher(c.realKey[:], iv); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// First we need the poly1305 key. This also sets the counter to 1.
|
||||||
|
firstBlock = make([]byte, len(initBlock))
|
||||||
|
cc20.XORKeyStream(firstBlock, initBlock)
|
||||||
|
copy(polyKey[:], firstBlock[:PolyKeySize])
|
||||||
|
// We explicitly set the counter to 1, just in case.
|
||||||
|
cc20.SetCounter(1)
|
||||||
|
encrypted = make([]byte, len(plaintext))
|
||||||
|
cc20.XORKeyStream(encrypted, plaintext)
|
||||||
|
|
||||||
|
poly = poly1305.New(&polyKey)
|
||||||
|
poly.Write(encrypted)
|
||||||
|
tagTmp = poly.Sum(nil)
|
||||||
|
tag = make([]byte, TagSize)
|
||||||
|
copy(tag, tagTmp[:TagSize])
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
53
funcs_test.go
Normal file
53
funcs_test.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package cc20p1305ssh
|
||||||
|
|
||||||
|
import (
|
||||||
|
`bytes`
|
||||||
|
`encoding/hex`
|
||||||
|
`testing`
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNewCipher(t *testing.T) {
|
||||||
|
|
||||||
|
var err error
|
||||||
|
var c *ChaCha20Poly1305OpenSSH
|
||||||
|
var enc []byte
|
||||||
|
var plain []byte
|
||||||
|
var tag []byte
|
||||||
|
|
||||||
|
if c, err = New(testKdfKey); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("ChaCha20Poly1305OpenSSH:\n%#v", c)
|
||||||
|
|
||||||
|
// Decrypt...
|
||||||
|
if plain, err = c.Decrypt(testEncBlock, testPoly1305Tag); err != nil {
|
||||||
|
t.Log("Failed during decrypt!")
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Logf("plain:\n%v", hex.EncodeToString(plain))
|
||||||
|
|
||||||
|
if !bytes.Equal(plain, testPlainBlock) {
|
||||||
|
t.Fatal("decrypted does not match!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// And encrypt...
|
||||||
|
if enc, tag, err = c.Encrypt(plain); err != nil {
|
||||||
|
t.Log("Failed during encrypt!")
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Logf("crypted:\n%v", hex.EncodeToString(enc))
|
||||||
|
|
||||||
|
if !bytes.Equal(enc, testEncBlock) {
|
||||||
|
t.Fatal("encrypted does not match!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// And check tags.
|
||||||
|
if !bytes.Equal(tag, testPoly1305Tag) {
|
||||||
|
t.Logf("real tag: %v", hex.EncodeToString(testPoly1305Tag))
|
||||||
|
t.Logf("generated tag: %v", hex.EncodeToString(tag))
|
||||||
|
t.Fatal("tags do not match!")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log("The cipher is functioning correctly.")
|
||||||
|
}
|
11
types.go
Normal file
11
types.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package cc20p1305ssh
|
||||||
|
|
||||||
|
/*
|
||||||
|
ChaCha20Poly1305OpenSSH is an implementation of the chacha20poly1305@openssh.com private key cipher.
|
||||||
|
|
||||||
|
Use New to return a usable version.
|
||||||
|
*/
|
||||||
|
type ChaCha20Poly1305OpenSSH struct {
|
||||||
|
kdfKey [KDFKeySize]byte
|
||||||
|
realKey [KeySize]byte
|
||||||
|
}
|
100
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go
generated
vendored
Normal file
100
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go
generated
vendored
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package chacha20poly1305 implements the ChaCha20-Poly1305 AEAD and its
|
||||||
|
// extended nonce variant XChaCha20-Poly1305, as specified in RFC 8439 and
|
||||||
|
// draft-irtf-cfrg-xchacha-01.
|
||||||
|
package chacha20poly1305 // import "golang.org/x/crypto/chacha20poly1305"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/cipher"
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// KeySize is the size of the key used by this AEAD, in bytes.
|
||||||
|
KeySize = 32
|
||||||
|
|
||||||
|
// NonceSize is the size of the nonce used with the standard variant of this
|
||||||
|
// AEAD, in bytes.
|
||||||
|
//
|
||||||
|
// Note that this is too short to be safely generated at random if the same
|
||||||
|
// key is reused more than 2³² times.
|
||||||
|
// NonceSize = 12
|
||||||
|
// BITE ME, GOLANG DEVS.
|
||||||
|
NonceSize = 16
|
||||||
|
|
||||||
|
// NonceSizeX is the size of the nonce used with the XChaCha20-Poly1305
|
||||||
|
// variant of this AEAD, in bytes.
|
||||||
|
NonceSizeX = 24
|
||||||
|
|
||||||
|
// Overhead is the size of the Poly1305 authentication tag, and the
|
||||||
|
// difference between a ciphertext length and its plaintext.
|
||||||
|
Overhead = 16
|
||||||
|
)
|
||||||
|
|
||||||
|
type chacha20poly1305 struct {
|
||||||
|
key [KeySize]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns a ChaCha20-Poly1305 AEAD that uses the given 256-bit key.
|
||||||
|
func New(key []byte) (cipher.AEAD, error) {
|
||||||
|
if len(key) != KeySize {
|
||||||
|
return nil, errors.New("chacha20poly1305: bad key length")
|
||||||
|
}
|
||||||
|
ret := new(chacha20poly1305)
|
||||||
|
copy(ret.key[:], key)
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *chacha20poly1305) NonceSize() int {
|
||||||
|
return NonceSize
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *chacha20poly1305) Overhead() int {
|
||||||
|
return Overhead
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *chacha20poly1305) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
|
||||||
|
if len(nonce) != NonceSize {
|
||||||
|
panic("chacha20poly1305: bad nonce length passed to Seal")
|
||||||
|
}
|
||||||
|
|
||||||
|
if uint64(len(plaintext)) > (1<<38)-64 {
|
||||||
|
panic("chacha20poly1305: plaintext too large")
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.seal(dst, nonce, plaintext, additionalData)
|
||||||
|
}
|
||||||
|
|
||||||
|
var errOpen = errors.New("chacha20poly1305: message authentication failed")
|
||||||
|
|
||||||
|
func (c *chacha20poly1305) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
||||||
|
if len(nonce) != NonceSize {
|
||||||
|
panic("chacha20poly1305: bad nonce length passed to Open")
|
||||||
|
}
|
||||||
|
if len(ciphertext) < 16 {
|
||||||
|
return nil, errOpen
|
||||||
|
}
|
||||||
|
if uint64(len(ciphertext)) > (1<<38)-48 {
|
||||||
|
panic("chacha20poly1305: ciphertext too large")
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.open(dst, nonce, ciphertext, additionalData)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sliceForAppend takes a slice and a requested number of bytes. It returns a
|
||||||
|
// slice with the contents of the given slice followed by that many bytes and a
|
||||||
|
// second slice that aliases into it and contains only the extra bytes. If the
|
||||||
|
// original slice has sufficient capacity then no allocation is performed.
|
||||||
|
func sliceForAppend(in []byte, n int) (head, tail []byte) {
|
||||||
|
if total := len(in) + n; cap(in) >= total {
|
||||||
|
head = in[:total]
|
||||||
|
} else {
|
||||||
|
head = make([]byte, total)
|
||||||
|
copy(head, in)
|
||||||
|
}
|
||||||
|
tail = head[len(in):]
|
||||||
|
return
|
||||||
|
}
|
87
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go
generated
vendored
Normal file
87
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go
generated
vendored
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build gc && !purego
|
||||||
|
// +build gc,!purego
|
||||||
|
|
||||||
|
package chacha20poly1305
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/internal/alias"
|
||||||
|
"golang.org/x/sys/cpu"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:noescape
|
||||||
|
func chacha20Poly1305Open(dst []byte, key []uint32, src, ad []byte) bool
|
||||||
|
|
||||||
|
//go:noescape
|
||||||
|
func chacha20Poly1305Seal(dst []byte, key []uint32, src, ad []byte)
|
||||||
|
|
||||||
|
var (
|
||||||
|
useAVX2 = cpu.X86.HasAVX2 && cpu.X86.HasBMI2
|
||||||
|
)
|
||||||
|
|
||||||
|
// setupState writes a ChaCha20 input matrix to state. See
|
||||||
|
// https://tools.ietf.org/html/rfc7539#section-2.3.
|
||||||
|
func setupState(state *[16]uint32, key *[32]byte, nonce []byte) {
|
||||||
|
state[0] = 0x61707865
|
||||||
|
state[1] = 0x3320646e
|
||||||
|
state[2] = 0x79622d32
|
||||||
|
state[3] = 0x6b206574
|
||||||
|
|
||||||
|
state[4] = binary.LittleEndian.Uint32(key[0:4])
|
||||||
|
state[5] = binary.LittleEndian.Uint32(key[4:8])
|
||||||
|
state[6] = binary.LittleEndian.Uint32(key[8:12])
|
||||||
|
state[7] = binary.LittleEndian.Uint32(key[12:16])
|
||||||
|
state[8] = binary.LittleEndian.Uint32(key[16:20])
|
||||||
|
state[9] = binary.LittleEndian.Uint32(key[20:24])
|
||||||
|
state[10] = binary.LittleEndian.Uint32(key[24:28])
|
||||||
|
state[11] = binary.LittleEndian.Uint32(key[28:32])
|
||||||
|
|
||||||
|
state[12] = 0
|
||||||
|
state[13] = binary.LittleEndian.Uint32(nonce[0:4])
|
||||||
|
state[14] = binary.LittleEndian.Uint32(nonce[4:8])
|
||||||
|
state[15] = binary.LittleEndian.Uint32(nonce[8:12])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte {
|
||||||
|
if !cpu.X86.HasSSSE3 {
|
||||||
|
return c.sealGeneric(dst, nonce, plaintext, additionalData)
|
||||||
|
}
|
||||||
|
|
||||||
|
var state [16]uint32
|
||||||
|
setupState(&state, &c.key, nonce)
|
||||||
|
|
||||||
|
ret, out := sliceForAppend(dst, len(plaintext)+16)
|
||||||
|
if alias.InexactOverlap(out, plaintext) {
|
||||||
|
panic("chacha20poly1305: invalid buffer overlap")
|
||||||
|
}
|
||||||
|
chacha20Poly1305Seal(out[:], state[:], plaintext, additionalData)
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
||||||
|
if !cpu.X86.HasSSSE3 {
|
||||||
|
return c.openGeneric(dst, nonce, ciphertext, additionalData)
|
||||||
|
}
|
||||||
|
|
||||||
|
var state [16]uint32
|
||||||
|
setupState(&state, &c.key, nonce)
|
||||||
|
|
||||||
|
ciphertext = ciphertext[:len(ciphertext)-16]
|
||||||
|
ret, out := sliceForAppend(dst, len(ciphertext))
|
||||||
|
if alias.InexactOverlap(out, ciphertext) {
|
||||||
|
panic("chacha20poly1305: invalid buffer overlap")
|
||||||
|
}
|
||||||
|
if !chacha20Poly1305Open(out, state[:], ciphertext, additionalData) {
|
||||||
|
for i := range out {
|
||||||
|
out[i] = 0
|
||||||
|
}
|
||||||
|
return nil, errOpen
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
2696
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s
generated
vendored
Normal file
2696
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
81
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go
generated
vendored
Normal file
81
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go
generated
vendored
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package chacha20poly1305
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/chacha20"
|
||||||
|
"golang.org/x/crypto/internal/alias"
|
||||||
|
"golang.org/x/crypto/internal/poly1305"
|
||||||
|
)
|
||||||
|
|
||||||
|
func writeWithPadding(p *poly1305.MAC, b []byte) {
|
||||||
|
p.Write(b)
|
||||||
|
if rem := len(b) % 16; rem != 0 {
|
||||||
|
var buf [16]byte
|
||||||
|
padLen := 16 - rem
|
||||||
|
p.Write(buf[:padLen])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeUint64(p *poly1305.MAC, n int) {
|
||||||
|
var buf [8]byte
|
||||||
|
binary.LittleEndian.PutUint64(buf[:], uint64(n))
|
||||||
|
p.Write(buf[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *chacha20poly1305) sealGeneric(dst, nonce, plaintext, additionalData []byte) []byte {
|
||||||
|
ret, out := sliceForAppend(dst, len(plaintext)+poly1305.TagSize)
|
||||||
|
ciphertext, tag := out[:len(plaintext)], out[len(plaintext):]
|
||||||
|
if alias.InexactOverlap(out, plaintext) {
|
||||||
|
panic("chacha20poly1305: invalid buffer overlap")
|
||||||
|
}
|
||||||
|
|
||||||
|
var polyKey [32]byte
|
||||||
|
s, _ := chacha20.NewUnauthenticatedCipher(c.key[:], nonce)
|
||||||
|
s.XORKeyStream(polyKey[:], polyKey[:])
|
||||||
|
s.SetCounter(1) // set the counter to 1, skipping 32 bytes
|
||||||
|
s.XORKeyStream(ciphertext, plaintext)
|
||||||
|
|
||||||
|
p := poly1305.New(&polyKey)
|
||||||
|
writeWithPadding(p, additionalData)
|
||||||
|
writeWithPadding(p, ciphertext)
|
||||||
|
writeUint64(p, len(additionalData))
|
||||||
|
writeUint64(p, len(plaintext))
|
||||||
|
p.Sum(tag[:0])
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *chacha20poly1305) openGeneric(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
||||||
|
tag := ciphertext[len(ciphertext)-16:]
|
||||||
|
ciphertext = ciphertext[:len(ciphertext)-16]
|
||||||
|
|
||||||
|
var polyKey [32]byte
|
||||||
|
s, _ := chacha20.NewUnauthenticatedCipher(c.key[:], nonce)
|
||||||
|
s.XORKeyStream(polyKey[:], polyKey[:])
|
||||||
|
s.SetCounter(1) // set the counter to 1, skipping 32 bytes
|
||||||
|
|
||||||
|
p := poly1305.New(&polyKey)
|
||||||
|
writeWithPadding(p, additionalData)
|
||||||
|
writeWithPadding(p, ciphertext)
|
||||||
|
writeUint64(p, len(additionalData))
|
||||||
|
writeUint64(p, len(ciphertext))
|
||||||
|
|
||||||
|
ret, out := sliceForAppend(dst, len(ciphertext))
|
||||||
|
if alias.InexactOverlap(out, ciphertext) {
|
||||||
|
panic("chacha20poly1305: invalid buffer overlap")
|
||||||
|
}
|
||||||
|
if !p.Verify(tag) {
|
||||||
|
for i := range out {
|
||||||
|
out[i] = 0
|
||||||
|
}
|
||||||
|
return nil, errOpen
|
||||||
|
}
|
||||||
|
|
||||||
|
s.XORKeyStream(out, ciphertext)
|
||||||
|
return ret, nil
|
||||||
|
}
|
16
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go
generated
vendored
Normal file
16
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build !amd64 || !gc || purego
|
||||||
|
// +build !amd64 !gc purego
|
||||||
|
|
||||||
|
package chacha20poly1305
|
||||||
|
|
||||||
|
func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte {
|
||||||
|
return c.sealGeneric(dst, nonce, plaintext, additionalData)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
||||||
|
return c.openGeneric(dst, nonce, ciphertext, additionalData)
|
||||||
|
}
|
86
vendor/golang.org/x/crypto/chacha20poly1305/xchacha20poly1305.go
generated
vendored
Normal file
86
vendor/golang.org/x/crypto/chacha20poly1305/xchacha20poly1305.go
generated
vendored
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package chacha20poly1305
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/cipher"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/chacha20"
|
||||||
|
)
|
||||||
|
|
||||||
|
type xchacha20poly1305 struct {
|
||||||
|
key [KeySize]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewX returns a XChaCha20-Poly1305 AEAD that uses the given 256-bit key.
|
||||||
|
//
|
||||||
|
// XChaCha20-Poly1305 is a ChaCha20-Poly1305 variant that takes a longer nonce,
|
||||||
|
// suitable to be generated randomly without risk of collisions. It should be
|
||||||
|
// preferred when nonce uniqueness cannot be trivially ensured, or whenever
|
||||||
|
// nonces are randomly generated.
|
||||||
|
func NewX(key []byte) (cipher.AEAD, error) {
|
||||||
|
if len(key) != KeySize {
|
||||||
|
return nil, errors.New("chacha20poly1305: bad key length")
|
||||||
|
}
|
||||||
|
ret := new(xchacha20poly1305)
|
||||||
|
copy(ret.key[:], key)
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*xchacha20poly1305) NonceSize() int {
|
||||||
|
return NonceSizeX
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*xchacha20poly1305) Overhead() int {
|
||||||
|
return Overhead
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *xchacha20poly1305) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
|
||||||
|
if len(nonce) != NonceSizeX {
|
||||||
|
panic("chacha20poly1305: bad nonce length passed to Seal")
|
||||||
|
}
|
||||||
|
|
||||||
|
// XChaCha20-Poly1305 technically supports a 64-bit counter, so there is no
|
||||||
|
// size limit. However, since we reuse the ChaCha20-Poly1305 implementation,
|
||||||
|
// the second half of the counter is not available. This is unlikely to be
|
||||||
|
// an issue because the cipher.AEAD API requires the entire message to be in
|
||||||
|
// memory, and the counter overflows at 256 GB.
|
||||||
|
if uint64(len(plaintext)) > (1<<38)-64 {
|
||||||
|
panic("chacha20poly1305: plaintext too large")
|
||||||
|
}
|
||||||
|
|
||||||
|
c := new(chacha20poly1305)
|
||||||
|
hKey, _ := chacha20.HChaCha20(x.key[:], nonce[0:16])
|
||||||
|
copy(c.key[:], hKey)
|
||||||
|
|
||||||
|
// The first 4 bytes of the final nonce are unused counter space.
|
||||||
|
cNonce := make([]byte, NonceSize)
|
||||||
|
copy(cNonce[4:12], nonce[16:24])
|
||||||
|
|
||||||
|
return c.seal(dst, cNonce[:], plaintext, additionalData)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *xchacha20poly1305) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
||||||
|
if len(nonce) != NonceSizeX {
|
||||||
|
panic("chacha20poly1305: bad nonce length passed to Open")
|
||||||
|
}
|
||||||
|
if len(ciphertext) < 16 {
|
||||||
|
return nil, errOpen
|
||||||
|
}
|
||||||
|
if uint64(len(ciphertext)) > (1<<38)-48 {
|
||||||
|
panic("chacha20poly1305: ciphertext too large")
|
||||||
|
}
|
||||||
|
|
||||||
|
c := new(chacha20poly1305)
|
||||||
|
hKey, _ := chacha20.HChaCha20(x.key[:], nonce[0:16])
|
||||||
|
copy(c.key[:], hKey)
|
||||||
|
|
||||||
|
// The first 4 bytes of the final nonce are unused counter space.
|
||||||
|
cNonce := make([]byte, NonceSize)
|
||||||
|
copy(cNonce[4:12], nonce[16:24])
|
||||||
|
|
||||||
|
return c.open(dst, cNonce[:], ciphertext, additionalData)
|
||||||
|
}
|
1
vendor/modules.txt
vendored
1
vendor/modules.txt
vendored
@ -1,6 +1,7 @@
|
|||||||
# golang.org/x/crypto v0.5.0
|
# golang.org/x/crypto v0.5.0
|
||||||
## explicit; go 1.17
|
## explicit; go 1.17
|
||||||
golang.org/x/crypto/chacha20
|
golang.org/x/crypto/chacha20
|
||||||
|
golang.org/x/crypto/chacha20poly1305
|
||||||
golang.org/x/crypto/internal/alias
|
golang.org/x/crypto/internal/alias
|
||||||
golang.org/x/crypto/internal/poly1305
|
golang.org/x/crypto/internal/poly1305
|
||||||
golang.org/x/crypto/poly1305
|
golang.org/x/crypto/poly1305
|
||||||
|
Loading…
Reference in New Issue
Block a user