summaryrefslogtreecommitdiff
path: root/src/pubkey.h
blob: ca662ba801201caadfbc05464148aba29a540459 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#pragma once

#include "storage.h"

#include <openssl/evp.h>

using std::nullopt;
using std::optional;
using std::shared_ptr;

namespace erebos {

template<typename T> class Signed;

class PublicKey
{
	PublicKey(EVP_PKEY * key):
		key(key, EVP_PKEY_free) {}
	friend class SecretKey;
public:
	static PublicKey load(const Ref &);
	Ref store(const Storage &) const;

	const shared_ptr<EVP_PKEY> key;
};

class SecretKey
{
	SecretKey(EVP_PKEY * key, const Stored<PublicKey> & pub):
		key(key, EVP_PKEY_free), pub_(pub) {}
	SecretKey(shared_ptr<EVP_PKEY> && key, const Stored<PublicKey> & pub):
		key(key), pub_(pub) {}
public:
	static SecretKey generate(const Storage & st);
	static optional<SecretKey> load(const Stored<PublicKey> & st);

	static optional<SecretKey> fromData(const Stored<PublicKey> &, const vector<uint8_t> &);
	vector<uint8_t> getData() const;

	Stored<PublicKey> pub() const { return pub_; }

	template<class T>
	Stored<Signed<T>> sign(const Stored<T> &) const;
	template<class T>
	Stored<Signed<T>> signAdd(const Stored<Signed<T>> &) const;

private:
	vector<uint8_t> sign(const Digest &) const;

	const shared_ptr<EVP_PKEY> key;
	Stored<PublicKey> pub_;
};

class Signature
{
public:
	static Signature load(const Ref &);
	Ref store(const Storage &) const;

	bool verify(const Ref &) const;

	Stored<PublicKey> key;
	vector<uint8_t> sig;

private:
	friend class SecretKey;
	Signature(const Stored<PublicKey> & key, const vector<uint8_t> & sig):
		key(key), sig(sig) {}
};

template<typename T>
class Signed
{
public:
	static Signed<T> load(const Ref &);
	Ref store(const Storage &) const;

	bool isSignedBy(const Stored<PublicKey> &) const;

	const Stored<T> data;
	const vector<Stored<Signature>> sigs;

private:
	friend class SecretKey;
	Signed(const Stored<T> & data, const vector<Stored<Signature>> & sigs):
		data(data), sigs(sigs) {}
};

template<class T>
Stored<Signed<T>> SecretKey::sign(const Stored<T> & val) const
{
	auto st = val.ref().storage();
	auto sig = st.store(Signature(pub(), sign(val.ref().digest())));
	return st.store(Signed(val, { sig }));
}

template<class T>
Stored<Signed<T>> SecretKey::signAdd(const Stored<Signed<T>> & val) const
{
	auto st = val.ref().storage();
	auto sig = st.store(Signature(pub(), sign(val.ref().digest())));
	auto sigs = val->sigs;
	sigs.push_back(st.store(Signature(pub(), sign(val->data.ref().digest()))));
	return st.store(Signed(val->data, sigs));
}

template<typename T>
Signed<T> Signed<T>::load(const Ref & ref)
{
	if (auto rec = ref->asRecord())
		if (auto data = rec->item("SDATA").as<T>()) {
			vector<Stored<Signature>> sigs;
			for (const auto & sig : rec->items("sig").as<Signature>())
				if (sig->verify(data.value().ref()))
					sigs.push_back(sig);

			return Signed(*data, sigs);
		}

	return Signed(Stored<T>::load(ref.storage().zref()), {});
}

template<typename T>
Ref Signed<T>::store(const Storage & st) const
{
	vector<Record::Item> items;

	items.emplace_back("SDATA", data);
	for (const auto & sig : sigs)
		items.emplace_back("sig", sig);

	return st.storeObject(Record(std::move(items)));
}

template<typename T>
bool Signed<T>::isSignedBy(const Stored<PublicKey> & key) const
{
	for (const auto & sig : sigs)
		if (sig->key == key)
			return true;
	return false;
}


class PublicKexKey
{
	PublicKexKey(EVP_PKEY * key):
		key(key, EVP_PKEY_free) {}
	friend class SecretKexKey;
public:
	static PublicKexKey load(const Ref &);
	Ref store(const Storage &) const;

	const shared_ptr<EVP_PKEY> key;
};

class SecretKexKey
{
	SecretKexKey(EVP_PKEY * key, const Stored<PublicKexKey> & pub):
		key(key, EVP_PKEY_free), pub_(pub) {}
	SecretKexKey(shared_ptr<EVP_PKEY> && key, const Stored<PublicKexKey> & pub):
		key(key), pub_(pub) {}
public:
	static SecretKexKey generate(const Storage & st);
	static optional<SecretKexKey> load(const Stored<PublicKexKey> & st);

	Stored<PublicKexKey> pub() const { return pub_; }
	vector<uint8_t> dh(const PublicKexKey &) const;

private:
	const shared_ptr<EVP_PKEY> key;
	Stored<PublicKexKey> pub_;
};

}