diff options
Diffstat (limited to 'crypto/test/src/openssl')
-rw-r--r-- | crypto/test/src/openssl/test/AllTests.cs | 133 | ||||
-rw-r--r-- | crypto/test/src/openssl/test/ReaderTest.cs | 380 | ||||
-rw-r--r-- | crypto/test/src/openssl/test/WriterTest.cs | 185 |
3 files changed, 698 insertions, 0 deletions
diff --git a/crypto/test/src/openssl/test/AllTests.cs b/crypto/test/src/openssl/test/AllTests.cs new file mode 100644 index 000000000..921208179 --- /dev/null +++ b/crypto/test/src/openssl/test/AllTests.cs @@ -0,0 +1,133 @@ +using System; +using System.IO; +using System.Text; + +using NUnit.Core; +using NUnit.Framework; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities.Test; + +namespace Org.BouncyCastle.OpenSsl.Tests +{ + [TestFixture] + public class AllTests + { + private class Password + : IPasswordFinder + { + private readonly char[] password; + + public Password( + char[] word) + { + this.password = (char[]) word.Clone(); + } + + public char[] GetPassword() + { + return (char[]) password.Clone(); + } + } + + [Suite] + public static TestSuite Suite + { + get + { + TestSuite suite = new TestSuite("OpenSSL Tests"); + suite.Add(new AllTests()); + return suite; + } + } + + [Test] + public void TestOpenSsl() + { + Org.BouncyCastle.Utilities.Test.ITest[] tests = new Org.BouncyCastle.Utilities.Test.ITest[]{ + new ReaderTest(), + new WriterTest() + }; + + foreach (Org.BouncyCastle.Utilities.Test.ITest test in tests) + { + SimpleTestResult result = (SimpleTestResult)test.Perform(); + + if (!result.IsSuccessful()) + { + Assert.Fail(result.ToString()); + } + } + } + + [Test] + public void TestPkcs8Encrypted() + { + IAsymmetricCipherKeyPairGenerator kpGen = GeneratorUtilities.GetKeyPairGenerator("RSA"); + kpGen.Init(new KeyGenerationParameters(new SecureRandom(), 1024)); + + AsymmetricKeyParameter privKey = kpGen.GenerateKeyPair().Private; + + // FIXME see PbeUtilities and Pkcs8Generator +// EncryptedTest(privKey, Pkcs8Generator.Aes256Cbc); +// EncryptedTest(privKey, Pkcs8Generator.Des3Cbc); + EncryptedTest(privKey, Pkcs8Generator.PbeSha1_3DES); + } + + private void EncryptedTest(AsymmetricKeyParameter privKey, string algorithm) + { + StringWriter sw = new StringWriter(); + PemWriter pWrt = new PemWriter(sw); + Pkcs8Generator pkcs8 = new Pkcs8Generator(privKey, algorithm); + pkcs8.Password = "hello".ToCharArray(); + + pWrt.WriteObject(pkcs8); + pWrt.Writer.Close(); + + String result = sw.ToString(); + + PemReader pRd = new PemReader(new StringReader(result), new Password("hello".ToCharArray())); + + AsymmetricKeyParameter rdKey = (AsymmetricKeyParameter)pRd.ReadObject(); + pRd.Reader.Close(); + + Assert.AreEqual(privKey, rdKey); + } + + [Test] + public void TestPkcs8Plain() + { + IAsymmetricCipherKeyPairGenerator kpGen = GeneratorUtilities.GetKeyPairGenerator("RSA"); + kpGen.Init(new KeyGenerationParameters(new SecureRandom(), 1024)); + + AsymmetricKeyParameter privKey = kpGen.GenerateKeyPair().Private; + + StringWriter sw = new StringWriter(); + PemWriter pWrt = new PemWriter(sw); + + Pkcs8Generator pkcs8 = new Pkcs8Generator(privKey); + pWrt.WriteObject(pkcs8); + pWrt.Writer.Close(); + + string result = sw.ToString(); + + PemReader pRd = new PemReader(new StringReader(result), new Password("hello".ToCharArray())); + + AsymmetricKeyParameter rdKey = (AsymmetricKeyParameter)pRd.ReadObject(); + pRd.Reader.Close(); + + Assert.AreEqual(privKey, rdKey); + } + + public static void Main( + string[] args) + { + //junit.textui.TestRunner.run(suite()); + EventListener el = new NullListener(); + Suite.Run(el); + } + } +} diff --git a/crypto/test/src/openssl/test/ReaderTest.cs b/crypto/test/src/openssl/test/ReaderTest.cs new file mode 100644 index 000000000..d27ed742f --- /dev/null +++ b/crypto/test/src/openssl/test/ReaderTest.cs @@ -0,0 +1,380 @@ +using System; +using System.IO; + +using NUnit.Framework; + +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities.Test; + +namespace Org.BouncyCastle.OpenSsl.Tests +{ + /** + * basic class for reading test.pem - the password is "secret" + */ + [TestFixture] + public class ReaderTest + : SimpleTest + { + private class Password + : IPasswordFinder + { + private readonly char[] password; + + public Password( + char[] word) + { + this.password = (char[]) word.Clone(); + } + + public char[] GetPassword() + { + return (char[]) password.Clone(); + } + } + + public override string Name + { + get { return "PEMReaderTest"; } + } + + public override void PerformTest() + { + IPasswordFinder pGet = new Password("secret".ToCharArray()); + PemReader pemRd = OpenPemResource("test.pem", pGet); + AsymmetricCipherKeyPair pair; + + object o; + while ((o = pemRd.ReadObject()) != null) + { +// if (o is AsymmetricCipherKeyPair) +// { +// ackp = (AsymmetricCipherKeyPair)o; +// +// Console.WriteLine(ackp.Public); +// Console.WriteLine(ackp.Private); +// } +// else +// { +// Console.WriteLine(o.ToString()); +// } + } + + // + // pkcs 7 data + // + pemRd = OpenPemResource("pkcs7.pem", null); + + ContentInfo d = (ContentInfo)pemRd.ReadObject(); + + if (!d.ContentType.Equals(CmsObjectIdentifiers.EnvelopedData)) + { + Fail("failed envelopedData check"); + } + + /* + { + // + // ECKey + // + pemRd = OpenPemResource("eckey.pem", null); + + // TODO Resolve return type issue with EC keys and fix PemReader to return parameters +// ECNamedCurveParameterSpec spec = (ECNamedCurveParameterSpec)pemRd.ReadObject(); + + pair = (AsymmetricCipherKeyPair)pemRd.ReadObject(); + ISigner sgr = SignerUtilities.GetSigner("ECDSA"); + + sgr.Init(true, pair.Private); + + byte[] message = new byte[] { (byte)'a', (byte)'b', (byte)'c' }; + + sgr.BlockUpdate(message, 0, message.Length); + + byte[] sigBytes = sgr.GenerateSignature(); + + sgr.Init(false, pair.Public); + + sgr.BlockUpdate(message, 0, message.Length); + + if (!sgr.VerifySignature(sigBytes)) + { + Fail("EC verification failed"); + } + + // TODO Resolve this issue with the algorithm name, study Java version +// if (!((ECPublicKeyParameters) pair.Public).AlgorithmName.Equals("ECDSA")) +// { +// Fail("wrong algorithm name on public got: " + ((ECPublicKeyParameters) pair.Public).AlgorithmName); +// } +// +// if (!((ECPrivateKeyParameters) pair.Private).AlgorithmName.Equals("ECDSA")) +// { +// Fail("wrong algorithm name on private got: " + ((ECPrivateKeyParameters) pair.Private).AlgorithmName); +// } + } + */ + + // + // writer/parser test + // + IAsymmetricCipherKeyPairGenerator kpGen = GeneratorUtilities.GetKeyPairGenerator("RSA"); + kpGen.Init( + new RsaKeyGenerationParameters( + BigInteger.ValueOf(0x10001), + new SecureRandom(), + 768, + 25)); + + pair = kpGen.GenerateKeyPair(); + + keyPairTest("RSA", pair); + +// kpGen = KeyPairGenerator.getInstance("DSA"); +// kpGen.initialize(512, new SecureRandom()); + DsaParametersGenerator pGen = new DsaParametersGenerator(); + pGen.Init(512, 80, new SecureRandom()); + + kpGen = GeneratorUtilities.GetKeyPairGenerator("DSA"); + kpGen.Init( + new DsaKeyGenerationParameters( + new SecureRandom(), + pGen.GenerateParameters())); + + pair = kpGen.GenerateKeyPair(); + + keyPairTest("DSA", pair); + + // + // PKCS7 + // + MemoryStream bOut = new MemoryStream(); + PemWriter pWrt = new PemWriter(new StreamWriter(bOut)); + + pWrt.WriteObject(d); + pWrt.Writer.Close(); + + pemRd = new PemReader(new StreamReader(new MemoryStream(bOut.ToArray(), false))); + d = (ContentInfo)pemRd.ReadObject(); + + if (!d.ContentType.Equals(CmsObjectIdentifiers.EnvelopedData)) + { + Fail("failed envelopedData recode check"); + } + + + // OpenSSL test cases (as embedded resources) + doOpenSslDsaTest("unencrypted"); + doOpenSslRsaTest("unencrypted"); + + doOpenSslTests("aes128"); + doOpenSslTests("aes192"); + doOpenSslTests("aes256"); + doOpenSslTests("blowfish"); + doOpenSslTests("des1"); + doOpenSslTests("des2"); + doOpenSslTests("des3"); + doOpenSslTests("rc2_128"); + + doOpenSslDsaTest("rc2_40_cbc"); + doOpenSslRsaTest("rc2_40_cbc"); + doOpenSslDsaTest("rc2_64_cbc"); + doOpenSslRsaTest("rc2_64_cbc"); + + // TODO Figure out why exceptions differ for commented out cases + doDudPasswordTest("7fd98", 0, "Corrupted stream - out of bounds length found"); + doDudPasswordTest("ef677", 1, "Corrupted stream - out of bounds length found"); +// doDudPasswordTest("800ce", 2, "cannot recognise object in stream"); + doDudPasswordTest("b6cd8", 3, "DEF length 81 object truncated by 56"); + doDudPasswordTest("28ce09", 4, "DEF length 110 object truncated by 28"); + doDudPasswordTest("2ac3b9", 5, "DER length more than 4 bytes: 11"); + doDudPasswordTest("2cba96", 6, "DEF length 100 object truncated by 35"); + doDudPasswordTest("2e3354", 7, "DEF length 42 object truncated by 9"); + doDudPasswordTest("2f4142", 8, "DER length more than 4 bytes: 14"); + doDudPasswordTest("2fe9bb", 9, "DER length more than 4 bytes: 65"); + doDudPasswordTest("3ee7a8", 10, "DER length more than 4 bytes: 57"); + doDudPasswordTest("41af75", 11, "malformed sequence in DSA private key"); + doDudPasswordTest("1704a5", 12, "corrupted stream detected"); +// doDudPasswordTest("1c5822", 13, "corrupted stream detected"); +// doDudPasswordTest("5a3d16", 14, "corrupted stream detected"); + doDudPasswordTest("8d0c97", 15, "corrupted stream detected"); + doDudPasswordTest("bc0daf", 16, "corrupted stream detected"); + doDudPasswordTest("aaf9c4d",17, "Corrupted stream - out of bounds length found"); + + // encrypted private key test + pGet = new Password("password".ToCharArray()); + pemRd = OpenPemResource("enckey.pem", pGet); + + RsaPrivateCrtKeyParameters privKey = (RsaPrivateCrtKeyParameters)pemRd.ReadObject(); + + if (!privKey.PublicExponent.Equals(new BigInteger("10001", 16))) + { + Fail("decryption of private key data check failed"); + } + + // general PKCS8 test + pGet = new Password("password".ToCharArray()); + pemRd = OpenPemResource("pkcs8test.pem", pGet); + + while ((privKey = (RsaPrivateCrtKeyParameters)pemRd.ReadObject()) != null) + { + if (!privKey.PublicExponent.Equals(new BigInteger("10001", 16))) + { + Fail("decryption of private key data check failed"); + } + } + } + + private void keyPairTest( + string name, + AsymmetricCipherKeyPair pair) + { + MemoryStream bOut = new MemoryStream(); + PemWriter pWrt = new PemWriter(new StreamWriter(bOut)); + + pWrt.WriteObject(pair.Public); + pWrt.Writer.Close(); + + PemReader pemRd = new PemReader(new StreamReader(new MemoryStream(bOut.ToArray(), false))); + + AsymmetricKeyParameter pubK = (AsymmetricKeyParameter) pemRd.ReadObject(); + if (!pubK.Equals(pair.Public)) + { + Fail("Failed public key read: " + name); + } + + bOut = new MemoryStream(); + pWrt = new PemWriter(new StreamWriter(bOut)); + + pWrt.WriteObject(pair.Private); + pWrt.Writer.Close(); + + pemRd = new PemReader(new StreamReader(new MemoryStream(bOut.ToArray(), false))); + + AsymmetricCipherKeyPair kPair = (AsymmetricCipherKeyPair) pemRd.ReadObject(); + if (!kPair.Private.Equals(pair.Private)) + { + Fail("Failed private key read: " + name); + } + + if (!kPair.Public.Equals(pair.Public)) + { + Fail("Failed private key public read: " + name); + } + } + + private void doOpenSslTests( + string baseName) + { + doOpenSslDsaModesTest(baseName); + doOpenSslRsaModesTest(baseName); + } + + private void doOpenSslDsaModesTest( + string baseName) + { + doOpenSslDsaTest(baseName + "_cbc"); + doOpenSslDsaTest(baseName + "_cfb"); + doOpenSslDsaTest(baseName + "_ecb"); + doOpenSslDsaTest(baseName + "_ofb"); + } + + private void doOpenSslRsaModesTest( + string baseName) + { + doOpenSslRsaTest(baseName + "_cbc"); + doOpenSslRsaTest(baseName + "_cfb"); + doOpenSslRsaTest(baseName + "_ecb"); + doOpenSslRsaTest(baseName + "_ofb"); + } + + private void doOpenSslDsaTest( + string name) + { + string fileName = "dsa.openssl_dsa_" + name + ".pem"; + + doOpenSslTestFile(fileName, typeof(DsaPrivateKeyParameters)); + } + + private void doOpenSslRsaTest( + string name) + { + string fileName = "rsa.openssl_rsa_" + name + ".pem"; + + doOpenSslTestFile(fileName, typeof(RsaPrivateCrtKeyParameters)); + } + + private void doOpenSslTestFile( + string fileName, + Type expectedPrivKeyType) + { + PemReader pr = OpenPemResource(fileName, new Password("changeit".ToCharArray())); + AsymmetricCipherKeyPair kp = pr.ReadObject() as AsymmetricCipherKeyPair; + pr.Reader.Close(); + + if (kp == null) + { + Fail("Didn't find OpenSSL key"); + } + + if (!expectedPrivKeyType.IsInstanceOfType(kp.Private)) + { + Fail("Returned key not of correct type"); + } + } + + private void doDudPasswordTest(string password, int index, string message) + { + // illegal state exception check - in this case the wrong password will + // cause an underlying class cast exception. + try + { + IPasswordFinder pGet = new Password(password.ToCharArray()); + PemReader pemRd = OpenPemResource("test.pem", pGet); + + Object o; + while ((o = pemRd.ReadObject()) != null) + { + } + + Fail("issue not detected: " + index); + } + catch (IOException e) + { + if (e.Message.IndexOf(message) < 0) + { + Console.Error.WriteLine(message); + Console.Error.WriteLine(e.Message); + Fail("issue " + index + " exception thrown, but wrong message"); + } + } + } + + private static PemReader OpenPemResource( + string fileName, + IPasswordFinder pGet) + { + Stream data = GetTestDataAsStream("openssl." + fileName); + TextReader tr = new StreamReader(data); + return new PemReader(tr, pGet); + } + + public static void Main( + string[] args) + { + RunTest(new ReaderTest()); + } + + [Test] + public void TestFunction() + { + string resultText = Perform().ToString(); + + Assert.AreEqual(Name + ": Okay", resultText); + } + } +} diff --git a/crypto/test/src/openssl/test/WriterTest.cs b/crypto/test/src/openssl/test/WriterTest.cs new file mode 100644 index 000000000..41f371708 --- /dev/null +++ b/crypto/test/src/openssl/test/WriterTest.cs @@ -0,0 +1,185 @@ +using System; +using System.IO; + +using NUnit.Framework; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities.Encoders; +using Org.BouncyCastle.Utilities.IO.Pem; +using Org.BouncyCastle.Utilities.Test; + +namespace Org.BouncyCastle.OpenSsl.Tests +{ + [TestFixture] + public class WriterTest + : SimpleTest + { + private static readonly SecureRandom random = new SecureRandom(); + + // TODO Replace with a randomly generated key each test run? + private static readonly RsaPrivateCrtKeyParameters testRsaKey = new RsaPrivateCrtKeyParameters( + new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16), + new BigInteger("11", 16), + new BigInteger("9f66f6b05410cd503b2709e88115d55daced94d1a34d4e32bf824d0dde6028ae79c5f07b580f5dce240d7111f7ddb130a7945cd7d957d1920994da389f490c89", 16), + new BigInteger("c0a0758cdf14256f78d4708c86becdead1b50ad4ad6c5c703e2168fbf37884cb", 16), + new BigInteger("f01734d7960ea60070f1b06f2bb81bfac48ff192ae18451d5e56c734a5aab8a5", 16), + new BigInteger("b54bb9edff22051d9ee60f9351a48591b6500a319429c069a3e335a1d6171391", 16), + new BigInteger("d3d83daf2a0cecd3367ae6f8ae1aeb82e9ac2f816c6fc483533d8297dd7884cd", 16), + new BigInteger("b8f52fc6f38593dabb661d3f50f8897f8106eee68b1bce78a95b132b4e5b5d19", 16)); + + private static readonly DsaParameters testDsaParams = new DsaParameters( + new BigInteger("7434410770759874867539421675728577177024889699586189000788950934679315164676852047058354758883833299702695428196962057871264685291775577130504050839126673"), + new BigInteger("1138656671590261728308283492178581223478058193247"), + new BigInteger("4182906737723181805517018315469082619513954319976782448649747742951189003482834321192692620856488639629011570381138542789803819092529658402611668375788410")); + +// private static readonly PKCS8EncodedKeySpec testEcDsaKeySpec = new PKCS8EncodedKeySpec( +// Base64.Decode("MIG/AgEAMBAGByqGSM49AgEGBSuBBAAiBIGnMIGkAgEBBDCSBU3vo7ieeKs0ABQamy/ynxlde7Ylr8HmyfLaNnMr" + +// "jAwPp9R+KMUEhB7zxSAXv9KgBwYFK4EEACKhZANiAQQyyolMpg+TyB4o9kPWqafHIOe8o9K1glus+w2sY8OIPQQWGb5i5LdAyi" + +// "/SscwU24rZM0yiL3BHodp9ccwyhLrFYgXJUOQcCN2dno1GMols5497in5gL5+zn0yMsRtyv5o=") +// ); + private static readonly byte[] testEcDsaKeyBytes = Base64.Decode( + "MIG/AgEAMBAGByqGSM49AgEGBSuBBAAiBIGnMIGkAgEBBDCSBU3vo7ieeKs0ABQamy/ynxlde7Ylr8HmyfLaNnMr" + + "jAwPp9R+KMUEhB7zxSAXv9KgBwYFK4EEACKhZANiAQQyyolMpg+TyB4o9kPWqafHIOe8o9K1glus+w2sY8OIPQQWGb5i5LdAyi" + + "/SscwU24rZM0yiL3BHodp9ccwyhLrFYgXJUOQcCN2dno1GMols5497in5gL5+zn0yMsRtyv5o="); + + private static readonly char[] testPassword = "bouncy".ToCharArray(); + + private static readonly string[] algorithms = new string[] + { + "AES-128-CBC", "AES-128-CFB", "AES-128-ECB", "AES-128-OFB", + "AES-192-CBC", "AES-192-CFB", "AES-192-ECB", "AES-192-OFB", + "AES-256-CBC", "AES-256-CFB", "AES-256-ECB", "AES-256-OFB", + "BF-CBC", "BF-CFB", "BF-ECB", "BF-OFB", + "DES-CBC", "DES-CFB", "DES-ECB", "DES-OFB", + "DES-EDE", "DES-EDE-CBC", "DES-EDE-CFB", "DES-EDE-ECB", "DES-EDE-OFB", + "DES-EDE3", "DES-EDE3-CBC", "DES-EDE3-CFB", "DES-EDE3-ECB", "DES-EDE3-OFB", + "RC2-CBC", "RC2-CFB", "RC2-ECB", "RC2-OFB", + "RC2-40-CBC", + "RC2-64-CBC", + }; + + private class Password + : IPasswordFinder + { + private readonly char[] password; + + public Password( + char[] word) + { + this.password = (char[]) word.Clone(); + } + + public char[] GetPassword() + { + return (char[]) password.Clone(); + } + } + + public override string Name + { + get { return "PEMWriterTest"; } + } + + public override void PerformTest() + { + IAsymmetricCipherKeyPairGenerator dsaKpg = GeneratorUtilities.GetKeyPairGenerator("DSA"); + dsaKpg.Init(new DsaKeyGenerationParameters(random, testDsaParams)); + AsymmetricCipherKeyPair testDsaKp = dsaKpg.GenerateKeyPair(); + AsymmetricKeyParameter testDsaKey = testDsaKp.Private; + + doWriteReadTest(testDsaKey); + doWriteReadTests(testDsaKey, algorithms); + + doWriteReadTest(testRsaKey); + doWriteReadTests(testRsaKey, algorithms); + + AsymmetricKeyParameter ecPriv = PrivateKeyFactory.CreateKey(testEcDsaKeyBytes); + doWriteReadTest(ecPriv); + doWriteReadTests(ecPriv, algorithms); + + IAsymmetricCipherKeyPairGenerator ecKpg = GeneratorUtilities.GetKeyPairGenerator("ECDSA"); + ecKpg.Init(new KeyGenerationParameters(random, 239)); + ecPriv = ecKpg.GenerateKeyPair().Private; + doWriteReadTest(ecPriv); + doWriteReadTests(ecPriv, algorithms); + + // override test + PemWriter pWrt = new PemWriter(new StringWriter()); + + object o = new PemObject("FRED", new byte[100]); + pWrt.WriteObject(o); + + pWrt.Writer.Close(); + } + + private void doWriteReadTests( + AsymmetricKeyParameter akp, + string[] algorithms) + { + foreach (string algorithm in algorithms) + { + doWriteReadTest(akp, algorithm); + } + } + + private void doWriteReadTest( + AsymmetricKeyParameter akp) + { + StringWriter sw = new StringWriter(); + PemWriter pw = new PemWriter(sw); + + pw.WriteObject(akp); + pw.Writer.Close(); + + string data = sw.ToString(); + + PemReader pr = new PemReader(new StringReader(data)); + + AsymmetricCipherKeyPair kp = pr.ReadObject() as AsymmetricCipherKeyPair; + + if (kp == null || !kp.Private.Equals(akp)) + { + Fail("Failed to read back test key"); + } + } + + private void doWriteReadTest( + AsymmetricKeyParameter akp, + string algorithm) + { + StringWriter sw = new StringWriter(); + PemWriter pw = new PemWriter(sw); + + pw.WriteObject(akp, algorithm, testPassword, random); + pw.Writer.Close(); + + string data = sw.ToString(); + + PemReader pr = new PemReader(new StringReader(data), new Password(testPassword)); + + AsymmetricCipherKeyPair kp = pr.ReadObject() as AsymmetricCipherKeyPair; + + if (kp == null || !kp.Private.Equals(akp)) + { + Fail("Failed to read back test key encoded with: " + algorithm); + } + } + + public static void Main( + string[] args) + { + RunTest(new WriterTest()); + } + + [Test] + public void TestFunction() + { + string resultText = Perform().ToString(); + + Assert.AreEqual(Name + ": Okay", resultText); + } + } +} |