ใช้ S-box ของ Rijndael


15

S-box ของ Rijndaelเป็นการดำเนินการที่ใช้บ่อยในการเข้ารหัสAESและถอดรหัส โดยทั่วไปแล้วจะใช้งานเป็นตารางค้นหาขนาด 256 ไบต์ เร็วมาก แต่หมายความว่าคุณต้องระบุตารางการค้นหาขนาด 256- ไบต์ในรหัสของคุณ ฉันเดิมพันคนในฝูงชนนี้สามารถทำได้ด้วยรหัสน้อยลงเนื่องจากโครงสร้างทางคณิตศาสตร์พื้นฐาน

เขียนฟังก์ชั่นในภาษาที่คุณชื่นชอบซึ่งใช้ S-box ของ Rijndael รหัสที่สั้นที่สุดชนะ


1
คะแนนโบนัส (upvotes จากฉัน) หากฟังก์ชันผลลัพธ์เป็นเวลาคงที่ (เช่นไม่มีการใช้เส้นทางโค้ดหรือการเข้าถึงอาเรย์หรือสิ่งที่ภาษาของคุณสนับสนุน)
Paŭlo Ebermann

การเข้าถึงอาร์เรย์ @ PaŭloEbermannเป็นเวลาคงที่ในหลาย ๆ ภาษา (มันเป็นการเพิ่มค่า (มาตราส่วน) ให้กับตัวชี้และทำการอ้างอิงมันนี่คือเหตุผลที่ตารางการค้นหาเร็วมาก)
ratchet freak

@ratchetfreak การเข้าถึง Array คือ O (1) แต่เวลาเข้าถึงจริงขึ้นอยู่กับจำนวนการเข้าชมแคชหรือการขาดหายไปซึ่งนำไปสู่การโจมตีช่องทางด้านข้างบน AES
Paŭlo Ebermann

@ PaŭloEbermann แต่คุณสามารถใช้รหัสที่สั้นกว่าเพื่อเติมตารางการค้นหาซึ่งจะเหมาะกับหน้าหน่วยความจำ
Peter Taylor

@ PaŭloEbermannและหากมีการจัดเก็บตารางความยาว 256 ตัวตามรหัส (ตาม enum ที่สร้างขึ้นในเวลารวบรวม) คุณเกือบจะรับประกันว่าจะมีการโจมตีแคช
ratchet freak

คำตอบ:


6

Ruby, 161 ตัวอักษร

R=0..255
S=R.map{|t|t=b=R.select{|y|x=t;z=0;8.times{z^=y*(x&1);x/=2;y*=2};r=283<<8;8.times{r/=2;z^r<z/2&&z^=r};z==1}[0]||0;4.times{|r|t^=b<<1+r^b>>4+r};t&255^99}

เพื่อตรวจสอบผลลัพธ์ที่คุณสามารถใช้รหัสต่อไปนี้เพื่อพิมพ์ในรูปแบบตาราง:

S.map{|x|"%02x"%x}.each_slice(16){|l|puts l*' '}

7

GolfScript 60 ตัวอักษร

{[[0 1{.283{1$2*.255>@*^}:r~^}255*].@?~)={257r}4*99]{^}*}:S;

รหัสนี้กำหนดฟังก์ชั่นที่มีชื่อSเป็นไบต์และใช้ Rijndael S-box กับมัน (นอกจากนี้ยังใช้ฟังก์ชันตัวช่วยภายในที่ตั้งชื่อrเพื่อบันทึกตัวอักษรสองสามตัว)

การใช้งานนี้ใช้ตารางลอการิทึมเพื่อคำนวณค่าผกผันGF (2 8 ) ตามที่ Thomas Porninแนะนำ หากต้องการบันทึกสองสามตัวตารางลอการิทึมทั้งหมดจะถูกคำนวณใหม่สำหรับแต่ละไบต์อินพุต ถึงอย่างนั้นและถึงแม้ว่า GolfScript จะเป็นภาษาที่ช้ามากโดยทั่วไปรหัสนี้ใช้เวลาเพียง 10 ms ในการประมวลผลไบต์บนแล็ปท็อปเครื่องเก่าของฉัน การประมาณค่าตารางลอการิทึม (ตามL) จะเพิ่มความเร็วได้สูงถึงประมาณ 0.5 มิลลิวินาทีต่อไบต์ด้วยค่าใช้จ่ายที่น้อยกว่าสามตัวอักษร:

[0 1{.283{1$2*.255>@*^}:r~^}255*]:L;{[L?~)L={257r}4*99]{^}*}:S;

เพื่อความสะดวกนี่คือสายรัดทดสอบแบบง่ายที่เรียกใช้ฟังก์ชั่นSตามที่นิยามไว้ข้างต้นเพื่อคำนวณและพิมพ์ S-box ทั้งหมดในรูปหกเหลี่ยมเช่นเดียวกับใน Wikipedia :

"0123456789abcdef"1/:h; 256, {S .16/h= \16%h= " "++ }% 16/ n*

ลองใช้รหัสนี้ทางออนไลน์

(การสาธิตออนไลน์จะคำนวณตารางลอการิทึมล่วงหน้าเพื่อหลีกเลี่ยงการใช้เวลามากเกินไปถึงกระนั้นเว็บไซต์ GolfScript ออนไลน์บางครั้งก็อาจจะหมดเวลาแบบสุ่มนี่เป็นปัญหาที่ทราบกันดีของไซต์และการโหลดซ้ำมักแก้ไขได้)

คำอธิบาย:

เริ่มจากการคำนวณตารางลอการิทึมและโดยเฉพาะกับฟังก์ชันตัวช่วยr:

{1$2*.255>@*^}:r

ฟังก์ชันนี้ใช้สองอินพุตในสแต็ก: ไบต์และบิตมัสค์ลด (ค่าคงที่ระหว่าง 256 และ 511) มันทำซ้ำอินพุตไบต์คูณสำเนาด้วย 2 และหากผลลัพธ์เกิน 255 XOR จะใช้ bitmask เพื่อนำกลับมาต่ำกว่า 256

ภายในโค้ดสร้างตารางบันทึกฟังก์ชันrจะถูกเรียกใช้พร้อมกับการลด bitmask 283 = 0x11b (ซึ่งสอดคล้องกับRijndael GF (2 8 ) การลดพหุนาม x 8 + x 4 + x 3 + x + 1) และผลลัพธ์คือ XORed กับไบต์ดั้งเดิมคูณได้อย่างมีประสิทธิภาพด้วย 3 (= x + 1, เป็นพหุนาม) ในเขตข้อมูล Rijndael การคูณนี้ทำซ้ำ 255 ครั้งเริ่มจากไบต์ 1 และผลลัพธ์ (บวกศูนย์เริ่มต้นไบต์) จะถูกรวบรวมลงในอาร์เรย์องค์ประกอบ 257 Lที่มีลักษณะเช่นนี้ (ละเว้นส่วนตรงกลาง):

[0 1 3 5 15 17 51 85 255 26 46 ... 180 199 82 246 1]

เหตุผลที่มี 257 องค์ประกอบคือด้วย 0 ที่ได้รับการเติมและมี 1 เกิดขึ้นสองครั้งเราสามารถหาค่าผกผันแบบแยกส่วนของไบต์ที่กำหนดได้ง่ายๆโดยค้นหาดัชนี (zero-based) ในอาเรย์นี้ลบมันและมองหา ขึ้นไบต์ที่ดัชนีเมื่อตะกี้ในอาร์เรย์เดียวกัน (ใน GolfScript เช่นเดียวกับในภาษาการเขียนโปรแกรมอื่น ๆ ดัชนีอาเรย์เชิงลบจะนับถอยหลังจากจุดสิ้นสุดของอาเรย์) แน่นอนว่านี่คือสิ่งที่รหัสL?~)L=ที่จุดเริ่มต้นของฟังก์ชั่นSทำ

ส่วนที่เหลือของรหัสเรียกฟังก์ชั่นผู้ช่วยrสี่ครั้งด้วยการลด bitmask 257 = 2 8 + 1 เพื่อสร้างสำเนาแบบหมุนสี่บิตของไบต์อินพุตแบบ inverted สิ่งเหล่านี้ถูกรวบรวมไว้ในอาร์เรย์พร้อมกับค่าคงที่ 99 = 0x63 และ XORed ร่วมกันเพื่อสร้างผลลัพธ์สุดท้าย


7

x86-64 รหัสเครื่อง - 23 22 20 19 ไบต์

ใช้ชุดคำสั่ง AES-NI

66 0F 6E C1          movd        xmm0,ecx
66 0F 38 DD C1       aesenclast  xmm0,xmm1
0F 57 C1             xorps       xmm0,xmm1  
66 0F 3A 14 C0 00    pextrb      eax,xmm0,0
C3                   ret

การใช้การเรียกการประชุม Windows ใช้เวลาเป็นไบต์และส่งออกไบต์ ไม่จำเป็นต้องย้อนกลับShiftRowsเนื่องจากไม่มีผลกับไบต์แรก


2
ครั้งหนึ่ง x86_64 ดึง mathematica และสร้างขึ้นมาเพื่อสิ่งนั้น
moonheart08

6

สามารถสร้างตารางได้โดยไม่ต้องคำนวณค่า inverses ในฟิลด์ จำกัด GF (256) โดยใช้ลอการิทึม มันจะมีลักษณะเช่นนี้ (รหัส Java ใช้intเพื่อหลีกเลี่ยงปัญหากับbyteประเภทที่ลงนาม):

int[] t = new int[256];
for (int i = 0, x = 1; i < 256; i ++) {
    t[i] = x;
    x ^= (x << 1) ^ ((x >>> 7) * 0x11B);
}
int[] S = new int[256];
S[0] = 0x63;
for (int i = 0; i < 255; i ++) {
    int x = t[255 - i];
    x |= x << 8;
    x ^= (x >> 4) ^ (x >> 5) ^ (x >> 6) ^ (x >> 7);
    S[t[i]] = (x ^ 0x63) & 0xFF;
}

แนวคิดคือ 3 เป็นตัวสร้างแบบหลายค่าของ GF (256) * ตารางt[]เป็นเช่นนั้นt[x]จะเท่ากับ 3 x ; ตั้งแต่วันที่ 3 255 = 1 เราได้รับที่ 1 / (3 x ) = 3 255 x


ไม่ควรจะเป็น0x1B(หนึ่งในตัวอักษรฐานสิบหก) แทนที่จะเป็น0x11B
วงล้อประหลาด

@ ratchetfreak: ไม่ต้องเป็น 0x11B (ฉันลอง) intประเภทเป็น 32 บิตใน Java; ฉันต้องยกเลิกบิตที่สูงขึ้น
โทมัสพริน

อาไม่รู้ตัวเลย
วงล้อประหลาด

นั่นคือ >>> แทนที่จะเป็น >> ในบรรทัด 4 หรือไม่?
Joe Z.

@ JoeZeng: ทั้งสองจะทำงาน ใน Java, '>>>' คือ "shift ที่ไม่ได้ลงชื่อ", ">>" คือ "shift shift" พวกเขาแตกต่างกันโดยวิธีจัดการบิต ที่นี่ค่าจะไม่กว้างพอที่จะให้เครื่องหมายบิตเป็นศูนย์ดังนั้นจึงไม่มีความแตกต่างอย่างแท้จริง
โทมัสพริน

6

GolfScript (82 ตัวอักษร)

{256:B,{0\2${@1$3$1&*^@2/@2*.B/283*^}8*;;1=},\+0=B)*:A.2*^4A*^8A*^128/A^99^B(&}:S;

ใช้ตัวแปรทั่วโลกAและและสร้างฟังก์ชั่นเป็นตัวแปรทั่วโลกBS

การผกผันกาลัวส์เป็นสัตว์เดรัจฉาน ฉันทดลองกับการมีmulฟังก์ชั่นแยกซึ่งสามารถนำกลับมาใช้ใหม่สำหรับการแปลงเลียนแบบการโพสต์ผกผันได้ แต่มันกลับกลายเป็นว่ามีราคาแพงกว่าเนื่องจากพฤติกรรมล้นที่แตกต่างกัน

นี่ช้าเกินไปสำหรับการสาธิตออนไลน์ - มันจะหมดเวลาแม้แต่ในสองแถวแรกของตาราง


ของฉันเร็วขึ้น (และสั้นกว่า) +1 อย่างไรก็ตาม
Ilmari Karonen

4

Python 176 ตัวอักษร

คำตอบนี้สำหรับคำถามแสดงความคิดเห็นของPaŭlo Ebermann เกี่ยวกับการทำให้ฟังก์ชั่นเวลาคงที่ รหัสนี้เหมาะกับการเรียกเก็บเงิน

def S(x):
 i=0
 for y in range(256):
  p,a,b=0,x,y
  for j in range(8):p^=b%2*a;a*=2;a^=a/256*283;b/=2
  m=(p^1)-1>>8;i=y&m|i&~m
 i|=i*256;return(i^i/16^i/32^i/64^i/128^99)&255

การคูณด้วยค่าคงที่นั้นขึ้นอยู่กับแพลตฟอร์ม (แม้แต่บนแพลตฟอร์ม 32 บิตเช่น ARM Cortex M0) ดูคำถามที่เกี่ยวข้อง
fgrieu

1
@fgrieu แน่นอน แต่สิ่งเหล่านี้เป็นทวีคูณโดยค่าคงที่ซึ่งสามารถนำมาใช้อย่างง่ายดายในเวลาคงที่โดยใช้กะและเพิ่ม
Keith Randall

2

d

ubyte[256] getLookup(){

    ubyte[256] t=void;
    foreach(i;0..256){
        t[i] = x;
        x ^= (x << 1) ^ ((x >>> 7) * 0x1B);
    }
    ubyte[256] S=void;
    S[0] = 0x63;
    foreach(i;0..255){
        int x = t[255 - i];
        x |= x << 8;
        x ^= (x >> 4) ^ (x >> 5) ^ (x >> 6) ^ (x >> 7);
        S[t[i]] = cast(ubyte)(x & 0xFF) ^ 0x63 ;
    }
    return S;

}

นี้สามารถสร้างตารางการค้นหาในเวลารวบรวมฉันสามารถบันทึกบางอย่างโดยการทำให้ ubyte เป็นพารามิเตอร์ทั่วไป

แก้ไขโดยตรงubyteไปยังubyteโดยไม่ต้องค้นหาอาร์เรย์ไม่มีการแยกและลูปที่ไม่สามารถควบคุมได้อย่างเต็มที่

B[256] S(B:ubyte)(B i){
    B mulInv(B x){
        B r;
        foreach(i;0..256){
            B p=0,h,a=i,b=x;
            foreach(c;0..8){
                p^=(b&1)*a;
                h=a>>>7;
                a<<=1;
                a^=h*0x1b;//h is 0 or 1
                b>>=1;
            }
            if(p==1)r=i;//happens 1 or less times over 256 iterations
        }
        return r;
    }
    B s= x=mulInv(i);
    foreach(j,0..4){
        x^=(s=s<<1|(s>>>7));
    }
    return x^99;
}

edit2 ใช้ @Thomas 'algo เพื่อสร้างตารางการค้นหา


0

Stax , 53 ไบต์

ë■ÿÆ♂◄º5hUø√!«mr¿¡ƒR3Å←ç≥#/$taJkαn∩╓▒ÿ╔τy╫π§╪S♫╔┴H╔║Ö

เรียกใช้และแก้ไขข้อบกพร่อง

ฉันไม่มีความเข้าใจเป็นพิเศษเกี่ยวกับกล่อง S นี่คือการแปลงของโทมัส Pornin ของ (อายุ 8 ปี!) วิธีการแก้ปัญหา

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.