Android: расшифровать текст RSA с помощью открытого ключа, хранящегося в файле
Я несколько дней пытался сделать это без успеха.
В StackOverflow есть много подобных вопросов, и даже два из них точно такие же, как мои, но не ответили и не были решены:
1) Преобразование PHP RSA PublicKey в Android PublicKey
2) Android: как расшифровать зашифрованный файл openssl с ключом RSA?
Мой сценарий:
У меня есть текст, зашифрованный с помощью RSA (не зашифрованный мной). У меня есть файл public.key в моей папке res/raw с открытым ключом, необходимым для его расшифровки (открытый ключ, связанный с закрытым ключом, используемым для шифрования сообщения), с таким форматом, как в следующем примере:
![enter image description here]()
Я вижу много примеров того, как расшифровать текст RSA, например следующий:
public static byte[] decryptRSA( PublicKey key, byte[] text) throws Exception
{
byte[] dectyptedText = null;
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
dectyptedText = cipher.doFinal(text);
return dectyptedText;
}
Но мой вопрос: как получить правильный экземпляр PublicKey из файла? Нет примеров этого.
Если я просто попробую:
InputStream is = getResources().openRawResource(R.raw.public);
DataInputStream dis = new DataInputStream(is);
byte [] keyBytes = new byte [(int) is.available()];
dis.readFully(keyBytes);
dis.close();
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePublic(spec);
Я получаю InvalidKeyException в возвращаемом предложении.
Должен ли я декодировать Hex или Base64? Не проблема в первой и последней строках файла открытого ключа (те, у кого есть "---- BEGIN PUBLIC KEY ----" и т.д.)?
Возможно, мы можем получить ответ об этом в первый раз в StackOverflow: -)
Ответы
Ответ 1
Наконец-то решил!!! Барабаны, трубы и симфония феерических звуков!!!
public static byte[] decryptRSA(Context mContext, byte[] message) throws Exception {
// reads the public key stored in a file
InputStream is = mContext.getResources().openRawResource(R.raw.sm_public);
BufferedReader br = new BufferedReader(new InputStreamReader(is));
List<String> lines = new ArrayList<String>();
String line = null;
while ((line = br.readLine()) != null)
lines.add(line);
// removes the first and last lines of the file (comments)
if (lines.size() > 1 && lines.get(0).startsWith("-----") && lines.get(lines.size()-1).startsWith("-----")) {
lines.remove(0);
lines.remove(lines.size()-1);
}
// concats the remaining lines to a single String
StringBuilder sb = new StringBuilder();
for (String aLine: lines)
sb.append(aLine);
String keyString = sb.toString();
Log.d("log", "keyString:"+keyString);
// converts the String to a PublicKey instance
byte[] keyBytes = Base64.decodeBase64(keyString.getBytes("utf-8"));
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey key = keyFactory.generatePublic(spec);
// decrypts the message
byte[] dectyptedText = null;
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, key);
dectyptedText = cipher.doFinal(Base64.decodeBase64(message));
return dectyptedText;
}
Решение состояло в том, чтобы Base64 декодировал не только открытый ключ, прочитанный из файла, но и само зашифрованное сообщение!
Кстати, я прочитал открытый ключ из файла так, как предложил @Nikolay (tnx again man).
Спасибо вам большое за вашу помощь. Скалы StackOverflow!
Ответ 2
Вам не хватает ключевого слова - общедоступные и закрытые ключи являются отдельными, и вы не можете рассчитать их на основе другого. Это своего рода точка шифрования с открытым ключом. Проблемы с использованием необработанного RSA в стороне, если у вас что-то зашифровано открытым ключом, для его расшифровки необходимо иметь соответствующий закрытый ключ. И наоборот. Поэтому, если у вас есть файл открытого ключа, вы можете получить только открытый ключ. Это было бы полезно, только если ваши данные были зашифрованы с помощью соответствующего закрытого ключа.
Что касается фактического исключения: удалите строки "---" в начале и конце, используйте Base64.decode(), чтобы получить массив байтов, и используйте это для создания X509EncodedKeySpec
. Один из способов сделать это - используйте что-то вроде BufferedReader
для чтения по строкам, игнорируйте строки "---" и разделите остальные на один большой String
.
Ответ 3
Открытые ключи могут только шифровать данные. Открытые ключи не могут расшифровывать данные. Вы можете расшифровывать данные только с помощью закрытого ключа. Все дело в том, что вы можете раздавать открытый ключ всем и каждому, и они могут отправлять вам зашифрованные сообщения, которые могут видеть только владелец частного ключа.
Вам действительно нужно быть очень осторожным с использованием технологии шифрования. Я боюсь, вы просто собираетесь распространять секретный ключ на все ваши устройства, что ослабит вашу безопасность, поскольку каждый будет иметь тот же секретный ключ. Поэтому, если я хочу взломать вашу безопасность, я просто перехожу к Google Play и загружаю приложение и вытаскиваю секретный ключ из вашего приложения. Виола Я вижу все.
Итак, у вас есть ответ, почему это не сработает, но вам теперь нужно дать совет о дизайне, который я не могу дать вам, зная, почему вы используете шифрование. Что ты скрываешь?
Update:
Похоже, вы пытаетесь выполнить проверку шифрования и подписи, например, как работает RSA, но вы смущены тем, как это работает. Для этого вам нужны два набора частных/открытых ключей. Один набор ключей для клиента и один набор ключей для сервера.
Веб-сервер отправит свой открытый ключ клиенту. Клиент мог отправить аутентифицированное и зашифрованное сообщение на сервер, используя открытый ключ сервера, а затем подписав это сообщение с использованием закрытого ключа клиента. И наоборот для сервера. Сервер будет использовать открытый ключ клиента для шифрования сообщения и подписывать его своим личным ключом для отправки сообщения клиенту. Затем клиент может расшифровать сообщение с помощью закрытого ключа клиента и проверить подпись с использованием открытого ключа сервера.
Теперь вы повторно используете SSL? Прекрати это. Использовать SSL.
Вот как SSL достигает безопасного канала. Клиент получает ключ PUBLIC с веб-сервера и 1 или более имен для симметричных алгоритмов шифрования. Он выбирает общий алгоритм, а затем генерирует секретный ключ для использования для всех сообщений в будущем. Он ОБЕСПЕЧИВАЕТ этот секретный ключ с открытым ключом веб-сервера и отправляет его вместе с выбранным алгоритмом. Веб-сервер DECRYPTS использует ключ PRIVATE для получения общего секретного ключа. После этого все шифрование представляет собой симметричное шифрование с использованием общего секрета, который намного быстрее, чем асимметричное шифрование.
Ответ 4
Чтобы создать открытый ключ RSA из формата PEM, как вы указали (ключ openssl gen. rsa)
-----BEGIN PUBLIC KEY-----
SOMEDES3UNREADABLETEXT+PADDING==
-----END PUBLIC KEY
и использовать его для чтения содержимого, подписанного с ним?
-посмотрите мой ответ в подобном вопросе здесь:
fooobar.com/info/325678/...