|
WizardsToolkit
1.0.7
|
00001 /* 00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00003 % % 00004 % % 00005 % SSSSS H H AAA % 00006 % SS H H A A % 00007 % SSS HHHHH AAAAA % 00008 % SS H H A A % 00009 % SSSSS H H A A % 00010 % % 00011 % % 00012 % Wizard's Toolkit Secure Hash Algorithm-256 Methods % 00013 % % 00014 % Software Design % 00015 % John Cristy % 00016 % March 2003 % 00017 % % 00018 % % 00019 % Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization % 00020 % dedicated to making software imaging solutions freely available. % 00021 % % 00022 % You may not use this file except in compliance with the License. You may % 00023 % obtain a copy of the License at % 00024 % % 00025 % http://www.wizards-toolkit.org/script/license.php % 00026 % % 00027 % Unless required by applicable law or agreed to in writing, software % 00028 % distributed under the License is distributed on an "AS IS" BASIS, % 00029 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 00030 % See the License for the specific language governing permissions and % 00031 % limitations under the License. % 00032 % % 00033 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00034 % 00035 % See http://csrc.nist.gov/cryptval/shs.html 00036 % 00037 */ 00038 00039 /* 00040 Include declarations. 00041 */ 00042 #include "wizard/studio.h" 00043 #include "wizard/exception.h" 00044 #include "wizard/exception-private.h" 00045 #include "wizard/memory_.h" 00046 #include "wizard/sha1.h" 00047 00048 /* 00049 Define declarations. 00050 */ 00051 #define SHA1Blocksize 64 00052 #define SHA1Digestsize 20 00053 00054 /* 00055 Typedef declarations. 00056 */ 00057 struct _SHA1Info 00058 { 00059 unsigned int 00060 digestsize, 00061 blocksize; 00062 00063 StringInfo 00064 *digest, 00065 *message; 00066 00067 unsigned int 00068 *accumulator, 00069 low_order, 00070 high_order; 00071 00072 size_t 00073 offset; 00074 00075 WizardBooleanType 00076 lsb_first; 00077 00078 time_t 00079 timestamp; 00080 00081 size_t 00082 signature; 00083 }; 00084 00085 /* 00086 Forward declarations. 00087 */ 00088 static void 00089 TransformSHA1(SHA1Info *); 00090 00091 /* 00092 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00093 % % 00094 % % 00095 % % 00096 % A c q u i r e S H A I n f o % 00097 % % 00098 % % 00099 % % 00100 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00101 % 00102 % AcquireSHA1Info() allocate the SHA1Info structure. 00103 % 00104 % The format of the AcquireSHA1Info method is: 00105 % 00106 % SHA1Info *AcquireSHA1Info(void) 00107 % 00108 */ 00109 WizardExport SHA1Info *AcquireSHA1Info(void) 00110 { 00111 SHA1Info 00112 *sha_info; 00113 00114 unsigned int 00115 lsb_first; 00116 00117 sha_info=(SHA1Info *) AcquireWizardMemory(sizeof(*sha_info)); 00118 if (sha_info == (SHA1Info *) NULL) 00119 ThrowWizardFatalError(HashDomain,MemoryError); 00120 (void) ResetWizardMemory(sha_info,0,sizeof(*sha_info)); 00121 sha_info->digestsize=SHA1Digestsize; 00122 sha_info->blocksize=SHA1Blocksize; 00123 sha_info->digest=AcquireStringInfo(SHA1Digestsize); 00124 sha_info->message=AcquireStringInfo(SHA1Blocksize); 00125 sha_info->accumulator=(unsigned int *) AcquireQuantumMemory(SHA1Blocksize, 00126 sizeof(*sha_info->accumulator)); 00127 if (sha_info->accumulator == (unsigned int *) NULL) 00128 ThrowWizardFatalError(HashDomain,MemoryError); 00129 lsb_first=1; 00130 sha_info->lsb_first=(int) 00131 (*(char *) &lsb_first) == 1 ? WizardTrue : WizardFalse; 00132 sha_info->timestamp=time((time_t *) NULL); 00133 sha_info->signature=WizardSignature; 00134 InitializeSHA1(sha_info); 00135 return(sha_info); 00136 } 00137 00138 /* 00139 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00140 % % 00141 % % 00142 % % 00143 % D e s t r o y S H A I n f o % 00144 % % 00145 % % 00146 % % 00147 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00148 % 00149 % DestroySHA1Info() zeros memory associated with the SHA1Info structure. 00150 % 00151 % The format of the DestroySHA1Info method is: 00152 % 00153 % SHA1Info *DestroySHA1Info(SHA1Info *sha_info) 00154 % 00155 % A description of each parameter follows: 00156 % 00157 % o sha_info: The cipher sha_info. 00158 % 00159 */ 00160 WizardExport SHA1Info *DestroySHA1Info(SHA1Info *sha_info) 00161 { 00162 (void) LogWizardEvent(TraceEvent,GetWizardModule(),"..."); 00163 assert(sha_info != (SHA1Info *) NULL); 00164 assert(sha_info->signature == WizardSignature); 00165 if (sha_info->accumulator != (unsigned int *) NULL) 00166 sha_info->accumulator=(unsigned int *) 00167 RelinquishWizardMemory(sha_info->accumulator); 00168 if (sha_info->message != (StringInfo *) NULL) 00169 sha_info->message=DestroyStringInfo(sha_info->message); 00170 if (sha_info->digest != (StringInfo *) NULL) 00171 sha_info->digest=DestroyStringInfo(sha_info->digest); 00172 sha_info->signature=(~WizardSignature); 00173 sha_info=(SHA1Info *) RelinquishWizardMemory(sha_info); 00174 return(sha_info); 00175 } 00176 00177 /* 00178 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00179 % % 00180 % % 00181 % % 00182 % F i n a l i z e S H A % 00183 % % 00184 % % 00185 % % 00186 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00187 % 00188 % FinalizeSHA1() finalizes the SHA1 message accumulator computation. 00189 % 00190 % The format of the FinalizeSHA1 method is: 00191 % 00192 % FinalizeSHA1(SHA1Info *sha_info) 00193 % 00194 % A description of each parameter follows: 00195 % 00196 % o sha_info: The address of a structure of type SHA1Info. 00197 % 00198 % 00199 */ 00200 WizardExport void FinalizeSHA1(SHA1Info *sha_info) 00201 { 00202 register size_t 00203 i; 00204 00205 register unsigned char 00206 *q; 00207 00208 register unsigned int 00209 *p; 00210 00211 size_t 00212 count; 00213 00214 unsigned char 00215 *datum; 00216 00217 unsigned int 00218 high_order, 00219 low_order; 00220 00221 /* 00222 Add padding and return the message accumulator. 00223 */ 00224 (void) LogWizardEvent(TraceEvent,GetWizardModule(),"..."); 00225 assert(sha_info != (SHA1Info *) NULL); 00226 assert(sha_info->signature == WizardSignature); 00227 low_order=sha_info->low_order; 00228 high_order=sha_info->high_order; 00229 count=(size_t) ((low_order >> 3) & 0x3f); 00230 datum=GetStringInfoDatum(sha_info->message); 00231 datum[count++]=(unsigned char) 0x80; 00232 if (count <= (GetStringInfoLength(sha_info->message)-8)) 00233 (void) ResetWizardMemory(datum+count,0,GetStringInfoLength( 00234 sha_info->message)-8-count); 00235 else 00236 { 00237 (void) ResetWizardMemory(datum+count,0,GetStringInfoLength( 00238 sha_info->message)-count); 00239 TransformSHA1(sha_info); 00240 (void) ResetWizardMemory(datum,0,GetStringInfoLength(sha_info->message)- 00241 8); 00242 } 00243 datum[56]=(unsigned char) (high_order >> 24); 00244 datum[57]=(unsigned char) (high_order >> 16); 00245 datum[58]=(unsigned char) (high_order >> 8); 00246 datum[59]=(unsigned char) high_order; 00247 datum[60]=(unsigned char) (low_order >> 24); 00248 datum[61]=(unsigned char) (low_order >> 16); 00249 datum[62]=(unsigned char) (low_order >> 8); 00250 datum[63]=(unsigned char) low_order; 00251 TransformSHA1(sha_info); 00252 p=sha_info->accumulator; 00253 q=GetStringInfoDatum(sha_info->digest); 00254 for (i=0; i < (SHA1Digestsize/4); i++) 00255 { 00256 *q++=(unsigned char) ((*p >> 24) & 0xff); 00257 *q++=(unsigned char) ((*p >> 16) & 0xff); 00258 *q++=(unsigned char) ((*p >> 8) & 0xff); 00259 *q++=(unsigned char) (*p & 0xff); 00260 p++; 00261 } 00262 /* 00263 Reset working registers. 00264 */ 00265 count=0; 00266 high_order=0; 00267 low_order=0; 00268 } 00269 00270 /* 00271 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00272 % % 00273 % % 00274 % % 00275 % G e t S H A 1 B l o c k s i z e % 00276 % % 00277 % % 00278 % % 00279 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00280 % 00281 % GetSHA1Blocksize() returns the SHA1 blocksize. 00282 % 00283 % The format of the GetSHA1Blocksize method is: 00284 % 00285 % unsigned int *GetSHA1Blocksize(const SHA1Info *sha1_info) 00286 % 00287 % A description of each parameter follows: 00288 % 00289 % o sha1_info: The sha1 info. 00290 % 00291 */ 00292 WizardExport unsigned int GetSHA1Blocksize(const SHA1Info *sha1_info) 00293 { 00294 (void) LogWizardEvent(TraceEvent,GetWizardModule(),"..."); 00295 WizardAssert(CipherDomain,sha1_info != (SHA1Info *) NULL); 00296 WizardAssert(CipherDomain,sha1_info->signature == WizardSignature); 00297 return(sha1_info->blocksize); 00298 } 00299 00300 /* 00301 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00302 % % 00303 % % 00304 % % 00305 % G e t S H A 1 D i g e s t % 00306 % % 00307 % % 00308 % % 00309 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00310 % 00311 % GetSHA1Digest() returns the SHA1 digest. 00312 % 00313 % The format of the GetSHA1Digest method is: 00314 % 00315 % const StringInfo *GetSHA1Digest(const SHA1Info *sha1_info) 00316 % 00317 % A description of each parameter follows: 00318 % 00319 % o sha1_info: The sha1 info. 00320 % 00321 */ 00322 WizardExport const StringInfo *GetSHA1Digest(const SHA1Info *sha1_info) 00323 { 00324 (void) LogWizardEvent(TraceEvent,GetWizardModule(),"..."); 00325 WizardAssert(HashDomain,sha1_info != (SHA1Info *) NULL); 00326 WizardAssert(HashDomain,sha1_info->signature == WizardSignature); 00327 return(sha1_info->digest); 00328 } 00329 00330 /* 00331 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00332 % % 00333 % % 00334 % % 00335 % G e t S H A 1 D i g e s t s i z e % 00336 % % 00337 % % 00338 % % 00339 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00340 % 00341 % GetSHA1Digestsize() returns the SHA1 digest size. 00342 % 00343 % The format of the GetSHA1Digestsize method is: 00344 % 00345 % unsigned int *GetSHA1Digestsize(const SHA1Info *sha1_info) 00346 % 00347 % A description of each parameter follows: 00348 % 00349 % o sha1_info: The sha1 info. 00350 % 00351 */ 00352 WizardExport unsigned int GetSHA1Digestsize(const SHA1Info *sha1_info) 00353 { 00354 (void) LogWizardEvent(TraceEvent,GetWizardModule(),"..."); 00355 WizardAssert(CipherDomain,sha1_info != (SHA1Info *) NULL); 00356 WizardAssert(CipherDomain,sha1_info->signature == WizardSignature); 00357 return(sha1_info->digestsize); 00358 } 00359 00360 /* 00361 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00362 % % 00363 % % 00364 % % 00365 % I n i t i a l i z e S H A % 00366 % % 00367 % % 00368 % % 00369 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00370 % 00371 % IntializeSHA1() intializes the SHA1 accumulator. 00372 % 00373 % The format of the DestroySHA1Info method is: 00374 % 00375 % void InitializeSHA1Info(SHA1Info *sha_info) 00376 % 00377 % A description of each parameter follows: 00378 % 00379 % o sha_info: The cipher sha_info. 00380 % 00381 */ 00382 WizardExport void InitializeSHA1(SHA1Info *sha_info) 00383 { 00384 (void) LogWizardEvent(TraceEvent,GetWizardModule(),"..."); 00385 assert(sha_info != (SHA1Info *) NULL); 00386 assert(sha_info->signature == WizardSignature); 00387 sha_info->accumulator[0]=0x67452301U; 00388 sha_info->accumulator[1]=0xefcdab89U; 00389 sha_info->accumulator[2]=0x98badcfeU; 00390 sha_info->accumulator[3]=0x10325476U; 00391 sha_info->accumulator[4]=0xc3d2e1f0U; 00392 sha_info->low_order=0; 00393 sha_info->high_order=0; 00394 sha_info->offset=0; 00395 } 00396 00397 /* 00398 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00399 % % 00400 % % 00401 % % 00402 % T r a n s f o r m S H A % 00403 % % 00404 % % 00405 % % 00406 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00407 % 00408 % TransformSHA1() transforms the SHA1 message accumulator. 00409 % 00410 % The format of the TransformSHA1 method is: 00411 % 00412 % TransformSHA1(SHA1Info *sha_info) 00413 % 00414 % A description of each parameter follows: 00415 % 00416 % o sha_info: The address of a structure of type SHA1Info. 00417 % 00418 % 00419 */ 00420 00421 static inline unsigned int Trunc32(unsigned int x) 00422 { 00423 return(x & 0xffffffffU); 00424 } 00425 00426 static unsigned int RotateLeft(unsigned int x,unsigned int n) 00427 { 00428 return(Trunc32((x << n) | (x >> (32-n)))); 00429 } 00430 00431 static void TransformSHA1(SHA1Info *sha_info) 00432 { 00433 register ssize_t 00434 i; 00435 00436 register unsigned char 00437 *p; 00438 00439 register unsigned int 00440 *q; 00441 00442 unsigned int 00443 A, 00444 B, 00445 C, 00446 D, 00447 E, 00448 shift, 00449 T, 00450 W[80]; 00451 00452 shift=32; 00453 p=GetStringInfoDatum(sha_info->message); 00454 if (sha_info->lsb_first == WizardFalse) 00455 { 00456 if (sizeof(unsigned int) <= 4) 00457 for (i=0; i < 16; i++) 00458 { 00459 T=(*((unsigned int *) p)); 00460 p+=4; 00461 W[i]=Trunc32(T); 00462 } 00463 else 00464 for (i=0; i < 16; i+=2) 00465 { 00466 T=(*((unsigned int *) p)); 00467 p+=8; 00468 W[i]=Trunc32(T >> shift); 00469 W[i+1]=Trunc32(T); 00470 } 00471 } 00472 else 00473 if (sizeof(unsigned int) <= 4) 00474 for (i=0; i < 16; i++) 00475 { 00476 T=(*((unsigned int *) p)); 00477 p+=4; 00478 W[i]=((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) | 00479 ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff); 00480 } 00481 else 00482 for (i=0; i < 16; i+=2) 00483 { 00484 T=(*((unsigned int *) p)); 00485 p+=8; 00486 W[i]=((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) | 00487 ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff); 00488 T>>=shift; 00489 W[i+1]=((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) | 00490 ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff); 00491 } 00492 /* 00493 Copy accumulator to registers. 00494 */ 00495 A=sha_info->accumulator[0]; 00496 B=sha_info->accumulator[1]; 00497 C=sha_info->accumulator[2]; 00498 D=sha_info->accumulator[3]; 00499 E=sha_info->accumulator[4]; 00500 for (i=16; i < 80; i++) 00501 { 00502 W[i]=W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16]; 00503 W[i]=RotateLeft(W[i],1); 00504 } 00505 q=W; 00506 for (i=0; i < 20; i++) 00507 { 00508 T=Trunc32(RotateLeft(A,5)+((B & C) | (~B & D))+E+(*q)+0x5a827999U); 00509 E=D; 00510 D=C; 00511 C=RotateLeft(B,30); 00512 B=A; 00513 A=T; 00514 q++; 00515 } 00516 for ( ; i < 40; i++) 00517 { 00518 T=Trunc32(RotateLeft(A,5)+(B ^ C ^ D)+E+(*q)+0x6ed9eba1U); 00519 E=D; 00520 D=C; 00521 C=RotateLeft(B,30); 00522 B=A; 00523 A=T; 00524 q++; 00525 } 00526 for ( ; i < 60; i++) 00527 { 00528 T=Trunc32(RotateLeft(A,5)+((B & C) | (B & D) | (C & D))+E+(*q)+ 00529 0x8F1bbcdcU); 00530 E=D; 00531 D=C; 00532 C=RotateLeft(B,30); 00533 B=A; 00534 A=T; 00535 q++; 00536 } 00537 for ( ; i < 80; i++) 00538 { 00539 T=Trunc32(RotateLeft(A,5)+(B ^ C ^ D)+E+(*q)+0xca62c1d6U); 00540 E=D; 00541 D=C; 00542 C=RotateLeft(B,30); 00543 B=A; 00544 A=T; 00545 q++; 00546 } 00547 /* 00548 Add registers back to accumulator. 00549 */ 00550 sha_info->accumulator[0]=Trunc32(sha_info->accumulator[0]+A); 00551 sha_info->accumulator[1]=Trunc32(sha_info->accumulator[1]+B); 00552 sha_info->accumulator[2]=Trunc32(sha_info->accumulator[2]+C); 00553 sha_info->accumulator[3]=Trunc32(sha_info->accumulator[3]+D); 00554 sha_info->accumulator[4]=Trunc32(sha_info->accumulator[4]+E); 00555 /* 00556 Reset working registers. 00557 */ 00558 A=0; 00559 B=0; 00560 C=0; 00561 D=0; 00562 E=0; 00563 T=0; 00564 (void) ResetWizardMemory(W,0,sizeof(W)); 00565 } 00566 00567 /* 00568 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00569 % % 00570 % % 00571 % % 00572 % U p d a t e S H A % 00573 % % 00574 % % 00575 % % 00576 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00577 % 00578 % UpdateSHA1() updates the SHA1 message accumulator. 00579 % 00580 % The format of the UpdateSHA1 method is: 00581 % 00582 % UpdateSHA1(SHA1Info *sha_info,const StringInfo *message) 00583 % 00584 % A description of each parameter follows: 00585 % 00586 % o sha_info: The address of a structure of type SHA1Info. 00587 % 00588 % o message: The message 00589 % 00590 */ 00591 WizardExport void UpdateSHA1(SHA1Info *sha_info,const StringInfo *message) 00592 { 00593 register size_t 00594 i; 00595 00596 register unsigned char 00597 *p; 00598 00599 size_t 00600 n; 00601 00602 unsigned int 00603 length; 00604 00605 /* 00606 Update the SHA1 accumulator. 00607 */ 00608 assert(sha_info != (SHA1Info *) NULL); 00609 assert(sha_info->signature == WizardSignature); 00610 n=GetStringInfoLength(message); 00611 length=Trunc32((unsigned int) (sha_info->low_order+(n << 3))); 00612 if (length < sha_info->low_order) 00613 sha_info->high_order++; 00614 sha_info->low_order=length; 00615 sha_info->high_order+=(unsigned int) (n >> 29); 00616 p=GetStringInfoDatum(message); 00617 if (sha_info->offset != 0) 00618 { 00619 i=GetStringInfoLength(sha_info->message)-sha_info->offset; 00620 if (i > n) 00621 i=n; 00622 (void) CopyWizardMemory(GetStringInfoDatum(sha_info->message)+ 00623 sha_info->offset,p,i); 00624 n-=i; 00625 p+=i; 00626 sha_info->offset+=i; 00627 if (sha_info->offset != GetStringInfoLength(sha_info->message)) 00628 return; 00629 TransformSHA1(sha_info); 00630 } 00631 while (n >= GetStringInfoLength(sha_info->message)) 00632 { 00633 SetStringInfoDatum(sha_info->message,p); 00634 p+=GetStringInfoLength(sha_info->message); 00635 n-=GetStringInfoLength(sha_info->message); 00636 TransformSHA1(sha_info); 00637 } 00638 (void) CopyWizardMemory(GetStringInfoDatum(sha_info->message),p,n); 00639 sha_info->offset=n; 00640 /* 00641 Reset working registers. 00642 */ 00643 i=0; 00644 n=0; 00645 length=0; 00646 }