001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.license.util;
016    
017    import com.liferay.portal.kernel.cluster.ClusterExecutorUtil;
018    import com.liferay.portal.kernel.cluster.ClusterNode;
019    import com.liferay.portal.kernel.cluster.ClusterNodeResponse;
020    import com.liferay.portal.kernel.cluster.ClusterNodeResponses;
021    import com.liferay.portal.kernel.cluster.ClusterRequest;
022    import com.liferay.portal.kernel.cluster.FutureClusterResponses;
023    import com.liferay.portal.kernel.json.JSONFactoryUtil;
024    import com.liferay.portal.kernel.json.JSONObject;
025    import com.liferay.portal.kernel.log.Log;
026    import com.liferay.portal.kernel.log.LogFactoryUtil;
027    import com.liferay.portal.kernel.util.Base64;
028    import com.liferay.portal.kernel.util.CharPool;
029    import com.liferay.portal.kernel.util.Constants;
030    import com.liferay.portal.kernel.util.FileUtil;
031    import com.liferay.portal.kernel.util.GetterUtil;
032    import com.liferay.portal.kernel.util.Http;
033    import com.liferay.portal.kernel.util.MethodHandler;
034    import com.liferay.portal.kernel.util.MethodKey;
035    import com.liferay.portal.kernel.util.ParamUtil;
036    import com.liferay.portal.kernel.util.ReleaseInfo;
037    import com.liferay.portal.kernel.util.StringPool;
038    import com.liferay.portal.kernel.util.StringUtil;
039    import com.liferay.portal.kernel.util.Validator;
040    import com.liferay.portal.util.ClassLoaderUtil;
041    import com.liferay.portal.util.PortalUtil;
042    import com.liferay.portal.util.PropsUtil;
043    import com.liferay.portal.util.PropsValues;
044    import com.liferay.util.Encryptor;
045    
046    import java.io.File;
047    import java.io.InputStream;
048    import java.io.OutputStream;
049    
050    import java.net.Inet4Address;
051    import java.net.InetAddress;
052    import java.net.InetSocketAddress;
053    import java.net.NetworkInterface;
054    import java.net.Proxy;
055    import java.net.URL;
056    import java.net.URLConnection;
057    
058    import java.security.Key;
059    import java.security.KeyFactory;
060    import java.security.PublicKey;
061    import java.security.SecureRandom;
062    import java.security.spec.X509EncodedKeySpec;
063    
064    import java.util.Arrays;
065    import java.util.Collections;
066    import java.util.HashMap;
067    import java.util.HashSet;
068    import java.util.Iterator;
069    import java.util.List;
070    import java.util.Map;
071    import java.util.Set;
072    import java.util.TreeMap;
073    import java.util.concurrent.TimeUnit;
074    import java.util.regex.Matcher;
075    import java.util.regex.Pattern;
076    
077    import javax.crypto.KeyGenerator;
078    
079    import javax.servlet.http.HttpServletRequest;
080    
081    import org.apache.commons.io.IOUtils;
082    
083    /**
084     * @author Amos Fong
085     */
086    public class LicenseUtil {
087    
088            public static final String LICENSE_REPOSITORY_DIR =
089                    PropsValues.LIFERAY_HOME.concat("/data/license");
090    
091            public static final String LICENSE_SERVER_URL = GetterUtil.get(
092                    PropsUtil.get("license.server.url"), "https://www.liferay.com");
093    
094            public static Map<String, String> getClusterServerInfo(String clusterNodeId)
095                    throws Exception {
096    
097                    List<ClusterNode> clusterNodes = ClusterExecutorUtil.getClusterNodes();
098    
099                    ClusterNode clusterNode = null;
100    
101                    for (ClusterNode curClusterNode : clusterNodes) {
102                            String curClusterNodeId = curClusterNode.getClusterNodeId();
103    
104                            if (curClusterNodeId.equals(clusterNodeId)) {
105                                    clusterNode = curClusterNode;
106    
107                                    break;
108                            }
109                    }
110    
111                    if (clusterNode == null) {
112                            return null;
113                    }
114    
115                    try {
116                            if (clusterNode.equals(ClusterExecutorUtil.getLocalClusterNode())) {
117                                    return getServerInfo();
118                            }
119    
120                            ClusterRequest clusterRequest = ClusterRequest.createUnicastRequest(
121                                    _getServerInfoMethodHandler, clusterNodeId);
122    
123                            FutureClusterResponses futureClusterResponses =
124                                    ClusterExecutorUtil.execute(clusterRequest);
125    
126                            ClusterNodeResponses clusterNodeResponses =
127                                    futureClusterResponses.get(20000, TimeUnit.MILLISECONDS);
128    
129                            ClusterNodeResponse clusterNodeResponse =
130                                    clusterNodeResponses.getClusterResponse(clusterNode);
131    
132                            return (Map<String, String>)clusterNodeResponse.getResult();
133                    }
134                    catch (Exception e) {
135                            _log.error(e, e);
136    
137                            throw e;
138                    }
139            }
140    
141            /**
142             * @deprecated As of 6.2.0, replaced by {@link PortalUtil#getComputerName()}
143             */
144            public static String getHostName() {
145                    return PortalUtil.getComputerName();
146            }
147    
148            public static Set<String> getIpAddresses() {
149                    if (_ipAddresses != null) {
150                            return new HashSet<String>(_ipAddresses);
151                    }
152    
153                    _ipAddresses = new HashSet<String>();
154    
155                    try {
156                            List<NetworkInterface> networkInterfaces = Collections.list(
157                                    NetworkInterface.getNetworkInterfaces());
158    
159                            for (NetworkInterface networkInterface : networkInterfaces) {
160                                    List<InetAddress> inetAddresses = Collections.list(
161                                            networkInterface.getInetAddresses());
162    
163                                    for (InetAddress inetAddress : inetAddresses) {
164                                            if (inetAddress.isLinkLocalAddress() ||
165                                                    inetAddress.isLoopbackAddress() ||
166                                                    !(inetAddress instanceof Inet4Address)) {
167    
168                                                    continue;
169                                            }
170    
171                                            _ipAddresses.add(inetAddress.getHostAddress());
172                                    }
173                            }
174                    }
175                    catch (Exception e) {
176                            _log.error("Unable to read local server's IP addresses");
177    
178                            _log.error(e, e);
179                    }
180    
181                    return new HashSet<String>(_ipAddresses);
182            }
183    
184            public static Set<String> getMacAddresses() {
185                    if (_macAddresses != null) {
186                            return new HashSet<String>(_macAddresses);
187                    }
188    
189                    Set<String> macAddresses = new HashSet<String>();
190    
191                    String osName = System.getProperty("os.name");
192    
193                    String executable = null;
194                    String arguments = null;
195    
196                    if (StringUtil.startsWith(osName, "win")) {
197                            executable = "ipconfig";
198                            arguments = "/all";
199                    }
200                    else {
201                            if (StringUtil.startsWith(osName, "aix")) {
202                                    executable = "netstat";
203                                    arguments = "-ina";
204                            }
205                            else {
206                                    executable = "ifconfig";
207                                    arguments = "-a";
208                            }
209    
210                            File sbinDir = new File("/sbin", executable);
211    
212                            if (sbinDir.exists()) {
213                                    executable = "/sbin/".concat(executable);
214                            }
215                    }
216    
217                    try {
218                            Runtime runtime = Runtime.getRuntime();
219    
220                            Process process = runtime.exec(
221                                    new String[] {executable, arguments});
222    
223                            macAddresses = getMacAddresses(osName, process.getInputStream());
224                    }
225                    catch (Exception e) {
226                            _log.error(e, e);
227                    }
228    
229                    _macAddresses = macAddresses;
230    
231                    return new HashSet<String>(macAddresses);
232            }
233    
234            public static Set<String> getMacAddresses(
235                            String osName, InputStream processInputStream)
236                    throws Exception {
237    
238                    Set<String> macAddresses = new HashSet<String>();
239    
240                    Pattern macAddressPattern = _macAddressPattern1;
241    
242                    if (StringUtil.startsWith(osName, "aix")) {
243                            macAddressPattern = _macAddressPattern2;
244                    }
245    
246                    String processOutput = StringUtil.read(processInputStream);
247    
248                    String[] lines = StringUtil.split(processOutput, CharPool.NEW_LINE);
249    
250                    for (String line : lines) {
251                            Matcher matcher = macAddressPattern.matcher(line);
252    
253                            if (!matcher.find()) {
254                                    continue;
255                            }
256    
257                            String macAddress = matcher.group(1);
258    
259                            macAddress = StringUtil.toLowerCase(macAddress);
260                            macAddress = macAddress.replace(CharPool.DASH, CharPool.COLON);
261                            macAddress = macAddress.replace(CharPool.PERIOD, CharPool.COLON);
262    
263                            StringBuilder sb = new StringBuilder(17);
264    
265                            sb.append(macAddress);
266    
267                            for (int i = 1; i < 5; ++i) {
268                                    int pos = (i * 3) - 1;
269    
270                                    if (sb.charAt(pos) != CharPool.COLON) {
271                                            sb.insert((i - 1) * 3, CharPool.NUMBER_0);
272                                    }
273                            }
274    
275                            if (sb.length() < 17) {
276                                    sb.insert(15, CharPool.NUMBER_0);
277                            }
278    
279                            macAddress = sb.toString();
280    
281                            macAddresses.add(macAddress);
282                    }
283    
284                    return macAddresses;
285            }
286    
287            public static byte[] getServerIdBytes() throws Exception {
288                    if (_serverIdBytes != null) {
289                            return _serverIdBytes;
290                    }
291    
292                    File serverIdFile = new File(
293                            LICENSE_REPOSITORY_DIR + "/server/serverId");
294    
295                    if (!serverIdFile.exists()) {
296                            return new byte[0];
297                    }
298    
299                    _serverIdBytes = FileUtil.getBytes(serverIdFile);
300    
301                    return _serverIdBytes;
302            }
303    
304            public static Map<String, String> getServerInfo() {
305                    Map<String, String> serverInfo = new HashMap<String, String>();
306    
307                    serverInfo.put("hostName", PortalUtil.getComputerName());
308                    serverInfo.put("ipAddresses", StringUtil.merge(getIpAddresses()));
309                    serverInfo.put("macAddresses", StringUtil.merge(getMacAddresses()));
310    
311                    return serverInfo;
312            }
313    
314            public static void registerOrder(HttpServletRequest request) {
315                    String orderUuid = ParamUtil.getString(request, "orderUuid");
316                    String productEntryName = ParamUtil.getString(
317                            request, "productEntryName");
318                    int maxServers = ParamUtil.getInteger(request, "maxServers");
319    
320                    List<ClusterNode> clusterNodes = ClusterExecutorUtil.getClusterNodes();
321    
322                    if ((clusterNodes.size() <= 1) || Validator.isNull(productEntryName) ||
323                            Validator.isNull(orderUuid)) {
324    
325                            Map<String, Object> attributes = registerOrder(
326                                    orderUuid, productEntryName, maxServers);
327    
328                            for (Map.Entry<String, Object> entry : attributes.entrySet()) {
329                                    request.setAttribute(entry.getKey(), entry.getValue());
330                            }
331                    }
332                    else {
333                            for (ClusterNode clusterNode : clusterNodes) {
334                                    boolean register = ParamUtil.getBoolean(
335                                            request, clusterNode.getClusterNodeId() + "_register");
336    
337                                    if (!register) {
338                                            continue;
339                                    }
340    
341                                    try {
342                                            _registerClusterOrder(
343                                                    request, clusterNode, orderUuid, productEntryName,
344                                                    maxServers);
345                                    }
346                                    catch (Exception e) {
347                                            _log.error(e, e);
348    
349                                            InetAddress inetAddress = clusterNode.getInetAddress();
350    
351                                            String message =
352                                                    "Error contacting " + inetAddress.getHostName();
353    
354                                            if (clusterNode.getPort() != -1) {
355                                                    message += StringPool.COLON + clusterNode.getPort();
356                                            }
357    
358                                            request.setAttribute(
359                                                    clusterNode.getClusterNodeId() + "_ERROR_MESSAGE",
360                                                    message);
361                                    }
362                            }
363                    }
364            }
365    
366            public static Map<String, Object> registerOrder(
367                    String orderUuid, String productEntryName, int maxServers) {
368    
369                    Map<String, Object> attributes = new HashMap<String, Object>();
370    
371                    if (Validator.isNull(orderUuid)) {
372                            return attributes;
373                    }
374    
375                    try {
376                            JSONObject jsonObject = _createRequest(
377                                    orderUuid, productEntryName, maxServers);
378    
379                            String response = sendRequest(jsonObject.toString());
380    
381                            JSONObject responseJSONObject = JSONFactoryUtil.createJSONObject(
382                                    response);
383    
384                            attributes.put(
385                                    "ORDER_PRODUCT_ID", responseJSONObject.getString("productId"));
386                            attributes.put(
387                                    "ORDER_PRODUCTS", _getOrderProducts(responseJSONObject));
388    
389                            String errorMessage = responseJSONObject.getString("errorMessage");
390    
391                            if (Validator.isNotNull(errorMessage)) {
392                                    attributes.put("ERROR_MESSAGE", errorMessage);
393    
394                                    return attributes;
395                            }
396    
397                            String licenseXML = responseJSONObject.getString("licenseXML");
398    
399                            if (Validator.isNotNull(licenseXML)) {
400                                    LicenseManagerUtil.registerLicense(responseJSONObject);
401    
402                                    attributes.clear();
403                                    attributes.put(
404                                            "SUCCESS_MESSAGE",
405                                            "Your license has been successfully registered.");
406                            }
407                    }
408                    catch (Exception e) {
409                            _log.error(e, e);
410    
411                            attributes.put(
412                                    "ERROR_MESSAGE",
413                                    "There was an error contacting " + LICENSE_SERVER_URL);
414                    }
415    
416                    return attributes;
417            }
418    
419            public static String sendRequest(String request) throws Exception {
420                    InputStream inputStream = null;
421                    OutputStream outputStream = null;
422    
423                    try {
424                            String serverURL = LICENSE_SERVER_URL;
425    
426                            if (!serverURL.endsWith(StringPool.SLASH)) {
427                                    serverURL += StringPool.SLASH;
428                            }
429    
430                            serverURL += "osb-portlet/license";
431    
432                            URL url = new URL(serverURL);
433    
434                            URLConnection connection = null;
435    
436                            if (Validator.isNotNull(_PROXY_URL)) {
437                                    if (_log.isInfoEnabled()) {
438                                            _log.info(
439                                                    "Using proxy " + _PROXY_URL + StringPool.COLON +
440                                                            _PROXY_PORT);
441                                    }
442    
443                                    Proxy proxy = new Proxy(
444                                            Proxy.Type.HTTP,
445                                            new InetSocketAddress(_PROXY_URL, _PROXY_PORT));
446    
447                                    connection = url.openConnection(proxy);
448    
449                                    if (Validator.isNotNull(_PROXY_USER_NAME)) {
450                                            String login =
451                                                    _PROXY_USER_NAME + StringPool.COLON + _PROXY_PASSWORD;
452    
453                                            String encodedLogin = Base64.encode(login.getBytes());
454    
455                                            connection.setRequestProperty(
456                                                    "Proxy-Authorization", "Basic " + encodedLogin);
457                                    }
458                            }
459                            else {
460                                    connection = url.openConnection();
461                            }
462    
463                            connection.setDoOutput(true);
464    
465                            outputStream = connection.getOutputStream();
466    
467                            outputStream.write(_encryptRequest(serverURL, request));
468    
469                            String response = _decryptResponse(
470                                    serverURL, connection.getInputStream());
471    
472                            if (_log.isDebugEnabled()) {
473                                    _log.debug("Server response: " + response);
474                            }
475    
476                            if (Validator.isNull(response)) {
477                                    throw new Exception("Server response is null");
478                            }
479    
480                            return response;
481                    }
482                    finally {
483                            try {
484                                    if (inputStream != null) {
485                                            inputStream.close();
486                                    }
487                            }
488                            catch (Exception e) {
489                            }
490    
491                            try {
492                                    if (outputStream != null) {
493                                            outputStream.close();
494                                    }
495                            }
496                            catch (Exception e) {
497                            }
498                    }
499            }
500    
501            public static void writeServerProperties(byte[] serverIdBytes)
502                    throws Exception {
503    
504                    File serverIdFile = new File(
505                            LICENSE_REPOSITORY_DIR + "/server/serverId");
506    
507                    FileUtil.write(serverIdFile, serverIdBytes);
508            }
509    
510            private static JSONObject _createRequest(
511                            String orderUuid, String productEntryName, int maxServers)
512                    throws Exception {
513    
514                    JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
515    
516                    jsonObject.put("version", 2);
517                    jsonObject.put("orderUuid", orderUuid);
518                    jsonObject.put("liferayVersion", ReleaseInfo.getBuildNumber());
519    
520                    if (Validator.isNull(productEntryName)) {
521                            jsonObject.put(Constants.CMD, "QUERY");
522                    }
523                    else {
524                            jsonObject.put(Constants.CMD, "REGISTER");
525    
526                            if (productEntryName.startsWith("basic")) {
527                                    jsonObject.put("productEntryName", "basic");
528    
529                                    if (productEntryName.equals("basic-cluster")) {
530                                            jsonObject.put("cluster", true);
531                                            jsonObject.put("maxServers", maxServers);
532                                    }
533                                    else if (productEntryName.startsWith("basic-")) {
534                                            String[] productNameArray = StringUtil.split(
535                                                    productEntryName, StringPool.DASH);
536    
537                                            if (productNameArray.length >= 3) {
538                                                    jsonObject.put("offeringEntryId", productNameArray[1]);
539                                                    jsonObject.put("clusterId", productNameArray[2]);
540                                            }
541                                    }
542                            }
543                            else {
544                                    jsonObject.put("productEntryName", productEntryName);
545                            }
546    
547                            jsonObject.put("hostName", PortalUtil.getComputerName());
548                            jsonObject.put("ipAddresses", StringUtil.merge(getIpAddresses()));
549                            jsonObject.put("macAddresses", StringUtil.merge(getMacAddresses()));
550                            jsonObject.put("serverId", Arrays.toString(getServerIdBytes()));
551                    }
552    
553                    return jsonObject;
554            }
555    
556            private static String _decryptResponse(
557                            String serverURL, InputStream inputStream)
558                    throws Exception {
559    
560                    if (serverURL.startsWith(Http.HTTPS)) {
561                            return StringUtil.read(inputStream);
562                    }
563    
564                    byte[] bytes = IOUtils.toByteArray(inputStream);
565    
566                    if ((bytes == null) || (bytes.length <= 0)) {
567                            return null;
568                    }
569    
570                    bytes = Encryptor.decryptUnencodedAsBytes(_symmetricKey, bytes);
571    
572                    return new String(bytes, StringPool.UTF8);
573            }
574    
575            private static byte[] _encryptRequest(String serverURL, String request)
576                    throws Exception {
577    
578                    byte[] bytes = request.getBytes(StringPool.UTF8);
579    
580                    if (serverURL.startsWith(Http.HTTPS)) {
581                            return bytes;
582                    }
583    
584                    JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
585    
586                    bytes = Encryptor.encryptUnencoded(_symmetricKey, bytes);
587    
588                    jsonObject.put("content", Base64.objectToString(bytes));
589                    jsonObject.put("key", _encryptedSymmetricKey);
590    
591                    return jsonObject.toString().getBytes(StringPool.UTF8);
592            }
593    
594            private static Map<String, String> _getOrderProducts(
595                    JSONObject jsonObject) {
596    
597                    JSONObject productsJSONObject = jsonObject.getJSONObject(
598                            "productsJSONObject");
599    
600                    if (productsJSONObject == null) {
601                            return null;
602                    }
603    
604                    Map<String, String> sortedMap = new TreeMap<String, String>(
605                            String.CASE_INSENSITIVE_ORDER);
606    
607                    Iterator<String> itr = productsJSONObject.keys();
608    
609                    while (itr.hasNext()) {
610                            String key = itr.next();
611    
612                            sortedMap.put(key, productsJSONObject.getString(key));
613                    }
614    
615                    return sortedMap;
616            }
617    
618            private static void _initKeys() {
619                    ClassLoader classLoader = ClassLoaderUtil.getPortalClassLoader();
620    
621                    if ((classLoader == null) || (_encryptedSymmetricKey != null)) {
622                            return;
623                    }
624    
625                    try {
626                            URL url = classLoader.getResource(
627                                    "com/liferay/portal/license/public.key");
628    
629                            byte[] bytes = IOUtils.toByteArray(url.openStream());
630    
631                            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(
632                                    bytes);
633    
634                            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
635    
636                            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
637    
638                            KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
639    
640                            keyGenerator.init(128, new SecureRandom());
641    
642                            _symmetricKey = keyGenerator.generateKey();
643    
644                            byte[] encryptedSymmetricKey = Encryptor.encryptUnencoded(
645                                    publicKey, _symmetricKey.getEncoded());
646    
647                            _encryptedSymmetricKey = Base64.objectToString(
648                                    encryptedSymmetricKey);
649                    }
650                    catch (Exception e) {
651                            _log.error(e, e);
652                    }
653            }
654    
655            private static void _registerClusterOrder(
656                            HttpServletRequest request, ClusterNode clusterNode,
657                            String orderUuid, String productEntryName, int maxServers)
658                    throws Exception {
659    
660                    MethodHandler methodHandler = new MethodHandler(
661                            _registerOrderMethodKey, orderUuid, productEntryName, maxServers);
662    
663                    ClusterRequest clusterRequest = ClusterRequest.createUnicastRequest(
664                            methodHandler, clusterNode.getClusterNodeId());
665    
666                    FutureClusterResponses futureClusterResponses =
667                            ClusterExecutorUtil.execute(clusterRequest);
668    
669                    ClusterNodeResponses clusterNodeResponses = futureClusterResponses.get(
670                            20000, TimeUnit.MILLISECONDS);
671    
672                    ClusterNodeResponse clusterNodeResponse =
673                            clusterNodeResponses.getClusterResponse(clusterNode);
674    
675                    Map<String, Object> attributes =
676                            (Map<String, Object>)clusterNodeResponse.getResult();
677    
678                    for (Map.Entry<String, Object> entry : attributes.entrySet()) {
679                            request.setAttribute(
680                                    clusterNode.getClusterNodeId() + StringPool.UNDERLINE +
681                                            entry.getKey(),
682                                    entry.getValue());
683                    }
684            }
685    
686            private static final String _PROXY_PASSWORD = GetterUtil.getString(
687                    PropsUtil.get("license.proxy.password"));
688    
689            private static final int _PROXY_PORT = GetterUtil.getInteger(
690                    PropsUtil.get("license.proxy.port"), 80);
691    
692            private static final String _PROXY_URL = PropsUtil.get("license.proxy.url");
693    
694            private static final String _PROXY_USER_NAME = GetterUtil.getString(
695                    PropsUtil.get("license.proxy.username"));
696    
697            private static Log _log = LogFactoryUtil.getLog(LicenseUtil.class);
698    
699            private static String _encryptedSymmetricKey;
700            private static MethodHandler _getServerInfoMethodHandler =
701                    new MethodHandler(new MethodKey(LicenseUtil.class, "getServerInfo"));
702            private static Set<String> _ipAddresses;
703            private static Set<String> _macAddresses;
704            private static Pattern _macAddressPattern1 = Pattern.compile(
705                    "\\s((\\p{XDigit}{1,2}(-|:)){5}(\\p{XDigit}{1,2}))(?:\\s|$)");
706            private static Pattern _macAddressPattern2 = Pattern.compile(
707                    "\\s((\\p{XDigit}{1,2}(\\.)){5}(\\p{XDigit}{1,2}))(?:\\s|$)");
708            private static MethodKey _registerOrderMethodKey = new MethodKey(
709                    LicenseUtil.class, "registerOrder", String.class, String.class,
710                    int.class);
711            private static byte[] _serverIdBytes;
712            private static Key _symmetricKey;
713    
714            static {
715                    _initKeys();
716            }
717    
718    }