mirror of https://github.com/hashcat/hashcat.git
parent
adbcef6909
commit
f70f3761a9
@ -0,0 +1,341 @@
|
|||||||
|
/**
|
||||||
|
* Author......: See docs/credits.txt
|
||||||
|
* License.....: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "inc_vendor.h"
|
||||||
|
#include "inc_common.h"
|
||||||
|
#include "inc_types.h"
|
||||||
|
#include "inc_platform.h"
|
||||||
|
#include "inc_bip39.h"
|
||||||
|
#include "inc_hash_sha256.h"
|
||||||
|
|
||||||
|
CONSTANT_VK char BIP39_WORDS[2048][9] =
|
||||||
|
{ "abandon", "ability", "able", "about", "above", "absent", "absorb", "abstract", "absurd", "abuse", "access", "accident", "account", "accuse", "achieve", "acid", "acoustic", "acquire", "across", "act", "action", "actor", "actress", "actual", "adapt", "add", "addict", "address", "adjust", "admit", "adult", "advance", "advice", "aerobic", "affair", "afford", "afraid", "again", "age", "agent", "agree", "ahead", "aim", "air", "airport", "aisle", "alarm", "album", "alcohol", "alert", "alien", "all", "alley", "allow", "almost", "alone", "alpha", "already", "also", "alter", "always", "amateur", "amazing", "among", "amount", "amused", "analyst", "anchor", "ancient", "anger", "angle", "angry", "animal", "ankle", "announce", "annual", "another", "answer", "antenna", "antique", "anxiety", "any", "apart", "apology", "appear", "apple", "approve", "april", "arch", "arctic", "area", "arena", "argue", "arm", "armed", "armor", "army", "around", "arrange", "arrest", "arrive", "arrow", "art", "artefact", "artist", "artwork",
|
||||||
|
"ask", "aspect", "assault", "asset", "assist", "assume", "asthma", "athlete", "atom", "attack", "attend", "attitude", "attract", "auction", "audit", "august", "aunt", "author", "auto", "autumn", "average", "avocado", "avoid", "awake", "aware", "away", "awesome", "awful", "awkward", "axis", "baby", "bachelor", "bacon", "badge", "bag", "balance", "balcony", "ball", "bamboo", "banana", "banner", "bar", "barely", "bargain", "barrel", "base", "basic", "basket", "battle", "beach", "bean", "beauty", "because", "become", "beef", "before", "begin", "behave", "behind", "believe", "below", "belt", "bench", "benefit", "best", "betray", "better", "between", "beyond", "bicycle", "bid", "bike", "bind", "biology", "bird", "birth", "bitter", "black", "blade", "blame", "blanket", "blast", "bleak", "bless", "blind", "blood", "blossom", "blouse", "blue", "blur", "blush", "board", "boat", "body", "boil", "bomb", "bone", "bonus", "book", "boost", "border", "boring", "borrow", "boss", "bottom", "bounce", "box", "boy", "bracket",
|
||||||
|
"brain", "brand", "brass", "brave",
|
||||||
|
"bread", "breeze", "brick", "bridge", "brief", "bright", "bring", "brisk", "broccoli", "broken", "bronze", "broom", "brother", "brown", "brush", "bubble", "buddy", "budget", "buffalo", "build", "bulb", "bulk", "bullet", "bundle", "bunker", "burden", "burger", "burst", "bus", "business", "busy", "butter", "buyer", "buzz", "cabbage", "cabin", "cable", "cactus", "cage", "cake", "call", "calm", "camera", "camp", "can", "canal", "cancel", "candy", "cannon", "canoe", "canvas", "canyon", "capable", "capital", "captain", "car", "carbon", "card", "cargo", "carpet", "carry", "cart", "case", "cash", "casino", "castle", "casual", "cat", "catalog", "catch", "category", "cattle", "caught", "cause", "caution", "cave", "ceiling", "celery", "cement", "census", "century", "cereal", "certain", "chair", "chalk", "champion", "change", "chaos", "chapter", "charge", "chase", "chat", "cheap", "check", "cheese", "chef", "cherry", "chest", "chicken", "chief", "child", "chimney", "choice", "choose", "chronic", "chuckle", "chunk",
|
||||||
|
"churn", "cigar", "cinnamon", "circle",
|
||||||
|
"citizen", "city", "civil", "claim", "clap", "clarify", "claw", "clay", "clean", "clerk", "clever", "click", "client", "cliff", "climb", "clinic", "clip", "clock", "clog", "close", "cloth", "cloud", "clown", "club", "clump", "cluster", "clutch", "coach", "coast", "coconut", "code", "coffee", "coil", "coin", "collect", "color", "column", "combine", "come", "comfort", "comic", "common", "company", "concert", "conduct", "confirm", "congress", "connect", "consider", "control", "convince", "cook", "cool", "copper", "copy", "coral", "core", "corn", "correct", "cost", "cotton", "couch", "country", "couple", "course", "cousin", "cover", "coyote", "crack", "cradle", "craft", "cram", "crane", "crash", "crater", "crawl", "crazy", "cream", "credit", "creek", "crew", "cricket", "crime", "crisp", "critic", "crop", "cross", "crouch", "crowd", "crucial", "cruel", "cruise", "crumble", "crunch", "crush", "cry", "crystal", "cube", "culture", "cup", "cupboard", "curious", "current", "curtain", "curve", "cushion", "custom",
|
||||||
|
"cute", "cycle", "dad", "damage",
|
||||||
|
"damp", "dance", "danger", "daring", "dash", "daughter", "dawn", "day", "deal", "debate", "debris", "decade", "december", "decide", "decline", "decorate", "decrease", "deer", "defense", "define", "defy", "degree", "delay", "deliver", "demand", "demise", "denial", "dentist", "deny", "depart", "depend", "deposit", "depth", "deputy", "derive", "describe", "desert", "design", "desk", "despair", "destroy", "detail", "detect", "develop", "device", "devote", "diagram", "dial", "diamond", "diary", "dice", "diesel", "diet", "differ", "digital", "dignity", "dilemma", "dinner", "dinosaur", "direct", "dirt", "disagree", "discover", "disease", "dish", "dismiss", "disorder", "display", "distance", "divert", "divide", "divorce", "dizzy", "doctor", "document", "dog", "doll", "dolphin", "domain", "donate", "donkey", "donor", "door", "dose", "double", "dove", "draft", "dragon", "drama", "drastic", "draw", "dream", "dress", "drift", "drill", "drink", "drip", "drive", "drop", "drum", "dry", "duck", "dumb", "dune", "during",
|
||||||
|
"dust", "dutch", "duty", "dwarf",
|
||||||
|
"dynamic", "eager", "eagle", "early", "earn", "earth", "easily", "east", "easy", "echo", "ecology", "economy", "edge", "edit", "educate", "effort", "egg", "eight", "either", "elbow", "elder", "electric", "elegant", "element", "elephant", "elevator", "elite", "else", "embark", "embody", "embrace", "emerge", "emotion", "employ", "empower", "empty", "enable", "enact", "end", "endless", "endorse", "enemy", "energy", "enforce", "engage", "engine", "enhance", "enjoy", "enlist", "enough", "enrich", "enroll", "ensure", "enter", "entire", "entry", "envelope", "episode", "equal", "equip", "era", "erase", "erode", "erosion", "error", "erupt", "escape", "essay", "essence", "estate", "eternal", "ethics", "evidence", "evil", "evoke", "evolve", "exact", "example", "excess", "exchange", "excite", "exclude", "excuse", "execute", "exercise", "exhaust", "exhibit", "exile", "exist", "exit", "exotic", "expand", "expect", "expire", "explain", "expose", "express", "extend", "extra", "eye", "eyebrow", "fabric", "face", "faculty",
|
||||||
|
"fade", "faint", "faith", "fall",
|
||||||
|
"false", "fame", "family", "famous", "fan", "fancy", "fantasy", "farm", "fashion", "fat", "fatal", "father", "fatigue", "fault", "favorite", "feature", "february", "federal", "fee", "feed", "feel", "female", "fence", "festival", "fetch", "fever", "few", "fiber", "fiction", "field", "figure", "file", "film", "filter", "final", "find", "fine", "finger", "finish", "fire", "firm", "first", "fiscal", "fish", "fit", "fitness", "fix", "flag", "flame", "flash", "flat", "flavor", "flee", "flight", "flip", "float", "flock", "floor", "flower", "fluid", "flush", "fly", "foam", "focus", "fog", "foil", "fold", "follow", "food", "foot", "force", "forest", "forget", "fork", "fortune", "forum", "forward", "fossil", "foster", "found", "fox", "fragile", "frame", "frequent", "fresh", "friend", "fringe", "frog", "front", "frost", "frown", "frozen", "fruit", "fuel", "fun", "funny", "furnace", "fury", "future", "gadget", "gain", "galaxy", "gallery", "game", "gap", "garage", "garbage", "garden", "garlic", "garment", "gas", "gasp",
|
||||||
|
"gate", "gather", "gauge", "gaze",
|
||||||
|
"general", "genius", "genre", "gentle", "genuine", "gesture", "ghost", "giant", "gift", "giggle", "ginger", "giraffe", "girl", "give", "glad", "glance", "glare", "glass", "glide", "glimpse", "globe", "gloom", "glory", "glove", "glow", "glue", "goat", "goddess", "gold", "good", "goose", "gorilla", "gospel", "gossip", "govern", "gown", "grab", "grace", "grain", "grant", "grape", "grass", "gravity", "great", "green", "grid", "grief", "grit", "grocery", "group", "grow", "grunt", "guard", "guess", "guide", "guilt", "guitar", "gun", "gym", "habit", "hair", "half", "hammer", "hamster", "hand", "happy", "harbor", "hard", "harsh", "harvest", "hat", "have", "hawk", "hazard", "head", "health", "heart", "heavy", "hedgehog", "height", "hello", "helmet", "help", "hen", "hero", "hidden", "high", "hill", "hint", "hip", "hire", "history", "hobby", "hockey", "hold", "hole", "holiday", "hollow", "home", "honey", "hood", "hope", "horn", "horror", "horse", "hospital", "host", "hotel", "hour", "hover", "hub", "huge", "human",
|
||||||
|
"humble", "humor", "hundred",
|
||||||
|
"hungry", "hunt", "hurdle", "hurry", "hurt", "husband", "hybrid", "ice", "icon", "idea", "identify", "idle", "ignore", "ill", "illegal", "illness", "image", "imitate", "immense", "immune", "impact", "impose", "improve", "impulse", "inch", "include", "income", "increase", "index", "indicate", "indoor", "industry", "infant", "inflict", "inform", "inhale", "inherit", "initial", "inject", "injury", "inmate", "inner", "innocent", "input", "inquiry", "insane", "insect", "inside", "inspire", "install", "intact", "interest", "into", "invest", "invite", "involve", "iron", "island", "isolate", "issue", "item", "ivory", "jacket", "jaguar", "jar", "jazz", "jealous", "jeans", "jelly", "jewel", "job", "join", "joke", "journey", "joy", "judge", "juice", "jump", "jungle", "junior", "junk", "just", "kangaroo", "keen", "keep", "ketchup", "key", "kick", "kid", "kidney", "kind", "kingdom", "kiss", "kit", "kitchen", "kite", "kitten", "kiwi", "knee", "knife", "knock", "know", "lab", "label", "labor", "ladder", "lady", "lake",
|
||||||
|
"lamp", "language", "laptop", "large",
|
||||||
|
"later", "latin", "laugh", "laundry", "lava", "law", "lawn", "lawsuit", "layer", "lazy", "leader", "leaf", "learn", "leave", "lecture", "left", "leg", "legal", "legend", "leisure", "lemon", "lend", "length", "lens", "leopard", "lesson", "letter", "level", "liar", "liberty", "library", "license", "life", "lift", "light", "like", "limb", "limit", "link", "lion", "liquid", "list", "little", "live", "lizard", "load", "loan", "lobster", "local", "lock", "logic", "lonely", "long", "loop", "lottery", "loud", "lounge", "love", "loyal", "lucky", "luggage", "lumber", "lunar", "lunch", "luxury", "lyrics", "machine", "mad", "magic", "magnet", "maid", "mail", "main", "major", "make", "mammal", "man", "manage", "mandate", "mango", "mansion", "manual", "maple", "marble", "march", "margin", "marine", "market", "marriage", "mask", "mass", "master", "match", "material", "math", "matrix", "matter", "maximum", "maze", "meadow", "mean", "measure", "meat", "mechanic", "medal", "media", "melody", "melt", "member", "memory",
|
||||||
|
"mention", "menu", "mercy", "merge",
|
||||||
|
"merit", "merry", "mesh", "message", "metal", "method", "middle", "midnight", "milk", "million", "mimic", "mind", "minimum", "minor", "minute", "miracle", "mirror", "misery", "miss", "mistake", "mix", "mixed", "mixture", "mobile", "model", "modify", "mom", "moment", "monitor", "monkey", "monster", "month", "moon", "moral", "more", "morning", "mosquito", "mother", "motion", "motor", "mountain", "mouse", "move", "movie", "much", "muffin", "mule", "multiply", "muscle", "museum", "mushroom", "music", "must", "mutual", "myself", "mystery", "myth", "naive", "name", "napkin", "narrow", "nasty", "nation", "nature", "near", "neck", "need", "negative", "neglect", "neither", "nephew", "nerve", "nest", "net", "network", "neutral", "never", "news", "next", "nice", "night", "noble", "noise", "nominee", "noodle", "normal", "north", "nose", "notable", "note", "nothing", "notice", "novel", "now", "nuclear", "number", "nurse", "nut", "oak", "obey", "object", "oblige", "obscure", "observe", "obtain", "obvious", "occur",
|
||||||
|
"ocean", "october", "odor", "off",
|
||||||
|
"offer", "office", "often", "oil", "okay", "old", "olive", "olympic", "omit", "once", "one", "onion", "online", "only", "open", "opera", "opinion", "oppose", "option", "orange", "orbit", "orchard", "order", "ordinary", "organ", "orient", "original", "orphan", "ostrich", "other", "outdoor", "outer", "output", "outside", "oval", "oven", "over", "own", "owner", "oxygen", "oyster", "ozone", "pact", "paddle", "page", "pair", "palace", "palm", "panda", "panel", "panic", "panther", "paper", "parade", "parent", "park", "parrot", "party", "pass", "patch", "path", "patient", "patrol", "pattern", "pause", "pave", "payment", "peace", "peanut", "pear", "peasant", "pelican", "pen", "penalty", "pencil", "people", "pepper", "perfect", "permit", "person", "pet", "phone", "photo", "phrase", "physical", "piano", "picnic", "picture", "piece", "pig", "pigeon", "pill", "pilot", "pink", "pioneer", "pipe", "pistol", "pitch", "pizza", "place", "planet", "plastic", "plate", "play", "please", "pledge", "pluck", "plug", "plunge",
|
||||||
|
"poem", "poet", "point", "polar",
|
||||||
|
"pole", "police", "pond", "pony", "pool", "popular", "portion", "position", "possible", "post", "potato", "pottery", "poverty", "powder", "power", "practice", "praise", "predict", "prefer", "prepare", "present", "pretty", "prevent", "price", "pride", "primary", "print", "priority", "prison", "private", "prize", "problem", "process", "produce", "profit", "program", "project", "promote", "proof", "property", "prosper", "protect", "proud", "provide", "public", "pudding", "pull", "pulp", "pulse", "pumpkin", "punch", "pupil", "puppy", "purchase", "purity", "purpose", "purse", "push", "put", "puzzle", "pyramid", "quality", "quantum", "quarter", "question", "quick", "quit", "quiz", "quote", "rabbit", "raccoon", "race", "rack", "radar", "radio", "rail", "rain", "raise", "rally", "ramp", "ranch", "random", "range", "rapid", "rare", "rate", "rather", "raven", "raw", "razor", "ready", "real", "reason", "rebel", "rebuild", "recall", "receive", "recipe", "record", "recycle", "reduce", "reflect", "reform", "refuse",
|
||||||
|
"region", "regret", "regular", "reject",
|
||||||
|
"relax", "release", "relief", "rely", "remain", "remember", "remind", "remove", "render", "renew", "rent", "reopen", "repair", "repeat", "replace", "report", "require", "rescue", "resemble", "resist", "resource", "response", "result", "retire", "retreat", "return", "reunion", "reveal", "review", "reward", "rhythm", "rib", "ribbon", "rice", "rich", "ride", "ridge", "rifle", "right", "rigid", "ring", "riot", "ripple", "risk", "ritual", "rival", "river", "road", "roast", "robot", "robust", "rocket", "romance", "roof", "rookie", "room", "rose", "rotate", "rough", "round", "route", "royal", "rubber", "rude", "rug", "rule", "run", "runway", "rural", "sad", "saddle", "sadness", "safe", "sail", "salad", "salmon", "salon", "salt", "salute", "same", "sample", "sand", "satisfy", "satoshi", "sauce", "sausage", "save", "say", "scale", "scan", "scare", "scatter", "scene", "scheme", "school", "science", "scissors", "scorpion", "scout", "scrap", "screen", "script", "scrub", "sea", "search", "season", "seat", "second",
|
||||||
|
"secret", "section", "security", "seed",
|
||||||
|
"seek", "segment", "select", "sell", "seminar", "senior", "sense", "sentence", "series", "service", "session", "settle", "setup", "seven", "shadow", "shaft", "shallow", "share", "shed", "shell", "sheriff", "shield", "shift", "shine", "ship", "shiver", "shock", "shoe", "shoot", "shop", "short", "shoulder", "shove", "shrimp", "shrug", "shuffle", "shy", "sibling", "sick", "side", "siege", "sight", "sign", "silent", "silk", "silly", "silver", "similar", "simple", "since", "sing", "siren", "sister", "situate", "six", "size", "skate", "sketch", "ski", "skill", "skin", "skirt", "skull", "slab", "slam", "sleep", "slender", "slice", "slide", "slight", "slim", "slogan", "slot", "slow", "slush", "small", "smart", "smile", "smoke", "smooth", "snack", "snake", "snap", "sniff", "snow", "soap", "soccer", "social", "sock", "soda", "soft", "solar", "soldier", "solid", "solution", "solve", "someone", "song", "soon", "sorry", "sort", "soul", "sound", "soup", "source", "south", "space", "spare", "spatial", "spawn", "speak",
|
||||||
|
"special", "speed", "spell", "spend",
|
||||||
|
"sphere", "spice", "spider", "spike", "spin", "spirit", "split", "spoil", "sponsor", "spoon", "sport", "spot", "spray", "spread", "spring", "spy", "square", "squeeze", "squirrel", "stable", "stadium", "staff", "stage", "stairs", "stamp", "stand", "start", "state", "stay", "steak", "steel", "stem", "step", "stereo", "stick", "still", "sting", "stock", "stomach", "stone", "stool", "story", "stove", "strategy", "street", "strike", "strong", "struggle", "student", "stuff", "stumble", "style", "subject", "submit", "subway", "success", "such", "sudden", "suffer", "sugar", "suggest", "suit", "summer", "sun", "sunny", "sunset", "super", "supply", "supreme", "sure", "surface", "surge", "surprise", "surround", "survey", "suspect", "sustain", "swallow", "swamp", "swap", "swarm", "swear", "sweet", "swift", "swim", "swing", "switch", "sword", "symbol", "symptom", "syrup", "system", "table", "tackle", "tag", "tail", "talent", "talk", "tank", "tape", "target", "task", "taste", "tattoo", "taxi", "teach", "team", "tell",
|
||||||
|
"ten", "tenant", "tennis", "tent",
|
||||||
|
"term", "test", "text", "thank", "that", "theme", "then", "theory", "there", "they", "thing", "this", "thought", "three", "thrive", "throw", "thumb", "thunder", "ticket", "tide", "tiger", "tilt", "timber", "time", "tiny", "tip", "tired", "tissue", "title", "toast", "tobacco", "today", "toddler", "toe", "together", "toilet", "token", "tomato", "tomorrow", "tone", "tongue", "tonight", "tool", "tooth", "top", "topic", "topple", "torch", "tornado", "tortoise", "toss", "total", "tourist", "toward", "tower", "town", "toy", "track", "trade", "traffic", "tragic", "train", "transfer", "trap", "trash", "travel", "tray", "treat", "tree", "trend", "trial", "tribe", "trick", "trigger", "trim", "trip", "trophy", "trouble", "truck", "true", "truly", "trumpet", "trust", "truth", "try", "tube", "tuition", "tumble", "tuna", "tunnel", "turkey", "turn", "turtle", "twelve", "twenty", "twice", "twin", "twist", "two", "type", "typical", "ugly", "umbrella", "unable", "unaware", "uncle", "uncover", "under", "undo", "unfair",
|
||||||
|
"unfold", "unhappy", "uniform", "unique",
|
||||||
|
"unit", "universe", "unknown", "unlock", "until", "unusual", "unveil", "update", "upgrade", "uphold", "upon", "upper", "upset", "urban", "urge", "usage", "use", "used", "useful", "useless", "usual", "utility", "vacant", "vacuum", "vague", "valid", "valley", "valve", "van", "vanish", "vapor", "various", "vast", "vault", "vehicle", "velvet", "vendor", "venture", "venue", "verb", "verify", "version", "very", "vessel", "veteran", "viable", "vibrant", "vicious", "victory", "video", "view", "village", "vintage", "violin", "virtual", "virus", "visa", "visit", "visual", "vital", "vivid", "vocal", "voice", "void", "volcano", "volume", "vote", "voyage", "wage", "wagon", "wait", "walk", "wall", "walnut", "want", "warfare", "warm", "warrior", "wash", "wasp", "waste", "water", "wave", "way", "wealth", "weapon", "wear", "weasel", "weather", "web", "wedding", "weekend", "weird", "welcome", "west", "wet", "whale", "what", "wheat", "wheel", "when", "where", "whip", "whisper", "wide", "width", "wife", "wild", "will", "win",
|
||||||
|
"window", "wine", "wing", "wink",
|
||||||
|
"winner", "winter", "wire", "wisdom", "wise", "wish", "witness", "wolf", "woman", "wonder", "wood", "wool", "word", "work", "world", "worry", "worth", "wrap", "wreck", "wrestle", "wrist", "write", "wrong", "yard", "year", "yellow", "you", "young", "youth", "zebra", "zero", "zone", "zoo"
|
||||||
|
};
|
||||||
|
|
||||||
|
CONSTANT_VK u8 BIP39_WORD_LENGTHS[2048] =
|
||||||
|
{ 7, 7, 4, 5, 5, 6, 6, 8, 6, 5, 6, 8, 7, 6, 7, 4, 8, 7, 6, 3, 6, 5, 7, 6, 5, 3, 6, 7, 6, 5, 5, 7, 6, 7, 6, 6, 6, 5, 3, 5, 5, 5, 3, 3, 7, 5, 5, 5, 7, 5, 5, 3, 5, 5, 6, 5, 5, 7, 4, 5, 6, 7, 7, 5, 6, 6, 7, 6, 7, 5, 5, 5, 6, 5, 8, 6, 7, 6, 7, 7, 7, 3, 5, 7, 6, 5, 7, 5, 4, 6, 4, 5, 5, 3, 5, 5, 4, 6, 7, 6, 6, 5, 3, 8, 6, 7, 3, 6, 7, 5, 6, 6, 6, 7, 4, 6, 6, 8, 7, 7, 5, 6, 4, 6, 4, 6, 7, 7, 5, 5, 5, 4, 7, 5, 7, 4, 4, 8, 5, 5, 3, 7, 7, 4, 6, 6, 6, 3, 6, 7, 6, 4, 5, 6, 6, 5, 4, 6, 7, 6, 4, 6, 5, 6, 6, 7, 5, 4, 5, 7, 4, 6, 6, 7, 6, 7, 3, 4, 4, 7, 4, 5, 6, 5, 5, 5, 7, 5, 5, 5, 5, 5, 7, 6, 4, 4, 5, 5, 4, 4, 4, 4, 4, 5, 4, 5, 6, 6, 6, 4, 6, 6, 3, 3, 7, 5, 5, 5, 5, 5, 6, 5, 6, 5, 6, 5, 5, 8, 6, 6, 5, 7, 5, 5, 6, 5, 6, 7, 5, 4, 4, 6, 6, 6, 6, 6, 5, 3, 8, 4, 6, 5, 4, 7, 5, 5, 6, 4, 4, 4, 4, 6, 4, 3, 5, 6, 5, 6, 5, 6, 6, 7, 7, 7, 3, 6, 4, 5, 6, 5, 4, 4, 4, 6, 6, 6, 3, 7, 5, 8, 6, 6, 5, 7, 4, 7, 6, 6, 6, 7, 6, 7, 5, 5, 8, 6, 5, 7, 6, 5, 4, 5, 5, 6, 4, 6, 5, 7, 5, 5, 7, 6, 6, 7, 7, 5, 5, 5, 8, 6, 7, 4, 5, 5, 4, 7, 4, 4, 5, 5,
|
||||||
|
6, 5, 6, 5, 5, 6, 4, 5, 4, 5, 5, 5, 5, 4, 5, 7, 6, 5, 5, 7, 4, 6, 4, 4, 7, 5, 6, 7, 4, 7, 5, 6, 7, 7, 7, 7, 8, 7, 8, 7, 8, 4, 4, 6, 4, 5, 4, 4, 7, 4, 6, 5, 7, 6, 6, 6, 5, 6, 5, 6, 5, 4, 5, 5, 6, 5, 5, 5, 6, 5, 4, 7, 5, 5, 6, 4, 5, 6, 5, 7, 5, 6, 7, 6, 5, 3, 7, 4, 7, 3, 8, 7, 7, 7, 5, 7, 6, 4, 5, 3, 6, 4, 5, 6, 6, 4, 8, 4, 3, 4, 6, 6, 6, 8, 6, 7, 8, 8, 4, 7, 6, 4, 6, 5, 7, 6, 6, 6, 7, 4, 6, 6, 7, 5, 6, 6, 8, 6, 6, 4, 7, 7, 6, 6, 7, 6, 6, 7, 4, 7, 5, 4, 6, 4, 6, 7, 7, 7, 6, 8, 6, 4, 8, 8, 7, 4, 7, 8, 7, 8, 6, 6, 7, 5, 6, 8, 3, 4, 7, 6, 6, 6, 5, 4, 4, 6, 4, 5, 6, 5, 7, 4, 5, 5, 5, 5, 5, 4, 5, 4, 4, 3, 4, 4, 4, 6, 4, 5, 4, 5, 7, 5, 5, 5, 4, 5, 6, 4, 4, 4, 7, 7, 4, 4, 7, 6, 3, 5, 6, 5, 5, 8, 7, 7, 8, 8, 5, 4, 6, 6, 7, 6, 7, 6, 7, 5, 6, 5, 3, 7, 7, 5, 6, 7, 6, 6, 7, 5, 6, 6, 6, 6, 6, 5, 6, 5, 8, 7, 5, 5, 3, 5, 5, 7, 5, 5, 6, 5, 7, 6, 7, 6, 8, 4, 5, 6, 5, 7, 6, 8, 6, 7, 6, 7, 8, 7, 7, 5, 5, 4, 6, 6, 6, 6, 7, 6, 7, 6, 5, 3, 7, 6, 4, 7, 4, 5, 5, 4, 5, 4, 6, 6, 3, 5, 7, 4, 7, 3, 5, 6, 7, 5, 8, 7, 8, 7, 3, 4, 4, 6, 5,
|
||||||
|
8, 5, 5, 3, 5, 7, 5, 6, 4, 4, 6, 5,
|
||||||
|
4, 4, 6, 6, 4, 4, 5, 6, 4, 3, 7, 3, 4, 5, 5, 4, 6, 4, 6, 4, 5, 5, 5, 6, 5, 5, 3, 4, 5, 3, 4, 4, 6, 4, 4, 5, 6, 6, 4, 7, 5, 7, 6, 6, 5, 3, 7, 5, 8, 5, 6, 6, 4, 5, 5, 5, 6, 5, 4, 3, 5, 7, 4, 6, 6, 4, 6, 7, 4, 3, 6, 7, 6, 6, 7, 3, 4, 4, 6, 5, 4, 7, 6, 5, 6, 7, 7, 5, 5, 4, 6, 6, 7, 4, 4, 4, 6, 5, 5, 5, 7, 5, 5, 5, 5, 4, 4, 4, 7, 4, 4, 5, 7, 6, 6, 6, 4, 4, 5, 5, 5, 5, 5, 7, 5, 5, 4, 5, 4, 7, 5, 4, 5, 5, 5, 5, 5, 6, 3, 3, 5, 4, 4, 6, 7, 4, 5, 6, 4, 5, 7, 3, 4, 4, 6, 4, 6, 5, 5, 8, 6, 5, 6, 4, 3, 4, 6, 4, 4, 4, 3, 4, 7, 5, 6, 4, 4, 7, 6, 4, 5, 4, 4, 4, 6, 5, 8, 4, 5, 4, 5, 3, 4, 5, 6, 5, 7, 6, 4, 6, 5, 4, 7, 6, 3, 4, 4, 8, 4, 6, 3, 7, 7, 5, 7, 7, 6, 6, 6, 7, 7, 4, 7, 6, 8, 5, 8, 6, 8, 6, 7, 6, 6, 7, 7, 6, 6, 6, 5, 8, 5, 7, 6, 6, 6, 7, 7, 6, 8, 4, 6, 6, 7, 4, 6, 7, 5, 4, 5, 6, 6, 3, 4, 7, 5, 5, 5, 3, 4, 4, 7, 3, 5, 5, 4, 6, 6, 4, 4, 8, 4, 4, 7, 3, 4, 3, 6, 4, 7, 4, 3, 7, 4, 6, 4, 4, 5, 5, 4, 3, 5, 5, 6, 4, 4, 4, 8, 6, 5, 5, 5, 5, 7, 4, 3, 4, 7, 5, 4, 6, 4, 5, 5, 7, 4, 3, 5, 6, 7, 5, 4, 6, 4, 7, 6, 6, 5, 4, 7, 7, 7,
|
||||||
|
4, 4, 5, 4, 4, 5, 4, 4, 6, 4, 6, 4,
|
||||||
|
6, 4, 4, 7, 5, 4, 5, 6, 4, 4, 7, 4, 6, 4, 5, 5, 7, 6, 5, 5, 6, 6, 7, 3, 5, 6, 4, 4, 4, 5, 4, 6, 3, 6, 7, 5, 7, 6, 5, 6, 5, 6, 6, 6, 8, 4, 4, 6, 5, 8, 4, 6, 6, 7, 4, 6, 4, 7, 4, 8, 5, 5, 6, 4, 6, 6, 7, 4, 5, 5, 5, 5, 4, 7, 5, 6, 6, 8, 4, 7, 5, 4, 7, 5, 6, 7, 6, 6, 4, 7, 3, 5, 7, 6, 5, 6, 3, 6, 7, 6, 7, 5, 4, 5, 4, 7, 8, 6, 6, 5, 8, 5, 4, 5, 4, 6, 4, 8, 6, 6, 8, 5, 4, 6, 6, 7, 4, 5, 4, 6, 6, 5, 6, 6, 4, 4, 4, 8, 7, 7, 6, 5, 4, 3, 7, 7, 5, 4, 4, 4, 5, 5, 5, 7, 6, 6, 5, 4, 7, 4, 7, 6, 5, 3, 7, 6, 5, 3, 3, 4, 6, 6, 7, 7, 6, 7, 5, 5, 7, 4, 3, 5, 6, 5, 3, 4, 3, 5, 7, 4, 4, 3, 5, 6, 4, 4, 5, 7, 6, 6, 6, 5, 7, 5, 8, 5, 6, 8, 6, 7, 5, 7, 5, 6, 7, 4, 4, 4, 3, 5, 6, 6, 5, 4, 6, 4, 4, 6, 4, 5, 5, 5, 7, 5, 6, 6, 4, 6, 5, 4, 5, 4, 7, 6, 7, 5, 4, 7, 5, 6, 4, 7, 7, 3, 7, 6, 6, 6, 7, 6, 6, 3, 5, 5, 6, 8, 5, 6, 7, 5, 3, 6, 4, 5, 4, 7, 4, 6, 5, 5, 5, 6, 7, 5, 4, 6, 6, 5, 4, 6, 4, 4, 5, 5, 4, 6, 4, 4, 4, 7, 7, 8, 8, 4, 6, 7, 7, 6, 5, 8, 6, 7, 6, 7, 7, 6, 7, 5, 5, 7, 5, 8, 6, 7, 5, 7, 7, 7, 6, 7, 7, 7, 5, 8, 7, 7, 5, 7, 6, 7, 4,
|
||||||
|
4, 5, 7, 5, 5, 5, 8, 6, 7, 5, 4, 3,
|
||||||
|
6, 7, 7, 7, 7, 8, 5, 4, 4, 5, 6, 7, 4, 4, 5, 5, 4, 4, 5, 5, 4, 5, 6, 5, 5, 4, 4, 6, 5, 3, 5, 5, 4, 6, 5, 7, 6, 7, 6, 6, 7, 6, 7, 6, 6, 6, 6, 7, 6, 5, 7, 6, 4, 6, 8, 6, 6, 6, 5, 4, 6, 6, 6, 7, 6, 7, 6, 8, 6, 8, 8, 6, 6, 7, 6, 7, 6, 6, 6, 6, 3, 6, 4, 4, 4, 5, 5, 5, 5, 4, 4, 6, 4, 6, 5, 5, 4, 5, 5, 6, 6, 7, 4, 6, 4, 4, 6, 5, 5, 5, 5, 6, 4, 3, 4, 3, 6, 5, 3, 6, 7, 4, 4, 5, 6, 5, 4, 6, 4, 6, 4, 7, 7, 5, 7, 4, 3, 5, 4, 5, 7, 5, 6, 6, 7, 8, 8, 5, 5, 6, 6, 5, 3, 6, 6, 4, 6, 6, 7, 8, 4, 4, 7, 6, 4, 7, 6, 5, 8, 6, 7, 7, 6, 5, 5, 6, 5, 7, 5, 4, 5, 7, 6, 5, 5, 4, 6, 5, 4, 5, 4, 5, 8, 5, 6, 5, 7, 3, 7, 4, 4, 5, 5, 4, 6, 4, 5, 6, 7, 6, 5, 4, 5, 6, 7, 3, 4, 5, 6, 3, 5, 4, 5, 5, 4, 4, 5, 7, 5, 5, 6, 4, 6, 4, 4, 5, 5, 5, 5, 5, 6, 5, 5, 4, 5, 4, 4, 6, 6, 4, 4, 4, 5, 7, 5, 8, 5, 7, 4, 4, 5, 4, 4, 5, 4, 6, 5, 5, 5, 7, 5, 5, 7, 5, 5, 5, 6, 5, 6, 5, 4, 6, 5, 5, 7, 5, 5, 4, 5, 6, 6, 3, 6, 7, 8, 6, 7, 5, 5, 6, 5, 5, 5, 5, 4, 5, 5, 4, 4, 6, 5, 5, 5, 5, 7, 5, 5, 5, 5, 8, 6, 6, 6, 8, 7, 5, 7, 5, 7, 6, 6, 7, 4, 6, 6, 5, 7, 4, 6, 3, 5,
|
||||||
|
6, 5, 6, 7, 4, 7, 5, 8, 8, 6, 7, 7,
|
||||||
|
7, 5, 4, 5, 5, 5, 5, 4, 5, 6, 5, 6, 7, 5, 6, 5, 6, 3, 4, 6, 4, 4, 4, 6, 4, 5, 6, 4, 5, 4, 4, 3, 6, 6, 4, 4, 4, 4, 5, 4, 5, 4, 6, 5, 4, 5, 4, 7, 5, 6, 5, 5, 7, 6, 4, 5, 4, 6, 4, 4, 3, 5, 6, 5, 5, 7, 5, 7, 3, 8, 6, 5, 6, 8, 4, 6, 7, 4, 5, 3, 5, 6, 5, 7, 8, 4, 5, 7, 6, 5, 4, 3, 5, 5, 7, 6, 5, 8, 4, 5, 6, 4, 5, 4, 5, 5, 5, 5, 7, 4, 4, 6, 7, 5, 4, 5, 7, 5, 5, 3, 4, 7, 6, 4, 6, 6, 4, 6, 6, 6, 5, 4, 5, 3, 4, 7, 4, 8, 6, 7, 5, 7, 5, 4, 6, 6, 7, 7, 6, 4, 8, 7, 6, 5, 7, 6, 6, 7, 6, 4, 5, 5, 5, 4, 5, 3, 4, 6, 7, 5, 7, 6, 6, 5, 5, 6, 5, 3, 6, 5, 7, 4, 5, 7, 6, 6, 7, 5, 4, 6, 7, 4, 6, 7, 6, 7, 7, 7, 5, 4, 7, 7, 6, 7, 5, 4, 5, 6, 5, 5, 5, 5, 4, 7, 6, 4, 6, 4, 5, 4, 4, 4, 6, 4, 7, 4, 7, 4, 4, 5, 5, 4, 3, 6, 6, 4, 6, 7, 3, 7, 7, 5, 7, 4, 3, 5, 4, 5, 5, 4, 5, 4, 7, 4, 5, 4, 4, 4, 3, 6, 4, 4, 4, 6, 6, 4, 6, 4, 4, 7, 4, 5, 6, 4, 4, 4, 4, 5, 5, 5, 4, 5, 7, 5, 5, 5, 4, 4, 6, 3, 5, 5, 5, 4, 4, 3
|
||||||
|
};
|
||||||
|
|
||||||
|
DECLSPEC msg_encoder_t encoder_init (PRIVATE_AS u32 * output)
|
||||||
|
{
|
||||||
|
msg_encoder_t encoder;
|
||||||
|
|
||||||
|
encoder.index = 0;
|
||||||
|
encoder.len = 0;
|
||||||
|
encoder.bitwise_offset = 32;
|
||||||
|
encoder.output = output;
|
||||||
|
return encoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encodes a char into the output
|
||||||
|
DECLSPEC void encode_char (PRIVATE_AS msg_encoder_t * encoder, PRIVATE_AS const u8 c)
|
||||||
|
{
|
||||||
|
if (encoder->bitwise_offset == 0)
|
||||||
|
{
|
||||||
|
encoder->bitwise_offset = 32;
|
||||||
|
encoder->index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder->bitwise_offset -= 8;
|
||||||
|
encoder->output[encoder->index] |= c << encoder->bitwise_offset;
|
||||||
|
encoder->len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encodes a u32 array into the output, big-endian (in order)
|
||||||
|
DECLSPEC void encode_array_be (PRIVATE_AS msg_encoder_t * encoder, PRIVATE_AS const u32 * array, PRIVATE_AS const u32 len, PRIVATE_AS const u32 start_index)
|
||||||
|
{
|
||||||
|
for (u32 i = start_index; i < len; i++)
|
||||||
|
{
|
||||||
|
u32 array_index = i / 4;
|
||||||
|
u32 array_offset = 24 - (i % 4) * 8;
|
||||||
|
|
||||||
|
encode_char (encoder, array[array_index] >> array_offset & 0xff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encodes a u32 array into the output, little-endian (reverse order)
|
||||||
|
DECLSPEC void encode_array_le (PRIVATE_AS msg_encoder_t * encoder, PRIVATE_AS const u32 * array, PRIVATE_AS const u32 len, PRIVATE_AS const u32 start_index)
|
||||||
|
{
|
||||||
|
for (u32 i = start_index; i < len; i++)
|
||||||
|
{
|
||||||
|
u32 array_index = i / 4;
|
||||||
|
u32 array_offset = (i % 4) * 8;
|
||||||
|
|
||||||
|
encode_char (encoder, array[array_index] >> array_offset & 0xff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encodes one of the BIP-39 seed words
|
||||||
|
DECLSPEC u32 encode_mnemonic_word (PRIVATE_AS msg_encoder_t * encoder, PRIVATE_AS const u32 word_index)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < BIP39_WORD_LENGTHS[word_index]; j++)
|
||||||
|
{
|
||||||
|
encode_char (encoder, BIP39_WORDS[word_index][j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DECLSPEC bool bip39_matches (PRIVATE_AS const char *word, PRIVATE_AS const u32 word_index)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < BIP39_WORD_LENGTHS[word_index] + 1; j++)
|
||||||
|
{
|
||||||
|
if (BIP39_WORDS[word_index][j] != word[j])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encodes the mnemonic_phrase as specified in BIP-39
|
||||||
|
DECLSPEC void encode_mnemonic_phrase (PRIVATE_AS msg_encoder_t * encoder, PRIVATE_AS const u32 * words)
|
||||||
|
{
|
||||||
|
for (int i = 0; words[i] != MNEMONIC_END; i++)
|
||||||
|
{
|
||||||
|
encode_mnemonic_word (encoder, words[i]);
|
||||||
|
|
||||||
|
if (words[i + 1] != MNEMONIC_END)
|
||||||
|
{
|
||||||
|
encode_char (encoder, ' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare all BIP39 words against the word to find a match, returning the index
|
||||||
|
DECLSPEC u32 bip39_from_word (PRIVATE_AS const char *word)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 2048; i++)
|
||||||
|
{
|
||||||
|
if (bip39_matches (word, i))
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return MNEMONIC_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
DECLSPEC u32 bip39_byte_from_password (PRIVATE_AS const u32 * password, PRIVATE_AS const u32 index, PRIVATE_AS const u32 bits)
|
||||||
|
{
|
||||||
|
u32 index32 = index / 4;
|
||||||
|
u32 offset32 = (index % 4) * 8;
|
||||||
|
u32 bits32 = (password[index32] >> offset32 & 0xff);
|
||||||
|
|
||||||
|
// 48 is the character before '1' which is where the bin charsets begin
|
||||||
|
u32 min_bits = BIP39_BYTE_OFFSET + bits;
|
||||||
|
u32 max_bits = 2;
|
||||||
|
|
||||||
|
for (int i = 1; i < bits; i++)
|
||||||
|
{
|
||||||
|
max_bits *= 2;
|
||||||
|
}
|
||||||
|
max_bits += min_bits;
|
||||||
|
|
||||||
|
// Check whether the password contains an invalid encoded byte
|
||||||
|
if (bits32 < min_bits || bits32 >= max_bits)
|
||||||
|
{
|
||||||
|
// Could be a good place to fail except it gets triggered by autotuning
|
||||||
|
// printf("\nError: password[%d] contains invalid char '%c' dec '%d'", index, bits32, bits32);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return bits32 - min_bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Computes the last checksum word with the last_entropy bits from the password
|
||||||
|
DECLSPEC u32 bip39_checksum_word (PRIVATE_AS const u32 * wordlist, PRIVATE_AS const u32 num_words, PRIVATE_AS const u32 * password, PRIVATE_AS const u32 password_index)
|
||||||
|
{
|
||||||
|
u32 entropy[16] = { 0 };
|
||||||
|
u32 total_bits = num_words * 11;
|
||||||
|
u32 total_entroy = total_bits - total_bits % 32;
|
||||||
|
u32 checksum_bits = total_bits - total_entroy;
|
||||||
|
u32 entropy_bits = 11 - checksum_bits;
|
||||||
|
u32 last_entropy = bip39_byte_from_password (password, password_index, entropy_bits);
|
||||||
|
|
||||||
|
// Encode the 11-bits words into entropy array
|
||||||
|
u32 index = 0;
|
||||||
|
int offset = 32;
|
||||||
|
|
||||||
|
for (int i = 0; i < num_words - 1; i++)
|
||||||
|
{
|
||||||
|
offset -= 11;
|
||||||
|
if (offset < 0)
|
||||||
|
{
|
||||||
|
entropy[index] |= (wordlist[i] >> -offset);
|
||||||
|
index++;
|
||||||
|
offset += 32;
|
||||||
|
}
|
||||||
|
entropy[index] |= (wordlist[i] << offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode the lasts_bits of entropy
|
||||||
|
offset -= entropy_bits;
|
||||||
|
if (offset < 0)
|
||||||
|
{
|
||||||
|
entropy[index] |= (last_entropy >> -offset);
|
||||||
|
index++;
|
||||||
|
offset += 32;
|
||||||
|
}
|
||||||
|
entropy[index] |= (last_entropy << offset);
|
||||||
|
|
||||||
|
sha256_ctx_t ctx;
|
||||||
|
|
||||||
|
sha256_init (&ctx);
|
||||||
|
sha256_update (&ctx, entropy, total_entroy / 8);
|
||||||
|
sha256_final (&ctx);
|
||||||
|
|
||||||
|
u32 checksum = ctx.h[0] >> (32 - checksum_bits);
|
||||||
|
|
||||||
|
return checksum | last_entropy << checksum_bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fills in BIP-39 words given a salt, pulling guesses from the password, generating the checksum
|
||||||
|
DECLSPEC u32 bip39_guess_words (PRIVATE_AS const u32 * password, PRIVATE_AS const u32 * salt, PRIVATE_AS u32 * wordlist)
|
||||||
|
{
|
||||||
|
u32 salt_index = 0;
|
||||||
|
|
||||||
|
while (salt[salt_index] != DERIVATION_END)
|
||||||
|
{
|
||||||
|
salt_index++;
|
||||||
|
}
|
||||||
|
salt_index++;
|
||||||
|
|
||||||
|
u32 password_index = 0;
|
||||||
|
|
||||||
|
for (int i = salt_index; salt[i - 1] != MNEMONIC_END; i++)
|
||||||
|
{
|
||||||
|
u32 word_index = i - salt_index;
|
||||||
|
u32 word = salt[i];
|
||||||
|
|
||||||
|
if (salt[i] == MNEMONIC_GUESS)
|
||||||
|
{
|
||||||
|
if (salt[i + 1] == MNEMONIC_END)
|
||||||
|
{
|
||||||
|
word = bip39_checksum_word (wordlist, word_index + 1, password, password_index);
|
||||||
|
password_index += 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
u32 bit5 = bip39_byte_from_password (password, password_index, 5);
|
||||||
|
u32 bit6 = bip39_byte_from_password (password, password_index + 1, 6);
|
||||||
|
u32 bit11 = (bit5 << 6) | bit6;
|
||||||
|
|
||||||
|
word = bit11;
|
||||||
|
password_index += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wordlist[word_index] = word;
|
||||||
|
}
|
||||||
|
|
||||||
|
return password_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* This section contains some unit tests
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
DECLSPEC bool bip39_byte_from_password_test ()
|
||||||
|
{
|
||||||
|
u32 password[2] = { 0x34333231, 0x433a3532 };
|
||||||
|
u32 max[4] = { 1, 3, 7, 15 };
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
if (bip39_byte_from_password (password, i, i + 1) != 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
if (bip39_byte_from_password (password, i + 4, i + 1) != max[i])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
DECLSPEC u32 bip39_checksum_word_test ()
|
||||||
|
{
|
||||||
|
u32 wordlist[11] = { 382, 566, 904, 858, 1836, 1147, 894, 1014, 1380, 1932, 744 };
|
||||||
|
u32 entropy[1] = { 0x0000005A };
|
||||||
|
entropy[0] += BIP39_BYTE_OFFSET + 7;
|
||||||
|
if (bip39_checksum_word (wordlist, 12, entropy, 0) != 1444)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
u32 wordlist2[23] = { 70, 1828, 769, 514, 1812, 937, 323, 1091, 1874, 1275, 363, 1482, 1136, 1131, 1941, 1888, 672, 1584, 1493, 1015, 1090, 960, 920 };
|
||||||
|
u32 entropy2[1] = { 0x00000006 };
|
||||||
|
entropy2[0] += BIP39_BYTE_OFFSET + 3;
|
||||||
|
if (bip39_checksum_word (wordlist2, 24, entropy2, 0) != 1590)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DECLSPEC bool bip39_guess_words_test ()
|
||||||
|
{
|
||||||
|
// Tests the min and max of bit-11 words (0 and 2047)
|
||||||
|
u32 salt[9] = { 0, DERIVATION_END, 1, 2, 3, MNEMONIC_GUESS, MNEMONIC_GUESS, 6, MNEMONIC_END };
|
||||||
|
u32 password[1] = { 0x75543635 };
|
||||||
|
u32 expected[7] = { 1, 2, 3, 0, 2047, 6, MNEMONIC_END };
|
||||||
|
u32 words[7] = { 0 };
|
||||||
|
bip39_guess_words (password, salt, words);
|
||||||
|
for (int i = 0; i < 7; i++)
|
||||||
|
{
|
||||||
|
if (expected[i] != words[i])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests checksum derivation
|
||||||
|
u32 salt2[14] = { DERIVATION_END, 881, 1096, 399, 1671, 966, 819, 1392, 1511, 1797, 231, 273, MNEMONIC_GUESS, MNEMONIC_END };
|
||||||
|
u32 password2[1] = { 0x00000016 };
|
||||||
|
password2[0] += BIP39_BYTE_OFFSET + 7;
|
||||||
|
u32 expected2[13] = { 881, 1096, 399, 1671, 966, 819, 1392, 1511, 1797, 231, 273, 355, MNEMONIC_END };
|
||||||
|
u32 words2[13] = { 0 };
|
||||||
|
bip39_guess_words (password2, salt2, words2);
|
||||||
|
for (int i = 0; i < 13; i++)
|
||||||
|
{
|
||||||
|
if (expected2[i] != words2[i])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
/**
|
||||||
|
* Author......: See docs/credits.txt
|
||||||
|
* License.....: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INC_BIP39_H
|
||||||
|
#define INC_BIP39_H
|
||||||
|
|
||||||
|
// Special salt codes
|
||||||
|
#define MNEMONIC_END (0x1FFFFFFF)
|
||||||
|
#define MNEMONIC_ERROR (0x2FFFFFFF)
|
||||||
|
#define MNEMONIC_GUESS (0x3FFFFFFF)
|
||||||
|
#define DERIVATION_END (0x4FFFFFFF)
|
||||||
|
#define DERIVATION_ERROR (0x5FFFFFFF)
|
||||||
|
#define DERIVATION_HARDENED (0x80000000)
|
||||||
|
|
||||||
|
// Start of BIP-39 xbit charsets
|
||||||
|
#define BIP39_BYTE_OFFSET (48)
|
||||||
|
|
||||||
|
// Address (digest) encoding types
|
||||||
|
#define XPUB_ADDRESS_ID (0)
|
||||||
|
#define P2PKH_ADDRESS_ID (1)
|
||||||
|
#define P2SHWPKH_ADDRESS_ID (2)
|
||||||
|
#define P2WPKH_ADDRESS_ID (3)
|
||||||
|
|
||||||
|
// BIP-39 variables that store the iterations of PBKDF2-SHA512
|
||||||
|
typedef struct bip39_tmp
|
||||||
|
{
|
||||||
|
u64 ipad[8];
|
||||||
|
u64 opad[8];
|
||||||
|
|
||||||
|
u64 dgst[16];
|
||||||
|
u64 out[16];
|
||||||
|
|
||||||
|
u32 salt_index;
|
||||||
|
} bip39_tmp_t;
|
||||||
|
|
||||||
|
// Represents the current state of encoding a message
|
||||||
|
typedef struct msg_encoder
|
||||||
|
{
|
||||||
|
u32 bitwise_offset;
|
||||||
|
u32 index;
|
||||||
|
u32 *output;
|
||||||
|
u32 len;
|
||||||
|
} msg_encoder_t;
|
||||||
|
|
||||||
|
DECLSPEC msg_encoder_t encoder_init (PRIVATE_AS u32 * output);
|
||||||
|
DECLSPEC void encode_char (PRIVATE_AS msg_encoder_t * encoder, PRIVATE_AS const u8 c);
|
||||||
|
DECLSPEC void encode_array_be (PRIVATE_AS msg_encoder_t * encoder, PRIVATE_AS const u32 * array, PRIVATE_AS const u32 len, PRIVATE_AS const u32 start_index);
|
||||||
|
DECLSPEC void encode_array_le (PRIVATE_AS msg_encoder_t * encoder, PRIVATE_AS const u32 * array, PRIVATE_AS const u32 len, PRIVATE_AS const u32 start_index);
|
||||||
|
DECLSPEC u32 encode_mnemonic_word (PRIVATE_AS msg_encoder_t * encoder, PRIVATE_AS const u32 word_index);
|
||||||
|
DECLSPEC void encode_mnemonic_phrase (PRIVATE_AS msg_encoder_t * encoder, PRIVATE_AS const u32 * words);
|
||||||
|
DECLSPEC u32 bip39_guess_words (PRIVATE_AS const u32 * password, PRIVATE_AS const u32 * salt, PRIVATE_AS u32 * wordlist);
|
||||||
|
DECLSPEC u32 bip39_from_word (PRIVATE_AS const char *word);
|
||||||
|
|
||||||
|
#endif // INC_BIP39_H
|
@ -0,0 +1,634 @@
|
|||||||
|
/**
|
||||||
|
* Author......: See docs/credits.txt
|
||||||
|
* License.....: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SECP256K1_TMPS_TYPE PRIVATE_AS
|
||||||
|
|
||||||
|
#ifdef KERNEL_STATIC
|
||||||
|
#include M2S(INCLUDE_PATH/inc_vendor.h)
|
||||||
|
#include M2S(INCLUDE_PATH/inc_types.h)
|
||||||
|
#include M2S(INCLUDE_PATH/inc_platform.cl)
|
||||||
|
#include M2S(INCLUDE_PATH/inc_common.cl)
|
||||||
|
#include M2S(INCLUDE_PATH/inc_rp.h)
|
||||||
|
#include M2S(INCLUDE_PATH/inc_rp.cl)
|
||||||
|
#include M2S(INCLUDE_PATH/inc_scalar.cl)
|
||||||
|
#include M2S(INCLUDE_PATH/inc_simd.cl)
|
||||||
|
#include M2S(INCLUDE_PATH/inc_hash_base58.cl)
|
||||||
|
#include M2S(INCLUDE_PATH/inc_hash_sha256.cl)
|
||||||
|
#include M2S(INCLUDE_PATH/inc_hash_ripemd160.cl)
|
||||||
|
#include M2S(INCLUDE_PATH/inc_ecc_secp256k1.cl)
|
||||||
|
#include M2S(INCLUDE_PATH/inc_hash_sha512.cl)
|
||||||
|
#include M2S(INCLUDE_PATH/inc_bip39.cl)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define COMPARE_S M2S(INCLUDE_PATH/inc_comp_single.cl)
|
||||||
|
#define COMPARE_M M2S(INCLUDE_PATH/inc_comp_multi.cl)
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* This section is adapted from the optimized scalar_8x32 operations from
|
||||||
|
* https://github.com/bitcoin-core/secp256k1/, MIT license
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
// Represents the extended private key and chain code (each 256-bits)
|
||||||
|
typedef struct extended_key
|
||||||
|
{
|
||||||
|
// private_key is stored in reverse order for secp256k1 algorithms
|
||||||
|
u32 private_key[8];
|
||||||
|
u32 chain_code[8];
|
||||||
|
} extended_key_t;
|
||||||
|
|
||||||
|
#define SECP256K1_N_C_0 (~SECP256K1_N0 + 1)
|
||||||
|
#define SECP256K1_N_C_1 (~SECP256K1_N1)
|
||||||
|
#define SECP256K1_N_C_2 (~SECP256K1_N2)
|
||||||
|
#define SECP256K1_N_C_3 (~SECP256K1_N3)
|
||||||
|
#define SECP256K1_N_C_4 (1)
|
||||||
|
|
||||||
|
DECLSPEC int secp256k1_scalar_check_overflow (const u32 * a)
|
||||||
|
{
|
||||||
|
int yes = 0;
|
||||||
|
int no = 0;
|
||||||
|
|
||||||
|
no |= (a[7] < SECP256K1_N7); /* No need for a > check. */
|
||||||
|
no |= (a[6] < SECP256K1_N6); /* No need for a > check. */
|
||||||
|
no |= (a[5] < SECP256K1_N5); /* No need for a > check. */
|
||||||
|
no |= (a[4] < SECP256K1_N4);
|
||||||
|
yes |= (a[4] > SECP256K1_N4) & ~no;
|
||||||
|
no |= (a[3] < SECP256K1_N3) & ~yes;
|
||||||
|
yes |= (a[3] > SECP256K1_N3) & ~no;
|
||||||
|
no |= (a[2] < SECP256K1_N2) & ~yes;
|
||||||
|
yes |= (a[2] > SECP256K1_N2) & ~no;
|
||||||
|
no |= (a[1] < SECP256K1_N1) & ~yes;
|
||||||
|
yes |= (a[1] > SECP256K1_N1) & ~no;
|
||||||
|
yes |= (a[0] >= SECP256K1_N0) & ~no;
|
||||||
|
return yes;
|
||||||
|
}
|
||||||
|
|
||||||
|
DECLSPEC void secp256k1_scalar_reduce (u32 * r, u32 overflow)
|
||||||
|
{
|
||||||
|
u64 t;
|
||||||
|
|
||||||
|
t = (u64) r[0] + overflow * SECP256K1_N_C_0;
|
||||||
|
r[0] = t & 0xFFFFFFFFUL;
|
||||||
|
t >>= 32;
|
||||||
|
t += (u64) r[1] + overflow * SECP256K1_N_C_1;
|
||||||
|
r[1] = t & 0xFFFFFFFFUL;
|
||||||
|
t >>= 32;
|
||||||
|
t += (u64) r[2] + overflow * SECP256K1_N_C_2;
|
||||||
|
r[2] = t & 0xFFFFFFFFUL;
|
||||||
|
t >>= 32;
|
||||||
|
t += (u64) r[3] + overflow * SECP256K1_N_C_3;
|
||||||
|
r[3] = t & 0xFFFFFFFFUL;
|
||||||
|
t >>= 32;
|
||||||
|
t += (u64) r[4] + overflow * SECP256K1_N_C_4;
|
||||||
|
r[4] = t & 0xFFFFFFFFUL;
|
||||||
|
t >>= 32;
|
||||||
|
t += (u64) r[5];
|
||||||
|
r[5] = t & 0xFFFFFFFFUL;
|
||||||
|
t >>= 32;
|
||||||
|
t += (u64) r[6];
|
||||||
|
r[6] = t & 0xFFFFFFFFUL;
|
||||||
|
t >>= 32;
|
||||||
|
t += (u64) r[7];
|
||||||
|
r[7] = t & 0xFFFFFFFFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
DECLSPEC void secp256k1_scalar_add (u32 * r, const u32 * a, const u32 * b)
|
||||||
|
{
|
||||||
|
int overflow;
|
||||||
|
u64 t = (u64) a[0] + b[0];
|
||||||
|
|
||||||
|
r[0] = t & 0xFFFFFFFFUL;
|
||||||
|
t >>= 32;
|
||||||
|
t += (u64) a[1] + b[1];
|
||||||
|
r[1] = t & 0xFFFFFFFFUL;
|
||||||
|
t >>= 32;
|
||||||
|
t += (u64) a[2] + b[2];
|
||||||
|
r[2] = t & 0xFFFFFFFFUL;
|
||||||
|
t >>= 32;
|
||||||
|
t += (u64) a[3] + b[3];
|
||||||
|
r[3] = t & 0xFFFFFFFFUL;
|
||||||
|
t >>= 32;
|
||||||
|
t += (u64) a[4] + b[4];
|
||||||
|
r[4] = t & 0xFFFFFFFFUL;
|
||||||
|
t >>= 32;
|
||||||
|
t += (u64) a[5] + b[5];
|
||||||
|
r[5] = t & 0xFFFFFFFFUL;
|
||||||
|
t >>= 32;
|
||||||
|
t += (u64) a[6] + b[6];
|
||||||
|
r[6] = t & 0xFFFFFFFFUL;
|
||||||
|
t >>= 32;
|
||||||
|
t += (u64) a[7] + b[7];
|
||||||
|
r[7] = t & 0xFFFFFFFFUL;
|
||||||
|
t >>= 32;
|
||||||
|
overflow = t + secp256k1_scalar_check_overflow (r);
|
||||||
|
secp256k1_scalar_reduce (r, overflow);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* This section includes functions for encoding messages into u32 output buffers
|
||||||
|
* necessary for generating various hashes.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
// Encodes the passphrase as specified in BIP-39
|
||||||
|
DECLSPEC void encode_passphrase (PRIVATE_AS msg_encoder_t * encoder, PRIVATE_AS const u32 * password, PRIVATE_AS const u32 password_len, PRIVATE_AS const u32 start_index)
|
||||||
|
{
|
||||||
|
const char salt[] = "mnemonic";
|
||||||
|
|
||||||
|
for (u32 i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
encode_char (encoder, salt[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
encode_array_le (encoder, password, password_len, start_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encodes the derived 33 byte compressed public key for a given private_key
|
||||||
|
DECLSPEC void encode_compressed_public_key (PRIVATE_AS msg_encoder_t * encoder, PRIVATE_AS const extended_key_t * key)
|
||||||
|
{
|
||||||
|
secp256k1_t preG;
|
||||||
|
|
||||||
|
set_precomputed_basepoint_g (&preG);
|
||||||
|
|
||||||
|
u32 x[8];
|
||||||
|
u32 y[8];
|
||||||
|
|
||||||
|
// This next line reduces performance by ~40% compared to the pure 2048 round PBKDF2-HMAC-SHA512 derivation
|
||||||
|
// Possibly could be eliminated through precalculation as in https://github.com/XopMC/CudaBrainSecp
|
||||||
|
point_mul_xy (x, y, key->private_key, &preG);
|
||||||
|
|
||||||
|
encode_char (encoder, 0x02 | (y[0] & 1));
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
encode_array_be (encoder, &x[7 - i], 4, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* This section runs contains some common cryptographic helper functions.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
// Run another iteration of PBKDF2-HMAC-SHA512, optimized for loops
|
||||||
|
DECLSPEC void run_sha512_hmac_iter (PRIVATE_AS u32x * w0, PRIVATE_AS u32x * w1, PRIVATE_AS u32x * w2, PRIVATE_AS u32x * w3, PRIVATE_AS u32x * w4, PRIVATE_AS u32x * w5, PRIVATE_AS u32x * w6, PRIVATE_AS u32x * w7, PRIVATE_AS u64x * ipad, PRIVATE_AS u64x * opad, PRIVATE_AS u64x * digest)
|
||||||
|
{
|
||||||
|
digest[0] = ipad[0];
|
||||||
|
digest[1] = ipad[1];
|
||||||
|
digest[2] = ipad[2];
|
||||||
|
digest[3] = ipad[3];
|
||||||
|
digest[4] = ipad[4];
|
||||||
|
digest[5] = ipad[5];
|
||||||
|
digest[6] = ipad[6];
|
||||||
|
digest[7] = ipad[7];
|
||||||
|
|
||||||
|
sha512_transform_vector (w0, w1, w2, w3, w4, w5, w6, w7, digest);
|
||||||
|
|
||||||
|
w0[0] = h32_from_64 (digest[0]);
|
||||||
|
w0[1] = l32_from_64 (digest[0]);
|
||||||
|
w0[2] = h32_from_64 (digest[1]);
|
||||||
|
w0[3] = l32_from_64 (digest[1]);
|
||||||
|
w1[0] = h32_from_64 (digest[2]);
|
||||||
|
w1[1] = l32_from_64 (digest[2]);
|
||||||
|
w1[2] = h32_from_64 (digest[3]);
|
||||||
|
w1[3] = l32_from_64 (digest[3]);
|
||||||
|
w2[0] = h32_from_64 (digest[4]);
|
||||||
|
w2[1] = l32_from_64 (digest[4]);
|
||||||
|
w2[2] = h32_from_64 (digest[5]);
|
||||||
|
w2[3] = l32_from_64 (digest[5]);
|
||||||
|
w3[0] = h32_from_64 (digest[6]);
|
||||||
|
w3[1] = l32_from_64 (digest[6]);
|
||||||
|
w3[2] = h32_from_64 (digest[7]);
|
||||||
|
w3[3] = l32_from_64 (digest[7]);
|
||||||
|
w4[0] = 0x80000000;
|
||||||
|
w4[1] = 0;
|
||||||
|
w4[2] = 0;
|
||||||
|
w4[3] = 0;
|
||||||
|
w5[0] = 0;
|
||||||
|
w5[1] = 0;
|
||||||
|
w5[2] = 0;
|
||||||
|
w5[3] = 0;
|
||||||
|
w6[0] = 0;
|
||||||
|
w6[1] = 0;
|
||||||
|
w6[2] = 0;
|
||||||
|
w6[3] = 0;
|
||||||
|
w7[0] = 0;
|
||||||
|
w7[1] = 0;
|
||||||
|
w7[2] = 0;
|
||||||
|
w7[3] = (128 + 64) * 8;
|
||||||
|
|
||||||
|
digest[0] = opad[0];
|
||||||
|
digest[1] = opad[1];
|
||||||
|
digest[2] = opad[2];
|
||||||
|
digest[3] = opad[3];
|
||||||
|
digest[4] = opad[4];
|
||||||
|
digest[5] = opad[5];
|
||||||
|
digest[6] = opad[6];
|
||||||
|
digest[7] = opad[7];
|
||||||
|
|
||||||
|
sha512_transform_vector (w0, w1, w2, w3, w4, w5, w6, w7, digest);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Runs a single iteration of SHA512-HMAC to create an extended key
|
||||||
|
DECLSPEC extended_key_t run_sha512_hmac (PRIVATE_AS const u32 * key, PRIVATE_AS u32 key_bytes, PRIVATE_AS u32 * msg, PRIVATE_AS u32 msg_bytes)
|
||||||
|
{
|
||||||
|
// SHA512-HMAC requires length 32 arrays initialized to 0
|
||||||
|
u32 key_buf[32] = { 0 };
|
||||||
|
u32 msg_buf[32] = { 0 };
|
||||||
|
|
||||||
|
for (u32 i = 0; i * 4 < key_bytes; i++)
|
||||||
|
{
|
||||||
|
key_buf[i] = key[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u32 i = 0; i * 4 < msg_bytes; i++)
|
||||||
|
{
|
||||||
|
msg_buf[i] = msg[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run SHA512-HMAC algorithm on key and message
|
||||||
|
sha512_hmac_ctx_t sha512_hmac_ctx;
|
||||||
|
|
||||||
|
sha512_hmac_init (&sha512_hmac_ctx, key_buf, key_bytes);
|
||||||
|
sha512_hmac_update (&sha512_hmac_ctx, msg_buf, msg_bytes);
|
||||||
|
sha512_hmac_final (&sha512_hmac_ctx);
|
||||||
|
|
||||||
|
// Split the 512-bit result into 256-bit private_key (reversed) and 256-bit chain_code
|
||||||
|
extended_key_t extended;
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
int j = i * 2;
|
||||||
|
|
||||||
|
extended.private_key[7 - j] = h32_from_64_S (sha512_hmac_ctx.opad.h[i]);
|
||||||
|
extended.private_key[6 - j] = l32_from_64_S (sha512_hmac_ctx.opad.h[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 4; i < 8; i++)
|
||||||
|
{
|
||||||
|
int j = (i - 4) * 2;
|
||||||
|
|
||||||
|
extended.chain_code[j] = h32_from_64_S (sha512_hmac_ctx.opad.h[i]);
|
||||||
|
extended.chain_code[j + 1] = l32_from_64_S (sha512_hmac_ctx.opad.h[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return extended;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculates HASH160 given a message, defined as RIPE160(SHA256(msg))
|
||||||
|
DECLSPEC ripemd160_ctx_t run_hash160 (PRIVATE_AS const u32 * msg, PRIVATE_AS const u32 msg_bytes)
|
||||||
|
{
|
||||||
|
// SHA256 requires length 16 arrays initialized to 0
|
||||||
|
u32 msg_buf[32] = { 0 };
|
||||||
|
for (u32 i = 0; i * 4 < msg_bytes; i++)
|
||||||
|
{
|
||||||
|
msg_buf[i] = msg[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
sha256_ctx_t ctx;
|
||||||
|
|
||||||
|
sha256_init (&ctx);
|
||||||
|
sha256_update (&ctx, msg_buf, msg_bytes);
|
||||||
|
sha256_final (&ctx);
|
||||||
|
|
||||||
|
for (u32 i = 8; i < 16; i++)
|
||||||
|
ctx.h[i] = 0;
|
||||||
|
|
||||||
|
ripemd160_ctx_t rctx;
|
||||||
|
|
||||||
|
ripemd160_init (&rctx);
|
||||||
|
ripemd160_update_swap (&rctx, ctx.h, 32);
|
||||||
|
ripemd160_final (&rctx);
|
||||||
|
return rctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* This section specifies how to derive extended private keys from secrets
|
||||||
|
* according to the BIP-32 specification.
|
||||||
|
* https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
// Derives the BIP32 master extended key from a 512-bit seed
|
||||||
|
DECLSPEC extended_key_t extended_key_master (PRIVATE_AS const u64 * seed)
|
||||||
|
{
|
||||||
|
u32 master_seed[16] = { 0 };
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
int j = i * 2;
|
||||||
|
|
||||||
|
master_seed[j + 1] = l32_from_64_S (seed[i]);
|
||||||
|
master_seed[j] = h32_from_64_S (seed[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encoding of "Bitcoin seed" from BIP32
|
||||||
|
u32 bitcoin_seed[3] = { 0x42697463, 0x6f696e20, 0x73656564 };
|
||||||
|
|
||||||
|
return run_sha512_hmac (bitcoin_seed, 12, master_seed, 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper for tweaking the child key with the parent key
|
||||||
|
DECLSPEC void extended_key_tweak (extended_key_t * key, const extended_key_t * tweak)
|
||||||
|
{
|
||||||
|
secp256k1_scalar_add (key->private_key, key->private_key, tweak->private_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Derives the BIP32 hardened child key
|
||||||
|
DECLSPEC extended_key_t extended_key_hardened (PRIVATE_AS const extended_key_t * parent_key, PRIVATE_AS const u32 i)
|
||||||
|
{
|
||||||
|
u32 output[32] = { 0 };
|
||||||
|
msg_encoder_t encoder = encoder_init (output);
|
||||||
|
|
||||||
|
encode_char (&encoder, 0);
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
encode_array_be (&encoder, &parent_key->private_key[7 - i], 4, 0);
|
||||||
|
}
|
||||||
|
encode_array_be (&encoder, &i, 4, 0);
|
||||||
|
|
||||||
|
extended_key_t child_key = run_sha512_hmac (parent_key->chain_code, 32, output, encoder.len);
|
||||||
|
|
||||||
|
extended_key_tweak (&child_key, parent_key);
|
||||||
|
|
||||||
|
return child_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Derives the BIP32 normal child key
|
||||||
|
DECLSPEC extended_key_t extended_key_normal (PRIVATE_AS const extended_key_t * parent_key, PRIVATE_AS const u32 i)
|
||||||
|
{
|
||||||
|
u32 output[32] = { 0 };
|
||||||
|
msg_encoder_t encoder = encoder_init (output);
|
||||||
|
|
||||||
|
encode_compressed_public_key (&encoder, parent_key);
|
||||||
|
encode_array_be (&encoder, &i, 4, 0);
|
||||||
|
|
||||||
|
extended_key_t child_key = run_sha512_hmac (parent_key->chain_code, 32, output, encoder.len);
|
||||||
|
|
||||||
|
extended_key_tweak (&child_key, parent_key);
|
||||||
|
|
||||||
|
return child_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Derives the BIP32 key using the derivation path
|
||||||
|
DECLSPEC extended_key_t extended_key_derivation (PRIVATE_AS u64 * seed, PRIVATE_AS const u32 * derivation)
|
||||||
|
{
|
||||||
|
extended_key_t key = extended_key_master (seed);
|
||||||
|
|
||||||
|
for (int i = 0; derivation[i] != DERIVATION_END; i++)
|
||||||
|
{
|
||||||
|
if (derivation[i] >= DERIVATION_HARDENED)
|
||||||
|
{
|
||||||
|
key = extended_key_hardened (&key, derivation[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
key = extended_key_normal (&key, derivation[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
DECLSPEC void printf_array (const u32 * bytes, const u32 len)
|
||||||
|
{
|
||||||
|
printf ("\n'");
|
||||||
|
for (int i = 0; i <= len / 4; i++)
|
||||||
|
{
|
||||||
|
printf ("%c", bytes[i] >> 24 & 0xff);
|
||||||
|
printf ("%c", bytes[i] >> 16 & 0xff);
|
||||||
|
printf ("%c", bytes[i] >> 8 & 0xff);
|
||||||
|
printf ("%c", bytes[i] >> 0 & 0xff);
|
||||||
|
}
|
||||||
|
printf ("'");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debugging for printing out the private key followed by a ' ' then the chain code
|
||||||
|
DECLSPEC void extended_key_printf (extended_key_t * key)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
printf ("%08x", key->private_key[7 - i]);
|
||||||
|
}
|
||||||
|
printf (" ");
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
printf ("%08x", key->chain_code[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* This section contains the init, loop, and comp functions required by the pure
|
||||||
|
* kernel modules.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
// Initialize the PBKDF2-SHA512 with the mnemonic and passphrase as described in BIP-32
|
||||||
|
KERNEL_FQ void m28510_init (KERN_ATTR_TMPS (bip39_tmp_t))
|
||||||
|
{
|
||||||
|
const u64 gid = get_global_id (0);
|
||||||
|
|
||||||
|
if (gid >= GID_CNT)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Get the BIP39 word list
|
||||||
|
u32 pw_index = 0;
|
||||||
|
u32 words[25] = { MNEMONIC_END };
|
||||||
|
pw_index = bip39_guess_words (pws[gid].i, salt_bufs[SALT_POS_HOST].salt_buf, words);
|
||||||
|
tmps[gid].salt_index = SALT_POS_HOST;
|
||||||
|
|
||||||
|
u32 mnemonic[64] = { 0 };
|
||||||
|
msg_encoder_t mnemonic_encoder = encoder_init (mnemonic);
|
||||||
|
|
||||||
|
encode_mnemonic_phrase (&mnemonic_encoder, words);
|
||||||
|
|
||||||
|
u32 passphrase[64] = { 0 };
|
||||||
|
msg_encoder_t passphrase_encoder = encoder_init (passphrase);
|
||||||
|
|
||||||
|
encode_passphrase (&passphrase_encoder, pws[gid].i, pws[gid].pw_len, pw_index);
|
||||||
|
|
||||||
|
sha512_hmac_ctx_t sha512_hmac_ctx;
|
||||||
|
|
||||||
|
sha512_hmac_init (&sha512_hmac_ctx, mnemonic, mnemonic_encoder.len);
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
tmps[gid].ipad[i] = sha512_hmac_ctx.ipad.h[i];
|
||||||
|
tmps[gid].opad[i] = sha512_hmac_ctx.opad.h[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
sha512_hmac_update (&sha512_hmac_ctx, passphrase, passphrase_encoder.len);
|
||||||
|
|
||||||
|
u32 w0[4] = { 1, 0, 0, 0 };
|
||||||
|
u32 w1[4] = { 0 };
|
||||||
|
u32 w2[4] = { 0 };
|
||||||
|
u32 w3[4] = { 0 };
|
||||||
|
u32 w4[4] = { 0 };
|
||||||
|
u32 w5[4] = { 0 };
|
||||||
|
u32 w6[4] = { 0 };
|
||||||
|
u32 w7[4] = { 0 };
|
||||||
|
|
||||||
|
sha512_hmac_update_128 (&sha512_hmac_ctx, w0, w1, w2, w3, w4, w5, w6, w7, 4);
|
||||||
|
|
||||||
|
sha512_hmac_final (&sha512_hmac_ctx);
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
tmps[gid].dgst[i] = sha512_hmac_ctx.opad.h[i];
|
||||||
|
tmps[gid].out[i] = sha512_hmac_ctx.opad.h[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Identical to most modules that run PBKDF2-HMAC-SHA512 iterations
|
||||||
|
KERNEL_FQ void m28510_loop (KERN_ATTR_TMPS (bip39_tmp_t))
|
||||||
|
{
|
||||||
|
const u64 gid = get_global_id (0);
|
||||||
|
|
||||||
|
if ((gid * VECT_SIZE) >= GID_CNT)
|
||||||
|
return;
|
||||||
|
|
||||||
|
u64x ipad[8];
|
||||||
|
u64x opad[8];
|
||||||
|
|
||||||
|
for (u32 i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
ipad[i] = pack64v (tmps, ipad, gid, i);
|
||||||
|
opad[i] = pack64v (tmps, opad, gid, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
u64x dgst[8];
|
||||||
|
u64x out[8];
|
||||||
|
|
||||||
|
for (u32 i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
dgst[i] = pack64v (tmps, dgst, gid, i);
|
||||||
|
out[i] = pack64v (tmps, out, gid, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u32 j = 0; j < LOOP_CNT; j++)
|
||||||
|
{
|
||||||
|
u32x w0[4];
|
||||||
|
u32x w1[4];
|
||||||
|
u32x w2[4];
|
||||||
|
u32x w3[4];
|
||||||
|
u32x w4[4];
|
||||||
|
u32x w5[4];
|
||||||
|
u32x w6[4];
|
||||||
|
u32x w7[4];
|
||||||
|
|
||||||
|
w0[0] = h32_from_64 (dgst[0]);
|
||||||
|
w0[1] = l32_from_64 (dgst[0]);
|
||||||
|
w0[2] = h32_from_64 (dgst[1]);
|
||||||
|
w0[3] = l32_from_64 (dgst[1]);
|
||||||
|
w1[0] = h32_from_64 (dgst[2]);
|
||||||
|
w1[1] = l32_from_64 (dgst[2]);
|
||||||
|
w1[2] = h32_from_64 (dgst[3]);
|
||||||
|
w1[3] = l32_from_64 (dgst[3]);
|
||||||
|
w2[0] = h32_from_64 (dgst[4]);
|
||||||
|
w2[1] = l32_from_64 (dgst[4]);
|
||||||
|
w2[2] = h32_from_64 (dgst[5]);
|
||||||
|
w2[3] = l32_from_64 (dgst[5]);
|
||||||
|
w3[0] = h32_from_64 (dgst[6]);
|
||||||
|
w3[1] = l32_from_64 (dgst[6]);
|
||||||
|
w3[2] = h32_from_64 (dgst[7]);
|
||||||
|
w3[3] = l32_from_64 (dgst[7]);
|
||||||
|
w4[0] = 0x80000000;
|
||||||
|
w4[1] = 0;
|
||||||
|
w4[2] = 0;
|
||||||
|
w4[3] = 0;
|
||||||
|
w5[0] = 0;
|
||||||
|
w5[1] = 0;
|
||||||
|
w5[2] = 0;
|
||||||
|
w5[3] = 0;
|
||||||
|
w6[0] = 0;
|
||||||
|
w6[1] = 0;
|
||||||
|
w6[2] = 0;
|
||||||
|
w6[3] = 0;
|
||||||
|
w7[0] = 0;
|
||||||
|
w7[1] = 0;
|
||||||
|
w7[2] = 0;
|
||||||
|
w7[3] = (128 + 64) * 8;
|
||||||
|
|
||||||
|
run_sha512_hmac_iter (w0, w1, w2, w3, w4, w5, w6, w7, ipad, opad, dgst);
|
||||||
|
|
||||||
|
for (u32 i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
out[i] ^= dgst[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u32 i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
unpack64v (tmps, dgst, gid, i, dgst[i]);
|
||||||
|
unpack64v (tmps, out, gid, i, out[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final digest comparison depends on the address type
|
||||||
|
KERNEL_FQ void m28510_comp (KERN_ATTR_TMPS (bip39_tmp_t))
|
||||||
|
{
|
||||||
|
const u64 gid = get_global_id (0);
|
||||||
|
|
||||||
|
if (gid >= GID_CNT)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Get hardened 512-bit seed and useful salt values
|
||||||
|
u64 *seed = tmps[gid].out;
|
||||||
|
const u32 address_id = salt_bufs[SALT_POS_HOST].salt_buf[0];
|
||||||
|
const u32 *derivation_path = &salt_bufs[SALT_POS_HOST].salt_buf[1];
|
||||||
|
|
||||||
|
// 128-bits that get compared with the digest bits
|
||||||
|
u32 r0;
|
||||||
|
u32 r1;
|
||||||
|
u32 r2;
|
||||||
|
u32 r3;
|
||||||
|
|
||||||
|
if (address_id == XPUB_ADDRESS_ID)
|
||||||
|
{
|
||||||
|
extended_key_t master_key = extended_key_master (seed);
|
||||||
|
|
||||||
|
r0 = hc_swap32_S (master_key.chain_code[0]);
|
||||||
|
r1 = hc_swap32_S (master_key.chain_code[1]);
|
||||||
|
r2 = hc_swap32_S (master_key.chain_code[2]);
|
||||||
|
r3 = hc_swap32_S (master_key.chain_code[3]);
|
||||||
|
}
|
||||||
|
else if (address_id == P2PKH_ADDRESS_ID || address_id == P2WPKH_ADDRESS_ID)
|
||||||
|
{
|
||||||
|
const extended_key_t key = extended_key_derivation (seed, derivation_path);
|
||||||
|
|
||||||
|
u32 pubkey[9] = { 0 };
|
||||||
|
msg_encoder_t pubkey_encoder = encoder_init (pubkey);
|
||||||
|
|
||||||
|
encode_compressed_public_key (&pubkey_encoder, &key);
|
||||||
|
ripemd160_ctx_t hash160 = run_hash160 (pubkey, pubkey_encoder.len);
|
||||||
|
|
||||||
|
r0 = hash160.h[0];
|
||||||
|
r1 = hash160.h[1];
|
||||||
|
r2 = hash160.h[2];
|
||||||
|
r3 = hash160.h[3];
|
||||||
|
}
|
||||||
|
else if (address_id == P2SHWPKH_ADDRESS_ID)
|
||||||
|
{
|
||||||
|
const extended_key_t key = extended_key_derivation (seed, derivation_path);
|
||||||
|
|
||||||
|
u32 pubkey[9] = { 0 };
|
||||||
|
msg_encoder_t pubkey_encoder = encoder_init (pubkey);
|
||||||
|
|
||||||
|
encode_compressed_public_key (&pubkey_encoder, &key);
|
||||||
|
ripemd160_ctx_t hash160 = run_hash160 (pubkey, pubkey_encoder.len);
|
||||||
|
|
||||||
|
u32 script[9] = { 0 };
|
||||||
|
msg_encoder_t script_encoder = encoder_init (script);
|
||||||
|
|
||||||
|
encode_char (&script_encoder, 0x0);
|
||||||
|
encode_char (&script_encoder, 0x14);
|
||||||
|
encode_array_le (&script_encoder, hash160.h, 20, 0);
|
||||||
|
ripemd160_ctx_t script_hash160 = run_hash160 (script, script_encoder.len);
|
||||||
|
|
||||||
|
r0 = script_hash160.h[0];
|
||||||
|
r1 = script_hash160.h[1];
|
||||||
|
r2 = script_hash160.h[2];
|
||||||
|
r3 = script_hash160.h[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
#define il_pos 0
|
||||||
|
|
||||||
|
#ifdef KERNEL_STATIC
|
||||||
|
#include COMPARE_M
|
||||||
|
#endif
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
12
|
@ -0,0 +1 @@
|
|||||||
|
2345
|
@ -0,0 +1 @@
|
|||||||
|
3456789:
|
@ -0,0 +1 @@
|
|||||||
|
456789:;<=>?@ABC
|
@ -0,0 +1 @@
|
|||||||
|
56789:;<=>?@ABCDEFGHIJKLMNOPQRST
|
@ -0,0 +1 @@
|
|||||||
|
6789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstu
|
@ -0,0 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* Author......: See docs/credits.txt
|
||||||
|
* License.....: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HC_EMU_INC_BIP39_H
|
||||||
|
#define HC_EMU_INC_BIP39_H
|
||||||
|
|
||||||
|
#include "emu_general.h"
|
||||||
|
|
||||||
|
#include "inc_vendor.h"
|
||||||
|
#include "inc_bip39.h"
|
||||||
|
|
||||||
|
#endif // HC_EMU_INC_BIP39_H
|
@ -0,0 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* Author......: See docs/credits.txt
|
||||||
|
* License.....: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "emu_general.h"
|
||||||
|
|
||||||
|
#include "inc_bip39.cl"
|
||||||
|
|
@ -0,0 +1,747 @@
|
|||||||
|
/**
|
||||||
|
* Author......: See docs/credits.txt
|
||||||
|
* License.....: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "modules.h"
|
||||||
|
#include "bitops.h"
|
||||||
|
#include "convert.h"
|
||||||
|
#include "shared.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "bitops.h"
|
||||||
|
|
||||||
|
#include "emu_inc_hash_base58.h"
|
||||||
|
#include "emu_inc_bip39.h"
|
||||||
|
|
||||||
|
static const char SEPARATOR = ':';
|
||||||
|
static const u32 ATTACK_EXEC = ATTACK_EXEC_OUTSIDE_KERNEL;
|
||||||
|
static const u32 DGST_POS0 = 0;
|
||||||
|
static const u32 DGST_POS1 = 1;
|
||||||
|
static const u32 DGST_POS2 = 2;
|
||||||
|
static const u32 DGST_POS3 = 3;
|
||||||
|
static const u32 DGST_SIZE = DGST_SIZE_4_32;
|
||||||
|
static const u32 HASH_CATEGORY = HASH_CATEGORY_CRYPTOCURRENCY_WALLET;
|
||||||
|
static const char *HASH_NAME = "Bitcoin seed words and passphrase";
|
||||||
|
static const u64 KERN_TYPE = 28510;
|
||||||
|
static const u32 OPTI_TYPE = OPTI_TYPE_ZERO_BYTE | OPTI_TYPE_USES_BITS_64 | OPTI_TYPE_SLOW_HASH_SIMD_LOOP;
|
||||||
|
static const u64 OPTS_TYPE = OPTS_TYPE_COPY_TMPS;
|
||||||
|
static const u32 SALT_TYPE = SALT_TYPE_EMBEDDED;
|
||||||
|
static const char *ST_PASS = "hashcat";
|
||||||
|
static const char *ST_HASH = "P2PKH:m/44h/0h/0h/0/0:balcony catalog winner letter alley this:1B2hrNm7JGW6Wenf8oMvjWB3DPT9H9vAJ9";
|
||||||
|
|
||||||
|
typedef struct address_base58
|
||||||
|
{
|
||||||
|
u32 digest_len;
|
||||||
|
u32 address_len;
|
||||||
|
u32 prefix_len;
|
||||||
|
u8 prefix[];
|
||||||
|
} address_base58_t;
|
||||||
|
|
||||||
|
static const address_base58_t XPUB_ADDRESS = { 82, 111, 13, {0x04, 0x88, 0xb2, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF} };
|
||||||
|
static const address_base58_t P2PKH_ADDRESS = { 25, 34, 1, {0x0} };
|
||||||
|
static const address_base58_t P2SHWPKH_ADDRESS = { 25, 34, 1, {0x05} };
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* This section provides utilities for decoding the hash value.
|
||||||
|
* We need to parse out the address type, derivation path, mnemonic phrase,
|
||||||
|
* as the salt.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
// Output the next index from the derivation_path and increment the derivation_path pointer
|
||||||
|
DECLSPEC u32 decode_derivation_path (PRIVATE_AS u8 ** derivation_path, PRIVATE_AS const char end_char)
|
||||||
|
{
|
||||||
|
char word[9] = { 0 };
|
||||||
|
u32 hardened = 0;
|
||||||
|
|
||||||
|
if (derivation_path[0][0] == end_char)
|
||||||
|
return DERIVATION_END;
|
||||||
|
|
||||||
|
for (int i = 0; i < 9; i++)
|
||||||
|
{
|
||||||
|
// Parse out the digits or whether child is hardened
|
||||||
|
if (derivation_path[0][0] == 'h' || derivation_path[0][0] == '\'')
|
||||||
|
{
|
||||||
|
hardened = DERIVATION_HARDENED;
|
||||||
|
}
|
||||||
|
else if (derivation_path[0][0] == '/')
|
||||||
|
{
|
||||||
|
// Ends one child of the derivation path
|
||||||
|
*derivation_path += 1;
|
||||||
|
return hc_strtoul (word, 0, 10) | hardened;
|
||||||
|
}
|
||||||
|
else if (derivation_path[0][0] == end_char)
|
||||||
|
{
|
||||||
|
// Ends but don't advance derivation_path pointer so we'll return DERIVATION_END next
|
||||||
|
return hc_strtoul (word, 0, 10) | hardened;
|
||||||
|
}
|
||||||
|
else if (derivation_path[0][0] <= '9' && derivation_path[0][0] >= '0')
|
||||||
|
{
|
||||||
|
word[i] = derivation_path[0][0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return DERIVATION_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
*derivation_path += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Derivation path is too long
|
||||||
|
return DERIVATION_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output the next word index from the mnemonic_phrase and increment the mnemonic_phrase pointer
|
||||||
|
DECLSPEC u32 decode_mnemonic_phrase (PRIVATE_AS u8 ** mnemonic_phrase, PRIVATE_AS const char end_char)
|
||||||
|
{
|
||||||
|
char word[9] = { 0 };
|
||||||
|
if (mnemonic_phrase[0][0] == end_char)
|
||||||
|
return MNEMONIC_END;
|
||||||
|
|
||||||
|
for (int i = 0; i < 9; i++)
|
||||||
|
{
|
||||||
|
word[i] = mnemonic_phrase[0][0];
|
||||||
|
*mnemonic_phrase += 1;
|
||||||
|
|
||||||
|
if (mnemonic_phrase[0][0] == end_char)
|
||||||
|
break;
|
||||||
|
if (mnemonic_phrase[0][0] == ' ')
|
||||||
|
{
|
||||||
|
*mnemonic_phrase += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp (word, "?", 1) == 0)
|
||||||
|
return MNEMONIC_GUESS;
|
||||||
|
|
||||||
|
return bip39_from_word (word);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper for base58 decoding into the digest, assumes prefix ends in 0xFF
|
||||||
|
static bool decode_base58 (const address_base58_t * type, const char *address, u8 * digest)
|
||||||
|
{
|
||||||
|
u32 len = type->digest_len;
|
||||||
|
u32 prefix_len = type->prefix_len;
|
||||||
|
u8 decoded_address[128] = { 0 };
|
||||||
|
|
||||||
|
if (!b58dec (decoded_address, &len, (u8 *) address, type->address_len))
|
||||||
|
return false;
|
||||||
|
if (!b58check (decoded_address, len))
|
||||||
|
return false;
|
||||||
|
if (len != type->digest_len)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// skip encoding the known prefix (not useful for digest entropy)
|
||||||
|
for (u32 i = 0; i < prefix_len; i++)
|
||||||
|
{
|
||||||
|
if (type->prefix[i] != decoded_address[i])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (u32 i = 0; i < type->digest_len - prefix_len; i++)
|
||||||
|
{
|
||||||
|
digest[i] = decoded_address[i + prefix_len];
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper for base58 encoding into the digest
|
||||||
|
static void encode_base58 (const address_base58_t * type, u8 * address, const u8 * digest)
|
||||||
|
{
|
||||||
|
u32 len = 0xFFFFFFFF;
|
||||||
|
u32 prefix_len = type->prefix_len;
|
||||||
|
u8 decoded_address[128] = { 0 };
|
||||||
|
|
||||||
|
// build the address using the known prefix
|
||||||
|
for (u32 i = 0; i < prefix_len; i++)
|
||||||
|
{
|
||||||
|
decoded_address[i] = type->prefix[i];
|
||||||
|
}
|
||||||
|
for (u32 i = 0; i < type->digest_len - prefix_len; i++)
|
||||||
|
{
|
||||||
|
decoded_address[prefix_len + i] = digest[i];
|
||||||
|
}
|
||||||
|
b58enc (address, &len, decoded_address, type->digest_len);
|
||||||
|
|
||||||
|
// Sometimes encoding adds unnecessary zeros to the prefix
|
||||||
|
u32 offset = len - type->address_len - 1;
|
||||||
|
|
||||||
|
for (u32 i = 0; i < type->address_len; i++)
|
||||||
|
{
|
||||||
|
address[i] = address[i + offset];
|
||||||
|
}
|
||||||
|
address[type->address_len] = 0x0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* This section provides utilities for bech32 encoding/decoding necessary for
|
||||||
|
* newer bitcoin address types. Could be refactored for use in other bitcoin
|
||||||
|
* modules.
|
||||||
|
*
|
||||||
|
* Adapted from https://github.com/sipa/bech32/tree/master/ref/c
|
||||||
|
* Copyright (c) 2017, 2021 Pieter Wuille, MIT license
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
BECH32_ENCODING_NONE,
|
||||||
|
BECH32_ENCODING_BECH32,
|
||||||
|
BECH32_ENCODING_BECH32M
|
||||||
|
} bech32_encoding;
|
||||||
|
|
||||||
|
static u32 bech32_polymod_step (uint32_t pre)
|
||||||
|
{
|
||||||
|
u8 b = pre >> 25;
|
||||||
|
|
||||||
|
return ((pre & 0x1FFFFFF) << 5) ^ (-((b >> 0) & 1) & 0x3b6a57b2UL) ^ (-((b >> 1) & 1) & 0x26508e6dUL) ^ (-((b >> 2) & 1) & 0x1ea119faUL) ^ (-((b >> 3) & 1) & 0x3d4233ddUL) ^ (-((b >> 4) & 1) & 0x2a1462b3UL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 bech32_final_constant (bech32_encoding enc)
|
||||||
|
{
|
||||||
|
if (enc == BECH32_ENCODING_BECH32)
|
||||||
|
return 1;
|
||||||
|
if (enc == BECH32_ENCODING_BECH32M)
|
||||||
|
return 0x2bc830a3;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
|
||||||
|
|
||||||
|
static const int8_t charset_rev[128] = {
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
|
||||||
|
1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1,
|
||||||
|
-1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
|
||||||
|
1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1
|
||||||
|
};
|
||||||
|
|
||||||
|
int bech32_encode (char *output, const char *hrp, const uint8_t * data, size_t data_len, bech32_encoding enc)
|
||||||
|
{
|
||||||
|
uint32_t chk = 1;
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
while (hrp[i] != 0)
|
||||||
|
{
|
||||||
|
int ch = hrp[i];
|
||||||
|
|
||||||
|
if (ch < 33 || ch > 126)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch >= 'A' && ch <= 'Z')
|
||||||
|
return 0;
|
||||||
|
chk = bech32_polymod_step (chk) ^ (ch >> 5);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
if (i + 7 + data_len > 90)
|
||||||
|
return 0;
|
||||||
|
chk = bech32_polymod_step (chk);
|
||||||
|
while (*hrp != 0)
|
||||||
|
{
|
||||||
|
chk = bech32_polymod_step (chk) ^ (*hrp & 0x1f);
|
||||||
|
*(output++) = *(hrp++);
|
||||||
|
}
|
||||||
|
*(output++) = '1';
|
||||||
|
for (i = 0; i < data_len; ++i)
|
||||||
|
{
|
||||||
|
if (*data >> 5)
|
||||||
|
return 0;
|
||||||
|
chk = bech32_polymod_step (chk) ^ (*data);
|
||||||
|
*(output++) = charset[*(data++)];
|
||||||
|
}
|
||||||
|
for (i = 0; i < 6; ++i)
|
||||||
|
{
|
||||||
|
chk = bech32_polymod_step (chk);
|
||||||
|
}
|
||||||
|
chk ^= bech32_final_constant (enc);
|
||||||
|
for (i = 0; i < 6; ++i)
|
||||||
|
{
|
||||||
|
*(output++) = charset[(chk >> ((5 - i) * 5)) & 0x1f];
|
||||||
|
}
|
||||||
|
*output = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bech32_encoding bech32_decode (char *hrp, uint8_t * data, size_t *data_len, const char *input)
|
||||||
|
{
|
||||||
|
uint32_t chk = 1;
|
||||||
|
size_t i;
|
||||||
|
size_t input_len = strlen (input);
|
||||||
|
size_t hrp_len;
|
||||||
|
int have_lower = 0, have_upper = 0;
|
||||||
|
|
||||||
|
if (input_len < 8 || input_len > 90)
|
||||||
|
{
|
||||||
|
return BECH32_ENCODING_NONE;
|
||||||
|
}
|
||||||
|
*data_len = 0;
|
||||||
|
while (*data_len < input_len && input[(input_len - 1) - *data_len] != '1')
|
||||||
|
{
|
||||||
|
++(*data_len);
|
||||||
|
}
|
||||||
|
hrp_len = input_len - (1 + *data_len);
|
||||||
|
if (1 + *data_len >= input_len || *data_len < 6)
|
||||||
|
{
|
||||||
|
return BECH32_ENCODING_NONE;
|
||||||
|
}
|
||||||
|
*(data_len) -= 6;
|
||||||
|
for (i = 0; i < hrp_len; ++i)
|
||||||
|
{
|
||||||
|
int ch = input[i];
|
||||||
|
|
||||||
|
if (ch < 33 || ch > 126)
|
||||||
|
{
|
||||||
|
return BECH32_ENCODING_NONE;
|
||||||
|
}
|
||||||
|
if (ch >= 'a' && ch <= 'z')
|
||||||
|
{
|
||||||
|
have_lower = 1;
|
||||||
|
}
|
||||||
|
else if (ch >= 'A' && ch <= 'Z')
|
||||||
|
{
|
||||||
|
have_upper = 1;
|
||||||
|
ch = (ch - 'A') + 'a';
|
||||||
|
}
|
||||||
|
hrp[i] = ch;
|
||||||
|
chk = bech32_polymod_step (chk) ^ (ch >> 5);
|
||||||
|
}
|
||||||
|
hrp[i] = 0;
|
||||||
|
chk = bech32_polymod_step (chk);
|
||||||
|
for (i = 0; i < hrp_len; ++i)
|
||||||
|
{
|
||||||
|
chk = bech32_polymod_step (chk) ^ (input[i] & 0x1f);
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
while (i < input_len)
|
||||||
|
{
|
||||||
|
int v = (input[i] & 0x80) ? -1 : charset_rev[(int) input[i]];
|
||||||
|
|
||||||
|
if (input[i] >= 'a' && input[i] <= 'z')
|
||||||
|
have_lower = 1;
|
||||||
|
if (input[i] >= 'A' && input[i] <= 'Z')
|
||||||
|
have_upper = 1;
|
||||||
|
if (v == -1)
|
||||||
|
{
|
||||||
|
return BECH32_ENCODING_NONE;
|
||||||
|
}
|
||||||
|
chk = bech32_polymod_step (chk) ^ v;
|
||||||
|
if (i + 6 < input_len)
|
||||||
|
{
|
||||||
|
data[i - (1 + hrp_len)] = v;
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
if (have_lower && have_upper)
|
||||||
|
{
|
||||||
|
return BECH32_ENCODING_NONE;
|
||||||
|
}
|
||||||
|
if (chk == bech32_final_constant (BECH32_ENCODING_BECH32))
|
||||||
|
{
|
||||||
|
return BECH32_ENCODING_BECH32;
|
||||||
|
}
|
||||||
|
else if (chk == bech32_final_constant (BECH32_ENCODING_BECH32M))
|
||||||
|
{
|
||||||
|
return BECH32_ENCODING_BECH32M;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return BECH32_ENCODING_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int convert_bits (uint8_t * out, size_t *outlen, int outbits, const uint8_t * in, size_t inlen, int inbits, int pad)
|
||||||
|
{
|
||||||
|
uint32_t val = 0;
|
||||||
|
int bits = 0;
|
||||||
|
uint32_t maxv = (((uint32_t) 1) << outbits) - 1;
|
||||||
|
|
||||||
|
while (inlen--)
|
||||||
|
{
|
||||||
|
val = (val << inbits) | *(in++);
|
||||||
|
bits += inbits;
|
||||||
|
while (bits >= outbits)
|
||||||
|
{
|
||||||
|
bits -= outbits;
|
||||||
|
out[(*outlen)++] = (val >> bits) & maxv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pad)
|
||||||
|
{
|
||||||
|
if (bits)
|
||||||
|
{
|
||||||
|
out[(*outlen)++] = (val << (outbits - bits)) & maxv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (((val << (outbits - bits)) & maxv) || bits >= inbits)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int segwit_addr_encode (char *output, const char *hrp, int witver, const uint8_t * witprog, size_t witprog_len)
|
||||||
|
{
|
||||||
|
uint8_t data[65];
|
||||||
|
size_t datalen = 0;
|
||||||
|
bech32_encoding enc = BECH32_ENCODING_BECH32;
|
||||||
|
|
||||||
|
if (witver > 16)
|
||||||
|
return 0;
|
||||||
|
if (witver == 0 && witprog_len != 20 && witprog_len != 32)
|
||||||
|
return 0;
|
||||||
|
if (witprog_len < 2 || witprog_len > 40)
|
||||||
|
return 0;
|
||||||
|
if (witver > 0)
|
||||||
|
enc = BECH32_ENCODING_BECH32M;
|
||||||
|
data[0] = witver;
|
||||||
|
convert_bits (data + 1, &datalen, 5, witprog, witprog_len, 8, 1);
|
||||||
|
++datalen;
|
||||||
|
return bech32_encode (output, hrp, data, datalen, enc);
|
||||||
|
}
|
||||||
|
|
||||||
|
int segwit_addr_decode (int *witver, uint8_t * witdata, size_t *witdata_len, const char *hrp, const char *addr)
|
||||||
|
{
|
||||||
|
uint8_t data[84];
|
||||||
|
char hrp_actual[84];
|
||||||
|
size_t data_len;
|
||||||
|
bech32_encoding enc = bech32_decode (hrp_actual, data, &data_len, addr);
|
||||||
|
|
||||||
|
if (enc == BECH32_ENCODING_NONE)
|
||||||
|
return 0;
|
||||||
|
if (data_len == 0 || data_len > 65)
|
||||||
|
return 0;
|
||||||
|
if (strncmp (hrp, hrp_actual, 84) != 0)
|
||||||
|
return 0;
|
||||||
|
if (data[0] > 16)
|
||||||
|
return 0;
|
||||||
|
if (data[0] == 0 && enc != BECH32_ENCODING_BECH32)
|
||||||
|
return 0;
|
||||||
|
if (data[0] > 0 && enc != BECH32_ENCODING_BECH32M)
|
||||||
|
return 0;
|
||||||
|
*witdata_len = 0;
|
||||||
|
if (!convert_bits (witdata, witdata_len, 8, data + 1, data_len - 1, 5, 0))
|
||||||
|
return 0;
|
||||||
|
if (*witdata_len < 2 || *witdata_len > 40)
|
||||||
|
return 0;
|
||||||
|
if (data[0] == 0 && *witdata_len != 20 && *witdata_len != 32)
|
||||||
|
return 0;
|
||||||
|
*witver = data[0];
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* This section contains the typical module functions found in most modules
|
||||||
|
* such as the encoding and decoding of the hash value to the digest.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
u32 module_attack_exec (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const user_options_t * user_options, MAYBE_UNUSED const user_options_extra_t * user_options_extra)
|
||||||
|
{
|
||||||
|
return ATTACK_EXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 module_dgst_pos0 (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const user_options_t * user_options, MAYBE_UNUSED const user_options_extra_t * user_options_extra)
|
||||||
|
{
|
||||||
|
return DGST_POS0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 module_dgst_pos1 (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const user_options_t * user_options, MAYBE_UNUSED const user_options_extra_t * user_options_extra)
|
||||||
|
{
|
||||||
|
return DGST_POS1;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 module_dgst_pos2 (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const user_options_t * user_options, MAYBE_UNUSED const user_options_extra_t * user_options_extra)
|
||||||
|
{
|
||||||
|
return DGST_POS2;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 module_dgst_pos3 (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const user_options_t * user_options, MAYBE_UNUSED const user_options_extra_t * user_options_extra)
|
||||||
|
{
|
||||||
|
return DGST_POS3;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 module_dgst_size (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const user_options_t * user_options, MAYBE_UNUSED const user_options_extra_t * user_options_extra)
|
||||||
|
{
|
||||||
|
return DGST_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 module_hash_category (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const user_options_t * user_options, MAYBE_UNUSED const user_options_extra_t * user_options_extra)
|
||||||
|
{
|
||||||
|
return HASH_CATEGORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *module_hash_name (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const user_options_t * user_options, MAYBE_UNUSED const user_options_extra_t * user_options_extra)
|
||||||
|
{
|
||||||
|
return HASH_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 module_kern_type (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const user_options_t * user_options, MAYBE_UNUSED const user_options_extra_t * user_options_extra)
|
||||||
|
{
|
||||||
|
return KERN_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 module_opti_type (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const user_options_t * user_options, MAYBE_UNUSED const user_options_extra_t * user_options_extra)
|
||||||
|
{
|
||||||
|
return OPTI_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 module_opts_type (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const user_options_t * user_options, MAYBE_UNUSED const user_options_extra_t * user_options_extra)
|
||||||
|
{
|
||||||
|
return OPTS_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 module_salt_type (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const user_options_t * user_options, MAYBE_UNUSED const user_options_extra_t * user_options_extra)
|
||||||
|
{
|
||||||
|
return SALT_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *module_st_hash (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const user_options_t * user_options, MAYBE_UNUSED const user_options_extra_t * user_options_extra)
|
||||||
|
{
|
||||||
|
return ST_HASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *module_st_pass (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const user_options_t * user_options, MAYBE_UNUSED const user_options_extra_t * user_options_extra)
|
||||||
|
{
|
||||||
|
return ST_PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 module_tmp_size (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const user_options_t * user_options, MAYBE_UNUSED const user_options_extra_t * user_options_extra)
|
||||||
|
{
|
||||||
|
return (const u64) sizeof (bip39_tmp_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
int module_hash_decode (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED void *digest_buf, MAYBE_UNUSED salt_t * salt, MAYBE_UNUSED void *esalt_buf, MAYBE_UNUSED void *hook_salt_buf, MAYBE_UNUSED hashinfo_t * hash_info, const char *line_buf, MAYBE_UNUSED const int line_len)
|
||||||
|
{
|
||||||
|
u8 *digest = (u8 *) digest_buf;
|
||||||
|
hc_token_t token;
|
||||||
|
|
||||||
|
memset (&token, 0, sizeof (hc_token_t));
|
||||||
|
|
||||||
|
token.token_cnt = 4;
|
||||||
|
token.sep[0] = SEPARATOR;
|
||||||
|
token.sep[1] = SEPARATOR;
|
||||||
|
token.sep[2] = SEPARATOR;
|
||||||
|
token.sep[3] = SEPARATOR;
|
||||||
|
|
||||||
|
const int rc_tokenizer = input_tokenizer ((const u8 *) line_buf, line_len, &token);
|
||||||
|
|
||||||
|
if (rc_tokenizer != PARSER_OK)
|
||||||
|
return (rc_tokenizer);
|
||||||
|
|
||||||
|
const char *address_type = (char *) token.buf[0];
|
||||||
|
const char *derivation_path = (char *) token.buf[1];
|
||||||
|
const char *mnemonic_phrase = (char *) token.buf[2];
|
||||||
|
const char *address = (char *) token.buf[3];
|
||||||
|
|
||||||
|
// Store address type in salt[0] and convert into digest
|
||||||
|
if (strncmp (address_type, "XPUB", token.len[0]) == 0)
|
||||||
|
{
|
||||||
|
salt->salt_buf[0] = XPUB_ADDRESS_ID;
|
||||||
|
if (!decode_base58 (&XPUB_ADDRESS, address, digest))
|
||||||
|
return PARSER_HASH_ENCODING;
|
||||||
|
}
|
||||||
|
else if (strncmp (address_type, "P2PKH", token.len[0]) == 0)
|
||||||
|
{
|
||||||
|
salt->salt_buf[0] = P2PKH_ADDRESS_ID;
|
||||||
|
if (!decode_base58 (&P2PKH_ADDRESS, address, digest))
|
||||||
|
return PARSER_HASH_ENCODING;
|
||||||
|
}
|
||||||
|
else if (strncmp (address_type, "P2PKH-P2WPKH", token.len[0]) == 0)
|
||||||
|
{
|
||||||
|
salt->salt_buf[0] = P2SHWPKH_ADDRESS_ID;
|
||||||
|
if (!decode_base58 (&P2SHWPKH_ADDRESS, address, digest))
|
||||||
|
return PARSER_HASH_ENCODING;
|
||||||
|
}
|
||||||
|
else if (strncmp (address_type, "P2PWPKH", token.len[0]) == 0)
|
||||||
|
{
|
||||||
|
salt->salt_buf[0] = P2WPKH_ADDRESS_ID;
|
||||||
|
int ver;
|
||||||
|
size_t witprog_len;
|
||||||
|
|
||||||
|
if (!segwit_addr_decode (&ver, digest, &witprog_len, "bc", address))
|
||||||
|
return PARSER_HASH_ENCODING;
|
||||||
|
if (ver != 0)
|
||||||
|
return PARSER_HASH_ENCODING;
|
||||||
|
if (witprog_len != 20)
|
||||||
|
return PARSER_HASH_ENCODING;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return PARSER_SIGNATURE_UNMATCHED;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 salt_index = 1;
|
||||||
|
|
||||||
|
// Store the derivation path in the salt
|
||||||
|
if (strncmp (derivation_path, "m/", 2) != 0)
|
||||||
|
return PARSER_SALT_VALUE;
|
||||||
|
derivation_path += 2;
|
||||||
|
for (u32 derivation = 0; derivation != DERIVATION_END; salt_index++)
|
||||||
|
{
|
||||||
|
derivation = decode_derivation_path ((u8 **) & derivation_path, SEPARATOR);
|
||||||
|
if (derivation == DERIVATION_ERROR)
|
||||||
|
return PARSER_SALT_VALUE;
|
||||||
|
salt->salt_buf[salt_index] = derivation;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the mnemonic words in the salt
|
||||||
|
for (u32 mnemonic = 0; mnemonic != MNEMONIC_END; salt_index++)
|
||||||
|
{
|
||||||
|
mnemonic = decode_mnemonic_phrase ((u8 **) & mnemonic_phrase, SEPARATOR);
|
||||||
|
if (mnemonic == MNEMONIC_ERROR)
|
||||||
|
return PARSER_SALT_ENCODING;
|
||||||
|
salt->salt_buf[salt_index] = mnemonic;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BIP39 requires 2048 iterations of PBKDF2-HMAC-SHA512
|
||||||
|
salt->salt_iter = 2047;
|
||||||
|
salt->salt_len = salt_index + 1;
|
||||||
|
|
||||||
|
return (PARSER_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
int module_hash_encode (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const void *digest_buf, MAYBE_UNUSED const salt_t * salt, MAYBE_UNUSED const void *esalt_buf, MAYBE_UNUSED const void *hook_salt_buf, MAYBE_UNUSED const hashinfo_t * hash_info, char *line_buf, MAYBE_UNUSED const int line_size)
|
||||||
|
{
|
||||||
|
const u8 *digest = (const u8 *) digest_buf;
|
||||||
|
u8 address[128];
|
||||||
|
|
||||||
|
if (salt->salt_buf[0] == XPUB_ADDRESS_ID)
|
||||||
|
{
|
||||||
|
encode_base58 (&XPUB_ADDRESS, address, digest);
|
||||||
|
}
|
||||||
|
else if (salt->salt_buf[0] == P2PKH_ADDRESS_ID)
|
||||||
|
{
|
||||||
|
encode_base58 (&P2PKH_ADDRESS, address, digest);
|
||||||
|
}
|
||||||
|
else if (salt->salt_buf[0] == P2SHWPKH_ADDRESS_ID)
|
||||||
|
{
|
||||||
|
encode_base58 (&P2SHWPKH_ADDRESS, address, digest);
|
||||||
|
}
|
||||||
|
else if (salt->salt_buf[0] == P2WPKH_ADDRESS_ID)
|
||||||
|
{
|
||||||
|
segwit_addr_encode ((char *) address, "bc", 0, digest, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
return snprintf (line_buf, line_size, "%s", address);
|
||||||
|
}
|
||||||
|
|
||||||
|
int module_build_plain_postprocess (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const hashes_t * hashes, MAYBE_UNUSED const void *tmps, const u32 * src_buf, MAYBE_UNUSED const size_t src_sz, MAYBE_UNUSED const int src_len, u32 * dst_buf, MAYBE_UNUSED const size_t dst_sz)
|
||||||
|
{
|
||||||
|
u32 buf[32] = { 0 };
|
||||||
|
msg_encoder_t encoder = encoder_init (buf);
|
||||||
|
bip39_tmp_t *tmp = (bip39_tmp_t *) tmps;
|
||||||
|
|
||||||
|
const u32 *salt = hashes->salts_buf[tmp->salt_index].salt_buf;
|
||||||
|
u32 words[32] = { 0 };
|
||||||
|
u32 pw_index = bip39_guess_words (src_buf, salt, words);
|
||||||
|
|
||||||
|
u32 salt_index = 0;
|
||||||
|
|
||||||
|
while (salt[salt_index] != DERIVATION_END)
|
||||||
|
{
|
||||||
|
salt_index++;
|
||||||
|
}
|
||||||
|
salt_index++;
|
||||||
|
|
||||||
|
for (u32 i = salt_index; salt[salt_index] != MNEMONIC_END; salt_index++)
|
||||||
|
{
|
||||||
|
if (salt[salt_index] == MNEMONIC_GUESS)
|
||||||
|
{
|
||||||
|
encode_mnemonic_word (&encoder, words[salt_index - i]);
|
||||||
|
encode_char (&encoder, ',');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
encode_array_le (&encoder, src_buf, src_len, pw_index);
|
||||||
|
|
||||||
|
for (u32 i = 0; i <= encoder.len / 4; i++)
|
||||||
|
{
|
||||||
|
dst_buf[i] = byte_swap_32 (buf[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void module_init (module_ctx_t * module_ctx)
|
||||||
|
{
|
||||||
|
module_ctx->module_context_size = MODULE_CONTEXT_SIZE_CURRENT;
|
||||||
|
module_ctx->module_interface_version = MODULE_INTERFACE_VERSION_CURRENT;
|
||||||
|
|
||||||
|
module_ctx->module_attack_exec = module_attack_exec;
|
||||||
|
module_ctx->module_benchmark_esalt = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_benchmark_hook_salt = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_benchmark_mask = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_benchmark_charset = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_benchmark_salt = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_build_plain_postprocess = module_build_plain_postprocess;
|
||||||
|
module_ctx->module_deep_comp_kernel = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_deprecated_notice = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_dgst_pos0 = module_dgst_pos0;
|
||||||
|
module_ctx->module_dgst_pos1 = module_dgst_pos1;
|
||||||
|
module_ctx->module_dgst_pos2 = module_dgst_pos2;
|
||||||
|
module_ctx->module_dgst_pos3 = module_dgst_pos3;
|
||||||
|
module_ctx->module_dgst_size = module_dgst_size;
|
||||||
|
module_ctx->module_dictstat_disable = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_esalt_size = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_extra_buffer_size = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_extra_tmp_size = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_extra_tuningdb_block = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_forced_outfile_format = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_hash_binary_count = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_hash_binary_parse = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_hash_binary_save = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_hash_decode_postprocess = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_hash_decode_potfile = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_hash_decode_zero_hash = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_hash_decode = module_hash_decode;
|
||||||
|
module_ctx->module_hash_encode_status = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_hash_encode_potfile = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_hash_encode = module_hash_encode;
|
||||||
|
module_ctx->module_hash_init_selftest = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_hash_mode = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_hash_category = module_hash_category;
|
||||||
|
module_ctx->module_hash_name = module_hash_name;
|
||||||
|
module_ctx->module_hashes_count_min = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_hashes_count_max = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_hlfmt_disable = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_hook_extra_param_size = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_hook_extra_param_init = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_hook_extra_param_term = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_hook12 = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_hook23 = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_hook_salt_size = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_hook_size = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_jit_build_options = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_jit_cache_disable = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_kernel_accel_max = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_kernel_accel_min = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_kernel_loops_max = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_kernel_loops_min = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_kernel_threads_max = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_kernel_threads_min = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_kern_type = module_kern_type;
|
||||||
|
module_ctx->module_kern_type_dynamic = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_opti_type = module_opti_type;
|
||||||
|
module_ctx->module_opts_type = module_opts_type;
|
||||||
|
module_ctx->module_outfile_check_disable = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_outfile_check_nocomp = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_potfile_custom_check = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_potfile_disable = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_potfile_keep_all_hashes = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_pwdump_column = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_pw_max = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_pw_min = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_salt_max = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_salt_min = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_salt_type = module_salt_type;
|
||||||
|
module_ctx->module_separator = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_st_hash = module_st_hash;
|
||||||
|
module_ctx->module_st_pass = module_st_pass;
|
||||||
|
module_ctx->module_tmp_size = module_tmp_size;
|
||||||
|
module_ctx->module_unstable_warning = MODULE_DEFAULT;
|
||||||
|
module_ctx->module_warmup_disable = MODULE_DEFAULT;
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
# Runs tests of the BIP39 directly against hashcat
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
TEST1="XPUB:m/:coral dice harvest:xpub661MyMwAqRbcFaizXLqdLrqBkUJo4JyyXYNucU2hWQBDfhmCd3TL7USdpjhUddedvEiSo31BRg9QB4a5PNKcuQRWT6DA2YveGA2tzsqZQwg"
|
||||||
|
PASS1="hashca?4"
|
||||||
|
|
||||||
|
TEST2="P2PKH:m/44h/0h/0h/0/0:balcony catalog winner letter alley this:1B2hrNm7JGW6Wenf8oMvjWB3DPT9H9vAJ9"
|
||||||
|
PASS2="hashca?4"
|
||||||
|
|
||||||
|
TEST3="P2PKH-P2WPKH:m/49h/0h/0h/0/1:cage keep stone swarm open race toward state subway dutch extra short purpose interest enough idle found guilt will salt mixed boil heavy thing:361yU4TkuRSLTdTkfEUbWGfTJgJjFDZUvG"
|
||||||
|
PASS3="hashca?4"
|
||||||
|
|
||||||
|
TEST4="P2PWPKH:m/84h/0h/0h/0/2:donate dolphin bachelor excess stuff flower spread crazy scorpion zoo skull lottery:bc1q490ra0dcf4l58jzt2445akrxpj6aftkfdvs8n7"
|
||||||
|
PASS4="hashca?4"
|
||||||
|
|
||||||
|
# security sugar abandon diamond abandon orient zoo example crane fruit senior decade
|
||||||
|
TEST5="P2PWPKH:m/84h/0h/0h/0/0:security sugar ? diamond ? orient ? example crane fruit senior ?:bc1q6dlx8mxcxm3qterx35cul7z76v975tf2vq06yr"
|
||||||
|
PASS5="5656?1?2?3hashcat"
|
||||||
|
|
||||||
|
if [ -z $1 ] || [ -z $2 ]; then
|
||||||
|
echo "Usage ./tools/bip39-tests.sh <test|run|bench> <#|all>"
|
||||||
|
exit -1
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f hashcat.potfile
|
||||||
|
|
||||||
|
for i in $(seq 1 5);
|
||||||
|
do
|
||||||
|
if [[ "$2" = "$i" ]] || [[ "$2" = "all" ]]; then
|
||||||
|
echo "Running $1 #$i"
|
||||||
|
TEST="TEST$i"
|
||||||
|
PASS="PASS$i"
|
||||||
|
if [ $1 = "test" ]; then
|
||||||
|
./hashcat -m 28510 -a 3 --force -n 1 -u 1 -T 1 -1 T -2 u -3 S -4 t "${!TEST}" "${!PASS}"
|
||||||
|
elif [ $1 = "run" ]; then
|
||||||
|
./hashcat -m 28510 -a 3 -1 charsets/bin/5bit.hcchr -2 charsets/bin/6bit.hcchr -3 charsets/bin/7bit.hcchr -4 ?l "${!TEST}" "${!PASS}"
|
||||||
|
elif [ $1 = "bench" ]; then
|
||||||
|
./hashcat -m 28510 -a 3 -1 charsets/bin/5bit.hcchr -2 charsets/bin/6bit.hcchr -3 charsets/bin/7bit.hcchr -4 ?l --status "${!TEST}" "?1?2?1?2?1?2?3?l"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo -e "\nResults (should be 5 if running all tests):"
|
||||||
|
cat hashcat.potfile
|
Loading…
Reference in new issue