Direct-BT v3.3.0-1-gc2d430c
Direct-BT - Direct Bluetooth Programming.
BTSecurityRegistry.java
Go to the documentation of this file.
1/**
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2020 Gothel Software e.K.
4 * Copyright (c) 2020 ZAFENA AB
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26package org.direct_bt;
27
28import java.nio.ByteOrder;
29import java.util.ArrayList;
30import java.util.Arrays;
31import java.util.Iterator;
32import java.util.List;
33
34import org.jau.net.EUI48;
35import org.jau.net.EUI48Sub;
36
37/**
38 * Application toolkit providing BT security setup and its device association
39 * on a pattern matching basis, i.e. EUI48Sub or name-sub.
40 */
41public class BTSecurityRegistry {
42 public static final int NO_PASSKEY = -1;
43
44 /**
45 * Entry specifying SMP security details associated to a device query via {@link EUI48Sub} or {@code nameSub}.
46 */
47 public static class Entry {
48 public EUI48Sub addrSub;
49 public String nameSub;
50
54 public int passkey = NO_PASSKEY;
55
56 public Entry(final EUI48Sub addrSub) {
57 this.addrSub = addrSub;
58 this.nameSub = "";
59 }
60 public Entry(final String nameSub) {
61 this.addrSub = EUI48Sub.ALL_DEVICE;
62 this.nameSub = nameSub;
63 }
64
65 public boolean isSecLevelOrIOCapSet() {
66 return SMPIOCapability.UNSET != io_cap || BTSecurityLevel.UNSET != sec_level;
67 }
69 public SMPIOCapability getIOCap() { return io_cap; }
70
71 public boolean isSecurityAutoEnabled() { return SMPIOCapability.UNSET != io_cap_auto; }
73
74 public int getPairingPasskey() { return passkey; }
75
76 public boolean getPairingNumericComparison() { return true; }
77
78 @Override
79 public String toString() {
80 final String id = EUI48Sub.ALL_DEVICE.equals(addrSub) ? "'"+nameSub+"'" : addrSub.toString();
81 return "BTSecurityDetail["+id+", lvl "+sec_level+", io "+io_cap+", auto-io "+io_cap_auto+", passkey "+passkey+"]";
82 }
83 }
84 static private List<BTSecurityRegistry.Entry> devicesSecDetails = new ArrayList<BTSecurityRegistry.Entry>();
85
86 /**
87 * Interface for user defined {@link EUI48} address and name {@link BTSecurityRegistry.Entry} matching criteria and algorithm.
88 */
89 public static interface AddressNameEntryMatch {
90 /**
91 * Return {@code true} if the given {@code address} or {@code name} matches
92 * with the {@link BTSecurityRegistry.Entry}.
93 *
94 * @param address {@link EUI48} address
95 * @param name optional name, maybe empty
96 * @param e {@link BTSecurityRegistry.Entry} entry
97 */
98 public boolean match(final EUI48 address, final String name, final BTSecurityRegistry.Entry e);
99 }
100 /**
101 * Interface for user defined {@link EUI48Sub} addressSub and name {@link BTSecurityRegistry.Entry} matching criteria and algorithm.
102 */
103 public static interface AddressSubNameEntryMatch {
104 /**
105 * Return {@code true} if the given {@code addressSub} or {@code name} matches
106 * with the {@link BTSecurityRegistry.Entry}.
107 *
108 * @param addressSub {@link EUI48Sub} address
109 * @param name optional name, maybe empty
110 * @param e {@link BTSecurityRegistry.Entry} entry
111 */
112 public boolean match(final EUI48Sub addressSub, final String name, final BTSecurityRegistry.Entry e);
113 }
114 /**
115 * Interface for user defined name {@link BTSecurityRegistry.Entry} matching criteria and algorithm.
116 */
117 public static interface NameEntryMatch {
118 /**
119 * Return {@code true} if the given {@code name} matches
120 * with the {@link BTSecurityRegistry.Entry}.
121 *
122 * @param name
123 * @param e {@link BTSecurityRegistry.Entry} entry
124 */
125 public boolean match(final String name, final BTSecurityRegistry.Entry e);
126 }
127
128 /**
129 * Returns a matching {@link BTSecurityRegistry.Entry} with the given {@code addr} and/or {@code name}
130 * <p>
131 * Matching criteria and algorithm is defined by the given {@link AddressNameEntryMatch}.
132 * </p>
133 */
134 public static BTSecurityRegistry.Entry get(final EUI48 addr, final String name, final AddressNameEntryMatch m) {
135 for(final Iterator<BTSecurityRegistry.Entry> i=devicesSecDetails.iterator(); i.hasNext(); ) {
136 final BTSecurityRegistry.Entry sd = i.next();
137 if( m.match(addr, name, sd) ) {
138 return sd;
139 }
140 }
141 return null;
142 }
143 /**
144 * Returns a matching {@link BTSecurityRegistry.Entry} with the given {@code addrSub} and/or {@code name}.
145 * <p>
146 * Matching criteria and algorithm is defined by the given {@link AddressSubNameEntryMatch}.
147 * </p>
148 */
149 public static BTSecurityRegistry.Entry get(final EUI48Sub addrSub, final String name, final AddressSubNameEntryMatch m) {
150 for(final Iterator<BTSecurityRegistry.Entry> i=devicesSecDetails.iterator(); i.hasNext(); ) {
151 final BTSecurityRegistry.Entry sd = i.next();
152 if( m.match(addrSub, name, sd) ) {
153 return sd;
154 }
155 }
156 return null;
157 }
158 /**
159 * Returns a matching {@link BTSecurityRegistry.Entry} with the given {@code name}.
160 * <p>
161 * Matching criteria and algorithm is defined by the given {@link NameEntryMatch}.
162 * </p>
163 */
164 public static BTSecurityRegistry.Entry get(final String name, final NameEntryMatch m) {
165 for(final Iterator<BTSecurityRegistry.Entry> i=devicesSecDetails.iterator(); i.hasNext(); ) {
166 final BTSecurityRegistry.Entry sd = i.next();
167 if( m.match(name, sd) ) {
168 return sd;
169 }
170 }
171 return null;
172 }
173
174 /**
175 * Returns a matching {@link BTSecurityRegistry.Entry},
176 * - which {@link BTSecurityRegistry.Entry#addrSub} is set and the given {@code addr} starts with {@link BTSecurityRegistry.Entry#addrSub}, or
177 * - which {@link BTSecurityRegistry.Entry#nameSub} is set and the given {@code name} starts with {@link BTSecurityRegistry.Entry#nameSub}.
178 *
179 * Otherwise {@code null} is returned.
180 */
181 public static BTSecurityRegistry.Entry getStartOf(final EUI48 addr, final String name) {
182 return get(addr, name, (final EUI48 a, final String n, final BTSecurityRegistry.Entry e) -> {
183 return ( e.addrSub.length > 0 && 0 == a.indexOf(e.addrSub, ByteOrder.BIG_ENDIAN) ) ||
184 (e.nameSub.length() > 0 && n.startsWith(e.nameSub) );
185 });
186 }
187 /**
188 * Returns a matching {@link BTSecurityRegistry.Entry},
189 * - which {@link BTSecurityRegistry.Entry#addrSub} is set and the given {@code addrSub} starts with {@link BTSecurityRegistry.Entry#addrSub}, or
190 * - which {@link BTSecurityRegistry.Entry#nameSub} is set and the given {@code name} starts with {@link BTSecurityRegistry.Entry#nameSub}.
191 *
192 * Otherwise {@code null} is returned.
193 */
194 public static BTSecurityRegistry.Entry getStartOf(final EUI48Sub addrSub, final String name) {
195 return get(addrSub, name, (final EUI48Sub as, final String n, final BTSecurityRegistry.Entry e) -> {
196 return ( e.addrSub.length > 0 && 0 == as.indexOf(e.addrSub, ByteOrder.BIG_ENDIAN) ) ||
197 ( e.nameSub.length() > 0 && n.startsWith(e.nameSub) );
198 });
199 }
200 /**
201 * Returns a matching {@link BTSecurityRegistry.Entry},
202 * - which {@link BTSecurityRegistry.Entry#nameSub} is set and the given {@code name} starts with {@link BTSecurityRegistry.Entry#nameSub}.
203 *
204 * Otherwise {@code null} is returned.
205 */
206 public static BTSecurityRegistry.Entry getStartOf(final String name) {
207 return get(name, (final String n, final BTSecurityRegistry.Entry e) -> {
208 return e.nameSub.length() > 0 && n.startsWith(e.nameSub);
209 });
210 }
211
212 /**
213 * Returns a matching {@link BTSecurityRegistry.Entry},
214 * - which {@link BTSecurityRegistry.Entry#addrSub} is set and the given {@code addrSub} is equal with {@link BTSecurityRegistry.Entry#addrSub}, or
215 * - which {@link BTSecurityRegistry.Entry#nameSub} is set and the given {@code name} is equal with {@link BTSecurityRegistry.Entry#nameSub}.
216 *
217 * Otherwise {@code null} is returned.
218 */
219 public static BTSecurityRegistry.Entry getEqual(final EUI48Sub addrSub, final String name) {
220 return get(addrSub, name, (final EUI48Sub as, final String n, final BTSecurityRegistry.Entry e) -> {
221 return ( e.addrSub.length > 0 && as.equals(e.addrSub) ) ||
222 ( e.nameSub.length() > 0 && n.equals(e.nameSub) );
223 });
224 }
225 /**
226 * Returns a matching {@link BTSecurityRegistry.Entry},
227 * - which {@link BTSecurityRegistry.Entry#nameSub} is set and the given {@code name} is equal with {@link BTSecurityRegistry.Entry#nameSub}.
228 *
229 * Otherwise {@code null} is returned.
230 */
231 public static BTSecurityRegistry.Entry getEqual(final String name) {
232 return get(name, (final String n, final BTSecurityRegistry.Entry e) -> {
233 return e.nameSub.length() > 0 && n.equals(e.nameSub);
234 });
235 }
236
237 /**
238 * Returns the reference of the current list of {@link BTSecurityRegistry.Entry}, not a copy.
239 */
240 public static List<BTSecurityRegistry.Entry> getEntries() {
241 return devicesSecDetails;
242 }
243
244 /**
245 * Determines whether the given {@code addrOrNameSub} is a {@link EUI48Sub} or just a {@code name}
246 * and retrieves an entry. If no entry exists, creates a new entry.
247 * <p>
248 * Implementation uses {@link #getEqual(EUI48Sub, String)} to find a pre-existing entry.
249 * </p>
250 * @param addrOrNameSub either a {@link EUI48Sub} or just a name
251 * @return new or existing instance
252 */
253 public static BTSecurityRegistry.Entry getOrCreate(final String addrOrNameSub) {
254 final EUI48Sub addr1 = new EUI48Sub();
255 final StringBuilder errmsg = new StringBuilder();
256 BTSecurityRegistry.Entry sec = null;
257 if( EUI48Sub.scanEUI48Sub(addrOrNameSub, addr1, errmsg) ) {
258 sec = getEqual(addr1, "");
259 if( null == sec ) {
260 sec = new BTSecurityRegistry.Entry( addr1 );
261 devicesSecDetails.add(sec);
262 }
263 } else {
264 sec = getEqual(addrOrNameSub);
265 if( null == sec ) {
266 sec = new BTSecurityRegistry.Entry( addrOrNameSub );
267 devicesSecDetails.add(sec);
268 }
269 }
270 return sec;
271 }
272
273 /**
274 * Clears internal list
275 */
276 public static void clear() {
277 devicesSecDetails.clear();
278 }
279
280 public static String allToString() {
281 return Arrays.toString( devicesSecDetails.toArray() );
282 }
283}
Entry specifying SMP security details associated to a device query via EUI48Sub or nameSub.
Application toolkit providing BT security setup and its device association on a pattern matching basi...
static BTSecurityRegistry.Entry getEqual(final EUI48Sub addrSub, final String name)
Returns a matching BTSecurityRegistry.Entry,.
static void clear()
Clears internal list.
static List< BTSecurityRegistry.Entry > getEntries()
Returns the reference of the current list of BTSecurityRegistry.Entry, not a copy.
static BTSecurityRegistry.Entry getEqual(final String name)
Returns a matching BTSecurityRegistry.Entry,.
static BTSecurityRegistry.Entry getStartOf(final EUI48Sub addrSub, final String name)
Returns a matching BTSecurityRegistry.Entry,.
static BTSecurityRegistry.Entry getStartOf(final EUI48 addr, final String name)
Returns a matching BTSecurityRegistry.Entry,.
static BTSecurityRegistry.Entry getStartOf(final String name)
Returns a matching BTSecurityRegistry.Entry,.
static BTSecurityRegistry.Entry getOrCreate(final String addrOrNameSub)
Determines whether the given addrOrNameSub is a EUI48Sub or just a name and retrieves an entry.
Bluetooth Security Level.
UNSET
Security Level not set, value 0.
SMP IO Capability value.
UNSET
Denoting unset value, i.e.
Interface for user defined EUI48 address and name BTSecurityRegistry.Entry matching criteria and algo...
boolean match(final EUI48 address, final String name, final BTSecurityRegistry.Entry e)
Return true if the given address or name matches with the BTSecurityRegistry.Entry.
Interface for user defined EUI48Sub addressSub and name BTSecurityRegistry.Entry matching criteria an...
boolean match(final EUI48Sub addressSub, final String name, final BTSecurityRegistry.Entry e)
Return true if the given addressSub or name matches with the BTSecurityRegistry.Entry.
Interface for user defined name BTSecurityRegistry.Entry matching criteria and algorithm.
boolean match(final String name, final BTSecurityRegistry.Entry e)
Return true if the given name matches with the BTSecurityRegistry.Entry.