sec(3) | AFNIX Module | sec(3) |
sec - standard security module
The Standard Securitymodule is an original implementation of several standards and techniques used in the field of cryptography. The module provides the objects than enables message hashing, symetric and assymetric ciphers and digital signature computation. The implementation follows the recommendation from NIST and PKCS and the standard reference that it implements is always attached to the underlying object.
Hash objects
Hashing is the ability to generate an almostunique representation from a
string. Although, there is no guarantee that two different string will not
produce the same result -- known as a collision -- the sophistication of the
hashing function attempt to minimize such eventuality. The hashing process
is not reversible. There are several hashing functions available in the
public domain. To name a few, MD5 is the message digest 5, and SHA is the
secure hash algorithm. The following table illustrates the size of the
result with different hashing functions.
Function | Result size |
MD-2 | 128 bits |
MD-4 | 128 bits |
MD-5 | 128 bits |
SHA-1 | 160 bits |
SHA-224 | 224 bits |
SHA-256 | 256 bits |
SHA-384 | 384 bits |
SHA-512 | 512 bits |
Hasher object
The Hasherclass is a text hashing computation class. The class computes a hash
value from a literal object, a buffer or an input stream. Once computed, the
hash value is stored as an array of bytes that can be retrieved one by one
or at all in the form of a string representation.
Creating a hasher
Several hasher objects are available in the module. For example, the Md5object
is the hasher object that implements the MD-5 algorithm. The constructor
does not take any argument.
# get a MD-5 hasher const md (afnix:sec:Md5) # check the object afnix:sec:hasher-p md # true
The computemethod computes the hash value. For example, the string "abc" returns the value "900150983CD24FB0D6963F7D28E17F72"which is 16 bytes long.
const hval (md:compute "abc")
Creating a SHA hasher
There are several SHA objects that produces results of different size as
indicated in the next table.
Hasher | Size | Constructor |
SHA-1 | 160 bits | Sha1 |
SHA-224 | 224 bits | Sha224 |
SHA-256 | 256 bits | Sha256 |
SHA-384 | 384 bits | Sha384 |
SHA-512 | 512 bits | Sha512 |
The computemethod computes the hash value. For example, the string "abc" returns with SHA-1 the 20 bytes long value: "A9993E364706816ABA3E25717850C26C9CD0D89D"
Cipher key principles
Cipher key management is an important concept in the ciphering land. In a
simple mode, a key is used by a cipher to encode some data. Although the key
can be any sequence of bytes, it is preferable to have the key built from a
specific source such like a pass-phrase. A cipher key comes basically into
two flavors: keys for symmetric ciphers and keys for asymmetric ciphers. A
key for a symmetric cipher is easy to derive and generally follows a
standard process which is independent of the cipher itself. A key for an
asymmetric cipher is more complex to derive and is generally dependent on
the cipher itself.
Key operations
The basic operations associated with a key are the key identification by type
and size. The key type is an item that identifies the key nature. The
get-typemethod returns the key type as specified by the table below.
Key | Description |
KSYM | Symmetric cipher key |
KRSA | Asymmetric RSA cipher key |
KMAC | Message authentication key |
KDSA | Message signature key |
The message authentication key as represented by the KMACsymbol is similar to the symmetric key. The key type can be obtained with the get-typemethod.
# get the key type const type (key:get-type)
The key size is the canonical size as specified by the key or the cipher specification. The get-bitsreturns the key size in bits. The get-sizereturns the key size in bytes rounded to the nearest value. The table below describes the nature of the key size returned.
Key | Type | Description |
KSYM | byte | Byte array size |
KRSA | bits | Modulus size |
KMAC | byte | Byte array size |
KDSA | bits | Signature size |
const bits (key:get-bits) const size (key:get-size)
Key representation
Unfortunately, it is not easy to represent a key, since the representation
depends on the key's type. For example, a symmetric key can be formatted as
a simple octet string. On the other hand, a RSA key has two components;
namely the modulus and the exponent, which needs to be distinguished and
therefore making the representation more difficult. Other cipher keys are
even more complicated. For this reason, the representation model is a
relaxed one. The formatmethod can be called without argument to obtain an
unique octet string representation if this representation is possible. If
the key representation requires some parameters, the format method may
accept one or several arguments to distinguish the key components.
Key | Argument | Description |
KSYM | none | Symmetric key octet string |
KRSA | RSA-MODULUS | RSA modulus octet string |
KRSA | RSA-PUBLIC-EXPONENT | RSA public exponent octet string |
KRSA | RSA-SECRET-EXPONENT | RSA secret exponent octet string |
KMAC | none | Message authentication key octet string |
KDSA | DSA-P-PRIME | DSA secret prime octet string |
KDSA | DSA-Q-PRIME | DSA secret prime octet string |
KDSA | DSA-SECRET-KEY | DSA secret key |
KDSA | DSA-PUBLIC-KEY | DSA public key |
KDSA | DSA-PUBLIC-GENERATOR | DSA public generator |
# get a simple key representation println (key:format) # get a rsa modulus key representation println (key:format afnix:sec:Key:RSA-MODULUS)
There are other key representations. The natural one is the byte representation for a symmetric key, while a number based representation is generally more convenient with asymmetric keys. The get-bytemethod returns a key byte by index if possible. The get-relatif-keyreturns a key value by relatif number if possible.
Symmetric cipher key
Creating a symmetric cipher key
The Keyclass can be used to create a cipher key suitable for a symmetric
cipher. By default a 128 bits random key is generated, but the key can be
also generated from an octet string.
const key (afnix:sec:Key) assert true (afnix:sec:key-p key)
The constructor also supports the use of an octet string representation of the key.
# create an octet string key const key (afnix:sec:Key "0123456789ABCDEF") assert true (afnix:sec:key-p key)
Symmetric key functions
The basic operation associated with a symmetric key is the byte extraction.
The get-sizemethod can be used to determine the byte key size. Once the key
size has been obtained, the key byte can be accessed by index with the
get-bytemethod.
# create a 256 random symmetric key const key (afnix:sec:Key afnix:sec:Key:KSYM 256) # get the key size const size (key:get-size) # get the first byte const byte (key:get-byte 0)
Asymmetric cipher key
An asymmetric cipher key can be generated for a particular asymmetric cipher,
such like RSA. Generally, the key contains several components identified as
the public and secret key components. These components are highly dependent
on the cipher type. Under some circumstances, all components might not be
available.
Creating an asymmetric cipher key
The Keyclass can be used to create a specific asymmetric cipher key.
Generally, the key is created by type and and bits size.
# create a 1024 bits rsa key const key (afnix:sec:Key afnix:sec:Key:KRSA 1024)
An asymmetric cipher key constructor is extremely dependent on the cipher type. For this reason, there is no constructor that can operate with a pass-phrase.
Asymmetric key functions
The basic operation associated with a asymmetric key is the relatif based
representation which is generally available for all key components. For
example, in the case of the RSA cipher, the modulus, the public and secret
exponents can be obtained in a relatif number based representation with the
help of the get-relatif-keymethod.
# create a 512 rsa key const key (afnix:sec:Key afnix:sec:Key:KRSA 512) # get the key modulus const kmod (
key:get-relatif-key afnix:sec:Key:RSA-MODULUS) # get the public exponent const pexp (
key:get-relatif-key afnix:sec:Key:RSA-PUBLIC-EXPONENT) # get the secret exponent const sexp (
key:get-relatif-key afnix:sec:Key:RSA-SECRET-EXPONENT)
Message authentication key
Creating a message authentication key
The Keyclass can also be used to create a message authentication key suitable
for a message authentication code generator or validator. By default a 128
bits random key is generated, but the key can be also generated from an
octet string.
const key (afnix:sec:Key afnix:sec:Key:KMAC) assert true (afnix:sec:key-p key)
The constructor also supports the use of an octet string as a key representation.
# create an octet string key const key (
afnix:sec:Key afnix:sec:Key:KMAC "0123456789ABCDEF") assert true (afnix:sec:key-p key)
Message authentication key functions
The basic operation associated with a message authentication key is the byte
extraction. The get-sizemethod can be used to determine the byte key size.
Once the key size has been obtained, the key byte can be accessed by index
with the get-bytemethod.
# create a 256 random message authentication key const key (afnix:sec:Key afnix:sec:Key:KMAC 256) # get the key size const size (key:get-size) # get the first byte const byte (key:get-byte 0)
Signature key functions
The basic operation associated with a signature key is the relatif based
representation which is generally available for all key components. For
example, in the case of the DSA signer, the prime numbers, the public and
secret components can be obtained in a relatif number based representation
with the help of the get-relatif-keymethod.
# create a 1024 dsa key const key (afnix:sec:Key afnix:sec:Key:KDSA) # get the key size const size (key:get-size) # get the secret component const sexp (
key:get-relatif-key afnix:sec:Key:DSA-SECRET-KEY)
Stream cipher
A stream cipher is an object that encodes an input stream into an output
stream. The data are read from the input stream, encoded and transmitted
onto the output stream. There are basically two types of stream ciphers
known as symmetric cipher and asymmetric cipher.
Symmetric cipher
A symmetric cipher is a cipher that encodes and decode data with the same key.
Normally, the key is kept secret, and the data are encoded by block. For
this reason, symmetric cipher are also called block cipher. In normal mode,
a symmetric cipher is created with key and the data are encoded from an
input stream as long as they are available. The block size depends on the
nature of the cipher. As of today, the recommended symmetric cipher is the
Advanced Encryption Standardor AES, also known as Rijndael.
Asymmetric cipher
An asymmetric cipher is a cipher that encodes and decode data with two keys.
Normally, the data are encoded with a public key and decoded with a private
key. In this model, anybody can encode a data stream, but only one person
can read them. Obviously, the model can be reverse to operate in a kind of
signature mode, where only one person can encode the data stream and anybody
can read them. Asymmetric cipher are particularly useful when operating on
unsecured channels. In this model, one end can send its public key as a mean
for other people to crypt data that can only be read by the sender who is
supposed to have the private key. As of today, the recommended asymmetric
ciphers are RSA and DH.
Serial cipher
A serial cipher is a cipher that encodes and decode data on a byte basis.
Normally, the data are encoded and decoded with the same key, thus making
the symmetric cipher key, the ideal candidate for a serial cipher key. Since
the data is encoded on a byte basis, it can be used efficiently with a
stream. However, the serial cipher does not define a block size and
therefore require some mechanism to prevent a buffer overrun when reading
bytes from a stream. For this reason, the serial cipher defines a default
serial block sizethat can be used to buffer the stream data. A method is
provided in the class to control the buffer size and is by default set to
4Kib bytes.
Cipher base class
The Cipherbase class is an abstract class that supports the symmetric,
asymmetric and serial cipher models. A cipher object has a name and is bound
to a key that is used by the cipher. The class provides some base methods
that can be used to retrieve some information about the cipher. The
get-namemethod returns the cipher name. The set-keyand get-keymethods are
both used to set or retrieve the cipher key. The cipher operating mode can
be found with the get-reversemethod. If the get-reversemethod returns true,
the cipher is operating in decoding mode. Note that a set-reversemethod also
exists.
Block cipher
A block cipher is an object that encodes an input stream with a symmetric
cipher bound to a unique key. Since a block cipher is symmetric, the data
can be coded and later decoded to their original form. The difference with
the Cipherbase class is that the BlockCipherclass provides a
get-block-sizemethod which returns the cipher block size.
Block Cipher base
The BlockCipherclass is a base class for the block cipher engine. The class
implements the streammethod that reads from an input stream and write into
an output stream. The BlockCipherclass is an abstract class and cannot be
instantiated by itself. The object is actually created by using a cipher
algorithm class such like the Aesclass.
trans count (cipher:stream os is)
The streammethod returns the number of characters that have been encoded. Care should be taken that most of the stream cipher operates by block and therefore, will block until a complete block has been read from the input stream, unless the end of stream is read. The block cipher is always associated with a padding scheme. By default, the NIST 800-38A recommendation is associated with the block cipher, but can be changed with the set-padding-mode.
Creating a block cipher
A BlockCipherobject can be created with a cipher constructor. As of today, the
Advanced Encryption Standardor AES is the recommended symmetric cipher. The
Aesclass creates a new block cipher that conforms to the AES standard.
const cipher (afnix:sec:Aes)
A block cipher can be created with a key and eventually a reverse flag. With one argument, the block cipher key is associated with the cipher. Such key can be created as indicated in the previous section. The reverse flag is used to determine if the cipher operate in encoding or decoding mode. By default, the cipher operates in coding mode.
# create a 256 bits random key const key (afnix:sec:Key afnix:sec:KSYM 256) # create an aes block cipher const aes (afnix:sec:Aes key)
Block cipher information
The BlockCipherclass is derived from the Cipherclass and contains several
methods that provide information about the cipher. This include the cipher
block size with the get-block-sizemethod.
println (aes:get-block-size)
Input cipher
In the presence of a Cipherobject, it is difficult to read an input stream and
encode the character of a block basis. Furthermore, the existence of various
method for block padding makes the coding operation even more difficult. For
this reason, the InputCipherclass provides the necessary method to code or
decode an input stream in various mode of operations.
Input cipher mode
The InputCipherclass is an input stream that binds an input stream with a
cipher. The class acts like an input stream, read the character from the
bounded input stream and encode or decode them from the bended cipher. The
InputCipherdefines several modes of operations. In electronic codebook
modeor ECB, the character are encoded in a block basis. In cipher block
chainingmode, the block are encoded by doing an XOR operation with the
previous block. Other modes are also available such like cipher feedback
modeand output feedback mode.
Creating an input cipher
By default an input cipher is created with a cipher object. Eventually, an
input stream and/or the input mode can be specified at the object
construction.
# create a key const key (afnix:sec:Key "hello world") # create a direct cipher const aes (afnix:sec:Aes key) # create an input cipher const ic (afnix:sec:InputCipher aes)
In this example, the input cipher is created in ECB mode. The input stream is later associated with the set-ismethod.
Input cipher operation
The InputCipherclass operates with one or several input streams. The
set-ismethod sets the input stream. Read operation can be made with the help
of the valid-ppredicate.
while (ic:valid-p) (os:write (ic:read))
Since the InputCipheroperates like an input stream, the stream can be read as long as the valid-ppredicate returns true. Note that the InputCiphermanages automatically the padding operations with the mode associated with the block cipher.
Asymmetric cipher
A public cipher is an object that encodes an input stream with a asymmetric
cipher bound to a public and secret key. In theory, there is no difference
between a block cipher and a public cipher. Furthermore, the interface
provided by the engine is the same for both objects.
Public cipher
A public cipher is an asymmetric stream cipher which operates with an
asymmetric key. The main difference between a block cipher and a public
cipher is the key nature as well as the encoded block size. With an
asymmetric cipher, the size of the message to encode is generally not the
same as the encoded block, because a message padding operation must occurs
for each message block.
trans count (cipher:stream os is)
The streammethod returns the number of characters that have been encoded. Like the block cipher, the streammethod encodes an input stream or a buffer object. The number of encoded bytes is returned by the method.
Creating a public cipher
A PublicCipherobject can be created with a cipher constructor. The
RSAasymmetric cipher is the typical example of public cipher. It is created
by binding a RSA key to it. For security reasons, the key size must be large
enough, typically with a size of at lease 1024 bits.
const key (afnix:sec:Key afnix:sec:Key:KRSA 1024) const rsa (afnix:sec:Rsa key)
A block cipher can be created with a key and eventually a reverse flag. Additional constructors are available to support various padding mode. Such padding mode depends on the cipher type. For example, the RSA cipher supports the ISO 18033-2 padding mode with a KDF1 or KDF2 object. Such constructor requires a hasher object as well.
# create a 1024 bits rsa key const key (afnix:sec:Key afnix:sec:KRSA 1024) # create a SHA-1 hasher const ash (afnix:sec:Sha1) # create a rsa public cipher const rsa (afnix:sec:Rsa key ash "Demo") # set the padding mode rsa:set-padding-mode afnix:sec:Rsa:PAD-OAEP-K1
Public cipher padding mode
Like any cipher, a padding mode can be associated with the cipher. The
set-padding-modemethod can be used to set or change the padding mode.
Depending on the padding mode type, additional objects might be needed at
construction.
Cipher | Padding mode | Default |
RSA | PKCS 1.5, PKCS 2.1, ISO/IEC 18033-2 | PKCS 1.5 |
The default padding mode depends on the cipher type. For RSA, the default padding mode is set to PKCS 1.5 for compatibility reason.
Signature objects
A digital signature is a unique representation, supposedly non forgeable,
designed to authenticate a document, in whatever form it is represented. For
example, a signature is used to sign a certificate which is used during the
process of establish a secured connection over the Internet. A signature can
also be used to sign a courrieror keys as it is in the Openssh protocol.
Digital signatures come into several flavors eventually associated with the
signed document. Sometimes, the signature acts as a container and permits to
retrieve the document itself. Whatever the method, the principle remains the
same. As of today technology, there are two standards used to sign document
as indicated below.
Standard | Name |
DSS | Digital Signature Standard |
RSA | RSA based signature |
Signer and signature objects
The process of generating a signature is done with the help of a Signerobject.
A signer object is a generic object, similar in functionality to the hasher
object. The result produced by a signer object is a Signatureobject which
holds the generated signature.
Signature key
The process of generating a signature often requires the use of a key. Such
key can be generated with the help of the Keyobject. The nature of the key
will depend on the target signature. The following table is a resume of the
supported keys.
Standard | Key | Signer |
DSS | KDSA | Dsa |
In the case of DSS, a key can be generated automatically, although this process is time consuming. The default key size is 1024 bits.
const key (afnix:sec:Key afnix:sec:Key:KDSA) assert 1024 (key:get-bits)
Creating a signer
A Signerobject is created with a particular signature object such like DSA.
The Dsaobject is a signer object that implements the Digital Signature
Algorithmas specified by the Digital Signature Standard (DSS)in FIPS-PUB
186-3.
# create a dsa signer const dsa (afnix:sec:Dsa key) assert true (afnix:sec:dsa-p dsa)
Creating a signature
A signature is created with the help of the computemethod. The Signatureobject
is similar to the Hasherand operates with string or streams.
# create a signature object const sgn (dsa:compute "afnix") assert true (afnix:sec:signature-p sgn)
Once the signature is created, each data can be accessed directly with the associated component mapper. In the case of DSS, there are two components as show below.
# get the DSS S component sgn:get-relatif-component afnix:sec:Signature:DSA-S-COMPONENT # get the DSS R component sgn:get-relatif-component afnix:sec:Signature:DSA-R-COMPONENT
Hasher
The Hasherclass is a base class that is used to build a message hash. The hash
result is stored in an array of bytes and can be retrieved byte by byte or
as a formatted printable string. This class does not have a constructor.
Predicate
Inheritance
Methods
Md2
The Md2class is a hashing class that implements the MD-2 algorithm.
Predicate
Inheritance
Constructors
Md4
The Md4class is a hashing class that implements the MD-4 algorithm.
Predicate
Inheritance
Constructors
Md5
The Md5class is a hashing class that implements the MD-5 algorithm.
Predicate
Inheritance
Constructors
Sha1
The Sha1class is a hashing class that implements the SHA-1 algorithm.
Predicate
Inheritance
Constructors
Sha224
The Sha224class is a hashing class that implements the SHA-224 algorithm.
Predicate
Inheritance
Constructors
Sha256
The Sha256class is a hashing class that implements the SHA-256 algorithm.
Predicate
Inheritance
Constructors
Sha384
The Sha384class is a hashing class that implements the SHA-384 algorithm.
Predicate
Inheritance
Constructors
Sha512
The Sha512class is a hashing class that implements the SHA-512 algorithm.
Predicate
Inheritance
Constructors
Key
The Keyclass is an original class used to store a particular key or to
generate one. A key is designed to operate with a variety of cipher that can
be either symmetric or asymmetric. In the symmetric case, the key is
generally an array of bytes. Asymmetric key are generally stored in the form
of number list that can be computed or loaded by value. By default, a random
128 bit symmetric key is created.
Predicate
Inheritance
Constructors
Constants
Methods
Kdf
The Kdfclass is an abstract class used to model key derivation function. The
class provides only a byte buffer which can be accessed by index. In the key
derivation functions land, there are numerous standards, such like PKCS 2.1,
IEEE P1363-2000, ISO/IEC 18033-2. All of these standards have sometimes
conflicting definitions.
Predicate
Inheritance
Methods
Hkdf
The Hkdfclass is an abstract class used to model key derivation function based
on hash function. The class maintains a hasher object that is used to derive
the key from an octet string.
Predicate
Inheritance
Methods
Kdf1
The Kdf1class is a hashed key derivation function class that implements the
KDF1 specification as defined by ISO/IEC 18033-2. The class is strictly
equivalent to the mask generation function (MGF1) defined in PKCS 2.1. On
the other hand, this implementation does not conform to the KDF1
specification of IEEE 1363-2000 which is somehow rather bizarre. The class
operates in theory with any type of hasher object as long as the octet
string is not too long.
Predicate
Inheritance
Constructors
Kdf2
The Kdf2class is a hashed key derivation function class that implements the
KDF2 specification as defined by ISO/IEC 18033-2. The class is strictly
equivalent to the key function derivation (KDF1) except that the internal
counter runs from 1 to k instead of 0 to k-1. The class operates in theory
with any type of hasher object as long as the octet string is not too
long.
Predicate
Inheritance
Constructors
Cipher
The Cipherclass is a base class that is used to implement a cipher. A cipher
is used to encrypt or decrypt a message. There are basically two types of
ciphers, namely symmetric cipher and asymmetric cipher. For the base class
operation, only the cipher name and key is needed. A reverse flag controls
whether or not an encryption operation must be reversed. A reset method can
also be used to reset the internal cipher state.
Predicate
Inheritance
Methods
BlockCipher
The BlockCipherclass is an abstract class that is used to implement a
symmetric block cipher. By default the cipher operates in encryption mode.
When the reverse flag is set, the decryption mode is activated. For a block
cipher, a block size controls the cipher operations. The class also defines
the constants that control the block padding with the associated
methods.
Predicate
Inheritance
Constants
Methods
InputCipher
The InputCipherclass is an stream interface that can stream out an input
stream from a cipher. In other word, an input stream is read and block are
encoded as long as the input stream read characters. If the cipher is nil,
the input cipher simply read the input stream and is therefore transparent.
The class acts like an input stream, read the character from the bounded
input stream and encode or decode them from the bounded cipher. The
InputCipherdefines several modes of operations. In electronic codebook
modeor ECB, the character are encoded in a block basis. In cipher block
chainingmode, the block are encoded by doing an XOR operation with the
previous block. Other modes such like cipher feedback modeand output
feedback modeare also defined.
Predicate
Inheritance
Constructors
Constants
Methods
Aes
The Aesclass is a block cipher class that implements the advanced encryption
standard(AES), originally known as Rijndael. This is an original
implementation that conforms to the standard FIPS PUB 197. It should be
noted that the AES standard, unlike Rijndael, defines a fixed block size of
16 bytes (4 words) and 3 keys sizes (128, 192, 256).
Predicate
Inheritance
Constructors
PublicCipher
The PublicCipherclass is an abstract class that is used to implement an
asymmetric cipher. An asymmetric cipher or public key cipher is designed to
operate with a public key and a secret key. Depending on the use model, the
public key might be used to crypt the data, and the secret key to decrypt.
The basic assumption around a public cipher is that the secret key cannot be
derived from the public key.
Predicate
Inheritance
Methods
Rsa
The Rsaclass is a public cipher class that implements the RSA algorithm as
described by PKCS 2.1, RFC 2437 and ISO 18033-2. The class implements also
some padding mechanism described in PKCS 1.5, 2.1 and ISO 18033-2. The RSA
algorithm is a public cryptographic cipher based on a secret and public
keys. The class operates in crypting mode by default and uses the public key
to do the encryption while the secret key is used in reverse (decryption)
mode. By default, the PKCS 1.5 type 2 padding is used. The ISO RSA-REM1
padding with a key derivation function (KDF1) is equivalent to PKCS 2.1
padding with the mask generation function (MGF1). The ISO RSA-REM1 padding
with KDF2 is not described in the PKCS 2.1.
Predicate
Inheritance
Constructors
Constants
Methods
Signer
The Signerclass is a base class that is used to build a message signature. The
signature result is stored in a special signature object which is algorithm
dependent.
Predicate
Inheritance
Methods
Signature
The Signatureclass is a container class designed to store a message signature.
The signature object is produced by a signing process, implemented in the
form of a digital signature algorithm such like RSA or DSA.
Predicate
Inheritance
Constructors
Constants
Methods
Dsa
The Dsaclass is an original implementation of the Digital Signature Standard
(DSS) as published in FIPS PUB 186-3. This class implements the Digital
Signature Algorithm (DSA) with an approved key length of 1024, 2048 and 3072
bits with a 160, 224 and 256 bits hash function which is part of the SHA
family.
Predicate
Inheritance
Constructors
2018-07-20 | AFNIX |