이번 시간에는 지난 시간에 이어 NanoPi R4S board를 가지고 PQC Wireguard 기반 초소형 VPN router를 만드는 과정(Part II)을 소개해 보고자 한다. 😎
이번 장에서는 PQC 알고리즘 중 CRYSTALS Kyber의 세부 동작 과정을 분석해 보고자 한다. CRYSTALS Kyber 관련 많은 논문(paper)를 읽어 보았지만, 아래 논문이 가장 이해하기 쉬운 형태의 그림을 제공하고 있어서, 이번 장에서는 아래 논문을 기초로 CRYSTALS Kyber의 세부 동작 원리를 파헤쳐 보고자 한다. 이 자리를 빌어 아래 논문 저자에게 감사의 인사를 전한다. 😍
(2) pk를 받은 Bob은 Enc(encapsulation) 함수를 이용하여 대칭키 ss와 ss를 암호화한 값 c를 만든 후, Alice에게 c 값을 전달한다.
(3) c 값을 수신한 Alice는 자신이 이미 가지고 있는 sk(secret key = private key)와 Dec(decapsulation) 함수를 이용해 대칭 키 ss를 획득한다.
이번 장에서는 CRYSTALS Kyber KEM을 WireGuard에 접목시키는 내용을 소개해 보고자 한다. 이 장에서 소개하는 내용은 아래 PQ-WireGuard 논문에서 영감을 받긴 했으나, 접근 방법을 좀 달리 하고자 하였다.
6. Alpine Linux 용 Quantum Safe WireGuard 구현하기
a) Alpine Linux 소개
아주 오래 전(Long long ago 호랑이 담배 피던 시절에~ 😓)에 LEAF(Linux Embedded Appliance Framework)라는 project를 이용하여 Linux Router를 개발했던 적이 있다. 최근 들어 LEAF로 network 장비를 만들어 볼까 하는 마음에 다시 찾던 중, LEAF는 없어지고 그 후예(fork)로 Alpine linux가 있다는 사실을 알게 되었다.
b) Alpine Linux kernel build하기
이번 장에서는 Alpine Linux가 이미 설치되어 있는 서버(Intel CPU)상에서 alpine linux kernel을 build하는 절차를 소개하고자 한다.
📌 Alpine linux는 경량한 구조 덕분에 docker에 올라가는 OS로도 널리 알려져 있다. 따라서 아래 제시하는 내용은 Ubuntu PC에 Docker를 설치하고, 다시 docker 내에 Alpine linux를 설치한 후 테스트해 보아도 동일한 결과를 얻을 수 있다. 실제로 필자는 이와 같은 환경에서 개발을 하긴한다. 하지만, kernel build 속도가 아무래도 신경이 쓰이기 때문에 오늘은 실제 server에서 build하는 형태로 접근해 보자.
1) Kernel build 전 준비 작업(주요 패키지 설치)
📌 Alpine linux를 설치하는 내용은 다루지 않는다. 따라서 아래 내용은 이미 Alpine linux가 설치되었다고 가정하고 진행하도록 한다.
$ sudo apk update
$ sudo apk upgrade
$ sudo apk add vim alpine-sdk
/ # visudo /etc/sudoers
...
##
## User privilege specification
##
root ALL=(ALL) ALL
chyi ALL=(ALL) ALL //사용하는 계정을 등록한다.
...
PACKAGER 부분을 자신의 정보로 수정한다.
$ sudo addgroup chyi abuild
📌 group 추가 내용이 반영되려면, logout 후 재 login해 주어야 한다.
$ abuild-keygen -a -i
>>> Generating public/private rsa key pair for abuild
Enter file in which to save the key [/home/chyi/.abuild/chunghan.yi@gmail.com-61331fa6.rsa]: <Enter>
Generating RSA private key, 2048 bit long modulus (2 primes)
......+++++
......................................................................+++++
e is 65537 (0x010001)
writing RSA key
>>> Installing /home/chyi/.abuild/chunghan.yi@gmail.com-61331fa6.rsa.pub to /etc/apk/keys...
>>>
>>> Please remember to make a safe backup of your private key:
>>> /home/chyi/.abuild/chunghan.yi@gmail.com-61331fa6.rsa
$ ls -la
total 344
drwxr-sr-x 12 chyi chyi 4096 Sep 4 07:19 .
drwxr-sr-x 3 chyi chyi 4096 Sep 4 07:16 ..
-rw-r--r-- 1 chyi chyi 1631 Sep 4 07:19 .drone.yml
-rw-r--r-- 1 chyi chyi 371 Sep 4 07:19 .editorconfig
drwxr-sr-x 8 chyi chyi 4096 Sep 4 07:19 .git
drwxr-sr-x 2 chyi chyi 4096 Sep 4 07:19 .githookssudo
drwxr-sr-x 2 chyi chyi 4096 Sep 4 07:19 .github
-rw-r--r-- 1 chyi chyi 105 Sep 4 07:19 .gitignore
drwxr-sr-x 2 chyi chyi 4096 Sep 4 07:19 .gitlab
-rw-r--r-- 1 chyi chyi 2101 Sep 4 07:19 .gitlab-ci.yml
-rw-r--r-- 1 chyi chyi 1115 Sep 4 07:19 .mailmap
-rw-r--r-- 1 chyi chyi 5973 Sep 4 07:19 CODINGSTYLE.md
-rw-r--r-- 1 chyi chyi 5821 Sep 4 07:19 COMMITSTYLE.md
-rw-r--r-- 1 chyi chyi 881 Sep 4 07:19 README.md
drwxr-sr-x 4047 chyi chyi 135168 Sep 4 07:19 community
drwxr-sr-x 1530 chyi chyi 49152 Sep 4 07:19 main
drwxr-sr-x 21 chyi chyi 4096 Sep 4 07:19 non-free
drwxr-sr-x 2 chyi chyi 4096 Sep 4 07:19 scripts
drwxr-sr-x 2318 chyi chyi 69632 Sep 4 07:19 testing
drwxr-sr-x 261 chyi chyi 12288 Sep 4 07:19 unmaintained
$ cd ~/aports/main/linux-lts
$ abuild -r
abuild는 현재 디렉토리에 있는 APKBUILD 파일을 이용하여 build를 진행한다. -r option을 줄 경우, source download & patch 부터 kernel build 후 package 생성까지를 모두 처리한다. Build가 끝난 후에는 build 과정에서 생성한 src/ 디렉토리를 통째로 날려 버린다.
https://wiki.alpinelinux.org/wiki/APKBUILD_Reference
...
>>> linux-lts: Building main/linux-lts 5.10.61-r0 (using abuild 3.8.0_rc4-r0) started Sat, 04 Sep 2021 08:25:02 +0000
>>> linux-lts: Checking sanity of /home/chyi/aports/main/linux-lts/APKBUILD...
>>> linux-lts: Analyzing dependencies...
>>> linux-lts: Installing for build: build-base mkinitfs perl gmp-dev elfutils-dev bash flex bison sed installkernel bc linux-headers linux-firmware-any openssl-dev diffutils findutils
WARNING: Ignoring /home/chyi/packages//main: No such file or directory
(1/128) Installing lddtree (1.26-r2)
(2/128) Installing xz-libs (5.2.5-r0)
(3/128) Installing zstd-libs (1.4.9-r1)
(4/128) Installing kmod (29-r0)
(5/128) Installing libblkid (2.37-r0)
(6/128) Installing argon2-libs (20190702-r1)
(7/128) Installing device-mapper-libs (2.02.187-r1)
(8/128) Installing json-c (0.15-r1)
(9/128) Installing libuuid (2.37-r0)
(10/128) Installing cryptsetup-libs (2.3.6-r0)
(11/128) Installing kmod-libs (29-r0)
(12/128) Installing mkinitfs (3.5.0-r0)
Executing mkinitfs-3.5.0-r0.post-install
(13/128) Installing libbz2 (1.0.8-r1)
(14/128) Installing perl (5.32.1-r0)
(15/128) Installing libgmpxx (6.2.1-r0)
(16/128) Installing gmp-dev (6.2.1-r0)
(17/128) Installing fts (1.2.7-r1)
(18/128) Installing libelf (0.182-r1)
(19/128) Installing xz-dev (5.2.5-r0)
(20/128) Installing zlib-dev (1.2.11-r3)
(21/128) Installing elfutils-dev (0.182-r1)
(22/128) Installing readline (8.1.0-r0)
(23/128) Installing bash (5.1.4-r0)
Executing bash-5.1.4-r0.post-install
(24/128) Installing m4 (1.4.18-r2)
(25/128) Installing flex (2.6.4-r2)
(26/128) Installing bison (3.7.6-r0)
(27/128) Installing sed (4.8-r0)
...
(116/128) Purging kmod-libs (29-r0)
(117/128) Purging xz-libs (5.2.5-r0)
(118/128) Purging zstd-libs (1.4.9-r1)
(119/128) Purging cryptsetup-libs (2.3.6-r0)
(120/128) Purging libblkid (2.37-r0)
(121/128) Purging argon2-libs (20190702-r1)
(122/128) Purging device-mapper-libs (2.02.187-r1)
(123/128) Purging json-c (0.15-r1)
(124/128) Purging libuuid (2.37-r0)
(125/128) Purging libbz2 (1.0.8-r1)
(126/128) Purging fts (1.2.7-r1)
(127/128) Purging zlib-dev (1.2.11-r3)
(128/128) Purging readline (8.1.0-r0)
Executing busybox-1.33.1-r3.trigger
OK: 233 MiB in 58 packages
>>> linux-lts: Updating the main/x86_64 repository index...
>>> linux-lts: Signing the index...
Build 결과는 ~/packages 디렉토리에 자동으로 생성된다.
$ cd ~/packages/
$ ls -la
total 12
drwxr-sr-x 3 pufbox pufbox 4096 Jan 30 20:09 .
drwxr-sr-x 7 pufbox pufbox 4096 Jan 30 20:09 ..
drwxr-sr-x 3 pufbox pufbox 4096 Jan 30 20:09 main
$ cd main/
$ ls -la
total 12
drwxr-sr-x 3 pufbox pufbox 4096 Jan 30 20:09 .
drwxr-sr-x 3 pufbox pufbox 4096 Jan 30 20:09 ..
drwxr-sr-x 2 pufbox pufbox 4096 Jan 30 20:09 x86_64
$ cd x86_64/
$ ls -la
total 93356
drwxr-sr-x 2 pufbox pufbox 4096 Jan 30 20:09 .
drwxr-sr-x 3 pufbox pufbox 4096 Jan 30 20:09 ..
-rw-r--r-- 1 pufbox pufbox 904 Jan 30 20:09 APKINDEX.tar.gz
-rw-r--r-- 1 pufbox pufbox 74925531 Jan 30 20:09 linux-lts-5.15.24-r0.apk
-rw-r--r-- 1 pufbox pufbox 20655011 Jan 30 20:09 linux-lts-dev-5.15.24-r0.apk
📌 최종 build 결과물은 apk(zip 파일) 파일 형태로 생성된다.
3) Kernel build 하기 2 - 단계별 build 하기
APKBUILD를 사용할 경우 맨 마지막에 cleaup( ) 과정을 거치게 되므로, build를 위해 download한 source code가 자동 삭제되는 문제가 있다. 앞으로 WireGuard source code를 자유롭게 compile하려면 kernel source를 삭제해서는 안된다.
📌 아래 내용 중 linux kernel version이 약간씩 다르게(linux-5.10 or linux-5.15) 기술된 부분이 있는데, 이는 정리한 내용의 시간 차에 기인한 것이므로 양해를 바란다.
<APKBUILD 과정>
sanitycheck() -> clean()-> fetch() -> verify() -> unpack() -> prepare() -> mkusers() -> build() -> check() -> package() -> subpackages() -> language packs -> apk -> cleanup()
지금 부터는 이 방법을 소개해 보고자 한다. 먼저 kernel build가 원할히 진행되기 위해서는 몇가지 apk package를 먼저 설치해야 한다.
<package 설치>
$ sudo apk add perl
$ sudo apk add gmp-dev
$ sudo apk add elfutils-dev
$ sudo apk add bash
$ sudo apk add flex
$ sudo apk add bison
$ sudo apk add sed
$ sudo apk add installkernel
$ sudo apk add bc
$ sudo apk add linux-headers
$ sudo apk add linux-firmware-any
$ sudo apk add openssl-dev
$ sudo apk add diffutils
$ sudo apk add findutils
⇒ APKBUILD 내용 참조
⇒ 이 부분을 생략하면 kernel build가 안되니 반드시 설치하도록 한다.
⇒ abuild -r로 full build를 할 경우에는 마지막 단계에서 설치한 package를 uninstall 한다.
아, 그런데 위의 절차가 매우 번거롭다. 이를 한방에 처리할 수는 없을까 ?
$ abuild deps
⇒ 앞서 한 작업을 대신한다. :)
$ abuild fetch
⇒ source code download하여 /var/cache/distfiles 디렉토리에 위치시킨다.
⇒ 물론 이미 받아두었다면, 다시 받지는 않는다.
>>> linux-lts: Fetching https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.tar.xz
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 111M 100 111M 0 0 10.9M 0 0:00:10 0:00:10 --:--:-- 11.1M
>>> linux-lts: Fetching https://cdn.kernel.org/pub/linux/kernel/v5.x/patch-5.10.61.xz
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1904k 100 1904k 0 0 2450k 0 --:--:-- --:--:-- --:--:-- 2448k
$ abuild verify
⇒ patch file과 kernel config file에 대한 checksum을 verification하는 단계
$ abuild unpack
⇒ /var/cache/distfiles/linux-5.10.tar.xz 파일을 src/ 디렉토리 아래에 푼다.
$ abuild prepare
⇒ kernel patch 적용 후, kernel .config 까지 생성
⇒ build-lts.x86_64/.config
c3d01af6643e:~/workspace/aports/main/linux-lts$ ls -l src/build-lts.x86_64/.config
-rw-r--r-- 1 chyi chyi 224952 Sep 15 05:29 src/build-lts.x86_64/.config
$ abuild build
⇒ kernel build
---------<내부 동작>--------------------------------------------------------------------
abuild build를 하면 내부적으로 대략 아래와 같은 일을 수행한다(실제 menuconfig 단계는 수행하지 않음).
$ cd src/linux-5.10
$ make -C ../build-lts.x86_64 menuconfig
[그림 6.2] linux kernel menuconfig
$ make ARCH=x86_64 CC=gcc KBUILD_BUILD_VERSION=1-Alpine -C ../build-lts.x86_64
⇒ kernel image 생성하기
⇒ (아주 오랜 시간 경과 후) ../src/build-lts.x86_64 디렉토리 아래에 vmlinux 파일이 생성된다.
$ make ARCH=x86_64 CC=gcc KBUILD_BUILD_VERSION=1-Alpine -C /home/chyi/workspace/aports/main/linux-lts/src/build-lts.x86_64 modules
----------------------------------------------------------------------------------------
📌 수동으로 Kernel build하는 방법을 알아둘 필요가 있다. 그래야 새로운 kernel module을 추가하거나, kernel code를 수정할 경우 좀 더 편해질 수 있다.
__________________________________________
<여기서 잠깐>
실제 linux kernel site에서 download한 kernel source code는 어디에 있을까 ? 실제로 우리가 kernel code를 수정한다면 어디에서 하는게 맞을까 ?
$ cd /var/cache/distfiles
$ ls -la
total 115896
drwxrwxr-x 1 root abuild 4096 Sep 15 01:51 .
drwxr-xr-x 1 root root 4096 Sep 6 01:05 ..
-rw-r--r-- 1 chyi chyi 116606704 Sep 6 08:11 linux-5.10.tar.xz
-rw-r--r-- 1 chyi chyi 1950496 Sep 6 08:11 patch-5.10.61.xz
drwxr-xr-x 3 chyi chyi 4096 Sep 9 01:52 src
__________________________________________
$ abuild rootpkg
⇒ Kernel과 kernel module이 포함된 package 생성
$ ls -la pkg/
total 44
drwxr-sr-x 10 chyi chyi 4096 Sep 15 02:46 .
drwxr-sr-x 1 chyi chyi 4096 Sep 15 02:42 ..
drwxr-sr-x 2 chyi chyi 4096 Sep 15 02:48 .control.linux-lts
drwxr-sr-x 2 chyi chyi 4096 Sep 15 02:47 .control.linux-lts-dev
drwxr-sr-x 5 chyi chyi 4096 Sep 15 02:46 linux-lts
drwxr-sr-x 4 chyi chyi 4096 Sep 15 02:43 linux-lts-dev
만일 초기화한 상태에서 처음부터 다시 build를 하고자 한다면, 아래 명령을 수행할 수 있다.
$ abuild clean
⇒ linux-tls/src 디렉토리를 통째로 날린다.
$ abuild cleancache
⇒ /var/cache/disfiles 아래에 download해 두었던 kernel & patch source를 모두 삭제한다.
<참고 사항>
abuild 관련 주요 명령 option을 정리해 보면 다음과 같다.
📌 abuild 알면 알수록 꽤 괜찮은 tool이다. Yocto project의 bitbake와 유사하다고나 할까 ...
c) WireGuard에 Kyber KEM 추가하기
#wg genkey | tee ./privatekey | wg pubkey > ./publickey
sudo rmmod wireguard
sudo insmod avx2/wireguard.ko
sudo ip link add dev wg0 type wireguard
sudo ip address add dev wg0 10.1.1.5/24
sudo ip link set up dev wg0
sudo wg set wg0 listen-port 51820 private-key ./privatekey peer 9MXZLGChppVQ3oEcuQHz+axs6sU4sE9FJCn27jGqVQk= allowed-ips 10.1.1.0/24 endpoint 192.168.1.79:51820
$ sudo wg show
7. References
[1] https://wiki.friendlyelec.com/wiki/index.php/NanoPi_R4S#Install_OS