引言:
根據(jù)相關(guān)資料(上半部之哈希/下半部之對稱和非對稱加密)進行整理优床,方便以后回顧和查閱......
- Base64
- MD5谴蔑、SHA1、SHA256凭豪、SHA512、HMAC
- AES
- RSA
一晒杈、Base64
1. 算法介紹
Base64是網(wǎng)絡(luò)上最常見的用于傳輸8Bit字節(jié)代碼的編碼方式之一嫂伞,大家可以查看RFC2045~RFC2049,上面有MIME的詳細規(guī)范。Base64編碼可用于在HTTP環(huán)境下傳遞較長的標識信息帖努。個人感覺Base64僅僅是一種編碼方式(%02X
)而不是加密方式如同UTF-8撰豺。
它使用 2 的最大次方來代表僅可打印的ASCII字符。在 Base64 中的變量使用字符 A—Z拼余、a—z 和 0 —9 共 62 個字符 , 用來作為 Base64 編碼表中的 64 碼 , 最后兩個用作為數(shù)字的符號在不同的系統(tǒng)中而不同污桦。Base64 編碼轉(zhuǎn)換的時候,將三個字節(jié)的數(shù)據(jù) , 先后放入 24 位的緩沖區(qū)中 , 先來的字節(jié)占高位。如果數(shù)據(jù)不足 3 個字節(jié) , 將緩沖區(qū)中剩下的位用 0 補足匙监。然后 , 每次取出 6 位,按照其值選擇ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
中的字符作為編碼后的輸出凡橱。不斷進行 , 直到全部輸入數(shù)據(jù)轉(zhuǎn)換完成。
Base64 要求把每三個 8Bit 的字節(jié)按照每 6Bit 一組的長度分割成四組(3 X 8 = 4 X 6 = 24),然后給每組 6Bit 的數(shù)據(jù)添加兩位高位 0,組成四個新的 8Bit 的字節(jié)舅柜。也就是說, 轉(zhuǎn)換后的字符串理論上將要比原來的長 1/3梭纹。然后將新產(chǎn)生的四個8Bit字節(jié)根據(jù)轉(zhuǎn)換表映射為 ASCII 字符。(最后兩個字符的定義在不同的系統(tǒng)中有所不同)致份。為了保證所輸出的編碼位可讀字符变抽,Base64制定了一個編碼表,以便進行統(tǒng)一轉(zhuǎn)換氮块。編碼表的大小為2^6=64绍载,這也是Base64名稱的由來。
如果原文的字節(jié)數(shù)不是 3 的倍數(shù),即轉(zhuǎn)換到最后 部分時 bit 數(shù)不夠 6 的倍數(shù)時我們規(guī)定,不足的 bit 位 使用全 0 來補足,轉(zhuǎn)換后需要在密文的末尾添加 = 號來標注滔蝉。如果原文剩余 1 字節(jié)(即需要補足 4 位 0), 那么就在密文末尾添加兩個 = 號,如果原文剩余 2 字節(jié)(即需要補足 2 位 0),則添加一個 = 號击儡。
2. 上代碼。蝠引。阳谍。。
在iOS7之前我們一般用的都是第三方框架螃概,比如nicklockwood寫的Base64框架還有Google的GTMBase64矫夯,雖然蘋果有了自己的實現(xiàn),但是許多其它的加密框架都用到了它吊洼,所以還是要了解一下训貌,另外它還提供任意長度字符插入\r\n
,而蘋果只能是64或76長度冒窍。
Base64存儲方式(重要):
可見字符串形式
為了保證所輸出的每一個編碼字節(jié)都是可讀字符递沪,而不是0~63這些數(shù)字,Base64制作了一個碼表综液,就像ASCII碼表一樣款慨,每一個Base64碼值都有對應(yīng)的字符。64個可讀字符從0到63非別是A-Z谬莹、a-z檩奠、0-9约素、+、/笆凌,這也是Base64名字的由來。以16進制形式
即NSData形式保存士葫,Base64編碼結(jié)果為字符乞而,而這些字符又對應(yīng)ASCII碼表的碼值,NSData就是存儲ASCII碼表的碼值慢显。
示例: 蘋果原生API->NSData的擴展:NSData (NSDataBase64Encoding)
假設(shè)我們對字符串"123"進行Base64編碼爪模,"123"對應(yīng)的16進制是313233
,二進制為00110001 00110010 00110011
荚藻,將其變?yōu)?*** 6結(jié)果即下表中的第一行屋灌。然后根據(jù)Base64的碼表,它們分別對應(yīng)表中的第二行应狱。那么"123"編碼的最終結(jié)果即為MTIz共郭,以字符串的形式保存。然后根據(jù)MTIz對應(yīng)ASCII碼值疾呻,以NSData形式存儲除嘹,如表中的第三行。
轉(zhuǎn)換為4*6結(jié)果 | 00001100 | 00010011 | 00001000 | 00110011 |
---|---|---|---|---|
Base64對應(yīng)字符 | M | T | I | z |
對應(yīng)ASCII碼值(16進制) | 4d | 54 | 49 | 7a |
上面的過程通過代碼實現(xiàn)如下:
//1 待編碼的原始字符串
NSString *plainStr = @"123";
// 2 將其轉(zhuǎn)換成NSData保存岸蜗,那么"123"對應(yīng)的ASCII碼表碼值是31尉咕、32、33(16進制)
NSData *plainData = [plainStr dataUsingEncoding:NSUTF8StringEncoding];
// 3.1 將其進行Base64編碼璃岳,且結(jié)果以字符串形式保存年缎,對應(yīng)表中的第二行
NSString *baseStr = [plainData base64EncodedStringWithOptions:0];
// 3.2 將其進行Base64編碼,且結(jié)果以NSData形式保存
NSData *base64Data = [plainData base64EncodedDataWithOptions:0];
另外對于參數(shù)NSDataBase64EncodingOptions選項铃慷,有多種取值
- NSDataBase64Encoding64CharacterLineLength:每64個字符插入\r或\n
- NSDataBase64Encoding76CharacterLineLength:每76個字符插入\r或\n单芜,標準中有要求是76個字符要換行,不過具體還是自己定
- NSDataBase64EncodingEndLineWithCarriageReturn:插入字符為\r
- NSDataBase64EncodingEndLineWithLineFeed:插入字符為\n
前兩個選項為是否允許插入字符枚冗,以及多少個字符長度插入缓溅,兩個可以選其一或者都不選。后兩個選項代表要插入的具體字符赁温。比如我們想76個字符后插入一個\r則可以NSDataBase64Encoding76CharacterLineLength | NSDataBase64EncodingEndLineWithCarriageReturn
坛怪。而在上面舉的例子中選項為0,則代表不插入字符股囊。
二袜匿、MD5、SHA1稚疹、SHA256居灯、SHA512祭务、HMAC
實質(zhì)是抽取特征碼,這樣一般不會重復(fù)怪嫌!不同的文本它的哈希結(jié)果是有可能相同的义锥,但概率很小。(舉例:比如想要識別一個人岩灭,我們可以通過他的指紋來鎖定他拌倍,指紋出現(xiàn)相同的概率很低吧!在這里噪径,人就相當于數(shù)據(jù)柱恤,而指紋就相當于對人這個數(shù)據(jù)進行hash后得到的結(jié)果)
對任意一個二進制數(shù)據(jù)進行哈希,可以得到定長的字符串結(jié)果找爱,例如MD5哈希結(jié)果是128bit梗顺,更多是以32個字符的十六進制格式哈希輸出
還有就是不可逆的,既然是不可逆的车摄,那么當然不是用來加密的寺谤,而是簽名
以MD5為例說明:(SHA實現(xiàn)換湯不換藥,更換實現(xiàn)中的數(shù)據(jù)格式以及加密算法就ok了)
+ (NSString *)md5EncryptStringWithString:(NSString *)str{
const char *plain = str.UTF8String;
unsigned char *digest;
digest = malloc(CC_SHA1_DIGEST_LENGTH);
CC_MD5(plain, (CC_LONG)strlen(plain), digest);
NSString *encode = [self stringFromBytes:digest length:CC_MD5_DIGEST_LENGTH];
free(digest);
return encode;
}
+ (NSString *)md5EncryptStringWithData:(NSData *)data{
unsigned char *digest;
digest = malloc(CC_SHA1_DIGEST_LENGTH);
CC_MD5(data.bytes, (CC_LONG)data.length, digest);
NSString *encode = [self stringFromBytes:digest length:CC_MD5_DIGEST_LENGTH];
free(digest);
return encode;
}
+ (NSData *)md5EncryptDataWithString:(NSString *)str{
const char *plain = str.UTF8String;
unsigned char result[CC_MD5_DIGEST_LENGTH];
CC_MD5(plain, (CC_LONG)strlen(plain), result);
return [[NSData alloc] initWithBytes:result length:CC_MD5_DIGEST_LENGTH];
}
+ (NSData *)md5EncryptDataWithData:(NSData *)data{
unsigned char result[CC_MD5_DIGEST_LENGTH];
CC_MD5(data.bytes, (CC_LONG)data.length, result);
return [NSData dataWithBytes:result length:CC_MD5_DIGEST_LENGTH];
}
補充說明:
MD5一些算法
- 以NSData輸出练般,是以
dataWithBytes:length:
方法獲却Q(byte和長度)
- 以NSString輸出,蘋果沒有相關(guān)的方法提供薄料,見下面實現(xiàn)
+ (NSString *)stringFromBytes:(uint8_t *)bytes length:(int)length {
NSMutableString *strM = [NSMutableString string];
for (int i = 0; i < length; i++) {
//此處%02X中X的大小寫決定了輸出字母的大小寫
[strM appendFormat:@"%02X", bytes[i]];
}
return [strM copy];
}
以HMACMD5為例說明HAMAC:
HMAC是密鑰相關(guān)的哈希運算消息認證碼(Hash-based Message Authentication Code),HMAC運算利用哈希算法敞贡,以一個密鑰和一個消息為輸入,生成一個消息摘要作為輸出摄职。個人感覺有秘鑰會更安全一點誊役,但是HTTPS才是以后發(fā)展王道。谷市。蛔垢。。迫悠。下面實現(xiàn)有字符串輸出的依然參考上面stringFromBytes:length:
+ (NSString *)hmacMD5EncryptStringWithString:(NSString *)str andKey:(NSString *)key{
const char *keyData = key.UTF8String;
const char *strData = str.UTF8String;
uint8_t buffer[CC_MD5_DIGEST_LENGTH];
CCHmac(kCCHmacAlgMD5, keyData, strlen(keyData), strData, strlen(strData), buffer);
return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH];
}
+ (NSString *)hmacMD5EncryptStringWithData:(NSData *)data andKey:(NSString *)key{
const char *keyData = key.UTF8String;
// const char *strData = str.UTF8String
uint8_t buffer[CC_MD5_DIGEST_LENGTH];
CCHmac(kCCHmacAlgMD5, keyData, strlen(keyData), [data bytes], [data length], buffer);
return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH];
}
+ (NSData *)hmacMD5EncryptDataWithString:(NSString *)str andKey:(NSString *)key{
const char *keyData = key.UTF8String;
const char *strData = str.UTF8String;
unsigned char hash[CC_MD5_DIGEST_LENGTH];
CCHmac(kCCHmacAlgMD5, keyData, strlen(keyData), strData, strlen(strData), hash);
return ( [NSData dataWithBytes: hash length: CC_MD5_DIGEST_LENGTH] );
}
+ (NSData *)hmacMD5EncryptDataWithData:(NSData *)data andKey:(NSString *)key{
const char *keyData = key.UTF8String;
unsigned char hash[CC_MD5_DIGEST_LENGTH];
CCHmac(kCCHmacAlgMD5, keyData, strlen(keyData), data.bytes, data.length, hash);
return ( [NSData dataWithBytes: hash length: CC_MD5_DIGEST_LENGTH] );
}
三鹏漆、AES
AES加密過程涉及到4種操作:字節(jié)替代(SubBytes)、行移位(ShiftRows)创泄、列混淆(MixColumns)和輪密鑰加(AddRoundKey)艺玲。解密過程分別為對應(yīng)的逆操作。由于每一步操作都是可逆的鞠抑,按照相反的順序進行解密即可恢復(fù)明文饭聚。加解密中每輪的密鑰分別由初始密鑰擴展得到。算法中16字節(jié)的明文搁拙、密文和輪密鑰都以一個4x4的矩陣表示秒梳。
說明:AES根據(jù)秘鑰的長度不同分為AES128法绵、AES129、AES256酪碘;AES細分又有很多加密模式(ECB朋譬、CBC、CFB兴垦、OFB)此熬,一般開發(fā)常用的有ECB和CBC。
- ECB(Electronic Code Book滑进,電子密碼本)模式
是一種基礎(chǔ)的加密方式,要加密的數(shù)據(jù)被分割成分組長度相等的塊,不足補齊募谎,然后單獨的一個個組加密扶关,合在一起輸出組成密文。
優(yōu)點: 1.簡單数冬; 2.有利于并行計算节槐; 3.誤差不會被擴散;
缺點: 1.不能隱藏明文的模式拐纱; 2.可能對明文進行主動攻擊铜异;
因此,此模式適于加密小消息秸架。- CBC(Cipher Block Chaining揍庄,加密塊鏈)模式
是一種循環(huán)模式,也將要加密的數(shù)據(jù)分割為長度相等的組,不足補齊东抹,前一個分組的密文和當前分組的明文異或操作后再加密蚂子,這樣做的目的是增強破解難度,會比ECB安全一點缭黔。
優(yōu)點: 不容易主動攻擊,安全性好于ECB,適合傳輸長度長的報文,是SSL食茎、IPSec的標準。
缺點: 1.不利于并行計算馏谨; 2.誤差傳遞别渔; 3.需要初始化向量IV
AES加密
/// 默認使用kCCOptionPKCS7Padding填充
#define kPaddingMode kCCOptionPKCS7Padding
/*
默認CBC模式,返回base64編碼
*/
- (NSString *)aesEncryptWithHexKey:(NSString *)key hexIv:(NSString *)iv {
NSData *aesKey = [key dataFromHexString];
if (iv == nil) {
// 32長度
iv = @"00000000000000000000000000000000";
}
NSData *aesIv = [iv dataFromHexString];
NSData *resultData = [self aesEncryptWithDataKey:aesKey dataIv:aesIv];
return [resultData base64EncodedStringWithOptions:0];
}
/*
默認CBC模式惧互,返回base64編碼
*/
- (NSString *)aesEncryptWithKey:(NSString *)key iv:(NSString *)iv {
NSData *aesKey = [key dataUsingEncoding:NSUTF8StringEncoding];
if (iv == nil) {
// 32長度
iv = @"00000000000000000000000000000000";
}
NSData *aesIv = [iv dataUsingEncoding:NSUTF8StringEncoding];
NSData *resultData = [self aesEncryptWithDataKey:aesKey dataIv:aesIv];
return [resultData base64EncodedStringWithOptions:0];
}
/*
CBC模式哎媚,返回NSData
*/
- (NSData *)aesEncryptWithDataKey:(NSData *)key dataIv:(NSData *)iv {
return [self aesEncryptOrDecrypt:kCCEncrypt data:[self dataUsingEncoding:NSUTF8StringEncoding] dataKey:key dataIv:iv mode:kPaddingMode];
}
/*
ECB模式,返回base64編碼
*/
- (NSString *)aesECBEncryptWithHexKey:(NSString *)key {
NSData *aesKey = [key dataFromHexString];
NSData *resultData = [self aesECBEncryptWithDataKey:aesKey];
return [resultData base64EncodedStringWithOptions:0];
}
/*
ECB模式壹哺,返回base64編碼
*/
- (NSString *)aesECBEncryptWithKey:(NSString *)key {
NSData *aesKey = [key dataUsingEncoding:NSUTF8StringEncoding];
NSData *resultData = [self aesECBEncryptWithDataKey:aesKey];
return [resultData base64EncodedStringWithOptions:0];
}
/*
ECB模式抄伍,返回NSData
*/
- (NSData *)aesECBEncryptWithDataKey:(NSData *)key {
NSData *aesIv = [@"00000000000000000000000000000000" dataFromHexString];
return [self aesEncryptOrDecrypt:kCCEncrypt data:[self dataUsingEncoding:NSUTF8StringEncoding] dataKey:key dataIv:aesIv mode:kPaddingMode | kCCOptionECBMode];
}
AES解密
/*
默認CBC模式解密,默認string為base64格式
*/
- (NSString *)aesBase64StringDecryptWithHexKey:(NSString *)key hexIv:(NSString *)iv {
NSData *aesKey = [key dataFromHexString];
if (iv == nil) {
// 32長度
iv = @"00000000000000000000000000000000";
}
NSData *aesIv = [iv dataFromHexString];
NSData *data = [[NSData alloc] initWithBase64EncodedString:self options:0];
NSData *resultData = [NSString aesDecryptWithData:data dataKey:aesKey dataIv:aesIv];
return [[NSString alloc] initWithData:resultData encoding:NSUTF8StringEncoding];
}
/*
CBC模式解密管宵,返回NSData
*/
+ (NSData *)aesDecryptWithData:(NSData *)data dataKey:(NSData *)key dataIv:(NSData *)iv {
return [[NSString alloc] aesEncryptOrDecrypt:kCCDecrypt data:data dataKey:key dataIv:iv mode:kPaddingMode];
}
/*
ECB模式解密截珍,返回base64編碼
*/
- (NSString *)aesECBDecryptWithHexKey:(NSString *)key {
NSData *aesKey = [key dataFromHexString];
NSData *resultData = [self aesECBEncryptWithDataKey:aesKey];
return [[NSString alloc] initWithData:resultData encoding:NSUTF8StringEncoding];;
}
/*
ECB模式解密攀甚,返回NSData
*/
- (NSData *)aesECBDecryptWithDataKey:(NSData *)key {
NSData *aesIv = [@"00000000000000000000000000000000" dataFromHexString];
return [self aesEncryptOrDecrypt:kCCDecrypt data:[self dataUsingEncoding:NSUTF8StringEncoding] dataKey:key dataIv:aesIv mode:kPaddingMode | kCCOptionECBMode];
}
補充說明:
這個運算會根據(jù)傳入key的長度進行識別,只是加密的輪數(shù)不同
- (NSData *)aesEncryptOrDecrypt:(CCOperation)option data:(NSData *)data dataKey:(NSData *)key dataIv:(NSData *)iv mode:(int)mode{
// check length of key and iv
if ([iv length] != 16) {
@throw [NSException exceptionWithName:@"Encrypt"
reason:@"Length of iv is wrong. Length of iv should be 16(128bits)"
userInfo:nil];
}
if ([key length] != 16 && [key length] != 24 && [key length] != 32 ) {
@throw [NSException exceptionWithName:@"Encrypt"
reason:@"Length of key is wrong. Length of iv should be 16, 24 or 32(128, 192 or 256bits)"
userInfo:nil];
}
// setup output buffer
size_t bufferSize = [data length] + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
// do encrypt
size_t encryptedSize = 0;
CCCryptorStatus cryptStatus = CCCrypt(option,
kCCAlgorithmAES128,
mode,
[key bytes], // Key
[key length], // kCCKeySizeAES
[iv bytes], // IV
[data bytes],
[data length],
buffer,
bufferSize,
&encryptedSize);
NSData *resultData = nil;
if (cryptStatus == kCCSuccess) {
NSData *resultData = [NSData dataWithBytes:buffer length:encryptedSize];
free(buffer);
return resultData;
} else {
free(buffer);
@throw [NSException exceptionWithName:@"Encrypt"
reason:@"Encrypt Error!"
userInfo:nil];
return resultData;
}
return resultData;
}
四、RSA
使用說明
假設(shè)A岗喉、B雙方均擁有一對公私鑰(PUB_A
秋度、PRI_A
、PUB_B
钱床、PRI_B
)荚斯。
A向B發(fā)送Message
的整個簽名和加密的過程如下:
- A先使用HASH對
Message
生成一個固定長度的信息摘要Message_hash_A
- A使用A的私鑰
PRI_A
對Message_hash_A
進行簽名得到Message_sign
(這里為什么不直接對Message
進行簽名,而要對Message_hash_A
進行簽名呢查牌?因為Message
的長度可能很長事期,而Message_hash_A
的長度則是固定的,這樣性能更高纸颜,格式也固定兽泣,況且hash的結(jié)果一般不會出現(xiàn)重復(fù)的可能) - A接著使用B的公鑰PUB_B對信息
Message
和信息Message_sign
進行加密得到Message_RSA
,這時A將Message_RSA
發(fā)送給B胁孙。
當B接收到A的信息Message_RSA
后唠倦,獲取Message
的步驟如下:
- B用自己的私鑰
PRI_B
解密得到明文:Message
和Message_sign
; - 然后B使用A的公鑰
PUB_A
解Message_sign
得到Message_hash_A
涮较;同時稠鼻,B再對Message
使用與A相同的HASH得到Message_hash_B
; - 如果
Message_hash_A
與Message_hash_B
相同狂票,則說明Message
沒有被篡改過候齿。
秘鑰生成方法
先cd 一個文件夾 生成的pem文件就在這個文件夾下面,以文本編輯器方式打開闺属。毛肋。。屋剑。润匙。
- 生成私鑰,1024bit唉匾,PKCS1Padding格式,Base64編碼
命令行:openssl genrsa -out rsa_private_key.pem 1024
結(jié)果如下:
-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQDOxoZIsFbFMeR0OWnc/sF5A3Gj0BWsoClQW3BKgvMQ85ZXVCM6
7g6XItl5sSW2EyMaIeQ8tRsM0HI4oCvlOMjSVgdyZmqbUfaZDoDYPW2pDbLqMDr/
o1eKxYpssbAyH6ZDyJeTOEu9yF7XUsIilokzc0D9i+uPc8yp/vLYTPDJEQIDAQAB
AoGAFUMevcy8L2zQ9A6PTzU3Cc2L2u9juyuA9A1i/5Z1jhGuLO6u7Llb8LiZqkTH
/u/61Q4VHRT2YhvxEteNi/WJ2L+1wTZYWbE/NIHBls4dTDt4aiMGUG2y6uBcFPmB
97sjT3ofcOHVZuFc80ktyhVuvx5osB8obZHbjn+3hn/pIF0CQQDx1bollu3XXL08
YJrS1mpB3F/87HXcxDa0dWUoqBRUCPjqC+8SuxaddPK6RFvkb1UyWJNzQ5Mb3OZt
65/sipdDAkEA2uMWf0ukTRhxiEYhZIJDSaERYeaWFU+mc6mC2//Tcvy7hldBe15n
7UQNKWl7DbI3Z7NmuKPa+rWqwASqtBAHGwJAOav7iW1V6Q8fvd9X7MHfczdn2LxX
Wz+bwCti5XA38NZ27fHMoM3nFcPHAu68b1yxl6ESAOHzmihy93HCoLloWwJARodX
j2rTJRhUNMHMLrOedNIWZMJE59cDXk9nX/X9rxZqYi4pZlQUDqqXxxk60j3zhlGT
Lrl1bMUuoLKgQmbLswJAIfv1Vw18YcEexWPBkn5iKufu0Fo7+Z776lDLYP1kNyQZ
eohofAAWYNQvHZ4WTpiIxi2FZ9xIRu+M7smsIs0h2g==
-----END RSA PRIVATE KEY-----
- 根據(jù)上面的私鑰生成公鑰
命令行:openssl rsa -in rsa_private_key.pem -out rsa_public_key.pem -pubout
結(jié)果如下:
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOxoZIsFbFMeR0OWnc/sF5A3Gj
0BWsoClQW3BKgvMQ85ZXVCM67g6XItl5sSW2EyMaIeQ8tRsM0HI4oCvlOMjSVgdy
ZmqbUfaZDoDYPW2pDbLqMDr/o1eKxYpssbAyH6ZDyJeTOEu9yF7XUsIilokzc0D9
i+uPc8yp/vLYTPDJEQIDAQAB
-----END PUBLIC KEY-----
- 將私鑰生成pkcs8格式孕讳,可在iOS工程中直接使用
openssl pkcs8 -topk8 -in rsa_private_key.pem -out pkcs8_rsa_private_key.pem -nocrypt
結(jié)果:
-----BEGIN PRIVATE KEY-----
MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAM7GhkiwVsUx5HQ5
adz+wXkDcaPQFaygKVBbcEqC8xDzlldUIzruDpci2XmxJbYTIxoh5Dy1GwzQcjig
K+U4yNJWB3JmaptR9pkOgNg9bakNsuowOv+jV4rFimyxsDIfpkPIl5M4S73IXtdS
wiKWiTNzQP2L649zzKn+8thM8MkRAgMBAAECgYAVQx69zLwvbND0Do9PNTcJzYva
72O7K4D0DWL/lnWOEa4s7q7suVvwuJmqRMf+7/rVDhUdFPZiG/ES142L9YnYv7XB
NlhZsT80gcGWzh1MO3hqIwZQbbLq4FwU+YH3uyNPeh9w4dVm4VzzSS3KFW6/Hmiw
HyhtkduOf7eGf+kgXQJBAPHVuiWW7ddcvTxgmtLWakHcX/zsddzENrR1ZSioFFQI
+OoL7xK7Fp108rpEW+RvVTJYk3NDkxvc5m3rn+yKl0MCQQDa4xZ/S6RNGHGIRiFk
gkNJoRFh5pYVT6ZzqYLb/9Ny/LuGV0F7XmftRA0paXsNsjdns2a4o9r6tarABKq0
EAcbAkA5q/uJbVXpDx+931fswd9zN2fYvFdbP5vAK2LlcDfw1nbt8cygzecVw8cC
7rxvXLGXoRIA4fOaKHL3ccKguWhbAkBGh1ePatMlGFQ0wcwus5500hZkwkTn1wNe
T2df9f2vFmpiLilmVBQOqpfHGTrSPfOGUZMuuXVsxS6gsqBCZsuzAkAh+/VXDXxh
wR7FY8GSfmIq5+7QWjv5nvvqUMtg/WQ3JBl6iGh8ABZg1C8dnhZOmIjGLYVn3EhG
74zuyawizSHa
-----END PRIVATE KEY-----