Merge ssl password 39/98939/8
authorxuegao <xg353y@intl.att.com>
Thu, 28 Nov 2019 14:13:18 +0000 (15:13 +0100)
committerxuegao <xg353y@intl.att.com>
Fri, 29 Nov 2019 15:23:22 +0000 (16:23 +0100)
Use the aaf encrypted ssl password fot server.ssl parameters

Issue-ID: CLAMP-339
Change-Id: I8869bb527f2851c1d298cd03e45327791a8acfab
Signed-off-by: xuegao <xg353y@intl.att.com>
src/main/java/org/onap/clamp/clds/Application.java
src/main/java/org/onap/clamp/clds/config/CamelConfiguration.java
src/main/java/org/onap/clamp/clds/config/SslConfig.java [new file with mode: 0644]
src/main/java/org/onap/clamp/clds/filter/ClampCadiFilter.java
src/main/java/org/onap/clamp/util/PassDecoder.java [new file with mode: 0644]
src/main/resources/application-noaaf.properties
src/main/resources/application.properties
src/test/java/org/onap/clamp/util/PassDecoderTest.java [new file with mode: 0644]
src/test/resources/clds/aaf/org.onap.clamp.keyfile [new file with mode: 0644]

index efc4b12..e41140f 100644 (file)
@@ -29,6 +29,7 @@ import com.att.eelf.configuration.EELFLogger;
 import com.att.eelf.configuration.EELFManager;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.security.KeyStore;
 import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
@@ -39,6 +40,7 @@ import java.util.Enumeration;
 import org.apache.catalina.connector.Connector;
 import org.onap.clamp.clds.util.ClampVersioning;
 import org.onap.clamp.clds.util.ResourceFileUtil;
+import org.onap.clamp.util.PassDecoder;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.boot.SpringApplication;
@@ -135,6 +137,8 @@ public class Application extends SpringBootServletInitializer {
         return tomcat;
     }
 
+
+
     private Connector createRedirectConnector(int redirectSecuredPort) {
         if (redirectSecuredPort <= 0) {
             eelfLogger.warn("HTTP port redirection to HTTPS is disabled because the HTTPS port is 0 (random port) or -1"
@@ -155,10 +159,12 @@ public class Application extends SpringBootServletInitializer {
             if (env.getProperty("server.ssl.key-store") != null) {
 
                 KeyStore keystore = KeyStore.getInstance(env.getProperty("server.ssl.key-store-type"));
-                keystore.load(
-                        ResourceFileUtil.getResourceAsStream(
-                                env.getProperty("server.ssl.key-store").replaceAll("classpath:", "")),
-                        env.getProperty("server.ssl.key-store-password").toCharArray());
+                String password = PassDecoder.decode(env.getProperty("server.ssl.key-store-password"), 
+                        env.getProperty("clamp.config.keyFile"));
+                String keyStore = env.getProperty("server.ssl.key-store");
+                InputStream is = ResourceFileUtil.getResourceAsStream(keyStore.replaceAll("classpath:", ""));
+                keystore.load(is, password.toCharArray());
+
                 Enumeration<String> aliases = keystore.aliases();
                 while (aliases.hasMoreElements()) {
                     String alias = aliases.nextElement();
index 271dc84..949ff1e 100644 (file)
@@ -48,6 +48,7 @@ import org.apache.http.conn.ssl.SSLSocketFactory;
 import org.apache.http.impl.client.HttpClientBuilder;
 import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
 import org.onap.clamp.clds.util.ClampVersioning;
+import org.onap.clamp.util.PassDecoder;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.core.env.Environment;
 import org.springframework.stereotype.Component;
@@ -61,18 +62,24 @@ public class CamelConfiguration extends RouteBuilder {
     @Autowired
     private Environment env;
 
-    private void configureDefaultSslProperties() {
+    private void configureDefaultSslProperties() throws IOException {
         if (env.getProperty("server.ssl.trust-store") != null) {
             URL storeResource = Thread.currentThread().getContextClassLoader()
                 .getResource(env.getProperty("server.ssl.trust-store").replaceAll("classpath:", ""));
             System.setProperty("javax.net.ssl.trustStore", storeResource.getPath());
-            System.setProperty("javax.net.ssl.trustStorePassword", env.getProperty("server.ssl.trust-store-password"));
+            String keyFile = env.getProperty("clamp.config.keyFile");
+            String trustStorePass = PassDecoder.decode(env.getProperty("server.ssl.trust-store-password"),
+                keyFile);
+            System.setProperty("javax.net.ssl.trustStorePassword", trustStorePass);
             System.setProperty("javax.net.ssl.trustStoreType", "jks");
             System.setProperty("ssl.TrustManagerFactory.algorithm", "PKIX");
             storeResource = Thread.currentThread().getContextClassLoader()
                 .getResource(env.getProperty("server.ssl.key-store").replaceAll("classpath:", ""));
             System.setProperty("javax.net.ssl.keyStore", storeResource.getPath());
-            System.setProperty("javax.net.ssl.keyStorePassword", env.getProperty("server.ssl.key-store-password"));
+
+            String keyStorePass = PassDecoder.decode(env.getProperty("server.ssl.key-store-password"),
+                keyFile);
+            System.setProperty("javax.net.ssl.keyStorePassword", keyStorePass);
             System.setProperty("javax.net.ssl.keyStoreType", env.getProperty("server.ssl.key-store-type"));
         }
     }
@@ -81,10 +88,12 @@ public class CamelConfiguration extends RouteBuilder {
         throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException, CertificateException, IOException {
         if (env.getProperty("server.ssl.trust-store") != null) {
             KeyStore truststore = KeyStore.getInstance("JKS");
+            String keyFile = env.getProperty("clamp.config.keyFile");
+            String password = PassDecoder.decode(env.getProperty("server.ssl.trust-store-password"), keyFile);
             truststore.load(
                 Thread.currentThread().getContextClassLoader()
                     .getResourceAsStream(env.getProperty("server.ssl.trust-store").replaceAll("classpath:", "")),
-                env.getProperty("server.ssl.trust-store-password").toCharArray());
+                    password.toCharArray());
 
             TrustManagerFactory trustFactory = TrustManagerFactory.getInstance("PKIX");
             trustFactory.init(truststore);
diff --git a/src/main/java/org/onap/clamp/clds/config/SslConfig.java b/src/main/java/org/onap/clamp/clds/config/SslConfig.java
new file mode 100644 (file)
index 0000000..7c7433e
--- /dev/null
@@ -0,0 +1,97 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ *                             reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+package org.onap.clamp.clds.config;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+
+import org.onap.clamp.clds.util.ResourceFileUtil;
+import org.onap.clamp.util.PassDecoder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.web.ServerProperties;
+import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
+import org.springframework.boot.web.server.Ssl;
+import org.springframework.boot.web.server.SslStoreProvider;
+import org.springframework.boot.web.server.WebServerFactoryCustomizer;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import org.springframework.core.env.Environment;
+import org.springframework.core.io.ResourceLoader;
+
+@Configuration
+@Profile("clamp-ssl-config")
+public class SslConfig {
+    @Autowired
+    private Environment env;
+
+    @Bean
+    WebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatCustomizer(ServerProperties serverProperties,
+            ResourceLoader resourceLoader) {
+        return (tomcat) -> tomcat.setSslStoreProvider(new SslStoreProvider() {
+            @Override
+            public KeyStore getKeyStore() throws KeyStoreException, 
+                    NoSuchAlgorithmException, CertificateException, IOException {
+                KeyStore keystore = KeyStore.getInstance(env.getProperty("server.ssl.key-store-type"));
+                String password = PassDecoder.decode(env.getProperty("server.ssl.key-store-password"), 
+                    env.getProperty("clamp.config.keyFile"));
+                String keyStore = env.getProperty("server.ssl.key-store");
+                InputStream is = ResourceFileUtil.getResourceAsStream(keyStore.replaceAll("classpath:", ""));
+                keystore.load(is, password.toCharArray());
+                return keystore;
+            }
+
+            @Override
+            public KeyStore getTrustStore() throws KeyStoreException, 
+                    NoSuchAlgorithmException, CertificateException, IOException {
+                    KeyStore truststore = KeyStore.getInstance("JKS");
+                    String password = PassDecoder.decode(env.getProperty("server.ssl.trust-store-password"), 
+                            env.getProperty("clamp.config.keyFile"));
+                    truststore.load(
+                        Thread.currentThread().getContextClassLoader()
+                            .getResourceAsStream(env.getProperty("server.ssl.trust-store")
+                                .replaceAll("classpath:", "")),
+                            password.toCharArray());
+                    return truststore;
+            }
+        });
+    }
+
+    @Bean
+    WebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatSslCustomizer(ServerProperties serverProperties,
+            ResourceLoader resourceLoader) {
+        return (tomcat) -> tomcat.setSsl(new Ssl() {
+            @Override
+            public String getKeyPassword() {
+                    String password = PassDecoder.decode(env.getProperty("server.ssl.key-password"), 
+                            env.getProperty("clamp.config.keyFile"));
+                    return password;
+            }
+        });
+    }
+}
\ No newline at end of file
index 68544de..9e04bd0 100644 (file)
@@ -60,19 +60,19 @@ public class ClampCadiFilter extends CadiFilter {
     @Value("${server.ssl.key-store:#{null}}")
     private String keyStore;
 
-    @Value("${clamp.config.cadi.cadiKeystorePassword:#{null}}")
+    @Value("${server.ssl.key-store-password:#{null}}")
     private String keyStorePass;
 
     @Value("${server.ssl.trust-store:#{null}}")
     private String trustStore;
 
-    @Value("${clamp.config.cadi.cadiTruststorePassword:#{null}}")
+    @Value("${server.ssl.trust-store-password:#{null}}")
     private String trustStorePass;
 
     @Value("${server.ssl.key-alias:clamp@clamp.onap.org}")
     private String alias;
 
-    @Value("${clamp.config.cadi.keyFile:#{null}}")
+    @Value("${clamp.config.keyFile:#{null}}")
     private String keyFile;
 
     @Value("${clamp.config.cadi.cadiLoglevel:#{null}}")
@@ -152,7 +152,8 @@ public class ClampCadiFilter extends CadiFilter {
                         .generateCertificate(new ByteArrayInputStream(
                                 URLDecoder.decode(certHeader, StandardCharsets.UTF_8.toString()).getBytes()));
                 X509Certificate caCert = (X509Certificate) certificateFactory
-                        .generateCertificate(new ByteArrayInputStream(ResourceFileUtil.getResourceAsString("clds/aaf/ssl/ca-certs.pem").getBytes()));
+                        .generateCertificate(new ByteArrayInputStream(
+                        ResourceFileUtil.getResourceAsString("clds/aaf/ssl/ca-certs.pem").getBytes()));
 
                 X509Certificate[] certifArray = ((X509Certificate[]) request
                         .getAttribute("javax.servlet.request.X509Certificate"));
diff --git a/src/main/java/org/onap/clamp/util/PassDecoder.java b/src/main/java/org/onap/clamp/util/PassDecoder.java
new file mode 100644 (file)
index 0000000..70a4747
--- /dev/null
@@ -0,0 +1,74 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ *                             reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ */
+
+package org.onap.clamp.util;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import org.onap.aaf.cadi.Symm;
+import org.onap.clamp.clds.util.ResourceFileUtil;
+
+/**
+ * PassDecoder for decrypting the truststore and keystore password.
+ */
+public class PassDecoder {
+    /**
+     * Used to log PassDecoder class.
+     */
+    private static final EELFLogger logger = EELFManager.getInstance().getLogger(PassDecoder.class);
+
+    /**
+     * Decode the password.
+     * @param encryptedPass The encrypted password
+     * @param keyFileIs The key file in InputStream format
+     */
+    public static String decode(String encryptedPass, String keyFile) {
+        if (null == keyFile) {
+            logger.debug("Key file is not defined, thus password will not be decrypted");
+            return encryptedPass;
+        }
+        if (null == encryptedPass) {
+            logger.error("Encrypted password is not defined");
+            return null;
+        }
+        try {
+            InputStream is;
+            if (keyFile.contains("classpath:")) {
+                is = ResourceFileUtil.getResourceAsStream(keyFile.replaceAll("classpath:", ""));
+            } else {
+                File key = new File(keyFile);
+                is = new FileInputStream(key);
+            }
+            Symm symm = Symm.obtain(is);
+
+            return symm.depass(encryptedPass);
+        } catch (IOException e) {
+            logger.error("Exception occurred during the key decryption", e);
+            return null;
+        }
+    }
+}
index 79466c8..d389b21 100644 (file)
@@ -55,21 +55,25 @@ server.port=8443
 ## Config part for Server certificates
 # Can be a classpath parameter instead of file:/
 server.ssl.key-store=classpath:/clds/aaf/org.onap.clamp.p12
-server.ssl.key-store-password=China in the Spring
-server.ssl.key-password=China in the Spring
+server.ssl.key-store-password=enc:WWCxchk4WGBNSvuzLq3MLjMs5ObRybJtts5AI0XD1Vc
+server.ssl.key-password=enc:WWCxchk4WGBNSvuzLq3MLjMs5ObRybJtts5AI0XD1Vc
 server.ssl.key-store-type=PKCS12
 server.ssl.key-alias=clamp@clamp.onap.org
 
 ## Config part for Client certificates
 server.ssl.client-auth=want
 server.ssl.trust-store=classpath:/clds/aaf/truststoreONAPall.jks
-server.ssl.trust-store-password=changeit
+server.ssl.trust-store-password=enc:iDnPBBLq_EMidXlMa1FEuBR8TZzYxrCg66vq_XfLHdJ
+
+# The key file used to decode the key store and trust store password
+# If not defined, the key store and trust store password will not be decrypted
+clamp.config.keyFile=classpath:/clds/aaf/org.onap.clamp.keyfile
 
 #server.http-to-https-redirection.port=8080
 
 server.servlet.context-path=/
 #Modified engine-rest applicationpath
-spring.profiles.active=clamp-default,clamp-default-user,clamp-sdc-controller-new
+spring.profiles.active=clamp-default,clamp-default-user,clamp-sdc-controller-new,clamp-ssl-config
 spring.http.converters.preferred-json-mapper=gson
 
 #The max number of active threads in this pool
index 3ac6fa2..b97d643 100644 (file)
@@ -60,21 +60,25 @@ server.port=8443
 ## Config part for Server certificates
 # Can be a classpath parameter instead of file:/
 server.ssl.key-store=classpath:/clds/aaf/org.onap.clamp.p12
-server.ssl.key-store-password=China in the Spring
-server.ssl.key-password=China in the Spring
+server.ssl.key-store-password=enc:WWCxchk4WGBNSvuzLq3MLjMs5ObRybJtts5AI0XD1Vc
+server.ssl.key-password=enc:WWCxchk4WGBNSvuzLq3MLjMs5ObRybJtts5AI0XD1Vc
 server.ssl.key-store-type=PKCS12
 server.ssl.key-alias=clamp@clamp.onap.org
 
+# The key file used to decode the key store and trust store password
+# If not defined, the key store and trust store password will not be decrypted
+clamp.config.keyFile=classpath:/clds/aaf/org.onap.clamp.keyfile
+
 ## Config part for Client certificates
 server.ssl.client-auth=want
 server.ssl.trust-store=classpath:/clds/aaf/truststoreONAPall.jks
-server.ssl.trust-store-password=changeit
+server.ssl.trust-store-password=enc:iDnPBBLq_EMidXlMa1FEuBR8TZzYxrCg66vq_XfLHdJ
 
 #server.http-to-https-redirection.port=8080
 
 server.servlet.context-path=/
 #Modified engine-rest applicationpath
-spring.profiles.active=clamp-default,clamp-aaf-authentication,clamp-sdc-controller-new
+spring.profiles.active=clamp-default,clamp-aaf-authentication,clamp-sdc-controller-new,clamp-ssl-config
 spring.http.converters.preferred-json-mapper=gson
 
 #The max number of active threads in this pool
@@ -240,13 +244,10 @@ clamp.config.security.permission.instance=dev
 clamp.config.security.authentication.class=org.onap.aaf.cadi.principal.X509Principal
 
 #AAF related parameters
-clamp.config.cadi.keyFile=classpath:/clds/aaf/org.onap.clamp.keyfile
 clamp.config.cadi.cadiLoglevel=DEBUG
 clamp.config.cadi.cadiLatitude=10
 clamp.config.cadi.cadiLongitude=10
 clamp.config.cadi.aafLocateUrl=https://aaf-locate:8095
-clamp.config.cadi.cadiKeystorePassword=enc:WWCxchk4WGBNSvuzLq3MLjMs5ObRybJtts5AI0XD1Vc
-clamp.config.cadi.cadiTruststorePassword=enc:iDnPBBLq_EMidXlMa1FEuBR8TZzYxrCg66vq_XfLHdJ
 clamp.config.cadi.oauthTokenUrl= https://AAF_LOCATE_URL/locate/onap.org.osaaf.aaf.token:2.1/token
 clamp.config.cadi.oauthIntrospectUrll=https://AAF_LOCATE_URL/locate/onap.org.osaaf.aaf.introspect:2.1/introspect
 clamp.config.cadi.aafEnv=DEV
diff --git a/src/test/java/org/onap/clamp/util/PassDecoderTest.java b/src/test/java/org/onap/clamp/util/PassDecoderTest.java
new file mode 100644 (file)
index 0000000..56443e3
--- /dev/null
@@ -0,0 +1,52 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ *                             reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ * 
+ */
+
+package org.onap.clamp.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import org.junit.Test;
+
+public class PassDecoderTest {
+
+    private final String encrypted = "enc:WWCxchk4WGBNSvuzLq3MLjMs5ObRybJtts5AI0XD1Vc";
+
+    @Test
+    public final void testDecryptionNoKeyfile() throws Exception {
+        String decodedPass = PassDecoder.decode(encrypted, null);
+        assertEquals(decodedPass, encrypted);
+    }
+
+    @Test
+    public final void testDecryptionNoPassword() throws Exception {
+        String decodedPass = PassDecoder.decode(null, "src/test/resources/clds/aaf/org.onap.clamp.keyfile");
+        assertNull(decodedPass);
+    }
+
+    @Test
+    public final void testDecryption() throws Exception {
+        String decodedPass = PassDecoder.decode(encrypted, "src/test/resources/clds/aaf/org.onap.clamp.keyfile");
+        assertEquals(decodedPass, "China in the Spring");
+    }
+}
diff --git a/src/test/resources/clds/aaf/org.onap.clamp.keyfile b/src/test/resources/clds/aaf/org.onap.clamp.keyfile
new file mode 100644 (file)
index 0000000..c2521fc
--- /dev/null
@@ -0,0 +1,27 @@
+kzJMxgphAoBxJz1_vYjxx-V87fahDQdYUqBIyWhZp8ojXdNpmB-96T9CvgJScJynbLcqw2Cj2CYx
+wd97vFOYhlyz5zK3tSyIuydOkVGJsJ1S4PviTtjhiJvNourJNDHgtas1Y1y2fQ5_8aVxj-s4W72N
+MNYhkeTinaQx_d_5hkBPABJlgCxKLnmxHo2jAJktnZYa5t5h48m7KiUx_RVEkQVtEvux-7vgXaC4
+ymTXj6zI9XoMTVxM0OAl4y7kBiUoOUaxS4tVKV34RJYNNqBjiUTQa_ag-KeUacRABk1ozfwzpvE5
+Sjz8WCy0L-LtCQnapkhKLt04ndCZtw8LDJ-Zz0ZgR2PVIPpTgs9VnVuOi5jf4LzTrtUatvOWkKB9
+drXKzp6cNXnZ0jkD3vV1BzqzhynKnZR2o_ilZv5CTTdpGUt906N_DwZuX6LfcV_7yvjX42bTfeIR
+ycPtodFPXlqqn9VUyh5nOauJlnOHAQmSDzjMEgjy17nQX3Ad7s4BfvujzUl-d0MqB_HCKbaW32UT
+xcY-0JfI1Y-2IdYfIkUdhVmxop6sSg0jAobWzgCRoRQkP3a2iIlKdfMyskshoWKIDVtlr-3fkDEb
+x_b_o1rRoUfzUzxEdphaUAq80Sc0i77ZLT3KF9vJOhyU_pBnApYFxVk7Hkk3VRxJKS7jyL4H7k1x
+2m5-2G8fB9XbYZT82xmAquNx4oBdpwj3_ncGF9YRF94K6NZgqemT5iWhpXMoelSU1blASgT3qlTm
+B6YgbD5owExNHwRVd8KeRsYrOnBWUiktsIhXFhNZmDUNWMFGQ2KxEcOt1tJwsQDehJFgY_l1JQ0d
+643wJ7rTJkGkYX309cydRQUX4Z0ckSQS9LhMd9stxF5XOHlvHdbW0pXNS7SaLbzKCVldUgncvI6z
+KWkwrWbftrZK2RT1UZKNngQDMGOk9OhbHAs7YzhFNFARZoRNobIv5tZVDomy-YgJb9-mD1UTkRBL
+WXOyoryDlgKrgFsgHclGDI1UFO5N-JfebPKxbP505f4924hxF2r8bspvVW8ZtHQo_SJmhauOX8n_
+eN_LK43LB9k53WAHZ_utvs0s6wGf7I73oj_N7DIFaHTDSm_MhDsFDLVG_wUzCpZ5FP2uL3nnqMkF
+Ob-l1fywfmfOmrz1BY6g4sRPPeWXuclYTnRnDRu5VQyc7_aBEVkyt3zw0JEex0vJNFUJl3pYjS55
+GplAB6p7VbS9ceZEtc5Z3qFIVHEzKWZxT190E23t_LlMuEoQ1zaqdHynNaMs61-q_A2aHRiTqlRm
+7FahVB3RX4AVLl23mu4u3A9ZDXc40nzjs9mwOVsuKlPvQ2rteDUG1njr2R1_V_MyQuoJjdfbIkPG
+4eF0QzlSMdbkeprdQxSfV5YT-yPpkBxSsCMMM43sKm4Hy7_CUdvp4Iayrp3vtK3oYMuCGi6qTadz
+KzxfTf8meKan3eMZW4RLByyniH5nQnX_KGfBly05AmFyVH_j0fyOg-48kDhtEKeqmDnP4C01jOID
+Ip_AKaB6e0GwsHzVTLZOklHwu_qzsaTzchBOG_dJJju7bxY7qv78Pa92wZIP311gSCVbc-gxxbsR
+qI555twmYEoasFm4xz10OYDOkvM1E1Rtxu3ymRLZpe6AoyFBVzEW7Dncdw7O98dKcgrp8ZlQ_8Wg
+5zZH0Cic7xnIZ0bNZyQXw56CSUiXVWuwVY3e0djXP3F-FO5gP8VTxbpW4C0t6McXAOlvSEfFKxN7
+u6OBeOKwjrtHaJk2ghF8MUcpDXanhbAgHez9larGlscCkgvoRLNaRH9GIdSVgY3HtNhJRaJIq01S
+OGeBjC5J4o-nTrqRFkwyDAYcPL373eYX1dBFFVHR-4q50H9m_zMxZHXETafxzV4DT3Qi8Sxh3uaS
+ZX7mRaNaOE0uC1n87_IZ9WhrwIQaZng2lnd9yZ-4rx8fB8WA8KQzifzvHAcMb_HV10JWGaz5A2Rm
+EXDsfexQC6CqYg5rdzzlNWDPNlHy5ubyz7fRXZ99uIwBY9aJcvCXCiEXJkC6utj3NcXQrJmk
\ No newline at end of file