安卓常见算法
‘壹’ 安卓常见的一些加密((对称加密DES,AES),非对称加密(RSA),MD5)
DES是一种对称加密算法,所谓对称加密算法即:加密和解密使用相同密钥的算法。DES加密算法出自IBM的研究,
后来被美国政府正式采用,之后开始广泛流传,但是近些年使用越来越少,因为DES使用56位密钥,以现代计算能力,
24小时内即可被破解
调用过程
最近做微信小程序获取用户绑定的手机号信息解密,试了很多方法。最终虽然没有完全解决,但是也达到我的极限了。有时会报错:javax.crypto.BadPaddingException: pad block corrupted。
出现错误的详细描述
每次刚进入小程序登陆获取手机号时,会出现第一次解密失败,再试一次就成功的问题。如果连续登出,登入,就不会再出现揭秘失败的问题。但是如果停止操作过一会,登出后登入,又会出现第一次揭秘失败,再试一次就成功的问题。
网上说的,官方文档上注意点我都排除了。获取的加密密文是在前端调取wx.login()方法后,调用我后端的微信授权接口,获取用户的sessionkey,openId.然后才是前端调用的获取sessionkey加密的用户手机号接口,所以我可以保证每次sessionkey是最新的。不会过期。
并且我通过日志发现在sessionkey不变的情况下,第一次失败,第二次解密成功。
加密算法,RSA是绕不开的话题,因为RSA算法是目前最流行的公开密钥算法,既能用于加密,也能用户数字签名。不仅在加密货币领域使用,在传统互联网领域的应用也很广泛。从被提出到现在20多年,经历了各种考验,被普遍认为是目前最优秀的公钥方案之一
非对称加密算法的特点就是加密秘钥和解密秘钥不同,秘钥分为公钥和私钥,用私钥加密的明文,只能用公钥解密;用公钥加密的明文,只能用私钥解密。
一、 什么是“素数”?
素数是这样的整数,它除了能表示为它自己和1的乘积以外,不能表示为任何其它两个整数的乘积
二、什么是“互质数”(或“互素数”)?
小学数学教材对互质数是这样定义的:“公约数只有1的两个数,叫做互质数
(1)两个质数一定是互质数。例如,2与7、13与19。
(2)一个质数如果不能整除另一个合数,这两个数为互质数。例如,3与10、5与 26。
(3)1不是质数也不是合数,它和任何一个自然数在一起都是互质数。如1和9908。
(4)相邻的两个自然数是互质数。如 15与 16。
(5)相邻的两个奇数是互质数。如 49与 51。
(6)大数是质数的两个数是互质数。如97与88。
(7)小数是质数,大数不是小数的倍数的两个数是互质数。如 7和 16。
(8)两个数都是合数(二数差又较大),小数所有的质因数,都不是大数的约数,这两个数是互质数。如357与715,357=3×7×17,而3、7和17都不是715的约数,这两个数为互质数。等等。
三、什么是模指数运算?
指数运算谁都懂,不必说了,先说说模运算。模运算是整数运算,有一个整数m,以n为模做模运算,即m mod n。怎样做呢?让m去被n整除,只取所得的余数作为结果,就叫做模运算。例如,10 mod 3=1;26 mod 6=2;28 mod 2 =0等等。
模指数运算就是先做指数运算,取其结果再做模运算。如(5^3) mod 7 = (125 mod 7) = 6。
其中,符号^表示数学上的指数运算;mod表示模运算,即相除取余数。具体算法步骤如下:
(1)选择一对不同的、足够大的素数p,q。
(2)计算n=p q。
(3)计算f(n)=(p-1) (q-1),同时对p, q严加保密,不让任何人知道。
(4)找一个与f(n)互质的数e作为公钥指数,且1<e<f(n)。
(5)计算私钥指数d,使得d满足(d*e) mod f(n) = 1
(6)公钥KU=(e,n),私钥KR=(d,n)。
(7)加密时,先将明文变换成0至n-1的一个整数M。若明文较长,可先分割成适当的组,然后再进行交换。设密文为C,则加密过程为:C=M^e mod n。
(8)解密过程为:M=C^d mod n。
在RSA密码应用中,公钥KU是被公开的,即e和n的数值可以被第三方窃听者得到。破解RSA密码的问题就是从已知的e和n的数值(n等于pq),想法求出d的数值,这样就可以得到私钥来破解密文。从上文中的公式:(d e) mod ((p-1) (q-1)) = 1,我们可以看出,密码破解的实质问题是:从p q的数值,去求出(p-1)和(q-1)。换句话说,只要求出p和q的值,我们就能求出d的值而得到私钥。
当p和q是一个大素数的时候,从它们的积p q去分解因子p和q,这是一个公认的数学难题。比如当p*q大到1024位时,迄今为止还没有人能够利用任何计算工具去完成分解因子的任务。因此,RSA从提出到现在已近二十年,经历了各种攻击的考验,逐渐为人们接受,普遍认为是目前最优秀的公钥方案之一。
缺点1:虽然RSA的安全性依赖于大数的因子分解,但并没有从理论上证明破译RSA的难度与大数分解难度等价。即RSA的重大缺陷是无法从理论上把握它的保密性能如何。
在android 开发的很多时候。为了保证用户的账户的安全性,再保存用户的密码时,通常会采用MD5加密算法,这种算法是不可逆的,具有一定的安全性
MD5不是加密算法, 因为如果目的是加密,必须满足的一个条件是加密过后可以解密。但是MD5是无法从结果还原出原始数据的。
MD5只是一种哈希算法
‘贰’ Android面试 HashMap算法
基于hashing的原理,jdk8后采用数组+链表+红黑树的数据结构。我们通过put和get存储和获取对象。当我们给put()方法传递键和值时,先对键做一个hashCode()的计算来得到它在bucket数组中的位置来存储Entry对象。当获取对象时,通过get获取到bucket的位置,再通过键对象的equals()方法找到正确的键值对,然后在返回值对象。
当数组table的size达到阙值时即++size > load factor * capacity 时,也是在putVal函数中。
扩容需要重新分配一个新数组,新数组是老数组的2倍长,然后遍历整个老结构,把所有的元素挨个重新hash分配到新结构中去。
对key的hashCode进行hashing,与运算计算下标获取bucket位置,如果在桶的首位上就可以找到就直接返回,否则在树中找或者链表中遍历找,如果有hash冲突,则利用equals方法去遍历链表查找节点。
对key的hashCode做hash操作,与高16位做异或运算。
还有平方取中法,除留余数法,伪随机数法。
因为数组位置的确定用的是与运算,仅仅最后四位有效,设计者将key的哈希值与高16为做异或运算使得在做&运算确定数组的插入位置时,此时的低位实际是高位与低位的结合,增加了随机性,减少了哈希碰撞的次数。
会产生哈希碰撞,若key值相同则替换旧值,不然链接到链表后面,链表长度超过阙值8就转为红黑树存储。
HashCode相同,通过equals比较内容获取值对象。
超过阙值会进行扩容操作,概括的讲就是扩容后的数组大小是原数组的2倍,将原来的元素重新hashing放入到新的散列表中去。
相同点:都是存储key-value键值对的
不同点:
loadFactor表示HashMap的拥挤程度,影响hash操作到同一个数组位置的概率。默认loadFactor等于0.75,当HashMap里面容纳的元素已经达到HashMap数组长度的75%时,表示HashMap太挤了,需要扩容,在HashMap的构造器中可以定制loadFactor。
JDK 1.8 以前 HashMap 的实现是 数组+链表,即使哈希函数取得再好,也很难达到元素百分百均匀分布。当 HashMap 中有大量的元素都存放到同一个桶中时,这个桶下有一条长长的链表,这个时候 HashMap 就相当于一个单链表,假如单链表有 n 个元素,遍历的时间复杂度就是 O(n),完全失去了它的优势。针对这种情况,JDK 1.8 中引入了 红黑树(查找时间复杂度为 O(logn))来优化这个问题。但是链表大于8的概率是非常非常低的。
选择Integer,String这种不可变的类型,像对String的一切操作都是新建一个String对象,对新的对象进行拼接分割等,这些类已经很规范的覆写了hashCode()以及equals()方法。作为不可变类天生是线程安全的。如果要使用自定义类做为Key,就需要重写hashCode()以及equals()方法。红黑树在做比较的时候使用的是System.identityHashCode()方法,是不需要做特殊处理的。
更多内容戳这里(整理好的各种文集)
‘叁’ android 全景图像拼接算法哪种方案最好
首先介绍一下流程:
1.选图,两张图的重叠区域不能太小,我个人认为最少不少于15%,这样才能保证有足够的角点匹配。
2.角点检测。这一步OpenCV提供了很多种方法,譬如Harris角点检测,而监测出的角点用CvSeq存储,这是一个双向链表。
3.角点提纯。在提纯的时候,需要使用RANSAC提纯。OpenCV自带了一个函数,FindHomography,不但可以提纯,还可以计算出3x3的转换矩阵。这个转换矩阵十分重要。
4.角点匹配。经过提纯后的角点,则需要匹配。
5.图像变换。这一步我曾经尝试过很多办法,最后选择了FindHomography输出的变换矩阵,这是一个透视变换矩阵。经过这个透视变换后的图像,可以直接拿来做拼接。
6.图象拼接。完成上面步骤之后,其实这一步很容易。
7.球面变换。这一步需要对坐标系进行转换,从平面坐标到球面坐标。
‘肆’ 安卓常用的加密算法中,加密后生成42位的密文的是哪种加密方法
直接通用的加密算法好像都没有生成42位的,你这段看起来像MD5加密后的与另一个字符串连接在一起,你尝试对应其他字段看看
尝试:
1. 32+10
2. 5+32+5
3. 10+32
我看比较 像以上三种情况
‘伍’ Android开发 HashMap如何排序
HashMap排序是数据结构与算法中常见的一种排序算法。本文即以Android平台为例来实现该算法。
具体代码如下: public static void main(String[] args) { Map<String, Integer> map = new HashMap<String, Integer>(); map.put("lisi", 5); map.put("lisi1", 1); map.put("lisi2", 3); map.put("lisi3", 9); List<Map.Entry<String, Integer>> infoIds = new ArrayList<Map.Entry<String, Integer>>( map.entrySet()); System.out.println("--------------排序前--------------"); for (int i = 0; i < infoIds.size(); i++) { String id = infoIds.get(i).toString(); System.out.println(id); } // 排序 Collections.sort(infoIds, new Comparator<Map.Entry<String, Integer>>() { public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) { return ( o1.getValue()-o2.getValue()); } }); System.out.println("--------------排序后--------------"); for (int i = 0; i < infoIds.size(); i++) { Entry<String,Integer> ent=infoIds.get(i); System.out.println(ent.getKey()+"="+ent.getValue()); }}
‘陆’ android联系人排序用了什么算法
今天用了整整一下午去捣鼓这块,为什么模拟器上可以按拼音排序,中英文混排,及按字母搜索联系人,但到了开发板(平台是根据android2.2改过的)上就怎么不行了呢,虽然现在还没有解决,但也是知道了问题所在,离解决之路也就不远了
好吧,现在就解释下android2.2是怎么按拼音排序的。
首先我们来看下android.2自带通讯录的数据库文件contacts2.db的raw_contacts表。用sqlitedbviewer工具打开后可以看到有这么一个字段:sort_key(sort_key_alt与之相似,只不过是英文环境下有个按given name还是first name排序的问题)。
正常状况下,我们新建一个联系人的话,如果是英文,则sort_key与display_name字段显示相同,如果输入姓名是中文,如“你好”,sort_key则会显示“ni 你 hao 好”,这样开发者既可以根据此字段按拼音排序,中英文混排,以及按拼音搜索联系人拉。
现在就说下,android是如何将中文名的联系人转化为拼音存到sort_key里面的:
view plain to clipboardprint?
if (displayNameStyle == FullNameStyle.CHINESE ||
displayNameStyle == FullNameStyle.CJK) {
sortKeyPrimary = sortKeyAlternative =
ContactLocaleUtils.getIntanc).getSortKe(displayNamePrimary, displayNameStyle);}
if (displayNameStyle == FullNameStyle.CHINESE ||
displayNameStyle == FullNameStyle.CJK) { sortKeyPrimary =
sortKeyAlternative =
ContactLocaleUtils.getIntanc).getSortKe(displayNamePrimary,
displayNameStyle);}
这段代码是运行在contactsprovi2.Java的updateRawContactDisplayName()方法里面,这段代码我们用到了ContactLocaleUtils.java这个类,所以我们进入它以后最显眼的就是ChineseContactUtils这个ContactLocaleUtils的子类,它重写了ContactLocaleUtils的getSortKey()方法,如下:
view plain to clipboardprint?
public String getSortKey(String displayName) {
ArrayList tokens = HanziToPinyin.getInstance().get(displayName);
if (tokens != null && tokens.size() > 0) {
StringBuilder sb = new StringBuilder();
for (Token token : tokens) {
// Put Chinese character's pinyin, then proceed with the
// character itself.
if (Token.PINYIN == token.type) {
if (sb.length() > 0) {
sb.append(' ');
}
sb.append(token.target);
sb.append(' ');
sb.append(token.source);
} else {
if (sb.length() > 0) {
sb.append(' ');
}
sb.append(token.source);
}
}
return sb.toString();
}
return super.getSortKey(displayName);
}
public
String getSortKey(String displayName) {
ArrayList tokens =
HanziToPinyin.getInstance().get(displayName); if (tokens !=
null && tokens.size() > 0) { StringBuilder
sb = new StringBuilder(); for (Token token : tokens) {
// Put Chinese character's pinyin, then proceed
with the // character itself.
if (Token.PINYIN == token.type) { if
(sb.length() > 0) { sb.append(' ');
} sb.append(token.target);
sb.append(' ');
sb.append(token.source); } else {
if (sb.length() > 0) {
sb.append(' '); }
sb.append(token.source); } }
return sb.toString(); } return
super.getSortKey(displayName); }
首先我们看 ArrayList tokens = HanziToPinyin.getInstance().get(displayName);,因为其他的无非就是插入格式的问题,我们暂时不用看。
android如何将汉字转为拼音的?这就用到了HanziToPinyin这个类,好吧,我们先看下HanziToPinyin的getInstance()方法:
view plain to clipboardprint?
public static HanziToPinyin getInstance() {
synchronized(HanziToPinyin.class) {
if (sInstance != null) {
return sInstance;
}
// Check if zh_CN collation data is available
final Locale locale[] = Collator.getAvailableLocales();
for (int i = 0; i < locale.length; i++) {
if (locale[i].equals(Locale.CHINA)) {
sInstance = new HanziToPinyin(true);
return sInstance;
}
}
Log.w(TAG, "There is no Chinese collator, HanziToPinyin is disabled");
sInstance = new HanziToPinyin(false);
return sInstance;
}
}
public static HanziToPinyin getInstance() {
synchronized(HanziToPinyin.class) { if (sInstance != null) {
return sInstance; } // Check
if zh_CN collation data is available final Locale locale[]
= Collator.getAvailableLocales(); for (int i = 0; i <
locale.length; i++) { if
(locale[i].equals(Locale.CHINA)) { sInstance = new
HanziToPinyin(true); return sInstance;
} } Log.w(TAG, "There is no Chinese
collator, HanziToPinyin is disabled"); sInstance = new
HanziToPinyin(false); return sInstance; } }
现在说下我的开发板为什么不能转拼音;就是因为final Locale locale[] = Collator.getAvailableLocales()的Locale没有一项equals(Locale.CHINA),所以到时候解决了这项,联系人的按拼音排序也就解决了,如果大家不想用系统自带的,自己可以下载个pinyin4j.jar包自己实现吧。
好吧,继续:
看方法名也只到,这个方法返回一个HanziToPinyin实例,我仔细研究了HanziToPinyin的构造方法,无论纯如的布尔值是false还是true都不影响,返回的都一样,只不过这个方法的Log.w(TAG, "There is no Chinese collator, HanziToPinyin is disabled");可以提示是否支持汉字转拼音,如果不能,android就会将displayname原封不动的插入sort_key里面,如果能,就是刚才我说的 如“你好”,sort_key则会显示“ni 你 hao 好”,这种形式,具体的如何转拼音就是get()方法拉,直接插代码:
view plain to clipboardprint?
public ArrayList get(final String input) {
ArrayList tokens = new ArrayList();
if (!mHasChinaCollator || TextUtils.isEmpty(input)) {
// return empty tokens.
return tokens;
}
final int inputLength = input.length();
final StringBuilder sb = new StringBuilder();
int tokenType = Token.LATIN;
// Go through the input, create a new token when
// a. Token type changed
// b. Get the Pinyin of current charater.
// c. current character is space.
for (int i = 0; i < inputLength; i++) {
final char character = input.charAt(i);
if (character == ' ') {
if (sb.length() > 0) {
addToken(sb, tokens, tokenType);
}
} else if (character < 256) {
if (tokenType != Token.LATIN && sb.length() > 0) {
addToken(sb, tokens, tokenType);
}
tokenType = Token.LATIN;
sb.append(character);
} else if (character < FIRST_UNIHAN) {
if (tokenType != Token.UNKNOWN && sb.length() > 0) {
addToken(sb, tokens, tokenType);
}
tokenType = Token.UNKNOWN;
sb.append(character);
} else {
Token t = getToken(character);
if (t.type == Token.PINYIN) {
if (sb.length() > 0) {
addToken(sb, tokens, tokenType);
}
tokens.add(t);
tokenType = Token.PINYIN;
} else {
if (tokenType != t.type && sb.length() > 0) {
addToken(sb, tokens, tokenType);
}
tokenType = t.type;
sb.append(character);
}
}
}
if (sb.length() > 0) {
addToken(sb, tokens, tokenType);
}
return tokens;
}
‘柒’ Android基础‘V1V2V3签名’
基础概念
签名:在 APK 中写入一个“指纹”。指纹写入以后,APK 中有任何修改,都会导致这个指纹无效,Android 系统在安装 APK 进行签名校验时就会不通过,从而保证了安全性。
摘要算法: 使用一段简单的看上去随机的不可逆向的固定长度的字符串来表示一个文件的唯一性。 常见的摘要算法如MD5(128个比特位)、SHA-1算法(160/192/256个比特位)。
公钥密码体制:也称非对称算法,特点是 公钥是公开的 ,私钥是保密的。常见的如:RSA。
展开讨论一下RSA:
Android中的签名方案
V1 :基于jarsigner(JDK自带工具,使用keystore文件进行签名) 或 apksigner(Android专门提供的,使用pk8、x509.pem进行签名)。keystore和pk8/x509.pem可以相互转换。
签名原理:首先keystore文件包含一个MD5和一个SHA1摘要。 这也是很多开放平台需要我们上传的摘要数据 。
签名APK后会在META-INF文件夹下生产CERT.RSA、CERT.SF、MANIFEST.MF三个文件。
在apk中,/META-INF文件夹中保存着apk的签名信息,一般至少包含三个文件,[CERT].RSA,[CERT].SF和MANIFEIST.MF文件。这三个文件就是对apk的签名信息。
MANIFEST.MF中包含对apk中除了/META-INF文件夹外所有文件的签名值,签名方法是先SHA1()(或其他hash方法)在base64()。存储形式是:Name加[SHA1]-Digest。
[CERT].SF是对MANIFEST.MF文件整体签名以及其中各个条目的签名。一般地,如果是使用工具签名,还多包括一项。就是对MANIFEST.MF头部信息的签名,关于这一点前面源码分析中已经提到。
[CERT].RSA包含用私钥对[CERT].SF的签名以及包含公钥信息的数字证书。
是否存在签名伪造可能:
修改(含增删改)了apk中的文件,则:校验时计算出的文件的摘要值与MANIFEST.MF文件中的条目不匹配,失败。
修改apk中的文件+MANIFEST.MF,则:MANIFEST.MF修改过的条目的摘要与[CERT].SF对应的条目不匹配,失败。
修改apk中的文件+MANIFEST.MF+[CERT].SF,则:计算出的[CERT].SF签名与[CERT].RSA中记录的签名值不匹配,失败。
修改apk中的文件+MANIFEST.MF+[CERT].SF+[CERT].RSA,则:由于证书不可伪造,[CERT].RSA无法伪造。
V2 :7.0新增的
签名后的包会被分为四部分
1. Contents of ZIP entries(from offset 0 until the start of APK Signing Block)
2. APK Signing Block
3. ZIP Central Directory
4. ZIP End of Central Directory
新应用签名方案的签名信息会被保存在区块2(APK Signing Block) 中, 而区块1( Contents of ZIP entries )、区块3( ZIP Central Directory )、区块4( ZIP End of Central Directory )是受保护的, 在签名后任何对区块1、3、4的修改都逃不过新的应用签名方案的检查 。
V3 :9.0新增的
格式大体和 v2 类似,在 v2 插入的签名块(Apk Signature Block v2)中,又添加了一个新快(Attr块) 。
在这个新块中,会记录我们之前的签名信息以及新的签名信息,以 密钥转轮的方案,来做签名的替换和升级。这意味着,只要旧签名证书在手,我们就可以通过它在新的 APK 文件中,更改签名 。
v3 签名新增的新块(attr)存储了所有的签名信息,由更小的 Level 块,以 链表 的形式存储。
其中每个节点都包含用于为之前版本的应用签名的签名证书,最旧的签名证书对应根节点,系统会让每个节点中的证书为列表中下一个证书签名,从而为每个新密钥提供证据来证明它应该像旧密钥一样可信。
这个过程有点类似 CA 证书的证明过程,已安装的 App 的旧签名,确保覆盖安装的 APK 的新签名正确,将信任传递下去。
注意: 签名方式只支持升级不支持降级,如安装了V2的包,不能覆盖替换为V1的包。
参考
Android App签名(证书)校验过程源码分析
新一代开源Android渠道包生成工具Walle
Android 签名机制 v1、v2、v3
‘捌’ android加密算法有哪些
android中用的到加密:
Https编程 :应该是使用带安全的网络协议处理。除非你本地需要加密
2.数据签名:混淆代码和防二次打包的APK加密技术
3.对称加密:可以先将数据通过某种加密方式加密发送到服务器端,然后服务器端再解密 ,项目中除了登陆,支付等接口采用rsa非对称加密,之外的采用aes对称加密
4.非对称加密====支付宝
数字摘要是指通过算法将长数据变为短数据,通常用来标识数据的唯一性,是否被修改,常用的加密算法有md5和sha1两种,如Android的App签名也是用的这两种算法。
由于以上两种生成数字摘要的算法都是不可逆的,对于可逆的加密算法中,按照密钥的数量和加密规则一半分为对称加密和非对称加密两类:
对称加密:
密钥可以自己指定,只有一把密钥,如果密钥泄漏数据就会暴漏;
常用的对称加密算法有DES和AES两种;
特点是加密速度快,但是缺点是安全性低,因为只要密钥暴漏,数据就可以被解密。
非对称加密的特点:
常见的非对称加密算法是RSA;
他有两把密钥,且是由程序生成的,不能自己指定;
特点是加密速度比较慢,但是安全性比较高;
加密和解密的规则是:公钥加密只能私钥解密,私钥加密只能公钥解密;
‘玖’ Android APK hash值算法
无符号右移16位然后做异或运算
hash值计算公式:
对于key的hashCode做hash操作,无符号右移16位然后做异或运算。还有平方取中法,伪随机数法和取余数法。这三种效率都比较低。而无符号右移16位异或运算效率是最高的。集合中的初始化容量(必须是二的n次幂)//默认的初始容量是16--1<<4相当于1*2的4次方---1*16staticfinalintDEFAULT_INITIAL_CAPACITY=1<<4;1212staticfinalinthash(Objectkey){inth;/*
如果key等于null:可以看到当key等于null的时候也是有哈希值的,返回的是0.
如果key不等于null:首先计算出key的hashCode赋值给h,然后与h无符号右移16位后的二进制进行按位异或得到最后的hash值。