Bir Kerelik Ped Uygulayın


13

Arka fon

Bir defalık ped , doğru kullanıldığında kırılmasının imkansız olduğu kanıtlanmış bir şifreleme şeklidir.

Şifreleme, bir düz metin (yalnızca AZ harflerinden oluşur) alınarak ve aynı uzunlukta rastgele bir dize (yalnızca harfler) üretilerek gerçekleştirilir. Bu dize anahtar görevi görür. Düz metindeki her karakter daha sonra anahtardaki karşılık gelen karakterle eşleştirilir. Şifreleme metni şu şekilde hesaplanır: Her bir çift için her iki karakter de sayılara dönüştürülür (A = 0, B = 1, ... Z = 25). Bu iki sayıya modulo 26 eklenir. Bu sayı tekrar bir karaktere dönüştürülür.

Şifre çözme tam tersidir. Şifreleme ve anahtardaki karakterler eşleştirilir ve sayılara dönüştürülür. Daha sonra anahtar, şifreli metin modüloğundan 26 çıkarılır ve sonuç, tekrar AZ karakterine dönüştürülür.

Meydan okuma

Zorluk, bir kerelik bir pedi hem şifreleyip hem de şifresini çözebilen mümkün olan en kısa programı yazmaktır.

İlk girdi satırında (STDIN'a) ya "ENCRYPT" ya da "DECRYPT" kelimeleri olacaktır.

Sözcük şifrelenirse, sonraki satır düz metin olacaktır. Programınız, birincisi anahtar ve ikincisi şifre metni olmak üzere iki satır (STDOUT'a) çıkmalıdır.

Kelimenin şifresi çözülürse, programınız iki satır daha alır. İlk satır anahtar, ikinci satır şifre metni olacaktır. Programın şifresi çözülmüş düz metin olacak bir satır çıktı.

Düz metin, şifreli metin ve anahtar her zaman AZ büyük harflerinden oluşmalıdır. Her zaman tek bir satır olacak ve boşluk içermeyeceklerdir.

Anahtar her zaman rastgele olmalıdır. Hiçbir büyük kısmı çalışmalar arasında tekrarlanmamalı ve metinde bulunabilecek kalıplar olmamalıdır.

İki basit örnek:

ENCRYPT
HAPPYBIRTHDAY
>ABKJAQLRJESMG
>HBZYYRTICLVME

DECRYPT
ABKJAQLRJESMG
HBZYYRTICLVME
>HAPPYBIRTHDAY

>Eğer çıktı olarak o sembolü yazdırmak zorunda kalmamak, çıkış hangi hatlar temsil eder.


7
Değil (ince) vardır kendi esas hakkındaki meydan eleştirmek, ama ben ediyorum burada şifreleme eleştirmek olacak. Açıkladığınız şey, bir PRNG'ye bağlı olduğu için bir "akış şifresi" dir (bilgisayarınız bir kaynağa veya gerçek bir rasgele erişime sahip değilse (ve / dev / urandom sayılarının linux uygulaması bazı tartışmalara konu değilse)) ve anahtarın şifrelenme zamanında geliştirilmiş olması, OTP için güvenli iletişimlerin zaman kaydırması olan tek gerçekten iyi kullanımı yendi.
dmckee --- eski moderatör yavru kedi

1
Ayrıca, tüm zorluklar varsayılan olarak dil agnostiktir, bu yüzden bu etiketi kaldırdım.
dmckee --- eski moderatör yavru kedi

7
@dmckee İlk yorumunuzla ilgili olarak, katılıyorum, bu yüzden iletişimimi güvence altına almak için bu cevapları kullanmayı düşünmüyorum.
PhiNotPi

1
bu, rasgele problemin dışında kalması için daha eğlenceli bir IMO olurdu; rastgele bir kaynak ( /dev/random, haveged) verildiğinde, ordsları baytlarla xoring ederek şifreleyin ve anahtarla xoring yaparak şifresini çözün. gist.github.com/5078264 anahtar veya rasgelelik stdin'den okunabilir, mesaj veya şifre metni bir dosya adı argümanı olabilir.
ixtmixilix

@PhiNotPi Bir önerim var. Eğer gerçekten rastgele bir kaynak /dev/hwrngkullanıyorlarsa (neden sözde rastgele kullanmak yerine (teknik olarak onu
kırıyor

Yanıtlar:


8

GolfScript, 53 karakter

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

Bu, GolfScript'in neredeyse tamamen uygun olduğu bir görevdir.

Kodu kısa tutmak için, hem şifreleme hem de şifre çözme için aynı kodu kullanıyorum: şifresini çözmek için, şifreleme için anahtarı çıkarırken, şifreleme için önce rastgele bir şifre metni üretiyorum ve sonra düz metni ondan çıkarıyorum. Yine de, şifreleme modunu uygulamak için ekstra kod, programın uzunluğunun biraz üzerinde bir süre alır.

Yorumların kaldırıldığı sürüm:

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

Yakut ( 200 185)

örnek çalışmalar + 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,:-]yazılmalıdırs[k=f.map{rand 26}],r[k,$_,:-]
Hauleth

@Hauleth hayır $_, sadece okunan son satır gibi çalışmıyor gets. satır okuduktan sonra fda yapar .scan(/./).map{|b|b.ord-65}.
jsvnm

3

Haskell, 203 karakter

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

Misal:

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

3

Perl, 220 171 karakter

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}

Örnek Çalışma:

ENCRYPT
HELLO
CCTKK
JGEVY

DECRYPT
CCTKK
JGEVY
HELLO

Not: en azından çalıştırdığımda, "Devam etmek için herhangi bir tuşa basın ..." son çıktının sonuna eklenir. Umarım bu iyidir, çünkü programın bir parçası değildir. Değilse, bir sonraki satırda görünecek şekilde yapabilirim.

Bu Perl'deki ilk gerçek programım ve şimdiye kadarki ilk golfüm, bu yüzden ipuçlarını gerçekten takdir ediyorum. Ayrıca, /(.)/ginternette buldum , ancak nasıl çalıştığına dair hiçbir fikrim yok (düzenli bir ifade mi? Henüz bunları öğrenmedim). Birisi bana açıklayabilir mi?

EDIT: Regexps bana yardımcı olduğu için Ilmari Karonen sayesinde, 7 karakter kurtarmak için yeni bilgilerimi kullandım!

Genişletilmiş, hafif okunabilir versiyon:

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
}

Evet, bir /(.)/gnormal ifade. Perl golf oynayacaksanız bunları kesinlikle öğrenmek isteyeceksiniz. perldoc.perl.org/perlre.html kötü bir başlangıç ​​noktası değil.
Ilmari Karonen

2

Python - 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)

Bunun tam olarak özellikleri karşıladığına inanıyorum ( '>'giriş istemlerinin başlangıcında dahil .) Girişi doğrulamıyor, bu yüzden dışarıda karakterler verirseniz sadece çöp çıktısı üreteceğini düşünüyorum [A-Z]. Ayrıca yalnızca giriş komutunun ilk harfini kontrol eder. İle başlayan her şey Dbir şifre çözme ile sonuçlanacak ve herhangi bir şey bir şifreleme ile sonuçlanacaktır.


Sizden yazdırmayı beklemiyordum >, sadece hangi satırların çıktısı olduğunu göstermek için kullanıyordum. Bunları uygulamak zorunda değilsiniz.
PhiNotPi

Tamam, harika, 9 karakter daha az.
Gordon Bailey

1

C ++ - 220 241 karakter, 4 satır

#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);}

Düzenleme 1- MSVS standart kütüphanesi, ios'un ihtiyacım olan tüm içeriğe sahip olduğu anlamına gelen gereksiz dosyaları bir sürü içeriyor gibi görünüyor, ancak bu diğer derleyicilerle çalışmadı. İhtiyaç duyulan fonksiyonların değiştirilmiş ios'ları cstdlib ve cstdio'da görünür. Ilmari Karonen'e bunu işaret ettiği için teşekkürler.


Benim için g++ otp.cppotp.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
derlemez

Ha, bu garip, ben görsel stüdyo kullanıyorum. İçinde <ios> <conio.h> ve <stdio.h> bulunması standart olmamalıdır. Başlıkların her zaman aynı dosyaları farklı uygulamalarda içerdiğini varsaydım. Daha sonra bakacağım, teşekkürler.
Scott Logan

1

Python - 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

Örnek çıktı:

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

Karakter sayımı:

$ wc -c onetimepad.py 
270 onetimepad.py

1

J: 94 bayt

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

Gerekli tüm beyaz boşluklar sayıldı.

Yorumlanan sürüm:

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)

Toplamı unuttum. İyi bir parça kesin.

Biraz golf oynadı:

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);
        }
    }
}

}

golfed:

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 (derleyici bayrakları için 159 + 11)

golfed:

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);}

Ungolfed:

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);
}

İle derleyin -Dg=gets(s).

Misal:

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

Her çalıştırdığımda aynı anahtarı alıyorum - rastgelelik yok.
feersum

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}

Kullanımı:

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

0

Yakut - 184 179 177 karakter

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}*''

Bu şekilde çalıştırın: $ ruby pad-lock.rb

İşte kimse ilgileniyorsa ungolfed sürümü (olsa da golfed ile güncel değil)

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("")
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.