Mga Keys, Credentials at Storage sa Android
() translation by (you can also view the original English article)
Sa nakaraang post tungkol sa seguridad ng Android user data, tinignan natin ang pag-eencrypt ng datos sa pamamagitan ng passcode na binigay ng user. Ililipat ng pagtuturong ito ang focus sa credential at key storage. Sisismulan ko sa pamamagitan ng pagpapakilala ng mga account credentials at tatapusin ito sa pamamagitan ng isang halimbawa ng paprotekta ng data gamit ang KeyStore.
- SeguridadLigtas na Pag-iimbak ng Datos sa AndroidCollin Stuart
- AndroidPapaano Magsecure ng isang Android AppAshraff Hathibelagal
Kadalasan, kapag gumagamit ng isang
third-party service, mangangailangan ng ilang uri ng authentication. Maaaring kasingsimple lang ito ng isang /login
endpoint na tumatanggap ng isang username at password.
Sa una, mukhang ang pinaksimpleng
solusyon ay bumuo ng isang UI na nanghihingi sa user na maglog-in, pagkatapos
ay kunin at iimbak ang kanilang mga login credentials. Gayunpaman, hindi ito ang pinakamahusay
na kasanayan sapagkat hindi dapat kailanganing alamin ng ating app ang ating
mga credentials para sa isang third-party account. Sa halip, maaari nating gamitin ang
Account Manager, na nagtatalaga ng pag-aasikaso ng sensitibong kaaalaman na ito
para sa atin.
Ang Account Manager
Ang Account Manager ay isang sentralisadong taga-alalay para sa mga credentials ng user account para hindi na tuwirang alalahanin ng iyong app ang pag-aasikaso ng mga password. Kadalasan itong nagbibigay ng isang token kapalit ng tunay na username at password na maaaring gamitin upang gumawa ng mga authenticated na mga requests sa isang service. Ang isang halimbawa ay kapag nag-rerequest ng isang token ng OAuth2.
Minsan, ang kinakailangan lang na impormasyon ay nakalagay na sa device, at sa ibang pagkakataon naman ay kakailanganin ng Account Manager tumawag sa server para sa isang na-refresh na token. Maaaring nakita mo na ang Accounts section sa Settings ng iyong device para sa sari-saring mga apps. Maaari tayong makakuha ng listahan ng mga available accounts na gaya nito:
1 |
AccountManager accountManager = AccountManager.get(this); |
2 |
Account[] accounts = accountManager.getAccounts(); |
Ang code ay mangangailangan ng
permission ng android.permission.GET_ACCOUNTS
Kung may isang tiyak na account kang
hinahanap, maaari mo itong hanapin sa ganitong paraan:
1 |
AccountManager accountManager = AccountManager.get(this); |
2 |
Account[] accounts = accountManager.getAccountsByType("com.google"); |
Kapag nasa iyo na ang account,
makakakuha ka ng isang token para sa account sa pamamagitan ng pagtawag sa getAuthToken (Account, String, Bundle, Activity, AccountManagerCallback, Handler)
method. Ang token ay maaaring gamitin upang
gumawa ng mga authenticated na API requests sa isang service. Maaari itong maging isang RESTful na
API, kung saan ipinapasa mo ang isang token parameter habang ginagawa ang HTTPS
request, ng hindi inaalam ang pribadong account details ng user.
Dahil ang bawat serbisyo ay may iba-ibang paraan ng pag-aauthenticate at pag-iimbak ng mga pribadong credentials, binibigay ng Account Manager ang mga authenticator modules para maipatupad ang isang third-party service. Habang ang Android ay mayroong mga pagpapatupad para sa maraming popular na mga serbisyo, nangangahuluhan iyong maaari kang magsulat ng sarili mong authenticator upang asikasuhin ang account authentication at pag-iimbak ng credential ng iyong app. Binibigyan ka nito ng kakayahang siguruhing ang mga credentials ay encrypted. Tandaan, nangangahulugan din ito na ang mga credentials sa Account Manager na ginagamit ng ibang mga serbisyo ay maaaring iimbak sa clear text, na ginagawa itong madaling makita sa sinumang naka-root ang device.
Sa halip na simpleng credentials lang, may mga panahong kakailanganin mong gumamit ng isang key o isang certificate para sa isang indibidwal o entity-halimbawa, kapag ang isang third party ay nagpadala sa iyo ng isang certificate file na kailangan mong itago. Ang pinakamadalas na scenario ay kapag ang app ay kailangang mag-authenticate sa server ng isang pribadong organisasyon.
Sa susunod na pagtuturo, tatalakayin natin ang paggamit ng mga certificates para sa authentication at ligtas na komunikasyon, ngunit gusto ko munang talakayin kung papaano iimbak ang mga items na ito. Ang Keychain API ay orihinal na binuo para sa tiyak na gamit na ito-pag-iinstall ng isang pribadong key o pares ng certificate mula sa isang PKCS#12 na file.
Ang Keychain
Ipinakilala sa Android 4.0 (API_Level
14), ang Keychain_API ay tumatalakay sa pamamahala ng mga keys. Sa katiyakan, gumagana ito sa mga PrivateKey
at X509Certificate
na
objects at nagbibigay ng isang mas ligtas na lalagyan kaysa sa paggamit ng
imbakan ng datos ng iyong app. Ito’y dahil ang mga permissions para sa
pribadong keys ay nagbibigay lang ng kakayahan sa iyong sariling app upang
maaccess ang mga keys, matapos ang authorization ng user. Ibig sabihin nito ay kailangang magsetup
ng lock screen sa device bago kayo makagamit ng imbakan ng mga credentials. Higit pa riyan, ang mga objects sa
keychain ay maaaring nakatakdang bigyang-seguridad ang hardware, kung
available.
Ang code para mag-install ng isang certificate ay gaya ng sumusunod:
1 |
Intent intent = KeyChain.createInstallIntent(); |
2 |
byte[] p12Bytes = //... read from file, such as example.pfx or example.p12... |
3 |
intent.putExtra(KeyChain.EXTRA_PKCS12, p12Bytes); |
4 |
startActivity(intent); |
Ang user ay hihingan ng isang password
upang ma-access ang pribadong key at isang pagkakataong pangalanan ang
certificate. Upang mabawi ang key, ang sumusunod na
code ay nagpapakita ng isang UI na hinahayaan ang user na mamili mula sa isang
listahan ng mga naka-install nang mga keys.
1 |
KeyChain.choosePrivateKeyAlias(this, this, new String[]{"RSA"}, null, null, -1, null); |
Kapag nakapili na, isang pangalan ng
string alias ang ibabalik sa alias(final String alias)
na callback kung saan maaari ninyong tuwirang
maaccess ang pribadong key o certificate chain.
1 |
public class KeychainTest extends Activity implements ..., KeyChainAliasCallback |
2 |
{
|
3 |
//...
|
4 |
|
5 |
@Override
|
6 |
public void alias(final String alias) |
7 |
{
|
8 |
Log.e("MyApp", "Alias is " + alias); |
9 |
|
10 |
try
|
11 |
{
|
12 |
PrivateKey privateKey = KeyChain.getPrivateKey(this, alias); |
13 |
X509Certificate[] certificateChain = KeyChain.getCertificateChain(this, alias); |
14 |
}
|
15 |
catch ... |
16 |
}
|
17 |
|
18 |
//...
|
19 |
}
|
Taglay ang kaalamang ito, tignan natin kung papaano natin pwedeng gamitin ang imbakan ng mga credentials upang i-save ang sarili ninyong sensitibong datos.
Ang KeyStore
Sa nakaraang pagtuturo, tinalakay natin ang pagprotekta ng datos sa pamamagitan ng passcode na binigay ng user. Ang ganitong uri ng setup ay mabuti, ngunit ang mga pangangailangan ng app ay madalas umiiwas sa pangangailangang maglog-in ng user kada oras at umalala ng karagdagang passcode.
Dito maaaring magamit ang Keystore_API. Mula sa API 1, ginagamit na ny system ang KeyStore upang mag-imbak ng mga credentials ng WiFi at VPN. Sa 4.3 (API 18), binibigyan ka nito ng kakayahang kumilos gamit ang sarili mong app-sepcific na mga keys, at sa Android M (API 23) naman ay maaari itong mag-imbak ng AES symmetric na key. Kaya habang hindi pa pinapayagan ng API ang tuwirang pag-iimbak ng mga sensitibong strings, maaaring iimbak ang mga keys na ito at pagkatapos ay gamitin ito upang mag-encrypt ng mga strings.
Ang benepisyo ng pag-iimbak ng isang key sa KeyStore ay hinahayaan nito ang mga keys na mapatakbo ng hindi ibinubunyag ang lihim na laman ng key na ito; hindi pumapasok sa app space ang key data. Tandaan na ang mga keys ay protektado ng mga permissions upang tanging ang app ninyo lang ang makaka-access sa mga ito, at karagdagang maaaring maging maging secure hardware-backed kung kaya ng device. Gumagawa ito ng isang lalagyan na pinapahirap ang pag-eextract ng mga keys mula sa isang device.
Lumikha ng Bagong Random Key
Para sa halimbawang ito, sa halip na
lumikha ng isang AES key mula sa isang passcode na binigay ng passcode, maaari
tayong mag auto-generate ng isang random key na magiging protektado sa isang
KeyStore. Magagawa natin ito sa pamamagitan ng
paglikha ng isang KeyGenerator
na instance, na naka-set sa "AndroidKeyStore"
.
1 |
//Generate a key and store it in the KeyStore
|
2 |
final KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore"); |
3 |
final KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder("MyKeyAlias", |
4 |
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) |
5 |
.setBlockModes(KeyProperties.BLOCK_MODE_GCM) |
6 |
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) |
7 |
//.setUserAuthenticationRequired(true) //requires lock screen, invalidated if lock screen is disabled
|
8 |
//.setUserAuthenticationValidityDurationSeconds(120) //only available x seconds from password authentication. -1 requires finger print - every time
|
9 |
.setRandomizedEncryptionRequired(true) //different ciphertext for same plaintext on each call |
10 |
.build(); |
11 |
keyGenerator.init(keyGenParameterSpec); |
12 |
keyGenerator.generateKey(); |
Ang mahahalagang bahaging makita dito ay
ang mga .setUserAuthenticationRequired(true)
at .setUserAuthenticationValidityDurationSeconds(120)
na specifications. Nangangailangan ang mga ito ng isang
lock screen upang mai-setup at ang key na kailangang mai-lock hanggang ang user
ay ma-authenticate.
Kapag tinignan natin ang documentation para sa .setUserAuthenticationValidityDurationSeconds()
,
makikita ninyo na nangangahulugan itong ang key ay available lamang sa loob ng
iilang Segundo mula sa password authentication, at ang pagpapasa ng -1
ay
nangangailangan ng fingerprint authentication sa bawat pagkakataong gusto mong
i-access ang key. Ang pag-eenable ng pangangailangang
mag-authenticate ay taglay din ang effect ng pagbawi ng key kapag tinanggal o
binago ng user ang kanyang lock screen.
Dahil ang pag-iimbak ng isang di-protektadong key kasabay ng encrypted na datos ay gaya ng paglalagay ng susi ng bahay sa ilalim ng doormat, ang mga pagpipiliang ito ay sinusubukang protektahan ang naka-tenggang key sa oras na ang isang device ay makompromiso. Isang maaaring maging halimbawa ay ang isang offline data dump ng device. Kung wala ang password na kilala para sa device, ang datos na ito ay walang silbi.
Ang .setRandomizedEncryptionRequired(true)
na option ay ine-enable ang
requirement na mayronng sapat na randomization(isang bagong random IV kada
panahon) para kung ang parehong datos ay na-encrypt sa ikalawang pagkakataon,
ang encrypted output ay magiging iba parin. Pinipigilan nito ang isang attacker sa
pagkamit ng mga palatandaan tungkol sa ciphertext batay sa pag-feed sa parehong
datos.
Ang isa pang pagpipiliang maaaring
isaalang-alang ay ang setUserAuthenticationValidWhileOnBody(boolean remainsValid)
, na ikinakandado ang key kapag napag-alaman nitong ang
device ay wala na sa tao.
Pag-eencrypt ng Datos
Ngayon na ang key ay nakaimbak na sa
KeyStore, maaari na tayong gumawa ng isang method na nag-eencrypt ng datos
gamit ang Cipher
object, kapag mayroon nang SecretKey
. Magbabalik ito ng isang HashMap
na
nilalaman ang encrypted na datos at isang randomized IV na kakailanganin upang
i-decrypt ang datos. Ang encrypted na datos, kasama ng IV, ay
maaaring iimbak sa isang file o tungo sa nakabahaging mga preferences.
1 |
private HashMap<String, byte[]> encrypt(final byte[] decryptedBytes) |
2 |
{
|
3 |
final HashMap<String, byte[]> map = new HashMap<String, byte[]>(); |
4 |
try
|
5 |
{
|
6 |
//Get the key
|
7 |
final KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); |
8 |
keyStore.load(null); |
9 |
final KeyStore.SecretKeyEntry secretKeyEntry = (KeyStore.SecretKeyEntry)keyStore.getEntry("MyKeyAlias", null); |
10 |
final SecretKey secretKey = secretKeyEntry.getSecretKey(); |
11 |
|
12 |
//Encrypt data
|
13 |
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); |
14 |
cipher.init(Cipher.ENCRYPT_MODE, secretKey); |
15 |
final byte[] ivBytes = cipher.getIV(); |
16 |
final byte[] encryptedBytes = cipher.doFinal(decryptedBytes); |
17 |
map.put("iv", ivBytes); |
18 |
map.put("encrypted", encryptedBytes); |
19 |
}
|
20 |
catch (Throwable e) |
21 |
{
|
22 |
e.printStackTrace(); |
23 |
}
|
24 |
|
25 |
return map; |
26 |
}
|
Pag-dedecrypt patungo sa isang Byte Array
Para sa decryption, ginagamit natin ang
kabaliktaran Ang Cipher
object ay ini-initialize
gamit ang DECRYPT_MODE
constant, at ang decrypted byte na byte[]
array ay
ibinabalik.
1 |
private byte[] decrypt(final HashMap<String, byte[]> map) |
2 |
{
|
3 |
byte[] decryptedBytes = null; |
4 |
try
|
5 |
{
|
6 |
//Get the key
|
7 |
final KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); |
8 |
keyStore.load(null); |
9 |
final KeyStore.SecretKeyEntry secretKeyEntry = (KeyStore.SecretKeyEntry)keyStore.getEntry("MyKeyAlias", null); |
10 |
final SecretKey secretKey = secretKeyEntry.getSecretKey(); |
11 |
|
12 |
//Extract info from map
|
13 |
final byte[] encryptedBytes = map.get("encrypted"); |
14 |
final byte[] ivBytes = map.get("iv"); |
15 |
|
16 |
//Decrypt data
|
17 |
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); |
18 |
final GCMParameterSpec spec = new GCMParameterSpec(128, ivBytes); |
19 |
cipher.init(Cipher.DECRYPT_MODE, secretKey, spec); |
20 |
decryptedBytes = cipher.doFinal(encryptedBytes); |
21 |
}
|
22 |
catch (Throwable e) |
23 |
{
|
24 |
e.printStackTrace(); |
25 |
}
|
26 |
|
27 |
return decryptedBytes; |
28 |
}
|
Pagsubok sa Halimbawa
Maaari na nating subukin an gating halimbawa!
1 |
@TargetApi(Build.VERSION_CODES.M) |
2 |
private void testEncryption() |
3 |
{
|
4 |
try
|
5 |
{
|
6 |
//Generate a key and store it in the KeyStore
|
7 |
final KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore"); |
8 |
final KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder("MyKeyAlias", |
9 |
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) |
10 |
.setBlockModes(KeyProperties.BLOCK_MODE_GCM) |
11 |
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) |
12 |
//.setUserAuthenticationRequired(true) //requires lock screen, invalidated if lock screen is disabled
|
13 |
//.setUserAuthenticationValidityDurationSeconds(120) //only available x seconds from password authentication. -1 requires finger print - every time
|
14 |
.setRandomizedEncryptionRequired(true) //different ciphertext for same plaintext on each call |
15 |
.build(); |
16 |
keyGenerator.init(keyGenParameterSpec); |
17 |
keyGenerator.generateKey(); |
18 |
|
19 |
//Test
|
20 |
final HashMap<String, byte[]> map = encrypt("My very sensitive string!".getBytes("UTF-8")); |
21 |
final byte[] decryptedBytes = decrypt(map); |
22 |
final String decryptedString = new String(decryptedBytes, "UTF-8"); |
23 |
Log.e("MyApp", "The decrypted string is " + decryptedString); |
24 |
}
|
25 |
catch (Throwable e) |
26 |
{
|
27 |
e.printStackTrace(); |
28 |
}
|
29 |
}
|
Gamit ang Asymmetric Keys ng RSA para sa Mga Mas Lumang Devices
Ito ay isang magandang solusyon para mag-imbak ng datos para sa bersyong M at mas mataas pa, ngunit papaano naman kung suportado ng iyong app ang mga naunang mga bersyon? Habang ang mga symmetric keys ng AES ay hindi suportado sa ilalim ng M, ang symmetric keys ng RSA ay suportado naman. Ibig sabihin nito ay maaari nating gamitin ang mga RSA keys at encryption upang magawa ang parehong bagay.
Ang pinakapinagkaiba nito ay ang isang
asymmetric keypair ay naglalaman ng dalawang keys, isang pribado at publikong
key,kung saan ang pampublikong key ay ine-encrypt ang datos at ang pribadong
key ay dine-decrypt ito. Ang AKeyPairGeneratorSpec
ay ipinapasa
tungo sa KeyPairGenerator
na ini-initialize gamit ang provider ng
KEY_ALGORITHM_RSA
at "AndroidKeyStore"
.
1 |
private void testPreMEncryption() |
2 |
{
|
3 |
try
|
4 |
{
|
5 |
//Generate a keypair and store it in the KeyStore
|
6 |
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); |
7 |
keyStore.load(null); |
8 |
|
9 |
Calendar start = Calendar.getInstance(); |
10 |
Calendar end = Calendar.getInstance(); |
11 |
end.add(Calendar.YEAR, 10); |
12 |
KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(this) |
13 |
.setAlias("MyKeyAlias") |
14 |
.setSubject(new X500Principal("CN=MyKeyName, O=Android Authority")) |
15 |
.setSerialNumber(new BigInteger(1024, new Random())) |
16 |
.setStartDate(start.getTime()) |
17 |
.setEndDate(end.getTime()) |
18 |
.setEncryptionRequired() //on API level 18, encrypted at rest, requires lock screen to be set up, changing lock screen removes key |
19 |
.build(); |
20 |
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore"); |
21 |
keyPairGenerator.initialize(spec); |
22 |
keyPairGenerator.generateKeyPair(); |
23 |
|
24 |
//Encryption test
|
25 |
final byte[] encryptedBytes = rsaEncrypt("My secret string!".getBytes("UTF-8")); |
26 |
final byte[] decryptedBytes = rsaDecrypt(encryptedBytes); |
27 |
final String decryptedString = new String(decryptedBytes, "UTF-8"); |
28 |
Log.e("MyApp", "Decrypted string is " + decryptedString); |
29 |
}
|
30 |
catch (Throwable e) |
31 |
{
|
32 |
e.printStackTrace(); |
33 |
}
|
34 |
}
|
Upang mag-encrypt, kukunin natin ang
RSAPublicKey
mula sa keypair at gamitin ito kasama ang Cipher
object.
1 |
public byte[] rsaEncrypt(final byte[] decryptedBytes) |
2 |
{
|
3 |
byte[] encryptedBytes = null; |
4 |
try
|
5 |
{
|
6 |
final KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); |
7 |
keyStore.load(null); |
8 |
final KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry("MyKeyAlias", null); |
9 |
final RSAPublicKey publicKey = (RSAPublicKey)privateKeyEntry.getCertificate().getPublicKey(); |
10 |
|
11 |
final Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL"); |
12 |
cipher.init(Cipher.ENCRYPT_MODE, publicKey); |
13 |
|
14 |
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); |
15 |
final CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, cipher); |
16 |
cipherOutputStream.write(decryptedBytes); |
17 |
cipherOutputStream.close(); |
18 |
|
19 |
encryptedBytes = outputStream.toByteArray(); |
20 |
|
21 |
}
|
22 |
catch (Throwable e) |
23 |
{
|
24 |
e.printStackTrace(); |
25 |
}
|
26 |
return encryptedBytes; |
27 |
}
|
Ang decryption ay ginagawa gamit ang
RSAPrivateKey
object.
1 |
public byte[] rsaDecrypt(final byte[] encryptedBytes) |
2 |
{
|
3 |
byte[] decryptedBytes = null; |
4 |
try
|
5 |
{
|
6 |
final KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); |
7 |
keyStore.load(null); |
8 |
final KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry("MyKeyAlias", null); |
9 |
final RSAPrivateKey privateKey = (RSAPrivateKey)privateKeyEntry.getPrivateKey(); |
10 |
|
11 |
final Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL"); |
12 |
cipher.init(Cipher.DECRYPT_MODE, privateKey); |
13 |
|
14 |
final CipherInputStream cipherInputStream = new CipherInputStream(new ByteArrayInputStream(encryptedBytes), cipher); |
15 |
final ArrayList<Byte> arrayList = new ArrayList<>(); |
16 |
int nextByte; |
17 |
while ( (nextByte = cipherInputStream.read()) != -1 ) |
18 |
{
|
19 |
arrayList.add((byte)nextByte); |
20 |
}
|
21 |
|
22 |
decryptedBytes = new byte[arrayList.size()]; |
23 |
for(int i = 0; i < decryptedBytes.length; i++) |
24 |
{
|
25 |
decryptedBytes[i] = arrayList.get(i); |
26 |
}
|
27 |
}
|
28 |
catch (Throwable e) |
29 |
{
|
30 |
e.printStackTrace(); |
31 |
}
|
32 |
|
33 |
return decryptedBytes; |
34 |
}
|
Ang isang bagay mula sa RSA ay ang
encryption ay mas mabagal kaysa sa AES. Kadalasan ay ayos lang ito para sa
kakaunting dami ng impormasyon, gaya ng kapag nagse-secure ng mga strings para
sa shared preference. Kung mapapagalaman mong mayroong isang
problema sa performance habang nag-eencrypt ng malalaking dami ng datos, maaari
mong gamitin sa halip ang halimbawang ito at mag-imbak lang ng AES key. Matapos ito, gamitin ang mas mabilis na
AES encryption na tinalakay sa nakaraang pagtuturo para sa kabuuan ng iyong
datos. Maaari kang mag-generate ng isang bagong
AES key at i-convert ito sa isang byte[]
array na compatible sa halimbawang
ito.
1 |
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); |
2 |
keyGenerator.init(256); //AES-256 |
3 |
SecretKey secretKey = keyGenerator.generateKey(); |
4 |
byte[] keyBytes = secretKey.getEncoded(); |
Upang makuha ang key pabalik mula sa mga bytes, ito ang kailangang gawin:
1 |
SecretKey key = new SecretKeySpec(keyBytes, 0, keyBytes.length, "AES"); |
Andaming code noon! Upang mapanatiling simple ang lahat ng
mga halimbawang ito, tinanggal ko na ang masinsinang exception handling. Ngunit tandaan na para sa iyong
production code, hindi inirerekumenda na i-catch ang lahat ng Throwable
na mga
cases sa loob ng isang catch statement.
Konklusyon
Dito nagtatapos ang pagtuturo sa pag-asikaso ng mga credentials at mga keys. Karamihan sa kalituhan sa mga keys at pag-iimbak ay may kinalaman sa ebolusyon ng Android OS, ngunit maaari mong piliin ang solusyon ang gusto mong gamitin kung alam mo ang antas ng API na suportado ng iyong app.
Ngayong natalakay na natin ang lahat ng pinakamahusay na kasanayan sa pagse-secure ng datos at ang iba pa, ang susunod na pagtuturo ay tututok sa pagse-secure ng datos habang inihahatid ito.