Files
gf/crypto/gdes/gdes.go

302 lines
8.2 KiB
Go
Raw Normal View History

2021-01-17 21:46:25 +08:00
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
2018-05-22 20:43:42 +08:00
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
2019-01-15 23:27:47 +08:00
// Package gdes provides useful API for DES encryption/decryption algorithms.
2018-05-22 20:43:42 +08:00
package gdes
import (
2019-06-19 09:06:52 +08:00
"bytes"
2018-05-22 20:43:42 +08:00
"crypto/cipher"
2019-06-19 09:06:52 +08:00
"crypto/des"
2021-11-13 23:23:55 +08:00
2021-10-11 21:41:56 +08:00
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
2018-05-22 20:43:42 +08:00
)
const (
2019-06-19 09:06:52 +08:00
NOPADDING = iota
2018-05-22 20:43:42 +08:00
PKCS5PADDING
)
// EncryptECB encrypts `plainText` using ECB mode.
func EncryptECB(plainText []byte, key []byte, padding int) ([]byte, error) {
text, err := Padding(plainText, padding)
2018-05-22 20:43:42 +08:00
if err != nil {
return nil, err
}
cipherText := make([]byte, len(text))
block, err := des.NewCipher(key)
if err != nil {
err = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `des.NewCipher failed for key "%s"`, key)
2018-05-22 20:43:42 +08:00
return nil, err
}
blockSize := block.BlockSize()
for i, count := 0, len(text)/blockSize; i < count; i++ {
2019-06-19 09:06:52 +08:00
begin, end := i*blockSize, i*blockSize+blockSize
2018-05-22 20:43:42 +08:00
block.Encrypt(cipherText[begin:end], text[begin:end])
}
return cipherText, nil
}
// DecryptECB decrypts `cipherText` using ECB mode.
func DecryptECB(cipherText []byte, key []byte, padding int) ([]byte, error) {
2018-05-22 20:43:42 +08:00
text := make([]byte, len(cipherText))
block, err := des.NewCipher(key)
if err != nil {
err = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `des.NewCipher failed for key "%s"`, key)
2018-05-22 20:43:42 +08:00
return nil, err
}
blockSize := block.BlockSize()
2019-06-19 09:06:52 +08:00
for i, count := 0, len(text)/blockSize; i < count; i++ {
begin, end := i*blockSize, i*blockSize+blockSize
2018-05-22 20:43:42 +08:00
block.Decrypt(text[begin:end], cipherText[begin:end])
}
plainText, err := UnPadding(text, padding)
2018-05-22 20:43:42 +08:00
if err != nil {
return nil, err
}
return plainText, nil
2018-05-22 20:43:42 +08:00
}
// EncryptECBTriple encrypts `plainText` using TripleDES and ECB mode.
// The length of the `key` should be either 16 or 24 bytes.
func EncryptECBTriple(plainText []byte, key []byte, padding int) ([]byte, error) {
2018-05-22 20:43:42 +08:00
if len(key) != 16 && len(key) != 24 {
return nil, gerror.NewCode(gcode.CodeInvalidParameter, "key length error")
2018-05-22 20:43:42 +08:00
}
text, err := Padding(plainText, padding)
2018-05-22 20:43:42 +08:00
if err != nil {
return nil, err
}
2019-06-21 22:23:07 +08:00
var newKey []byte
2018-05-22 20:43:42 +08:00
if len(key) == 16 {
newKey = append([]byte{}, key...)
newKey = append(newKey, key[:8]...)
} else {
newKey = append([]byte{}, key...)
}
block, err := des.NewTripleDESCipher(newKey)
if err != nil {
err = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `des.NewTripleDESCipher failed for key "%s"`, newKey)
2018-05-22 20:43:42 +08:00
return nil, err
}
blockSize := block.BlockSize()
cipherText := make([]byte, len(text))
2019-06-19 09:06:52 +08:00
for i, count := 0, len(text)/blockSize; i < count; i++ {
begin, end := i*blockSize, i*blockSize+blockSize
2018-05-22 20:43:42 +08:00
block.Encrypt(cipherText[begin:end], text[begin:end])
}
return cipherText, nil
}
// DecryptECBTriple decrypts `cipherText` using TripleDES and ECB mode.
// The length of the `key` should be either 16 or 24 bytes.
func DecryptECBTriple(cipherText []byte, key []byte, padding int) ([]byte, error) {
2018-05-22 20:43:42 +08:00
if len(key) != 16 && len(key) != 24 {
return nil, gerror.NewCode(gcode.CodeInvalidParameter, "key length error")
2018-05-22 20:43:42 +08:00
}
2019-06-21 22:23:07 +08:00
var newKey []byte
2018-05-22 20:43:42 +08:00
if len(key) == 16 {
newKey = append([]byte{}, key...)
newKey = append(newKey, key[:8]...)
} else {
newKey = append([]byte{}, key...)
}
block, err := des.NewTripleDESCipher(newKey)
if err != nil {
err = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `des.NewTripleDESCipher failed for key "%s"`, newKey)
2018-05-22 20:43:42 +08:00
return nil, err
}
blockSize := block.BlockSize()
text := make([]byte, len(cipherText))
2019-06-19 09:06:52 +08:00
for i, count := 0, len(text)/blockSize; i < count; i++ {
begin, end := i*blockSize, i*blockSize+blockSize
2018-05-22 20:43:42 +08:00
block.Decrypt(text[begin:end], cipherText[begin:end])
}
plainText, err := UnPadding(text, padding)
2018-05-22 20:43:42 +08:00
if err != nil {
return nil, err
}
return plainText, nil
2018-05-22 20:43:42 +08:00
}
// EncryptCBC encrypts `plainText` using CBC mode.
func EncryptCBC(plainText []byte, key []byte, iv []byte, padding int) ([]byte, error) {
2018-05-22 20:43:42 +08:00
block, err := des.NewCipher(key)
if err != nil {
err = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `des.NewCipher failed for key "%s"`, key)
2018-05-22 20:43:42 +08:00
return nil, err
}
if len(iv) != block.BlockSize() {
return nil, gerror.NewCode(gcode.CodeInvalidParameter, "invalid iv length")
2018-05-22 20:43:42 +08:00
}
text, err := Padding(plainText, padding)
2018-05-22 20:43:42 +08:00
if err != nil {
return nil, err
}
cipherText := make([]byte, len(text))
encryptor := cipher.NewCBCEncrypter(block, iv)
encryptor.CryptBlocks(cipherText, text)
2018-05-22 20:43:42 +08:00
return cipherText, nil
}
// DecryptCBC decrypts `cipherText` using CBC mode.
func DecryptCBC(cipherText []byte, key []byte, iv []byte, padding int) ([]byte, error) {
2018-05-22 20:43:42 +08:00
block, err := des.NewCipher(key)
if err != nil {
err = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `des.NewCipher failed for key "%s"`, key)
2018-05-22 20:43:42 +08:00
return nil, err
}
if len(iv) != block.BlockSize() {
return nil, gerror.NewCode(gcode.CodeInvalidParameter, "iv length invalid")
2018-05-22 20:43:42 +08:00
}
text := make([]byte, len(cipherText))
decrypter := cipher.NewCBCDecrypter(block, iv)
decrypter.CryptBlocks(text, cipherText)
plainText, err := UnPadding(text, padding)
2018-05-22 20:43:42 +08:00
if err != nil {
return nil, err
}
return plainText, nil
2018-05-22 20:43:42 +08:00
}
// EncryptCBCTriple encrypts `plainText` using TripleDES and CBC mode.
func EncryptCBCTriple(plainText []byte, key []byte, iv []byte, padding int) ([]byte, error) {
2018-05-22 20:43:42 +08:00
if len(key) != 16 && len(key) != 24 {
return nil, gerror.NewCode(gcode.CodeInvalidParameter, "key length invalid")
2018-05-22 20:43:42 +08:00
}
2019-06-21 22:23:07 +08:00
var newKey []byte
2018-05-22 20:43:42 +08:00
if len(key) == 16 {
newKey = append([]byte{}, key...)
newKey = append(newKey, key[:8]...)
} else {
newKey = append([]byte{}, key...)
}
block, err := des.NewTripleDESCipher(newKey)
if err != nil {
err = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `des.NewTripleDESCipher failed for key "%s"`, newKey)
2018-05-22 20:43:42 +08:00
return nil, err
}
if len(iv) != block.BlockSize() {
return nil, gerror.NewCode(gcode.CodeInvalidParameter, "invalid iv length")
2018-05-22 20:43:42 +08:00
}
text, err := Padding(plainText, padding)
2018-05-22 20:43:42 +08:00
if err != nil {
return nil, err
}
cipherText := make([]byte, len(text))
encrypter := cipher.NewCBCEncrypter(block, iv)
encrypter.CryptBlocks(cipherText, text)
return cipherText, nil
}
// DecryptCBCTriple decrypts `cipherText` using TripleDES and CBC mode.
func DecryptCBCTriple(cipherText []byte, key []byte, iv []byte, padding int) ([]byte, error) {
2018-05-22 20:43:42 +08:00
if len(key) != 16 && len(key) != 24 {
return nil, gerror.NewCode(gcode.CodeInvalidParameter, "key length invalid")
2018-05-22 20:43:42 +08:00
}
2019-06-21 22:23:07 +08:00
var newKey []byte
2018-05-22 20:43:42 +08:00
if len(key) == 16 {
newKey = append([]byte{}, key...)
newKey = append(newKey, key[:8]...)
} else {
newKey = append([]byte{}, key...)
}
block, err := des.NewTripleDESCipher(newKey)
if err != nil {
err = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `des.NewTripleDESCipher failed for key "%s"`, newKey)
2018-05-22 20:43:42 +08:00
return nil, err
}
if len(iv) != block.BlockSize() {
return nil, gerror.NewCode(gcode.CodeInvalidParameter, "invalid iv length")
2018-05-22 20:43:42 +08:00
}
text := make([]byte, len(cipherText))
decrypter := cipher.NewCBCDecrypter(block, iv)
decrypter.CryptBlocks(text, cipherText)
plainText, err := UnPadding(text, padding)
2018-05-22 20:43:42 +08:00
if err != nil {
return nil, err
}
return plainText, nil
2018-05-22 20:43:42 +08:00
}
func PaddingPKCS5(text []byte, blockSize int) []byte {
2019-06-19 09:06:52 +08:00
padding := blockSize - len(text)%blockSize
padText := bytes.Repeat([]byte{byte(padding)}, padding)
return append(text, padText...)
2018-05-22 20:43:42 +08:00
}
func UnPaddingPKCS5(text []byte) []byte {
2018-05-22 20:43:42 +08:00
length := len(text)
padText := int(text[length-1])
return text[:(length - padText)]
2018-05-22 20:43:42 +08:00
}
2019-06-19 09:06:52 +08:00
func Padding(text []byte, padding int) ([]byte, error) {
2018-05-22 20:43:42 +08:00
switch padding {
2019-06-19 09:06:52 +08:00
case NOPADDING:
if len(text)%8 != 0 {
return nil, gerror.NewCode(gcode.CodeInvalidParameter, "invalid text length")
2019-06-19 09:06:52 +08:00
}
2019-06-19 09:06:52 +08:00
case PKCS5PADDING:
return PaddingPKCS5(text, 8), nil
2019-06-19 09:06:52 +08:00
default:
return nil, gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported padding type "%d"`, padding)
2018-05-22 20:43:42 +08:00
}
return text, nil
}
2019-06-19 09:06:52 +08:00
func UnPadding(text []byte, padding int) ([]byte, error) {
2018-05-22 20:43:42 +08:00
switch padding {
2019-06-19 09:06:52 +08:00
case NOPADDING:
if len(text)%8 != 0 {
return nil, gerror.NewCode(gcode.CodeInvalidParameter, "invalid text length")
2019-06-19 09:06:52 +08:00
}
2019-06-19 09:06:52 +08:00
case PKCS5PADDING:
return UnPaddingPKCS5(text), nil
2019-06-19 09:06:52 +08:00
default:
return nil, gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported padding type "%d"`, padding)
2018-05-22 20:43:42 +08:00
}
return text, nil
2019-06-19 09:06:52 +08:00
}