1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "remoting/protocol/authentication_method.h"
6
7#include "base/base64.h"
8#include "base/logging.h"
9#include "crypto/hmac.h"
10#include "remoting/protocol/auth_util.h"
11
12namespace remoting {
13namespace protocol {
14
15// static
16AuthenticationMethod AuthenticationMethod::Invalid() {
17  return AuthenticationMethod();
18}
19
20// static
21AuthenticationMethod AuthenticationMethod::Spake2(HashFunction hash_function) {
22  return AuthenticationMethod(SPAKE2, hash_function);
23}
24
25// static
26AuthenticationMethod AuthenticationMethod::Spake2Pair() {
27  return AuthenticationMethod(SPAKE2_PAIR, HMAC_SHA256);
28}
29
30// static
31AuthenticationMethod AuthenticationMethod::ThirdParty() {
32  return AuthenticationMethod(THIRD_PARTY, NONE);
33}
34
35// static
36AuthenticationMethod AuthenticationMethod::FromString(
37    const std::string& value) {
38  if (value == "spake2_pair") {
39    return Spake2Pair();
40  } else if (value == "spake2_plain") {
41    return Spake2(NONE);
42  } else if (value == "spake2_hmac") {
43    return Spake2(HMAC_SHA256);
44  } else if (value == "third_party") {
45    return ThirdParty();
46  } else {
47    return AuthenticationMethod::Invalid();
48  }
49}
50
51// static
52std::string AuthenticationMethod::ApplyHashFunction(
53    HashFunction hash_function,
54    const std::string& tag,
55    const std::string& shared_secret) {
56  switch (hash_function) {
57    case NONE:
58      return shared_secret;
59      break;
60
61    case HMAC_SHA256: {
62      crypto::HMAC response(crypto::HMAC::SHA256);
63      if (!response.Init(tag)) {
64        LOG(FATAL) << "HMAC::Init failed";
65      }
66
67      unsigned char out_bytes[kSharedSecretHashLength];
68      if (!response.Sign(shared_secret, out_bytes, sizeof(out_bytes))) {
69        LOG(FATAL) << "HMAC::Sign failed";
70      }
71
72      return std::string(out_bytes, out_bytes + sizeof(out_bytes));
73    }
74  }
75
76  NOTREACHED();
77  return shared_secret;
78}
79
80AuthenticationMethod::AuthenticationMethod()
81    : type_(INVALID),
82      hash_function_(NONE) {
83}
84
85AuthenticationMethod::AuthenticationMethod(MethodType type,
86                                           HashFunction hash_function)
87    : type_(type),
88      hash_function_(hash_function) {
89  DCHECK_NE(type_, INVALID);
90}
91
92AuthenticationMethod::HashFunction AuthenticationMethod::hash_function() const {
93  DCHECK(is_valid());
94  return hash_function_;
95}
96
97const std::string AuthenticationMethod::ToString() const {
98  DCHECK(is_valid());
99
100  switch (type_) {
101    case INVALID:
102      NOTREACHED();
103      break;
104
105    case SPAKE2_PAIR:
106      return "spake2_pair";
107
108    case SPAKE2:
109      switch (hash_function_) {
110        case NONE:
111          return "spake2_plain";
112        case HMAC_SHA256:
113          return "spake2_hmac";
114      }
115      break;
116
117    case THIRD_PARTY:
118      return "third_party";
119  }
120
121  return "invalid";
122}
123
124bool AuthenticationMethod::operator ==(
125    const AuthenticationMethod& other) const {
126  return type_ == other.type_ &&
127      hash_function_ == other.hash_function_;
128}
129
130bool SharedSecretHash::Parse(const std::string& as_string) {
131  size_t separator = as_string.find(':');
132  if (separator == std::string::npos)
133    return false;
134
135  std::string function_name = as_string.substr(0, separator);
136  if (function_name == "plain") {
137    hash_function = AuthenticationMethod::NONE;
138  } else if (function_name == "hmac") {
139    hash_function = AuthenticationMethod::HMAC_SHA256;
140  } else {
141    return false;
142  }
143
144  if (!base::Base64Decode(as_string.substr(separator + 1), &value)) {
145    return false;
146  }
147
148  return true;
149}
150
151}  // namespace protocol
152}  // namespace remoting
153