See this article students can be happy, at that time in the RSA encryption and signature when the online information is simply not too old, after finishing it is unbearable, this article I will explain in detail iOS how to implement RSA encryption and signature, and full synchronization with Java, this is my second blog, If there are any shortcomings, please advise us.
Basic knowledge
What is RSA?
A: RSA is an asymmetric encryption algorithm, often used to encrypt the transmitted data, with the Digital Digest algorithm, you can also be text signature.
RSA encryption in padding?
A: Padding is the Fill method, because the RSA encryption algorithm to encrypt the clear text is smaller than the modulus, padding is through some fill way to limit the length of the plaintext. Several modes of padding and segmented encryption are described in detail later.
What is the difference between encryption and signing?
A: The public key is placed on the client, and the data is encrypted with the public key, and the server is decrypted with the private key after it gets the data;
Add-on: The private key is placed on the client, and the data is signed with the private key, the service side to get the data with the public key for verification.
The former is purely for encryption, the latter is mainly for the purpose of preventing malicious attacks, to prevent others from impersonating our client to attack our server, causing the server to crash.
Basic principle
RSA encrypts the data using a key pair, which needs to survive the public key and the private key before encryption and decryption.
Public key: Used to encrypt data. Used for public, typically stored in data providers, such as iOS clients.
Private key: Used to decrypt data. Must be kept secret and private key leaks can create security issues.
The Security.framework in iOS provides support for the RSA algorithm, which requires processing the key pair, generating a certificate from public key, and generating a key in the P12 format with private key. Think of the Jave directly with string encryption and decryption is much simpler. (⊙o⊙) ...
Actual combat
Certificate generation
RSA encrypts this public key, the private key is necessary. Apple does not support encrypting and decrypting directly using strings, it is recommended to use the P12 file. Here to teach you to generate all the files used in the encryption, and provided to Java use, think of this public key private key for half a day. %>_
Generate a private key with a modulus length of 1024bit
OpenSSL genrsa-out Private_key.pem 1024
Generate certification Require file
OpenSSL Req-new-key private_key.pem-out RSACERTREQ.CSR
Generate certification and specify expiration time
OpenSSL x509-req-days 3650-in rsacertreq.csr-signkey private_key.pem-out rsacert.crt
Generate a public key for use with iOS
OpenSSL x509-outform der-in rsacert.crt-out Public_key.der
Generate a private key for iOS use this way you will be prompted for a password, which will be used later when generating seckeyref.
OpenSSL pkcs12-export-out Private_key.p12-inkey private_key.pem-in rsacert.crt
Generate the public key at the end of the PEM for use in Java
OpenSSL rsa-in private_key.pem-out rsa_public_key.pem-pubout
Generate the private key at the end of the PEM for Java to use OpenSSL pkcs8-topk8-in private_key.pem-out pkcs8_private_key.pem-nocrypt
All of the above steps are done under the terminal Oh (^__^)
Generate Seckeyref for public and private keys
Generate the private key according to your p12 file the corresponding seckeyref this side returns if nil please check your P12 file generation steps
- (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;
}
–
Based on the seckeyref of your der file's public key
- (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;
}
Encryption and decryption
- (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 - one;
size_t Blockcount = (size_t)ceil([data length] / ( Double)blockSize);
nsmutabledata *encrypteddata = [[nsmutabledata alloc] init];
for (int i=0; i
–
- (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
Padding in RSA encryption
Rsa_pkcs1_padding fill mode, the most commonly used mode
Requirements: Input: must be shorter than RSA key modulo length (modulus) at least 11 bytes, that is, Rsa_size (RSA) –11 If the input clear text is too long, you must cut and then fill.
Output: As long as modulus
According to this requirement, for a 1024bit key, block length = 1024/8–11 = 117 bytes
Rsa_pkcs1_oaep_padding
Input: Rsa_size (RSA) –41
Output: As long as modulus
Rsa_no_padding not populated
Input: Can be as long as the RSA key modulus, if the input clear text is too long, you must cut, and then fill
Output: As long as modulus
Signature and verification
SHA256 Signature of data
- (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;
}
–
//This side verifies that the signed data is successful, then returns 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)) {< /c2>
return NO;
}
osstatus Status = seckeyrawverify(key,
ksecpaddingpkcs1sha256,
hashbytes,
hashbytessize,
signedhashbytes,
signedhashbytessize);
return status = = errsecsuccess;
}
This is the end of the article, I hope this article is helpful to everyone. To see the demo, click here: Xyrsacryptor
Https://github.com/panxianyue/RSACryptor.git
One piece of RSA encryption and SHA Signature | Fully synchronized with Java