维坦
感谢您的关注!
-
Jul231 Comment
之前的一篇文章提到过一种逆向思维求解MD5的方法.
后来发现真的有人这么做了, 其中数据量最大的网站标称自己拥有4T的数据量, 可以解8位以下的数字和字母组合.
即然是之前自己有过的想法, 那就拿F#来具体实现一下吧:
#light namespace ViTarn module MD5 open System open System.Data open System.Diagnostics open System.IO open System.Security.Cryptography open System.Text // sqlite.phxsoftware.com #r "System.Data.SQLite.DLL" open System.Data.SQLite // 数据库名 let dbFile = "db.sqlite" // 连接字符串 let connString = let csb = SQLiteConnectionStringBuilder () csb.DataSource <- dbFile csb.ConnectionString // 秒表 let watch = new Stopwatch () watch.Start() // 为调试方便 输出对象并换行 let debug x = x |> print_any Console.WriteLine () // 从' '到'~'共95个常用于密码的字符 可以当成95进制看待 let n2cl n = let rec prase n l = let d = n % 95 let c = d + 32 |> char let d = n - d if d > 95 then prase (d / 95) (c :: l) else c :: l |> List.to_array prase n [] // MD5加密字符串 let md5 (str : string) = use md5Hasher = MD5.Create () str |> Encoding.Default.GetBytes |> md5Hasher.ComputeHash |> Seq.map (fun x -> x.ToString "x2") |> Seq.fold (fun x y -> x + y) "" // 创建数据库 if dbFile |> File.Exists |> not then dbFile |> SQLiteConnection.CreateFile use conn = new SQLiteConnection (connString) let sql = "PRAGMA auto_vacuum = 1; " + "PRAGMA encoding = 'UTF-8'; " + "PRAGMA page_size = 4096; " + "PRAGMA synchronous = OFF; " + "CREATE TABLE md5 (p VARCHAR(42) NOT NULL COLLATE NOCASE, s VARCHAR(9) NOT NULL COLLATE NOCASE);" use cmd = new SQLiteCommand (sql, conn) conn.Open () cmd.ExecuteNonQuery () |> ignore conn.Close () let main _ = let sql = "INSERT INTO md5 " + "VALUES(?, ?); " use conn = new SQLiteConnection (connString) use cmd = new SQLiteCommand(sql, conn) cmd.Parameters.AddRange [|new SQLiteParameter(); new SQLiteParameter()|] conn.Open () use tr = conn.BeginTransaction () cmd.Transaction <- tr for i = 0 to 857374 do let s = new String (n2cl i) let p = md5 s cmd.Parameters.[0].Value <- p cmd.Parameters.[1].Value <- s cmd.ExecuteNonQuery () |> ignore if i % 10000 = 0 then i |> debug tr.Commit() conn.Close () main () watch.Elapsed |> debug Console.ReadKey()
为什么是857374?
95 * 95 * 95 - 1 = 857374模拟的95进制, 是从"空格"(' ')到波浪线('~')的, 用ASCII表示就是32到126.
所在0 to 857374代表' '到'~~~'在我的电脑上耗时00:01:08
CPU: AMD3000+
RAM: 1G
以DEBUG模式运行
最终产生的数据库约36M+ -
Jul8No Comments
虽然上篇文章中提到 SQLite 是弱类型数据库, 但对于 System.Data.SQLite 来说, 为了更好的与 Ado.NET 2.0 互操作, 作者仍然建议在创建表的时候就指定类型, 以方便程序进行类型转换, 下面是类型关键字列表:
DbType.Boolean
BIT
YESNO
LOGICAL
BOOLDbType.Byte
TINYINTDbType.Int16
SMALLINTDbType.Int32
INTDbType.Int64
INTEGER
BIGINT
COUNTER
AUTOINCREMENT
IDENTITY
LONGDbType.Single
REALDbType.Double
DOUBLE
FLOATDbType.Decimal
NUMERIC
DECIMAL
MONEY
CURRENCYDbType.String
CHAR
NCHAR
VARCHAR
NVARCHAR
TEXT
NTEXT
LONGTEXT
LONGCHAR
LONGVARCHAR
STRING
MEMO
NOTEDbType.Binary
BLOB
BINARY
VARBINARY
IMAGE
GENERAL
OLEOBJECTDbType.Guid
GUID
UNIQUEIDENTIFIERDbType.DateTime
TIME
DATE
DATETIME
SMALLDATE
SMALLDATETIME
TIMESTAMP有两点需要注意:
- SQLite 主键默认的 INTEGER 类型对应的是 Int64, 而 INT 对应的是 Int32.
- 日期和时间类型最终存储为字符串, 所以格式必须符合ISO8601标准:
"yyyy-MM-dd HH:mm:ss",
"yyyyMMddHHmmss",
"yyyyMMddTHHmmssfffffff",
"yyyy-MM-dd",
"yy-MM-dd",
"yyyyMMdd",
"HH:mm:ss",
"THHmmss"
-
Jul7No Comments
System.Data.SQLite.dll可以从http://sqlite.phxsoftware.com/得到
冷门的语言+冷门的应用. 不多解释了, 直接上代码:
#light open System open System.Data open System.IO #r "System.Data.SQLite.DLL" open System.Data.SQLite // 输出调试结果到命名行 let debug x = x |> print_any Console.WriteLine() let space = [|for i in 1 .. 50 -> "*"|] |> string.Concat // 数据库文件名 let dbFileName = "HelloSQLite.sqlite" // 连接字符串 let connString = let builder = SQLiteConnectionStringBuilder() builder.DataSource <- dbFileName builder.ConnectionString space |> debug "连接字符串: " + connString |> debug // 创建数据库文件 space |> debug "创建数据库..." |> debug try dbFileName |> File.Delete SQLiteConnection.CreateFile dbFileName with e -> e |> debug let test _ = use conn = new SQLiteConnection(connString) use cmd = conn.CreateCommand() conn.Open() // 开始计时 let watch = new System.Diagnostics.Stopwatch() watch.Start() space |> debug "创建表..." |> debug try (* SQLite 官方文档提及的数据类型只有5种: NULL INTEGER NUMERIC TEXT BLOB 你可能觉得太少了, 事实上 SQLite 是弱类型, 建表时定义的数据类型只是个标识, 对数据列的类型并没有实质性的作用. 你也可以把 TEXT 类型定义成更复杂的 NVARCHAR(50) 之类的, 这只是为了未来数据迁移的方便. *) cmd.CommandText <- "CREATE TABLE [Test] ( " + "[Int32] INTEGER NOT NULL, " + "[String] TEXT NOT NULL)" cmd.ExecuteNonQuery() |> ignore with e -> conn.Close() e |> debug watch.Elapsed |> debug watch.Reset() watch.Start() space |> debug "乱入数据十万行..." |> debug use trans = conn.BeginTransaction() cmd.Transaction <- trans try // 注意: Int32这个列名有些误导, 封装的作者提及 INTEGER 对应 ADO.net 2.0 的 Int64 类型 cmd.CommandText <- "INSERT INTO [Test](Int32, String) " + "VALUES(?, ?)" // 下面这种生成参数的方式 在参数较多时会有方便 但不能用seq [for i in 0 .. 1 -> cmd.CreateParameter()] |> List.to_array |> cmd.Parameters.AddRange |> ignore // 参数化插入 这是官方推荐的方式 性能最好 for i in 0 .. 99999 do let vl = [box i; box ((i * 1000).ToString())] for j = 0 to (cmd.Parameters.Count - 1) do cmd.Parameters.[j].Value <- List.nth vl j cmd.ExecuteNonQuery() |> ignore trans.Commit() with e -> trans.Rollback() conn.Close() e |> debug watch.Elapsed |> debug watch.Reset() watch.Start() space |> debug "查询前3行..." |> debug try cmd.CommandText <- "SELECT * FROM [Test] " + "WHERE [Int32]<3" use reader = cmd.ExecuteReader() while reader.Read() do reader.GetInt32 0 |> debug reader.GetString 1 |> debug with e -> e |> debug watch.Elapsed |> debug watch.Stop() conn.Close() test() Console.ReadKey()

评论