28import java.io.FileInputStream;
29import java.io.FileOutputStream;
30import java.io.IOException;
31import java.io.InputStream;
32import java.io.OutputStream;
33import java.nio.ByteOrder;
34import java.text.SimpleDateFormat;
37import org.direct_bt.SMPKeyMask.KeyType;
38import org.jau.io.PrintUtil;
39import org.jau.net.EUI48;
40import org.jau.sys.Clock;
76 public static final short VERSION = (short)0b0101010101010101 + (
short)6;
78 private short version;
80 private long ts_creation_sec;
100 private static final int byte_size_max = 205;
101 private static final int byte_size_min = 31;
103 boolean verbose =
true;
105 final private short calcSize() {
233 final boolean overwrite = PairingMode.PRE_PAIRED != device.
getPairingMode();
234 return smpKeyBin.
write( path, overwrite );
237 PrintUtil.println(System.err,
"Create SMPKeyBin: Invalid "+smpKeyBin+
", "+device);
261 smpKeyBin.
read( fname );
292 this.ts_creation_sec = Clock.wallClockSeconds();
293 this.localRole = localRole_;
294 this.localAddress = localAddress_;
295 this.remoteAddress = remoteAddress_;
296 this.sec_level = sec_level_;
297 this.io_cap = io_cap_;
312 this.size = calcSize();
426 final public void setVerbose(
final boolean v) { verbose = v; }
430 final boolean local_is_responder =
BTRole.
Slave.equals(localRole);
431 final BDAddressAndType responderAddress = local_is_responder ? localAddress : remoteAddress;
432 final BDAddressAndType initiatorAddress = local_is_responder ? remoteAddress : localAddress;
435 BTSecurityLevel.UNSET != sec_level &&
436 SMPIOCapability.UNSET != io_cap &&
449 final String r =
"bd_"+localAddress.
address.toString()+
"_"+remoteAddress.
address.toString()+remoteAddress.
type.
value+
".key";
450 return r.replace(
":",
"");
456 final String r =
"bd_"+localAddress_.
address.toString()+
"_"+remoteAddress_.
address.toString()+remoteAddress_.
type.
value+
".key";
457 return r.replace(
":",
"");
466 return getFilename(path, localAddress, remoteAddress);
471 final StringBuilder res =
new StringBuilder();
472 res.append(
"SMPKeyBin[local[").append(localRole.toString()).append(
", ").append(localAddress.
toString()).append(
"], remote ").append(remoteAddress.
toString()).append(
", SC ").append(
uses_SC()).append(
", sec ").append(sec_level).append(
", io ").append(io_cap).append(
", ");
474 boolean comma =
false;
502 res.append(
"], Resp[");
530 res.append(
"ver[0x").append(Integer.toHexString(version)).append(
", ok ").append(
isVersionValid()).append(
"], size[").append(size);
532 res.append(
", calc ").append(calcSize());
534 res.append(
", valid ").append(
isSizeValid()).append(
"], ");
536 final SimpleDateFormat sdf =
new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss");
537 final Date d =
new Date(ts_creation_sec*1000);
538 res.append(sdf.format(d));
540 res.append(
", valid ").append(
isValid()).append(
"]");
542 return res.toString();
545 final private static boolean remove_impl(
final String fname) {
546 final File file =
new File( fname );
548 return file.delete();
549 }
catch (
final Exception ex) {
550 PrintUtil.println(System.err,
"Remove SMPKeyBin: Failed "+fname+
": "+ex.getMessage());
551 ex.printStackTrace();
555 final public static boolean remove(
final String path,
final BTDevice remoteDevice_) {
556 return remove(path, remoteDevice_.getAdapter().getAddressAndType(), remoteDevice_.getAddressAndType());
559 return remove_impl(
getFilename(path, localAddress_, remoteAddress_) );
561 final public boolean remove(
final String path) {
565 final public boolean write(
final String path,
final boolean overwrite) {
567 PrintUtil.println(System.err,
"Write SMPKeyBin: Invalid (skipped) "+
toString());
571 final File file =
new File( fname );
572 OutputStream out =
null;
574 if( file.exists() ) {
576 if( !file.delete() ) {
577 PrintUtil.println(System.err,
"Write SMPKeyBin: Failed deletion of existing file "+fname+
": "+
toString());
581 PrintUtil.println(System.err,
"Write SMPKeyBin: Not overwriting existing file "+fname+
": "+
toString());
585 final byte[] buffer =
new byte[byte_size_max];
587 out =
new FileOutputStream(file);
588 out.write( (
byte) version );
589 out.write( (
byte)( version >> 8 ) );
590 out.write( (
byte) size );
591 out.write( (
byte)( size >> 8 ) );
593 writeLong(ts_creation_sec, out, buffer);
594 out.write(localRole.
value);
596 localAddress.
address.put(buffer, 0, ByteOrder.LITTLE_ENDIAN);
597 out.write(buffer, 0, localAddress.
address.b.length);
601 remoteAddress.
address.put(buffer, 0, ByteOrder.LITTLE_ENDIAN);
602 out.write(buffer, 0, remoteAddress.
address.b.length);
605 out.write(sec_level.
value);
606 out.write(io_cap.
value);
608 out.write(keys_init.
mask);
609 out.write(keys_resp.
mask);
612 ltk_init.
put(buffer, 0);
616 irk_init.
put(buffer, 0);
620 csrk_init.
put(buffer, 0);
624 lk_init.
put(buffer, 0);
629 ltk_resp.
put(buffer, 0);
633 irk_resp.
put(buffer, 0);
637 csrk_resp.
put(buffer, 0);
641 lk_resp.
put(buffer, 0);
646 PrintUtil.println(System.err,
"Write SMPKeyBin: "+fname+
": "+
toString());
649 }
catch (
final Exception ex) {
650 PrintUtil.println(System.err,
"Write SMPKeyBin: Failed "+fname+
": "+
toString()+
": "+ex.getMessage());
651 ex.printStackTrace();
657 }
catch (
final IOException e) {
664 final public boolean read(
final String fname) {
665 final File file =
new File(fname);
666 InputStream in =
null;
670 if( !file.canRead() ) {
672 PrintUtil.println(System.err,
"Read SMPKeyBin: Failed "+fname+
": Not existing or readable: "+
toString());
677 final byte[] buffer =
new byte[byte_size_max];
678 in =
new FileInputStream(file);
679 read(in, buffer, byte_size_min, fname);
682 version = (short) ( ( buffer[i++] & 0xff ) | ( ( buffer[i++] & 0xff ) << 8 ) );
683 size = (short) ( ( buffer[i++] & 0xff ) | ( ( buffer[i++] & 0xff ) << 8 ) );
685 remaining = size - 2 - 2 ;
687 if( !err && 8 <= remaining ) {
688 ts_creation_sec = getLong(buffer, i); i+=8;
693 if( !err && 1+7+7+4 <= remaining ) {
695 localAddress.address =
new EUI48(buffer, i, ByteOrder.LITTLE_ENDIAN); i+=6;
697 remoteAddress.address =
new EUI48(buffer, i, ByteOrder.LITTLE_ENDIAN); i+=6;
701 keys_init.mask = buffer[i++];
702 keys_resp.mask = buffer[i++];
704 remaining -= 1+7+7+4;
712 ltk_init.
get(buffer, 0);
721 irk_init.
get(buffer, 0);
730 csrk_init.
get(buffer, 0);
739 lk_init.
get(buffer, 0);
749 ltk_resp.
get(buffer, 0);
758 irk_resp.
get(buffer, 0);
767 csrk_resp.
get(buffer, 0);
776 lk_resp.
get(buffer, 0);
786 }
catch (
final Exception ex) {
787 PrintUtil.println(System.err,
"Read SMPKeyBin: Failed "+fname+
": "+
toString()+
": "+ex.getMessage());
788 ex.printStackTrace();
795 }
catch (
final IOException e) {
802 PrintUtil.println(System.err,
"Read SMPKeyBin: Failed "+fname+
" (removed): "+
toString()+
", remaining "+remaining);
807 PrintUtil.println(System.err,
"Read SMPKeyBin: OK "+fname+
": "+
toString()+
", remaining "+remaining);
812 final static private int read(
final InputStream in,
final byte[] buffer,
final int rsize,
final String fname)
throws IOException {
813 final int read_count = in.
read(buffer, 0, rsize);
814 if( read_count != rsize ) {
815 throw new IOException(
"Couldn't read "+rsize+
" bytes, only "+read_count+
" from "+fname);
819 final static private long getLong(
final byte[] buffer,
final int offset)
throws IOException {
821 for (
int j = 0; j < 8; ++j) {
822 res |= ((long) buffer[offset+j] & 0xff) << j*8;
826 final static private void writeLong(
final long value,
final OutputStream out,
final byte[] buffer)
throws IOException {
827 for (
int i = 0; i < 8; ++i) {
828 buffer[i] = (byte) (value >> i*8);
830 out.write(buffer, 0, 8);
833 public static void main(
final String[] args) {
836 boolean verbose=
false;
837 for(
int i=0; i< args.length; i++) {
838 final String arg = args[i];
839 if( arg.equals(
"-verbose") || arg.equals(
"-v") ) {
843 System.err.println(
"Read: '"+arg+
"'");
Unique Bluetooth EUI48 address and BDAddressType tuple.
One stop BTManager API entry point.
static synchronized void initDirectBTLibrary()
Preloads the DirectBT native library w/o instantiating BTManager.
SMP Identity Resolving Key, used for platform agnostic persistence.
EUI48 id_address
Identity Address for the IRK.
static final int byte_size
Size of the byte stream representation in bytes.
void get(final byte[] source, int pos)
Method transfers all bytes representing a SMPIdentityResolvingKeyInfo from the given source array at ...
final void put(final byte[] sink, int pos)
Method transfers all bytes representing this instance into the given destination array at the given p...
Storage for SMP keys including required connection parameter per local adapter and remote device.
final boolean uses_SC()
Return whether Secure Connection (SC) is being used via LTK keys.
final SMPIOCapability getIOCap()
final void setLKResp(final SMPLinkKey v)
static SMPKeyBin read(final String fname, final boolean verbose_)
Create a new SMPKeyBin instance based upon stored file denoted by fname.
final boolean hasIRKInit()
final boolean isVersionValid()
final void setLTKResp(final SMPLongTermKey v)
final boolean write(final String path, final boolean overwrite)
final BDAddressAndType getRemoteAddrAndType()
Return the remote device address.
final BDAddressAndType getLocalAddrAndType()
Return the local adapter address.
final static String getFilename(final String path, final BTDevice remoteDevice)
final boolean hasLKResp()
final SMPLongTermKey getLTKResp()
final void setVerbose(final boolean v)
final boolean hasCSRKResp()
final void setCSRKResp(final SMPSignatureResolvingKey v)
final SMPSignatureResolvingKey getCSRKResp()
static final short VERSION
final boolean hasLTKResp()
final boolean hasLKInit()
final void setIRKInit(final SMPIdentityResolvingKey v)
final boolean hasLTKInit()
SMPKeyBin(final BTRole localRole_, final BDAddressAndType localAddress_, final BDAddressAndType remoteAddress_, final BTSecurityLevel sec_level_, final SMPIOCapability io_cap_)
final SMPSignatureResolvingKey getCSRKInit()
final BTRole getLocalRole()
Return the local adapter BTRole.
static SMPKeyBin create(final BTDevice device)
Create a new SMPKeyBin instance based upon given BTDevice's BTSecurityLevel, SMPPairingState,...
final SMPLinkKey getLKInit()
final SMPLinkKey getLKResp()
final BTSecurityLevel getSecLevel()
final void setCSRKInit(final SMPSignatureResolvingKey v)
final String getFileBasename()
Returns the base filename, see SMPKeyBin API doc for naming scheme.
static SMPKeyBin read(final String path, final BTDevice device, final boolean verbose_)
Create a new SMPKeyBin instance based upon the given BTDevice's matching filename,...
final static String getFilename(final String path, final BDAddressAndType localAddress_, final BDAddressAndType remoteAddress_)
final void setLTKInit(final SMPLongTermKey v)
final void setIRKResp(final SMPIdentityResolvingKey v)
static boolean createAndWrite(final BTDevice device, final String path, final boolean verbose_)
Create a new SMPKeyBin instance on the fly based upon given BTDevice's BTSecurityLevel,...
final String getFilename(final String path)
final SMPIdentityResolvingKey getIRKResp()
final SMPLongTermKey getLTKInit()
static void main(final String[] args)
final boolean isSizeValid()
final static String getFileBasename(final BDAddressAndType localAddress_, final BDAddressAndType remoteAddress_)
Returns the base filename, see SMPKeyBin API doc for naming scheme.
final boolean hasCSRKInit()
final SMPIdentityResolvingKey getIRKInit()
final boolean hasIRKResp()
final long getCreationTime()
Returns the creation timestamp in seconds since Unix epoch.
final boolean read(final String fname)
final void setLKInit(final SMPLinkKey v)
SMP Key Type for Distribution, indicates keys distributed in the Transport Specific Key Distribution ...
void set(final KeyType bit)
byte mask
The KeyType bit mask.
boolean isSet(final KeyType bit)
Local SMP Link Key, used for platform agnostic persistence, mapping to platform specific link keys fo...
void get(final byte[] source, int pos)
Method transfers all bytes representing a SMPLinkKeyInfo from the given source array at the given pos...
static final int byte_size
Size of the byte stream representation in bytes.
final void put(final byte[] sink, int pos)
Method transfers all bytes representing this instance into the given destination array at the given p...
boolean isSet(final PropertyType bit)
SMP Long Term Key, used for platform agnostic persistence.
void get(final byte[] source, int pos)
Method transfers all bytes representing a SMPLongTermKeyInfo from the given source array at the given...
Properties properties
Properties bit mask.
static final int byte_size
Size of the byte stream representation in bytes (28)
final void put(final byte[] sink, int pos)
Method transfers all bytes representing this instance into the given destination array at the given p...
SMP Signature Resolving Key, used for platform agnostic persistence.
final void put(final byte[] sink, int pos)
Method transfers all bytes representing this instance into the given destination array at the given p...
static final int byte_size
Size of the byte stream representation in bytes.
void get(final byte[] source, int pos)
Method transfers all bytes representing a SMPSignatureResolvingKeyInfo from the given source array at...
Bluetooth address type constants.
static BDAddressType get(final String name)
Maps the specified name to a constant of BDAddressType.
Bluetooth roles from the perspective of the link layer (connection initiator).
static BTRole get(final String name)
Maps the specified name to a constant of BTRole.
Slave
Slave or peripheral role, advertising and waiting for connections to accept.
Bluetooth Security Level.
UNSET
Security Level not set, value 0.
NONE
No encryption and no authentication.
static BTSecurityLevel get(final String name)
Maps the specified name to a constant of BTSecurityLevel.
Bluetooth secure pairing mode.
NEGOTIATING
Pairing mode in negotiating, i.e.
NONE
No pairing mode, implying no secure connections, no encryption and no MITM protection.
UNSET
Denoting unset value, i.e.
static SMPIOCapability get(final String name)
Maps the specified name to a constant of SMPIOCapability.
LINK_KEY
SMP on the LE transport: Indicate that the device would like to derive the Link Key from the LTK.
ID_KEY
Indicates that the device shall distribute IRK using the Identity Information command followed by its...
SIGN_KEY
Indicates that the device shall distribute CSRK using the Signing Information command.
ENC_KEY
LE legacy pairing: Indicates device shall distribute LTK using the Encryption Information command,...
SMPLongTermKey Property Bits
SC
Secure Connection used.
SMP Pairing Process state definition.
NONE
No pairing in process.
COMPLETED
Phase 3: Key & value distribution completed by responding (slave) device sending SMPIdentInfoMsg (#1)...
BDAddressAndType getAddressAndType()
Returns the adapter's public BDAddressAndType.
BTRole getRole()
Return the current BTRole of this adapter.
BTDevice represents one remote Bluetooth device.
BTAdapter getAdapter()
Returns the adapter on which this device was discovered or connected.
BTSecurityLevel getConnSecurityLevel()
Return the BTSecurityLevel, determined when the connection is established.
SMPLinkKey getLinkKey(final boolean responder)
Returns a copy of the Link Key (LK), valid after connection and SMP pairing has been completed.
SMPIdentityResolvingKey getIdentityResolvingKey(final boolean responder)
Returns a copy of the Identity Resolving Key (IRK), valid after connection and SMP pairing has been c...
SMPKeyMask getAvailableSMPKeys(final boolean responder)
Returns the available SMPKeyMask.KeyType SMPKeyMask for the responder (LL slave) or initiator (LL mas...
SMPPairingState getPairingState()
Returns the current SMPPairingState.
SMPIOCapability getConnIOCapability()
Return the SMPIOCapability value, determined when the connection is established.
SMPSignatureResolvingKey getSignatureResolvingKey(final boolean responder)
Returns a copy of the Signature Resolving Key (CSRK), valid after connection and SMP pairing has been...
PairingMode getPairingMode()
Returns the current PairingMode used by the device.
BDAddressAndType getAddressAndType()
Returns the devices' unique EUI48 address and BDAddressType type tuple, might be its initially report...
SMPLongTermKey getLongTermKey(final boolean responder)
Returns a copy of the long term key (LTK), valid after connection and SMP pairing has been completed.