加密整理


引言:

根據相關資料(上半部之哈希/下半部之對稱和非對稱加密)進行整理,方便以后回顧和查閱......

  1. Base64
  2. MD5、SHA1、SHA256、SHA512、HMAC
  3. AES
  4. RSA

一、Base64

1. 算法介紹

Base64是網絡上最常見的用于傳輸8Bit字節代碼的編碼方式之一,大家可以查看RFC2045~RFC2049,上面有MIME的詳細規范。Base64編碼可用于在HTTP環境下傳遞較長的標識信息。個人感覺Base64僅僅是一種編碼方式(%02X)而不是加密方式如同UTF-8。
它使用 2 的最大次方來代表僅可打印的ASCII字符。在 Base64 中的變量使用字符 A—Z、a—z 和 0 —9 共 62 個字符 , 用來作為 Base64 編碼表中的 64 碼 , 最后兩個用作為數字的符號在不同的系統中而不同。Base64 編碼轉換的時候,將三個字節的數據 , 先后放入 24 位的緩沖區中 , 先來的字節占高位。如果數據不足 3 個字節 , 將緩沖區中剩下的位用 0 補足。然后 , 每次取出 6 位,按照其值選擇ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ 中的字符作為編碼后的輸出。不斷進行 , 直到全部輸入數據轉換完成。
Base64 要求把每三個 8Bit 的字節按照每 6Bit 一組的長度分割成四組(3 X 8 = 4 X 6 = 24),然后給每組 6Bit 的數據添加兩位高位 0,組成四個新的 8Bit 的字節。也就是說, 轉換后的字符串理論上將要比原來的長 1/3。然后將新產生的四個8Bit字節根據轉換表映射為 ASCII 字符。(最后兩個字符的定義在不同的系統中有所不同)。為了保證所輸出的編碼位可讀字符,Base64制定了一個編碼表,以便進行統一轉換。編碼表的大小為2^6=64,這也是Base64名稱的由來。

Base64編碼表

如果原文的字節數不是 3 的倍數,即轉換到最后 部分時 bit 數不夠 6 的倍數時我們規定,不足的 bit 位 使用全 0 來補足,轉換后需要在密文的末尾添加 = 號來標注。如果原文剩余 1 字節(即需要補足 4 位 0), 那么就在密文末尾添加兩個 = 號,如果原文剩余 2 字節(即需要補足 2 位 0),則添加一個 = 號。

2. 上代碼。。。。

在iOS7之前我們一般用的都是第三方框架,比如nicklockwood寫的Base64框架還有Google的GTMBase64,雖然蘋果有了自己的實現,但是許多其它的加密框架都用到了它,所以還是要了解一下,另外它還提供任意長度字符插入\r\n
,而蘋果只能是64或76長度。

Base64存儲方式(重要):

  • 可見字符串形式
    為了保證所輸出的每一個編碼字節都是可讀字符,而不是0~63這些數字,Base64制作了一個碼表,就像ASCII碼表一樣,每一個Base64碼值都有對應的字符。64個可讀字符從0到63非別是A-Z、a-z、0-9、+、/,這也是Base64名字的由來。

  • 以16進制形式
    即NSData形式保存,Base64編碼結果為字符,而這些字符又對應ASCII碼表的碼值,NSData就是存儲ASCII碼表的碼值。

示例: 蘋果原生API->NSData的擴展:NSData (NSDataBase64Encoding)

假設我們對字符串"123"進行Base64編碼,"123"對應的16進制是313233,二進制為00110001 00110010 00110011,將其變為4*** 6結果即下表中的第一行。然后根據Base64的碼表,它們分別對應表中的第二行。那么"123"編碼的最終結果即為MTIz,以字符串的形式保存。然后根據MTIz對應ASCII碼值,以NSData形式存儲,如表中的第三行。

轉換為4*6結果 00001100 00010011 00001000 00110011
Base64對應字符 M T I z
對應ASCII碼值(16進制) 4d 54 49 7a

上面的過程通過代碼實現如下:

//1 待編碼的原始字符串
NSString *plainStr = @"123";
// 2 將其轉換成NSData保存,那么"123"對應的ASCII碼表碼值是31、32、33(16進制)
NSData *plainData = [plainStr dataUsingEncoding:NSUTF8StringEncoding];
// 3.1 將其進行Base64編碼,且結果以字符串形式保存,對應表中的第二行
NSString *baseStr = [plainData base64EncodedStringWithOptions:0];
// 3.2 將其進行Base64編碼,且結果以NSData形式保存
NSData *base64Data = [plainData base64EncodedDataWithOptions:0];

另外對于參數NSDataBase64EncodingOptions選項,有多種取值

  • NSDataBase64Encoding64CharacterLineLength:每64個字符插入\r或\n
  • NSDataBase64Encoding76CharacterLineLength:每76個字符插入\r或\n,標準中有要求是76個字符要換行,不過具體還是自己定
  • NSDataBase64EncodingEndLineWithCarriageReturn:插入字符為\r
  • NSDataBase64EncodingEndLineWithLineFeed:插入字符為\n

前兩個選項為是否允許插入字符,以及多少個字符長度插入,兩個可以選其一或者都不選。后兩個選項代表要插入的具體字符。比如我們想76個字符后插入一個\r則可以NSDataBase64Encoding76CharacterLineLength | NSDataBase64EncodingEndLineWithCarriageReturn
。而在上面舉的例子中選項為0,則代表不插入字符。

二、MD5、SHA1、SHA256、SHA512、HMAC

實質是抽取特征碼,這樣一般不會重復!不同的文本它的哈希結果是有可能相同的,但概率很小。(舉例:比如想要識別一個人,我們可以通過他的指紋來鎖定他,指紋出現相同的概率很低吧!在這里,人就相當于數據,而指紋就相當于對人這個數據進行hash后得到的結果)
對任意一個二進制數據進行哈希,可以得到定長的字符串結果,例如MD5哈希結果是128bit,更多是以32個字符的十六進制格式哈希輸出
還有就是不可逆的,既然是不可逆的,那么當然不是用來加密的,而是簽名
以MD5為例說明:(SHA實現換湯不換藥,更換實現中的數據格式以及加密算法就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];
}

補充說明:

  1. MD5一些算法
  1. 以NSData輸出,是以dataWithBytes:length:方法獲取(byte和長度)
  1. 以NSString輸出,蘋果沒有相關的方法提供,見下面實現
+ (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是密鑰相關的哈希運算消息認證碼(Hash-based Message Authentication Code),HMAC運算利用哈希算法,以一個密鑰和一個消息為輸入,生成一個消息摘要作為輸出。個人感覺有秘鑰會更安全一點,但是HTTPS才是以后發展王道。。。。。下面實現有字符串輸出的依然參考上面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種操作:字節替代(SubBytes)行移位(ShiftRows)列混淆(MixColumns)輪密鑰加(AddRoundKey)。解密過程分別為對應的逆操作。由于每一步操作都是可逆的,按照相反的順序進行解密即可恢復明文。加解密中每輪的密鑰分別由初始密鑰擴展得到。算法中16字節的明文、密文和輪密鑰都以一個4x4的矩陣表示。
說明:AES根據秘鑰的長度不同分為AES128、AES129、AES256;AES細分又有很多加密模式(ECB、CBC、CFB、OFB),一般開發常用的有ECB和CBC。

  • ECB(Electronic Code Book,電子密碼本)模式
    是一種基礎的加密方式,要加密的數據被分割成分組長度相等的塊,不足補齊,然后單獨的一個個組加密,合在一起輸出組成密文。
    優點: 1.簡單; 2.有利于并行計算; 3.誤差不會被擴散;
    缺點: 1.不能隱藏明文的模式; 2.可能對明文進行主動攻擊;
    因此,此模式適于加密小消息。
  • CBC(Cipher Block Chaining,加密塊鏈)模式
    是一種循環模式,也將要加密的數據分割為長度相等的組,不足補齊,前一個分組的密文和當前分組的明文異或操作后再加密,這樣做的目的是增強破解難度,會比ECB安全一點。
    優點: 不容易主動攻擊,安全性好于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];
}

補充說明:
這個運算會根據傳入key的長度進行識別,只是加密的輪數不同

- (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

使用說明

假設A、B雙方均擁有一對公私鑰(PUB_APRI_APUB_BPRI_B)。

A向B發送Message的整個簽名和加密的過程如下:

  1. A先使用HASH對Message生成一個固定長度的信息摘要Message_hash_A
  2. A使用A的私鑰PRI_AMessage_hash_A進行簽名得到Message_sign(這里為什么不直接對Message進行簽名,而要對Message_hash_A進行簽名呢?因為Message的長度可能很長,而Message_hash_A的長度則是固定的,這樣性能更高,格式也固定,況且hash的結果一般不會出現重復的可能)
  3. A接著使用B的公鑰PUB_B對信息Message和信息Message_sign進行加密得到Message_RSA,這時A將Message_RSA發送給B。

當B接收到A的信息Message_RSA后,獲取Message的步驟如下:

  1. B用自己的私鑰PRI_B解密得到明文:MessageMessage_sign
  2. 然后B使用A的公鑰PUB_AMessage_sign得到Message_hash_A;同時,B再對Message使用與A相同的HASH得到Message_hash_B
  3. 如果Message_hash_AMessage_hash_B相同,則說明Message沒有被篡改過。

秘鑰生成方法
先cd 一個文件夾 生成的pem文件就在這個文件夾下面,以文本編輯器方式打開。。。。。

  • 生成私鑰,1024bit,PKCS1Padding格式,Base64編碼
命令行:openssl genrsa -out rsa_private_key.pem 1024

結果如下:
-----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-----
  • 根據上面的私鑰生成公鑰
命令行:openssl rsa -in rsa_private_key.pem -out rsa_public_key.pem -pubout

結果如下:
-----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

結果:
-----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-----
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,835評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,676評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,730評論 0 380
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,118評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,873評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,266評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,330評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,482評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,036評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,846評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,025評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,575評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,279評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,684評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,953評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,751評論 3 394
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,016評論 2 375

推薦閱讀更多精彩內容

  • 之前的項目中接觸過一些加密的方法,也沒有太仔細的進行記錄和研究。最近在寫SDK時,加密模塊的占比相當之大;借此時機...
    大雄記閱讀 10,998評論 20 63
  • 概述 之前一直對加密相關的算法知之甚少,只知道類似DES、RSA等加密算法能對數據傳輸進行加密,且各種加密算法各有...
    Henryzhu閱讀 3,044評論 0 14
  • 這篇文章主要講述在Mobile BI(移動商務智能)開發過程中,在網絡通信、數據存儲、登錄驗證這幾個方面涉及的加密...
    雨_樹閱讀 2,566評論 0 6
  • 我們花了三年的時間學會說話,卻要用一輩子的時間學會閉嘴。可見,說話是一門藝術活,學會閉嘴更是尤為重要。 ...
    Ms_珍小姐閱讀 548評論 0 0
  • 我的母親是一位地地道道的農民,她善良,美麗,執著,熱情。曾經的我沒發現母親的美麗,隨著歲月的沉淀和閱歷的增加慢慢的...
    liu佳閱讀 223評論 0 0