Skip to content

Commit

Permalink
Merge pull request #1065 from microsoft/dev/qmuntal/rc4
Browse files Browse the repository at this point in the history
Implement support for crypto/rc4 using OpenSSL/CNG
  • Loading branch information
qmuntal authored Oct 18, 2023
2 parents 0ce9216 + fdcc079 commit 0ce5483
Show file tree
Hide file tree
Showing 6 changed files with 740 additions and 165 deletions.
47 changes: 45 additions & 2 deletions eng/doc/fips/UserGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ The Go crypto documentation is available online at https://pkg.go.dev/crypto.
- [func Prime](#func-prime)
- [func Read](#func-read)
- [crypto/rc4](#cryptorc4)
- [func NewCipher](#func-newcipher-1)
- [crypto/sha1](#cryptosha1)
- [func New](#func-new-1)
- [func Sum](#func-sum)
Expand Down Expand Up @@ -806,7 +807,44 @@ Read is a helper function that calls rand.Reader.Read using io.ReadFull.

### [crypto/rc4](https://pkg.go.dev/crypto/rc4)

Not implemented by any backend.
Package rc4 implements RC4 encryption, as defined in Bruce Schneier's Applied Cryptography.

#### func [NewCipher](https://pkg.go.dev/crypto/rc4#NewCipher)

```go
func rc4.NewCipher() rc4.Cipher
```

NewCipher creates and returns a new Cipher. The key argument should be the RC4 key, at least 1 byte and at most 256 bytes.

**Requirements**

Some OpenSSL distributions don't implement RC4, e.g., OpenSSL 1.x compiled with `-DOPENSSL_NO_RC4` and OpenSSL 3.x that can't load the legacy provider.
In those cases, `rc4.NewCipher()` will fall back to standard Go crypto.

**Implementation**

<details><summary>OpenSSL (click for details)</summary>

The cipher is generated using [EVP_CIPHER_CTX_new] and [EVP_CipherInit_ex] with the cipher type [EVP_rc4].

The rc4.Cipher methods are implemented as follows:

- `Reset` using [EVP_CIPHER_CTX_free].
- `XORKeyStream` using [EVP_EncryptUpdate].

</details>

<details><summary>CNG (click for details)</summary>

The cipher is generated using [BCryptGenerateSymmetricKey] using the `BCRYPT_RC4_ALGORITHM` mode.

The rc4.Cipher methods are implemented as follows:

- `Reset` using [BCryptDestroyKey].
- `XORKeyStream` using [BCryptEncrypt].

</details>

### [crypto/sha1](https://pkg.go.dev/crypto/sha1)

Expand Down Expand Up @@ -1442,6 +1480,7 @@ When using TLS in FIPS-only mode the TLS handshake has the following restriction
[EVP_aes_128_cbc]: https://www.openssl.org/docs/man3.0/man3/EVP_aes_128_cbc.html
[EVP_aes_192_cbc]: https://www.openssl.org/docs/man3.0/man3/EVP_aes_192_cbc.html
[EVP_aes_256_cbc]: https://www.openssl.org/docs/man3.0/man3/EVP_aes_256_cbc.html
[EVP_rc4]: https://www.openssl.org/docs/man3.0/man3/EVP_rc4.html
[EVP_sha1]: https://www.openssl.org/docs/man3.0/man3/EVP_sha1.html
[EVP_sha224]: https://www.openssl.org/docs/man3.0/man3/EVP_sha224.html
[EVP_sha256]: https://www.openssl.org/docs/man3.0/man3/EVP_sha256.html
Expand All @@ -1455,6 +1494,9 @@ When using TLS in FIPS-only mode the TLS handshake has the following restriction
[EVP_MAC_init]: https://www.openssl.org/docs/man3.0/man3/EVP_MAC_init.html
[EVP_MAC_update]: https://www.openssl.org/docs/man3.0/man3/EVP_MAC_update.html
[EVP_MAC_final]: https://www.openssl.org/docs/man3.0/man3/EVP_MAC_final.html
[EVP_CIPHER_CTX_new]: https://www.openssl.org/docs/man3.0/man3/EVP_CIPHER_CTX_new.html
[EVP_CipherInit_ex]: https://www.openssl.org/docs/man3.0/man3/EVP_CipherInit_ex.html
[EVP_CIPHER_CTX_free]: https://www.openssl.org/docs/man3.0/man3/EVP_CIPHER_CTX_free.html

[algorithm identifier]: https://docs.microsoft.com/en-us/windows/win32/seccng/cng-algorithm-identifiers
[named elliptic curve]: https://docs.microsoft.com/en-us/windows/win32/seccng/cng-named-elliptic-curves
Expand All @@ -1474,4 +1516,5 @@ When using TLS in FIPS-only mode the TLS handshake has the following restriction
[BCRYPT_OAEP_PADDING_INFO]: https://docs.microsoft.com/en-us/windows/win32/api/Bcrypt/ns-bcrypt-bcrypt_oaep_padding_info
[BCRYPT_PKCS1_PADDING_INFO]: https://docs.microsoft.com/en-us/windows/win32/api/Bcrypt/ns-bcrypt-bcrypt_pkcs1_padding_info
[BCRYPT_PSS_PADDING_INFO]: https://docs.microsoft.com/en-us/windows/win32/api/Bcrypt/ns-bcrypt-bcrypt_pss_padding_info
[BCryptDeriveKey]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptderivekey
[BCryptDeriveKey]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptderivekey
[BCryptDestroyKey]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptdestroykey
81 changes: 74 additions & 7 deletions patches/0002-Add-crypto-backend-foundation.patch
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,16 @@ Subject: [PATCH] Add crypto backend foundation
src/crypto/hmac/hmac.go | 2 +-
src/crypto/hmac/hmac_test.go | 2 +-
src/crypto/internal/backend/backend_test.go | 30 ++++
src/crypto/internal/backend/bbig/big.go | 17 +++
src/crypto/internal/backend/bbig/big.go | 17 ++
src/crypto/internal/backend/common.go | 78 ++++++++++
src/crypto/internal/backend/isrequirefips.go | 9 ++
src/crypto/internal/backend/nobackend.go | 145 +++++++++++++++++++
src/crypto/internal/backend/nobackend.go | 154 +++++++++++++++++++
src/crypto/internal/backend/norequirefips.go | 9 ++
src/crypto/internal/backend/stub.s | 10 ++
src/crypto/md5/md5.go | 7 +
src/crypto/md5/md5_test.go | 4 +
src/crypto/rand/rand_unix.go | 2 +-
src/crypto/rc4/rc4.go | 18 +++
src/crypto/rsa/boring.go | 4 +-
src/crypto/rsa/notboring.go | 2 +-
src/crypto/rsa/pkcs1v15.go | 2 +-
Expand All @@ -39,14 +40,14 @@ Subject: [PATCH] Add crypto backend foundation
src/crypto/sha512/sha512.go | 2 +-
src/crypto/sha512/sha512_test.go | 2 +-
src/crypto/tls/cipher_suites.go | 2 +-
src/crypto/tls/handshake_client.go | 25 +++-
src/crypto/tls/handshake_server.go | 25 +++-
src/crypto/tls/handshake_client.go | 25 ++-
src/crypto/tls/handshake_server.go | 25 ++-
src/crypto/tls/key_schedule.go | 18 ++-
src/crypto/tls/prf.go | 77 +++++++---
src/crypto/tls/prf_test.go | 12 +-
src/go/build/deps_test.go | 2 +
src/runtime/runtime_boring.go | 5 +
42 files changed, 473 insertions(+), 65 deletions(-)
43 files changed, 500 insertions(+), 65 deletions(-)
create mode 100644 src/crypto/internal/backend/backend_test.go
create mode 100644 src/crypto/internal/backend/bbig/big.go
create mode 100644 src/crypto/internal/backend/common.go
Expand Down Expand Up @@ -395,10 +396,10 @@ index 00000000000000..e5d7570d6d4363
+const isRequireFIPS = true
diff --git a/src/crypto/internal/backend/nobackend.go b/src/crypto/internal/backend/nobackend.go
new file mode 100644
index 00000000000000..275a6078f90514
index 00000000000000..f45f2fe76d54f1
--- /dev/null
+++ b/src/crypto/internal/backend/nobackend.go
@@ -0,0 +1,145 @@
@@ -0,0 +1,154 @@
+// Copyright 2017 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.
Expand Down Expand Up @@ -544,6 +545,15 @@ index 00000000000000..275a6078f90514
+func NewDESCipher(key []byte) (cipher.Block, error) { panic("cryptobackend: not available") }
+
+func NewTripleDESCipher(key []byte) (cipher.Block, error) { panic("cryptobackend: not available") }
+
+func SupportsRC4() bool { panic("cryptobackend: not available") }
+
+type RC4Cipher struct{}
+
+func (c *RC4Cipher) Reset() { panic("cryptobackend: not available") }
+func (c *RC4Cipher) XORKeyStream(dst, src []byte) { panic("cryptobackend: not available") }
+
+func NewRC4Cipher(key []byte) (*RC4Cipher, error) { panic("cryptobackend: not available") }
diff --git a/src/crypto/internal/backend/norequirefips.go b/src/crypto/internal/backend/norequirefips.go
new file mode 100644
index 00000000000000..26bfb5f6a643f3
Expand Down Expand Up @@ -642,6 +652,63 @@ index 40fce36314adfa..1d6231ae91d5ae 100644
"errors"
"io"
"os"
diff --git a/src/crypto/rc4/rc4.go b/src/crypto/rc4/rc4.go
index f08da0e469cd07..b3e7db0413ed72 100644
--- a/src/crypto/rc4/rc4.go
+++ b/src/crypto/rc4/rc4.go
@@ -11,6 +11,7 @@ package rc4

import (
"crypto/internal/alias"
+ boring "crypto/internal/backend"
"strconv"
)

@@ -18,6 +19,8 @@ import (
type Cipher struct {
s [256]uint32
i, j uint8
+
+ boring *boring.RC4Cipher
}

type KeySizeError int
@@ -33,6 +36,13 @@ func NewCipher(key []byte) (*Cipher, error) {
if k < 1 || k > 256 {
return nil, KeySizeError(k)
}
+ if boring.Enabled && boring.SupportsRC4() {
+ c, err := boring.NewRC4Cipher(key)
+ if err != nil {
+ return nil, err
+ }
+ return &Cipher{boring: c}, nil
+ }
var c Cipher
for i := 0; i < 256; i++ {
c.s[i] = uint32(i)
@@ -50,6 +60,10 @@ func NewCipher(key []byte) (*Cipher, error) {
// Deprecated: Reset can't guarantee that the key will be entirely removed from
// the process's memory.
func (c *Cipher) Reset() {
+ if boring.Enabled && boring.SupportsRC4() {
+ c.boring.Reset()
+ return
+ }
for i := range c.s {
c.s[i] = 0
}
@@ -59,6 +73,10 @@ func (c *Cipher) Reset() {
// XORKeyStream sets dst to the result of XORing src with the key stream.
// Dst and src must overlap entirely or not at all.
func (c *Cipher) XORKeyStream(dst, src []byte) {
+ if boring.Enabled && boring.SupportsRC4() {
+ c.boring.XORKeyStream(dst, src)
+ return
+ }
if len(src) == 0 {
return
}
diff --git a/src/crypto/rsa/boring.go b/src/crypto/rsa/boring.go
index b9f9d3154f2589..ecb43aaf264743 100644
--- a/src/crypto/rsa/boring.go
Expand Down
19 changes: 15 additions & 4 deletions patches/0003-Add-BoringSSL-crypto-backend.patch
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ Subject: [PATCH] Add BoringSSL crypto backend

---
.../internal/backend/bbig/big_boring.go | 12 ++
src/crypto/internal/backend/boring_linux.go | 175 ++++++++++++++++++
2 files changed, 187 insertions(+)
src/crypto/internal/backend/boring_linux.go | 186 ++++++++++++++++++
2 files changed, 198 insertions(+)
create mode 100644 src/crypto/internal/backend/bbig/big_boring.go
create mode 100644 src/crypto/internal/backend/boring_linux.go

Expand All @@ -30,10 +30,10 @@ index 00000000000000..0b62cef68546d0
+var Dec = bbig.Dec
diff --git a/src/crypto/internal/backend/boring_linux.go b/src/crypto/internal/backend/boring_linux.go
new file mode 100644
index 00000000000000..bc5c54b02acf2f
index 00000000000000..af2d4b857df333
--- /dev/null
+++ b/src/crypto/internal/backend/boring_linux.go
@@ -0,0 +1,175 @@
@@ -0,0 +1,186 @@
+// Copyright 2017 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.
Expand Down Expand Up @@ -209,3 +209,14 @@ index 00000000000000..bc5c54b02acf2f
+func NewTripleDESCipher(key []byte) (cipher.Block, error) {
+ panic("cryptobackend: not available")
+}
+
+func SupportsRC4() bool { return false }
+
+type RC4Cipher struct{}
+
+func (c *RC4Cipher) Reset() { panic("cryptobackend: not available") }
+func (c *RC4Cipher) XORKeyStream(dst, src []byte) { panic("cryptobackend: not available") }
+
+func NewRC4Cipher(key []byte) (*RC4Cipher, error) {
+ panic("cryptobackend: not available")
+}
30 changes: 19 additions & 11 deletions patches/0004-Add-OpenSSL-crypto-backend.patch
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Subject: [PATCH] Add OpenSSL crypto backend
src/crypto/ecdsa/notboring.go | 2 +-
src/crypto/internal/backend/bbig/big.go | 2 +-
.../internal/backend/bbig/big_openssl.go | 12 +
src/crypto/internal/backend/openssl_linux.go | 279 ++++++++++++++++++
src/crypto/internal/backend/openssl_linux.go | 287 ++++++++++++++++++
src/crypto/internal/boring/fipstls/stub.s | 2 +-
src/crypto/internal/boring/fipstls/tls.go | 2 +-
src/crypto/rsa/boring.go | 2 +-
Expand All @@ -37,7 +37,7 @@ Subject: [PATCH] Add OpenSSL crypto backend
.../goexperiment/exp_opensslcrypto_on.go | 9 +
src/internal/goexperiment/flags.go | 1 +
src/os/exec/exec_test.go | 9 +
33 files changed, 361 insertions(+), 23 deletions(-)
33 files changed, 369 insertions(+), 23 deletions(-)
create mode 100644 src/crypto/internal/backend/bbig/big_openssl.go
create mode 100644 src/crypto/internal/backend/openssl_linux.go
create mode 100644 src/internal/goexperiment/exp_opensslcrypto_off.go
Expand Down Expand Up @@ -190,10 +190,10 @@ index 00000000000000..e6695dd66b1d02
+var Dec = bbig.Dec
diff --git a/src/crypto/internal/backend/openssl_linux.go b/src/crypto/internal/backend/openssl_linux.go
new file mode 100644
index 00000000000000..d342e4b0f11e23
index 00000000000000..ff02e561452aa3
--- /dev/null
+++ b/src/crypto/internal/backend/openssl_linux.go
@@ -0,0 +1,279 @@
@@ -0,0 +1,287 @@
+// Copyright 2017 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.
Expand Down Expand Up @@ -322,14 +322,14 @@ index 00000000000000..d342e4b0f11e23
+ return openssl.SupportsHash(h)
+}
+
+func NewMD5() hash.Hash { return openssl.NewMD5() }
+func NewMD5() hash.Hash { return openssl.NewMD5() }
+func NewSHA1() hash.Hash { return openssl.NewSHA1() }
+func NewSHA224() hash.Hash { return openssl.NewSHA224() }
+func NewSHA256() hash.Hash { return openssl.NewSHA256() }
+func NewSHA384() hash.Hash { return openssl.NewSHA384() }
+func NewSHA512() hash.Hash { return openssl.NewSHA512() }
+
+func MD5(p []byte) (sum [16]byte) { return openssl.MD5(p) }
+func MD5(p []byte) (sum [16]byte) { return openssl.MD5(p) }
+func SHA1(p []byte) (sum [20]byte) { return openssl.SHA1(p) }
+func SHA224(p []byte) (sum [28]byte) { return openssl.SHA224(p) }
+func SHA256(p []byte) (sum [32]byte) { return openssl.SHA256(p) }
Expand Down Expand Up @@ -473,6 +473,14 @@ index 00000000000000..d342e4b0f11e23
+func NewTripleDESCipher(key []byte) (cipher.Block, error) {
+ return openssl.NewTripleDESCipher(key)
+}
+
+func SupportsRC4() bool {
+ return openssl.SupportsRC4()
+}
+
+type RC4Cipher = openssl.RC4Cipher
+
+func NewRC4Cipher(key []byte) (*RC4Cipher, error) { return openssl.NewRC4Cipher(key) }
diff --git a/src/crypto/internal/boring/fipstls/stub.s b/src/crypto/internal/boring/fipstls/stub.s
index f2e5a503eaacb6..1dc7116efdff2e 100644
--- a/src/crypto/internal/boring/fipstls/stub.s
Expand Down Expand Up @@ -669,24 +677,24 @@ index c83a7272c9f01f..a0548a7f9179c5 100644
package x509

diff --git a/src/go.mod b/src/go.mod
index 8f7dd5c0b69932..b5222cd4fb66b3 100644
index 8f7dd5c0b69932..0a9f28adb67211 100644
--- a/src/go.mod
+++ b/src/go.mod
@@ -3,6 +3,7 @@ module std
go 1.22

require (
+ github.com/golang-fips/openssl/v2 v2.0.0-rc.3.0.20230926133027-251d5fd9efa6
+ github.com/golang-fips/openssl/v2 v2.0.0-rc.3.0.20231013091736-92d3f16e56cd
golang.org/x/crypto v0.14.0
golang.org/x/net v0.17.0
)
diff --git a/src/go.sum b/src/go.sum
index 22511da608a07b..2e071695221e13 100644
index 22511da608a07b..afa147f35171de 100644
--- a/src/go.sum
+++ b/src/go.sum
@@ -1,3 +1,5 @@
+github.com/golang-fips/openssl/v2 v2.0.0-rc.3.0.20230926133027-251d5fd9efa6 h1:htngJbDceHA29WbezaO55msU/iITDkdto1p1iHHmjC0=
+github.com/golang-fips/openssl/v2 v2.0.0-rc.3.0.20230926133027-251d5fd9efa6/go.mod h1:7tuBqX2Zov8Yq5mJ2yzlKhpnxOnWyEzi38AzeWRuQdg=
+github.com/golang-fips/openssl/v2 v2.0.0-rc.3.0.20231013091736-92d3f16e56cd h1:+SvJEqhqQ8d/wzyk+xmTgBpHDOYQtnS/F8283hznEAc=
+github.com/golang-fips/openssl/v2 v2.0.0-rc.3.0.20231013091736-92d3f16e56cd/go.mod h1:7tuBqX2Zov8Yq5mJ2yzlKhpnxOnWyEzi38AzeWRuQdg=
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
Expand Down
Loading

0 comments on commit 0ce5483

Please sign in to comment.