Skip to content

Commit 13f20f3

Browse files
authored
Merge pull request #105 from golang-fips/md4md5
Support for MD4 and MD5
2 parents c96fdff + 9e9cc11 commit 13f20f3

File tree

7 files changed

+183
-69
lines changed

7 files changed

+183
-69
lines changed

evp.go

+19-13
Original file line numberDiff line numberDiff line change
@@ -60,23 +60,21 @@ func cryptoHashToMD(ch crypto.Hash) (md C.GO_EVP_MD_PTR) {
6060
}
6161
cacheMD.Store(ch, md)
6262
}()
63-
// SupportsHash returns false for MD5 and MD5SHA1 because we don't
64-
// provide a hash.Hash implementation for them. Yet, they can
63+
// SupportsHash returns false for MD5SHA1 because we don't
64+
// provide a hash.Hash implementation for it. Yet, it can
6565
// still be used when signing/verifying with an RSA key.
66-
switch ch {
67-
case crypto.MD5:
68-
return C.go_openssl_EVP_md5()
69-
case crypto.MD5SHA1:
66+
if ch == crypto.MD5SHA1 {
7067
if vMajor == 1 && vMinor == 0 {
7168
return C.go_openssl_EVP_md5_sha1_backport()
7269
} else {
7370
return C.go_openssl_EVP_md5_sha1()
7471
}
7572
}
76-
if !SupportsHash(ch) {
77-
return nil
78-
}
7973
switch ch {
74+
case crypto.MD4:
75+
return C.go_openssl_EVP_md4()
76+
case crypto.MD5:
77+
return C.go_openssl_EVP_md5()
8078
case crypto.SHA1:
8179
return C.go_openssl_EVP_sha1()
8280
case crypto.SHA224:
@@ -88,13 +86,21 @@ func cryptoHashToMD(ch crypto.Hash) (md C.GO_EVP_MD_PTR) {
8886
case crypto.SHA512:
8987
return C.go_openssl_EVP_sha512()
9088
case crypto.SHA3_224:
91-
return C.go_openssl_EVP_sha3_224()
89+
if version1_1_1_or_above() {
90+
return C.go_openssl_EVP_sha3_224()
91+
}
9292
case crypto.SHA3_256:
93-
return C.go_openssl_EVP_sha3_256()
93+
if version1_1_1_or_above() {
94+
return C.go_openssl_EVP_sha3_256()
95+
}
9496
case crypto.SHA3_384:
95-
return C.go_openssl_EVP_sha3_384()
97+
if version1_1_1_or_above() {
98+
return C.go_openssl_EVP_sha3_384()
99+
}
96100
case crypto.SHA3_512:
97-
return C.go_openssl_EVP_sha3_512()
101+
if version1_1_1_or_above() {
102+
return C.go_openssl_EVP_sha3_512()
103+
}
98104
}
99105
return nil
100106
}

goopenssl.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,14 @@ FOR_ALL_OPENSSL_FUNCTIONS
6666
#undef DEFINEFUNC_RENAMED_1_1
6767
#undef DEFINEFUNC_RENAMED_3_0
6868

69-
// go_sha_sum copies ctx into ctx2 and calls EVP_DigestFinal using ctx2.
69+
// go_hash_sum copies ctx into ctx2 and calls EVP_DigestFinal using ctx2.
7070
// This is necessary because Go hash.Hash mandates that Sum has no effect
7171
// on the underlying stream. In particular it is OK to Sum, then Write more,
7272
// then Sum again, and the second Sum acts as if the first didn't happen.
7373
// It is written in C because Sum() tend to be in the hot path,
7474
// and doing one cgo call instead of two is a significant performance win.
7575
static inline int
76-
go_sha_sum(GO_EVP_MD_CTX_PTR ctx, GO_EVP_MD_CTX_PTR ctx2, unsigned char *out)
76+
go_hash_sum(GO_EVP_MD_CTX_PTR ctx, GO_EVP_MD_CTX_PTR ctx2, unsigned char *out)
7777
{
7878
if (go_openssl_EVP_MD_CTX_copy(ctx2, ctx) != 1)
7979
return 0;

sha.go renamed to hash.go

+130-33
Original file line numberDiff line numberDiff line change
@@ -24,81 +24,87 @@ import (
2424
// and applying a noescape along the way.
2525
// This is all to preserve compatibility with the allocation behavior of the non-openssl implementations.
2626

27-
func shaX(ch crypto.Hash, p []byte, sum []byte) bool {
27+
func hashOneShot(ch crypto.Hash, p []byte, sum []byte) bool {
2828
return C.go_openssl_EVP_Digest(unsafe.Pointer(&*addr(p)), C.size_t(len(p)), (*C.uchar)(unsafe.Pointer(&*addr(sum))), nil, cryptoHashToMD(ch), nil) != 0
2929
}
3030

31+
func MD4(p []byte) (sum [16]byte) {
32+
if !hashOneShot(crypto.MD4, p, sum[:]) {
33+
panic("openssl: MD4 failed")
34+
}
35+
return
36+
}
37+
38+
func MD5(p []byte) (sum [16]byte) {
39+
if !hashOneShot(crypto.MD5, p, sum[:]) {
40+
panic("openssl: MD5 failed")
41+
}
42+
return
43+
}
44+
3145
func SHA1(p []byte) (sum [20]byte) {
32-
if !shaX(crypto.SHA1, p, sum[:]) {
46+
if !hashOneShot(crypto.SHA1, p, sum[:]) {
3347
panic("openssl: SHA1 failed")
3448
}
3549
return
3650
}
3751

3852
func SHA224(p []byte) (sum [28]byte) {
39-
if !shaX(crypto.SHA224, p, sum[:]) {
53+
if !hashOneShot(crypto.SHA224, p, sum[:]) {
4054
panic("openssl: SHA224 failed")
4155
}
4256
return
4357
}
4458

4559
func SHA256(p []byte) (sum [32]byte) {
46-
if !shaX(crypto.SHA256, p, sum[:]) {
60+
if !hashOneShot(crypto.SHA256, p, sum[:]) {
4761
panic("openssl: SHA256 failed")
4862
}
4963
return
5064
}
5165

5266
func SHA384(p []byte) (sum [48]byte) {
53-
if !shaX(crypto.SHA384, p, sum[:]) {
67+
if !hashOneShot(crypto.SHA384, p, sum[:]) {
5468
panic("openssl: SHA384 failed")
5569
}
5670
return
5771
}
5872

5973
func SHA512(p []byte) (sum [64]byte) {
60-
if !shaX(crypto.SHA512, p, sum[:]) {
74+
if !hashOneShot(crypto.SHA512, p, sum[:]) {
6175
panic("openssl: SHA512 failed")
6276
}
6377
return
6478
}
6579

6680
// SupportsHash returns true if a hash.Hash implementation is supported for h.
6781
func SupportsHash(h crypto.Hash) bool {
68-
switch h {
69-
case crypto.SHA1, crypto.SHA224, crypto.SHA256, crypto.SHA384, crypto.SHA512:
70-
return true
71-
case crypto.SHA3_224, crypto.SHA3_256, crypto.SHA3_384, crypto.SHA3_512:
72-
return vMajor > 1 ||
73-
(vMajor >= 1 && vMinor > 1) ||
74-
(vMajor >= 1 && vMinor >= 1 && vPatch >= 1)
75-
}
76-
return false
82+
return cryptoHashToMD(h) != nil
7783
}
7884

7985
func SHA3_224(p []byte) (sum [28]byte) {
80-
if !shaX(crypto.SHA3_224, p, sum[:]) {
86+
if !hashOneShot(crypto.SHA3_224, p, sum[:]) {
8187
panic("openssl: SHA3_224 failed")
8288
}
8389
return
8490
}
8591

8692
func SHA3_256(p []byte) (sum [32]byte) {
87-
if !shaX(crypto.SHA3_256, p, sum[:]) {
93+
if !hashOneShot(crypto.SHA3_256, p, sum[:]) {
8894
panic("openssl: SHA3_256 failed")
8995
}
9096
return
9197
}
9298

9399
func SHA3_384(p []byte) (sum [48]byte) {
94-
if !shaX(crypto.SHA3_384, p, sum[:]) {
100+
if !hashOneShot(crypto.SHA3_384, p, sum[:]) {
95101
panic("openssl: SHA3_384 failed")
96102
}
97103
return
98104
}
99105

100106
func SHA3_512(p []byte) (sum [64]byte) {
101-
if !shaX(crypto.SHA3_512, p, sum[:]) {
107+
if !hashOneShot(crypto.SHA3_512, p, sum[:]) {
102108
panic("openssl: SHA3_512 failed")
103109
}
104110
return
@@ -183,17 +189,17 @@ func (h *evpHash) BlockSize() int {
183189
}
184190

185191
func (h *evpHash) sum(out []byte) {
186-
if C.go_sha_sum(h.ctx, h.ctx2, base(out)) != 1 {
187-
panic(newOpenSSLError("go_sha_sum"))
192+
if C.go_hash_sum(h.ctx, h.ctx2, base(out)) != 1 {
193+
panic(newOpenSSLError("go_hash_sum"))
188194
}
189195
runtime.KeepAlive(h)
190196
}
191197

192-
// shaState returns a pointer to the internal sha structure.
198+
// hashState returns a pointer to the internal hash structure.
193199
//
194200
// The EVP_MD_CTX memory layout has changed in OpenSSL 3
195201
// and the property holding the internal structure is no longer md_data but algctx.
196-
func (h *evpHash) shaState() unsafe.Pointer {
202+
func (h *evpHash) hashState() unsafe.Pointer {
197203
switch vMajor {
198204
case 1:
199205
// https://github.com/openssl/openssl/blob/0418e993c717a6863f206feaa40673a261de7395/crypto/evp/evp_local.h#L12.
@@ -217,6 +223,97 @@ func (h *evpHash) shaState() unsafe.Pointer {
217223
}
218224
}
219225

226+
// NewMD4 returns a new MD4 hash.
227+
// The returned hash doesn't implement encoding.BinaryMarshaler and
228+
// encoding.BinaryUnmarshaler.
229+
func NewMD4() hash.Hash {
230+
return &md4Hash{
231+
evpHash: newEvpHash(crypto.MD4, 16, 64),
232+
}
233+
}
234+
235+
type md4Hash struct {
236+
*evpHash
237+
out [16]byte
238+
}
239+
240+
func (h *md4Hash) Sum(in []byte) []byte {
241+
h.sum(h.out[:])
242+
return append(in, h.out[:]...)
243+
}
244+
245+
// NewMD5 returns a new MD5 hash.
246+
func NewMD5() hash.Hash {
247+
return &md5Hash{
248+
evpHash: newEvpHash(crypto.MD5, 16, 64),
249+
}
250+
}
251+
252+
// md5State layout is taken from
253+
// https://github.com/openssl/openssl/blob/0418e993c717a6863f206feaa40673a261de7395/include/openssl/md5.h#L33.
254+
type md5State struct {
255+
h [4]uint32
256+
nl, nh uint32
257+
x [64]byte
258+
nx uint32
259+
}
260+
261+
type md5Hash struct {
262+
*evpHash
263+
out [16]byte
264+
}
265+
266+
func (h *md5Hash) Sum(in []byte) []byte {
267+
h.sum(h.out[:])
268+
return append(in, h.out[:]...)
269+
}
270+
271+
const (
272+
md5Magic = "md5\x01"
273+
md5MarshaledSize = len(md5Magic) + 4*4 + 64 + 8
274+
)
275+
276+
func (h *md5Hash) MarshalBinary() ([]byte, error) {
277+
d := (*md5State)(h.hashState())
278+
if d == nil {
279+
return nil, errors.New("crypto/md5: can't retrieve hash state")
280+
}
281+
b := make([]byte, 0, md5MarshaledSize)
282+
b = append(b, md5Magic...)
283+
b = appendUint32(b, d.h[0])
284+
b = appendUint32(b, d.h[1])
285+
b = appendUint32(b, d.h[2])
286+
b = appendUint32(b, d.h[3])
287+
b = append(b, d.x[:d.nx]...)
288+
b = b[:len(b)+len(d.x)-int(d.nx)] // already zero
289+
b = appendUint64(b, uint64(d.nl)>>3|uint64(d.nh)<<29)
290+
return b, nil
291+
}
292+
293+
func (h *md5Hash) UnmarshalBinary(b []byte) error {
294+
if len(b) < len(md5Magic) || string(b[:len(md5Magic)]) != md5Magic {
295+
return errors.New("crypto/md5: invalid hash state identifier")
296+
}
297+
if len(b) != md5MarshaledSize {
298+
return errors.New("crypto/md5: invalid hash state size")
299+
}
300+
d := (*md5State)(h.hashState())
301+
if d == nil {
302+
return errors.New("crypto/md5: can't retrieve hash state")
303+
}
304+
b = b[len(md5Magic):]
305+
b, d.h[0] = consumeUint32(b)
306+
b, d.h[1] = consumeUint32(b)
307+
b, d.h[2] = consumeUint32(b)
308+
b, d.h[3] = consumeUint32(b)
309+
b = b[copy(d.x[:], b):]
310+
_, n := consumeUint64(b)
311+
d.nl = uint32(n << 3)
312+
d.nh = uint32(n >> 29)
313+
d.nx = uint32(n) % 64
314+
return nil
315+
}
316+
220317
// NewSHA1 returns a new SHA1 hash.
221318
func NewSHA1() hash.Hash {
222319
return &sha1Hash{
@@ -249,7 +346,7 @@ const (
249346
)
250347

251348
func (h *sha1Hash) MarshalBinary() ([]byte, error) {
252-
d := (*sha1State)(h.shaState())
349+
d := (*sha1State)(h.hashState())
253350
if d == nil {
254351
return nil, errors.New("crypto/sha1: can't retrieve hash state")
255352
}
@@ -273,7 +370,7 @@ func (h *sha1Hash) UnmarshalBinary(b []byte) error {
273370
if len(b) != sha1MarshaledSize {
274371
return errors.New("crypto/sha1: invalid hash state size")
275372
}
276-
d := (*sha1State)(h.shaState())
373+
d := (*sha1State)(h.hashState())
277374
if d == nil {
278375
return errors.New("crypto/sha1: can't retrieve hash state")
279376
}
@@ -341,7 +438,7 @@ type sha256State struct {
341438
}
342439

343440
func (h *sha224Hash) MarshalBinary() ([]byte, error) {
344-
d := (*sha256State)(h.shaState())
441+
d := (*sha256State)(h.hashState())
345442
if d == nil {
346443
return nil, errors.New("crypto/sha256: can't retrieve hash state")
347444
}
@@ -362,7 +459,7 @@ func (h *sha224Hash) MarshalBinary() ([]byte, error) {
362459
}
363460

364461
func (h *sha256Hash) MarshalBinary() ([]byte, error) {
365-
d := (*sha256State)(h.shaState())
462+
d := (*sha256State)(h.hashState())
366463
if d == nil {
367464
return nil, errors.New("crypto/sha256: can't retrieve hash state")
368465
}
@@ -389,7 +486,7 @@ func (h *sha224Hash) UnmarshalBinary(b []byte) error {
389486
if len(b) != marshaledSize256 {
390487
return errors.New("crypto/sha256: invalid hash state size")
391488
}
392-
d := (*sha256State)(h.shaState())
489+
d := (*sha256State)(h.hashState())
393490
if d == nil {
394491
return errors.New("crypto/sha256: can't retrieve hash state")
395492
}
@@ -417,7 +514,7 @@ func (h *sha256Hash) UnmarshalBinary(b []byte) error {
417514
if len(b) != marshaledSize256 {
418515
return errors.New("crypto/sha256: invalid hash state size")
419516
}
420-
d := (*sha256State)(h.shaState())
517+
d := (*sha256State)(h.hashState())
421518
if d == nil {
422519
return errors.New("crypto/sha256: can't retrieve hash state")
423520
}
@@ -490,7 +587,7 @@ const (
490587
)
491588

492589
func (h *sha384Hash) MarshalBinary() ([]byte, error) {
493-
d := (*sha512State)(h.shaState())
590+
d := (*sha512State)(h.hashState())
494591
if d == nil {
495592
return nil, errors.New("crypto/sha512: can't retrieve hash state")
496593
}
@@ -511,7 +608,7 @@ func (h *sha384Hash) MarshalBinary() ([]byte, error) {
511608
}
512609

513610
func (h *sha512Hash) MarshalBinary() ([]byte, error) {
514-
d := (*sha512State)(h.shaState())
611+
d := (*sha512State)(h.hashState())
515612
if d == nil {
516613
return nil, errors.New("crypto/sha512: can't retrieve hash state")
517614
}
@@ -541,7 +638,7 @@ func (h *sha384Hash) UnmarshalBinary(b []byte) error {
541638
if len(b) != marshaledSize512 {
542639
return errors.New("crypto/sha512: invalid hash state size")
543640
}
544-
d := (*sha512State)(h.shaState())
641+
d := (*sha512State)(h.hashState())
545642
if d == nil {
546643
return errors.New("crypto/sha512: can't retrieve hash state")
547644
}
@@ -572,7 +669,7 @@ func (h *sha512Hash) UnmarshalBinary(b []byte) error {
572669
if len(b) != marshaledSize512 {
573670
return errors.New("crypto/sha512: invalid hash state size")
574671
}
575-
d := (*sha512State)(h.shaState())
672+
d := (*sha512State)(h.hashState())
576673
if d == nil {
577674
return errors.New("crypto/sha512: can't retrieve hash state")
578675
}

0 commit comments

Comments
 (0)