Java Code Examples for javax.crypto.KeyAgreement#generateSecret()
The following examples show how to use
javax.crypto.KeyAgreement#generateSecret() .
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: DhTest.java From wycheproof with Apache License 2.0 | 7 votes |
/** Check that key agreement using DH works. */ @SuppressWarnings("InsecureCryptoUsage") @Test public void testDh() throws Exception { KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH"); DHParameterSpec dhparams = ike2048(); keyGen.initialize(dhparams); KeyPair keyPairA = keyGen.generateKeyPair(); KeyPair keyPairB = keyGen.generateKeyPair(); KeyAgreement kaA = KeyAgreement.getInstance("DH"); KeyAgreement kaB = KeyAgreement.getInstance("DH"); kaA.init(keyPairA.getPrivate()); kaB.init(keyPairB.getPrivate()); kaA.doPhase(keyPairB.getPublic(), true); kaB.doPhase(keyPairA.getPublic(), true); byte[] kAB = kaA.generateSecret(); byte[] kBA = kaB.generateSecret(); assertEquals(TestUtil.bytesToHex(kAB), TestUtil.bytesToHex(kBA)); }
Example 2
Source File: EcdhKeyAgreementAlgorithm.java From Jose4j with Apache License 2.0 | 6 votes |
private byte[] generateEcdhSecret(PrivateKey privateKey, PublicKey publicKey, ProviderContext providerContext) throws JoseException { String keyAgreementProvider = providerContext.getSuppliedKeyProviderContext().getKeyAgreementProvider(); KeyAgreement keyAgreement = getKeyAgreement(keyAgreementProvider); try { keyAgreement.init(privateKey); keyAgreement.doPhase(publicKey, true); } catch (java.security.InvalidKeyException e) { throw new InvalidKeyException("Invalid Key for " + getJavaAlgorithm() + " key agreement." ,e); } return keyAgreement.generateSecret(); }
Example 3
Source File: TestDH.java From openjdk-jdk9 with GNU General Public License v2.0 | 6 votes |
private static void testAlgorithm(KeyAgreement ka1, KeyPair kp1, KeyAgreement ka2, KeyPair kp2, String algorithm) throws Exception { SecretKey key1; ka1.init(kp1.getPrivate()); ka1.doPhase(kp2.getPublic(), true); System.out.println("Derive " + algorithm + " using SunJCE..."); key1 = ka1.generateSecret(algorithm); ka2.init(kp1.getPrivate()); ka2.doPhase(kp2.getPublic(), true); System.out.println("Derive " + algorithm + " using PKCS#11..."); SecretKey key2 = ka2.generateSecret(algorithm); byte[] b1 = key1.getEncoded(); byte[] b2 = key2.getEncoded(); if (Arrays.equals(b1, b2) == false) { System.out.println(b1.length + " bytes: " + toString(b1)); System.out.println(b2.length + " bytes: " + toString(b2)); throw new Exception(algorithm + " secret mismatch"); } }
Example 4
Source File: KAKeyDerivation.java From Bytecoder with Apache License 2.0 | 6 votes |
/** * Handle the TLSv1-1.2 objects, which don't use the HKDF algorithms. */ private SecretKey t12DeriveKey(String algorithm, AlgorithmParameterSpec params) throws IOException { try { KeyAgreement ka = KeyAgreement.getInstance(algorithmName); ka.init(localPrivateKey); ka.doPhase(peerPublicKey, true); SecretKey preMasterSecret = ka.generateSecret("TlsPremasterSecret"); SSLMasterKeyDerivation mskd = SSLMasterKeyDerivation.valueOf( context.negotiatedProtocol); if (mskd == null) { // unlikely throw new SSLHandshakeException( "No expected master key derivation for protocol: " + context.negotiatedProtocol.name); } SSLKeyDerivation kd = mskd.createKeyDerivation( context, preMasterSecret); return kd.deriveKey("MasterSecret", params); } catch (GeneralSecurityException gse) { throw (SSLHandshakeException) new SSLHandshakeException( "Could not generate secret").initCause(gse); } }
Example 5
Source File: EcdhTest.java From wycheproof with Apache License 2.0 | 6 votes |
/** Checks that key agreement using ECDH works. */ @Test public void testBasic() throws Exception { KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC"); ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1"); keyGen.initialize(ecSpec); KeyPair keyPairA = keyGen.generateKeyPair(); KeyPair keyPairB = keyGen.generateKeyPair(); KeyAgreement kaA = KeyAgreement.getInstance("ECDH"); KeyAgreement kaB = KeyAgreement.getInstance("ECDH"); kaA.init(keyPairA.getPrivate()); kaB.init(keyPairB.getPrivate()); kaA.doPhase(keyPairB.getPublic(), true); kaB.doPhase(keyPairA.getPublic(), true); byte[] kAB = kaA.generateSecret(); byte[] kBA = kaB.generateSecret(); assertEquals(TestUtil.bytesToHex(kAB), TestUtil.bytesToHex(kBA)); }
Example 6
Source File: DHKeyExchange.java From openjsse with GNU General Public License v2.0 | 5 votes |
private SecretKey t13DeriveKey(String algorithm, AlgorithmParameterSpec params) throws IOException { try { KeyAgreement ka = JsseJce.getKeyAgreement("DiffieHellman"); ka.init(localPrivateKey); ka.doPhase(peerPublicKey, true); SecretKey sharedSecret = ka.generateSecret("TlsPremasterSecret"); HashAlg hashAlg = context.negotiatedCipherSuite.hashAlg; SSLKeyDerivation kd = context.handshakeKeyDerivation; HKDF hkdf = new HKDF(hashAlg.name); if (kd == null) { // No PSK is in use. // If PSK is not in use Early Secret will still be // HKDF-Extract(0, 0). byte[] zeros = new byte[hashAlg.hashLength]; SecretKeySpec ikm = new SecretKeySpec(zeros, "TlsPreSharedSecret"); SecretKey earlySecret = hkdf.extract(zeros, ikm, "TlsEarlySecret"); kd = new SSLSecretDerivation(context, earlySecret); } // derive salt secret SecretKey saltSecret = kd.deriveKey("TlsSaltSecret", null); // derive handshake secret return hkdf.extract(saltSecret, sharedSecret, algorithm); } catch (GeneralSecurityException gse) { throw (SSLHandshakeException) new SSLHandshakeException( "Could not generate secret").initCause(gse); } }
Example 7
Source File: DHCrypt.java From openjdk-jdk8u-backup with GNU General Public License v2.0 | 5 votes |
/** * Get the secret data that has been agreed on through Diffie-Hellman * key agreement protocol. Note that in the two party protocol, if * the peer keys are already known, no other data needs to be sent in * order to agree on a secret. That is, a secured message may be * sent without any mandatory round-trip overheads. * * <P>It is illegal to call this member function if the private key * has not been set (or generated). * * @param peerPublicKey the peer's public key. * @param keyIsValidated whether the {@code peerPublicKey} has beed * validated * @return the secret, which is an unsigned big-endian integer * the same size as the Diffie-Hellman modulus. */ SecretKey getAgreedSecret(BigInteger peerPublicValue, boolean keyIsValidated) throws SSLHandshakeException { try { KeyFactory kf = JsseJce.getKeyFactory("DiffieHellman"); DHPublicKeySpec spec = new DHPublicKeySpec(peerPublicValue, modulus, base); PublicKey publicKey = kf.generatePublic(spec); KeyAgreement ka = JsseJce.getKeyAgreement("DiffieHellman"); // validate the Diffie-Hellman public key if (!keyIsValidated && !KeyUtil.isOracleJCEProvider(ka.getProvider().getName())) { try { KeyUtil.validate(spec); } catch (InvalidKeyException ike) { // prefer handshake_failure alert to internal_error alert throw new SSLHandshakeException(ike.getMessage()); } } ka.init(privateKey); ka.doPhase(publicKey, true); return ka.generateSecret("TlsPremasterSecret"); } catch (GeneralSecurityException e) { throw (SSLHandshakeException) new SSLHandshakeException( "Could not generate secret").initCause(e); } }
Example 8
Source File: ToolDH.java From protools with Apache License 2.0 | 5 votes |
/** * 构建密钥 * * @param publicKey * 公钥 * @param privateKey * 私钥 * * @return byte[] 本地密钥 * * @throws Exception */ public static byte[] getSecretKey(byte[] publicKey, byte[] privateKey) throws InvalidKeySpecException, NoSuchAlgorithmException, InvalidKeyException { // 实例化密钥工厂 KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); // 初始化公钥 // 密钥材料转换 X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKey); // 产生公钥 PublicKey pubKey = keyFactory.generatePublic(x509KeySpec); // 初始化私钥 // 密钥材料转换 PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey); // 产生私钥 PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec); // 实例化 KeyAgreement keyAgree = KeyAgreement.getInstance(keyFactory.getAlgorithm()); // 初始化 keyAgree.init(priKey); keyAgree.doPhase(pubKey, true); // 生成本地密钥 SecretKey secretKey = keyAgree.generateSecret(SECRET_KEY_ALGORITHM); return secretKey.getEncoded(); }
Example 9
Source File: HandShake.java From gemfirexd-oss with Apache License 2.0 | 5 votes |
static public byte[] decryptBytes(byte[] data, String dhSKAlgo, PublicKey publicKey) throws Exception{ try { KeyAgreement ka = KeyAgreement.getInstance("DH"); ka.init(dhPrivateKey); ka.doPhase(publicKey, true); Cipher decrypt; int keysize = getKeySize(dhSKAlgo); int blocksize = getBlockSize(dhSKAlgo); if (keysize == -1 || blocksize == -1) { SecretKey sKey = ka.generateSecret(dhSKAlgo); decrypt = Cipher.getInstance(dhSKAlgo); decrypt.init(Cipher.DECRYPT_MODE, sKey); } else { String algoStr = getDhAlgoStr(dhSKAlgo); byte[] sKeyBytes = ka.generateSecret(); SecretKeySpec sks = new SecretKeySpec(sKeyBytes, 0, keysize, algoStr); IvParameterSpec ivps = new IvParameterSpec(sKeyBytes, keysize, blocksize); decrypt = Cipher.getInstance(algoStr + "/CBC/PKCS5Padding"); decrypt.init(Cipher.DECRYPT_MODE, sks, ivps); } byte[] decrptBytes = decrypt.doFinal(data); return decrptBytes; }catch(Exception ex) { throw ex; } }
Example 10
Source File: ECDHCrypt.java From openjdk-jdk8u with GNU General Public License v2.0 | 5 votes |
SecretKey getAgreedSecret( PublicKey peerPublicKey) throws SSLHandshakeException { try { KeyAgreement ka = JsseJce.getKeyAgreement("ECDH"); ka.init(privateKey); ka.doPhase(peerPublicKey, true); return ka.generateSecret("TlsPremasterSecret"); } catch (GeneralSecurityException e) { throw (SSLHandshakeException) new SSLHandshakeException( "Could not generate secret").initCause(e); } }
Example 11
Source File: DHCrypt.java From openjdk-jdk9 with GNU General Public License v2.0 | 5 votes |
/** * Get the secret data that has been agreed on through Diffie-Hellman * key agreement protocol. Note that in the two party protocol, if * the peer keys are already known, no other data needs to be sent in * order to agree on a secret. That is, a secured message may be * sent without any mandatory round-trip overheads. * * <P>It is illegal to call this member function if the private key * has not been set (or generated). * * @param peerPublicKey the peer's public key. * @param keyIsValidated whether the {@code peerPublicKey} has beed * validated * @return the secret, which is an unsigned big-endian integer * the same size as the Diffie-Hellman modulus. */ SecretKey getAgreedSecret(BigInteger peerPublicValue, boolean keyIsValidated) throws SSLHandshakeException { try { KeyFactory kf = JsseJce.getKeyFactory("DiffieHellman"); DHPublicKeySpec spec = new DHPublicKeySpec(peerPublicValue, modulus, base); PublicKey publicKey = kf.generatePublic(spec); KeyAgreement ka = JsseJce.getKeyAgreement("DiffieHellman"); // validate the Diffie-Hellman public key if (!keyIsValidated && !KeyUtil.isOracleJCEProvider(ka.getProvider().getName())) { try { KeyUtil.validate(spec); } catch (InvalidKeyException ike) { // prefer handshake_failure alert to internal_error alert throw new SSLHandshakeException(ike.getMessage()); } } ka.init(privateKey); ka.doPhase(publicKey, true); return ka.generateSecret("TlsPremasterSecret"); } catch (GeneralSecurityException e) { throw (SSLHandshakeException) new SSLHandshakeException( "Could not generate secret").initCause(e); } }
Example 12
Source File: ECDHCrypt.java From openjdk-8 with GNU General Public License v2.0 | 5 votes |
SecretKey getAgreedSecret(PublicKey peerPublicKey) { try { KeyAgreement ka = JsseJce.getKeyAgreement("ECDH"); ka.init(privateKey); ka.doPhase(peerPublicKey, true); return ka.generateSecret("TlsPremasterSecret"); } catch (GeneralSecurityException e) { throw new RuntimeException("Could not generate secret", e); } }
Example 13
Source File: DHCrypt.java From TencentKona-8 with GNU General Public License v2.0 | 5 votes |
/** * Get the secret data that has been agreed on through Diffie-Hellman * key agreement protocol. Note that in the two party protocol, if * the peer keys are already known, no other data needs to be sent in * order to agree on a secret. That is, a secured message may be * sent without any mandatory round-trip overheads. * * <P>It is illegal to call this member function if the private key * has not been set (or generated). * * @param peerPublicKey the peer's public key. * @param keyIsValidated whether the {@code peerPublicKey} has beed * validated * @return the secret, which is an unsigned big-endian integer * the same size as the Diffie-Hellman modulus. */ SecretKey getAgreedSecret(BigInteger peerPublicValue, boolean keyIsValidated) throws SSLHandshakeException { try { KeyFactory kf = JsseJce.getKeyFactory("DiffieHellman"); DHPublicKeySpec spec = new DHPublicKeySpec(peerPublicValue, modulus, base); PublicKey publicKey = kf.generatePublic(spec); KeyAgreement ka = JsseJce.getKeyAgreement("DiffieHellman"); // validate the Diffie-Hellman public key if (!keyIsValidated && !KeyUtil.isOracleJCEProvider(ka.getProvider().getName())) { try { KeyUtil.validate(spec); } catch (InvalidKeyException ike) { // prefer handshake_failure alert to internal_error alert throw new SSLHandshakeException(ike.getMessage()); } } ka.init(privateKey); ka.doPhase(publicKey, true); return ka.generateSecret("TlsPremasterSecret"); } catch (GeneralSecurityException e) { throw (SSLHandshakeException) new SSLHandshakeException( "Could not generate secret").initCause(e); } }
Example 14
Source File: ECDHCrypt.java From openjdk-jdk8u-backup with GNU General Public License v2.0 | 5 votes |
SecretKey getAgreedSecret( PublicKey peerPublicKey) throws SSLHandshakeException { try { KeyAgreement ka = JsseJce.getKeyAgreement("ECDH"); ka.init(privateKey); ka.doPhase(peerPublicKey, true); return ka.generateSecret("TlsPremasterSecret"); } catch (GeneralSecurityException e) { throw (SSLHandshakeException) new SSLHandshakeException( "Could not generate secret").initCause(e); } }
Example 15
Source File: KAKeyDerivation.java From Bytecoder with Apache License 2.0 | 5 votes |
/** * Handle the TLSv1.3 objects, which use the HKDF algorithms. */ private SecretKey t13DeriveKey(String algorithm, AlgorithmParameterSpec params) throws IOException { try { KeyAgreement ka = KeyAgreement.getInstance(algorithmName); ka.init(localPrivateKey); ka.doPhase(peerPublicKey, true); SecretKey sharedSecret = ka.generateSecret("TlsPremasterSecret"); CipherSuite.HashAlg hashAlg = context.negotiatedCipherSuite.hashAlg; SSLKeyDerivation kd = context.handshakeKeyDerivation; HKDF hkdf = new HKDF(hashAlg.name); if (kd == null) { // No PSK is in use. // If PSK is not in use Early Secret will still be // HKDF-Extract(0, 0). byte[] zeros = new byte[hashAlg.hashLength]; SecretKeySpec ikm = new SecretKeySpec(zeros, "TlsPreSharedSecret"); SecretKey earlySecret = hkdf.extract(zeros, ikm, "TlsEarlySecret"); kd = new SSLSecretDerivation(context, earlySecret); } // derive salt secret SecretKey saltSecret = kd.deriveKey("TlsSaltSecret", null); // derive handshake secret return hkdf.extract(saltSecret, sharedSecret, algorithm); } catch (GeneralSecurityException gse) { throw (SSLHandshakeException) new SSLHandshakeException( "Could not generate secret").initCause(gse); } }
Example 16
Source File: DHCrypt.java From jdk8u_jdk with GNU General Public License v2.0 | 5 votes |
/** * Get the secret data that has been agreed on through Diffie-Hellman * key agreement protocol. Note that in the two party protocol, if * the peer keys are already known, no other data needs to be sent in * order to agree on a secret. That is, a secured message may be * sent without any mandatory round-trip overheads. * * <P>It is illegal to call this member function if the private key * has not been set (or generated). * * @param peerPublicKey the peer's public key. * @param keyIsValidated whether the {@code peerPublicKey} has beed * validated * @return the secret, which is an unsigned big-endian integer * the same size as the Diffie-Hellman modulus. */ SecretKey getAgreedSecret(BigInteger peerPublicValue, boolean keyIsValidated) throws SSLHandshakeException { try { KeyFactory kf = JsseJce.getKeyFactory("DiffieHellman"); DHPublicKeySpec spec = new DHPublicKeySpec(peerPublicValue, modulus, base); PublicKey publicKey = kf.generatePublic(spec); KeyAgreement ka = JsseJce.getKeyAgreement("DiffieHellman"); // validate the Diffie-Hellman public key if (!keyIsValidated && !KeyUtil.isOracleJCEProvider(ka.getProvider().getName())) { try { KeyUtil.validate(spec); } catch (InvalidKeyException ike) { // prefer handshake_failure alert to internal_error alert throw new SSLHandshakeException(ike.getMessage()); } } ka.init(privateKey); ka.doPhase(publicKey, true); return ka.generateSecret("TlsPremasterSecret"); } catch (GeneralSecurityException e) { throw (SSLHandshakeException) new SSLHandshakeException( "Could not generate secret").initCause(e); } }
Example 17
Source File: ECDHKeyExchange.java From openjsse with GNU General Public License v2.0 | 5 votes |
SecretKey getAgreedSecret( PublicKey peerPublicKey) throws SSLHandshakeException { try { KeyAgreement ka = JsseJce.getKeyAgreement("ECDH"); ka.init(privateKey); ka.doPhase(peerPublicKey, true); return ka.generateSecret("TlsPremasterSecret"); } catch (GeneralSecurityException e) { throw (SSLHandshakeException) new SSLHandshakeException( "Could not generate secret").initCause(e); } }
Example 18
Source File: ECDHCrypt.java From openjdk-8-source with GNU General Public License v2.0 | 5 votes |
SecretKey getAgreedSecret(PublicKey peerPublicKey) { try { KeyAgreement ka = JsseJce.getKeyAgreement("ECDH"); ka.init(privateKey); ka.doPhase(peerPublicKey, true); return ka.generateSecret("TlsPremasterSecret"); } catch (GeneralSecurityException e) { throw new RuntimeException("Could not generate secret", e); } }
Example 19
Source File: TestCurves.java From openjdk-jdk9 with GNU General Public License v2.0 | 4 votes |
@Override public void main(Provider p) throws Exception { if (p.getService("KeyAgreement", "ECDH") == null) { System.out.println("Not supported by provider, skipping"); return; } if (isBadNSSVersion(p)) { return; } if (isBadSolarisSparc(p)) { return; } // Check if this is sparc for later failure avoidance. boolean sparc = false; if (props.getProperty("os.arch").equals("sparcv9")) { sparc = true; System.out.println("This is a sparcv9"); } Random random = new Random(); byte[] data = new byte[2048]; random.nextBytes(data); List<ECParameterSpec> curves = getKnownCurves(p); for (ECParameterSpec params : curves) { System.out.println("Testing " + params + "..."); KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", p); kpg.initialize(params); KeyPair kp1, kp2; kp1 = kpg.generateKeyPair(); kp2 = kpg.generateKeyPair(); testSigning(p, "SHA1withECDSA", data, kp1, kp2); // Check because Solaris ncp driver does not support these but // Solaris metaslot causes them to be run. try { testSigning(p, "SHA224withECDSA", data, kp1, kp2); testSigning(p, "SHA256withECDSA", data, kp1, kp2); testSigning(p, "SHA384withECDSA", data, kp1, kp2); testSigning(p, "SHA512withECDSA", data, kp1, kp2); } catch (ProviderException e) { if (sparc) { Throwable t = e.getCause(); if (t instanceof sun.security.pkcs11.wrapper.PKCS11Exception && t.getMessage().equals("CKR_ATTRIBUTE_VALUE_INVALID")) { System.out.print("-Failure not uncommon. Probably pre-T4."); } else { throw e; } } else { throw e; } } System.out.println(); KeyAgreement ka1 = KeyAgreement.getInstance("ECDH", p); ka1.init(kp1.getPrivate()); ka1.doPhase(kp2.getPublic(), true); byte[] secret1 = ka1.generateSecret(); KeyAgreement ka2 = KeyAgreement.getInstance("ECDH", p); ka2.init(kp2.getPrivate()); ka2.doPhase(kp1.getPublic(), true); byte[] secret2 = ka2.generateSecret(); if (Arrays.equals(secret1, secret2) == false) { throw new Exception("Secrets do not match"); } } System.out.println("OK"); }
Example 20
Source File: TestInterop.java From openjdk-jdk9 with GNU General Public License v2.0 | 4 votes |
@Override public void main(Provider prov) throws Exception { if (prov.getService("KeyAgreement", "DH") == null) { System.out.println("DH not supported, skipping"); return; } try { System.out.println("testing generateSecret()"); DHPublicKeySpec publicSpec; DHPrivateKeySpec privateSpec; KeyFactory kf = KeyFactory.getInstance("DH"); KeyAgreement ka = KeyAgreement.getInstance("DH", prov); KeyAgreement kbSunJCE = KeyAgreement.getInstance("DH", "SunJCE"); DHPrivateKeySpec privSpecA = new DHPrivateKeySpec(xa, p, g); DHPublicKeySpec pubSpecA = new DHPublicKeySpec(ya, p, g); PrivateKey privA = kf.generatePrivate(privSpecA); PublicKey pubA = kf.generatePublic(pubSpecA); DHPrivateKeySpec privSpecB = new DHPrivateKeySpec(xb, p, g); DHPublicKeySpec pubSpecB = new DHPublicKeySpec(yb, p, g); PrivateKey privB = kf.generatePrivate(privSpecB); PublicKey pubB = kf.generatePublic(pubSpecB); ka.init(privA); ka.doPhase(pubB, true); byte[] n1 = ka.generateSecret(); kbSunJCE.init(privB); kbSunJCE.doPhase(pubA, true); byte[] n2 = kbSunJCE.generateSecret(); if (Arrays.equals(n1, n2) == false) { throw new Exception("values mismatch!"); } else { System.out.println("values: same"); } System.out.println("testing generateSecret(byte[], int)"); byte[] n3 = new byte[n1.length]; ka.init(privB); ka.doPhase(pubA, true); int n3Len = ka.generateSecret(n3, 0); if (n3Len != n3.length) { throw new Exception("PKCS11 Length mismatch!"); } else System.out.println("PKCS11 Length: ok"); byte[] n4 = new byte[n2.length]; kbSunJCE.init(privA); kbSunJCE.doPhase(pubB, true); int n4Len = kbSunJCE.generateSecret(n4, 0); if (n4Len != n4.length) { throw new Exception("SunJCE Length mismatch!"); } else System.out.println("SunJCE Length: ok"); if (Arrays.equals(n3, n4) == false) { throw new Exception("values mismatch! "); } else { System.out.println("values: same"); } } catch (Exception ex) { System.out.println("Unexpected ex: " + ex); ex.printStackTrace(); throw ex; } }