To, czego potrzebuję, to zaszyfrować ciąg, który pojawi się w kodzie kreskowym 2D (PDF-417), więc gdy ktoś wpadnie na pomysł, aby go zeskanować, nic nie da się odczytać.
Inne wymagania:
- nie powinno być skomplikowane
- nie powinien składać się z RSA, infrastruktury PKI, par kluczy itp.
Musi być na tyle proste, aby pozbyć się ludzi węszących wokół i łatwe do odszyfrowania dla innych firm zainteresowanych uzyskaniem tych danych. Dzwonią do nas, podajemy im standard lub podajemy prosty klucz, którego można następnie użyć do odszyfrowania.
Prawdopodobnie firmy te mogłyby korzystać z różnych technologii, więc dobrze byłoby trzymać się jakiegoś standardu, który nie jest powiązany z żadną specjalną platformą czy technologią.
Co sugerujesz? Czy jakaś klasa Java osiąga wysokie standardy bezpieczeństwa encrypt()
i decrypt()
bez większych komplikacji?
java
encryption
ante.sabo
źródło
źródło
Odpowiedzi:
Przedmowa
Poniżej opiszę podstawy bezpiecznej kryptografii symetrycznej i wskażę typowe błędy, które widzę w Internecie, gdy ludzie samodzielnie wdrażają kryptografię w standardowej bibliotece Java. Jeśli chcesz po prostu pominąć wszystkie szczegóły, przejdź do nowej biblioteki Google Tink, zaimportuj ją do swojego projektu i użyj trybu AES-GCM do wszystkich swoich szyfrowań, a będziesz bezpieczny.
Teraz, jeśli chcesz poznać podstawowe szczegóły dotyczące szyfrowania w Javie, czytaj dalej :)
Szyfry blokowe
Najpierw musisz wybrać symetryczny klucz szyfrujący blokowy. Szyfr blokowy to funkcja / program komputerowy używany do tworzenia pseudolosowości. Pseudolosowość to fałszywa losowość, której żaden komputer inny niż komputer kwantowy nie byłby w stanie odróżnić go od prawdziwej losowości. Szyfr blokowy jest jak element konstrukcyjny kryptografii, a gdy jest używany z różnymi trybami lub schematami, możemy tworzyć szyfrowanie.
Jeśli chodzi o dostępne dzisiaj algorytmy szyfrowania blokowego, upewnij się, że NIGDY , powtarzam NIGDY nie używam DES , powiedziałbym nawet, że NIGDY nie używaj 3DES . Jedynym szyfrem blokowym, który nawet wydanie Snowdena z NSA było w stanie zweryfikować, że jest naprawdę tak blisko Pseudo-Random, jak to tylko możliwe, to AES 256 . Istnieje również AES 128; różnica polega na tym, że AES 256 działa w 256-bitowych blokach, podczas gdy AES 128 działa w 128 blokach. Podsumowując, AES 128 jest uważany za bezpieczny, chociaż odkryto pewne słabości, ale 256 jest tak solidny, jak to tylko możliwe.
Zabawny fakt DES został złamany przez NSA, kiedy został założony i przez kilka lat trzymany w tajemnicy. Chociaż niektórzy ludzie nadal twierdzą, że 3DES jest bezpieczny, istnieje sporo artykułów naukowych, które odkryły i przeanalizowały słabości 3DES .
Tryby szyfrowania
Szyfrowanie jest tworzone, gdy bierzesz szyfr blokowy i używasz określonego schematu, tak że losowość jest połączona z kluczem do stworzenia czegoś, co jest odwracalne, o ile znasz klucz. Nazywa się to trybem szyfrowania.
Oto przykład trybu szyfrowania i najprostszego trybu znanego jako EBC, abyś mógł wizualnie zrozumieć, co się dzieje:
Tryby szyfrowania, które najczęściej zobaczysz w Internecie, to:
CTR EBC, CBC, GCM
Istnieją inne tryby poza wymienionymi, a naukowcy zawsze pracują nad nowymi, aby poprawić istniejące problemy.
Przejdźmy teraz do implementacji i tego, co jest bezpieczne. NIGDY nie używaj EBC, jest to złe w ukrywaniu powtarzających się danych, jak pokazał słynny pingwin linuksowy .
Podczas implementacji w Javie należy pamiętać, że jeśli używasz następującego kodu, tryb EBC jest ustawiony domyślnie:
... NIEBEZPIECZEŃSTWO TO JEST WRAŻLIWOŚĆ! i niestety jest to widoczne w całym StackOverflow oraz online w samouczkach i przykładach.
Nonces i IV
W odpowiedzi na problem znaleziony w trybie EBC stworzono rzeczowniki znane również jako IV. Chodzi o to, że generujemy nową zmienną losową i dołączamy ją do każdego szyfrowania, aby po zaszyfrowaniu dwóch takich samych wiadomości wychodziły one różne. Piękno za tym kryje się w tym, że kroplówka lub nonce jest powszechnie znana. Oznacza to, że osoba atakująca może mieć do tego dostęp, ale dopóki nie ma Twojego klucza, nie może nic zrobić z tą wiedzą.
Typowe problemy, które zobaczę, to to, że ludzie ustawią IV jako wartość statyczną, jak w tej samej stałej wartości w swoim kodzie. i tutaj jest pułapka dla IV, gdy powtórzysz jeden, faktycznie naruszysz całe bezpieczeństwo swojego szyfrowania.
Generowanie losu IV
Uwaga: SHA1 jest zepsuty, ale nie mogłem znaleźć sposobu prawidłowego zaimplementowania SHA256 w tym przypadku użycia, więc jeśli ktoś chciałby się tym zająć i zaktualizować, byłoby wspaniale! Również ataki SHA1 są nadal niekonwencjonalne, ponieważ złamanie ogromnego klastra może zająć kilka lat. Sprawdź szczegóły tutaj.
Implementacja CTR
W trybie CTR nie jest wymagane dopełnienie.
Wdrożenie CBC
Jeśli zdecydujesz się zaimplementować tryb CBC, zrób to z PKCS7Padding w następujący sposób:
Luka w zabezpieczeniach CBC i CTR oraz dlaczego warto używać GCM
Chociaż niektóre inne tryby, takie jak CBC i CTR, są bezpieczne, napotykają na problem polegający na tym, że atakujący może odwrócić zaszyfrowane dane, zmieniając ich wartość po odszyfrowaniu. Powiedzmy, że szyfrujesz wyimaginowaną wiadomość bankową „Sprzedaj 100”, zaszyfrowana wiadomość wygląda tak, jakby to „eu23ng” atakujący zmienił się o jeden bit na „eu53ng”, a po odszyfrowaniu wiadomości nagle brzmiała „Sprzedaj 900”.
Aby tego uniknąć, większość internetu korzysta z GCM i za każdym razem, gdy widzisz HTTPS, prawdopodobnie używa GCM. GCM podpisuje zaszyfrowaną wiadomość hashem i sprawdza, czy wiadomość nie została zmieniona przy użyciu tego podpisu.
Unikałbym wdrażania GCM ze względu na jego złożoność. Lepiej jest korzystać z nowej biblioteki Google Tink, ponieważ tutaj ponownie, jeśli przypadkowo powtórzysz IV, narażasz klucz w przypadku GCM, co jest ostateczną luką w zabezpieczeniach. Nowi badacze pracują nad trybami szyfrowania IV odpornymi na powtórzenia, w których nawet jeśli powtórzysz IV, klucz nie jest zagrożony, ale to jeszcze nie weszło do głównego nurtu.
Jeśli chcesz zaimplementować GCM, oto link do ładnej implementacji GCM . Nie mogę jednak zapewnić bezpieczeństwa lub czy jest on prawidłowo zaimplementowany, ale powoduje to uszkodzenie podstaw. Zwróć też uwagę, że w przypadku GCM nie ma dopełnienia.
Klucze a hasła
Kolejną bardzo ważną uwagą jest to, że w przypadku kryptografii klucz i hasło to nie to samo. Klucz w kryptografii musi mieć pewną entropię i losowość, aby można go było uznać za bezpieczny. Dlatego musisz upewnić się, że używasz odpowiednich bibliotek kryptograficznych do wygenerowania klucza.
Więc naprawdę masz dwie implementacje, które możesz tutaj zrobić, pierwszą jest użycie kodu znalezionego w tym wątku StackOverflow do generowania losowego klucza . To rozwiązanie wykorzystuje bezpieczny generator liczb losowych do tworzenia od podstaw klucza, którego możesz użyć.
Inną mniej bezpieczną opcją jest użycie danych wejściowych użytkownika, takich jak hasło. Problem, o którym mówiliśmy, polega na tym, że hasło nie ma wystarczającej entropii, więc musielibyśmy użyć PBKDF2 , algorytmu, który pobiera hasło i je wzmacnia. Oto implementacja StackOverflow, która mi się podobała . Jednak biblioteka Google Tink ma to wszystko wbudowane i powinieneś z tego skorzystać.
Programiści Androida
Jedną z ważnych kwestii, na które należy zwrócić uwagę, jest wiedza, że kod Androida można poddać inżynierii wstecznej, aw większości przypadków jest to również kod Java. Oznacza to, że jeśli przechowujesz hasło w postaci zwykłego tekstu w swoim kodzie. Haker może go łatwo odzyskać. Zwykle w przypadku tego typu szyfrowania chcesz użyć kryptografii asymetrycznej i tak dalej. To jest poza zakresem tego postu, więc nie będę się w to zagłębiał.
Ciekawa lektura z 2013 roku : wskazuje, że 88% implementacji Crypto w systemie Android zostało wykonanych nieprawidłowo.
Końcowe przemyślenia
Po raz kolejny sugerowałbym unikanie bezpośredniego wdrażania biblioteki java dla kryptowalut i używanie Google Tink , zaoszczędzi ci to bólu głowy, ponieważ naprawdę wykonali dobrą robotę, poprawnie implementując wszystkie algorytmy. A nawet wtedy upewnij się, że sprawdziłeś problemy poruszane na githubie Tink, tu i tam pojawiają się luki w zabezpieczeniach.
Jeśli masz jakieś pytania lub uwagi, możesz je skomentować! Bezpieczeństwo zawsze się zmienia i musisz zrobić wszystko, aby za nim nadążyć :)
źródło
getInstanceStrong()
metoda ofCipher
jest lepsza niż SHA1PRNGZalecałbym użycie standardowego szyfru symetrycznego, który jest szeroko dostępny, jak DES , 3DES lub AES . Chociaż nie jest to najbezpieczniejszy algorytm, istnieje mnóstwo implementacji i wystarczy podać klucz każdemu, kto ma odszyfrować informacje w kodzie kreskowym. javax.crypto.Cipher jest tym, z czym chcesz tutaj pracować.
Załóżmy, że znajdują się bajty do zaszyfrowania
Następnie będziesz potrzebować klucza i bajtów wektora inicjalizacji
Teraz możesz zainicjować szyfr dla wybranego algorytmu:
Szyfrowanie wyglądałoby tak:
I odszyfrowanie w ten sposób:
źródło
DESede
algorytmu? Ponieważ jest to popularne pytanie (i odpowiedź), szkoda byłoby zachęcać ludzi do używania DES, ponieważ szyfr jest tak słaby jak na dzisiejsze standardy.Używam Base64Encoder / Decoder firmy Sun, który można znaleźć w środowisku JRE firmy Sun, aby uniknąć kolejnego pliku JAR w bibliotece. To niebezpieczne z punktu widzenia używania OpenJDK lub JRE innego. Poza tym, czy jest jeszcze jeden powód, dla którego powinienem rozważyć użycie Apache commons lib z koderem / dekoderem?
źródło
dzięki, że stworzyłem tę klasę używając twojego kodu, być może ktoś uzna ją za pełną użytkownika
szyfrowanie obiektów
źródło
Aktualizacja w dniu 12 grudnia 2019 r
W przeciwieństwie do niektórych innych trybów, takich jak CBC, tryb GCM nie wymaga, aby IV był nieprzewidywalny. Jedynym wymaganiem jest to, że IV musi być unikalny dla każdego wywołania z danym kluczem. Jeśli powtórzy się raz dla danego klucza, bezpieczeństwo może zostać naruszone. Łatwym sposobem osiągnięcia tego jest użycie losowego IV z silnego generatora liczb pseudolosowych, jak pokazano poniżej.
Użycie sekwencji lub znacznika czasu jak IV jest również możliwe, ale może nie być tak banalne, jak mogłoby się wydawać. Na przykład, jeśli system nie śledzi poprawnie sekwencji już używanych jako IV w trwałym magazynie, wywołanie może powtórzyć IV po ponownym uruchomieniu systemu. Podobnie nie ma idealnego zegara. Zegar komputera przestawia się itp.
Ponadto klucz należy obracać po każdych 2 ^ 32 wywołaniach. Więcej informacji na temat wymogu IV można znaleźć w tej odpowiedzi i w zaleceniach NIST .
To jest kod szyfrowania i deszyfrowania, który właśnie napisałem w Javie 8, biorąc pod uwagę następujące punkty. Mam nadzieję, że ktoś uzna to za przydatne:
Algorytm szyfrowania : Szyfr blokowy AES z kluczem 256-bitowym jest uważany za wystarczająco bezpieczny. Aby zaszyfrować całą wiadomość, należy wybrać tryb. Zalecane jest uwierzytelnione szyfrowanie (zapewniające zarówno poufność, jak i integralność). GCM, CCM i EAX to najczęściej używane uwierzytelnione tryby szyfrowania. GCM jest zwykle preferowany i działa dobrze w architekturach Intela, które zapewniają dedykowane instrukcje dla GCM. Wszystkie te trzy tryby są trybami opartymi na CTR (opartymi na licznikach) i dlatego nie wymagają dopełniania. W rezultacie nie są podatne na ataki związane z wypełnianiem
W przypadku GCM wymagany jest wektor inicjujący (IV). IV nie jest tajemnicą. Jedyny wymóg musi być losowy lub nieprzewidywalny. W Javie
SecuredRandom
klasa ma na celu tworzenie silnych kryptograficznie liczb pseudolosowych. WgetInstance()
metodzie można określić algorytm generowania liczb pseudolosowych . Jednak od wersji Java 8 zalecanym sposobem jest użyciegetInstanceStrong()
metody, która będzie wykorzystywać najsilniejszy algorytm skonfigurowany i dostarczony przezProvider
NIST zaleca 96 bit IV dla GCM w celu promowania interoperacyjności, wydajności i prostoty projektowania
Aby zapewnić dodatkowe bezpieczeństwo, w poniższej implementacji
SecureRandom
jest ponownie inicjowany po wygenerowaniu co 2 ^ 16 bajtów pseudolosowego generowania bajtówOdbiorca musi znać IV, aby móc odszyfrować zaszyfrowany tekst. Dlatego IV należy przesłać wraz z zaszyfrowanym tekstem. Niektóre implementacje wysyłają IV jako AD (Associated Data), co oznacza, że znacznik uwierzytelnienia zostanie obliczony zarówno na podstawie zaszyfrowanego tekstu, jak i IV. Jednak nie jest to wymagane. IV może być po prostu poprzedzony zaszyfrowanym tekstem, ponieważ jeśli IV zostanie zmieniony podczas transmisji z powodu celowego ataku lub błędu sieci / systemu plików, walidacja znacznika uwierzytelniającego i tak zakończy się niepowodzeniem
Ciągów nie należy używać do przechowywania zwykłej wiadomości tekstowej lub klucza, ponieważ ciągi są niezmienne i dlatego nie możemy ich wyczyścić po użyciu. Te nieoczyszczone struny pozostają w pamięci i mogą pojawić się na wysypisku sterty. Z tego samego powodu klient wywołujący te metody szyfrowania lub deszyfrowania powinien wyczyścić wszystkie zmienne lub tablice przechowujące wiadomość lub klucz, gdy nie są już potrzebne.
Żaden dostawca nie jest zakodowany na stałe w kodzie zgodnie z ogólnymi zaleceniami
Wreszcie w przypadku transmisji przez sieć lub pamięć masową klucz lub zaszyfrowany tekst powinien być zakodowany przy użyciu kodowania Base64. Szczegóły dotyczące Base64 można znaleźć tutaj . Należy postępować zgodnie z podejściem Java 8
Tablice bajtów można wyczyścić za pomocą:
Jednak od wersji Java 8 nie ma łatwego sposobu, aby to wyczyścić,
SecretKeyspec
aSecretKey
implementacje tych dwóch interfejsów nie wydają się zaimplementować metodydestroy()
interfejsuDestroyable
. W poniższym kodzie zapisano oddzielną metodę, aby wyczyścićSecretKeySpec
iSecretKey
używać odbicia.Klucz należy wygenerować przy użyciu jednego z dwóch podejść wymienionych poniżej.
Zauważ, że klucze są sekretami, takimi jak hasła, ale w przeciwieństwie do haseł przeznaczonych do użytku przez ludzi, klucze są przeznaczone do użytku przez algorytmy kryptograficzne i dlatego powinny być generowane tylko w powyższy sposób.
Klucz szyfrowania można wygenerować przede wszystkim na dwa sposoby:
Bez hasła
Z hasłem
Aktualizacja na podstawie komentarzy
Jak wskazał @MaartenBodewes, moja odpowiedź nie obejmowała żadnego,
String
jak wymaga tego pytanie. Dlatego spróbuję wypełnić tę lukę, na wypadek gdyby ktoś natknął się na tę odpowiedź i zastanawiał się, jak sobie poradzićString
.Jak wskazano wcześniej w odpowiedzi, obsługa poufnych informacji w a nie
String
jest generalnie dobrym pomysłem, ponieważString
jest niezmienna i dlatego nie możemy ich usunąć po użyciu. I jak wiemy, nawet jeśli aString
nie ma silnego odniesienia, śmieciarz nie spieszy się natychmiast z usunięciem go ze stosu. W ten sposóbString
plik nadal znajduje się w pamięci przez nieznane okno czasu, mimo że nie jest dostępny dla programu. Problem polega na tym, że zrzut sterty w tym okresie ujawniłby poufne informacje. Dlatego zawsze lepiej jest obsłużyć wszystkie poufne informacje w tablicy bajtów lub tablicy znaków, a następnie wypełnić tablicę zerami, gdy zostanie osiągnięty ich cel.Jednak przy całej tej wiedzy, jeśli nadal znajdziemy się w sytuacji, w której poufne informacje do zaszyfrowania znajdują się w a
String
, musimy najpierw przekształcić je w tablicę bajtów i wywołać funkcjeencrypt
idecrypt
wprowadzone powyżej. (Drugi klucz wejściowy można wygenerować za pomocą fragmentu kodu podanego powyżej).A
String
można przekonwertować na bajty w następujący sposób:Począwszy od Java 8,
String
jest wewnętrznie przechowywany w stercie zUTF-16
kodowaniem. Jednak użyliśmyUTF-8
tutaj, ponieważ zwykle zajmuje mniej miejsca niżUTF-16
, szczególnie w przypadku znaków ASCII.Podobnie zaszyfrowaną tablicę bajtów można również przekonwertować na ciąg, jak poniżej:
źródło
String
przy użyciu funkcji stworzonych powyżej byłoby trywialne. Jednak po drugim spojrzeniu po przeczytaniu Twojego komentarza rozumiem, że może to nie być oczywiste. Na pewno edytuję, aby dodać te szczegóły.Co powiesz na to:
U mnie działa dobrze i jest raczej kompaktowy.
źródło
input.length <= secret.length
blokuje i niesecret
jest używane ponownie, jest to bezpieczne i nazywa sięone-time-pad
. W tym przypadkuinput.length > secret.length
jest to wariant szyfru Vigenère'a i uważany za bardzo słaby.Możesz użyć Jasypt
Dzięki Jasypt szyfrowanie i sprawdzanie hasła może być tak proste, jak ...
Szyfrowanie:
Deszyfrowanie:
Gradle:
Cechy:
źródło
Jasypt
zapewnia bezpieczeństwo ? Nie mogę tego rozgryźć na podstawie ich strony internetowej. Czy jest nie do odróżnienia w atakach z wybranym tekstem jawnym? Integralność? Poufność?Oto moja implementacja z meta64.com jako Spring Singleton. Jeśli chcesz utworzyć instancję cipera dla każdego wywołania, która również działałaby, a następnie możesz usunąć wywołania „zsynchronizowane”, ale uważaj, że „szyfr” nie jest bezpieczny dla wątków.
źródło
Tutaj proste rozwiązanie z tylko
java.*
ijavax.crypto.*
zależnościami do szyfrowania bajtów zapewniające poufność i integralność . Powinien być nie do odróżnienia w przypadku wybranego ataku w postaci zwykłego tekstu dla krótkich wiadomości w kolejności kilobajtów.Używa
AES
wGCM
trybie bez dopełnienia, 128-bitowy klucz jest uzyskiwany przezPBKDF2
wiele iteracji i statyczną sól z podanego hasła. Dzięki temu brutalne wymuszanie haseł jest trudne i rozkłada entropię na cały klucz.Generowany jest losowy wektor inicjujący (IV), który zostanie dołączony do zaszyfrowanego tekstu. Ponadto bajt statyczny
0x01
jest dodawany jako pierwszy bajt jako „wersja”.Cała wiadomość trafia do kodu uwierzytelniania wiadomości (MAC) wygenerowanego przez
AES/GCM
.Tak więc, klasa szyfrowania zerowych zależności zewnętrznych zapewniająca poufność i integralność :
Tutaj cały projekt z ładnym CLI: https://github.com/trichner/tcrypt
Edycja: teraz z odpowiednimi
encryptString
idecryptString
źródło
encryptString
idecryptString
:)Rozważałbym użycie czegoś takiego jak https://www.bouncycastle.org/ Jest to wstępnie zbudowana biblioteka, która umożliwia szyfrowanie, co chcesz, za pomocą wielu różnych szyfrów.Rozumiem, że chcesz chronić tylko przed szpiegowaniem, ale jeśli naprawdę chcesz chronić informacje, używanie Base64 w rzeczywistości cię nie ochroni.
źródło
Oto kilka linków, dzięki którym możesz przeczytać, co obsługuje Java
Szyfrowanie / deszyfrowanie strumienia danych.
JCERefGuide
Przykłady szyfrowania Java
źródło
Jak wielu z nich już powiedziało, powinieneś użyć standardowego szyfru, który jest nadmiernie używany, jak DES lub AES.
Prosty przykład tego, jak można zaszyfrować i odszyfrować ciąg znaków w Javie przy użyciu AES .
źródło
Oto rozwiązanie kopiuj / wklej. Polecam również przeczytanie i zagłosowanie na odpowiedź @ Konstantino, mimo że nie dostarcza ona żadnego kodu. Wektor inicjalizacyjny (IV) jest jak sól - nie musi być trzymany w tajemnicy. Jestem nowy w GCM i najwyraźniej AAD jest opcjonalny i używany tylko w określonych okolicznościach. Ustaw klucz w zmiennej środowiskowej
SECRET_KEY_BASE
. Użyj czegoś takiego jak KeePass, aby wygenerować 32-znakowe hasło. To rozwiązanie jest wzorowane na moim rozwiązaniu Ruby.Oto przykład:
źródło
Możesz rozważyć użycie zautomatyzowanego narzędzia do generowania kodu szyfrowania / deszyfrowania, np. https://www.stringencrypt.com/java-encryption/
Może generować za każdym razem inny kod szyfrowania i deszyfrowania dla ciągu lub szyfrowania pliku.
Jest to bardzo przydatne, jeśli chodzi o szybkie szyfrowanie ciągów bez używania RSA, AES itp.
Przykładowe wyniki:
Używamy go cały czas w naszej firmie.
źródło
źródło
źródło