Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Schamir, RSA, RC4.docx
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
681.81 Кб
Скачать
  • Пара   играет роль закрытого ключа RSA (англ. RSA private key) и держится в секрете.

    Шифрование и дешифрование

    Предположим, Боб хочет послать Алисе сообщение  .

    Сообщениями являются целые числа в интервале от   до  , т.е .

    Система RSA может использоваться не только для шифрования, но и для цифровой подписи.

    Предположим, что Алисе (стороне  ) нужно отправить Бобу (стороне  ) сообщение  , подтверждённое электронной цифровой подписью.

      1. Потоковый шифр rc4

    Ядро алгоритма состоит из функции генерации ключевого потока. Эта функция генерирует последовательность битов ( ), которая затем объединяется с открытым текстом ( ) посредством суммирования по модулю два. Так получается шифрограмма ( ):

    .

    Расшифровка заключается в регенерации этого ключевого потока ( ) и сложении его и шифрограммы ( ) по модулю два. В силу свойств суммирования по модулю два на выходе мы получим исходный незашифрованный текст( ):

    Другая главная часть алгоритма — функция инициализации, которая использует ключ переменной длины для создания начального состояния генератора ключевого потока.

    RC4 — фактически класс алгоритмов, определяемых размером его блока. Этот параметр n является размером слова для алгоритма. Обычно, n = 8, но в целях анализа можно уменьшить его. Однако для повышения безопасности необходимо увеличить эту величину. Внутреннее состояние RC4 представляется в виде массива слов размером 2n и двух счетчиков, каждый размером в одно слово. Массив известен как S-бокс, и далее будет обозначаться как S. Он всегда содержит перестановку 2n возможных значений слова. Два счетчика обозначены через i и j.

    Алгоритм инициализации RC4 приведен ниже. Этот алгоритм также называется алгоритмом ключевого расписания (англ. Key-Scheduling Algorithm or KSA). Этот алгоритм использует ключ, сохраненный в Key, и имеющий длину L байт. Инициализация начинается с заполнения массива S, далее этот массив перемешивается путем перестановок, определяемых ключом. Так как только одно действие выполняется над S, то должно выполняться утверждение, что Sвсегда содержит все значения кодового слова.

    Генератор ключевого потока RC4 переставляет значения, хранящиеся в S, и каждый раз выбирает различное значение из S в качестве результата. В одном цикле RC4 определяется одно n-битное слово K из ключевого потока, которое в последующем суммируется с исходным текстом для получения зашифрованного текста. Эта часть алгоритма называется генератором псевдослучайной последовательности (англ. Pseudo-Random Generation Algorithmor PRGA).

    Рис 2.1- Генератор ключевого потока RC4

    1. Реализация шифрования и дешифрования шифром Шамира на C++

      1. Листинг программы с описаниями основных функций и переменных

    #include <iostream>//подключение встроенных библиотек

    #include <fstream>

    #include <stdio.h>

    #include <cstdlib>

    #include <math.h>//

    #include <cstdlib>

    using std::srand;

    using std::rand;

    #include <time.h>

    void extended_euclid(__int64 a, __int64 b, __int64 *x, __int64 *y, __int64 *d)

    /* calculates a * *x + b * *y = gcd(a, b) = *d */

    {// алгоритм для нахождения наибольшего общего делителя двух целых чисел

    __int64 q, r, x1, x2, y1, y2;

    if (b == 0) {

    *d = a, *x = 1, *y = 0;

    return;

    }

    x2 = 1, x1 = 0, y2 = 0, y1 = 1;

    while (b > 0) {

    q = a / b, r = a - q * b;

    *x = x2 - q * x1, *y = y2 - q * y1;

    a = b, b = r;

    x2 = x1, x1 = *x, y2 = y1, y1 = *y;

    }

    *d = a, *x = x2, *y = y2;

    }

    __int64 invmod(__int64 a, __int64 n)

    /* computes the inverse of a modulo n */

    {

    __int64 d, x, y;

    extended_euclid(a, n, &x, &y, &d);

    if (d == 1)

    if (x>0)

    return x;

    else

    return x+n;

    return 0;

    }

    __int64 powmod(__int64 a, __int64 k, __int64 n)

    {//вычисление a^k mod n

    __int64 b=1;

    while (k) {

    if (k%2==0) {

    k /= 2;

    a = (a*a)%n;

    }

    else {

    k--;

    b = (b*a)%n;

    }

    }

    return b;

    }

    int main()

    {

    __int64 Ca,Da,Cb,Db,x1,x2,x3,x4,x,P;

    P=65537;//любое большое простое число

    srand(time(0)); // Инициализируем генератор текущим временем.

    FILE* f_in=fopen("Shamira_in.txt","r");

    FILE* f_out=fopen("Shamira_out.txt","w");

    char ch='a';

    printf("cryptotext:\n");

    while((ch=getc(f_in))!=EOF)

    {

    Ca=7;

    // Ca = rand()%(10)+1; // Случайное число в пределах от 1 включительно до P исключительно.

    Da=invmod(Ca,P-1);

    Cb=5;

    // Cb = rand()%(10)+1;

    Db=invmod(Cb,P-1);

    x=ch;

    x1=powmod(x,Ca,P);

    printf("%c",x2);

    x2=powmod(x1,Cb,P);

    printf("%c",x2);

    x3=powmod(x2,Da,P);

    printf("%c",x3);

    x4=powmod(x3,Db,P);

    fprintf(f_out,"%c",x4);

    }

    fclose(f_in);

    fclose(f_out);

    printf("\n");

    system("PAUSE");

    return 0;

    }

      1. Результаты выполнения программы.

    Программа считывает входное сообщение из файла “Shamir_in”

    Рис. 3.1 – Файл входных данных.

    Зашифрованное сообщение выводится на экран

    Рис. 3.2- Окно выполнения программы

    Затем сообщение дешифруется и сохраняется в файле “ Shamir_out2”

    Рис. 3.4 – Файл дешифрованных данных.

    1. Реализация алгоритма создания цифровой подписи RSA и проверки её подлинности на С++.

      1. Листинг программы с описанием основных переменных и функций.

    #include <iostream>

    #include <fstream>

    #include <stdio.h>

    #include <cstdlib>

    //#include <math.h>

    using namespace std;

    char str[1024];

    int gcd(__int64 vl,__int64 v2 )

    {

    // возвращает наибольший общий делитель

    while ( v2 )

    {

    int temp = v2;

    v2 = vl % v2;

    vl = temp;

    }

    return vl;

    }

    //Генерация ключа

    void keygen(__int64 *n, __int64 *e, __int64 *d)

    {

    __int64 p=127; //любые большие простые числа

    __int64 q=401;

    __int64 m,x;

    int i=4;

    *n=p*q;

    m=(p-1)*(q-1); //Функция Эвклида

    __int64 CislaFerma[5]={3,5,17,257,65537};//Простые числа Ферма

    do //выбрать число e взаимно простое m, причем e<m;

    {

    x=CislaFerma[i];

    if(gcd(m,x)==1)

    {

    *e=x;

    // break;

    }

    i--;

    }while(x>=m);

    // вычислить число d, такое что: d=e^-1 mod m

    for( x=1; x; x++ )

    if( !(((*e)*x-1)%m)){ *d=x; break; }

    if((*e==*d)||(*e==m)){cout<<"Не удалось найти корректный ключь, повторите попытку";}

    }

    __int64 modpow(__int64 x,__int64 e,__int64 n)

    {

    __int64 r = 1;

    while( e>0 )

    {

    if( (e%2)==1 ) { r = (r*x) % n; }

    e = e/2;

    x = (x * x) % n;

    }

    return r;

    }

    void encript(__int64 *msg,__int64 e,__int64 n)

    { *msg=modpow(*msg,e,n);}

    void decript(__int64 *EncriptMsg,__int64 d,__int64 n)

    { *EncriptMsg=modpow(*EncriptMsg,d,n);}

    void int_to_string(__int64 X)

    {// записывает каждую цифру числа Х в отдельную ячейку str.

    FILE* f_temp=fopen("temp.txt","w");

    fprintf(f_temp,"%ld",X);//записываем Х в файл

    fclose(f_temp);

    f_temp=fopen("temp.txt","r");

    fscanf(f_temp,"%s",str);//затем считываем его как строку.

    fclose(f_temp);

    }

    int main()

    {

    /* -------------Создание подписи RSA--------------*/

    __int64 n,e,d; char ch;

    __int64 p_pow=1,p=2,H=0,msg;

    keygen(&n,&e,&d);// генерируем ключи для шифрования и дешифрования

    printf("privat key(d,n)=(%ld,",d);printf("%ld)\n",n);

    printf("pablic key(e,n)=(%ld,",e);printf("%ld)\n",n);

    FILE* f_in=fopen("RSA_in.txt","r");//открываем входной файл

    FILE* f_out=fopen("RSA_out.txt","w");//открываем выходной файл

    if(f_in != NULL)

    {

    printf("\n plaintext:\n-------------------\n");

    while((ch = getc(f_in)) != EOF)//пока не конец файла

    {

    H+=ch*p_pow; //вычмсляем ХЭШ сообшения

    p_pow*=p;

    fprintf(f_out,"%c",ch);

    printf("%c",ch);

    }

    fprintf(f_out,"\n%Ld\n",0);//обозначаем конец файла

    int_to_string(H);

    for(int i=0;i<strlen(str);i++)

    {

    msg=str[i];

    encript(&msg,d,n);//шифруем ХЭШ секретным ключем

    fprintf(f_out,"%ld ",msg);//добовляем подпись

    }

    fprintf(f_out,"\n%Ld\n",0);

    }else printf("No file(read).\n");

    fclose(f_in);

    fclose(f_out);

    /* -------------проверка подлинности сообщения--------------*/

    f_in=fopen("RSA_out.txt","r");//открываем файл с подписью

    H=0;p_pow=1;

    while((ch = getc(f_in))!= '0')//считываем посимвольно

    {

    H+=ch*p_pow;//вычисляем ХЭШ

    p_pow*=p;

    }

    char dH[1024];

    msg=1;int i=0;

    printf("\n--------------------\nDS=");

    while(msg!=0)

    {

    fscanf(f_in,"%ld",&msg);

    printf("%ld ",msg);

    decript(&msg,e,n);

    dH[i++]=msg;

    }

    fclose(f_in);

    int_to_string(H);

    printf("\nHash=%s\n",str);

    printf("dHash=%s\n",dH);

    int flag=0;

    for(i=0;i<strlen(str);i++)if(str[i]!=dH[i])flag=1;

    if(flag==0)printf("Verification OK!\n");

    else printf("Verification failed!\n");

    system("PAUSE");

    return 0;

    }

      1. Результаты выполнения программы

    Рис 4.1 – Окно выполнения программы

    Программа считывает текст из файла “RSA_in.txt” :

    Рис 4.2 – Входной файл.

    Текст с электронной подписью сохраняется в файле “RSA_out”:

    Рис 4.3 – Файл с электронной подписью.

    В окне выполнения программы видим сообщение , т.е. в тексте не было никаких изменений с момента создания подписи, и ХЭШ сообщения совпадает с восстановленным из DS ХЭШем.

    Чтобы убедится в правильной работе программы, внесем небольшие изменения в текст с подписью и снова проведем проверку подлинности.

    Рис 4.4 – Файл с измененным сообщением

    Рис 4.5 – Окно выполнения программы

    Видим сообщение , т.к. восстановленный ХЭШ и ХЭШ сообщения не совпадают (даже при незначительных изменениях в тексте). Т.е. программа заметила изменения.

    1. Реализация алгоритма шифрования и дешифрования сообщения c помощью потокового шифра rc4.

      1. Листинг программы с описанием основных переменных и функций.

    #include<iostream>

    #include<cstring>

    using namespace std;

    void crypt(char cipher[]);

    int main()

    {

    cout<<"--------RC4---------"<<endl;

    char choose1,choose2;

    do{

    int s[256],t[256];

    char k[256];

    char plaintext[1024],ciphertext[1024];

    cout<<"Enter key:";

    cin>>k; //считать ключ

    for(int i=0;i<256;i++) //инициализация ключевого массива

    {

    s[i]=i;

    t[i]=k[i%strlen(k)]; //strlen(k)- длинна строки k

    }

    int j=0;

    for(int i=0;i<256;i++) //создание ключа

    {

    int temp;

    j=(j+s[i]+t[i])%256;

    temp=s[i];

    s[i]=s[j];

    s[j]=temp;

    }

    cout<<"\nEnter plaintext:"<<endl;

    cin>>plaintext; //считать текст, который требуется зашифровать

    int m,n,key[256],q;

    m=n=0;

    int i;

    cout<<"\nciphertext:"<<endl;

    for(i=0;i<strlen(plaintext);i++)//шифруем

    {

    int temp;

    m=(m+1)% 256;

    n=(n+s[n])% 256;

    temp=s[m];

    s[m]=s[n];

    s[n]=temp;

    q=(s[m]+s[n])%256;

    key[i]=s[q];

    ciphertext[i]=plaintext[i]^key[i];

    cout<<ciphertext[i];

    }

    ciphertext[i]='\0';

    cout<<endl;

    cout<<"\ndecrypt (y/n)";

    cin>>choose2;

    while(choose2=='y'||choose2=='Y')

    {

    crypt(ciphertext);//вызываем функцию, для дешифрования

    choose2='n';

    }

    cout<<endl;

    cout<<"\nrepeat encryption?(y/n)";

    cin>>choose1;

    }while(choose1=='y'||choose1=='Y');

    cout<<"\n______________________EXID_________________________"<<endl<<endl;

    system("pause");

    }

    void crypt(char cipher[])

    {

    int s[256],t[256];

    char k[256];

    char plaintext[1024];

    cout<<"\nEnter key:";

    cin>>k;

    for(int i=0;i<256;i++)

    {

    s[i]=i;

    t[i]=k[i%strlen(k)];

    }

    int j=0;

    for(int i=0;i<256;i++)

    {

    int temp;

    j=(j+s[i]+t[i])%256;

    temp=s[i];

    s[i]=s[j];

    s[j]=temp;

    }

    int m,n,key[256],q;

    m=n=0;

    int i;

    cout<<"\ndecriptet text"<<endl;

    for(i=0;i<strlen(cipher);i++)

    {

    int temp;

    m=(m+1)% 256;

    n=(n+s[n])% 256;

    temp=s[m];

    s[m]=s[n];

    s[n]=temp;

    q=(s[m]+s[n])%256;

    key[i]=s[q];

    plaintext[i]=cipher[i]^key[i];

    cout<<plaintext[i];

    }

    cout<<endl;

    }

      1. Результат выполнения программы.

    Рис 5.1 – Окно выполнения программы

    Введенный текст шифрован и дешифрован.

    Теперь попробуем ввести неверный ключ, при дешифровке:

    Рис 5.2 – Дешифровка с неверным ключом

    Видим, что дешифровка не происходит.

    Заключение

    На практике разумеется, никто не шифрует сообщение побайтово — разных значений всего лишь 256, и их легко получить перебором. Также никто не пытается представить всё сообщение в виде большого числа (т.к, шифруемое число не может быть больше n). На практике применяют метод, который называют «цифровым конвертом»: для каждого шифруемого сообщения создаётся случайный сеансовый ключ какого-то из методов симметричной криптографии; этим сеансовым ключом шифруют сообщение, а затем сеансовый ключ шифруют при помощи RSA. Получатель закрытым ключом восстанавливает сеансовый ключ, а сеансовым ключом расшифровывает сообщение.

    Симметричная криптография — штука хорошо изученная, надёжная, эффективная, быстрая и так далее. Когда-то, в 70-х годах, применяли DES, сейчас применяют AES, но по сути ничего не изменилось. Главная особенность: в симметричной криптографии ключ для шифрования и расшифровки — один и тот же. Применив случайные сеансовые ключи и RSA, мы запросто получаем асимметричную криптографию.

    Электронные подписи

    Здесь всё так же, как и с шифрованием: никто не пытается засунуть в RSA всё сообщение. На практике подписывают не само сообщение, а хэш сообщения. Это может быть устаревший MD5, SHA1 или что-то другое, но суть одинакова. Получается быстро, экономно и эффективно.

  • Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]