YARP
Yet Another Robot Platform
AuthHMAC.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3 * SPDX-FileCopyrightText: 2010 Daniel Krieg <krieg@fias.uni-frankfurt.de>
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
8
9#include <yarp/os/Bytes.h>
10#include <yarp/os/Network.h>
11#include <yarp/os/Property.h>
15
16#include <cstdio>
17#include <cstdlib>
18#include <cstring>
19#include <ctime>
20#include <random>
21#include <string>
22
23namespace {
24YARP_OS_LOG_COMPONENT(AUTHHMAC, "yarp.os.impl.AuthHMAC")
25} // namespace
26
27void show_hmac_debug(unsigned char* hex, unsigned int length, const std::string& context)
28{
29 char* buf;
30 int off = context.length();
31 buf = new char[length * 3 + off + 2];
32 strcpy(buf, context.c_str());
33 for (unsigned int i = 0; i < length; i++) {
34 sprintf(&(buf[off + i * 3]), "%X ", hex[i]);
35 }
36 yCDebug(AUTHHMAC, "%s\n", buf);
37 delete[] buf;
38}
39
40using namespace yarp::os::impl;
41using namespace yarp::os;
42
43AuthHMAC::AuthHMAC() :
44 authentication_enabled(false)
45{
46 memset(&context, 0, sizeof(HMAC_CONTEXT));
47 static bool auth_warning_shown = false;
48 if (auth_warning_shown) {
49 // If the warning was already shown, we have nothing to do.
50 // return as soon as possible
51 return;
52 }
53 std::string key;
55 std::string fname;
59 fname = rf.findFile("auth.conf", opt);
61
62
63 if (fname.empty()) {
64 yCDebug(AUTHHMAC, "Cannot find auth.conf file. Authentication disabled.\n");
65 auth_warning_shown = true;
66 return;
67 }
68
69 Property config;
70 config.fromConfigFile(fname);
71 Bottle group = config.findGroup("AUTH");
72
73 if (group.isNull()) {
74 yCWarning(AUTHHMAC, "No \"AUTH\" group found in auth.conf file. Authentication disabled.\n");
75 auth_warning_shown = true;
76 return;
77 }
78
79 key = group.find("key").asString();
80 if (!(key.length() > 0)) {
81 yCWarning(AUTHHMAC, "No \"key\" found in \"AUTH\" group in auth.conf file. Authentication disabled.\n");
82 auth_warning_shown = true;
83 return;
84 }
85
86 size_t key_len = key.length();
87 auto* tmp = new unsigned char[key_len];
88 strcpy(reinterpret_cast<char*>(tmp), key.c_str());
89 HMAC_INIT(&context, tmp, static_cast<unsigned int>(key_len));
90 delete[] tmp;
91 srand(static_cast<unsigned>(time(nullptr)));
92
93 if (!authentication_enabled) {
94 yCInfo(AUTHHMAC, "Authentication enabled.\n");
95 authentication_enabled = true;
96 }
97}
98
99
101{
102
103 if (!authentication_enabled) {
104 return true;
105 }
106
107 /* ---------------
108 * 3-way auth
109 * Port A
110 * ---------------
111 */
112
113 unsigned char nonce1[NONCE_LEN];
114 unsigned char nonce2[NONCE_LEN];
115 unsigned char nonce3[NONCE_LEN];
116
117 unsigned char mac[DIGEST_SIZE];
118 unsigned char mac_check[DIGEST_SIZE];
119
120 /* ---------------
121 * Send first msg: A->B
122 */
123 fill_nonce(nonce1);
124 HMAC_REINIT(&context);
125 HMAC_UPDATE(&context, nonce1, NONCE_LEN);
126 HMAC_FINAL(&context, mac, DIGEST_SIZE);
127 if (!send_hmac(streamOut, nonce1, mac)) {
128 return false;
129 }
130
131 /* ---------------
132 * Receive and check second msg: B->A
133 */
134 if (!receive_hmac(streamIn, nonce2, mac)) {
135 return false;
136 }
137
138 HMAC_REINIT(&context);
139 HMAC_UPDATE(&context, nonce1, NONCE_LEN);
140 HMAC_UPDATE(&context, nonce2, NONCE_LEN);
141 HMAC_FINAL(&context, mac_check, DIGEST_SIZE);
142 if (!check_hmac(mac, mac_check)) {
143 return false;
144 }
145 /* Authentication of B successful */
146
147
148 /* ---------------
149 * Send third msg: A->B
150 */
151 fill_nonce(nonce3);
152 HMAC_REINIT(&context);
153 HMAC_UPDATE(&context, nonce1, NONCE_LEN);
154 HMAC_UPDATE(&context, nonce2, NONCE_LEN);
155 HMAC_UPDATE(&context, nonce3, NONCE_LEN);
156 HMAC_FINAL(&context, mac, DIGEST_SIZE);
157 return send_hmac(streamOut, nonce3, mac);
158}
159bool AuthHMAC::authDest(InputStream* streamIn, OutputStream* streamOut)
160{
161
162 if (!authentication_enabled) {
163 return true;
164 }
165
166 /* ---------------
167 * 3-way auth
168 * Port B
169 * ---------------
170 */
171
172 unsigned char nonce1[NONCE_LEN];
173 unsigned char nonce2[NONCE_LEN];
174 unsigned char nonce3[NONCE_LEN];
175
176 unsigned char mac[DIGEST_SIZE];
177 unsigned char mac_check[DIGEST_SIZE];
178
179 /* ---------------
180 * Receive and check first msg: A->B
181 */
182 if (!receive_hmac(streamIn, nonce1, mac)) {
183 return false;
184 }
185 HMAC_REINIT(&context);
186 HMAC_UPDATE(&context, nonce1, NONCE_LEN);
187 HMAC_FINAL(&context, mac_check, DIGEST_SIZE);
188 if (!check_hmac(mac, mac_check)) {
189 return false;
190 }
191
192 /* ---------------
193 * Send second msg: B->A
194 */
195 fill_nonce(nonce2);
196 HMAC_REINIT(&context);
197 HMAC_UPDATE(&context, nonce1, NONCE_LEN);
198 HMAC_UPDATE(&context, nonce2, NONCE_LEN);
199 HMAC_FINAL(&context, mac, DIGEST_SIZE);
200 if (!send_hmac(streamOut, nonce2, mac)) {
201 return false;
202 }
203
204
205 /* ---------------
206 * Receive and check third msg: A->B
207 */
208 if (!receive_hmac(streamIn, nonce3, mac)) {
209 return false;
210 }
211 HMAC_REINIT(&context);
212 HMAC_UPDATE(&context, nonce1, NONCE_LEN);
213 HMAC_UPDATE(&context, nonce2, NONCE_LEN);
214 HMAC_UPDATE(&context, nonce3, NONCE_LEN);
215 HMAC_FINAL(&context, mac_check, DIGEST_SIZE);
216 if (!check_hmac(mac, mac_check)) {
217 return false;
218 }
219 /* Authentication of A successful */
220
221 return true;
222}
223
224
225bool AuthHMAC::send_hmac(OutputStream* stream, unsigned char* nonce, unsigned char* mac)
226{
227 Bytes nonce_bytes(reinterpret_cast<char*>(nonce), NONCE_LEN);
228 Bytes mac_bytes(reinterpret_cast<char*>(mac), DIGEST_SIZE);
229 stream->write(nonce_bytes);
230 stream->write(mac_bytes);
231
232 show_hmac_debug(nonce, NONCE_LEN, "send nonce ");
233 show_hmac_debug(mac, DIGEST_SIZE, "send digest ");
234
235 return stream->isOk();
236}
237
238bool AuthHMAC::receive_hmac(InputStream* stream, unsigned char* nonce, unsigned char* mac)
239{
240 Bytes nonce_bytes(reinterpret_cast<char*>(nonce), NONCE_LEN);
241 Bytes mac_bytes(reinterpret_cast<char*>(mac), DIGEST_SIZE);
242 stream->read(nonce_bytes);
243 stream->read(mac_bytes);
244
245 show_hmac_debug(nonce, NONCE_LEN, "got nonce ");
246 show_hmac_debug(mac, DIGEST_SIZE, "got digest ");
247
248 return stream->isOk();
249}
250
251bool AuthHMAC::check_hmac(unsigned char* mac, unsigned char* mac_check)
252{
253 int cmp = memcmp(mac, mac_check, DIGEST_SIZE);
254
255 std::string check = "digest check ";
256 if (cmp == 0) {
257 check += "successful";
258 } else {
259 check += "FAILED";
260 }
261 show_hmac_debug(mac_check, DIGEST_SIZE, check);
262
263 return (cmp == 0);
264}
265
266
267void AuthHMAC::fill_nonce(unsigned char* nonce)
268{
269 std::random_device rd;
270 std::mt19937 mt(rd());
271 std::uniform_int_distribution<int> dist(0, 255);
272 for (unsigned int i = 0; i < NONCE_LEN; i++) {
273 nonce[i] = static_cast<unsigned char>(dist(mt));
274 }
275}
void show_hmac_debug(unsigned char *hex, unsigned int length, const std::string &context)
Definition: AuthHMAC.cpp:27
#define HMAC_FINAL
Definition: AuthHMAC.h:20
#define HMAC_INIT
Definition: AuthHMAC.h:17
#define HMAC_UPDATE
Definition: AuthHMAC.h:19
#define NONCE_LEN
Definition: AuthHMAC.h:21
#define DIGEST_SIZE
Definition: AuthHMAC.h:15
#define HMAC_REINIT
Definition: AuthHMAC.h:18
#define HMAC_CONTEXT
Definition: AuthHMAC.h:16
A simple collection of objects that can be described and transmitted in a portable way.
Definition: Bottle.h:64
bool isNull() const override
Checks if the object is invalid.
Definition: Bottle.cpp:370
Value & find(const std::string &key) const override
Gets a value corresponding to a given keyword.
Definition: Bottle.cpp:287
A simple abstraction for a block of bytes.
Definition: Bytes.h:24
Simple specification of the minimum functions needed from input streams.
Definition: InputStream.h:25
virtual bool isOk() const =0
Check if the stream is ok or in an error state.
virtual int read()
Read and return a single byte.
Definition: InputStream.cpp:20
static void unlock()
Call post() on a global mutual-exclusion semaphore allocated by YARP.
Definition: Network.cpp:1464
static void lock()
Call wait() on a global mutual-exclusion semaphore allocated by YARP.
Definition: Network.cpp:1459
Simple specification of the minimum functions needed from output streams.
Definition: OutputStream.h:21
virtual bool isOk() const =0
Check if the stream is ok or in an error state.
virtual void write(char ch)
Write a single byte to the stream.
A class for storing options and configuration information.
Definition: Property.h:33
bool fromConfigFile(const std::string &fname, bool wipe=true)
Interprets a file as a list of properties.
Definition: Property.cpp:1098
Bottle & findGroup(const std::string &key) const override
Gets a list corresponding to a given keyword.
Definition: Property.cpp:1142
These options are loosely based on http://wiki.icub.org/wiki/YARP_ResourceFinder.
Helper class for finding config files and other external resources.
static ResourceFinder & getResourceFinderSingleton()
Access a ResourceFinder singleton whose lifetime will match that of the YARP library.
std::string findFile(const std::string &name)
Find the full path to a file.
virtual std::string asString() const
Get string value.
Definition: Value.cpp:234
bool authDest(yarp::os::InputStream *streamIn, yarp::os::OutputStream *streamOut)
Definition: AuthHMAC.cpp:159
bool authSource(yarp::os::InputStream *streamIn, yarp::os::OutputStream *streamOut)
Definition: AuthHMAC.cpp:100
#define yCInfo(component,...)
Definition: LogComponent.h:171
#define yCWarning(component,...)
Definition: LogComponent.h:192
#define yCDebug(component,...)
Definition: LogComponent.h:128
#define YARP_OS_LOG_COMPONENT(name, name_string)
Definition: LogComponent.h:29
The components from which ports and connections are built.
An interface to the operating system, including Port based communication.