Thực hiện Pad một lần


13

Lý lịch

Một miếng đệm một lần một là một hình thức mã hóa đã được chứng minh là không thể bẻ khóa nếu được sử dụng đúng cách.

Mã hóa được thực hiện bằng cách lấy một bản rõ (chỉ bao gồm các chữ cái AZ) và tạo ra một chuỗi ngẫu nhiên trên cùng một độ dài (cũng chỉ có các chữ cái). Chuỗi này đóng vai trò là chìa khóa. Mỗi ký tự trong bản rõ sau đó được ghép với ký tự tương ứng trong khóa. Bản mã được tính như sau: Đối với mỗi cặp, cả hai ký tự được chuyển đổi thành số (A = 0, B = 1, ... Z = 25). Hai số được thêm modulo 26. Số này được chuyển đổi trở lại thành một ký tự.

Giải mã hoàn toàn ngược lại. Các ký tự trong bản mã và khóa được ghép nối và chuyển đổi thành số. Sau đó, khóa được trừ khỏi modulo mã hóa 26 và kết quả được chuyển đổi thành ký tự AZ.

Các thách thức

Thách thức của bạn là viết chương trình ngắn nhất có thể vừa có thể mã hóa và giải mã một bảng đệm một lần.

Trên dòng đầu tiên (đến STDIN), sẽ có từ "ENCRYPT" hoặc từ "DECRYPT".

Nếu từ được mã hóa, thì dòng tiếp theo sẽ là bản rõ. Chương trình của bạn sẽ xuất hai dòng (sang STDOUT), dòng đầu tiên là khóa và dòng thứ hai là bản mã.

Nếu từ được giải mã, chương trình của bạn sẽ nhận được thêm hai dòng đầu vào. Dòng đầu tiên sẽ là khóa và dòng thứ hai sẽ là bản mã. Chương trình của bạn sẽ xuất ra một dòng, đây sẽ là bản rõ đã được giải mã.

Bản rõ, bản mã và khóa phải luôn bao gồm các chữ cái in hoa AZ. Chúng sẽ luôn là một dòng duy nhất và không chứa khoảng trắng.

Chìa khóa phải luôn luôn là ngẫu nhiên. Không có phần lớn của nó nên lặp lại giữa các lần chạy và không nên có các mẫu có thể tìm thấy trong văn bản.

Hai ví dụ đơn giản:

ENCRYPT
HAPPYBIRTHDAY
>ABKJAQLRJESMG
>HBZYYRTICLVME

DECRYPT
ABKJAQLRJESMG
HBZYYRTICLVME
>HAPPYBIRTHDAY

Biểu >thị dòng nào là đầu ra, vì vậy bạn không phải in biểu tượng đó làm đầu ra.


7
Không chỉ trích các thách thức về giá trị riêng của nó (là tốt), nhưng tôi đang đi để chỉ trích các mật mã ở đây. Những gì bạn đang mô tả là một "mật mã dòng" vì nó phụ thuộc vào PRNG (trừ khi máy tính của bạn có quyền truy cập vào nguồn hoặc tính ngẫu nhiên thực sự (và nếu việc triển khai linux / dev / urandom là vấn đề cần bàn cãi)) và có khóa được phát triển trong thời gian mã hóa đánh bại việc sử dụng thực sự tốt duy nhất cho một OTP, đó là sự dịch chuyển thời gian của truyền thông an toàn.
dmckee --- ex-moderator mèo con

1
Ngoài ra, tất cả các thách thức là bất khả tri về ngôn ngữ theo mặc định, vì vậy tôi đã xóa thẻ đó.
dmckee --- ex-moderator mèo con

7
@dmckee Về nhận xét đầu tiên của bạn, tôi đồng ý, đó là lý do tại sao tôi không có ý định sử dụng những câu trả lời này để bảo mật thông tin liên lạc của mình.
PhiNotPi

1
IMO sẽ vui hơn khi loại bỏ sự ngẫu nhiên ra khỏi vấn đề; được cung cấp một nguồn ngẫu nhiên ( /dev/random, haveged), mã hóa bằng cách xé các quỹ đạo bằng các byte và giải mã bằng cách xé chúng bằng khóa. gist.github.com/5078264 khóa hoặc tính ngẫu nhiên có thể được đọc từ stdin, tin nhắn hoặc cyphertext có thể là một đối số tên tệp.
ixtmixilix

@PhiNotPi Tôi có một gợi ý. Tại sao không cho tiền thưởng nếu họ sử dụng một nguồn thực sự ngẫu nhiên (như /dev/hwrng, thay vì sử dụng giả ngẫu nhiên (về mặt kỹ thuật làm cho nó bị hỏng.)
PyRulez

Câu trả lời:


8

GolfScript, 53 ký tự

n%(0=2%{~.,[{26rand 65+}*]:K]}*zip{{-}*~)26%65+}%K]n*

Đây là một nhiệm vụ mà GolfScript dường như hoàn toàn phù hợp.

Để giữ mã ngắn, tôi đang sử dụng cùng một mã cho cả mã hóa và giải mã: để giải mã, tôi trừ khóa khỏi bản mã, trong khi để mã hóa, trước tiên tôi tạo một bản mã ngẫu nhiên và sau đó trừ bản rõ từ nó. Mặc dù vậy, mã bổ sung để thực hiện chế độ mã hóa chỉ mất hơn một nửa thời lượng của chương trình.

Phiên bản bỏ chơi golf với ý kiến:

n %             # split input into an array of lines

# KEY GENERATION FOR ENCRYPTION MODE:
(               # extract the first line from the array
0 = 2 %         # check if the first char of that line is odd (E = 69)...
{               # ...and execute this block if it is:
    ~           # dump the remaining lines (of which the should be only one) on the stack
    . ,         # calculate the length of the last line...
    [ { 26 rand 65 + } * ]  # ...make an array of that many random letters...
    :K          # ...and assign it to K
    ]           # collect all the lines, including K, back into an array
} *

# ENCRYPTION / DECRYPTION ROUTINE:
zip             # transpose the array of 2 n-char strings into n 2-char strings...
{               # ...and execute this block for each 2-char string:
    {-} *       # subtract the second char code from the first
    ~ )         # negate the result (using the two's complement trick -x = ~x+1)
    26 % 65 +   # reduce modulo 26 and add 65 = A
} %

# OUTPUT:
K ] n*         # join the result and K (if defined) with a newline, stringifying them

4

Hồng ngọc ( 200 185)

mẫu chạy + wc:

$ ruby onetimepad.rb
ENCODE
ANOTHERTESTINPUTZZZ
ZYCLGHDWLDASFUTHWKC
BPMIBXOXTPTQIVBMDPX
$ ruby onetimepad.rb
DECODE
ZYCLGHDWLDASFUTHWKC
BPMIBXOXTPTQIVBMDPX
ANOTHERTESTINPUTZZZ
$ wc onetimepad.rb
       4       7     185 onetimepad.rb
def f;gets.scan(/./).map{|b|b.ord-65};end
s=->a{a.map{|b|(b+65).chr}*''}
r=->b,a,o{s[a.zip(b).map{|a,b|(a.send o,b)%26}]}
puts(gets=~/^D/?r[f,f,:+]:[s[k=(p=f).map{rand 26}],r[k,p,:-]])

s[k=(p=f).map{rand 26}],r[k,p,:-]nên được viếts[k=f.map{rand 26}],r[k,$_,:-]
Hauleth

@Hauleth không, nó không hoạt động, vì $_đây chỉ là dòng cuối cùng được đọc bởi gets. fcũng làm .scan(/./).map{|b|b.ord-65}sau khi đọc một dòng.
jsvnm

3

Haskell, 203 ký tự

import Random
main=newStdGen>>=interact.(unlines.).(.lines).f.randomRs('A','Z')
f k['E':_,x]=[z const k x,z(e(+))k x]
f _[_,k,x]=[z(e(-))k x]
e(%)k x=toEnum$65+o x%o k`mod`26
o c=fromEnum c-65;z=zipWith

Thí dụ:

$ runghc OneTimePad.hs <<< $'ENCRYPT\nHELLOWORLD'
QMNQKGFZFD
XQYBYCTQQG
$ runghc OneTimePad.hs <<< $'DECRYPT\nQMNQKGFZFD\nXQYBYCTQQG'
HELLOWORLD

3

Perl, 220 171 ký tự

if(<>=~/D/){$_=<>;$w=<>;print chr((ord(substr$w,$i++,1)-ord$1)%26+65)while/(.)/g}else{$_=<>;$c.=chr((ord($1)-65+($i=rand(26)))%26+65),print chr$i+65while/(.)/g;print$/.$c}

Chạy mẫu:

ENCRYPT
HELLO
CCTKK
JGEVY

DECRYPT
CCTKK
JGEVY
HELLO

Lưu ý: ít nhất là khi tôi chạy nó, "Nhấn phím bất kỳ để tiếp tục ..." được gắn vào cuối đầu ra cuối cùng. Tôi hy vọng điều này là ổn, bởi vì nó không phải là một phần của chương trình. Nếu không, tôi có thể làm cho nó xuất hiện trên dòng tiếp theo.

Đây là chương trình thực sự đầu tiên của tôi ở Perl và là sân golf đầu tiên của tôi, vì vậy tôi thực sự sẽ đánh giá cao các mẹo. Ngoài ra, tôi tìm thấy /(.)/gtrên internet, nhưng tôi không biết nó hoạt động như thế nào (nó có phải là một biểu thức thông thường không? Tôi chưa học được những điều đó). Ai đó có thể giải thích cho tôi?

EDIT: Cảm ơn Ilmari Karonen đã giúp tôi thoát khỏi các biểu thức chính tả, tôi đã sử dụng kiến ​​thức mới của mình để lưu 7 ký tự!

Phiên bản mở rộng, hơi dễ đọc:

if(<>=~/D/){
    $_=<>;
    $w=<>;
    print chr((ord(substr$w,$i++,1)-ord$1)%26+65)while/(.)/g
}
else{
    $_=<>;
    $c.=chr((ord($1)-65+($i=rand(26)))%26+65),print chr$i+65while/(.)/g;
    print$/.$c
}

Vâng, /(.)/glà một regrec. Bạn chắc chắn sẽ muốn học những thứ đó nếu bạn chơi golf Perl. perldoc.perl.org/perlre.html không phải là nơi khởi đầu tồi.
Ilmari Karonen 17/03/2016

2

Con trăn - 304 295

import random
r=raw_input
R=lambda s:range(len(s))
o=lambda c:ord(c)-65
j=''.join
if r()[0]=='D':
 s=r()
 d=r()
 print j(chr((o(s[i])-o(d[i]))%26+65)for i in R(s))
else:
 s=r()
 d=[random.randint(0,26)for i in R(s)]
 print j(chr((o(s[i])+d[i])%26+65)for i in R(s))
 print j(chr(n+65)for n in d)

Tôi tin rằng điều này đáp ứng chính xác các thông số kỹ thuật (Bao gồm cả '>'khi bắt đầu lời nhắc nhập.) Nó không xác thực đầu vào, vì vậy tôi nghĩ rằng nó sẽ chỉ tạo ra đầu ra rác nếu bạn đưa ra các ký tự bên ngoài [A-Z]. Nó cũng chỉ kiểm tra chữ cái đầu tiên của lệnh đầu vào. Bất cứ điều gì bắt đầu với Dsẽ dẫn đến việc giải mã và bất cứ điều gì khác sẽ dẫn đến việc mã hóa.


Tôi không mong đợi bạn in >, tôi chỉ sử dụng nó để chứng minh dòng nào là đầu ra. Bạn không phải thực hiện những điều đó.
PhiNotPi

Ok, tuyệt, 9 ký tự ít hơn.
Gordon Bailey

1

C ++ - 220 241 ký tự, 4 dòng

#include<cstdlib>
#include<cstdio>
#define a scanf("%s"
char i,s[99],t[99];int main(){a,t);a,s);if(t[0]>68){for(;s[i];++i)s[i]=(s[i]+(t[i]=rand()%26+65))%26+65;puts(t);}else for(a,t);s[i];++i){s[i]=65+t[i]-s[i];if(s[i]<65)s[i]+=26;}puts(s);}

Chỉnh sửa 1- Thư viện chuẩn MSVS dường như bao gồm rất nhiều tệp không cần thiết, điều đó có nghĩa là ios có tất cả những thứ tôi cần nhưng điều này không hoạt động với các trình biên dịch khác. Đã thay đổi ios cho các tệp thực tế mà các chức năng cần thiết xuất hiện trong cstdlib và cstdio. Cảm ơn Ilmari Karonen đã chỉ ra điều này.


Không biên dịch cho tôi: g++ otp.cppnóiotp.cpp: In function ‘int main()’: otp.cpp:3: error: ‘scanf’ was not declared in this scope otp.cpp:3: error: ‘rand’ was not declared in this scope otp.cpp:3: error: ‘puts’ was not declared in this scope otp.cpp:3: error: ‘puts’ was not declared in this scope
Ilmari Karonen 17/03/2016

Huh, thật lạ, tôi sử dụng studio hình ảnh. Nó phải không chuẩn để <ios> có <conio.h> và <stdio.h> trong đó bao gồm. Tôi giả sử các tiêu đề luôn bao gồm các tệp giống nhau trên các triển khai khác nhau. Tôi sẽ xem xét nó sau, Cảm ơn.
Scott Logan

1

Con trăn - 270

import random
i=raw_input  
m=i()
a=i()
r=range(len(a))
o=ord
j=''.join
if m=='ENCRYPT':
  k=j(chr(65+random.randint(0,25)) for x in r)
  R=k+"\n"+j(chr((o(a[x])+o(k[x]))%26+65) for x in r)
elif m=='DECRYPT':
  k=i()
  R=j(chr((o(k[x])-o(a[x]))%26+65) for x in r)
print R

Đầu ra mẫu:

$ python onetimepad.py 
ENCRYPT
HELLOWORLD
UXCYNPXNNV
BBNJBLLEYY
$ python onetimepad.py 
DECRYPT
UXCYNPXNNV
BBNJBLLEYY
HELLOWORLD

Số lượng nhân vật:

$ wc -c onetimepad.py 
270 onetimepad.py

1

J: 94 byte

3 :0]1
c=:(26&|@)(&.(65-~a.&i.))
r=:1!:1@1:
((],:+c)[:u:65+[:?26$~#)@r`(r-c r)@.('D'={.)r 1
)

Tất cả các khoảng trắng cần thiết được tính.

Phiên bản đã bình luận:

3 :0]1                                          NB. Make a function and call it
c=:(26&|@)(&.(65-~a.&i.))                       NB. Adverb for operating on the alphabet
                                                NB. (used for adding and subtracting the pad)
r=:1!:1@1:                                      NB. Read input line and decide (right to left)
((],:+c)[:u:65+[:?26$~#)@r   ` (r-c r)            @. ('D'={.)r 1
NB. Encryption (ger    0)    | Decryption (ger 1)| Agenda               
NB. pad,:(crypt=:plain + pad)| crypt - pad       | If D is first input, do (ger 1), else do (ger 0)
)

1

C # ( 445 416)

Quên về Uẩn. Cắt bỏ một chút tốt.

Hơi bị đánh gôn:

namespace G {
using System;
using System.Linq;
using x = System.Console;
class P {
    static void Main() {
        string p = "", c = "", k = "";
        Random r = new Random();
        int i = 0;
        if (x.ReadLine()[0] == 'E') {
            p = x.ReadLine();
            k=p.Aggregate(k,(l,_)=>l+(char)r.Next(65,90));
            c=p.Aggregate(c,(m,l)=>m+(char)((l+k[i++])%26+65));
            x.WriteLine(k + "\n" + c);
        } else {
            k = x.ReadLine();
            c = x.ReadLine();
            p=c.Aggregate(p,(l,a)=>l+(char)((a-k[i++]+26)%26+65));
            x.WriteLine(p);
        }
    }
}

}

Chơi gôn

namespace G{using System;using System.Linq;using x=System.Console;class P{static void Main(){string p="",c="",k="";Random r=new Random();int i=0;if (x.ReadLine()[0]=='E'){p=x.ReadLine();k=p.Aggregate(k,(l,_)=>l+(char)r.Next(65,90));c=p.Aggregate(c,(m,l)=>m+(char)((l+k[i++])%26+65));x.WriteLine(k+"\n"+c);}else{k=x.ReadLine();c=x.ReadLine();p=c.Aggregate(p,(l,a)=>l+(char)((a-k[i++]+26)%26+65));x.WriteLine(p);}}}}

0

C (159 + 11 cho cờ trình biên dịch)

Chơi gôn

d(a,b){return(a+b+26)%26+65;}a;char s[999],b,*c=s-1;main(){g;a=*s-69;g;while(*++c)a?b=-*c,*c=getchar():putchar(b=rand()%26+65),*c=d(*c,b);a||puts("");puts(s);}

Ung dung:

d(a,b){
    //*a = (*a + b - 2*65 + 26) % 26 + 65; 
    return (a + b + 26) % 26 + 65;
}
a; char s[999], b, *c = s-1;
main(){
    gets(s);
    a = *s - 69; // -1 if decrypt 0 if encrypt
    gets(s);
    while(*++c){
        if(!a)
            putchar(b = rand() % 26 + 65); // 'A'
        else
            b = -*c, *c = getchar();
        *c = d(*c,b);
    }
    if(!a) puts("");
    puts(s);
}

Biên dịch với -Dg=gets(s).

Thí dụ:

$./onetimepad
ENCRYPT
FOOBAR
>PHQGHU
>UVEHHL
$./onetimepad
DECRYPT
PHQGHU
UVEHHL
>FOOBAR

Tôi nhận được cùng một khóa mỗi lần tôi chạy nó - không có sự ngẫu nhiên.
frageum

0

JavaScript 239

var F=String.fromCharCode
function R(l){var k='';while(l--)k+=F(~~(Math.random()*26)+65);return k}
function X(s,k,d){var o='',i=0,a,b,c
while(i<s.length)a=s.charCodeAt(i)-65,b=k.charCodeAt(i++)-65,c=d?26+(a-b):a+b,o+=F((c%26)+65)
return o}

Sử dụng:

var str = "HELLOWORLD";
var key = R(str.length);
var enc = X(str, key, false);
console.log(enc);
console.log(X(enc,key, true));

0

Ruby - 184 179 177 ký tự

def g;gets.scan(/./).map{|c|c.ord-65}end
m,=g
k=(s=g).map{rand 26}
m==4?(puts k.map{|c|(c+65).chr}*'';y=:+):(k,s=s,g)
puts s.zip(k).map{|c,o|(c.send(y||:-,o).to_i%26+65).chr}*''

Chạy nó như thế này: $ ruby pad-lock.rb

Đây là phiên bản chưa được chỉnh sửa nếu có ai quan tâm (mặc dù nó không hoàn toàn cập nhật với phiên bản golf)

def prompt
    gets.scan(/./).map{ |c|c.ord - 65 }
end

mode = prompt[0]
operator = :-
secret = prompt
key = secret.map { |char| rand(26) }

if mode == 4 # the letter E, or ENCRYPT
    key.map { |char| print (char + 65).chr }
    puts
    operator = :+
else
    # make the old secret the new key,
    # and get a new secret (that has been encrypted)
    key, secret = secret, prompt
end

chars = secret.zip(key).map do |secret_char, key_char|

    # if mode == 4 (E) then add, otherwise subtract
    i = secret_char.send(operator, key_char).to_i

    ((i % 26) + 65).chr
end

puts chars.join("")
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.