Android 5.0中的FDE功能实现
生活随笔
收集整理的這篇文章主要介紹了
Android 5.0中的FDE功能实现
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
標(biāo) 題:
?【分享】Android 5.0中的FDE功能實(shí)現(xiàn)
作 者:?netsniffer
時(shí) 間:?2015-01-27,21:15:06
鏈 接:?http://bbs.pediy.com/showthread.php?t=197289
Android?5.0中的FDE(full?disk?encryption-全磁盤(pán)加密)
在Android?5.0之前,vold中的磁盤(pán)加密功能FDE(full?disk?encryption),只是對(duì)用戶(hù)密碼及SALT采用了scrypt算法來(lái)生成加密密鑰(4.4以前使用pkdf2,強(qiáng)度更低),這些只是增加了暴力破解的難度,但風(fēng)險(xiǎn)依然很高。比如可以獲取分區(qū)鏡像?前1K?及?后16K?的數(shù)據(jù)?(Android?FDE的相關(guān)加密密鑰默認(rèn)存儲(chǔ)在分區(qū)尾部的16?KBytes中,前4K是EXT4文件系統(tǒng)的Superblock,一般EXT4?FS?SuperBlock前1K均為0),暴力枚舉用戶(hù)密碼,并采用vold中相同的磁盤(pán)加密算法來(lái)生成解密密鑰,嘗試用其對(duì)前1K中的部分?jǐn)?shù)據(jù)進(jìn)行AES算法解密,解出來(lái)都為0則碰撞OK。默認(rèn)Android原生的用戶(hù)密碼6位數(shù)字密碼,即使很普通的PC?3、5個(gè)小時(shí)都能跑出來(lái)。
從5.0開(kāi)始,增加了硬件TEE(Trusted?Execution?Environment)中的簽名過(guò)程,結(jié)合多次scrypt算法來(lái)產(chǎn)生加密密鑰,以此密鑰來(lái)加密?磁盤(pán)加密主密鑰,使得離線暴力破解幾乎無(wú)可能,除非破解者獲得了TEE中的RSA私鑰,并清楚特定硬件平臺(tái)HAL中的keymaster模塊實(shí)現(xiàn)。
5.0中的加密?磁盤(pán)加密密鑰?的實(shí)現(xiàn)邏輯:
1.?產(chǎn)生隨機(jī)16?Bytes?DEK(disk?encryption?key--磁盤(pán)加密用的密鑰)及16?Bytes?SALT;
2.?對(duì)(用戶(hù)密碼+SALT)使用scrypt算法產(chǎn)生32?Bytes?HASH?作為IK1(intermediate?key?1);
3.?將IK1填充到硬件產(chǎn)生的私鑰規(guī)格大小(目前看到是RSA算法,256Bytes),?具體是:?
00?||?IK1?||?00..00??##?one?zero?byte,?32?IK1?bytes,?223?zero?bytes.
4.?使用硬件私鑰?HBK?對(duì)?IK1?進(jìn)行簽名,生成256?Bytes簽名數(shù)據(jù)作為IK2;
5.?對(duì)(IK2+SALT)使用scrypt算法(與第二步中的SALT相同)產(chǎn)生出32?Bytes?HASH?作為IK3;
6.?使用IK3前16?Bytes作為KEK(用來(lái)加密主密鑰DEK的KEY),后16?Bytes作為算法IV(初始化向量);
7.?使用AES_CBC算法,采用KEK作為密鑰,IV作為初始化向量來(lái)加密用戶(hù)的主密鑰DEK,生成加密后的主密鑰,存入分區(qū)尾部數(shù)據(jù)結(jié)構(gòu)中;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>?4.4之前的分區(qū)尾部?磁盤(pán)加密相關(guān)的存儲(chǔ)結(jié)構(gòu),默認(rèn)采用pbkdf2來(lái)做密鑰導(dǎo)出算法
struct?crypt_mnt_ftr?{
??__le32?magic;????/*?See?above?*/
??__le16?major_version;
??__le16?minor_version;
??__le32?ftr_size;???/*?in?bytes,?not?including?key?following?*/
??__le32?flags;????/*?See?above?*/
??__le32?keysize;??/*?in?bytes?*/
??__le32?spare1;??/*?ignored?*/
??__le64?fs_size;??/*?Size?of?the?encrypted?fs,?in?512?byte?sectors?*/
??__le32?failed_decrypt_count;?/*?count?of?#?of?failed?attempts?to?decrypt?and
??????????mount,?set?to?0?on?successful?mount?*/
??unsigned?char?crypto_type_name[MAX_CRYPTO_TYPE_NAME_LEN];?/*?The?type?of?encryption
?????????????????????needed?to?decrypt?this
?????????????????????partition,?null?terminated?*/
};
>?4.4中的分區(qū)尾部?磁盤(pán)加密相關(guān)的存儲(chǔ)結(jié)構(gòu),可選擇使用scrypt及pbkdf2,默認(rèn)為scrypt
struct?crypt_mnt_ftr?{
??__le32?magic;????/*?See?above?*/
??__le16?major_version;
??__le16?minor_version;
??__le32?ftr_size;???/*?in?bytes,?not?including?key?following?*/
??__le32?flags;????/*?See?above?*/
??__le32?keysize;??/*?in?bytes?*/
??__le32?spare1;??/*?ignored?*/
??__le64?fs_size;??/*?Size?of?the?encrypted?fs,?in?512?byte?sectors?*/
??__le32?failed_decrypt_count;?/*?count?of?#?of?failed?attempts?to?decrypt?and
??????????mount,?set?to?0?on?successful?mount?*/
??unsigned?char?crypto_type_name[MAX_CRYPTO_TYPE_NAME_LEN];?/*?The?type?of?encryption
?????????????????????needed?to?decrypt?this
?????????????????????partition,?null?terminated?*/
??__le32?spare2;????????/*?ignored?*/
??unsigned?char?master_key[MAX_KEY_LEN];?/*?The?encrypted?key?for?decrypting?the?filesystem?*/
??unsigned?char?salt[SALT_LEN];???/*?The?salt?used?for?this?encryption?*/
??__le64?persist_data_offset[2];??/*?Absolute?offset?to?both?copies?of?crypt_persist_data
???????????????????????????????????*?on?device?with?that?info,?either?the?footer?of?the
???????????????????????????????????*?real_blkdevice?or?the?metadata?partition.?*/
??__le32?persist_data_size;???????/*?The?number?of?bytes?allocated?to?each?copy?of?the
???????????????????????????????????*?persistent?data?table*/
??__le8??kdf_type;?/*?The?key?derivation?function?used.?*/
??/*?scrypt?parameters.?See?www.tarsnap.com/scrypt/scrypt.pdf?*/
??__le8??N_factor;?/*?(1?<<?N)?*/
??__le8??r_factor;?/*?(1?<<?r)?*/
??__le8??p_factor;?/*?(1?<<?p)?*/
};
>?5.0中默認(rèn)采用基于TEE簽名外加多輪scrypt算法來(lái)導(dǎo)出加密密鑰
struct?crypt_mnt_ftr?{
??__le32?magic;?????????/*?See?above?*/
??__le16?major_version;
??__le16?minor_version;
??__le32?ftr_size;??????/*?in?bytes,?not?including?key?following?*/
??__le32?flags;?????????/*?See?above?*/
??__le32?keysize;???????/*?in?bytes?*/
??__le32?crypt_type;????/*?how?master_key?is?encrypted.?Must?be?a
?????????????????????????*?CRYPT_TYPE_XXX?value?*/
??__le64?fs_size;??/*?Size?of?the?encrypted?fs,?in?512?byte?sectors?*/
??__le32?failed_decrypt_count;?/*?count?of?#?of?failed?attempts?to?decrypt?and
??????????????????????????????????mount,?set?to?0?on?successful?mount?*/
??unsigned?char?crypto_type_name[MAX_CRYPTO_TYPE_NAME_LEN];?/*?The?type?of?encryption
???????????????????????????????????????????????????????????????needed?to?decrypt?this
???????????????????????????????????????????????????????????????partition,?null?terminated?*/
??__le32?spare2;????????/*?ignored?*/
??unsigned?char?master_key[MAX_KEY_LEN];?/*?The?encrypted?key?for?decrypting?the?filesystem?*/
??unsigned?char?salt[SALT_LEN];???/*?The?salt?used?for?this?encryption?*/
??__le64?persist_data_offset[2];??/*?Absolute?offset?to?both?copies?of?crypt_persist_data
???????????????????????????????????*?on?device?with?that?info,?either?the?footer?of?the
???????????????????????????????????*?real_blkdevice?or?the?metadata?partition.?*/
??__le32?persist_data_size;???????/*?The?number?of?bytes?allocated?to?each?copy?of?the
???????????????????????????????????*?persistent?data?table*/
??__le8??kdf_type;?/*?The?key?derivation?function?used.?*/
??/*?scrypt?parameters.?See?www.tarsnap.com/scrypt/scrypt.pdf?*/
??__le8??N_factor;?/*?(1?<<?N)?*/
??__le8??r_factor;?/*?(1?<<?r)?*/
??__le8??p_factor;?/*?(1?<<?p)?*/
??__le64?encrypted_upto;?/*?If?we?are?in?state?CRYPT_ENCRYPTION_IN_PROGRESS?and
????????????????????????????we?have?to?stop?(e.g.?power?low)?this?is?the?last
????????????????????????????encrypted?512?byte?sector.*/
??__le8??hash_first_block[SHA256_DIGEST_LENGTH];?/*?When?CRYPT_ENCRYPTION_IN_PROGRESS
????????????????????????????????????????????????????set,?hash?of?first?block,?used
????????????????????????????????????????????????????to?validate?before?continuing*/
??/*?key_master?key,?used?to?sign?the?derived?key?which?is?then?used?to?generate
???*?the?intermediate?key
???*?This?key?should?be?used?for?no?other?purposes!?We?use?this?key?to?sign?unpadded?
???*?data,?which?is?acceptable?but?only?if?the?key?is?not?reused?elsewhere.?*/
??__le8?keymaster_blob[KEYMASTER_BLOB_SIZE];
??__le32?keymaster_blob_size;
??/*?Store?scrypt?of?salted?intermediate?key.?When?decryption?fails,?we?can
?????check?if?this?matches,?and?if?it?does,?we?know?that?the?problem?is?with?the
?????drive,?and?there?is?no?point?in?asking?the?user?for?more?passwords.
?????Note?that?if?any?part?of?this?structure?is?corrupt,?this?will?not?match?and
?????we?will?continue?to?believe?the?user?entered?the?wrong?password.?In?that
?????case?the?only?solution?is?for?the?user?to?enter?a?password?enough?times?to
?????force?a?wipe.
?????Note?also?that?there?is?no?need?to?worry?about?migration.?If?this?data?is
?????wrong,?we?simply?won't?recognise?a?right?password,?and?will?continue?to
?????prompt.?On?the?first?password?change,?this?value?will?be?populated?and
?????then?we?will?be?OK.
???*/
??unsigned?char?scrypted_intermediate_key[SCRYPT_LEN];
};
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
幾種密鑰導(dǎo)出算法
static?int?pbkdf2(const?char?*passwd,?const?unsigned?char?*salt,
??????????????????unsigned?char?*ikey,?void?*params?UNUSED)
{
????SLOGI("Using?pbkdf2?for?cryptfs?KDF");
????/*?Turn?the?password?into?a?key?and?IV?that?can?decrypt?the?master?key?*/
????unsigned?int?keysize;
????char*?master_key?=?(char*)convert_hex_ascii_to_key(passwd,?&keysize);
????if?(!master_key)?return?-1;
???? //?2000輪,顯然強(qiáng)度很低,所以4.4以后改成scrypt這種強(qiáng)度適中的算法
????PKCS5_PBKDF2_HMAC_SHA1(master_key,?keysize,?salt,?SALT_LEN,
??????????????????????????? /*2000*/ HASH_COUNT,? /*16+16*/ KEY_LEN_BYTES+IV_LEN_BYTES,?ikey);
????memset(master_key,?0,?keysize);
????free?(master_key);
????return?0;
}
----------------------------------------------------
static?int?scrypt(const?char?*passwd,?const?unsigned?char?*salt,
??????????????????unsigned?char?*ikey,?void?*params)
{
????SLOGI("Using?scrypt?for?cryptfs?KDF");
????struct?crypt_mnt_ftr?*ftr?=?(struct?crypt_mnt_ftr?*)?params;
????
????int?N?=?1?<<?ftr->N_factor;? //?15
????int?r?=?1?<<?ftr->r_factor; ?//?3
????int?p?=?1?<<?ftr->p_factor;? //?1
????/*?Turn?the?password?into?a?key?and?IV?that?can?decrypt?the?master?key?*/
????unsigned?int?keysize;
????unsigned?char*?master_key?=?convert_hex_ascii_to_key(passwd,?&keysize);
????if?(!master_key)?return?-1;
????crypto_scrypt(master_key,?keysize,?salt,?SALT_LEN,?N,?r,?p,?ikey,
????????????KEY_LEN_BYTES?+?IV_LEN_BYTES);
????memset(master_key,?0,?keysize);
????free?(master_key);
????return?0;
}
----------------------------------------------------
static?int?scrypt_keymaster(const?char?*passwd,?const?unsigned?char?*salt,
????????????????????????????unsigned?char?*ikey,?void?*params)
{
????SLOGI("Using?scrypt?with?keymaster?for?cryptfs?KDF");
????int?rc;
????unsigned?int?key_size;
????size_t?signature_size;
????unsigned?char*?signature;
????struct?crypt_mnt_ftr?*ftr?=?(struct?crypt_mnt_ftr?*)?params;
????int?N?=?1?<<?ftr->N_factor;
????int?r?=?1?<<?ftr->r_factor;
????int?p?=?1?<<?ftr->p_factor;
????unsigned?char*?master_key?=?convert_hex_ascii_to_key(passwd,?&key_size);
????if?(!master_key)?{
????????SLOGE("Failed?to?convert?passwd?from?hex");
????????return?-1;
????}
???? //?第一輪scrypt,生成IK1
????rc?=?crypto_scrypt(master_key,?key_size,?salt,?SALT_LEN,
???????????????????????N,?r,?p,?ikey,?KEY_LEN_BYTES?+?IV_LEN_BYTES);
????memset(master_key,?0,?key_size);
????free(master_key);
????if?(rc)?{
????????SLOGE("scrypt?failed");
????????return?-1;
????}
???? //?TEE中初始化RSA密鑰對(duì),最終在TEE中對(duì)IK1進(jìn)行簽名,并返回簽名結(jié)果作為IK2
????if?(keymaster_sign_object(ftr,?ikey,?KEY_LEN_BYTES?+?IV_LEN_BYTES,
??????????????????????????????&signature,?&signature_size))?{
????????SLOGE("Signing?failed");
????????return?-1;
????}
???? //?對(duì)IK2結(jié)合salt再進(jìn)行一輪scrypt,產(chǎn)生最終的AES_CBC使用的ikey(16B?KEK?+?16B?IV)
????rc?=?crypto_scrypt(signature,?signature_size,?salt,?SALT_LEN,
???????????????????????N,?r,?p,?ikey,?KEY_LEN_BYTES?+?IV_LEN_BYTES);
????free(signature);
????if?(rc)?{
????????SLOGE("scrypt?failed");
????????return?-1;
????}
????return?0;
}
/*?Create?a?new?keymaster?key?and?store?it?in?this?footer?*/
static?int?keymaster_create_key(struct?crypt_mnt_ftr?*ftr)
{
????uint8_t*?key?=?0;
????keymaster_device_t?*keymaster_dev?=?0;
????if?(keymaster_init(&keymaster_dev))?{
????????SLOGE("Failed?to?init?keymaster");
????????return?-1;
????}
????int?rc?=?0;
????keymaster_rsa_keygen_params_t?params;
????memset(¶ms,?'\0',?sizeof(params));
????params.public_exponent?=?RSA_EXPONENT;
????params.modulus_size?=?RSA_KEY_SIZE;
????size_t?key_size;
??? ?//?調(diào)用HAL中的加密模塊,產(chǎn)生RSA密鑰對(duì)
????//?其中的私鑰一般是加密返回的,具體keymaster_blob數(shù)據(jù)結(jié)構(gòu)和算法不同硬件平臺(tái)廠家實(shí)現(xiàn)不一樣
????if?(keymaster_dev->generate_keypair(keymaster_dev,?TYPE_RSA,?¶ms,
????????????????????????????????????????&key,?&key_size))?{
????????SLOGE("Failed?to?generate?keypair");
????????rc?=?-1;
????????goto?out;
????}
????if?(key_size?>?KEYMASTER_BLOB_SIZE)?{
????????SLOGE("Keymaster?key?too?large?for?crypto?footer");
????????rc?=?-1;
????????goto?out;
????}
????memcpy(ftr->keymaster_blob,?key,?key_size);
????ftr->keymaster_blob_size?=?key_size;
out:
????keymaster_close(keymaster_dev);
????free(key);
????return?rc;
}
static?int?encrypt_master_key(const?char?*passwd,?const?unsigned?char?*salt,
??????????????????????????????const?unsigned?char?*decrypted_master_key,
??????????????????????????????unsigned?char?*encrypted_master_key,
??????????????????????????????struct?crypt_mnt_ftr?*crypt_ftr)
{
????unsigned?char?ikey[32+32]?=?{?0?};?/*?Big?enough?to?hold?a?256?bit?key?and?256?bit?IV?*/
????EVP_CIPHER_CTX?e_ctx;
????int?encrypted_len,?final_len;
????int?rc?=?0;
????/*?Turn?the?password?into?an?intermediate?key?and?IV?that?can?decrypt?the?master?key?*/
????get_device_scrypt_params(crypt_ftr);
????switch?(crypt_ftr->kdf_type)?{
????case?KDF_SCRYPT_KEYMASTER_UNPADDED:
????case?KDF_SCRYPT_KEYMASTER_BADLY_PADDED:
????case?KDF_SCRYPT_KEYMASTER:
???????? //?加載并初始化HAL?keymaster模塊,調(diào)用TEE接口得到RSA的公私鑰對(duì)keymaster_blob
????????if?(keymaster_create_key(crypt_ftr))?{
????????????SLOGE("keymaster_create_key?failed");
????????????return?-1;
????????}
????????//?產(chǎn)生加密密鑰KEK
????????if?(scrypt_keymaster(passwd,?salt,?ikey,?crypt_ftr))?{
????????????SLOGE("scrypt?failed");
????????????return?-1;
????????}
????????break;
????case?KDF_SCRYPT:
????????if?(scrypt(passwd,?salt,?ikey,?crypt_ftr))?{
????????????SLOGE("scrypt?failed");
????????????return?-1;
????????}
????????break;
????default:
????????SLOGE("Invalid?kdf_type");
????????return?-1;
????}
???? //?使用前邊得到的KEK及IV,采用AES_CBC算法對(duì)磁盤(pán)加密密鑰master_key進(jìn)行加密
????
????/*?Initialize?the?decryption?engine?*/
????if?(!?EVP_EncryptInit(&e_ctx,?EVP_aes_128_cbc(),?ikey,?ikey+KEY_LEN_BYTES))?{
????????SLOGE("EVP_EncryptInit?failed\n");
????????return?-1;
????}
????EVP_CIPHER_CTX_set_padding(&e_ctx,?0);?/*?Turn?off?padding?as?our?data?is?block?aligned?*/
????/*?Encrypt?the?master?key?*/
????if?(!?EVP_EncryptUpdate(&e_ctx,?encrypted_master_key,?&encrypted_len,
??????????????????????????????decrypted_master_key,?KEY_LEN_BYTES))?{
????????SLOGE("EVP_EncryptUpdate?failed\n");
????????return?-1;
????}
????if?(!?EVP_EncryptFinal(&e_ctx,?encrypted_master_key?+?encrypted_len,?&final_len))?{
????????SLOGE("EVP_EncryptFinal?failed\n");
????????return?-1;
????}
????if?(encrypted_len?+?final_len?!=?KEY_LEN_BYTES)?{
????????SLOGE("EVP_Encryption?length?check?failed?with?%d,?%d?bytes\n",?encrypted_len,?final_len);
????????return?-1;
????}
????/*?Store?the?scrypt?of?the?intermediate?key,?so?we?can?validate?if?it's?a
???????password?error?or?mount?error?when?things?go?wrong.
???????Note?there's?no?need?to?check?for?errors,?since?if?this?is?incorrect,?we
???????simply?won't?wipe?userdata,?which?is?the?correct?default?behavior
????*/
????int?N?=?1?<<?crypt_ftr->N_factor;
????int?r?=?1?<<?crypt_ftr->r_factor;
????int?p?=?1?<<?crypt_ftr->p_factor;
????//?對(duì)ikey(KEK+IV)進(jìn)行一次摘要存入分區(qū)尾部的crypt_ftr數(shù)據(jù)結(jié)構(gòu)中,
????//?后續(xù)驗(yàn)證可對(duì)傳入的用戶(hù)密碼+分區(qū)尾部存儲(chǔ)的SALT?采用同樣的密鑰導(dǎo)出算法,
????//?生成加密密鑰,并做一次scrypt摘要,將摘要值與之前crypt_ftr存儲(chǔ)的進(jìn)行比較來(lái)檢驗(yàn)是否一致
????rc?=?crypto_scrypt(ikey,?KEY_LEN_BYTES,
???????????????????????crypt_ftr->salt,?sizeof(crypt_ftr->salt),?N,?r,?p,
???????????????????????crypt_ftr->scrypted_intermediate_key,
???????????????????????sizeof(crypt_ftr->scrypted_intermediate_key));
????if?(rc)?{
??????SLOGE("encrypt_master_key:?crypto_scrypt?failed");
????}
????return?0;
} 《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專(zhuān)家共同創(chuàng)作,文字、視頻、音頻交互閱讀
作 者:?netsniffer
時(shí) 間:?2015-01-27,21:15:06
鏈 接:?http://bbs.pediy.com/showthread.php?t=197289
Android?5.0中的FDE(full?disk?encryption-全磁盤(pán)加密)
在Android?5.0之前,vold中的磁盤(pán)加密功能FDE(full?disk?encryption),只是對(duì)用戶(hù)密碼及SALT采用了scrypt算法來(lái)生成加密密鑰(4.4以前使用pkdf2,強(qiáng)度更低),這些只是增加了暴力破解的難度,但風(fēng)險(xiǎn)依然很高。比如可以獲取分區(qū)鏡像?前1K?及?后16K?的數(shù)據(jù)?(Android?FDE的相關(guān)加密密鑰默認(rèn)存儲(chǔ)在分區(qū)尾部的16?KBytes中,前4K是EXT4文件系統(tǒng)的Superblock,一般EXT4?FS?SuperBlock前1K均為0),暴力枚舉用戶(hù)密碼,并采用vold中相同的磁盤(pán)加密算法來(lái)生成解密密鑰,嘗試用其對(duì)前1K中的部分?jǐn)?shù)據(jù)進(jìn)行AES算法解密,解出來(lái)都為0則碰撞OK。默認(rèn)Android原生的用戶(hù)密碼6位數(shù)字密碼,即使很普通的PC?3、5個(gè)小時(shí)都能跑出來(lái)。
從5.0開(kāi)始,增加了硬件TEE(Trusted?Execution?Environment)中的簽名過(guò)程,結(jié)合多次scrypt算法來(lái)產(chǎn)生加密密鑰,以此密鑰來(lái)加密?磁盤(pán)加密主密鑰,使得離線暴力破解幾乎無(wú)可能,除非破解者獲得了TEE中的RSA私鑰,并清楚特定硬件平臺(tái)HAL中的keymaster模塊實(shí)現(xiàn)。
5.0中的加密?磁盤(pán)加密密鑰?的實(shí)現(xiàn)邏輯:
1.?產(chǎn)生隨機(jī)16?Bytes?DEK(disk?encryption?key--磁盤(pán)加密用的密鑰)及16?Bytes?SALT;
2.?對(duì)(用戶(hù)密碼+SALT)使用scrypt算法產(chǎn)生32?Bytes?HASH?作為IK1(intermediate?key?1);
3.?將IK1填充到硬件產(chǎn)生的私鑰規(guī)格大小(目前看到是RSA算法,256Bytes),?具體是:?
00?||?IK1?||?00..00??##?one?zero?byte,?32?IK1?bytes,?223?zero?bytes.
4.?使用硬件私鑰?HBK?對(duì)?IK1?進(jìn)行簽名,生成256?Bytes簽名數(shù)據(jù)作為IK2;
5.?對(duì)(IK2+SALT)使用scrypt算法(與第二步中的SALT相同)產(chǎn)生出32?Bytes?HASH?作為IK3;
6.?使用IK3前16?Bytes作為KEK(用來(lái)加密主密鑰DEK的KEY),后16?Bytes作為算法IV(初始化向量);
7.?使用AES_CBC算法,采用KEK作為密鑰,IV作為初始化向量來(lái)加密用戶(hù)的主密鑰DEK,生成加密后的主密鑰,存入分區(qū)尾部數(shù)據(jù)結(jié)構(gòu)中;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>?4.4之前的分區(qū)尾部?磁盤(pán)加密相關(guān)的存儲(chǔ)結(jié)構(gòu),默認(rèn)采用pbkdf2來(lái)做密鑰導(dǎo)出算法
struct?crypt_mnt_ftr?{
??__le32?magic;????/*?See?above?*/
??__le16?major_version;
??__le16?minor_version;
??__le32?ftr_size;???/*?in?bytes,?not?including?key?following?*/
??__le32?flags;????/*?See?above?*/
??__le32?keysize;??/*?in?bytes?*/
??__le32?spare1;??/*?ignored?*/
??__le64?fs_size;??/*?Size?of?the?encrypted?fs,?in?512?byte?sectors?*/
??__le32?failed_decrypt_count;?/*?count?of?#?of?failed?attempts?to?decrypt?and
??????????mount,?set?to?0?on?successful?mount?*/
??unsigned?char?crypto_type_name[MAX_CRYPTO_TYPE_NAME_LEN];?/*?The?type?of?encryption
?????????????????????needed?to?decrypt?this
?????????????????????partition,?null?terminated?*/
};
>?4.4中的分區(qū)尾部?磁盤(pán)加密相關(guān)的存儲(chǔ)結(jié)構(gòu),可選擇使用scrypt及pbkdf2,默認(rèn)為scrypt
struct?crypt_mnt_ftr?{
??__le32?magic;????/*?See?above?*/
??__le16?major_version;
??__le16?minor_version;
??__le32?ftr_size;???/*?in?bytes,?not?including?key?following?*/
??__le32?flags;????/*?See?above?*/
??__le32?keysize;??/*?in?bytes?*/
??__le32?spare1;??/*?ignored?*/
??__le64?fs_size;??/*?Size?of?the?encrypted?fs,?in?512?byte?sectors?*/
??__le32?failed_decrypt_count;?/*?count?of?#?of?failed?attempts?to?decrypt?and
??????????mount,?set?to?0?on?successful?mount?*/
??unsigned?char?crypto_type_name[MAX_CRYPTO_TYPE_NAME_LEN];?/*?The?type?of?encryption
?????????????????????needed?to?decrypt?this
?????????????????????partition,?null?terminated?*/
??__le32?spare2;????????/*?ignored?*/
??unsigned?char?master_key[MAX_KEY_LEN];?/*?The?encrypted?key?for?decrypting?the?filesystem?*/
??unsigned?char?salt[SALT_LEN];???/*?The?salt?used?for?this?encryption?*/
??__le64?persist_data_offset[2];??/*?Absolute?offset?to?both?copies?of?crypt_persist_data
???????????????????????????????????*?on?device?with?that?info,?either?the?footer?of?the
???????????????????????????????????*?real_blkdevice?or?the?metadata?partition.?*/
??__le32?persist_data_size;???????/*?The?number?of?bytes?allocated?to?each?copy?of?the
???????????????????????????????????*?persistent?data?table*/
??__le8??kdf_type;?/*?The?key?derivation?function?used.?*/
??/*?scrypt?parameters.?See?www.tarsnap.com/scrypt/scrypt.pdf?*/
??__le8??N_factor;?/*?(1?<<?N)?*/
??__le8??r_factor;?/*?(1?<<?r)?*/
??__le8??p_factor;?/*?(1?<<?p)?*/
};
>?5.0中默認(rèn)采用基于TEE簽名外加多輪scrypt算法來(lái)導(dǎo)出加密密鑰
struct?crypt_mnt_ftr?{
??__le32?magic;?????????/*?See?above?*/
??__le16?major_version;
??__le16?minor_version;
??__le32?ftr_size;??????/*?in?bytes,?not?including?key?following?*/
??__le32?flags;?????????/*?See?above?*/
??__le32?keysize;???????/*?in?bytes?*/
??__le32?crypt_type;????/*?how?master_key?is?encrypted.?Must?be?a
?????????????????????????*?CRYPT_TYPE_XXX?value?*/
??__le64?fs_size;??/*?Size?of?the?encrypted?fs,?in?512?byte?sectors?*/
??__le32?failed_decrypt_count;?/*?count?of?#?of?failed?attempts?to?decrypt?and
??????????????????????????????????mount,?set?to?0?on?successful?mount?*/
??unsigned?char?crypto_type_name[MAX_CRYPTO_TYPE_NAME_LEN];?/*?The?type?of?encryption
???????????????????????????????????????????????????????????????needed?to?decrypt?this
???????????????????????????????????????????????????????????????partition,?null?terminated?*/
??__le32?spare2;????????/*?ignored?*/
??unsigned?char?master_key[MAX_KEY_LEN];?/*?The?encrypted?key?for?decrypting?the?filesystem?*/
??unsigned?char?salt[SALT_LEN];???/*?The?salt?used?for?this?encryption?*/
??__le64?persist_data_offset[2];??/*?Absolute?offset?to?both?copies?of?crypt_persist_data
???????????????????????????????????*?on?device?with?that?info,?either?the?footer?of?the
???????????????????????????????????*?real_blkdevice?or?the?metadata?partition.?*/
??__le32?persist_data_size;???????/*?The?number?of?bytes?allocated?to?each?copy?of?the
???????????????????????????????????*?persistent?data?table*/
??__le8??kdf_type;?/*?The?key?derivation?function?used.?*/
??/*?scrypt?parameters.?See?www.tarsnap.com/scrypt/scrypt.pdf?*/
??__le8??N_factor;?/*?(1?<<?N)?*/
??__le8??r_factor;?/*?(1?<<?r)?*/
??__le8??p_factor;?/*?(1?<<?p)?*/
??__le64?encrypted_upto;?/*?If?we?are?in?state?CRYPT_ENCRYPTION_IN_PROGRESS?and
????????????????????????????we?have?to?stop?(e.g.?power?low)?this?is?the?last
????????????????????????????encrypted?512?byte?sector.*/
??__le8??hash_first_block[SHA256_DIGEST_LENGTH];?/*?When?CRYPT_ENCRYPTION_IN_PROGRESS
????????????????????????????????????????????????????set,?hash?of?first?block,?used
????????????????????????????????????????????????????to?validate?before?continuing*/
??/*?key_master?key,?used?to?sign?the?derived?key?which?is?then?used?to?generate
???*?the?intermediate?key
???*?This?key?should?be?used?for?no?other?purposes!?We?use?this?key?to?sign?unpadded?
???*?data,?which?is?acceptable?but?only?if?the?key?is?not?reused?elsewhere.?*/
??__le8?keymaster_blob[KEYMASTER_BLOB_SIZE];
??__le32?keymaster_blob_size;
??/*?Store?scrypt?of?salted?intermediate?key.?When?decryption?fails,?we?can
?????check?if?this?matches,?and?if?it?does,?we?know?that?the?problem?is?with?the
?????drive,?and?there?is?no?point?in?asking?the?user?for?more?passwords.
?????Note?that?if?any?part?of?this?structure?is?corrupt,?this?will?not?match?and
?????we?will?continue?to?believe?the?user?entered?the?wrong?password.?In?that
?????case?the?only?solution?is?for?the?user?to?enter?a?password?enough?times?to
?????force?a?wipe.
?????Note?also?that?there?is?no?need?to?worry?about?migration.?If?this?data?is
?????wrong,?we?simply?won't?recognise?a?right?password,?and?will?continue?to
?????prompt.?On?the?first?password?change,?this?value?will?be?populated?and
?????then?we?will?be?OK.
???*/
??unsigned?char?scrypted_intermediate_key[SCRYPT_LEN];
};
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
幾種密鑰導(dǎo)出算法
static?int?pbkdf2(const?char?*passwd,?const?unsigned?char?*salt,
??????????????????unsigned?char?*ikey,?void?*params?UNUSED)
{
????SLOGI("Using?pbkdf2?for?cryptfs?KDF");
????/*?Turn?the?password?into?a?key?and?IV?that?can?decrypt?the?master?key?*/
????unsigned?int?keysize;
????char*?master_key?=?(char*)convert_hex_ascii_to_key(passwd,?&keysize);
????if?(!master_key)?return?-1;
???? //?2000輪,顯然強(qiáng)度很低,所以4.4以后改成scrypt這種強(qiáng)度適中的算法
????PKCS5_PBKDF2_HMAC_SHA1(master_key,?keysize,?salt,?SALT_LEN,
??????????????????????????? /*2000*/ HASH_COUNT,? /*16+16*/ KEY_LEN_BYTES+IV_LEN_BYTES,?ikey);
????memset(master_key,?0,?keysize);
????free?(master_key);
????return?0;
}
----------------------------------------------------
static?int?scrypt(const?char?*passwd,?const?unsigned?char?*salt,
??????????????????unsigned?char?*ikey,?void?*params)
{
????SLOGI("Using?scrypt?for?cryptfs?KDF");
????struct?crypt_mnt_ftr?*ftr?=?(struct?crypt_mnt_ftr?*)?params;
????
????int?N?=?1?<<?ftr->N_factor;? //?15
????int?r?=?1?<<?ftr->r_factor; ?//?3
????int?p?=?1?<<?ftr->p_factor;? //?1
????/*?Turn?the?password?into?a?key?and?IV?that?can?decrypt?the?master?key?*/
????unsigned?int?keysize;
????unsigned?char*?master_key?=?convert_hex_ascii_to_key(passwd,?&keysize);
????if?(!master_key)?return?-1;
????crypto_scrypt(master_key,?keysize,?salt,?SALT_LEN,?N,?r,?p,?ikey,
????????????KEY_LEN_BYTES?+?IV_LEN_BYTES);
????memset(master_key,?0,?keysize);
????free?(master_key);
????return?0;
}
----------------------------------------------------
static?int?scrypt_keymaster(const?char?*passwd,?const?unsigned?char?*salt,
????????????????????????????unsigned?char?*ikey,?void?*params)
{
????SLOGI("Using?scrypt?with?keymaster?for?cryptfs?KDF");
????int?rc;
????unsigned?int?key_size;
????size_t?signature_size;
????unsigned?char*?signature;
????struct?crypt_mnt_ftr?*ftr?=?(struct?crypt_mnt_ftr?*)?params;
????int?N?=?1?<<?ftr->N_factor;
????int?r?=?1?<<?ftr->r_factor;
????int?p?=?1?<<?ftr->p_factor;
????unsigned?char*?master_key?=?convert_hex_ascii_to_key(passwd,?&key_size);
????if?(!master_key)?{
????????SLOGE("Failed?to?convert?passwd?from?hex");
????????return?-1;
????}
???? //?第一輪scrypt,生成IK1
????rc?=?crypto_scrypt(master_key,?key_size,?salt,?SALT_LEN,
???????????????????????N,?r,?p,?ikey,?KEY_LEN_BYTES?+?IV_LEN_BYTES);
????memset(master_key,?0,?key_size);
????free(master_key);
????if?(rc)?{
????????SLOGE("scrypt?failed");
????????return?-1;
????}
???? //?TEE中初始化RSA密鑰對(duì),最終在TEE中對(duì)IK1進(jìn)行簽名,并返回簽名結(jié)果作為IK2
????if?(keymaster_sign_object(ftr,?ikey,?KEY_LEN_BYTES?+?IV_LEN_BYTES,
??????????????????????????????&signature,?&signature_size))?{
????????SLOGE("Signing?failed");
????????return?-1;
????}
???? //?對(duì)IK2結(jié)合salt再進(jìn)行一輪scrypt,產(chǎn)生最終的AES_CBC使用的ikey(16B?KEK?+?16B?IV)
????rc?=?crypto_scrypt(signature,?signature_size,?salt,?SALT_LEN,
???????????????????????N,?r,?p,?ikey,?KEY_LEN_BYTES?+?IV_LEN_BYTES);
????free(signature);
????if?(rc)?{
????????SLOGE("scrypt?failed");
????????return?-1;
????}
????return?0;
}
/*?Create?a?new?keymaster?key?and?store?it?in?this?footer?*/
static?int?keymaster_create_key(struct?crypt_mnt_ftr?*ftr)
{
????uint8_t*?key?=?0;
????keymaster_device_t?*keymaster_dev?=?0;
????if?(keymaster_init(&keymaster_dev))?{
????????SLOGE("Failed?to?init?keymaster");
????????return?-1;
????}
????int?rc?=?0;
????keymaster_rsa_keygen_params_t?params;
????memset(¶ms,?'\0',?sizeof(params));
????params.public_exponent?=?RSA_EXPONENT;
????params.modulus_size?=?RSA_KEY_SIZE;
????size_t?key_size;
??? ?//?調(diào)用HAL中的加密模塊,產(chǎn)生RSA密鑰對(duì)
????//?其中的私鑰一般是加密返回的,具體keymaster_blob數(shù)據(jù)結(jié)構(gòu)和算法不同硬件平臺(tái)廠家實(shí)現(xiàn)不一樣
????if?(keymaster_dev->generate_keypair(keymaster_dev,?TYPE_RSA,?¶ms,
????????????????????????????????????????&key,?&key_size))?{
????????SLOGE("Failed?to?generate?keypair");
????????rc?=?-1;
????????goto?out;
????}
????if?(key_size?>?KEYMASTER_BLOB_SIZE)?{
????????SLOGE("Keymaster?key?too?large?for?crypto?footer");
????????rc?=?-1;
????????goto?out;
????}
????memcpy(ftr->keymaster_blob,?key,?key_size);
????ftr->keymaster_blob_size?=?key_size;
out:
????keymaster_close(keymaster_dev);
????free(key);
????return?rc;
}
static?int?encrypt_master_key(const?char?*passwd,?const?unsigned?char?*salt,
??????????????????????????????const?unsigned?char?*decrypted_master_key,
??????????????????????????????unsigned?char?*encrypted_master_key,
??????????????????????????????struct?crypt_mnt_ftr?*crypt_ftr)
{
????unsigned?char?ikey[32+32]?=?{?0?};?/*?Big?enough?to?hold?a?256?bit?key?and?256?bit?IV?*/
????EVP_CIPHER_CTX?e_ctx;
????int?encrypted_len,?final_len;
????int?rc?=?0;
????/*?Turn?the?password?into?an?intermediate?key?and?IV?that?can?decrypt?the?master?key?*/
????get_device_scrypt_params(crypt_ftr);
????switch?(crypt_ftr->kdf_type)?{
????case?KDF_SCRYPT_KEYMASTER_UNPADDED:
????case?KDF_SCRYPT_KEYMASTER_BADLY_PADDED:
????case?KDF_SCRYPT_KEYMASTER:
???????? //?加載并初始化HAL?keymaster模塊,調(diào)用TEE接口得到RSA的公私鑰對(duì)keymaster_blob
????????if?(keymaster_create_key(crypt_ftr))?{
????????????SLOGE("keymaster_create_key?failed");
????????????return?-1;
????????}
????????//?產(chǎn)生加密密鑰KEK
????????if?(scrypt_keymaster(passwd,?salt,?ikey,?crypt_ftr))?{
????????????SLOGE("scrypt?failed");
????????????return?-1;
????????}
????????break;
????case?KDF_SCRYPT:
????????if?(scrypt(passwd,?salt,?ikey,?crypt_ftr))?{
????????????SLOGE("scrypt?failed");
????????????return?-1;
????????}
????????break;
????default:
????????SLOGE("Invalid?kdf_type");
????????return?-1;
????}
???? //?使用前邊得到的KEK及IV,采用AES_CBC算法對(duì)磁盤(pán)加密密鑰master_key進(jìn)行加密
????
????/*?Initialize?the?decryption?engine?*/
????if?(!?EVP_EncryptInit(&e_ctx,?EVP_aes_128_cbc(),?ikey,?ikey+KEY_LEN_BYTES))?{
????????SLOGE("EVP_EncryptInit?failed\n");
????????return?-1;
????}
????EVP_CIPHER_CTX_set_padding(&e_ctx,?0);?/*?Turn?off?padding?as?our?data?is?block?aligned?*/
????/*?Encrypt?the?master?key?*/
????if?(!?EVP_EncryptUpdate(&e_ctx,?encrypted_master_key,?&encrypted_len,
??????????????????????????????decrypted_master_key,?KEY_LEN_BYTES))?{
????????SLOGE("EVP_EncryptUpdate?failed\n");
????????return?-1;
????}
????if?(!?EVP_EncryptFinal(&e_ctx,?encrypted_master_key?+?encrypted_len,?&final_len))?{
????????SLOGE("EVP_EncryptFinal?failed\n");
????????return?-1;
????}
????if?(encrypted_len?+?final_len?!=?KEY_LEN_BYTES)?{
????????SLOGE("EVP_Encryption?length?check?failed?with?%d,?%d?bytes\n",?encrypted_len,?final_len);
????????return?-1;
????}
????/*?Store?the?scrypt?of?the?intermediate?key,?so?we?can?validate?if?it's?a
???????password?error?or?mount?error?when?things?go?wrong.
???????Note?there's?no?need?to?check?for?errors,?since?if?this?is?incorrect,?we
???????simply?won't?wipe?userdata,?which?is?the?correct?default?behavior
????*/
????int?N?=?1?<<?crypt_ftr->N_factor;
????int?r?=?1?<<?crypt_ftr->r_factor;
????int?p?=?1?<<?crypt_ftr->p_factor;
????//?對(duì)ikey(KEK+IV)進(jìn)行一次摘要存入分區(qū)尾部的crypt_ftr數(shù)據(jù)結(jié)構(gòu)中,
????//?后續(xù)驗(yàn)證可對(duì)傳入的用戶(hù)密碼+分區(qū)尾部存儲(chǔ)的SALT?采用同樣的密鑰導(dǎo)出算法,
????//?生成加密密鑰,并做一次scrypt摘要,將摘要值與之前crypt_ftr存儲(chǔ)的進(jìn)行比較來(lái)檢驗(yàn)是否一致
????rc?=?crypto_scrypt(ikey,?KEY_LEN_BYTES,
???????????????????????crypt_ftr->salt,?sizeof(crypt_ftr->salt),?N,?r,?p,
???????????????????????crypt_ftr->scrypted_intermediate_key,
???????????????????????sizeof(crypt_ftr->scrypted_intermediate_key));
????if?(rc)?{
??????SLOGE("encrypt_master_key:?crypto_scrypt?failed");
????}
????return?0;
} 《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專(zhuān)家共同創(chuàng)作,文字、視頻、音頻交互閱讀
總結(jié)
以上是生活随笔為你收集整理的Android 5.0中的FDE功能实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: ASP.NET运行环境配置
- 下一篇: android开发关于和使用本机内存,内