It’s a part of the wechatpay-axios-plugin codes, regarding by the rfc2315, the PKCS7/Padding spec was post a notes there:

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.

For other developing language, there were more than one librares did the right thing. In Javascript, there were also lots of librares too. The following codes is another implementation on ES2015+ style. It just using the Native Buffer library to do the right things.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
class Aes {
  /**
   * @property {integer} BLOCK_SIZE - The `aes` block size
   */
  static get BLOCK_SIZE() { return 16 }

  /**
   * @property {object} pkcs7 - The PKCS7 padding/unpadding container
   */
  static get pkcs7() {
    const {BLOCK_SIZE} = this

    return {
      /**
       * padding, 32 bytes/256 bits `secret key` may optional need the last block.
       * @see https://tools.ietf.org/html/rfc2315#section-10.3
       * <quote>
       * 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.
       * </quote>
       *
       * @param {string|Buffer} thing - The input
       * @param {boolean} [optional = true] - The flag for the last padding
       *
       * @return {Buffer} - The PADDING tailed payload
       */
      padding: (thing, optional = true) => {
        const payload = Buffer.from(thing)
        const pad = BLOCK_SIZE - payload.length % BLOCK_SIZE

        if (optional && pad === BLOCK_SIZE) {
          return payload
        }

        return Buffer.concat([payload, Buffer.alloc(pad, pad)])
      },

      /**
       * unpadding
       *
       * @param  {string|Buffer} thing - The input
       * @return {Buffer} - The PADDING wiped payload
       */
      unpadding: thing => {
        const byte = Buffer.alloc(1)
        const payload = Buffer.from(thing)
        payload.copy(byte, 0, payload.length - 1)
        const pad = byte.readUInt8()

        if (!~~Buffer.compare(Buffer.alloc(pad, pad), payload.slice(-pad))) {
          return payload.slice(0, -pad)
        }

        return payload
      },
    }
  }
}

Usage manual

1
console.log(Aes.pkcs7.padding(''))
1
<Buffer >
1
console.log(Aes.pkcs7.padding('', false))
1
<Buffer 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10>
1
console.log(Aes.pkcs7.padding('1234567890'))
1
<Buffer 31 32 33 34 35 36 37 38 39 30 06 06 06 06 06 06>
1
console.log(Aes.pkcs7.unpadding(Aes.pkcs7.padding('', false)).toString())
1
''
1
console.log(Aes.pkcs7.unpadding(Aes.pkcs7.padding('1234567890')).toString())
1
1234567890

That’s it!