ESP32学习笔记(47)——加密算法AES/MD5/SHA

一、简介

1.1 SSL

SSL:(Secure Socket Layer,安全套接字层),位于可靠的面向连接的网络层协议和应用层协议之间的一种协议层。SSL通过互相认证、使用数字签名确保完整性、使用加密确保私密性,以实现客户端和服务器之间的安全通讯。该协议由两层组成:SSL记录协议和SSL握手协议。

1.2 TLS

TLS:(Transport Layer Security,传输层安全协议),用于两个应用程序之间提供保密性和数据完整性。该协议由两层组成:TLS记录协议和TLS握手协议。

1.3 mbed TLS

乐鑫esp-idf框架集成开源的 mbedtls 加密库。mbedtls 也许是最小巧的SSL代码库。高效、便于移植和集成。支持常见的安全算法,如:AES、DES、RSA、ECC、SHA256、MD5、BASE64等等。除此之外还支持公钥证书体系。它提供了具有直观的 API 和可读源代码的 SSL 库。该工具即开即用,可以在大部分系统上直接构建它,也可以手动选择和配置各项功能。

从功能角度来看,该mbedtls分为三个主要部分:

  • SSL/TLS 协议实施。
  • 一个加密库。
  • 一个 X.509 证书处理库。

二、AES - ECB

2.1 简介

AES(Advanced Encryption Standard,高级加密标准) 又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。

ECB(Electronic Code Book电子密码本),是最早采用和最简单的模式,它将加密的数据分成若干组,每组的大小跟加密密钥长度相同,然后每组都用相同的密钥进行加密。

优点:

  • 简单;
  • 有利于并行计算;
  • 误差不会被传送;

缺点:

  • 不能隐藏明文的模式;
  • 可能对明文进行主动攻击;

因此,此模式适于加密小消息。

2.2 API说明

API 文档查看 mbed TLS源码文档

2.2.1 mbedtls_aes_init

功能 初始化指定的 AES 上下文。它必须是在使用上下文之前调用的第一个 API。
函数定义 void mbedtls_aes_init(mbedtls_aes_context * ctx)
参数 ctx:要初始化的 AES 上下文。这一定不是NULL
返回

2.2.2 mbedtls_aes_setkey_enc

功能 设置加密密钥。
函数定义 int mbedtls_aes_setkey_enc(mbedtls_aes_context * ctx, const unsigned char * key, unsigned int keybits)
参数 ctx:密钥应绑定到的 AES 上下文。它必须被初始化。
key:加密密钥。这必须是大小keybits位的可读缓冲区。
keybits:以位为单位传递的数据大小。有效的选项是:128 位 / 192位 / 256 位
返回 0 - 成功,0x0020 - 密钥长度无效

2.2.3 mbedtls_aes_crypt_ecb

功能 执行 AES 单块加密或解密操作。
它对mode参数中定义的输入数据缓冲区执行参数中定义的操作(加密或解密)input
mbedtls_aes_init()以及mbedtls_aes_setkey_enc()mbedtls_aes_setkey_dec()必须在第一次使用相同上下文调用此 API 之前调用。
函数定义 int mbedtls_aes_crypt_ecb(mbedtls_aes_context * ctx, int mode, const unsigned char input[16], unsigned char output[16])
参数 ctx:用于加密或解密的 AES 上下文。它必须被初始化并绑定到一个键。
mode:AES 操作:MBEDTLS_AES_ENCRYPTMBEDTLS_AES_DECRYPT
input:保存输入数据的缓冲区。它必须是可读的,并且16长度至少为Bytes。
output:将写入输出数据的缓冲区。它必须是可写的,并且16长度至少为Bytes。
返回 0 - 成功

2.2.4 mbedtls_aes_setkey_dec

功能 设置解密密钥。
函数定义 int mbedtls_aes_setkey_dec(mbedtls_aes_context * ctx, const unsigned char * key, unsigned int keybits)
参数 ctx:密钥应绑定到的 AES 上下文。它必须被初始化。
key:解密密钥。这必须是大小keybits位的可读缓冲区。
keybits:以位为单位传递的数据大小。有效的选项是:128 位 / 192位 / 256 位
返回 0 - 成功,0x0020 - 密钥长度无效

2.2.5 mbedtls_aes_free

功能 释放并清除指定的 AES 上下文。
函数定义 void mbedtls_aes_free(mbedtls_aes_context * ctx)
参数 ctx:要清除的 AES 上下文。如果是NULL,则此函数不执行任何操作。否则,上下文必须至少已初始化。
返回

2.3 实例

ECB模式只能实现16字节的明文加解密。

需要包含 mbedtls/aes.h

#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"

#include "mbedtls/aes.h"

void app_main(void)
{
    printf("AES-ECB 加密-数据块(128位),偏移量为0\n");

    mbedtls_aes_context aes_ctx;
    //密钥数值
    unsigned char key[16] = {'e', 'c', 'b', 'p', 'a', 's', 's', 'w', 'o', 'r', 'd', '1', '2', '3', '4'};
    //明文空间
    unsigned char plain[16] = "test1234";
    //解密后明文的空间
    unsigned char dec_plain[16] = {0};
    //密文空间
    unsigned char cipher[16] = {0};

    mbedtls_aes_init(&aes_ctx);
    mbedtls_aes_setkey_enc(&aes_ctx, key, 128);
    printf("要加密的数据: %s\n", plain);
    printf("加密的密码: %s\n", key);
    mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, plain, cipher);
    printf("加密结果,二进制表示: ");
    for(int loop = 0; loop < 16; loop++)
    {
        printf("%02x", cipher[loop]);
    }
    printf("\r\n");

    //设置解密密钥
    mbedtls_aes_setkey_dec(&aes_ctx, key, 128);
    mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_DECRYPT, cipher, dec_plain);
    printf("解密后的数据: %s\n", dec_plain);
    mbedtls_aes_free(&aes_ctx);
}

2.4 加密解密验证

在线AES-ECB加密解密:http://tool.chacuo.net/cryptaes


与网站加密后结果一致:


三、AES - CBC

3.1 简介

AES(Advanced Encryption Standard,高级加密标准) 又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。

CBC(Cipher Block Chaining,加密块链) 模式。

优点:

  • 不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准。

缺点:

  • 不利于并行计算;
  • 误差传递;
  • 需要初始化向量IV;

3.2 API说明

API 文档查看 mbed TLS源码文档

3.2.1 mbedtls_aes_init

功能 初始化指定的 AES 上下文。它必须是在使用上下文之前调用的第一个 API。
函数定义 void mbedtls_aes_init(mbedtls_aes_context * ctx)
参数 ctx:要初始化的 AES 上下文。这一定不是NULL
返回

3.2.2 mbedtls_aes_setkey_enc

功能 设置加密密钥。
函数定义 int mbedtls_aes_setkey_enc(mbedtls_aes_context * ctx, const unsigned char * key, unsigned int keybits)
参数 ctx:密钥应绑定到的 AES 上下文。它必须被初始化。
key:加密密钥。这必须是大小keybits位的可读缓冲区。
keybits:以位为单位传递的数据大小。有效的选项是:128 位 / 192位 / 256 位
返回 0 - 成功,0x0020 - 密钥长度无效

3.2.3 mbedtls_aes_crypt_cbc

功能 执行 AES-CBC 加密或解密操作。
它对mode参数中定义的输入数据缓冲区执行参数中定义的操作(加密或解密)input
mbedtls_aes_init()以及mbedtls_aes_setkey_enc()mbedtls_aes_setkey_dec()必须在第一次使用相同上下文调用此 API 之前调用。该函数对完整块进行操作,即输入大小必须是 AES 块大小的16Bytes的倍数。
函数定义 int mbedtls_aes_crypt_cbc(mbedtls_aes_context * ctx, int mode, size_t length, unsigned char iv[16], const unsigned char * input, unsigned char * output)
参数 ctx:用于加密或解密的 AES 上下文。它必须被初始化并绑定到一个键。
mode:AES 操作:MBEDTLS_AES_ENCRYPTMBEDTLS_AES_DECRYPT
length:输入数据的长度(以字节为单位)。这必须是块大小(16字节)的倍数。
iv:初始化向量(使用后更新)。它必须是一个可读可写的16字节缓冲区。
input:保存输入数据的缓冲区。它必须是可读的并且大小为lengthBytes。
output:保存输出数据的缓冲区。它必须是可写的并且大小为lengthBytes。
返回 0 - 成功

3.2.4 mbedtls_aes_setkey_dec

功能 设置解密密钥。
函数定义 int mbedtls_aes_setkey_dec(mbedtls_aes_context * ctx, const unsigned char * key, unsigned int keybits)
参数 ctx:密钥应绑定到的 AES 上下文。它必须被初始化。
key:解密密钥。这必须是大小keybits位的可读缓冲区。
keybits:以位为单位传递的数据大小。有效的选项是:128 位 / 192位 / 256 位
返回 0 - 成功,0x0020 - 密钥长度无效

3.2.5 mbedtls_aes_free

功能 释放并清除指定的 AES 上下文。
函数定义 void mbedtls_aes_free(mbedtls_aes_context * ctx)
参数 ctx:要清除的 AES 上下文。如果是NULL,则此函数不执行任何操作。否则,上下文必须至少已初始化。
返回

3.3 实例

CBC能实现大于16字节的明文加解密,前提是需要为16的整数倍。

需要包含 mbedtls/aes.h

void app_main(void)
{
    printf("AES-CBC 加密-数据块(128位)\n");
    int i;
    mbedtls_aes_context aes_ctx;
    //密钥数值
    unsigned char key[16] = {'c', 'b', 'c', 'p', 'a', 's', 's', 'w', 'o', 'r', 'd', '1', '2', '3', '4'};
    //iv
    unsigned char iv[16];
    //明文空间
    unsigned char plain[64] = "hello_worled1234";
    //解密后明文的空间
    unsigned char dec_plain[64] = {0};
    //密文空间
    unsigned char cipher[64] = {0};

    mbedtls_aes_init(&aes_ctx);
    mbedtls_aes_setkey_enc(&aes_ctx, key, 128);
    for(i = 0; i < 16; i++)
    {
        iv[i] = 0x01;
    }
    printf("要加密的数据: %s\n", plain);
    printf("加密的密码: %s\n", key);
    mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_ENCRYPT, 64, iv, plain, cipher);
    printf("加密结果,二进制表示: ");
    for(int loop = 0; loop < 64; loop++)
    {
        printf("%02x", cipher[loop]);
    }
    printf("\r\n");

    //设置解密密钥
    mbedtls_aes_setkey_dec(&aes_ctx, key, 128);
    for(i = 0; i < 16; i++)
    {
        iv[i] = 0x01;
    }
    mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, 64, iv, cipher, dec_plain);
    printf("解密后的数据: %s\n", dec_plain);
    mbedtls_aes_free(&aes_ctx);
}

四、MD5

4.1 简介

MD5信息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。

应用场景:

  • 密码管理
  • 电子签名
  • 垃圾邮件筛选

4.2 API说明

API 文档查看 mbed TLS源码文档

MD5 被认为是一种弱消息摘要,它的使用构成了安全风险。我们建议考虑使用更强的消息摘要。

4.2.1 mbedtls_md5_init

功能 初始化 MD5 上下文。
函数定义 void mbedtls_md5_init(mbedtls_md5_context * ctx)
参数 ctx:要初始化的 MD5 上下文。
返回

4.2.2 mbedtls_md5_starts

功能 MD5 上下文设置。在 2.7.0 中被mbedtls_md5_starts_ret()取代
函数定义 void mbedtls_md5_starts(mbedtls_md5_context * ctx)
参数 ctx:要初始化的 MD5 上下文。
返回

4.2.3 mbedtls_md5_update

功能 MD5 进程缓冲区。在 2.7.0 中被mbedtls_md5_update_ret()取代
函数定义 void mbedtls_md5_update(mbedtls_md5_context * ctx, const unsigned char * input, size_t ilen)
参数 ctx:MD5 上下文
input:保存数据的缓冲区
ilen:输入数据的长度
返回

4.2.4 mbedtls_md5_finish

功能 MD5 最终摘要。在 2.7.0 中被mbedtls_md5_finish_ret()取代
函数定义 void mbedtls_md5_finish(mbedtls_md5_context * ctx, unsigned char output[16])
参数 ctx:MD5 上下文
output:MD5 校验和结果
返回

4.2.5 mbedtls_md5_free

功能 清除 MD5 上下文。
函数定义 void mbedtls_md5_free(mbedtls_md5_context * ctx)
参数 ctx:要清除的 MD5 上下文
返回

4.3 实例

需要包含 mbedtls/md5.h

void app_main(void)
{
    printf("MD5 加密\n");

    mbedtls_md5_context md5_ctx;

    unsigned char encrypt[] = "hello_worled1234";
    unsigned char decrypt[16];

    mbedtls_md5_init(&md5_ctx);
    mbedtls_md5_starts(&md5_ctx);
    mbedtls_md5_update(&md5_ctx, encrypt, strlen((char *)encrypt));
    mbedtls_md5_finish(&md5_ctx, decrypt);

    printf("MD5加密前:[%s]\n", encrypt);
    printf("MD5加密后(32位):");
    for(int i = 0; i < 16; i++)
    {
        printf("%02x", decrypt[i]);
    }
    printf("\r\n");

    mbedtls_md5_free(&md5_ctx);
}

4.4 加密验证

在线MD5加密:https://www.cmd5.com/

与网站加密后结果一致:

五、SHA-1

5.1 简介

SHA-1(英语:Secure Hash Algorithm 1,中文名:安全散列算法1)是一种密码散列函数,美国国家安全局设计,并由美国国家标准技术研究所(NIST)发布为联邦数据处理标准(FIPS)。SHA-1可以生成一个被称为消息摘要的160位(20字节)散列值,散列值通常的呈现形式为40个十六进制数。

SHA在很多安全协定中广为运用,包含TLS和SSL、PGP、SSH、S/MIME和IPsec,曾被视为是MD5(更早之前被广为运用的杂凑函数)的后继者。 但SHA-1的安全性现在被密码学家严峻质疑,有学者曾经爆出NSA在SHA-1留下的后门。

5.2 API说明

API 文档查看 mbed TLS源码文档

SHA-1 被认为是一种弱消息摘要,它的使用构成了安全风险。我们建议考虑使用更强的消息摘要。

5.2.1 mbedtls_sha1_init

功能 初始化 SHA-1 上下文。
函数定义 void mbedtls_sha1_init(mbedtls_sha1_context * ctx)
参数 ctx:要初始化的 SHA-1 上下文。这一定不是NULL
返回

5.2.2 mbedtls_sha1_starts

功能 启动 SHA-1 校验和计算。在 2.7.0 中被mbedtls_sha1_starts_ret()取代。
函数定义 void mbedtls_sha1_starts(mbedtls_sha1_context * ctx)
参数 ctx:要初始化的 SHA-1 上下文。这必须被初始化。
返回

5.2.3 mbedtls_sha1_update

功能 将输入缓冲区提供给正在进行的 SHA-1 校验和计算。在在 2.7.0 中被mbedtls_sha1_update_ret()取代。
函数定义 void mbedtls_sha1_update(mbedtls_sha1_context * ctx, const unsigned char * input, size_t ilen)
参数 ctx:SHA-1 上下文。这必须初始化并启动散列操作。
input:保存输入数据的缓冲区。这必须是长度为ilenBytes的可读缓冲区。
ilen:输入数据的长度(input以字节为单位)。
返回

5.2.4 mbedtls_sha1_finish

功能 完成 SHA-1 操作,并将结果写入输出缓冲区。在 2.7.0 中被mbedtls_sha1_finish_ret()取代。
函数定义 void mbedtls_sha1_finish(mbedtls_sha1_context * ctx, unsigned char output[20])
参数 ctx:SHA-1 上下文。这必须初始化并启动散列操作。
output:SHA-1 校验和结果。这必须是长度为20Bytes的可写缓冲区。
返回

5.2.5 mbedtls_sha1_free

功能 清除 SHA-1 上下文。
函数定义 void mbedtls_sha1_free(mbedtls_sha1_context * ctx)
参数 ctx:要清除的 SHA-1 上下文。这可能是NULL,在这种情况下这个函数什么都不做。如果不是NULL,它必须指向一个初始化的 SHA-1 上下文。
返回

5.3 实例

需要包含 mbedtls/sha1.h

void app_main(void)
{
    printf("SHA-1 加密\n");

    mbedtls_sha1_context sha1_ctx;;

    const unsigned char encrypt[] = "hello_worled1234";
    unsigned char decrypt[32];

    mbedtls_sha1_init(&sha1_ctx);
    mbedtls_sha1_starts(&sha1_ctx);
    mbedtls_sha1_update(&sha1_ctx, encrypt, strlen((char *)encrypt));
    mbedtls_sha1_finish(&sha1_ctx, decrypt);

    printf("SHA1加密前:[%s]\n", encrypt);
    printf("SHA1加密后(40位):");
    for(int i = 0; i < 20; i++)
    {
        printf("%02x", decrypt[i]);
    }
    printf("\r\n");

    mbedtls_sha1_free(&sha1_ctx);
}

5.4 加密验证

在线SHA1加密:http://www.ttmd5.com/hash.php?type=5

与网站加密后结果一致:

六、SHA-256

6.1 简介

SHA256 是SHA-2下细分出的一种算法。SHA-2,名称来自于安全散列算法2(英语:Secure Hash Algorithm 2)的缩写,一种密码散列函数算法标准,由美国国家安全局研发,属于SHA算法之一,是SHA-1的后继者。虽然至今尚未出现对SHA-2有效的攻击,但是它的算法跟SHA-1基本上仍然相似,因此有些人开始发展其他替代的杂凑算法。

SHA-2下又可再分为六个不同的算法标准,包括了:SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/224、SHA-512/256。这些变体除了生成摘要的长度 、循环运行的次数等一些微小差异外,算法的基本结构是一致的。

6.2 API说明

API 文档查看 mbed TLS源码文档

6.2.1 mbedtls_sha256_init

功能 初始化 SHA-256 上下文。
函数定义 void mbedtls_sha256_init(mbedtls_sha256_context * ctx)
参数 ctx:要初始化的 SHA-256 上下文。这一定不是NULL
返回

6.2.2 mbedtls_sha256_starts

功能 启动 SHA-224 或 SHA-256 校验和计算。在 2.7.0 中被mbedtls_sha256_starts_ret()取代。
函数定义 void mbedtls_sha256_starts(mbedtls_sha256_context * ctx, int is224)
参数 ctx:要使用的上下文。这必须被初始化。
is224:确定要使用的函数。这必须0适用于 SHA-256 或1SHA-224。
返回

6.2.3 mbedtls_sha256_update

功能 将输入缓冲区提供给正在进行的 SHA-256 校验和计算。在 2.7.0 中被mbedtls_sha256_update_ret()取代。
函数定义 void mbedtls_sha256_update(mbedtls_sha256_context * ctx, const unsigned char * input, size_t ilen)
参数 ctx:SHA-1 上下文。这必须初始化并启动散列操作。
input:保存数据的缓冲区。这必须是长度为ilenBytes的可读缓冲区。
ilen:输入数据的长度(以字节为单位)。
返回

6.2.4 mbedtls_sha256_finish

功能 完成 SHA-256 操作,并将结果写入输出缓冲区。在 2.7.0 中被mbedtls_sha256_finish_ret()取代。
函数定义 void mbedtls_sha256_finish(mbedtls_sha256_context * ctx, unsigned char output[32])
参数 ctx:SHA-256 上下文。这必须初始化并启动散列操作。
output:SHA-224 或 SHA-256 校验和结果。这必须是长度为32Bytes的可写缓冲区。
返回

6.2.5 mbedtls_sha256_free

功能 清除 SHA-256 上下文。
函数定义 void mbedtls_sha256_free(mbedtls_sha256_context * ctx)
参数 ctx:要清除的 SHA-256 上下文。这可能是NULL,在这种情况下这个函数什么都不做。如果不是NULL,它必须指向一个初始化的 SHA-256 上下文。
返回

6.3 实例

需要包含 mbedtls/sha256.h

void app_main(void)
{
    printf("SHA-256 加密\n");

    mbedtls_sha256_context sha256_ctx;;

    const unsigned char encrypt[] = "hello_worled1234";
    unsigned char decrypt[32];

    mbedtls_sha256_init(&sha256_ctx);
    mbedtls_sha256_starts(&sha256_ctx, 0); // 0表示传sha256 , 1 表示传SHA-244
    mbedtls_sha256_update(&sha256_ctx, encrypt, strlen((char *)encrypt));
    mbedtls_sha256_finish(&sha256_ctx, decrypt);

    printf("SHA256加密前:[%s]\n", encrypt);
    printf("SHA256加密后:");
    for(int i = 0; i < 32; i++)
    {
        printf("%02x", decrypt[i]);
    }
    printf("\r\n");

    mbedtls_sha256_free(&sha256_ctx);
}

6.4 加密验证

在线SHA256加密:http://www.ttmd5.com/hash.php?type=5

与网站加密后结果一致:


• 由 Leung 写于 2021 年 10 月 27 日

• 参考:乐鑫Esp32学习之旅 22 讨论下程序员 “青春饭” 那些事,分享在esp32实现多种加密算法md5 |AES CBC-ECB| Sha1 | Sha256 等,附带Demo

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容