util  Check-in [4e2b17fce2]

Overview
Comment:add rd-key
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 4e2b17fce2c5086be6d1c53bbed3d9c07692db2047f51351eca24aaeb67050be
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
-- [ʞ] rd-key.lua
--  ~ lexi hale
--  © GNU AGPLv3
--  ? utility for generating and applying 64bit key
--    schedules to RD-5R "codeplug" provisioning profiles
--  > lua rd-key.lua gen sched.kch
--  > lua rd-key.lua apply sched.kch device.img
--  > dmrconfig -w device.img

function B(b, ...)
	if not b then return "" end
	return string.pack("I1", b) .. B(...)
end

local const = {
	kch_header = B(0x9a, 0x1e, 0x2f) .. "kCH";
	maxkeys = 16;
	keylen = 64/8;

	plug = {
		kch_start = 0x1370;
		kch_end   = 0x13f8;
		bank_chns = 128;
		chn_sz    = 56;
		bank_sz   = 16 + (56 * 128);
		chn_regions = {
			{top = 128,  start = 0x3780};
			{top = 1023, start = 0xb1b0};
		};

		mode = {
			analog = 0;
			digital = 1;
		};
	};
}

math.randomseed(os.time())
function log(...) print(string.format(...)) end
function keymask(num)
	local mask = 0
	for i = 0, num-1 do
		mask = mask | 1 << i
	end

	return string.pack("<I2", mask)
end

function strdec(str)
	for i = 1, #str do
		if string.byte(str, i) == 0xFF then
			return str:sub(1, i-1)
		end
	end
	return str
end

function chans(mem)
	local i = 1
	local region = 1
	return function()
		local r = const.plug.chn_regions[region]
		::tryagain::
		if i > r.top then
			region = region + 1
			r = const.plug.chn_regions[region]
		end
		if r == nil then return nil end
		local bottom = region > 1 and const.plug.chn_regions[region-1].top or 1

		local bank = (i - bottom) // const.plug.bank_chns
		local bo = r.start + bank * const.plug.bank_sz
		local bankpos = (i - bottom) % const.plug.bank_chns

		i = i + 1

		-- local bitmap = mem:sub(bo, bo + 16)
		-- local bitmap_b = string.byte(bitmap, 1 + bankpos // 8)
		-- if bitmap_b & (1 << (bankpos % 8)) == 0 then  --- doesn't work
		-- 	goto tryagain
		-- end

		local chans = bo + 16
		local ent = chans + bankpos * const.plug.chn_sz

		local rec = mem:sub(1+ent,1+ent + const.plug.chn_sz)


		return rec, i-1, 1+ent
	end
end

function strchg(str, ofs, sz, new)
	local head = string.sub(str, 1, ofs-1)
	local tail = string.sub(str, ofs+sz)
	local n = head .. new .. tail
	if #n ~= #str then
		print("old str") dumpline(string.sub(str, ofs, ofs + (sz-1)))
		print("new str should be", sz, #new) dumpline(new)
		error("bad str chg")
	end
	return n
end

function dumpline(str)
	local function dump(line)
		local top="\t"
		local bottom="\t"

		for i=1,#line do
			local val = string.byte(line, i)
			if val >= 0x20 and val <= 0x7e then
				top = top .. string.format(" %c ", val)
			else
				top = top .. " : "
			end
			bottom = bottom .. string.format("%02x ", val)
		end
		print(top)
		print(bottom)
	end
	local cpl = 32
	for i = 0, #str // cpl do
		local st = 1 + i*cpl
		dump(str:sub(st, st+cpl))
	end
end
function applykeychain(chain, file)
	local h = io.open(file, 'rb')
	if not h then error("could not open file") end
	local pl = h:read('a') h:close()

	local keylist = B(1,0) -- basic mode
		.. keymask(const.maxkeys) -- number of keys
		.. B(0,0, 0,0) -- padding??
		.. table.concat(chain)
	pl = strchg(pl, const.plug.kch_start+1, #keylist, keylist)
	
	for ch, idx, ofs in chans(pl) do
		if string.byte(ch, 1) ~= 0xFF then -- is channel defined?
			local name = strdec(ch:sub(1,16))
			local mode = string.byte(ch, 25)
			local function say(fmt, ...)
				log("\x1b[1mchannel [%04u] “%s”\x1b[m: " .. fmt, idx, name, ...)
			end
			local newch
			if mode == const.plug.mode.digital then
				local privg = string.byte(ch, 42)
				local chkey = idx % const.maxkeys
				if privg == 0 then
					say("marked clear, comms on this channel will NOT be encrypted")
				elseif privg ~= chkey then
					say("changing key from #%u to #%u", privg, chkey)
					newch = strchg(ch, 42, 1, B(chkey))
					dirty = true
				-- else
				-- 	say("already keyed correctly")
				end
			else
				say("analog channel, cannot be encrypted")
			end

			if newch then
				pl=strchg(pl, ofs, 1+const.plug.chn_sz, newch)
			end
		end
	end

	h = io.open(file, 'w+b')
	h:write(pl)
	h:close()
end

function loadkeychain(file)
	local f = io.open(file, "r")
	if f:read(#const.kch_header) ~= const.kch_header then
		error "not a valid keychain file"
	end
	local ch = {}
	for i=1, const.maxkeys do
		ch[i] = f:read(const.keylen)
	end
	local comment = f:read('a')
	f:close()
	log("using keychain for %s", comment)
	return ch
end

function savekeychain(file, kch)
	local f = io.open(file, "w+b")
	f:write(const.kch_header)
	for i=1, const.maxkeys do
		f:write(kch[i])
	end
	f:write(os.date())
	f:close()
end

function genkeychain()
	local ch = {}
	local rng = io.open("/dev/urandom") or io.open("/dev/random")
	function rb(n)
		if rng then return rng:read(n) else
			log('warning, cannot read /dev/[u]random, random bytes may be low-quality')
			local str = ""
			for i = 1,n do str = str .. B(math.random(0,0xff)) end
			return str
		end
	end
	for i=1,const.maxkeys do
		ch[i] = rb(64/8)
	end
	if rng then rng:close() end
	return ch
end

local cmd, keychain, target = ...
if not cmd then
	print("usage: lua rd-key.lua (gen|apply|extract) keychain [codeplug]")
else
	if keychain == nil or file == "" then keychain = "chain.kch" end
	if target == nil or target == "" then target = "device.img" end
	if cmd == "gen" then
		log("writing new keychain to %s", keychain)
		local ch = genkeychain()
		savekeychain(keychain, ch)
	elseif cmd == "apply" then
		log("applying keychain %s to codeplug %s", keychain, target)
		local ch = loadkeychain(keychain)
		applykeychain(ch, target)
	elseif cmd == "extract" then
		log("extracting keychain %s from codeplug %s", keychain, target)
		log(" -- unimplemented --")
	end
end

Modified tenki/make.sh from [f7f3655bf1] to [3702e74b7e].

1
2
3
4
5
6
#!/bin/bash
if test -e apikey; then
	cc -Ofast -Dds_apikey="\"$(cat apikey)\"" tenki.c -lssl -otenki
else
	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"
fi
|





1
2
3
4
5
6
#!/usr/bin/env bash
if test -e apikey; then
	cc -Ofast -Dds_apikey="\"$(cat apikey)\"" tenki.c -lssl -otenki
else
	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"
fi