Страницы

Поиск по вопросам

Показаны сообщения с ярлыком rsa. Показать все сообщения
Показаны сообщения с ярлыком rsa. Показать все сообщения

среда, 4 марта 2020 г.

Авторизация в Steam на Delphi

#delphi #rsa #steam #cryptoapi


Добрый день, есть желание из своей программы, написанной на Delphi, авторизоваться
в Steam.
Посмотрев исходники программы Steam Desktop Authenticator, пришел к выводу, что нам
нужно сделать 2 POST-запроса к серверу Steam, первый вернет нам модуль и экспоненту
открытого ключа RSA, которым мы должны зашифровать свой пароль и отправить его во втором
запросе. Решил попробовать реализовать это с помощью функций Microsoft CryptoAPI: Next
Generation.
Набросал функцию, которая на входе получает 3 строки: пароль от Стима, открытые модуль
и экспоненту в виде строк, состоящих из шестнадцатеричных символов (их нам присылает
сервер). На выходе должны получить пароль, зашифрованный открытым ключом по алгоритму
RSA и закодированный в BASE64.




    unit uRSA;

    interface
    uses WinAPI.Windows, System.SysUtils, VCL.Dialogs, System.NetEncoding;

    //БЛОБ открытого ключа RSA, описание структуры есть на MSDN
    type TPublicKeyBLOB = packed record
    Magic: ULONG;
    BitLength: ULONG;
    cbPublicExp: ULONG;
    cbModulus: ULONG;
    cbPrime1: ULONG;
    cbPrime2: ULONG;
    exponent: array[0..2] of byte;
    modulus: array[0..255] of byte;
    end;
    pPublicKeyBLOB = ^TPublicKeyBLOB;

    //прототипы функций из библиотеки BCRYPT.DLL
    TBCryptOpenAlgorithmProvider = function (phAlgorithm: pHandle; pszAlgId: LPCWSTR;
    pszImplementation: LPCWSTR; dwFlags: DWORD): ULONG; stdcall;
    //--
    TBCryptImportKeyPair = function (hAlgorithm: THandle; hImportKey: THandle; pszBlobType:
LPCWSTR;
    phKey: pHandle; pbInput: pPublicKeyBLOB; cbInput: ULONG; dwFlags: ULONG): ULONG;
stdcall;
    //--
    TBCryptEncrypt = function (hKey: THandle; pbInput: PUCHAR; cbInput: ULONG; pPaddingInfo:
POINTER;
    pbIV: PUCHAR; cbIV: ULONG; pbOutput: PUCHAR; cbOutput: ULONG; pcbResult: PULONG;
dwFlags: ULONG): ULONG; stdcall;
    //--
    TBCryptCloseAlgorithmProvider = function (hAlgorithm: THandle; dwFlags: ULONG):
ULONG; stdcall;

    //сама функция шифрования
    type TRSA = class
    public
    function RSA_Encrypt(DataStr: string; modulusStr: string; exponentStr:   string):
string;
    end;

    const
    BCRYPT_RSAPUBLIC_MAGIC = $31415352;  // RSA1
    BCRYPT_PAD_PKCS1 = $00000002;

    implementation

    function HexToByte(Str: string): Byte;
    begin
    result :=  Byte(StrToInt('$' + (Str)));
    end;

    function TRsa.RSA_Encrypt(DataStr: string; modulusStr: string; exponentStr: string):
string;
    var
    PublicKeyBLOB: TPublicKeyBlob;
    i: word;
    status: ULONG;
    hLib: THandle;
    hAlg: THandle;
    hKey: tHandle;
    Password: TBytes;
    EncryptedPassword: TBytes;
    EncryptedSize: ULONG;
    BCryptOpenAlgorithmProvider: TBCryptOpenAlgorithmProvider;
    BCryptImportKeyPair: TBCryptImportKeyPair;
    BCryptEncrypt: TBCryptEncrypt;
    BCryptCloseAlgorithmProvider: TBCryptCloseAlgorithmProvider;
    begin
    //преобразовываем входные данные в массив байтов;
    Password := TEncoding.ASCII.GetBytes(DataStr);
    hLib := LoadLibrary('BCRYPT.DLL');
    //загрузка функций из библиотеки
    //функция инициализации провайдера
    @BCryptOpenAlgorithmProvider := GetProcAddress(hLib, 'BCryptOpenAlgorithmProvider');
    //функция импорта ключа
    @BCryptImportKeyPair := GetProcAddress(hLib, 'BCryptImportKeyPair');
    //функция шифрования
    @BCryptEncrypt := GetProcAddress(hLib, 'BCryptEncrypt');
    //функция освобождения провайдера
    @BCryptCloseAlgorithmProvider := GetProcAddress(hLib, 'BCryptCloseAlgorithmProvider');
    //собираем ключ
    with PublicKeyBLOB do
    begin
    Magic := BCRYPT_RSAPUBLIC_MAGIC;  // RSA1;
    BitLength := SizeOf(Modulus)*8;//размер модуля в битах
    cbPublicExp := SizeOf(Exponent);//размер экспоненты в байтах
    cbModulus := SizeOf(Modulus);//размер модуля в байтах
    //(необязательно) проверим, что в переданных параметрах - четное количество символов
    if (length(exponentstr) mod 2)  0 then
    exponentstr := '0' + exponentstr;
    if (length(modulusstr) mod 2)  0 then
    modulusstr := '0' + modulusstr;
    for i := Low(exponent) to High(exponent) do
    exponent[i] := HexToByte(copy(exponentstr,i*2+1,2));
    for i := Low(modulus) to High(modulus) do
    modulus[i] := HexToByte(copy(modulusstr,i*2+1,2));
    end;
    //инициализация провайдера
    status := BCryptOpenAlgorithmProvider(@halg,'RSA',nil,0);
    //импорт ключа
    status := BCryptImportKeyPair(hAlg,0,'RSAPUBLICBLOB', @hKey, @PublicKeyBLOB,
    SizeOf(PublicKeyBLOB),0);
    //шифрование сообщения. Первый проход - получаем размер выходного буфера, второй
- шифруем текст
    status := BCryptEncrypt(hKey, @Password[0], Length(Password), nil, nil, 0, nil,
0, @EncryptedSize, BCRYPT_PAD_PKCS1);
    SetLength(EncryptedPassword,EncryptedSize);
    status := BCryptEncrypt(hKey, @Password[0], Length(Password), nil, nil, 0, @EncryptedPassword[0],
Length(EncryptedPassword), @EncryptedSize, BCRYPT_PAD_PKCS1);
    //кодируем зашифрованное сообщение в Base64
    Result := TNetEncoding.Base64.EncodeBytesToString(EncryptedPassword);
    //освобождаем память
    status := BCryptCloseAlgorithmProvider(hAlg,0);
    FreeLibrary(hLib);
    end;

    end.




Вроде бы все успешно отрабатывает, но, когда делаю POST-запрос с зашифрованным паролем
к серверу STEAM - получаю в ответ:
    {"success":false,"requires_twofactor":false,
   "message":"The account name or password that you have entered is incorrect.",
   "clear_password_field":true,"captcha_needed":false,"captcha_gid":-1}

На вход функции подаются строки в виде

   "publickey_mod":"c152954756c74aee68ca1e6ac77bc71af6a93660bd56f1517e8141436b8fda4e32cc123ced02c0421a6a8d505dd25d07c4df9a25cf682799ea87ceb0eeaef7c7e71a8a30ec6c60d4dcfa8006a193f0b99958655894147b13d4f15285f9d7dc75baaa61b1b12265a303324c6b5e648bb272d87e0003295ca124e6e7a8a5ec45b9d2f1399e3ffbd0d9aec012afe1fbe65bfc9bd4c2087e7b7a73d2f9286e311e77341113f4cbde9a2a94141252e395e36bc2bf135ef38be90458090d6cd2c419e293a5dcf93bff3df2ca641edfb38ff85f6c9f8864f2905015cf34bd35d74e324f4a6a156c2462cfdd1c1fafb15567047a59b188c9f2a4f78157f2ec120ce09b5d",
   "publickey_exp":"010001"


Буду очень признателен, если кто-нибудь укажет на ошибку или даст совет: как в Delphi
можно зашифровать сообщение, имея экспоненту и модуль открытого ключа RSA.
    


Ответы

Ответ 1



Проблема была в некорректной работе //кодируем зашифрованное сообщение в Base64 Result := TNetEncoding.Base64.EncodeBytesToString(EncryptedPassword); Эта функция не убирает переносы строки, так что придется получившийся результат обработать дополнительно: //кодируем зашифрованное сообщение в Base64 Result := TNetEncoding.Base64.EncodeBytesToString(EncryptedPassword); //удалим переносы строки Result := StringReplace(Result, #13#10, '',[rfReplaceAll]); Либо же можно использовать аналогичную функцию из пакета Indy, которая работает верно: uses IdCoderMIME, idcoder, idglobal; ... function MyFunc(): string; var Temp: TIdBytes; begin ... Result := TIdEncoderMIME.EncodeBytes(Temp); end; Рабочий код : unit uRSA; interface uses WinAPI.Windows, System.SysUtils, VCL.Dialogs, System.NetEncoding; //БЛОБ открытого ключа RSA, описание структуры есть на MSDN type TPublicKeyBLOB = packed record Magic: ULONG; BitLength: ULONG; cbPublicExp: ULONG; cbModulus: ULONG; cbPrime1: ULONG; cbPrime2: ULONG; exponent: array[0..2] of byte; modulus: array[0..255] of byte; end; pPublicKeyBLOB = ^TPublicKeyBLOB; //прототипы функций из библиотеки BCRYPT.DLL TBCryptOpenAlgorithmProvider = function (phAlgorithm: pHandle; pszAlgId: LPCWSTR; pszImplementation: LPCWSTR; dwFlags: DWORD): ULONG; stdcall; //-- TBCryptImportKeyPair = function (hAlgorithm: THandle; hImportKey: THandle; pszBlobType: LPCWSTR; phKey: pHandle; pbInput: pPublicKeyBLOB; cbInput: ULONG; dwFlags: ULONG): ULONG; stdcall; //-- TBCryptEncrypt = function (hKey: THandle; pbInput: PUCHAR; cbInput: ULONG; pPaddingInfo: POINTER; pbIV: PUCHAR; cbIV: ULONG; pbOutput: PUCHAR; cbOutput: ULONG; pcbResult: PULONG; dwFlags: ULONG): ULONG; stdcall; //-- TBCryptCloseAlgorithmProvider = function (hAlgorithm: THandle; dwFlags: ULONG): ULONG; stdcall; //сама функция шифрования type TRSA = class public function Encrypt(DataStr: string; modulusStr: string; exponentStr: string): string; end; const BCRYPT_RSAPUBLIC_MAGIC = $31415352; // RSA1 BCRYPT_PAD_PKCS1 = $00000002; BCRYPT_RSA_ALGORITHM = 'RSA'; BCRYPT_RSAPUBLIC_BLOB = 'RSAPUBLICBLOB'; implementation function HexToByte(Str: string): Byte; begin result := Byte(StrToInt('$' + (Str))); end; function TRsa.Encrypt(DataStr: string; modulusStr: string; exponentStr: string): string; var PublicKeyBLOB: TPublicKeyBlob; i: word; status: ULONG; hLib: THandle; hAlg: THandle; hKey: tHandle; Password: TBytes; EncryptedPassword: TBytes; EncryptedSize: ULONG; BCryptOpenAlgorithmProvider: TBCryptOpenAlgorithmProvider; BCryptImportKeyPair: TBCryptImportKeyPair; BCryptEncrypt: TBCryptEncrypt; BCryptCloseAlgorithmProvider: TBCryptCloseAlgorithmProvider; begin //преобразовываем входные данные в массив байтов; Password := TEncoding.ASCII.GetBytes(DataStr); hLib := LoadLibrary('BCRYPT.DLL'); if hLib < 32 then begin ShowMessage('Error while loading BCRYPT.DLL!'); exit; end; //загрузка функций из библиотеки //функция инициализации провайдера @BCryptOpenAlgorithmProvider := GetProcAddress(hLib, 'BCryptOpenAlgorithmProvider'); //функция импорта ключа @BCryptImportKeyPair := GetProcAddress(hLib, 'BCryptImportKeyPair'); //функция шифрования @BCryptEncrypt := GetProcAddress(hLib, 'BCryptEncrypt'); //функция освобождения провайдера @BCryptCloseAlgorithmProvider := GetProcAddress(hLib, 'BCryptCloseAlgorithmProvider'); //собираем ключ with PublicKeyBLOB do begin Magic := BCRYPT_RSAPUBLIC_MAGIC; // RSA1; BitLength := SizeOf(Modulus)*8;//размер модуля в битах cbPublicExp := SizeOf(Exponent);//размер экспоненты в байтах cbModulus := SizeOf(Modulus);//размер модуля в байтах //(необязательно) проверим, что в переданных параметрах - четное количество символов if (length(exponentstr) mod 2) <> 0 then exponentstr := '0' + exponentstr; if (length(modulusstr) mod 2) <> 0 then modulusstr := '0' + modulusstr; for i := Low(exponent) to High(exponent) do exponent[i] := HexToByte(copy(exponentstr,i*2+1,2)); for i := Low(modulus) to High(modulus) do modulus[i] := HexToByte(copy(modulusstr,i*2+1,2)); end; //инициализация провайдера status := BCryptOpenAlgorithmProvider(@halg,BCRYPT_RSA_ALGORITHM,nil,0); if status <> 0 then begin ShowMessage('BCryptOpenAlgorithmProvider error, status: ' + IntToStr(status) + ', ' + SysErrorMessage(GetLastError())); exit; end; //импорт ключа status := BCryptImportKeyPair(hAlg,0,BCRYPT_RSAPUBLIC_BLOB, @hKey, @PublicKeyBLOB, SizeOf(PublicKeyBLOB),0); if status <> 0 then begin ShowMessage('BCryptImportKeyPair error, status: ' + IntToStr(status) + ', ' + SysErrorMessage(GetLastError())); exit; end; //шифрование сообщения. Первый проход - получаем размер выходного буфера, второй - шифруем текст status := BCryptEncrypt(hKey, @Password[0], Length(Password), nil, nil, 0, nil, 0, @EncryptedSize, BCRYPT_PAD_PKCS1); if status <> 0 then begin ShowMessage('BCryptEncrypt error 1, status: ' + IntToStr(status) + ', ' + SysErrorMessage(GetLastError())); exit; end; SetLength(EncryptedPassword,EncryptedSize); status := BCryptEncrypt(hKey, @Password[0], Length(Password), nil, nil, 0, @EncryptedPassword[0], Length(EncryptedPassword), @EncryptedSize, BCRYPT_PAD_PKCS1); if status <> 0 then begin ShowMessage('BCryptEncrypt error 2, status: ' + IntToStr(status) + ', ' + SysErrorMessage(GetLastError())); exit; end; //освобождаем занятые ресурсы status := BCryptCloseAlgorithmProvider(hAlg,0); if status <> 0 then begin ShowMessage('BCryptCloseAlgorithmProvider error, status: ' + IntToStr(status) + SysErrorMessage(GetLastError())); exit; end; //кодируем зашифрованное сообщение в Base64 Result := TNetEncoding.Base64.EncodeBytesToString(EncryptedPassword); //удалим переносы строки Result := StringReplace(Result, #13#10, '',[rfReplaceAll]); //выгружаем библиотеку FreeLibrary(hLib); end; end. На вход функции подаются строки в виде: "publickey_mod":"c152954756c74aee68ca1e6ac77bc71af6a93660bd56f1517e8141436b8fda4e32cc123ced02c0421a6a8d505dd25d07c4df9a25cf682799ea87ceb0eeaef7c7e71a8a30ec6c60d4dcfa8006a193f0b99958655894147b13d4f15285f9d7dc75baaa61b1b12265a303324c6b5e648bb272d87e0003295ca124e6e7a8a5ec45b9d2f1399e3ffbd0d9aec012afe1fbe65bfc9bd4c2087e7b7a73d2f9286e311e77341113f4cbde9a2a94141252e395e36bc2bf135ef38be90458090d6cd2c419e293a5dcf93bff3df2ca641edfb38ff85f6c9f8864f2905015cf34bd35d74e324f4a6a156c2462cfdd1c1fafb15567047a59b188c9f2a4f78157f2ec120ce09b5d", "publickey_exp":"010001"

среда, 26 февраля 2020 г.

RSA криптография между Java и C# приложениями

#java #c_sharp #криптография #rsa


Почему при генерации RSA ключа длиной 512 бит в C# и в Java разная длина в байтах
публичного ключа?

Пример кода C#:

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(512);
XDocument xdocPub = XDocument.Parse(rsa.ToXmlString(false));
string publicKey = xdocPub.Element("RSAKeyValue").Element("Modulus").Value;

byte[] publicArray = Convert.FromBase64String(publicKey);
Console.WriteLine("Public Key Byte Array Length: " + publicArray.Length);
Console.WriteLine("Public Key Base64 Length: " + publicKey.Length);
Console.WriteLine("Public Key Text: " + publicKey);


Результат:

Public Key Byte Array Length: 64
Public Key Base64 Length: 88
Public Key Text: uELcIjgR6GpiayZ1wHruHOtO8dpg+xmg85VAvunWUEL+aifoyk9+CA/dez4UmuIwLEgRlpVoIIOD0e5i9v8lrQ==


Пример кода Java:

final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(new RSAKeyGenParameterSpec(512, RSAKeyGenParameterSpec.F4));
KeyPair pair = keyGen.genKeyPair();

final byte[] arrayPublic = ((RSAPublicKey) pair.getPublic()).getModulus().toByteArray();

System.out.println("Public Key [origin] lenght: " + arrayPublic.length);

String publicBase64 = Base64.getEncoder().encodeToString(arrayPublic);

System.out.println("Public Key [base64] lenght : " + publicBase64.length());
System.out.println("Public Key [base64]: " + publicBase64);


Результат:

Public Key [origin] lenght: 65
Public Key [base64] lenght : 88
Public Key [base64]: ANuun1/CnOmk2ghsydz4cKvPCd7q0YqqeyjzLqtKx7QHqv1tFjJYsXquYGcY8zkaPsPBrRlCAJov7+J88GaFDKc=


Заметил, что в байт массиве ключа сгенерированного в Java присутствует нулевой байт
в начале массива ключа.

Самое интересное, что если я отправляю ключ из C# приложения длиной 64 байта, то
в Java приложении получаю ошибку "exponent is larger than modulus" в следующем коде:

try
{
    final KeyFactory kfac = KeyFactory.getInstance("RSA");
    final BigInteger modulus = new BigInteger("здесь вставляется byte[] массив публичного
ключа от C#");
    final RSAPublicKeySpec kspec1 = new RSAPublicKeySpec(modulus, RSAKeyGenParameterSpec.F4);

    RSAPublicKey publicKey = (RSAPublicKey) kfac.generatePublic(kspec1);
}
catch (GeneralSecurityException e)
{
    e.printStackTrace();
}


При этом, если я добавлю нулевой байт в начало ключа перед отправкой из C# приложения
в Java приложение, то со стороны Java приложения нет никаких проблем с инициализацией
криптографии и шифровкой отправляемых данных. Но в этом случае я не могу декодировать
входящие данные в C# приложении этим же экземпляром криптографии. Получаю ошибку "Плохие
данные".

Подскажите, что я делаю не так и почему длина ключей разная?


  UPD 1: добавлен тест в Java


PublicKey взят из первого примера сгенерированного в C#.

public class Test
{
    public static void main(String[] args)
    {
        final String base64key = "uELcIjgR6GpiayZ1wHruHOtO8dpg+xmg85VAvunWUEL+aifoyk9+CA/dez4UmuIwLEgRlpVoIIOD0e5i9v8lrQ==";

        try
        {
            byte[] publicKeyArray = Base64.getDecoder().decode(base64key);
            final KeyFactory kfac = KeyFactory.getInstance("RSA");
            final BigInteger modulus = new BigInteger(1, publicKeyArray);
            final RSAPublicKeySpec kspec1 = new RSAPublicKeySpec(modulus, RSAKeyGenParameterSpec.F4);

            RSAPublicKey publicKey = (RSAPublicKey) kfac.generatePublic(kspec1);

            byte[] array = publicKey.getModulus().toByteArray();

            System.out.println("Public Key [Array] lenght : " + array.length);

            String publicBase64 = Base64.getEncoder().encodeToString(array);

            System.out.println("Public Key [base64] lenght : " + publicBase64.length());
            System.out.println("Public Key [base64]: " + publicBase64);
        }
        catch (GeneralSecurityException e)
        {
            e.printStackTrace();
        }
    }
}


В результате инициализации RSAPublicKey в Java Base64 ключ не соответствует входному.
Хотя по длине 65 байт. Но это работает только с signum = 1.

Public Key [Array] lenght : 65
Public Key [base64] lenght : 88
Public Key [base64]: ALhC3CI4EehqYmsmdcB67hzrTvHaYPsZoPOVQL7p1lBC/mon6MpPfggP3Xs+FJriMCxIEZaVaCCDg9HuYvb/Ja0=



  UPD 2: проблему C# генерации ключей RSA решила библиотека Bouncy
  Castle. У библиотеки есть
  исходники поэтому я взял только RSA часть и внедрил в свой проект.

    


Ответы

Ответ 1



Лишний байт BigInteger.toByteArray включает в результат знаковый бит числа: ... The array will contain the minimum number of bytes required to represent this BigInteger, including at least one sign bit, which is (ceil((this.bitLength() + 1)/8)) ... Т.ч. да, нулевой байт в начале можно отрезать по необходимости. Сделать это можно с помощью System.arraycopy: byte[] array = publicKey.getModulus().toByteArray(); //убираем лишний нолик final byte[] keyBytes = new byte[64]; System.arraycopy(array, 1, keyBytes, 0, 64); Посмотрите ответ @Maarten Bodewes на близкий вопрос на английском (How insert bits into block in java cryptography?), там приводится готовый метод для «нормализации» массива байтов с учетом ведущего нуля, также учитывается случай, когда массив короче 64 (вроде возникает только для приватных ключей). Плохие данные Конструктор BigInteger​(byte[] val) также ожидает получить знаковое представление числа и пытается считать у ключа знаковый бит. Попробуйте использовать конструктор, который принимает знаковый бит отдельно BigInteger​(int signum, byte\[\] magnitude): new BigInteger(1, /*байты ключа*/) Похожие вопросы на en.SO: how to build a rsa key with a modulus of 64 bytes in java How insert bits into block in java cryptography?

среда, 5 февраля 2020 г.

308 в степени 611 mod 899

#cpp #алгоритм #математика #шифрование #rsa


Как вычислить значение настолько "большого" выражения, как 308^611 (mod 899).
Просто делаю алгоритм RSA на C++. Возможно, решение в mod n, но я не понимаю? как
это сделать.
    


Ответы

Ответ 1



Просто выполняете умножения по модулю, а для возведения в степень используете быстрое возведение в степень. Рассмотрим ваш случай. 689 = 1010110001 Значит, 308 в 689 степени считается так (все действия по модулю 899). 308^2 = 469 308^4 = 469^2 = 605 308^8 = 605*605 = 132 308^16 = 132*132 = 343 16 степень соответствует второй справа единице в бинарном представлении, так что теперь множим 343 на 308 и получаем 461 - это 308 в 17 степени по модулю 899. Дальше получаем 308^32, перемножая 343*343, умножаем на наше 461... Ну, и так далее. Идея понятна? Примерно так это выглядит на C++: unsigned long long iqpow(unsigned long long x, unsigned long long e, unsigned long long p) { unsigned long long res = 1; for(x %= p;e;e>>=1) { if (e&1) res = (res*x)%p; x = (x*x)%p; } return res; } int main() { cout << iqpow(308,611,899) << endl; }

четверг, 23 января 2020 г.

Как создать RSA (PEM 1024 bit) пару ключей на Objective-C или Apple Swift?

#swift #objective_c #ios #rsa #key


Доброе время суток, в общем нужно создать RSA (PEM 1024 bit) пару ключей, пробовал
разные варианты, но проблема в том, что как оказалось под iOS это большая редкость,
пробовал таким образом:

Способ #1

Способ #2

Но это не то что нужно, они создаются в HEX нужен PEM, либо же как можно преобразовать
ключ в PEM?
    


Ответы

Ответ 1



Получилось реализовать с помощью библиотеки.

воскресенье, 12 января 2020 г.

Шифрование строки

#php #rsa


Есть модуль, есть экспонента, есть строка, которую нужно зашифровать:

$modulus = 'CD0....C9246E1';
$exponent = '0...1';
$rsa = new Crypt_RSA();
$modulus = new Math_BigInteger(base64_decode($modulus), 256);
$exponent = new Math_BigInteger(base64_decode($exponent), 256);
$rsa->loadKey(array('n' => $modulus, 'e' => $exponent));
echo $rsa->encrypt('THISISMYSTR');


THISISMYST - строка, которую пытаюсь зашифровать. Но получаю какую-то гадость на выходе.
    


Ответы

Ответ 1



Эта гадость на выходе результат работы функции и она в бинарном виде. Для перевода в читаемый вид можно использовать base64_encode(); Что касается того, что echo выводит разные строки, если не ошибаюсь, результат работы RSA всегда разный. Для проверки выполните расшифровку через $rsa->decrypt(), если результат будет соответствовать тому, что вы зашифровали, то ваш алгоритм работает правильно.

суббота, 11 января 2020 г.

Использование RSA для “Ментального покера”

#криптография #rsa


В книге "Прикладная криптография" Шнайера, в разделе посвященном "Ментальному покеру"
предлагается использовать для шифрования RSA с идентичными модулями. В этом случае
процедура становится коммутативной, это в данном случае важно:


  Т.е. для расшифровки карт последовательно зашифрованных двумя ключами, можно применять
эти ключи в произвольном порядке. 


А я вот что-то не могу сообразить - как у двух игроков могут быть ключи с идентичными
модулями? Если модуль в RSA это произведение двух простых чисел - то существует единственный
вариант его разложения на эти числа. И идентичными модули могут быть только если у
обоих одинаковые пары ключей - а это лишает всю процедуру шифрования смысла.

Или тут имеется в виду что-то другое?

    


Ответы

Ответ 1



И идентичными модули могут быть только если у обоих одинаковые пары ключей - а это лишает всю процедуру шифрования смысла. Здесь вы неправы, для одного модуля существует очень много разных пар ключей. Обратите внимание на процедуру генерации ключей RSA: публичная экспонента e выбирается случайным образом (на практике всегда берут 65537). Мы можем выбрать любое e, и получим уникальную пару ключей. В описанной в книге схеме не совсем тот RSA, который привычно видеть в других криптосхемах. Стороны генерируют разные ключи для одного модуля, и обе стороны знают его разложение на простые числа. Факторизация дает возможность вычислить приватный ключ с публичного ключа, но в приведенной схеме они не знают даже публичные ключи друг друга. Только на шаге 7 они раскрывают свои ключи, что бы убедится в отсутствии мошенничества.

среда, 25 декабря 2019 г.

RSA шифрование своим ключом на Python

#python #криптография #rsa


Как зашифровать методом RSA сообщение своим ключом?

import rsa
(pubkey, privkey) = rsa.newkeys(512)

message = b'Hello world!'

# шифруем
crypto = rsa.encrypt(message, pubkey)
print(crypto)

    


Ответы

Ответ 1



Шифрование с публичным ключом Если Алиса хочет послать Бобу сообщение, зашифрованное его открытым ключом, не подписывая сообщение, то нужен только публичный ключ Боба: >>> # Generate keys on Bob's computer >>> import nacl.encoding # $ pip install pynacl >>> import nacl.public >>> skbob = nacl.public.PrivateKey.generate() >>> skbob.public_key.encode(encoder=nacl.encoding.Base64Encoder) b'eVNxqEZ1/cbiu8G+aep6OR+ccf2kZLKqDYGhtZPLnRg=' Получив этот ключ, Алиса может зашифровать своё сообщение для Боба: >>> # Encrypt message on Alice's computer >>> import nacl.encoding >>> import nacl.public >>> pkbob = nacl.public.PublicKey(b'eVNxqEZ1/cbiu8G+aep6OR+ccf2kZLKqDYGhtZPLnRg=', encoder=nacl.encoding.Base64Encoder) >>> sealed_box = nacl.public.SealedBox(pkbob) >>> message = b'hello world' >>> sealed_box.encrypt(message, encoder=nacl.encoding.Base64Encoder) b'jhh9bnv5boORCrnEVzKYxh6tMr7iJ9npzLRSpUXGAXXUuFUZQS9Y7UCSBVuyfGvA9suZ4rMDbRfBy0c=' Получив зашифрованное сообщение, Бобу легко его расшифровать: >>> # Decrypt message on Bob's computer >>> encrypted = b'jhh9bnv5boORCrnEVzKYxh6tMr7iJ9npzLRSpUXGAXXUuFUZQS9Y7UCSBVuyfGvA9suZ4rMDbRfBy0c=' >>> unseal_box = nacl.public.SealedBox(skbob) >>> unseal_box.decrypt(encrypted, encoder=nacl.encoding.Base64Encoder) b'hello world' Приведённый код реализован на Curve25519 примитивах на эллиптических кривых. Обратите внимание: в коде явно не упоминается ни один криптографический примитив. Чем меньше движущихся частей, которые нужно понимать, тем меньше шансов сломать что-то ненароком. См. If You’re Typing the Letters A-E-S Into Your Code You’re Doing It Wrong. PyNaCl это Питон-обёртка для современной переносимой libsodium крипто-библиотеки. RSA шифрование Чтобы зашифровать сообщение именно RSA алгоритмом, используя публичный ключ из файла, можно M2Crypto обёртку над OpenSSL использовать: #!/usr/bin/env python import base64 from M2Crypto import RSA # $ pip install m2crypto # ssh-keygen -f ~/.ssh/id_rsa.pub -e -m PKCS8 >id_rsa.pub.pem rsa = RSA.load_pub_key('id_rsa.pub.pem') # load public key encrypted = rsa.public_encrypt(b'hello world', RSA.pkcs1_oaep_padding) # encrypt print(base64.b64encode(encrypted).decode()) # print as base64 Обратите внимание: здесь используетcя требуемая для новых приложений RSAES-OAEP схема. Чтобы расшифровать encrypted_base64 сообщение, используя частный ключ из файла: #!/usr/bin/env python import base64 import os from M2Crypto import RSA # $ pip install m2crypto rsa = RSA.load_key(os.path.expanduser('~/.ssh/id_rsa')) # load private key encrypted = base64.b64decode(encrypted_base64) # get raw bytes print(rsa.private_decrypt(encrypted, RSA.pkcs1_oaep_padding).decode()) # decrypt # -> hello world

Ответ 2



Вот пример, используещий модуль PyCrypto: In [2]: from Crypto.PublicKey import RSA ...: ...: fn_priv = r'D:\temp\id_rsa' ...: fn_pub = r'D:\temp\id_rsa.pub' ...: ...: with open(fn_pub, 'rb') as pub, open(fn_priv, 'rb') as priv: ...: key_pub = RSA.importKey(pub.read()) ...: key_priv = RSA.importKey(priv.read()) ...: ...: encrypted = key_pub.encrypt(b'Hello world!', 111) ...: ...: decrypted = key_priv.decrypt(encrypted) ...: ...: print(encrypted) ...: print('=' * 60) ...: print(decrypted) ...: (b'\xa7\xf1\x8b0\xe8\xcb|\xda\xb9F\\o_\xd5r\x07&\x92/S\x93\xb9\x91\xe9s({\x00\x93U\'\xe6_=M\x07PBI\xab!\xb2 |Fi\xca\xdf\x9d\xb9\x8fJ\x0f\xe6 \xc6\x14\xac\x15?)u\x15\xf6\xb8\xe2\xe8\xef\x8e$1\xe3\xa5v\xa0G\xa3\x 80y\xec\xf1c\x16\x15&u\x85O\xc5i\xcfCY\x17\x0fq\tI\x9f\x1e\x94_\x81\xb6\x1f\x0f\xc7\xa3\x8bL\xee\xf0_jA\xeea\x15\xa2{ )\xb9\x0c\x96\xaa\xea* \x8c\xb4g\xd0&\xd1\x9b\x9d\xe3\xe4\xe1d\xa9zi\xe2\x8c\x93\xc8\'V#\xf24tEoXo\xc7\x01\xa2\x92\xb1\x9c\x1a\x0f\x10,\x99r)m\x85F\xcdO\xa3\xe1\x8 b\xc6\xd7\x0e\xc7l\x97u\x94&\x17\xd7\x18\x88\x9c9\xc0\x86\xcf\x1f\xf3yd\xfd=-BF\xdc\xeaj\xf7\xee\xf6$\x8e\xc4\x9c\xb6YCF+\x03\xcb\xe2',) ============================================================ b'Hello world!' PS для данного примера я специально сгенерировал ключи без пароля, с длиной 4096 бит

воскресенье, 15 декабря 2019 г.

Почему не работает git clone при подключении к репозиторию по putty?

#linux #git #ssh #rsa #putty


Сервер с centos подключается к репозиторию bitbucket по ssh-rsa ключам. Если это
делать непосредственно под root'ом на этой машине, то git clone проходит успешно. Если
подключиться к машине по putty и попробовать склонировать репозиторий под рутом, появляется
сообщение об отказе в правах. Почему так происходит? Как сгенерировать ключи, по которым
можно будет работать с гитом под putty?

Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
    


Ответы

Ответ 1



ни в коем случае не надо «работать под root-ом». подключаетесь к машине вы, надеюсь, под именем «рядового» пользователя, вот от его имени и надо работать, получая root-овые привилегии лишь для выполнения административных задач. git clone и тому подобные команды оперируют приватным ключом (в вашем случае — из файла id_rsa), хранящимся в каталоге .ssh/ в домашнем каталоге пользователя, от имени которого выполняется команда. для пользователя root это обычно каталог /root/.ssh/. для «рядового» пользователя это обычно /home/пользователь/.ssh/. вам надо скопировать файл (в вашем случае /root/.ssh/id_rsa) в каталог «рядового» пользователя /home/пользователь/.ssh/. если такого каталога нет, создайте его (от имени пользователя). если каталог уже существует, эта команда не сделают ничего: $ mkdir -p ~/.ssh если такой каталог уже существовал и в нём уже были файлы id_rsa и id_rsa.pub, на всякий случай переименуйте их (вдруг они нужны для доступа куда-нибудь ещё): $ mv ~/.ssh/id_rsa{,.backup}; mv ~/.ssh/id_rsa.pub{,.backup} теперь копируем файлы и изменяем их владельца (операция осуществляется от имени root-а, ведь у «рядовых» пользователей нет доступа к его домашнему каталогу): # cp /root/.ssh/id_rsa{,.pub} /home/пользователь/.ssh/ # chown -R пользователь /home/пользователь/.ssh/ дальше (уже от имени пользователя) сто́ит [пере]установить права на каталог и его содержимое: $ chmod -R u+w,go= ~/.ssh если проделанные операции не помогли, и при выполнении git clone от имени пользователя (при подключении с помощью putty) возникает та же самая ошибка, в первую очередь проверьте значение переменной окружения HOME: $ echo $HOME она должна содержать домашний каталог пользователя (обычно: /home/пользователь). именно на значение этой переменной и «опираются» программы (тот же git) при поиске файлов: если в этой переменной хранится что-то отличное от домашнего каталога, то, например, каталог .ssh (и файлы в нём) будут разыскиваться совсем не там, где следует. дополнение по поводу использования нестандартного имени (или местоположения) файла с секретным ключом. например, файл с секретным ключом называется ~/.ssh/id_rsa.vtoroj. тогда для использования именно этого ключа при подключении к серверу bitbucket.org можно добавить в конец файла ~/.ssh/config такие строки: host bitbucket.org identityfile ~/.ssh/id_rsa.vtoroj

понедельник, 20 мая 2019 г.

Авторизация в Steam на Delphi

Добрый день, есть желание из своей программы, написанной на Delphi, авторизоваться в Steam. Посмотрев исходники программы Steam Desktop Authenticator, пришел к выводу, что нам нужно сделать 2 POST-запроса к серверу Steam, первый вернет нам модуль и экспоненту открытого ключа RSA, которым мы должны зашифровать свой пароль и отправить его во втором запросе. Решил попробовать реализовать это с помощью функций Microsoft CryptoAPI: Next Generation. Набросал функцию, которая на входе получает 3 строки: пароль от Стима, открытые модуль и экспоненту в виде строк, состоящих из шестнадцатеричных символов (их нам присылает сервер). На выходе должны получить пароль, зашифрованный открытым ключом по алгоритму RSA и закодированный в BASE64.

unit uRSA;
interface uses WinAPI.Windows, System.SysUtils, VCL.Dialogs, System.NetEncoding;
//БЛОБ открытого ключа RSA, описание структуры есть на MSDN type TPublicKeyBLOB = packed record Magic: ULONG; BitLength: ULONG; cbPublicExp: ULONG; cbModulus: ULONG; cbPrime1: ULONG; cbPrime2: ULONG; exponent: array[0..2] of byte; modulus: array[0..255] of byte; end; pPublicKeyBLOB = ^TPublicKeyBLOB;
//прототипы функций из библиотеки BCRYPT.DLL TBCryptOpenAlgorithmProvider = function (phAlgorithm: pHandle; pszAlgId: LPCWSTR; pszImplementation: LPCWSTR; dwFlags: DWORD): ULONG; stdcall; //-- TBCryptImportKeyPair = function (hAlgorithm: THandle; hImportKey: THandle; pszBlobType: LPCWSTR; phKey: pHandle; pbInput: pPublicKeyBLOB; cbInput: ULONG; dwFlags: ULONG): ULONG; stdcall; //-- TBCryptEncrypt = function (hKey: THandle; pbInput: PUCHAR; cbInput: ULONG; pPaddingInfo: POINTER; pbIV: PUCHAR; cbIV: ULONG; pbOutput: PUCHAR; cbOutput: ULONG; pcbResult: PULONG; dwFlags: ULONG): ULONG; stdcall; //-- TBCryptCloseAlgorithmProvider = function (hAlgorithm: THandle; dwFlags: ULONG): ULONG; stdcall;
//сама функция шифрования type TRSA = class public function RSA_Encrypt(DataStr: string; modulusStr: string; exponentStr: string): string; end;
const BCRYPT_RSAPUBLIC_MAGIC = $31415352; // RSA1 BCRYPT_PAD_PKCS1 = $00000002;
implementation
function HexToByte(Str: string): Byte; begin result := Byte(StrToInt('$' + (Str))); end;
function TRsa.RSA_Encrypt(DataStr: string; modulusStr: string; exponentStr: string): string; var PublicKeyBLOB: TPublicKeyBlob; i: word; status: ULONG; hLib: THandle; hAlg: THandle; hKey: tHandle; Password: TBytes; EncryptedPassword: TBytes; EncryptedSize: ULONG; BCryptOpenAlgorithmProvider: TBCryptOpenAlgorithmProvider; BCryptImportKeyPair: TBCryptImportKeyPair; BCryptEncrypt: TBCryptEncrypt; BCryptCloseAlgorithmProvider: TBCryptCloseAlgorithmProvider; begin //преобразовываем входные данные в массив байтов; Password := TEncoding.ASCII.GetBytes(DataStr); hLib := LoadLibrary('BCRYPT.DLL'); //загрузка функций из библиотеки //функция инициализации провайдера @BCryptOpenAlgorithmProvider := GetProcAddress(hLib, 'BCryptOpenAlgorithmProvider'); //функция импорта ключа @BCryptImportKeyPair := GetProcAddress(hLib, 'BCryptImportKeyPair'); //функция шифрования @BCryptEncrypt := GetProcAddress(hLib, 'BCryptEncrypt'); //функция освобождения провайдера @BCryptCloseAlgorithmProvider := GetProcAddress(hLib, 'BCryptCloseAlgorithmProvider'); //собираем ключ with PublicKeyBLOB do begin Magic := BCRYPT_RSAPUBLIC_MAGIC; // RSA1; BitLength := SizeOf(Modulus)*8;//размер модуля в битах cbPublicExp := SizeOf(Exponent);//размер экспоненты в байтах cbModulus := SizeOf(Modulus);//размер модуля в байтах //(необязательно) проверим, что в переданных параметрах - четное количество символов if (length(exponentstr) mod 2) 0 then exponentstr := '0' + exponentstr; if (length(modulusstr) mod 2) 0 then modulusstr := '0' + modulusstr; for i := Low(exponent) to High(exponent) do exponent[i] := HexToByte(copy(exponentstr,i*2+1,2)); for i := Low(modulus) to High(modulus) do modulus[i] := HexToByte(copy(modulusstr,i*2+1,2)); end; //инициализация провайдера status := BCryptOpenAlgorithmProvider(@halg,'RSA',nil,0); //импорт ключа status := BCryptImportKeyPair(hAlg,0,'RSAPUBLICBLOB', @hKey, @PublicKeyBLOB, SizeOf(PublicKeyBLOB),0); //шифрование сообщения. Первый проход - получаем размер выходного буфера, второй - шифруем текст status := BCryptEncrypt(hKey, @Password[0], Length(Password), nil, nil, 0, nil, 0, @EncryptedSize, BCRYPT_PAD_PKCS1); SetLength(EncryptedPassword,EncryptedSize); status := BCryptEncrypt(hKey, @Password[0], Length(Password), nil, nil, 0, @EncryptedPassword[0], Length(EncryptedPassword), @EncryptedSize, BCRYPT_PAD_PKCS1); //кодируем зашифрованное сообщение в Base64 Result := TNetEncoding.Base64.EncodeBytesToString(EncryptedPassword); //освобождаем память status := BCryptCloseAlgorithmProvider(hAlg,0); FreeLibrary(hLib); end;
end.

Вроде бы все успешно отрабатывает, но, когда делаю POST-запрос с зашифрованным паролем к серверу STEAM - получаю в ответ: {"success":false,"requires_twofactor":false, "message":"The account name or password that you have entered is incorrect.", "clear_password_field":true,"captcha_needed":false,"captcha_gid":-1} На вход функции подаются строки в виде
"publickey_mod":"c152954756c74aee68ca1e6ac77bc71af6a93660bd56f1517e8141436b8fda4e32cc123ced02c0421a6a8d505dd25d07c4df9a25cf682799ea87ceb0eeaef7c7e71a8a30ec6c60d4dcfa8006a193f0b99958655894147b13d4f15285f9d7dc75baaa61b1b12265a303324c6b5e648bb272d87e0003295ca124e6e7a8a5ec45b9d2f1399e3ffbd0d9aec012afe1fbe65bfc9bd4c2087e7b7a73d2f9286e311e77341113f4cbde9a2a94141252e395e36bc2bf135ef38be90458090d6cd2c419e293a5dcf93bff3df2ca641edfb38ff85f6c9f8864f2905015cf34bd35d74e324f4a6a156c2462cfdd1c1fafb15567047a59b188c9f2a4f78157f2ec120ce09b5d", "publickey_exp":"010001"
Буду очень признателен, если кто-нибудь укажет на ошибку или даст совет: как в Delphi можно зашифровать сообщение, имея экспоненту и модуль открытого ключа RSA.


Ответ

Проблема была в некорректной работе
//кодируем зашифрованное сообщение в Base64 Result := TNetEncoding.Base64.EncodeBytesToString(EncryptedPassword);
Эта функция не убирает переносы строки, так что придется получившийся результат обработать дополнительно:
//кодируем зашифрованное сообщение в Base64 Result := TNetEncoding.Base64.EncodeBytesToString(EncryptedPassword); //удалим переносы строки Result := StringReplace(Result, #13#10, '',[rfReplaceAll]);
Либо же можно использовать аналогичную функцию из пакета Indy, которая работает верно:
uses IdCoderMIME, idcoder, idglobal; ... function MyFunc(): string; var Temp: TIdBytes; begin ... Result := TIdEncoderMIME.EncodeBytes(Temp); end;

Рабочий код :
unit uRSA;
interface uses WinAPI.Windows, System.SysUtils, VCL.Dialogs, System.NetEncoding;
//БЛОБ открытого ключа RSA, описание структуры есть на MSDN type TPublicKeyBLOB = packed record Magic: ULONG; BitLength: ULONG; cbPublicExp: ULONG; cbModulus: ULONG; cbPrime1: ULONG; cbPrime2: ULONG; exponent: array[0..2] of byte; modulus: array[0..255] of byte; end; pPublicKeyBLOB = ^TPublicKeyBLOB;
//прототипы функций из библиотеки BCRYPT.DLL TBCryptOpenAlgorithmProvider = function (phAlgorithm: pHandle; pszAlgId: LPCWSTR; pszImplementation: LPCWSTR; dwFlags: DWORD): ULONG; stdcall; //-- TBCryptImportKeyPair = function (hAlgorithm: THandle; hImportKey: THandle; pszBlobType: LPCWSTR; phKey: pHandle; pbInput: pPublicKeyBLOB; cbInput: ULONG; dwFlags: ULONG): ULONG; stdcall; //-- TBCryptEncrypt = function (hKey: THandle; pbInput: PUCHAR; cbInput: ULONG; pPaddingInfo: POINTER; pbIV: PUCHAR; cbIV: ULONG; pbOutput: PUCHAR; cbOutput: ULONG; pcbResult: PULONG; dwFlags: ULONG): ULONG; stdcall; //-- TBCryptCloseAlgorithmProvider = function (hAlgorithm: THandle; dwFlags: ULONG): ULONG; stdcall;
//сама функция шифрования type TRSA = class public function Encrypt(DataStr: string; modulusStr: string; exponentStr: string): string; end;
const BCRYPT_RSAPUBLIC_MAGIC = $31415352; // RSA1 BCRYPT_PAD_PKCS1 = $00000002; BCRYPT_RSA_ALGORITHM = 'RSA'; BCRYPT_RSAPUBLIC_BLOB = 'RSAPUBLICBLOB';
implementation
function HexToByte(Str: string): Byte; begin result := Byte(StrToInt('$' + (Str))); end;
function TRsa.Encrypt(DataStr: string; modulusStr: string; exponentStr: string): string; var PublicKeyBLOB: TPublicKeyBlob; i: word; status: ULONG; hLib: THandle; hAlg: THandle; hKey: tHandle; Password: TBytes; EncryptedPassword: TBytes; EncryptedSize: ULONG; BCryptOpenAlgorithmProvider: TBCryptOpenAlgorithmProvider; BCryptImportKeyPair: TBCryptImportKeyPair; BCryptEncrypt: TBCryptEncrypt; BCryptCloseAlgorithmProvider: TBCryptCloseAlgorithmProvider; begin //преобразовываем входные данные в массив байтов; Password := TEncoding.ASCII.GetBytes(DataStr); hLib := LoadLibrary('BCRYPT.DLL'); if hLib < 32 then begin ShowMessage('Error while loading BCRYPT.DLL!'); exit; end; //загрузка функций из библиотеки //функция инициализации провайдера @BCryptOpenAlgorithmProvider := GetProcAddress(hLib, 'BCryptOpenAlgorithmProvider'); //функция импорта ключа @BCryptImportKeyPair := GetProcAddress(hLib, 'BCryptImportKeyPair'); //функция шифрования @BCryptEncrypt := GetProcAddress(hLib, 'BCryptEncrypt'); //функция освобождения провайдера @BCryptCloseAlgorithmProvider := GetProcAddress(hLib, 'BCryptCloseAlgorithmProvider'); //собираем ключ with PublicKeyBLOB do begin Magic := BCRYPT_RSAPUBLIC_MAGIC; // RSA1; BitLength := SizeOf(Modulus)*8;//размер модуля в битах cbPublicExp := SizeOf(Exponent);//размер экспоненты в байтах cbModulus := SizeOf(Modulus);//размер модуля в байтах //(необязательно) проверим, что в переданных параметрах - четное количество символов if (length(exponentstr) mod 2) <> 0 then exponentstr := '0' + exponentstr; if (length(modulusstr) mod 2) <> 0 then modulusstr := '0' + modulusstr; for i := Low(exponent) to High(exponent) do exponent[i] := HexToByte(copy(exponentstr,i*2+1,2)); for i := Low(modulus) to High(modulus) do modulus[i] := HexToByte(copy(modulusstr,i*2+1,2)); end; //инициализация провайдера status := BCryptOpenAlgorithmProvider(@halg,BCRYPT_RSA_ALGORITHM,nil,0); if status <> 0 then begin ShowMessage('BCryptOpenAlgorithmProvider error, status: ' + IntToStr(status) + ', ' + SysErrorMessage(GetLastError())); exit; end; //импорт ключа status := BCryptImportKeyPair(hAlg,0,BCRYPT_RSAPUBLIC_BLOB, @hKey, @PublicKeyBLOB, SizeOf(PublicKeyBLOB),0); if status <> 0 then begin ShowMessage('BCryptImportKeyPair error, status: ' + IntToStr(status) + ', ' + SysErrorMessage(GetLastError())); exit; end; //шифрование сообщения. Первый проход - получаем размер выходного буфера, второй - шифруем текст status := BCryptEncrypt(hKey, @Password[0], Length(Password), nil, nil, 0, nil, 0, @EncryptedSize, BCRYPT_PAD_PKCS1); if status <> 0 then begin ShowMessage('BCryptEncrypt error 1, status: ' + IntToStr(status) + ', ' + SysErrorMessage(GetLastError())); exit; end; SetLength(EncryptedPassword,EncryptedSize); status := BCryptEncrypt(hKey, @Password[0], Length(Password), nil, nil, 0, @EncryptedPassword[0], Length(EncryptedPassword), @EncryptedSize, BCRYPT_PAD_PKCS1); if status <> 0 then begin ShowMessage('BCryptEncrypt error 2, status: ' + IntToStr(status) + ', ' + SysErrorMessage(GetLastError())); exit; end; //освобождаем занятые ресурсы status := BCryptCloseAlgorithmProvider(hAlg,0); if status <> 0 then begin ShowMessage('BCryptCloseAlgorithmProvider error, status: ' + IntToStr(status) + SysErrorMessage(GetLastError())); exit; end; //кодируем зашифрованное сообщение в Base64 Result := TNetEncoding.Base64.EncodeBytesToString(EncryptedPassword); //удалим переносы строки Result := StringReplace(Result, #13#10, '',[rfReplaceAll]); //выгружаем библиотеку FreeLibrary(hLib); end;
end.
На вход функции подаются строки в виде:
"publickey_mod":"c152954756c74aee68ca1e6ac77bc71af6a93660bd56f1517e8141436b8fda4e32cc123ced02c0421a6a8d505dd25d07c4df9a25cf682799ea87ceb0eeaef7c7e71a8a30ec6c60d4dcfa8006a193f0b99958655894147b13d4f15285f9d7dc75baaa61b1b12265a303324c6b5e648bb272d87e0003295ca124e6e7a8a5ec45b9d2f1399e3ffbd0d9aec012afe1fbe65bfc9bd4c2087e7b7a73d2f9286e311e77341113f4cbde9a2a94141252e395e36bc2bf135ef38be90458090d6cd2c419e293a5dcf93bff3df2ca641edfb38ff85f6c9f8864f2905015cf34bd35d74e324f4a6a156c2462cfdd1c1fafb15567047a59b188c9f2a4f78157f2ec120ce09b5d", "publickey_exp":"010001"

суббота, 9 марта 2019 г.

Шифрование строки

Есть модуль, есть экспонента, есть строка, которую нужно зашифровать:
$modulus = 'CD0....C9246E1'; $exponent = '0...1'; $rsa = new Crypt_RSA(); $modulus = new Math_BigInteger(base64_decode($modulus), 256); $exponent = new Math_BigInteger(base64_decode($exponent), 256); $rsa->loadKey(array('n' => $modulus, 'e' => $exponent)); echo $rsa->encrypt('THISISMYSTR');
THISISMYST - строка, которую пытаюсь зашифровать. Но получаю какую-то гадость на выходе.


Ответ

Эта гадость на выходе результат работы функции и она в бинарном виде. Для перевода в читаемый вид можно использовать base64_encode();
Что касается того, что echo выводит разные строки, если не ошибаюсь, результат работы RSA всегда разный.
Для проверки выполните расшифровку через $rsa->decrypt(), если результат будет соответствовать тому, что вы зашифровали, то ваш алгоритм работает правильно.

пятница, 1 марта 2019 г.

Использование RSA для “Ментального покера”

В книге "Прикладная криптография" Шнайера, в разделе посвященном "Ментальному покеру" предлагается использовать для шифрования RSA с идентичными модулями. В этом случае процедура становится коммутативной, это в данном случае важно:
Т.е. для расшифровки карт последовательно зашифрованных двумя ключами, можно применять эти ключи в произвольном порядке.
А я вот что-то не могу сообразить - как у двух игроков могут быть ключи с идентичными модулями? Если модуль в RSA это произведение двух простых чисел - то существует единственный вариант его разложения на эти числа. И идентичными модули могут быть только если у обоих одинаковые пары ключей - а это лишает всю процедуру шифрования смысла.
Или тут имеется в виду что-то другое?


Ответ

И идентичными модули могут быть только если у обоих одинаковые пары ключей - а это лишает всю процедуру шифрования смысла.
Здесь вы неправы, для одного модуля существует очень много разных пар ключей. Обратите внимание на процедуру генерации ключей RSA: публичная экспонента e выбирается случайным образом (на практике всегда берут 65537). Мы можем выбрать любое e, и получим уникальную пару ключей.
В описанной в книге схеме не совсем тот RSA, который привычно видеть в других криптосхемах. Стороны генерируют разные ключи для одного модуля, и обе стороны знают его разложение на простые числа. Факторизация дает возможность вычислить приватный ключ с публичного ключа, но в приведенной схеме они не знают даже публичные ключи друг друга.
Только на шаге 7 они раскрывают свои ключи, что бы убедится в отсутствии мошенничества.

пятница, 16 ноября 2018 г.

Почему не работает git clone при подключении к репозиторию по putty?

Сервер с centos подключается к репозиторию bitbucket по ssh-rsa ключам. Если это делать непосредственно под root'ом на этой машине, то git clone проходит успешно. Если подключиться к машине по putty и попробовать склонировать репозиторий под рутом, появляется сообщение об отказе в правах. Почему так происходит? Как сгенерировать ключи, по которым можно будет работать с гитом под putty?
Permission denied (publickey). fatal: Could not read from remote repository.
Please make sure you have the correct access rights and the repository exists.


Ответ

ни в коем случае не надо «работать под root-ом». подключаетесь к машине вы, надеюсь, под именем «рядового» пользователя, вот от его имени и надо работать, получая root-овые привилегии лишь для выполнения административных задач. git clone и тому подобные команды оперируют приватным ключом (в вашем случае — из файла id_rsa), хранящимся в каталоге .ssh/ в домашнем каталоге пользователя, от имени которого выполняется команда. для пользователя root это обычно каталог /root/.ssh/. для «рядового» пользователя это обычно /home/пользователь/.ssh/ вам надо скопировать файл (в вашем случае /root/.ssh/id_rsa) в каталог «рядового» пользователя /home/пользователь/.ssh/. если такого каталога нет, создайте его (от имени пользователя). если каталог уже существует, эта команда не сделают ничего:
$ mkdir -p ~/.ssh
если такой каталог уже существовал и в нём уже были файлы id_rsa и id_rsa.pub, на всякий случай переименуйте их (вдруг они нужны для доступа куда-нибудь ещё):
$ mv ~/.ssh/id_rsa{,.backup}; mv ~/.ssh/id_rsa.pub{,.backup}
теперь копируем файлы и изменяем их владельца (операция осуществляется от имени root-а, ведь у «рядовых» пользователей нет доступа к его домашнему каталогу):
# cp /root/.ssh/id_rsa{,.pub} /home/пользователь/.ssh/ # chown -R пользователь /home/пользователь/.ssh/
дальше (уже от имени пользователя) сто́ит [пере]установить права на каталог и его содержимое:
$ chmod -R u+w,go= ~/.ssh если проделанные операции не помогли, и при выполнении git clone от имени пользователя (при подключении с помощью putty) возникает та же самая ошибка, в первую очередь проверьте значение переменной окружения HOME
$ echo $HOME
она должна содержать домашний каталог пользователя (обычно: /home/пользователь). именно на значение этой переменной и «опираются» программы (тот же git) при поиске файлов: если в этой переменной хранится что-то отличное от домашнего каталога, то, например, каталог .ssh (и файлы в нём) будут разыскиваться совсем не там, где следует.
дополнение по поводу использования нестандартного имени (или местоположения) файла с секретным ключом.
например, файл с секретным ключом называется ~/.ssh/id_rsa.vtoroj. тогда для использования именно этого ключа при подключении к серверу bitbucket.org можно добавить в конец файла ~/.ssh/config такие строки:
host bitbucket.org identityfile ~/.ssh/id_rsa.vtoroj