KeyNub License Dongle
| (require keynub/licdongle) | package: keynub-licdongle |
Verify that a KeyNub License Dongle is genuine, read and write the license records it holds, use its hardware counters and seal data so that only a dongle can open it.
(require keynub/licdongle) (define secret (with-dongle (d) ; first dongle, or (d #:serial "...") (dongle-verify-genuine d) ; raises unless genuine (with-session d ; closed on every exit path (app-decrypt d sealed)))) ; build the licence check on this
The package calls the SDK’s flat C API from the native library keynub_licdongle_flat through ffi/unsafe. The library is loaded on the first call that needs it, so requiring the module and building this documentation work without it. Every function checks its arguments with a contract before it calls the library.
Read the SDK’s integration security notes before writing the check. (unless (dongle-genuine? d) (exit 1)) is one conditional branch, and patching one of those in a release binary is a beginner exercise. Route something the program needs through app-encrypt and app-decrypt, so removing the check removes the data.
1 Installation and the Native Library
raco pkg install keynub-licdongle
The package does not contain the native library. Take the file for your platform from the SDK’s natives folder. The package looks for it in this order:
the path given to set-library-path!;
the path in the environment variable KEYNUB_LICDONGLE_FLAT_LIBRARY;
natives/<platform>/<file name> in the folder of the running program, the current directory and the package’s own folder, and in each of their parent folders, where <platform> is one of win-x64, win-x86, win-arm64, linux-x64, linux-arm64, osx-x64 and osx-arm64;
the bare file name, for the system loader.
A process loads the library once. On Linux, install the udev rule described in the natives folder’s notes so the dongle is accessible without root.
procedure
procedure
(library-candidates) → (listof string?)
procedure
(set-library-path! path) → void?
path : path-string?
procedure
(library-path) → string?
procedure
(loaded-library-path) → (or/c string? #f)
struct
(struct lib-version (major minor patch) #:transparent) major : exact-integer? minor : exact-integer? patch : exact-integer?
procedure
2 Errors
struct
(struct exn:fail:keynub exn:fail (status code operation detail))
status : (or/c symbol? #f) code : exact-integer? operation : string? detail : string?
struct
procedure
(status-symbol code) → (or/c symbol? #f)
code : exact-integer?
procedure
(status-code name) → (or/c exact-integer? #f)
name : symbol?
procedure
(status-text code) → string?
code : (integer-in -2147483648 2147483647)
3 Finding and Opening a Dongle
procedure
(dongle-open [serial]) → dongle?
serial : (or/c string? #f) = #f
procedure
(dongle-open-path path) → dongle?
path : string?
procedure
(dongle-close d) → void?
d : dongle?
procedure
(dongle-open? d) → boolean?
d : dongle?
procedure
(call-with-dongle proc [ #:serial serial #:path path]) → any proc : (-> dongle? any) serial : (or/c string? #f) = #f path : (or/c string? #f) = #f
syntax
(with-dongle (id) body ...+)
(with-dongle (id #:serial serial-expr) body ...+) (with-dongle (id #:path path-expr) body ...+)
4 Information and Authenticity
procedure
(dongle-serial d) → string?
d : dongle?
struct
(struct device-info ( protocol-major protocol-minor firmware-major firmware-minor firmware-patch secure-element-ready? provisioned? watchdog-reboot? isolated? write-auth-rotated? data-capacity data-free) #:transparent) protocol-major : exact-integer? protocol-minor : exact-integer? firmware-major : exact-integer? firmware-minor : exact-integer? firmware-patch : exact-integer? secure-element-ready? : boolean? provisioned? : boolean? watchdog-reboot? : boolean? isolated? : boolean? write-auth-rotated? : boolean? data-capacity : exact-integer? data-free : exact-integer?
procedure
(dongle-info d) → device-info?
d : dongle?
struct
(struct verification (serial provisioned-date) #:transparent) serial : string? provisioned-date : string?
procedure
d : dongle?
procedure
(dongle-genuine? d) → boolean?
d : dongle?
procedure
(set-dongle-trust-root! d der) → void?
d : dongle? der : bytes?
procedure
(dongle-last-error d) → string?
d : dongle?
5 Sessions and the Write Role
Records, counters and app-data encryption need an authenticated session. Writing records, erasing them and incrementing counters also need the write role.
procedure
(session-open d) → void?
d : dongle?
procedure
(session-close d) → void?
d : dongle?
procedure
(call-with-session d thunk) → any
d : dongle? thunk : (-> any)
syntax
(with-session dongle-expr body ...+)
procedure
(authorize-write d key) → void?
d : dongle? key : bytes?
procedure
(rotate-write-key d key) → void?
d : dongle? key : bytes?
6 Records
struct
(struct record (name size) #:transparent) name : string? size : exact-integer?
procedure
(dongle-records d) → (listof record?)
d : dongle?
procedure
(read-record d name) → bytes?
d : dongle? name : string?
procedure
(write-record! d name data) → void?
d : dongle? name : string? data : bytes?
procedure
(erase-record! d name) → void?
d : dongle? name : string?
procedure
(erase-all-records! d) → void?
d : dongle?
7 Counters
procedure
(read-counter d counter-id) → exact-integer?
d : dongle? counter-id : (integer-in -2147483648 2147483647)
procedure
(increment-counter! d counter-id) → exact-integer?
d : dongle? counter-id : (integer-in -2147483648 2147483647)
8 App-Data Encryption
procedure
(app-encrypt d scope plaintext) → bytes?
d : dongle? scope : (or/c 'device 'developer) plaintext : bytes?
procedure
(app-decrypt d packed) → bytes?
d : dongle? packed : bytes?