java实现RSA加密与SHA签名的例子

看到这篇文章的同学可幸福了,当时在做RSA加密与签名的时候网上的资料简直不要太老,做完后实在是忍受不下去了,这篇文章我会详细讲解iOS如何实现RSA加密与签名,并且与Java完全同步,这是我的第二篇博客,若有什么不足之处还请大家指教。

什么是RSA?

答:RSA是一种非对称加密算法,常用来对传输数据进行加密,配合上数字摘要算法,也可以进行文字签名。

RSA加密中padding?

答:padding即填充方式,由于RSA加密算法中要加密的明文是要比模数小的,padding就是通过一些填充方式来限制明文的长度。后面会详细介绍padding的几种模式以及分段加密。

加密和加签有什么区别?

答:加密:公钥放在客户端,并使用公钥对数据进行加密,服务端拿到数据后用私钥进行解密;

加签:私钥放在客户端,并使用私钥对数据进行加签,服务端拿到数据后用公钥进行验签。

前者完全为了加密;后者主要是为了防恶意攻击,防止别人模拟我们的客户端对我们的服务器进行攻击,导致服务器瘫痪。

基本原理

RSA使用“密钥对”对数据进行加密解密,在加密解密前需要先生存公钥(Public Key)和私钥(Private Key)。

公钥(Public key): 用于加密数据. 用于公开, 一般存放在数据提供方, 例如iOS客户端。

私钥(Private key): 用于解密数据. 必须保密, 私钥泄露会造成安全问题。

iOS中的Security.framework提供了对RSA算法的支持,这种方式需要对密匙对进行处理, 根据public key生成证书, 通过private key生成p12格式的密匙。想想jave直接用字符串进行加密解密简单多了。(⊙o⊙)…

 

实战

证书生成

RSA加密这块公钥、私钥必不可少的。Apple是不支持直接使用字符串进行加密解密的,推荐使用p12文件。这边教大家去生成在加密中使用到的所有文件,并提供给Java使用,想当年这个公钥私钥搞了半天了。 %>_<%

 

生成模长为1024bit的私钥

openssl genrsa -out private_key.pem 1024

生成certification require file

openssl req -new -key private_key.pem -out rsaCertReq.csr

生成certification 并指定过期时间

openssl x509 -req -days3650-in rsaCertReq.csr -signkey private_key.pem -out rsaCert.crt

生成公钥供iOS使用

openssl x509 -outform der -in rsaCert.crt -out public_key.der

生成私钥供iOS使用 这边会让你输入密码,后期用到在生成secKeyRef的时候会用到这个密码

openssl pkcs12 -export -out private_key.p12 -inkey private_key.pem -in rsaCert.crt

生成pem结尾的公钥供Java使用

openssl rsa -in private_key.pem -out rsa_public_key.pem -pubout

生成pem结尾的私钥供Java使用openssl pkcs8 -topk8 -in private_key.pem -out pkcs8_private_key.pem -nocrypt

以上所有的步骤都是在终端下完成的哦 (^__^)

生成公钥和私钥的secKeyRef

//根据你的p12文件生成私钥对应的SecKeyRef 这边返回若是nil 请检查你p12文件的生成步骤
- (SecKeyRef)getPrivateKeyRefrenceFromData:(NSData*)p12Data password:(NSString*)password {
SecKeyRef privateKeyRef = NULL;
NSMutableDictionary * options = [[NSMutableDictionary alloc] init];
[options setObject: password forKey:(__bridge id)kSecImportExportPassphrase];
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
OSStatus securityError = SecPKCS12Import((__bridge CFDataRef) p12Data, (__bridge CFDictionaryRef)options, &items);
if (securityError == noErr && CFArrayGetCount(items) > 0) {
    CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0);
    SecIdentityRef identityApp = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity);
    securityError = SecIdentityCopyPrivateKey(identityApp, &privateKeyRef);
    if (securityError != noErr) {
        privateKeyRef = NULL;
    }
}
CFRelease(items);
return privateKeyRef;
}
-
 //根据你的der文件公钥对应的SecKeyRef
 - (SecKeyRef)getPublicKeyRefrenceFromeData:    (NSData*)derData {
SecCertificateRef myCertificate = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)derData);
SecPolicyRef myPolicy = SecPolicyCreateBasicX509();
SecTrustRef myTrust;
OSStatus status = SecTrustCreateWithCertificates(myCertificate,myPolicy,&myTrust);
SecTrustResultType trustResult;
if (status == noErr) {
    status = SecTrustEvaluate(myTrust, &trustResult);
}
SecKeyRef securityKey = SecTrustCopyPublicKey(myTrust);
CFRelease(myCertificate);
CFRelease(myPolicy);
CFRelease(myTrust);
return securityKey;
}
加密与解密
- (NSData*)rsaEncryptData:(NSData*)data {
    SecKeyRef key = [self getPublicKey];
    size_t cipherBufferSize = SecKeyGetBlockSize(key);
    uint8_t *cipherBuffer = malloc(cipherBufferSize * sizeof(uint8_t));
    size_t blockSize = cipherBufferSize - 11;
      size_t blockCount = (size_t)ceil([data length] / (double)blockSize);
      NSMutableData *encryptedData = [[NSMutableData alloc] init];
    for (int i=0; i<blockCount; i++) {
    unsigned long bufferSize = MIN(blockSize , [data length] - i * blockSize);
    NSData *buffer = [data subdataWithRange:NSMakeRange(i * blockSize, bufferSize)];
    OSStatus status = SecKeyEncrypt(key, kSecPaddingPKCS1, (const uint8_t *)[buffer bytes], [buffer length], cipherBuffer, &cipherBufferSize);
    if (status != noErr) {
        return nil;
    }
    NSData *encryptedBytes = [[NSData alloc] initWithBytes:(const void *)cipherBuffer length:cipherBufferSize];
    [encryptedData appendData:encryptedBytes];
    }
  if (cipherBuffer){
    free(cipherBuffer);
  }
  return encryptedData;
  }
-
- (NSData*)rsaDecryptData:(NSData*)data {
SecKeyRef key = [self getPrivatKey];
size_t cipherBufferSize = SecKeyGetBlockSize(key);
size_t blockSize = cipherBufferSize;
size_t blockCount = (size_t)ceil([data length] / (double)blockSize);
NSMutableData *decryptedData = [[NSMutableData alloc] init];
for (int i = 0; i < blockCount; i++) {
    unsigned long bufferSize = MIN(blockSize , [data length] - i * blockSize);
    NSData *buffer = [data subdataWithRange:NSMakeRange(i * blockSize, bufferSize)];
    size_t cipherLen = [buffer length];
    void *cipher = malloc(cipherLen);
    [buffer getBytes:cipher length:cipherLen];
    size_t plainLen = SecKeyGetBlockSize(key);
    void *plain = malloc(plainLen);
    OSStatus status = SecKeyDecrypt(key, kSecPaddingPKCS1, cipher, cipherLen, plain, &plainLen);
    if (status != noErr) {
        return nil;
    }
    NSData *decryptedBytes = [[NSData alloc] initWithBytes:(const void *)plain length:plainLen];
    [decryptedData appendData:decryptedBytes];
}
return decryptedData;
}
RSA加密中的Padding

RSA_PKCS1_PADDING 填充模式,最常用的模式

要求: 输入:必须 比 RSA 钥模长(modulus) 短至少11个字节, 也就是 RSA_size(rsa) – 11 如果输入的明文过长,必须切割,然后填充。

输出:和modulus一样长

根据这个要求,对于1024bit的密钥,block length = 1024/8 – 11 = 117 字节

 

RSA_PKCS1_OAEP_PADDING

输入:RSA_size(rsa) – 41

输出:和modulus一样长

 

RSA_NO_PADDING  不填充

输入:可以和RSA钥模长一样长,如果输入的明文过长,必须切割, 然后填充

输出:和modulus一样长

 

签名与验证

//对数据进行sha256签名

  - (NSData *)rsaSHA256SignData:(NSData *)plainData {

  SecKeyRef key = [self getPrivatKey];

 

  size_t signedHashBytesSize = SecKeyGetBlockSize(key);

  uint8_t* signedHashBytes = malloc(signedHashBytesSize);

  memset(signedHashBytes, 0x0, signedHashBytesSize);

 

  size_t hashBytesSize = CC_SHA256_DIGEST_LENGTH;

  uint8_t* hashBytes = malloc(hashBytesSize);

  if (!CC_SHA256([plainData bytes], (CC_LONG)[plainData length], hashBytes)) {

    return nil;

}

 

       SecKeyRawSign(key,

              kSecPaddingPKCS1SHA256,

              hashBytes,

              hashBytesSize,

              signedHashBytes,

              &signedHashBytesSize);

 

    NSData* signedHash = [NSData dataWithBytes:signedHashBytes

                                    length:(NSUInteger)signedHashBytesSize];

 

    if (hashBytes)

    free(hashBytes);

    if (signedHashBytes)

    free(signedHashBytes);

 

    return signedHash;

    }

-

 

      //这边对签名的数据进行验证 验签成功,则返回YES

    - (BOOL)rsaSHA256VerifyData:(NSData *)plainData     withSignature:(NSData *)signature {

    SecKeyRef key = [self getPublicKey];

 

    size_t signedHashBytesSize = SecKeyGetBlockSize(key);

    const void* signedHashBytes = [signature bytes];

 

    size_t hashBytesSize = CC_SHA256_DIGEST_LENGTH;

    uint8_t* hashBytes = malloc(hashBytesSize);

    if (!CC_SHA256([plainData bytes], (CC_LONG)[plainData length], hashBytes)) {

       return NO;

    }

 

      OSStatus status = SecKeyRawVerify(key,

                                  kSecPaddingPKCS1SHA256,

                                  hashBytes,

                                  hashBytesSize,

                                  signedHashBytes,

                                  signedHashBytesSize);

 

    return status == errSecSuccess;

    }

时间: 2024-07-30 03:31:24

java实现RSA加密与SHA签名的例子的相关文章

iOS在RSA加密解密和签名的时候已经生成密钥、摘要和密文。向服务器请求为何后台没有反应

问题描述 iOS在RSA加密解密和签名的时候已经生成密钥.摘要和密文.向服务器请求为何后台没有反应 是RSA加密签名这里的问题吗 解决方案 先要看后台有没有收到数据,然后就是后台是否正确处理

python下RSA 加密/解密,签名/验证

基于win7 + python3.4   原文是py2环境,而我的环境是py3,所以对原代码做了修改:decode(), encode() import rsa # 生成密钥 (pubkey, privkey) = rsa.newkeys(1024) # 保存密钥 with open('public.pem','w+') as f: f.write(pubkey.save_pkcs1().decode()) with open('private.pem','w+') as f: f.write(

PHP OpenSSL实现RSA加密解密(通java)

openssl是一个功能强大的工具包,它集成了众多密码算法及实用工具.我们即可以利用它提供的命令台工具生成密钥.证书来加密解密文件,也可以在利用其提供的API接口在代码中对传输信息进行加密. 加密使用 公钥, 解密使用 私钥 签名使用 私钥, 验证使用 公钥 rsa加密的明文最大长度117字节,解密要求密文最大长度为128字节.待加密的字节数不能超过密钥的长度值除以8再减去11,而加密后得到密文的字节数,正好是密钥的长度值除以8.这个规定很狗血,所以就出现了分片加密,网上很流行这个版本.很简单,

C# Java间进行RSA加密解密交互

原文:C# Java间进行RSA加密解密交互 这里,讲一下RSA算法加解密在C#和Java之间交互的问题,这两天纠结了很久,也看了很多其他人写的文章,颇受裨益,但没能解决我的实际问题,终于,还是被我捣鼓出来了. 首先,介绍一下写这代码的目的:完成webService验证问题,服务器端采用C#开发,客户端采用Java开发.服务器端给客户端提供公钥,已进行数据加密,客户端加密后提数据提交给服务器,服务器用私钥对数据解密,进行验证.  这里遇到的主要问题是C# RSACryptoServiceProv

PHP rsa加密解密使用方法_php实例

php服务端与客户端交互.提供开放api时,通常需要对敏感的部分api数据传输进行数据加密,这时候rsa非对称加密就能派上用处了,下面通过一个例子来说明如何用php来实现数据的加密解密 1.加密解密的第一步是生成公钥.私钥对,私钥加密的内容能通过公钥解密(反过来亦可以) 下载开源RSA密钥生成工具openssl(通常Linux系统都自带该程序),解压缩至独立的文件夹,进入其中的bin目录,执行以下命令: openssl genrsa -out rsa_private_key.pem 1024 o

php rsa 加密,解密,签名,验签详解_php技巧

php rsa 加密,解密,签名,验签 由于对接第三方机构使用的是Java版本的rsa加解密方法,所有刚开始在网上搜到很多PHP版本的rsa加解密,但是对接java大多都不适用. 以下php版本是适用于对接java接口,java适用密钥再php语言使用是需要添加 -----BEGIN CERTIFICATE----- -----END CERTIFICATE----- 使用密钥:加密公钥  public_key.cer 解密私钥  private_key.key 签名私钥 sign_key.ke

RSA加密解密及RSA签名和验证

加密|解密 此Demo包含两个文件,建立一个解决方案,然后建立两个文件,一个为Form,一个为Class,把代码分别复制进去即可 RSA正确的执行过程:加密解密:1.获取密钥,这里是产生密钥,实际应用中可以从各种存储介质上读取密钥2.加密3.解密签名和验证:签名:1.获取密钥,这里是产生密钥,实际应用中可以从各种存储介质上读取密钥2.获取待签名的Hash码3.签名其中,1和2的步骤无所谓,在本例中,我们将对txtSource里的内容进行签名,也可以对文件进行签名验证签名:1.获取密钥,这里是产生

rsa加解密-java产生RSA公钥,C++进行加密问题

问题描述 java产生RSA公钥,C++进行加密问题 如何将java生产的RSA公钥传递给C++,C++采用的加密函数是RSA_public_encrypt.是否需要将java产生的公钥进行什么格式转换?

C# Java间进行RSA加密解密交互(二)

原文:C# Java间进行RSA加密解密交互(二) 接着前面一篇文章C# Java间进行RSA加密解密交互,继续探讨这个问题. 在前面,虽然已经实现了C# Java间进行RSA加密解密交互,但是还是与项目中要求的有所出入.在项目中,客户端(Java)的加密是通过这么一个方法实现的: /** * RSA加密 * @param text--待加密的明文 * @param key--公钥,由服务器端提供的经base64编码的字符串 * @return */ public static String R