国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Android 應(yīng)用安全開(kāi)發(fā)之淺談加密算法的坑

不知名網(wǎng)友 / 3409人閱讀

摘要:還有很多開(kāi)發(fā)者沒(méi)有意識(shí)到的加密算法的問(wèn)題。不要使用哈希函數(shù)做為對(duì)稱加密算法的簽名。開(kāi)發(fā)者建議使用基于口令的加密算法時(shí),生成密鑰時(shí)要加鹽,鹽的取值最好來(lái)自,并指定迭代次數(shù)。不要使用沒(méi)有消息認(rèn)證的加密算法加密消息,無(wú)法防重放。

本文作者:阿里移動(dòng)安全@伊樵,@舟海

Android開(kāi)發(fā)中,難免會(huì)遇到需要加解密一些數(shù)據(jù)內(nèi)容存到本地文件、或者通過(guò)網(wǎng)絡(luò)傳輸?shù)狡渌?wù)器和設(shè)備的問(wèn)題,但并不是使用了加密就絕對(duì)安全了,如果加密函數(shù)使用不正確,加密數(shù)據(jù)很容易受到逆向破解攻擊。還有很多開(kāi)發(fā)者沒(méi)有意識(shí)到的加密算法的問(wèn)題。

1. 需要了解的基本概念

密碼學(xué)的三大作用:加密( Encryption)、認(rèn)證(Authentication),鑒定(Identification)

加密:防止壞人獲取你的數(shù)據(jù)。

認(rèn)證:防止壞人修改了你的數(shù)據(jù)而你卻并沒(méi)有發(fā)現(xiàn)。

鑒權(quán):防止壞人假冒你的身份。

明文、密文、密鑰、對(duì)稱加密算法、非對(duì)稱加密算法,這些基本概念和加密算法原理就不展開(kāi)敘述了。

2. Android SDK提供的API 2.1 Android 加密相關(guān)API結(jié)構(gòu)

Android SDK使用的API和JAVA提供的基本相似,由 Java Cryptography Architecture (JCA,java加密體系結(jié)構(gòu)) ,Java Cryptography Extension (JCE,Java加密擴(kuò)展包) ,Java Secure Sockets Extension(JSSE,Java安全套接字?jǐn)U展包),Java Authentication and Authentication Service(JAAS,Java 鑒別與安全服務(wù))組成。

JCA提供基本的加密框架,如證書、數(shù)字簽名、消息摘要和密鑰對(duì)產(chǎn)生器,對(duì)應(yīng)的Android API中的以下幾個(gè)包:

java.security 
java.security.acl
java.security.cert
java.security.interfaces
java.security.spec

JCE擴(kuò)展了JCA,提供了各種加密算法、摘要算法、密鑰管理等功能,對(duì)應(yīng)的Android API中的以下幾個(gè)包:

javax.crypto 
javax.crypto.interfaces 
javax.crypto.spec

JSSE提供了SSL(基于安全套接層)的加密功能,使用HTTPS加密傳輸使用,對(duì)應(yīng)的Android API主要是java.net.ssl包中。

JAAS 提供了在Java平臺(tái)上進(jìn)行用戶身份鑒別的功能。對(duì)應(yīng)的Android API主要在以下幾個(gè)包:

javax.security.auth 
javax.security.auth.login 
javax.security.auth.callback 
javax.security.auth.x500

它們其實(shí)只是一組接口,實(shí)際的算法是可由不同的Provider提供,Android API默認(rèn)的Provider主要是是Bouncy Castle和OpenSSL。

此外Android API還提供了android.security和android.security.keystore(API 23新增)來(lái)管理keychain和keystore。

2.2 Base64編碼算法

Base64編碼算法是一種用64個(gè)字符(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/)來(lái)表示任意二進(jìn)制數(shù)據(jù)的方法。在計(jì)算機(jī)網(wǎng)絡(luò)發(fā)展的早期,由于“歷史原因”,電子郵件不支持非ASCII碼字符,如果要傳送的電子郵件帶有非ASCII碼字符(諸如中文)或者圖片,用戶收到的電子郵件將會(huì)是一堆亂碼,因此發(fā)明了Base64編碼算法。至于為何會(huì)亂碼?請(qǐng)大家自行Google。在加解密算法中,原始的數(shù)據(jù)和加密后的數(shù)據(jù)一般也是二進(jìn)制數(shù)據(jù),為了不傳輸出錯(cuò),方便保存或者調(diào)試代碼,一般需要對(duì)加密后的數(shù)據(jù)進(jìn)行base64編碼。

Android提供了Base64編碼的工具類android.util.Base64,可以直接使用,不用自己去實(shí)現(xiàn)base64編碼的算法了。 如:

byte[] output = sha.digest();
String result = Base64.encodeToString(output, Base64.DEFAULT);

開(kāi)發(fā)者建議:base64只是一種編碼方式,并不是一種加密算法,不要使用base64來(lái)加密數(shù)據(jù)。

2.3 隨機(jī)數(shù)生成器

在Android加密算法中需要隨機(jī)數(shù)時(shí)要使用SecureRandom來(lái)獲取隨機(jī)數(shù)。 如:

SecureRandom sr = new SecureRandom();
byte[] output = new byte[16];
sr.nextBytes(output);

注意不要給SecureRandom設(shè)置種子。調(diào)用seeded constructor或者setSeed(byte[])是不安全的。SecureRandom()默認(rèn)使用的是dev/urandom作為種子產(chǎn)生器,這個(gè)種子是不可預(yù)測(cè)的。

開(kāi)發(fā)者建議:

不要使用Random類來(lái)獲取隨機(jī)數(shù)。

在使用SecureRandom時(shí)候,不要設(shè)置種子。使用以下函數(shù)設(shè)置種子都是有風(fēng)險(xiǎn)的:

SecureRandom.SecureRandom(byte[] seed) 
SecureRandom.setSeed(long seed) 
SecureRandom.setSeed(byte[] seed)

2.4 Hash算法

Hash算法是指任意長(zhǎng)度的字符串輸入,此算法能給出固定n比特的字符串輸出,輸出的字符串一般稱為Hash值。

具有以下兩個(gè)特點(diǎn):

抗碰撞性:尋找兩個(gè)不同輸入得到相同的輸出值在計(jì)算上是不可行的,需要大約 的時(shí)間去尋找到具有相同輸出的兩個(gè)輸入字符串。

不可逆:不可從結(jié)果推導(dǎo)出它的初始狀態(tài)。

抗碰撞性使Hash算法對(duì)原始輸入的任意一點(diǎn)更改,都會(huì)導(dǎo)致產(chǎn)生不同的Hash值,因此Hash算法可以用來(lái)檢驗(yàn)數(shù)據(jù)的完整性。我們經(jīng)常見(jiàn)到在一些網(wǎng)站下載某個(gè)文件時(shí),網(wǎng)站還提供了此文件的hash值,以供我們下載文件后檢驗(yàn)文件是否被篡改。

不可逆的特性使Hash算法成為一種單向密碼體制,只能加密不能解密,可以用來(lái)加密用戶的登錄密碼等憑證。

開(kāi)發(fā)者建議:

建議使用SHA-256、SHA-3算法。 如使用SHA-256算法對(duì)message字符串做哈希:

...
byte[] input = message.getBytes();
MessageDigest sha = MessageDigest.getInstance("SHA-256");
sha.update(input);
byte[] output = sha.digest();
String result = Base64.encodeToString(output, Base64.DEFAULT);

不建議使用MD2、MD4、MD5、SHA-1、RIPEMD算法來(lái)加密用戶密碼等敏感信息。這一類算法已經(jīng)有很多破解辦法,例如md5算法,網(wǎng)上有很多查詢的字典庫(kù),給出md5值,可以查到加密前的數(shù)據(jù)。

MessageDigest md = MessageDigest.getInstance("MD5");
byte[] md5Bytes = md.digest(str.getBytes());
String result = Base64.encodeToString(md5Bytes, Base64.DEFAULT);

不要使用哈希函數(shù)做為對(duì)稱加密算法的簽名。

注意:當(dāng)多個(gè)字符串串接后再做hash,要非常當(dāng)心。**

如:字符串S,字符串T,串接做hash,記為 H (S||T)。但是有可能發(fā)生以下情況。

如“builtin||securely” 和 “built||insecurely”的hash值是完全一樣的。

如何修改從而避免上述問(wèn)題產(chǎn)生? 改為H(length(S) || S || T)或者 H(H(S)||H(T))或者H(H(S)||T)。

實(shí)際開(kāi)發(fā)過(guò)程中經(jīng)常會(huì)對(duì)url的各個(gè)參數(shù),做詞典排序,然后取參數(shù)名和值串接后加上某個(gè)SECRET字符串,計(jì)算出hash值,作為此URL的簽名,如foo=1, bar=2, baz=3 排序后為bar=2, baz=3, foo=1,做hash的字符串為:SECRETbar2baz3foo1,在參數(shù)和值之間沒(méi)有分隔符,則”foo=bar”和”foob=ar”的hash值是一樣的,”foo=bar&fooble=baz”和”foo=barfooblebaz”一樣,這樣通過(guò)精心構(gòu)造的惡意參數(shù)就有可能與正常參數(shù)的hash值一樣,從而騙過(guò)服務(wù)器的簽名校驗(yàn)。

2.5 消息認(rèn)證算法

要確保加密的消息不是別人偽造的,需要提供一個(gè)消息認(rèn)證碼(MAC,Message authentication code)。

消息認(rèn)證碼是帶密鑰的hash函數(shù),基于密鑰和hash函數(shù)。

密鑰雙方事先約定,不能讓第三方知道。

消息發(fā)送者使用MAC算法計(jì)算出消息的MAC值,追加到消息后面一起發(fā)送給接收者。

接收者收到消息后,用相同的MAC算法計(jì)算接收到消息MAC值,并與接收到的MAC值對(duì)比是否一樣。

開(kāi)發(fā)者建議: 建議使用HMAC-SHA256算法,避免使用CBC-MAC。

HMAC-SHA256例子如下:

//初始化KeyGenerator
KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacSHA256");
//產(chǎn)生密鑰
SecretKey secretKey = keyGenerator.generateKey();
//獲取密鑰
byte[] key = secretKey.getEncoded();
Log.d(Base64.encodeToString(key, Base64.DEFAULT));

//還原密鑰
SecretKey restoreSecretKey = new SecretKeySpec(key, "HmacSHA256");
//實(shí)例化MAC
Mac mac = Mac.getInstance(restoreSecretKey.getAlgorithm());
//初始化MAC
mac.init(restoreSecretKey);
//執(zhí)行摘要
byte[] hmacSHA256Bytes = mac.doFinal(message.getBytes());
result = Base64.encodeToString(hmacSHA256Bytes, Base64.DEFAULT);
2.6 對(duì)稱加密算法

在對(duì)稱加密算法中,數(shù)據(jù)發(fā)信方將明文(原始數(shù)據(jù))和加密密鑰一起經(jīng)過(guò)特殊加密算法處理后,使其變成復(fù)雜的加密密文發(fā)送出去。收信方收到密文后,若想解讀原文,則需要使用加密用過(guò)的密鑰及相同算法的逆算法對(duì)密文進(jìn)行解密,才能使其恢復(fù)成可讀明文。在對(duì)稱加密算法中,使用的密鑰只有一個(gè),發(fā)收信雙方都使用這個(gè)密鑰對(duì)數(shù)據(jù)進(jìn)行加密和解密,這就要求解密方事先必須知道加密密鑰。

該算法的缺點(diǎn)是,如果一旦密鑰泄漏,那么加密的內(nèi)容將都不可信了。

開(kāi)發(fā)者建議:

建議使用AES算法。

DES默認(rèn)的是56位的加密密鑰,已經(jīng)不安全,不建議使用。

注意加密模式不要使用ECB模式。ECB模式不安全,說(shuō)明問(wèn)題的經(jīng)典的三張圖片,如 明文是:

用ECB加密模式后:

用CBC加密模式后:

想更深入的了解關(guān)于對(duì)CBC加密模式的攻擊,可參看:《SSL/TLS協(xié)議安全系列:CBC 模式的弱安全性介紹(一)》http://drops.wooyun.org/tips/6619

Android 提供的AES加密算法API默認(rèn)使用的是ECB模式,所以要顯式指定加密算法為:CBC或CFB模式,可帶上PKCS5Padding填充。AES密鑰長(zhǎng)度最少是128位,推薦使用256位。

//生成KEY
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(256);
//產(chǎn)生密鑰
SecretKey secretKey = keyGenerator.generateKey();
//獲取密鑰
byte[] keyBytes = secretKey.getEncoded();
Log.d("AES KEY", Base64.encodeToString(keyBytes, 0));

//還原密鑰
SecretKey key = new SecretKeySpec(keyBytes, "AES");

//加密
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encodeResult = cipher.doFinal(plainText.getBytes());
Log.d("AES encode", Base64.encodeToString(encodeResult, Base64.DEFAULT));

2.7 非對(duì)稱加密

非對(duì)稱加密算法需要兩個(gè)密鑰:公開(kāi)密鑰(publickey)和私有密鑰(privatekey)。公開(kāi)密鑰與私有密鑰是一對(duì),如果用公開(kāi)密鑰對(duì)數(shù)據(jù)進(jìn)行加密,只有用對(duì)應(yīng)的私有密鑰才能解密;如果用私有密鑰對(duì)數(shù)據(jù)進(jìn)行加密,那么只有用對(duì)應(yīng)的公開(kāi)密鑰才能解密(這個(gè)過(guò)程可以做數(shù)字簽名)。

非對(duì)稱加密主要使用的是RSA算法。

開(kāi)發(fā)者建議:

注意密鑰長(zhǎng)度不要低于512位,建議使用2048位的密鑰長(zhǎng)度。使用RSA進(jìn)行數(shù)字簽名的算法,如:

//生成密鑰
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
RSAPublicKey rsaPublicKey = (RSAPublicKey)keyPair.getPublic();
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey)keyPair.getPrivate();

//簽名            
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(src.getBytes());
byte[] result = signature.sign();

使用RSA算法做加密,RSA加密算法應(yīng)使用Cipher.getInstance(RSA/ECB/OAEPWithSHA256AndMGF1Padding),否則會(huì)存在重放攻擊的風(fēng)險(xiǎn)。如:

KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();

//公鑰加密
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded());
KeyFactory keyFactory= KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA256AndMGF1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] result = cipher.doFinal(src.getBytes());
...
//私鑰解密
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
KeyFactory keyFactory2 = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory2.generatePrivate(pkcs8EncodedKeySpec);
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA256AndMGF1Padding");
cipher5.init(Cipher.DECRYPT_MODE, privateKey5);
byte[] result2 = cipher.doFinal(result);

2.8 加密算法PBE

PBE是一種基于口令的加密算法,其特點(diǎn)是使用口令代替了密鑰,而口令由用戶自己掌管,采用隨機(jī)數(shù)雜湊多重加密等方法保證數(shù)據(jù)的安全性。

開(kāi)發(fā)者建議:使用基于口令的加密算法PBE時(shí),生成密鑰時(shí)要加鹽,鹽的取值最好來(lái)自SecureRandom,并指定迭代次數(shù)。如:

//初始化鹽
mSalt = new byte[SALT_LENGTH_BYTES];
SecureRandom sr = new SecureRandom();
sr.nextBytes(mSalt);

SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(KEY_GENERATOR_MODE);
keySpec = new PBEKeySpec(password, salt, KEY_GEN_ITERATION_COUNT, KEY_LENGTH_BITS);
secretKey = secretKeyFactory.generateSecret(keySpec);

(以上所有示例算法僅供參考)

3. 總結(jié)

幾條原則:

不要自己設(shè)計(jì)加密算法和協(xié)議,使用業(yè)界標(biāo)準(zhǔn)的算法。

對(duì)稱加密算法不要使用ECB模式,不建議使用DES算法。

要選擇合適長(zhǎng)度的密鑰。

要確保隨機(jī)數(shù)生成器的種子具有足夠的信息熵。

不要使用沒(méi)有消息認(rèn)證的加密算法加密消息,無(wú)法防重放。

當(dāng)多個(gè)字符串拼接后做hash,要非常當(dāng)心。

當(dāng)給算法加yan鹽取值時(shí)不要太短,不要重復(fù)。

使用初始化向量時(shí)IV時(shí),IV為常量的CBC,CFB,GCM等和ECB一樣可以重放,即采用上一個(gè)消息的最后一塊密文作為下一個(gè)消息的IV,是不安全的。

密鑰應(yīng)遵循的原則

密鑰不能為常量,應(yīng)隨機(jī),定期更換,如果加密數(shù)據(jù)時(shí)使用的密鑰為常量,則相同明文加密會(huì)得到相同的密文,很難防止字典攻擊。

開(kāi)發(fā)同學(xué)要防范密鑰硬編碼的毛病。

而在實(shí)際開(kāi)發(fā)中,密鑰如何保存始終是繞不過(guò)的坎?如果硬編碼在代碼中容易被逆向,如果放在設(shè)備的某個(gè)文件,也會(huì)被有經(jīng)驗(yàn)的破解者逆向找到,在這里推薦阿里聚安全的安全組件服務(wù),其中的安全加密功能提供了開(kāi)發(fā)者密鑰的安全管理與加密算法實(shí)現(xiàn),保證密鑰的安全性,實(shí)現(xiàn)安全的加解密操作。

參考

《Java加密與解密的藝術(shù)》

《Android Application Secure Design/Secure Coding Guidebook》

http://security.stackexchange.com/questions/2202/lessons-learned-and-misconceptions-regarding-encryption-and-cryptology

http://netifera.com/research/flickr_api_signature_forgery.pdf

http://nelenkov.blogspot.com/2012/04/using-password-based-encryption-on.html*

了解更多技術(shù)干貨和最新安全年報(bào),請(qǐng)點(diǎn)擊這里

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/65635.html

相關(guān)文章

  • Android 安全開(kāi)發(fā)之 ZIP 文件目錄遍歷

    摘要:阿里聚安全的應(yīng)用漏洞掃描服務(wù),可以檢測(cè)出應(yīng)用的文件目錄遍歷風(fēng)險(xiǎn)。阿里聚安全對(duì)開(kāi)發(fā)者建議對(duì)重要的壓縮包文件進(jìn)行數(shù)字簽名校驗(yàn),校驗(yàn)通過(guò)才進(jìn)行解壓。 1、ZIP文件目錄遍歷簡(jiǎn)介 因?yàn)閆IP壓縮包文件中允許存在../的字符串,攻擊者可以利用多個(gè)../在解壓時(shí)改變ZIP包中某個(gè)文件的存放位置,覆蓋掉應(yīng)用原有的文件。如果被覆蓋掉的文件是動(dòng)態(tài)鏈接so、dex或者odex文件,輕則產(chǎn)生本地拒絕服務(wù)漏洞...

    sorra 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<