Kriptografi

Bu dokümanda, Android'in kriptografik özelliklerinin doğru şekilde kullanılması açıklanmakta ve bu özelliklerin kullanımına dair 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 Anahtar Deposu sistemini kullanmadan bir sağlayıcı belirtmek, gelecekteki 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
Şifre 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)

Genel şifreleme işlemlerini 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 imzaları doğrulama

İmzalayanın ortak anahtarını içeren bir PublicKey nesnenizin olması gerekir. Bu nesneyi uygulamanızla birlikte paket halinde sunulan bir dosyadan okuyabilir, bir sertifikadan çıkarabilir 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ıyla ilgili, anormal görünen ancak uyumlulukla ilgili endişeler nedeniyle oluşan 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'da MGF1 özeti için SHA-1 kullanılır. Diğer Android şifreleme sağlayıcıları için iki özet 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 uygulaması kullanımdan kaldırıldı. 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 ile ilgili bölümde belirtildiği gibi, belirli bir sağlayıcı talep etmek ö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 şifreleri kullanırken her zaman aşağıdaki kod snippet'inde gösterildiği gibi 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, şifreleme sağlayıcısının bir örneğini isterse (ör. aşağıdaki yöntemi çağırarak) NoSuchProviderException gerçekleşir.

Kotlin

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

Java

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

Jetpack Security şifreleme kitaplığı

Jetpack güvenlik şifreleme kitaplığı 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:

Eski

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: