Kriptografi

Bu belgede, Android'in kriptografik özelliklerinin doğru şekilde kullanılması açıklanmakta ve bu özelliklerin kullanımına ilişkin bazı örnekler verilmektedir. Uygulamanız için daha fazla anahtar güvenliği gerekiyorsa Android Anahtar Deposu sistemini kullanın.

Yalnızca Android Anahtar Deposu sistemiyle sağlayıcı belirtme

Android Anahtar Deposu sistemini kullanıyorsanız bir sağlayıcı belirtmeniz gerekir.

Ancak Android, belirli bir algoritma için belirli bir sağlayıcıyı garanti etmez. Android Keystore sistemini kullanmadan bir sağlayıcı belirtmek, sonraki sürümlerde uyumluluk sorunlarına neden olabilir.

Önerilen bir algoritma seçin

Hangi algoritmayı kullanacağınızı seçme özgürlüğüne sahip olduğunuzda (ör. üçüncü taraf bir sistemle uyumluluğu gerektirmediğinizde) aşağıdaki algoritmaları kullanmanızı öneririz:

Sınıf Öneri
Cipher 256 bit anahtarlarla (AES/GCM/NoPadding gibi) CBC veya GCM modunda AES
MessageDigest SHA-2 ailesi (SHA-256 gibi)
Mac SHA-2 ailesi HMAC'si (HMACSHA256 gibi)
İmza ECDSA ile SHA-2 ailesi (SHA256withECDSA gibi)

Yaygın kriptografik işlemleri gerçekleştirme

Aşağıdaki bölümlerde, uygulamanızda yaygın kriptografik işlemleri nasıl tamamlayabileceğinizi gösteren snippet'ler bulunmaktadır.

İleti şifreleme

KotlinJava
val plaintext: ByteArray = ...
val keygen = KeyGenerator.getInstance("AES")
keygen
.init(256)
val key: SecretKey = keygen.generateKey()
val cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING")
cipher
.init(Cipher.ENCRYPT_MODE, key)
val ciphertext: ByteArray = cipher.doFinal(plaintext)
val iv: ByteArray = cipher.iv
byte[] plaintext = ...;
KeyGenerator keygen = KeyGenerator.getInstance("AES");
keygen
.init(256);
SecretKey key = keygen.generateKey();
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher
.init(Cipher.ENCRYPT_MODE, key);
byte[] ciphertext = cipher.doFinal(plaintext);
byte[] iv = cipher.getIV();

Mesaj özeti oluşturma

KotlinJava
val message: ByteArray = ...
val md = MessageDigest.getInstance("SHA-256")
val digest: ByteArray = md.digest(message)
byte[] message = ...;
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] digest = md.digest(message);

Dijital imza oluşturma

Çalışma zamanında oluşturabileceğiniz, uygulamanızla birlikte paketlenmiş bir dosyadan okuyabileceğiniz veya ihtiyaçlarınıza bağlı olarak başka bir kaynaktan alabileceğiniz imzalama anahtarını içeren bir PrivateKey nesnenizin olması gerekir.

KotlinJava
val message: ByteArray = ...
val key: PrivateKey = ...
val s = Signature.getInstance("SHA256withECDSA")
       
.apply {
            initSign
(key)
            update
(message)
       
}
val signature: ByteArray = s.sign()
byte[] message = ...;
PrivateKey key = ...;
Signature s = Signature.getInstance("SHA256withECDSA");
s
.initSign(key);
s
.update(message);
byte[] signature = s.sign();

Dijital imzayı doğrulama

İmzalayanın ortak anahtarını içeren bir PublicKey nesnenize ihtiyacınız vardır. Bu nesneyi uygulamanızla birlikte paketlenmiş bir dosyadan okuyabilir, sertifikadan ayıklayabilir veya ihtiyaçlarınıza bağlı olarak başka bir kaynaktan edinebilirsiniz.

KotlinJava
val message: ByteArray = ...
val signature: ByteArray = ...
val key: PublicKey = ...
val s = Signature.getInstance("SHA256withECDSA")
       
.apply {
            initVerify
(key)
            update
(message)
       
}
val valid: Boolean = s.verify(signature)
byte[] message = ...;
byte[] signature = ...;
PublicKey key = ...;
Signature s = Signature.getInstance("SHA256withECDSA");
s
.initVerify(key);
s
.update(message);
boolean valid = s.verify(signature);

Uygulamanın karmaşıklığı

Android kriptografi uygulamasında, alışılmadık görünen ancak uyumluluk endişeleri nedeniyle mevcut olan bazı ayrıntılar vardır. Bu bölümde, büyük olasılıkla karşılaşacağınız sorunlar ele alınmaktadır.

OAEP MGF1 mesaj özeti

RSA OAEP şifreleri iki farklı ileti özetiyle parametrelendirilir: "ana" özet ve MGF1 özeti. Ana özeti belirten ve MGF1 özetini belirtilmemiş durumda bırakan Cipher.getInstance("RSA/ECB/OAEPwithSHA-256andMGF1Padding") gibi özet adlarını içeren Cipher tanımlayıcılar vardır. Android Keystore için MGF1 karması SHA-1 kullanılırken diğer Android kriptografi sağlayıcıları için iki karma aynıdır.

Uygulamanızın kullandığı özetler üzerinde daha fazla kontrole sahip olmak için Cipher.getInstance("RSA/ECB/OAEPPadding")'te olduğu gibi OAEPPadding ile şifre isteyin ve her iki özeti de açıkça seçmek için OAEPParameterSpec ile init() arasında bir değer sağlayın. Bu durum aşağıdaki kodda gösterilmektedir:

KotlinJava
val key: Key = ...
val cipher = Cipher.getInstance("RSA/ECB/OAEPPadding")
       
.apply {
           
// To use SHA-256 the main digest and SHA-1 as the MGF1 digest
           
init(Cipher.ENCRYPT_MODE, key, OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT))
           
// To use SHA-256 for both digests
           
init(Cipher.ENCRYPT_MODE, key, OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT))
       
}
Key key = ...;
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPPadding");
// To use SHA-256 the main digest and SHA-1 as the MGF1 digest
cipher
.init(Cipher.ENCRYPT_MODE, key, new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT));
// To use SHA-256 for both digests
cipher
.init(Cipher.ENCRYPT_MODE, key, new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT));

Desteği sonlandırılan işlevler

Aşağıdaki bölümlerde desteği sonlandırılan işlevler açıklanmaktadır. Uygulamanızda kullanmayın.

Bouncy Castle algoritmaları

Birçok algoritmanın Bouncy Castle uygulamaları desteklenmiyor. Bu durum yalnızca aşağıdaki örnekte gösterildiği gibi Bouncy Castle sağlayıcısını açıkça istediğiniz durumları etkiler:

KotlinJava
Cipher.getInstance("AES/CBC/PKCS7PADDING", "BC")
// OR
Cipher.getInstance("AES/CBC/PKCS7PADDING", Security.getProvider("BC"))
Cipher.getInstance("AES/CBC/PKCS7PADDING", "BC");
// OR
Cipher.getInstance("AES/CBC/PKCS7PADDING", Security.getProvider("BC"));

Yalnızca Android Anahtar Deposu sistemiyle sağlayıcı belirtme hakkındaki bölümde belirtildiği gibi, belirli bir sağlayıcı istemek önerilmez. Bu kurala uyuyorsanız bu desteğin sonlandırılması sizi etkilemez.

Başlatma vektörü olmayan şifre tabanlı şifreleme anahtarları

Başlatma vektörü (IV) gerektiren şifre tabanlı şifreleme (PBE) şifreleri, uygun şekilde oluşturulmuşsa anahtardan veya açıkça iletilen bir IV'den bu vektörü alabilir. IV içermeyen bir PBE anahtarı ve açık bir IV iletmezseniz Android'deki PBE şifreleri şu anda sıfır IV olduğunu varsayar.

PBE şifrelerini kullanırken aşağıdaki kod snippet'inde gösterildiği gibi her zaman açık bir IV iletin:

KotlinJava
val key: SecretKey = ...
val cipher = Cipher.getInstance("PBEWITHSHA256AND256BITAES-CBC-BC")
val iv = ByteArray(16)
SecureRandom().nextBytes(iv)
cipher
.init(Cipher.ENCRYPT_MODE, key, IvParameterSpec(iv))
SecretKey key = ...;
Cipher cipher = Cipher.getInstance("PBEWITHSHA256AND256BITAES-CBC-BC");
byte[] iv = new byte[16];
new SecureRandom().nextBytes(iv);
cipher
.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));

Kripto para sağlayıcı

Android 9 (API düzeyi 28) itibarıyla Crypto Java Cryptography Architecture (JCA) sağlayıcısı kaldırıldı. Uygulamanız, aşağıdaki yöntemi çağırarak kripto sağlayıcı örneği talep ederse NoSuchProviderException meydana gelir.

KotlinJava
SecureRandom.getInstance("SHA1PRNG", "Crypto")
SecureRandom.getInstance("SHA1PRNG", "Crypto");

Jetpack Security şifreleme kitaplığı

Jetpack Security şifreleme kitaplığının desteği sonlandırıldı. Bu durum yalnızca uygulama modülünüzün build.gradle dosyasında aşağıdaki bağımlılıklara sahip olduğunuz durumları etkiler:

GroovyKotlin
dependencies {
    implementation
"androidx.security:security-crypto:1.0.0"
}
dependencies {
    implementation
("androidx.security:security-crypto:1.0.0")
}

Desteklenen algoritmalar

Android'de desteklenen JCA algoritma tanımlayıcıları şunlardır: