바이트 예산을 가진 사람들을위한 간단한 암호화


17

개요

목표는 RC4 암호화를 구현하는 것입니다. Ron Rivest (RSA 명성의)가 발명 한 RC4 암호화는 전장의 군인들이 기억에서 구현할 수있을 정도로 안전하면서도 간단하게 설계되었습니다. 현재 RC4에 대한 몇 가지 공격이 있지만 오늘날에도 많은 곳에서 사용되고 있습니다.

프로그램은 키와 일부 데이터가있는 단일 문자열을 허용해야합니다. 이 형식으로 제공됩니다.

\x0Dthis is a keythis is some data to encrypt

첫 번째 바이트는 키 길이를 나타냅니다. 키가 255 바이트를 넘지 않고 1 바이트를 넘지 않는 것으로 가정 할 수 있습니다. 데이터는 임의로 길 수 있습니다.

프로그램이 키를 처리 한 다음 암호화 된 데이터를 반환해야합니다. RC4 암호화 및 암호 해독은 동일하므로 암호 키를 "암호화"하기 위해 동일한 키를 사용하면 원래 일반 텍스트를 반환해야합니다.

RC4 작동 방식

초기화

RC4의 초기화는 매우 간단합니다. 256 바이트의 상태 배열은 0에서 255까지의 모든 바이트로 초기화됩니다.

S = [0, 1, 2, 3, ..., 253, 254, 255]

키 처리

상태 값은 키를 기준으로 교체됩니다.

j = 0
for i from 0 to 255
    j = (j + S[i] + key[i mod keylength]) mod 256
    swap S[i] and S[j]

암호화

암호화는 상태를 사용하여 의사 난수 바이트를 생성 한 다음 데이터에 XOR됩니다. 상태의 값은 지속적으로 교체됩니다.

i = j = 0
for each byte B in data
    i = (i + 1) mod 256
    j = (j + S[i]) mod 256
    swap S[i] and S[j]
    K = S[(S[i] + S[j]) mod 256]
    output K XOR B

예상되는 입력 및 출력

인쇄 할 수없는 문자는 \xAB 형식 됩니다.

입력 : \x01\x00\x00\x00\x00\x00\x00
출력 :\xde\x18\x89A\xa3
출력 (16 진) :de188941a3

입력 : \x0Dthis is a keythis is some data to encrypt
출력 : \xb5\xdb?i\x1f\x92\x96\x96e!\xf3\xae(!\xf3\xeaC\xd4\x9fS\xbd?d\x82\x84{\xcdN
출력 (16 진) :b5db3f691f9296966521f3ae2821f3ea43d49f53bd3f6482847bcd4e

입력 : \x0dthis is a key\xb5\xdb?i\x1f\x92\x96\x96e!\xf3\xae(!\xf3\xeaC\xd4\x9fS\xbd?d\x82\x84{\xcdN
입력 (16 진) : 0d746869732069732061206b6579b5db3f691f9296966521f3ae2821f3ea43d49f53bd3f6482847bcd4e
출력 :this is some data to encrypt

입력 : Sthis is a rather long key because the value of S is 83 so the key length must matchand this is the data to be encrypted
출력 : \x96\x1f,\x8f\xa3%\x9b\xa3f[mk\xdf\xbc\xac\x8b\x8e\xfa\xfe\x96B=!\xfc;\x13`c\x16q\x04\x11\xd8\x86\xee\x07
출력 (16 진) :961f2c8fa3259ba3665b6d6bdfbcac8b8efafe96423d21fc3b13606316710411d886ee07


어떤 출력 모드를 원하십니까? 아니면 어느 것을 선택할 수 있습니까? 진수하는 것이 바람직 할 것이다
andrewarchi

@andrewarchi 출력은 바이트 단위로되어 있으므로 해독을 위해 다시 순환 할 수 있습니다.
Daffy

1
바이트 배열로 입력을받을 수 있습니까?
Arnauld 2012 년

1
@andrewarchi이 표기법은 가독성을위한 것입니다. 프로그램이 output \xde이어야한다면 1 바이트 길이 여야하며 (python ord()또는 javascript를 통해) 숫자로 변환하면 .charCodeAt(0)222 (0xDE)를 반환해야합니다.
Daffy

1
@Arnauld 두 언어는 기본적으로 많은 언어에서 구분할 수 없다고 생각합니다.
Daffy

답변:


3

자바 스크립트 (ES6), 169 168 바이트

바이트 배열로 입력을받습니다. 다른 바이트 배열을 반환합니다.

([l,...s])=>s.slice(l).map(b=>b^S[(S[S[J=J+(t=S[I=I+1&m])&m,I]=x=S[J],J]=t)+x&m],[...S=[...Array(m=255).keys(),m]].map(i=>S[S[i]=S[j=j+(t=S[i])+s[i%l]&m],j]=t,I=J=j=0))

어떻게?

이것은 본질적으로 스펙의 실제 구현입니다.

먼저 입력 배열을 l (키 길이)과 s (페이로드 데이터 : 키 + 메시지) 로 분할합니다 . 그런 다음 실행 순서대로 :

  • 상태 배열 S를 초기화하고 나중에 비트 마스크로 반복적으로 사용되는 m = 255 를 정의 합니다.

    S = [...Array(m = 255).keys(), m]
  • 상태 배열을 섞습니다. 여기서 초기화 된 인덱스 IJ 는 실제로 다음 단계에서 사용됩니다.

    [...S].map(i =>
      S[S[i] = S[j = j + (t = S[i]) + s[i % l] & m], j] = t,
      I = J = j = 0
    )
  • 우리는 암호화를 적용합니다.

    s.slice(l).map(b =>
      b ^ S[
        (S[S[J = J + (t = S[I = I + 1 & m]) & m, I] = x = S[J], J] = t) +
        x & m
      ]
    )
    

테스트 사례


13

138 바이트, 머신 코드 (16 비트 x86)

000000 88 9f 00 02 fe c3 75 f8 b9 01 00 89 fa b4 3f cd
000010 21 86 0d ba 00 03 b4 3f cd 21 89 dd 01 f6 02 9e
000020 00 03 8a 04 00 c3 86 87 00 02 88 04 46 45 39 cd
000030 75 02 31 ed 81 fe 00 03 75 e4 81 ee 00 01 31 db
000040 31 d2 ff c6 81 fe 00 03 75 04 81 ee 00 01 8a 04
000050 00 c3 88 c2 86 87 00 02 88 04 00 c2 89 d7 81 c7
000060 00 02 8a 15 89 d7 89 dd 31 db ba 00 03 b9 01 00
000070 b8 00 3f cd 21 87 fa 30 15 85 c0 74 0b 87 fa 43
000080 b4 40 cd 21 89 eb eb b8 cd 20

실행 중 : codegolf.com에 저장, dosbox :

codegolf.com < input.bin

성공적인 시도

이것이 항목으로 계산되는지는 모르겠지만 16 진수 편집기를 사용하여 수동으로 결정했습니다 . 이 작업에는 컴파일러 가 사용 되지 않았습니다 .

ht 에디터는 실제로 어셈블러를 가지고 있지만 솔직히 말하면 내가 끝내기 전까지는 이것에 대해 알지 못했습니다 ¯ \ _ (ツ) _ / ¯

왜 어떻게

이유 : 주로이 작업을 수행 할 수 있는지 확인하고 싶었습니다.

방법 : NOPs로 채워진 바이트를 작성 하고 간단한 부분으로 다음과 같이 시작했습니다 . 첫 번째 루프를 작성하려고합니다.S 으로 시작했습니다 .0..255 값으로 tate 합니다. 나는 파이썬으로 바꾸고 파이썬 버전을 빨리 작성했다. 다음으로 파이썬 코드를 의사 코드 / 의사 어셈블리로 단순화했습니다. 그런 다음 II는 작은 조각을 쓰려고했습니다. stdin에서 읽는 것이 가장 쉽다고 결정했기 때문에 작은 바이트로 시작하여 작은 바이트로 시작한 다음 암호 읽기 및 키 초기화를 추가했습니다. 어떤 레지스터를 선택할지 알아내는 데 어느 정도 시간이 걸렸습니다.

해독 / 암호화 루프를 추가하는 것은 쉽지만 먼저 단일 바이트 디코딩을 얻은 다음 전체 루프를 추가했습니다.

마지막 단계는 nops명령을 작성할 때 지시 사항 사이에 남은 추가 사항 을 제거하는 것 입니다 (수정 점프가 필요한 경우도 있음).

당신은 내가 여기에서 진행하는 동안 만들려고 작은 갤러리를 볼 수 있습니다 .

해부

이 프로그램은 시작 후 일부 초기 값에 의존합니다 (아래 리소스 참조).

00000000 889f0002                  mov         [bx+0200], bl
00000004 fec3                      inc         bl
00000006 75f8                      jnz         0x0

상태 채우기 (0x200)

00000008 b90100                    mov         cx, 0x1
0000000b 89fa                      mov         dx, di
0000000d b43f                      mov         ah, 0x3f
0000000f cd21                      int         0x21
00000011 860d                      xchg        [di], cl
00000013 ba0003                    mov         dx, 0300
00000016 b43f                      mov         ah, 0x3f
00000018 cd21                      int         0x21

길이 읽기, 비밀번호 읽기, ds : 0x300에 비밀번호 저장

0000001a 89dd                      mov         bp, bx
0000001c 01f6                      add         si, si
0000001e 029e0003                  add         bl, [bp+0300]
00000022 8a04                      mov         al, [si]
00000024 00c3                      add         bl, al
00000026 86870002                  xchg        [bx+0200], al
0000002a 8804                      mov         [si], al
0000002c 46                        inc         si
0000002d 45                        inc         bp
0000002e 39cd                      cmp         bp, cx
00000030 7502                      jnz         0x34
00000032 31ed                      xor         bp, bp
00000034 81fe0003                  cmp         si, 0300
00000038 75e4                      jnz         0x1e

키로 상태 초기화 ( BPSI를 통과하는 데 사용되고 상태를 통과하는 데 사용됨)

0000003a 81ee0001                  sub         si, 0100
0000003e 31db                      xor         bx, bx
00000040 31d2                      xor         dx, dx
00000042 ffc6                      inc         si
00000044 81fe0003                  cmp         si, 0300
00000048 7504                      jnz         0x4e
0000004a 81ee0001                  sub         si, 0100
0000004e 8a04                      mov         al, [si]
00000050 00c3                      add         bl, al
00000052 88c2                      mov         dl, al
00000054 86870002                  xchg        [bx+0200], al
00000058 8804                      mov         [si], al
0000005a 00c2                      add         dl, al
0000005c 89d7                      mov         di, dx
0000005e 81c70002                  add         di, 0200
00000062 8a15                      mov         dl, [di]

의사 난수 생성 (in DL, DH0 thx ~ x 또는 0x140)

00000064 89d7                      mov         di, dx      
00000066 89dd                      mov         bp, bx      
00000068 31db                      xor         bx, bx      
0000006a ba0003                    mov         dx, 0300    
0000006d b90100                    mov         cx, 0x1     
00000070 b8003f                    mov         ax, 3f00    
00000073 cd21                      int         0x21        
00000075 87fa                      xchg        dx, di      
00000077 3015                      xor         [di], dl    
00000079 85c0                      test        ax, ax      
0000007b 740b                      jz          0x88        
0000007d 87fa                      xchg        dx, di      
0000007f 43                        inc         bx          
00000080 b440                      mov         ah, 0x40    
00000082 cd21                      int         0x21        
00000084 89eb                      mov         bx, bp      
00000086 ebb8                      jmp         0x40        
00000088 cd20                      int         0x20        
  • 우리가 보존해야 할 가치를 저장하십시오 ( SI-ints는 그것을 만지지 않을 것입니다 BX)
  • 입력에서 문자를 읽거나 xor it
  • 스트림이 끝나면 종료
  • 출력 디코딩 된 문자
  • 값을 복원
  • 0x40으로 루프 (xor on 재사용 DX)

추신 : 아마이게 더 짧을 수도 있지만,이 날은 4 일이 걸렸으므로 다른 것을 보내고 싶은지 확실하지 않습니다 ...

도구 및 리소스


4

C (gcc) , 193188182178171172 바이트

f(x,l)int*x;{unsigned char*X=x,i=0,j=0,S[256],t;for(;S[i]=++i;);for(;t=S[i],S[i]=S[j+=t+X[1+i%*X]],S[j]=t,t=++i;);for(X+=*X;l--;S[i]-=S[t]=j)*++X^=S[S[i]+=S[t+=j=S[++i]]];}

온라인으로 사용해보십시오!

편집 : 이제 127 바이트보다 긴 키로 작동합니다.

Edit2 : TIO 링크에 129 바이트 키가있는 테스트 케이스가 추가되었습니다.

약간 덜 골프 버전

f(x,l)int*x;{
  unsigned char*X=x,i=0,j=0,S[256],t;
  // initialize state
  for(;S[i]=++i;);
  // key processing
  for(;t=S[i],S[i]=S[j+=t+X[1+i%*X]],S[j]=t,t=++i;);
  // encrypt
  for(X+=*X;l--;S[i]-=S[t]=j)
    *++X^=S[S[i]+=S[t+=j=S[++i]]];
}

일반적인 C 컴파일러의 버그를 두려워하지 않습니까? 정의되지 않은 동작입니다. s [i] = ++ i? 예, 아마도 컴파일러가 사용하는 것이 중요하다는 것을 알고 있습니다 ...
RosLuP

"키 처리"로 작성된 부분 키의 경우 <= 256 바이트 ... (다른 문자는 계산 및 스왑에 영향을 미치지 않기 때문에)
RosLuP

그리고 인수에 int * 대신 char *를 사용하면 왜 좋지 않습니까? 129 바이트 길이 키에서도 괜찮아 보입니다 ... 정의되지 않은 동작 인 것 같습니다
RosLuP

4

CPU x86 명령어 세트, 133 바이트

000009F8  53                push ebx
000009F9  56                push esi
000009FA  57                push edi
000009FB  55                push ebp
000009FC  55                push ebp
000009FD  BF00010000        mov edi,0x100
00000A02  29FC              sub esp,edi
00000A04  8B6C3C18          mov ebp,[esp+edi+0x18]
00000A08  31DB              xor ebx,ebx
00000A0A  8A5D00            mov bl,[ebp+0x0]
00000A0D  45                inc ebp
00000A0E  31C0              xor eax,eax
00000A10  880404            mov [esp+eax],al
00000A13  40                inc eax
00000A14  39F8              cmp eax,edi
00000A16  72F8              jc 0xa10
00000A18  31F6              xor esi,esi
00000A1A  31C9              xor ecx,ecx
00000A1C  89F0              mov eax,esi
00000A1E  31D2              xor edx,edx
00000A20  F7F3              div ebx
00000A22  8A0434            mov al,[esp+esi]
00000A25  02441500          add al,[ebp+edx+0x0]
00000A29  00C1              add cl,al
00000A2B  8A0434            mov al,[esp+esi]
00000A2E  8A140C            mov dl,[esp+ecx]
00000A31  88040C            mov [esp+ecx],al
00000A34  881434            mov [esp+esi],dl
00000A37  46                inc esi
00000A38  39FE              cmp esi,edi
00000A3A  72E0              jc 0xa1c
00000A3C  8B443C1C          mov eax,[esp+edi+0x1c]
00000A40  01E8              add eax,ebp
00000A42  722F              jc 0xa73
00000A44  48                dec eax
00000A45  89C6              mov esi,eax
00000A47  01DD              add ebp,ebx
00000A49  31C0              xor eax,eax
00000A4B  31D2              xor edx,edx
00000A4D  31C9              xor ecx,ecx
00000A4F  39F5              cmp ebp,esi
00000A51  7320              jnc 0xa73
00000A53  FEC2              inc dl
00000A55  8A0414            mov al,[esp+edx]
00000A58  00C1              add cl,al
00000A5A  8A1C0C            mov bl,[esp+ecx]
00000A5D  88040C            mov [esp+ecx],al
00000A60  881C14            mov [esp+edx],bl
00000A63  00D8              add al,bl
00000A65  8A1C04            mov bl,[esp+eax]
00000A68  8A4500            mov al,[ebp+0x0]
00000A6B  30D8              xor al,bl
00000A6D  884500            mov [ebp+0x0],al
00000A70  45                inc ebp
00000A71  EBDC              jmp short 0xa4f
00000A73  01FC              add esp,edi
00000A75  5D                pop ebp
00000A76  5D                pop ebp
00000A77  5F                pop edi
00000A78  5E                pop esi
00000A79  5B                pop ebx
00000A7A  C20800            ret 0x8
00000A7D

A7D-9F8 = 85h = 133 바이트이지만 동일한 함수 결과 130 바이트의 선행 바이트 수가 있기 때문에 계산에 문제가 없는지 모르겠습니다. "cript"라는 함수의 첫 번째 argumenti는 문자열입니다. 두 번째 인수 i는 문자열 길이입니다 (첫 번째 바이트 + 키 길이 + 메시지 길이). 아래에는 해당 암호 루틴을 얻기위한 어셈블리 언어 파일이 있습니다.

; nasmw -fobj  this.asm

section _DATA use32 public class=DATA
global cript
section _TEXT use32 public class=CODE

cript:    
      push    ebx
      push    esi
      push    edi
      push    ebp
      push    ebp
      mov     edi,  256
      sub     esp,  edi
      mov     ebp,  dword[esp+  edi+24]
      xor     ebx,  ebx
      mov     bl,  [ebp]
      inc     ebp
      xor     eax,  eax
.1:   mov     [esp+eax],  al
      inc     eax
      cmp     eax,  edi
      jb      .1
      xor     esi,  esi
      xor     ecx,  ecx
.2:   mov     eax,  esi
      xor     edx,  edx
      div     ebx
      mov     al,  [esp+esi]
      add     al,  [ebp+edx]
      add     cl,  al
      mov     al,  [esp+esi]
      mov     dl,  [esp+ecx]
      mov     [esp+ecx],  al
      mov     [esp+esi],  dl
      inc     esi
      cmp     esi,  edi
      jb      .2
      mov     eax,  dword[esp+  edi+28]
      add     eax,  ebp
      jc      .z
      dec     eax
      mov     esi,  eax
      add     ebp,  ebx
      xor     eax,  eax
      xor     edx,  edx
      xor     ecx,  ecx
.3:   cmp     ebp,  esi
      jae     .z
      inc     dl
      mov     al,  [esp+edx]
      add     cl,  al
      mov     bl,  [esp+ecx]
      mov     [esp+ecx],  al
      mov     [esp+edx],  bl ; swap S[c] S[r]
      add     al,  bl
      mov     bl,  [esp+eax]
      mov     al,  [ebp]
      xor     al,  bl
      mov     [ebp],  al
      inc     ebp
      jmp     short  .3
.z:       
      add     esp,  edi
      pop     ebp
      pop     ebp
      pop     edi
      pop     esi
      pop     ebx
      ret     8

확인 결과를 위해 C 파일 아래 :

// Nasmw  -fobj  fileasm.asm
// bcc32 -v filec.c fileasm.obj
#include <stdio.h>

void _stdcall cript(char*,unsigned);

char es1[]="\x01\x00\x00\x00\x00\x00\x00";
char es2[]="\x0Dthis is a keythis is some data to encrypt";
char es3[]="\x0dthis is a key\xb5\xdb?i\x1f\x92\x96\226e!\xf3\xae(!\xf3\xea\x43\xd4\x9fS\xbd?d\x82\x84{\xcdN";
char es4[]="Sthis is a rather long key because the value of S is 83 so the key length must matchand this is the data to be encrypted";

void printMSGKeyC(unsigned char* a, unsigned len)
{unsigned i,j,k;
 unsigned char *p,*end;

 printf("keylen = %u\nKey    = [", (unsigned)*a);
 for(i=1, j=*a;i<=j;++i) printf("%c", a[i]);
 printf("]\nMessage= [");
 for(p=a+i,end=a+len-1;p<end;++p)printf("%c", *p);
 printf("]\n");
}

void printMSGKeyHex(unsigned  char* a, unsigned len)
{unsigned i,j,k;
 unsigned char *p,*end;

 printf("keylen = %u\nKey    = [", (unsigned)*a);
 for(i=1, j=*a;i<=j;++i) printf("%02x", a[i]);
 printf("]\nMessage= [");
 for(p=a+i,end=a+len-1;p<end;++p)printf("%02x", *p);
 printf("]\n");
}


main()
{printf("sizeof \"%s\"= %u [so the last byte 0 is in the count]\n", "this", sizeof "this");

 printf("Input:\n");
 printMSGKeyHex(es1, sizeof es1);
 cript(es1,  (sizeof es1)-1);
 printf("Afther I cript:\n");
 printMSGKeyHex(es1, sizeof es1);

 printf("Input:\n");
 printMSGKeyC(es2, sizeof es2);
 printMSGKeyHex(es2, sizeof es2);
 cript(es2,  (sizeof es2)-1);
 printf("Afther I cript:\n");
 printMSGKeyC(es2, sizeof es2);
 printMSGKeyHex(es2, sizeof es2);
 cript(es2,  (sizeof es2)-1);
 printf("Afther II cript:\n");
 printMSGKeyC(es2, sizeof es2);
 printMSGKeyHex(es2, sizeof es2);
 printf("----------------------\n");

 printf("Input:\n");
 printMSGKeyHex(es3, sizeof es3);
 cript(es3,  (sizeof es3)-1);
 printf("Afther I cript:\n");
 printMSGKeyHex(es3, sizeof es3);
 printf("----------------------\n");

 printf("Input:\n");
 printMSGKeyHex(es4, sizeof es4);
 cript(es4,  (sizeof es4)-1);
 printf("Afther I cript:\n");
 printMSGKeyHex(es4, sizeof es4);
 cript(es4,  (sizeof es4)-1);
 printf("Afther II cript:\n");
 printMSGKeyHex(es4, sizeof es4);

 return 0;
}

결과 :

 sizeof "this"= 5 [so the last byte 0 is in the count]
Input:
keylen = 1
Key    = [00]
Message= [0000000000]
Afther I cript:
keylen = 1
Key    = [00]
Message= [de188941a3]
Input:
keylen = 13
Key    = [this is a key]
Message= [this is some data to encrypt]
keylen = 13
Key    = [746869732069732061206b6579]
Message= [7468697320697320736f6d65206461746120746f20656e6372797074]
Afther I cript:
keylen = 13
Key    = [this is a key]
Message= [Á█?iÆûûe!¾«(!¾ÛCȃS¢?déä{═N]
keylen = 13
Key    = [746869732069732061206b6579]
Message= [b5db3f691f9296966521f3ae2821f3ea43d49f53bd3f6482847bcd4e]
Afther II cript:
keylen = 13
Key    = [this is a key]
Message= [this is some data to encrypt]
keylen = 13
Key    = [746869732069732061206b6579]
Message= [7468697320697320736f6d65206461746120746f20656e6372797074]
----------------------
Input:
keylen = 13
Key    = [746869732069732061206b6579]
Message= [b5db3f691f9296966521f3ae2821f3ea43d49f53bd3f6482847bcd4e]
Afther I cript:
keylen = 13
Key    = [746869732069732061206b6579]
Message= [7468697320697320736f6d65206461746120746f20656e6372797074]
----------------------
Input:
keylen = 83
Key    = [74686973206973206120726174686572206c6f6e67206b65792062656361757365207468652076616c7565206f66205320697320383320736f20746865206b6579206c656e677468206d757374206d61746368]
Message= [616e64207468697320697320746865206461746120746f20626520656e63727970746564]
Afther I cript:
keylen = 83
Key    = [74686973206973206120726174686572206c6f6e67206b65792062656361757365207468652076616c7565206f66205320697320383320736f20746865206b6579206c656e677468206d757374206d61746368]
Message= [961f2c8fa3259ba3665b6d6bdfbcac8b8efafe96423d21fc3b13606316710411d886ee07]
Afther II cript:
keylen = 83
Key    = [74686973206973206120726174686572206c6f6e67206b65792062656361757365207468652076616c7565206f66205320697320383320736f20746865206b6579206c656e677468206d757374206d61746368]
Message= [616e64207468697320697320746865206461746120746f20626520656e63727970746564]

3

자바 스크립트 (ES6), 262 바이트

나는 체인 함수 만 사용하는 것을 고려했지만 https://gist.github.com/farhadi/2185197에서 주어진 알고리즘을 골라 내도록 선택했습니다 .

A=>eval(`for(C=A[c='charCodeAt']
(),K=A.slice(1,++C),T=A.slice(C),i=j=k=l=m=y=0,s=[],r=[],a=256;i<a;)s[i]=i++
for(;j<a;){t=s[k=(k+s[j]+K[c](j%K.length))%a]
s[k]=s[j]
s[j++]=t}for(;y<T.length;){r[y]=T[c](y++)^s[((t=s[m=(m+s[l=++l%a])%a])+
(s[m]=s[l]))%a]
s[l]=t}r`)

덜 골프

A=>{
  C=A.charCodeAt()
  K=A.slice(1,++C)
  T=A.slice(C)
  for(i=j=k=l=m=y=0,s=[],r=[];i<256;)s[i]=i++
  for(;j<256;){
    t=s[k=(k+s[j]+K.charCodeAt(j%K.length))%256];
    s[k]=s[j];
    s[j++]=t;
  }
  for(;y<T.length;){
    t=s[m=(m+s[l=(l+1)%256])%256];
    s[m]=s[l];
    s[l]=t;
    r[y]=T.charCodeAt(y++)^s[(s[l]+s[m])%256];
  }
  return r;
}


2
+1 사람들이 골프 코드에 대한 설명을 포함 할 때 항상 감사합니다.
Daffy

2

파이썬 2 , 203 바이트

def f(x):
	def h():S[i],S[j]=S[j],S[i]
	m=256;x=map(ord,x);S=range(m);l=x.pop(0);j=0
	for i in S[:]:j=(j+S[i]+x[i%l])%m;h()
	i=j=0
	for b in x[l:]:i=(i+1)%m;j=(j+S[i])%m;h();yield chr(S[(S[i]+S[j])%m]^b)

온라인으로 사용해보십시오!

f 문자열 생성기 (반복 가능)입니다.

언 골프 드 :

def f(x):
    def h():
        S[i], S[j] = S[j], S[i]  # we have to do this two times
    m = 256  # used often
    x = map(ord, x)  # get numbers to do stuff with
    S = range(m)  # init State
    l = x.pop(0)  # get key length and remove the first byte in one go
    j = 0
    for i in S[:]:  # shorter than range(256)
        j = (j + S[i] + x[i%l]) % m
        h()
    i = j = 0
    for b in x[l:]:  # data comes after the key
        i = (i+1) % m
        j = (j+S[i]) % m
        h()
        yield chr(S[(S[i]+S[j]) % m] ^ b)  # convert to str again

1

루비, 234 바이트

테스트되지 않았습니다.

->s{l=s[0].ord;k=s[1..l];i=s[l+1..-1];o='';s=[*0..255];i,j,q=0;256.times{|i|j=(j+s[i]+k[i%k.size].ord)%256;s[i],s[j]=s[j],s[i]};i.size.times{|k|i=(i+1)%256;q=(q+s[i])%256;s[i],s[q]=s[q],s[i];b=s[(s[i]+s[q])%256];o<<(b^i[k].ord).chr;o}

1

C, 181 바이트

f(a,n)char*a;{unsigned char A=*a++,i=-1,j=0,k,s[256];for(;s[i]=i;--i);for(;k=s[i],s[i]=s[j+=k+a[i%A]],s[j]=k,k=++i;);for(n-=A,a+=A;--n;*a++^=s[j+=A])j=s[++i],A=s[i]=s[k+=j],s[k]=j;}

bytescat에 대한 ceilingcat 덕분에

f(a,n)char*a;
{unsigned char A=*a++,i=-1,j=0,k,s[256];
 for(;s[i]=i;--i);
 for(;k=s[i],s[i]=s[j+=k+a[i%A]],s[j]=k,k=++i;);
 for(n-=A,a+=A;--n;*a++^=s[j+=A])j=s[++i],A=s[i]=s[k+=j],s[k]=j;
}

"a"의 f (a, n)에는 문자 배열 1Byte len + key + message가 있습니다. n에는 "a"의 모든 배열의 크기가 마지막 '\ 0'을 포함하지 않습니다. 테스트 및 결과 코드는 어셈블리 기능에 사용되는 코드입니다.


@ceilingcat 함수 n의 인수는 여기에 모든 문자 배열의 길이입니다 (1 바이트 + 키 + 메시지) ... 메시지 길이 : nk-1 여기서 k는 키의 길이와 n 모든 문자 배열의 길이입니다.
RosLuP

@ceilingcat 나에게 전화 "f (a, sizeof a);" sizeof는 문자열 끝에서 추가 된 문자 '\ 0'의 길이로 'a'의 길이로 계산하기 때문에 잘못되었습니다. 따라서 f (a, (sizeof a) -1)
이어야합니다.

나는이 ", * ++ a ^ = s [j + = s [i]])"에 동의하지 않는다. 여기서는 배열에 대해 2 번 읽었고 여기에서 비슷한 명령어가 다른 것으로 보인다. ..
RosLuP

1

APL (NARS), 329 자, 658 바이트

xor←{⍺<0:¯1⋄⍵<0:¯1⋄⍺=0:⍵⋄⍵=0:⍺⋄k←⌈/{⌊1+2⍟⍵}¨⍺⍵⋄(2⍴⍨≢m)⊥m←↑≠/{(k⍴2)⊤⍵}¨⍺⍵}
∇r←C w;s;i;j;l;t;b;x
k←256⋄s←¯1+⍳k⋄i←j←0⋄l←¯1+⎕AV⍳↑w
t←s[1+i]⋄j←k∣¯1+j+t+⎕AV⍳w[2+l∣i]⋄s[1+i]←s[1+j]⋄s[1+j]←t⋄i+←1⋄→2×⍳i<k
i←j←0⋄b←≢w⋄l+←1
l+←1⋄→6×⍳l>b⋄i←k∣i+1⋄t←s[1+i]⋄j←k∣j+t⋄s[1+i]←s[1+j]⋄s[1+j]←t
x←s[1+k∣t+s[1+i]] xor ¯1+⎕AV⍳w[l]⋄w[l]←⎕AV[1+x]⋄→4
r←w
∇

항상 다른 사람에게 오류 검사가 필요할 것입니다 ... 이것은 입력 및 출력에 문제가없는 것 같습니다.

  str2Hex←{∊{'0123456789ABCDEF'[1+{(2⍴16)⊤⍵}⍵]}¨{¯1+⎕AV⍳⍵}⍵}
  str2Hex ⎕AV[2,1,1,1,1,1,1]
01000000000000
  str2Hex C ⎕AV[2,1,1,1,1,1,1]
0100DE188941A3
  str2Hex C C ⎕AV[2,1,1,1,1,1,1]
01000000000000
  str2Hex C ⎕AV[14],'this is a keythis is some data to encrypt'
0D746869732069732061206B6579B5DB3F691F9296966521F3AE2821F3EA43D49F53BD3F6482847BCD4E
  C C ⎕AV[14],'this is a keythis is some data to encrypt'

this is a keythis is some data to encrypt

  str2Hex C 'Sthis is a rather long key because the value of S is 83 so the key length must matchand this is the data to be encrypted'
5374686973206973206120726174686572206C6F6E67206B65792062656361757365207468652076616C7565206F662053
  20697320383320736F20746865206B6579206C656E677468206D757374206D61746368961F2C8FA3259BA3665B6D
  6BDFBCAC8B8EFAFE96423D21FC3B13606316710411D886EE07

  C C 'Sthis is a rather long key because the value of S is 83 so the key length must matchand this is the data to be encrypted'
Sthis is a rather long key because the value of S is 83 so the key length must matchand this is th
  e data to be encrypted

예, 모든 것을 줄일 수는 있지만 예를 들어 xor 함수를 더 작게 만들면 덜 일반적입니다 ...


0

녹 348

fn rc4(n:Vec<u8>)->Vec<u8>{let(mut s,mut j,mut t,l)=((0..256).collect::<Vec<usize>>(),0,0,n[0] as usize);let(key,msg)=n[1..].split_at(l);(0..256).fold(0,|a,i|{j=(a+s[i]+key[i%l] as usize)%256;t=s[i];s[i]=s[j];s[j]=t;j});j=0;(1..).zip(msg.iter()).map(|(i,b)|{j=(j+s[i])%256;t=s[i];s[i]=s[j];s[j]=t;s[(s[i]+s[j])%256]as u8^b}).collect::<Vec<u8>>()}

이것은 매우 끔찍합니다. 누군가가 제안을 해 줄 수 있기를 바랍니다.

ungolfed : play.rust-lang.org 놀이터에서


k대신에 key그리고 m대신에 msg그리고 foo&255대신에 제안(foo)%256
ceilingcat
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.