加解密(AES,RSA)和签名(MD5,HmacSHA256,SHA1WithRSA,SHA256WithRSA)

最近对接各种支付以及数据库连接池加密Druid,里面涉及到许多加密解密,加签验签的过程,这里总结一下(以下代码全部测试通过)

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import sun.security.rsa.RSACore;
import sun.security.rsa.RSAKeyFactory;

import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Random;

/**
 * @author paul
 * @description
 * @date 2018/12/24
 */
public abstract class SignatureTools {

    public static void main(String[] args) throws Exception {
        String content = "";
        for (int i = 0; i < 100; i++) {
            content = content + "0123456789";
        }

        //生成rsa秘钥
        byte[][] keyPairBytes = genRsaKeyPairBytes(1024);
        String privateKey = new String(Base64.getEncoder().encode(keyPairBytes[0]));
        String publicKey = new String(Base64.getEncoder().encode(keyPairBytes[1]));

        String rsaEncrypt = null;
        String rsaDecrypt = null;

        rsaEncrypt = rsaEncryptByPublicKey(content, publicKey, "UTF-8");
        rsaDecrypt = rsaDecryptByPrivateKey(rsaEncrypt, privateKey, "UTF-8");
        System.out.println("1:rsa私钥分段解密:" + rsaDecrypt.equals(content));
        rsaEncrypt = rsaEncryptByPrivateKey(content, privateKey, "UTF-8");
        rsaDecrypt = rsaDecryptByPublicKey(rsaEncrypt, publicKey, "UTF-8");
        System.out.println("2:rsa公钥分段解密:" + rsaDecrypt.equals(content));

        String sign = rsa256Sign(content, privateKey, "UTF-8");
        boolean b = rsa256CheckContent(content, sign, publicKey, "UTF-8");
        System.out.println("3:SHA256WithRSA验签结果:" + rsaDecrypt.equals(content));

        sign = rsaSign(content, privateKey, "UTF-8");
        b = rsaCheckContent(content, sign, publicKey, "UTF-8");
        System.out.println("3:SHA1WithRSA验签结果:" + rsaDecrypt.equals(content));

        System.out.println("4.1:MD5:" + MD5(content));
        System.out.println("4.2:MD5:" + MD5(content));

        System.out.println("5.1:HmacSHA256:" + HmacSHA256(content,"0123456789"));
        System.out.println("5.2:HmacSHA256:" + HmacSHA256(content,content));
        //256秘钥问题需要安转jce:https://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
        //Exception in thread "main" java.security.InvalidKeyException: Illegal key size or default parameters

        //String key256 = generateNonceStr();
        String key256 = generateNonceStr().substring(0,16);
        String aesEncrypt = AES_ENCRYPT(content, key256);
        String aesDecrypt = AES_DECRYPT(aesEncrypt, key256);
        System.out.println("6:AES解密结果:" + aesDecrypt.equals(content));

    }

    public static final String SIGN_TYPE_RSA = "RSA";

    public static final String SIGN_TYPE_RSA_PAD = "RSA/ECB/PKCS1Padding";
    //int MAX_ENCRYPT_BLOCK = RSACore.getByteLength(RSAKeyFactory.toRSAKey(pubKey)) - 11;  -11与PKCS1Padding有关

    public static final String SIGN_ALGORITHMS = "SHA1WithRSA";

    public static final String SIGN_SHA256RSA_ALGORITHMS = "SHA256WithRSA";

    /**
     * RSA最大加密明文大小,秘钥1024位
     */
    private static final int MAX_ENCRYPT_BLOCK_1024 = 117;

    /**
     * RSA最大解密密文大小,秘钥1024位
     */
    private static final int MAX_DECRYPT_BLOCK_1024 = 128;

    /**
     * RSA最大加密明文大小,秘钥2048位
     */
    private static final int MAX_ENCRYPT_BLOCK_2048 = 245;

    /**
     * RSA最大解密密文大小,秘钥2048位
     */
    private static final int MAX_DECRYPT_BLOCK_2048 = 256;

    /**
     * RSA公钥和私钥生成
     *
     * @param keySize 秘钥长度 1024 2048 4096
     * @return
     * @throws NoSuchAlgorithmException
     * @throws NoSuchProviderException
     */
    public static byte[][] genRsaKeyPairBytes(int keySize)
            throws NoSuchAlgorithmException, NoSuchProviderException {
        byte[][] keyPairBytes = new byte[2][];

        KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
        gen.initialize(keySize, new SecureRandom());
        KeyPair pair = gen.generateKeyPair();

        keyPairBytes[0] = pair.getPrivate().getEncoded();
        keyPairBytes[1] = pair.getPublic().getEncoded();

        return keyPairBytes;
    }

    /**
     * sha256WithRsa 加签
     */
    public static String rsa256Sign(String content, String privateKey,
                                    String charset) throws ApiException {
        try {
            PrivateKey priKey = getPrivateKeyFromPKCS8(SIGN_TYPE_RSA,
                    new ByteArrayInputStream(privateKey.getBytes()));

            java.security.Signature signature = java.security.Signature
                    .getInstance(SIGN_SHA256RSA_ALGORITHMS);
            signature.initSign(priKey);

            if (isEmpty(charset)) {
                signature.update(content.getBytes());
            } else {
                signature.update(content.getBytes(charset));
            }

            byte[] signed = signature.sign();


            java.util.Base64.Encoder encoder = java.util.Base64.getEncoder();
            byte[] encode = encoder.encode(signed);
            return new String(encode);
        } catch (Exception e) {
            throw new ApiException("RSAcontent = " + content + "; charset = " + charset, e);
        }

    }

    /**
     * sha1WithRsa 加签
     */
    public static String rsaSign(String content, String privateKey,
                                 String charset) throws ApiException {
        try {
            PrivateKey priKey = getPrivateKeyFromPKCS8(SIGN_TYPE_RSA,
                    new ByteArrayInputStream(privateKey.getBytes()));
            java.security.Signature signature = java.security.Signature
                    .getInstance(SIGN_ALGORITHMS);
            signature.initSign(priKey);
            if (isEmpty(charset)) {
                signature.update(content.getBytes());
            } else {
                signature.update(content.getBytes(charset));
            }
            byte[] signed = signature.sign();
            return new String(Base64.getEncoder().encode(signed));
        } catch (InvalidKeySpecException ie) {
            throw new ApiException("RSA私钥格式不正确,请检查是否正确配置了PKCS8格式的私钥", ie);
        } catch (Exception e) {
            throw new ApiException("RSAcontent = " + content + "; charset = " + charset, e);
        }
    }

    /**
     * PrivateKey
     *
     * @param algorithm
     * @param ins
     * @return
     * @throws Exception
     */
    public static PrivateKey getPrivateKeyFromPKCS8(String algorithm,
                                                    InputStream ins) throws Exception {
        if (ins == null || isEmpty(algorithm)) {
            return null;
        }
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        byte[] encodedKey = readText(ins).getBytes();
        encodedKey = Base64.getDecoder().decode(encodedKey);
        return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));
    }

    /**
     * PublicKey
     *
     * @param algorithm
     * @param ins
     * @return
     * @throws Exception
     */
    public static PublicKey getPublicKeyFromX509(String algorithm,
                                                 InputStream ins) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        StringWriter writer = new StringWriter();
        io(new InputStreamReader(ins), writer);
        byte[] encodedKey = writer.toString().getBytes();
        encodedKey = Base64.getDecoder().decode(encodedKey);
        return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
    }

    /**
     * 验签:SHA256WithRSA
     *
     * @param content
     * @param sign
     * @param publicKey
     * @param charset
     * @return
     * @throws ApiException
     */
    public static boolean rsa256CheckContent(String content, String sign, String publicKey,
                                             String charset) throws ApiException {
        try {
            PublicKey pubKey = getPublicKeyFromX509("RSA",
                    new ByteArrayInputStream(publicKey.getBytes()));
            java.security.Signature signature = java.security.Signature
                    .getInstance(SIGN_SHA256RSA_ALGORITHMS);
            signature.initVerify(pubKey);
            if (isEmpty(charset)) {
                signature.update(content.getBytes());
            } else {
                signature.update(content.getBytes(charset));
            }
            return signature.verify(Base64.getDecoder().decode(sign.getBytes()));
        } catch (Exception e) {
            throw new ApiException(
                    "RSAcontent = " + content + ",sign=" + sign + ",charset = " + charset, e);
        }
    }

    /**
     * 验签:SHA1WithRSA
     *
     * @param content
     * @param sign
     * @param publicKey
     * @param charset
     * @return
     * @throws ApiException
     */
    public static boolean rsaCheckContent(String content, String sign, String publicKey,
                                          String charset) throws ApiException {
        try {
            PublicKey pubKey = getPublicKeyFromX509("RSA",
                    new ByteArrayInputStream(publicKey.getBytes()));

            java.security.Signature signature = java.security.Signature
                    .getInstance(SIGN_ALGORITHMS);
            signature.initVerify(pubKey);
            if (isEmpty(charset)) {
                signature.update(content.getBytes());
            } else {
                signature.update(content.getBytes(charset));
            }
            return signature.verify(Base64.getDecoder().decode(sign.getBytes()));
        } catch (Exception e) {
            throw new ApiException(
                    "RSAcontent = " + content + ",sign=" + sign + ",charset = " + charset, e);
        }
    }


    /**
     * rsa公钥分段加密
     *
     * @param content   待加密内容
     * @param publicKey 公钥
     * @param charset   字符集,如UTF-8, GBK, GB2312
     * @return 密文内容
     * @throws ApiException
     */
    public static String rsaEncryptByPublicKey(String content, String publicKey,
                                               String charset) throws ApiException {
        try {
            PublicKey pubKey = getPublicKeyFromX509(SIGN_TYPE_RSA,
                    new ByteArrayInputStream(publicKey.getBytes()));

            int MAX_ENCRYPT_BLOCK = RSACore.getByteLength(RSAKeyFactory.toRSAKey(pubKey)) - 11;

            Cipher cipher = Cipher.getInstance(SIGN_TYPE_RSA_PAD);
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);
            byte[] data = isEmpty(charset) ? content.getBytes()
                    : content.getBytes(charset);
            int inputLen = data.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 对数据分段加密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                    cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(data, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_ENCRYPT_BLOCK;
            }
            byte[] encryptedData = Base64.getEncoder().encode(out.toByteArray());
            out.close();

            return isEmpty(charset) ? new String(encryptedData)
                    : new String(encryptedData, charset);
        } catch (Exception e) {
            throw new ApiException("EncryptContent = " + content + ",charset = " + charset,
                    e);
        }
    }

    /**
     * rsa私钥分段解密
     *
     * @param content    待解密内容
     * @param privateKey 私钥
     * @param charset    字符集,如UTF-8, GBK, GB2312
     * @return 明文内容
     * @throws ApiException
     */
    public static String rsaDecryptByPrivateKey(String content, String privateKey,
                                                String charset) throws ApiException {
        try {
            PrivateKey priKey = getPrivateKeyFromPKCS8(SIGN_TYPE_RSA,
                    new ByteArrayInputStream(privateKey.getBytes()));

            int MAX_DECRYPT_BLOCK = RSACore.getByteLength(RSAKeyFactory.toRSAKey(priKey));


            Cipher cipher = Cipher.getInstance(SIGN_TYPE_RSA_PAD);
            cipher.init(Cipher.DECRYPT_MODE, priKey);
            byte[] encryptedData = isEmpty(charset)
                    ? Base64.getDecoder().decode(content.getBytes())
                    : Base64.getDecoder().decode(content.getBytes(charset));
            int inputLen = encryptedData.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 对数据分段解密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                    cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_DECRYPT_BLOCK;
            }
            byte[] decryptedData = out.toByteArray();
            out.close();

            return isEmpty(charset) ? new String(decryptedData)
                    : new String(decryptedData, charset);
        } catch (Exception e) {
            throw new ApiException("EncodeContent = " + content + ",charset = " + charset, e);
        }
    }

    /**
     * rsa私钥分段加密
     *
     * @param content    待加密内容
     * @param privateKey 私钥
     * @param charset    字符集,如UTF-8, GBK, GB2312
     * @return 密文内容
     * @throws ApiException
     */
    public static String rsaEncryptByPrivateKey(String content, String privateKey,
                                                String charset) throws ApiException {
        try {
            PrivateKey priKey = getPrivateKeyFromPKCS8(SIGN_TYPE_RSA,
                    new ByteArrayInputStream(privateKey.getBytes()));

            int MAX_ENCRYPT_BLOCK = RSACore.getByteLength(RSAKeyFactory.toRSAKey(priKey)) - 11;
            Cipher cipher = Cipher.getInstance(SIGN_TYPE_RSA_PAD);
            cipher.init(Cipher.ENCRYPT_MODE, priKey);
            byte[] data = isEmpty(charset) ? content.getBytes()
                    : content.getBytes(charset);
            int inputLen = data.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 对数据分段加密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                    cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(data, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_ENCRYPT_BLOCK;
            }
            byte[] encryptedData = Base64.getEncoder().encode(out.toByteArray());
            out.close();

            return isEmpty(charset) ? new String(encryptedData)
                    : new String(encryptedData, charset);
        } catch (Exception e) {
            throw new ApiException("EncryptContent = " + content + ",charset = " + charset,
                    e);
        }
    }

    /**
     * rsa公钥分段解密
     *
     * @param content   待解密内容
     * @param publicKey 私钥
     * @param charset   字符集,如UTF-8, GBK, GB2312
     * @return 明文内容
     * @throws ApiException
     */
    public static String rsaDecryptByPublicKey(String content, String publicKey,
                                               String charset) throws ApiException {
        try {
            PublicKey pubKey = getPublicKeyFromX509(SIGN_TYPE_RSA,
                    new ByteArrayInputStream(publicKey.getBytes()));
            Cipher cipher = Cipher.getInstance(SIGN_TYPE_RSA_PAD);

            int MAX_DECRYPT_BLOCK = RSACore.getByteLength(RSAKeyFactory.toRSAKey(pubKey));

            cipher.init(Cipher.DECRYPT_MODE, pubKey);
            byte[] encryptedData = isEmpty(charset)
                    ? Base64.getDecoder().decode(content.getBytes())
                    : Base64.getDecoder().decode(content.getBytes(charset));
            int inputLen = encryptedData.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 对数据分段解密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                    cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_DECRYPT_BLOCK;
            }
            byte[] decryptedData = out.toByteArray();
            out.close();

            return isEmpty(charset) ? new String(decryptedData)
                    : new String(decryptedData, charset);
        } catch (Exception e) {
            throw new ApiException("EncodeContent = " + content + ",charset = " + charset, e);
        }
    }

    public static boolean isEmpty(String value) {
        int strLen;
        if (value == null || (strLen = value.length()) == 0) {
            return true;
        }
        for (int i = 0; i < strLen; i++) {
            if ((Character.isWhitespace(value.charAt(i)) == false)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 支持的Algorithm以及提供者
     */
    public static void support() {
        Security.addProvider(new BouncyCastleProvider());
        for (Provider provider : Security.getProviders()) {
            System.out.println("Provider: " + provider.getName());
            for (Provider.Service service : provider.getServices()) {
                System.out.println("  Algorithm: " + service.getAlgorithm());
            }
        }
    }

    /**
     * AES 加密
     *
     * @param data
     * @param key  长度 128/192/256 bits.256注意jdk问题
     * @return
     * @throws Exception
     */
    public static String AES_ENCRYPT(String data, String key) throws Exception {
        Security.addProvider(new BouncyCastleProvider());
        SecretKey secretKey = new SecretKeySpec(key.getBytes(), "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);

        byte[] result = cipher.doFinal(data.getBytes("UTF-8"));
        byte[] encode = Base64.getEncoder().encode(result);
        return new String(encode);
    }

    /**
     * AES 解密
     *
     * @param data
     * @param key  128/192/256 bits.256注意jdk问题
     * @return
     * @throws Exception
     */
    public static String AES_DECRYPT(String data, String key) throws Exception {
        Security.addProvider(new BouncyCastleProvider());
        SecretKey secretKey = new SecretKeySpec(key.getBytes(), "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
        cipher.init(Cipher.DECRYPT_MODE, secretKey);

        byte[] encode = Base64.getDecoder().decode(data);
        byte[] result = cipher.doFinal(encode);

        return new String(result, "UTF-8");
    }



    /**
     * MD5
     *
     * @param data
     * @return
     * @throws Exception
     */
    public static String MD5(String data) throws Exception {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] array = md.digest(data.getBytes("UTF-8"));
        StringBuilder sb = new StringBuilder();
        for (byte item : array) {
            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
        }
        return sb.toString().toUpperCase();
    }

    /**
     * HMACSHA256
     *
     * @param data 待处理数据
     * @param key  密钥
     * @return 加密结果
     */
    public static String HmacSHA256(String data, String key) throws Exception {
        Mac hmacSHA256 = Mac.getInstance("HmacSHA256");
        SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
        hmacSHA256.init(secret_key);
        byte[] array = hmacSHA256.doFinal(data.getBytes("UTF-8"));
        StringBuilder sb = new StringBuilder();
        for (byte item : array) {
            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
        }
        return sb.toString().toUpperCase();
    }


    private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static final Random RANDOM = new SecureRandom();

    /**
     * 作为MD5和HMACSHA256的随机值
     *
     * @return
     */
    public static String generateNonceStr() {
        char[] nonceChars = new char[32];
        for (int index = 0; index < nonceChars.length; ++index) {
            nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
        }
        return new String(nonceChars);
    }

    public static class ApiException extends Exception {
        private String errCode;
        private String errMsg;

        public ApiException() {
            super();
        }

        public ApiException(String message, Throwable cause) {
            super(message, cause);
        }

        public ApiException(String message) {
            super(message);
        }

        public ApiException(Throwable cause) {
            super(cause);
        }

        public ApiException(String errCode, String errMsg) {
            super(errCode + ":" + errMsg);
            this.errCode = errCode;
            this.errMsg = errMsg;
        }

        public String getErrCode() {
            return this.errCode;
        }

        public String getErrMsg() {
            return this.errMsg;
        }

    }


    private static String readText(InputStream in)
            throws IOException {
        return readText(in, null);
    }

    private static String readText(InputStream in, String encoding)
            throws IOException {
        Reader reader = (encoding == null) ? new InputStreamReader(in) : new InputStreamReader(in,
                encoding);
        return readText(reader);
    }

    private static String readText(Reader reader) throws IOException {
        StringWriter writer = new StringWriter();
        io(reader, writer);
        return writer.toString();
    }

    private static void io(Reader in, Writer out) throws IOException {
        int bufferSize = 1024;
        char[] buffer = new char[bufferSize];
        int amount;

        while ((amount = in.read(buffer)) >= 0) {
            out.write(buffer, 0, amount);
        }
    }
}

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

推荐阅读更多精彩内容