I've used this for dualboot-systems because I didn't want to
pair the devices every time I've switched systems.
Currently it exports the keys using the old bluez format with files
named 'link_key' and 'linkkeys'. To use it with newer versions of bluez
it has either to be modified or someone has to write an import.
---
tools/windows/BTWinLinkKeyExport.cpp | 210 ++++++++++++++++++++++++++++++++++
1 files changed, 210 insertions(+), 0 deletions(-)
create mode 100644 tools/windows/BTWinLinkKeyExport.cpp
diff --git a/tools/windows/BTWinLinkKeyExport.cpp b/tools/windows/BTWinLinkKeyExport.cpp
new file mode 100644
index 0000000..deadabe
--- /dev/null
+++ b/tools/windows/BTWinLinkKeyExport.cpp
@@ -0,0 +1,210 @@
+//
+// BTWinLinkKeyExport.cpp
+//
+// Exports bluetooth-link-keys stored by the WIDCOMM stack for use with
+// Dual- or Multi-booting systems.
+//
+// Written 2004 by Alexander Holler.
+//
+// This source is free in every aspect. You can use, modify, distribute
+// or sell it at your wish. You can even replace my name with yours if
+// that would earn you some credits you otherwise wouldn't get.
+//
+// No warrantys are given. This software might destroy your hardware,
+// software or datas.
+//
+// This software uses functions like sscanf() and such bad things,
+// feel free to make it safe up to point your security-officer wants it.
+//
+// To compile it I've used the free Borland Compiler, but it should work using
+// any compiler. For bcc I've used the following few lines:
+//
+// path=%path%;d:\Programme\Borland\Bcc55\bin
+// bcc32 -O2 -DNDEBUG -c BTWinLinkKeyExport.cpp
+// bcc32 -O2 -DNDEBUG BTWinLinkKeyExport.obj
+//
+// (WIDCOMM is a registered trademark of WIDCOMM Inc. and
+// Borland is a trademark of Borland Software Corporation)
+//
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <string>
+
+#include <windows.h>
+#include <wincrypt.h>
+
+typedef unsigned char uint8_t;
+
+#pragma pack(1)
+
+typedef struct {
+ uint8_t b[6];
+} bdaddr_t;
+
+#pragma pack(4)
+
+struct link_key {
+ bdaddr_t sba; // Dongle address
+ bdaddr_t dba; // external Device address
+ uint8_t key[16];
+ uint8_t type;
+ time_t time;
+};
+
+#pragma pack()
+
+static char* local_device;
+
+static void displayLastError(void)
+{
+ LPVOID lpMsgBuf;
+ DWORD msgid=GetLastError();
+ if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, msgid, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf, 0, NULL ))
+ return;
+ fprintf(stderr, "Error %u: %s\n", msgid, lpMsgBuf);
+ LocalFree( lpMsgBuf );
+}
+
+static int exportKey(const char* regkeyname, HCRYPTPROV& hProv, FILE* file,
+ FILE* file2)
+{
+ // This function tries to read the registry entry linkkey, decrypts it and
+ // writes an entry to the link-key-file for linux
+ std::string s=std::string("SOFTWARE\\Widcomm\\BTConfig\\Devices\\") +
+ regkeyname;
+ HKEY rKey=NULL;
+ long rc=RegOpenKeyEx(HKEY_LOCAL_MACHINE, s.c_str(), 0, KEY_READ, &rKey);
+ if(rc!=ERROR_SUCCESS) {
+ LPVOID lpMsgBuf;
+ if(!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, rc, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf,
+ 0, NULL ))
+ return 0;
+ fprintf(stderr, "Error %u: %s\n", rc, lpMsgBuf);
+ LocalFree( lpMsgBuf );
+ return 1;
+ }
+ BYTE keybuf[1024]; // I'm lazy, fixed size
+ DWORD keybuflen=sizeof(keybuf);
+ DWORD type;
+ rc=RegQueryValueEx(rKey, "LinkKey", NULL, &type, keybuf, &keybuflen);
+ RegCloseKey(rKey);
+ if(rc!=ERROR_SUCCESS)
+ return 0; // No error, just no link key
+ // If anyone wants to implement boundary checks for keybuf,
+ // he has my permissions. ;)
+ DWORD dwDataLen=*((DWORD*)(keybuf+4));
+ unsigned char *importkey=keybuf+8;
+ HCRYPTKEY hKey = NULL;
+ if(!CryptImportKey(hProv, importkey, dwDataLen, 0, 0, &hKey)) {
+ displayLastError();
+ return 2;
+ }
+ unsigned char* realkey=importkey+dwDataLen+4;
+ DWORD dwDataLen2=*((DWORD*)(realkey-4));
+ BYTE* newkey=(BYTE*)malloc(dwDataLen2);
+ memcpy(newkey, realkey, dwDataLen2);
+ if(!CryptDecrypt(hKey, 0, 1, 0, newkey, &dwDataLen2 )) {
+ displayLastError();
+ CryptDestroyKey(hKey);
+ return 3;
+ }
+ CryptDestroyKey(hKey);
+ struct link_key lkey;
+ memset(&lkey, 0, sizeof(lkey));
+ unsigned adr[6];
+ if(sscanf(regkeyname, "%x:%x:%x:%x:%x:%x", &adr[0], &adr[1], &adr[2],
+ &adr[3],&adr[4], &adr[5])!= 6)
+ return 4;
+ for(int i=0; i<6; i++)
+ lkey.dba.b[5-i]=adr[i];
+ if(sscanf(local_device, "%x:%x:%x:%x:%x:%x", &adr[0], &adr[1], &adr[2],
+ &adr[3],&adr[4], &adr[5])!= 6)
+ return 5;
+ for(int i=0; i<6; i++)
+ lkey.sba.b[5-i]=adr[i];
+ for(int i=0; i<16; i++)
+ lkey.key[i]=newkey[dwDataLen2-1-i];
+ lkey.time=time(NULL); // We are faking as this is not needed for operation
+ lkey.type=0; // I don't know the types, but my devices are all having 0
+ if(fwrite(&lkey, sizeof(lkey), 1, file)!=1)
+ return 6;
+ for(int i=0; i<17; i++)
+ // I haven't checked if bluez treads them case insensitiv, so we are
+ // exporting them like they were originally found in bluez (uppercase)
+ fprintf(file2, "%c", toupper(regkeyname[i]));
+ fprintf(file2, " ");
+ for(int i=0; i<16; i++)
+ fprintf(file2, "%02X", lkey.key[i]);
+ fprintf(file2, " 0%c", 0x0a);
+ printf("Link key for %s exported.\n", regkeyname);
+ return 0;
+}
+
+static void showHelp(void)
+{
+ printf("\nBTLinkKeyExport V1.0\nWritten 2004 Alexander Holler\n"
+ "Free in every aspect. See the source for details.\n\n");
+ printf(" Usage: BTLinkKeyExport localDeviceMAC\n");
+ printf(" Where localDeviceMAC is in the form xx:xx:xx:xx:xx:xx\n");
+}
+
+int main(int argc, char **argv)
+{
+ if(argc!=2) {
+ showHelp();
+ return 1;
+ }
+ if(strlen(argv[1])!=17) {
+ showHelp();
+ return 2;
+ }
+ local_device=argv[1];
+ FILE* file=fopen("link_key", "wb");
+ if(!file) {
+ fprintf(stderr, "Unable to open file 'link_key' for writing!\n");
+ return 3;
+ }
+ FILE* file2=fopen("linkkeys", "wb");
+ if(!file2) {
+ fprintf(stderr, "Unable to open file 'linkkeys' for writing!\n");
+ return 3;
+ }
+ const char* provider="Microsoft Base Cryptographic Provider v1.0";
+ const char* container="Widcomm Bluetooth Key Container Name";
+ HCRYPTPROV hProv = NULL;
+ if(!CryptAcquireContext(&hProv, container, provider, 1 /* dwProviderType */,
+ 0x20 /* dwFlags */ )) {
+ displayLastError();
+ fclose(file);
+ return 4;
+ }
+ HKEY rKey;
+ RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Widcomm\\BTConfig\\Devices", 0,
+ KEY_READ, &rKey);
+ int ret=0;
+ for(unsigned i=0; ; i++) {
+ char rkeyname[255];
+ DWORD rkeynamelen=sizeof(rkeyname);
+ FILETIME ftLastWriteTime;
+ int rc=RegEnumKeyEx(rKey, i, rkeyname, &rkeynamelen, NULL, NULL, NULL,
+ &ftLastWriteTime);
+ if(rc!=ERROR_SUCCESS)
+ break;
+ ret=exportKey(rkeyname, hProv, file, file2);
+ if(ret) {
+ ret+=4;
+ break; // An error occured
+ }
+ }
+ RegCloseKey(rKey);
+ CryptReleaseContext(hProv, 0);
+ fclose(file);
+ return ret;
+}
--
1.6.0.4
Hi lUiz,
Luiz Augusto von Dentz schrieb:
> Im afraid this is not really useful anymore, at least not if you
> expect to things like the new gnome-bluetooth to work since bluetoothd
> needs the sdp records the device export in order to probe the driver
> which takes care of profiles. In other words profiles won't just work
> because you got the linkkey. Despite this I don't think such thing
> belongs to BlueZ codebase, nobody will be going to maintain a windows
> c++ source code.
I don't care. I just wanted to post that thing, if someone else is
interested. I've asked some years ago, and nobody really answered, so it
rested somewhere in my source-directories, seldom used (just) by me and
got forgotten. Now it has at least found a place in the mailing-list
here and I have a clear conscience having it (finally) published.
Kind regards,
Alexander Holler
Hi Alexander,
On Fri, May 22, 2009 at 10:38 AM, Alexander Holler <[email protected]> wrote:
> I've used this for dualboot-systems because I didn't want to
> pair the devices every time I've switched systems.
>
> Currently it exports the keys using the old bluez format with files
> named 'link_key' and 'linkkeys'. To use it with newer versions of bluez
> it has either to be modified or someone has to write an import.
Im afraid this is not really useful anymore, at least not if you
expect to things like the new gnome-bluetooth to work since bluetoothd
needs the sdp records the device export in order to probe the driver
which takes care of profiles. In other words profiles won't just work
because you got the linkkey. Despite this I don't think such thing
belongs to BlueZ codebase, nobody will be going to maintain a windows
c++ source code.
--
Luiz Augusto von Dentz
Engenheiro de Computa??o