17b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root/*
27b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root * Copyright (C) 2014 The Android Open Source Project
37b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root *
47b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root * Licensed under the Apache License, Version 2.0 (the "License");
57b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root * you may not use this file except in compliance with the License.
67b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root * You may obtain a copy of the License at
77b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root *
87b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root *      http://www.apache.org/licenses/LICENSE-2.0
97b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root *
107b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root * Unless required by applicable law or agreed to in writing, software
117b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root * distributed under the License is distributed on an "AS IS" BASIS,
127b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root * See the License for the specific language governing permissions and
147b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root * limitations under the License.
157b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root */
167b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
177b27ca77c328e510a165712a497c20b67c68e8a3Kenny Rootpackage org.conscrypt;
187b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
197b27ca77c328e510a165712a497c20b67c68e8a3Kenny Rootimport java.io.IOException;
207b27ca77c328e510a165712a497c20b67c68e8a3Kenny Rootimport java.io.NotSerializableException;
217b27ca77c328e510a165712a497c20b67c68e8a3Kenny Rootimport java.io.ObjectInputStream;
227b27ca77c328e510a165712a497c20b67c68e8a3Kenny Rootimport java.io.ObjectOutputStream;
237b27ca77c328e510a165712a497c20b67c68e8a3Kenny Rootimport java.math.BigInteger;
247b27ca77c328e510a165712a497c20b67c68e8a3Kenny Rootimport java.security.InvalidKeyException;
257b27ca77c328e510a165712a497c20b67c68e8a3Kenny Rootimport java.security.spec.InvalidKeySpecException;
267b27ca77c328e510a165712a497c20b67c68e8a3Kenny Rootimport javax.crypto.interfaces.DHPrivateKey;
277b27ca77c328e510a165712a497c20b67c68e8a3Kenny Rootimport javax.crypto.spec.DHParameterSpec;
287b27ca77c328e510a165712a497c20b67c68e8a3Kenny Rootimport javax.crypto.spec.DHPrivateKeySpec;
297b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
307b27ca77c328e510a165712a497c20b67c68e8a3Kenny Rootpublic class OpenSSLDHPrivateKey implements DHPrivateKey, OpenSSLKeyHolder {
317b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    private static final long serialVersionUID = -7321023036951606638L;
327b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
337b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    private transient OpenSSLKey key;
347b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
357b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    /** base prime */
367b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    private transient byte[] p;
377b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
387b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    /** generator */
397b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    private transient byte[] g;
407b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
417b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    /** private key */
427b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    private transient byte[] x;
437b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
44e526e75cfe12c2908d37b03562ac48a5bbefdf11Kenny Root    private transient Object mParamsLock = new Object();
457b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
467b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    private transient boolean readParams;
477b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
487b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    OpenSSLDHPrivateKey(OpenSSLKey key) {
497b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        this.key = key;
507b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    }
517b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
527b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    @Override
537b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    public OpenSSLKey getOpenSSLKey() {
547b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        return key;
557b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    }
567b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
577b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    OpenSSLDHPrivateKey(DHPrivateKeySpec dhKeySpec) throws InvalidKeySpecException {
587b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        try {
597b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root            key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_DH(
607b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root                    dhKeySpec.getP().toByteArray(),
617b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root                    dhKeySpec.getG().toByteArray(),
627b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root                    null,
637b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root                    dhKeySpec.getX().toByteArray()));
647b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        } catch (Exception e) {
657b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root            throw new InvalidKeySpecException(e);
667b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        }
677b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    }
687b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
697b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    private void ensureReadParams() {
707b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        synchronized (mParamsLock) {
717b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root            if (readParams) {
727b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root                return;
737b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root            }
747b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
757b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root            byte[][] params = NativeCrypto.get_DH_params(key.getPkeyContext());
767b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
777b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root            p = params[0];
787b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root            g = params[1];
797b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root            x = params[3];
807b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
817b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root            readParams = true;
827b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        }
837b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    }
847b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
857b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    static OpenSSLKey getInstance(DHPrivateKey dhPrivateKey) throws InvalidKeyException {
867b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        try {
877b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root            DHParameterSpec dhParams = dhPrivateKey.getParams();
887b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root            return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_DH(
897b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root                    dhParams.getP().toByteArray(),
907b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root                    dhParams.getG().toByteArray(),
917b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root                    null,
927b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root                    dhPrivateKey.getX().toByteArray()));
937b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        } catch (Exception e) {
947b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root            throw new InvalidKeyException(e);
957b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        }
967b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    }
977b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
987b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    @Override
997b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    public String getAlgorithm() {
1007b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        return "DH";
1017b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    }
1027b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
1037b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    @Override
1047b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    public String getFormat() {
1057b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        /*
1067b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root         * If we're using an OpenSSL ENGINE, there's no guarantee we can export
1077b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root         * the key. Returning {@code null} tells the caller that there's no
1087b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root         * encoded format.
1097b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root         */
1107b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        if (key.isEngineBased()) {
1117b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root            return null;
1127b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        }
1137b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
1147b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        return "PKCS#8";
1157b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    }
1167b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
1177b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    @Override
1187b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    public byte[] getEncoded() {
1197b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        /*
1207b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root         * If we're using an OpenSSL ENGINE, there's no guarantee we can export
1217b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root         * the key. Returning {@code null} tells the caller that there's no
1227b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root         * encoded format.
1237b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root         */
1247b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        if (key.isEngineBased()) {
1257b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root            return null;
1267b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        }
1277b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
1287b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        return NativeCrypto.i2d_PKCS8_PRIV_KEY_INFO(key.getPkeyContext());
1297b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    }
1307b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
1317b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    @Override
1327b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    public DHParameterSpec getParams() {
1337b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        ensureReadParams();
1347b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        return new DHParameterSpec(new BigInteger(p), new BigInteger(g));
1357b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    }
1367b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
1377b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    @Override
1387b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    public BigInteger getX() {
1397b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        if (key.isEngineBased()) {
1407b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root            throw new UnsupportedOperationException("private key value X cannot be extracted");
1417b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        }
1427b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
1437b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        ensureReadParams();
1447b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        return new BigInteger(x);
1457b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    }
1467b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
1477b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    @Override
1487b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    public boolean equals(Object o) {
1497b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        if (o == this) {
1507b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root            return true;
1517b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        }
1527b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
1537b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        if (o instanceof OpenSSLDHPrivateKey) {
1547b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root            OpenSSLDHPrivateKey other = (OpenSSLDHPrivateKey) o;
1557b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
1567b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root            /*
1577b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root             * We can shortcut the true case, but it still may be equivalent but
1587b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root             * different copies.
1597b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root             */
1607b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root            if (key.equals(other.getOpenSSLKey())) {
1617b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root                return true;
1627b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root            }
1637b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        }
1647b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
1657b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        if (!(o instanceof DHPrivateKey)) {
1667b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root            return false;
1677b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        }
1687b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
1697b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        ensureReadParams();
1707b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
1717b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        final DHPrivateKey other = (DHPrivateKey) o;
1727b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        if (!x.equals(other.getX())) {
1737b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root            return false;
1747b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        }
1757b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
1767b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        DHParameterSpec spec = other.getParams();
1777b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        return g.equals(spec.getG()) && p.equals(spec.getP());
1787b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    }
1797b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
1807b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    @Override
1817b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    public int hashCode() {
1827b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        ensureReadParams();
1837b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        int hash = 1;
1847b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        if (!key.isEngineBased()) {
1857b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root            hash = hash * 3 + x.hashCode();
1867b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        }
1877b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        hash = hash * 7 + p.hashCode();
1887b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        hash = hash * 13 + g.hashCode();
1897b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        return hash;
1907b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    }
1917b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
1927b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    @Override
1937b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    public String toString() {
1947b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        final StringBuilder sb = new StringBuilder("OpenSSLDHPrivateKey{");
1957b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
1967b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        if (key.isEngineBased()) {
1977b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root            sb.append("key=");
1987b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root            sb.append(key);
1997b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root            sb.append('}');
2007b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root            return sb.toString();
2017b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        }
2027b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
2037b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        ensureReadParams();
2047b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        sb.append("X=");
2057b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        sb.append(new BigInteger(x).toString(16));
2067b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        sb.append(',');
2077b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        sb.append("P=");
2087b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        sb.append(new BigInteger(p).toString(16));
2097b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        sb.append(',');
2107b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        sb.append("G=");
2117b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        sb.append(new BigInteger(g).toString(16));
2127b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        sb.append('}');
2137b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
2147b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        return sb.toString();
2157b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    }
2167b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
2177b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
2187b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        stream.defaultReadObject();
2197b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
2207b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        final BigInteger g = (BigInteger) stream.readObject();
2217b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        final BigInteger p = (BigInteger) stream.readObject();
2227b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        final BigInteger x = (BigInteger) stream.readObject();
2237b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
2247b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_DH(
2257b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root                p.toByteArray(),
2267b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root                g.toByteArray(),
2277b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root                null,
2287b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root                x.toByteArray()));
229e526e75cfe12c2908d37b03562ac48a5bbefdf11Kenny Root        mParamsLock = new Object();
2307b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    }
2317b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
2327b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    private void writeObject(ObjectOutputStream stream) throws IOException {
2337b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        if (getOpenSSLKey().isEngineBased()) {
2347b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root            throw new NotSerializableException("engine-based keys can not be serialized");
2357b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        }
2367b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
2377b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        stream.defaultWriteObject();
2387b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root
2397b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        ensureReadParams();
2407b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        stream.writeObject(new BigInteger(g));
2417b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        stream.writeObject(new BigInteger(p));
2427b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root        stream.writeObject(new BigInteger(x));
2437b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root    }
2447b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root}
245