add m4 and m5 wrappers (#104)

This commit is contained in:
Ramesh V Rayaprolu 2018-09-13 15:38:26 -07:00 committed by Jeff Wendling
parent 0ffbced908
commit 543df27fc7
7 changed files with 413 additions and 0 deletions

View File

@ -31,6 +31,7 @@ type EVP_MD int
const (
EVP_NULL EVP_MD = iota
EVP_MD5 EVP_MD = iota
EVP_MD4 EVP_MD = iota
EVP_SHA EVP_MD = iota
EVP_SHA1 EVP_MD = iota
EVP_DSS EVP_MD = iota

89
md4.go Normal file
View File

@ -0,0 +1,89 @@
// Copyright (C) 2017. See AUTHORS.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package openssl
// #include "shim.h"
import "C"
import (
"errors"
"runtime"
"unsafe"
)
type MD4Hash struct {
ctx *C.EVP_MD_CTX
engine *Engine
}
func NewMD4Hash() (*MD4Hash, error) { return NewMD4HashWithEngine(nil) }
func NewMD4HashWithEngine(e *Engine) (*MD4Hash, error) {
hash := &MD4Hash{engine: e}
hash.ctx = C.X_EVP_MD_CTX_new()
if hash.ctx == nil {
return nil, errors.New("openssl: md4: unable to allocate ctx")
}
runtime.SetFinalizer(hash, func(hash *MD4Hash) { hash.Close() })
if err := hash.Reset(); err != nil {
return nil, err
}
return hash, nil
}
func (s *MD4Hash) Close() {
if s.ctx != nil {
C.X_EVP_MD_CTX_free(s.ctx)
s.ctx = nil
}
}
func (s *MD4Hash) Reset() error {
if 1 != C.X_EVP_DigestInit_ex(s.ctx, C.X_EVP_md4(), engineRef(s.engine)) {
return errors.New("openssl: md4: cannot init digest ctx")
}
return nil
}
func (s *MD4Hash) Write(p []byte) (n int, err error) {
if len(p) == 0 {
return 0, nil
}
if 1 != C.X_EVP_DigestUpdate(s.ctx, unsafe.Pointer(&p[0]),
C.size_t(len(p))) {
return 0, errors.New("openssl: md4: cannot update digest")
}
return len(p), nil
}
func (s *MD4Hash) Sum() (result [16]byte, err error) {
if 1 != C.X_EVP_DigestFinal_ex(s.ctx,
(*C.uchar)(unsafe.Pointer(&result[0])), nil) {
return result, errors.New("openssl: md4: cannot finalize ctx")
}
return result, s.Reset()
}
func MD4(data []byte) (result [16]byte, err error) {
hash, err := NewMD4Hash()
if err != nil {
return result, err
}
defer hash.Close()
if _, err := hash.Write(data); err != nil {
return result, err
}
return hash.Sum()
}

120
md4_test.go Normal file
View File

@ -0,0 +1,120 @@
// Copyright (C) 2017. See AUTHORS.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package openssl
import (
"crypto/rand"
"golang.org/x/crypto/md4"
"io"
"testing"
)
func TestMD4(t *testing.T) {
for i := 0; i < 100; i++ {
buf := make([]byte, 10*1024-i)
if _, err := io.ReadFull(rand.Reader, buf); err != nil {
t.Fatal(err)
}
expected := [16]byte{}
md4Ctx := md4.New()
md4Ctx.Write(buf)
copy(expected[:], md4Ctx.Sum(nil))
got, err := MD4(buf)
if err != nil {
t.Fatal(err)
}
if expected != got {
t.Fatalf("exp:%x got:%x", expected, got)
}
}
}
func TestMD4Writer(t *testing.T) {
ohash, err := NewMD4Hash()
if err != nil {
t.Fatal(err)
}
hash := md4.New()
for i := 0; i < 100; i++ {
if err := ohash.Reset(); err != nil {
t.Fatal(err)
}
hash.Reset()
buf := make([]byte, 10*1024-i)
if _, err := io.ReadFull(rand.Reader, buf); err != nil {
t.Fatal(err)
}
if _, err := ohash.Write(buf); err != nil {
t.Fatal(err)
}
if _, err := hash.Write(buf); err != nil {
t.Fatal(err)
}
var got, exp [16]byte
hash.Sum(exp[:0])
got, err := ohash.Sum()
if err != nil {
t.Fatal(err)
}
if got != exp {
t.Fatalf("exp:%x got:%x", exp, got)
}
}
}
type md4func func([]byte)
func benchmarkMD4(b *testing.B, length int64, fn md4func) {
buf := make([]byte, length)
if _, err := io.ReadFull(rand.Reader, buf); err != nil {
b.Fatal(err)
}
b.SetBytes(length)
b.ResetTimer()
for i := 0; i < b.N; i++ {
fn(buf)
}
}
func BenchmarkMD4Large_openssl(b *testing.B) {
benchmarkMD4(b, 1024*1024, func(buf []byte) { MD4(buf) })
}
func BenchmarkMD4Large_stdlib(b *testing.B) {
benchmarkMD4(b, 1024*1024, func(buf []byte) {
md4Ctx := md4.New()
md4Ctx.Write(buf)
md4Ctx.Sum(nil)
})
}
func BenchmarkMD4Small_openssl(b *testing.B) {
benchmarkMD4(b, 1, func(buf []byte) { MD4(buf) })
}
func BenchmarkMD4Small_stdlib(b *testing.B) {
benchmarkMD4(b, 1, func(buf []byte) {
md4Ctx := md4.New()
md4Ctx.Write(buf)
md4Ctx.Sum(nil)
})
}

89
md5.go Normal file
View File

@ -0,0 +1,89 @@
// Copyright (C) 2017. See AUTHORS.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package openssl
// #include "shim.h"
import "C"
import (
"errors"
"runtime"
"unsafe"
)
type MD5Hash struct {
ctx *C.EVP_MD_CTX
engine *Engine
}
func NewMD5Hash() (*MD5Hash, error) { return NewMD5HashWithEngine(nil) }
func NewMD5HashWithEngine(e *Engine) (*MD5Hash, error) {
hash := &MD5Hash{engine: e}
hash.ctx = C.X_EVP_MD_CTX_new()
if hash.ctx == nil {
return nil, errors.New("openssl: md5: unable to allocate ctx")
}
runtime.SetFinalizer(hash, func(hash *MD5Hash) { hash.Close() })
if err := hash.Reset(); err != nil {
return nil, err
}
return hash, nil
}
func (s *MD5Hash) Close() {
if s.ctx != nil {
C.X_EVP_MD_CTX_free(s.ctx)
s.ctx = nil
}
}
func (s *MD5Hash) Reset() error {
if 1 != C.X_EVP_DigestInit_ex(s.ctx, C.X_EVP_md5(), engineRef(s.engine)) {
return errors.New("openssl: md5: cannot init digest ctx")
}
return nil
}
func (s *MD5Hash) Write(p []byte) (n int, err error) {
if len(p) == 0 {
return 0, nil
}
if 1 != C.X_EVP_DigestUpdate(s.ctx, unsafe.Pointer(&p[0]),
C.size_t(len(p))) {
return 0, errors.New("openssl: md5: cannot update digest")
}
return len(p), nil
}
func (s *MD5Hash) Sum() (result [16]byte, err error) {
if 1 != C.X_EVP_DigestFinal_ex(s.ctx,
(*C.uchar)(unsafe.Pointer(&result[0])), nil) {
return result, errors.New("openssl: md5: cannot finalize ctx")
}
return result, s.Reset()
}
func MD5(data []byte) (result [16]byte, err error) {
hash, err := NewMD5Hash()
if err != nil {
return result, err
}
defer hash.Close()
if _, err := hash.Write(data); err != nil {
return result, err
}
return hash.Sum()
}

109
md5_test.go Normal file
View File

@ -0,0 +1,109 @@
// Copyright (C) 2017. See AUTHORS.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package openssl
import (
"crypto/md5"
"crypto/rand"
"io"
"testing"
)
func TestMD5(t *testing.T) {
for i := 0; i < 100; i++ {
buf := make([]byte, 10*1024-i)
if _, err := io.ReadFull(rand.Reader, buf); err != nil {
t.Fatal(err)
}
expected := md5.Sum(buf)
got, err := MD5(buf)
if err != nil {
t.Fatal(err)
}
if expected != got {
t.Fatalf("exp:%x got:%x", expected, got)
}
}
}
func TestMD5Writer(t *testing.T) {
ohash, err := NewMD5Hash()
if err != nil {
t.Fatal(err)
}
hash := md5.New()
for i := 0; i < 100; i++ {
if err := ohash.Reset(); err != nil {
t.Fatal(err)
}
hash.Reset()
buf := make([]byte, 10*1024-i)
if _, err := io.ReadFull(rand.Reader, buf); err != nil {
t.Fatal(err)
}
if _, err := ohash.Write(buf); err != nil {
t.Fatal(err)
}
if _, err := hash.Write(buf); err != nil {
t.Fatal(err)
}
var got, exp [16]byte
hash.Sum(exp[:0])
got, err := ohash.Sum()
if err != nil {
t.Fatal(err)
}
if got != exp {
t.Fatalf("exp:%x got:%x", exp, got)
}
}
}
type md5func func([]byte)
func benchmarkMD5(b *testing.B, length int64, fn md5func) {
buf := make([]byte, length)
if _, err := io.ReadFull(rand.Reader, buf); err != nil {
b.Fatal(err)
}
b.SetBytes(length)
b.ResetTimer()
for i := 0; i < b.N; i++ {
fn(buf)
}
}
func BenchmarkMD5Large_openssl(b *testing.B) {
benchmarkMD5(b, 1024*1024, func(buf []byte) { MD5(buf) })
}
func BenchmarkMD5Large_stdlib(b *testing.B) {
benchmarkMD5(b, 1024*1024, func(buf []byte) { md5.Sum(buf) })
}
func BenchmarkMD5Small_openssl(b *testing.B) {
benchmarkMD5(b, 1, func(buf []byte) { MD5(buf) })
}
func BenchmarkMD5Small_stdlib(b *testing.B) {
benchmarkMD5(b, 1, func(buf []byte) { md5.Sum(buf) })
}

4
shim.c
View File

@ -602,6 +602,10 @@ const EVP_MD *X_EVP_md5() {
return EVP_md5();
}
const EVP_MD *X_EVP_md4() {
return EVP_md4();
}
const EVP_MD *X_EVP_ripemd160() {
return EVP_ripemd160();
}

1
shim.h
View File

@ -109,6 +109,7 @@ extern EVP_MD_CTX *X_EVP_MD_CTX_new();
extern void X_EVP_MD_CTX_free(EVP_MD_CTX *ctx);
extern const EVP_MD *X_EVP_md_null();
extern const EVP_MD *X_EVP_md5();
extern const EVP_MD *X_EVP_md4();
extern const EVP_MD *X_EVP_sha();
extern const EVP_MD *X_EVP_sha1();
extern const EVP_MD *X_EVP_dss();