// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. // // 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. // Package gdes provides useful API for DES encryption/decryption algorithms. package gdes import ( "bytes" "crypto/cipher" "crypto/des" "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" ) const ( NOPADDING = iota PKCS5PADDING ) // EncryptECB encrypts `plainText` using ECB mode. func EncryptECB(plainText []byte, key []byte, padding int) ([]byte, error) { text, err := Padding(plainText, padding) 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) return nil, err } blockSize := block.BlockSize() for i, count := 0, len(text)/blockSize; i < count; i++ { begin, end := i*blockSize, i*blockSize+blockSize 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) { 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) return nil, err } blockSize := block.BlockSize() for i, count := 0, len(text)/blockSize; i < count; i++ { begin, end := i*blockSize, i*blockSize+blockSize block.Decrypt(text[begin:end], cipherText[begin:end]) } plainText, err := UnPadding(text, padding) if err != nil { return nil, err } return plainText, nil } // 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) { if len(key) != 16 && len(key) != 24 { return nil, gerror.NewCode(gcode.CodeInvalidParameter, "key length error") } text, err := Padding(plainText, padding) if err != nil { return nil, err } var newKey []byte 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) return nil, err } blockSize := block.BlockSize() cipherText := make([]byte, len(text)) for i, count := 0, len(text)/blockSize; i < count; i++ { begin, end := i*blockSize, i*blockSize+blockSize 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) { if len(key) != 16 && len(key) != 24 { return nil, gerror.NewCode(gcode.CodeInvalidParameter, "key length error") } var newKey []byte 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) return nil, err } blockSize := block.BlockSize() text := make([]byte, len(cipherText)) for i, count := 0, len(text)/blockSize; i < count; i++ { begin, end := i*blockSize, i*blockSize+blockSize block.Decrypt(text[begin:end], cipherText[begin:end]) } plainText, err := UnPadding(text, padding) if err != nil { return nil, err } return plainText, nil } // EncryptCBC encrypts `plainText` using CBC mode. func EncryptCBC(plainText []byte, key []byte, iv []byte, padding int) ([]byte, error) { block, err := des.NewCipher(key) if err != nil { err = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `des.NewCipher failed for key "%s"`, key) return nil, err } if len(iv) != block.BlockSize() { return nil, gerror.NewCode(gcode.CodeInvalidParameter, "invalid iv length") } text, err := Padding(plainText, padding) if err != nil { return nil, err } cipherText := make([]byte, len(text)) encryptor := cipher.NewCBCEncrypter(block, iv) encryptor.CryptBlocks(cipherText, text) return cipherText, nil } // DecryptCBC decrypts `cipherText` using CBC mode. func DecryptCBC(cipherText []byte, key []byte, iv []byte, padding int) ([]byte, error) { block, err := des.NewCipher(key) if err != nil { err = gerror.WrapCodef(gcode.CodeInvalidParameter, err, `des.NewCipher failed for key "%s"`, key) return nil, err } if len(iv) != block.BlockSize() { return nil, gerror.NewCode(gcode.CodeInvalidParameter, "iv length invalid") } text := make([]byte, len(cipherText)) decrypter := cipher.NewCBCDecrypter(block, iv) decrypter.CryptBlocks(text, cipherText) plainText, err := UnPadding(text, padding) if err != nil { return nil, err } return plainText, nil } // EncryptCBCTriple encrypts `plainText` using TripleDES and CBC mode. func EncryptCBCTriple(plainText []byte, key []byte, iv []byte, padding int) ([]byte, error) { if len(key) != 16 && len(key) != 24 { return nil, gerror.NewCode(gcode.CodeInvalidParameter, "key length invalid") } var newKey []byte 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) return nil, err } if len(iv) != block.BlockSize() { return nil, gerror.NewCode(gcode.CodeInvalidParameter, "invalid iv length") } text, err := Padding(plainText, padding) 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) { if len(key) != 16 && len(key) != 24 { return nil, gerror.NewCode(gcode.CodeInvalidParameter, "key length invalid") } var newKey []byte 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) return nil, err } if len(iv) != block.BlockSize() { return nil, gerror.NewCode(gcode.CodeInvalidParameter, "invalid iv length") } text := make([]byte, len(cipherText)) decrypter := cipher.NewCBCDecrypter(block, iv) decrypter.CryptBlocks(text, cipherText) plainText, err := UnPadding(text, padding) if err != nil { return nil, err } return plainText, nil } func PaddingPKCS5(text []byte, blockSize int) []byte { padding := blockSize - len(text)%blockSize padText := bytes.Repeat([]byte{byte(padding)}, padding) return append(text, padText...) } func UnPaddingPKCS5(text []byte) []byte { length := len(text) padText := int(text[length-1]) return text[:(length - padText)] } func Padding(text []byte, padding int) ([]byte, error) { switch padding { case NOPADDING: if len(text)%8 != 0 { return nil, gerror.NewCode(gcode.CodeInvalidParameter, "invalid text length") } case PKCS5PADDING: return PaddingPKCS5(text, 8), nil default: return nil, gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported padding type "%d"`, padding) } return text, nil } func UnPadding(text []byte, padding int) ([]byte, error) { switch padding { case NOPADDING: if len(text)%8 != 0 { return nil, gerror.NewCode(gcode.CodeInvalidParameter, "invalid text length") } case PKCS5PADDING: return UnPaddingPKCS5(text), nil default: return nil, gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported padding type "%d"`, padding) } return text, nil }