cipher.go raw

   1  package pkcs8
   2  
   3  import (
   4  	"bytes"
   5  	"crypto/cipher"
   6  	"encoding/asn1"
   7  )
   8  
   9  type cipherWithBlock struct {
  10  	oid      asn1.ObjectIdentifier
  11  	ivSize   int
  12  	keySize  int
  13  	newBlock func(key []byte) (cipher.Block, error)
  14  }
  15  
  16  func (c cipherWithBlock) IVSize() int {
  17  	return c.ivSize
  18  }
  19  
  20  func (c cipherWithBlock) KeySize() int {
  21  	return c.keySize
  22  }
  23  
  24  func (c cipherWithBlock) OID() asn1.ObjectIdentifier {
  25  	return c.oid
  26  }
  27  
  28  func (c cipherWithBlock) Encrypt(key, iv, plaintext []byte) ([]byte, error) {
  29  	block, err := c.newBlock(key)
  30  	if err != nil {
  31  		return nil, err
  32  	}
  33  	return cbcEncrypt(block, key, iv, plaintext)
  34  }
  35  
  36  func (c cipherWithBlock) Decrypt(key, iv, ciphertext []byte) ([]byte, error) {
  37  	block, err := c.newBlock(key)
  38  	if err != nil {
  39  		return nil, err
  40  	}
  41  	return cbcDecrypt(block, key, iv, ciphertext)
  42  }
  43  
  44  func cbcEncrypt(block cipher.Block, key, iv, plaintext []byte) ([]byte, error) {
  45  	mode := cipher.NewCBCEncrypter(block, iv)
  46  	paddingLen := block.BlockSize() - (len(plaintext) % block.BlockSize())
  47  	ciphertext := make([]byte, len(plaintext)+paddingLen)
  48  	copy(ciphertext, plaintext)
  49  	copy(ciphertext[len(plaintext):], bytes.Repeat([]byte{byte(paddingLen)}, paddingLen))
  50  	mode.CryptBlocks(ciphertext, ciphertext)
  51  	return ciphertext, nil
  52  }
  53  
  54  func cbcDecrypt(block cipher.Block, key, iv, ciphertext []byte) ([]byte, error) {
  55  	mode := cipher.NewCBCDecrypter(block, iv)
  56  	plaintext := make([]byte, len(ciphertext))
  57  	mode.CryptBlocks(plaintext, ciphertext)
  58  	// TODO: remove padding
  59  	return plaintext, nil
  60  }
  61