This is an implementation of functions for forward and reverse conversion using the S-box algorithm as well as the P-box algorithm.
src/sbox/
- S-box implementation
src/pbox/
- P-box implementation
tests/
- tests for the functions
This implementation uses an S-box from the AES (Rijndael).
The src/sbox
package has two public functions:
Lookup(uint8) uint8
- to substitute the value using the s-box.ReverseLookup(uint8) uint8
- to get the original value using the reversed s-box.
The input must be an 8-bit unsigned integer (byte/uint8
). The output is an 8-bit unsigned integer as well.
When looking up, a byte is splitted into two tetrads (4-bit unsigned integers). Then the AES S-box is used - the first tetrad is the row number of the table, and the second tetrad is the column number.
import (
"fmt"
"github.com/danielost/sp-box/src/sbox"
)
func foo() {
var b uint8 = 0x2d
sB := sbox.Lookup(b)
rsB := sbox.ReverseLookup(sB)
fmt.Println(b) // 0x2d = 45
fmt.Println(sB) // 0xd8 = 216
fmt.Println(b == rsB) // 0x2d == 0x2d
}
In the above example 0x2d
is divided into two tetrads – 0x2
and 0xd
, where 0x2
is the row of the S-box and 0xd
is the column. 0xd8
is the intersection of these values in the AES S-box, which looks as follows:
0x0 | 0x1 | 0x2 | 0x3 | 0x4 | 0x5 | 0x6 | 0x7 | 0x8 | 0x9 | 0xa | 0xb | 0xc | 0xd | 0xe | 0xf | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0 | 0x63 | 0x7c | 0x77 | 0x7b | 0xf2 | 0x6b | 0x6f | 0xc5 | 0x30 | 0x01 | 0x67 | 0x2b | 0xfe | 0xd7 | 0xab | 0x76 |
0x1 | 0xca | 0x82 | 0xc9 | 0x7d | 0xfa | 0x59 | 0x47 | 0xf0 | 0xad | 0xd4 | 0xa2 | 0xaf | 0x9c | 0xa4 | 0x72 | 0xc0 |
0x2 | 0xb7 | 0xfd | 0x93 | 0x26 | 0x36 | 0x3f | 0xf7 | 0xcc | 0x34 | 0xa5 | 0xe5 | 0xf1 | 0x71 | 0xd8 | 0x31 | 0x15 |
0x3 | 0x04 | 0xc7 | 0x23 | 0xc3 | 0x18 | 0x96 | 0x05 | 0x9a | 0x07 | 0x12 | 0x80 | 0xe2 | 0xeb | 0x27 | 0xb2 | 0x75 |
0x4 | 0x09 | 0x83 | 0x2c | 0x1a | 0x1b | 0x6e | 0x5a | 0xa0 | 0x52 | 0x3b | 0xd6 | 0xb3 | 0x29 | 0xe3 | 0x2f | 0x84 |
0x5 | 0x53 | 0xd1 | 0x00 | 0xed | 0x20 | 0xfc | 0xb1 | 0x5b | 0x6a | 0xcb | 0xbe | 0x39 | 0x4a | 0x4c | 0x58 | 0xcf |
0x6 | 0xd0 | 0xef | 0xaa | 0xfb | 0x43 | 0x4d | 0x33 | 0x85 | 0x45 | 0xf9 | 0x02 | 0x7f | 0x50 | 0x3c | 0x9f | 0xa8 |
0x7 | 0x51 | 0xa3 | 0x40 | 0x8f | 0x92 | 0x9d | 0x38 | 0xf5 | 0xbc | 0xb6 | 0xda | 0x21 | 0x10 | 0xff | 0xf3 | 0xd2 |
0x8 | 0xcd | 0x0c | 0x13 | 0xec | 0x5f | 0x97 | 0x44 | 0x17 | 0xc4 | 0xa7 | 0x7e | 0x3d | 0x64 | 0x5d | 0x19 | 0x73 |
0x9 | 0x60 | 0x81 | 0x4f | 0xdc | 0x22 | 0x2a | 0x90 | 0x88 | 0x46 | 0xee | 0xb8 | 0x14 | 0xde | 0x5e | 0x0b | 0xdb |
0xa | 0xe0 | 0x32 | 0x3a | 0x0a | 0x49 | 0x06 | 0x24 | 0x5c | 0xc2 | 0xd3 | 0xac | 0x62 | 0x91 | 0x95 | 0xe4 | 0x79 |
0xb | 0xe7 | 0xc8 | 0x37 | 0x6d | 0x8d | 0xd5 | 0x4e | 0xa9 | 0x6c | 0x56 | 0xf4 | 0xea | 0x65 | 0x7a | 0xae | 0x08 |
0xc | 0xba | 0x78 | 0x25 | 0x2e | 0x1c | 0xa6 | 0xb4 | 0xc6 | 0xe8 | 0xdd | 0x74 | 0x1f | 0x4b | 0xbd | 0x8b | 0x8a |
0xd | 0x70 | 0x3e | 0xb5 | 0x66 | 0x48 | 0x03 | 0xf6 | 0x0e | 0x61 | 0x35 | 0x57 | 0xb9 | 0x86 | 0xc1 | 0x1d | 0x9e |
0xe | 0xe1 | 0xf8 | 0x98 | 0x11 | 0x69 | 0xd9 | 0x8e | 0x94 | 0x9b | 0x1e | 0x87 | 0xe9 | 0xce | 0x55 | 0x28 | 0xdf |
0xf | 0x8c | 0xa1 | 0x89 | 0x0d | 0xbf | 0xe6 | 0x42 | 0x68 | 0x41 | 0x99 | 0x2d | 0x0f | 0xb0 | 0x54 | 0xbb | 0x16 |
The src/pbox
package has one public function: Permute(uint8) (uint8, func(uint8) uint8)
. It takes an 8-bit unsigned integer as an input, converts it to a binary representation, shuffles the bits and returns the decimal representation of the permuted binary value as well as a function that is used to get the original value.
Each call to Permute
randomly shuffles the bits, even in case of multiple calls for the same input. That is why each call returns a function to restore exactly the returned byte.
To randomly permute the bit sequence, Fisher–Yates shuffle Algorithm was used.
import (
"fmt"
"github.com/danielost/sp-box/src/pbox"
)
func foo() {
var b uint8 = 0x2d
pB, reverse := pbox.Permute(b)
rpB := reverse(pB)
fmt.Println(b) // 45
fmt.Println(pB) // permuted b - pB
fmt.Println(rpB == b)
}
The tests run the s-box and p-box functions for all the values in range [0;2^8]
To run the tests, execute this command:
go test .\tests\
or, for the detailed overview:
go test -v .\tests\