starcrypto/paddingx/padding.go

129 lines
3.3 KiB
Go

package paddingx
import (
"bytes"
"errors"
"strings"
)
const (
PKCS5 = "PKCS5"
PKCS7 = "PKCS7"
ZERO = "ZERO"
ANSIX923 = "ANSIX923"
)
func Pad(data []byte, blockSize int, mode string) ([]byte, error) {
if blockSize <= 0 {
return nil, errors.New("block size must be greater than zero")
}
switch normalizeMode(mode) {
case "", PKCS7:
return PKCS7Padding(data, blockSize), nil
case PKCS5:
// Compatibility mode: historically PKCS5 was used generically in this project.
return PKCS7Padding(data, blockSize), nil
case ZERO:
return zeroPadding(data, blockSize), nil
case ANSIX923:
return ansiX923Padding(data, blockSize), nil
default:
return nil, errors.New("padding type not supported")
}
}
func Unpad(data []byte, blockSize int, mode string) ([]byte, error) {
if blockSize <= 0 {
return nil, errors.New("block size must be greater than zero")
}
switch normalizeMode(mode) {
case "", PKCS7:
return PKCS7Unpadding(data, blockSize)
case PKCS5:
// Compatibility mode: historically PKCS5 was used generically in this project.
return PKCS7Unpadding(data, blockSize)
case ZERO:
return zeroUnpadding(data)
case ANSIX923:
return ansiX923Unpadding(data, blockSize)
default:
return nil, errors.New("padding type not supported")
}
}
func PKCS7Padding(data []byte, blockSize int) []byte {
padding := blockSize - len(data)%blockSize
padText := bytes.Repeat([]byte{byte(padding)}, padding)
return append(data, padText...)
}
func PKCS7Unpadding(data []byte, blockSize int) ([]byte, error) {
if len(data) == 0 || len(data)%blockSize != 0 {
return nil, errors.New("invalid PKCS7 padding")
}
padding := int(data[len(data)-1])
if padding <= 0 || padding > blockSize || padding > len(data) {
return nil, errors.New("invalid PKCS7 padding")
}
for i := len(data) - padding; i < len(data); i++ {
if int(data[i]) != padding {
return nil, errors.New("invalid PKCS7 padding")
}
}
return data[:len(data)-padding], nil
}
func PKCS5Padding(data []byte) []byte {
return PKCS7Padding(data, 8)
}
func PKCS5Unpadding(data []byte) ([]byte, error) {
return PKCS7Unpadding(data, 8)
}
func zeroPadding(data []byte, blockSize int) []byte {
padding := blockSize - len(data)%blockSize
if padding == blockSize {
return data
}
return append(data, bytes.Repeat([]byte{0x00}, padding)...)
}
func zeroUnpadding(data []byte) ([]byte, error) {
idx := len(data)
for idx > 0 && data[idx-1] == 0x00 {
idx--
}
return data[:idx], nil
}
func ansiX923Padding(data []byte, blockSize int) []byte {
padding := blockSize - len(data)%blockSize
if padding == 0 {
padding = blockSize
}
pad := make([]byte, padding)
pad[len(pad)-1] = byte(padding)
return append(data, pad...)
}
func ansiX923Unpadding(data []byte, blockSize int) ([]byte, error) {
if len(data) == 0 || len(data)%blockSize != 0 {
return nil, errors.New("invalid ANSI X9.23 padding")
}
padding := int(data[len(data)-1])
if padding <= 0 || padding > blockSize || padding > len(data) {
return nil, errors.New("invalid ANSI X9.23 padding")
}
for i := len(data) - padding; i < len(data)-1; i++ {
if data[i] != 0x00 {
return nil, errors.New("invalid ANSI X9.23 padding")
}
}
return data[:len(data)-padding], nil
}
func normalizeMode(mode string) string {
return strings.ToUpper(strings.TrimSpace(mode))
}