challenge 1:
welcome_to_11@flare-on.com
challenge 2:Th3_M4tH_Do_b3_mAth1ng@flare-on.com
challenge 3:1RuleADayK33p$Malw4r3Aw4y@flare-on.com
challenge 4:wh0a_it5_4_cru3l_j4va5cr1p7@flare-on.com
challenge 5:supp1y_cha1n_sund4y@flare-on.com
challenge 6:please_send_help_i_am_trapped_in_a_ctf_flag_factory@flare-on.com
filename:
frog.7z
filetype:python source
(and some other files)
estimated time: 1 min
題目敘述
Welcome to Flare-On 11! Download this 7zip package, unzip it with the password 'flare', and read the README.txt file for launching instructions. It is written in PyGame so it may be runnable under many architectures, but also includes a pyinstaller created EXE file for easy execution on Windows.
Your mission is get the frog to the "11" statue, and the game will display the flag. Enter the flag on this page to advance to the next stage. All flags in this event are formatted as email addresses ending with the @flare-on.com domain.
解題思路
這題一看是 Python 寫的, 並且有附原始碼, 直接可以找到 decode flag 的程式碼
def decode_flag(key):
encoded = "\xa5\xb7\xbe\xb1\xbd\xbf\xb7\x8d\xa6\xbd\x8d\xe3\xe3\x92\xb4\xbe\xb3\xa0\xb7\xff\xbd\xbc\xfc\xb1\xbd\xbf"
return ''.join([chr(ord(c) ^ key) for c in encoded])
for i in range(256):
if "@flare-on.com" in decode_flag(i):
print(decode_flag(i))
filename:
checksum.exe
filetype:PE64
estimated time: 3 hours ~ 24 hours
題目敘述
We recently came across a silly executable that appears benign. It just asks us to do some math... From the strings found in the sample, we suspect there are more to the sample than what we are seeing. Please investigate and let us know what you find!
7zip archive password: flare
解題經歷
這是一支 Golang 寫的程式, 因為是不熟的程式語言, 所以我的做法是邊寫 Golang 程式(chatgpt)邊逆寫好的程式, 再去比對題目裡的 pesudo code, 在把 Golang 程式丟進 IDA Pro 之後, 人寫的 code 基本上會排在一起, 且開頭會是 main_*
, 所以這題只要專注分析 main_main
, main_a
及 main_b
逆向工程
main_main
Check sum: %d + %d =
Checksum:
, 後來發現這個值會用來當 chacha20 的加解密參數
main_a
FlareOn2024
cQoFRQErX1YAVw1zVQdFUSxfAQNRBXUNAxBSe15QCVRVJ1pQEwd/WFBUAlElCFBFUnlaB1ULByRdBEFdfVtWVA==
7fd7dd1d0e959f74c133c13abb740b9faa61ab06bd0ecd177645e93b1e3825dd
給出對的 checksum 會用 chacha20 把一塊資料解密出 JPEG 圖片寫入 %userprofile%/AppData/Local/REAL_FLAREON_FLAG.JPG
reference
filename:
aray.yara
filetype:txt
estimated time: 1 hour
Image Not Showing Possible ReasonsLearn More →
- The image was uploaded to a note which you don't have access to
- The note which the image was originally uploaded to has been deleted
題目敘述
And now for something completely different. I'm pretty sure you know how to write Yara rules, but can you reverse them?
解題經歷
逆向 yara rule, 回推出可以被這條規則偵測的 85 bytes 字串, 評估拿 hex editor 手拼花不到一個小時, 就不寫程式了
計算過程
first byte
hash cracking
Line 37: hash.crc32(8, 2) == 0x61089c5c and
Line 43: hash.crc32(34, 2) == 0x5888fc1b and
Line 152: hash.crc32(63, 2) == 0x66715919 and
Line 166: hash.sha256(14, 2) == "403d5f23d149670348b147a15eeb7010914701a7e99aad2e43f90cfa0325c76f" and
Line 232: hash.sha256(56, 2) == "593f2d04aab251f60c9e4b8bbc1e05a34e920980ec08351a18459b2bc7dbf2f6" and
Line 326: hash.md5(0, 2) == "89484b14b36a8d5329426a3d944d2983" and
Line 332: hash.crc32(78, 2) == 0x7cab8d64 and
Line 381: hash.md5(76, 2) == "f98ed07a4d5f50f7de1410d905f1477f" and
Line 457: hash.md5(50, 2) == "657dae0913ee12be6fb2a6f687aae1c7" and
Line 498: hash.md5(32, 2) == "738a656e8e8ec272ca17cd51e12f558b" and
593f2d04aab251f60c9e4b8bbc1e05a34e920980ec08351a18459b2bc7dbf2f6:fl
657dae0913ee12be6fb2a6f687aae1c7:3A
738a656e8e8ec272ca17cd51e12f558b:ul
89484b14b36a8d5329426a3d944d2983:ru
f98ed07a4d5f50f7de1410d905f1477f:io
403d5f23d149670348b147a15eeb7010914701a7e99aad2e43f90cfa0325c76f: s
import zlib
import itertools
def crack_crc(target):
for byte1 in range(256):
for byte2 in range(256):
data = bytes([byte1, byte2])
crc32_value = zlib.crc32(data) & 0xFFFFFFFF
if crc32_value == target:
return data
print(crack_crc(0x61089c5c)) # re
print(crack_crc(0x5888fc1b)) # eA
print(crack_crc(0x66715919)) # n.
print(crack_crc(0x7cab8d64)) # n:
simple math
Line 8: filesize == 85 and
Line 10: uint8(58) + 25 == 122 and
Line 15: uint32(52) ^ 425706662 == 1495724241 and
Line 29: uint32(17) - 323157430 == 1412131772 and
Line 37: uint8(36) + 4 == 72 and
Line 56: uint8(27) ^ 21 == 40 and
Line 78: uint32(59) ^ 512952669 == 1908304943 and
Line 91: uint8(65) - 29 == 70 and
Line 108: uint8(45) ^ 9 == 104 and
Line 140: uint32(28) - 419186860 == 959764852 and
Line 141: uint8(74) + 11 == 116 and
Line 244: uint8(75) - 30 == 86 and
Line 249: uint32(66) ^ 310886682 == 849718389 and
Line 251: uint32(10) + 383041523 == 2448764514 and
Line 280: uint32(37) + 367943707 == 1228527996 and
Line 286: uint32(22) ^ 372102464 == 1879700858 and
Line 313: uint8(2) + 11 == 119 and
Line 322: uint32(46) - 412326611 == 1503714457 and
Line 355: uint8(7) - 15 == 82 and
Line 358: uint32(70) + 349203301 == 2034162376 and
Line 390: uint32(80) - 473886976 == 69677856 and
Line 411: uint32(3) ^ 298697263 == 2108416586 and
Line 412: uint8(21) - 21 == 94 and
Line 417: uint8(16) ^ 7 == 115 and
Line 437: uint32(41) + 404880684 == 1699114335 and
Line 458: uint8(26) - 7 == 25 and
Line 510: uint8(84) + 3 == 128 and
結果
rule flareon { strings: $f = "1RuleADayK33p$Malw4r3Aw4y@flare-on.com" condition: $f }
filename:
mememaker3000.html
filetype:javascript
estimated time: 1~2 hour
題目敘述
You've made it very far, I'm proud of you even if noone else is. You've earned yourself a break with some nice HTML and JavaScript before we get into challenges that may require you to be very good at computers.
解題經歷
html 裡包含一個經過混淆的 javascript, 解的時候是用 vscode + 瀏覽器 Console 硬幹, 發現跳 flag 邏輯就在 a0k 裡, 事後看官方解答發現有工具 Obfuscator.io Deobfuscator
逆向工程
a0k - get flag
function a0k() {
const a = a0g['alt']['split']('/')['pop']();
if (a !== Object['keys'](meme_image)[0x5]) return; // a should be boy_friend0.jpg
const b = a0l['textContent'], // should be "FLARE On"
c = a0m['textContent'], // should be "Security Expert"
d = a0n['textContent']; // should be "Malware"
if (a0c['indexOf'](b) == 0xe && a0c['indexOf'](c) == a0c['length'] - 0x1 && a0c['indexOf'](d) == 0x16) {
var e = new Date()['getTime']();
while (new Date()['getTime']() < e + 0xbb8) {}
var f = d[0x3] + 'h' + a[0xa] + b[0x2] + a[0x3] + c[0x5] + c[c['length'] - 0x1] + '5' + a[0x3] + '4' + a[0x3] + c[0x2] + c[0x4] + c[0x3] + '3' + d[0x2] + a[0x3] + 'j4' + a0c[0x1][0x2] + d[0x4] + '5' + c[0x2] + d[0x5] + '1' + c[0xb] + '7' + a0c[0x15][0x1] + b[a0b(0x15e39) + 'e']('\x20', '-') + a[0xb] + a0c[0x4][a0b(0x9a82) + a0b(0x1656b)](0xc, 0xf);
f = f['toLowerCase'](), alert(atob('Q29uZ3JhdHVsYXRpb25zISBIZXJlIHlvdSBnbzog') + f);
}
}
boy_friend0.jpg
結果
const a = 'boy_friend0.jpg',
b = 'FLARE On',
c = 'Security Expert',
d = 'Malware';
var f = d[0x3] + 'h' + a[0xa] + b[0x2] + a[0x3] + c[0x5] + c[c['length'] - 0x1] + '5' + a[0x3] + '4' + a[0x3] + c[0x2] + c[0x4] + c[0x3] + '3' + d[0x2] + a[0x3] + 'j4' + a0c[0x1][0x2] + d[0x4] + '5' + c[0x2] + d[0x5] + '1' + c[0xb] + '7' + a0c[0x15][0x1] + b[a0b(0x15e39) + 'e']('\x20', '-') + a[0xb] + a0c[0x4][a0b(0x9a82) + a0b(0x1656b)](0xc, 0xf);
f = f['toLowerCase'](), alert(atob('Q29uZ3JhdHVsYXRpb25zISBIZXJlIHlvdSBnbzog') + f);
tool
filename:
ssh_container.tar
filetype:docker image
estimated time: ??
real time: 8 days
題目敘述
Our server in the FLARE Intergalactic HQ has crashed! Now criminals are trying to sell me my own data!!! Do your part, random internet hacker, to help FLARE out and tell us what data they stole! We used the best forensic preservation technique of just copying all the files on the system for you.
解題經歷
這題給了一個 docker container dump, 一開始找分析目標 (coredump) 就花了不少時間, 打開 coredump 看了一下, 發現問題是出在 /lib/x86_64-linux-gnu/liblzma.so.5
這個函式庫, 這個函式庫經過篡改(重裝了一個一樣版本的 docker 及 sshd, 比對檔案 hash), 分析 coredump 中指出這個函式庫的問題點, 發現這裡包含一個解密 shellcode -> 執行shellcode -> 加密 shellcode 的邏輯, 以 coredump 中殘留的 chacha20 key 跟 nonce 解出 shellcode, shellcode 裡面執行了回報中繼站、讀檔、加密等行為, 加密也是用 chacha20, 但有偷改加密參數 expand 32-byte K
(原標準 chacha20 是 expand 32-byte k
), 花了兩天的時間才發現==
import docker image
docker import .\ssh_container.tar
docker run -it ssh_container:latest bash
docker run --init --ulimit core=-1 --security-opt seccomp=unconfined -it ssh_container:latest bash
lastb
root@3bb39ed25370:~# lastb
remnux ssh:notty 172.17.0.1 Tue Jul 30 22:08 - 22:08 (00:00)
remnux ssh:notty 172.17.0.1 Tue Jul 30 22:08 - 22:08 (00:00)
btmp begins Tue Jul 30 22:08:53 2024
added user
apt log
cat var/log/apt/history.log | grep 'Start-Date:'
Start-Date: 2024-07-30 21:23:22
Commandline: apt-get install openssh-server
--
Start-Date: 2024-07-30 22:22:39
Commandline: apt-get install build-essential
--
Start-Date: 2024-07-30 22:36:08
Commandline: apt-get install ltrace
--
Start-Date: 2024-07-31 19:14:55
Commandline: apt-get install vim
--
Start-Date: 2024-07-31 22:18:10
Commandline: apt-get install iputils-ping
--
Start-Date: 2024-09-09 21:21:50
Commandline: apt-get install gdb
search by timeline
find / -type f -newermt "2024-09-09 21:00" ! -newermt "2024-09-09 21:55" | grep -v 'mime'
...
/var/lib/systemd/coredump/sshd.core.93794.0.0.11.1725917676
...
something weird
same version sshd OpenSSH_9.2p1 Debian-2+deb12u3, OpenSSL 3.0.14 4 Jun 2024
with different hash
$ cmp -l sshd/usr/sbin/sshd baseline/sshd | awk '{printf "%08X %02X %02X\n", $1, strtonum(0$2), strtonum(0$3)}'
0005AF71 C3 41
000C33F1 C3 53
different library hash
lz version in victim
root@b74702cbbdeb:/# xz --version
xz (XZ Utils) 5.4.1
liblzma 5.6.2
sshd config - victim has added one line
...
UsePrivilegeSeparation no
sshd source
gdb
gdb /usr/sbin/sshd /var/lib/systemd/coredump/sshd.core.93794.0.0.11.1725917676
gdb with debuginfo
apt install debuginfod
export DEBUGINFOD_URLS="https://debuginfod.debian.net/"
backtrace
(gdb) backtrace
#0 0x0000000000000000 in ?? ()
#1 0x00007f4a18c8f88f in ?? () from /lib/x86_64-linux-gnu/liblzma.so.5
#2 0x000055b46c7867c0 in ?? ()
#3 0x000055b46c73f9d7 in ?? ()
#4 0x000055b46c73ff80 in ?? ()
#5 0x000055b46c71376b in ?? ()
#6 0x000055b46c715f36 in ?? ()
#7 0x000055b46c7199e0 in ?? ()
#8 0x000055b46c6ec10c in ?? ()
#9 0x00007f4a18e5824a in __libc_start_call_main (main=main@entry=0x55b46c6e7d50, argc=argc@entry=4, argv=argv@entry=0x7ffcc6602eb8)
at ../sysdeps/nptl/libc_start_call_main.h:58
#10 0x00007f4a18e58305 in __libc_start_main_impl (main=0x55b46c6e7d50, argc=4, argv=0x7ffcc6602eb8, init=<optimized out>, fini=<optimized out>,
rtld_fini=<optimized out>, stack_end=0x7ffcc6602ea8) at ../csu/libc-start.c:360
#11 0x000055b46c6ec621 in ?? ()
after loading symbols
(gdb) backtrace
#0 0x0000000000000000 in ?? ()
#1 0x00007f4a18c8f88f in ?? () from /lib/x86_64-linux-gnu/liblzma.so.5
#2 0x000055b46c7867c0 in openssh_RSA_verify (rsa=0x55b46d58e080, siglen=<optimized out>, sigbuf=<optimized out>, hashlen=<optimized out>,
hash=0x7ffcc6602020 "\317\301\b\021F\016\3367\250\223j\342\345\303~\356O\"\370,\032=Y%r\247\311\324n\263z\303\037\225\342\0335\375}\360\242\200&,\254(\271\354\252n\200\300\245\326:u{&K{?+NlP\316Xm\264U", hash_alg=4) at ../../ssh-rsa.c:660
#3 ssh_rsa_verify (key=<optimized out>, sig=<optimized out>, siglen=<optimized out>, data=<optimized out>, dlen=<optimized out>, alg=<optimized out>, compat=0,
detailsp=0x0) at ../../ssh-rsa.c:552
#4 0x000055b46c73f9d7 in cert_parse (certbuf=0x55b46d58c300, key=0x55b46d58c350, b=0x55b46d58c230) at ../../sshkey.c:1867
#5 sshkey_from_blob_internal (b=0x55b46d58c230, keyp=keyp@entry=0x7ffcc66021b8, allow_cert=allow_cert@entry=1) at ../../sshkey.c:1942
#6 0x000055b46c73ff80 in sshkey_froms (buf=buf@entry=0x55b46d58c1e0, keyp=keyp@entry=0x7ffcc66021b8) at ../../sshkey.c:1988
#7 0x000055b46c71376b in mm_answer_keyallowed (ssh=0x55b46d57a100, sock=5, m=0x55b46d58c1e0) at ../../monitor.c:1206
#8 0x000055b46c715f36 in monitor_read (ssh=ssh@entry=0x55b46d57a100, pmonitor=pmonitor@entry=0x55b46d56ecb0, ent=0x55b46c80d320 <mon_dispatch_proto20+224>,
pent=pent@entry=0x7ffcc66022b0) at ../../monitor.c:535
#9 0x000055b46c7199e0 in monitor_child_preauth (ssh=ssh@entry=0x55b46d57a100, pmonitor=0x55b46d56ecb0) at ../../monitor.c:316
#10 0x000055b46c6ec10c in privsep_preauth (ssh=0x55b46d57a100) at ../../sshd.c:519
#11 main (ac=<optimized out>, av=<optimized out>) at ../../sshd.c:2336
proc mappings
(gdb) info proc mappings
Mapped address spaces:
Start Addr End Addr Size Offset objfile
0x55b46c6d9000 0x55b46c6e6000 0xd000 0x0 /usr/sbin/sshd
0x55b46c6e6000 0x55b46c7b4000 0xce000 0xd000 /usr/sbin/sshd
0x55b46c7b4000 0x55b46c809000 0x55000 0xdb000 /usr/sbin/sshd
0x55b46c809000 0x55b46c80d000 0x4000 0x12f000 /usr/sbin/sshd
0x55b46c80d000 0x55b46c80e000 0x1000 0x133000 /usr/sbin/sshd
0x7f4a188a2000 0x7f4a188a3000 0x1000 0x0 /usr/lib/x86_64-linux-gnu/security/pam_env.so
0x7f4a188a3000 0x7f4a188a5000 0x2000 0x1000 /usr/lib/x86_64-linux-gnu/security/pam_env.so
0x7f4a188a5000 0x7f4a188a6000 0x1000 0x3000 /usr/lib/x86_64-linux-gnu/security/pam_env.so
0x7f4a188a6000 0x7f4a188a7000 0x1000 0x3000 /usr/lib/x86_64-linux-gnu/security/pam_env.so
0x7f4a188a7000 0x7f4a188a8000 0x1000 0x4000 /usr/lib/x86_64-linux-gnu/security/pam_env.so
0x7f4a188a8000 0x7f4a188aa000 0x2000 0x0 /usr/lib/x86_64-linux-gnu/security/pam_limits.so
0x7f4a188aa000 0x7f4a188ad000 0x3000 0x2000 /usr/lib/x86_64-linux-gnu/security/pam_limits.so
0x7f4a188ad000 0x7f4a188ae000 0x1000 0x5000 /usr/lib/x86_64-linux-gnu/security/pam_limits.so
0x7f4a188ae000 0x7f4a188af000 0x1000 0x6000 /usr/lib/x86_64-linux-gnu/security/pam_limits.so
0x7f4a188af000 0x7f4a188b0000 0x1000 0x7000 /usr/lib/x86_64-linux-gnu/security/pam_limits.so
0x7f4a188b0000 0x7f4a188b1000 0x1000 0x0 /usr/lib/x86_64-linux-gnu/security/pam_mail.so
0x7f4a188b1000 0x7f4a188b2000 0x1000 0x1000 /usr/lib/x86_64-linux-gnu/security/pam_mail.so
0x7f4a188b2000 0x7f4a188b3000 0x1000 0x2000 /usr/lib/x86_64-linux-gnu/security/pam_mail.so
0x7f4a188b3000 0x7f4a188b4000 0x1000 0x2000 /usr/lib/x86_64-linux-gnu/security/pam_mail.so
0x7f4a188b4000 0x7f4a188b5000 0x1000 0x3000 /usr/lib/x86_64-linux-gnu/security/pam_mail.so
0x7f4a188b5000 0x7f4a188c5000 0x10000 0x0 /usr/lib/x86_64-linux-gnu/libm.so.6
0x7f4a188c5000 0x7f4a18938000 0x73000 0x10000 /usr/lib/x86_64-linux-gnu/libm.so.6
0x7f4a18938000 0x7f4a18992000 0x5a000 0x83000 /usr/lib/x86_64-linux-gnu/libm.so.6
0x7f4a18992000 0x7f4a18993000 0x1000 0xdc000 /usr/lib/x86_64-linux-gnu/libm.so.6
0x7f4a18993000 0x7f4a18994000 0x1000 0xdd000 /usr/lib/x86_64-linux-gnu/libm.so.6
...
0x7f4a18c86000 0x7f4a18c8a000 0x4000 0x0 / (deleted)
0x7f4a18c8a000 0x7f4a18ca9000 0x1f000 0x4000 / (deleted)
0x7f4a18ca9000 0x7f4a18cb7000 0xe000 0x23000 / (deleted)
0x7f4a18cb7000 0x7f4a18cb8000 0x1000 0x30000 / (deleted)
0x7f4a18cb8000 0x7f4a18cb9000 0x1000 0x31000 / (deleted)
...
registers
(gdb) info registers
rax 0x0 0
rbx 0x1 1
rcx 0x55b46d58e080 94233417015424
rdx 0x55b46d58eb20 94233417018144
rsi 0x55b46d51dde0 94233416556000
rdi 0x200 512
rbp 0x55b46d51dde0 0x55b46d51dde0
rsp 0x7ffcc6601e98 0x7ffcc6601e98
r8 0x1 1
r9 0x7ffcc6601e10 140723636674064
r10 0x1e 30
r11 0x7d63ee63 2103701091
r12 0x200 512
r13 0x55b46d58eb20 94233417018144
r14 0x55b46d58e080 94233417015424
r15 0x7ffcc6601ec0 140723636674240
rip 0x0 0x0
eflags 0x10206 [ PF IF RF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
rsp
(gdb) x/16xg $rsp
0x7ffcc6601e98: 0x00007f4a18c8f88f 0x000055b46d58df60
0x7ffcc6601ea8: 0x00007f4a188a1000 0x000055b46d51dde4
0x7ffcc6601eb8: 0x000055b46d51de04 0x7cd703ae8b2ff828
0x7ffcc6601ec8: 0x67711ce280e2582c 0x0be691bcde9b3c23
0x7ffcc6601ed8: 0x034c0c188bde1fac 0xe479508bfe7ad8d6
0x7ffcc6601ee8: 0x2331758100073bf5 0x505e2d16722f862c
0x7ffcc6601ef8: 0x291ce37558aa8b9f 0x0000000000000016
0x7ffcc6601f08: 0xe21318a838f63d94 0xbaa0f907a51863de
frame 1
#1 0x00007f4a18c8f88f in ?? () from /lib/x86_64-linux-gnu/liblzma.so.5
...
(gdb) print $edi
$2 = 512
(gdb) print *(RSA *)$rcx
$1 = {dummy_zero = 0, libctx = 0x0, version = 0, meth = 0x7f4a194b4260 <rsa_pkcs1_ossl_meth>, engine = 0x0, n = 0x55b46d58e1f0, e = 0x55b46d58e1b0, d = 0x0, p = 0x0,
q = 0x0, dmp1 = 0x0, dmq1 = 0x0, iqmp = 0x0, pss_params = {hash_algorithm_nid = 0, mask_gen = {algorithm_nid = 0, hash_algorithm_nid = 0}, salt_len = 0,
trailer_field = 0}, pss = 0x0, prime_infos = 0x0, ex_data = {ctx = 0x0, sk = 0x0}, references = 1, flags = 6, _method_mod_n = 0x0, _method_mod_p = 0x0,
_method_mod_q = 0x0, blinding = 0x0, mt_blinding = 0x0, lock = 0x55b46d58e170, dirty_cnt = 1}
frame 2
#2 0x000055b46c7867c0 in openssh_RSA_verify (rsa=0x55b46d58e080, siglen=<optimized out>, sigbuf=<optimized out>,
hashlen=<optimized out>,
hash=0x7ffcc6602020 "\317\301\b\021F\016\3367\250\223j\342\345\303~\356O\"\370,\032=Y%r\247\311\324n\263z\303\037\225\342\0335\375}\360\242\200&,\254(\271\354\252n\200\300\245\326:u{&K{?+NlP\316Xm\264U", hash_alg=4)
at ../../ssh-rsa.c:660
...
#define SSH_DIGEST_SHA512 4
sha512: cfc10811460ede37a8936ae2e5c37eee4f22f82c1a3d592572a7c9d46eb37ac31f95e21b35fd7df0a280262cac28b9ecaa6e80c0a5d63a757b264b7b3f2b4e6c
decrypt
94 3D F6 38 A8 18 13 E2 DE 63 18 A5 07 F9 A0 BA 2D BB 8A 7B A6 36 66 D0 8D 11 A6 5E C9 14 D6 6F
F2 36 83 9F 4D CD 71 1A 52 86 29 55
decrypted result
11c5a6eda8ffbcda6d618564e2938a4a
/root/certificate_authority_signing_key.txt
decrypt
A9 F6 34 08 42 2A 9E 1C 0C 03 A8 08 94 70 BB 8D AA DC 6D 7B 24 FF 7F 24 7C DA 83 9E 92 F7 07 1D 02 63 90 2E C1 58
8D EC 91 12 EB 76 0E DA 7C 7D 87 A4 43 27 1C 35 D9 E0 CB 87 89 93 B4 D9 04 AE F9 34 FA 21 66 D7
11 11 11 11 11 11 11 11 11 11 11 11
TODO - failed
key point
from binascii import hexlify
import struct
chacha20_constants = [0x61707865, 0x3320646e, 0x79622d32, 0x6b206574] # "expand 32-byte k"
chacha20_constants1 = [0x61707865, 0x3320646e, 0x79622d32, 0x4b206574] # "expand 32-byte K"
# Rotates the bits of the number x left by n positions
def rotate_left(x, n):
return ((x << n) & 0xFFFFFFFF) | (x >> (32 - n))
# ChaCha20 quarter round function
def quarter_round(state, a, b, c, d):
state[a] = (state[a] + state[b]) & 0xFFFFFFFF
state[d] ^= state[a]
state[d] = rotate_left(state[d], 16)
state[c] = (state[c] + state[d]) & 0xFFFFFFFF
state[b] ^= state[c]
state[b] = rotate_left(state[b], 12)
state[a] = (state[a] + state[b]) & 0xFFFFFFFF
state[d] ^= state[a]
state[d] = rotate_left(state[d], 8)
state[c] = (state[c] + state[d]) & 0xFFFFFFFF
state[b] ^= state[c]
state[b] = rotate_left(state[b], 7)
# ChaCha20 block function
def chacha20_block1(key, counter, nonce):
# Constants
constants = chacha20_constants1
# Initialize the state
state = constants + list(struct.unpack('<8L', key)) + [counter] + list(struct.unpack('<3L', nonce))
# Copy the state for use in the final addition step
working_state = state[:]
# Perform 20 rounds (10 iterations of the double round)
for _ in range(10):
# Odd round
quarter_round(working_state, 0, 4, 8, 12)
quarter_round(working_state, 1, 5, 9, 13)
quarter_round(working_state, 2, 6, 10, 14)
quarter_round(working_state, 3, 7, 11, 15)
# Even round
quarter_round(working_state, 0, 5, 10, 15)
quarter_round(working_state, 1, 6, 11, 12)
quarter_round(working_state, 2, 7, 8, 13)
quarter_round(working_state, 3, 4, 9, 14)
# Add the original state to the working state
output_state = [(working_state[i] + state[i]) & 0xFFFFFFFF for i in range(16)]
# Convert the state to bytes
return struct.pack('<16L', *output_state)
def chacha20_block2(key, counter, nonce):
# Constants
constants = chacha20_constants1
#constants = [0x65787061, 0x6e642033, 0x322d6279, 0x7465206b]
# Initialize the state
state = constants + list(struct.unpack('<8L', key)) + [counter] + list(struct.unpack('<3L', nonce))
# Copy the state for use in the final addition step
working_state = state[:]
# Perform 20 rounds (10 iterations of the double round)
for _ in range(10):
# Odd round
# First quarter round (0, 4, 8, 12)
working_state[0] = (working_state[0] + working_state[4]) & 0xFFFFFFFF
working_state[12] ^= working_state[0]
working_state[12] = rotate_left(working_state[12], 16)
working_state[8] = (working_state[8] + working_state[12]) & 0xFFFFFFFF
working_state[4] ^= working_state[8]
working_state[4] = rotate_left(working_state[4], 12)
working_state[0] = (working_state[0] + working_state[4]) & 0xFFFFFFFF
working_state[12] ^= working_state[0]
working_state[12] = rotate_left(working_state[12], 8)
working_state[8] = (working_state[8] + working_state[12]) & 0xFFFFFFFF
working_state[4] ^= working_state[8]
working_state[4] = rotate_left(working_state[4], 7)
# Second quarter round (1, 5, 9, 13)
working_state[1] = (working_state[1] + working_state[5]) & 0xFFFFFFFF
working_state[13] ^= working_state[1]
working_state[13] = rotate_left(working_state[13], 16)
working_state[9] = (working_state[9] + working_state[13]) & 0xFFFFFFFF
working_state[5] ^= working_state[9]
working_state[5] = rotate_left(working_state[5], 12)
working_state[1] = (working_state[1] + working_state[5]) & 0xFFFFFFFF
working_state[13] ^= working_state[1]
working_state[13] = rotate_left(working_state[13], 8)
working_state[9] = (working_state[9] + working_state[13]) & 0xFFFFFFFF
working_state[5] ^= working_state[9]
working_state[5] = rotate_left(working_state[5], 7)
# Third quarter round (2, 6, 10, 14)
working_state[2] = (working_state[2] + working_state[6]) & 0xFFFFFFFF
working_state[14] ^= working_state[2]
working_state[14] = rotate_left(working_state[14], 16)
working_state[10] = (working_state[10] + working_state[14]) & 0xFFFFFFFF
working_state[6] ^= working_state[10]
working_state[6] = rotate_left(working_state[6], 12)
working_state[2] = (working_state[2] + working_state[6]) & 0xFFFFFFFF
working_state[14] ^= working_state[2]
working_state[14] = rotate_left(working_state[14], 8)
working_state[10] = (working_state[10] + working_state[14]) & 0xFFFFFFFF
working_state[6] ^= working_state[10]
working_state[6] = rotate_left(working_state[6], 7)
# Fourth quarter round (3, 7, 11, 15)
working_state[3] = (working_state[3] + working_state[7]) & 0xFFFFFFFF
working_state[15] ^= working_state[3]
working_state[15] = rotate_left(working_state[15], 16)
working_state[11] = (working_state[11] + working_state[15]) & 0xFFFFFFFF
working_state[7] ^= working_state[11]
working_state[7] = rotate_left(working_state[7], 12)
working_state[3] = (working_state[3] + working_state[7]) & 0xFFFFFFFF
working_state[15] ^= working_state[3]
working_state[15] = rotate_left(working_state[15], 8)
working_state[11] = (working_state[11] + working_state[15]) & 0xFFFFFFFF
working_state[7] ^= working_state[11]
working_state[7] = rotate_left(working_state[7], 7)
# Even round
# First quarter round (0, 5, 10, 15)
working_state[0] = (working_state[0] + working_state[5]) & 0xFFFFFFFF
working_state[15] ^= working_state[0]
working_state[15] = rotate_left(working_state[15], 16)
working_state[10] = (working_state[10] + working_state[15]) & 0xFFFFFFFF
working_state[5] ^= working_state[10]
working_state[5] = rotate_left(working_state[5], 12)
working_state[0] = (working_state[0] + working_state[5]) & 0xFFFFFFFF
working_state[15] ^= working_state[0]
working_state[15] = rotate_left(working_state[15], 8)
working_state[10] = (working_state[10] + working_state[15]) & 0xFFFFFFFF
working_state[5] ^= working_state[10]
working_state[5] = rotate_left(working_state[5], 7)
# Second quarter round (1, 6, 11, 12)
working_state[1] = (working_state[1] + working_state[6]) & 0xFFFFFFFF
working_state[12] ^= working_state[1]
working_state[12] = rotate_left(working_state[12], 16)
working_state[11] = (working_state[11] + working_state[12]) & 0xFFFFFFFF
working_state[6] ^= working_state[11]
working_state[6] = rotate_left(working_state[6], 12)
working_state[1] = (working_state[1] + working_state[6]) & 0xFFFFFFFF
working_state[12] ^= working_state[1]
working_state[12] = rotate_left(working_state[12], 8)
working_state[11] = (working_state[11] + working_state[12]) & 0xFFFFFFFF
working_state[6] ^= working_state[11]
working_state[6] = rotate_left(working_state[6], 7)
# Third quarter round (2, 7, 8, 13)
working_state[2] = (working_state[2] + working_state[7]) & 0xFFFFFFFF
working_state[13] ^= working_state[2]
working_state[13] = rotate_left(working_state[13], 16)
working_state[8] = (working_state[8] + working_state[13]) & 0xFFFFFFFF
working_state[7] ^= working_state[8]
working_state[7] = rotate_left(working_state[7], 12)
working_state[2] = (working_state[2] + working_state[7]) & 0xFFFFFFFF
working_state[13] ^= working_state[2]
working_state[13] = rotate_left(working_state[13], 8)
working_state[8] = (working_state[8] + working_state[13]) & 0xFFFFFFFF
working_state[7] ^= working_state[8]
working_state[7] = rotate_left(working_state[7], 7)
# Fourth quarter round (3, 4, 9, 14)
working_state[3] = (working_state[3] + working_state[4]) & 0xFFFFFFFF
working_state[14] ^= working_state[3]
working_state[14] = rotate_left(working_state[14], 16)
working_state[9] = (working_state[9] + working_state[14]) & 0xFFFFFFFF
working_state[4] ^= working_state[9]
working_state[4] = rotate_left(working_state[4], 12)
working_state[3] = (working_state[3] + working_state[4]) & 0xFFFFFFFF
working_state[14] ^= working_state[3]
working_state[14] = rotate_left(working_state[14], 8)
working_state[9] = (working_state[9] + working_state[14]) & 0xFFFFFFFF
working_state[4] ^= working_state[9]
working_state[4] = rotate_left(working_state[4], 7)
# Add the original state to the working state
output_state = [(working_state[i] + state[i]) & 0xFFFFFFFF for i in range(16)]
# Convert the state to bytes
return struct.pack('<16L', *output_state)
# ChaCha20 encryption function
def chacha20_encrypt1(key, counter, nonce, plaintext):
key_stream = bytearray()
ciphertext = bytearray()
# Split plaintext into 64-byte blocks
for i in range(0, len(plaintext), 64):
block = plaintext[i:i + 64]
key_stream_block = chacha20_block1(key, counter, nonce)
# XOR the key stream with the plaintext
for j in range(len(block)):
ciphertext.append(block[j] ^ key_stream_block[j])
# Increment the counter
counter += 1
return ciphertext
# ChaCha20 encryption function
def chacha20_encrypt2(key, counter, nonce, plaintext):
key_stream = bytearray()
ciphertext = bytearray()
# Split plaintext into 64-byte blocks
for i in range(0, len(plaintext), 64):
block = plaintext[i:i + 64]
key_stream_block = chacha20_block2(key, counter, nonce)
# XOR the key stream with the plaintext
for j in range(len(block)):
ciphertext.append(block[j] ^ key_stream_block[j])
# Increment the counter
counter += 1
return ciphertext
# Example key and nonce
key = bytes.fromhex('8DEC9112EB760EDA7C7D87A443271C35D9E0CB878993B4D904AEF934FA2166D7')
nonce = bytes.fromhex('111111111111111111111111')
counter = 0
# Example plaintext
plaintext = b"\xA9\xF6\x34\x08\x42\x2A\x9E\x1C\x0C\x03\xA8\x08\x94\x70\xBB\x8D\xAA\xDC\x6D\x7B\x24\xFF\x7F\x24\x7C\xDA\x83\x9E\x92\xF7\x07\x1D\x02\x63\x90\x2E\xC1\x58"
ciphertext1 = chacha20_encrypt1(key, counter, nonce, plaintext)
print(ciphertext1)
ciphertext2 = chacha20_encrypt2(key, counter, nonce, plaintext)
print(ciphertext2)
filename:
bloke2
filetype:verilog source codes
estimated time: 3 min
real time: 3 day
題目敘述
You've been so helpful lately, and that was very good work you did. Yes, I'm going to put it right here, on the refrigerator, very good job indeed. You're the perfect person to help me with another issue that come up. One of our lab researchers has mysteriously disappeared. He was working on the prototype for a hashing IP block that worked very much like, but not identically to, the common Blake2 hash family. Last we heard from him, he was working on the testbenches for the unit. One of his labmates swears she knew of a secret message that could be extracted with the testbenches, but she couldn't quite recall how to trigger it. Maybe you could help?
解題經歷
這題是一個 Verilog 專案, 稍微看了一下程式碼, 發現裡面有一些有趣的參數跟 blake2 雜湊演算法有關, 執行之後發現雜湊結果跟正常的結果差蠻多的, 而且只能 hash 63/127 bytes 的 message, 再長結果就會一樣, 就在想是不是要跟上一題一樣找出與標準實作的差異, 猜劇本是可碰撞或可逆, 也花了好幾天幾乎快實作出一個變形的 blake2 hash, 在比對之後發現這支 Verilog 專案實作的 blake2 核心功能大部分都一樣, 雖然沒有做得很標準, 但應該沒有碰撞或可逆的空間, 就仔細回去看題目, 才發現只要修改專案, 把 TEST_VAL 那邊註解掉直接跑 testbench 就可以了(了解題目想幹麼也是非常的重要!)
線索
clue 1
clue 2
clue 3 XOR operation
Background
background
sha2 initial hash value
.IV(512'h6A09E667F3BCC908BB67AE8584CAA73B3C6EF372FE94F82BA54FF53A5F1D36F1510E527FADE682D19B05688C2B3E6C1F1F83D9ABFB41BD6B5BE0CD19137E2179)
.IV(256'h6a09e667bb67ae853c6ef372a54ff53a510e527f9b05688c1f83d9ab5be0cd19)
run the code
sudo apt update
sudo apt install iverilog
make
make tests
test make tests
(modify %s
to %x
in $display("Received message: %x", message);
)
iverilog -g2012 -o f_sched.test.out f_sched.v f_sched_tb.v
vvp f_sched.test.out
iverilog -g2012 -o bloke2b.test.out bloke2.v f_sched.v f_unit.v g_over_2.v g.v g_unit.v data_mgr.v bloke2s.v bloke2b.v bloke2b_tb.v
vvp bloke2b.test.out
Received message: 37d68109da41fb2695333737ecd653b9f1339ef00cacd9e4329baad32645e67d273cd7f5e2597c4eecc43a279bd49fc5ca2cd98baee8099136904105e6e64336
Received message: 18bd715d0f0f16167938ccc242a0e179a3fb233e5b8be47169dc8a775267fd10923abd92ce30b7e2a0da1a0fb724450ecb05978d77e8354355e6e04d2dcfc0d7
Received message: 30d2cf2b11287333b4bc19f4d0db88169fb32770c9a3db24967667c81e78a8d39cefbe43b15fd56a6595fa89869fde30febb1533796dea268a6841b18393f351
iverilog -g2012 -o bloke2s.test.out bloke2.v f_sched.v f_unit.v g_over_2.v g.v g_unit.v data_mgr.v bloke2s.v bloke2b.v bloke2s_tb.v
vvp bloke2s.test.out
Received message: 0000000000000000000000000000000000000000000000000000000000000000c1f4134633d0c0708c8db5d9a8fa708d7b33784de22503c1c8e83d57abc2ec20
Received message: 00000000000000000000000000000000000000000000000000000000000000006ea2fe2803fb1e09f90005da46b472aa63e193c4406c75f09773c266460e7672
Received message: 00000000000000000000000000000000000000000000000000000000000000000c9d03a40f610224cd61e362a2ae7dacacb85cc548acbc4f3f77aa603fceb562
rm f_sched.test.out bloke2s.test.out bloke2b.test.out
something interesting
# bloke2s_tb.v
hash_message("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); // len=62
hash_message("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); // len=63
hash_message("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); // len=64
Received message: 0000000000000000000000000000000000000000000000000000000000000000dd13dcd91301072a3981052845185456fdca2fcc6a3f3b87e5977395e6beee9b
Received message: 000000000000000000000000000000000000000000000000000000000000000060dcc93bdd129fcba8873f2b9977f9ed6d687246bc70cb90ee2b85d882666d75
Received message: 000000000000000000000000000000000000000000000000000000000000000060dcc93bdd129fcba8873f2b9977f9ed6d687246bc70cb90ee2b85d882666d75
# bloke2b_tb.v
hash_message("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); // len=126
hash_message("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); // len=127
hash_message("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); // len=128
Received message: 6c960dc172b83dcbced592dae94c9095667d3622c04f545258c5a20eb98561d1dc33a17ef423ff35b85820b4c819352255199aaf390255398fda72ac1750621b
Received message: 83c991ffc30674512bb27f5e52a1c7e413254addf6280c1faa805f601976c1be8421b561e961b182a19b269a3c2270ae14f2ef4c9aaab34e7433715a95d0aa57
Received message: 83c991ffc30674512bb27f5e52a1c7e413254addf6280c1faa805f601976c1be8421b561e961b182a19b269a3c2270ae14f2ef4c9aaab34e7433715a95d0aa57
# reference: https://github.com/buggywhip/blake2_py/blob/master/blake2.py
import struct, binascii, copy
from ctypes import *
DBUG2 = False # True False
MASK8BITS = 0xff
MASK16BITS = 0xffff
MASK32BITS = 0xffffffff
MASK48BITS = 0xffffffffffff
MASK64BITS = 0xffffffffffffffff
#---------------------------------------------------------------
class BLAKE2(object):
""" BLAKE2 is a base class for BLAKE2b and BLAKE2s """
sigma = [
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 ],
[ 14,10, 4, 8, 9,15,13, 6, 1,12, 0, 2,11, 7, 5, 3 ],
[ 11, 8,12, 0, 5, 2,15,13,10,14, 3, 6, 7, 1, 9, 4 ],
[ 7, 9, 3, 1,13,12,11,14, 2, 6, 5,10, 4, 0,15, 8 ],
[ 9, 0, 5, 7, 2, 4,10,15,14, 1,11,12, 6, 8, 3,13 ],
[ 2,12, 6,10, 0,11, 8, 3, 4,13, 7, 5,15,14, 1, 9 ],
[ 12, 5, 1,15,14,13, 4,10, 0, 7, 6, 3, 9, 2, 8,11 ],
[ 13,11, 7,14,12, 1, 3, 9, 5, 0,15, 4, 8, 6, 2,10 ],
[ 6,15,14, 9,11, 3, 0, 8,12, 2,13, 7, 1, 4,10, 5 ],
[ 10, 2, 8, 4, 7, 6, 1, 5,15,11, 9,14, 3,12,13 ,0 ],
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 ],
[ 14,10, 4, 8, 9,15,13, 6, 1,12, 0, 2,11, 7, 5, 3 ],
] # only 1st 10 rows are used by BLAKE2s
# - - - - - - - - - - - - - - - - - - - - - - - - - - -
def __init__(self, digest_size=0, **args):
print("""
***********************************************
* You just instantiated a base class. Please *
* instantiate either BLAKE2b or BLAKE2s. *
***********************************************
""")
raise Exception('base class instantiation')
# - - - - - - - - - - - - - - - - - - - - - - - - - - -
def _init(self, key=b''):
assert len(key) <= self.KEYBYTES
# load parameters
P = self.PARAMS()
P.F.digest_size = self.digest_size
P.F.key_length = len(key)
P.F.fanout = self.fanout
P.F.depth = self.depth
P.F.leaf_size = self.leaf_size
P.F.node_offset_lo = self.node_offset & MASK32BITS
P.F.node_offset_hi = self.node_offset >> 32
P.F.node_depth = self.node_depth
P.F.inner_size = self.inner_size
P.F.salt = (self.salt +
(chr(0).encode())*(self.SALTBYTES-len(self.salt)))
P.F.person = (self.person +
(chr(0).encode())*(self.PERSONALBYTES-len(self.person)))
if DBUG2:
print('')
fmt = '%0' + str(self.WORDBYTES*2) + 'x'
for i in range(8):
print(' %2d: %s' % (i*8, fmt % P.W[i]))
self.h = [self.IV[i] ^ P.W[i] for i in range(8)]
self.totbytes = 0
self.t = [0]*2
self.f = [0]*2
self.buflen = 0
self.buf = b''
self.finalized = False
self.block_size = self.BLOCKBYTES
if key:
block = key + (chr(0).encode())*(self.BLOCKBYTES-len(key))
self.update(block)
if self.data:
self.update(self.data)
# - - - - - - - - - - - - - - - - - - - - - - - - - - -
def _compress(self, block):
MASKBITS = self.MASKBITS
WORDBITS = self.WORDBITS
WORDBYTES = self.WORDBYTES
IV = self.IV
sigma = self.sigma
ROT1 = self.ROT1
ROT2 = self.ROT2
ROT3 = self.ROT3
ROT4 = self.ROT4
WB_ROT1 = WORDBITS - ROT1
WB_ROT2 = WORDBITS - ROT2
WB_ROT3 = WORDBITS - ROT3
WB_ROT4 = WORDBITS - ROT4
# convert block (bytes) into 16 LE words
m = struct.unpack_from('<16%s' % self.WORDFMT, bytes(block))
v = [0]*16
'''
v[ 0: 8] = self.h
v[ 8:12] = IV[:4]
v[12] = self.t[0] ^ IV[4]
v[13] = self.t[1] ^ IV[5]
v[14] = self.f[0] ^ IV[6]
v[15] = self.f[1] ^ IV[7]
'''
v[:8] = IV[::-1]
print(m)
print([hex(v[i]) for i in range(16)])
# g.v and g_over_2.v
def G(a, b, c, d):
# dereference v[] for another small speed improvement - g_unit.v
va = v[a]
vb = v[b]
vc = v[c]
vd = v[d]
# g.v - g_over_2 g0
va = (va + vb + m0_sel) & MASKBITS
w = vd ^ va
vd = (w >> ROT1) | (w << (WB_ROT1)) & MASKBITS
vc = (vc + vd) & MASKBITS
w = vb ^ vc
vb = (w >> ROT2) | (w << (WB_ROT2)) & MASKBITS
# g.v - g_over_2 g1
va = (va + vb + m1_sel) & MASKBITS
w = vd ^ va
vd = (w >> ROT3) | (w << (WB_ROT3)) & MASKBITS
vc = (vc + vd) & MASKBITS
w = vb ^ vc
vb = (w >> ROT4) | (w << (WB_ROT4)) & MASKBITS
# re-reference v[] - g_unit.v
v[a] = va
v[b] = vb
v[c] = vc
v[d] = vd
# time to ChaCha
for r in range(self.ROUNDS):
print("funit rnd", r, "sub 0", [hex(v[i]) for i in range(16)])
sr = sigma[r]
m0_sel = m[sr[15]]
m1_sel = m[sr[14]]
G( 0, 4, 8, 12)
print("funit rnd", r, "sub 1", [hex(v[i]) for i in range(16)])
m0_sel = m[sr[13]]
m1_sel = m[sr[12]]
G( 1, 5, 9, 13)
print("funit rnd", r, "sub 2", [hex(v[i]) for i in range(16)])
m0_sel = m[sr[11]]
m1_sel = m[sr[10]]
G( 2, 6, 10, 14)
print("funit rnd", r, "sub 3", [hex(v[i]) for i in range(16)])
m0_sel = m[sr[9]]
m1_sel = m[sr[8]]
G( 3, 7, 11, 15)
print("funit rnd", r, "sub 4", [hex(v[i]) for i in range(16)])
m0_sel = m[sr[7]]
m1_sel = m[sr[6]]
G( 0, 5, 10, 15)
print("funit rnd", r, "sub 5", [hex(v[i]) for i in range(16)])
m0_sel = m[sr[5]]
m1_sel = m[sr[4]]
G( 1, 6, 11, 12)
print("funit rnd", r, "sub 6", [hex(v[i]) for i in range(16)])
m0_sel = m[sr[3]]
m1_sel = m[sr[2]]
G( 2, 7, 8, 13)
# !!!!
self.h = [v[i] ^ v[i+8] for i in range(8)]
print("funit rnd", r, "sub 7", [hex(v[i]) for i in range(16)])
m0_sel = m[sr[1]]
m1_sel = m[sr[0]]
G( 3, 4, 9, 14)
#self.h = [self.h[i] ^ v[i] ^ v[i+8] for i in range(8)]
# - - - - - - - - - - - - - - - - - - - - - - - - - - -
def update(self, data):
assert self.finalized == False
BLOCKBYTES = self.BLOCKBYTES
datalen = len(data)
dataptr = 0
while True:
if len(self.buf) > BLOCKBYTES:
self._increment_counter(BLOCKBYTES)
self._compress(self.buf[:BLOCKBYTES])
self.buf = self.buf[BLOCKBYTES:]
if dataptr <= datalen:
self.buf += data[dataptr:dataptr + BLOCKBYTES]
dataptr += BLOCKBYTES
else:
break
# - - - - - - - - - - - - - - - - - - - - - - - - - - -
def final(self):
# is there any residue remaining to be processed?
if not self.finalized:# and len(self.buf):
self._increment_counter(len(self.buf))
self._set_lastblock()
# add padding
self.buf += (chr(0).encode())*(self.BLOCKBYTES - len(self.buf))
print(len(self.buf))
print(self.buf)
# final compress
self._compress(self.buf)
self.buf = b'' # nothing more (no residue)
# convert 8 LE words into digest (bytestring)
self.digest_ = struct.pack('<8%s' % self.WORDFMT, *tuple(self.h))
self.finalized = True
return self.digest_[:self.digest_size]
digest = final
def hexdigest(self):
return binascii.hexlify(self.final()).decode()
def _set_lastblock(self):
if self.last_node:
self.f[1] = self.MASKBITS
self.f[0] = self.MASKBITS
def _increment_counter(self, numbytes):
self.totbytes += numbytes
self.t[0] = self.totbytes & self.MASKBITS
self.t[1] = self.totbytes >> self.WORDBITS
# - - - - - - - - - - - - - - - - - - - - - - - - - - -
# common utility functions
def copy(self):
return copy.deepcopy(self)
#---------------------------------------------------------------
class BLAKE2b(BLAKE2):
WORDBITS = 64
WORDBYTES = 8
MASKBITS = MASK64BITS
WORDFMT = 'Q' # used in _compress() and final()
ROUNDS = 12
BLOCKBYTES = 128
OUTBYTES = 64
KEYBYTES = 64
SALTBYTES = 16 # see also hardcoded value in ParamFields64
PERSONALBYTES = 16 # see also hardcoded value in ParamFields64
IV = [
0x6a09e667f3bcc908, 0xbb67ae8584caa73b,
0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
0x510e527fade682d1, 0x9b05688c2b3e6c1f,
0x1f83d9abfb41bd6b, 0x5be0cd19137e2179
]
ROT1 = 32
ROT2 = 24
ROT3 = 16
ROT4 = 63
# - - - - - - - - - - - - - - - - - - - - - - - - - - -
def __init__(self, data=b'', digest_size=64, key=b'',
salt=b'', person=b'', fanout=1, depth=1,
leaf_size=0, node_offset=0, node_depth=0,
inner_size=0, last_node=False):
assert 1 <= digest_size <= self.OUTBYTES
assert len(key) <= self.KEYBYTES
assert len(salt) <= self.SALTBYTES
assert len(person) <= self.PERSONALBYTES
assert 0 <= fanout <= MASK8BITS
assert 0 <= depth <= MASK8BITS
assert 0 <= leaf_size <= MASK32BITS
assert 0 <= node_offset <= MASK64BITS
assert 0 <= node_depth <= MASK8BITS
assert 0 <= inner_size <= MASK8BITS
# - - - - - - - - - - - - - - - - - - - - - - - - -
# use ctypes LittleEndianStructure and Union as a
# convenient way to organize complex structs, convert
# to little endian, and access by words
class ParamFields64(LittleEndianStructure):
_fields_ = [("digest_size", c_ubyte),
("key_length", c_ubyte),
("fanout", c_ubyte),
("depth", c_ubyte),
("leaf_size", c_uint32),
("node_offset_lo", c_uint32),
("node_offset_hi", c_uint32),
("node_depth", c_ubyte),
("inner_size", c_ubyte),
("reserved", c_char * 14),
("salt", c_char * 16),
("person", c_char * 16),
]
class Params64(Union):
_fields_ = [("F", ParamFields64),
("W", c_uint64 * 8),
]
# this next makes PARAMS a 'proper' instance variable
self.PARAMS = Params64
# key is passed as an argument; all other variables are
# defined as instance variables
self.digest_size = digest_size
self.data = data
self.salt = salt
self.person = person
self.fanout = fanout
self.depth = depth
self.leaf_size = leaf_size
self.node_offset = node_offset
self.node_depth = node_depth
self.inner_size = inner_size
self.last_node = last_node
# now call init routine common to BLAKE2b and BLAKE2s
self._init(key=key)
#---------------------------------------------------------------
class BLAKE2s(BLAKE2):
WORDBITS = 32
WORDBYTES = 4
MASKBITS = MASK32BITS
WORDFMT = 'L' # used in _compress() and final()
ROUNDS = 10
BLOCKBYTES = 64
OUTBYTES = 32
KEYBYTES = 32
SALTBYTES = 8
PERSONALBYTES = 8
IV = [
0x6a09e667, 0xbb67ae85,
0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c,
0x1f83d9ab, 0x5be0cd19
]
ROT1 = 16
ROT2 = 12
ROT3 = 8
ROT4 = 7
# - - - - - - - - - - - - - - - - - - - - - - - - - - -
def __init__(self, data=b'', digest_size=32, key=b'',
salt=b'', person=b'', fanout=1, depth=1,
leaf_size=0, node_offset=0, node_depth=0,
inner_size=0, last_node=False):
assert 1 <= digest_size <= self.OUTBYTES
assert len(key) <= self.KEYBYTES
assert len(salt) <= self.SALTBYTES
assert len(person) <= self.PERSONALBYTES
assert 0 <= fanout <= MASK8BITS
assert 0 <= depth <= MASK8BITS
assert 0 <= leaf_size <= MASK32BITS
assert 0 <= node_offset <= MASK48BITS
assert 0 <= node_depth <= MASK8BITS
assert 0 <= inner_size <= MASK8BITS
class ParamFields32(LittleEndianStructure):
pass
ParamFields32.SALTBYTES = self.SALTBYTES
ParamFields32.PERSONALBYTES = self.PERSONALBYTES
ParamFields32._fields_ = [
("digest_size", c_ubyte),
("key_length", c_ubyte),
("fanout", c_ubyte),
("depth", c_ubyte),
("leaf_size", c_uint32),
("node_offset_lo", c_uint32),
("node_offset_hi", c_uint16),
("node_depth", c_ubyte),
("inner_size", c_ubyte),
("salt", c_char * self.SALTBYTES),
("person", c_char * self.PERSONALBYTES),
]
class Params32(Union):
_fields_ = [("F", ParamFields32),
("W", c_uint32 * 8),
]
# this next makes PARAMS union a 'proper' instance variable
self.PARAMS = Params32
# key is passed as an argument; all other variables are
# defined as instance variables
self.digest_size = digest_size
self.data = data
self.salt = salt
self.person = person
self.fanout = fanout
self.depth = depth
self.leaf_size = leaf_size
self.node_offset = node_offset
self.node_depth = node_depth
self.inner_size = inner_size
self.last_node = last_node
# now call init routine common to BLAKE2b and BLAKE2s
self._init(key=key)
# Example usage
if __name__ == "__main__":
message = b""
# Manual implementation
b2 = BLAKE2s(digest_size=32)
b2.update(message)
digest = b2.final()
manual_hash_value = binascii.hexlify(digest).decode()
print("my imp:", manual_hash_value)
print("bloke2: c1f4134633d0c0708c8db5d9a8fa708d7b33784de22503c1c8e83d57abc2ec20") # ""
# Verify that both results are the same
assert manual_hash_value == "c1f4134633d0c0708c8db5d9a8fa708d7b33784de22503c1c8e83d57abc2ec20", "The outputs do not match!"
message = b"123"
# Manual implementation
b2 = BLAKE2s(digest_size=32)
b2.update(message)
digest = b2.final()
manual_hash_value = binascii.hexlify(digest).decode()
print("my imp:", manual_hash_value)
print("bloke2: 6ea2fe2803fb1e09f90005da46b472aa63e193c4406c75f09773c266460e7672") # "123"
# Verify that both results are the same
assert manual_hash_value == "6ea2fe2803fb1e09f90005da46b472aa63e193c4406c75f09773c266460e7672", "The outputs do not match!"
filename:
fullspeed.exe
,capture.pcapng
filetype:.NET PE64
,pcap
estimated time: ? min
題目敘述
Has this all been far too easy? Where's the math? Where's the science? Where's the, I don't know.... cryptography? Well we don't know about any of that, but here is a little .NET binary to chew on while you discuss career changes with your life coach.
解題經歷
這題一支 Windows dotnet 執行程式搭配一個封包, 猜是要解出封包的內容, dotnet 程式是 AOT(ahead of time) 編譯而成, 去除了很多函數的 metadata, 沒辦法用 ILSpy/dnSpy 直接看原始碼, 丟進 IDA Pro 裡會是一堆未知功能的 sub function, 後來參考了一篇做法, 是使用 IDA Pro 的 FLIRT 特徵, 大致流程如下 猜功能 -> 寫dotnet 程式 -> AOT 編譯 -> 建立 FLIRT Signature -> 在題目裡套用 FLIRT Signature, 如此一來 IDA Pro 裡的 pesudo code 就會好看許多, 需要進行逆向的就只剩下十個 function
全部看懂之後, 發現這之程式實作了一套 ECDH 流程, client server 互丟橢圓曲線上的點 (client_secret*G
, server_secret*G
), secret 大小為 128 bit, 然後以 sha512 hash client_secret*server_secret*G
X 軸推出 chacha20 的 key 與 nonce, 作後續 command and control 的加解密方式
仔細分析橢圓曲線的參數會發現其 order 是可分解(smooth), 也就是可以運用 Pohlig-Hellman 在有限時間內推出 secret, 但分解結果裡有一個大質數 35809 * 46027 * 56369 * 57301 * 65063 * 111659 * 113111 * 7072010737074051173701300310820071551428959987622994965153676442076542799542912293
, 導致想解 112 bit 以上的 secret 一樣得花很久的時間, 因為對密碼學的不熟悉, 就卡死在這裡了
後來看完官方的 writeup, 簡單來說就是還是可以把暴力破解的難度降到 216 - picoCTF_2017 ECC2
dotnet (8.0.5 - SDK 8.0.300)
BouncyCastle Cryptography - https://github.com/bcgit/bc-csharp/blob/59f5f71f1a1b4b67ee3d25997350f4a00d07490b/README.md
not
BouncyCastle.Crypto
!!!
dotnet add package BouncyCastle.Cryptography
TestApp.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PublishAot>true</PublishAot>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
<ItemGroup>
</ItemGroup>
<ItemGroup>
<PackageReference Include="BouncyCastle.Cryptography" Version="2.4.0" />
</ItemGroup>
</Project>
pcapng
00000000 0a 6c 55 90 73 da 49 75 4e 9a d9 84 6a 72 95 47 .lU.s.Iu N...jr.G
00000010 45 e4 f2 92 12 13 ec cd a4 b1 42 2e 2f dd 64 6f E....... ..B./.do
00000020 c7 e2 83 89 c7 c2 e5 1a 59 1e 01 47 e2 eb e7 ae ........ Y..G....
00000030 26 40 22 da f8 c7 67 6a 1b 27 20 91 7b 82 99 9d &@"...gj .' .{...
00000040 42 cd 18 78 d3 1b c5 7b 6d b1 7b 97 05 c7 ff 24 B..x...{ m.{....$
00000050 04 cb bf 13 cb db 8c 09 66 21 63 40 45 29 39 22 ........ f!c@E)9"
00000000 a0 d2 eb a8 17 e3 8b 03 cd 06 32 27 bd 32 e3 53 ........ ..2'.2.S
00000010 88 08 18 89 3a b0 23 78 d7 db 3c 71 c5 c7 25 c6 ....:.#x ..<q..%.
00000020 bb a0 93 4b 5d 5e 2d 3c a6 fa 89 ff bb 37 4c 31 ...K]^-< .....7L1
00000030 96 a3 5e af 2a 5e 0b 43 00 21 de 36 1a a5 8f 80 ..^.*^.C .!.6....
00000040 15 98 1f fd 0d 98 24 b5 0a f2 3b 5c cf 16 fa 4e ......$. ..;\...N
00000050 32 34 83 60 2d 07 54 53 4d 2e 7a 8a af 81 74 dc 24.`-.TS M.z...t.
00000060 f2 72 d5 4c 31 86 0f .r.L1..
00000060 3f bd 43 da 3e e3 25 ?.C.>.%
00000067 86 df d7 ...
00000067 c5 0c ea 1c 4a a0 64 c3 5a 7f 6e 3a b0 25 84 41 ....J.d. Z.n:.%.A
00000077 ac 15 85 c3 62 56 de a8 3c ac 93 00 7a 0c 3a 29 ....bV.. <...z.:)
00000087 86 4f 8e 28 5f fa 79 c8 eb 43 97 6d 5b 58 7f 8f .O.(_.y. .C.m[X..
00000097 35 e6 99 54 71 16 5..Tq.
0000006A fc b1 d2 cd bb a9 79 c9 89 99 8c ......y. ...
0000009D 61 49 0b aI.
00000075 ce 39 da .9.
000000A0 57 70 11 e0 d7 6e c8 eb 0b 82 59 33 1d ef 13 ee Wp...n.. ..Y3....
000000B0 6d 86 72 3e ac 9f 04 28 92 4e e7 f8 41 1d 4c 70 m.r>...( .N..A.Lp
000000C0 1b 4d 9e 2b 37 93 f6 11 7d d3 0d ac ba .M.+7... }....
00000078 2c ae 60 0b 5f 32 ce a1 93 e0 de 63 d7 09 83 8b ,.`._2.. ...c....
00000088 d6 .
000000CD a7 fd 35 ..5
00000089 ed f0 fc ...
000000D0 80 2b 15 18 6c 7a 1b 1a 47 5d af 94 ae 40 f6 bb .+..lz.. G]...@..
000000E0 81 af ce dc 4a fb 15 8a 51 28 c2 8c 91 cd 7a 88 ....J... Q(....z.
000000F0 57 d1 2a 66 1a ca ec W.*f...
0000008C ae c8 d2 7a 7c f2 6a 17 27 36 85 ...z|.j. '6.
000000F7 35 a4 4e 5.N
00000097 2f 39 17 /9.
000000FA ed 09 44 7d ed 79 72 19 c9 66 ef 3d d5 70 5a 3c ..D}.yr. .f.=.pZ<
0000010A 32 bd b1 71 0a e3 b8 7f e6 66 69 e0 b4 64 6f c4 2..q.... .fi..do.
0000011A 16 c3 99 c3 a4 fe 1e dc 0a 3e c5 82 7b 84 db 5a ........ .>..{..Z
0000012A 79 b8 16 34 e7 c3 af e5 28 a4 da 15 45 7b 63 78 y..4.... (...E{cx
0000013A 15 37 3d 4e dc ac 21 59 d0 56 .7=N..!Y .V
0000009A f5 98 1f 71 c7 ea 1b 5d 8b 1e 5f 06 fc 83 b1 de ...q...] .._.....
000000AA f3 8c 6f 4e 69 4e 37 06 41 2e ab f5 4e 3b 6f 4d ..oNiN7. A...N;oM
000000BA 19 e8 ef 46 b0 4e 39 9f 2c 8e ce 84 17 fa ...F.N9. ,.....
00000144 40 08 bc @..
000000C8 54 e4 1e T..
00000147 f7 01 fe e7 4e 80 e8 df b5 4b 48 7f 9b 2e 3a 27 ....N... .KH...:'
00000157 7f a2 89 cf 6c b8 df 98 6c dd 38 7e 34 2a c9 f5 ....l... l.8~4*..
00000167 28 6d a1 1c a2 78 40 84 (m...x@.
000000CB 5c a6 8d 13 94 be 2a 4d 3d 4d 7c 82 e5 \.....*M =M|..
0000016F 31 b6 da c6 2e f1 ad 8d c1 f6 0b 79 26 5e d0 de 1....... ...y&^..
0000017F aa 31 dd d2 d5 3a a9 fd 93 43 46 38 10 f3 e2 23 .1...:.. .CF8...#
0000018F 24 06 36 6b 48 41 53 33 d4 b8 ac 33 6d 40 86 ef $.6kHAS3 ...3m@..
0000019F a0 f1 5e 6e 59 ..^nY
000000D8 0d 1e c0 6f 36 ...o6
PE file does not contain any managed metadata.
https://harfanglab.io/insidethelab/reverse-engineering-ida-pro-aot-net/
https://blog.cyberethical.me/htb-cyber-apocalypse-forensics-oblique-final
BouncyCastle Examples - https://downloads.bouncycastle.org/csharp/docs/BC-CSharpDotNet-Examples.zip
.NETCoreApp,Version=v8.0
8.0.524.21615\8.0.5+087e15321bb712ef6fe8b0ba6f8bd12facf92629
sub_7FF7E24E7D80
import binascii
def decrypt(enc_str):
enc_bytes = binascii.unhexlify(enc_str)
j = 0
dec_bytes = b""
for e in enc_bytes:
j = 13 * j + 37
dec_bytes += bytes([e ^ (j & 0xFF)])
print(dec_bytes)
return dec_bytes
enc_addr_info = decrypt("143f41d2c05427964848a505f9698c43e4c5905b") # 192.168.56.103;31337
decrypt("1e") # ;
decrypt("4b731f90") # null
decrypt("51691cdc9d0d71df") # too long
decrypt("59") # |
decrypt("4662") # cd
decrypt("4a6d") # ok
decrypt("4975") # ls
decrypt("183b4edc950b6dcb5d43b609") # === dirs ===
decrypt("0b") # .
decrypt("183b4edc970b73dd0e5eb609f4") # === files ===
decrypt("466707") # cat
decrypt("407e1a88") # exit
decrypt("476717dc920f7b") # bad cmd
decrypt("407401") # err
decrypt("53630195971b3fde1c17e751ad") # verify failed
decrypt("53630195971b") # verify
decrypt("4c6815") # inf
buf_1337 = decrypt("143540cbc0512c8f4c4db803f8698447e4c5905b90617c1f1c5d88934879d4d7b4d5e0eb60714cafec6dd8231809246704e5307b30019c3fbc7d28b3e81974f7d4f5008b8011ec4f0c0d78c3b8294407a485501b50213cdfdc1d485308399497") # 133713371337133713371337133713371337133713371337133713371337133713371337133713371337133713371337
buf_1 = decrypt("463f43cdc15079d91c4ab352f862d545b097c05dc765794a4f5a8bc54828de86e7d6b7e4657348a9ef3c89711a5f226502e0627b60079931ba7878b6bb4b22a384f20484811be84e080c73c7e87b4707ad835b1f04236aded81f4c565839c1c4") # c90102faa48f18b5eac1f76bb40a1b9fb0d841712bbe3e5576a7a56976c2baeca47809765283aa078583e1e65172a3fd
buf_2 = decrypt("443644c595002f80181fb900fe6a8445e59592549366771f4f5b8bc24e7dd7d7e182e7ea307747f9ec3ada22195c71670ce43a7b6551cc31ef287ae0ef4921a3dcf052848041eb1904097ec2bd2b4608f482531f5223698ddd4818550a3890c6") # a079db08ea2470350c182487b50f7707dd46a58a1d160ff79297dcc9bfad6cfc96a81c4a97564118a40331fe0fc1327f
buf_3 = decrypt("1c604acfc8012f8a1c49e950fe3cd442e3c5c258c2312a1c1c58dd901a7fd0d5e3d4ebb861214eabec6b88204f0a74620de4652f60049838b42f2ee2e04c70a6dca501898041e61d585a2ecdec784652f4d7501d57223dd9db191d050c399f90") # 9f939c02a7bd7fc263a4cce416f4c575f28d0c1315c4f0c282fca6709a5f9f7f9c251c9eede9eb1baa31602167fa5380
buf_4 = decrypt("153e449ec4047a8b1c1bbd50aa3cd540b0c69458c3667f4e1b5c8b9c1a7281d6e183e7ba65244faeea678f22100924670ce0677f630bcd6cbb7b22b3e91e21a2ddf307898344ef4c0c582d92b82e1456a5d35a4d00256adcd81b4f505f33c398") # 087b5fe3ae6dcfb0e074b40f6208c8f6de4f4f0679d6933796d3b9bd659704fb85452f041fff14cf0e9aa7e45544f9d8
buf_5 = decrypt("143444c8c3577c89194db804ac3e8243e2c0955fc46a781c1857dec5187b85d1e7d3e0b935241aabed6b8d22480d2e3204ee372e32039738bd7d28e5b84876f9d5a35185d043ef480e5b7bc6ec231352f380071958216cdd881d1954013b9f92") # 127425c1d330ed537663e87459eaa1b1b53edfe305f6a79b184b3180033aab190eb9aa003e02e9dbf6d593c5e3b08182
b4 sha512 hash src of buf_0x30
(have value after .managed:00007FF7E24E813F call qword ptr [rax+88h])
(.managed:00007FF7E2456B87 call qword ptr [rax+50h] ; sub_7FF7E2455F10)
0000025176D390D0 60 BB 56 E2 F7 7F 00 00 0C 00 00 00 00 00 00 00 `»Vâ÷...........
0000025176D390E0 F7 2F 71 7F 45 83 2E FB 49 D4 9D A1 BE 6B 59 87 ÷/q.Eƒ.ûIÔ.¡¾kY‡
0000025176D390F0 FF FC C6 2E D8 88 A8 57 CA CD 35 84 DE E9 19 6A ÿüÆ.؈¨WÊÍ5„Þé.j
0000025176D39100 67 19 01 E2 1E 7B 96 45 E8 B5 38 D9 D4 CE FC 24 g..â.{–Eèµ8ÙÔÎü$
b4 sha512 hash buf_0x30
0000025174AD91D0 88 B6 56 E2 F7 7F 00 00 30 00 00 00 00 00 00 00 ˆ¶Vâ÷...0.......
0000025174AD91E0 7F 71 2F F7 FB 2E 83 45 A1 9D D4 49 87 59 6B BE .q/÷û.ƒE¡.ÔI‡Yk¾
0000025174AD91F0 2E C6 FC FF 57 A8 88 D8 84 35 CD CA 6A 19 E9 DE .ÆüÿW¨ˆØ„5ÍÊj.éÞ
0000025174AD9200 E2 01 19 67 45 96 7B 1E D9 38 B5 E8 24 FC CE D4 â..gE–{.Ù8µè$üÎÔ
sha512 result 1
0000025176D39760 00 00 00 00 00 00 00 00 88 B6 56 E2 F7 7F 00 00 ........ˆ¶Vâ÷...
0000025176D39770 40 00 00 00 00 00 00 00 2D 8E 5D E2 A2 9B 02 57 @.......-Ž]⢛.W
0000025176D39780 C0 73 72 57 61 23 61 4F 30 85 E7 34 C6 67 CC 99 ÀsrWa#aO0…ç4ÆgÌ™
0000025176D39790 E5 01 C7 CF 38 CA 48 3F AE 1E A1 5D C9 1C 70 E7 å.ÇÏ8ÊH?®.¡]É.pç
0000025176D397A0 5E 86 1E 77 B3 24 F8 CD 46 65 E2 BC 1F B5 0A B7 ^†.w³$øÍFeâ¼.µ.·
0000025176D397B0 2E 95 C3 C2 FC 9B 3A 95 00 00 00 00 00 00 00 00 .•ÃÂü›:•........
chacha20 initial state (c2 - client)
0000025176D39FF0 60 BB 56 E2 F7 7F 00 00 10 00 00 00 00 00 00 00 `»Vâ÷...........
0000025176D3A000 65 78 70 61 6E 64 20 33 32 2D 62 79 74 65 20 6B expand 32-byte k
0000025176D3A010 2D 8E 5D E2 A2 9B 02 57 C0 73 72 57 61 23 61 4F -Ž]⢛.WÀsrWa#aO
0000025176D3A020 30 85 E7 34 C6 67 CC 99 E5 01 C7 CF 38 CA 48 3F 0…ç4ÆgÌ™å.ÇÏ8ÊH?
0000025176D3A030 00 00 00 00 00 00 00 00 AE 1E A1 5D C9 1C 70 E7 ........®.¡]É.pç
data c2 - client (encrypted "verify")
\x7c\xbb\xd4\x66\x75\xc9\x23
data client - c2 (encrypted "verify")
0000025176D3A700 64 73 18 8C 2D 43 08 00 00 00 00 00 00 00 00 00 ds.Œ-C..........
chacha20 initial state (client - c2)
0000025176D39FF0 60 BB 56 E2 F7 7F 00 00 10 00 00 00 00 00 00 00 `»Vâ÷...........
0000025176D3A000 65 78 70 61 6E 64 20 33 32 2D 62 79 74 65 20 6B expand 32-byte k
0000025176D3A010 2D 8E 5D E2 A2 9B 02 57 C0 73 72 57 61 23 61 4F -Ž]⢛.WÀsrWa#aO
0000025176D3A020 30 85 E7 34 C6 67 CC 99 E5 01 C7 CF 38 CA 48 3F 0…ç4ÆgÌ™å.ÇÏ8ÊH?
0000025176D3A030 01 00 00 00 00 00 00 00 AE 1E A1 5D C9 1C 70 E7 ........®.¡]É.pç
import struct
# Rotate left (32-bit)
def rotl32(x, n):
return ((x << n) & 0xffffffff) | (x >> (32 - n))
# ChaCha20 quarter-round function
def quarterround(state, a, b, c, d):
state[a] = (state[a] + state[b]) & 0xffffffff
state[d] ^= state[a]
state[d] = rotl32(state[d], 16)
state[c] = (state[c] + state[d]) & 0xffffffff
state[b] ^= state[c]
state[b] = rotl32(state[b], 12)
state[a] = (state[a] + state[b]) & 0xffffffff
state[d] ^= state[a]
state[d] = rotl32(state[d], 8)
state[c] = (state[c] + state[d]) & 0xffffffff
state[b] ^= state[c]
state[b] = rotl32(state[b], 7)
# ChaCha20 block function for an 8-byte nonce
def chacha20_block(key, counter, nonce):
# ChaCha20 constants ("expand 32-byte k" in ASCII, split into 32-bit words)
constants = [0x61707865, 0x3320646e, 0x79622d32, 0x6b206574]
# ChaCha20 constants ("expand 16-byte k" in ASCII, split into 32-bit words)
#constants = [0x61707865, 0x3120646e, 0x79622d36, 0x6b206574]
# Convert key to 32-bit words
key_words = struct.unpack('<8I', key)
# Convert 64-bit counter and 64-bit nonce to 32-bit words
counter_words = struct.unpack('<2I', struct.pack('<Q', counter))
nonce_words = struct.unpack('<2I', nonce)
# Initialize the state array (16 32-bit integers)
state = [
constants[0], constants[1], constants[2], constants[3],
key_words[0], key_words[1], key_words[2], key_words[3],
key_words[4], key_words[5], key_words[6], key_words[7],
counter_words[0], counter_words[1], nonce_words[0], nonce_words[1]
]
# Run 20 rounds (10 double rounds)
working_state = state[:]
for _ in range(10):
# Column round
quarterround(working_state, 0, 4, 8, 12)
quarterround(working_state, 1, 5, 9, 13)
quarterround(working_state, 2, 6, 10, 14)
quarterround(working_state, 3, 7, 11, 15)
# Diagonal round
quarterround(working_state, 0, 5, 10, 15)
quarterround(working_state, 1, 6, 11, 12)
quarterround(working_state, 2, 7, 8, 13)
quarterround(working_state, 3, 4, 9, 14)
# Add the original state to the result and return
output = [(working_state[i] + state[i]) & 0xffffffff for i in range(16)]
return b''.join(struct.pack('<I', word) for word in output)
# ChaCha20 encryption function: XORs the keystream with plaintext
def chacha20_encrypt(key, nonce, plaintext):
if len(key) != 32 or len(nonce) != 8:
raise ValueError("Key must be 32 bytes and nonce 8 bytes")
ciphertext = bytearray(len(plaintext))
block_counter = 0
for i in range(0, len(plaintext), 64):
keystream = chacha20_block(key, block_counter, nonce)
block = plaintext[i:i+64]
keystream_block = keystream[:len(block)]
# XOR plaintext block with keystream to produce ciphertext block
for j in range(len(block)):
ciphertext[i + j] = block[j] ^ keystream_block[j]
block_counter += 1
return bytes(ciphertext)
# Example usage
if __name__ == "__main__":
key = b"\x2D\x8E\x5D\xE2\xA2\x9B\x02\x57\xC0\x73\x72\x57\x61\x23\x61\x4F\x30\x85\xE7\x34\xC6\x67\xCC\x99\xE5\x01\xC7\xCF\x38\xCA\x48\x3F" # 32 bytes
nonce = b"\xAE\x1E\xA1\x5D\xC9\x1C\x70\xE7" # 8 bytes
plaintext = b"verify\x00" # plaintext
# Encrypt
ciphertext = chacha20_encrypt(key, nonce, plaintext)
print("Ciphertext:", ciphertext)
# Decrypt (Salsa20 is symmetric, so encrypting again decrypts)
decrypted = chacha20_encrypt(key, nonce, ciphertext)
print("Decrypted:", decrypted)
ref: sub_7FF7BA3F7BC0
using System;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Math.EC.Custom.Sec;
using Org.BouncyCastle.Security;
namespace ECCValidation
{
class Program
{
static void Main(string[] args)
{
// Split the data into x and y coordinates (each 48 bytes for P-384)
byte[] xBytes = new byte[48];
byte[] yBytes = new byte[48];
Array.Copy(pointData, 0, xBytes, 0, 48);
Array.Copy(pointData, 48, yBytes, 0, 48);
// Convert x and y to BigInteger
BigInteger x_recv = new BigInteger(1, xBytes); // '1' specifies a positive number
BigInteger y_recv = new BigInteger(1, yBytes);
// Load P-384 curve parameters
//X9ECParameters ecParams = ECNamedCurveTable.GetByName("P-384");
//var curve = ecParams.Curve;
// Custom curve parameters (ref: sub_7FF7BA3F7BC0)
// Define the custom prime modulus p
BigInteger p = new BigInteger("c90102faa48f18b5eac1f76bb40a1b9fb0d841712bbe3e5576a7a56976c2baeca47809765283aa078583e1e65172a3fd", 16);
// Define coefficients a and b (example values here, replace with actual values for your curve)
BigInteger a = new BigInteger("a079db08ea2470350c182487b50f7707dd46a58a1d160ff79297dcc9bfad6cfc96a81c4a97564118a40331fe0fc1327f", 16);
BigInteger b = new BigInteger("9f939c02a7bd7fc263a4cce416f4c575f28d0c1315c4f0c282fca6709a5f9f7f9c251c9eede9eb1baa31602167fa5380", 16);
BigInteger order = BigInteger.Zero;
BigInteger cofactor = BigInteger.Zero;
// Create the custom elliptic curve
ECCurve curve = new FpCurve(p, a, b);
// Generator point
BigInteger x_G = new BigInteger("087b5fe3ae6dcfb0e074b40f6208c8f6de4f4f0679d6933796d3b9bd659704fb85452f041fff14cf0e9aa7e45544f9d8", 16);
BigInteger y_G = new BigInteger("127425c1d330ed537663e87459eaa1b1b53edfe305f6a79b184b3180033aab190eb9aa003e02e9dbf6d593c5e3b08182", 16);
ECPoint generator = curve.CreatePoint(x_G, y_G);
//SecureRandom random = SecureRandom.GetInstance("SHA256PRNG");
//BigInteger randomScalar = new BigInteger(384, random);
BigInteger rand = new BigInteger("96f6e8b7f27c4850e4c72e251926aece", 16);
ECPoint randomPoint = generator.Multiply(rand);
ECPoint normalizedPoint = randomPoint.Normalize();
Console.WriteLine("X: " + normalizedPoint.AffineXCoord.ToBigInteger().ToString(16));
Console.WriteLine("Y: " + normalizedPoint.AffineYCoord.ToBigInteger().ToString(16));
// Byte stream representing an EC point (x and y coordinates)
byte[] pointData = new byte[]
{
0xb3,0xe5,0xf8,0x9f,0x04,0xd4,0x98,0x34,0xde,0x31,0x21,0x10,0xae,0x05,0xf0,0x64,0x9b,0x3f,0x0b,0xbe,0x29,0x87,0x30,0x4f,0xc4,0xec,0x2f,0x46,0xd6,0xf0,0x36,0xf1,0xa8,0x97,0x80,0x7c,0x4e,0x69,0x3e,0x0b,0xb5,0xcd,0x9a,0xc8,0xa8,0x00,0x5f,0x06,0x85,0x94,0x4d,0x98,0x39,0x69,0x18,0x74,0x13,0x16,0xcd,0x01,0x09,0x92,0x9c,0xb7,0x06,0xaf,0x0c,0xca,0x1e,0xaf,0x37,0x82,0x19,0xc5,0x28,0x6b,0xdc,0x21,0xe9,0x79,0x21,0x03,0x90,0x57,0x3e,0x30,0x47,0x64,0x5e,0x19,0x69,0xbd,0xbc,0xb6,0x67,0xeb
};
// Attempt to create the point on the curve
try
{
ECPoint point2 = curve.ValidatePoint(x_recv, y_recv);
Console.WriteLine("Point is valid on the curve:");
Console.WriteLine("X: " + point2.AffineXCoord.ToBigInteger().ToString(16));
Console.WriteLine("Y: " + point2.AffineYCoord.ToBigInteger().ToString(16));
ECPoint randomPoint2 = point2.Multiply(rand);
ECPoint normalizedPoint2 = randomPoint2.Normalize();
Console.WriteLine("data for SHA512");
Console.WriteLine("X: " + normalizedPoint2.AffineXCoord.ToBigInteger().ToString(16));
//Console.WriteLine("Y: " + normalizedPoint2.AffineYCoord.ToBigInteger().ToString(16));
}
catch (Exception e)
{
Console.WriteLine("The point is not valid on the curve: " + e.Message);
}
}
}
}
sub_7FF7E24E7E20
ref: https://lazzzaro.github.io/2020/11/07/crypto-ECC/#Pohlig-Hellman算法
p: 0xc90102faa48f18b5eac1f76bb40a1b9fb0d841712bbe3e5576a7a56976c2baeca47809765283aa078583e1e65172a3fd
a: 0xa079db08ea2470350c182487b50f7707dd46a58a1d160ff79297dcc9bfad6cfc96a81c4a97564118a40331fe0fc1327f
b: 0x9f939c02a7bd7fc263a4cce416f4c575f28d0c1315c4f0c282fca6709a5f9f7f9c251c9eede9eb1baa31602167fa5380
order: 0xc90102faa48f18b5eac1f76bb40a1b9fb0d841712bbe3e547761ec3ea549979d50c95478998110005c8c2b7f3498ee71
Order of the curve: 35809 * 46027 * 56369 * 57301 * 65063 * 111659 * 113111 * 7072010737074051173701300310820071551428959987622994965153676442076542799542912293
poc.sage
import time
p = 0xc90102faa48f18b5eac1f76bb40a1b9fb0d841712bbe3e5576a7a56976c2baeca47809765283aa078583e1e65172a3fd
a = 0xa079db08ea2470350c182487b50f7707dd46a58a1d160ff79297dcc9bfad6cfc96a81c4a97564118a40331fe0fc1327f
b = 0x9f939c02a7bd7fc263a4cce416f4c575f28d0c1315c4f0c282fca6709a5f9f7f9c251c9eede9eb1baa31602167fa5380
F = GF(p)
E = EllipticCurve(F, [a, b])
N = E.order()
print("Order of the curve:", N.factor())
x_G = F(0x087b5fe3ae6dcfb0e074b40f6208c8f6de4f4f0679d6933796d3b9bd659704fb85452f041fff14cf0e9aa7e45544f9d8)
y_G = F(0x127425c1d330ed537663e87459eaa1b1b53edfe305f6a79b184b3180033aab190eb9aa003e02e9dbf6d593c5e3b08182)
G = E(x_G, y_G)
order_G = G.order()
print("Order of the G:", hex(order_G))
x_hex1 = "195b46a760ed5a425dadcab37945867056d3e1a50124fffab78651193cea7758d4d590bed4f5f62d4a291270f1dcf499"
y_hex1 = "357731edebf0745d081033a668b58aaa51fa0b4fc02cd64c7e8668a016f0ec1317fcac24d8ec9f3e75167077561e2a15"
x_hex2 = "b3e5f89f04d49834de312110ae05f0649b3f0bbe2987304fc4ec2f46d6f036f1a897807c4e693e0bb5cd9ac8a8005f06"
y_hex2 = "85944d98396918741316cd0109929cb706af0cca1eaf378219c5286bdc21e979210390573e3047645e1969bdbcb667eb"
x_hex3 = "b65c41823709a297d2f884d573f86613b215a76131b30736a1fca665fbc5720e721b077a10717a81a0d43ce6a8a5d93f"
y_hex3 = "2c1b0fe9b00467aa9f4670f30ec1de25b8695d3cee8ee212db8003a58b504d936c44d03da3b17e97a8edf9db25a0e7b1"
x_c = F(int(x_hex1, 16))
y_c = F(int(y_hex1, 16))
x_s = F(int(x_hex2, 16))
y_s = F(int(y_hex2, 16))
x_test = F(int(x_hex3, 16))
y_test = F(int(y_hex3, 16))
try:
QTest = E(x_test, y_test)
print(f"The point ({x_test}, {y_test}) is on the curve.")
except ValueError:
print(f"The point ({x_test}, {y_test}) is NOT on the curve.")
try:
QA = E(x_c, y_c)
print(f"The point ({x_c}, {y_c}) is on the curve.")
except ValueError:
print(f"The point ({x_c}, {y_c}) is NOT on the curve.")
try:
QB = E(x_s, y_s)
print(f"The point ({x_s}, {y_s}) is on the curve.")
except ValueError:
print(f"The point ({x_s}, {y_s}) is NOT on the curve.")
# Factorize the order of P
factorization = N.factor()
factors, exponents = zip(*factor(N))
primes = [factors[i] ^ exponents[i] for i in range(len(factors))]
print(primes)
dlogs = []
for fac in primes:
t = int(int(N) // int(fac))
print("t: " + str(t))
start_time = time.time()
dlog = discrete_log(t*QA, t*G, operation="+")
end_time = time.time()
time_cost = end_time - start_time
dlogs += [dlog]
print("factor: " + str(fac) + ", Discrete Log: " + str(dlog) + ", time: " + str(time_cost)) #calculates discrete logarithm for each prime order
l = crt(dlogs,primes)
print("l: ", l)
lg = l*G
x, y = lg.xy()
print(f"The point ({x_test}, {y_test})")
print(f"The point ({x}, {y})")
solve.sage
import time
p = 0xc90102faa48f18b5eac1f76bb40a1b9fb0d841712bbe3e5576a7a56976c2baeca47809765283aa078583e1e65172a3fd
a = 0xa079db08ea2470350c182487b50f7707dd46a58a1d160ff79297dcc9bfad6cfc96a81c4a97564118a40331fe0fc1327f
b = 0x9f939c02a7bd7fc263a4cce416f4c575f28d0c1315c4f0c282fca6709a5f9f7f9c251c9eede9eb1baa31602167fa5380
F = GF(p)
E = EllipticCurve(F, [a, b])
N = E.order()
print("Order of the curve:", N.factor())
x_G = F(0x087b5fe3ae6dcfb0e074b40f6208c8f6de4f4f0679d6933796d3b9bd659704fb85452f041fff14cf0e9aa7e45544f9d8)
y_G = F(0x127425c1d330ed537663e87459eaa1b1b53edfe305f6a79b184b3180033aab190eb9aa003e02e9dbf6d593c5e3b08182)
G = E(x_G, y_G)
order_G = G.order()
print("Order of the G:", hex(order_G))
x_hex_client = "195b46a760ed5a425dadcab37945867056d3e1a50124fffab78651193cea7758d4d590bed4f5f62d4a291270f1dcf499"
y_hex_client = "357731edebf0745d081033a668b58aaa51fa0b4fc02cd64c7e8668a016f0ec1317fcac24d8ec9f3e75167077561e2a15"
x_hex_server = "b3e5f89f04d49834de312110ae05f0649b3f0bbe2987304fc4ec2f46d6f036f1a897807c4e693e0bb5cd9ac8a8005f06"
y_hex_server = "85944d98396918741316cd0109929cb706af0cca1eaf378219c5286bdc21e979210390573e3047645e1969bdbcb667eb"
x_hex3 = "b65c41823709a297d2f884d573f86613b215a76131b30736a1fca665fbc5720e721b077a10717a81a0d43ce6a8a5d93f"
y_hex3 = "2c1b0fe9b00467aa9f4670f30ec1de25b8695d3cee8ee212db8003a58b504d936c44d03da3b17e97a8edf9db25a0e7b1"
x_client = F(int(x_hex_client, 16))
y_client = F(int(y_hex_client, 16))
x_server = F(int(x_hex_server, 16))
y_server = F(int(y_hex_server, 16))
x_test = F(int(x_hex3, 16))
y_test = F(int(y_hex3, 16))
QTest = E(x_test, y_test)
QA = E(x_client, y_client)
QB = E(x_server, y_server)
# Factorize the order of P
factorization = N.factor()
factors, exponents = zip(*factor(N))
primes = [factors[i] ^ exponents[i] for i in range(len(factors))]
print(primes)
factors = factor(order_G, proof=False)
smooth_part = Factorization(factors[:-1]).value()
big_part = Factorization(factors[-1:]).value()
print(smooth_part)
print(big_part)
secret_mod_smooth = (G*big_part).discrete_log(QA*big_part)
print(secret_mod_smooth)
possible_secret = secret_mod_smooth
while True:
if QA == possible_secret * G:
break
possible_secret += smooth_part
print(possible_secret) # 168606034648973740214207039875253762473
using System;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Security.Cryptography;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Math.EC.Custom.Sec;
using Org.BouncyCastle.Security;
namespace ECCValidation
{
class Program
{
static void Main(string[] args)
{
// Create ChaCha20 engine and initialize with key and nonce
byte[] key = new byte[] { 0x2D, 0x8E, 0x5D, 0xE2, 0xA2, 0x9B, 0x02, 0x57, 0xC0, 0x73, 0x72, 0x57, 0x61, 0x23, 0x61, 0x4F,
0x30, 0x85, 0xE7, 0x34, 0xC6, 0x67, 0xCC, 0x99, 0xE5, 0x01, 0xC7, 0xCF, 0x38, 0xCA, 0x48, 0x3F };
byte[] nonce = new byte[] { 0xAE, 0x1E, 0xA1, 0x5D, 0xC9, 0x1C, 0x70, 0xE7 };
var engine = new ChaChaEngine(20);
var parameters = new ParametersWithIV(new KeyParameter(key), nonce);
engine.Init(true, parameters);
string plaintext = "verify";
byte[] data = Encoding.UTF8.GetBytes(plaintext);
// Allocate buffer for output
byte[] output = new byte[data.Length];
// Encrypt each byte individually using ReturnByte
for (int i = 0; i < data.Length; i++)
{
output[i] = engine.ReturnByte(data[i]);
}
Console.WriteLine("Ciphertext: " + BitConverter.ToString(output).Replace("-", " "));
// Custom curve parameters (ref: sub_7FF7BA3F7BC0)
// Define the custom prime modulus p
BigInteger p = new BigInteger("c90102faa48f18b5eac1f76bb40a1b9fb0d841712bbe3e5576a7a56976c2baeca47809765283aa078583e1e65172a3fd", 16);
//bool isPrime = p.IsProbablePrime(20);
//Console.WriteLine(isPrime);
// Define coefficients a and b (example values here, replace with actual values for your curve)
BigInteger a = new BigInteger("a079db08ea2470350c182487b50f7707dd46a58a1d160ff79297dcc9bfad6cfc96a81c4a97564118a40331fe0fc1327f", 16);
BigInteger b = new BigInteger("9f939c02a7bd7fc263a4cce416f4c575f28d0c1315c4f0c282fca6709a5f9f7f9c251c9eede9eb1baa31602167fa5380", 16);
//BigInteger order = BigInteger.Zero;
//BigInteger cofactor = BigInteger.Zero;
// Create the custom elliptic curve
Org.BouncyCastle.Math.EC.ECCurve curve = new FpCurve(p, a, b); // order, cofactor);
// Identity point
Org.BouncyCastle.Math.EC.ECPoint identity = curve.Infinity;
// Generator point
BigInteger x_G = new BigInteger("087b5fe3ae6dcfb0e074b40f6208c8f6de4f4f0679d6933796d3b9bd659704fb85452f041fff14cf0e9aa7e45544f9d8", 16);
BigInteger y_G = new BigInteger("127425c1d330ed537663e87459eaa1b1b53edfe305f6a79b184b3180033aab190eb9aa003e02e9dbf6d593c5e3b08182", 16);
Org.BouncyCastle.Math.EC.ECPoint generator = curve.CreatePoint(x_G, y_G);
Console.WriteLine("X: " + generator.AffineXCoord.ToBigInteger().ToString(16));
Console.WriteLine("Y: " + generator.AffineYCoord.ToBigInteger().ToString(16));
/* Definition of identity
Org.BouncyCastle.Math.EC.ECPoint result = generator.Add(identity);
bool isIdentityPreserved = result.Equals(generator);
Console.WriteLine("Is identity preserved (P + O = P)? " + isIdentityPreserved);
// Get Order
Org.BouncyCastle.Math.EC.ECPoint tmp = generator.Add(generator);
int i = 1;
while (tmp != identity) {
tmp = tmp.Add(generator);
Console.WriteLine("X: " + tmp.Normalize().AffineXCoord.ToBigInteger().ToString(16));
Console.WriteLine("Y: " + tmp.Normalize().AffineYCoord.ToBigInteger().ToString(16));
Console.WriteLine(i);
i += 1;
}
Console.WriteLine(i);
*/
SecureRandom secureRandom = new SecureRandom();
int bitLength = 128;
BigInteger randomScalar = new BigInteger(bitLength, secureRandom);
//BigInteger randomScalar = new BigInteger("96f6e8b7f27c4850e4c72e251926aece", 16);
Console.WriteLine("Random BigInteger: " + randomScalar.ToString(16));
Org.BouncyCastle.Math.EC.ECPoint randomPoint = generator.Multiply(randomScalar);
Org.BouncyCastle.Math.EC.ECPoint publicKey = randomPoint.Normalize();
Console.WriteLine("X: " + publicKey.AffineXCoord.ToBigInteger().ToString(16));
Console.WriteLine("Y: " + publicKey.AffineYCoord.ToBigInteger().ToString(16));
// Byte stream representing an EC point (x and y coordinates)
byte[] pointData2 = new byte[]
{
0xb3,0xe5,0xf8,0x9f,0x04,0xd4,0x98,0x34,0xde,0x31,0x21,0x10,0xae,0x05,0xf0,0x64,0x9b,0x3f,0x0b,0xbe,0x29,0x87,0x30,0x4f,0xc4,0xec,0x2f,0x46,0xd6,0xf0,0x36,0xf1,0xa8,0x97,0x80,0x7c,0x4e,0x69,0x3e,0x0b,0xb5,0xcd,0x9a,0xc8,0xa8,0x00,0x5f,0x06,0x85,0x94,0x4d,0x98,0x39,0x69,0x18,0x74,0x13,0x16,0xcd,0x01,0x09,0x92,0x9c,0xb7,0x06,0xaf,0x0c,0xca,0x1e,0xaf,0x37,0x82,0x19,0xc5,0x28,0x6b,0xdc,0x21,0xe9,0x79,0x21,0x03,0x90,0x57,0x3e,0x30,0x47,0x64,0x5e,0x19,0x69,0xbd,0xbc,0xb6,0x67,0xeb
};
// Split the data into x and y coordinates (each 48 bytes for P-384)
byte[] xBytes = new byte[48];
byte[] yBytes = new byte[48];
Array.Copy(pointData2, 0, xBytes, 0, 48);
Array.Copy(pointData2, 48, yBytes, 0, 48);
// Convert x and y to BigInteger
BigInteger x_recv = new BigInteger(1, xBytes); // '1' specifies a positive number
BigInteger y_recv = new BigInteger(1, yBytes);
// Attempt to create the point on the curve
try
{
Org.BouncyCastle.Math.EC.ECPoint point2 = curve.ValidatePoint(x_recv, y_recv);
Console.WriteLine("Point is valid on the curve:");
Console.WriteLine("X: " + point2.AffineXCoord.ToBigInteger().ToString(16));
Console.WriteLine("Y: " + point2.AffineYCoord.ToBigInteger().ToString(16));
Org.BouncyCastle.Math.EC.ECPoint randomPoint2 = point2.Multiply(randomScalar);
Org.BouncyCastle.Math.EC.ECPoint normalizedPoint2 = randomPoint2.Normalize();
Console.WriteLine("X: " + normalizedPoint2.AffineXCoord.ToBigInteger().ToString(16));
Console.WriteLine("Y: " + normalizedPoint2.AffineYCoord.ToBigInteger().ToString(16));
BigInteger xCoord = normalizedPoint2.AffineXCoord.ToBigInteger();
byte[] xCoordBytes = xCoord.ToByteArray();
//byte[] inputBytes = Encoding.UTF8.GetBytes("Hello world");
byte[] hashBytes = SHA512.HashData(xCoordBytes);
StringBuilder hash = new StringBuilder();
foreach (byte bb in hashBytes)
{
hash.Append(bb.ToString("x2"));
}
Console.WriteLine($"SHA-512 Hash of session key X Coord: {hash}");
}
catch (Exception e)
{
Console.WriteLine("The point is not valid on the curve: " + e.Message);
}
try
{
// Connect to the server at localhost:5000
TcpClient client = new TcpClient("192.168.1.6", 31337);
Console.WriteLine("Connected to server");
// Get the network stream for communication
NetworkStream stream = client.GetStream();
// Send a response to the server
byte[] xCoord = publicKey.AffineXCoord.ToBigInteger().ToByteArray();
byte[] yCoord = publicKey.AffineYCoord.ToBigInteger().ToByteArray();
byte[] publicKeyByteX = new byte[48];
byte[] publicKeyByteY = new byte[48];
Buffer.BlockCopy(xCoord, xCoord.Length - 48, publicKeyByteX, 0, 48);
Buffer.BlockCopy(yCoord, yCoord.Length - 48, publicKeyByteY, 0, 48);
stream.Write(publicKeyByteX);
Console.WriteLine("Sent X");
Thread.Sleep(1000);
stream.Write(publicKeyByteY);
Console.WriteLine("Sent Y");
// Receive message from the server
byte[] buffer = new byte[1024];
int bytesRead = stream.Read(buffer); // Blocking read
string receivedMessage = Encoding.UTF8.GetString(buffer, 0, bytesRead);
Console.WriteLine("Received from server: " + receivedMessage);
// Close the stream and the client connection
stream.Close();
client.Close();
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
}
}
}
}
P_session_key = client_rand * P_recv
hash_digest = sha512(P_session_key.x_coord)
chacha_key = hash_digest[:0x20]
chacha_nonce = hash_digest[0x20:0x28]