il cifrario di meh :P

Stato
Discussione chiusa ad ulteriori risposte.

Oromis92

Utente Silver
22 Dicembre 2007
102
12
2
84
rileggendo il contest vecchio ( http://www.infernet-x.com/contest/cifrario-simmetrico-t-14176-2.html )

mi è venuta voglia di riscrivere il codice di meh.

esercizio:
Codice:
/*
- Get the binary from the ascii code xor'd 42
- Invert the bits
- Reverse the order
- Move the first 4 bits at the end
- Swap the first bit with the last the second with the seventh etc
- Substitute 1 and 0 with their (random) possible chars:

        zeroes: / $ [ ] { ~ ) @ # _ , ; . :
        ones:   + - % ? } < > ( !

- Add a random char with a 42% chance:

        0-9 A-Z a-z " ' & | * ^ =

*/

ed ecco il mio codice perl (solo cifratura)
Codice:
#!/usr/bin/perl -w

@A = ( '/', '$', '[', ']', '{', '~', ')', '@', '#', '_', ',', ';', '.', ':' );
@B = ( '+', '-', '%', '?', '}', '<', '>', '(', '!' );
@C = ( 0 .. 9, "A" .. "Z", "a" .. "z", '"', '\'', '&', '|', '*', '^', '=' );

print "> ";
$text = <>;
chomp $text;

@text = map( ord ^ 42, split //, $text );
for $i ( 0 .. $#text ) {
    $text[$i] = 0 . sprintf( '%b', $text[$i] ) while length $text[$i] < 8;
    @bits = split //, $text[$i] ;
    for $j ( 0 .. $#bits ) {
        $bits[$j] =~ s/1/x/;
        $bits[$j] =~ s/0/1/;
        $bits[$j] =~ s/x/0/;
    }
    @bits = split //, ( $bits[4] . $bits[5] . $bits[6] . $bits[7] . $bits[0] . $bits[1] . $bits[2] . $bits[3] );
    for $j ( 0 .. $#bits ) {
        $output .= $A[ int( rand(@A) ) ] if $bits[$j] eq "0";
        $output .= $B[ int( rand(@B) ) ] if $bits[$j] eq "1";
        $output .= $C[ int( rand(@C) ) ] if int( rand(100) ) < 42;
    }
}

print "$output\n";

qualcuno noterà che manca il reverse e lo spostamento, ma ecco perchè:
scimmia nel mio cervello ha detto:
- Reverse the order
- Move the first 4 bits at the end
- Swap the first bit with the last the second with the seventh etc

- Swap the first bit with the last the second with the seventh etc ==> reverse

- Reverse the order
- Move the first 4 bits at the end
- Reverse the order

01234567
76543210
32107654
45670123

quindi i due reverse si annullano a vicenda
 
- Get the binary from the ascii code xor'd 42
- Invert the bits
- Reverse the order
- Move the first 4 bits at the end
- Swap the first bit with the last the second with the seventh etc
- Substitute 1 and 0 with their (random) possible chars:

zeroes: / $ [ ] { ~ ) @ # _ , ; . :
ones: + - % ? } < > ( !

- Add a random char with a 42% chance:

0-9 A-Z a-z " ' & | * ^ =
non ho capito tanto bene l'algoritmo, mi potresti fare un esempio? Grazie mille
 
certo.

esempio: lettera 'O' maiuscola.
codice ascii: 79
79 xor 42 = 101
101 in binario = 01100101
inverto i bit = 10011010
reverso = 01011001
sposto i primi quattro bit alla fine = 10010101
reverso ancora = 10101001
adesso, presi *casualmente*:
+$}~?(>#
adesso tra un simbolo e l'altro calcolo un rand minore di 100 se è <42 aggiungo un altro carattere
+$0}~C?(>^#*

quindi O diventa +$0}~C?(>^#*
ovviamente dato che c'entra la casualità ogni volta che cifri sarà diverso il risultato
 
Codice:
#include <iostream>
#include <sstream>

using namespace std;

string cif(string s);
string tobin(int a);
void invert(string& b);
string reverse(string a);

int main()
{
    string s;
    cout<<"Stringa: ";
    cin>>s;
    cout<<cif(s)<<endl;
    return 0;
}

string cif(string s) {

    string out="",a;
    string zeri = "/$[]{~)@#_,;.:", uni = "+-%?}<>(!", r="0987654321ABCDEFGHILMNOPQRSTUVZXYKJabcdefghilmnopqrstuvzxykj\"'f&|*^=";

    int app;

    for(unsigned int i=0;i<s.length();i++) {
        app = (((int)s[i]) ^ 42);
        a=tobin(abs(app));
        invert(a);
        a = a.substr(4, a.length()-4) + a.substr(0,4);
        a = reverse(a);
        for(unsigned int i=0;i<a.length();i++) {
            if(a[i] == '1')
                out+=uni[rand()%uni.length()];
            else
                out+=zeri[rand()%zeri.length()];
            if((rand()%100) < 42)
                out+=r[rand()%r.length()];
        }
    }
    return out;
}

string reverse(string a) {
    string b;
    for(int i=a.length()-1; i>= 0; i--)
        b+=a[i];
    return b;
}

void invert(string& b) {
    for(unsigned int i=0;i<b.length();i++)
        if(b[i] == '1')
            b[i] = '0';
        else
            b[i] = '1';
}

string tobin(int a) {
    int r;
    stringstream ss;
    do {
        r=a%2;
        a/=2;
        ss<<r;
    }while(r || a);
    return ss.str();
}
 
Grazie della spiegazione. Ma come si fa a decriptarlo? :eek:
Vabbè mi metto al lavoro e poi posto.
EDIT: ecco il mio codice in php:
PHP:
<?php
//error_reporting(0);
function str2bin($str, $mode=0) {
	//funzione non mia
	$out = false;
	for($a=0; $a < strlen($str); $a++) {
		$dec = ord(substr($str,$a,1));
		$bin = '';
		for($i=7; $i>=0; $i--) {
			if ( $dec >= pow(2, $i) ) {
				$bin .= "1";
				$dec -= pow(2, $i);
			} else {
				$bin .= "0";
			}
		}
		($mode == 0) ? $out .= $bin." " : (($mode == 1) ? $out .= $bin : (($mode == 2) ? $out[$a] = $bin : $out = false));
	}
	return $out;
}
function bin2str($bin) {
   $bin_ = (!eregi(" ",trim($bin))) ? join(" ",str_split(trim($bin), 8)) : trim($bin);
   $explo = explode(" ",$bin_);
   for($i=0;$i<count($explo);$i++) {
      $ascii .= chr(bindec($explo[$i]));
   }
   return $ascii;
}
function Meh_Cript($str) {
	//zeroes: / $ [ ] { ~ ) @ # _ , ; . :
	//ones: + - % ? } < > ( !
	$zero = str_split("/\$[]{~)@#_,;.:");
	$uno = str_split("+-%?}<>(!");
	$due = str_split("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\"'&|*^=");
	for($i=0;$i<strlen($str);$i++) {
		$tmp = str2bin(ord($str[$i]) ^ 42,1);
		$tmp = str_replace(array(0,1),array(1,0),$tmp);
		$tt = join("",array_reverse(str_split($tmp, 1)));
		$t = str_split($tt, 4);
		$tmp = join("",array_reverse($t));
		$tmp = join("",array_reverse(str_split($tmp, 1)));
		for($j=0;$j<strlen($tmp);$j++) {
			$tmpr = mt_rand(0,100);
			if($tmp[$j] == "0")
				$r[] = $zero[mt_rand(0,count($zero)-1)].(($tmpr < 42) ? $due[mt_rand(0,count($due)-1)] : "");
			else
				$r[] = $uno[mt_rand(0,count($uno)-1)].(($tmpr < 42) ? $due[mt_rand(0,count($due)-1)] : "");
		}
		$as[] = join("",$r);
	}
	return join("",$as);
}
?>
 
Fai il processo inverso Lal... ho fatto anche il decript
Codice:
#include <iostream>
#include <sstream>

using namespace std;

string cif(string s);
string tobin(int a);
void invert(string& b);
string reverse(string a);


string decript(string crip);
int to_dec(string s);
int m_pow(int b, int e);

int main()
{
    string s, o;
    cout<<"Stringa: ";
    cin>>s;

    o=cif(s);
    cout<<o<<endl<<endl;
    cout<<decript(o)<<endl;
    return 0;
}

string cif(string s) {
    string out="",a;
    string zeri = "/$[]{~)@#_,;.:", uni = "+-%?}<>(!", r="0987654321ABCDEFGHILMNOPQRSTUVZXYKJabcdefghilmnopqrstuvzxykj\"'f&|*^=";

    srand(time(0));
    for(unsigned int i=0;i<s.length();i++) {
        a=tobin(abs((((int)s[i]) ^ 42)));
        invert(a);
        a = a.substr(4, a.length()-4) + a.substr(0,4);
        a = reverse(a);
        for(unsigned int i=0;i<a.length();i++) {
            if(a[i] == '1')
                out+=uni[rand()%uni.length()];
            else
                out+=zeri[rand()%zeri.length()];
            if((rand()%100) < 42)
                out+=r[rand()%r.length()];
        }
    }
    return out;
}

string reverse(string a) {
    string b;
    for(int i=a.length()-1; i>= 0; i--)
        b+=a[i];
    return b;
}

void invert(string& b) {
    for(unsigned int i=0;i<b.length();i++)
        if(b[i] == '1')
            b[i] = '0';
        else
            b[i] = '1';
}

string tobin(int a) {
    int r;
    stringstream ss;
    do {
        r=a%2;
        a/=2;
        ss<<r;
    }while(r || a);
    return ss.str();
}

string decript(string crip) {
    string zeri = "/$[]{~)@#_,;.:", uni = "+-%?}<>(!", res="", out="";

    for(unsigned int i=0;i<crip.length();i++) {
        if(zeri.find(crip[i]) < zeri.length())
            res+="0";
        else
            if(uni.find(crip[i]) < uni.length())
                res+="1";

        if(res.length() == 8) {
            res = reverse(res);
            res = res.substr(res.length()-4, 4) + res.substr(0,res.length()-4);
            res = reverse(res);
            invert(res);
            res = reverse(res);
            out+=(char)(to_dec(res)^42);
            res = "";
        }
    }
    return out;
}


int to_dec(string s) {
    int out=0;
    for(int i=s.length()-1;i>=0;i--)
        out+= m_pow(2, i)*(int)(s[i]-48);
    return out;
}

int m_pow(int b, int e) {
    int o=1;
    for(int i=0;i<e;i++)
        o*=b;
    return o;
}
 
Hai un set di valori che sai che corrispondo ad 1 e un altro set che corrispondono a 0. Gli altri che vengono inseriti sono spazzatura. Infatti leggi questa parte
Codice:
  if(zeri.find(crip[i]) < zeri.length())
            res+="0";
        else
            if(uni.find(crip[i]) < uni.length())
                res+="1";
cioè se nella stringa degli zeri il carattere che sto leggendo vi appartiene allora è uno 0, altrimenti se appartiene a quella degli uni è un 1. Gli altri non servono a nulla ai fini dell'algoritmo di decriptazione.
 
Eureka! Ci sono riuscito!

PHP:
<?php
$str    = $argv[1];
$zeroes = explode (" ", "/ $ [ ] { ~ ) @ # _ , ; . :");
$ones   = explode (" ", "+ - % ? } < > ( !");
$random = str_split ("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\"'&|*^=", 1);

function bin ($char) {
	/* A little function to convert
	 * a ascii-code (number format) to binary. */
	return sprintf('%08s', decbin ($char)); // Return binary-converted char
}

function invert ($bincode) {
	/* Function to reverse 0 and 1 */
	$n = "";
	foreach (str_split ($bincode, 1) as $single) {
		if ($single == "0") $n .= "1";
		elseif ($single == "1") $n .= "0";
	}
	return $n;
}

function substitute ($bincode) {
	/* Function to substitute zeroes ad ones to random chars */ 
	global $zeroes, $ones;
	$result = "";
	foreach (str_split ($bincode, 1) as $single) {
		if ($single == "0") $result .= $zeroes[rand (0, (count ($zeroes) - 1))];
		elseif ($single == "1") $result .= $ones[rand (0, (count ($ones) - 1))];
	}
	return $result;
}

foreach (str_split ($str, 1) as $char) {
	$bin = bin (ord ($char) ^ 42); // Calculate binary code from ASCII (singleChar) xor 42
	$bin = invert ($bin); // Invert bytes
	$bin = strrev ($bin); // Reverse string
	$fourBytes = substr ($bin, 0, 4); // Get the first four bytes (19192 = 1919)
	$bin = substr ($bin, 4) . $fourBytes; // Add the first four bytes to the end
	$bin = strrev ($bin); // Reverse another time the string
	$bin = substitute ($bin); // Substitute zeroes ad ones to random chars
	$bin .= ((rand (0, 100) < 42) ? $random[rand (0, (count ($random) - 1))] : $bin); // Add a random char to the end if a random number > 42
	print $bin; // Print the code.
}
print "\n";
?>
Va eseguito via terminale con php /path/to/script.php stringa_da_encryptare =D
Appena posso vedo di fare il decrypter.
 
fatto, almeno credo, il decrypt arriva fra poco... da eseguire da linea di comando passando come secondo argomento la parola da cryptare

Codice:
# coding: iso-8859-1
#!/usr/bin/python

from random import randint
def to_bin(num):
    s=""
    while num!=0:
        s+=str(num%2)
        num/=2
    return s[::-1]

def sy(string):
    s=ord(string) #to ASCII
    s=s^42 #XOR
    s=[x for x in to_bin(s)] #to decimal and split into a list
    c=0
    for i in s:
        if i=="0":
            s[c]="1"
        else:
            s[c]="0"
        c+=1
    s=s[::-1]
    t=s[0:4]
    s[0:4]=s[4:]
    s[4:]=t
    s=s[::-1]
    zeros=["/","$","[","]","{","~",")","@","#","_",",",";",":","."]
    ones=["+","-","%","?","}","<",">","(","!"]
    de=""
    for j in s:
        if j=="0":
            de+=zeros[randint(0,13)]
        elif j=="1":
            de+=ones[randint(0,8)]
    f=randint(0,100)
    if f<=42:
        de+=(zeros+ones)[randint(0,22)]
    return "".join(de)





from sys import argv

cif=[sy(i) for i in argv[1]]

print cif

Dimostrazione:
Codice:
C:\> meh.py ciao
[':(+/+_((', '+<:$<{+%{', '[>$;-_(<', '}#<;>#?!']
 
Stato
Discussione chiusa ad ulteriori risposte.