Giter Site home page Giter Site logo

andreburgaud / crypt2go Goto Github PK

View Code? Open in Web Editor NEW
103.0 103.0 26.0 106 KB

Go (golang) ECB mode of encryption and padding.

Home Page: https://pkg.go.dev/github.com/andreburgaud/crypt2go/ecb

License: BSD 3-Clause "New" or "Revised" License

Go 95.29% Makefile 4.71%
aes blowfish crypto ecb ecb-mode encryption golang padding pkcs security

crypt2go's Introduction

Crypt2go

GoDoc License Go Report Card

Crypt2go includes Go packages complementing existing standard library crypto packages and the extension packages x/crypto.

Installation

go get github.com/andreburgaud/crypt2go

Or to update to the latest version:

go get -u github.com/andreburgaud/crypt2go

Development

In the crypt2go directory, execute make or make help to display the build commands.

Test

make test

Run Examples

To execute the code examples found in this document (README):

make run

Disclaimer

I'm not an expert in cryptography, and I welcome any comments or suggestions to improve the code included in this repository.

ECB (Electronic Codebook)

The ECB mode of operation should NOT be used anymore. I wrote Crypt2go to facilitate migrating legacy data encrypted with ECB. Plenty of literature explains why ECB is not recommended in cryptographic protocols. Nevertheless, this code might be helpful if someone needs to solve a problem with legacy software using ECB.

Examples

AES Encryption in ECB mode with padding

package main

import (
  "fmt"

  "crypto/aes"

  "github.com/andreburgaud/crypt2go/ecb"
  "github.com/andreburgaud/crypt2go/padding"
)

func encrypt(pt, key []byte) []byte {
  block, err := aes.NewCipher(key)
  if err != nil {
    panic(err.Error())
  }
  mode := ecb.NewECBEncrypter(block)
  padder := padding.NewPkcs7Padding(mode.BlockSize())
  pt, err = padder.Pad(pt) // pad last block of plaintext if block size less than block cipher size
  if err != nil {
    panic(err.Error())
  }
  ct := make([]byte, len(pt))
  mode.CryptBlocks(ct, pt)
  return ct
}

func decrypt(ct, key []byte) []byte {
  block, err := aes.NewCipher(key)
  if err != nil {
    panic(err.Error())
  }
  mode := ecb.NewECBDecrypter(block)
  pt := make([]byte, len(ct))
  mode.CryptBlocks(pt, ct)
  padder := padding.NewPkcs7Padding(mode.BlockSize())
  pt, err = padder.Unpad(pt) // unpad plaintext after decryption
  if err != nil {
    panic(err.Error())
  }
  return pt
}

func example() {
  pt := []byte("Some plain text")
  // Key size for AES is either: 16 bytes (128 bits), 24 bytes (192 bits), or 32 bytes (256 bits)
  key := []byte("secretkey16bytes")

  ct := encrypt(pt, key)
  fmt.Printf("Ciphertext: %x\n", ct)

  recoveredPt := decrypt(ct, key)
  fmt.Printf("Recovered plaintext: %s\n", recoveredPt)
}

func main() {
  fmt.Println("AES encryption with ECB and PKCS7 padding")
  example()
}

Blowfish encryption in ECB mode with padding

Note: The Golang blowfish package is deprecated and should not be used for any new system (https://pkg.go.dev/golang.org/x/crypto/blowfish). Nevertheless, you could still benefit from the following example if you needed to convert legacy encryption from blowfish with ECB to a secure encryption algorithm and mode of encryption, for example, AES with GCM (Gallois Counter Mode).

package main

import (
  "fmt"

  "golang.org/x/crypto/blowfish"

  "github.com/andreburgaud/crypt2go/ecb"
  "github.com/andreburgaud/crypt2go/padding"
)

func encrypt(pt, key []byte) []byte {
  block, err := blowfish.NewCipher(key)
  if err != nil {
    panic(err.Error())
  }
  mode := ecb.NewECBEncrypter(block)
  padder := padding.NewPkcs5Padding()
  pt, err = padder.Pad(pt) // pad last block of plaintext if block size less than block cipher size
  if err != nil {
    panic(err.Error())
  }
  ct := make([]byte, len(pt))
  mode.CryptBlocks(ct, pt)
  return ct
}

func decrypt(ct, key []byte) []byte {
  block, err := blowfish.NewCipher(key)
  if err != nil {
    panic(err.Error())
  }
  mode := ecb.NewECBDecrypter(block)
  pt := make([]byte, len(ct))
  mode.CryptBlocks(pt, ct)
  padder := padding.NewPkcs5Padding()
  pt, err = padder.Unpad(pt) // unpad plaintext after decryption
  if err != nil {
    panic(err.Error())
  }
  return pt
}

func example() {
  pt := []byte("Some plain text")
  key := []byte("a_very_secret_key")

  ct := encrypt(pt, key)
  fmt.Printf("Ciphertext: %x\n", ct)

  recoveredPt := decrypt(ct, key)
  fmt.Printf("Recovered plaintext: %s\n", recoveredPt)
}

func main() {
  fmt.Println("Blowfish encryption with ECB and PKCS5 padding")
  example()
}

Padding

ECB (Electronic Codebook) and CBC (Cipher Block Chaining) require fixed-size blocks. Encryption with ECB and CBC modes requires padding the plain text to a size multiple of the block size.

The padding package exposes simple functions to provide a way to pad before encryption and unpad a given plaintext after decryption.

The code examples in the previous sections show encryption patterns with Blowfish and AES in ECB mode. Blowfish encrypts blocks of 8 bytes (64 bits) using the padding type described in the PKCS #5: Password-Based Cryptography Specification Version 2.1. In contrast, AES requires blocks of 16 bytes (128 bits). The padding type in the second example follows the specs documented in PKCS #7: Cryptographic Message Syntax Version 1.5.

The only difference between the two specs is that PKCS #5 accommodates only blocks of 8 bytes. The padding package reflects that and exposes two builders, respectively NewPkcs5Padding() that embeds a hard-coded value for a block size of 8, while NewPkcs7Padding(int blockSize) takes a parameter for the block size. Nothing prevents using NewPkcs7Padding with a block size of 8 to work with an encryption scheme on blocks of 8 bytes, like Blowfish.

Full block of padding

Padding is always performed to ensure there is no ambiguity for the receiver of a message, even if the message is of an exact multiple-block size. It is intentional and complies with the NIST Recommendation for Block Cipher Modes of Operation Appendix A: Padding (page 17), and the following RFCs:

The padding goes as follows for blocks of 8 bytes (8 octets):

Given a message M, we obtain an encoded message EM by concatenating M with a padding string PS:

EM = M || PS

The padding string PS consists of 8 - (||M|| mod 8) octets, each with value 8 - (||M|| mod 8). Examples:

PS = 01, if ||M|| mod 8 = 7
PS = 02 02, if ||M|| mod 8 = 6
...
PS = 08 08 08 08 08 08 08 08, if ||M|| mod 8 = 0

The last example is essential. Yes, it will intentionally add an entire padding block. Doing so removes the ambiguity for the receiver, that expects every message to be padded.

To illustrate what would happen if some messages are not padded, let's take an example of a message with the last octet with the value 01. As the receiver of this message, should I remove the padding 01? Or, is the last byte 01 part of a message not padded because it was an exact multiple-block size?

If the receiver knows that every message is padded, even if this results in a message padded with a whole block of 08, there is no ambiguity.

Another approach to removing this ambiguity would be to provide a separate indicator that would remove this ambiguity. An example would be to give a message length indicator.

The implementation in this package relies on padding every message (see method padding.Pad()).

Additional Examples

See the unit tests or the example tests in the respective package directories.

License

The Crypt2go ecb package is directly modeled after the CBC Go code released under a BSD license. To avoid license conflicts, Crypt2go is also released under a BSD license.

See the LICENSE file in the repository.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.