New Upstream Release - golang-gopkg-jcmturner-aescts.v1
Ready changes
Summary
Merged new upstream version: 2.0.0 (was: 1.0.1).
Resulting package
Built on 2022-11-24T02:42 (took 3m36s)
The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:
apt install -t fresh-releases golang-gopkg-jcmturner-aescts.v1-dev
Lintian Result
Diff
diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml
new file mode 100644
index 0000000..46478fa
--- /dev/null
+++ b/.github/workflows/testing.yml
@@ -0,0 +1,67 @@
+name: v1
+on:
+ push:
+ paths-ignore:
+ - 'v[0-9]+/**'
+ pull_request:
+ paths-ignore:
+ - 'v[0-9]+/**'
+
+jobs:
+ build:
+ name: Tests
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ go: [ '1.11.x', '1.12.x', '1.13.x' ]
+ steps:
+ - name: Set up Go ${{ matrix.go }}
+ uses: actions/setup-go@v1
+ with:
+ go-version: ${{ matrix.go }}
+
+ - name: Checkout
+ uses: actions/checkout@v2
+ with:
+ ref: ${{ github.ref }}
+
+ - name: Test well formatted with gofmt
+ run: |
+ # Remove major version sub directories
+ find . -maxdepth 1 -type d -regex '\./v[0-9]+' | xargs -i rm -rf {}
+ GO_FILES=$(find . -iname '*.go' -type f | grep -v /vendor/)
+ test -z $(gofmt -s -d -l -e $GO_FILES | tee /dev/fd/2 | xargs | sed 's/\s//g')
+ id: gofmt
+
+ - name: Copy into GOPATH
+ run: |
+ # Default GOPATH=${HOME}/go
+ mkdir -p ${HOME}/go/src/github.com/${GITHUB_REPOSITORY}
+ cp -r $GITHUB_WORKSPACE/* /home/runner/go/src/github.com/${GITHUB_REPOSITORY}
+ id: copyToGOPATH
+
+ - name: Get dependencies
+ run: |
+ cd ${HOME}/go/src/github.com/${GITHUB_REPOSITORY}
+ go get -v -t -d ./...
+ id: goGet
+
+ - name: Go vet
+ run: |
+ cd ${HOME}/go/src/github.com/${GITHUB_REPOSITORY}
+ go vet $(go list ./... | grep -E -v '/v[0-9]+' | grep -v /vendor/)
+ id: govet
+
+ - name: Unit tests
+ run: |
+ cd ${HOME}/go/src/github.com/${GITHUB_REPOSITORY}
+ go test -race $(go list ./... | grep -E -v '/v[0-9]+' | grep -v /vendor/)
+ id: unitTests
+
+ - name: Unit tests (32bit)
+ run: |
+ cd ${HOME}/go/src/github.com/${GITHUB_REPOSITORY}
+ go test $(go list ./... | grep -E -v '/v[0-9]+' | grep -v /vendor/)
+ env:
+ GOARCH: 386
+ id: unitTest32
\ No newline at end of file
diff --git a/.github/workflows/testingv2.yml b/.github/workflows/testingv2.yml
new file mode 100644
index 0000000..ec65a3e
--- /dev/null
+++ b/.github/workflows/testingv2.yml
@@ -0,0 +1,53 @@
+# Name of the workflow needs to match the name of the major version directory
+name: v2
+on:
+ push:
+ paths:
+ - 'v2/**'
+ pull_request:
+ paths:
+ - 'v2/**'
+
+jobs:
+ build:
+ name: Tests
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ go: [ '1.11.x', '1.12.x', '1.13.x' ]
+ steps:
+ - name: Set up Go ${{ matrix.go }}
+ uses: actions/setup-go@v1
+ with:
+ go-version: ${{ matrix.go }}
+
+ - name: Checkout
+ uses: actions/checkout@v2
+ with:
+ ref: ${{ github.ref }}
+
+ - name: Test well formatted with gofmt
+ run: |
+ GO_FILES=$(find ${GITHUB_WORKFLOW} -iname '*.go' -type f | grep -v /vendor/)
+ test -z $(gofmt -s -d -l -e $GO_FILES | tee /dev/fd/2 | xargs | sed 's/\s//g')
+ id: gofmt
+
+ - name: Go vet
+ run: |
+ cd ${GITHUB_WORKFLOW}
+ go vet ./...
+ id: govet
+
+ - name: Unit tests
+ run: |
+ cd ${GITHUB_WORKFLOW}
+ go test -race ./...
+ id: unitTests
+
+ - name: Unit tests (32bit)
+ run: |
+ cd ${GITHUB_WORKFLOW}
+ go test ./...
+ env:
+ GOARCH: 386
+ id: unitTest32
\ No newline at end of file
diff --git a/aescts.go b/aescts.go
index 278713e..fee3b43 100644
--- a/aescts.go
+++ b/aescts.go
@@ -15,7 +15,7 @@ func Encrypt(key, iv, plaintext []byte) ([]byte, []byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
- return []byte{}, []byte{}, fmt.Errorf("Error creating cipher: %v", err)
+ return []byte{}, []byte{}, fmt.Errorf("error creating cipher: %v", err)
}
mode := cipher.NewCBCEncrypter(block, iv)
@@ -43,7 +43,7 @@ func Encrypt(key, iv, plaintext []byte) ([]byte, []byte, error) {
m, _ = zeroPad(m, aes.BlockSize)
rb, pb, lb, err := tailBlocks(m, aes.BlockSize)
if err != nil {
- return []byte{}, []byte{}, fmt.Errorf("Error tailing blocks: %v", err)
+ return []byte{}, []byte{}, fmt.Errorf("error tailing blocks: %v", err)
}
var ct []byte
if rb != nil {
@@ -70,12 +70,12 @@ func Decrypt(key, iv, ciphertext []byte) ([]byte, error) {
ct := make([]byte, len(ciphertext))
copy(ct, ciphertext)
if len(ct) < aes.BlockSize {
- return []byte{}, fmt.Errorf("Ciphertext is not large enough. It is less that one block size. Blocksize:%v; Ciphertext:%v", aes.BlockSize, len(ct))
+ return []byte{}, fmt.Errorf("ciphertext is not large enough. It is less that one block size. Blocksize:%v; Ciphertext:%v", aes.BlockSize, len(ct))
}
// Configure the CBC
block, err := aes.NewCipher(key)
if err != nil {
- return nil, fmt.Errorf("Error creating cipher: %v", err)
+ return nil, fmt.Errorf("error creating cipher: %v", err)
}
var mode cipher.BlockMode
@@ -172,10 +172,10 @@ func swapLastTwoBlocks(b []byte, c int) ([]byte, error) {
// zeroPad pads bytes with zeros to nearest multiple of message size m.
func zeroPad(b []byte, m int) ([]byte, error) {
if m <= 0 {
- return nil, errors.New("Invalid message block size when padding")
+ return nil, errors.New("invalid message block size when padding")
}
if b == nil || len(b) == 0 {
- return nil, errors.New("Data not valid to pad: Zero size")
+ return nil, errors.New("data not valid to pad: Zero size")
}
if l := len(b) % m; l != 0 {
n := m - l
diff --git a/debian/changelog b/debian/changelog
index fe5a270..a0462d3 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+golang-gopkg-jcmturner-aescts.v1 (2.0.0-1) UNRELEASED; urgency=low
+
+ * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk> Thu, 24 Nov 2022 02:39:02 -0000
+
golang-gopkg-jcmturner-aescts.v1 (1.0.1-4) unstable; urgency=medium
[ Debian Janitor ]
diff --git a/v2/aescts.go b/v2/aescts.go
new file mode 100644
index 0000000..fee3b43
--- /dev/null
+++ b/v2/aescts.go
@@ -0,0 +1,186 @@
+// Package aescts provides AES CBC CipherText Stealing encryption and decryption methods
+package aescts
+
+import (
+ "crypto/aes"
+ "crypto/cipher"
+ "errors"
+ "fmt"
+)
+
+// Encrypt the message with the key and the initial vector.
+// Returns: next iv, ciphertext bytes, error
+func Encrypt(key, iv, plaintext []byte) ([]byte, []byte, error) {
+ l := len(plaintext)
+
+ block, err := aes.NewCipher(key)
+ if err != nil {
+ return []byte{}, []byte{}, fmt.Errorf("error creating cipher: %v", err)
+ }
+ mode := cipher.NewCBCEncrypter(block, iv)
+
+ m := make([]byte, len(plaintext))
+ copy(m, plaintext)
+
+ /*For consistency, ciphertext stealing is always used for the last two
+ blocks of the data to be encrypted, as in [RC5]. If the data length
+ is a multiple of the block size, this is equivalent to plain CBC mode
+ with the last two ciphertext blocks swapped.*/
+ /*The initial vector carried out from one encryption for use in a
+ subsequent encryption is the next-to-last block of the encryption
+ output; this is the encrypted form of the last plaintext block.*/
+ if l <= aes.BlockSize {
+ m, _ = zeroPad(m, aes.BlockSize)
+ mode.CryptBlocks(m, m)
+ return m, m, nil
+ }
+ if l%aes.BlockSize == 0 {
+ mode.CryptBlocks(m, m)
+ iv = m[len(m)-aes.BlockSize:]
+ rb, _ := swapLastTwoBlocks(m, aes.BlockSize)
+ return iv, rb, nil
+ }
+ m, _ = zeroPad(m, aes.BlockSize)
+ rb, pb, lb, err := tailBlocks(m, aes.BlockSize)
+ if err != nil {
+ return []byte{}, []byte{}, fmt.Errorf("error tailing blocks: %v", err)
+ }
+ var ct []byte
+ if rb != nil {
+ // Encrpt all but the lats 2 blocks and update the rolling iv
+ mode.CryptBlocks(rb, rb)
+ iv = rb[len(rb)-aes.BlockSize:]
+ mode = cipher.NewCBCEncrypter(block, iv)
+ ct = append(ct, rb...)
+ }
+ mode.CryptBlocks(pb, pb)
+ mode = cipher.NewCBCEncrypter(block, pb)
+ mode.CryptBlocks(lb, lb)
+ // Cipher Text Stealing (CTS) - Ref: https://en.wikipedia.org/wiki/Ciphertext_stealing#CBC_ciphertext_stealing
+ // Swap the last two cipher blocks
+ // Truncate the ciphertext to the length of the original plaintext
+ ct = append(ct, lb...)
+ ct = append(ct, pb...)
+ return lb, ct[:l], nil
+}
+
+// Decrypt the ciphertext with the key and the initial vector.
+func Decrypt(key, iv, ciphertext []byte) ([]byte, error) {
+ // Copy the cipher text as golang slices even when passed by value to this method can result in the backing arrays of the calling code value being updated.
+ ct := make([]byte, len(ciphertext))
+ copy(ct, ciphertext)
+ if len(ct) < aes.BlockSize {
+ return []byte{}, fmt.Errorf("ciphertext is not large enough. It is less that one block size. Blocksize:%v; Ciphertext:%v", aes.BlockSize, len(ct))
+ }
+ // Configure the CBC
+ block, err := aes.NewCipher(key)
+ if err != nil {
+ return nil, fmt.Errorf("error creating cipher: %v", err)
+ }
+ var mode cipher.BlockMode
+
+ //If ciphertext is multiple of blocksize we just need to swap back the last two blocks and then do CBC
+ //If the ciphertext is just one block we can't swap so we just decrypt
+ if len(ct)%aes.BlockSize == 0 {
+ if len(ct) > aes.BlockSize {
+ ct, _ = swapLastTwoBlocks(ct, aes.BlockSize)
+ }
+ mode = cipher.NewCBCDecrypter(block, iv)
+ message := make([]byte, len(ct))
+ mode.CryptBlocks(message, ct)
+ return message[:len(ct)], nil
+ }
+
+ // Cipher Text Stealing (CTS) using CBC interface. Ref: https://en.wikipedia.org/wiki/Ciphertext_stealing#CBC_ciphertext_stealing
+ // Get ciphertext of the 2nd to last (penultimate) block (cpb), the last block (clb) and the rest (crb)
+ crb, cpb, clb, _ := tailBlocks(ct, aes.BlockSize)
+ v := make([]byte, len(iv), len(iv))
+ copy(v, iv)
+ var message []byte
+ if crb != nil {
+ //If there is more than just the last and the penultimate block we decrypt it and the last bloc of this becomes the iv for later
+ rb := make([]byte, len(crb))
+ mode = cipher.NewCBCDecrypter(block, v)
+ v = crb[len(crb)-aes.BlockSize:]
+ mode.CryptBlocks(rb, crb)
+ message = append(message, rb...)
+ }
+
+ // We need to modify the cipher text
+ // Decryt the 2nd to last (penultimate) block with a the original iv
+ pb := make([]byte, aes.BlockSize)
+ mode = cipher.NewCBCDecrypter(block, iv)
+ mode.CryptBlocks(pb, cpb)
+ // number of byte needed to pad
+ npb := aes.BlockSize - len(ct)%aes.BlockSize
+ //pad last block using the number of bytes needed from the tail of the plaintext 2nd to last (penultimate) block
+ clb = append(clb, pb[len(pb)-npb:]...)
+
+ // Now decrypt the last block in the penultimate position (iv will be from the crb, if the is no crb it's zeros)
+ // iv for the penultimate block decrypted in the last position becomes the modified last block
+ lb := make([]byte, aes.BlockSize)
+ mode = cipher.NewCBCDecrypter(block, v)
+ v = clb
+ mode.CryptBlocks(lb, clb)
+ message = append(message, lb...)
+
+ // Now decrypt the penultimate block in the last position (iv will be from the modified last block)
+ mode = cipher.NewCBCDecrypter(block, v)
+ mode.CryptBlocks(cpb, cpb)
+ message = append(message, cpb...)
+
+ // Truncate to the size of the original cipher text
+ return message[:len(ct)], nil
+}
+
+func tailBlocks(b []byte, c int) ([]byte, []byte, []byte, error) {
+ if len(b) <= c {
+ return []byte{}, []byte{}, []byte{}, errors.New("bytes slice is not larger than one block so cannot tail")
+ }
+ // Get size of last block
+ var lbs int
+ if l := len(b) % aes.BlockSize; l == 0 {
+ lbs = aes.BlockSize
+ } else {
+ lbs = l
+ }
+ // Get last block
+ lb := b[len(b)-lbs:]
+ // Get 2nd to last (penultimate) block
+ pb := b[len(b)-lbs-c : len(b)-lbs]
+ if len(b) > 2*c {
+ rb := b[:len(b)-lbs-c]
+ return rb, pb, lb, nil
+ }
+ return nil, pb, lb, nil
+}
+
+func swapLastTwoBlocks(b []byte, c int) ([]byte, error) {
+ rb, pb, lb, err := tailBlocks(b, c)
+ if err != nil {
+ return nil, err
+ }
+ var out []byte
+ if rb != nil {
+ out = append(out, rb...)
+ }
+ out = append(out, lb...)
+ out = append(out, pb...)
+ return out, nil
+}
+
+// zeroPad pads bytes with zeros to nearest multiple of message size m.
+func zeroPad(b []byte, m int) ([]byte, error) {
+ if m <= 0 {
+ return nil, errors.New("invalid message block size when padding")
+ }
+ if b == nil || len(b) == 0 {
+ return nil, errors.New("data not valid to pad: Zero size")
+ }
+ if l := len(b) % m; l != 0 {
+ n := m - l
+ z := make([]byte, n)
+ b = append(b, z...)
+ }
+ return b, nil
+}
diff --git a/v2/aescts_test.go b/v2/aescts_test.go
new file mode 100644
index 0000000..1a1da4f
--- /dev/null
+++ b/v2/aescts_test.go
@@ -0,0 +1,44 @@
+package aescts
+
+import (
+ "encoding/hex"
+ "github.com/stretchr/testify/assert"
+ "testing"
+)
+
+func TestAesCts_Encrypt_Decrypt(t *testing.T) {
+ iv := make([]byte, 16)
+ key, _ := hex.DecodeString("636869636b656e207465726979616b69")
+ var tests = []struct {
+ plain string
+ cipher string
+ nextIV string
+ }{
+ //Test vectors from RFC 3962 Appendix B
+ {"4920776f756c64206c696b652074686520", "c6353568f2bf8cb4d8a580362da7ff7f97", "c6353568f2bf8cb4d8a580362da7ff7f"},
+ {"4920776f756c64206c696b65207468652047656e6572616c20476175277320", "fc00783e0efdb2c1d445d4c8eff7ed2297687268d6ecccc0c07b25e25ecfe5", "fc00783e0efdb2c1d445d4c8eff7ed22"},
+ {"4920776f756c64206c696b65207468652047656e6572616c2047617527732043", "39312523a78662d5be7fcbcc98ebf5a897687268d6ecccc0c07b25e25ecfe584", "39312523a78662d5be7fcbcc98ebf5a8"},
+ {"4920776f756c64206c696b65207468652047656e6572616c20476175277320436869636b656e2c20706c656173652c", "97687268d6ecccc0c07b25e25ecfe584b3fffd940c16a18c1b5549d2f838029e39312523a78662d5be7fcbcc98ebf5", "b3fffd940c16a18c1b5549d2f838029e"},
+ {"4920776f756c64206c696b65207468652047656e6572616c20476175277320436869636b656e2c20706c656173652c20", "97687268d6ecccc0c07b25e25ecfe5849dad8bbb96c4cdc03bc103e1a194bbd839312523a78662d5be7fcbcc98ebf5a8", "9dad8bbb96c4cdc03bc103e1a194bbd8"},
+ {"4920776f756c64206c696b65207468652047656e6572616c20476175277320436869636b656e2c20706c656173652c20616e6420776f6e746f6e20736f75702e", "97687268d6ecccc0c07b25e25ecfe58439312523a78662d5be7fcbcc98ebf5a84807efe836ee89a526730dbc2f7bc8409dad8bbb96c4cdc03bc103e1a194bbd8", "4807efe836ee89a526730dbc2f7bc840"},
+ }
+ for i, test := range tests {
+ m, _ := hex.DecodeString(test.plain)
+ niv, c, err := Encrypt(key, iv, m)
+ if err != nil {
+ t.Errorf("Encryption failed for test %v: %v", i+1, err)
+ }
+ assert.Equal(t, test.cipher, hex.EncodeToString(c), "Encrypted result not as expected")
+ assert.Equal(t, test.nextIV, hex.EncodeToString(niv), "Next state IV not as expected")
+ }
+ //t.Log("AES CTS Encryption tests finished")
+ for i, test := range tests {
+ b, _ := hex.DecodeString(test.cipher)
+ p, err := Decrypt(key, iv, b)
+ if err != nil {
+ t.Errorf("Decryption failed for test %v: %v", i+1, err)
+ }
+ assert.Equal(t, test.plain, hex.EncodeToString(p), "Decrypted result not as expected")
+ }
+ //t.Log("AES CTS Decryption tests finished")
+}
diff --git a/v2/go.mod b/v2/go.mod
new file mode 100644
index 0000000..034c3ce
--- /dev/null
+++ b/v2/go.mod
@@ -0,0 +1,5 @@
+module github.com/jcmturner/aescts/v2
+
+go 1.13
+
+require github.com/stretchr/testify v1.4.0
diff --git a/v2/go.sum b/v2/go.sum
new file mode 100644
index 0000000..e863f51
--- /dev/null
+++ b/v2/go.sum
@@ -0,0 +1,10 @@
+github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
Debdiff
[The following lists of changes regard files as different if they have different names, permissions or owners.]
Files in second set of .debs but not in first
-rw-r--r-- root/root /usr/share/gocode/src/gopkg.in/jcmturner/aescts.v1/v2/aescts.go -rw-r--r-- root/root /usr/share/gocode/src/gopkg.in/jcmturner/aescts.v1/v2/aescts_test.go
No differences were encountered in the control files