RSA暗号化プロセスノート
11779 ワード
一、各種の異なる接尾辞名が表す意味
X.509は一般的な一般的な証明書フォーマットです.すべての証明書はPublic Key Infrastructure(PKI)のために制定されたITU-T X 509国際基準に合致している.
二、opensslコマンドrsa秘密鍵共通鍵及び証明書の生成
コマンドラインを対応するフォルダに切り替え
$ openssl // openssl
$ genrsa -out rsa_private_key.pem 1024 //
$ rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
writing RSA key //
$ pkcs8 -topk8 -in rsa_private_key.pem -out pkcs8_rsa_private_key.pem -nocrypt // PKCS#8 ,
$ req -new -key rsa_private_key.pem -out rsa_cert.csr // ,
$ x509 -req -days 3650 -in rsa_cert.csr -signkey rsa_private_key.pem -out rsa_cert.crt // , 10
$ x509 -outform der -in rsa_cert.crt -out rsa_cert.der // - PEM DER
$ pkcs12 -export -out p.p12 -inkey rsa_private_key.pem -in rsa_cert.crt // P12 ,
$ exit // openssl
三、暗号化の方式及び起動方法
暗号化の方式は主に2種類に分けられる
四、実現過程で踏んだ穴
/*!
@function SecKeyEncrypt
@abstract Encrypt a block of plaintext.
@param key Public key with which to encrypt the data.
@param padding See Padding Types above, typically kSecPaddingPKCS1.
@param plainText The data to encrypt.
@param plainTextLen Length of plainText in bytes, this must be less
or equal to the value returned by SecKeyGetBlockSize().
@param cipherText Pointer to the output buffer.
@param cipherTextLen On input, specifies how much space is available at
cipherText; on return, it is the actual number of cipherText bytes written.
@result A result code. See "Security Error Codes" (SecBase.h).
@discussion If the padding argument is kSecPaddingPKCS1 or kSecPaddingOAEP,
PKCS1 (respectively kSecPaddingOAEP) padding will be performed prior to encryption.
If this argument is kSecPaddingNone, the incoming data will be encrypted "as is".
kSecPaddingOAEP is the recommended value. Other value are not recommended
for security reason (Padding attack or malleability).
When PKCS1 padding is performed, the maximum length of data that can
be encrypted is the value returned by SecKeyGetBlockSize() - 11.
When memory usage is a critical issue, note that the input buffer
(plainText) can be the same as the output buffer (cipherText).
*/
OSStatus SecKeyEncrypt(
SecKeyRef key,
SecPadding padding,
const uint8_t *plainText,
size_t plainTextLen,
uint8_t *cipherText,
size_t *cipherTextLen)
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0);
/*!
@function SecKeyDecrypt
@abstract Decrypt a block of ciphertext.
@param key Private key with which to decrypt the data.
@param padding See Padding Types above, typically kSecPaddingPKCS1.
@param cipherText The data to decrypt.
@param cipherTextLen Length of cipherText in bytes, this must be less
or equal to the value returned by SecKeyGetBlockSize().
@param plainText Pointer to the output buffer.
@param plainTextLen On input, specifies how much space is available at
plainText; on return, it is the actual number of plainText bytes written.
@result A result code. See "Security Error Codes" (SecBase.h).
@discussion If the padding argument is kSecPaddingPKCS1 or kSecPaddingOAEP,
the corresponding padding will be removed after decryption.
If this argument is kSecPaddingNone, the decrypted data will be returned "as is".
When memory usage is a critical issue, note that the input buffer
(plainText) can be the same as the output buffer (cipherText).
*/
OSStatus SecKeyDecrypt(
SecKeyRef key, /* Private key */
SecPadding padding, /* kSecPaddingNone,
kSecPaddingPKCS1,
kSecPaddingOAEP */
const uint8_t *cipherText,
size_t cipherTextLen, /* length of cipherText */
uint8_t *plainText,
size_t *plainTextLen) /* IN/OUT */
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0);
//
- (NSData *)encryptData:(NSData *)data
withKeyType:(QKeyType)keyType {
SecKeyRef keyRef = _pubSecKeyRef;
if (keyRef == NULL) {
NSAssert(NO, @" ");
return nil;
}
int dataLength = (int)data.length;
int blockSize = (int)SecKeyGetBlockSize(keyRef) * sizeof(uint8_t);
int maxLen = blockSize;
if (padding == kSecPaddingPKCS1) {
/**When PKCS1 padding is performed, the maximum length of data that can
be encrypted is the value returned by SecKeyGetBlockSize() - 11. */
maxLen -= 11;
}
int count = (int)ceil(dataLength * 1.0 / maxLen); // count ,ceil ,
// ,
NSMutableData *encryptedData = [[NSMutableData alloc] init] ;
uint8_t* cipherText = (uint8_t*)malloc(blockSize);
for (int i = 0; i < count; i++) {
NSUInteger bufferSize = MIN(maxLen, dataLength - i * maxLen);
NSData *inputData = [data subdataWithRange:NSMakeRange(i * maxLen, bufferSize)];
bzero(cipherText, blockSize);//
size_t outlen = blockSize; // maxLen , ,
OSStatus status = SecKeyEncrypt(keyRef,
kSecPaddingPKCS1,
(const uint8_t *)[inputData bytes],
bufferSize,
cipherText,
&outlen);
if (status == errSecSuccess) {//errSecSuccess == 0
[encryptedData appendBytes:cipherText length:outlen];
}else{
free(cipherText);
cipherText = NULL;
return nil;
}
}
free(cipherText);
cipherText = NULL;
return encryptedData;
}
//
- (NSData *)decryptEncryptedData:(NSData *)encryptedData
withKeyType:(QKeyType)keyType {
SecKeyRef keyRef = _priSecKeyRef;
if (keyRef == NULL) {
NSAssert(NO, @" ");
return nil;
}
int dataLength = (int)encryptedData.length;
int blockSize = (int)SecKeyGetBlockSize(keyRef) * sizeof(uint8_t);
int maxLen = blockSize ; // 11
int count = (int)ceil(dataLength * 1.0 / blockSize);
NSMutableData *decryptedData = [[NSMutableData alloc] init] ;
UInt8 *outbuf = malloc(blockSize);
for (int i = 0; i < count; i++) {
NSUInteger bufferSize = MIN(maxLen, dataLength - i * maxLen);
NSData *inputData = [encryptedData subdataWithRange:NSMakeRange(i * maxLen, bufferSize)];
bzero(outbuf, blockSize);//
size_t outlen = blockSize;
OSStatus status = SecKeyDecrypt(keyRef,
secPadding(),
(const uint8_t *)[inputData bytes],
bufferSize,
outbuf,
&outlen);
if (status == errSecSuccess) {
[decryptedData appendBytes:outbuf length:outlen];
}else{
free(outbuf);
outbuf = NULL;
return nil;
}
}
free(outbuf);
outbuf = NULL;
return decryptedData;
}
PEM_read_RSAPrivateKey(, , , )
通過するpemファイルがRSAを作成する時、この関数によってパスワードを伝達することができて、cに対して熟知していないで、しかし長い間探してやっと探し当てて、他の人はどのように使います
int pass_cb(char *buf, int size, int rwflag, void* password) {
snprintf(buf, size, "%s", (char*) password);
return (int)strlen(buf);
}
パスワードはありますpemファイルはRSAの作成に失敗し、その後も努力を続けます.
- (NSData *)encryptData:(NSData *)data
withKeyType:(QKeyType)keyType {
RSA *rsa = [self rsaForKey:keyType];
if (rsa == NULL) {
NSAssert(NO, @" ");
return nil;
}
QRSA_PADDING_TYPE type = [self current_PADDING_TYPE];
NSUInteger length = [self sizeOfRSA_PADDING_TYPE:type andRSA:rsa] * 1.0;
NSUInteger dataLength = data.length;
int count = (int)ceil(dataLength * 1.0 / length);
int status;//
char *encData = (char *)malloc(length);
NSMutableData *encryptedData = [[NSMutableData alloc] init] ;
for (int i = 0; i < count; i++) {
NSUInteger bufferSize = MIN(length, dataLength - i * length);
NSData *inputData = [data subdataWithRange:NSMakeRange(i * length, bufferSize)];
bzero(encData, length);//
switch (keyType) {
case QKeyTypePublic:
status = RSA_public_encrypt((int)bufferSize,
(unsigned char *)[inputData bytes],
(unsigned char *)encData,
_pubRSA,
type);
break;
case QKeyTypePrivate:
status = RSA_private_encrypt((int)bufferSize,
(unsigned char*)[inputData bytes],
(unsigned char*)encData,
_priRSA,
type);
break;
}
if (status > 0){// status -1 >0
[encryptedData appendBytes:encData length:status];
}else{
if (encData) {
free(encData);
}
return nil;
}
}
if (encData){
free(encData);
}
return encryptedData;
}
五、感謝
同じ鍵セットで作成されたSecKeyRefとRSAは、互いに復号化することができる.
コードの実現の過程の中で、多くのコードの参考を探して、一部は直接借りて、数日かかりました.本文で書いたコード全体が実現した後、参考にした文章のリンクはここで一つ一つ列挙することができなくて、とても感謝しています.
暗号化と署名
PS:補足、2018年3月23日暗号化:データに対して機密性保護を行う;対称暗号化、公開鍵暗号化、秘密鍵暗号化の3つの方法があります.3つの方法は、いずれも許容できない欠点があるため、それらを組み合わせて使用する.主に以下のプロセスを行います.
署名:主に認証に使用されます.データの整合性、一貫性、およびデータ・ソースの信頼性を保証します.主に以下のプロセスを行います.