Skip to content

Commit cfef866

Browse files
committed
Autentikasi SCRAM-SHA-256 (RFC 5802/7677), terverifikasi vektor uji
1 parent 1b36826 commit cfef866

3 files changed

Lines changed: 55 additions & 4 deletions

File tree

‎README.md‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,16 @@ kalau db < 0 {
3939

4040
## Autentikasi
4141

42-
Didukung: `trust` (tanpa sandi), `cleartext`, `md5`. SCRAM-SHA-256 belum (memerlukan primitif kripto tambahan) — gunakan `md5`/`trust` di `pg_hba.conf` untuk sementara.
42+
Didukung: `trust`, `cleartext`, `md5`, dan **`scram-sha-256`** (default PostgreSQL modern). Implementasi SCRAM (RFC 5802/7677) memakai builtin kripto `pbkdf2`/`hmacSha256Raw`/`sha256Raw`/`xor`/`base64` — ClientProof terverifikasi terhadap vektor uji RFC 7677.
4343

4444
## Struktur
4545

4646
```
4747
modul-postgres/
4848
tenun.json
49-
src/postgres.tenun
49+
src/
50+
postgres.tenun koneksi, query (sederhana & berparameter), parser
51+
scram.tenun autentikasi SCRAM-SHA-256
5052
contoh/contoh.tenun
5153
.github/workflows/ci.yml
5254
```

‎src/postgres.tenun‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Auth: trust (0), cleartext (3), md5 (5). SCRAM (10) belum didukung.
33
// Dibangun di atas builtin inti: sambung/kirim/terimaPasti, keByte/bacaInt, md5, potong.
44

5+
impor "./scram.tenun";
6+
57
// Baca satu pesan: type(1) + panjang(4, big-endian) + body. Kembalikan pesan utuh.
68
fungsi pg_baca(s: bulat): teks {
79
biar hdr: teks = terimaPasti(s, 5);
@@ -43,9 +45,13 @@ fungsi pg_sambung(inang: teks, port: bulat, pengguna: teks, sandi: teks, db: tek
4345
biar tok: teks = "md5" + md5(inner + salt) + nul;
4446
kirim(s, pg_pesan(112, tok));
4547
}
46-
kalau at == 10 { // SASL/SCRAM — belum didukung
47-
kembali -1;
48+
kalau at == 10 { // SASL: mulai SCRAM-SHA-256
49+
pg_scram_mulai(s);
50+
}
51+
kalau at == 11 { // SASLContinue: server-first
52+
pg_scram_lanjut(s, sandi, potong(m, 9, panjangTeks(m) - 9));
4853
}
54+
// at == 12 (SASLFinal) diabaikan; lanjut ke AuthenticationOk + ReadyForQuery
4955
}
5056
}
5157
kembali s;

‎src/scram.tenun‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// SCRAM-SHA-256 (RFC 5802 / 7677) untuk autentikasi PostgreSQL.
2+
// Memakai builtin kripto: pbkdf2, hmacSha256Raw, sha256Raw, xor, base64, dariBase64, acak.
3+
4+
biar pg_nonce: teks = "";
5+
biar pg_cfirst_bare: teks = "";
6+
7+
// ClientProof (base64) dari sandi, salt mentah, iterasi, dan AuthMessage.
8+
fungsi pg_scram_proof(sandi: teks, salt: teks, iter: bulat, authMessage: teks): teks {
9+
biar sp: teks = pbkdf2(sandi, salt, iter); // SaltedPassword
10+
biar ck: teks = hmacSha256Raw(sp, "Client Key"); // ClientKey
11+
biar sk: teks = sha256Raw(ck); // StoredKey
12+
biar cs: teks = hmacSha256Raw(sk, authMessage); // ClientSignature
13+
kembali base64(xor(ck, cs)); // ClientProof
14+
}
15+
16+
// Langkah 1: kirim SASLInitialResponse (client-first).
17+
fungsi pg_scram_mulai(s: bulat): kosong {
18+
pg_nonce = acak(18);
19+
pg_cfirst_bare = "n=,r=" + pg_nonce;
20+
biar cfirst: teks = "n,," + pg_cfirst_bare;
21+
biar nul: teks = keByte(0, 1, salah);
22+
biar body: teks = "SCRAM-SHA-256" + nul + keByte(panjangTeks(cfirst), 4, benar) + cfirst;
23+
kirim(s, pg_pesan(112, body)); // 'p'
24+
}
25+
26+
// Langkah 2: terima server-first, hitung proof, kirim client-final.
27+
fungsi pg_scram_lanjut(s: bulat, sandi: teks, serverFirst: teks): kosong {
28+
biar bagian: []teks = pisah(serverFirst, ",");
29+
biar rnonce: teks = "";
30+
biar saltB64: teks = "";
31+
biar iter: bulat = 4096;
32+
untuk i dari 0 sampai panjang(bagian) {
33+
biar f: teks = bagian[i];
34+
kalau mulaiDengan(f, "r=") { rnonce = potong(f, 2, panjangTeks(f) - 2); }
35+
kalau mulaiDengan(f, "s=") { saltB64 = potong(f, 2, panjangTeks(f) - 2); }
36+
kalau mulaiDengan(f, "i=") { iter = keBulat(potong(f, 2, panjangTeks(f) - 2)); }
37+
}
38+
biar salt: teks = dariBase64(saltB64);
39+
biar cfinal_np: teks = "c=biws,r=" + rnonce;
40+
biar authMessage: teks = pg_cfirst_bare + "," + serverFirst + "," + cfinal_np;
41+
biar proof: teks = pg_scram_proof(sandi, salt, iter, authMessage);
42+
kirim(s, pg_pesan(112, cfinal_np + ",p=" + proof)); // 'p'
43+
}

0 commit comments

Comments
 (0)