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

Kotlin

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

Java

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

Kotlin

val message: ByteArray = ...
val md = MessageDigest.getInstance("SHA-256")
val digest: ByteArray = md.digest(message)

Java

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.

Kotlin

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

Java

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.

Kotlin

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)

Java

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:

Kotlin

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))
        }

Java

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:

Kotlin

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

Java

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:

Kotlin

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))

Java

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.

Kotlin

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

Java

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:

Groovy

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

Kotlin

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

Desteklenen algoritmalar

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