Files CCore/inc/net/PSecCore.h CCore/src/net/PSecCore.cpp
Files CCore/inc/net/PSec.h CCore/src/net/PSec.cpp
Files CCore/inc/net/PSecKey.h CCore/src/net/PSecKey.cpp
PSec is a security protocol for point-to-point packet-based communication. CCore provides an implementation of this protocol. It's enclosed in the namespace PSec. The protocol itself is described in this document.
The following utility classes are used in the PSec implementation.
AbstractCryptFunc is an abstract block cipher function class.
struct AbstractCryptFunc : MemBase_nocopy
{
virtual ~AbstractCryptFunc() {}
virtual ulen getBLen() const =0;
virtual ulen getKLen() const =0;
virtual void key(const uint8 key[ /* KLen */ ])=0;
virtual void apply(uint8 block[ /* BLen */ ]) const =0;
};
getBLen() returns the cipher block length.
getKLen() returns the key length.
key() activates the given key. The length of the buffer is getKLen(). After this method call the function can process data blocks.
apply() performs the block cipher in-place. The length of the buffer is getBLen().
AbstractHashFunc is an abstract hash function class.
struct AbstractHashFunc : MemBase_nocopy
{
virtual ~AbstractHashFunc() {}
virtual ulen getHLen() const =0;
virtual void add(PtrLen<const uint8> data)=0;
virtual const uint8 * finish()=0; /* [HLen] */
};
getHLen() returns the digest length.
add() adds a chunk of data in the hash calculation.
finish() finishes the hash calculation and starts the hash function over. The result is returned in some internal buffer of the length getHLen().
AbstractKeyGen is used in the key generation process. It implements the power calculation for some finite group.
struct AbstractKeyGen : MemBase_nocopy
{
virtual ~AbstractKeyGen() {}
virtual ulen getGLen() const =0;
virtual ulen getKLen() const =0;
virtual void pow(const uint8 x[ /* GLen */ ],uint8 gx[ /* GLen */ ])=0;
virtual void key(const uint8 x[ /* GLen */ ],const uint8 gy[ /* GLen */ ],uint8 key[ /* KLen */ ])=0;
};
getGLen() returns the group element octet representation length.
getKLen() returns the key length.
pow() calculates the power of the generator element gx.
key() calculates the power gyx and transforms the result into the key. (gx)y and (gy)x renders the same key.
AbstractRandomGen is an abstract random generator class. It is not required to be a cryptography strong. But it should be a quality RNG.
struct AbstractRandomGen : MemBase_nocopy
{
virtual ~AbstractRandomGen() {}
virtual void fill(PtrLen<uint8> buf)=0;
};
fill() fills the buffer with random bytes.
LifeLim presents key lifetime limits.
struct LifeLim
{
uint32 ttl; // sec
uint32 utl;
LifeLim() : ttl(0),utl(0) {}
LifeLim(uint32 ttl_,uint32 utl_) : ttl(ttl_),utl(utl_) {}
....
};
ttl is the time limit in seconds. A key must be replaced after this time is expired.
utl is the traffic limit in octets. A key must be replaced after this number of octets has been encrypted using this key.
AlgoLen presents key algorithms properties.
struct AlgoLen
{
ulen blen;
ulen hlen;
AlgoLen(ulen blen_,ulen hlen_) : blen(blen_),hlen(hlen_) {}
};
blen is the block cipher length.
hlen is the hash digest length.
EndpointManager is an interface to manage secure endpoint session.
/* struct AbstractClientProfile */ struct AbstractClientProfile : MemBase_nocopy { virtual ~AbstractClientProfile() {} }; /* type ClientProfilePtr */ using ClientProfilePtr = OwnPtr<AbstractClientProfile> ; /* struct EndpointManager */ struct EndpointManager { static const Unid TypeUnid; enum OpenErrorCode : uint32 { Open_Ok = 0, OpenError_NoMemory, OpenError_OpenLimit, OpenError_NoAccess }; virtual OpenErrorCode open(XPoint point,const MasterKey &skey,ClientProfilePtr &&client_profile)=0; virtual bool close(XPoint point)=0; virtual ulen closeAll()=0; virtual AbstractClientProfile * getClientProfile(XPoint point)=0; };
open() opens a communication session with the given endpoint. The endpoint is identified by its abstract XPoint address point. The second argument is a MasterKey reference. The object is used only inside the method and may be destroyed after the method call. The last argument is a client profile pointer. A client profile is an abstract piece of data associated with the client. It is provided by the caller of the method open() and can be retrieved by the method getClientProfile(). The method returns the status code.
close() closes the session with the given endpoint. It returns true if such connection exists and false otherwise.
closeAll() closes all sessions and returns the number of sessions closed.
getClientProfile() returns the pointer to the client profile, associated with the endpoint. The pointer is null, if there is no session with this endpoint. An implementation should provide a context requirement for the calling this method.
The MasterKey class is used to present a key information for a PSec connection. It is an abstract multi-factory.
struct MasterKey : MemBase_nocopy { virtual ~MasterKey() {} // factory virtual AbstractCryptFunc * createEncrypt() const =0; virtual AbstractCryptFunc * createDecrypt() const =0; virtual AbstractHashFunc * createHash() const =0; virtual AbstractKeyGen * createKeyGen() const =0; virtual AbstractRandomGen * createRandom() const =0; // keys virtual ulen getKLen() const =0; virtual LifeLim getLifeLim() const =0; virtual void getKey0(uint8 key[ /* KLen */ ]) const =0; virtual ulen getKeySetLen() const =0; virtual void getKey(ulen index,uint8 key[ /* KLen */ ]) const =0; }; using MasterKeyPtr = OwnPtr<MasterKey> ;
The first group of method is used to create various processing objects. They return a pointer to an abstract object interface. An exception is thrown in case of error.
createEncrypt() creates an encryption function.
createDecrypt() creates a complementary decryption function.
createHash() creates a hash function.
createKeyGen() creates a key generator.
createRandom() creates a random generator.
The second group of methods present key information.
getKLen() returns the key length. It is the key length of the encryption and decryption functions.
getLifeLim() returns the life limit per key.
getKey0() copies the key-0 into the provided buffer. The buffer length is getKLen().
getKeySetLen() returns the number of keys in the keyset.
getKey() copies the key from the keyset into the provided buffer. The buffer length is getKLen(). The key index is zero-based.
EndpointDevice transforms an insecure PacketEndpointDevice into a secure PacketEndpointDevice. Usually it is used on the client side.
class EndpointDevice : public ObjBase , public PacketEndpointDevice
{
....
public:
EndpointDevice(StrLen ep_dev_name,const MasterKey &master_key,MSec keep_alive_timeout=Null);
virtual ~EndpointDevice();
void close(); // send Close to the peer and assert connection_lost
// stat
using StatInfo = ProcessorStatInfo ;
void getStat(StatInfo &ret) const;
// InterfaceHost
virtual void requestInterface(InterfaceCaster &caster);
// PacketEndpointDevice
virtual PacketFormat getOutboundFormat() const;
virtual void outbound(Packet<uint8> packet);
virtual ulen getMaxInboundLen() const;
virtual void attach(InboundProc *proc);
virtual void detach();
};
Constructor takes three arguments. The first argument is the name of an insecure endpoint device. The second is the master key for the protected session. The key object may be destroyed after the constructor call. The third is the keep-alive timeout. If this argument is not null, then the keep-alive mechanic is activated. If there is no confirmed inbound packets during some period then the connection is closed. Ping packets are sent prior the timeout expiration to make sure the peer is alive.
The object itself is the secure endpoint device. Outbound packets are encrypted and sent to the insecure device. Inbound packets from the insecure device are verified, decrypted and sent to the inbound processor.
close() can be used to close the connection. The Close packet is sent to the peer and the connection_lost is asserted.
getStat() returns the connection statistic counters.
MultipointDevice transforms insecure PacketMultipointDevice into s secure PacketMultipointDevice. Usually it is used on the server side. The communication with a particular network peer is protected using the particular master key. This class implements the EndpointManager interface to control opened sessions.
class MultipointDevice : public ObjBase , public PacketMultipointDevice , public EndpointManager
{
....
public:
MultipointDevice(StrLen mp_dev_name,PtrLen<const AlgoLen> algo_lens,ulen max_clients,MSec keep_alive_timeout);
virtual ~MultipointDevice();
// stat
using StatInfo = ProcessorStatInfo ;
void getStat(StatInfo &ret) const;
bool getStat(XPoint point,StatInfo &ret) const;
template <class FuncInit>
void processStat(FuncInit func_init) const; // func(XPoint point,StatInfo &temp_copy)
// InterfaceHost
virtual void requestInterface(InterfaceCaster &caster);
// PacketMultipointDevice
virtual StrLen toText(XPoint point,PtrLen<char> buf) const;
virtual PacketFormat getOutboundFormat() const;
virtual void outbound(XPoint point,Packet<uint8> packet);
virtual ulen getMaxInboundLen() const;
virtual void attach(InboundProc *proc);
virtual void detach();
// EndpointManager
virtual OpenErrorCode open(XPoint point,const MasterKey &skey,ClientProfilePtr &&client_profile);
virtual bool close(XPoint point);
virtual ulen closeAll();
virtual AbstractClientProfile * getClientProfile(XPoint point); // only inside inbound processing or processStat
};
The first argument of the constructor is the name of the insecure PacketMultipointDevice. The second is the list of the AlgoLen structures for the expected session keys. The max_clients is the maximum client number which can be active simultaneously. If last argument is the keep-alive timeout. If it is not null, then the keep-alive is activated.
To manage client sessions the EndpointManager interface is provided.
getStat() returns the connection statistic counters. If the XPoint is given it returns the counters for the particular session.
The method processStat() can be used to iterate over the active sessions. It calls the given functor per each session with two arguments: the first is the peer address, the second is the statistic counters for this session. The method is working under the internal mutex protection.
Outbound packets are encrypted using the session key of the correspondent session. The peer address determines the particular session. Inbound packets are verified, decrypted and sent to the inbound processor. They are processed in the context of the opened session. If there is no such one the packet is discarded.
The method open() opens or reopens the session. In the last case the session key and the client profile are replaced. A session can be closed manually or by the keep-alive processor if there is no response from the peer during the given period.
The method getClientProfile() can be safely called inside the inbound processing or the method processStat().