Swift RSA 加解密,RSAWithSHA1簽名和驗簽

從OC轉到Swift以后循头,我發(fā)現(xiàn)有了一個強迫癥绵估,就是只想使用純的swift,不到萬不得已就不想使用混合開發(fā)卡骂,所以即使有了OC版的加解密以后還是想要實現(xiàn)Swift版本的国裳,花了一天的時間整理了我目前用到的RSA和AES加解密,RSAWithSHA1簽名和驗簽的方法全跨。我會分兩篇來分別實現(xiàn)RSA和AES的加解密缝左。RSA、AES浓若、MD5整合github地址盒使。
目前RSA主要參考了swift-rsautils,他是可以設置是否保存在keychain七嫌。我在他的基礎上添加了加簽和驗簽的方法少办。

目錄
1.頭文件
2.具體的代碼實現(xiàn)
3.外部調(diào)用

一、 需要導入的頭文件

import Security
import CommonCrypto

二诵原、RSA加密和解密英妓、加簽和驗簽的具體代碼

internal class RSACrypt: NSObject {
    
    // Configuration keys
    struct Config {
        /// Determines whether to add key hash to the keychain path when searching for a key
        /// or when adding a key to keychain
        static var useKeyHashes = true
    }
    
    // Base64 encode a block of data
    class fileprivate func base64Encode(_ data: Data) -> String {
        return data.base64EncodedString(options: [])
    }
    
    // Base64 decode a base64-ed string
    class fileprivate func base64Decode(_ strBase64: String) -> Data {
        let data = Data(base64Encoded: strBase64, options: [])
        return data!
    }
    
    // Encrypts data with a RSA key
    class open func encryptWithRSAKey(_ data: Data, rsaKeyRef: SecKey, padding: SecPadding) -> Data? {
        let blockSize = SecKeyGetBlockSize(rsaKeyRef)
        let maxChunkSize = blockSize - 11
        
        var decryptedDataAsArray = [UInt8](repeating: 0, count: data.count / MemoryLayout<UInt8>.size)
        (data as NSData).getBytes(&decryptedDataAsArray, length: data.count)

        var encryptedData = [UInt8](repeating: 0, count: 0)
        var idx = 0
        while (idx < decryptedDataAsArray.count ) {
            var idxEnd = idx + maxChunkSize
            if ( idxEnd > decryptedDataAsArray.count ) {
                idxEnd = decryptedDataAsArray.count
            }
            var chunkData = [UInt8](repeating: 0, count: maxChunkSize)
            for i in idx..<idxEnd {
                chunkData[i-idx] = decryptedDataAsArray[i]
            }
            
            var encryptedDataBuffer = [UInt8](repeating: 0, count: blockSize)
            var encryptedDataLength = blockSize
            
            let status = SecKeyEncrypt(rsaKeyRef, padding, chunkData, idxEnd-idx, &encryptedDataBuffer, &encryptedDataLength)
            if ( status != noErr ) {
                NSLog("Error while ecrypting: %i", status)
                return nil
            }
            //let finalData = removePadding(encryptedDataBuffer)
            encryptedData += encryptedDataBuffer
            
            idx += maxChunkSize
        }
        
        return Data(bytes: UnsafePointer<UInt8>(encryptedData), count: encryptedData.count)
    }
    
    // Decrypt an encrypted data with a RSA key
    class open func decryptWithRSAKey(_ encryptedData: Data, rsaKeyRef: SecKey, padding: SecPadding) -> Data? {
        let blockSize = SecKeyGetBlockSize(rsaKeyRef)
        
        var encryptedDataAsArray = [UInt8](repeating: 0, count: encryptedData.count / MemoryLayout<UInt8>.size)
        (encryptedData as NSData).getBytes(&encryptedDataAsArray, length: encryptedData.count)
        
        var decryptedData = [UInt8](repeating: 0, count: 0)
        var idx = 0
        while (idx < encryptedDataAsArray.count ) {
            var idxEnd = idx + blockSize
            if ( idxEnd > encryptedDataAsArray.count ) {
                idxEnd = encryptedDataAsArray.count
            }
            var chunkData = [UInt8](repeating: 0, count: blockSize)
            for i in idx..<idxEnd {
                chunkData[i-idx] = encryptedDataAsArray[i]
            }
            
            var decryptedDataBuffer = [UInt8](repeating: 0, count: blockSize)
            var decryptedDataLength = blockSize
            
            let status = SecKeyDecrypt(rsaKeyRef, padding, chunkData, idxEnd-idx, &decryptedDataBuffer, &decryptedDataLength)
            if ( status != noErr ) {
                return nil
            }
            let finalData = removePadding(decryptedDataBuffer)
            decryptedData += finalData
            
            idx += blockSize
        }
        
        return Data(bytes: UnsafePointer<UInt8>(decryptedData), count: decryptedData.count)
    }
    
    class fileprivate func removePadding(_ data: [UInt8]) -> [UInt8] {
        var idxFirstZero = -1
        var idxNextZero = data.count
        for i in 0..<data.count {
            if ( data[i] == 0 ) {
                if ( idxFirstZero < 0 ) {
                    idxFirstZero = i
                } else {
                    idxNextZero = i
                    break
                }
            }
        }
        var newData = [UInt8](repeating: 0, count: idxNextZero-idxFirstZero-1)
        for i in idxFirstZero+1..<idxNextZero {
            newData[i-idxFirstZero-1] = data[i]
        }
        return newData
    }
    
    // Verify that the supplied key is in fact a X509 public key and strip the header
    // On disk, a X509 public key file starts with string "-----BEGIN PUBLIC KEY-----",
    // and ends with string "-----END PUBLIC KEY-----"
    class fileprivate func stripPublicKeyHeader(_ pubkey: Data) -> Data? {
        if ( pubkey.count == 0 ) {
            return nil
        }
        
        var keyAsArray = [UInt8](repeating: 0, count: pubkey.count / MemoryLayout<UInt8>.size)
        (pubkey as NSData).getBytes(&keyAsArray, length: pubkey.count)
        
        var idx = 0
        if (keyAsArray[idx] != 0x30) {
            return nil
        }
        idx += 1
        
        if (keyAsArray[idx] > 0x80) {
            idx += Int(keyAsArray[idx]) - 0x80 + 1
        } else {
            idx += 1
        }
        
        let seqiod = [UInt8](arrayLiteral: 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00)
        for i in idx..<idx+15 {
            if ( keyAsArray[i] != seqiod[i-idx] ) {
                return nil
            }
        }
        idx += 15
        
        if (keyAsArray[idx] != 0x03) {
            return nil
        }
        idx += 1
        
        if (keyAsArray[idx] > 0x80) {
            idx += Int(keyAsArray[idx]) - 0x80 + 1;
        } else {
            idx += 1
        }
        
        if (keyAsArray[idx] != 0x00) {
            return nil
        }
        idx += 1
        //return pubkey.subdata(in: idx..<keyAsArray.count - idx)
        //return pubkey.subdata(in: NSMakeRange(idx, keyAsArray.count - idx))
        return pubkey.subdata(in:Range(NSMakeRange(idx, keyAsArray.count - idx))!)
    }
    
    // Verify that the supplied key is in fact a PEM RSA private key key and strip the header
    // On disk, a PEM RSA private key file starts with string "-----BEGIN RSA PRIVATE KEY-----",
    // and ends with string "-----END RSA PRIVATE KEY-----"
    class fileprivate func stripPrivateKeyHeader(_ privkey: Data) -> Data? {
        if ( privkey.count == 0 ) {
            return nil
        }
        
        var keyAsArray = [UInt8](repeating: 0, count: privkey.count / MemoryLayout<UInt8>.size)
        (privkey as NSData).getBytes(&keyAsArray, length: privkey.count)
        
        //magic byte at offset 22, check if it's actually ASN.1
        var idx = 22
        if ( keyAsArray[idx] != 0x04 ) {
            return nil
        }
        idx += 1
        
        //now we need to find out how long the key is, so we can extract the correct hunk
        //of bytes from the buffer.
        var len = Int(keyAsArray[idx])
        idx += 1
        let det = len & 0x80 //check if the high bit set
        if (det == 0) {
            //no? then the length of the key is a number that fits in one byte, (< 128)
            len = len & 0x7f
        } else {
            //otherwise, the length of the key is a number that doesn't fit in one byte (> 127)
            var byteCount = Int(len & 0x7f)
            if (byteCount + idx > privkey.count) {
                return nil
            }
            //so we need to snip off byteCount bytes from the front, and reverse their order
            var accum: UInt = 0
            var idx2 = idx
            idx += byteCount
            while (byteCount > 0) {
                //after each byte, we shove it over, accumulating the value into accum
                accum = (accum << 8) + UInt(keyAsArray[idx2])
                idx2 += 1
                byteCount -= 1
            }
            // now we have read all the bytes of the key length, and converted them to a number,
            // which is the number of bytes in the actual key.  we use this below to extract the
            // key bytes and operate on them
            len = Int(accum)
        }
        
        //return privkey.subdata(in: idx..<len)
        //return privkey.subdata(in: NSMakeRange(idx, len))
        return privkey.subdata(in: Range(NSMakeRange(idx, len))!)
    }
    
    // Delete any existing RSA key from keychain
    class open func deleteRSAKeyFromKeychain(_ tagName: String) {
        let queryFilter: [String: AnyObject] = [
            String(kSecClass)             : kSecClassKey,
            String(kSecAttrKeyType)       : kSecAttrKeyTypeRSA,
            String(kSecAttrApplicationTag): tagName as AnyObject
        ]
        SecItemDelete(queryFilter as CFDictionary)
    }
    
    // Get a SecKeyRef from keychain
    class open func getRSAKeyFromKeychain(_ tagName: String) -> SecKey? {
        let queryFilter: [String: AnyObject] = [
            String(kSecClass)             : kSecClassKey,
            String(kSecAttrKeyType)       : kSecAttrKeyTypeRSA,
            String(kSecAttrApplicationTag): tagName as AnyObject,
            //String(kSecAttrAccessible)    : kSecAttrAccessibleWhenUnlocked,
            String(kSecReturnRef)         : true as AnyObject
        ]
        
        var keyPtr: AnyObject?
        let result = SecItemCopyMatching(queryFilter as CFDictionary, &keyPtr)
        if ( result != noErr || keyPtr == nil ) {
            return nil
        }
        return keyPtr as! SecKey?
    }
    
    // Add a RSA private key to keychain and return its SecKeyRef
    // privkeyBase64: RSA private key in base64 (data between "-----BEGIN RSA PRIVATE KEY-----" and "-----END RSA PRIVATE KEY-----")
    class open func addRSAPrivateKey(_ privkeyBase64: String, tagName: String) -> SecKey? {
        return addRSAPrivateKey(privkey: base64Decode(privkeyBase64), tagName: tagName)
    }
    
    class fileprivate func addRSAPrivateKey(privkey: Data, tagName: String) -> SecKey? {
        // Delete any old lingering key with the same tag
        deleteRSAKeyFromKeychain(tagName)
        
        let privkeyData = stripPrivateKeyHeader(privkey)
        if ( privkeyData == nil ) {
            return nil
        }
        
        // Add persistent version of the key to system keychain
        // var prt: AnyObject?
        let queryFilter = [
            String(kSecClass)              : kSecClassKey,
            String(kSecAttrKeyType)        : kSecAttrKeyTypeRSA,
            String(kSecAttrApplicationTag) : tagName,
            //String(kSecAttrAccessible)     : kSecAttrAccessibleWhenUnlocked,
            String(kSecValueData)          : privkeyData!,
            String(kSecAttrKeyClass)       : kSecAttrKeyClassPrivate,
            String(kSecReturnPersistentRef): true
            ] as [String : Any]
        let result = SecItemAdd(queryFilter as CFDictionary, nil)
        if ((result != noErr) && (result != errSecDuplicateItem)) {
            return nil
        }
        
        return getRSAKeyFromKeychain(tagName)
    }
    
    // Add a RSA pubic key to keychain and return its SecKeyRef
    // pubkeyBase64: RSA public key in base64 (data between "-----BEGIN PUBLIC KEY-----" and "-----END PUBLIC KEY-----")
    class open func addRSAPublicKey(_ pubkeyBase64: String, tagName: String) -> SecKey? {
        return addRSAPublicKey(pubkey: base64Decode(pubkeyBase64), tagName: tagName)
    }
    
    class fileprivate func addRSAPublicKey(pubkey: Data, tagName: String) -> SecKey? {
        // Delete any old lingering key with the same tag
        deleteRSAKeyFromKeychain(tagName)
        
        let pubkeyData = stripPublicKeyHeader(pubkey)
        if ( pubkeyData == nil ) {
            return nil
        }
        
        // Add persistent version of the key to system keychain
        //var prt1: Unmanaged<AnyObject>?
        let queryFilter = [
            String(kSecClass)              : kSecClassKey,
            String(kSecAttrKeyType)        : kSecAttrKeyTypeRSA,
            String(kSecAttrApplicationTag) : tagName,
            String(kSecValueData)          : pubkeyData!,
            String(kSecAttrKeyClass)       : kSecAttrKeyClassPublic,
            String(kSecReturnPersistentRef): true
            ] as [String : Any]
        let result = SecItemAdd(queryFilter as CFDictionary, nil)
        if ((result != noErr) && (result != errSecDuplicateItem)) {
            return nil
        }
        
        return getRSAKeyFromKeychain(tagName)
    }
    
    // Encrypt data with a RSA private key
    // privkeyBase64: RSA private key in base64 (data between "-----BEGIN RSA PRIVATE KEY-----" and "-----END RSA PRIVATE KEY-----")
    // NOT WORKING YET!
    class open func encryptWithRSAPrivateKey(_ data: Data, privkeyBase64: String, keychainTag: String) -> Data? {
        let myKeychainTag = keychainTag + (Config.useKeyHashes ? "-" + String(privkeyBase64.hashValue) : "")
        var keyRef = getRSAKeyFromKeychain(myKeychainTag)
        if ( keyRef == nil ) {
            keyRef = addRSAPrivateKey(privkeyBase64, tagName: myKeychainTag)
        }
        if ( keyRef == nil ) {
            return nil
        }
        
        return encryptWithRSAKey(data, rsaKeyRef: keyRef!, padding: SecPadding.PKCS1)
    }
    
    // Encrypt data with a RSA public key
    // pubkeyBase64: RSA public key in base64 (data between "-----BEGIN PUBLIC KEY-----" and "-----END PUBLIC KEY-----")
    class open func encryptWithRSAPublicKey(_ data: Data, pubkeyBase64: String, keychainTag: String) -> Data? {
        let myKeychainTag = keychainTag + (Config.useKeyHashes ? "-" + String(pubkeyBase64.hashValue) : "")
        var keyRef = getRSAKeyFromKeychain(myKeychainTag)
        if ( keyRef == nil ) {
            keyRef = addRSAPublicKey(pubkeyBase64, tagName: myKeychainTag)
        }
        if ( keyRef == nil ) {
            return nil
        }
        
        return encryptWithRSAKey(data, rsaKeyRef: keyRef!, padding: SecPadding.PKCS1)
    }
    
    // Decrypt an encrypted data with a RSA private key
    // privkeyBase64: RSA private key in base64 (data between "-----BEGIN RSA PRIVATE KEY-----" and "-----END RSA PRIVATE KEY-----")
    class open func decryptWithRSAPrivateKey(_ encryptedData: Data, privkeyBase64: String, keychainTag: String) -> Data? {
        let myKeychainTag = keychainTag + (Config.useKeyHashes ? "-" + String(privkeyBase64.hashValue) : "")
        var keyRef = getRSAKeyFromKeychain(myKeychainTag)
        if ( keyRef == nil ) {
            keyRef = addRSAPrivateKey(privkeyBase64, tagName: myKeychainTag)
        }
        if ( keyRef == nil ) {
            return nil
        }
        
        return decryptWithRSAKey(encryptedData, rsaKeyRef: keyRef!, padding: SecPadding())
    }
    
    // Decrypt an encrypted data with a RSA public key
    // pubkeyBase64: RSA public key in base64 (data between "-----BEGIN PUBLIC KEY-----" and "-----END PUBLIC KEY-----")
    class open func decryptWithRSAPublicKey(_ encryptedData: Data, pubkeyBase64: String, keychainTag: String) -> Data? {
        let myKeychainTag = keychainTag + (Config.useKeyHashes ? "-" + String(pubkeyBase64.hashValue) : "")
        var keyRef = getRSAKeyFromKeychain(myKeychainTag)
        if ( keyRef == nil ) {
            keyRef = addRSAPublicKey(pubkeyBase64, tagName: myKeychainTag)
        }
        if ( keyRef == nil ) {
            return nil
        }
        
        return decryptWithRSAKey(encryptedData, rsaKeyRef: keyRef!, padding: SecPadding())
    }
    
    
    class open func siginWithRsaSHA1(_ singData: Data, _ privateBase64: String, _ keychainTag: String) -> Data? {
        let myKeychainTag = keychainTag + (Config.useKeyHashes ? "-" + String(privateBase64.hashValue) : "")
        var keyRef = getRSAKeyFromKeychain(myKeychainTag)
        if ( keyRef == nil ) {
            keyRef = addRSAPrivateKey(privateBase64, tagName: myKeychainTag)
        }
        if ( keyRef == nil ) {
            return nil
        }
        
        if  let hash = NSMutableData(length: Int(CC_SHA1_DIGEST_LENGTH)) {
            CC_SHA1((singData as NSData).bytes, CC_LONG(singData.count), hash.mutableBytes.assumingMemoryBound(to: UInt8.self))
            let blockSize = SecKeyGetBlockSize(keyRef!)
            let hashDataLength = Int(hash.length)
            let hashData = hash.bytes.bindMemory(to: UInt8.self, capacity: hash.length)
            if let result = NSMutableData(length: Int(blockSize)) {
                let encryptedData = result.mutableBytes.assumingMemoryBound(to: UInt8.self)
                var encryptedDataLength = blockSize
                let status = SecKeyRawSign(keyRef!, .PKCS1SHA1, hashData, hashDataLength, encryptedData, &encryptedDataLength)
                if status == noErr {
                    result.length = encryptedDataLength
                    return result as Data
                }
            }
        }
        return nil
    }
    
    class open func verifySigin(_ originalData: String, _ singData: String, _ publicBase64: String, _ keychainTag: String) -> Bool  {
        
        if let data = originalData.data(using: String.Encoding.utf8), let signature = Data(base64Encoded: singData, options: NSData.Base64DecodingOptions(rawValue: 0)) {
            let myKeychainTag = keychainTag + (Config.useKeyHashes ? "-" + String(publicBase64.hashValue) : "")
            var keyRef = getRSAKeyFromKeychain(myKeychainTag)
            if ( keyRef == nil ) {
                keyRef = addRSAPublicKey(publicBase64, tagName: myKeychainTag)
            }
            if ( keyRef == nil ) {
                return false
            }
            if let hashData = NSMutableData(length: Int(CC_SHA1_DIGEST_LENGTH)) {
                CC_SHA1((data as NSData).bytes, CC_LONG(data.count), hashData.mutableBytes.assumingMemoryBound(to: UInt8.self))
                let signedData = hashData.bytes.bindMemory(to: UInt8.self, capacity: hashData.length)
                let signatureLength = Int(signature.count)
                let signatureData = (signature as NSData).bytes.bindMemory(to: UInt8.self, capacity: signature.count)
                let result = SecKeyRawVerify(keyRef!, .PKCS1SHA1, signedData, Int(CC_SHA1_DIGEST_LENGTH), signatureData, signatureLength)
                switch result {
                case noErr:
                    return true
                default:
                    return false
                }
            }
        }
        return false
    }
}

三、具體的使用方法

我這里整理的是公鑰和私鑰都是字符串的形式

private let ZZ_RSA_PRIVATE_KEY_TAG = "RSAUtil_PrivKey"
private let ZZ_RSA_PUBLIC_KEY_TAG = "RSAUtil_PubKey"

1. RSA的加密

 open class func zz_rsaEncrypt(_ text: String, _ publicKey: String) -> String? {
        guard let textData = text.data(using: String.Encoding.utf8) else { return nil }
        let encryptedData = RSACrypt.encryptWithRSAPublicKey(textData, pubkeyBase64: publicKey, keychainTag: ZZ_RSA_PUBLIC_KEY_TAG)
        if ( encryptedData == nil ) {
            print("Error while encrypting")
            return nil
        } else {
            let encryptedDataText = encryptedData!.base64EncodedString(options: NSData.Base64EncodingOptions())
            return encryptedDataText
        }
    }

2. RSA的解密

 /// RSA解密
   open class func zz_rsaDecrypt(_ encryptData: String, _ privateKey: String) -> String? {
        guard let baseDecodeData = Data(base64Encoded: encryptData, options: NSData.Base64DecodingOptions()) else { return nil }
        let decryptedInfo = RSACrypt.decryptWithRSAPrivateKey(baseDecodeData, privkeyBase64: privateKey, keychainTag: ZZ_RSA_PRIVATE_KEY_TAG)
        if ( decryptedInfo != nil ) {
            let result = String(data: decryptedInfo!, encoding: .utf8)
            return result
        } else {
            print("Error while decrypting")
            return nil
        }
    }

3. RSAWithSHA1加簽

/// RSA簽名
    open class func zz_rsaSignWithSHA1(_ text: String, _ privateKey: String) -> String? {
        guard let textData = text.data(using: String.Encoding.utf8) else { return nil }
        let siginData = RSACrypt.siginWithRsaSHA1(textData, privateKey, ZZ_RSA_PRIVATE_KEY_TAG)
        if  siginData != nil {
            let encryptedDataText = siginData!.base64EncodedString(options: NSData.Base64EncodingOptions())
            return encryptedDataText
        } else {
            print("Error while sigining")
            return nil
        }
    }

4. RSAWithSHA1驗簽

 /// RSA驗簽
    open class func zz_rsaSignVerifyWithSHA1(_ originalStr: String, _ siginStr: String, _ publicKey: String) -> Bool {
       return RSACrypt.verifySigin(originalStr, siginStr, publicKey, ZZ_RSA_PRIVATE_KEY_TAG)
    }

到此為止RSA的加解密和RSAWithSHA1的加簽驗簽已完成绍赛。下一篇會實現(xiàn)AES128/ CBC/PKCS7Padding的加解密

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蔓纠,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子吗蚌,更是在濱河造成了極大的恐慌腿倚,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蚯妇,死亡現(xiàn)場離奇詭異敷燎,居然都是意外死亡暂筝,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門硬贯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來焕襟,“玉大人,你說我怎么就攤上這事饭豹⊥依担” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵拄衰,是天一觀的道長它褪。 經(jīng)常有香客問我,道長翘悉,這世上最難降的妖魔是什么列赎? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮镐确,結果婚禮上包吝,老公的妹妹穿的比我還像新娘。我一直安慰自己源葫,他們只是感情好诗越,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著息堂,像睡著了一般嚷狞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上荣堰,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天床未,我揣著相機與錄音,去河邊找鬼振坚。 笑死薇搁,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的渡八。 我是一名探鬼主播啃洋,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼屎鳍!你這毒婦竟也來了宏娄?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤逮壁,失蹤者是張志新(化名)和其女友劉穎孵坚,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡卖宠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年巍杈,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片逗堵。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡秉氧,死狀恐怖眷昆,靈堂內(nèi)的尸體忽然破棺而出蜒秤,到底是詐尸還是另有隱情,我是刑警寧澤亚斋,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布作媚,位于F島的核電站,受9級特大地震影響帅刊,放射性物質(zhì)發(fā)生泄漏纸泡。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一赖瞒、第九天 我趴在偏房一處隱蔽的房頂上張望女揭。 院中可真熱鬧,春花似錦栏饮、人聲如沸吧兔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽境蔼。三九已至,卻和暖如春伺通,著一層夾襖步出監(jiān)牢的瞬間箍土,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工罐监, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留吴藻,地道東北人。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓弓柱,卻偏偏與公主長得像调缨,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子吆你,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容

  • RSA 簡介 RSA是一種非對稱加密算法弦叶,使用公鑰加密就可以使用私鑰解密,使用私鑰加密就可以使用公鑰解密妇多。RSA公...
    __Simon__閱讀 8,218評論 7 19
  • 加密分為對稱加密伤哺,非對稱加密, 不可逆加密。 對稱加密:描述: 加密解密使用同樣的密鑰立莉。特點: 速度快绢彤,安全性一般...
    熾熱冰峰閱讀 3,613評論 0 0
  • 轉:http://caisenchen.blog.163.com/blog/static/552865502008...
    right_33cb閱讀 4,361評論 0 4
  • 科創(chuàng)板的創(chuàng)新與發(fā)展論壇20日在北京舉行。萬博新經(jīng)濟研究院院長蜓耻、萬博兄弟資產(chǎn)管理有限公司董事長滕泰在會上表示茫舶,不盈利...
    東方政經(jīng)閱讀 229評論 0 1
  • 親愛的讀者,我想告訴你一個普通的故事刹淌,那就是我的故事饶氏,我是一個普通的中國人,我熱愛我的家庭和我的祖國有勾,我有一個追求...
    効忠娘閱讀 447評論 0 0