- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
这让我很困惑 - 以下代码使用 SpongyCaSTLe 的 Android 加密/解密 - 我正在尝试实现 iOS 的跨平台加密/解密。
下面的代码(来自 Android)有效,AES 128 位 CBC 和 PKCS7Padding,使用提供的盐和密码,盐存储在 mysql 数据库中,密码由最终用户提供,以下代码是改编自 kelhoer 的这个答案.
我使用 AES128bit 的原因是 AES256 在 iOS 4+ 中不可用,它是在 iOS5+ 中引入的,并且不得不尝试使用 openssl
生成派生 key 和初始化向量( iv),据悉苹果拒绝与 openssl 库静态链接的应用程序,这很冒险。
由于该平台基于 iOS 4.2+,因此求助于 bundling and statically linking the openssl库似乎有点过分了,最好使用 CommonCryptor 库。
这是带有 SpongycaSTLe 代码的 Android 版本:
private static void encrypt(InputStream fin,
OutputStream fout,
String password,
byte[] bSalt) {
try {
PKCS12ParametersGenerator pGen = new PKCS12ParametersGenerator(
new SHA256Digest()
);
char[] passwordChars = password.toCharArray();
final byte[] pkcs12PasswordBytes =
PBEParametersGenerator.PKCS12PasswordToBytes(passwordChars);
pGen.init(pkcs12PasswordBytes, bSalt, ITERATIONS);
CBCBlockCipher aesCBC = new CBCBlockCipher(new AESEngine());
ParametersWithIV aesCBCParams =
(ParametersWithIV) pGen.generateDerivedParameters(128, 128);
aesCBC.init(true, aesCBCParams);
PaddedBufferedBlockCipher aesCipher =
new PaddedBufferedBlockCipher(aesCBC, new PKCS7Padding());
aesCipher.init(true, aesCBCParams);
byte[] buf = new byte[BUF_SIZE];
// Read in the decrypted bytes and write the cleartext to out
int numRead = 0;
while ((numRead = fin.read(buf)) >= 0) {
if (numRead == 1024) {
byte[] plainTemp = new byte[
aesCipher.getUpdateOutputSize(numRead)];
int offset =
aesCipher.processBytes(buf, 0, numRead, plainTemp, 0);
final byte[] plain = new byte[offset];
System.arraycopy(plainTemp, 0, plain, 0, plain.length);
fout.write(plain, 0, plain.length);
} else {
byte[] plainTemp = new byte[aesCipher.getOutputSize(numRead)];
int offset =
aesCipher.processBytes(buf, 0, numRead, plainTemp, 0);
int last = aesCipher.doFinal(plainTemp, offset);
final byte[] plain = new byte[offset + last];
System.arraycopy(plainTemp, 0, plain, 0, plain.length);
fout.write(plain, 0, plain.length);
}
}
fout.close();
fin.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private static void decrypt(InputStream fin,
OutputStream fout,
String password,
byte[] bSalt) {
try {
PKCS12ParametersGenerator pGen = new PKCS12ParametersGenerator(
new SHA256Digest()
);
char[] passwordChars = password.toCharArray();
final byte[] pkcs12PasswordBytes =
PBEParametersGenerator.PKCS12PasswordToBytes(passwordChars);
pGen.init(pkcs12PasswordBytes, bSalt, ITERATIONS);
CBCBlockCipher aesCBC = new CBCBlockCipher(new AESEngine());
ParametersWithIV aesCBCParams =
(ParametersWithIV) pGen.generateDerivedParameters(128, 128);
aesCBC.init(false, aesCBCParams);
PaddedBufferedBlockCipher aesCipher =
new PaddedBufferedBlockCipher(aesCBC, new PKCS7Padding());
aesCipher.init(false, aesCBCParams);
byte[] buf = new byte[BUF_SIZE];
// Read in the decrypted bytes and write the cleartext to out
int numRead = 0;
while ((numRead = fin.read(buf)) >= 0) {
if (numRead == 1024) {
byte[] plainTemp = new byte[
aesCipher.getUpdateOutputSize(numRead)];
int offset =
aesCipher.processBytes(buf, 0, numRead, plainTemp, 0);
// int last = aesCipher.doFinal(plainTemp, offset);
final byte[] plain = new byte[offset];
System.arraycopy(plainTemp, 0, plain, 0, plain.length);
fout.write(plain, 0, plain.length);
} else {
byte[] plainTemp = new byte[
aesCipher.getOutputSize(numRead)];
int offset =
aesCipher.processBytes(buf, 0, numRead, plainTemp, 0);
int last = aesCipher.doFinal(plainTemp, offset);
final byte[] plain = new byte[offset + last];
System.arraycopy(plainTemp, 0, plain, 0, plain.length);
fout.write(plain, 0, plain.length);
}
}
fout.close();
fin.close();
} catch (Exception e) {
e.printStackTrace();
}
}
但是在 iOS 4.2(使用 XCode)下我不知道如何做同样的事情,
这是我在 Objective C 下尝试过的,目的是从 Android 端解密存储在 mysql 数据库中的数据,以测试这一点:
+(NSData*) decrypt:(NSData*)cipherData
userPassword:(NSString*)argPassword
genSalt:(NSData*)argPtrSalt{
size_t szPlainBufLen = cipherData.length + (kCCBlockSizeAES128);
uint8_t *ptrPlainBuf = malloc(szPlainBufLen);
//
const unsigned char *ptrPasswd =
(const unsigned char*)[argPassword
cStringUsingEncoding:NSASCIIStringEncoding];
int ptrPasswdLen = strlen(ptrPasswd);
//
NSString *ptrSaltStr = [[NSString alloc]
initWithData:argPtrSalt
encoding:NSASCIIStringEncoding];
const unsigned char *ptrSalt =
(const unsigned char *)[ptrSaltStr UTF8String];
NSString *ptrCipherStr =
[[NSString alloc]initWithData:cipherData
encoding:NSASCIIStringEncoding];
unsigned char *ptrCipher = (unsigned char *)[ptrCipherStr UTF8String];
unsigned char key[kCCKeySizeAES128];
unsigned char iv[kCCKeySizeAES128];
//
//int EVP_BytesToKey(const EVP_CIPHER *type,const EVP_MD *md,
//const unsigned char *salt, const unsigned char *data,
//int datal, int count, unsigned char *key,unsigned char *iv);
int i = EVP_BytesToKey(EVP_aes_128_cbc(),
EVP_sha256(),
ptrSalt,
ptrPasswd,
ptrPasswdLen,
PBKDF2_ITERATIONS,
key,
iv);
NSAssert(i == kCCKeySizeAES128,
@"Unable to generate key for AES");
//
size_t cipherLen = [cipherData length];
size_t outlength = 0;
//
CCCryptorStatus resultCCStatus = CCCrypt(kCCDecrypt,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding,
key,
kCCBlockSizeAES128,
iv,
ptrCipher,
cipherLen,
ptrPlainBuf,
szPlainBufLen,
&outlength);
NSAssert(resultCCStatus == kCCSuccess,
@"Unable to perform PBE AES128bit decryption: %d", errno);
NSData *ns_dta_PlainData = nil;
if (resultCCStatus == kCCSuccess){
ns_dta_PlainData =
[NSData dataWithBytesNoCopy:ptrPlainBuf length:outlength];
}else{
return nil;
}
return ns_dta_PlainData;
}
已提供数据和用户密码,并从 CCCrypt
获取返回代码为 -4304
,表示解码不成功和错误。
我认为编码方案可能会丢弃 CommonCryptor 的解密路由,因此转换为 NSASCIIStringEncoding
的冗长方法。
Salt 与密码数据一起存储,长度为 32 字节。
请记住,我在这方面缺少什么,在密码学方面很薄弱。
最佳答案
我冒昧地编写了 PKCS12Parameters generator 的直接端口在 Android 端使用时,此 header 的要点如上。
实现也是直接复制,如发现here ,密码,转换为 PKCS12 等价物 - unicode,big-endian,并在末尾填充两个额外的零。
生成器通过执行迭代次数生成派生 key 和 iv,在本例中为 1000,与在 Android 端一样,使用 SHA256 摘要,最终生成的 key 和 iv 是然后用作 CCCryptorCreate
的参数.
使用以下代码示例也不起作用,它以 -4304
结尾调用CCCryptorFinal
代码摘录如下:
#define ITERATIONS 1000
PKCS12ParametersGenerator *pGen = [[PKCS12ParametersGenerator alloc]
init:argPassword
saltedHash:argPtrSalt
iterCount:ITERATIONS
keySize:128
initVectSize:128];
//
[pGen generateDerivedParameters];
//
CCCryptorRef decryptor = NULL;
// Create and Initialize the crypto reference.
CCCryptorStatus ccStatus = CCCryptorCreate(kCCDecrypt,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding,
pGen.derivedKey.bytes,
kCCKeySizeAES128,
pGen.derivedIV.bytes,
&decryptor
);
NSAssert(ccStatus == kCCSuccess,
@"Unable to initialise decryptor!");
//
size_t szPlainBufLen = cipherData.length + (kCCBlockSizeAES128);
// Calculate byte block alignment for all calls through to and including final.
size_t szPtrPlainBufSize = CCCryptorGetOutputLength(decryptor, szPlainBufLen, true);
uint8_t *ptrPlainBuf = calloc(szPtrPlainBufSize, sizeof(uint8_t));
//
// Set up initial size.
size_t remainingBytes = szPtrPlainBufSize;
uint8_t *ptr = ptrPlainBuf;
size_t movedBytes = 0;
size_t totalBytesWritten = 0;
// Actually perform the encryption or decryption.
ccStatus = CCCryptorUpdate(decryptor,
(const void *) cipherData.bytes,
szPtrPlainBufSize,
ptr,
remainingBytes,
&movedBytes
);
NSAssert(ccStatus == kCCSuccess,
@"Unable to update decryptor! Error: %d", ccStatus);
ptr += movedBytes;
remainingBytes -= movedBytes;
totalBytesWritten += movedBytes;
//
// Finalize everything to the output buffer.
CCCryptorStatus resultCCStatus = CCCryptorFinal(decryptor,
ptr,
remainingBytes,
&movedBytes
);
totalBytesWritten += movedBytes;
if(decryptor) {
(void) CCCryptorRelease(decryptor);
decryptor = NULL;
}
NSAssert(resultCCStatus == kCCSuccess,
@"Unable to perform PBE AES128bit decryption: %d", resultCCStatus);
有趣的是,解密成功了,最后调用了CCCryptorFinal
返回 0
如果我替换 kCCOptionPKCS7Padding
对于 0x0000
在 CCCryptorCreate
的开头,即没有填充。 las,数据不是我所期望的,无论何时“不起作用”,数据仍然完全困惑。
它在某处失败了,所以如果有人对如何实现等效有任何更好的想法,我会很高兴听到其他意见。
它要么改变 Android 端的机制以使其“跨平台”与 iPhone 兼容,要么寻求一种替代的加密解决方案以在两端都兼容,但代价是双方的加密都较弱用于使数据交换可移植的平台的侧面。
提供的输入数据:
tnNhKyJ2vvrUzAmtQV5q9uEwzzAH63sTKtLf4pOQylw=:qTBluA+aNeFnEUfkUFUEVgNYrdz7enn5W1n4Q9uBKYmFfJeSCcbsfziErsa4EU9Cz/pO0KE4WE1QdqRcvSXthQ==
f00b4r
The quick brown fox jumped over the lazy dog and ran away
关于android - 等效于 ios 的 spongycaSTLe 加密,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16380768/
我最近在/ drawable中添加了一些.gifs,以便可以将它们与按钮一起使用。这个工作正常(没有错误)。现在,当我重建/运行我的应用程序时,出现以下错误: Error: Gradle: Execu
Android 中有返回内部存储数据路径的方法吗? 我有 2 部 Android 智能手机(Samsung s2 和 s7 edge),我在其中安装了一个应用程序。我想使用位于这条路径中的 sqlit
这个问题在这里已经有了答案: What's the difference between "?android:" and "@android:" in an android layout xml f
我只想知道 android 开发手机、android 普通手机和 android root 手机之间的实际区别。 我们不能从实体店或除 android marketplace 以外的其他地方购买开发手
自Gradle更新以来,我正在努力使这个项目达到标准。这是一个团队项目,它使用的是android-apt插件。我已经进行了必要的语法更改(编译->实现和apt->注释处理器),但是编译器仍在告诉我存在
我是android和kotlin的新手,所以请原谅要解决的一个非常简单的问题! 我已经使用导航体系结构组件创建了一个基本应用程序,使用了底部的导航栏和三个导航选项。每个导航选项都指向一个专用片段,该片
我目前正在使用 Facebook official SDK for Android . 我现在正在使用高级示例应用程序,但我不知道如何让它获取应用程序墙/流/状态而不是登录的用户。 这可能吗?在那种情
我在下载文件时遇到问题, 我可以在模拟器中下载文件,但无法在手机上使用。我已经定义了上网和写入 SD 卡的权限。 我在服务器上有一个 doc 文件,如果用户单击下载。它下载文件。这在模拟器中工作正常但
这个问题在这里已经有了答案: What is the difference between gravity and layout_gravity in Android? (22 个答案) 关闭 9
任何人都可以告诉我什么是 android 缓存和应用程序缓存,因为当我们谈论缓存清理应用程序时,它的作用是,缓存清理概念是清理应用程序缓存还是像内存管理一样主存储、RAM、缓存是不同的并且据我所知,缓
假设应用程序 Foo 和 Eggs 在同一台 Android 设备上。任一应用程序都可以获取设备上所有应用程序的列表。一个应用程序是否有可能知道另一个应用程序是否已经运行以及运行了多长时间? 最佳答案
我有点困惑,我只看到了从 android 到 pc 或者从 android 到 pc 的例子。我需要制作一个从两部手机 (android) 连接的 android 应用程序进行视频聊天。我在想,我知道
用于使用 Android 以编程方式锁定屏幕。我从 Stackoverflow 之前关于此的问题中得到了一些好主意,并且我做得很好,但是当我运行该代码时,没有异常和错误。而且,屏幕没有锁定。请在这段代
文档说: android:layout_alignParentStart If true, makes the start edge of this view match the start edge
我不知道这两个属性和高度之间的区别。 以一个TextView为例,如果我将它的layout_width设置为wrap_content,并将它的width设置为50 dip,会发生什么情况? 最佳答案
这两个属性有什么关系?如果我有 android:noHistory="true",那么有 android:finishOnTaskLaunch="true" 有什么意义吗? 最佳答案 假设您的应用中有
我是新手,正在尝试理解以下 XML 代码: 查看 developer.android.com 上的文档,它说“starStyle”是 R.attr 中的常量, public static final
在下面的代码中,为什么当我设置时单选按钮的外观会发生变化 android:layout_width="fill_parent" 和 android:width="fill_parent" 我说的是
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 9
假设我有一个函数 fun myFunction(name:String, email:String){},当我调用这个函数时 myFunction('Ali', 'ali@test.com ') 如何
我是一名优秀的程序员,十分优秀!