 //
 
 import Foundation
-//import CommonCrypto
+import CommonCrypto
 import Security
-var str = "Hello, playground"
+
+let  supported_ciphers_iv_size = [
+    0, 0, 16, 16, 16, 16, 8, 16, 16, 16, 8, 8, 8, 8, 16, 8, 8, 12
+];
+
+let supported_ciphers_key_size = [
+    0, 16, 16, 16, 24, 32, 16, 16, 24, 32, 16, 8, 16, 16, 16, 32, 32, 32
+];
+let SODIUM_BLOCK_SIZE:UInt64 = 64
+public enum  CryptoMethod:Int,CustomStringConvertible{
+    //case NONE       =         -1
+    case TABLE     =          0
+    case RC4         =        1
+    case RC4_MD5      =       2
+    case AES_128_CFB   =      3
+    case AES_192_CFB    =     4
+    case AES_256_CFB     =    5
+    case BF_CFB           =   6
+    case CAMELLIA_128_CFB  =  7
+    case CAMELLIA_192_CFB   = 8
+    case CAMELLIA_256_CFB    = 9
+    case CAST5_CFB  =         10
+    case DES_CFB     =        11
+    case IDEA_CFB     =       12
+    case RC2_CFB       =      13
+    case SEED_CFB       =     14
+    case SALSA20         =    15
+    case CHACHA20         =   16
+    case CHACHA20IETF      =  17
+    public var description: String {
+        switch self {
+            
+        //case NONE:      return         "NONE"
+        case TABLE:     return         "TABLE"
+        case RC4:         return        "RC4"
+        case RC4_MD5:      return       "RC4-MD5"
+        case AES_128_CFB:   return      "AES-128-CFB"
+        case AES_192_CFB:    return     "AES_192-CFB"
+        case AES_256_CFB:     return    "AES-256-CFB"
+        case BF_CFB:           return   "BF-CFB"
+        case CAMELLIA_128_CFB:  return  "CAMELLIA-128-CFB"
+        case CAMELLIA_192_CFB:   return "CAMELLIA-192-CFB"
+        case CAMELLIA_256_CFB:    return "CAMELLIA-256-CFB"
+        case CAST5_CFB:  return         "CAST5-CFB"
+        case DES_CFB:     return        "DES-CFB"
+        case IDEA_CFB:     return       "IDEA-CFB"
+        case RC2_CFB:       return      "RC2-CFB"
+        case SEED_CFB:       return     "SEED-CFB"
+        case SALSA20:         return    "SALSA20"
+        case CHACHA20:         return   "CHACHA20"
+        case CHACHA20IETF:      return  "CHACHA20IETF"
+         }
+    }
+    public var support:Bool {
+        switch self {
+        //case NONE:      return         false
+        case TABLE:     return         false
+        case RC4:         return        false
+        case RC4_MD5:      return       false
+        case AES_128_CFB:   return      true
+        case AES_192_CFB:    return     true
+        case AES_256_CFB:     return    true
+        case BF_CFB:           return   false
+        case CAMELLIA_128_CFB:  return  false
+        case CAMELLIA_192_CFB:   return false
+        case CAMELLIA_256_CFB:    return false
+        case CAST5_CFB:  return         false
+        case DES_CFB:     return        false
+        case IDEA_CFB:     return       false
+        case RC2_CFB:       return      false
+        case SEED_CFB:       return     false
+        case SALSA20:         return    true
+        case CHACHA20:         return   true
+        case CHACHA20IETF:      return  true
+        }
+    }
+    public var ccmode:CCMode {
+        switch self {
+//            public var kCCModeECB: Int { get } 1
+//        public var kCCModeCBC: Int { get } 2
+//        public var kCCModeCFB: Int { get } 3
+//        public var kCCModeCTR: Int { get } 4
+//        public var kCCModeF8: Int { get } 5// Unimplemented for now (not included)
+//        public var kCCModeLRW: Int { get } 6// Unimplemented for now (not included)
+//        public var kCCModeOFB: Int { get } 7
+//        public var kCCModeXTS: Int { get } 8
+//        public var kCCModeRC4: Int { get } 9
+//        public var kCCModeCFB8: Int { get } 10
+        case RC4:         return        9
+        case RC4_MD5:      return       9
+        case AES_128_CFB:   return      3
+        case AES_192_CFB:    return     3
+        case AES_256_CFB:     return    3
+        case BF_CFB:           return   3
+//        case CAMELLIA_128_CFB:  return  false
+//        case CAMELLIA_192_CFB:   return false
+//        case CAMELLIA_256_CFB:    return false
+        case CAST5_CFB:  return         3
+        case DES_CFB:     return        3
+        case IDEA_CFB:     return       3
+        case RC2_CFB:       return      3
+        case SEED_CFB:       return     3
+//        case SALSA20:         return    true
+//        case CHACHA20:         return   true
+//        case CHACHA20IETF:      return  true
+
+        default:
+            return UInt32.max
+        }
+    }
+//    func supported_ciphers() ->CCAlgorithm {
+//        if self.rawValue != -1{
+//            let algorithm = findCCAlgorithm(Int32(self.rawValue))
+//            return algorithm
+//        }else {
+//            return UInt32.max
+//        }
+//        
+//    }
+    public var iv_size:Int {
+        return supported_ciphers_iv_size[self.rawValue]
+    }
+    public var key_size:Int {
+        return supported_ciphers_key_size[self.rawValue]
+    }
+    init(cipher:String){
+        let up = cipher.uppercaseString
+        var raw = 0
+        switch up {
+        //case "NONE":     raw = -1
+        case "TABLE":     raw = 0
+        case "RC4":         raw = 1
+        case "RC4-MD5":      raw = 2
+        case "AES-128-CFB":   raw = 3
+        case "AES-192-CFB":    raw = 4
+        case "AES-256-CFB":     raw = 5
+        case "BF-CFB":           raw = 6
+        case "CAMELLIA-128-CFB":  raw = 7
+        case "CAMELLIA-192-CFB":   raw = 8
+        case "CAMELLIA-256-CFB":    raw = 9
+        case "CAST5-CFB":          raw = 10
+        case "DES-CFB":     raw = 11
+        case "IDEA-CFB":     raw = 12
+        case "RC2-CFB":       raw = 13
+        case "SEED-CFB":       raw = 14
+        case "SALSA20":         raw = 15
+        case "CHACHA20":         raw = 16
+        case "CHACHA20IETF":      raw = 17
+        default:
+            raw = 0
+        }
+        self = CryptoMethod(rawValue:raw)!
+    }
+}
+
+
 let  config_ciphers = [
     "table":false,
     "rc4":false,

            return nil;
            
        }
        
        if let left = genData(encrypt_bytes) {
            
            // Alloc Data Out
            let cipherDataDecrypt:NSMutableData = NSMutableData.init(length: left.length)!;
            
            //alloc number of bytes written to data Out
            var  outLengthDecrypt:NSInteger = 0
            
            //Update Cryptor
            let updateDecrypt:CCCryptorStatus = CCCryptorUpdate(recv_ctx!.ctx,
                                                                left.bytes, //const void *dataIn,
                left.length,  //size_t dataInLength,
                cipherDataDecrypt.mutableBytes, //void *dataOut,
                cipherDataDecrypt.length, // size_t dataOutAvailable,
                &outLengthDecrypt); // size_t *dataOutMoved)
            
            if (updateDecrypt == CCCryptorStatus(kCCSuccess))
            {
                //Cut Data Out with nedded length
                cipherDataDecrypt.length = outLengthDecrypt;
                
                // Data to String
                //NSString* cipherFinalDecrypt = [[NSString alloc] initWithData:cipherDataDecrypt encoding:NSUTF8StringEncoding];
                
                //Final Cryptor
                let final:CCCryptorStatus = CCCryptorFinal(recv_ctx!.ctx, //CCCryptorRef cryptorRef,
                    cipherDataDecrypt.mutableBytes, //void *dataOut,
                    cipherDataDecrypt.length, // size_t dataOutAvailable,
                    &outLengthDecrypt); // size_t *dataOutMoved)
                
                if (final != CCCryptorStatus( kCCSuccess))
                {
                    logStream.write("decrypt CCCryptorFinal failure")
                    //Release Cryptor
                    //CCCryptorStatus release =
                    //CCCryptorRelease(cryptor); //CCCryptorRef cryptorRef
                }
                
                return cipherDataDecrypt ;//cipherFinalDecrypt;
            }else {
                
                logStream.write("decrypt CCCryptorUpdate failure")
            }
        }else {
            logStream.write("decrypt no Data")
        }
        
        
        
        return nil
    }
    func getSecureRandom(bytesCount:Int) ->NSData {
        // Swift
        //import Security
        

        let d = NSMutableData.init(length: md5Len+bytes.length)!
        //d := make([]byte, md5Len+len(password))
        var start = 0
        for _ in 0 ..< cnt {//最长32,算法还不支持>32 的情况
            start += md5Len
            memcpy(d.mutableBytes,m.bytes , m.length)
            memcpy(d.mutableBytes+md5Len, bytes.bytes, bytes.length)
            let md5 = d.md5
            m.appendData(md5)
            if m.length >= keyLen {
                break;
            }
        }
        
        
        return m
    }
    func crypto_stream_xor_ic(cd:NSMutableData,md:NSData,mlen: UInt64, nd:NSData, ic:UInt64, kd:NSData)  ->Int32{
        
        let c:UnsafeMutablePointer<UInt8> = UnsafeMutablePointer<UInt8>.init(cd.mutableBytes)
        let m:UnsafePointer<UInt8> = UnsafePointer<UInt8>.init(md.bytes)
        let n:UnsafePointer<UInt8> = UnsafePointer<UInt8>.init(md.bytes)
        let k:UnsafePointer<UInt8> = UnsafePointer<UInt8>.init(kd.bytes)
        let xx = Int32(send_ctx!.m.rawValue)
        switch send_ctx!.m{
        case .SALSA20:
            return crypto_stream_salsa20_xor_ic(c, m, mlen, n, ic, k);
            //return crypto_stream_xor_icc(c, m, mlen, n, ic, k,xx)
        case .CHACHA20:
            return crypto_stream_chacha20_xor_ic(c, m, mlen, n, ic, k);
            //return crypto_stream_xor_icc(c, m, mlen, n, ic, k,xx)
        case .CHACHA20IETF:
            //return crypto_stream_chacha20_ietf_xor_ic(c, m, mlen, n, UInt32(ic), k);
            return 0 
        default:
            break
        }
        return 0
    }
    func genData(encrypt_bytes:NSData) ->NSData?{
        
