2015-08-13 5 views
3

Как говорится в названиях, я хотел бы знать, как наилучшим образом использовать экземпляр Cipher в многопоточной среде с учетом алгоритма RSA.Безопасность потоков с RSA Cipher

Я прочитал несколько вопросов по данной теме, а также от того, что я собрал:

  • Cipher не поточно, поскольку она поддерживает внутреннее состояние во время шифрования/дешифрования

  • , если AES является используется, то doFinal() будут сброшены вектор инициализации, чтобы последний известное значение, и поэтому новый экземпляр Cipher должен быть сформирован каждый раз, когда

Мои вопросы

  • Это хорошо, чтобы вызвать cipher.init() только один раз, если выбран алгоритм RSA? Это противоречит второму пулю, как показано в нижеследующем коде. Я считаю, что нет никакого вектора инициализации. Кроме того, шифр будет использоваться только для дешифрования данных.

  • Должен ли я синхронизироваться только на вызове cipher.doFinal()?

  • Каков общий способ обработки нескольких потоков, запрашивающих службы криптографии, должен ли я иметь пул шифров в качестве блокирующей очереди за некоторым прокси-сервером?

Пример кода:

public class RsaPrototype { 

private static PrivateKey privKey; 
private static Cipher cipher; 
private static final String PRIVATE_KEY_PATH ="./privK.pem"; 

/* 
* ALGORITHM/BLOCKING_MODE/PADDING_SCHEMA 
*/ 
private static final String CIPHER_SPECIFICATION = "RSA/None/NoPadding"; 
private static final String RSA_PROVIDER ="BC"; 

static { 

    Security.addProvider(new BouncyCastleProvider()); 
    importPrivateKey(); 
    cipher = getCipher(); 

} 

/** 
* Initializes cipher with RSA algorithm, without blocking mode and padding. 
* Implementation provider is bouncy castle. 
* 
* @return cipher instance. 
*/ 
private static Cipher getCipher() { 

    try 
    { 

      Cipher cipher = Cipher.getInstance(CIPHER_SPECIFICATION, RSA_PROVIDER); 
      cipher.init(Cipher.DECRYPT_MODE, privKey); 
      return cipher; 

    } catch (NoSuchAlgorithmException | NoSuchPaddingException | NoSuchProviderException e) { 

     throw new RuntimeException(e.getMessage()); 
    } 
} 

/** 
* Imports public key from the given .PEM file into application cache. 
*/ 
private static void importPrivateKey() { 

    try (BufferedReader reader = 
      new BufferedReader(new FileReader(PRIVATE_KEY_PATH)); 

     PEMParser pemParser = 
      new PEMParser(reader);) { 


     privKey = new JcaPEMKeyConverter().getPrivateKey((PrivateKeyInfo) pemParser.readObject()); 
    } 

    catch (IOException ignorable) { 
     // not handled 
     } 
    } 

public static String decrypt(byte[] encryptedText) { 

    byte[] plainText; 

    synchronized (cipher) { 

     plainText = cipher.doFinal(encryptedText); 
    } 

    return new String(plainText, StandardCharsets.UTF_8); 
    } 
} 
+0

Как получить метод, который «делает материал» с 'Cipher' вместо этого (например, метод' encrypt() 'для шифрования чего-то)? –

+0

Я забыл вставить его O_O – John

+0

Сколько будет конкуренции? Первое, что я хотел бы сделать, - это сериализовать доступ, сделав его «синхронизированным» и протестировать, если это будет работать достаточно хорошо. –

ответ

2

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

Я написал тест быстрой загрузки, чтобы проверить это.

Кажется, что достаточно синхронизировать по cipher.doInit() и использовать один экземпляр Cipher для дешифрования.

private static Queue<String> results = new ConcurrentLinkedQueue<String>(); 

@Test 
public void test() throws InterruptedException { 

    String plainText = "some text to verify data integrity"; 

    String encryptedText = Encrypt.encrypt(plainText); 


    for (int i = 0; i < 5000; i++) { 

     new Thread(() -> { results.add(Decrypt.decrypt(encryptedText)); }) 
     .start();;   
    } 

    Thread.sleep(5000); 

    assertTrue(results.size() == 5000); 

    while(!results.isEmpty()) { 

     assertTrue(results.poll().equals(plainText)); 
    } 
} 
1

Шифрование (и написание сообщений) является по своей сути синхронными. Использование нескольких потоков не было бы моим подходом. Рассмотрим сообщение aabb. С несколькими потоками, которые могут стать abba или baba или abab или bbaa. Обратите внимание, что внутреннее состояние шифра также синхронно ... Чтобы получить aabb, вы должны отправить aabb.

+0

У меня есть параллельные HTTP-запросы с зашифрованными данными. Поскольку реализация является стандартной блокировкой IO, для каждого запроса есть поток, и мне нужно будет расшифровывать данные для каждого такого запроса/потока. Я смотрю на правильный дизайн/синхронизацию, учитывая такую ​​среду. – John

+4

Каждый поток должен использовать экземпляры локального шифрования потока. –

+0

@ Ellliott Frisch вы бы предложили это на Tomcat? Я помню, как читал статью о локальном потоке и утечке памяти.Также это: http://stackoverflow.com/questions/13852632/is-it-really-my-job-to-clean-up-threadlocal-resources-when-classes-have-been-exp – John

Смежные вопросы