Turn: Using Kerberos to lock, Part 2: Generate a Kerberos Bill Request

xiaoxiao2021-03-05  49

Use Kerberos to lock, Part 2: Generate a Kerberos Bill Request

content:

Based on J2ME-based Kerveros clients generate basic ASN.1 data types Using user password generation key generation TGT request Conclusion Reference information About the author to the evaluation of this article

related information:

Simplify Enterprise Java Authentication with Single Sign-on

subscription:

DeveloperWorks Newsletter

J2ME has sufficient ability to perform complex encryption

Faheem Khan Free Consultant January 16, 2004

In this series of previous articles, you see a description of the J2ME application that can be securely connected to the server that supports Kerveros, you can also understand the details of Kerberos encryption on bytes. This article deepened into the application itself. You will see how to use J2ME toolpies and some open source libraries to complete unusual powerful encryption tasks.

In this series of previous articles, I introduced a mobile bank MIDlet application that uses Kerberos to securely communicate with the e-bank server. I also explain the data format and message sequence exchanged based on J2ME-based Kerveros client applications and remote servers exchange Kerberos bills and keys. In this article, I will begin to generate and process the J2ME classes for these messages. I will first simply describe the main class of J2ME-based Kerveros client, and then I will explain and demonstrate how these classes are generated in the first article. The basic ASN.1 data types discussed in the first article. In Section III, I will show how to generate a key for encryption and decryption in Kerveros communication. The last section will show how J2ME client generates requests to the Kerveros ticket. The class in the J2ME-based Kerveros client is hereby discussed three J2ME classes:

Asn1DataTypes Kerberosclient Kerberoskey Asn1DataTypes class will package all general ASN.1 features, such as publishing a general data type like Integer and String. The KerberoscLient class extends the Asn1DataTypes class, using its underlying feature and provides all Kerveros-specific features. Therefore, it can be said that I will simply divide the functions into two groups: All general ASN.1 features are in the Asn1DataTypes class, while all Kerveros-specific features are in the Kerberosclient class. This improves the reuse of the code. If you want to build your own non-Kerveros app, use the ASN.1 feature, you can use the ASN1DATYPES class. Kerberos defines an algorithm for generating a key using the user's password. The KerberosKey class implements this algorithm. You will need this key in Kerveros communication. I will show each method in these classes in this article. I also added these classes in a separate source code download. This package puts all things in a set of classes to compile them into a J2ME project. This download contains the following files:

Readme.txt, which contains guidance to describe how to practice these code according to the needs of this article. Asn1DataTypes.java, it implements an Asn1DataTypes class. Kerberosclient.java, which implements the KerberoscLient class. Kerberoskey.java, it implements the KerberosKey class. J2MeclientMidlet.java provides a very simple MIDLET wrapper that can be used to test these codes. Now, I will further explore the details of these classes. Generate the Asn1DataTypes class displayed in Basic ASN.1 Data Type Listing 1 to generate all the underlying functions required for the ASN.1 data structure. This class contains two methods: generating method is responsible for generating an ASN.1 data structure, and processing the processing method is responsible for handling messages that have been generated or from the remote application. I will explain and implement the generation method in this article, and the processing method is discussed in this series. Listing 1 contains only declarations of different methods in the ASN.1 class. I will display the implementation of each method in a separate list in several sections. Listing 1. Asn1DataTypes PUBLIC CLASS Asn1DataTypes

{

Public Byte [] getLength "{}

Public Byte [] GetintegerBytes (int integerContents) {}

Public Byte [] getGeneralstringBytes (String GeneralStringContent) {}

Public Byte [] getOCTStringBytes (byte [] octetstringcontents) {}

Public Byte [] getBitstringBytes (Byte [] content) {}

PUBLIC BYTE [] getGeneralizedTimeBytes (byte [] generalizedtimecontent) {}

Public Byte [] ConcatenateBytes (Byte [] array1, byte [] array2) {}

Public Byte [] getsequenceBytes (byte [] sequencecontents) {}

Public Byte [] getTagandLengthbytes (int tagtype, int tagnumber, byte "tagcontents) {}

} // asn1DataTypes

GetLengthbytes () (shown in Listing 2) This method uses an integer value (length) as a parameter. It generates a length of ASN.1 represents and returns a byte array that conforms to the ASN.1 length format. Listing 2. GetLengthbytes () method

Public Byte [] getLengthbytes (int LENGTH)

{

IF (Length <0)

Return NULL;

Byte Lengthbytes [];

IF (Length <= 127)

{

Lengthbytes = new byte [1];

Lengthbytes [0] = (Byte) (Length & 0xFF);

}

Else

{

Int templength = length;

INT BYTESREQUIRED = 2;

DO

{

Templength = Templength / 256;

IF (Templength> 0)

BYTESREQUIRED ;

WHILE (Templength> 0); lengthbytes = new byte [bytesRequired];

Byte firstLengthbyte = (byte) (bytesRequired -1);

FirstLengthbyte | = 0x80;

Lengthbytes [0] = firstLENGTHBYTE;

INT J = BYTESREQUIRED - 1;

For (int i = 1; i

J -;

Lengthbytes [i] = (Byte) (Length >>> (J * 8) & 0xFF);

} // for

} // else

Return Lengthbytes;

} // getLengthbytes

Recall the discussion of Table 2 in this series, there are two methods that represent byte lengths: single-byte representation and multi-byte representation. The single-byte length representation is used to represent a length value of less than or equal to 127, while the multi-byte length representation is used when the length value is greater than 127. The getLengthbytes () method first checks if the length value is negative. If it is negative, just return null because I can't handle negative values. This method then checks if the length value is less than or equal to 127. If so, you need to use a single byte length representation. Note An integer in J2ME is 4-byte data, while single-byte length indication is only one byte. If the length parameter is a value between 0 and 127 (including this two), its byte expression is between 0x00000000 and 0x0000007f (meaning only the least significant bit byte contains useful data). When this integer shape is a single byte, only the lowest effective bit byte (0x00 to 0x7f) is copied as a hexadecimal value to a single-by-item array. Therefore, if the length value is between 0 and 127, then I can only perform one bit bit AND operation between the length and 0xFF. This operation will get an integer, and it is valid for 3 bytes to be filled in zero. Therefore, I can put the result of the bitwise operation as a byte, put this byte into a single-by-item array and return this array to the calling application. If the length value is greater than 127, then I must use the multi-byte length representation, which uses at least 2 bytes of data. The first byte indicates the number of bytes of length bytes, and later is the actual length byte (see the first article for detailed explanation on this format). If the length value is less than 256, then a total of 2 length bytes is needed - 1 byte indicates that there is a length byte, and one byte contains the actual length value. If the length value is at least 256 and less than 65536 (256 multiplying 256), then a total of 3 length bytes is required - 1 byte indicates that there are two length bytes, and the two bytes contain the actual length value. Therefore, the number of bytes required in the multi-byte format depends on the length value. That's why the number of bytes required to calculate the length byte in the Do - While cycle of the ELSE block in getLengthbytes (). Method for determining the number of bytes required is simple. I declare a byte counter named bytesRequired, start counting from 2 (the minimum number of bytes required), divides the length value at 256, and check whether the merchant is greater or equal to 1. If so, then the original length value is greater than 256, so I need to at least 3 bytes, so I add a counter (BytesRequired). I continue to remove the length value at 256 and increase the byte counter until the value is less than 1. At this time, I know that I have found the number of bytes required in the multi-bypique integer format. After you know the number of bytes you need, I instantiate a byte array with an appropriate size. Naturally, the first byte in the length byte will indicate how many length bytes are there. Therefore, I just subtract the number of bytes required by 1 (bytesRequired-1) and copy it to a byte called FirstLengthbyte. Look at the firstLengthbyte | = 0x80 of the getLengthbytes () method in the list 2. This line of code performs the firstLengthbyte and 0x80 (1000 0000) and store the results into FirstLengthbyte.

This logic OR operation sets the leftmost (highest valid) bit of FirstLengthbyte to 1. Recalling the discussion in the first article in this series, when you want to use the multi-by-section integer format, you must set the leftmost bit of the first length byte to 1. Next line (Lengthbytes [0] = firstLengthbyte is only copied at the firstLENGTHBYTE at the start position of the array containing the length byte. Then, there is a FOR loop that copies the length byte from the length parameter to its correct position in the lengthbytes array. When the FOR loop is exited, this Lengthbytes array in accordance with the ASN.1 format is obtained. The last line of the getLengthbytes () method in Listing 2 returns this array. GetIntegerBytes () This method takes an integer (value) as a parameter and returns this integer value expressed in ASN.1 Integer. Recall that in Table 1 in this series, INTEGER is a general data type in ASN.1. The implementation of the GetIntegerBytes () method is shown in Listing 3. Listing 3. GetIntegerBytes () method public byte [] getintegerbytes (int integerContents)

{

// 1. Declare a byte array name named Finalbytes, Which Will

// Hold All the bytes of the asn.1 byte array rezeation.

Byte firmbytes [];

// 2. Calculate the number of bytes required to Hold To

// contents part of the asn.1 byte array representation.

INT TEMPVALUE = IntegerContents;

INT contentBytescount = 1;

Do {

TempValue = TempValue / 256;

IF (TempValue> 0)

CONTENTBYTESCOUNT ;

WHILE (TEMPVALUE> 0);

// 3. Use the getlengthbytes () Method of Listing 3 To Author

// The length bytes. Store the length bytes in an array named lengthbytes.

Byte lengthbytes [] = getLengthbytes (ContentBytescount);

// 4. Get the number of bytes in the lengthbytes array.

INT lengthbytescount = lengthbytes.length;

// 5. Calculate the number of bytes required to hold the

// Complete Asn.1 byte Array Representation

// (The Sum Total of The Number of Tag Bytes, Length Bytes, And Content Bytes).

// store the number of bytes in a variable named Totalbytescount.

INT TOTALBYTESCOUNT = 1 Lengthbytescount ContentBytescount;

//6. Instantiate the firmbytes array to totalbytescount size.finalbytes = new byte [TOTALBYTESCOUNT];

// 7. Copy The Tag Byte at the start of the finalbytes array.

FinalBytes [0] = (Byte) 0x02;

// 8. Copy The Length bytes from the lengthbytes array

// to the finlbytes array just after the tag byte.

For (int i = 0; i

FinalBytes [i 1] = Lengthbytes [i];

// 9. Copy the content bytes to the finlbytes array

// Just after the length.

INT K = Totalbytescount - Lengthbytescount - 1;

For (int J = Lengthbytescount 1; J

K -;

FinalBytes [J] = (Byte) (IntegerContents >>> (K * 8) & 255);

} // for

// 10. Return The Finalbytes Array.

Return FinalBytes;

} // getIntegerbytes

This method first declares an array named FinalBytes. This byte array contains all bytes of the Integer data type structure. However, I still don't know the size of the FinalBytes array. I first need to calculate the number of bytes in the Integer structure, which consists of several steps: The first step is to calculate the number of bytes required to accommodate this integer value (the content part of the Integer structure). To this end, I used a Do - While loop that continuously divided the value integer at 256 until the value was less than 1. When this cycle exits, the number of bytes required to accommodate the content portion is stored in a variable called ContentBytescount. This method then passes the required length as an integer to the getLengthBytes () method, which returns the length byte expressed in ASN.1. I store the length byte number to a variable called Lengthbytescount. Recalling that in this series, the byte arrays expressed in this series include three parts: label bytes, length bytes, and content bytes. Therefore, the ASN.1 byte array expression needs to contain enough space for all these three parts. The next step is to calculate the size of the array of all bytes that will include all bytes of the Integer structure. I am calculated by adding the label byte length (for Integer and all other labels used in Kerberos), the length byte number and the contents of the content bytes are calculated. INT TOTALBYTESCOUNT = 1 Lengthbytescount ContentBytescount; this is this calculation and stores the number of bytes required to a variable called TotalBytescount. Below, I instantiate a size of TotalBytescount FinalBytes. The rest of the process is simple, I will store the label byte (for Integer 0x02) to the beginning of the FinalBytes array. Then, copy the length byte to the latch field behind the FinalBytes array. Finally, I copied the content byte to the length byte and returns the FinalBytes array. getGeneralstringBytes (), getOCTStringBytes (), getBitstringBytes () and getGeneralizedTIMEBYTES () are like getIntegerBytes (), each method returns an ASN.1 universal data type structure. The getGeneralstringBytes () method in Listing 4 generates an ASN.1 generalstring byte array expression. Similarly, the getOCTStringBytes () method in Listing 5 returns the byte array expression of Asn.1 OCTETString. The getBitstringBytes () method in Listing 6 returns Bitstring ASN.1 expression. Finally, the getGeneralizedTimeBytes () method in Listing 7 returns the byte array expression of the ASN.1 generalizedtime value. All of these methods follow the same implementation logic seen in the previous discussion of GetIntegerBytes () methods:

Declare a byte array called FinalBytes, which will contain all bytes expressed in an ASN.1 byte array. Calculate the number of bytes required to accommodate an ASN.1 byte array expression. The length byte is generated in the GetLengthbytes () method in Listing 3. Save the length byte to an array called Lengthbytes. Get the number of bytes in the Lengthbytes array. Calculate the number of bytes required to accommodate the complete ASN.1 byte array (the sum of the tag bytes, length bytes, and content bytes). Save this byte number into a variable called TotalBytescount. Instantiate a FinalBytes array of values ​​with Totalbytescount. Copy the label item to the beginning of the FinalBytes array. Copy the length bytes in the Lengthbytes array to the position of the tag byte in the FinalBytes array. Copy the content byte to the position of the length byte in the FinalBytes array. Returns the FinalBytes array. Listing 4, Listing 5, Listing 6, and Listing 7 With a comment that helps you track and compare each step in the J2ME code in the J2ME code. Listing 4. GetGeneralstringBytes () method public byte [] getGeneralstringBytes (String GeneralStringContent)

{

// 1. Declare a byte array name named Finalbytes, Which Will

// Hold All the bytes of the asn.1 byte array rezeation.

Byte firmbytes [];

// 2. Calculate the number of bytes required to Hold To

// contents part of the asn.1 byte array representation.

Int contentBytescount = generalstringcontent.length ();

// 3. Use the getlengthbytes () Method of Listing 3 To Author

// The length bytes. Store The Length Bytes in

// AN array named lengthbytes.

Byte lengthbytes [] = getLengthbytes (ContentBytescount);

// 4. Get the number of bytes in the lengthbytes array.

INT lengthbytescount = lengthbytes.length;

// 5. Calculate the number of bytes required to hold the completion

// asn.1 byte array representation (The Sum Total of the Number

// of tag bytes, length bytes, and content Bytes.

// store the number of bytes in a variable named Totalbytescount.

INT TOTALBYTESCOUNT = 1 Lengthbytescount ContentBytescount;

// 6. Instantiate the firmbytes array to totalbytescount size.

FinalBytes = new byte [Totalbytescount];

//7.copy the tag byte at the start of the finlbytes array.

FinalBytes [0] = (byte) 0x1b; // 8. Copy the length bytes from the lengthbytes array

// to the finlbytes array just after the tag byte.

For (int i = 0; i

FinalBytes [i 1] = Lengthbytes [i];

// 9. Copy the content bytes to the finalBytes array just after the length.

BYTE TEMPSTRING [] = generalstringcontent.getbytes ();

For (Int J = Lengthbytescount 1; J

FinalBytes [J] = Tempstring [J- (Lengthbytescount 1)];

// 10. Return The Finalbytes Array.

Return FinalBytes;

} // getGeneralstringBytes

Listing 5. GetOCTStringBytes () method

Public Byte [] getOCTStringBytes (byte [] octetstringcontents)

{

// 1. Declare a byte array name named Finalbytes, Which Will

// Hold All the bytes of the asn.1 byte array rezeation.

Byte firmbytes [];

// 2. Calculate the number of bytes required to Hold To

// contents part of the asn.1 byte array representation.

Int contentBytescount = OCTETSTRINGCONTENTS.LENGTH;

// 3. Use the getlengthbytes () Method of Listing 3 To Author

// The length bytes. Store The Length Bytes in

// AN array named lengthbytes.

Byte lengthbytes [] = getLengthbytes (ContentBytescount);

// 4. Get the number of bytes in the lengthbytes array.

INT lengthbytescount = lengthbytes.length;

// 5. Calculate the number of bytes required to hold the completion

// asn.1 byte array representation (The Sum Total of the Number

// of tag bytes, length bytes, and content Bytes.

// store the number of bytes in a variable named Totalbytescount.

INT TOTALBYTESCOUNT = 1 Lengthbytescount ContentBytescount;

// 6. Instantiate the firmbytes array to totalbytescount size.

FinalBytes = new byte [totalbytescount]; // 7. Copy The Tag Byte At The Start of the Finalbytes Array.

FinalBytes [0] = (Byte) 0x04;

// 8. COPY The length bytes from the lengththing array to the lengthbytes

// FinalBytes array just after the tag byte.

For (int i = 0; i

FinalBytes [i 1] = Lengthbytes [i];

// 9. Copy the content bytes to the finlbytes array

// Just after the length.

For (Int J = Lengthbytescount 1; J

FinalBytes [J] = OCTETSTRINGCONTENTS [J- (Lengthbytescount 1)];

// 10. Return The Finalbytes Array.

Return FinalBytes;

} // getOCTStringBytes

Listing 6. GetBitstringBytes () method

Public Byte [] getBitstringBytes (byte [] content)

{

// 1. Declare a byte array name named Finalbytes, Which Will

// Hold All the bytes of the asn.1 byte array rezeation.

Byte firmbytes [];

// 2. Calculate the number of bytes required to Hold To

// contents part of the asn.1 byte array representation.

Int contentBytescount = Content.length;

// 3. Use the getlengthbytes () Method of Listing 3 To Author

// The length bytes. Store The Length Bytes in

// AN array named lengthbytes.

Byte lengthbytes [] = getLengthbytes (ContentBytescount);

// 4. Get the number of bytes in the lengthbytes array.

INT lengthbytescount = lengthbytes.length;

// 5. Calculate the number of bytes required to hold the completion

// asn.1 byte array representation (The Sum Total of the Number

// of tag bytes, length bytes, and content Bytes.

// store the number of bytes in a variable named Totalbytescount.

INT TOTALBYTESCOUNT = 1 Lengthbytescount ContentBytescount;

//6. Instantiate the firmbytes array to totalbytescount size.finalbytes = new byte [TOTALBYTESCOUNT];

// 7. Copy The Tag Byte at the start of the finalbytes array.

FinalBytes [0] = (Byte) 0x03;

// 8. COPY The length bytes from the lengththing array to the lengthbytes

// FinalBytes array just after the tag byte.

For (int i = 0; i

FinalBytes [i 1] = Lengthbytes [i];

// 9. Copy the content bytes to the finlbytes array

// Just after the length.

For (Int J = Lengthbytescount 1; J

FinalBytes [J] = Content [J- (Lengthbytescount 1)];

// 10. Return The Finalbytes Array.

Return FinalBytes;

} // getBitStringBytes

Listing 7. getGeneralizedTimeBytes () method

Public Byte [] getGeneralizedTimeBytes (byte [] generalizedtimecontent)

{

// 1. Declare a byte array name named Finalbytes, Which Will

// Hold All the bytes of the asn.1 byte array rezeation.

Byte firmbytes [];

// 2. Calculate the number of bytes required to Hold To

// contents part of the asn.1 byte array representation.

INT contentBytescount = generalizedtimecontent.length;

// 3. Use the getlengthbytes () Method of Listing 3 To Author

// The length bytes. Store The Length Bytes in

// AN array named lengthbytes.

Byte lengthbytes [] = getLengthbytes (ContentBytescount);

// 4. Get the number of bytes in the lengthbytes array.

INT lengthbytescount = lengthbytes.length;

// 5. Calculate the number of bytes required to hold the completion

// asn.1 byte array representation (The Sum Total of the Number

// of tag bytes, length bytes, and content Bytes.

// store the number of bytes in a variable named Totalbytescount.

INT TOTALBYTESCOUNT = 1 Lengthbytescount ContentBytescount; // 6. Instantiate The FinalBytes Array To Totalbytescount size.

FinalBytes = new byte [Totalbytescount];

// 7. Copy The Tag Byte at the start of the finalbytes array.

FinalBytes [0] = (Byte) 0x18;

// 8. COPY The length bytes from the lengththing array to the lengthbytes

// FinalBytes array just after the tag byte.

For (int i = 0; i

FinalBytes [i 1] = Lengthbytes [i];

// 9. Copy the content bytes to the finlbytes array

// Just after the length.

For (Int J = Lengthbytescount 1; J

FinalBytes [J] = GeneralizedTimeContent [J- (Lengthbytescount 1)];

// 10. Return The Finalbytes Array.

Return FinalBytes;

} // getGeneralizedTimeBytes

ConcatenateBytes () This method (see Listing 8) Take two byte arrays to receive the second array series and return the array of series. Because this method takes two byte arrays and returns another byte array, it can be self-contained as an array of byte arrays in a string. For example, concatenatebytes (ByteArray1, ConcateNateBytes) will add ByteArray3 after ByteArray2, then add the result to ByteArray1. Listing 8. ConcateNateBytes () method

Public Byte [] ConcateNateBytes (byte [] array1, byte [] array2)

{

Byte concatenedBytes [] = new byte [array1.length array2.length];

For (int i = 0; I

ConcatenatedBytes [i] = array1 [i];

For (int J = array1.length; j

ConcatenatedBytes [J] = array2 [j-array1.length];

Return ConcatenatedBytes;

} // ConcatenateBytes

GetSequenceBytes () This method (see Listing 9) Generates an ASN.1 Sequence's byte array expression. It takes a byte array as an input parameter, which uses the byte array as the content of Sequence, plus the Sequence tag byte (0x30) and length bytes in front, and returns a complete sequence structure. Typically, getsequenceBytes () methods will be used with ConcateNateBytes (). An application will generate separate structures in Sequence, connect the byte arrays of each structure to constitute an array and pass the series after the array to getSequenceBytes () method, this method will return the complete words of SEQUENCE An array group expression. Listing 9. GetsequenceBytes () method public byte [] getsequencebytes (byte [] sequencecontents)

{

// 1. Declare a byte array name named Finalbytes, Which Will

// Hold All the bytes of the asn.1 byte array rezeation.

Byte firmbytes [];

// 2. Calculate the number of bytes required to Hold To

// contents part of the asn.1 byte array representation.

INT contentBytescount = sequencecontents.length;

// 3. Use the getlengthbytes () Method of Listing 3 To Author

// The length bytes. Store The Length Bytes in

// AN array named lengthbytes.

Byte lengthbytes [] = getLengthbytes (ContentBytescount);

// 4. Get the number of bytes in the lengthbytes array.

INT lengthbytescount = lengthbytes.length;

// 5. Calculate the number of bytes required to hold the completion

// asn.1 byte array representation (The Sum Total of the Number

// of tag bytes, length bytes, and content Bytes.

// store the number of bytes in a variable named Totalbytescount.

INT TOTALBYTESCOUNT = Lengthbytescount 1;

// 6. Instantiate the firmbytes array to totalbytescount size.

FinalBytes = new byte [Totalbytescount];

// 7. Copy The Tag Byte at the start of the finalbytes array.

FinalBytes [0] = (Byte) 0x30;

// 8. COPY The length bytes from the lengththing array to the lengthbytes

// FinalBytes array just after the tag byte.

For (int i = 0; I

// 9. Copy the content bytes to the finlbytes array

// Just after the length.

FinalBytes = ConcateNateBytes (FinalBytes, SequenceContents);

// 10. Return The Finalbytes Array.

Return FinalBytes;

} // GetSequenceBytes

GetTagandLengthbytes () This method is very similar to the various getxxBytes () methods discussed. However, although each of them generates a specific ASN.1 universal data type, the getTagandLengthbytes () method (see Listing 10) generates the application level and context-specific data type. This method takes three parameters. The first parameter specifies the tag type. If its value is equal to the static integer asn1DataTypes.context_specific, it specifies a context-specific tag, if its value is equal to Asn1DataTypes.Application_Type, then it specifies an application-level label. The second parameter specifies the number of labels, and the third (tagContents) contains the contents of the content byte. GetTagandLengthbytes () calculates the value of the tag and length byte according to the input parameter, plus the label and length byte to the content byte, and returns the full-byte array expression of the application level or context-specific ASN.1 structure. Listing 10. GetTagandLengthbytes () method

Public Byte [] getTagandLengthbytes (int tagtype, int tagnumber, byte "tagcontents)

{

// 1. Declare a byte array name named Finalbytes,

// Which Will Hold All the bytes of the asn.1 byte array representation.

Byte firmbytes [];

// 2. Declare a byte array name named TagandLengthbytes,

// Which Will Hold The Tag and length bytes.

Byte tagandlengthbytes [];

// 3. Now Calculate The value of the tag byte.

INT tag = tagtype tagnumber;

// 4. Calculate the number of bytes request to hold

// The contents part of the asn.1 byte array representation.

INT contentBytescount = tagcontents.length;

// 5. Use the getLengthbytes () Method of Listing 3

// TO Author The Length Bytes.

// store the length bytes in an array named longthbytes.

Byte lengthbytes [] = getLengthbytes (ContentBytescount);

// 6. Get the number of bytes in the lengthbetes array.int lengthbytescount = lengthnessbytes.length;

// 7. Calculate the number of bytes required to hold

// the tag byte and length bytes

// (The Sum Total of The Number of Tag Bytes and length Bytes).

// Store the Number of bytes in a variable named tagbytescount.

INT tagandLengthbytescount = 1 longthbytescount;

// 8. Instantiate The Finalbytes Array to TagandLengthbytescount size.

Tagandleyngthbytes = new byte [tagandlengthbytescount];

// 9. Copy The Tag Byte at The Start of the TagandLengthbytes Array.

TagandLengthbytes [0] = (byte) TAG;

// 10. Copy The Length bytes from the lengthbytes array

// to the tagandenstething array just after the tag byte.

For (int i = 0; i

TagandLengthbytes [i 1] = Lengthbytes [i];

// 11. Now Instansiate The FinalBytes Array of Size Equal To

// The sum Total of the number of tag bytes,

// Length bytes and content bytes.

FinalBytes = New byte [1 TagandLengthbytescount ContentBytescount];

// 12. Copy the content bytes to the finalbytes array

// Just after the length.

FinalBytes = ConcatenateBytes (TagandLengthbytes); TagContents

// 13. Return The Finalbytes Array.

Return FinalBytes;

} // gettagandLengthbytes

At this time, the discussion of the generation method of the Asn1DataTypes class is completed. However, before starting to discuss how Kerberosclient generates a TGT request to generate a TGT request with the Asn1DataTypes method, I need to discuss how to use the user's password to generate a key. This key is needed when communicating with the Kerberos server. A algorithm for processing a user password to generate a key is defined by using the user password generation key Kerberos. During the process of obtaining TGT, the Kerberos client will decrypt this key to decrypt this J2ME-based Kerberos client. I will only support a cryptographic algorithm, which is DES in CBC (Password Group Link Cipher Block Chaining) mode. Encryption standard). DES is a FIPS (Federal Information Processing Standard Federal Information Process "published, which describes an encryption algorithm that will encrypt data (plain text) and key as input to the encryption process. The key and plain text is unified based on the DES algorithm to generate an encrypted (ciphertext) form of plain text data. (For more information on DES, please refer to the reference). The CBC is an encrypted mode of operation, where plain text data is divided into data blocks of the same size. For example, in 64-bit DES-CBC encryption, data is divided into 8-bytes of blocks. If the number of bytes in plain text data is not an integer multiple of the number of bytes you want each block, add the appropriate number of bytes to the last piece to make it the size as other blocks. Then create a byte array with the same size with your block. This byte array is called the initial vector (IV). The Kerveros specification defines all initial vectors based on Kerberos-based applications (similarly, others using the DES-CBC specification define the IV values ​​used). Thereafter, the first block and key of this IV, pure text data are taken, and they are processed according to the DES algorithm to form a ciphertext corresponding to the first data block of the plain text data. The ciphertext form of the first data block is then taken as the initial vector of the second block and the same DES encryption process is performed to generate a second plain text data block. In this way, a piece of ciphertext forming each block is continued. Finally, all secret blocks are connected in series to obtain a ciphertext form of all plain text data. Because I only intend to support DES-CBC in this Kerberos client, I will only discuss the generation process of the key used by the DES-CBC, as shown below:

Connect the user password, the KDC domain name, and the user's user name string together to form a string. Kerberos uses this series of strings, not just a password generation key. Why join domain names and usernames in key generation? Many users will use the same password on different servers. If I use a password to generate a key, a given password always generates the same key on all Kerberos servers. Thus, if a hacker can get the key on a Kerberos server, he can use the same key on all Kerberos servers. On the other hand, if I joined the domain name and user name, a key that is subject to such an attack will only violate a specific domain. Get the byte array expression of the string of strings in step 1. Statistical Number of bytes in the byte array in step 2. Additional quantity zero bytes are attached to the back of this byte string to make it an integer multiple of 8. For example, if this byte array contains 53 bytes, then the last additional three bytes of this byte array have 56 bytes. The byte array after the byte of the byte is divided into two blocks in the third step, each block has 8 bytes. Each sequence of the block is inverted. In other words, the first block remains unchanged, the bit order of the second block should be reversed, the third block should remain unchanged, the order of the second block should be reversed, and in this class. Take the first (unlike) block and perform each bit of Exclusive or in the second (reverse) block. The result obtained by the first Exclusive OR operation is then performed with the third (unlike) block for another Exclusive OR operation. Continue to Exclusive or operation until all blocks have been completed. The final result of all EXCLUSIVE OR operations is a 8-byte length block. Fix the parity of the 8-word blocks obtained in step 6. The minimum significant bit of each piece is kept as parity. Statistics 1 of 1 in the 8-byte block, if the number of 1 is even, then set the lowest bit of 1 to make it an odd number. For example, if the value of one byte is 00000000, then it is changed to 00000001. If the number of 1 in one byte is already odd, then set it to zero. For example, if a byte is 00000010, then no change is made to modify its parity. DES defines some weak, so it is not suitable for encrypted keys. The eighth step of our key generation process is to check if the parity correction byte array is a weak key. If so, use 0xF0 (11110000) to perform Exclusive or in the 8-byte block with the parity correction. If the parity correction is not a weak key, then this Exclusive OR operation is not required. The byte array through this weak key is a temporary key. Now I want to use this temporary key to encrypt the additional byte array obtained in step 3 in the DES-CBC algorithm. This temporary key is simultaneously used as the value of the key and the value of the initial vector encrypted by the DES-CBC. Recalling in the previous discussion, CBC requires a secret block link. The result of step 9 is the encryption result of the last 8-word block (abandon the previous ciphertext block). Therefore, the result of this step is another 8-word block. Now I correct the parity of each byte of the 8-byte block generated in step 9. I explain the parity correction in step 7 above. Now check that the parity-corrected 8-byte block obtained by step 10 is not a weak key (just like it is done in step 8). The result of step 11 is a KeerOS client to communicate with the Kerberos server. Now look at the Kerberoskey class in Listing 11. The generateKey () method of this class implements the 11 steps to generate algorithms described above. Listing 11. KerberosKey class

Import org.bouncecastle.crypto.params.parameterswithrams.ParameterswithraM; Import Org.Bouncecastle.crypto.modes.cbcblockcipher

Import org.bouncycastle.crypto.generators.deskeyGenerator;

Import org.bouncycastle.crypto.params.desparameters;

Import Org.bouncecastle.crypto.engines.desengine;

Import org.bouncycastle.crypto.params.KeyParameter;

Import org.bouncycastle.crypto.params.Parameterswithiv;

Public Class Kerberoskey

{

Private cbcblockcipher copher;

Private keyparameter KP;

Private parameterswithiv iv;

Private byte kerberoskey [];

Private asn1dattypes asn1;

Private stringprincipalid;

Public Kerberoskey (String UserName, String Password, String Realmname)

{

Kerberoskey = new byte [8];

Kerberoskey = GenerateKey (Password, Realmname, UserName);

} // kerberoskey

Public Byte [] GenerateKey (String Password, String Realmname, String Username)

{

// Step 1:

String str = new string (Password Realmname UserName);

Byte SecretKey [] = new byte [8];

// STEP 2:

Byte EncodedByteArray [] = EncodeString (STR);

// STEP 3:

BYTE PADDEDBYTEARRAY [] = Padstring (EncodedByteaRray);

// STEP 4:

INT i = paddedbytearray.length / 8;

// STEP 5:

FOR (int x = 0; x

{

BYTE BLOCKVALUE1 [] = New byte [8];

System.ArrayCopy (PaddedByteArray, x * 8, blockValue1, 0, 8);

IF (x% 2 == 1)

{

BYTE TEMPBYTE1 = 0;

BYTE TEMPBYTE2 = 0;

BYTE BLOCKVALUE2 [] = New byte [8];

For (int y = 0; y <8; y )

{

TEMPBYTE2 = 0;

For (int z = 0; z <4; z )

{

Tempbyte2 = (Byte) ((1 << (7-Z)) & 0xFF);

Tempbyte1 | = (BlockValue1 [Y] & Tempbyte2) >>> (7-2 * z);

TEMPBYTE2 = 0;

}

For (int z = 4; z <8; z )

{

TempByte2 = (BYTE) ((1 << (7-Z)) & 0xFF); Tempbyte1 | = (BlockValue1 [Y] & Tempbyte2) << (2 * z-7);

TEMPBYTE2 = 0;

}

BlockValue2 [7-y] = tempbyte1;

TEMPBYTE1 = 0;

} // Outer for

For (int A = 0; a <8; A )

BlockValue2 [A] = (Byte) (((Byte) block2 [A] & 0xFF) >>> 1) & 0xFF);

System.ArrayCopy (BlockValue2, 0, BlockValue1, 0, BlockValue2.Length);

} // if (x% 2 == 1)

For (int A = 0; a <8; A )

BlockValue1 [A] = ((Byte) (((Byte) BlockValue1 [A] & 0xFF) << 1) & 0xFF);

// STEP 6:

For (int b = 0; b <8; b )

SECRETKEY [B] ^ = BlockValue1 [B];

} // for

// STEP 7:

SECRETKEY = setParity (SecretKey);

// STEP 8:

IF (IsweakKey (SECRETKEY))

SecretKey = GetStrongKey (SECRETKEY);

// STEP 9:

SecretKey = GetFinalKey (PaddedByteaRray, SecretKey);

// STEP 10:

SECRETKEY = setParity (SecretKey);

IF (IsweakKey (SECRETKEY))

SecretKey = GetStrongKey (SECRETKEY);

Return SecretKey;

} // generateKey

Public Byte [] getFinalKey (byte data ", byte key [])

{

// The cipher instance with des algo and cbc mode.

Cipher = new cbcblockcipher (new desengine ());

KP = New KeyParameter (Key);

IV = New Parameterswithiv (KP, Key);

Cipher.init (TRUE, IV);

BYTE ENCKEY [] = New byte [data.length];

Byte ivbytes [] = new byte [8];

For (int x = 0; x

{

Cipher.ProcessBlock (Data, X * 8, Enckey, x * 8);

System.ArrayCopy (Enckey, x * 8, Ivbytes, 0, 8);

IV = New Parameterswithiv (KP, IvBytes);

Cipher.init (TRUE, IV);

}

Return Ivbytes;

} // getFinalKey

Public Byte [] setParity (byte bytevalue [])

{

FOR (int x = 0; x <8; x )

Bytevalue [x] = parityValues ​​[bytevalue [x] & 0xff]; return bytevalue;

}

// Checks Weak Key

Public Boolean isweakkey (byte keyvalue "

{

Byte WeakKeyValue [];

For (int x = 0; x

{

WeakKeyValue = WeakKeybytevalues ​​[x];

WeakKeyValue.equals (keyvalue))

Return True;

}

Return False;

} // isweakkey

// CORRECTS The Weak key by Exclusive or with 0xf0 constant.

Public Byte [] getStrongKey (Byte KeyValue "

{

KeyValue [7] ^ = 0xF0;

Return KeyValue;

} // checkweakkey

// encodes string with iso-limited eNCodings

Public Byte [] ENCODESTRING (String STR)

{

Byte encodedbyteArray [] = new byte [str.length ()];

Try

{

EncodeByteArray = str.getbytes ("8859_1");

}

Catch (java.io.unsupportedEncodingexception UE)

{

}

Return EncodedByteArray;

} // encodestring

// this method Pads the byte [] with ascii nulls to an 8 byte boundary.

Public Byte [] Padstring (Byte EncodedString [])

{

INT X;

EncodedString.Length <8)

X = encodedstring.length;

Else

X = EncodedString.length% 8;

IF (x == 0)

Return encodedstring;

Byte PaddedByteArray [] = new byte [(8 - x) encodedString.Length];

For (int y = paddedbytearray.length - 1; y> encodedstring.length - 1; y -)

PaddedByteArray [Y] = 0;

System.Arraycopy (EncodedString, 0, PaddedByteArray, 0, EncodedString.Length);

Return PaddedbyTearray;

} // Padstring

// returns the secret key bytes.

Public Byte [] getKey ()

{

Return this.kerberoskey;

} // getKey ()

Private byte weakkeybytevalues ​​[] [] = {

{(Byte) 0x10, (byte) 0x10, (byte) 0x10, (byte) 0x10,

(Byte) 0x10, (byte) 0x10, (byte) 0x10, (byte) 0x1},

{(Byte) 0xfe, (Byte) 0xfe, (Byte) 0xfe, (Byte) 0xfe,

(Byte) 0xfe, (byte) 0xfe, (byte) 0xfE}, {(byte) 0x1f, (byte) 0x1f, (byte) 0x1f, (byte) 0x1f,

(Byte) 0x1f, (byte) 0x1f, (byte) 0x1f, (byte) 0x1f},

{(byte) 0xE0, (byte) 0xE0, (byte) 0xE0, (Byte) 0xE0,

(Byte) 0xE0, (Byte) 0xE0, (Byte) 0xE0, (Byte) 0xE0},

{(Byte) 0x1f, (byte) 0xE0, (byte) 0x1f, (byte) 0xE0,

(Byte) 0x1f, (byte) 0xE, (byte) 0x01, (byte) 0xfe},

{(Byte) 0xFE, (Byte) 0x01, (Byte) 0xFe, (Byte) 0x01,

(Byte) 0xFE, (Byte) 0x01, (Byte) 0xfe, (Byte) 0x01},

{(Byte) 0x1f, (byte) 0xE0, (byte) 0x1f, (byte) 0xE0,

(Byte) 0x0E, (Byte) 0xF1, (Byte) 0x0E, (Byte) 0xf1},

{(Byte) 0x1f, (byte) 0x1f, (byte) 0x1f,

(Byte) 0xF1, (Byte) 0x0E, (Byte) 0xF1, (Byte) 0x0e},

{(Byte) 0x1e, (byte) 0x00, (byte) 0x1e, (byte) 0x00,

(Byte) 0x1f, (byte) 0x10, (byte) 0x1f, (byte) 0x1},

{(Byte) 0x01, (Byte) 0xE0, (Byte) 0x01,

(byte) 0xf1, (byte) 0x01, (byte) 0xF1, (byte) 0x01},

{(Byte) 0x1f, (byte) 0xFe, (Byte) 0x1f, (byte) 0xFe,

(Byte) 0x0E, (Byte) 0xfe, (byte) 0x0E, (Byte) 0xfe},

{(Byte) 0xfe, (byte) 0x1f, (byte) 0xfe, (Byte) 0x1f,

(byte) 0xfe, (byte) 0x0E, (byte) 0xfe, (byte) 0x0e},

{(Byte) 0x11, (byte) 0xf0, (byte) 0x11, (byte) 0xF0,

(byte) 0x10, (byte) 0x10, (Byte) 0x10, (byte) 0xE},

{(Byte) 0x1f, (byte) 0x01, (byte) 0x1f, (byte) 0x01,

(Byte) 0x0E, (Byte) 0x01, (Byte) 0x0E, (Byte) 0x01},

{(Byte) 0xe0, (Byte) 0xfe, (byte) 0xE0, (byte) 0xfe,

(Byte) 0xF1, (Byte) 0xfe, (byte) 0xF1, (byte) 0xfe},

{(Byte) 0xfe, (byte) 0xE0, (byte) 0xfe, (byte) 0xE0,

(byte) 0xfe, (byte) 0xF1, (byte) 0xfe, (byte) 0xf1}

}

// Parity Values ​​for All Possible Combinations

// 256 entries

Private Byte ParityValues ​​[] = {

1, 1, 2, 2, 4, 4, 7, 7, 8, 8,

11, 11, 13, 13, 14, 14, 16, 16, 19, 19,

21, 21, 22, 22, 25, 25, 26, 26, 28, 28,

31, 31, 32, 32, 35, 35, 37, 37, 38, 38,

41, 41, 42, 42, 44, 44, 47, 47, 49, 49,

50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62, 64, 64, 67, 67, 69, 69,

70, 70, 73, 73, 74, 74, 76, 76, 79, 79,

81, 81, 82, 82, 84, 84, 87, 87, 88, 88,

91, 91, 93, 93, 94, 94, 97, 97, 98, 98,

100, 100, 103, 103, 104, 104, 107, 107, 109, 109,

110, 110, 112, 112, 115, 115, 117, 117, 118, 118,

121, 121, 122, 122, 124, 124, 127, 127, -128, -128,

-125, -125, -123, -123, -122, -122, -119, -119, -118, -118,

-116, -116, -113, -113, -111, -111, -110, -110, -108, -108,

-105, -105, -104, -104, -101, -101, -99, -99, -98, -98,

-95, -95, -94, -94, -92, -92, -89, -89, -88, -88,

-85, -85, -83, -83, -82, -82, -80, -80, -77, -77,

-75, -75, -74, -74, -71, -71, -70, -70, -68, -68,

-65, -65, -63, -63, -62, -62, -60, -60, -57, -57,

-56, -56, -53, -53, -51, -51, -50, -50, -48, -48,

-45, -45, -43, -43, -42, -42, -39, -39, -38, -38,

-36, -36, -33, -33, -32, -32, -29, -29, -27, -27,

-26, -26, -23, -23, -22, -22, -20, -20, -17, -17,

-15, -15, -14, -14, -12, -12, -9, -9, -8, -8,

-5, -5, -3, -3, -2, -2

}

} // kerberoskey class

I have already marked those of the generateKey () method in Listing 11 to help you correspond to the corresponding rows of the algorithm from the corresponding rows in the J2ME code. The point in the code is truly explained is the 9th step, here I actually execute DES-CBC encryption. Look at those line code in the generateKey () method in the list 11, they mark with annotations as step 9. It is a call to the method named getFinalKey (). This method implements the ninth step and takes two parameters. The first parameter (DATA) is an array of byte arrays obtained in the additional operation of the third step, and the second parameter (key) is a temporary key obtained as a result of the eighth step. Desengine and CbcBlockCIpher class are actually encrypted. These classes are part of the J2ME platform of the Bounce Castle group. Bouncy Castle's implementation can be available for free and can be used for any purpose as long as you join license information when publishing. You will need to download the Bounce Castle class (see References) and follow the setup instructions thereto to use the sample code of this article. The KerberosKey class in Listing 11 contains all IMPORT statements required to use the Bounce Castle class in the Kerberos class. Now look at what happened in the getFinalKey () method in Listing 11. I first instantiate the Desengine class, this class implements the DES encryption algorithm. Then, I passed this Desengine object to the constructor CBCBLOCKCIPHER to create a CBCBLockCIpher object called Cipher. This CiPher object will perform the actual DES-CBC operation. Then I passed a KEY parameter to create a KEY parameter with a key parameter with a constructor called KeyParameter. This KeyParameter class is also part of the Bounce Castle's encrypted library. The KP object is now packaged, so I will pass this object when I need to specify the key. The next step is to create another object called IV. This object is another instance of the Bounce Castle class named Parameterwithiv. Parameterwithiv constructor takes two parameters. The first is a KP object packaged by the key. The second is the initial vector byte array. Since I must use the key as the initial vector, the key is passed as an initial vector byte array. IV objects are now packaged and initial vectors, so I will pass this object when you need to specify a key and initial vector. The next step is to invoke the INIT () method of the Cipher object to initialize this object. This method takes two parameters. The first is the Boolean type, transmitting true when you need to initialize a password to encrypt, and deliver FALSE when you want to decode. The second is the IV object packaged by the key and the initial vector, and now you can make a secret block link. I declare a byte array called Ivbytes, which will include the initial vector byte of the password block link. A FOR loop will continuously call the ProcessBlock () method of the Cipher object. ProcessBlock () method processes a data block at a time. ProcessBlock () method takes four parameters. The first is an input array (DATA), the second is the offset in the byte array. ProcessBlock () method The block input is started from this offset value. The third parameter is the name of the output array, and the fourth is the offset in the output array. The FOR cycle calls the processBlock () method handles a block. This method processes a piece at a time and stores the output (encrypted result) in the Ivbytes array.

After that, I created a new IV object by passing the IvBytes array to the Parameterswithiv constructor (an instance of the Parameterswithiv class). Then I reinitialize this password with the new IV object. The loop can then use the initial vector of the first block to process the next piece. When the loop is exited, I just returned the encrypted result of the last data block. This is the result of the 9th step of the key generation process. Generating TGT requests so far, I discussed the underlying method of the ASN1DATYPES class and implemented an algorithm for generating a key using the user's password. You can now show how Kerberosclient classes use these underlying details. Look at the list 12, it shows the implementation of the getTicketResponse () method. This method belongs to the Kerberosclient class. The basic purpose of the getTicketResponse () method is to generate a request to the Kerberos Bill (a TGT or Service Bill), send a ticket request to the Kerberos server, get a response from the server, and return the response to the calling application. In this article, I will only describe the process of generating TGT requests. The next article of this series will display the KDC server to send a request to the KDC to get the step of responding and processes it. Listing 12. GetticketResponse () method Import Org.bouncycastle.crypto.digests.md5digest;

Public Class Kerberosclient Extends Asn1DataTypes

{

Static long seed = system.currenttimemillis ();

Private string kdcServiceName = "kRBTGT";

Private Kerberoskey KrbKey;

PRIVATE STRING UserName;

PRIVATE STRING Password;

PRIVATE STRING Realmname;

Public Kerberosclient (String Username, String Realmname)

{

KrbKey = New Kerberoskey (Username, Password, Realmname);

THIS.USERNAME = UserName;

this.password = password;

This.Realmname = realmname;

} // kerberosclient

Public Byte [] getticketResponse ()

{

Byte pvno [] = getTagandLengthbytes (asn1dattypes.context_specific,

1, GetIntegerbytes (5));

BYTE MSG_TYPE [] = gettagandLengthbytes (asn1dattypes.context_specific,

2, Getintegerbytes (10));

Byte noptions [] = new byte [5];

BYTE KDC_OPTIONS [] = gettagandLengthbytes (asn1dattypes.context_specific,

0, GetBitstringBytes (noptions));

Byte generalstringsequence [] = getsequenceBytes

getGeneralstringBytes (username);

Byte name_string [] = gettagandLengthbytes (asn1dattypes.context_specific,

1, generalstringsequence; byte name_type [] = gettagandLengthBytes (asn1dattypes.context_specific,

0, getIntegerbytes (asn1dattypes.nt_principal);

Byte PrincipalNamesequence [] = getsequenceBytes

(ConcatenateBytes (name_type, name_string);

Byte cname [] = gettagandLengthbytes (asn1dattypes.context_specific,

1, PrincipalNamesequence);

Byte realm [] = getTagandLengthbytes (asn1dattypes.context_specific,

2, getGeneralstringBytes (realmname));

Byte sgeneralstringsequence [] =

ConcatenateBytes (Getgeneral4tringBytes (KdcServiceName),

getGeneralstringBytes (realmname));

Byte sname_string [] = gettagandLengthbytes (asn1DataTypes.context_specific,

1, getsequenceBytes (sgeneralstringsequence));

BYTE SNAME_TYPE [] = gettagandLengthbytes (asn1dattypes.context_specific,

0, getintegerbytes (asn1dattypes.nt_unknown);

Byte sprincipalnamesequence [] = getsequencebytes

(ConcatenateBytes (SNAME_TYPE, SNAME_STRING);

Byte sname [] = gettagandLengthbytes (asn1dattypes.context_specific,

3, sprincipalnamesequence);

Byte till [] = getTagandLengthbytes

Asn1DataTypes.Context_specific,

5,

getGeneralizedTimeBytes

NEW STRING ("19700101000000z). getBytes ()));

BYTE NONCE [] = GetTagandLengthbytes

Asn1DataTypes.Context_specific,

7.

Getintegerbytes (getrandomnumber ()));

Byte eType [] = getTagandLengthbytes

Asn1DataTypes.Context_specific,

8,

GetSequenceBytes (GetIntegerbytes (3))

);

BYTE REQ_BODY [] = GetTagandLengthbytes

Asn1DataTypes.Context_specific,

4,

GetSequenceBytes

ConcatenateBytes

KDC_OPTIONS,

ConcatenateBytes

CNAME,

ConcatenateBytes

Realm,

ConcatenateBytes

SNAME,

ConcatenateBytes

TILL,

ConcatenateBytes

(nonce, eType)

)

)

)

)

)

)

);

Byte TicketRequest [] = GetTagandLengthbytes

Asn1DataTypes.Application_type,

10,

GetSequenceBytes

ConcatenateBytes

PVNO,

ConcatenateBytes

(MSG_TYPE, REQ_BODY)

)

)

);

Return TicketRequest;

}

Public Byte [] getrandomnumber ()

{

String userdata = username password;

Byte SecretKey [] = getByteArray (System.currentTimeMillis () * 6 seed);

SEED = SEED / 5;

INT userdatahash = userdata.hashcode () * 5;

BYTE NUMDATA [] = new string (String.Valueof (userDatahash)). GetBytes ();

BYTE NUMBYTES [] = KrBKey.GetFinalKey (Numdata, SecretKey);

Byte randomnum [] = new byte [4];

INT j = 1;

For (int i = 0; i <4; i )

{

Randomnum [i] = NumBytes [i j];

J ;

}

Return Randomnum;

} // getrandomnumber

// it is a helper method used to generate the random number bytes structure.

Public Byte [] getintegerbytes (byte [] bytecontent)

{

Byte firmbytes [];

Int contentBytescount = bytecontent.length;

Byte lengthbytes [] = getLengthbytes (ContentBytescount);

INT lengthbytescount = lengthbytes.length;

INTEGERBYTESCOUNT = Lengthbytescount ContentBytescount 1;

FinalBytes = new byte [integerBytescount];

FinalBytes [0] = (Byte) 0x02;

For (int i = 0; i

FinalBytes [i 1] = Lengthbytes [i];

For (int J = longthbytescount 1; j

FinalBytes [J] = bytecontent [J- (Lengthbytescount 1)];

Return FinalBytes;

} // getIntegerbytes

// Converts a long Into a byte arch.

Public Byte [] GetByTearray (long L)

{

BYTE BYTEVALUE [] = new byte [8];

FOR (int x = 0; x <8; x )

Bytevalue [x] = (byte) (INT) (L >>> (7 - x) * 8 & 255L); Return Bytevalue;

}

} // kerberosclient class

The first article in this series I discussed the structure of TGT requests in the discussion of Figure 2, inventory 1 and Table 2. In the discussion there, the TGT requests contains four data fields: PVNO, MSG-Type, Padata and Req-Body. Generating PVNO and MSG-Type fields is very simple because two fields contain only an integer (as mentioned in the first article "Request TGT" section, PVNO is 5, MSG-Type is 10). You only need to call the GetIntegerBytes () method, pass this integer value to this method. GetIntegerBytes () Method Returns an Integer structure expressed in an ASN.1 byte array, and you pass it to your GetTagAndLengthbytes () method. This method will return the full ASN.1 expression of the PVNO or the MSG-Type field. This is how the PVNO and MSG-Type fields are generated at the beginning of the GetticketResponse () method in Listing 12. After generating the PVNO and the MSG-Type field, the next step is to generate a PADATA field. This field is optional. Most KDC servers have a setting option that can be configured separately. The system administrator can set the Kerberos server to a specific customer to send a TGT request that does not include the PADATA field. In order to alleviate the processing burden on the J2ME device on the limited resources, I assume that the electronic bank has a Kerberos server that allows the wireless mobile user to send a TGT request without a PADATA field (and I will show how to set up in this series. The Keberos server makes it a behavior). So I will go to the PADATA field in the TGT request to be generated. Therefore, after generating the PVNO and the MSG-Type field, I will directly generate the Req-Body structure, which takes a few steps. Generate the request body in the GetticKetResponse () method of Listing 12, my request body (Req-Body structure) generated a policy is all separate subfields of the structure, and then connect them together and packaged into a sequence to construct Request a text. Recalling in the discussion in the first article Figure 2, Req-Body's sub-fields (removed some optional fields):

KDC-Options CName Realm Sname Till Nonce ETYPE I will generate these fields in the order in the above list. Therefore, the first task is to generate a KDC-Options field. Because I don't want to use any KDC options, I don't need any logic to generate the KDC-Options field. I just use a 5-byte array of zero as its content. Take a look at the GetticketPonse () method of the list 12 byte noptions [] = new byte [5]; this line. This method instantiates a 5-byte array called NOOPTIONS, which is initialized to five zero. Next line (Byte Kdc_Options [] = gettagandens.context_specific, 0, getBitstringBytes (noptions))) Execute two tasks:

It first passes the Nooptions byte array to the getBitstringBytes () method, which returns 5 zero expressed with the bit string of ASN.1. Then it passes the bit string to the getTagAndLengthbytes () method, which returns the complete ASN.1 byte array expression of the KDC-Options field. The next step is to generate a CNAME structure. In the discussion of the first article Listing 1, the type of CName field is Type CNAME. This type of data is two fields - name-type and name-string - Sequence SEQUENCE. The Name-Type field is constructed with an Integer. The name-string field is a Sequence of GeneralString s. Therefore, in order to generate a CNAME structure, I have to follow several of the steps in the GetticketResponse () method of the list 12:

Call the getGeneralstringBytes () method, and pass the username of the customer. The getGeneralstringBytes () method will return to GeneralString expression of the customer's username. Passing GeneralString to getSequenceBytes () methods, this method is attached to the sequence byte in front of GeneralString and returns the ASN.1 expression of Sequence of Sequence, which contains the customer's username string. Byte generalstringsequence [] = getsequenceBytes (UserName); this line performs these first two steps. Call the getTagandLengthbytes () method, pass the sequence byte as its content. GetTagandLengthbytes () method will attach the Name-String tag byte (context-specific tag number 0) and length bytes in front of Sequence, and returns a complete Name-String structure. Byte name_string [] = getTagandLengthBytes (asn1dattypes.context_specific, 1, generalstringsequence); this line performs this step. Generate the Name-Type section of PrincipalName. The name-type section contains only an integer, which identifies the type of username. Kerbros allows several types of names (username, unique identity, etc.). For this J2ME-based Kerberos client, I am interested in the only name type of interest is the username, and its name type identifier is 1. Therefore, I will first construct an Integer and pass this Integer byte to the GetTagAndLengthbytes () method. This method generates the full Name-Type section of PrincipalName. Listing 12 BYTE Name_TYPE [] = getTagandLengthBytes (asn1DataTypes.context_specific, 0, getintegerbytes (asn1dattypes.nt_principal); this line performs this task. Connect the PrincipalName's Name-Type and Name-String section together, then additional sequence bytes in front of the string by-array. Byte PrincipalNamesequence [] = getsequenceBytes (correnatebytes (name_type, name_string); executive this task. Additional CNAME tag bytes (context-specific labels 1) and length bytes are attached in front of SEQUENCE above. This gives a complete CNAME structure. Byte cname [] = getTagandLengthBytes (asn1dattypes.context_specific, 1, principalnamesequence); executing this task. The above 6 step policy can generate a complete CNAME structure. My next step is to generate a Realm field, which is generalstring. The strategy for generating a Realm field is as follows:

Use the getGeneralstringBytestringBytes () method to generate generalstring. Passing the generalstring bytes along with the gettagandens () method, it returns the full-byte string of the Realm field. Listing 12 Byte realm [] = gettagandens.context_specific, 2, getGeneralstringBytes (realmname); this line is called. The next task is to generate a Sname field, which is the PrincipalName data type. I have described policies that generate the PrincipalName data structure when discussing the CNAME field. After the sname field, I need to generate the Till field, which specifies the failure time of the bill I requested. For this J2ME-based Kerberos client, I don't want to specify any specific fault time of the ticket, I only want to publish the standard failure time by the KDC server according to the server's policy. Therefore, I always send hard-coded dates (January 1, 1970) as the value of the Till field. The date I have chosen is the past date, which indicates that I don't want to specify an expiration time for the requested bill. The Till field is the Kerberostime type, which follows the GeneralizedTime Universal Data Type. The process of generating the Kerberostime structure is first calling the getGeneralizedTimeBytes () method and communicates with the method to transfer the time string. For example, ETGENERALIZEDTIMEBYTES (New String ("197001010000z") method call returns the GeneralizedTime structure on January 1, 1970. After the GeneralizedTime Byte array, I can pass it to the getTagandens () method call, which generates Till parameters . till complete byte in the byte array getTicketResponse () method of the list 12 [] = getTagAndLengthBytes (ASN1DataTypes.Context_Specific, 5, getGeneralizedTimeBytes (new String ( "19700101000000Z") getBytes ()).); the complete till this line structure Below, it is necessary to generate a Nonce field. It wraps a random number as an integer. I first born a random number, then generate this random number of byte array expressions, finally call the GetTagAndLengthBytes () method, which generates the full structure of the nonce field In the Req-Body field, the last structure that must also be generated is an ETYPE field. This is an Integer sequence. Each integer in Sequence Specifies an encryption algorithm supported by the client. I only want to support a encryption algorithm ( DES in CBC mode), according to the message summary algorithm selected by the client, its integer identification number is 1, 2 or 3. I will explain the use of the message summary algorithm in this series, but now I know that I want to use the MD5 message summary algorithm in the Kerberos client. Identification number of des-cbc-md5 combined with 3. Therefore, I will first be generated into 3 Integer bytes, and then add sequence bytes before INTEGER byte, and finally Call the GetTagandLengthBytes () method to get the complete byte array expression of the ETYPE field.

Now I have generated all the fields of the Req-Body field. Therefore, I can call multipleatebytes () methods multiple times to connect all individual fields into one byte array. The next step is to call the getSequenceBytes () method to place the series byte arrays in a sequence. A GetTagandens () method will take the sequence byte and generate a complete REQ-BODY structure. The final step of generating TGT requests will be serially connected to the PVNO and MSG-Fields generated in front of this section together with the Req-Body byte. These fields are then placed in a sequence, and finally call the gettagandens () method to get a complete, you can send a ticket request for the Kerberos server. Conclusion I discussed several basic concepts in this article. I have developed a J2ME class that contains several methods for generating an ASN.1 data structure, and I also showcase how to generate a Kerberos key with the user's password. Finally, I demonstrate how the Kerberos client generates TGT requests. Next time, I will build a KDC server, get Kerberos bills from the server, and use these tickets to exchange keys with the business logic server of the e-banking. Reference You can see the original text of this article on the Worldworks global site. Download the source code included in this article. Read the first article of this series. Read the official RFC 1510 on the Kerberos (5th Edition) on Ietf.org. Download the Bounce Castle encryption library. I tested the code of this article with the 1.19 version of Bouncy Castle. If you want to release the code including these libraries, you must read the license terms of Bounce Castle. Read the official DES and DES MODES OF OPERATION (including the CBC mode) specification. Visit the Kerberos Working Group on the IETF website. In the article "SIMPLIFY Enterprise Java Authentication with Single Sign-on" (DeveloperWorks, Sep 2003), Faheem Khan dedicated the single sign-on using Kerberos and Java GSS API. This page contains a good set of links on Kerberos. Download a complete ASN.1 document and encoding rules. Read Jason Garman's Kerberos: The Definitive Guide (O'Reilly & Associates, 2003) to learn Kerberos. See how IBM products use Kerberos. IBM AlphaWorks provides Web Services Toolkit for Mobile Devices, you can connect your J2ME device to the Web service world.

About the author Faheem Khan is an independent software consultant, expertise is an enterprise application integration (EAI) and B2B solution. Readers can contact Faheem via fkhan872@yahoo.com.

转载请注明原文地址:https://www.9cbs.com/read-32763.html

New Post(0)