Overview
Comment: | add rd-key |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
4e2b17fce2c5086be6d1c53bbed3d9c0 |
User & Date: | lexi on 2021-09-11 22:18:39 |
Other Links: | manifest | tags |
Context
2022-04-25
| ||
21:01 | add first parvan revision check-in: bf5f4fd9ca user: lexi tags: trunk | |
2021-09-11
| ||
22:18 | add rd-key check-in: 4e2b17fce2 user: lexi tags: trunk | |
2019-12-16
| ||
06:16 | fix newtab to keep userscript sockets/fifos from tripping it up check-in: 4cecd72436 user: lexi tags: trunk | |
Changes
Added rd-key.lua version [4ea4dcd59f].
1 +-- [ʞ] rd-key.lua 2 +-- ~ lexi hale 3 +-- © GNU AGPLv3 4 +-- ? utility for generating and applying 64bit key 5 +-- schedules to RD-5R "codeplug" provisioning profiles 6 +-- > lua rd-key.lua gen sched.kch 7 +-- > lua rd-key.lua apply sched.kch device.img 8 +-- > dmrconfig -w device.img 9 + 10 +function B(b, ...) 11 + if not b then return "" end 12 + return string.pack("I1", b) .. B(...) 13 +end 14 + 15 +local const = { 16 + kch_header = B(0x9a, 0x1e, 0x2f) .. "kCH"; 17 + maxkeys = 16; 18 + keylen = 64/8; 19 + 20 + plug = { 21 + kch_start = 0x1370; 22 + kch_end = 0x13f8; 23 + bank_chns = 128; 24 + chn_sz = 56; 25 + bank_sz = 16 + (56 * 128); 26 + chn_regions = { 27 + {top = 128, start = 0x3780}; 28 + {top = 1023, start = 0xb1b0}; 29 + }; 30 + 31 + mode = { 32 + analog = 0; 33 + digital = 1; 34 + }; 35 + }; 36 +} 37 + 38 +math.randomseed(os.time()) 39 +function log(...) print(string.format(...)) end 40 +function keymask(num) 41 + local mask = 0 42 + for i = 0, num-1 do 43 + mask = mask | 1 << i 44 + end 45 + 46 + return string.pack("<I2", mask) 47 +end 48 + 49 +function strdec(str) 50 + for i = 1, #str do 51 + if string.byte(str, i) == 0xFF then 52 + return str:sub(1, i-1) 53 + end 54 + end 55 + return str 56 +end 57 + 58 +function chans(mem) 59 + local i = 1 60 + local region = 1 61 + return function() 62 + local r = const.plug.chn_regions[region] 63 + ::tryagain:: 64 + if i > r.top then 65 + region = region + 1 66 + r = const.plug.chn_regions[region] 67 + end 68 + if r == nil then return nil end 69 + local bottom = region > 1 and const.plug.chn_regions[region-1].top or 1 70 + 71 + local bank = (i - bottom) // const.plug.bank_chns 72 + local bo = r.start + bank * const.plug.bank_sz 73 + local bankpos = (i - bottom) % const.plug.bank_chns 74 + 75 + i = i + 1 76 + 77 + -- local bitmap = mem:sub(bo, bo + 16) 78 + -- local bitmap_b = string.byte(bitmap, 1 + bankpos // 8) 79 + -- if bitmap_b & (1 << (bankpos % 8)) == 0 then --- doesn't work 80 + -- goto tryagain 81 + -- end 82 + 83 + local chans = bo + 16 84 + local ent = chans + bankpos * const.plug.chn_sz 85 + 86 + local rec = mem:sub(1+ent,1+ent + const.plug.chn_sz) 87 + 88 + 89 + return rec, i-1, 1+ent 90 + end 91 +end 92 + 93 +function strchg(str, ofs, sz, new) 94 + local head = string.sub(str, 1, ofs-1) 95 + local tail = string.sub(str, ofs+sz) 96 + local n = head .. new .. tail 97 + if #n ~= #str then 98 + print("old str") dumpline(string.sub(str, ofs, ofs + (sz-1))) 99 + print("new str should be", sz, #new) dumpline(new) 100 + error("bad str chg") 101 + end 102 + return n 103 +end 104 + 105 +function dumpline(str) 106 + local function dump(line) 107 + local top="\t" 108 + local bottom="\t" 109 + 110 + for i=1,#line do 111 + local val = string.byte(line, i) 112 + if val >= 0x20 and val <= 0x7e then 113 + top = top .. string.format(" %c ", val) 114 + else 115 + top = top .. " : " 116 + end 117 + bottom = bottom .. string.format("%02x ", val) 118 + end 119 + print(top) 120 + print(bottom) 121 + end 122 + local cpl = 32 123 + for i = 0, #str // cpl do 124 + local st = 1 + i*cpl 125 + dump(str:sub(st, st+cpl)) 126 + end 127 +end 128 +function applykeychain(chain, file) 129 + local h = io.open(file, 'rb') 130 + if not h then error("could not open file") end 131 + local pl = h:read('a') h:close() 132 + 133 + local keylist = B(1,0) -- basic mode 134 + .. keymask(const.maxkeys) -- number of keys 135 + .. B(0,0, 0,0) -- padding?? 136 + .. table.concat(chain) 137 + pl = strchg(pl, const.plug.kch_start+1, #keylist, keylist) 138 + 139 + for ch, idx, ofs in chans(pl) do 140 + if string.byte(ch, 1) ~= 0xFF then -- is channel defined? 141 + local name = strdec(ch:sub(1,16)) 142 + local mode = string.byte(ch, 25) 143 + local function say(fmt, ...) 144 + log("\x1b[1mchannel [%04u] “%s”\x1b[m: " .. fmt, idx, name, ...) 145 + end 146 + local newch 147 + if mode == const.plug.mode.digital then 148 + local privg = string.byte(ch, 42) 149 + local chkey = idx % const.maxkeys 150 + if privg == 0 then 151 + say("marked clear, comms on this channel will NOT be encrypted") 152 + elseif privg ~= chkey then 153 + say("changing key from #%u to #%u", privg, chkey) 154 + newch = strchg(ch, 42, 1, B(chkey)) 155 + dirty = true 156 + -- else 157 + -- say("already keyed correctly") 158 + end 159 + else 160 + say("analog channel, cannot be encrypted") 161 + end 162 + 163 + if newch then 164 + pl=strchg(pl, ofs, 1+const.plug.chn_sz, newch) 165 + end 166 + end 167 + end 168 + 169 + h = io.open(file, 'w+b') 170 + h:write(pl) 171 + h:close() 172 +end 173 + 174 +function loadkeychain(file) 175 + local f = io.open(file, "r") 176 + if f:read(#const.kch_header) ~= const.kch_header then 177 + error "not a valid keychain file" 178 + end 179 + local ch = {} 180 + for i=1, const.maxkeys do 181 + ch[i] = f:read(const.keylen) 182 + end 183 + local comment = f:read('a') 184 + f:close() 185 + log("using keychain for %s", comment) 186 + return ch 187 +end 188 + 189 +function savekeychain(file, kch) 190 + local f = io.open(file, "w+b") 191 + f:write(const.kch_header) 192 + for i=1, const.maxkeys do 193 + f:write(kch[i]) 194 + end 195 + f:write(os.date()) 196 + f:close() 197 +end 198 + 199 +function genkeychain() 200 + local ch = {} 201 + local rng = io.open("/dev/urandom") or io.open("/dev/random") 202 + function rb(n) 203 + if rng then return rng:read(n) else 204 + log('warning, cannot read /dev/[u]random, random bytes may be low-quality') 205 + local str = "" 206 + for i = 1,n do str = str .. B(math.random(0,0xff)) end 207 + return str 208 + end 209 + end 210 + for i=1,const.maxkeys do 211 + ch[i] = rb(64/8) 212 + end 213 + if rng then rng:close() end 214 + return ch 215 +end 216 + 217 +local cmd, keychain, target = ... 218 +if not cmd then 219 + print("usage: lua rd-key.lua (gen|apply|extract) keychain [codeplug]") 220 +else 221 + if keychain == nil or file == "" then keychain = "chain.kch" end 222 + if target == nil or target == "" then target = "device.img" end 223 + if cmd == "gen" then 224 + log("writing new keychain to %s", keychain) 225 + local ch = genkeychain() 226 + savekeychain(keychain, ch) 227 + elseif cmd == "apply" then 228 + log("applying keychain %s to codeplug %s", keychain, target) 229 + local ch = loadkeychain(keychain) 230 + applykeychain(ch, target) 231 + elseif cmd == "extract" then 232 + log("extracting keychain %s from codeplug %s", keychain, target) 233 + log(" -- unimplemented --") 234 + end 235 +end
Modified tenki/make.sh from [f7f3655bf1] to [3702e74b7e].
1 -#!/bin/bash 1 +#!/usr/bin/env bash 2 2 if test -e apikey; then 3 3 cc -Ofast -Dds_apikey="\"$(cat apikey)\"" tenki.c -lssl -otenki 4 4 else 5 5 echo "tenki requires an API key. get one from dark sky and put it in a file in this directory named 'apikey' before you try to build" 6 6 fi