mirror of
https://github.com/emmansun/gmsm.git
synced 2025-04-26 20:26:19 +08:00
Extract padding utility
This commit is contained in:
parent
cfe9842cc0
commit
d389da6bcb
15
padding/pads.go
Normal file
15
padding/pads.go
Normal file
@ -0,0 +1,15 @@
|
||||
package padding
|
||||
|
||||
// Padding interface represents a padding scheme
|
||||
type Padding interface {
|
||||
BlockSize() int
|
||||
Pad(src []byte) []byte
|
||||
Unpad(src []byte) ([]byte, error)
|
||||
}
|
||||
|
||||
func NewPKCS7Padding(blockSize uint) Padding {
|
||||
if blockSize == 0 || blockSize > 255 {
|
||||
panic("padding: invalid block size")
|
||||
}
|
||||
return pkcs7Padding(blockSize)
|
||||
}
|
44
padding/pkcs7.go
Normal file
44
padding/pkcs7.go
Normal file
@ -0,0 +1,44 @@
|
||||
// https://datatracker.ietf.org/doc/html/rfc5652#section-6.3
|
||||
package padding
|
||||
|
||||
import (
|
||||
goSubtle "crypto/subtle"
|
||||
"errors"
|
||||
|
||||
"github.com/emmansun/gmsm/internal/subtle"
|
||||
)
|
||||
|
||||
type pkcs7Padding uint
|
||||
|
||||
func (pad pkcs7Padding) BlockSize() int {
|
||||
return int(pad)
|
||||
}
|
||||
|
||||
func (pad pkcs7Padding) Pad(src []byte) []byte {
|
||||
overhead := pad.BlockSize() - len(src)%pad.BlockSize()
|
||||
ret, out := subtle.SliceForAppend(src, overhead)
|
||||
for i := 0; i < overhead; i++ {
|
||||
out[i] = byte(overhead)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (pad pkcs7Padding) Unpad(src []byte) ([]byte, error) {
|
||||
if len(src)%pad.BlockSize() != 0 {
|
||||
return nil, errors.New("pkcs7: invalid src size")
|
||||
}
|
||||
overhead := src[len(src)-1]
|
||||
if overhead == 0 || int(overhead) > pad.BlockSize() {
|
||||
return nil, errors.New("pkcs7: invalid padding byte/length")
|
||||
}
|
||||
tag := make([]byte, pad.BlockSize())
|
||||
copy(tag, src[len(src)-pad.BlockSize():])
|
||||
for i := pad.BlockSize() - int(overhead); i < pad.BlockSize(); i++ {
|
||||
tag[i] = byte(overhead)
|
||||
}
|
||||
if goSubtle.ConstantTimeCompare(tag, src[len(src)-pad.BlockSize():]) != 1 {
|
||||
return nil, errors.New("pkcs7: inconsistent padding bytes")
|
||||
}
|
||||
|
||||
return src[:len(src)-int(overhead)], nil
|
||||
}
|
89
padding/pkcs7_test.go
Normal file
89
padding/pkcs7_test.go
Normal file
@ -0,0 +1,89 @@
|
||||
// https://datatracker.ietf.org/doc/html/rfc5652#section-6.3
|
||||
|
||||
package padding
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_pkcs7Padding_Pad(t *testing.T) {
|
||||
pad := NewPKCS7Padding(16)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
src []byte
|
||||
want []byte
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
{"16 bytes", []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}},
|
||||
{"15 bytes", []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 1}},
|
||||
{"14 bytes", []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 2, 2}},
|
||||
{"13 bytes", []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}, []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 3, 3, 3}},
|
||||
{"12 bytes", []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 4, 4, 4, 4}},
|
||||
{"11 bytes", []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 5, 5, 5, 5, 5}},
|
||||
{"10 bytes", []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 6, 6, 6, 6, 6, 6}},
|
||||
{"9 bytes", []byte{0, 1, 2, 3, 4, 5, 6, 7, 8}, []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 7, 7, 7, 7, 7, 7, 7}},
|
||||
{"8 bytes", []byte{0, 1, 2, 3, 4, 5, 6, 7}, []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8}},
|
||||
{"7 bytes", []byte{0, 1, 2, 3, 4, 5, 6}, []byte{0, 1, 2, 3, 4, 5, 6, 9, 9, 9, 9, 9, 9, 9, 9, 9}},
|
||||
{"6 bytes", []byte{0, 1, 2, 3, 4, 5}, []byte{0, 1, 2, 3, 4, 5, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}},
|
||||
{"5 bytes", []byte{0, 1, 2, 3, 4}, []byte{0, 1, 2, 3, 4, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11}},
|
||||
{"4 bytes", []byte{0, 1, 2, 3}, []byte{0, 1, 2, 3, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12}},
|
||||
{"3 bytes", []byte{0, 1, 2}, []byte{0, 1, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13}},
|
||||
{"2 bytes", []byte{0, 1}, []byte{0, 1, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14}},
|
||||
{"1 bytes", []byte{0}, []byte{0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := pad.Pad(tt.src); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("pkcs7Padding.Pad() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_pkcs7Padding_Unpad(t *testing.T) {
|
||||
pad := NewPKCS7Padding(16)
|
||||
type args struct {
|
||||
src []byte
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
want []byte
|
||||
src []byte
|
||||
wantErr bool
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
{"16 bytes", []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}, false},
|
||||
{"15 bytes", []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 1}, false},
|
||||
{"14 bytes", []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 2, 2}, false},
|
||||
{"13 bytes", []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}, []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 3, 3, 3}, false},
|
||||
{"12 bytes", []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 4, 4, 4, 4}, false},
|
||||
{"11 bytes", []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 5, 5, 5, 5, 5}, false},
|
||||
{"10 bytes", []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 6, 6, 6, 6, 6, 6}, false},
|
||||
{"9 bytes", []byte{0, 1, 2, 3, 4, 5, 6, 7, 8}, []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 7, 7, 7, 7, 7, 7, 7}, false},
|
||||
{"8 bytes", []byte{0, 1, 2, 3, 4, 5, 6, 7}, []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8}, false},
|
||||
{"7 bytes", []byte{0, 1, 2, 3, 4, 5, 6}, []byte{0, 1, 2, 3, 4, 5, 6, 9, 9, 9, 9, 9, 9, 9, 9, 9}, false},
|
||||
{"6 bytes", []byte{0, 1, 2, 3, 4, 5}, []byte{0, 1, 2, 3, 4, 5, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, false},
|
||||
{"5 bytes", []byte{0, 1, 2, 3, 4}, []byte{0, 1, 2, 3, 4, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11}, false},
|
||||
{"4 bytes", []byte{0, 1, 2, 3}, []byte{0, 1, 2, 3, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12}, false},
|
||||
{"3 bytes", []byte{0, 1, 2}, []byte{0, 1, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13}, false},
|
||||
{"2 bytes", []byte{0, 1}, []byte{0, 1, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14}, false},
|
||||
{"1 bytes", []byte{0}, []byte{0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15}, false},
|
||||
{"invalid src length", nil, []byte{0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15}, true},
|
||||
{"invalid padding byte", nil, []byte{0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 17}, true},
|
||||
{"inconsistent padding bytes", nil, []byte{0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 15}, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := pad.Unpad(tt.src)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("pkcs7Padding.Unpad() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("pkcs7Padding.Unpad() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -4,38 +4,13 @@ import (
|
||||
"bytes"
|
||||
"crypto/cipher"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/emmansun/gmsm/padding"
|
||||
"github.com/emmansun/gmsm/sm4"
|
||||
)
|
||||
|
||||
func paddingPKCS7(buf []byte, blockSize int) []byte {
|
||||
bufLen := len(buf)
|
||||
padLen := blockSize - bufLen%blockSize
|
||||
padded := make([]byte, bufLen+padLen)
|
||||
copy(padded, buf)
|
||||
for i := 0; i < padLen; i++ {
|
||||
padded[bufLen+i] = byte(padLen)
|
||||
}
|
||||
return padded
|
||||
}
|
||||
|
||||
func unpaddingPKCS7(padded []byte, size int) ([]byte, error) {
|
||||
if len(padded)%size != 0 {
|
||||
return nil, errors.New("pkcs7: Padded value wasn't in correct size")
|
||||
}
|
||||
paddedByte := int(padded[len(padded)-1])
|
||||
if (paddedByte > size) || (paddedByte < 1) {
|
||||
return nil, fmt.Errorf("Invalid decrypted text, no padding")
|
||||
}
|
||||
bufLen := len(padded) - paddedByte
|
||||
buf := make([]byte, bufLen)
|
||||
copy(buf, padded[:bufLen])
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
var cbcSM4Tests = []struct {
|
||||
name string
|
||||
key []byte
|
||||
@ -143,6 +118,7 @@ var cbcSM4Tests = []struct {
|
||||
}
|
||||
|
||||
func TestCBCEncrypterSM4(t *testing.T) {
|
||||
pad := padding.NewPKCS7Padding(sm4.BlockSize)
|
||||
for _, test := range cbcSM4Tests {
|
||||
c, err := sm4.NewCipher(test.key)
|
||||
if err != nil {
|
||||
@ -152,7 +128,7 @@ func TestCBCEncrypterSM4(t *testing.T) {
|
||||
|
||||
encrypter := cipher.NewCBCEncrypter(c, test.iv)
|
||||
|
||||
plainText := paddingPKCS7(test.in, sm4.BlockSize)
|
||||
plainText := pad.Pad(test.in)
|
||||
data := make([]byte, len(plainText))
|
||||
copy(data, plainText)
|
||||
|
||||
@ -170,6 +146,7 @@ func TestCBCEncrypterSM4(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCBCDecrypterSM4(t *testing.T) {
|
||||
pad := padding.NewPKCS7Padding(sm4.BlockSize)
|
||||
for _, test := range cbcSM4Tests {
|
||||
c, err := sm4.NewCipher(test.key)
|
||||
if err != nil {
|
||||
@ -183,7 +160,7 @@ func TestCBCDecrypterSM4(t *testing.T) {
|
||||
copy(data, test.out)
|
||||
|
||||
decrypter.CryptBlocks(data, data)
|
||||
data, err = unpaddingPKCS7(data, sm4.BlockSize)
|
||||
data, err = pad.Unpad(data)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user