2016-05-03 11 views
5

Jak wiadomo, gdy chcemy wykonywać operacje kryptograficzne za pomocą kart Java, musimy użyć obiektów Cipher. Pytanie, które mam, jest w rzeczywistości związane z wydajnością. Załóżmy, że chcę wykonać operacje odszyfrowujące i odszyfrowywania przy użyciu klucza AES.Używanie pojedynczego obiektu Cipher lub dwóch różnych obiektów do deszyfrowania i szyfrowania operacji?

Która z poniższych strategii jest lepsza?

  1. Definiowanie dwóch różnych Cipher obiektów i wstępne je za pomocą jednego przycisku, ale różne tryby (MODE_ENCRYPT i MODE_DECRYPT). Następnie dla każdej operacji wystarczy wywołać metodę doFinal() na odpowiednim obiekcie.
  2. Definiowanie pojedynczego obiektu i każdorazowo przed wywołaniem metody doFinal() wywołanie metody należy wykonać na obiekcie z odpowiednim trybem.

Odpowiedz

4

po pierwsze, zgodnie z dokumentacją Cipher.doFinal(...):

AES DES potrójny DES i koreańskie algorytmy nasion w tryb CBC przywrócić początkowy wektor (IV) 0. początkowy wektor (IV) może być ponownie zainicjowany przy użyciu metody init(Key, byte, byte[], short, short).

Oznacza to, że jeśli używasz AES-CBC z niezerową IV, trzeba zadzwonić init po każdym doFinal, więc nie ma wyboru, naprawdę.


Zobaczmy teraz niektóre pomiary w świecie rzeczywistym, które zrobiłem na moich kartach J2E145 przez NXP.

Zarówno ALG_AES_BLOCK_128_CBC_NOPAD i ALG_AES_BLOCK_128_ECB_NOPAD wymagają 34 bajtów pamięci RAM i 32 bajtów pamięci trwałej na przykład obiektu.

Jeżeli chodzi o zużycie czasu, są 4 możliwe sytuacje:

Sytuacja 1: ten sam klucz przejściowy:

key1 = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT, 
KeyBuilder.LENGTH_AES_128, false); 
... 
cipher.init(key1, Cipher.MODE_DECRYPT); 
cipher.init(key1, Cipher.MODE_ENCRYPT); 

Wynik: 11 ms za każdym init(...)

sytuacji 2: różne klucze przejściowe:

key1 = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT, 
    KeyBuilder.LENGTH_AES_128, false); 
key2 = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT, 
    KeyBuilder.LENGTH_AES_128, false); 
... 
cipher.init(key1, Cipher.MODE_DECRYPT); 
cipher.init(key2, Cipher.MODE_ENCRYPT); 

Wynik: 18 ms za każdym init(...)

Sytuacja 3: ten sam klucz trwałe:

key1 = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, 
KeyBuilder.LENGTH_AES_128, false); 
... 
cipher.init(key1, Cipher.MODE_DECRYPT); 
cipher.init(key1, Cipher.MODE_ENCRYPT); 

wynikowe: 12 ms za każdy init(...)

Sytuacja 4: różne klawisze trwałe:

key1 = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, 
    KeyBuilder.LENGTH_AES_128, false); 
key2 = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, 
    KeyBuilder.LENGTH_AES_128, false); 
... 
cipher.init(key1, Cipher.MODE_DECRYPT); 
cipher.init(key2, Cipher.MODE_ENCRYPT); 

wynikowe: 19 ms za każdym init(...)

Wniosek:init jest bardzo szybki, niezależnie od typu pamięci, ponieważ pamięć EEPROM jest tylko do odczytu i kopiowane do wewnętrznego (przejściowa) pamięć instancji Cipher. Chociaż mogę sobie wyobrazić niektóre przypadki wymagające dużych nakładów czasu, 34 bajty RAM wydają się być zbyt duże, by zapłacić za 20 ms. Dokładne wyniki mogą oczywiście różnić się na twojej platformie, ale efektywność kompromisu pozostanie mniej więcej taka sama.

+0

Dobre erfforts w dokładnym czasie vojta! Mimo to, jeśli korzystasz z IV = 0, możesz korzystać z trwałych danych kluczowych. Myślę, że to ważna sprawa ... –

+0

Zastanawiam się, czy to tylko literówka w twoich liniach kodu, że zawsze jest tylko jeden "szyfr", a nie "szyfr1"; 'cipher2'? –

+0

@PaulBastian Tak, ale możesz zyskać tylko 20 ms ... Czy to wystarcza na 34 bajty pamięci RAM? Nie sądzę ... – vojta

3

Zależy od tego, czy użytkownik posługuje się trwałym lub przejściowym materiałem kluczowym.
Jeśli masz trwały materiał klucz:

  • Wariant 1 potrzebuje więcej EEPROM ale trzeba mieć znaczący impuls czasowy bo nazywasz init() tylko raz, gdy materiał jest generowany klucz lub importowane.
  • dlatego Wariant 2 nie jest pożądane

Jeśli masz przemijające materiał klucz:

  • Wariant 1 potrzebuje więcej EEPROM i zwiększyć czas jest prawie nie istnieje, ponieważ trzeba zadzwonić init() tak. Zrobiłem kilka głównych 2 lata testowania temu i jeśli dobrze pamiętam tam jest albo żadna albo bardzo mały trójkąt wydajności pomiędzy tymi dwoma opcjami
  • Opcja 2 potrzebuje mniej pamięci EEPROM i zmniejsza złożoność kodu, zatem jego pożądane
Powiązane problemy