PKCS#7 Padding

ブロック暗号では、決められたサイズのブロックごとに暗号化を行います。暗号元の値がブロックのサイズに満たない場合、足りないサイズ分を埋めることでサイズを合わせます。

https://go.dev/play/p/lKMSllajNkm

package main

import (
	"bytes"
	"fmt"
)

func PKCS7Padding(data []byte, blockSize int) []byte {
	padding := blockSize - len(data)%blockSize
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(data, padtext...)
}

func showPadding(data string, blockSize int) {
	paddedData := PKCS7Padding([]byte(data), blockSize)
	for _, b := range paddedData {
		fmt.Printf("0x%02x ", b)
	}
	fmt.Println()
}

func main() {
	showPadding("", 16)
	showPadding("A", 16)
	showPadding("AB", 16)
	showPadding("ABC", 16)
	showPadding("ABCD", 16)
	showPadding("ABCDE", 16)
	showPadding("ABCDEF", 16)
	showPadding("ABCDEFG", 16)
	showPadding("ABCDEFGH", 16)
	showPadding("ABCDEFGHI", 16)
	showPadding("ABCDEFGHIJ", 16)
	showPadding("ABCDEFGHIJK", 16)
	showPadding("ABCDEFGHIJKL", 16)
	showPadding("ABCDEFGHIJKLM", 16)
	showPadding("ABCDEFGHIJKLMN", 16)
	showPadding("ABCDEFGHIJKLMNO", 16)
	showPadding("ABCDEFGHIJKLMNOP", 16)
}
0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 
0x41 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 0x0f 
0x41 0x42 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 0x0e 
0x41 0x42 0x43 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 0x0d 
0x41 0x42 0x43 0x44 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 0x0c 
0x41 0x42 0x43 0x44 0x45 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 0x0b 
0x41 0x42 0x43 0x44 0x45 0x46 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 0x0a 
0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 0x09 
0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08 
0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x07 0x07 0x07 0x07 0x07 0x07 0x07 
0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4a 0x06 0x06 0x06 0x06 0x06 0x06 
0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4a 0x4b 0x05 0x05 0x05 0x05 0x05 
0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4a 0x4b 0x4c 0x04 0x04 0x04 0x04 
0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4a 0x4b 0x4c 0x4d 0x03 0x03 0x03 
0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4a 0x4b 0x4c 0x4d 0x4e 0x02 0x02 
0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4a 0x4b 0x4c 0x4d 0x4e 0x4f 0x01
0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4a 0x4b 0x4c 0x4d 0x4e 0x4f 0x50 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10

AESの場合は、16バイトのブロックになります。

1文字で値が A の場合は、残り 15バイトを 15(0x0f) で埋めます
2文字で値が AB の場合は、残りの 14バイトを 14(0x0e) で埋めます
15文字で値が ABCDEFGHIJKLMNO の場合は、残りの 1バイトを 1(0x01) で埋めます

16文字の場合は、16バイトが 16(0x10) の値となったブロックを追加します。結果として32バイトとなっています。これは、最後の文字が 1(0x01)だった場合に、パディングなのか値なのか判別が付かないためです。