2016-04-13 7 views
3

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

public static string EncryptString(string StringToEncrypt) 
{ 
    RSACryptoServiceProvider provider = new RSACryptoServiceProvider(); 
    string xmlString = "<RSAKeyValue><Modulus>qqoWhMwGrrEBRr92VYud3j+iIEm7652Fs20HvNckH3tRDJIL465TLy7Cil8VYxJre69zwny1aUAPYItybg5pSbSORmP+hMp6Jhs+mg3qRPvHfNIl23zynb4kAi4Mx/yEkGwsa6L946lZKY8f9UjDkLJY7yXevMML1LT+h/a0a38=</Modulus><Exponent>AQAB</Exponent><P>20PwC7nSsfrfA9pzwSOnRYdbhOYivFSuERxvXHvNjCll5XdmFYYp1d2evXcXbyj3E1k8azce1avQ9njH85NMNQ==</P><Q>x0G0lWcQ13NDhEcWbA7R2W5LPUmRqcjQXo8qFIaHk7LZ7ps9fAk/kOxaCR6hvfczgut1xSpXv6rnQ5IGvxaHYw==</Q><DP>lyybF2qSEvYVxvFZt8MeM/jkJ5gIQPLdZJzHRutwx39PastMjfCHbZW0OYsflBuZZjSzTHSfhNBGbXjO22gmNQ==</DP><DQ>NJVLYa4MTL83Tx4vdZ7HlFi99FOI5ESBcKLZWQdTmg+14XkIVcZfBxDIheWWi3pEFsWqk7ij5Ynlc/iCXUVFvw==</DQ><InverseQ>X5Aw9YSQLSfTSXEykTt7QZe6SUA0QwGph3mUae6A2SaSTmIZTcmSUsJwhL7PLNZKbMKSWXfWoemj0EVUpZbZ3Q==</InverseQ><D>jQL4lEUYCGNMUK6GEezIRgiB5vfFg8ql3DjsOcXxnOmBcEeD913kcYnLSBWEUFW55Xp0xW/RXOOHURgnNnRF3Ty5UR73jPN3/8QgMSxV8OXFo3+QvX+KHNHzf2cjKQDVObJTKxHsHKy+L2qjfULA4e+1cSDNn5zIln2ov51Ou3E=</D></RSAKeyValue>"; 
    provider.FromXmlString(xmlString); 
    return Convert.ToBase64String(provider.Encrypt(Encoding.ASCII.GetBytes(StringToEncrypt), false)); 
} 

Однако мне нужно изменить или перевести его на JAVA. Я написал метод ниже для этой же цели.

public static String EncryptString(String strToBeEncrypted) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, UnsupportedEncodingException, IllegalBlockSizeException, BadPaddingException 
{ 
    String modulusString = "qqoWhMwGrrEBRr92VYud3j+iIEm7652Fs20HvNckH3tRDJIL465TLy7Cil8VYxJre69zwny1aUAPYItybg5pSbSORmP+hMp6Jhs+mg3qRPvHfNIl23zynb4kAi4Mx/yEkGwsa6L946lZKY8f9UjDkLJY7yXevMML1LT+h/a0a38="; 
    String publicExponentString = "AQAB"; 
    byte[] modulusBytes = Base64.decodeBase64(modulusString); 
    byte[] exponentBytes = Base64.decodeBase64(publicExponentString); 
    BigInteger modulus = new BigInteger(1, modulusBytes); 
    BigInteger publicExponent = new BigInteger(1, exponentBytes); 
    RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, publicExponent); 
    KeyFactory fact = KeyFactory.getInstance("RSA"); 
    PublicKey pubKey = fact.generatePublic(rsaPubKey); 
    Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING"); 
    cipher.init(Cipher.ENCRYPT_MODE, pubKey); 
    byte[] plainBytes = strToBeEncrypted.getBytes("US-ASCII"); 
    byte[] cipherData = cipher.doFinal(plainBytes); 
    String encryptedStringBase64 = Base64.encodeBase64String(cipherData); 

    return encryptedStringBase64; 
} 

Но результаты выборки не совпадают.

Строка "4111111111111111" и зашифрованы результат должен быть:

PfU31ai9dSwWX4Im19TlikfO9JetkJbUE + btuvpBuNHTnnfrt4XdM4PmGA19z8rF + lPUC/kcOEXciUSxFrAPyuRJHifIDqWFbbJvPhatbf269BXUiAW31UBX3X5bBOqNWjh4LDitYY0BtarlTU4xzOFyb7vLpLJe9aHGWhzs6q0 =

Но результат от Java кода

Cxp5AIzTHEkrU6YWwYo5yYvpED2qg9IC/0ct + tRgDZi9fJb8LAk + E1l9ljEt7MFQ2KB/экзо 4NYwijnBKYPeLStXyfVO1Bj6S76zMeKygAlCtDukq1UhJaJKaCXY94wi9Kel09VTmj + VByIYvAGUFqZGaK1CyLnd8QXMcdcWi3sA =

алгоритм
+2

Что произойдет, если вы снова запустите свой код C# и Java? Изменены ли зашифрованные тексты? Если это так, то рандомизированное заполнение используется (важно), и вам нужно зашифровать в одном и дешифровать в другом, чтобы проверить совместимость. –

+0

Спасибо @ArtjomB. Я просто проверил совместимость с кодом дешифрования вендора, и он отлично работает. – RahulMuk07

+0

@ArtjomB. Для шифрования используется рандомизированное заполнение * must *. Шифрование должно быть недетерминированным, иначе вы получите один и тот же шифртекст для одного и того же открытого текста (как и в симметричном режиме шифрования в режиме ECB). Только учебник RSA является детерминированным и очень неуверенным по всем видам или причинам.Однако генерация подписи может быть детерминированной. Не могли бы вы отправить ответ? –

ответ

1

Каждое шифрование должно быть рандомизированы для того, чтобы обеспечить семантическую безопасность. В противном случае злоумышленник может заметить, что вы отправили одно и то же сообщение, просто наблюдая за зашифрованными текстами. В симметричных шифрах это свойство достигается случайным IV. В RSA это достигается путем рандомизированного заполнения (PKCS # 1 v1.5 type 2 и PKCS # 1 v2.x OAEP рандомизированы).

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

Правильный способ проверить это, было бы зашифровать что-то на одном языке, а затем расшифровать в другом. Для полной совместимости вы также должны попробовать это по-другому.

Глядя на ваш код, как кажется, эквивалентны, так как false передается в качестве второго параметра в RSACryptoServiceProvider#Encrypt использовать PKCS # 1 v1.5 отступы и Cipher.getInstance("RSA/ECB/PKCS1PADDING") запросы того же отступы. Кодировки ввода/вывода также кажутся эквивалентными. Итак, да, этот код будет эквивалентен.


PKCS # 1 v1.5 обивка не должна использоваться в настоящее время, потому что она уязвима против Bleichenbacher атаки (reference). Вы должны использовать OAEP для шифрования и PSS для подписи, которые считаются безопасными. C# и Java поддерживают OAEP, но могут быть различия в хэш-функциях по умолчанию, которые используются (хэш и MGF1).

+0

Привет, Я столкнулся с тем же сценарием в quesiton. Если используется рандомизированное заполнение, как проверить, является ли пароль enterd пользователем таким же, как пароль в базе данных, без дешифрования пароля из базы данных? Поскольку я слышал, что дешифрование пароля не является хорошей практикой. Мы проверяем только то, является ли зашифрованное значение одинаковым. Однако здесь я не вижу, как я могу это сделать. Единственным способом, по-видимому, является дешифрование пароля с db. – nanospeck

+0

@nanospeck Вы никогда не должны шифровать пароли своего пользователя. Вместо этого вам нужно использовать хеширование, а некоторые сильные - PBKDF2, bcrypt, scrypt и Argon2. Поскольку хеш-функции являются однонаправленной, вы не сможете «расшифровать» хеши. Чтобы аутентифицировать пользователя, вы можете снова запустить пароль через хеш-функцию, чтобы сравнить с хешем, который хранится в базе данных. Подробнее: [Как безопасно использовать хэш-пароли?] (Http://security.stackexchange.com/q/211/45523) RSA определенно является неправильным инструментом для работы. –

+0

Ваши слова действительно помогли мне по этой теме. К сожалению, я переношу проект, уже реализованный в .NET, используя RSACryptoServiceProvider для Java, поэтому я не могу переопределить шифрование паролей. – nanospeck