加密整理


引言:

根据相关资料(上半部之哈希/下半部之对称和非对称加密)进行整理,方便以后回顾和查阅......

  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阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容

  • 之前的项目中接触过一些加密的方法,也没有太仔细的进行记录和研究。最近在写SDK时,加密模块的占比相当之大;借此时机...
    大雄記阅读 10,899评论 20 63
  • 概述 之前一直对加密相关的算法知之甚少,只知道类似DES、RSA等加密算法能对数据传输进行加密,且各种加密算法各有...
    Henryzhu阅读 2,931评论 0 14
  • 这篇文章主要讲述在Mobile BI(移动商务智能)开发过程中,在网络通信、数据存储、登录验证这几个方面涉及的加密...
    雨_树阅读 2,235评论 0 6
  • 我们花了三年的时间学会说话,却要用一辈子的时间学会闭嘴。可见,说话是一门艺术活,学会闭嘴更是尤为重要。 ...
    Ms_珍小姐阅读 520评论 0 0
  • 我的母亲是一位地地道道的农民,她善良,美丽,执着,热情。曾经的我没发现母亲的美丽,随着岁月的沉淀和阅历的增加慢慢的...
    liu佳阅读 209评论 0 0