EXPLOREAPI

Logo Explore - Data for success

Fonctionnement général

L'authentification sur l'API EXPLORE fonctionne en temps normal selon un principe de clé d'authentification (CleClient) et de contrôle IP. Lorsque ce dernier n'est pas possible, un système de chiffrement est mis en place. Tous les webservices génériques d'EXPLORE disposent d'un équivalent dit "signé" permettant ces appels.

Seuls deux paramètres d'entrée sont nécessaires :

Le paramètre « Signature » est crypté selon une méthode de chiffrement basée sur un algorithme fiable ; AES (Advanced Encryption Standard). Pour plus d'informations sur AES, vous pouvez vous référer à la page suivante.

Votre organisation ainsi qu'EXPLORE disposent ainsi d'une clé secrète permettant l'échange confidentiel des données en cryptant et décryptant cette chaîne de paramètres. Toute personne ne possédant pas cette clé sera incapable de révéler le contenu de la signature.

L'URL obtenue par le biais du chiffrement, pour des raisons de sécurité, n'est valable que le jour même de sa génération. Il convient ainsi de rajouter la date du jour à la clé secrète comme dans l'exemple ci-dessous (en C#) :

string cleCrypteeClient = DateTime.Today.ToString("yyyyMMdd") + CleSecrete;

Le contenu du paramètre « Signature » correspond à la chaîne de paramètre « normale » du web service. Ainsi, pour le web service Amenagements de la rubrique générique Opportunites, une chaîne à crypter a pour format « CleClient=[Votre clé client]&DateDebut=[yyyy-MM-dd]&DateFin=[yyyy-MM-dd]&MAJ=[false / true] ».

Fonctions de cryptage

La chaîne « Signature » peut être cryptée grâce aux fonctions suivantes :

            
public static string Encrypt(string toEncrypt, string cKey)
{
    byte[] plainText = Encoding.UTF8.GetBytes(toEncrypt);

    Rfc2898DeriveBytes rfcDb = new(cKey, Encoding.UTF8.GetBytes(cKey));
    byte[] key = rfcDb.GetBytes(16);
    byte[] iv = rfcDb.GetBytes(16);

    Aes? aes = Aes.Create("AesManaged");

    if (aes == null)
        throw new NotImplementedException();

    ICryptoTransform encryptor = aes.CreateEncryptor(key, iv);
    byte[]? cipherBytes = null;

    using (MemoryStream ms = new())
    {
        using CryptoStream cs = new(ms, encryptor, CryptoStreamMode.Write);
        cs.Write(plainText, 0, plainText.Length);
        cs.FlushFinalBlock();

        cipherBytes = ms.ToArray();
    }

    return Convert.ToBase64String(cipherBytes).Replace("+", "-").Replace("/", "_");
}
            
        
            
public static string Encrypt(string toEncrypt, string ckey)
{
    byte[] plainText = Encoding.UTF8.GetBytes(toEncrypt);

    Rfc2898DeriveBytes rfcDb = new Rfc2898DeriveBytes(ckey, Encoding.UTF8.GetBytes(ckey));
    byte[] key = rfcDb.GetBytes(16);
    byte[] iv = rfcDb.GetBytes(16);

    RijndaelManaged rijndael = new RijndaelManaged
    {
        Mode = CipherMode.CBC;
    };

    ICryptoTransform encryptor = rijndael.CreateEncryptor(key, iv);
    byte[] cipherBytes = null;

    using (MemoryStream ms = new MemoryStream())
    {
        using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write));
        {
            cs.Write(plainText, 0, plainText.Length);
            cs.FlushFinalBlock();

            cipherBytes = ms.ToArray();
        }
    }

    return Convert.ToBase64String(cipherBytes).Replace("+", "-").Replace("/", "_");
}
            
        
            
public static string Encrypt(string toEncrypt, string cKey)
{
    byte[] encrypted = null;

    using (AesCryptoServiceProvider aes = new AesCryptoServiceProvider())
    {
        char[] keyChars = cKey.ToCharArray();
        byte[] key = new byte[16];
        byte[] iv = new byte[16];

        for (int i = 0; i < 16; i++)
        key[i] = (byte)key[i];

        for (int i = 16; i < 32; i++)
        iv[i - 16] = (byte)key[i];

        aes.Key = key;
        aes.IV = iv;
        aes.Mode = CipherMode.CBC;
        aes.Padding = PaddingMode.PKCS7;

        ICryptoTransform enc = aes.CreateEncryptor(aes.Key, aes.IV);

        using (MemoryStream ms = new MemoryStream())
        {
            using (CryptoStream cs = new CryptoStream(ms, enc, CryptoStreamMode.Write))
            {
                using (StreamWriter sw = new StreamWriter(cs))
                {
                    sw.Write(toEncrypt);
                }

                encrypted = ms.ToArray();
            }
        }
    }

    return Convert.ToBase64String(encrpted).Replace("+", "-").Replace("/", "_");
}
            
        
            
public static String encrypt(String toEncrypt, String cKey) throws Exception
{
    try
    {
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        PBEKeySpec pbeKeySpec = new PBEKeySpec(cKey.toCharArray(), Arrays.copyOf(cKey.getBytes("UTF-8"), cKey.getBytes("UTF-8").length), 1000, 384);
        byte[] secretKeyBytes = factory.generateSecret(pbeKeySpec).getEncoded();

        IvParameterSpec ivSpec = new IvParameterSpec(Arrays.copyOfRange(secretKeyBytes, 16, 32));
        SecretKeySpec secretKeySpec = new SecretKeySpec(Arrays.copyOfRange(secretKeyBytes, 0, 16), "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivSpec);

        byte[] encrypted = cipher.doFinal(toEncrypt.getBytes("UTF-8"));

        return Base64.getEncoder().encodeToString(encrypted).replace("+", "-").replace("/", "_");
    }
        catch (Exception ex)
    {
        throw ex;
    }
}
            
        
            
<?php

function Encrypt($toEncrypt, $cKey)
{
    require 'PBKDF2.class.php';
    $pbkdf = new PBKDF2();
    $rfcdb = $pbkdf->hash("sha1", $cKey, $cKey, 1000, 32, true);

    $key = substr($rfcdb, 0, 16);
    $iv = substr($rfcdb, 16, 16);

    $cipherTextRaw = openssl_encrypt($toEncrypt, "AES-128-CBC", $key, 1, $iv);
    $cipherTextBase64 = str_replace(array("+", "/"), array("-", "_"), base64_encode($cipherTextRaw));

    return $cipherTextBase64;
}

?>
            
        
            
<?php

function Encrypt($toEncrypt, $cKey)
{
    $rfcdb = hash_pbkdf2("sha1", $cKey, $cKey, 1000, 32, true);

    $key = substr($rfcdb, 0, 16);
    $iv = substr($rfcdb, 16, 16);

    $cipherTextRaw = openssl_encrypt($toEncrypt, "AES-128-CBC", $key, 1, $iv);
    $cipherTextBase64 = str_replace(array("+", "/"), array("-", "_"), base64_encode($cipherTextRaw));

    return $cipherTextBase64;
}

?>
            
        
            
import base64
import hashlib
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad

def encrypt(to_encrypt, cKey):
    padded = pad(to_encrypt.encode('utf-8'), AES.block_size)

    salt = cKey.encode('utf-8')
    key = hashlib.pbkdf2_hmac('sha1', cKey.encode('utf-8'), salt, 1000, dklen=32)
    iv = key[16:32]
    key = key[:16]
    
    cipher = AES.new(key, AES.MODE_CBC, iv)
    encrypted = cipher.encrypt(padded)
    
    encoded = base64.urlsafe_b64encode(encrypted).decode().replace("+", "-").replace("/", "_")
    return encoded
            
        
            
DateTime dateDebut = DateTime.Today.AddDays(-6);
DateTime dateFin = DateTime.Today;
string cKey = DateTime.Today.ToString("yyyyMMdd") + CleSecrete;
string parameters = string.Concat("CleClient=", CleClient, "&DateDebut=", dateDebut.ToString("yyyy-MM-dd"), "&DateFin=", dateFin.ToString("yyyy-MM-dd"));
string signature = Encrypt(parameters, cKey);
string apiUri = "https://extranet.explore.fr/ExploreAPI/api/Opportunites/MarchesPublics?CleClient=" + CleClient + "&Signature=" + signature;