(********************************************************************)
(*                                                                  *)
(*  cipher.s7i    Generic support for TLS bulk cipher algorithms.   *)
(*  Copyright (C) 2013  Thomas Mertes                               *)
(*                                                                  *)
(*  This file is part of the Seed7 Runtime Library.                 *)
(*                                                                  *)
(*  The Seed7 Runtime Library is free software; you can             *)
(*  redistribute it and/or modify it under the terms of the GNU     *)
(*  Lesser General Public License as published by the Free Software *)
(*  Foundation; either version 2.1 of the License, or (at your      *)
(*  option) any later version.                                      *)
(*                                                                  *)
(*  The Seed7 Runtime Library is distributed in the hope that it    *)
(*  will be useful, but WITHOUT ANY WARRANTY; without even the      *)
(*  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(*  PURPOSE.  See the GNU Lesser General Public License for more    *)
(*  details.                                                        *)
(*                                                                  *)
(*  You should have received a copy of the GNU Lesser General       *)
(*  Public License along with this program; if not, write to the    *)
(*  Free Software Foundation, Inc., 51 Franklin Street,             *)
(*  Fifth Floor, Boston, MA  02110-1301, USA.                       *)
(*                                                                  *)
(********************************************************************)


(**
 *  Enumeration of cipher algorithms.
 *  Currently the ciphers NO_CIPHER, RC4, DES, TDES, BLOWFISH, AES and
 *  AES_GCM are supported.
 *)
const type: cipherAlgorithm is new enum
    NO_CIPHER, RC4, DES, TDES, BLOWFISH, AES, AES_GCM
  end enum;


(**
 *  Interface type for the internal state of a cipher.
 *  The cipherState interface is implemented with [[arc4]], [[des]], [[tdes]],
 *  [[blowfish]], [[aes]], [[aes_gcm]] and [[#noCipherState|noCipher]] (no encryption).
 *)
const type: cipherState is sub object interface;



(**
 *  Block size used by the given [[cipher#cipherAlgorithm|cipherAlgorithm]].
 *  Stream ciphers have a block size of 0.
 *  @return the block size used by the ''cipherAlgorithm''.
 *)
const func integer: blockSize (in cipherAlgorithm: cipherAlg) is DYNAMIC;


(**
 *  Set key and initialization vector for the given [[cipher#cipherAlgorithm|cipherAlgorithm]].
 *  @param cipherAlg The [[cipher#cipherAlgorithm|cipherAlgorithm]] to be used.
 *  @return the ''cipherState'' of the ''cipherAlgorithm''.
 *)
const func cipherState: setCipherKey (in cipherAlgorithm: cipherAlg,
    in string: cipherKey, in string: initializationVector) is DYNAMIC;


(**
 *  Initialize the authenticated encryption with associated data (AEAD).
 *  For all other cipher algorithms this function does nothing.
 *)
const proc: initAead (inout cipherState: state, in string: recordTypeAndVersion,
    in integer: sequenceNumber) is DYNAMIC;


(**
 *  Obtain the computed MAC of data that has been decrypted with an AEAD cipher.
 *  For all other cipher algorithms this function raises an exception.
 *  After a successful decryption with an AEAD cipher getComputedMac and getMac
 *  should return the same value.
 *)
const func string: getComputedMac (in cipherState: state) is DYNAMIC;


(**
 *  Obtain the MAC that is appended to the encrypted data of an AEAD cipher.
 *  For all other cipher algorithms this function raises an exception.
 *  After a successful decryption with an AEAD cipher getComputedMac and getMac
 *  should return the same value.
 *)
const func string: getMac (in cipherState: state) is DYNAMIC;


(**
 *  Encode a string with the ''state'' of the selected cipher algorithm.
 *  @return the encoded string.
 *)
const func string: encode (inout cipherState: state, in string: plaintext) is DYNAMIC;


(**
 *  Decode a string with the ''state'' of the selected cipher algorithm.
 *  @return the decoded string.
 *)
const func string: decode (inout cipherState: state, in string: encoded) is DYNAMIC;


(* NO_CIPHER *)


(**
 *  [[cipher|cipherState]] implementation type describing the state if no cipher is used.
 *  The data remains unencrypted if NO_CIPHER is used.
 *)
const type: noCipherState is new struct
  end struct;


type_implements_interface(noCipherState, cipherState);


const cipherState: (attr cipherState) . value is noCipherState.value;


const func integer: blockSize (NO_CIPHER) is 0;


const func cipherState: setCipherKey (NO_CIPHER, in string: cipherKey,
    in string: initializationVector) is func
  result
    var cipherState: state is cipherState.value;
  local
    var noCipherState: new_state is noCipherState.value;
  begin
    state := toInterface(new_state);
  end func;


const proc: initAead (inout noCipherState: state, in string: recordTypeAndVersion,
    in integer: sequenceNumber) is noop;


const func string: encode (inout noCipherState: state, in string: plaintext) is
  return plaintext;


const func string: decode (inout noCipherState: state, in string: encoded) is
  return encoded;