cbc.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. /*
  2. CBC describes a block cipher mode. In cryptography, a block cipher mode of operation is an algorithm that uses a
  3. block cipher to provide an information service such as confidentiality or authenticity. A block cipher by itself
  4. is only suitable for the secure cryptographic transformation (encryption or decryption) of one fixed-length group of
  5. bits called a block. A mode of operation describes how to repeatedly apply a cipher's single-block operation to
  6. securely transform amounts of data larger than a block.
  7. This package simplifies the usage of AES-256-CBC.
  8. */
  9. package cbc
  10. /*
  11. Some code is provided by the GitHub user locked (github.com/locked):
  12. https://gist.github.com/locked/b066aa1ddeb2b28e855e
  13. Thanks!
  14. */
  15. import (
  16. "bytes"
  17. "crypto/aes"
  18. "crypto/cipher"
  19. "crypto/rand"
  20. "fmt"
  21. "io"
  22. )
  23. /*
  24. Decrypt is a function that decrypts a given cipher text with a provided key and initialization vector(iv).
  25. */
  26. func Decrypt(key, iv, ciphertext []byte) ([]byte, error) {
  27. block, err := aes.NewCipher(key)
  28. if err != nil {
  29. return nil, err
  30. }
  31. if len(ciphertext) < aes.BlockSize {
  32. return nil, fmt.Errorf("ciphertext is shorter then block size: %d / %d", len(ciphertext), aes.BlockSize)
  33. }
  34. if iv == nil {
  35. iv = ciphertext[:aes.BlockSize]
  36. ciphertext = ciphertext[aes.BlockSize:]
  37. }
  38. cbc := cipher.NewCBCDecrypter(block, iv)
  39. cbc.CryptBlocks(ciphertext, ciphertext)
  40. return unpad(ciphertext)
  41. }
  42. /*
  43. Encrypt is a function that encrypts plaintext with a given key and an optional initialization vector(iv).
  44. */
  45. func Encrypt(key, iv, plaintext []byte) ([]byte, error) {
  46. plaintext = pad(plaintext, aes.BlockSize)
  47. if len(plaintext)%aes.BlockSize != 0 {
  48. return nil, fmt.Errorf("plaintext is not a multiple of the block size: %d / %d", len(plaintext), aes.BlockSize)
  49. }
  50. block, err := aes.NewCipher(key)
  51. if err != nil {
  52. return nil, err
  53. }
  54. var ciphertext []byte
  55. if iv == nil {
  56. ciphertext = make([]byte, aes.BlockSize+len(plaintext))
  57. iv := ciphertext[:aes.BlockSize]
  58. if _, err := io.ReadFull(rand.Reader, iv); err != nil {
  59. return nil, err
  60. }
  61. cbc := cipher.NewCBCEncrypter(block, iv)
  62. cbc.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)
  63. } else {
  64. ciphertext = make([]byte, len(plaintext))
  65. cbc := cipher.NewCBCEncrypter(block, iv)
  66. cbc.CryptBlocks(ciphertext, plaintext)
  67. }
  68. return ciphertext, nil
  69. }
  70. func pad(ciphertext []byte, blockSize int) []byte {
  71. padding := blockSize - len(ciphertext)%blockSize
  72. padtext := bytes.Repeat([]byte{byte(padding)}, padding)
  73. return append(ciphertext, padtext...)
  74. }
  75. func unpad(src []byte) ([]byte, error) {
  76. length := len(src)
  77. padLen := int(src[length-1])
  78. if padLen > length {
  79. return nil, fmt.Errorf("padding is greater then the length: %d / %d", padLen, length)
  80. }
  81. return src[:(length - padLen)], nil
  82. }