RSA是一种非对称加密算法,使用公钥加密就可以使用私钥解密,使用私钥加密就可以使用公钥解密。RSA公钥对外公开,私钥自己保留。RSA既能加密、解密,也能加签、验签
加密解密:RSA是公钥加密,私钥私密。数据发送方使用接收方的公钥来对数据进行加密,接收方接收到数据之后用自己的私钥解密
加签验签:RSA私钥加签,公钥验签。数据发送方使用自己的私钥对数据进行签名,数据接收方使用数据发送方的公钥来验签。
我遇到的业务场景是:服务端接口开发人员给了我一套客户端的PKCS1格式的私钥字符串和服务端的公钥字符串。我给服务端发送数据的时候要使用私钥对数据进行签名之后再发送。接收到服务端返回的数据之后要使用服务端的公钥验签。下面接详细讲解在iOS上SHA1WithRSA的实现过程。


在数据传输的过程中如果原文是以明文的形式传输,数据还是会被泄漏。所以我这里对原文数据进行了一次AES加密,然后再走加签的流程
下面讲解iOS中使用Security.framework系统框架来实现RSA相关功能,以及使用<CommonCrypto/CommonDiges.h> 下的CC_SHA1实现sha1算法
- PKCS1格式的RSA私钥的字符串转SecKeyRef
- 公钥字符串转SeckeyRef
- SHA1算法的实现
- 使用RSA私钥签名的实现
- 使用RSA公钥验签的实现
将
PKCS#1格式的RSA私钥转成可供Security.framework框架中使用的SecKeyRef
+ (SecKeyRef)addPrivateKey:(NSString *)key{
// This is a base64 encoded key. so, decode it.
NSData *data = [[NSData alloc] initWithBase64EncodedString:key options:NSDataBase64DecodingIgnoreUnknownCharacters];
if(!data){ return nil; }
//a tag to read/write keychain storage
NSString *tag = @"RSA_PRIVATE_KEY";
NSData *d_tag = [NSData dataWithBytes:[tag UTF8String] length:[tag length]];
// Delete any old lingering key with the same tag
NSMutableDictionary *privateKey = [[NSMutableDictionary alloc] init];
[privateKey setObject:(__bridge id) kSecClassKey forKey:(__bridge id)kSecClass];
[privateKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
[privateKey setObject:d_tag forKey:(__bridge id)kSecAttrApplicationTag];
SecItemDelete((__bridge CFDictionaryRef)privateKey);
// Add persistent version of the key to system keychain
[privateKey setObject:data forKey:(__bridge id)kSecValueData];
[privateKey setObject:(__bridge id) kSecAttrKeyClassPrivate forKey:(__bridge id)kSecAttrKeyClass];
[privateKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnPersistentRef];
CFTypeRef persistKey = nil;
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)privateKey, &persistKey);
if (persistKey != nil){ CFRelease(persistKey); }
if ((status != noErr) && (status != errSecDuplicateItem)) { return nil; }
[privateKey removeObjectForKey:(__bridge id)kSecValueData];
[privateKey removeObjectForKey:(__bridge id)kSecReturnPersistentRef];
[privateKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
[privateKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
// Now fetch the SecKeyRef version of the key
SecKeyRef keyRef = nil;
status = SecItemCopyMatching((__bridge CFDictionaryRef)privateKey, (CFTypeRef *)&keyRef);
if(status != noErr){
return nil;
}
return keyRef;
}
+ (SecKeyRef)addPublicKey:(NSString *)pubKey
{
NSData *data = [[NSData alloc] initWithBase64EncodedString:pubKey options:NSDataBase64DecodingIgnoreUnknownCharacters];
//a tag to read/write keychain storage
NSString *tag = @"RSA_PUBLIC_KEY";
NSData *d_tag = [NSData dataWithBytes:[tag UTF8String] length:[tag length]];
// Delete any old lingering key with the same tag
NSMutableDictionary *publicKey = [[NSMutableDictionary alloc] init];
[publicKey setObject:(__bridge id) kSecClassKey forKey:(__bridge id)kSecClass];
[publicKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
[publicKey setObject:d_tag forKey:(__bridge id)kSecAttrApplicationTag];
SecItemDelete((__bridge CFDictionaryRef)publicKey);
// Add persistent version of the key to system keychain
[publicKey setObject:data forKey:(__bridge id)kSecValueData];
[publicKey setObject:(__bridge id) kSecAttrKeyClassPublic forKey:(__bridge id)kSecAttrKeyClass];
[publicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnPersistentRef];
CFTypeRef persistKey = nil;
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)publicKey, &persistKey);
if (persistKey != nil){
CFRelease(persistKey);
}
if ((status != noErr) && (status != errSecDuplicateItem)) { return nil; }
[publicKey removeObjectForKey:(__bridge id)kSecValueData];
[publicKey removeObjectForKey:(__bridge id)kSecReturnPersistentRef];
[publicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
[publicKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
// Now fetch the SecKeyRef version of the key
SecKeyRef keyRef = nil;
status = SecItemCopyMatching((__bridge CFDictionaryRef)publicKey, (CFTypeRef *)&keyRef);
if(status != noErr){
return nil;
}
return keyRef;
}
// digest message with sha1
+ (NSData *)sha1:(NSString *)str
{
const void *data = [str cStringUsingEncoding:NSUTF8StringEncoding];
CC_LONG len = (CC_LONG)strlen(data);
uint8_t * md = malloc( CC_SHA1_DIGEST_LENGTH * sizeof(uint8_t) );;
CC_SHA1(data, len, md);
return [NSData dataWithBytes:md length:CC_SHA1_DIGEST_LENGTH];
}
// Using the RSA private key to sign the specified message
+ (NSString *)sign:(NSString *)content withPriKey:(NSString *)priKey
{
SecKeyRef privateKeyRef = [self addPrivateKey:priKey];
if (!privateKeyRef) { NSLog(@"添加私钥失败"); return nil; }
NSData *sha1Data = [self sha1:content];
unsigned char *sig = (unsigned char *)malloc(256);
size_t sig_len;
OSStatus status = SecKeyRawSign(privateKeyRef, kSecPaddingPKCS1SHA1, [sha1Data bytes], CC_SHA1_DIGEST_LENGTH, sig, &sig_len);
if (status != noErr) { NSLog(@"加签失败:%d",status); return nil; }
NSData *outData = [NSData dataWithBytes:sig length:sig_len];
return [outData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
}
// verify Signature
+ (BOOL)verify:(NSString *)content signature:(NSString *)signature withPublivKey:(NSString *)publicKey {
SecKeyRef publicKeyRef = [self addPublicKey:publicKey];
if (!publicKeyRef) { NSLog(@"添加公钥失败"); return NO; }
NSData *originData = [self sha1:content];
NSData *signatureData = [[NSData alloc] initWithBase64EncodedString:signature options:NSDataBase64DecodingIgnoreUnknownCharacters];
if (!originData || !signatureData) { return NO; }
OSStatus status = SecKeyRawVerify(publicKeyRef, kSecPaddingPKCS1SHA1, [originData bytes], originData.length, [signatureData bytes], signatureData.length);
if (status ==noErr) { return YES; }
else{ NSLog(@"验签失败:%d",status); return NO; }
}
完整的示例代码可以在GitHub上查看
本文介绍的加签是基于RSA的PKCS#1格式的私钥来完成。如实你使用的是PKCS#8格式的私钥请参考另一个库Encrypt。关于RSA私钥的格式请自行百度了解。关于PKCS1转PKCS8请看这篇文章RSA私钥PKCS1 转 PKCS8
我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha
我想生成SHA512散列密码以直接包含在/etc/shadow文件中以与chef'suserresource一起使用.通常我会为此访问stdlib的Digest库,但它不会以正确的格式生成哈希:ruby-1.9.2-p136:001>require'digest/sha2'=>trueruby-1.9.2-p136:002>Digest::SHA512.hexdigest('test')=>"ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b1437
Ruby最近停止在我兄弟的机器上工作。gem命令rails服务器rails控制台全部失败并出现以下错误:$irbirb(main):001:0>require'digest/sha1'LoadError:dlopen(~/.rbenv/versions/2.0.0-p0/lib/ruby/2.0.0/x86_64-darwin12.2.0/digest/sha1.bundle,9):Symbolnotfound:_rb_Digest_SHA1_FinishReferencedfrom:~/.rbenv/versions/2.0.0-p0/lib/ruby/2.0.0/x86_64-da
我正在尝试测试来自ankoder.com的APIauthenticationtoken的摘要计算有问题.当我尝试从C#调用时,示例是ruby。当我比较HMAC-SHA1中的摘要结果时,我发现key结果有问题。为了便于测试这里是代码:require'hmac-sha1'require'digest/sha1'require'base64'token="-Sat,14Nov200909:47:53GMT-GET-/video.xml-"private_key="whatever"salt=Digest::SHA1.hexdigest(token)[0..19]passkey=Base64.
我正在尝试找出与我拥有的小型ruby脚本等效的shell脚本。这是ruby脚本:require'openssl'require'base64'k=OpenSSL::PKey::RSA.new(File.read("key.pem"))res=File.read("res.tmp")digest=OpenSSL::Digest::SHA256.newsignature=k.sign(digest,res)File.write("foo1.txt",Base64.strict_encode64(signature))就是这样。它需要一些数据,获取它的SHA256哈希值,然后用我拥有的私
我在浏览亚马逊产品广告APIRESTsignaturedocs时卡在了#8CalculateanRFC2104-compliantHMACwiththeSHA256hashalgorithmusingthestringabovewithour"dummy"SecretAccessKey:1234567890.Formoreinformationaboutthisstep,seedocumentationandcodesamplesforyourprogramminglanguage.没关系,在CalculatingaSHAhashwithastring+secretkeyinpytho
我正在尝试应用HMAC-SHA256为RestAPI生成key。我正在做这样的事情:defgenerateTransactionHash(stringToHash)key='123'data='stringToHash'digest=OpenSSL::Digest.new('sha256')hmac=OpenSSL::HMAC.digest(digest,key,data)putshmacend它的输出始终是这样的:(如果我将“12345”作为参数或“HUSYED815X”,我会得到相同的结果)ۯw/{o���p�T����:��a�h��E|qAPI因此无法正常工作...有人可以帮我
我有一个Cocoa应用程序将一些数据连同该数据的SHA1哈希值一起发送到Rails应用程序,该应用程序验证数据和哈希值是否匹配,但它们不匹配。为了确保我已经记录了在Rails和Cocoa端散列到控制台的数据的十六进制版本,并且它们完全匹配。这是Cocoa部分:#import//...-(NSData*)dataOfSHA1Hash{unsignedcharhashBytes[CC_SHA1_DIGEST_LENGTH];CC_SHA1([selfbytes],CC_SHA1_DIGEST_LENGTH,hashBytes);return[NSDatadataWithBytes:hash
我正在编写一个小的ruby程序来通过OAuth与Twitter一起玩,但还没有找到一个正确的方法来进行HMAC-SHA1签名。到目前为止,我搞砸了Base64.encode64(OpenSSL::HMAC.hexdigest(digest,key,stuff)).chomp但这会输出Twitter拒绝的内容,而不是有效签名。我实际上以更糟糕的方式解决了它,请不要打我耳光:php-r"echorawurlencode(base64_encode(hash_hmac('sha1','#{@signature}','#{llave}',true)));"最后一个确实有效,我可以四处做我的
我想知道如何使用Capistrano在Git中针对特定的提交SHA进行部署?应该是这样的capdeploy--version=经过大量搜索似乎无法找到这个问题的答案。 最佳答案 对于Capistrano2.9到3.0:cap-Srevision=80655da8d80aaaf92ce5357e7828dc09adb00993deploy对于旧版本的Capistrano,您可以通过执行以下操作来部署特定的gitcommit/tree/branch/tag:cap-sbranch=80655da8d80aaaf92ce5357e7828