Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@nanmu42
Last active October 3, 2023 06:55
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nanmu42/b838acc10d393bc51cb861128ce7f89c to your computer and use it in GitHub Desktop.
Save nanmu42/b838acc10d393bc51cb861128ce7f89c to your computer and use it in GitHub Desktop.
Golang PKCS7 Padding/Unpadding
// pkcs7strip remove pkcs7 padding
func pkcs7strip(data []byte, blockSize int) ([]byte, error) {
length := len(data)
if length == 0 {
return nil, errors.New("pkcs7: Data is empty")
}
if length%blockSize != 0 {
return nil, errors.New("pkcs7: Data is not block-aligned")
}
padLen := int(data[length-1])
ref := bytes.Repeat([]byte{byte(padLen)}, padLen)
if padLen > blockSize || padLen == 0 || !bytes.HasSuffix(data, ref) {
return nil, errors.New("pkcs7: Invalid padding")
}
return data[:length-padLen], nil
}
// pkcs7pad add pkcs7 padding
func pkcs7pad(data []byte, blockSize int) ([]byte, error) {
if blockSize <= 1 || blockSize >= 256 {
return nil, fmt.Errorf("pkcs7: Invalid block size %d", blockSize)
} else {
padLen := blockSize - len(data) % blockSize
padding := bytes.Repeat([]byte{byte(padLen)}, padLen)
return append(data, padding...), nil
}
}
@gregorkrz
Copy link

What's the meaning of the 16 on line 23? Shouldn't it be equal to blockSize?

@nanmu42
Copy link
Author

nanmu42 commented Feb 22, 2020

What's the meaning of the 16 on line 23? Shouldn't it be equal to blockSize?

Opps, I was using it only for AES.

You are right, thanks for notification. I have altered it to blockSize.

@Haiyung
Copy link

Haiyung commented Dec 15, 2020

Cool. It helped me.

@deeuu
Copy link

deeuu commented Jan 13, 2021

Nice, thanks

@ucfjimg
Copy link

ucfjimg commented Jul 28, 2021

This has a subtle off by one bug in line 20. The block size must fit in a byte; the condition should be >= 256 (also, zero is invalid)

@XfedeX
Copy link

XfedeX commented Jul 3, 2022

There is a bug at line 23.
It should be
padLen := (blockSize - len(data)) % blockSize

@nanmu42
Copy link
Author

nanmu42 commented Jul 3, 2022

There is a bug at line 23.
It should be
padLen := (blockSize - len(data)) % blockSize

I failed to see the reason. Why?

@ucfjimg
Copy link

ucfjimg commented Jul 3, 2022

There is a bug at line 23.
It should be
padLen := (blockSize - len(data)) % blockSize

The original code is correct. If the data is an integral number of blocks there should be a full block of padding. It’s necessary in order for the last byte to make sense.

@nanmu42
Copy link
Author

nanmu42 commented Jul 4, 2022

So current implementation is correct, yes?

padLen := blockSize - len(data) % blockSize

It is effectively the same as:

padLen := blockSize - (len(data) % blockSize)

if we use

padLen := (blockSize - len(data)) % blockSize

len(data) could be greater than blockSize and produces minus result.

@aimuz
Copy link

aimuz commented Dec 19, 2022

https://www.rfc-editor.org/rfc/rfc2315

There is an error in line 20 of the code, as described on page 21 of this link.

Kaliski                      Informational                     [Page 21]


[RFC 2315](https://www.rfc-editor.org/rfc/rfc2315)          PKCS #7: Crytographic Message Syntax        March 1998


        2.   Some content-encryption algorithms assume the
             input length is a multiple of k octets, where k > 1, and
             let the application define a method for handling inputs
             whose lengths are not a multiple of k octets. For such
             algorithms, the method shall be to pad the input at the
             trailing end with k - (l mod k) octets all having value k -
             (l mod k), where l is the length of the input. In other
             words, the input is padded at the trailing end with one of
             the following strings:

                      01 -- if l mod k = k-1
                     02 02 -- if l mod k = k-2
                                 .
                                 .
                                 .
                   k k ... k k -- if l mod k = 0

             The padding can be removed unambiguously since all input is
             padded and no padding string is a suffix of another. This
             padding method is well-defined if and only if k < 256;
             methods for larger k are an open issue for further study.

@nanmu42
Copy link
Author

nanmu42 commented Dec 19, 2022

https://www.rfc-editor.org/rfc/rfc2315

There is an error in line 20 of the code, as described on page 21 of this link.

Hi @aimuz , thanks for your feedback. What change should be made? Is it this?

if blockSize <= 1 || blockSize >= 256 {

@aimuz
Copy link

aimuz commented Dec 19, 2022

Yes, I think that should be the case

@nanmu42
Copy link
Author

nanmu42 commented Dec 20, 2022

Yes, I think that should be the case

Thanks, I have updated the gist per your suggestion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment