PGP source code and internals
 0262240394

  • 0 0 0
  • Like this paper and download? You can publish your own PDF file online for free in a few minutes! Sign Up
File loading please wait...
Citation preview

a

ey

weiesrrtt a y

sft tii

aay ig

te

:

ie

i

i ieee ait !

et

:

. it

i

ior

Ba

Ua he ay Ai uray

Lua nt is ais

ie

tise, i ita ais

Le ae : st

Fen

in

Sees

ia

i

aeeearsese ieee Peibsase

i af

fta

satstenes

SESS os hitoh iit i

{oneit iFiis ru

LE

a

| ae _ :ath Seneca

ai

ee

rb

ehece

= Stacee

uae

a

MONTANA STATE _.. LIBRAR

Cee

ats

eWee

Ss

tY

coum, t DHEA

=

pee

bcd tae Fahe hy I nd gl = Oren

7g)

PGP

Source

Code

and Internals

Digitized by the Internet Archive in 2023 with funding from Kahle/Austin Foundation

https://archive.org/details/ogosourcecodeintO000zimm

PGP

Source

Code

and Internals

Philip Zimmermann

The MIT Press Cambridge, Massachusetts

London, England

©1995 Philip Zimmermann

PGP is freely distributable. For detailed information on PGP licensing, distribution, copyrights, patents, trademarks, liability limitations, and export controls, see chapter 12 (“Legal Issues”) in The Official PGP User’s Guide, also published by The MIT*’Press.

“PGP”, “Pretty Good Privacy”, “Phil’s Pretty Good Software”, and the “Pretty Good” label for computer software and hardware products are all trademarks of Philip Zimmermann. This book was was printed and bound in the United States of America.

Library of Congress Cataloging-in-Publication Data Zimmermann, Philip (Philip R.) PGP source code and internals / Philip Zimmermann. p. cm. Includes indexes. ISBN 0-262-24039-4 (hc) 1. Telecommunication systems—Security measures—Data processing. 2. Data encryption (Computer science) 3. PGP (Computer file) 4. Electronic mail systems—Security measures—Data processing. i, Wake. MKSOZS 5225.8 L995 005.8'2—dc20 95-15916 CIP

top ipets) KD \495°

Contents RE GLaC Orme

COGS

ee, oe

St TUCUIOL Smart te

| OAM IG IES DIED

erence ee

ne

WS) acer

peMORORLLGRMSGC.©or

ae

ne

tn

eens

atte helt,

USNDESe822 «ccs nin.edges ted a

a

Lee

ene Tne

perk let

tne

a dir

POLE

Cra Penns / oth ect 4... cor cee ee as cucu. dee meas

FH

maps pedate

MILE

pepe p mak

PMIGE mee PAM Ee

COD Um

VO

ae

19

ae

25

eee

26

ee

30 ne

SOG GMarn tere

TN COS OD OMS

mA

oe

ee

te ee

en

oi

65

66

ren ata arena Cemirrmgr het eB ear MAE MC Aves nats NBR bse ole ok

70

a ese inch be Gk

eae

aN

OE Fe

ees

Nae

ALE t4 Sir

be eG RADE TUR LETTS Vere ee Mae |e

ot bons teases ASST

er eneMe mean

PPL TEC Oe Mette

ue eR Aerie

re a UPS

a ares cents acti ir iaetre: Scene

hens eee

ee hi

Sy devonSidae ond Rie ee Dae

Onn ae ip

a ne

reir

ie

eee

76

eee

aA lite

tg

ot Run suereveuer eiciara raeretney et

oe 3 Labul fafasieue adn

ne

ne

iets ie Sn recevsv hs ecsecevos oc dw gealela ts erovenenn o¢ oe ian

Ee Pome tOUOaera) chs bola dee so eiiee eke eel dG bh ol kaha PaneHauer ec eee

31

ee

eC CCCs 2482 wae an

aa RA a LAL nla MCL RUSS

DTT |

eee

cc os ae Ser nae. ees tg ke ieee tn ote OPC

CLEIY ODL Mee

PALE MOS OSSOMOUR TANS: G2

HAE

18

setae e nein tree Ge een Nn wens On ee Ce

ts nite

PLAGE ©TATOO.»

Tih

ee

DED DW DeMaAK ir eon op) pci. esp cpitieadd unwise tos wre oe elder

Elie Wo bd COQUURSan ne

PEN

Ws

eevee

Nn

eee Te

1

ce

a

aw rere (ian er tee i

pe oats coos mee Ghee

ane te

EMU Mev axemarceee

PSU

Gee ton ener

bt

13

ee

RE

Ap te frais. PMet ¢ f.55 .< Sawing ot evans Coc pewes siertert rey eet

Xxill

re

Panta oe ee oe

ae

ess ei

eae

MRLea Pvdevvdslok She 9s

MC OGUR 2D Meer te koe

x1x

eee

gr aie cern x bane

en nt ene

DAU

car ae

eee

ann) Ree

rte iene teaA Aa eT

ee

oe eee

ioe cco a

85

96

em ene teas 100

eee

107

Gie ¢ se eO EPR meReeeees 7 122

23 0c8 ops coca nee

162

vl

FILE:

Sra GCLUES MIs, c i.Siacsee nikoe » SalDene RO boo vie Cath GPOTS

FILE:

s2matchvasm ey.,20.2 stale: Serer eee

BILE:

Sarmonsh

FILE:

SA MMOL Cyril cach seve eit eeUaye Soe a on Seta a iece eo et ae ene 174 TCE CUD Cheers, oe.Ferg aoe eT tls Fee ee cee, Deeg ce so. ea 176 CLEDY LEST Te, ONAL ESTE ACA) EIR REISER BEM, olla dake 17% EL SCLC EEOe Pot. CS ae eon ae a ete Saas Oe 2 Ding eUNtersn tare en een i i CLSOC RCs ree 2 totais ot. IUCN lig el O SonSoG OMaR rn a 178 Olt crCrete re Ane ented ieee aa ae ee SS Ne ee es ees 178

teem. 4.5. peel

Mune Plena

is eee PP A

ee)

054 oy ae «ee

ee, Ee

ee ie ee

ag Cea

ee

164

os bo ee

Pes

se Teta

167

on. salon

a

173

aay eee ee

SKIP MNO seM ieee mm den Rocke eotceeiemane ch LEGA deb e8 Feeney A ee eee coe COPVUNG a5 se ee ee eee eee Eger et ees een 2 een get lin Cee Pe Bb ocsounes a dchuee banner soo ahead paaaieh Pano. een

PolmaT

imionlin erate

SENG NC le Con RAENUTUem I ULLOL ese

atts Shere

ges 64

ein ec

Pode

ee

etn re a oo eee al eee ee ae. os 2iic hota ss sein etahice cid a.tsar inn ECR,

CONUS ee Pr

Ad

oo Sols

Ms

SIDING AGCT Sime

Vick dese ce ky fo MM

eke es Oe

iseader linet Ailend: csuetitele A dteietitt aS

ec Nae ha

aPTIOLCCCONE ama. dz-murer sex Rrurtee

at: wma

ee

ie

i

nena eed te

teeetles. «kWh

eee

re ee

A

182

184 188

190

ene eee

642 eet»

179 180 181

189

te: see

ENON os cone on

179

191

SOR

oes 192

SWAT ITLL PLO rms catce Care vtec raceh eae ce, «Nay neeoe ae Rk! ARs ae some Garinor tilege canes ence Jobe hey oe dco ae eho is ee le A ee

LOG 197

Rema EMIOTAT Grams 2.o07 Pas. cu

201

ADSA8 >6108) wd1 pana eae eo

atSeeelon AION SERRE BEMIL

a

Cee

ne

ee

6 Eat, At

Recent

ei

POW SCI

oe

Secret

eva

ee

aeRO

Ne 201

aire

FILE:

RCO BL Se Diet

FILE:

ONAL GO Ge ie Areysees sates2s Grp tase crn yaad
NORE RE Cael ee SLCC ene tre wind tgrdas Padah OREM egestas ae ee

751 751

FILE:

"Stdla pen’ 23¢ 200 tb ero last

752

eee

ee

ee

ee

MUI

eeeyeomi a. fo.

an dns

STARE OPSCSI

SECON

FULE Sfayis om «6s nnn wek nah era EnenS ents CE RIOT ERED

RA Ea

Ae

ete

/REARA CIRCUS

URN ET EMM Ee Fee

OE

4 2 sed

2%"

753

754

tt a eaeeaeanna PERE EA Rath easing ns tao ti ois RR sigl RMA soe Cha vik. Scab is wad bao ido MM ae ie rece A calae ee ASS GT Tere adts CAME eRe Ts eee ad Se eee Cine ce as Ba eM eo ELT aL UTE it ate oc ri. eg a ROP a Sik i eeaneaerenaeS SARA RAEGEL AAS Ca RELA AAEAE SOA Ca BEE patie icy ceo taornce tise asa ups a eae ieee Ome es Pees Feige treceter center cece tgtascareecsoes cceccess 1} RERUN ge Fea aan pCR ona oeria stot ane e aadine 8 eRe Aga 3 ees eee cee caer een ee ee Pe REGRD ease alo oe ee cee PE aa oe oe TORN Nic catia CORR ee Fate Pe ie ee Ea ee cs cara eda ember CaN Stee ae Ren ne ey ee pe Ee rece a aa rt ca SE RTL DOE EERE 19°" DLR eD RIE Te eS, BE igs ee EN Le

756 757 758 758 759 759 759 760 761 761 761 762 762 762 765 766 767 769

pee Pitch bead Bene a rhe UIT SE pS Gg Se LL de eee a

al i 772 774 776 ata

Boel

A t et tuts ticfs cuetek ea tected ee ono

Ee

ee a

aaa a

gira gerreigtee

Pe conerate Neate (i. fal wey tatiana

Pies

UE

em

re

GSA

Be

aaah DN Saf okAPLEN Covel 2 LOTTA BEN AMRR

ee

Pere NE ey Cy ty | ae TELIRSS te seein Be

ee

EMT AERIGR oy oo

pe

at ee te eo s uaaGeM ta Minin Sone ye rey ei a Pirie eae eeepc eee a CM cae agen magia ee ee ee eee ae

eee

etn eet

eae ant ail ia

et ss acd

Ne

a gelled cN

kee

a ee ee en ee Oe OES | eae

RECRIT

ame Rechteae bet ae Melani

ng aes Apa Moko

23 £5.10 5.2. noe Jek EEG sales Sore naa

rin tricn onion ae ate Aaa a Saar ROC IE

a x,

Be

acta ee ae

ace ae

ee

ee

i Migin iets ES eh dk rade ec eee

dee

780 ne 782

135

787 ie tI

ln sansncn re aheens eee aMPPEPERE ae IDS T eee SP.

oe vegunicece a,nico oda TVLO Delete meer ec oe a lamin cr ee 2 I

SANGHire

Lovattal 778

en

eae eG te

ee

aI 791 ae

792

ison

195

ie

ot ie

nego ee me nee aieore Or Aa

195 795

Xvi

FILE:

SA TE

BCE ore adenkitatehanersdiereraiannl orcuunrarevsiellenpht oboe arenanokost etek Ala exc te Raa

Bhi MR

NIM oss

oe om

cndec ceelvvnchonre decpncattoeckeciacell paces ee

Bene DibSe EP aco. scos-

iad

vet

=

ire

aa _

-

4

Ap dee

7

4,).i-8

RE T

i

_

n

cecehuaebes@

(co

rhea

wee

ia

:

a

poe ~

=

assen esi Yi

ee

PES

aiverall s-1te

-O

aie

eevee

Oe

-

a :

ee



00

f

Santaet

=

€ “7

el =

pearance aD aireovtees sy Hea eaeee :«

i

=

.

.

Mel

~~

=p) &@Os>-.

POR ES Cet

=

64808 -

eee

i

,

ad ee are

bedi

:

[vw

: +29 4 5@a ve “yi ~

i

——

Per eee ee

FN

=

aed

i

:

Be

-

ek ee

ee

:

ae sep en

oe ib eaben s

re

a

7 pred av Sond

webesiuis

“PSe- 0 ngs

2

til

aa

hile

_

2

Preface This book contains all of the C source code to a software package

called PGP (Pretty Good Privacy).

PGP is the most widely used

software in the the world for the encryption of electronic mail. It uses public key cryptography to let you communicate securely with people you’ve never met, without the prior exchange of keys over secure channels. Why publish an entire book (and a big one at that) comprised mainly of boring source code for a computer program? Well, there are some really good reasons. It concerns your civil liberties and poauies a bit of explaining, but it’s Bema quite an interesting story. Cryptography is a surprisingly political technology. In recent years, it has become more so min the controversy surrounding the Government’s Clipper i, the FBI wiretap legislation, export controls on cryptographic software, and the balance of power between a government and its people. Historically, cryptography has been used mainly by governments for diplomatic and military traffic. But with the coming of the information age, ubiquitous personal computers, modems, and fax machines, this is changing. With an emerging global economy depending more and more on digital communication, ordinary people and companies need cryptography to protect their everyday communications. Law enforcement and intelligence peace want access to all of our communications, to catch people who break the law, and detect threats to National Security. Civil libertarians want to keep the Government out of our private communications, to protect our privacy and maintain a healthy democracy. PGP is free software. Anyone may download it on the Internet, or from many Bulletin Board Systems. It has stirred up some controversy, because it has become a worldwide de facto standard for e-mail encryption, despite United States export restrictions. Initially published in the US, this package has spread by the diffusion that is common to free software packages, with its “forbidden” flavor giving it an extra popularity lick. Oddly enough, the US Government may have inadvertantly contributed to PGP’s spread by making it more popular because of my case. I am under criminal investigation as a result of PGP’s spread overseas, which the Government holds is in violation of US export restrictions. My case has captured a lotof press attention, in part because journalists realize that if an American can be imprisoned for electronically publishing something in the United States then journalists may themselves be at risk in tomorrow’s world of electronic newspapers on the information highway. Another reason the press is so interested in my case is the Government’s attempts to suppress public access to strong cryptography.

The Clinton administration is trying to get the phone companies to put a special encryption device into every telephone. They eXpect it to take many years to accomplish this. When this “Clipper chip”, as it’s called, is manufactured by the Government, they place a unique encryption key in each chip and keep a copy of the keys in

Preface

a vast government database, for wiretap purposes. Your telephone will someday have Big Brother inside. The Government hopes that the American public will accept this government-controlled cryptography and is trying to discourage other forms of cryptography they do not control. One way they discourage it is by the use of export restrictions on cryptographic software. This draws PGP into the press spotlight. The US State Department has a list of items that may not be exported without a license. The Munitions List. Mostly weapons, but included in that is encryption software. Encryption software may not be exported without a license, and that license is hard to come by if the software uses advanced encryption techniques that the Government can’t easily break. Software like PGP. The State Department allows items on the munitions list to be ex-

ported if they grant a Commodities Jurisdiction (CJ) for it, allowing it to be handled under the jurisdiction of the Commerce Department instead of the State Department. A CJ allows the item to be legally exported from the United States. It would be politically difficult for the Government to prohibit the export of a book that anyone may find in a public library or a bookstore. The State Department has already granted a CJ for another book containing cryptographic source code, oe Schneier’s Applied Cryptography. So, we’re putting the PGP source code in a book, which may be scanned in with optical

character recognition (OCR) software. And we are applying for a CJ. It will be interesting to see where this process leads. PGP uses the best encryption algorithms available in the open academic literature — the algorithms that have withstood the most peer review and are rooted in the best design principles of modern cryptography. PGP version 2.6.2 uses RSA for key management and digital signatures, the IDEA cipher for bulk data encryption, and MD5 for a secure one-way hash for digital signatures. And it compresses the data before encrypting it, using the ZIP algorithm. PGP was developed under difficult conditions, with no funding in a race against time in 1991 to get it out before it became illegal to publish software of this type. Senate Bill 266, the 1991 anti-crime bill, had a measure buried in it that foretold the shape of things to come. It was a “sense of Congress” resolution that said that communications system implementors should provide a way for the Government to obtain the plaintext contents of traffic. The resolution was defeated shortly after PGP was initially published, owing to public outcry from civil liberties groups. PGP was published as freeware, in an effort to preempt the possibility that the Government could suppress this technology later. There are other books in the computer science section of your bookstore that have source code examples of various algorithms. These books teach good programming style by providing good code

examples. This book is mostly not like that. Ar aaa some instructive examples of how to implement certain one might observe that this body of source code is not ample of clean modularity. The code is the way it is.

it does have algorithms, the best exThe trying

Preface

Xxl

conditions of PGP’s development led to expedient approaches to implementation, sometimes at a cost of elegance. Global variables are used more than they should be, there are many cases of redundant code, and there are many intermodule dependencies. As other software engineers all over the world contributed their own development efforts to PGP after version 1.0 was published in 1991, they inherited a misshapen crystal nucleus to accrete more code onto, and modified and remodified the code under pressures of expedience. Very little of my original code remains in PGP, mostly comprised of the multiprecision integer library, which I first wrote in late 1986. It is unfortunate that cleaner examples of code from my 20-year career as a software engineer could not have served as a basis for what would eventually become such a widely distributed body of source code that so many other programmers would look at. Despite the inelegance of the code, the quality of the cryptography and key management is very good, good enough to make a mark upon the world in such a way that no other cryptography software ever has, mpeeu ne some elements of the US Government as well as a number of foreign governments. PGP would not be where it is today without the volunteer efforts of many talented programmers from all over the world. Peter Gutmann and Branko Lankester contributed much effort to PGP development. Jean-loup Gailly contributed his ZIP compression routines. Many others contributed code, and they are named in the comments of the source code. Other people contributed their pee eae efforts to the PGP project, including my own legal defense team, suc as Phil Dubois, Eben Moglen, Ken Bass, and Curt Karnow. Other lawyers who provided legal advice include Tom Nolan and Chuck Marson. I’m writing some of this preface in the air between Bucharest and Budapest, on a speaking tour about privacy in the information age. In Bucharest, I saw the terrible legacy of a system designed by men who craved certainty, not trusting the people with individual freedom. Those men would have loved the Clipper chip. The people there now are glad to have their freedom, and they understand my concern about the power of Government. They already get it — and they don’t understand why we Americans don’t. A book comprised entirely of thousands of lines of source code looks pretty dull. But, then, so does a nondescript fragment of concrete — unless it happens to be a piece of the Berlin Wall, which many people display on their mantles as a symbol of freedom opening up for millions of Hee le. Perhaps in the long run, this book will hele open up the US borders to the free flow of information.

Philip R. Zimmermann Boulder, Colorado December 1994

ral Paes cages =

ugée

ERR AD beam 1? om Ce er pe

‘ rr

Pee

hen or

Secret”

i

» wend te

aaa

+o

ee af

Were

a

ath; SAH

©os

[oS tees ‘the sete x Fu? wor Gove cow

a «ats

aw

Sew

4b : eS ane

i.

bealhit

“asa

pe

=

adh

|)!

ie

HEM Muss

6 OO

O27 ts hevrvog

bo beady , tpt

sys wee aot

wre @

oF

ets

y ret eT EP

—_—

a

as.teenth 7}red haat cab; 4

y

ws

:

ee

vt teade

—— a

wee

iyi

al

Ce ;

w

it a.

J

ve

he

as -.

a

a

eb walt eh

je

"4

nh 5

“The

:

wr

Ot

it; +

"a

in ast

dione? Pe .

deh

reo velquil

ot

: “rh

®

fheasanls

-

iqail Al ks rm

i aera erie Wh sis PS BPE (ae

bart),

vadpcr ot net bie asar ea0dT

ieootlihrerGe?

rea

Area

.

‘bag

ero nd

—— epee nipe i.a buarebo pF Paig S| a, i? ihn ark beso aon

cay jhobtctt Wind.

pO:

eet

fre Orie leee Yat

cy

A & a0

Jee

keg rendts

eS TPn TR Epi

en

imoe

Pi

ia ithe vi hortlt , eu Chee ta

bares! ot “Sehwe ooreys Gas

o

Saat

&

Aer: OF: aa

Sram

Af)



Me

rite 7

ms

legs. ike

ae

eo

tye

7 -

*

i

OCR Instructions We offer the following suggestions for best optical character recog-

nition (OCR) results, whether with freeware OCR or with one of the commercial products.

Use a good scanner set to at least 300 dpi resolution. Scan from the original pages rather than from photocopies. Avoid any page rotation on the scanner. Re ewN Follow the instructions in your OCR product manual. If you are considering a commercial product, the University of Nevada at Las Vegas has rated several of the commercial systems. Based on their ratings, either Calera Recognition Systems or Expervision product offerings should give satisfactory recognition on these pages. For either of these products, edit the resulting recognition files and save them after cleanup as ASCII before attempting to compile.

Free OCR There are a small number of shareware and PD OCR programs. Unfortunately, none of them will cut it for OCRing this book. They are: CalPoly OCR Library PD, source form, buggy and slow. ProCR by David P. Gray Shareware for DOS, poor accuracy. OCRShare from Solution Technologies Shareware for DOS, no scanner and bad image format support.

Reconstituting Files Usually, OCR programs start by scanning each page into a separate image file, and then produce a text file corresponding to each image file. The files get names that convey the order they were scanned in. If you scan and OCR the files in order, you should be able to reconstitute the files by looking for the “New File” comment

strings found throughout the book. If you are familiar with a text processing language such as AWK, you will be able to process the files in batch mode.

Sree

“toda culls AYE

_

;

i

~

: 7

;

6

teri

at

ee { bie yd cae rad erie geOO, pe fe wade

‘ =.

-

Saliy ee ward. arth ee

get

«quar tat hee venoan

tate

oF

a

‘on

a

ste ng ogg

-

v=, sali aurusioaaeons ou &

tact ft wire

«

oA) own

fone wince

We Fiat anaes

yal yoqeerios ol? txat @ esbog Bayt

atl Meats oy

Te

io

(arm

j

%@

Th)

hea

‘an — ane off

eaTithiy

>

°S

At all ey BOY hype en pas ie a

Seinen? “fT? esi oni 4 ds a pom

att rut patho of belt of) siitiiiaeeras hy nes) heed wt twoureia® hare

poll a2) deeesiy

de od Wo oire We

02

em

Ao sengQgnnl

abut

PGP

Source

Code

and Internals

=

File:

‘makefile’

4 Pile +*

makefi le2

(New File)

Makefile

for PGP

(unix)

Most MS-DOS make utilities are a Makefile as complex as this, PGP 2.6.1 can routines that

lobotomized so they cannot cope so MS-DOS is not included here.

be compiled to use either come with RSAREF or those

multiprecision

library

(mpilib)

that

with

the modular exponentiation that are built into the

comes

with PGP.

For UNIX machines

(and probably VAX/VMS, too), we recommend using the RSAREF routines. For MSDOS, we recommend using the mpilib routines (there are assembly language routines that mpilib can call under MSDOS making it much faster than the C code in RSAREF). To use the mpilib routines, you should: (1) make sure you have the version of RSAREF that comes with

the PGP 2.6.1 distribution, in this makefile, add the compiler

(2)

CFLAGS

(3) Note:

for

your

system

switch

-DUSEMPILIB

to

below,

in the RSAREF makefile, add the compiler switch -DUSEMPILIB to CFLAGS before building RSAREF.

when

you

build

RSAREF

with

-DUSEMPILIB,

fail to link, because they will be unable exponentiation routines. This is OK. Alternatively, to build PGP 2.6.1 (1) you can use any version of

rdemo

to find

and

dhdemo

will

the modular

with the RSAREF exponentiation routines, of the March 16, 1994 distribution

RSAREF.

(2) you need not modify this makefile, (3) you need not modify the RSAREF makefile. Note: If your system does not have memmove, then you should to OBJS_EXT for your rule and send that in as a bug for your CFLAGS

add memmove.o platform.

options:

-DHIGHFIRST -DDEBUG -DNOTERMIO

if building PGP on a big-endian system to include debugging information if your system has no termios

-DSVR2 -DDYN_ALLOC -DSMALL_MEM -DIDEA32

for System V release 2 if your compiler does not support large static arrays if your machine has a small memory (required for MSDOS) if your int’s are 32 bits this is probably faster

-DPORTABLE -DMPORTABLE

and to build the portable version of the (ie if no optimized asm versions are

RSA primitives available)

Define one of: +H HH HHHHHHHHRHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

—-DMERRITT

Merritt’s

-DPEASANT -DUPTON -DSMITH See also the

Russian peasant modulo multiply algorithm use Upton’s modmult algorithm use Smith’s modmult file platform.h for system defaults

modmult

If you don’t

have

a working

(fast on risc machines)

FIONREAD

ioctl

you must

use

one

of these:

-DUSE_SELECT to use select() system call -DUSE_NBIO to use non-blocking read() H HH HHHHAHAH CFLAGS=

-O

-DUNIX

-DPORTABLE

# must set byte order for # BYTEORDER= -DHIGHFIRST CG

=

cc

LD LDFLAGS CPP DBG

= = = =

(Xe

=

targets

# Link

$(CC) -0

and

"bsd"

command

$(CC)

for

old

versions

-c

of

make

# Assembler

OBJS_EXT= LIBS_EXT=

PROJ

"sysv"

-E

# uncomment this #MAKE = make

ASM

$(BYTEORDER)

command

# ASM obj. files # Libararies

= pgp

default:

all:

@echo @echo

''To build PGP "' make

@echo

""

@echo @echo

"where can be:" " 386bsd, 3b1, 3b1_asm, amix-68k-gcc,

@echo

" bsdgcc,

@echo @echo

" hpux-68k-gcc, hpux-pa(*), hpux-pa-ansi, hpux-pa-gec," "' hpux9-pa-ansi, irix, irix_asm, isc, isc_asm, linux, machten,"'

@echo @echo @echo

" mach_386, mips-ultrix, netbsd, newsasm, newsgcc, next," '' next486, nextHP, os2, osf, qnx4 , rs6000, rt_aos4,"' " sco-2.0, sgigcc, sgigcc_asm, solx86gcc, sun386i, sun3asm,"

@echo

" sun3cc(*),

@echo

"'

@echo

" vax_bsd43,

@echo

""

@echo

"For targets marked

@echo

"See

$(PROJ)

on your flavour "'

djgpp,

sun4acc,

encore,

sun3gcc,

hpux-68k(*),

sun4cc(*),

sun4sunosS5acc,

x286(*),

setup.doc

for

of Unix,

sunspc,

type:"

aux(*), aux-gcec, hpux-68k-ansi,"

sun4gcc,

bsd,"

sun4sunos5gcc,"

sysv_386,

vax-ultrix,"

xenix386"

with

(*) you must

further

details."

first

get unproto."

#

File:

‘makefile’

# For a pure MPILIB version, #RSALIBS #RSAOBJS rsagluel.o # For

an

RSADIR

RSAREF

=

version,

uncomment

the

the following

following

lines

lines

2 2/rsaret

RSALIBDIR RSAINCDIR RSALIBS RSAOBJS

= $(RSADIR)/install/unix = -I$(RSADIR)/source -I$(RSADIR)/test

$(USEMPILIB)

= $(RSALIBDIR)/rsaref.a = rsaglue2.o

# If you want to use MPILIB USEMPILIB = -DUSEMPILIB

# Assembly-language

_80386.0: $(CPP) $(ASM) rail

8086.0:

uncomment

=s2

as

subroutine

a back

end to RSAREF,

uncomment

dependencies

80386.S $(ASMDEF) 80386.S -o $@ _80386.s

> _80386.s

_sHOSEIS., S

8086.asm

cp

8086.asm

8086.s

$(ASM) -o $@ 8086.s TMe—-teoOSomS _zmatch.o:

zmatch.S

$(CPP) $(ASM) rm

-f

$(ASMDEF) zmatch.S -o $0 _zmatch.s

> _zmatch.s

_zmatch.s

sparc.o:

sparc.s

$(CPP) $(ASM) rest

$(ASMDEF) sparc.S -o $@ _sparc.s

| grep -v

’°#

’ > _sparc.s

Ssparces

#mc68020.0:

#

$(CC)

ZIPOBJS=

zbits.o zdeflate.o zfile_io.o zglobals.o \ zinflate.o zip.o zipup.o ztrees.o zunzip.o

OBJ1

pgp.o crypto.o keymgmt.o fileio.o \ mdfile.o more.o armor.o mpilib.o mpiio.o \ genprime.o rsagen.o random.o idea.o passwd.o \ md5.o system.o language.o getopt.o keyadd.o \ config.o keymaint.o charset.o \ randpool.o noise.o

=

OBJS =

-c

mc68020.S

$(OBJ1) $(ZIPOBJS) $(RSAOBJS) $(OBJS_EXT)

this

line:

CFLAGS

= $(CFLAGS)

$(PROJ):

-I$(RSAINCDIR)

$(OBJS)

$(LD) # Commodore Amiga amix-68k-gcc:

$(MAKE)

-o $(PROJ)

Running

$(OBJS)

SVR4

2.ip2a

$(LDFLAGS)

with

GCC

$(LIBS_EXT)

2.6.0

$(RSALIBS)

LER

all CC=gcec LD=gcc \

CFLAGS="$(RSAINCDIR) -DPORTABLE —-DIDEA32"

-O02 -DHIGHFIRST

-DUNIX

\

linux:

$(MAKE)

all CC=gcc LD=gcc

CFLAGS="$(RSAINCDIR)

-06

OBJS_EXT="_80386.0 -g3 -DUNIX

-DIDEA32

_zmatch.o"

\

-DASM"

386bsd:

$(MAKE)

all CC=gcc LD=gcc

CFLAGS="$(RSAINCDIR)

OBJS_EXT=""_80386.0

-O -DUNIX

-DIDEA32

-DASM

_zmatch.o"

\

-DMAX_NAMELEN=255"

netbsd:

$(MAKE)

all CC=gcc LD=gcc

CFLAGS="$(RSAINCDIR)

# Sun 3 with gcc # change -traditional-cpp sun3gcc:

-O

OBJS_EXT="_80386.0

-DUNIX

-DIDEA32

to -traditional

_zmatch.o"

-DASM

for gcc

\

-DMAX_NAMELEN=255"

< 2.0

$(MAKE) all CC=gcc LD=gcc OBJS_EXT=memmove.o \ CFLAGS="$(RSAINCDIR) -O -traditional-cpp -DUNIX -DIDEA32 -DPORTABLE"

-DHIGHFIRST

\

sun3asm:

$(MAKE)

all CC=gcc LD=gcc

CFLAGS="$(RSAINCDIR)

# Sun

3 with

sun3cc:

standard

cc:

compile

with

memmove.o"

-DUNIX

# Sun 4 SPARC

\

-DHIGHFIRST

-DHIGHFIRST

\

-DPORTABLE"

with

gcc

(tested

# used with older versions -traditional-cpp

with

of gcc)

gcc

1.39

to -traditional

and newer,

for gcc

sparc.s

can

sun4cc:

with

standard

cc:

compile

with

not

be

< 2.0

$(MAKE) all CC=gcc LD=gcc OBJS_EXT="sparc.o memmove.o" \ CFLAGS=""$(RSAINCDIR) -O -traditional-cpp -DUNIX -DHIGHFIRST # Sun 4 SPARC

-DIDEA32"

unproto

unproto/cpp $(MAKE) all CC=cc LD=cc OBJS_EXT=memmove.o \ CFLAGS="$(RSAINCDIR) -Qpath unproto -O -DUNIX -DIDEA32

# change sun4gcc:

OBJS_EXT="mc68020.0

-O -traditional-cpp

unproto

unproto/cpp $(MAKE) all CC=cc LD=cc OBJS_EXT="sparc.o memmove.o" \ CFLAGS="$(RSAINCDIR) -Qpath unproto -Dconst= -O -DUNIX \

-DIDEA32"

#

File:

‘makefile’

—-DHIGHFIRST

# Sun 4 running

-DIDEA32"

Sunos5

(Solaris).

sun4sunos5dgcc:

$(MAKE) all CC=gcec LD=we OBJS_EXT=sparc.o \ CFLAGS="$(RSAINCDIR) -O -traditional-cpp -DSOLARIS -DIDEA32"

# Sun 4 using sun4acc:

ASMDEF=-DSYSV

SunPro

$(MAKE)

# Sun 4 running

-DHIGHFIRST

\

C compiler

all CC=acc

CFLAGS=""-w

-DUNIX

LD=acc

$(RSAINCDIR)

SunOs

CPP="cc

-x04

5 CRY

-E" OBJS_EXT="sparc.o

-DUNIX

-DHIGHFIRST

using SunPro

memmove.o"

-DIDEA32"

\

\

C compiler

sun4sunosSacc:

$(MAKE)

all CC=cc

LD=gcec OBJS_EXT=sparc.o

CFLAGS=""-w $(RSAINCDIR) ASMDEF=-DSYSV

-x04

-DSOLARIS

\

-DUNIX

-DHIGHFIRST

-DIDEA32"

\

sun3861:

$(MAKE)

all

CC=gcc

LD=gcc

CFLAGS="$(RSAINCDIR) ASMDEF=-DSYSV

-I.

OBJS_EXT="_80386.0 -O

-DUNIX

-DIDEA32

memmove.o"

\

-DNOTERMIO"

\

sunspc:

$(MAKE)

all

CC="ccspce

-B/1.8.6/sun4

CFLAGS="$(RSAINCDIR)

-DMERRITT"

# x86 running

-O

-DUNIX

-ansi

-DIDEA32

-w -I/usr/include"

-DHIGHFIRST

-DUNIT32

\ \

OBJS_EXT=sparc.o

Sunos5

(Solaris)..

solx86gcc: $(MAKE) all CC=gcc LD=gcc OBJS_EXT=_80386.0 \ CFLAGS="$(RSAINCDIR) -O -traditional-cpp -DSOLARIS ASMDEF=-DSYSV

# Sony newsos v3 for m68k, with gcc # change -traditional-cpp to -traditional newsgcc:

$(MAKE)

all CC=gcc LD=gcc

with

gcc

-DIDEA32"

\

< 2.0

\

CFLAGS="$(RSAINCDIR) -O -I. -DUNIX -DHIGHFIRST -DIDEA32 #

for

-DUNIX

-traditional-cpp -DPORTABLE"

-DNOTERMIO

-D_BSD

\

asm

newsasm: $(MAKE) all CC=gcc LD=gcc OBJS_EXT=mc68020.s CFLAGS="$(RSAINCDIR) -O -I. -traditional-cpp -DNOTERMIO -D_BSD -DUNIX -DHIGHFIRST -DIDEA32"

qnx4:

$(MAKE)

all \

CFLAGS=""$(RSAINCDIR)

-DPORTABLE

-3

-DMPORTABLE

-O

-I.

-b

$(BYTEORDER)

-DNO_PARAM_H

-DUNIX

-DMAX_NAMELEN=255"'

-DIDEA32

\

\

encore:

$(MAKE) all -DMPORTABLE sysv:

CC=gcc LD=gcc CFLAGS="$(RSAINCDIR) -O -DUNIX -DUSE_NBIO -DIDEA32 -DUPTON -DHIGHFIRST"

-DPORTABLE

\

$(MAKE) all CPP=/lib/cpp \ CFLAGS="$(RSAINCDIR) -O -DUNIX -DPORTABLE -DUSE_NBIO $(BYTEORDER)"

# optimized version with 80386.5S sysv_386: $(MAKE) all CPP="/lib/cpp -DSYSV" OBJS_EXT="_80386.0 _zmatch.o" CFLAGS="$(RSAINCDIR) -O -DUNIX -DIDEA32 -DUSE_NBIO -DASM"

\

xenix386:

$(MAKE)

all CPP=/lib/cpp

CFLAGS="$(RSAINCDIR)

# Interactive

Unix

OBJS_EXT=""_80386.0

-O -DUNIX

SVR3/386

version

-DSVR2

_zmatch.o"

-DIDEA32

\

-DUSE_NBIO

-DASM"

3.2 with gcc

SICi:

$(MAKE)

all CC=gcc LD=gcc LDFLAGS="-lcposix

CFLAGS="$(RSAINCDIR)

-O

-DUNIX

-DIDEA32

-lrpc"

-DUSE_NBIO

OBJS_EXT=memmove.o -DPORTABLE

\

\

-DNO_ITIMER"

isc_asm:

$(MAKE)

all CC=gcc LD=gcc

CFLAGS="$(RSAINCDIR)

LDFLAGS="'~lcposix

OBJS_EXT=""_80386.0

-O -DUNIX

-DIDEA32

memmove.o"'

-DUSE_NBIO

ASMDEF=-DSYSV

-DNO_ITIMER"

\

\

-lrpc"

mach_386:

$(MAKE)

all CC=gcc LD=gcc

CFLAGS="$(RSAINCDIR)

CPP=/lib/cpp

-O -I.

-DMACH

OBJS_EXT=_80386.0

-DUNIX

-DIDEA32

\

-DNOTERMIO"

machten:

$(MAKE)

all

CC=gcc

LD=gcc

CFLAGS="$(RSAINCDIR)

-DIDEA32

-O

CPP=/lib/cpp

-I.

-DMACH

OBJS_EXT=mc68020.0

-DUNIX

-DHIGHFIRST

\

\

-DNOTERMIO"

SiCOm 2m): $(MAKE) all CC=gcc LD=gcc CPP=/usr/lib/xcpp ASMDEF=-DSYSV CFLAGS="$(RSAINCDIR) -Dsco -O

# Xenix x286:

OBJS_EXT=_80386.0 \ -DUNIX -DIDEA32 -DUSE_NBIO"

286 $(MAKE) all CC="sh ccc.x286 -M21" LD="cc -M21" ASM=""cc -M21" OBJS_EXT=8086.0 LDFLAGS=""-F 3000" \ CFLAGS="$(RSAINCDIR) -LARGE -Ot -DUNIX -DNOPROTO -DSMALL_MEM -DDYN_ALLOC -DUSE_NBIO -DSVR2"

ce INDY SES aix386:

Wal. 3

\ \

#

File:

‘makefile’

$(MAKE) all CPP="/lib/cpp -DSYSV" \ CFLAGS="$(RSAINCDIR) -O -DUNIX -DIDEA32 -DUSE_NBIO -DSYSV -DPORTABLE" # AIX/370

(like general

SysV)

aix370:

$(MAKE)

all CPP=/lib/cpp \

CFLAGS="$(RSAINCDIR) -DPORTABLE"

-O -DUNIX

-DIDEA32

-DUSE_NBIO

-DSYSV

-DHIGHFIRST

\

3b1:

$(MAKE)

all CC=gcc LD=gcc CPP=/usr/lib/cpp \

CFLAGS="$(RSAINCDIR) -O -I. -DUNIX —-DHIGHFIRST -DMAX_NAMELEN=14"

-DSVR2

-DPORTABLE

-DUSE_NBIO

\

3bi_asm:

$(MAKE)

all CC=gcc LD=gcc

CFLAGS="$(RSAINCDIR) —-DMAX_NAMELEN=14"'

# Silicon sgigcc:

Graphics

Iris

-O

CPP=/usr/lib/cpp

-I.

-DUNIX

-DSVR2

OBJS_EXT=3b168010.0 -DUSE_NBIO

\

IRIX

$(MAKE) all CC=gcc LD=gcec CPP=/usr/lib/cpp \ CFLAGS="$(RSAINCDIR) -O -DUNIX -DPORTABLE -DUSE_NBIO # SGI with assembler sgigcc_asm:

\

-DHIGHFIRST

-DHIGHFIRST"

modules

$(MAKE) all CC=gcc LD=gcc CPP=/usr/lib/cpp OBJS_EXT="1r3000.0 CFLAGS="$(RSAINCDIR) -O -DUNIX -DUSE_NBIO -DHIGHFIRST"

r3kd.o"

\

arse

$GMAKE)

Malle GC=cc

LD=cc

CFLAGS=""$(RSAINCDIR)

-O

\ -DUNIX

-DPORTABLE

-DUSE_NBIO

-DHIGHFIRST

—acpp"

irix_asm:

$¢(MAKE) all CC=cc LD=cc CFLAGS="$(RSAINCDIR) -O

# Users

of PGP

# a snake hpux:

versions

(HP Series

will

expect

700 RISC machine).

a target

Don’t

’hpux’

disappoint

to build

-acpp"

for

them.

hpux-pa-ansi

# HP series 700 pa-risc # UNTESTED for PGP 2.5 hpux-pa-ansi:

.

pgp.rsp $(0BJ2)+ >>pgp.rsp $(0BJ3)+ >>pgp.rsp $(0BJ4)+ >>pgp.rsp $(0BJ5)+ >>pgp.rsp $(ZIPOBJS) >>pgp.rsp $(PROJ)$(EXT) >>pgp.rsp

echo

NUL.MAP

>>pgp.rsp

echo $(LIBS_EXT) $(RSALIBS); >>pgp.rsp

$(LD)

$(LDFLAGS)

OQpgp.rsp

## Dependencies ## armor.obj: armor.c mpilib.h usuals.h platform.h fileio.h mpiio.h language.h armor.obj: pgp.h more.h armor.h crypto.h charset.obj: charset.c usuals.h language.h charset.h system.h config.obj: config.c usuals.h fileio.h pgp.h more.h armor.h config.h charset.h crypto.obj: crypto.c mpilib.h usuals.h platform.h mpiio.h random.h idea.h crypto.obj: crypto.h keymgmt.h keymaint.h pgp.h more.h armor.h mdfile.h md5.h crypto.obj: fileio.h charset.h language.h exitpgp.h zipup.h rsaglue.h fileio.obj: fileio.c random.h usuals.h mpilib.h platform.h mpiio.h fileio.h fileio.obj: language.h pgp.h more.h armor.h exitpgp.h charset.h system.h genprime.obj: genprime.c mpilib.h usuals.h platform.h genprime.h random.h getopt.obj: getopt.c getopt.h idea.obj: idea.c idea.h usuals.h randpool.h keyadd.obj: keyadd.c mpilib.h usuals.h platform.h crypto.h fileio.h keymgmt.h keyadd.obj: charset.h language.h pgp.h more.h armor.h exitpgp.h keyadd.h keyadd.obj: keymaint.h keymaint.c mpilib.h usuals.h platform.h random.h keymaint.obj: crypto.h fileio.h keymgmt.h keymaint.h pgp.h more.h armor.h keymaint.obj: mpiio.h charset.h language.h keymgmt.obj: keymgmt.c system.h mpilib.h usuals.h platform.h idea.h random.h keymgmt.obj: crypto.h fileio.h keymgmt.h rsagen.h mpiio.h language.h pgp.h keymgmt.obj: more.h armor.h md5.h charset.h keymaint.h language.obj: language.c usuals.h fileio.h language.h pgp.h more.h armor.h language.obj: charset.h md5.obj: md5.c md5.h mdfile.obj: mdfile.c mpilib.h usuals.h platform.h mdfile.h md5.h fileio.h mdfile.obj: language.h pgp.h more.h armor.h more.obj: more.c mpilib.h usuals.h platform.h language.h fileio.h pgp.h more.h more.obj: armor.h charset.h mpiio.obj: mpiio.c mpilib.h usuals.h platform.h mpiio.h pgp.h more.h armor.h mpilib.obj: mpilib.c mpilib.h usuals.h platform.h noise.obj: noise.c usuals.h randpool.h noise.h

passwd.obj: passwd.c random.h usuals.h md5.h language.h pgp.h more.h armor.h pgp.obj: pgp.c system.h mpilib.h usuals.h platform.h random.h crypto.h fileio.h pgp.obj: keymgmt.h language.h pgp.h more.h armor.h exitpgp.h charset.h getopt.h pgp.obj: config.h keymaint.h keyadd.h rsaglue.h r3000.obj: r3000.c mpilib.h usuals.h platform.h lmul.h random.obj: random.c system.h idea.h usuals.h md5.h noise.h language.h random.h random.obj: fileio.h pgp.h more.h armor.h randpool.h randpool.obj: randpool.c randpool.h usuals.h md5.h rsagen.obj: rsagen.c mpilib.h usuals.h platform.h genprime.h rsagen.h random.h rsagen.obj: rsaglue.h rsagluel.obj: rsaglue1.c mpilib.h usuals.h platform.h mpiio.h pgp.h more.h rsaglueil.obj: armor.h rsaglue.h random.h rsaglue2.obj: rsaglue2.c mpilib.h usuals.h platform.h mpiio.h pgp.h more.h rsaglue2.obj: armor.h rsaglue.h random.h ../rsaref/install/global.h

rsaglue2.obj: rsaglue2.obj: rsaglue2.obj:

../rsaref/source/rsaref.h ../rsaref/source/md2.h ../rsaref/source/md5.h ../rsaref/source/des.h ../rsaref/source/rsa.h

sleep.obj: sleep.c system.obj: system.c exitpgp.h system.h usuals.h zbits.obj: zbits.c zip.h ztailor.h ziperr.h zdeflate.obj: zdeflate.c zunzip.h usuals.h system.h zip.h ztailor.h ziperr.h zfile_io.obj: zfile_io.c zunzip.h usuals.h system.h zglobals.obj: zglobals.c zip.h ztailor.h ziperr.h zinflate.obj: zinflate.c zunzip.h usuals.h system.h exitpgp.h zip.obj: zip.c usuals.h fileio.h language.h pgp.h more.h armor.h exitpgp.h Zip.obj: ziperr.h zipup.obj: zipup.c zip.h ztailor.h ziperr.h zrevisio.h ztrees.obj: ztrees.c zip.h ztailor.h ziperr.h zunzip.obj: zunzip.c zunzip.h usuals.h system.h

#

Ealiers

‘coe.

Her iler #

ef

Gee?

(New File)

#!/bin/sh # # script to a while

compile

ANSI

source

with

a K&R

:

do

case

$1 in

=c)

-—o) *.c) *)

ap

shift 3; break ;; arg="$arg

$1"

esac shift done set

-e

foal shift

b=‘basename

$f

.c‘

cc -E $arg $f | unproto/unproto cc -c $arg ${b}.i $* rm ${b}.i

>${b}.i

;;

compiler

and unproto.

!

18

ie AWWA #

revares 5 ia

(New File)

# # script # while do

to

compile

ANSI

source

with

a K&R

compiler

and unproto.

:

case

$1 in =c) -o) *.C) *)

a Ainsisdy 9 9 break ;; arg="$arg

$1"

;;

esac shift done set

-e

f=$1 shift b=‘basename

$f

.c‘

ce -E -C -1. $arg $f | unproto/unproto | \ sed ’s/-#[ ]+*\( [0-9] [0-9] *\)/#line \1 "’"\/tmp\/${b}.c'"?"/? cc -c $arg /tmp/${b}.c $* rm /tmp/${b}.c

>/tmp/${b}.c

File:

‘descrip.mms’

File:

its)

‘descrip.mms’

(New File) DESCRIP.MMS (c)

- MMS file

Copyright

1991-93

for PGP/VMS by Hugh Kennedy.

All

rights

reserved.

The author assumes no liability for damages resulting from the use of this software, even if the damage results from defects in this software. No warranty is expressed or implied. The above notwithstanding, a license to use this software is granted to anyone either in the original form or modified on condition that this notice is not removed. Options

Flags:

PGP_DEBUG PGP=GCC — PGP_RSADIR

Define Define -

Use

Modified: Adapted

to use

Change

for

new

method

change

Modified: Allow cm cam Come fam pam emus came fmm fem Sum cm cum cam pm sem fae tee tem fam sam mm cme

use

cleaner).

Date:

modules

for

for

from

for

release

11-Mar-1991 as

release

GCC

1.8.

Hugh A.J.

Kennedy.

Author:

Hugh A.J.

Kennedy

Author:

Hugh A.J.

Kennedy

1.7.

(use one

options

routine

file)

Author:

module

18-Sep-1992

string

Author:

a target.

Alphabetise

to private

directory.

1.3

25-Jun-1992

Date:

10

specified

8-Apr-1992

Date:

09

references

fixes

from

RSATST

of support

(again)

Modified: Misc

program,

from

21-Nov-1991

Date:

08

Modified:

Remove

modules

O07

Modified: All

new

harness

Modified:

Routines

Date:

04

test

Adapted

RSAREF

03

Modified: Add

if you want the debug version to use GNU C instead of VAX C

list

Author:

versions

Hugh A.J. for

ease

of

Hugh A.J.

- no

Kennedy. comparison.

Kennedy

longer reqd.

Date:

7-Nov-1992

Author:

Hugh A.J.

Kennedy

Date:

28-Jan-1993

Author:

Hugh A.J.

Kennedy

V2.01

11 of logicals

for

source

and object

directories

(keeps

things

|

'! ' '! ! ! ' ! !

Modified: Ammend

7?

dependencies

Modified: Update

Date: to

13

support

Add support

24-Feb-1993

include

Date:

for

GNU

for RSAREF

C.

new

header

Author:

Author:

as I live outside

PGP_COMPAT

VFLAGS = MD = MD4

,COMPATIBLE

.else

MD = MD5 . endif .ifdef

WFLAGS

XFLAGS ZFLAGS

= /define=($(WFLAGS) ) = /define=($(WFLAGS) , EXPORT ,NO_ASM,NOSTORE)

.else

ZFLAGS

=

$(CFLAGS)

/define=(EXPORT,NO_ASM,NOSTORE)

.endif

.ifdef CC

=

PGP_GCC

! Use

GNU

GCC

C_PATH_NAME .ifdef CCLIB

= C_INCLUDE_PATH

PGP_RSADIR =

,GNU_CC:

[000000]GCCLIB/1ib,

.else

CCLIB

GNU_CC: [000000] GCCLIB/1lib,

.endif .else

C_PATH_NAME

= C$INCLUDE

. endif

! ! Debugging !

Support

Hugh A.J.

Kennedy

dependencies.

(untested,

'

.ifdef

Kennedy

files.

10-May-1993

Fix

Hugh A.J.

CC

Compiler

the US).

!

File:

‘descrip.mms’

-ifdef

PGP_DEBUG

MFLAGS

= $(MFLAGS)

LINKFLAGS

/debug

= $(LINKFLAGS)

.ifdef

PGP_GCC

DFLAGS

= /DEBUG

/debug/exe=$(mms$target ) ! Are we debugging

.else

DFLAGS

Poa

! No,

Debugging

! Not

debugging

! Use

GCC w/o debug

AND using

with

VAX

GCC?

C

= /debug/noopt

. endif YFLAGS

= $(XFLAGS)

else

.ifdef

PGP_GCC

YFLAGS

= $(XFLAGS)

.else DFLAGS

! Use VAX C w/o debug = /opt=noinline

YFLAGS = $(XFLAGS) endif

LINKFLAGS

= /exe=$(mms$target )

.endif CFLAGS default

= $(CFLAGS)$(DFLAGS)$(YFLAGS ) : obj:pgp.exe ! do nothing... @

petal SiG if

f$trnlnm("src")

.eqs.

""

then

define

src

’f$environment ("default")?

if f$trninm("obj") .eqs. "" then define obj ’f$environment ("default") ’ if f$trnlnm("$(C_PATH_NAME)") .eqs. ""' then define $(C_PATH_NAME) SRC .last

'

deassign

$(C_PATH_NAME)

! RSAREF Stuff ! ifdef PGP_RSADIR

RSAOBJS

= obj:rsa.obj

obj:rsa.obj

obj:nn.obj

obj:r_random.obj

: $(PGP_RSADIR)rsa.c

src:global.h

$(PGP_RSADIR)r_random.h

obj:r_stdlib.obj

$(PGP_RSADIR)rsaref.h

$(PGP_RSADIR)md5.h

-

$(CC) obj:nn.obj

$(CFLAGS) /INCLUDE=(src,$(PGP_RSADIR) )/define=("static=") $(MMS$SOURCE) : $(PGP_RSADIR)nn.c src:global.h $(PGP_RSADIR)rsaref.h $(PGP_RSADIR)digit.h $(CC) $(CFLAGS) /INCLUDE=(src,$(PGP_RSADIR)) $(MMS$SOURCE) obj:digit.obj : $(PGP_RSADIR)digit.c src:global.h $(PGP_RSADIR)rsaref.h $(PGP_RSADIR)nn.h $(PGP_RSADIR)digit.h $(CC) $(CFLAGS) /INCLUDE=(src,$(PGP_RSADIR)) $(MMS$SOURCE) obj:r_random.obj : $(PGP_RSADIR)r_random.c src:global.h $(PGP_RSADIR)rsaref.h

$(PGP_RSADIR)r_random.h

$(PGP_RSADIR)md5.h

$(CC) $(CFLAGS) /INCLUDE=(src,$(PGP_RSADIR) )/define=("static=") obj:r_stdlib.obj : $(PGP_RSADIR)r_stdlib.c srce:global.h $(PGP_RSADIR)rsaref.h $(CC) $(CFLAGS) /INCLUDE=(src,$(PGP_RSADIR) )/define=("static=")

$(MMS$SOURCE) $(MMS$SOURCE)

. endif

ieZieaocurt ' ZIPOBJS = obj:zbits.obj obj:zdeflate.obj obj:zglobals.obj obj:zinflate.obj obj:zip.obj obj:zipup.obj obj:zfile_io.obj obj:ztrees.obj obj:zunzip.obj ZIPH= @esrc:zrevisio.h srce:ztailor.h sre:zunzip.h sre:zip.h src: zipere-n obj-zbits.obj,: sres:zbits.c $(ZIPH)

$(CC) $(DFLAGS) $(ZFLAGS) $(mms$source)

obj:zdeflate.obj

$(CC)

obj:zfile_io.obj

$(CC)

obj:zglobals.obj

$(CC)

$(CC)

obj:zipup.obj

$(CC) obj:ztrees.obj

$(CC)

obj :Zunzip.obj ' ! PGP

: src:zfile_io.c

$(ZIPH)

: src:zglobals.c

$(ZIPH)

$(DFLAGS) $(ZFLAGS) $(mms$source) $(ZFLAGS)

: src:zinflate.c

$(mms$source) $(ZIPH)

$(DFLAGS) $(ZFLAGS) $(mms$source)

: src:zip.c

$(CC)

$(CC)

$(ZIPH)

$(DFLAGS)

obj:zinflate.obj

obj:Zip.obj

: src:zdeflate.c

$(DFLAGS) $(ZFLAGS) $(mms$source)

$(DFLAGS)

$(ZIPH)

$(ZFLAGS)

: src:zipup.c

$(DFLAGS)

$(mms$source)

$(ZIPH)

$(ZFLAGS)

$(mms$source)

: src:ztrees.c

$(ZIPH)

: srcizunzip.c

$(ZIPH)

$(DFLAGS) $(ZFLAGS) $(mms$source) $(DFLAGS)

$(ZFLAGS)

$(nms$source)

Stuff

|

obj:armor.obj : src:armor.c src:armor.h obj:charset.obj : src:charset.c src:usuals.h src:language.h src:charset.h src:system.h obj:config.obj : src:config.c src:usuals.h src:pgp.h obj:CRYPTO.obj : src:mpilib.h src:mpiio.h src:random.h src:crypto.h src: keymgmt .h src:mdfile.h src:md5.h srce:fileio.h src:pgp.h srce:rsaglue.h sre:platform.h sre:usuals.h — src:CRYPTO.C

-

!

File:

‘descrip.mms’

23

obj:idea.obj : src:idea.h src:pgp.h src:idea.c obj:FILEIO.obj : src:FILEIO.C src:random.h src:mpilib.h src:platform.h src:usuals.h src:fileio.h src:pgp.h obj: getopt.obj : src: getopt.c

src: Mpr10 shi=

obj:genprime.obj

: src:genprime.c src:genprime.h src:mpilib.h src:random.h src:platform.h src:usuals.h obj: keyadd.obj : src:mpilib.h src:random.h sre:crypto.h src:fileio.h src:keymgmt.h src:keyadd.h src: genprime.h src:rsagen.h src:mpiio.h src:platform.h src:usuals.h src:pgp-h src:language.h src:charset.h src:keyadd.c

-

-

obj: keymaint.obj : src:mpilib.h src:random.h src:crypto.h src:fileio.h src: keymgmt.h src:keyadd.h src:genprime.h src:mpiio.h src:pgp.h src:platform.h src:usuals.h src: language.h — src:charset.h src: ovmaine c obj: KEYMGMT.obj : src:mpilib.h src:usuals.h src:random.h src:crypto.h src:fileio.h src:mpiio.h srce:pgp.h srce:charset.h src:platform.h src:usuals.h src:KEYMGMT.C obj:MD5.obj : src:md5.h srce:md5.C obj:MDFILE.obj : src:mpilib.h src:mdfile.h src:md5.h src:pgp.h src:platform.h src:usuals.h src:MDFILE.C obj:MORE.obj : src:MORE.C src:mpilib.h src:pgp.h obj:MPIIO.obj ; sre:MPIIO.C sre:mpiio.h sre:mpilib.h — src:platform.h src:usuals.h obj:MPILIB.obj : src:MPILIB.C src:mpilib.h src:platform.h src:usuals.h obj:passwd.obj : src:passwd.c src:random.h src:md5.h src:pgp.h obj: PGP.obj :) src:mpilib.h src:random.h src:crypto.h sre;fileio.h src:keymgmt.h src: keymaint.h src:charset.h src:pgp.h src:config.h src:platform.h src:usuals.h — srce:PGP.C obj:RANDOM.obj : src:random.h src:pgp.h src:RANDOM.C obj:rsagen.obj : src:rsagen.c src:mpilib.h src:genprime.h src:rsagen.h — src:platform.h src:usuals.h — src:random.h src:rsaglue.h obj:rsaglue.obj : src:rsaglue.c src:mpilib.h src:mpiio.h src:pgp.h src:rsaglue.h obj:rsatst.obj : src:rsatst.c src:mpilib.h src:mpiio.h src:genprime.h — src:platform.h src:usuals.h src:rsagen.h src:random.h obj:language.obj : src:language.c src:charset.h src:usuals.h srce:fileio.h src:pgp.h obj:SYSTEM.obj : src:exitpgp.h src:system.h src:pgp.h src:mpilib.h src:mpiio.h src:fileio.h src:charset.h src:platform.h src:usuals.h src: SYSTEM.C obj:vax.obj : src:vax.mar

RSATST '

Is the

RSA/Multiple

Precision

Library

Test

Harness

obj:rsatst.exe : src:rsatst.opt obj:rsatst.obj obj:mpilib.obj obj:genprime.obj obj:rsagen.obj obj:mpiio.obj obj:random.obj obj:vax.obj obj:system.obj obj: language.obj obj:fileio.obj

$(LINK)

$(LINKFLAGS)

-

rsatst/opt

!

! Link PGP ' OBJ1 = obj:pgp.obj obj:config.obj obj:crypto.obj obj: keymgmt.obj obj:keyadd.obj obj: keymaint.obj obj:fileio.obj obj:mdfile.obj obj:more.obj obj:armor.obj obj:mpilib.obj obj:mpiio.obj obj:getopt.obj obj:genprime.obj obj:rsagen.obj obj:random.obj obj:idea.obj obj:passwd.obj obj:md5.obj obj:system.obj obj: language.obj obj:vax.obj obj:charset.obj obj:rsaglue.obj

obj:pgp.exe

: src:pgp.opt

$(RSAOBJS)

$(OBJ1)

$(ZIPOBJS)

-

$(LINK) $(LINKFLAGS) src:pgp/opt, $(RSAOBJS) $(CCLIB) src:VAXCRTL/opt

#

File:

‘pgp.def’

# File: #

25

‘pgp.def’

(New File)

NAME PGP WINDOWCOMPAT STACKSIZE 0x50000

NEWFILES

#

26

# File: #

‘pgp.mak’

(New File)

. AUTODEPEND #

*Translator

Definitions*

CC = bcc +PGP.CFG TASM = TASM

TLINK

= tlink

# 7cAObae

*Implicit

Rules*

$(CC) -c {$< } .cpp.obj:

$(CC) -c {$< }

#

*xList

EXE_dependencies charset.obj \

config.obj \ crypto.obj \ fileio.obj \ genprime.obj \ getopt.obj \ idea.obj \ keyadd.obj \ keymaint.obj \ keymgmt.obj \ language.obj \

md5.obj \

mdfile.obj

\

more.obj \ mpiio.obj \ mpilib.obj \ passwd.obj \ armor.obj

pgp.obj \

\

random.obj

\

rsagen.obj

\

system.obj \ zbits.obj \ zdeflate.obj zZfile_io.obj zglobals.obj zinflate.obj

\ \ \ \

=

\

Macros*

#

File:

‘pgp.mak’

Zip .Ob js\ Zipup.obj \ ztrees.obj \ zunzip.obj \

8086.obj \

zmatch.obj #

*Explicit

pgp.exe:

pgp.cfg

Rules*

$(EXE_dependencies)

$(TLINK) /x/c/P-/L\BCC\LIB 0&& |

cOl.obj+ charset .obj+ config.obj+ crypto.obj+ fileio.objt+ genprime.obj+ getopt.objt idea.obj+ keyadd.obj+ keymaint.obj+ keymgmt .obj+ language.objt+ md5.obj+ mdfile.objt+ more.objt+ mpiio.objt+ mpilib.objt passwd.obj+ armor .obj+

pgp.obj+

random.obj+ rsagen.objt system.obj+ zbits.objt+ zdeflate.obj+ zfile_io.obj+ zglobals.objt zinflate.objt+ zip.obj+ zipup.obj+ ztrees.objt zunzip.objt 8086.obj+ zmatch.obj

P&P

# no

map file

Gil. Akio)

| #

*Individual

File

Dependencies*

#

28

charset.obj:

charset.c

config.obj:

config.c

crypto.obj:

crypto.c

Tileio-obj:

fileio.c

genprime.obj:

getopt.obj: idea.obj:

genprime.c

getopt.c idea.c

keyadd.obj:

keyadd.c

keymaint.obj:

keymaint.c

keymgmt .obj:

keymgmt.c

language.obj: md5.obj:

language.c

md5.c

mdfile.obj:

more.obj: mpiio.obj:

mdfile.c

more.c mpiio.c

mpilib.obj:

mpilib.c

passwd.obj:

passwd.c

armor.obj:

armor.c

pgp.obj: pgp.c random.obj:

random.c

rsagen.obj:

rsagen.c

system.obj:

system.c

ZDAtS

Obs

Zba tS). C

zdeflate.obj:

zdeflate.c

répeLihe) Sho) Oley]

PAreslaley Sie) te

zglobals.obj:

zglobals.c

#

File:

‘pgp.mak’

zinflate.obj: Zip.Obye

29

zinflate.c

Zipsc

zipup.obj:

zipup.c

ztrees.obj:

ztrees.c

zunzip.obj:

zunzip.c

8086.o0bj}: 8086.asm $(TASM) /MX /ZI

/O 8086.ASM,8086.0BJ

zmatch.obj: zmatch.asm $(TASM) /DDYN_ALLOC=1

£

*Compiler

pgp.cfg:

/DSS_NEQ_DS=1

Configuration

pgp-mak

copy &&|

-ml1 -f-

=G =G -Z =i -wamb —wamp -wasm —wpro -wdef -wnod -wstv

-wuse -I\BCC\ INCLUDE

-L\BCC\LIB

—DMSDOS ; DYN_ALLOC ; SMALL_MEM =P=3¢

/MX /ZI /O ZMATCH.ASM,ZMATCH.OBJ

File*

#

30

lee

ape pops.

! nsi(NewiF ile) '! PGP.OPT - Options file for PGP/VMS \ (c) Copyright 1991-93 by Hugh Kennedy.

All

rights

reserved.

i}

'! The author assumes no liability for damages resulting from the use ! of this software, even if the damage results from defects in this ' software. No warranty is expressed or implied. '

!\ The

above

notwithstanding,

a license

'! to anyone either in the original ! this notice is not removed.

to

use

or modified

this

form

software

on

is

granted

condition

that

!

!! Version: \ !' Original:

2

OOA

13-Nov-1992

Author:

Hugh A.J.

Kennedy

O2A

11-Feb-1993

Author:

Hugh A.J.

Kennedy.

Hugh A.J.

Kennedy.

!

!iJ Modification: '

!' Update version number. Remove MD5 ' !i} Modification: 02e 14-May-1993

logical. Author:

i}

! Update version ' NAME=PGP IDENT="V2.3" ! '

number.

Add rsa

glue

stuff.

obj :more,fileio,md5 ,mdfile,getopt,system,mpilib,mpiio,random,crypto,rsagen,idea, passwd, genprime, pgp, config,vax, language, charset, armor i]

| RSA Stuff '

obj :rsaglue '

| Key Stuff !

obj :keymgmt ,keymaint ,keyadd ' ! ZIP Stuff ' obj:zbits,zdeflate,zglobals,zinflate,zip,zipup,zfile_io,ztrees,zunzip

#

File:

‘pgppwb.mak’

# File: #

on

‘pgppwb.mak’

(New File)

ORIGIN = PWB ORIGIN_VER = 2.1.49 PROJ = PGP PROJFILE = PGPPWB.MAK DEBUG = 0 BSCMAKE

=

SBRPACK

=

bscmake

sbrpack

NMAKEBSC1 NMAKEBSC2 CC = cl CFLAGS_G CFLAGS_D CFLAGS_R CXYX = Ver CXXFLAGS_G CXXFLAGS_D CXXFLAGS_R ASM = ml AFLAGS_G AFLAGS_D

= set = nmake

= /Zi

AFLAGS_R

= /nologo

MAPFILE_D MAPFILE_R LFLAGS_G LFLAGS_D LFLAGS_R

= NUL = NUL = /NOI /STACK:12288 = /CO /FAR /PACKC = /EXE /FAR /PACKC

= /AL /W2 /DDYN_ALLOC /DSMALL_MEM = /f /Od /Zi = /f- /Ot /01 /Og /Oe /Oi /Gs

/DMSDOS

/BATCH

/FR$*.sbr

/Gt

= /W2 /BATCH /FR$*.sbr = /f /Zi /Od = /f- /Ot /Oi /01 /Oe /Og /Gs

= /Cp /W2 /WX /Zm /FR$*.sbr

/BATCH

/ONERROR:NOEXE

LINKER = link ILINK = ilink LRF = echo > NUL ILFLAGS = /a /e BRFLAGS = /o $(PROJ).bsc BROWSE = 1 PACK_SBRS = 1 FILES

OBJS

= 8086.ASM ARMOR.C CHARSET.C CONFIG.C CRYPTO.C CRYPTO.H FILEIO.C\ FILEIO.H GENPRIME.C GENPRIME.H GETOPT.C IDEA.C IDEA.H KEYADD.C\ KEYMAINT.C KEYMGMT.C KEYMGMT.H LANGUAGE.C LANGUAGE.H MD5.C MD5.H\ MDFILE.C MDFILE.H MORE.C MPIIO.C MPILIB.C MPILIB.H PASSWD.C PGP.c\ PGP.H RANDOM.C RANDOM.H RSAGEN.C RSAGEN.H STDLIB.H SYSTEM.C USUALS.H\ ZBITS.C ZDEFLATE.C ZFILE_I0O.C ZGLOBALS.C ZINFLATE.C ZIP.C ZIP.H\ ZIPERR.H ZIPUP.C ZMATCH.ASM ZREVISIO.H ZTAILOR.H ZTREES.C ZUNZIP.C\ ZUNZIP.H = 8086.obj ARMOR.obj CHARSET.obj CONFIG.obj CRYPTO.obj FILEIO.obj\ GENPRIME.obj GETOPT.obj IDEA.obj KEYADD.obj KEYMAINT.obj KEYMGMT.obj\ LANGUAGE.obj MD5.obj MDFILE.obj MORE.obj MPIIO.obj MPILIB.obj\

#

32

PASSWD.obj PGP.obj RANDOM.obj RSAGEN.obj SYSTEM. obj ZBITS.obj\ ZDEFLATE.obj ZFILE_I0.obj ZGLOBALS.obj ZINFLATE.obj ZIP.obj ZIPUP.obj\ ZMATCH.obj ZTREES.obj ZUNZIP.obj = 8086.sbr ARMOR.sbr CHARSET.sbr CONFIG.sbr CRYPTO.sbr FILEIO.sbr\ GENPRIME.sbr GETOPT.sbr IDEA.sbr KEYADD.sbr KEYMAINT.sbr KEYMGMT.sbr\

SBRS

LANGUAGE.sbr MD5.sbr MDFILE.sbr MORE.sbr PASSWD.sbr PGP.sbr RANDOM.sbr RSAGEN.sbr

ZDEFLATE.sbr ZMATCH.sbr

all:

ZFILE_I0.sbr

ZTREES.sbr

ZGLOBALS.sbr

MPIIO.sbr MPILIB.sbr\ SYSTEM.sbr ZBITS.sbr\

ZINFLATE.sbr

ZIP.sbr

ZIPUP.sbr\

ZUNZIP.sbr

$(PROJ).exe

. SUFFIXES : . SUFFIXES: SSUIMSID GSS sOly)

sek

aS

oeIRIN

8086.obj : 8086.ASM 'IF $(DEBUG) $(ASM) /c $(AFLAGS_G) \ELSE $(ASM) /c $(AFLAGS_G) (‘ENDIF 8086.sbr : 8086.ASM !'IF $(DEBUG) $(ASM) /Zs $(AFLAGS_G) \ELSE $(ASM) /Zs $(AFLAGS_G) (‘ENDIF

$(AFLAGS_D)

/Fo8086.obj

8086.ASM

$(AFLAGS_R)

/Fo8086.obj

8086.ASM

$(AFLAGS_D)

/FR8086.sbr

8086.ASM

$(AFLAGS_R)

/FR8086.sbr

8086.ASM

ARMOR.obj : ARMOR.C MPILIB.H FILEIO.H mpiio.h LANGUAGE.H !IF $(DEBUG) @$(CC) /c $(CFLAGS_G)

$(CFLAGS_D)

PGP.H USUALS.H

@16-bit temporaries #define low16(x) ((x) & OxFFFF) typedef unsigned int uinti6; /* at LEAST

*/

16 bits,

maybe more

*/

#else

#define

lowi6(x)

typedef #endif

wordi6é

#ifdef /*

(x) /* this

is only ever

applied to uinti6’s

_GNUC_

__const__

* which

simply

is useful

means

info

there

are

for the gcc

no

side

effects

for

this

optimizer

*/ #define #telse #define #Hendif

CONST

__const__

CONST

/*

* Multiplication,

modulo

(2**16)+1

* Note that this code is structured on the assumption that * untaken branches are cheaper than taken branches, and the * compiler doesn’t schedule branches.

+/

/*

mul */

#ifdef SMALL_CACHE CONST static uint16 mul (register uinti6

a, register

i register

p =

word32

(word32)

p;

a *b;

lun)

vl

b = lowi6

(p);

Gl Si jo) 22> alee return (b - a) + (b < a); else

*/

uinti16;

if

(a)

uinti6

b)

function,

*/

/*

Fado

o idea.c2

*/

/*

{ return

ie —

ra?

ect

le—" bi

else

{ } } /* mul */ #endif

/* SMALL_CACHE

*/

/*

* Compute the multiplicative inverse of x, modulo 65537, using Euclid’s * algorithm. It is unrolled twice to avoid swapping the registers each * iteration, and some subtracts of t have been changed to adds.

*/ /*

mulinv */ CONST

static

mulInv

uinti6

(uintié6

WinG1 uinti6

x)

OmcO mois q, y;

sig? (Ge = 2, this fits y = 0x10001L % x;

if (y == v=

16 bits

1)

return Ol do

into

low16

(1 - t1);

des

{

fc as

5 ee

tol Ra i

tO t= q * t1; Hee uve SS Aly) return

t0;

Go = Visa x; y =.Y 4x; t1

+=

-q * t0;

} while (y != 1); return lowi6 (1 - t1); } /* mukInv */ /* * Expand

*/

a 128-bit

user

key to a working

encryption

key EK

*/

371

*/

/*

S20

ey

/*

PGP

Source

Code

and

Internals

/*

ideaExpandKey */ static

void

ideaExpandKey au shake

(byte const

*userkey,

wordi6

* EK)

oh, ops

fors¢j] = 0.) eos jtt) { EK[j] = (userkey[0] 7;

Is } /* ideaExpandKey */ /* * Compute IDEA decryption key DK from an expanded * Note that the input and output may be the same. * inverted

7,

into

an

internal

buffer,

and

then

IDEA encryption key EK Thus, the key is

copied

to

/*

ideaInvertKey */ static

void

ideaInvertKey

(word16

const

*EK,

word16

{ int

i;

Wane)

wil,

WA,

weir

word16 temp[IDEAKEYLEN] ; wordi6

*#p = temp

t1

= mulInv

t3

=

+ IDEAKEYLEN;

(+*EK++);

t2 = -*EK++; —*EK++;

*--p = mulInv (19)

=

a=) cto)

= oA SS “upabs

(*EK++);

1328

for (i = 0; “

i < IDEAROUNDS

ti = *EK++;

-

1; i++)

DK[IDEAKEYLEN])

the

output.

+7,

fe

SPATS

O Taaaverm”

*-—p

=

=*/

*EK++;

AS Syo) =

wel

ti

= muliInv

t2

=

t3

(+*EK++);

= -*EK++;

-*EK++;

*--p = mulInv jo) =

/*

(*EK++);

= 745

S8) =

9)

t3;

=

cae

Me ti

= *EK++; +> pe =) ERE £3)

=

tl:

ti = muliInv

t2 = -*EK++;

(*EK++)

t3 = -*EK++; *--p = muliInv

che)

(*EK++);

ts:

ASS

=

+—peo

B45

Gl

/* Copy and destroy temp copy */ memcpy (DK, temp, sizeof (temp)); burn

(temp);

} /* ideaInvertKey

*/

/*

* MUL(x,y) *

t16

and

computes t32.

x

x = x*y,

is modified,

modulo and

0x10001. must

be

Requires

* y may be anything, but unlike x, must be strictly * even if lowi6() is #defined. * All of these are equivalent - see which is faster

less

#ifdef SMALL_CACHE #define MUL(x,y) (x = mul(lowi6(x),y)) #else /* !SMALL_CACHE */ #ifdef AVOID_JUMPS #define MUL(x,y) (x = low16(x-1), t16 = low16((y)-1),

(word32)x*t16

+ x + t16, x = low16(t32),

£168=!¢82>516, x! = "(x-t16)*+ (xiv; memcpy (context->oldcipher, ideaCipher (bufptr, bufptr, context->bufleft

=

8 -

bufptr, 8); context->key);

count;

do

{ t = *bufptr; *dest++ = t ~

(*bufptr++

= *srctt);

const

*src,

and

Internals

*/

/*

File:

while

‘idea.c’

*/

(--count);

BECCA

/* * * * *

*/

/*

AICS

CCGG

COCA

IAAI

I Fk i

/

Cryptographically strong pseudo-random-number generator. The design is from Appendix C of ANSI X9.17,: "Financial Institution Key Management (Wholesale)", with IDEA substituted for the DES.

/* * Initialize a cryptographic random-number * key and seed should be arbitrary. */

oe

generator.

ni

void

ideaRandInit (struct IdeaRandContext byte const seed[8]) omg

*context,

byte

const

key[16],

EL6

ideaExpandKey

(key,

context-—>bufleft

memcpy

/* * Read

=

context->key); 0;

(context->internalbuf,

out

the

RNG’s

seed,

8);

state.

*/ void

ideaRandState An

(struct

IdeaRandContext

*context,

byte key[16],

byte

seed[8] )

Gael:

memcpy

(seed,

context->internalbuf,

8);

foraviess 07 3, < S54it*) key[2 * i] = context->key[i] >> 8; key([2 * i + 1] = context->key[il ;

iy

} /*

* Encrypt

the

RNG’s

state

with

the

given

CFB

encryptor.

*/ void ideaRandWash

(struct

IdeaRandContext

byte keyseed[16 + 8];

*context,

struct

IdeaCfbContext

*cfb)

381

*/

/*

T3832

sean.

*7

:

/*

PGP Source

Code

and Internals

SL9

ideaRandState (context, keyseed, keyseed + 16); ideaCfbEncrypt (cfb, keyseed, keyseed, 16 + 8); ideaRandInit (context, keyseed, keyseed + 16);

memset

(keyseed,

0, 16 + 8);

} /* * Cryptographic * session keys.

pseudo-random-number

generator,

used

for

+/

byte

ideaRandByte

(struct

IdeaRandContext

*c)

‘A sla

if

545

('c->bufleft)

{

byte timestamp[8] ; /* Get

some

true-random

randPoolGetBytes

/* Compute axepe

next

noise

(timestamp,

8 bytes

(Ca = (08 Sh outbuf, c->outbuf, /* Compute new seed vector */ siepe ((G =) @)x Si internalbuf [i] = c->outbuf[i] burn

(c->internalbuf,

(timestamp) ;

c->bufleft

=

8;

Ip return

c->outbuf [--c->bufleft];

Me /* end

of

idea.c

*/

*/

Sigise))

c->outbuf [i] = c->internalbuf[i]

ideaCipher

(timestamp) );

c->key);

~ timestamp[il]; c->internalbuf,

c->key);

generating

/*

File:

‘keyadd.h’

/* File:

‘keyadd.h’

/* (New File) */ /* Adds int

*/

(prepends)

addto_keyring

(x

*/

| key file to key ring file (char

*keyfile,

char

*/

*ringfile);

#333

+*/

384

/*

*/

/* File: /* (New File)

/*

‘keyadd.c’

PGP

Source

PGP:

and

Internals

*/

*/

keyadd.c - Keyring merging routines for PGP. Pretty Good(tm) Privacy - public key cryptography

/*

Code

for the masses.

(c) Copyright 1990-1994 by Philip Zimmermann. All rights reserved. The author assumes no liability for damages resulting from the use of this software, even if the damage results from defects in this software. No warranty is expressed or implied. Note that while most PGP source modules bear Philip Zimmermann’s copyright notice, many of them have been revised or entirely written by contributors who frequently failed to put their names in their code. Code that has been incorporated into PGP from other authors was either originally published in the public domain or is used with permission from the various authors. PGP is available for free to the public under certain restrictions. See the PGP User’s Guide (included in the release package) for important information about licensing, patent restrictions on certain algorithms, trademarks, copyrights, and export controls.

#7 #include #include #ifdef UNIX

#include

#endif #include #include #include #include #include #include #include #include #include #include #include #include

"mpilib.h" "crypto.h" "fileio.h" "keymgmt.h" "charset.h"' "mpiio.h" "language.h" "pgp.h" “exitpgp.h" "keyadd.h" "keymaint.h"

void

gpk_close

int gpk_open

(void);

(char *keyfile);

int get_publickey (long *file_position, byte * keyID, byte * timestamp, byte

* userid,

unitptr

static

int ask_to_sign

static

boolean

n,

unitptr

(byte * keyID,

ask_first;

int

*pktlen,

e);

char *ringfile);

*/

/*

File:

‘keyadd.c’

*/

static

boolean

publickey;

/* if TRUE,

static

static

int newkeys, newsigs, newids, byte mykeyID [KEYFRAGSIZE] ;

static

struct

sig_list

struct sig list long pos;

*next;

*siglist; /*

sig

lis teadda

*/ static

void

sig_list_add

(long pos)

{ struct

sig_list

p = xmalloc

*p;

(sizeof *p);

p->pos = pos; p->next = siglist; Siglist = p; /*

So Cia ste iviid */ hy static

int

sig_list_find ai struct

(long pos)

sig_list

*p;

for (p = siglist; p; p = p->next) if (p->pos == pos) return return 0;

1;

/*

sigulastmcilear */ ip static

void

sig_list_clear 1. struct

(void)

sig_list

for (p ="siglist; { n = p->next;

free

(p);

} siglist

=

NULL;

*p,

*n;

p; p = 2)

/* add trust newrvks;

packets

*/

385

*/

/*

386

*/

/* Merge

:

signatures

* userid

from

from userid

fring

(which

/*

in fkey

PGP Source

(which is keyfile)

is ringfile)

at ringpos,

Code

and Internals

at keypos

appending

result

with to out.

*/ /*

mergesigs +/ static int mergesigs (FILE

* fkey,

char *ringfile,

char

*keyfile,

long *pringpos,

long keypos,

FILE

* fring,

FILE * out)

long ringuseridpos, ringpos; int ringpktlen, keypktlen; int

status;

byte ctb; int copying; word32 rstamp,

kstamp,

xstamp;

byte keyID[KEYFRAGSIZE] ; char

userid[256];

/* First,

copy

the

userid

ringuseridpos

= ringpos

fseek

ringpos,

(fring,

(void)

NULL,

readkeypacket

NULL,

NULL,

PascalToC

packet

plus

any

comments

or

ctrls

NULL,

NULL,

SEEK_SET) ; (fring,

NULL,

itself,

= *pringpos;

NULL,

FALSE,

&ctb,

NULL,

userid,

NULL);

(userid);

ringpktlen = ftell (fring) - ringpos; copyfilepos (fring, out, ringpktlen, ringpos) ;

for (;;) A

ringpos status

= ftell

(fring);

= nextkeypacket

Tf (status

= 0)

4. fring,

if ((status ringfile,

return

= TRUE)

userid_pos,

status;

= FALSE;

copying

= TRUE;

else

t he {

if (copying) /* Copy

ringfile

copyfilepos

}

userid

(fring,

and

out,

sigs

to out

ringpktlen,

*/

ringpos) ;

} /* End of loop for each key in ringfile fseek

(fring,

*pringpos return

ringpos,

= ringpos;

0;

} /* mergekeys

*/

SEEK_SET);

*/

userid,

= mergesigs (fkey, keyfile, &ringpos, out)) < 0)

copying

userid

+*/

/* Grab the keyID here readkeypacket

the

*/

NULL,

NULL,

393

*/

394

/*

*/

;

/*

PGP Source

Code

and Internals

/*

SIA

ISSN

ae

*

/* Adds

(prepends)

int _addto_keyring

key file to key ring file.

(char

*keyfile,

char

*/

+ringfile)

J FILEG+t oe *g, +h; long file_position,

fp;

int pktlen; byte ctb; int

status;

unit

n[MAX_UNIT_PRECISION] , e[MAX_UNIT_PRECISION] ;

unit ni[MAX_UNIT_PRECISION] ; byte keyID[KEYFRAGSIZE];

byte userid[256]; /* key certificate byte useridi[256]; word32

*/

tstamp;

byte *timestamp boolean

= (byte *) & tstamp;

userid_seen

=

int commonkeys = 0; int copying; struct newkey *nkey, char

userid

/* key certificate

timestamp

*/

FALSE;

*nkeys

= NULL;

*scratchf;

/* open

file

f for

if ((f = fopen

read,

in binary

(not

(keyfile,

FOPRBIN))

== NULL)

text)

mode...

*/

{

fprintf reGyeiban

(pgpout,

LANG

("\n\007Can’t

open key file

’%s’\n"),

keyfile);

als

} ctb

=

0;

ife(iread

(£ctb,

1,

1, £4)

=

1°)

tis key_ctb) (eth))

{ fclosouciys return

} rewind

-1;

(f);

setoutdir (ringfile); scratchf = tempfile (0); /* * get_userids

* keyring

from

both

if ringfile

*

setkrent

(ringfile) ;

setkrent

(keyfile);

init_userhash

();

files,

is not

maybe

the

should

default

also

ring.

use

the

default

public

*/

/*

File:

‘keyadd.c’

if (!file_exists

¥*/

/*

(ringfile))

{



/* ringfile does not exist. Can it be created? */ /* open file g for writing, in binary (not text) mode... g = fopen (ringfile, FOPWBIN); if (g == NULL) fprintf (pgpout, LANG ("\nKey ring file ringfile) ; fclose goto

’%s’

cannot be created. \n"),

(f);

err;

fclose

(g);

/* Create working output file */ /* open file g for writing, in binary if

((g = fopen

(scratchf,

FOPWBIN))

(not text)

==

mode...

*/

NULL)

{ tcloseu(t); goto

err;

newkeys

= newsigs

/* Pass /* Also

1 - copy all keys from f which aren’t in ring file copy userid and signature packets. */ (pgpout, LANG ("\nLooking for new keys...\n")); = FALSE;

fprintf

copying if (gpk_open

= newids

(ringfile)

= newrvks

= 0;

< 0)

{ fclose fclose goto

(f); (g);

/* close

key file

*/

err;

for (;;) {

file_position

= ftell

(f);

status = readkeypacket (f, FALSE, &ctb, timestamp, (char *) userid, n, e, NULL, NULL, NULL, NULL, NULL, NULL); /* Note that readkeypacket has called set_precision if (status == -1) /* EOF */ break;

if


= 0 && !filter_mode && !batchmode) for (nkey = nkeys; nkey; nkey = nkey->next) if (ask_to_sign (nkey->keyID, scratchf) != 0) break;

if (status && verbose) fprintf (pgpout, "addto_keyring: free_newkeys

(nkeys);

savetempbak

(scratchf,

return

0;

err: gpk_close endkrent /* make

/* normal

sure

we remove

rmtemp

(scratchf) ;

return

-1;

} /* _addto_keyring

*/

returned

%d\n",

ringfile);

return

(); /* save ();

maint_update

*/

to call any

if not

garbage

opened */

files

we may

have

created

*/

status);

7,

/*

File:

‘keyadd.c’

¥*/

/*

/*

addto_keyring */ int

‘iste

cia

(char *keyfile,

long

armorline

char

*tempf;

int

addflag

= 0;

= 0;

if (_addto_keyring return

char *ringfile)

(keyfile,

ringfile)

== 0)

0;

/* check if the keyfile to be added is armored while (is_armor_file (keyfile, armorline)) tempf

= tempfile

(TMP_TMPDIR

if (de_armor_file

i

rmtemp

(tempf);

return

—1;

| TMP_WIPE);

(keyfile,

tempf,

(tempf,

ringfile)

if (_addto_keyring addflag = 1; rmtemp

*/

&armorline))

== 0)

(tempf);

if (!addflag) “ fprintf

(pgpout,

Teturn

—1:

return

0;

LANG

("\nNo

keys found

in

’%s’.\n"),

else

4 }

} /*

ask */ static

fouesien int

ask_to_sign FILE

(byte * keyID,

char

*ringfile)

*f;

word32 timestamp; byte ctb, trust;

unit n[MAX_UNIT_PRECISION] , e[MAX_UNIT_PRECISION]; byte userid[256]; long fpos; int status;

keyfile);

401

*/

/*

402

*/

extern

/*

Source

Code

and

Internals

char my_name[] ;

if (getpublickey (byte return

return

(GPK_GIVEUP,

*) & timestamp,

ringfile,

userid,

n,

&fpos,

NULL,

keyID,

e) < 0)

-1;

if ((f = fopen fseek

PGP

(ringfile,

FOPRBIN))

== NULL)

-1;

(f, fpos,

SEEK_SET) ;

if (is_compromised fclose

(f);

return

0;

} if (nextkeypacket {

(f))

(f, &ctb)

< 0)

felosen(t)): return

-1;

} if

(ctb

!= CTB_CERT_PUBKEY)

fclose

(Ct):

return

0; /* don’t

ask to sign secret

} while (nextkeypacket (f, &ctb) == if (ctb == CTB_USERID) /* check break; TEmcCctbml—sCibe

fclose

(£);

return

-1;

key */

0 && !is_key_ctb first userid */

(ctb))

USERID)

Ited¢statuse—snead. trusteGr se tinust)))

fclose

(f);

return

status;

;

if (status

> 0 &&

!(options

fprintf (pgpout, LANG if (getyesno (’y’)) return

savetempbak

rmtemp

(fixfile);

return

status;

(fixfile,

>=

0)

changed.\n"),

status) ;

& MAINT_CHECK) )

("Update public keyring ringfile);

’%s’

(Y/n)?

"), ringfile);

*/

/*

416

*/

/*

} /* maint_check static int maintenance

PGP

Source

Code

and

Internals

*/

(char

*ringfile,

struct

newkey

const

*nkeys)

f int status; undefined_trust

= 0;

if (max_cert_depth max_cert_depth

/* None

so

far...

*/

> MAX_DEPTH)

= MAX_DEPTH;

if ((sec_fp = fopen (globalSecringName, FOPRBIN)) == NULL) fprintf (pgpout, LANG ("\nCan’t open secret key ring file

’%s’\n"),

globalSecringName) ;

setkrent (ringfile); setup_trust (); maint_init_mem

if

();

(mverbose || verbose) fprintf (pgpout, LANG ("\nPass 1: Looking

status

=

maint_read_data

for the \"ultimately-trusted\"

(ringfile,

keys...\n"));

nkeys);

if (sec_fp) 4 fclose (sec_fp); sec_fp

=

NULL;

a if if

(status < 0) goto failed; (mverbose

fprintf If) ((status goto

|| verbose)

(pgpout,

LANG

("\nPass

= marntetraceschain

2: Tracing ()))
uid_next else id

= allocn

= pk->pk_userids

= allocn

(sizeof (sizeof

(struct

userid));

(struct

userid));

419

*/

420

/*

if

¥*/

/*

PGP

Source

Code

and

Internals

(mverbose) id->uid_userid

keyctrl

&=

=

store_str

(userid);

~KC_LEGIT_MASK;

if (buckstop) keyctrl

|= KC_LEGIT_COMPLETE;

else

keyctrl

|= KC_LEGIT_UNKNOWN;

id->uid_next

=

NULL;

id->uid_key = pk; id->uid_legit = keyctrl; id->uid_signatures = sig = NULL; break;

case

CTB_SKE_TYPE:

ify Ghpk, |

lesbid)

break;

if (sig) sig =

sig->sig_next

= allocn

(sizeof

(struct

signature) );

else

sig = id->uid_signatures

= allocn

(sizeof

(struct

signature)) ;

sig->sig_next = NULL; sig->sig_uid = id;

sig->sig_from = getpubkey (sigkeyID); sig->sig_nextfrom = sig->sig_from->pk_signed; sig->sig_from->pk_signed = sig; sig->sig_trust = keyctrl & KC_SIG_CHECKED; break;

/* switch ctb_type keypos = ftell if

*/ (f);

(buckstopcount == 0 && mverbose) fprintf (pgpout, LANG ("No ultimately-trusted

fclose return

keys.\n"));

(£); 0;

I /* maint_read_data

*/

/*

* scan * *

/

on

keyring

for buckstop

keys

and

start

them

/*

ee *

st atic

int

maint_trace_chain

(void)

al char

*userid;

struct

pubkey

*pk;

for (pk = pklist; al

pk; pk = pk->pk_next)

the

recursive

trace_sig_chain()

#/

/*

File:

‘keymaint.c’

¥*/

if (!(pk->pk_owntrust

/*

& KC_BUCKSTOP) )

continue;

if (mverbose) fprintf (pgpout, "* Z%s\n",

LOCAL_CHARSET

if

(TRUST_LEV

(pk->pk_userids—>uid_userid));

(pk->pk_owntrust)

==

KC_OWNERTRUST_UNDEFINED )

userid = user_from_keyID (pk->pk_keyid); SET_TRUST (&pk->pk_owntrust, ask_owntrust

I trace_sig_chain return

(pk,

(userid,

pk->pk_owntrust));

0);

0;

} /* maint_trace_chain

*/

/*

* Find all signatures made with the key pk. * If a trusted signature makes a key fully legit then signatures * with this key are also recursively traced on down the tree.

made

*

* depth is the * and to check

level if we

of recursion, it is used to indent the userIDs don’t exceed the limit "max_cert_depth"

*

* NOTE: a signature made with a key with pk_depth == max_cert_depth will * not be counted here to limit the maximum chain length, but will be * counted when the validity of a key is computed in maint_final()

*/ static

int

trace_sig_chain Inca.

trust

(struct count

=

pubkey

*pk,

int depth)

10;

int counts [MAX_DEPTH] ; struct signature *sig, *s; struct pubkey *p; struct

userid

*id;

assert (depth pk_depth && pk->pk_depth pk_depth

= depth;

/* Should we ask for trust. * it! Ask the user....

If this

key is legit,

then

go for

*/ if (TRUST_LEV (pk->pk_owntrust) = = KC_OWNERTRUST_UNDEFINED ) for?{id!=" pk->pk_userids ; id}. id = id->uid_next) { compute_legit (id); if ((id->uid_legit & KC_LEGIT_MASK) == KC_LEGIT_COMPLETE)

421

*/

/*

422

*/

:

/*

PGP Source

Code and Internals

SET_TRUST (&pk->pk_owntrust, ask_owntrust (user_from_keyID (pk->pk_keyid), pk->pk_owntrust)); break;

}

}

/* Return if I haven’t * don’t need to check

signed anyone’s keys, since I any further.. -warlord 93-04-11

*/

if (!pk->pk_signed) return

#ifdef

0;

DEBUG

if (mverbose) fprintf (pgpout, "%*sid-v %s\n", 2 * depth, depth, pk->pk_userids->uid_userid) ;

'",

#endif

/* all keys signed by pk */ for

(sig = pk->pk_signed;

sig;

sig = sig->sig_nextfrom)

/* If signature is good, copy trust /* CONTIG bit currently unused */ if

(sig->sig_trust

from

signator

*/

& KC_SIG_CHECKED)

{ SET_TRUST

(&sig->sig_trust,

sig->sig_trust

|= KC_CONTIG;

TRUST_LEV

(pk->pk_owntrust)) ;

/* CONTIG

bit

currently

unused

if (mverbose) LprintfCpgpout, "'.¥s oes \n', 82 * depth, !", LOCAL_CHARSET (sig->sig_uid->uid_userid));

5 else

af SET_TRUST

(&sig->sig_trust,

KC_SIGTRUST_UNTRUSTED) ;

sig->sig_trust &= ~KC_CONTIG; if (mverbose) fprintf (pgpout, "4*s X “~s\n",

2 * depth, "", (sig->sig_uid->uid_userid));

LOCAL_CHARSET

Hs if (TRUST_FAC

(sig->sig_trust)

== 0)

continue;

p = sig->sig_uid->uid_key; /* this if (p->pk_owntrust & KC_BUCKSTOP) continue;

/* will

be handled

from

main

key signed by pk */

loop

*/

if (p->pk_depth && p->pk_depth sig_uid->uid_signatures;

s->sig_from->pk_depth;

(d < max_cert_depth) counts[d] += TRUST_FAC

(s->sig_trust);

/* * find a combination of signatures * valid through the shortest cert.

2a

trust_count

ft

for

=

that will path.

make

the key

0;

(d = 0; d < max_cert_depth;

trust_count if

s; s = s->sig_next)

++d)

+= counts[d]; .

(trust_count

>=

complete_min)

tracessigichain

(py id + 1);

break;

}

Yi #ifdef

if

DEBUG

(mverbose) fprintf (pgpout, "%tsid-s\n", 2 * depth, depth, pk->pk_userids->uid_userid) ;

"",

#endif return

0;

} /* trace_sig_chain

*/

/* * compute validity of userid/key pair, the number of signatures * trust level of these signatures determines the validity.

*/ static void compute_legit struct int

(struct

signature

trust_count,

userid

*s; legit;

if (id->uid_key->pk_owntrust legit else

=

*id)

& KC_BUCKSTOP)

KC_LEGIT_COMPLETE;

af Croust.=counta=—

for

(s =

trust_count if legit

=

0%

id->uid_signatures;

+= TRUST_FAC

-(trust=count

==

KC_LEGIT_UNKNOWN;

s;

s = s->sig_next)

(s->sig_trust); 0)

and the

423

Bf

/*

424

*/

;

/*

PGP

Source

Code

and

Internals

else if (trust_count < marginal_min) = KC_LEGIT_UNTRUSTED ; else if (trust_count < complete_min) = KC_LEGIT_MARGINAL; else = KC_LEGIT_COMPLETE;

legit legit legit

s

id->uid_legit = (id->uid_legit } /* compute_legit */

& ~“KC_LEGIT_MASK)

| legit;

/* * check if the maintenance pass changed anything * returns O if files f and g are equal and the number of changed * trust bytes if the files are different or a negative value on error

7,

/*

maint

final

*/ static int maint_final int

(char *ringfile)

status;

FILE *£; long trust_pos = 0; char userid[256] ; byte keyID[KEYFRAGSIZE] ;

byte sigkeyID[KEYFRAGSIZE] ; byte

ctb;

byte

kc_orig,

int

changed

kc_new

=

0,

mask;

= 0;

int

skip = 0; struct pubkey struct userid

struct

if

*pk; *id = NULL;

signature

*sig = NULL;

(check_only) f = fopen (ringfile,

else f = fopen if

(f ==

{

(ringfile,

FOPRBIN); FOPRWBIWN);

NULL)

fprintf (pgpout, LANG ('\n\007Can’t return

open key ring file

’%s’\n"),

ringfile);

-1;

pk = pklist; while ((status if it (status

= readkpacket

==

—Selilesitatus!

(f,

&ctb,

userid,

keyID,

sigkeyID))

=-a—o)

break;

if

(status

< 0

|| is_ctb_type

(ctb,

CTB_CERT_SECKEY_TYPE) )

!= -1)

*/

/*

File:

‘keymaint.c’

¥*/

/*

skip = 1; continue;

if (skip) if

(is_ctb_type skip = 0;

(ctb,

CTB_CERT_PUBKEY_TYPE) )

else continue;

if (is_ctb_type (ctb, CTB_CERT_PUBKEY_TYPE) | | is_ctb_type (ctb, CTB_SKE_TYPE) || ctb == CTB_USERID) trust_pos = ftell (f); pete if (read_trust (f, &kc_orig) < 0) t status

if

=

ERR_NOTRUST;

Cisictb type

continue; /* skip else

(ctb,

compr.

CIB_SKE_TYPE) )

cert.

*/

break;

+

}

switch

(ctb_type

(ctb))

% case

CTB_CERT_PUBKEY_TYPE:

assert assert

(pk && !memcmp ('!sig && !id);

(pk->pk_keyid,

keyID,

KEYFRAGSIZE));

id = pk->pk_userids; kc_new = pk->pk_owntrust ; #ifdef DEBUG

if (mverbose) Sprintt-(pgpout,-

"9

------—

#endif pk = pk->pk_next; mask = KC_OWNERTRUST_MASK

%a\n",

pk->pk_depth);

| KC_BUCKSTOP;

break; case CTB_USERID_TYPE:

assert (id && !sig); sig = id->uid_signatures; compute_legit (id); kc_new = id->uid_legit; #ifdef DEBUG

if (mverbose) fprintf (pgpout, "%c 402x %02x » > + (kc_new != kc_orig), kc_orig, #endif id

=

mask

kc_new,

id->uid_next;

= KC_LEGIT_MASK;

s\n",

id->uid_userid);

425

#/

/*

426

*/



/*

PGP

Source

Code

and

break;

case

CTB_SKE_TYPE:

assert assert

(sig); (!memcmp

(sig->sig_from->pk_keyid,

sigkeyID,

KEYFRAGSIZE) );

kc_new = sig->sig_trust; #ifdef DEBUG

if (mverbose && sig->sig_from->pk_userids) fprintf (pgpout, "Ac %02x 02x 4s\n", » 2? + (kc_new != kc_orig), kc_orig,

Kc_new,

sig->sig_from->pk_userids->uid_userid)

#endif sig = sig->sig_next; mask = KC_SIGTRUST_MASK break; default: mask

}

=

| KC_CONTIG;

0;

if ((kc_new & mask)

!= (kc_orig & mask))

if (!check_only) write_trust_pos

(f,

kc_new,

trust_pos);

++changed; i fcloseu (lr if (status < -1) return

eee

/* -1

is OK,

[esig

fprintf cecheamgn

(pgpout,

"maint_final:

al?

changed;

} /* maint_final

*/

/*

maint_list */ int

maint_list { int

FILE char byte

(char *ringfile)

status;

*f; userid[256]; keyID[KEYFRAGSIZE] ;

byte sigkeyID[KEYFRAGSIZE] ; char

*/

lil-id)

} return

EOF

status;

*signator;

char tchar = 0; byte ctb, kc; int owntrust = 0; int usercount = 0;

internal

error\n") ;

;

Internals

*/

/*

File:

‘keymaint.c’

aria = fopen

fprintf LANG

+*/

(ringfile,

FOPRBIN))

== NULL)

(pgpout, ("\n\007Can’t

return

/*

open key ring file

’%s’\n"),

ringfile);

-1;

} Inite crust 1sts) setkrent (ringfile); init_userhash

fprintf ces

();

(pgpout, ((status

if (status

LANG

("

KeyID

= readkpacket

==

-3

Trust

(f,

|| status

&ctb,

Validity

userid,

keyID,

User

ID\n"));

sigkeyID))

== -2)

break;

if (status continue;

< 0)

if (is_ctb_type

is_ctb_type

(ctb,

(ctb,

CTB_CERT_PUBKEY_TYPE) ||

CTB_SKE_TYPE)

|| ctb == CTB_USERID)

{ Tt

Gneadmtais

techn &kc)

= 0 && getc if (pktlen != -1)

x

(sec_fp)

== getc

(floppy_fp));

fprintf (pgpout, LANG ('"'\n\OO7WARNING: Secret key for: \"%s\"\n\ does not match the key in the backup keyring ’%s’.\n"), LOCAL_CHARSET (userid), floppyring); fprintf (pgpout, LANG ("This is a serious condition, indicating possible keyring tampering. \n")); status

}

=

—2;

}

+ ex:

}

fseek return

(f,

savepos,

status;

SEEK_SET);

} /* check_secretkey /* * setup

tables

= 0) (f,

&ctb,

userid,

NULL,

NULL))

!= -1

(ctbe=—iGlBaUSER IED)

fprintf (pgpout, "%s\n", LOCAL_CHARSET fseek (f, filepos, SEEK_SET);

(userid) );

return;

fprintf fseek

(pgpout, (f,

"(KeyID:

filepos,

%s)\n",

keyIDstring

(keyID));

SEEK_SET);

} /* show_userid */ /*

* messages printed by show_key() */ static char *owntrust_msg[] = i uu

/* Just

_LANG

("This

don’t

user

wu /* reserved wi | /* reserved

LANG LANG -LANG

static

("This ("This ("This

say

anything

is untrusted

in this

case

to certify

*/

other

keys.\n"),

*/ */

user is generally trusted to certify other keys.\n"), user is completely trusted to certify other keys.\n"), axiomatic key is ultimately trusted to certify other keys.\n"),

char *keylegit_msg[]

=

*/

/*

File:

‘keymaint.c’

¥*/

/*

a -LANG -LANG -LANG

("This ("This ("This

key/userID key/userID key/userID

association association association

is not certified.\n"), is not certified.\n"), is marginally certified.\n"),

-LANG

("This

key/userID

association

is fully

static il

char *sigtrust_msg[] Questionable

certified.\n"),

=

_LANG

(""

_LANG _LANG uu /* uu /* _LANG

("" Questionable certification from:\n "), (""| Untrusted certification from:\n "), reserved */ reserved */ ("" Generally trusted certification from:\n

certification

from:\n

."),

_LANG _LANG

("" ("|

"), Completely trusted certification from:\n "), Axiomatically trusted certification from:\n "),

ime —*

show the key in file f at file position keypos. *what’ controls the info that will be shown: SHOW_TRUST: show trust byte info SHOW_SIGS: show signatures SHOW_HASH: show key fingerprint these

constants

can

be

or’ed

*what’ can also be SHOW_LISTFMT to get the same format no signatures or extra userids will be printed in this

*what’

can be SHOW_CHANGE,

in which

case

it will

HH HEH He HE eee call show_update();

int show_key

(FILE

* f,

long keypos,

int

what)

{ int

status,

keystatus

=

-1;

long filepos; char userid[256]; unit

n[MAX_UNIT_PRECISION] , e[MAX_UNIT_PRECISION] ;

byte

sigkeyID[KEYFRAGSIZE];

word32

byte int int

timestamp;

ctb,

keyctb

= 0, keyctrl;

userids = 0; keyids = 0;

byte savekeyID[KEYFRAGSIZE] ; boolean print_trust = FALSE;

byte hash[16] ;

take

as for case.

pgp

the keyID

-kv

and

435

*/

436

/*

*/



/*

PGP

Source

Code

and

Internals

int precision = global_precision; int compromised = 0; int

disabled

filepos

=

0;

= ftell

(f);

fseek

(f,

keypos,

while

((status

= readkeypacket

SEEK_SET) ;

e,

NULL,

NULL,

==

|| status

(f, FALSE,

&ctb,

(byte *) & timestamp,

userid,

n,

{

NULL,

if

(status

-2

if

(is_key_ctb

NULL,

sigkeyID,

==

&keyctrl))

!= -1)

-3)

break;

(ctb))

{ if (keyids) break; extract_keyID (savekeyID, n); keyidstt+; if (what & SHOW_HASH) getKeyHash (hash, n, e); keyctb = ctb; keystatus = status; /* remember else

if

(ctb

==

status,

could

=

error

trust

*/

CTB_KEYCTRL)

/* trust bytes only in public keyrings */ if (keystatus >= 0 && !userids) /* key packet if (keyctrl & KC_DISABLED) disabled

be version

1;

if (what & SHOW_TRUST) print_trust

else

if

if

(userids

= TRUE;

(ctb

==

PascalToC

==

CTB_USERID)

0)

(userid);

/* for display

*/

++userids; if

(what

show_update

& SHOW_CHANGE)

(key2IDstring

(n));

break;

if if

(what

& SHOW_LISTFMT)

(is_ctb_type

(keyctb,

CTB_CERT_PUBKEY_TYPE) )

byte

*/

*/

/*

File:

‘keymaint.c’

*/

fprintf (pgpout, "pub"); else if (is_ctb_type (keyctb, fprintf (pgpout, "sec"); else fprintt.(pgpout, “??77""); if (keystatus < 0) fprintf (pgpout, "7 "); else if (compromised) fprintf (pgpout, "# "); else if (disabled) fprintt (pgpout, "—- ");

/*

CTB_CERT_SECKEY_TYPE))

else

fpeinté (pgpour, ‘”) fprintt (pepoute'4a7 isiiisaey countbits (n), key2IDstring (n), cdate (×tamp)); fprintf (pgpout, "%s\n", LOCAL_CHARSET (userid)); break; /* only print default userid */

I fprintf

(pgpout,

LOCAL_CHARSET

LANG

("\nKey

for user

ID:

%s\n"),

(userid) );

fprintf (pgpout, LANG ("%d-bit key, Key ID %s, created %s\n"), countbits (n), key2IDstring (n), cdate (×tamp)) ; if (keystatus == -4) fprintf (pgpout, LANG ("Bad key format.\n")); else if (keystatus == -6) fprintf (pgpout, LANG ("Unrecognized version. \n")); else

if

(what

& SHOW_HASH)

printKeyHash (hash, FALSE); if (compromised) fprintf (pgpout, LANG ("Key has been revoked.\n")) ; if

(disabled)

fprintf (pgpout, LANG if (print_trust fprintf (pgpout, LANG }

("Key is disabled.\n")); && *owntrust_msg[TRUST_LEV (keyctrl1)] (owntrust_msg[TRUST_LEV (keyctrl)]));

!= ’\0’)

else

£ PascalToC

(userid);

if (what != 0) fprintf (pgpout, “\n"); fprintf (pgpout, LANG LOCAL_CHARSET

("Also

known

as:

%s\n"),

(userid) );

if (print_trust) read_trust

fprintf

(f,

} /* print_trust else

&keyctrl);

(pgpout,

LANG

(keylegit_msg[keyctrl

*/

if (is_ctb_type

(ctb,

CTB_SKE_TYPE) )

& KC_LEGIT_MASK]));

437

+/

/*

438

if

*/

/*

(userids

==

compromised

if

PGP

Source

Code

and

Internals

0)

1; & SHOW_CHANGE)

(what

=

show_update

(key2IDstring

(n));

break;

if

(what

if

& SHOW_SIGS)

if (print_trust)

read_trust

fprintf

(f, &keyctrl);

(pgpout,

LANG

(sigtrust_msg[TRUST_LEV

(pgpout,

LANG

("

(keyctr1)]));

else

fprintf

show_userid

Certified

by:

"));

(f, sigkeyID);

3 o; if

(status status

==

=

-1 && userids)

0;

if (!userids { status

&&

=

!compromised

&& (what

!= SHOW_CHANGE))

-1;

fprintf (pgpout, LANG ("\nWarning: keyid 44d/%s %4s has no user countbits (n), keyIDstring (savekeyID), cdate (×tamp));

} set_precision fseek return

(f,

(precision);

filepos,

SEEK_SET) ;

status;

} /* show_key

*/

/* show_update -- this function just prints * pgpout to inform the user that an update

+/

an update happened.

message

/*

show_update */ void

show_update (char *s) { fprintf (pgpout, "Updated keyID:

Ox%s\n",

s);

/*

* stripped

down

version

of readkeypacket(),

the

output

userid

to

id!\n"),

*/

/*

File:

‘keymaint.c’

* is a null */

terminated i

¥*/

/*

string.

/*

readkpacket +7 int readkpacket

(FILE

* f, byte

byte * keyID,

* ctb,

char

*userid,

byte * sigkeyID)

int status; unit n[MAX_UNIT_PRECISION] , e[MAX_UNIT_PRECISION] ; status

= readkeypacket (f, FALSE, ctb, NULL, NULL, NULL, NULL, NULL, sigkeyID, NULL);

if

(status

userid,

n,

e,

< 0)

5! #ifdef

DEBUG

if (status fprintf (stderr,

< =1) "readkeypacket

returned

%d\n",

status);

f at file

position

#Hendif return

status;

}

if (keyID && is_key_ctb (*ctb)) extract_keyID (keyID, n); if

(userid

&&

PascalToC return

*ctb

CTB_USERID)

0;

} /* readkpacket /* * write

==

(userid);

trust

*/

byte

"keyctrl"

to file

*/ /*

write_trust_pos £7, void

write_trust_pos

(FILE * f, byte keyctrl,

long fpos;

fpos = ftell (f); fseek (f, pos, SEEK_SET);

write_trust fseek

(f,

(f, keyctrl);

fpos,

SEEK_SET);

} /* write_trust_pos /*

*/

long pos)

"pos"

439

*/

/*

440

* * * *

*/

/*

PGP

Source

read a trust byte packet from file f, the trust byte will be stored in "keyctrl". returns -1 on EOF, -3 on corrupt input, and ERR_NOTRUST if the packet was not a trust byte (this can be used to check if

* a file * The

is a keyring

current

file

(with trust

position

bytes)

is left

or a keyfile).

unchanged

in this

case.

/*

read_trust */ int read_trust

{,

Code

(FILE * f, byte

unsigned sae

* keyctrl)

char buf[3];

(Gueceyel

(eee,

return

ol, 3,

22)

TS &))

-1;

Tepe@buct LON

m=mGLBEKEVGERI)

f if (isictb

(buf [0l))

fseek (f, -3L, SEEK_CUR); return ERR_NOTRUST;

as else

return

-3;

/* bad

3

if (buf[i] return

data

*/

!= 1) /* length must be 1 */ -3;

if (keyctrl) *keyctrl = buf[2]; return

0;

} /* read_trust

*/

/**¥**#**

userid

lookup

#define

HASH_ALLOC

KK

/

(ALLOC_UNIT (char

/ sizeof(struct

static

char

*store_str

static static

VOID void

*allocbuf (int size); freebufpool ();

static

struct

hashent

{ struct

hashent

*next;

byte keyID[KEYFRAGSIZE] ; char

*userid;

ap **hashtbl

=

NULL,

*hashptr;

*str);

hashent))

and

Internals

#/

/*

File:

‘keymaint.c’

static

char

static static static

int int int

¥*/

/*

*strptr; strleft = 0; hashleft = 0 nleft = 0;

#define MAXKR 8 /* max. number static char *krnames[MAXKR] ; static

nkr

int

/* * Lookup

=

userid

*/

of keyrings

for user_from_keyID()

*/

0;

by keyID

without

using

the

in-memory

hash

table.

/*

_user_from_keyID +*/ static

char

*

_user_from_keyID

(byte * srch_keyID)

af FILE int

*f; i,

status,

found = 0;

byte keyID [KEYFRAGSIZE] ; static byte

char userid[256];

ctb;

/* search for

all keyfiles

(i = 0;

!found

if ((f = fopen continue; while


next) if (memcmp (keyID, p->keyID, KEYFRAGSIZE) == 0) return return

p->userid;

NULL;

} /* user_from_keyID /* * add

keyfile

* the

hash

to

*/

userid

hash

table,

userids

table.

*/ /*

setkrent +/ int

setkrent af mB

(char *keyring)

abe

assert

(nkr

< MAXKR);

if (keyring == NULL) keyring = globalPubringName; were (ai S Oe a & meee ersi)) if (strcmp (keyring, krnames[i])

==

return 0; /* duplicate name */ krnames[nkr++] = store_str (keyring); return

0;

} /* setkrent

*/

/*

endkrent */ void

endkrent

(void)

hashleft

hashtbl nkr

=

=

=

strleft NULL;

0;

freebufpool

();

=

0;

0)

are

added,

endkrent()

clears

*/

/*

File:

‘keymaint.c’

} /* endkrent

¥*/

/*

*/

/*

-

5

ae:

userid

hash

table,

read

all

files

set

with

setkrent()

*

/*

anit -userhash ok

int

init_userhash “

(void)

FILE *f; Ante sicabils

aes

byte keyID[KEYFRAGSIZE] ; char userid[256] ; byte ctb; int keyflag;

if (!hashtb1) ‘ hashtbl = allocbuf (PK_HASHSIZE memset (hashtbl, 0, PK_HASHSIZE foreG

—s07mie
keyID, keyID, KEYFRAGSIZE) ; hashptr->userid = store_str (userid); hashptr->next = hashtbl[PK_HASH (keyID)]; hashtb1[PK_HASH (keyID)] = hashptr; +thashptr; --hashleft;

keyflag

= 0;

} F

keyID,

if (!hashleft)

hashleft

Hs

= readkpacket

fclose ts return

0;

(f);

NULL))

!= -1)

443

#7),

/*

444

+*/

/*

} /* init_userhash /* * memory

PGP

Source

Code

and

Internals

*/

management

routines

*/ /*

maint_init_mem */ static

void

maint_init_mem

pkhash memset

(void)

= allocbuf (PK_HASHSIZE (pkhash, 0, PK_HASHSIZE

* sizeof * sizeof

(struct (struct

pubkey pubkey

*)); *));

/*

maint_release_mem */ static

void

maint_release_mem i nleft = strleft

(void)

0; =

pkhash = N LL; freebufpoo Hqo (

i; /*

* allocn() does * of ALLOC_UNIT */

the same as malloc(). Memory is allocated in chunks bytes, all memory can be freed by calling freebufpool().

/*

allocn */ static

VOID

*

allocn {

(int

size)

static

#ifndef size = #endif assert

if

char

MSDOS

*ptr;

/* don’t

align on MSDOS

(size

+ 3) & “3;

(size

< ALLOC_UNIT);

(size

> nleft)

{

ptr = allocbuf nleft

=

} nleft

ptr

+=

-=

(ALLOC_UNIT);

ALLOC_UNIT;

size; size;

to save memory

*/

*/

/*

File:

return

‘keymaint.c’

ptr -

} /* allocn

*/

/*

size;

*/

/*

i

apace

does

the

same

as

strdup(),

but

allocates

*

memory

with

allocbuf()

/*

store_str */ static

char

store_str

*

(char

‘.

int

size

if

(size

= strlen

fprintf (size

(stderr,

= allocbuf

strcpy

(strptr, += -=

str);

size;

strptr

struct

char

(ALLOC_UNIT);

size; -

} /* store_str

struct

string too long\n");

= ALLOC_UNIT;

strptr

static

"store_str:

> strleft)

strptr

strleft

+ 1;

NULL;

strleft

return

(str)

> ALLOC_UNIT)

return

If

*str)

bufpool

bufpool

buf[1];

size;

*/

*next;

/* variable

size

*/

J *bufpool long

= NULL;

totalsize

/* * allocate

* freed

= 0;

buffer,

with

one

all

call

*/ /*

allocbuf */ static

VOID

allocbuf

*

(int

size)

{ struct

bufpool

*p;

buffers

allocated

to freebufpool()

with

this

function

can

be

445

*/

/*

446

*/

/*

p = xmalloc (size + sizeof totalsize += size; p->next = bufpool; bufpool = p; return p->buf;

} /* allocbuf

(struct

bufpool

PGP

Source

Code

*));

*/

/*

* free all memory */

obtained

with

allocbuf()

/*

freebufpool */ static

void

freebufpool

(void)

“ struct

if

bufpool

*p;

(verbose) fprintf (pgpout,

totalsize

while

=

"\nMemory used:

0;

(bufpool)

3! p =

bufpool;

bufpool

free nleft

=

= bufpool->next ;

(p); strleft

} /* freebufpool

=

*/

hashleft

=

0;

%ldk\n",

totalsize

/ 1024);

and

Internals

*/

/*

File:

‘keymgmt.h’

/* File:

*/

/*

‘keymgmt.h’

447

*/

/* (New File) */ Lethe

- headers

for keymgmt.c

*

/*

Return

printable

public

key fragment.

+*/

char *keyIDstring (byte * keyID); char *key2IDstring (unitptr n); extern

char

const

blankkeyID[];

/* Do an RSA key pair generation, int

dokeygen

/* Edit

the

(char

*numstr,

userid

and/or

into the ring files

int

dokeyedit

(char

*/

and write

char

*numstr2,

pass phrase

*mcguffin,

char

for

them out to the keyring files. char

*/

*username) ;

an RSA key pair,

and put them

back

*ringfile);

/* Copy the first entry in key ring that has mcguffin string in userid and put it into keyfile */ int extract_from_keyring (char *mcguffin, char *keyfile, char *ringfile, boolean transflag);

/* Lists int

all

entries

view_keyring

boolean

in keyring that have mcguffin string

(char

*mcguffin,

show_signatures,

boolean

char

in userid

*/

*ringfile,

show_hashes);

/* Signature-check all entries in keyring that have mcguffin string in userid */ int dokeycheck (char *mcguffin, char *ringfile, int options) ;

/* options: #define #define

/* Allow int

*/

CHECK_ALL CHECK_NEW

user

0 /* Check all signatures */ 1 /* Only check new signatures

to remove

remove_sigs

(char

signatures

*mcguffin,

*/

from keys in keyring that have mcguffin

char

*ringfile);

/* Remove the first entry in key ring that has mcguffin int remove_from_keyring (byte * keyID, char *mcguffin,

char

*ringfile,

boolean

string

in userid

secring_too) ;

/* Extract key fragment from modulus n */ void extract_keyID (byteptr keyID, unitptr n);

/* Write message prefix keyID to a file void writekeyID (unitptr n, FILE * f);

*/

/* Extract public key corresponding to keyID or userid int getpublickey (int flags, char *keyfile, long *file_position, int *pktlen, byte * keyID, byte

* timestamp,

byte

* userid,

unitptr

n,

from

keyfile

*/

*/

*/

a)

/*

448

*/

unitptr

/* flags:

/*

PGP

Source

Internals

e);

GPK_SECRET

/* Extract

32 /* We are

actually

getting

*/

a secret

key */

private key corresponding to keyID or userid from keyfile

int getsecretkey (int flags, char *keyfile, byte byte * hpass, boolean * hkey, byte * userid, unitptr

and

*/

#define GPK_GIVEUP 1 #define GPK_SHOW 2 #define GPK_NORVK 4 #define GPK_DISABLED 8 /* Flag used in getsecretkey() only - should it be GSK_? /* Prevents use of existing password list. */ #define GPK_ASKPASS 16 #define

Code

n,

unitptr

e,

unitptr

d, unitptr

p,

* pe

unitptr

q,

in a keyring

*/

byte

*/

* timestamp,

unitptr wu); /* Return true int is_key_ctb

if ctb is one (byte ctb);

for

/* Read next key packet from * the file pointer to point

a key

file f, return its ctb beyond the key packet.

in *pctb,

and

advance

sal short

nextkeypacket

/* Read

the

* pointers.

next

(FILE

key

Most

* f, byte

packet

from

pointers

can

* pctb);

file

f,

be NULL

return

without

info

about

breaking

it

in

the

various

it.

*/ struct

short

IdeaCfbContext;

readkeypacket byte

(FILE

* timestamp,

* f,

char

struct

IdeaCfbContext

unitptr n, unitptr e, unitptr d, unitptr byte * sigkeyID, byte * keyctrl); /* Starting at key_position * matches C string userid. getpubuserid

long

(char

*keyfile,

*userid_position,

byte

p,

unitptr

q, unitptr

int

long key_position,

*userid_len,

boolean

byte

void getKeyHash (byte * hash, unitptr n, unitptr e); void printKeyHash (byteptr hash, boolean indent);

int

int

is_compromised

disable_key

(char

*,

(FILE * f); char

*);

u, which

* userid,

exact_match);

int getpubusersig (char *keyfile, long user_position, byte byte * timestamp, long *sig_position, int *sig_len);

extern

* pctb,

in keyfile, scan for the userid packet Return the packet position and size.

a7,

int

*cfb,

*userid,

* sigkeyID,

*/

/*

File:

‘keymgmt.c’

/* File:

¥*/

/*

‘keymgmt.c’

*/

/* (New File) */ /*

keymgmt.c - Key management routines for PGP. Pretty Good(tm) Privacy - public key cryptography

PGP:

(c) The of

for the

masses.

Copyright 1990-1994 by Philip Zimmermann. All rights reserved. author assumes no liability for damages resulting from the use this

software,

software.

even

No warranty

if

the

damage

is expressed

results

or

from

defects

in this

implied.

Note that while most PGP source modules bear Philip Zimmermann’s copyright notice, many of them have been revised or entirely written by contributors who frequently failed to put their names in their code. Code that has been incorporated into PGP from other authors Was either originally published in the public domain or is used with permission from the various authors. PGP

is available

for

See the PGP User’s important certain

free

Guide

information

algorithms,

to the

public

(included

about

licensing,

trademarks,

under

certain

in the release patent

copyrights,

restrictions.

package)

restrictions

and

export

for on

controls.

#7 #include #include #ifdef UNIX

#include

#endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include

"system.h" "mpilib.h" "random.h" ''crypto.h" ''fileio.h" '"keymgmt.h" "rsagen.h" ''mpiio.h" "language.h" "pgp.h" ''md5.h" "'charset.h" "keymaint.h" "idea.h"

/* #* ** **

*/

Convert to or from external byte order. Note that convert_byteorder does nothing is the same as the internal byteorder.

if the

external

byteorder

449

*/

/*

450

*/

:

#define

convert2(x,lx)

#define

convert(x)

* check * * * *

/*

convert_byteorder(

convert2(

if userid matches

(x),

the

Source

(byteptr)&(x),

sizeof(x)

substring,

PGP

Code

(1x)

and Internals

)

)

magic

characters

can be used to match start and end of userid. if n is NULL, only return TRUE if substr is an exact userid, a substring does not match in this case. the comparison is always case insensitive

~ and

match

$

of

*/

/*

BASS el {Hessel *

static boolean userid_match (char

*userid,

char

*substr,

unitptr

n)

sf boolean match_end = FALSE; int id_len, sub_len, i;

char buf[256],

if (substr return

if

*p;

NULL

|| *substr

==

’\0’)

NULL

|| *userid

==

’\0’)

TRUE;

(userid return

==

sub[256],

==

FALSE;

/* Check whether we have an ASCII af Gm '= NULL && substr[0] == °02 { userid = key2IDstring (n); Hilo sige a=

or hex userID to check for && to_lower (substrfil|) ==

Ae

iP id_len = strlen (userid); for (i = 0; i =10?

*/

i1-—)

sprintf (bufptr, bufptr += 2;

"%02X",

keyID[i]);

#else

/* MSB-first for

if

keyID

format

(i = KEYFRAGSIZE

-

sprintf

"%02X",

(bufptr,

bufptr

#endif *bufptr return

=

+=

4;

*/ i < KEYFRAGSIZE;

i++)

keyID[i]);

2;

’\0’;

keyIDbuf;

} /* keyIDstring */

/*

extract_keyID

*/

void extract_keyID (byteptr keyID, unitptr n) /* * Extract key fragment from modulus n. keyID * at least KEYFRAGSIZE bytes long.

{

byte

array

must

lf

byte buf [MAX_BYTE_PRECISION SHOTt Mel;

+ 2];

£1110 (buf, KEYFRAGSIZE + 2); /* in case n is too reg2mpi (buf, n); /* MUST be at least KEYFRAGSIZE #ifdef

XLOWFIRST

i = reg2mpi

(buf,

n);

/* MUST

be

at least

KEYFRAGSIZE

/* For LSB-first keyID format, start of keyID is: i = 2; /* skip over the 2 bytes of bitcount */

for (j = 0; j < KEYFRAGSIZE;) keyID[jt++] Helse

short */ long */

= buf [i++];

*/

long

*/

be

and Internals

*/

/*

File:

‘keymgmt.c’

¥*/

/*

i = reg2mpi (buf, n); /* MUST be at least KEYFRAGSIZE /* For MSB-first keyID format, start of keyID is: */ i =

i+

2 -

KEYFRAGSIZE;

for (j = 0; j < KEYFRAGSIZE;)

long

*/

4

= buf[it++];

keyID[j++] #tendif

} /* extract_keyID

*/

/*

key2IDstring a7 char

*

key2IDstring /*

{

(unitptr n)

Derive the key abbreviation fragment from and return printable string of key ID. n is key modulus from which to extract keyID.

the modulus

n,

MAX_KEYCERT_LENGTH

&&

-

detected

*/

certificate

length */

3)

/* bad length */ = ftell

(f) + cert_length;

/* * skip packet and return, keeps us in sync when we hit a * version error or bad data. Implemented oddly to make it * only one statement. */ #define SKIP_RETURN(x) return fseek(f, next_packet, SEEK_SET), if

(ctb

==

CTB_USERID)

it

if (cert_length > 255)

*/

*/

lis_ctb_type

return

CTB

(ctb != CTB_CERT_SECKEY) != CTB_KEYCTRL) &&

!is_ctb_type

cert_length

*/

certificate

eof */

type

/* Either bad key packet or X/Ymodem TeGhatan, (eine) == OGY) 7 —al 2g Ws

if

key

x

u,

*/

/*

File:

return

‘keymgmt.c’

¥*/

/*

-3; /* Bad Monge, error ot (userid)

*/

userid[0] = cert_length; /* Save user ID length */ fread (userid + 1, 1, cert_length, f); /* read rest

of user

}

ID */

else

fseek

(f,

(long)

return

iF else 4

if

if

cert_length,

0; /* normal

(is_ctb_type

SEEK_CUR);

return

(ctb,

*/

CTB_SKE_TYPE))

(sigkeyID)

fread (&version, 1, 1, f); /* Read version of sig packet if (version_byte_error (version) ) SKIP_RETURN (-6); /* Need a later version */ /* Skip

timestamp,

fread

(&mdlen,

fseek

(f,

/* Read fread

validity

period,

and type

byte

*/

*/

1, 1, f);

(long)

mdlen,

and return

(sigkeyID,

SKIP_RETURN

SEEK_CUR);

KEY ID */

1, KEYFRAGSIZE,

(0);

/* normal

f);

return

*/

else if (ctb == CTB_KEYCTRL) f return

if (cert_length != 1) -3; /* Bad length error if (keyctr1l)

fread

(keyctrl,

1, cert_length,

*/ f);

/* Read key control

byte

*/

else

fseek

(f, (long) cert_length, SEEK_CUR); return 0; /* normal return */

a else

if

(!is_key_ctb

SKIP_RETURN

(0);

/* Here we have if

(n

/* comment

a key packet

return

or other packet

*/

*/

*/

!= NULL)

set_precision fread

(ctb))

/* normal

(Xversion,

Sete UNIT_PRECISION); 1,

1, f);

/* read

if (version_byte_error (version) ) SKIP_RETURN (-6); /* Need a later if (timestamp)

/* safest

and

check

version

opening assumption

version

*/

*/

*/

459

*/,

/*

460

+*/

fread

/*

(timestamp,

timestamp

1, SIZEOF_TIMESTAMP,

f);

Source

/* read

Code

and

Internals

certificate

*/

convert_byteorder

external

PGP

(timestamp,

SIZEOF_TIMESTAMP);

/* convert

from

form */

else

t fseek

fread

(f,

(long)

(&validity,

SIZEOF_TIMESTAMP,

1, sizeof

SEEK_CUR);

(validity),

£);

/* Read

validity

period

*/

key material...

*/

convert (validity); /* convert from external byteorder /* We don’t use validity period yet */ freads(alg,015.15

2);

if (version_error

(alg,

RSA_ALGORITHM_BYTE) )

SKIP_RETURN (-6); /* Need a later version /*** End certificate header fields ***/ /* We’re

past

cert_length

certificate

-=

(read_mpi

Ga,

if

that

(d ==

WNiIA,

(e,

-=

INE)

/* data

precision

(read_mpi

if

a2,

(-4);

SKIP_RETURN cert_length

look

*/

at

some

+ 2 + 1;

data */

(0);

SKIP_RETURN

/* Note

now

/* Skip key certificate

SKIP_RETURN if

headers,

1 + SIZEOF_TIMESTAMP

if (n == NULL)

*/

f,

(-4);

was

FALSE,


0);

("(No changes will be made.)\n"));

/* init CFB IDEA key */ if (hidekey) it }

*/

= TRUE;

fprintf (pgpout, LANG if (getyesno (’n’))

goto

string

TRUE;

ideakey);

(y/N)?

"));

/*

File:

‘keymgmt.c’

¥*/

/*

/* First write secret key data to a file */ fname = tempfile (TMP_TMPDIR | TMP_WIPE); writekeyfile (fname, useridpengsee,=d; p,q;

if (hidekey)

hidekey i);

? &cfb

: 0, timestamp,

/* done with IDEA to protect

ideaCfbDestroy

RSA secret

key */

(&cfb);

if (changeID)

x keylen’=

+1);

/* don’t

copy userid */-

else

£

f = fopen if (f == err;

goto

(fname,

FOPRBIN);

NULL)

nextkeypacket (f, &ctb); keylen = ftell (f); fclose (f);

if (merge_key_to_ringfile

a

fprintf goto

fprintf

(pgpout,

LANG

/* skip key packet

(fname,

secring,

{

(pgpout,

LANG

if (insert_userid

fprintf goto

}

pslength,

("\n\007Unable to update secret

keylen)

< 0)

key ring.\n"));

err;

("\nSecret

key ring updated...\n"));

/* Now write public key data to file if (changeID)

£

fps,

*/

(pgpout,

LANG

(ringfile,

*/

userid,

("\n\007Unable

fpp) < 0)

to update public key ring.\n"));

err;

fprintf

(pgpout,

LANG

("Public key ring updated.\n"));

fprintf

(pgpout,

LANG

("(No need to update public key ring)\n"));

else

rmtemp done:

mp_burn mp_burn mp_burn mp_burn

(fname);

(d); /* burn (p); (q); (u);

sensitive

data on stack

*/

505

*),

/*

506

*/

/*

mp_burn

(e);

mp_burn

(n);

return 0; /* normal return */ err: mp_burn (d); /* burn sensitive

mp_burn

(p);

mp_burn mp_burn

(q); (wu);

mp_burn

(e);

mp_burn

(n);

rmtemp

(fname);

return

-1;

/* error

} /* dokeyedit

return

data

on

stack

PGP

Source

Code

and

Internals

*/

*/

*/

/*

disable_key +/ int

disable_key { PILE «+f; byte

(char *keyguffin,

char

*keyfile)

keyctrl;

byte keyID[KEYFRAGSIZE] ; byte userid[256]; unit

n[MAX_UNIT_PRECISION] , e[MAX_UNIT_PRECISION];

long

fp;

int pktlen;

strcpy if

((char

*) userid,

keyguffin);

(getpublickey (GPK_SHOW NULL, userid, n, e) =

NULL,

in secring

*/

to permanently

revoke

your public key\n\

a secret key compromise certificate\n\ (y/8)7 “); LOCALLCHARSET ((chars*)) userid)).

if (getyesno (’n’)) compromise (keyID, ((f = fopen

NULL,

0)

*) userid);

fprintf (pgpout, LANG ("\nDo you want

return

&fp,

n);

(GPK_GIVEUP,

/* can only compromise

by issuing for \""/s\""

keyfile,

-1;

extract_keyID if

| GPK_DISABLED,

(keyfile,

keyfile); FOPRWBIN))

==

NULL)

NULL,

*/

/*

File:

‘keymgmt.c’

¥*/

/*

af fprintf (pgpout,: LANG ("\n\007Can’t return

fseek

(f,

open key ring file

’%s’\n"),

keyfile);

-1;

fp + pktlen,

SEEK_SET);

if (read_trust (f, &keyctrl) < 0) { fprintf (pgpout, LANG ("\n\007File ’%s’ is not a public keyring.\n"), keyfile); fprintf (pgpout, LANG ("You can only disable keys on your public keyring.\n")); fclose

(f);

Eecilin

a

Ip , if (keyctrl & KC_DISABLED) it fprintf (pgpout, LANG ("\nKey is already disabled.\n\ Do you want to enable this key again (y/N)? ")); keyctrl

&=

~KC_DISABLED ;

fprintf

(pgpout,

keyctrl

|= KC_DISABLED;

else

f,

A; if (!getyesno fclose

(£);

re(ahinjboainl

ule

write_trust_pos fclose (f); return

LANG

("\nDisable

this

key

(y/N)?

"));

(’n’))

(f, keyctrl;

fp + pktlen);

0;

} /* disable_key

*/

/#SSsstsStSssssSSSSSSSsSSSSSSsSSSSSSSSSSSSS

SS

SSS

SS

Ss

Ss

sssSsssssssssssssat/

/*

* * * *

*/

Do an RSA key pair generation, and write them out to the keyring files. numstr is a decimal string, the desired bitcount for the modulus n. numstr2 is a decimal string, the desired bitcount for the exponent e. username is the desired name for the key.

507

#/

/*

508

*/

/*

PGP

Source

Code

and Internals

/*

dokeygen

*/

int dokeygen

(char

*numstr,

char

*numstr2,

char

*username)

unit n[{MAX_UNIT_PRECISION] , e[MAX_UNIT_PRECISION] ; unit d(MAX_UNIT_PRECISION] , p[MAX_UNIT_PRECISION]; unit

q[MAX_UNIT_PRECISION] , u[MAX_UNIT_PRECISION] ;

char

*fname;

wordié6

iv[4];

/* for

IDEA

CFB

mode,

to

protect

RSA secret key */ byte userid[256]; short keybits, ebits; word32 tstamp; boolean hidekey; /* TRUE boolean cryptrandflag;

iff

secret

key

is

encrypted

*/

byte ideakey[16]; struct

if

IdeaCfbContext

(!numstr

1) 2) 3)

fputs 512 #768 1024

Choose

1,

|| strlen

2,

or

3,

or

enter

==

0)

desired

= (char *) userid;

getstring

(numstr,

keybits = 0; while ((*numstr

>=

’0’)

= keybits

if (keybits Tecurne

(numstr)

(LANG ("Pick your RSA key size:\n\ bits- Low commercial grade, fast but less secure\n\ bits- High commercial grade, medium speed, good security\n\ bits- \"Military\" grade, slow, highest security\n\

numstr

keybits

cfb;

1:

5, TRUE);

&&

number

/* echo

(*numstr

(keybits

== 0) /* user entered /* error return */

keybits

#ifndef

=

3S

null

/* High commercial

DEBUG

keybits

’0’); response

grade */

/* Military grade */

/* minimum RSA keysize: if (keybits < 384) = 384;

*/

"),

’9’))

-

grade */

3)

1024;

bits:

keyboard

2)

= 768;

if (keybits keybits

a

1024)

keybits

=

1024;

} else

if keybits

(keybits =

> 2048)

2048;

} #else

if (keybits > MAX_BIT_PRECISION) keybits = MAX_BIT_PRECISION; #endif

ebits = 0; /* number of bits in e */ while ((*numstr2 >= ’0’) && (*numstr2 0);

/* init CFB IDEA key */ if (hidekey)

{ ideaCfbInit

(&cfb,

ideakey) ;

trueRandAccumLater

(64);

/* IV for

encryption

/* As rsa_keygen does a major accumulation of random * any others for a seed file, let’s get them at the

a7

cryptrandflag = (cryptRandOpen if (cryptrandflag) trueRandAccumLater

fputs if

{

(LANG

(rsa_keygen

fputs

(LANG

return

-1;

PUtCEW \ne, if

("\nNote (n,

e,

((struct

*/ bits, if we same time.

IdeaCfbContext

*) 0) < 0);

(192);

that key generation d, p,

q, u,

("\n\007Keygen /* error

is a lengthy process.\n"),

keybits,

failed!\n"),

return

ebits)

< 0)

pgpout) ;

*/

pepoub)s

(verbose)

{ fprintf

(pgpout,

mp_display mp_display

fputs

(LANG

need

LANG

("" modulus ("exponent

("Display

("Key n e

bee

ID %4s\n"),

key2IDstring

(n));

rah) 2

rte) s

secret

components

(y/N)?"),

pgpout);

pgpout);

*/

/*

File:

‘keymgmt.c’

if (getyesno mp_display mp_display mp_display mp_display

¥*/

/*

©5641

(’n’))

("exponent (" prime (" prime (" inverse

d p q u

=", =", =", =",

d); p); q); u);

A; tstamp = get_timestamp fputc (’\007’, pgpout); fflush (pgpout);

(NULL);

/* Timestamp when key was generated

*/

/* sound the bell when done with lengthy process

*/

/* First, write out the secret key... */ fname = tempfile (TMP_TMPDIR | TMP_WIPE) ; writekeyfile

(fname,

mp_burn

(d);

mp_burn mp_burn

(p); (q);

mp_burn

(u);

hidekey

if (hidekey) /* done with ideaCfbDestroy (&cfb);

if (file_exists

: 0,

tstamp,

IDEA to protect

userid,

RSA secret

n,

e,

d,

p,

q,

u);

key */

(globalSecringName) )

merge_key_to_ringfile

rmtemp

? &cfb

(fname,

globalSecringName,

OL,

0,

-1L);

(fname);

else

savetemp /* Second, fname

(fname,

write

= tempfile

writekeyfile

out the public (TMP_TMPDIR

(fname,

if (file_exists {

globalSecringName) ;

NULL,

*/

tstamp,

userid,

(fname,

mp_burn

mp_burn

(e);

(n);

e,

NULL,

globalPubringName,

(fname) ;

else savetemp

n,

NULL,

NULL,

(globalPubringName) )

merge_key_to_ringfile

rmtemp

key...

| TMP_WIPE);

(fname,

globalPubringName) ;

OL,

0, -1L);

NULL) ;

+7

/*

512

*/

/*

fputs

(LANG

("\007Key

/* *

If

need

we

generation

a seed

file,

completed.\n"),

create

it now.

*/ if (cryptrandflag) { trueRandConsume

(192);

cryptRandInit ((struct IdeaCfbContext /* It will get saved by exitPGP */

} return

0; /* normal

} /* dokeygen */

return

*/

*) 0);

PGP

Source

pgpout);

Code

and

Internals

*/

/*

File:

/*

File:

‘language.h’

/* (New File) /* or *

*/

*/

/#

‘language.h’

*/

*/

language.h Include file

for PGP

foreign

language

translation

facility

/*

* Strings * into * LANG

with LANG()

around them are found by automatic

* is no string to be extracted */ extern

char

/* * Use

the

*LANG dummy

* shouldn’t

af

#define extern

tools

and put

the special text file to be translated into foreign languages. () (note the space between ’G’ and ’(’) should be used if there

macro

*s); _LANG

be processed

_LANG(x) char

(char

(eg. prototype).

~for

strings

by the LANG

that

function

should

be

(eg.

array

extracted,

but

initializers).

x

language[];

/* language

selector prefix for string file */

#8523

*/

/*

514

*/

/*

/* File:

‘language.c’

PGP

Source

Code

and

Internals

*/

/* (New File) */ /*

language.c - Foreign language translation for PGP Finds foreign language "subtitles" for English phrases in external foriegn language text file.

(c) Copyright

1990-1994

by Philip Zimmermann.

All rights reserved.

The author assumes no liability for damages resulting from the use of this software, even if the damage results from defects in this software. No warranty is expressed or implied. Note that while most PGP source modules bear Philip Zimmermann’s copyright notice, many of them have been revised or entirely written by contributors who frequently failed to put their names in their code. Code that has been incorporated into PGP from other authors was either originally published in the public domain or is used with permission from the various authors. PGP is available for free to the public under certain restrictions. See the PGP User’s Guide (included in the release package) for important information about licensing, patent restrictions on certain algorithms, trademarks, copyrights, and export controls.

*/ #include #include



#include #include



#include #include

"usuals.h" "fileio.h"

#include #include

"language.h" "pgp.h"'

#include #include

"'charset.h" "armor.h"

#define #define

SUBTITLES_FILE LANG_INDEXFILE

#define

STRBUFSIZE

char language[16]

"language.txt" "language.idx"

2048

= "en";

static

char

*strbuf;

static

char

lang[16];

/* The language

/* readstr

sets

this

code,

defaults

to the

to English */

language

id of

the msg it last read */ static static /*

int int

subtitles_available line = 0;

=

0;

subtitles_available is used to determine if we know whether the special subtitles_file exists. subtitles_available has the following values: O = first time thru, we don’t yet know if subtitles_file exists.

*/

/*

File:

1

‘language.c’

we we

1

have have

already already

¥*/

/*

determined determined

that that

subtitles_file subtitles_file

exists. does not

exist.

*/ #define #define #define #define #define #define #define

NEWLINE 0 COMMENT 1 INSTRING 2 ESCAPE 3 IDENT 4 DONE 5 ERROR 6 ERR1 7

/* Look

for

#define

*

If

and return

nlabort

* before

we

is

true,

find

the

a quoted return

string

failure

from if

we

the find

file. a blank

line

opening. quote.

*/ /*

readstr */

static char * readstr (FILE * f, Ante

char

*buf,

int

nlabort)

cead:

char +p = buf; int state = NEWLINE; Int.

15 =

while

0;

((c = getc

if

(c-=2

(f))

!= EOF)

?’\r")

continue;

/* line numbers are only if (line && c == ’\n’) ++line; SW

itch

(state)

af case NEWLINE: switch (c)

“0 case

UGE Ds

state = break; case

PGE

COMMENT;

26

state = INSTRING; break; Nn): case Sige (nlabort)

1 =

NOE:

return

buf;

*buf

i,

incremented

when

creating

index

file

*/

615

*/

/*

516

*/

/*

PGP

Source

error\n",

line);

default:

if

(i ==

008%

isalnum

(c)))

{ state

=

IDENT;

lang[i++]

= ¢;

break;

if

('!isspace

fprintf

(stderr,

state

ERROR;

=

(c)) "language.txt:%d:

ly HF break; case COMMENT:

if

(c ==

’\n’)

state = NEWLINE; break; case INSTRING:

switch

(c)

CASE

O\\?s

state = ESCAPE; break; caseu.: state = DONE; break; default: *pt++ = c; break; case

ESCAPE:

switch

(c)

\ aAsmCumilul "q"

(b)

) 9

Lovee,

> vad"

(x1)

7 "ad"

(xh)

“0

(xi)

JN

\

c #else

#if defined(__GNUC__) && defined(i386) && defined(MUNIT32) Hdetinerinul (a,b, x.,2n) asm mull ,2"s "=a" (x1) ."=d (xhjevo™

(a)i'g"

#else

#define

MUNITHMASK

(((unsigned

#ifdef MUNIT16 #define lmul(a,b,xl,xh)

long)1

\

{\ unsigned long XX = (unsigned long) x1 xhe=e

rxeeroxifrt: ke 16 N

\

(MULTUNITSIZE/2); Xbl = Xbb&MUNITHMASK; Xbh = Xbb>>(MULTUNITSIZE/2); \

Xx1 = Xal*Xbl;

\

LOD S MEE Gels Kx3) =" Xal+Xbh;

\ \

Xx4 = Xah*Xbh; KxB = Xx2+Xx3;

\ \

Xx4 += ((MULTUNIT) (Xx5 < Xx2)) (MULTUNITSIZE/2)); \ \ \ x1 xh

Xx6;

\

Xx4-

\

} #Hendif

#endif #Hendif

#Hendif #endif

/* PATCH_ASM

*/

\

\

+*/

/*

File:

‘md5.h’

/* File: MD5_H

#define

MD5_H

#ifdef

typedef #else typedef

/*

‘md5.h’

/* (New File) #ifndef

*/

*/

*/

__alpha

unsigned

int

uint32;

unsigned

long uint32;

#endif struct

MD5Context

{ uint32 buf [4]; uint32 bits[2]; unsigned char in[64];

$; void

MD5Init

(struct

MD5Context

void MD5Update unsigned len);

(struct

void MD5Final

(unsigned

void

MD5Transform

*context);

MD5Context

*context,

char digest[16],

(uint32

buf[4],

to make

RSAREF

unsigned

struct

uint32

const

char

MD5Context

const

*context);

in[16]);

/*

* This

is needed

*/ typedef

#endif

struct

/*

MD5Context

!MD5_H

*/

MD5_CTX;

happy

on some

MS-DOS

*buf,

compilers.

527

a7

/*

528

*/

/*

fee bai ve

omdsuc?

/* (New File)

PGP

Source

Code

+/

*/

es*

This code implements the MD5 message-digest algorithm. The algorithm is due to Ron Rivest. This code was written by Colin Plumb in 1993, no copyright is claimed. This

code

is

in the

public

domain;

do

with

it

what

you

wish.

Equivalent code is available from RSA Data Security, Inc. This code has been tested against that, and is equivalent, except that you don’t need to include two pages of legalese with every copy. To

compute

the

MD5Context

message

structure,

digest pass

it

of

a chunk

to

MD5Init,

of bytes, call

declare

MD5Update

needed on buffers full of bytes, and then call MD5Final, fill a supplied i6-byte array with the digest.

which

eH KN OF etwill ee HH ee

*/ #Hinclude

#include

"md5.h"

#ifndef #define

HIGHFIRST byteReverse(buf,

#else void byteReverse #ifndef

/* for memcpy()

len)

(unsigned

*/

/* Nothing

char

*buf,

*/

unsigned

longs);

ASM_MD5

/*

* Note:

this

code

is

harmless

on

little-endian

machines.

*/ /*

byteReverse £7, void

byteReverse Wants2e do

(unsigned

char *buf,

unsigned

longs)

ce

af t =

(uint32)

((unsigned)

buf[1]

s(Qhlabaigey buf

while

\; #endif #endif

+=

((unsigned)

ts) Joybee = 46

4;

(--longs) ;

buf[3]

buf[2] = Ox98badcfe;

ctx->buf [3] = 0x10325476; ctx->bits[0] = 0; Gtx=>bits [1 = 0;

> /* * Update context * of bytes.

to reflect

the

concatenation

MD5Context

*ctx,

of

another

buffer

full

*/ void MD5Update

(struct

unsigned

char

const

*buf,

WINGS 2s te

/* Update t =

$f

bitcount

ctx->bits[0];

((ctx—>bits([0] ctx->bits[1i]++;

ctx->bits[1]

t =

*/

+=

= t + C(uint32) len

(t >> 3) & Ox3f;

/* Handle

29;

/* Bytes

any leading

already

odd-sized

chunks

in shsInfo->data

*/

if (t) {

unsigned

char

te=e645—e¢

5

*p =

(unsigned

char

*) ctx->in .

ifs (iensbuf, (uint32 but len

+= -=

t; t;

*)

ctx->in);

+ t;

*/

unsigned

len)

529

*/

/*

530

*/

/* Process

/*

data

in 64-byte

while (len >= 64) { memcpy (ctx->in,

buf,

chunks

+= -=

Source

Code

and

Internals

*/

64);

byteReverse (ctx->in, 16); MD5Transform (ctx->buf, (uint32 buf len

PGP

*) ctx->in);

64; 64;

N

/* Handle memcpy

any remaining bytes of data.

(ctx->in,

buf,

*/

len);

} /* * Final wrapup * 1 0* (64-bit

- pad to 64-byte boundary with the bit count of bits processed, MSB-first)

pattern

*/ void

MD5Final

(unsigned

char digest[16],

struct

MD5Context

*ctx)

Sh unsigned unsigned

count; char *p;

/* Compute number of bytes mod 64 */ count = (ctx->bits[0] >> 3) & Ox3F; /* Set the first char of padding always at least one byte free p = ctx->in + count; *pt+ = 0x80;

/* Bytes COUN

of padding needed

te=sO40—

ela

to 0x80. */

to make

This

64 bytes

is safe

since

there

*/

eCOUNtr

/* Pad out to 56 mod it (count in, 16); MD5Transform (ctx->buf, (uint32 *) ctx->in);

/* Now fill memset

the next

(ctx->in,

0,

block 56);

with 56 bytes

*/

to

64 bytes

*/

is

*/;

/*

File:

‘md5.c’

*/

/* Pad block memset

/* Append

to 56 bytes

(p, 0,

byteReverse

count

(ctx->in,

length

((uint32 ((uint32

/*

14);

in bits

and transform

*) ctx->in)[14] *) ctx->in)[15]

MD5Transform

*/

- 8);

(ctx->buf,

*/

= ctx->bits[0]; = ctx->bits[1]; (uint32

*) ctx->in);

byteReverse ((unsigned char *) ctx->buf, memcpy (digest, ctx->buf, 16); memset

(ctx,

0,

sizeof

(ctx));

4);

/* In case

it’s

sensitive

*/

r #ifndef /* The

ASM_MD5 four

core

functions

- Fi

is optimized

somewhat

*/

pevrdetine Fi(x, y,. 2) (x & y | (3x fiz) e+/ Hdefaneshi(xy sy, 212. (x & ytgez) p> Hdefine F2(s ay, 2) Fiz, x57)

tdefine #define

F3(x, F4(x,

-y, 0

*/ #define

TLOOP(s)

#define

TLOOP1i(s)

if ((unsigned 1

if

(t)

do

TLOOPi(s)

{ s;

} while

(--t)

long) dst < (unsigned long)

src)

/*

* Copy

forward.

*/ t =

if

(int) src; ((t | (int)

/* only need low bits dst) & wmask)

*/

/*

* Try to align operands. This * unless the low bits match.

*/ if ((t ~*~ (int) t = else

dst) & wmask

length;

t = wsize - (t & wmask); length == t; TLOOP1 (*dst++ = *srct+t);

cannot

be done

|| length < wsize)

*/

539

*/

/*

540

*/

/*

PGP

Source

/*

* Copy whole

words,

then mop

up any trailing

t = length / wsize; TLOOP (*(word *) dst

= *(word

*) src;

bytes.

+i, src

+=

wsize;

dst += wsize); t = length & wmask; TLOOP (*dst++ = *srct+t);

/* * Copy backwards. * Alignment works

* (t&wmask)

bytes

+/

Otherwise as before,

to align,

essentially except that

the.same. it takes

not wsize-(t&wmask).

src += length; dst += length; teint) msnce

if ((t if ((t ~

| (int)

(int)

dst) & wmask)

dst)

& wmask

|| length 0)

defaults

*/

#endif

if

(screen_lines screen_lines

if

==

(screen_columns screen_columns

#endif

0) /* nothing

worked,

use

= DEFAULT_LINES; =

== DEFAULT_COLUMNS ;

/* UNIX */

i #ifdef

#define #define

ATARI

reverse_attr() printf("\033p") norm_attr() printf("\033q")

#else

#define #define

reverse_attr() norm_attr()

#endif

#ifdef

VMS

char pager[80] = Helse /* not VMS char pager[80] = #Hendif /* not VMS /* Blort a file terminators,

chars */

"Type/Page"; */ ""; */

/* default

more_file */ int

(char

*fileName)

FILE *inFile; intelinesu—Onmichw

long fileLen;

for VMS

*/

to the screen with page breaks, intelligent handling of line truncation of overly long lines, and zapping of illegal

/*

more_file

pager

ea charsm—mO

smc:

*/

/*

File:

char char

‘more.c’

*/

/*

547

cmd[MAX_PATH] ; buf[16];

int lineno; char *p;

if

((inFile

= fopen

/* Can’t return

tread

if

(fileName,

see how this

FOPRBIN))

could fail

==

NULL)

since we just

created

the file

*/

-1;

(but,

15.16,

inFile);

(compressSignature

((byte

*) buf)

>= 0)

4 fprintf (pgpout, LANG ("'\n\007File fileName) ; recipe

hs) is not a text ao oat

cannot

display.\n"),

als

/* PAGER set set PAGER

in config.txt in config.txt

if (pager[0]

==

a

if

file;

overrides environment variable, to ’pgp’ to use builtin pager */

’\0’)

((p = getenv

("PAGER"))

!= NULL)

strncpy (pager, p, sizeof (pager) - 1); } if (strcmp (pager, "cat") == 0) 4. fclose (inFile); writePhantomOutput (fileName); return

/* Use

0;

built-in

pager

this

currently

real

filename

if

((strcemp

a #ifdef return

fclose

anymore

(fileName,

&& (strlen

if PAGER

doesn’t

(pager)

set

or

_CONSOLE

if this

is for

your

eyes

filename

isn’t

used

as

*/

!= 0) && strcmp

!= 0)

("pgp",

(inFile);

UNIX if (strchr

(fileName,

’\’’)

!= NULL)

-1;

(cmd,

"%s

sprintf

(cmd,

"%s 4s",

(p = cmd; ’/’) +pe=2\\? ;

*p; ++p)

#ifdef

the

CONSOLE_FILENAME)

sprintf

#else

is not

work,

’%s’",

MSDOS

for if (*p == #endif #endif

fflush return

(pgpout); system (cmd);

pager,

pager,

fileName) ;

fileName) ;

pager))

only,

the

#/

548

#ifdef

*/

;

/*

PGP

Source

Code

and

UNIX

if ('isatty (fileno (stdout))) at fclose (inFile); writePhantomOutput (fileName) ; return

0;

} #Hendif

/* UNIX

*/

getScreenSize

();

/* Get file length */ fseek (inFile, OL, SEEK_END); fileLen = ftell (inFile); rewind (inFile); lineno

=

1;

ttycbreak putcharz

(); (?\n”)%

fon (% ) {

ch = getc (inFile); if (ch == LF)

lines++;

putchar

(’\n’);

chars

0;

=

++lineno;

elseuite(ch

==

CR)

lines++;

putchar

(@An”);

chars = 0; ++lineno;

/* Skip following if

((ch

= getc

ungetc

(ch,

else /* Legal

putchar lees)

LF if there

(inFile))

*/ != EOF)

or tab,

char)

print

ch >=’

’? && ch != EOF)

|| ch == TAB)

it */

(ch);

GS

(in S=

/* If we’ve

GN)

reach

@ fs} 8 als

the max.no

of columns

rest of the line */

if

ch

inFile);

if (((unsigned char

is one

!= LF &&

(chars

==

screen_columns

-

1)

we

can handle,

skip the

Internals

sil

File:

‘more.c’

chars

=

while

((ch = getc

if

*/

/*

0;

(inFile))

!= CR && ch != LF && ch

!= EOF);

(ch != EOF) ungetc (ch, inFile); /*

If

we’ve

user while

(ch ==

/* Print

prompt

reverse_attr af

a¢ch) ==

printf

reached

to hit

the

max.no

EOF

|| lines

==

at end of screen

we

can

handle,

("\nDone...hit

screen_lines

-

c = to_upper

--

%d%%

--

new

line\

any key\r"));

Hit

space

for

next

screen,

Enter

/ fileLen);

(c);

/* Blank

out prompt

*/

retope (2b

Op. al & 7S).

sins),

putcnar (7, ?)5 putchar . screen_lines)

*/

int seek_line = lineno lineno = 1; rewind (inFile);

(seek_line

-

2 * screen_lines

+ 3;

> 1)

BLinbiv, 7a Skipping \n "yi; while ((ch = getc (inFile)) (che==)\n”) if (++lineno ==

!= EOF)

seek_line)

break;

Chas Ou lines = 0; else

{ if

for

*/

( ("More

G = getch ();

goto

the

1)

norm_attr (); fflush (stdout);

if

for

mi

7Q’? to quit --\r"), (100 * ftell (inFile))

if

wait

EOF)

(LANG

en

LANG

rows

();

else

printi

of

a key */

(c ==

*Q’'

|| ch

2

[ive s2

done;

Gf (cve=

==

EOF)

*\n2el|

cee

7\r?

I -c ==

73")

549

*/

/*

550

*/

lines -= lines

/*

(c ==» */

*) ? screen_lines

PGP

Source

Code

- 2 ; 1; /* Do n more

5 } done:

ttynorm

();

fclose

(inFile);

return

0;

} /* more_file

*/

/*

* open_more()

and close_more()

redirect

pgpout

to the pager.

*

*/ static

char

static static

boolean piping = FALSE; FILE *savepgpout ;

*mfile

=

NULL;

/*

Sree

pee

*

int

open_more #ifdef char #tendif

(void)

UNIX *p;

if (mfile

|| piping)

close_more savepgpout #ifdef UNIX

fflush

= pgpout;

(pgpout) ;

if (pager[0]

{

if

strncpy ay /* Use

();

==

’\0’)

((p = getenv

(pager,

("PAGER"))

p, sizeof

built-in

pager

(pager)

if PAGER

!= NULL)

- 1); is not

set

or

set

to

if ((strlen (pager) != 0) && strcmp ("pgp", pager) ) al if ((pgpout = popen (pager, "w")) != NULL) piping

= TRUE;

return

0;

"pgp"

*/

and

Internals

*/,

/*

File:

‘more.c’

*/

perror

("popen");

Pgpout

=

/*

savepgpout ;

#endif

if ((mfile = tempfile return

(TMP_TMPDIR

| TMP_WIPE))

== NULL)

-1;

pis SO

= fopen

Pgpout

=

rmtemp

(mfile);

return

-1;

(mfile,

FOPWTXT))

== NULL)

savepgpout ;

} /* user will not see anything until close_more() fprintf (savepgpout, LANG celts a moment..."')); fflush (savepgpout); 2

}

return

0;

/*

close_more */ int

close_more (void) 7 if (!mfile && !piping) return

#ifdef

0;

UNIX

if (piping) pclose

(pgpout);

else

#endif fclose pgpout

if

=

(pgpout); savepgpout ;

(mfile)

{

fprintf

(pgpout,

more_file

rmtemp mfile

(mfile); =

NULL;

}

}

(mfile);

piping

= FALSE;

return

0;

"\n");

is called

*/

551

*/

/*

552

*/

/*

PGP

Source

Code

and

Internals

id On tet f tebasleraemp

/

/* (New File) */ /*

C include

file

for MPI

library

I/O routines

(c) Copyright 1986 by Philip Zimmermann. All rights reserved. The author assumes no liability for damages resulting from the use of this software, even if the damage results from defects in this software.

No warranty

is

expressed

or

implied.

These routines are for multiprecision arithmetic I/O functions for number-theoretic cryptographic algorithms such as ElGamal, Diffie-Hellman, Rabin, or factoring studies for.large composite numbers, as well as Rivest-Shamir-Adleman (RSA) public key cryptography. The external data representation for RSA messages and keys that some of these library routines assume is outlined in a paper by Philip Zimmermann, ''A Proposed Standard Format for RSA Cryptosystems", IEEE

Computer,

September

Some revisions was published. NOTE:

Fi

This

on

to this

assumes

mt

1986,

data

previous

rm

Vol.

format

19 No.

have

inclusion

Byte ordering

#ifdef #undef #endif

NEEDSWAP NEEDSWAP

/* make

sure

NEEDSWAP

of

Stull

/* XLOWFIRST is defined iff external file /* #define XLOWFIRST defined if external is

9,

pages

occurred

21-34.

since

the paper

"mpilib.h"'

q—q-e---—===4—-— ae */

format is LSB-first byteorder byteorder is LSB-first */ initially

undefined

*/

*/

/* Assume MSB external byte ordering */ #ifndef

HIGHFIRST

#define

NEEDSWAP

/* External/internal

byteorder

differs,

need byte swap */

#endif

word16

fetch_wordi6

/*

Fetches a 16-bit word from where byte pointer points to external-format byteorder array. */

buf

byte *put_wordi16 /*

(byte * buf);

(word16

is pointing.

w, byte * buf);

Puts a 16-bit word to where byte pointer is pointing, returns updated byte pointer. buf points to external-format byteorder array. */

word32

fetch_word32

/*

Fetches a 32-bit word from where byte pointer points to external-format byteorder array. */

buf

and

(byte * buf); is pointing.

*/

/*

File:

‘mpiio.h’

byte *put_word32

= */

(word32

/*

553

w, byte * buf);

/*

Puts a 32-bit word to where byte pointer is pointing, and returns updated byte pointer. _ buf points to external-format byteorder array. */ /* Note that convert_byteorder does nothing if internal native byteorder is already the same as external byteorder. */ #ifdef NEEDSWAP /* External/internal byteorder differs, need byte swap

#define #define

convert_byteorder(buf,bytecount) hiloswap(buf ,bytecount) mp_convert_order(r) hiloswap(r,units2bytes(global_precision) )

#else #define

convert_byteorder(buf,bytecount)

#define mp_convert_order(r) #Hendif /* not NEEDSWAP */

#include #ifdef

/* nil

/* nil statement

statement

*/

*/

*/

EMBEDDED

int putchar

(int c);

#endif /* EMBEDDED */

/* standard

C library function

from

*/

int string_length (char *s); /* Returns string length */ int str2reg

(unitptr reg,

/* Converts

a possibly-signed

Returns

assumed

radix,

string digitstr);

int display_in_base (string s, /* Display n in any base, such

of digits.

digit

derived

string

from

unitptr as base

void

(register

checksum

cbc_xor

/* Performs

number.

*/

*/

checksum

/* Returns

a large binary ’h’,’o’,b’,’.’

n, short radix); 10. Returns number

void mp_display (string s, unitptr r); /* Display register r in hex, with prefix word16

into

suffix

byteptr

of buffer.

(register unitptr the

XOR necessary

buf,

string

register

s.

*/

word16

count);

*/ dst, for

register unitptr

RSA

Cipher

Block

void hiloswap (byteptr ri, short numbytes); /* Reverses the order of bytes in an array of bytes.

src,

word16

Chaining.

bytecount);

*/

*/

short mpi2reg (register unitptr r, register byteptr buf); /* Converts to unit array from byte array with bit length prefix

word.

*/

short reg2mpi (register byteptr buf, register unitptr is /* Converts from unit array to byte array with bit length prefix word. */ ARoa end of MPI 1/0 Library Heb Ed eso

ok /

*/

/*

554

*/

/*

/* File: /* (New File) /*

PGP

Source

Code

and

Internals

iMplioa? */ */

mpiio.c - C source code for multiprecision Implemented Nov 86 by Philip Zimmermann Last revised 13 Sep 91 by PRZ

integer

I/O routines.

Boulder Software Engineering 3021 Eleventh Street Boulder, CO 80304 (303) 541-0140

(c) Copyright 1986-1994 by Philip Zimmermann. All rights reserved. The author assumes no liability for damages resulting from the use of this software, even if the damage results from defects in this software. No warranty is expressed or implied. These routines are for multiprecision arithmetic I/0 functions for number-theoretic cryptographic algorithms such as ElGamal, Diffie-Hellman, Rabin, or factoring studies for large composite

numbers,

as well

as Rivest-Shamir-Adleman

(RSA)

public

key

cryptography.

The external data representation for RSA messages and keys that some of these library routines assume is outlined in a paper by Philip Zimmermann, ''A Proposed Standard Format for RSA Cryptosystems", IEEE

Computer,

Some revisions was published.

September

to

this

1986,

data

Vol.

format

19

have

No.

9,

pages

occurred

21-34.

since

the

paper

*/ /* #define DEBUG */ #ifndef EMBEDDED /* not embedded target */

#include

EMBEDDED

/* for printf,

#else /* EMBEDDED - compiling #define NULL (VOID *)O #endif #include #include #include

static

- not

for

etc.

compiling

for

*/

embedded

target

*/

"mpilib.h" "mpiio.h" "pgp.h''

void puthexbyte

(byte b); /* Put out byte

in ASCII

static

void puthexwi6

(wordi6

high byte first.

static void putstr

(string

*/ s);

w);

/* Put out

/* Put

out

16-bit

word

null-terminated

in hex, ASCII

hex via putchar.

*/

*/

Ye

BPUVetMAE

ypiiove>

«7.

/*

string via putchar. */ [*------------—-—-- Following procedures

relate

to I/0 ------------------ */

/*

string_length */ /* Returns

string length,

just like strlen()

from

*/

int

string_length 3: intr sh = if

(char *s)

13 (08 (s != NULL)

while

(*s++)

Beery

return

(i);

} /* string_length

*/

/*

ctox */ #ifdef

DEBUG

/* Returns static

ctox

integer

0-15

if c is an ASCII

hex digit,

-1 otherwise.

*/

int

(int c)

ifeC(ce>=5702)488

(co= %a’) && (ce

*/

3)

(n)

#endif #ifdef

UNIT16

typedef typedef

wordi6 unit; short signedunit;

#define

UNITSIZE

#define

LOG_UNITSIZE

#define #define #define #define #define

uppermostbit ((unit) 0x8000) BYTES_PER_UNIT 2 /* number of bytes in a unit */ units2bits(n) ((n) 4)

#define

bytes2units(n)

16 /* number

of bits

in a unit

*/

4

(((n)+1)

>>

1)

Internals

*/

*/

typedef typedef #define

(((n)+7)

and

*/

an unusual wide, then be

multiply

algorithm

enable

16-bit

Source

*/

/*

/*** CAUTION: power of 2 (8,

#ifdef

Smith’s

/* default--use

symbol

PGP

*/

a

*/



agFilesdefmpilib.h?

»»+/

/*

569

#Hendif

#ifdef

UNIT32

typedef typedef #define

word32 unit; long signedunit; UNITSIZE 32 /* number

#define

LOG_UNITSIZE

#define #define #define

uppermostbit ((unit) 0x80000000L) BYTES_PER_UNIT 4 /* number of bytes in a unit */ units2bits(n) ((n) bytes2units(n) (((n)+3) >>

5) 2)

#define

power_of_2(b)

(b))

/*

Some

((unit)

#define bits2bytes(n)

(((n)+7)

C compilers

expressions

at

of bits

in a unit

1 > 3)

/* computes

(like the ADSP2101)

compile

time

if the

/*

bytes2units(n) BYTES_PER_UNIT

LOG_UNITSIZE

/* #define

is

the

log

UNITSIZE */

units2bytes(n)

/* #define

bytes2units(n)

/* #define bits2units(n) typedef

#ifdef

unit

always

contain

+*/ of bits

bit masks

collapse

in a unit

base

2 of

((n)

(LOG_UNITSIZE-3))

*/

((r)+(prec)-1)

make_lsbptr(r,prec) (r) = lsbptr(r,prec) unmake_lsbptr(r,prec) (r) = ((r)-(prec)+1) msbptr(r,prec) (r) make_msbptr(r,prec) /* (r) = msbptr(r,prec) macro

units

(((n)+(UNITSIZE-1)) >> LOG_UNITSIZE) */

#define tohigher(n) (-(n)) /* offset towards higher unit */ #define pre_higherunit(r) (--(r)) #define pre_lowerunit(r) (++(r)) #define post_higherunit(r) ((r)--) #define post_lowerunit(r) ((r)++) #define bit_index(n) (global_precision-bits2units((n)+1))

#define

*/

*//* fast multiply by

*unitptr;

definitions

constant

shift

HIGHFIRST

/* these

*/

bits2units((n) 3) */

units2bits(n)

/* #define

*/

power-of-2

will not

expressions

operators. */ /* #define uppermostbit power_of_2(UNITSIZE-1) /* #define UNITSIZE units2bits(1) number /* #define /* #define

*/

5

*/

rescale(r,current_precision,new_precision)

rescales

*/

*/

/*

570

*/

/*

PGP

Source

Code

and

a multiprecision integer by adjusting r and its precision to new It can be used to reverse the effects of the normalize routine given above. See the comments in normalize concerning

Intel

vs.

Motorola LSB/MSB

Internals

values.

conventions.

WARNING: You can only safely call rescale on registers that you have previously normalized with the above normalize routine, or are known to be big enough for the new precision. You may specify a new precision that is smaller than the current precision. You must be careful not to specify a new_precision value that is too big, or which adjusts the r pointer out of range.

*/

#define

rescale(r,currentp,newp)

r -=

((newp)

-

(currentp))

/* The macro normalize(r,precision) "normalizes" a multiprecision integer by adjusting r and precision to new values. For Motorola-style processors (MSB-first), r is a pointer to the MSB of the register, and must be adjusted to point to the first nonzero unit. For Intel/VAX-style (LSB-first) processors, r is a pointer to the LSB of the register, and must be left unchanged. The precision counter is always adjusted, regardless of processor type. In the case of precision = 0, r becomes undefined.

*/ #define

normalize(r,prec)

\

{ prec = significance(r); #Helse

/* LOWFIRST

/* these

byte

definitions

r +=

order

assume

(global_precision-(prec));

*/

LSB

comes

first

*/

#define #define #define #define #define #define #define

tohigher(n) (n) /* offset towards higher unit pre_higherunit(r) (++(r)) pre_lowerunit(r) (--(r)) post_higherunit(r) ((r)++) post_lowerunit(r) ((r)--) bit_index(n) (bits2units((n)+1)-1) lsbptr(r,prec) (r)

#define

make_lsbptr(r,prec)

#define #define #define

unmake_lsbptr(r,prec) /* (r) = (r) */ msbptr(r,prec) ((r)+(prec)-1) make_msbptr(r,prec) (r) = msbptr(r,prec)

#define #define

rescale(r,currentp,newp) /* nil statement normalize(r,prec) prec = significance(r)

/*

#endif /* LOWFIRST byte order [Boe aa el aS SEES End byte /*

ch

(r)

= lsbptr(r,prec)

*/ ordering

stuff

bitptr(r,n)

&((r) [bit_index(n)])

*/

*/

*/

-----------------= 0) mp_sub(r,m) /* Prevents r from getting bigger than modulus m */ #define

testeq(r,i)

( (lsunit(r)==(i)) #define

\

&& (significance(r)1)

)

#define testge(r,i) \ ( (lsunit(r)>=(i)) || (significance(r)>1)

)

#define

testle(r,i)

( (lsunit(r)3)

SLOP_BITS is how many "carry bits"' to allow for intermediate calculation results to exceed the size of the modulus. It is used by modexp to give some overflow elbow room for modmult to use to perform modulo operations with the modulus. The number of slop bits required is determined by the modmult algorithm. The Russian peasant modmult algorithm only requires 1 slop bit, for example. Note that if we use an external assembly modmult routine, SLOP_BITS may be meaningless or may be defined in a non-constant manner.

*/

/*

oFile:}al'

npilib.h?

»5*/

/*

#define #define #define

PEASANT_SLOP_BITS 1 MERRITT_SLOP_BITS UNITSIZE UPTON_SLOP_BITS (UNITSIZE/2)

#ifdef

mp_smul

/* old version

requires

MS word = 0 */

#define SMITH_SLOP_BITS UNITSIZE #else /* mp_smula or C version of mp_smul #define SMITH_SLOP_BITS 0

#endif

/* mp_smul

/*

must

integer

be

*/

*/

MAX_BIT_PRECISION It

less

than

multiple

is upper

32704

limit

bits,

or

that

4088

assembly

bytes.

It

primitives should

be

can an

of UNITSIZE*2.

*/ #if

(SLOP_BITS

#define #telse #define #endif #define #define

> 0)

MAX_BIT_PRECISION

(2048+(2*UNITSIZE) )

MAX_BIT_PRECISION

2048

MAX_BYTE_PRECISION MAX_UNIT_PRECISION

(MAX_BIT_PRECISION/8) (MAX_BIT_PRECISION/UNITSIZE)

/* global_precision is the unit extern short global_precision;

/* They

The are

modulo,

wat

#define

"bit used

precision

last

set

by set_precision

sniffer" macros all begin sniffing at the MSB. internally by all the various multiply, divide,

exponentiation,

and

sniff_bit(bptr,bitmask)

square

root

(*(bptr)

functions.

& bitmask)

#define init_bitsniffer(bptr,bitmask,prec,bits) { normalize(bptr,prec); \

if@('prec)"

\

\

return(0);

\

bits = units2bits(prec); \ make_msbptr(bptr,prec); bitmask = uppermostbit; while (!sniff_bit(bptr,bitmask)) \ { bitmask >>= 1; bits--; \ pay

\

;

#define bump_bitsniffer(bptr,bitmask) { if (!(bitmask >>= 1)) \

{ bitmask

573

= uppermostbit;

post_lowerunit(bptr); Ade } /* bump_2bitsniffers

\

\

\

is used

internally

by mp_udiv.

*/

*/

handle.

*/,

/*

574

*/

/*

#define bump_2bitsniffers(bptr,bptr2,bitmask) { if (!(bitmask >>= 1)) \ { bitmask = uppermostbit; \ post_lowerunit(bptr); \ post_lowerunit(bptr2); \ aN $

PGP

Source

boolean

Internals

*/

unitptr r2, register boolean r2 to ri, result in ri */

carry);

unitptr

borrow) ;

mp_subb

(register

unitptr

/* multiprecision

ri,

register

subtract

with borrow,

r2,

*/

boolean mp_dec (register unitptr r); /* Decrement multiprecision integer r.

*/

void mp_neg (register unitptr r); /* Compute 2’s complement, the arithmetic

boolean

result

ri, register in ri. */

unitptr ri, register *r2, and returns -1,

boolean mp_inc (register unitptr r); /* Increment multiprecision integer r.

ri,

in ri

r1, register boolean carry, result in ri.

void mp_shift_right_bits (register unitptr /* multiprecision shift right bits, result short mp_compare (register /* Compares registers *r1,

register

r2 from

boolean mp_rotate_left (register unitptr /* multiprecision rotate left 1 bit with

#ifndef

and

\

/* stuff_bit is used internally by mp_udiv and mp_sqrt. #define stuff_bit(bptr,bitmask) *(bptr) |= bitmask boolean mp_addc (register unitptr ri, register /* multiprecision add with carry

Code

short

of r */

mp_move

#define mp_move(d,s) memcpy ((void*)(d), units2bytes(global_precision) )

(void*)(s),

#endif #ifndef #define #endif

unitfill0o unitfill0(r,ct)

#ifndef

mp_burn

#define #define #endif

mp_burn(r) mp_init(r,0) /* for burning mp_initO(r) mp_init(r,0)

memset((void*)(r),

\

0, units2bytes(ct))

the

evidence

carry); */

bits);

unitptr r2); 0, or 1 */

negative,

*/

*/

gi

/*

File:

#define

‘mpilib.h’

empty_array(r)

void mp_init (register /* Init multiprecision

+/

/*

unitfillO(r,

sizeof(r)/sizeof(r[0])/sizeof(unit) )

unitptr r, wordi6 value); register r with short value.

*/

short significance (register unitptr r); /* Returns number of significant units in r */ int mp_udiv (register unitptr remainder, register unitptr register unitptr dividend, register unitptr divisor);

/* Unsigned

divide,

treats

both operands

as positive.

quotient,

*/

int mp_recip (register unitptr quotient, register unitptr divisor); /* Compute reciprocal as 1/divisor. Used by faster modmult. */

int mp_div (register unitptr remainder, register unitptr quotient, register unitptr dividend, register unitptr divisor); /* Signed divide, either or both operands may be negative. */ wordi6 mp_shortdiv (register unitptr quotient, register unitptr dividend, register word16 divisor) ; /* Returns short remainder of unsigned divide. */

int mp_mod (register unitptr remainder, register unitptr dividend, register unitptr /* Unsigned

divide,

treats

both

operands

divisor); as positive. */

wordi6 mp_shortmod (register unitptr dividend, register /* Just returns short remainder of unsigned divide. */

word16

divisor) ;

int mp_mult (register unitptr prod, register unitptr multiplicand, register /* Computes

multiprecision

prod

unitptr multiplier) ; = multiplicand * multiplier */

int countbits (unitptr r); /* Returns number of significant

bits

int int int

stage_peasant_modulus (unitptr n); stage_merritt_modulus (unitptr n); stage_upton_modulus (unitptr n);

int

stage_smith_modulus

/* Must int

pass

modulus

*/

(unitptr n); stage_modulus

before

calling

modmult.

peasant_modmult (register unitptr prod, unitptr multiplicand, register unitptr multiplier);

int merritt_modmult unitptr

(register unitptr prod,

multiplicand,

int upton_modmult int

to

in r.

register

unitptr

multiplier);

(register unitptr prod,

unitptr multiplicand, register unitptr smith_modmult (register unitptr prod, unitptr multiplicand, register unitptr

multiplier) ; multiplier) ;

*/

5875

*/

/*

576

*/

/* Performs

/*

combined multiply/modulo

operation,

PGP

Source

exponentiation/modulo

int mp_modexp_crt (unitptr expout, unitptr p, unitptr q, unitptr /* exponentiation and modulo using

/FRRRRR ERK RK ERR

end Of MPI

algorithm.

and

with global modulus

int mp_modexp (register unitptr expout, register unitptr register unitptr exponent, register unitptr modulus);

/* Combined

Code

Internals

*/

expin,

*/

unitptr expin, ep, unitptr eq, unitptr u); Chinese Remainder Theorem */

Library

222K

/

*/

ie - OF ilecen=

(Guansiy))

(aseal))))s

else

5@ Ee egal

ca fae4e

carry = (x < *r1); post_higherunit (r2); *post_higherunit (ri) = x; return carry; /* return } /* mp_addc */ #e

ndif

/* mp_addc

#i fndef

the final

carry flag bit

*/

*/

mp_subb

/*

multiprecision subtract with borrow, r2 from ri, result in ri borrow is incoming borrow flag-- value should be 0 or 1 *

/

/*

boolean mp_subb */ bo olean

mp_subb

(register

unitptr

ri,

register

unitptr

r2,

register

ip register short

unit

x;

precision;

/* number

of

precision = global_precision; make_lsbptr (ri, precision) ; make_lsbptr (r2, precision);

while

(precision-—)

if

Xoo

(borrow)

ST

eed

[Xonaratoyn? =

oe

(Gagel =

cag) 2

else

> aS

al en

leepaagoyy =

3aA

(Geel

> UNITSIZE;

#endif

} /* mp_init

*/

/*

Significance */

/* Returns

number

of significant

units

short

significance
= 0)

mp_sub (remainder, divisor) ; stuff_bit (quotient, bitmask); bump_2bitsniffers return

#define

quotient,

bitmask) ;

0;

} /* mp_udiv #ifdef

(dividend,

*/

UPTON_OR_SMITH RECIPMARGIN

0 /* extra margin bits

used

by mp_recip()

*/

/*

mp_recip */ /* Compute reciprocal (quotient) as 1/divisor. Used by faster int mp_recip (register unitptr quotient, register unitptr divisor) athe loslieris short qprec;

modmult.

*/

*/

/*

Pacer

mpilibye’

#o7K/

/*

register unit bitmask; unit remainder [MAX_UNIT_PRECISION] if (testeq (divisor, 0))

return mp_initO mp_initO

-1; /* zero divisor (remainder); (quotient) ;

/* normalize

and compute number

bits = countbits bitmask = bitmsk

qprec

divide

of bits

(bits + 1);

(remainder,

(bits

error

*/

in quotient

(divisor) + RECIPMARGIN; (bits); /* bitmask within

= bits2units

mp_setbit

means

;

- RECIPMARGIN)

a single

-

first unit

*/ */

1);

/* rescale quotient to precision of divisor + RECIPMARGIN rescale (quotient, global_precision, qprec); make_msbptr (quotient, qprec); while (bits-——) { mp_shift_left

bits

(remainder) ;

if (mp_compare

(remainder,

divisor)

>= 0)

mp_sub (remainder, divisor); stuff_bit (quotient, bitmask) ; bump_bitsniffer mp_initO return

(quotient,

(remainder);

/* burn

bitmask); sensitive

data

left

on

stack

0;

} /* mp_recip */ #endif /* UPTON_OR_SMITH

*/

/*

mipaty, /* Signed divide, either or both operands may be negative. */ int mp_div (register unitptr remainder, register unitptr quotient, register unitptr dividend, register unitptr divisor)

{ boolean dvdsign, Inte status,

dsign;

dvdsign = (boolean) (mp_tstminus (dividend) != 0); dsign = (boolean) (mp_tstminus (divisor) != 0); if (dvdsign) mp_neg (dividend) ;

if (dsign) mp_neg

status

(divisor) ;

= mp_udiv

(remainder,

quotient,

dividend,

divisor) ;

if (dvdsign) mp_neg

if (dsign)

(dividend);

/* repair

caller’s

dividend

*/

*/

*/

— 887

*/

588

/*

*/

/*

mp_neg (divisor); if (status < 0) return

status;

/* repair

/* divide

caller’s

error?

divisor

PGP

Source

Code

and

Internals

*/

*/

if (dvdsign) mp_neg

(remainder) ;

if (dvdsign ~ dsign) mp_neg (quotient);_ return

status;

} /* mp_div */ /* * * * *

This function does a fast divide and mod on a multiprecision dividend using a short integer divisor returning a short integer remainder. This is an unsigned divide. It treats both operands as positive. It is used mainly for faster printing of large numbers in base 10.

*/ /*

mp_shortdiv */ wordi6 mp_shortdiv register int

(register unitptr unitptr dividend,

quotient, register word16

divisor)

bits;

short dprec; register unit bitmask; register wordi6 remainder;

if (!divisor)

/* if divisor

return -1; /* zero remainder = 0;

divisor

== 0 */ means

divide

error

*/

mp_initO (quotient); /* normalize and compute number of bits in dividend first init_bitsniffer (dividend, bitmask, dprec, bits); /* rescale quotient to same precision (dprec) as dividend rescale

(quotient,

make_msbptr while {

(quotient,

dprec);

dprec);

(bits--)

remainder

if

global_precision,

> #endif /*

Compute

the most

significant

& (qi

1) *+eCq2%>>0i) term

and add

~

q2));

+ 1s in the

others

*/

q = (q >> (MULTUNITSIZE - 2)) + (((dividend[0] q >>=

/*

Prevent

mutemp

ae

=

lsb_factor

(void)

~ MULTUNIT_mask)

* (unsigned

long)

reciph)

= 0) return -3; /* if expin >= modulus, return

if (mp_compare

*/

(exponent,

/* if

modulus)

exponent

>= modulus,

= global_precision;

error

*/

>= 0) /* save

return

error

*/

global_precision

*/

/* set smallest optimum precision for this modulus */ set_precision (bits2units (countbits (modulus) + SLOP_BITS)); /* rescale all these registers to global_precision we just defined rescale (modulus, oldprecision, global_precision) ; rescale (expin, oldprecision, global_precision); rescale (exponent, oldprecision, global_precision) ; rescale (expout, oldprecision, global_precision) ;

if (stage_modulus

(modulus))

set_precision (oldprecision); /* restore original precision return -5; /* unstageable modulus (STEWART algorithm) */

ip /* normalize and compute number of bits in exponent init_bitsniffer (exponent, bitmask, eprec, bits);

first

*/

/* We can “optimize out" the first modsquare and modmult: bits--; /* We know for sure at this point that bits>0 */ mp_move (expout, expin); /* expout = (1*1)*expin; */

*/

bump_bitsniffer

(exponent,

bitmask) ;

*/

*/

+/

/*

File:

while {

‘mpilib.c’

poll_for_break

(); /* polls keyboard,

COUNTMULTS tally_modsquares++;

/* bump

#endif /* COUNTMULTS */ mp_modsquare

:

/*

(bits--)

abort program */ #ifdef

¥*/

if

(product,

(sniff_bit

"number

allows

of modsquares"

counter

*/

expout);

(exponent,

bitmask))

mp_modmult (expout, product, expin); #ifdef COUNTMULTS tally_modmultst++; /* bump "number of modmults"

#endif /* COUNTMULTS */ Ny

ctrl1-C to

~

counter

*/

else

{

mp_move

(expout,

product) ;

bump_bitsniffer

} /* while mp_burn

bits--

(product);

(exponent,

bitmask);

*/ /* burn

the

evidence

modmult_burn (); /* ask mp_modmult own evidence */ #ifdef a

COUNTMULTS

/* diagnostic

long atomic_mults; unsigned int unitcount,

unitcount = bits2units /* calculation assumes

on

the

stack

*/

to also burn its

analysis

*/

totalmults;

(countbits (modulus) ); modsquare takes as long as

a modmult:

*/

atomic_mults = (long) tally_modmults *(unitcount * unitcount) ; atomic_mults += (long) tally_modsquares *(unitcount * unitcount) ; printf ("%1ld atomic mults for ", atomic_mults) ; printf ("%dt+%d = %d modsqrt+modmlt, tally_modsquares, tally_modmults, tally_modsquares + tally_modmults, countbits (modulus), unitcount);

at %d bits,

“%d words.\n",

ty

#endif /* COUNTMULTS */ set_precision /* Do an

will

(oldprecision);

explicit

be forced

copyright_notice

reference

to the

to include return

*/

original precision

copyright

it in the

(); /* has no real

return 0; /* normal } /* mp_modexp */ /*

/* restore

notice

executable

effect

so

that

object

at run time */

*/ the

image...

linker

*/

617

*/

618

~*

*/

/*

PGP

Source

Code

and

This is a faster modexp for moduli with a known factorisation into relatively prime factors p and q, and an input relatively prime to modulus, the Chinese Remainder Theorem to do the computation mod p mod q, and then combine the results. This relies on a number of precomputed values, but does not actually require the modulus n or exponent

expout

this

p2 = (expin q2 = (expin and then

the

(p*q).

by evaluating

~ e) mod p and ~ e) mod q a

combining

the

two

by the

CRT.

Two optimisations of this are possible. modulo p and q before starting.

First,

Second, since we know the factorisation from the factorisation of n = p*q), and

both p and q, to throw away Letting ep = eq = then

two the and

e.

= expin ~ e mod

We form

Internals

we

can

reduce

of p and q (trivially derived expin is relatively prime to

we can use Euler’s theorem, expin~phi(m) multiples of phi(p) or phi(q) in e. e mod phi(p) and e mod phi(q)

combining

these

two

speedups,

we

expin

only need

to

= 1 (mod m),

evaluate

p2 = ((expin mod p) ~ ep) mod p and q2 = ((expin mod q) ~ eq) mod q. Now

we

expout expout

need

to

apply

the

CRT.

Starting

with

= p2 (mod p) and = q2 (mod q)

we can say that expout = p2 + p * k, and if we assume then 0 = 0) return FALSE; /* probably not compressible return

TRUE;

/* possibly

} /* compressible

compressible

8);

*/

*/

*/

/* Possible error exit codes - not all of these are used. Note that don’t use the ANSI EXIT_SUCCESS and EXIT_FAILURE. To make things easier for compilers which don’t support enum we use #defines */ #define EXIT_OK 0 #define INVALID_FILE_ERROR 1 #define FILE_NOT_FOUND_ERROR 2 #define UNKNOWN_FILE_ERROR 3 #define NO_BATCH 4 #define BAD_ARG_ERROR 5 #define INTERRUPT 6 #define OUT_OF_MEM 7 /* Keyring errors: Base value = 10 */ #define KEYGEN_ERROR 10 #define NONEXIST_KEY_ERROR 11

we

*/

ie

aPiLeseeipgpsc!

#define #define #define #define #define #define #define #define

/*

/* Encode

errors:

Base

value

=

20

*/

SIGNATURE_ERROR 20 RSA_ENCR_ERROR 21 ENCR_ERROR 22 COMPRESS_ERROR 23

/* Decode #define #define #define #define

errors:

Base

value

SIGNATURE_CHECK_ERROR RSA_DECR_ERROR 31 DECR_ERROR 32 DECOMPRESS_ERROR 33

= 30 */ 30

SIGINT

/* This case

function is called if a BREAK we zap the temporary files.

signal

is sent

to the

*/ /*

breakHandler */ void

breakHandler cf #ifdef

(int

sig)

UNIX

if (sig == SIGPIPE) cf signal (SIGPIPE, SIG_IGN); exitPGP (INTERRUPT);

a if (sig fprintf else #endif

fprintf

exitPGP #Hendif

643

KEYRING_ADD_ERROR 12 KEYRING_EXTRACT_ERROR 13 KEYRING_EDIT_ERROR 14 . KEYRING_VIEW_ERROR 15 KEYRING_REMOVE_ERROR 16 KEYRING_CHECK_ERROR 17 KEY_SIGNATURE_ERROR 18 KEYSIG_REMOVE_ERROR 19

#define #define #define #define

#ifdef

hed+/

!= SIGINT) (stderr,

"\nreceived

(pgpout,

LANG

(INTERRUPT) ;

signal

("\nStopped

%d\n",

at user

sig); request\n"));

program.

In this

*/

/*

644

*/

/*

PGP

Source

Code

and

Internals

/*

clearscreen */ /*

Clears

static

screen

clearscreen

t

and

homes

the

cursor.

*/

void

(void)

fprintf (pgpout, '\n\033[0;0H\033[J\r fflush (pgpout);

/* We had to process the config file foreign language to translate the

\r");

first to possibly sign-on line that

/* ANSI

sequence.

select the follows...

*/

*/

/*

Signon_msg

*/ static

void

signon_msg

(void)

word32 tstamp; /* display message only once to static boolean printed = FALSE;

if

(quietmode

allow

calling

multiple

times

*/

|| printed)

return;

printed

= TRUE;

fprintf (stderr, LANG ("Pretty Good Privacy(tm) rel_version) ; #ifdef

%s - Public-key

encryption for the masses.\n"),

TEMP_VERSION

fputs,

¢

"Internal

development

version

only

- not

for

general

release.\n",

stderr);

#endif

fprintf

(stderr,

LANG ("(c) 1990-1994 Philip Zimmermann, rel_date) ; fputs (LANG (signon_legalese), stderr); fputs ( LANG

eee

of this

software

may

be

Phil’s

restricted

Pretty

by the

Good

Software.

U.S.

government.\n"),

stderr);

get_timestamp ((byte *) & tstamp); /* timestamp points to tstamp fprintf (pgpout, "Current time: %s\n", ctdate (&tstamp));

#ifdef TEMP_VERSION /* temporary experimental #include #define CREATION_DATE 0x2DCO79A4ul1

version

of PGP

%s\n"),

*/

*/

*/

/*

Filet»

‘pgp.c’

=*/

/*

645

/* CREATION_DATE is Fri

Apr

29

03:06:12

1994

UTC

*/

#define LIFESPAN ((unsigned long) /* LIFESPAN is 60 days */

60L * (unsigned long) 86400L)

/*

SR

SS

/* it this

fe

ed

Be

is an experimental

version

of PGP,

cut

its life

short

*/

TP ERNE kata eed aes (void) ‘ SiGoRs S

Aden,

(NULL)

>

(CREATION_DATE

fprintf (stderr, "\n\007This experimental

version

exit

*/

(-1);

/* error

exit

} /* check_expiration_date */ Helse /* no expiration date */ #define check_expiration_date()

/* -f means

act

/* -i means

internalize

*

as a unix-style filter

between

extended

like

show longer more

/* -m means /* -d means

display decrypt

/* -t

treat

statement

pure

compatible)

descriptive

text

function...

and

expired.\n");

*/

*/ attribute

plaintext output on only, leaving inner

as

/* Used by getopt

file

(or very

/* -1 means means

of PGP has

/* null

#endif /* TEMP_VERSION */

+ LIFESPAN) )

information,

operating

only

systems.

diagnostic messages

supported */

*/

screen, like unix "more" */ signature wrapping intact */

convert

to

canonical

text

format

*/

*/

#define OPTIONS "abcdefghiklmo: prstu: vwxz:ABCDEFGHIKLMO:PRSTU: VWx?7"' extern int optind; extern

boolean

static

char

*optarg;

emit_radix_64

boolean

=

FALSE;

sign flag

boolean

moreflag

boolean

filter_mode

=

/* set

config

file

*/

FALSE;

= FALSE;

static static

boolean boolean

preserve_filename decrypt_only_flag

static

boolean

de_armor_only

static

boolean

strip_sig_flag

boolean boolean

by

= FALSE;

clear_signatures strip_spaces;

=

=

= FALSE; = FALSE;

FALSE;

= FALSE;

TRUE;

static boolean c_flag = FALSE; static boolean u_flag = FALSE; /* Did I get my_name from -u? */ boolean encrypt_to_self = FALSE; /* should I encrypt messages to myself? boolean

batchmode

=

FALSE;

boolean

quietmode

= FALSE;

/*

if

TRUE:

don’t

ask

questions

*/

*/

*/

/*

646

*/

/*

PGP

Source

Code

boolean force_flag = FALSE; /* overwrite existing file without #Hifdef VMS /* kludge for those stupid VMS variable-length

text records char

and

asking

Internals

*/

*/

literal_mode

=

MODE_TEXT;

/* MODE_TEXT

or

MODE_BINARY

for

literal

packet */

#else /* not VMS */ char literal_mode packet */

#Hendif

= MODE_BINARY;

/* MODE_TEXT

or MODE_BINARY

is substring

char my_name[256] in ring */ boolean keepctx /* Ask for each boolean

of default

= "\0O";

userid

/* null my_name

for

secret

means

take

key to make

first

boolean

interactive_add

nomanual

/* If non-zero, makerandom

=

FALSE;

=

0;

=

0;

char *outputfile = NULL; int errorLvl = EXIT_OK;

search

tag */

char plainfile[MAX_PATH] ; int myArge = 2; char **myArgv; struct hashedpw *passwds = 0, *keypasswds = 0; static struct hashedpw **passwdstail = &passwds; /*

main

*/

int

(int argc,

char *argv[])

{ int

status,

before

initialize file to this many random bytes */

static char mcguffin[256]; /* userid boolean signature_checked = FALSE;

main

signatures

userid

= FALSE; /* TRUE means keep .ctx file on decrypt */ key separately if it should be added to the keyring */

boolean compress_enabled = TRUE; /* attempt compression long timeshift = OL; /* seconds from GMT timezone */ int version_byte = VERSION_BYTE_NEW;

static static

literal

/* not VMS */

/* my_name

int

for

opt;

char *inputfile = NULL; char **recipient = NULL; char **mcguffins; char *workfile, *tempf; boolean nestflag = FALSE; boolean decrypt_mode = FALSE; boolean wipeflag = FALSE; boolean armor_flag = FALSE; /* -a option boolean separate_signature = FALSE; boolean keyflag = FALSE; boolean encrypt_flag = FALSE;

*/

encryption

*/

*/

=/

(/*

wBilesvel

pgp.ood +/

/*

boolean boolean

conventional_flag = FALSE; attempt_compression; /* attempt

boolean

output_stdout;

compression

/* Output goes to stdout

char char

*clearfile = NULL; *literal_file = NULL;

char

literal_file_name[MAX_PATH] ;

char

cipherfile[MAX_PATH] ;

*/

before

encryption

char keychar = ’\0’; char *p; byte ctb; struct hashedpw *hpw;

/* Initial messages pgpout

to stderr */

= stderr;

#ifdef DEBUG1 verbose = TRUE; #endif /* * * * * * * *

The various places one can get passwords from. We accumulate them all into two lists. One is to try on keys only, and is stored in no particular order, while the other is of unknown purpose so far (they may be used for conventional encryption or decryption as well), and are kept in a specific order. If any password in the general list is found to decode a key, it is moved to the key list.

* The general * so the tail

list is not grown after initialization, pointer is not used after this.

*/ if

((p = getenv

{

("PGPPASS"))

!= NULL)

hpw = xmalloc (sizeof (struct hashedpw)); hashpass (p, strlen (p), hpw->hash); /* Add to linked list of key passwords hpw->next = keypasswds; keypasswds = hpw;

*/

+ /* * * * *

The -z "password" option should be used instead of PGPPASS if the environment can be displayed with the ps command (eg. BSD). If the system does not allow overwriting of the command line

argument should

list

but

if it has

*/

for’ (opt = 1; opt < argc;

\!

a "hidden"

environment,

be used.

p = argv[opt] ; if#e(pL0] (hepiic?

+topt)

| ileplil]et=sa?zs)

continue;

/* Accept Deter.

if

(!*p)

either

"-zpassword"

or

"-z password"

*/

PGPPASS

*/

647

*/

/*

648

*/

/*

PGP

Source

Code

and

p = argv[+t+opt] ;

/* p now points to password */ if.(!p)

break;

/* End

of arg

list

- ignore

*/

hpw = xmalloc (sizeof (struct hashedpw) ); hashpass (p, strlen (p), hpw->hash);

/* Wipe password */ while *ptte=

(*p)

2a:

/* Add to tail

of linked

hpw->next = 0; *passwdstail =

hpw;

passwdstail

list

of passwords

*/

= &hpw->next;

a /*

* If PGPPASSFD is set in the environment try to read the password * from this file descriptor. If you set PGPPASSFD to O pgp will * use the first line read from stdin as password.

*/ if

((p = getenv

("PGPPASSFD"))

!= NULL)

{ int

if

passfd;

(*p &&

(passfd = atoi

(p)) >= 0)

char pwbuf [256]; p = pwbuf;

while (read (passfd, p, 1) == 1 && *p != ’\n’) a oF hpw = xmalloc (sizeof (struct hashedpw)); hashpass (pwbuf, p - pwbuf, hpw->hash); memset

(pwbuf,

0, p - pwbuf);

/* Add to tail of linked

list

of passwords

*/

hpw->next = 0; *passwdstail = hpw; passwdstail = &hpw->next;

o; /* Process the config file. - Hard-coded defualts - The system config file - Hard-coded defaults for - The user’s config file - Environment variables - Command-line options.

+/

The

following

override

security-critical

opt = 0; /* Number of config files read */ #ifdef PGP_SYSTEM_DIR strcpy (mcguffin, PGP_SYSTEM_DIR) ; strcat (mcguffin, "config.txt"); if (access (mcguffin, 0) == 0)

each

things

other:

Internals

*/



GFibeste‘pepsc?

bol+/

/*

649

opttt;

/* * Note: errors here are.NOT fatal, so * can use PGP with a corrputed system

*7,

processConfigFile

that people file.

(mcguffin) ;

#endif /* * These must be personal; * influence them.

the

system

config

file

may not

*/

buildfilename buildfilename

(globalPubringName, (globalSecringName,

buildfilename

"pubring.pgp"); "secring.pgp");

(globalRandseedName,

my_name[O]

=

/* Process

the

"randseed.bin");

’\0’; config

file

first.

Any command-line

arguments

will

override the config file settings */

#if defined(UNIX)

|| defined(MSDOS)

/* Try “pgp.ini" #ifdef

on MS-DOS

|| defined(0S2)

or ".pgpre"

on Unix */

UNIX

buildfilename

(mcguffin,

".pgprc");

(mcguffin,

"pgp.ini");

#else

buildfilename #endif

;

if (access (mcguffin, 0) != 0) buildfilename (mcguffin, "config.txt"); #else

buildfilename #endif

if (access {

(mcguffin,

(mcguffin,

"config.txt");

0) == 0)

opttt;

if (processConfigFile exit

(mcguffin)

< 0)

(BAD_ARG_ERROR) ;

dy

PeeClopt) fprintf

(pgpout,

init_charset

LANG

("\007No

configuration

file

found.\n")) ;

();

#ifdef MSDOS /* only on MSDOS systems */ if ((p = getenv ("TZ")) == NULL || *p ==

’\0’)

x fprintf

(pgpout,

LANG

("\OO7WARNING:

defined, so GMT timestamps\n\ may be wrong. See the PGP User’s

in AUTOEXEC.BAT file.\n")); }

Guide

Environmental

to properly

variable

define

TZ\n\

TZ

is not

\

*/

650

/*

#Hendif

*/

/*

/* MSDOS

#ifdef VMS #define TEMP

PGP

Source

Code

and

(char

**)))

==

Internals

*/

"SYS$SCRATCH"

#telse

#define

#endif

TEMP

"TMP"

/* VMS

*/

if ((p = getenv (TEMP)) settmpdir (p); if

((myArgv

=

!= NULL && *p != ’\0’)

(char **) malloc

((arge + 2) * sizeof

NULL)

{ fprintf exitPGP

(stderr, (7);

} myArgv[0]

= NULL;

myArgv[i]

= NULL;

LANG

("\n\0070ut

/* Process all the command-line while (optind < argc)

of memory.\n"));

option

/* * Allow random order of options * NOTE: this does not work with * the PGP distribution.

switches:

*/

and arguments (like GNU getopt) GNU getopt, use getopt.c from

e/, if ((opt = pgp_getopt

{

(argc,

argv,

OPTIONS))

== EOF)

if (optind == argc) /* -- at end */ break;

myArgv[myArgct+t+]

= argv[optind+t+];

continue;

, opt = to_lower if (keyflag &&

t

if (keychar

==

keychar else keychar

’V’;

=

(opt); (keychar

==

’\0’

|| (keychar

’v’)

= opt;

continue;

} switch

(opt)

af Casemudia: armor_flag

= TRUE;

emit_radix_64 break;

=

1;

Gasieuubie:

separate_signature break;

= strip_sig_ flag = TRUE;

==

’v’

&& opt ==

’v’)))

#/

Y*

gsEA textal pep:ood */

GAS

/*

OmaGiar

encrypt_flag = conventional_flag c_flag = TRUE;

= TRUE;

break; case ’d’:

decrypt_only_flag

= TRUE;

break; case ’e’:

encrypt_flag break; case Vis filter_mode break; casen irene case ’h’:

usage

= TRUE;

=

TRUE;

();

break;

#ifdef VMS case 742% literal_mode break;

#endif case

/* VMS

= MODE_LOCAL;

*/

’k’:

keyflag break; case ’1’: verbose break; case ’m’:

= TRUE;

=

moreflag

TRUE;

= TRUE;

break;

case ?p’: preserve_filename

= TRUE;

break;

Casicmnows

outputfile

= optarg;

break; case ’s’:

sign_flag

= TRUE;

break; case ’t’: literal_mode break;

case

=

MODE_TEXT;

’u’:

strncpy

(my_name,

optarg,

sizeof

CONVERT_TO_CANONICAL_CHARSET u_flag = TRUE; break;

case

’w’:

wipeflag break;

= TRUE;

(my_name)

(my_name);

- 1);

651

/*

652

*/

/*

PGP

Source

Code

and

Internals

caseeZzis: break;

/* ?+? case

special

option:

does not require

- */

+’;

if (processConfigLine

(optarg)

== 0)

break;

fpranttacstderr,

."\n");

/* fallthrough */ default:

arg_error

();

myArgv[myArgc]

= NULL;

/* Just to make it NULL terminated */

if (keyflag && keychar key_usage ();

signon_msg

==

’\0’)

();

check_expiration_date

(); /* hobble

any experimental

/* * Write to stdout if explicitly asked * no explicit file name was given.

to,

or

version

in filter

mode

*/ and

*/ output_stdout

#if /* /* if

=

outputfile

? strcmp

(outputfile,

"-")

==

0

: filter_mode;

1 At request of Peter Simons, use stderr JIS: Put this code back in... removing

always. Sounds reasonable. */ it broke too many things */

(!output_stdout )

pgpout #endif

=

stdout;

#if defined(UNIX) umask

(077);

|| defined(VMS)

/* Make

files

default

to private

*/

#endif

initsigs (); /* Catch signals */ noise (); /* Start random number generation

*/

if (keyflag) { status

= do_keyopt

(keychar);

if (status < 0) user_error (); exitPGP (status); }

/* -db means break off signature certificate if (decrypt_only_flag && strip_sig_flag) decrypt_only_flag

= FALSE;

into

separate

file

*/

ey

/*

File:

‘pgp.c’

= */

if (decrypt_only_flag decrypt_mode

653

+7,

&& armor_flag)

= de_armor_only

if (outputfile

= TRUE;

!= NULL)

preserve_filename

or

/*

aie

&&

= FALSE;

tencrypt_flag

&&

!conventional_flag

if (wipeflag) { /* wipe only */ if (myArge != 3) arg_error (); /* need one argument */ Sica ia (myArgv[2]) == 0 && remove (myArgv[2]) fprintf (pgpout, LANG ("\nFile %s wiped and deleted.

fprintf

(pgpout,

exitPGP

(EXIT_OK);

&&

!armor_flag)

== 0)

"), myArgv[2]);

"\n");

ip exitPGP

(UNKNOWN_FILE_ERROR) ;

/* decrypt

if none

decrypt_mode

=

if (myArge == 2) { /* no arguments #ifdef

are

specified

+*/

*/

UNIX

if

{

of the -s -e -c -a -w options

TRUE;

(!filter_mode

/* piping * switch

!isatty

(fileno

(stdin) ))

to pgp without

arguments

and no -f:

to filter

but

write

* if it’s a tty, if (!moreflag) pgpout

&&

mode

use

don’t

the preserved

output

filename

to

stdout

*/

= stderr;

filter_mode

if (isatty

=

TRUE;

(fileno

(stdout))

preserve_filename

=

&&

!moreflag)

TRUE;

} #tendif

if

(!filter_mode)

if (quietmode) { quietmode

signon_msg

fprintf LANG

= FALSE;

();

(pgpout, ("\nFor

details

on

licensing

and

distribution,

see

\nFor other cryptography products and custom development \nPhilip Zimmermann, 3021 11th St, Boulder CO 80304 USA,

the

PGP

services, \

User’s

Guide.\

contact:\

/*

654

*/

+1

303

phone

PGP

/*

Source

Code

Internals

and

541-0140\n"));

if (strcmp ((p = LANG ("@translator®")), "@translator") ) fprintf (pgpout, p); fprintf (pgpout, LANG ("\nFor a usage summary, type: pgp —h\n")); exit

(BAD_ARG_ERROR);

/* error

exit

*/

tp if else

t if (filter_mode)

{ recipient

= &myArgv([2];

} else

uf

inputfile recipient

= myArgv([2]; = &myArgv([3];

} 5 if

(filter_mode)

“i inputfile

else

if

{ /* /* * * * * * * * *

=

"stdin";

(makerandom

Create

the

> 0)

input

file

*/

+makerandom=: Create an input file consisting of cryptographically strong random bytes, before applying the encryption options of PGP. This is an advanced option, so assume the user knows what he’s doing and don’t bother about overwriting questions. E.g. pgp tmakerandom=24 foofile Create "foofile" with 24 random bytes in it. pgp t+tmakerandom=24 -ea foofile recipient

* The same, but also encrypt it to * foofile.asc as well. * This feature was created to allow PGP * around for other applications to use.

"recipient",

to

create

and

creating

send

keys

+/ status

=

cryptRandWriteFile

(inputfile,

(struct

IdeaCfbContext

*) 0,

(unsigned) makerandom) ; if (status < 0)

{ fprintie(stderr, exitPGP

“Error

writing file

\“/s\\n"

einputrile) ;

(INVALID_FILE_ERROR) ;

fprintf

(pgpout,

LANG

("File %s created

inputfile, makerandom) ; /* If we aren’t encrypting,

don’t

bother

containing trying

4d random bytes.\n"),

to decrypt

this!

*/

+*/

/*

File:

‘pgp.c’?

= ¥*/

/*

if (decrypt_mode) exitPGP (EXIT_OK); — /* This

is obviously

literal_mode

=

NOT a text

file

+*/

MODE_BINARY;

else

{ if (decrypt_mode

strcpy

(cipherfile,

force_extension

&& no_extension

(inputfile) )

inputfile);

(cipherfile,

ASC_EXTENSION);

if (file_exists (cipherfile)) { inputfile = cipherfile; else

af force_extension if (file_exists

(cipherfile, PGP_EXTENSION) ; (cipherfile) )

4. inputfile

= cipherfile;

hp else

x force_extension if (file_exists inputfile

(cipherfile, SIG SSIS ELE: (cipherfile))

= cipherfile;

} if

fprintf

LANG

(!file_exists

(pgpout,

("\007File

(inputfile))

[%s] does not exist.\n"),

inputfile);

errorLvl = FILE_NOT_FOUND_ERROR; user_error ();

} if (strlen

(inputfile)

>=

(unsigned)

fprintf (pgpout, LANG ("\O007Invalid filename: errorLvl = user_error

} strcpy if

INVALID_FILE_ERROR; ();

(plainfile,

(filter_mode)

inputfile);

MAX_PATH

[%s]

- 4)

too long\n"),

inputfile) ;

655

*/

/*

a

656

/*

setoutdir

(NULL);

/* NULL means

PGP

Source

Code

and

Internals

/,

use tmpdir */

els e

af

if (outputfile)

setoutdir

(outputfile);

else

setoutdir if

(inputfile) ;

(filter_mode) workfile

= tempfile

readPhantomInput

(TMP_WIPE

| TMP_TMPDIR) ;

(workfile);

els e

{

workfile

= inputfile;

get_header_info_from_file

(workfile,

&ctb,

1);

if (decrypt_mode) x strip_spaces

=

FALSE;

if ('is_ctb (ctb) && is_armor_file do_armorfile (workfile);

else

if (do_decrypt

user_error (1);

OL))

< 0)

();

if (batchmode exitPGP

(workfile)

(workfile,

&&

!signature_checked)

/* alternate

success,

file

did not

have

sig.

*/

else

exitPGP }

(EXIT_OK);

/*

*

See if plaintext input file was actually created by PGP earlier-If it was, maybe we should NOT encapsulate it in a literal packet. (nestflag = TRUE). Otherwise, always encapsulate it (default).

*

(Why test

* *

for filter_mode??7)

*/ if

(!batchmode /*

do we

ip else

&&

!filter_mode

&& legal_ctb

(ctb))

Special case--may be a PGP-created packet, so inhibit encapsulation in literal packet? */

fprintf (pgpout, LANG ("\n\007Input file ’%s’ looks inputfile); fprintf (pgpout, LANG ("\nIs it safe to assume that nestflag = getyesno (’n’);

if (force_flag && makerandom

like

it may have

it was

been

created by PGP

== 0 && legal_ctb

(ctb))

created by PGP. (y/N)?

"));

")

>

Zt

agkidessa\

pgp:coho */

nestflag

/*

= TRUE;

if (moreflag && makerandom == 0) “ls /* special name to cause printout on decrypt */ strcpy (literal_file_name, CONSOLE_FILENAME) ; literal_mode

= MODE_TEXT;

/* will

check

for

text

file

later

*/

else

if strcpy #ifdef

(literal_file_name,

file_tail

(inputfile));

MSDOS

strlwr

(literal_file_name) ;

#endif

} literal_file

/* to for

=

literal_file_name;

Make sure non-text files are not accidentally converted canonical text. This precaution should only be followed US

8-bit

ASCII

text

character

files,

codes

suitable for conversion text format. */ if

(literal_mode

==

since

and

European

still

to canonical

MODE_TEXT

&&

text

be legitimate

text

may

have

files

(CR/LF-terminated)

'!is_text_file

{

files

(workfile))

.

fprintf (pgpout, LANG ("\nNote: ’%s’ is not a pure text file.\n\ will be treated as binary data.\n"),

File

workfile); literal_mode

= MODE_BINARY;

/* now

expect

straight

binary

*/

i

if (moreflag && literal_mode == MODE_BINARY) { /* For eyes only? Can’t display binary file. */ fprintf (pgpout, LANG (""\n\007Error: Only text files may be sent as display-only.\n")); errorLvl

=

INVALID_FILE_ERROR;

user_error

();

aS*

See if plainfile looks like it might be incompressible, by examining its contents for compression headers for commonly-used compressed file formats like PKZIP, etc. Remember

whether

this

to

Naturally,

information

attempt

for

compression

later,

before

when

we

are

deciding

encryption.

don’t bother if we are making a separate signature or message. Also, don’t bother trying to compress a

clear-signed Hee He HHH

657

*/,

/*

658

* PGP

*/

.

message,

as

it’s

probably

/*

already

PGP

Source

Code

and

Internals

compressed.

*/ attempt_compression = compress_enabled && !separate_signature Inestflag && !clearfile && makerandom == 0 &&

file_compressible

(plainfile);

if (sign_flag) t if (!filter_mode && fprintf (pgpout, LANG

("\nA

if

secret

key

(!quietmode

&&

!quietmode)

is required

&& my_name[0]

to make

==

a signature.

"));

’\0’)

{ fprintf (pgpout, LANG ("\nYou specified no user ID to select your secret key,\n\ so the default user ID and key will be the most recently\n\ added

key on your

secret

keyring. \n"));

} strip_spaces clearfile

if

{

= FALSE;

= NULL;

(literal_mode

==

MODE_TEXT)

/* Text mode requires becoming canonical */ tempf = tempfile (TMP_WIPE | TMP_TMPDIR); /* +clear means output file with signature in the only in combination with -t and -a, not with if ('encrypt_flag && !separate_signature &&

emit_radix_64 clearfile

&& clear_signatures) = TRUE;

make_canonical (workfile, if (!clearfile)

rmtemp

clear, or -b */

= workfile;

strip_spaces

workfile

-e

tempf);

(workfile) ; =

tempf;

if (attempt_compression || encrypt_flag output_stdout) tempf = tempfile (TMP_WIPE | TMP_TMPDIR);

|| emit_radix_64 ||

else

tempf

= tempfile

(TMP_WIPE);

/* for

clear

status

= signfile

my_name,

workfile,

rmt emp workfile

signatures tempf,

we

(nestflag,

create

a separate

signature

separate_signature

literal_mode,

literal_file);

(workfile); = tempf;

ify (status = 0)

producing

“/s’. \n'").

++success;

} else

al

if (do_decrypt

(tempf)

>= 0)

++success;

rmtemp

(tempf);

as if

{

(!is_armor_file

if (!success) /* print decrypt anything */

(armorfile,

linepos))

error msg if we didn’t

user. error) (): return;

fprintf (pgpout, LANG ('"\nLooking for next

ls } /* do_armorfile

*/

/*

do_decrypt */ static

int

do_decrypt

(char *cipherfile)

{ char *outfile = NULL; intmstabuls eel boolean nested_info = FALSE;

char ringfile[MAX_PATH] ;

packet

in ’4%s’. ..\n''),

armorfile) ;

665

+/

/*

666

byte

*/

/*

PGP

Source

and

Internals

ctb;

byte header[8]; /* used to classify file type at the char preserved_name[MAX_PATH] ; char

Code

end.

*/

*newname;

/* will be set to the literal packet */

preserved_name[0]

original

file

name

after

processing

a

= ’\0’;

do

{ /* while nested parsable if (nested_info) rmtemp

(cipherfile);

cipherfile if

/* never

executed

(get_header_info_from_file

errorLvl

*/

on first

pass

*/

= outfile;

fprintf (pgpout, LANG ("\n\007Can’t return

info present

open

(cipherfile,

ciphertext

file

&ctb,

’%s’\n"),

1) < 0)

cipherfile);

= FILE_NOT_FOUND_ERROR;

-1;

} if

(!is_ctb

(ctb))

/* not

a real

CTB --

complain

*/

break;

if (moreflag) outfile = tempfile (TMP_WIPE else outfile = tempfile

/* PKE Ife

| TMP_TMPDIR);

(TMP_WIPE);

is Public

Key Encryption

(ss octbLetypes(ctb.

*/

CIBLPKE/TYPE) )

if (!quietmode) fprintf (pgpout, LANG ("\nFile is encrypted.

Secret

key is required

/* Decrypt to scratch file since we may have status = decryptfile (cipherfile, outfile); ta

a LITERAL2

(statism)

{ /* error

return

errorLvl = Tech abba ale

nested_info

else

if

=

*/

RSA_DECR_ERROR;

(status

> 0);

(is_ctb_type

(ctb,

CTB_SKE_TYPE) )

to read

*/

it.

"));

#7,

/*

File:

‘pgp.c’

= */

/*

if (decrypt_only_flag) { /* swap file names

instead

of just

copying the file

667

*/

*/

rmtemp (outfile) ; outfile = cipherfile; cipherfile = NULL;

if (!quietmode) fprintf (pgpout, LANG

("\nThis

file

nested_info

break;

=

has

a signature,

which

will

be left

in place.\n"));

FALSE;

/* Do no more

*/

} if (!quietmode) fprintf (pgpout, LANG ("\nFile has status

=

check_signaturefile

strip_sig_flag, it

signature.

} nested_info

=

if (strcmp

key is required

(cipherfile,

to check

signature.

outfile,

preserved_name) ;

ae(stacusm 0);

(preserved_name,

"/dev/null")

== 0)

rmtemp (outfile) ; fprintf (pgpout, "\n"); return

else

0;

if (is_ctb_type

(ctb,

CTB_CKE_TYPE) )

/* Conventional Key Encrypted ciphertext. */ /* Tell user it’s encrypted here, and prompt for

password in subroutine. */ if (!quietmode) fprintf (pgpout, LANG ("\nFile

is conventionally

/* Decrypt

it may be a LITERAL2

to

scratch

file

status = idea_decryptfile if (status < 0) { /* error return */ errorLvl

return nested_info

since

(cipherfile,

= DECR_ERROR;

-1; =

/* error (status

exit

> 0);

status

*/

outfile);

encrypted. */

"));

"));

/*

668

*/

else

/*

if (is_ctb_type

/* Compressed

text.

(ctb,

/* Always

Code

CTB_COMPRESSED_TYPE) )

(cipherfile,

outfile);

DECOMPRESS_ERROR;

assume

nested_info

Source

*/

status = decompress_file see ((GiRewne = 0)

status = maint_update (keyfile, 0); if (status == -7) { /* ringfile is a keyfile or secret keyring */

fprintf (pgpout, "Warning: ’%s’ keyfile); return

is not

a public keyring\n",

0;

} if

(status < 0) fprintf (pgpout,

LANG

("\OO07Maintenance

pass

error.

"));

/*

678

*/

/*

ite (sitbaciseo) id

fprintf

(pgpout,

errorLvl

LANG

("\007Key

signature

PGP

error.

Source

Code

and

Internals

"));

= KEY_SIGNATURE_ERROR;

} return

status;

} /* Key signing */ [|*#-- 3-3-9 -

*/

Casem

dus:

{ /*

*/

disable/revoke

Arguments:

userid,

if (myArge >= 4) strncpy (keyfile,

key

keyfile

myArgv[3],

sizeof

(keyfile)

- 1);

else

strcpy

(keyfile,

globalPubringName);

if (myArge >= 3) { strcpy (mcguffin,

myArgv[2]);

/* Userid

to sign */

else

{

fprintf (pgpout, LANG ("\nA user

disable.

ID is required

to select

the key you want

"));

fprintf (pgpout, LANG ("\nEnter user ID: ")); getstring (mcguffin, 255, TRUE); /* echo keyboard CONVERT_TO_CANONICAL_CHARSET status

= disable_key

(mcguffin);

(mcguffin,

if (status >= 0) « status = maint_update if (status == -7)

*/

keyfile);

(keyfile,

0);

{ /* ringfile is a keyfile or secret keyring */ fprintf (pgpout, keyfile); return

"Warning:

is not

a public keyring\n",

0;

ifs (statuss= 4) strncpy (ringfile, myArgv[3], sizeof (ringfile) else /* default key ring filename */ strcpy (ringfile, globalPubringName);

if (myArge

- 1);

>= 3)

if strcpy

(mcguffin,

myArgv[2]);

/* Userid

to edit

*/

else

{ fprintf LANG

(pgpout, ("\nA

user

ID

is required

to

select

the

key you

want

fprintf (pgpout, LANG ("\nEnter the key’s user ID: ")); getstring (mcguffin, 255, TRUE); /* echo keyboard */ CONVERT_TO_CANONICAL_CHARSET

status

= dokeyedit

if (status

x

(mcguffin);

(mcguffin,

ringfile);

>= 0)

status = maint_update (ringfile, 0); if (status == -7) status = 0; /* ignore "not a public keyring" if) (status < 0) fprintf (pgpout, LANG ("\007Maintenance pass

ifeCstbavuse< {

fprintf

error error.

*/ "));

0)

(pgpout,

errorLvl

=

LANG

("\007Keyring

edit

error.

"));

KEYRING_EDIT_ERROR;

S return

status;

} /* Key edit

*/

[ rn caselwas:

{ /*

Add key to key ring

Arguments:

+/

if (myArge

keyfile,

< 3 &&

ang werror)()?

ringfile

!filter_mode)

*/

to

edit.

"));

679

*/

/*

680

*/

/*

if (!filter_mode) { /* Get the keyfile from args */ strncpy (keyfile, myArgv[2], sizeof

PGP

(keyfile)

- 1);

#ifdef MSDOS strlwr (keyfile); #endif

if (!file_exists

(keyfile))

default_extension

if (!file_exists { fprintf (pgpout, LANG

('"'\n\007Key

(keyfile,

PGP_EXTENSION) ;

(keyfile))

file

’%s’

does

not

exist.\n"),

keyfile); errorLvl = return -1;

NONEXIST_KEY_ERROR;

workfile

= keyfile;

workfile

= tempfile

else

"f readPhantomInput

(TMP_WIPE

| TMP_TMPDIR) ;

(workfile) ;

if (myArge < (filter_mode

7? 3 : 4))

{ /* default key ring filename byte

*/

ctb;

get_header_info_from_file

if

(ctb

strcpy

==

(workfile,

&ctb,

1);

CTB_CERT_SECKEY)

(ringfile,

globalSecringName) ;

(ringfile,

globalPubringName);

else

strcpy else

{ strncpy

(ringfile,

myArgv[(filter_mode

sizeof (ringfile) - 1); default_extension (ringfile, #ifdef

MSDOS

strlwr

(ringfile);

#endif status if

= addto_keyring

(filter_mode)

(workfile,

? 2 : 3)],

PGP_EXTENSION) ;

ringfile);

Source

Code

and

Internals

*/



SsEWMessa

rmtemp if

pepect in +7

681

(workfile);

(status

< 0)

fprintf

(pgpout,

errorLvl return

/*

=

LANG

("\007Keyring

add

error.

"));

KEYRING_ADD_ERROR;

status;

} /* Add key to key ring */ /*------------------------------------------------------- */

case

’x’

{ /*

Extract

poe tgs

mcguffin,

key from key ring keyfile,

ringfile

*

if (myArge >= (filter_mode ? 4 : 5)) /* default key ring filename */ strncpy (ringfile, myArgv[(filter_mode ? 3 : 4)], sizeot (ringfile) — 1); else

strcpy

(ringfile,

if (myArge al

>=

globalPubringName) ;

(filter_mode

? 2 : 3))

if (myArgv[2])

/* Userid to extract */ strcpy (mcguffin, myArgv[2]);

else

Strcepyancgut fing. "))s else

{

fprintf

(pgpout,

LANG ("\nA user ID is required to if (batchmode) /* not interactive,

must

be

on

returns

fprintf

getstring

command

line

(pgpout,

LANG

(mcguffin,

if (!filter_mode) A if (myArge >= 4) strncpy (keyfile, else

keyfile[0] workfile

the

key

you

want

*/

—1

("\nEnter

255,

CONVERT_TO_CANONICAL_CHARSET

}

select userid

=

’\0’;

= keyfile;

TRUE);

the key’s user

ID:

"));

/* echo keyboard */

(mcguffin);

myArgv[3],

sizeof

(keyfile)

- 1);

to

extract.

"));

#/;

PGP Source

/*

*/

682

/*

Code

and

Internals

else

{ workfile

= tempfile

(TMP_WIPE

| TMP_TMPDIR);

} #ifdef

MSDOS

strlwr strlwr

(workfile) ; (ringfile);

#Hendif

default_extension

status

(ringfile,

PGP_EXTENSION) ;

= extract_from_keyring

ringfile,

(filter_mode

(mcguffin,

? FALSE

workfile,

:

emit_radix_64));

rae (iesyane! < )) { fprintf (pgpout, errorLvl

if

LANG

("\007Keyring

extract

error.

"));

= KEYRING_EXTRACT_ERROR;

(filter_mode) rmtemp (workfile) ;

return

status;

} if

(filter_mode if

!status)

(emit_radix_64)

/* NULL for if

&&

outputfile means

(armor_file

(workfile,

write

NULL,

to stdout

NULL,

NULL)

*/ != 0)

{ errorLvl = return -1;

UNKNOWN_FILE_ERROR;

i } else

if

{ (writePhantomOutput errorLvl return

(workfile)

< 0)

= UNKNOWN_FILE_ERROR;

-1;

i rmtemp return

(workfile);

0;

} /* Extract

{ /*

key from key ring */

Remove

keys

or

selected

key

signatures

from

userid

keys

*/

ye

BEULeCIAL

pep:God */

Arguments:

userid,

/*

ringfile

*/ if (myArge >= 4) : strcpy (ringfile, myArgv[3]); else /* default key ring filename */ strcpy (ringfile, globalPubringName) ; if (myArge

>= 3)

j strcpy

(mcguffin,

myArgv[2]);

/* Userid to work on */

else

easen

tle)

fprintf (pgpout, LANG ("\nA user ID is required to select remove certifying signatures from. "));

the public key you want

to\n\

else

{ fprintf (pgpout, LANG ("\nA user } if

ID is required to select

(batchmode)

command

line

return

/* not

interactive,

the key you want

userid

must

to remove.

be on

*/

-1;

fprintf (pgpout, LANG ("\nEnter the key’s user ID: ")); getstring (mcguffin, 255, TRUE); /* echo keyboard */ CONVERT_TO_CANONICAL_CHARSET #ifdef strlwr #endif

(mcguffin);

MSDOS (ringfile) ;

if (!file_exists

(ringfile))

default_extension

if (sign_flag)

{ /* Remove if

(ringfile,

signatures

(remove_sigs

PGP_EXTENSION) ;

*/

(mcguffin,

ringfile)

< 0)

4. fprintf

(pgpout,

errorLvl return

LANG

("\007Key

signature

remove

error.

= KEYSIG_REMOVE_ERROR ;

-1;

i else

{ /* Remove keyring if

*/

(remove_from_keyring

(boolean)

(myArge

< 4))

(NULL,

< 0)

mcguffin,

ringfile,

"));

"));

683

*/

/*

684

fprintf

*/

/*

(pgpout,

errorLvl = return -1;

LANG

("\007Keyring

remove

PGP

error.

Source

Code

"));

KEYRING_REMOVE_ERROR;

} return

0;

} /* remove

key signatures

case ’V’?: /* -kvv */ { /* View or remove with userid match Arguments: userid,

from userid

*/

key ring entries,

ringfile

*/ if (myArge < 4) /* default

key ring filename

strcpy else

(ringfile,

globalPubringName) ;

strcpy

(ringfile,

myArgv[3]);

*/

if (myArge > 2) { strcpy (mcguffin, myArgv[2]); if (strcmp (mcguffin, "*") == mcguffin[0] = ’\0’; else

{ *mcguffin

=

’\0’;

if ((myArge == 3) && has_extension { strcpy (ringfile, myArgv[2]);

mcguffin[0]

(myArgv[2],

PGP_EXTENSION) )

= ’\0’;

ap CONVERT_TO_CANONICAL_CHARSET #ifdef

MSDOS

strlwr

(ringfile);

(mcguffin);

#endif

if (!file_exists

(ringfile) )

default_extension

/* If a second status

’v’

(ringfile,

(keychar = V), show signatures

= view_keyring

(mcguffin,

(boolean) (keychar == if (status < 0)

fprintf

(pgpout,

PGP_EXTENSION) ;

LANG

’V’),

too */

ringfile,

c_flag);

("\007Keyring view error.

"));

and

Internals

oy

[ee

ileretatpgpwc:hhor#/

errorLvl return

/*

= KEYRING_VIEW_ERROR;

status;

f

} /* view

key ring

entries,

with

userid

match

*/

default:

arg_error return

();

0;

} /* do_keyopt

*/

/* Wisseug_ Sicac@c */

/* comes

here

es

if user

made

a boo-boo.

*/

void

user_error

fprintf fprintf

s;

()

(pgpout, (pgpout,

LANG

("\nFor a usage

summary,

type:

pgp —-h\n"));

LANG ("'For more detailed help, consult the PGP User’s exitPGP (errorLvl ? errorLvl : 127); /* error exit */

#if

defined(DEBUG)

#include #endif

&&

Guide. \n"));

defined(linux)

/* * exitPGP: wipes * the stack.

and removes

temporary

files,

also

tries

to wipe

*/ /*

exitPGP */ void

exitPGP

ai

(int

returnval)

char buf [STACK_WIPE] ; struct

hashedpw

*hpw;

if (verbose) fprintf (pgpout, "exitPGP: exitcode = %d\n", for (hpw = passwds; hpw; hpw = hpw->next) memset (hpw->hash, 0, sizeof (hpw->hash)); for (hpw = keypasswds; hpw; hpw = hpw->next) memset

(hpw->hash,

cleanup_tmpf

();

/* Merge

entropy

any

if (cryptRandOpen

0,

sizeof

we

collected

((struct

returnval) ;

(hpw->hash) ); into

the

IdeaCfbContext

randseed.bin

*) 0) >= 0)

file

*/

685

*/

/*

686

*/

/*

cryptRandSave ((struct IdeaCfbContext #if defined(DEBUG) && defined(linux) if (verbose)

PGP

Source

Code

and

*) 0);

{ struct

mstats

mstate=

mstat;

mstats

printf

©);

('%d chunks

mstat.chunks_used,

used

(%d bytes)

‘%d bytes

mstat.bytes_used,

total\n",

mstat.bytes_total) ;

} #endif memset #ifdef /*

* Fake

(buf,

0, sizeof

(buf));

/* wipe

stack

*/

VMS

VMS

style

error

returns

with

severity

in bottom

3 bits

*/ if

(returnval) returnval = (returnval

> 24;

pliir=+t

>>-16;

pl2]

=+t

>>

p[3]

= t;

p t=

4;

8;

i++)

721

Ve)

22)

/* Set

7,

/*

up pointers

for

future

randPoolAddPos

=

randPoolGetPos

= sizeof

addition

PGP

or removal

Source

Code

of random

and

bytes

Internals

*/

0;

(randPoolKey);

i /* * Make a deposit of information (entropy) into the pool. The bits * deposited need not have any particular distribution; the stirring * operation transformes them to uniformly-distributed bits.

=m) /*

randPoolAddBytes */ void

randPoolAddBytes

(byte const

*buf,

unsigned len)

{ unsigned

t;

while (len > (t = sizeof (randPool) - randPoolAddPos)) { xorbytes ((byte *) randPool + randPoolAddPos, buf, t); bute. len -= t;

randPoolStir

();

3s if

(len)

{ xorbytes

((byte

*) randPool

randPoolAddPos

+=

randPoolGetPos

= sizeof

+ randPoolAddPos,

buf,

len);

len;

(randPool);

/* Force

stir

on

get

*/

} /* * Withdraw some bits from the pool. Regardless of the distribution of the * input bits, the bits returned are uniformly distributed, although they * cannot, of course, contain more Shannon entropy than the input bits.

y/

/*

randPoolGetBytes +/ void randPoolGetBytes

{

unsigned while

(byte

* buf,

unsigned

len)

t;

(len > (t = sizeof

(randPool)

- randPoolGetPos) )

t memcpy

(buf,

(byte

*) randPool

+ randPoolGetPos,

t);

*/

/*

File:

buf len

‘randpool.c’

+= -=

¥*/

1s

t; t;

randPoolStir

();

i; if

(len)

S memcpy

(buf,

(byte *) randPool

randPoolGetPos

+=

+ randPoolGetPos,

len;

} } /*

randPoolGetByte */ byte

randPoolGetByte

(void)

{ if

(randPoolGetPos randPoolStir ();

return

(((byte

==

sizeof

(randPool))

*) randPool) [randPoolGetPos++] ) ;

len);

Pies

37,

/*

724

*/

/*

/* File: /* (New File)

‘rsagen.h’

Source

Code

and

Internals

*/

*/

rsagen.h

/*

PGP

(c) Copyright

- C include

file

for RSA public-key

1987 by Philip Zimmermann.

key generation

routines.

All rights reserved.

The author assumes no liability for damages resulting from the use of this software, even if the damage results from defects in this software. No warranty is expressed or implied. RSA-specific routines follow. These are the only functions that are specific to the RSA public key cryptosystem. The other multiprecision integer math functions may be used for non-RSA applications. Without these functions that follow, the rest of the software cannot perform the RSA public key algorithm.

ca

NOTE:

This

assumes

previous

inclusion

of

"mpilib.h"

int rsa_keygen (unitptr n, unitptr e, unitptr d, unitptr p, unitptr q, unitptr u, short keybits, /* Generate

RSA

key

components

p,

q,

n,

e,

d,

and

short u.

*/

and

"genprime.h"

ebits);

*/

Ye

eEitextnYrsagensc?

/* File:

*/

*/

rsagen.c version

First

/*

‘rsagen.c’

/* (New File) /*

»o%/

— C source 17 Mar 87

(c) Copyright

code

for

RSA

public-key

1987 by Philip Zimmermann.

key generation

routines.

All rights reserved.

The author assumes no liability for damages resulting from the use of this software, even if the damage results from defects in this software. No warranty is expressed or implied. RSA-specific routines follow. These are the only functions that are specific to the RSA public key cryptosystem. The other multiprecision integer math functions may be used for non-RSA applications. Without these functions that follow, the rest of the software cannot perform the RSA public key algorithm. The

RSA

public

Institute

not

of

key

cryptosystem

Technology

apply outside

(U.S.

the USA.

is patented

patent

Public

by the

#4,405,829).

Key Partners

Massachusetts This

(PKP)

patent

holds

does

the

exclusive commercial license to sell and sub-license the RSA public key cryptosystem. The author of this software implementation of the RSA algorithm is providing this software for educational use only. Licensing this algorithm from PKP is the responsibility of you, the user, not Philip Zimmermann, the author of this software. The author assumes no liability for any breach of patent law resulting from the unlicensed use of this software by the user.

+/ #include #include #include #include #include

"mpilib.h" "genprime.h"' "rsagen.h"' "random.h" "rsaglue.h"

static void derive_rsakeys (unitptr n, unitptr e, unitptr d, unitptr p, unitptr q, unitptr u, short ebits); /* Given primes p and q, derive RSA key components n, e, d, and u.

/* Define

some

error

#define

KEYFAILED

#define

swap(p,q)

status

returns

-15 /* key failed

for

RSA

keygen...

final test

{ unitptr t; t =p;

p=q;

*/

*/

q=t;

}

*/

725

+/

Code and Internals

PGP Source

/*

*/

726

/*

/*

derive_rsakeys +/ static

void

derive_rsakeys

(unitptr n, unitptr

e, unitptr d,

unitptr p, unitptr q, unitptr u, short ebits) /* * Given primes p and q, derive RSA key components * The global_precision must have already been set * * * * * *

n, e, d, and wu. large enough for n.

Note that p must be < q. Primes p and q must have been previously generated elsewhere. The bit precision of e will be >= ebits. The search for a usable exponent e will begin with an ebits-sized number. The recommended value for ebits is 5, for efficiency’s sake. This could yield an e as small as 17.

{

unit F[MAX_UNIT_PRECISION] ; unitptr ptemp, qtemp, phi, G; /* scratchpads /*

*/

For strong prime which the modulus may It must be big enough goodprime reasonably

#define

latitude(bits)

*/

generation only, latitude is the amount differ from the desired bit precision. to allow primes to be generated by fast.

(max(min(bits/16,12),4))

/* between

4 and

12 bits

ptemp = d; /* use d for temporary scratchpad array */ qtemp = u; /* use u for temporary scratchpad array */ phi =n; /* use n for temporary scratchpad array */ G = F;

/* use

F for

if (mp_compare swap /*

both

G and

F */

(p, q) >= 0) /* ensure

(p, q); /* swap phi(n)

is

the

the pointers Euler

totient

that p 12) /* G shouldn’t get really big. mp_display ("\007G =", G); /* Worry the user. */ #Hendif

¥*/

*/

/* DEBUG

*/

*/

is

2.

of

*/

*/

Paves?

/*

mp -udiv mp _move

ei rsagentic?

#o'%/

(ptemp, qtemp, (F, qtemp);

fe

phi,

G); /* F(n)

= phi(n)/G(n)

¥*/

Pw

We

now

have

phi

and

F.

Next,

compute

e...

Strictly speaking, we might get slightly faster results by testing all small prime e’s greater than 2 until we hit a good e. But we can do just about as well by testing all odd e’s greater than 2. We could begin searching for a candidate e anywhere, perhaps using a random 16-bit starting point value for e, or even larger values. But the most efficient value for e would be 3, if it satisfied the gcd test with phi. Parameter ebits specifies the number of significant bits e should have to begin search for a workable e. We OE TE 96 oe ee Te ee i Make e at least 2 bits long, and no longer than one bit * shorter than the length of phi. *

/

ebits = min if (ebits == ebits = 5; ebits = max

mp_init

(ebits, countbits (phi) - 1); 0) /* default is 5 bits long */ (ebits, 2);

(e, 0);

mp_setbit (e, ebits - 1); lsunit (e) |= 1; /* set e candidate’s mp_dec (e);

mp_dec

(e);

/* precompensate

lsb

- make

for preincrements

it odd

*/

of e */

do

{ mp_inc mp_inc

(e); (e);

mp_gcd

(ptemp,

gced(e,phi(n)) while

(testne Now

/*

we

/* try odd e’s until e,

phi);

(ptemp,

(d,

e,

e such

*/ that

have

e.

1)); Next,

compute

inverse inverse p*q.

/

mp_inv

we get it. for

= 1 */

d is the multiplicative u is the multiplicative n is the public modulus *

/* look

F);

/* compute

d such

d,

then

u,

then

n.

of e, mod F(n). of p, mod q, if p= 0) { /* ensure that pp.

*/

for computing u */ mp_move

mp_move mp_move

(u, p);

(p, q); (q, wu);

/* See

mp_move

mp_sub

if p and

q are

far

enough

apart.

(u, q); /* use u as scratchpad

(u, p); /* compute q-p */

too_close_together

/* Keep trying

=

(countbits

q’s until

(u)

we get one

Is q-p big enough?

*/

< (countbits

far

enough

(q) - 7));

from p...

*/

*/

729

*/

/*

730

*/

while

/*

derive_rsakeys /* Now

test

unit

Code

and

Internals

(n,

e, d, p,

q, u,

(); /* ensure

ebits);

recycled random pool

key just to make

sure

--this

is destroyed

had better

work!

*/

*/

C[MAX_UNIT_PRECISION] ; obS

/* Create for

Source

(too_close_together) ;

trueRandFlush

bake

PGP

a dummy signature */ (i = 0;

i < 16;

itt)

CCbytes* eC) Filo= Ses eiire?; /* Encrypt it */ status

if

= rsa_private_encrypt

(status return

/* Extract status

if

< 0) /* modexp

status;

/*

return

the signature

return

< 0) /* modexp

status;

/*

(statisim! return

steps

*) C,

16,

e, d, p,

q, u, n);

*/

error

*) C, C,

e, n);

*/ status

same thing back.

*/

*/

a6)

KEYFAILED;

(GL S fe

al < lee

sinks),

if (((byte *) C)[iJ return

status

((byte

error?

return

/* Verify that we got the af

error

(byte

*/

*/

= rsa_public_decrypt

(status

(C,

error?

!= 3 * i + 7)

KEYFAILED;

a return 0; /* normal } /* rsa_keygen */ oboe em:

return

End

*/

of RSA-specific

routines

se

/

*/

/*

File:

‘rsaglue.h’

: /* File:

¢

*/

7%

‘rsaglue.h’

/* (New File) */ /* rsaglue.h extern

char

|

- Glue

routines

signon_legalese[]

/* Declarations

*/

for RSA

encryption

and decryption

*/

;

*/

int rsa_public_encrypt (unitptr outbuf, byteptr inbuf, short bytes, unitptr E, unitptr N); int rsa_private_encrypt (unitptr outbuf, byteptr inbuf, short bytes, unitptr E, unitptr D, unitptr P, unitptr Q, unitptr U, unitptr int rsa_public_decrypt (byteptr outbuf, unitptr inbuf,

unitptr E, unitptr int rsa_private_decrypt unitptr

E,

N);

(byteptr

unitptr

N);

D,

outbuf,

unitptr

unitptr P,

unitptr

inbuf, Q, unitptr

U,

unitptr

N);

Sst

*/

/*

732

#/

/*

/* File: /*

‘rsagluet.c’

PGP

Source

Code

and

Internals

*/

(New File) */

SS*

rsagluei.c

data

- These

functions

encryption keys

(DEKs)

wrap

and unwrap

message

digests

in padding and RSA-encrypt

them

(MDs)

and

into

multi-precision integers. This layer of abstraction was introduced to allow the transparent use of either the RSAREF Cryptographic Toolkit from RSA Data Security Inc for the RSA calculations (where the RSA patent applies), or, Philip Zimmermann’s mpi library for the RSA calculations. The rsaglue.c module from PGP version 2.3a performs the same functions as this module, but can be compiled to select the use of mpilib functions instead of RSAREF as the underlying math engine. That version of rsaglue.c would be suitable where the RSA patent does not apply, such as Canada. This file uses MPILIB to perform the actual encryption and decryption. It uses the same PKCS format as RSAREF, although it also accepts an older format used in PGP 2.1.

(c) Copyright

1990-1994

by Philip Zimmermann.

All rights reserved.

The author assumes no liability for damages resulting from the use of this software, even if the damage results from defects in this software. No warranty is expressed or implied. Note that while most PGP source modules bear Philip Zimmermann’s copyright notice, many of them have been revised or entirely written by contributors who frequently failed to put their names in their code. Code that has been incorporated into PGP from other authors was either originally published in the public domain or is used with permission from the various authors. PGP

is available

See the

important HEHE HEHEHE HEHE HE KH HH HHH HHHH certain

2;

if (i > nndigits) i = nndigits; nndigits -= i; #ifdef

HIGHFIRST

p = (word32

*) (mpi + global_precision) ;

0);

749

*/

/*

750

while

*/

/*

PGP

Source

Code

and

Internals

(i--)

saqiness

ES

L385

#else

p = (word32

*) mpi;

while (i--) *nnt+ = *pt+; #Hendif

while

(nndigits-—)

*nnt++

= 0;

i /*

NN_ModExp */ void NN_ModExp word32

unit unit alae

(word32 * result, word32 * base, * modulus, unsigned moddigits)

Sie

oldprecision;

oldprecision

set_precision

= global_precision;

(MAX_UNIT_PRECISION) ;

nn2mpi

(b, base,

nn2mpi

(c, exponent,

nn2mpi

(d, modulus,

moddigits);

expdigits) ; moddigits);

i = mp_modexp (a, b, c, d); ayasciaa (al SS @))s mpi2nn (result, moddigits, a);

set_precision te ndif

* exponent,

a[MAX_UNIT_PRECISION] , b[MAX_UNIT_PRECISION] ; c[MAX_UNIT_PRECISION], d[MAX_UNIT_PRECISION] ;

unsigned

}

word32

(oldprecision) ;

unsigned

expdigits,

*/

/*

File:

‘sleep.c’

/* File: /* (New File)

*/

/*

‘sleepyc?

*/

*/

[FREER * sleep.c -- provide

unix

style

sleep

function

*

AR A / #include /*

sleep */ int

sleep

(unsigned

long long

start; check;

long

finish;

secs)

time (&start); finish = start

+ (long) secs; #ifdef DEBUG printf ("sleep for 4d secs, stop time (&check); printf #endif

for

{

("it

is now

%ld\n",

eGys) time (&check); if (check > finish)

break;

return

I

(0);

sleeping

check);

at %ld\n",

secs,

finish);

761

#

/*

752

/*

*/

/*

Patlemmistdlvb,hh? */

/* (New File)

*/

/*

* Fake

+7,

stdlib.h

#Hinclude #ifndef

aAtolm@)s

extern

old

NULL

#define NULL #endif char *getenv char *malloc char *calloc char *realloc

long

for

int

( char *)0 () ’. () ’. 0) ,. ( ) .’

errno;

systems

PGP

Source

Code

and

Internals

*/

/*

File:

‘system.h’

/* File:

© */

/*

‘system.h’

*/

/* (New File) */ #ifndef #define

SYSTEM_H SYSTEM_H

#ifdef UNIX #if !defined(HAVE_UNISTD_H) #define HAVE_UNISTD_H #tHendif

&&

!defined(MACH)

&&

!defined(_BSD)

#ifdef HAVE_UNISTD_H #include #else

#include

#include

#Hendif

int getch

int kbhit

();

();

/* replacement

function for obsolete

#endif

*/

long Clock (); /* UNIX

#if defined(UNIX) void

ttycbreak

void ttynorm

|| defined(AMIGA)

clock(),

|| defined(VMS)

();

();

#else

#define #define

ttycbreak() /* nothing */ ttynorm() /* nothing */

#endif #if

'defined(MSDOS)

char

*strlwr

(char

&&

*);

#Hendif

void

breakHandler

#endif

/* SYSTEM_H

(int);

*/

just provides random data */

!defined(ATARI)

753

*/

/*

754

+*/

/*

/* File: /* (New File)

‘system.c’

PGP

Source

Code

and

Internals

*/

*/

aS*

system.c

Routines

specific

for non-MSDOS

implementations

of pgp.

(c) Copyright 1990-1994 by Philip Zimmermann. All rights reserved. The author assumes no liability for damages resulting from the use of this software, even if the damage results from defects in this software. No warranty is expressed or implied. Note that while most PGP source modules bear Philip Zimmermann’s copyright notice, many of them have been revised or entirely written by contributors who frequently failed to put their names in their code. Code that has been incorporated into PGP from other authors was either originally published in the public domain or is used with permission from the various authors. PGP is available for free to the public under certain restrictions. See the PGP User’s Guide (included in the release package) for important information about licensing, patent restrictions on certain

algorithms,

trademarks,

copyrights,

and

export

controls.

Modified 24-Jun-92 HAJK Adapt for VAX/VMS. Modified: 11-Nov-92 HAJK Add FDL Support Routines.

Modified: 31-Jan-93 HAJK Misc. updates for terminal Add VMS command stuff. Add fileparse routine.

HEHEHE HEHE HEH OE HH HH HHH

handling.

*/ #include #include #include #include

"“exitpgp.h" "system.h" "usuals.h"

*/ #if def

UNIX

/* *

* *

Define USE_SELECT to use the select() system call to check if keyboard input is available. Define USE_NBIO to use non-blocking read(). If you don’t define anything the FIONREAD ioctl() command

*/

/*

File:

* will

‘system.c’

be

*/

/*

755

used.

*

* Define

NOTERMIO

*/

if you

#include

#include

don’t

have

the

termios

stuff

#ifndef NOTERMIO #ifndef SVR2 #include #else #include

#endif

/* not SVR2 */

#else

#include

#Hendif

#ifdef

USE_SELECT

#include #ifdef

_IBMR2

#include

#endif /* _IBMR2 #else #ifndef USE_NBIO #ifndef sun

#include

*/

/* for FIONREAD

#else /* including both #include #endif /* sun */ #ifndef #define #endif #endif #endif

FIONREAD FIONREAD

#include

static static static

ioctl.h

TIOCINQ

void setsigs (void); void rmsigs (void); void sigi (int);

static void sig2 (int); void breakHandler (int); static) int-ttyid-= -1; #ifndef SVR2 static void (*savesig) (int); #else

static

int

(*savesig)

#endif

void ttycbreak

void ttynorm

(void);

(void);

(int);

*/

and termios.h

gives

a lot of warnings

on sun */

*/

/*

756

#ifndef #undef #endif

*/

/*

PGP

Source

Code

and

NEED_KBHIT USE_NBIO

#ifndef NOTERMIO #ifndef SVR2 static struct termios itio, tio; #else static struct termio itio, tio;

#endif

/* not

SVR2

+/

struct

sgttyb

#else

static

isg,

sg;

#endif

#ifdef static static

USE_NBIO int kbuf = -1; int fflags;

/* buffer

to

store

char

read

O_RDWR))

< 0)

by kbhit()

*/

#endif static

int gottio

= 0;

/*

ttycbreak */

void

ttycbreak {

(void)

if (ttyfd

== -1)

{ if

((ttyfd = open

fprintf (stderr, ttyfd = 0;

("/dev/tty",

"cannot

open tty,

using

stdin\n");

} #ifndef #ifndef

NOTERMIO SVR2

if (tcgetattr

(ttyfd,

&tio)

< 0)

#telse

ifscioctl

#endif {

(ttyid,

ICGETA,

&til0)

fprintf (stderr, "\nUnable perror ('tocti") exitPGP

(1);

itio = tio; setsigs (); gottio = 1; #ifdef

_kbhitChan_ IOSB

=

0;

");

/*

Prompt

string

*/

Internals

*/

/*

File:

‘system.c’

unsigned unsigned unsigned unsigned

}

short short short short

*/

/*

765

sts; byteCount; terminator; terminatorSize;

iosb; static

$DESCRIPTOR

static

volatile

char

(kbdev_desc,

"SYS$COMMAND:");

struct

Class;

char Type; unsigned short BufferSize; unsigned int Mode; int

}

ExtChar;

CharBuf,

OldCharBuf;

static $DESCRIPTOR File Descr */

(out_file_descr,

static

FDL$M_FDL_STRING;

int

flags

=

**-kbhit_handler-This

exit

"SYS$DISK:[]");

handler

restores

the

/* Default

terminal

Output

characteristics

Description: This procedure is invoked to return the the terminal to normality on what you think is normal!). Anyway, it gets called to restore characteristics either through ttynorm or via an exit handler.

*/

/*

po

enenalen

*

static

void

kbhit_handler

ttynorm (void)

(int

*sts)

();

sys$dassgn

_kbhitChan_) ;

_kbhitChan_

(

= 0;

} /* * Data

*/

Structures

unsigned static

int

struct

exsts;

For Linking

Up Exit

Handler

(depends

7,

766

*/

/*

PGP Source

Code

and

Internals

Sen GaelKee VOID *rtn; int argcnt; int *stsaddr;

a exhblk

=

0, &(kbhit_handler),

1, &(exsts)

. ’

—*

**-kbhit_Getchn-Get Functional

Channel

Description:

Private routine to get characteristics.

a terminal

channel

and save

the terminal

Arguments: None. Returns:

If 0, channel already assigned. If odd, otherwise returns VMS error status. Implicit

Channel

Initial Channel

ee ee ee ee 2 ee ee RE Oe ~S*

Spit ag setulae *

So AtCu lint kb hit_Getchn

()

t if

successful

assigned to the terminal

(if any).

terminal assigned

characteristics. to the terminal.

Effects:

Establishes an exit terminal channel.

he

was

Outputs:

OldCharBuf _kbhitChan_ Side

assign

Inputs:

_kbhitChan_ Implicit

then

SES

= Og

(_kbhitChan_

==

0)

handler

to

restore

characteristics

and

deassign

*/

/*

File:

‘system.c’

if ((sts

¥*/

= sys$assign

/*

(

&kbdev_desc, &_kbhitChan_,

0,

0)) & 1)

{

if ((sts

= sys$qiow

(

0, _kbhitChan_, I0$_SENSEMODE, &iosb, 0,

0, &01ldCharBuf,

Te

0, 0, 0, 0))

& 01) sts = iosb.sts; sae (Ghee €2 Oil) if

(!(OldCharBuf.Class

& DC$_TERM) )

of fprintf exitPGP

(stderr, (1);

(void)

return

"\nNot

sys$dclexh

running

on

a terminal");

(&exhblk);

(sts);

}

/* * **k-ttynorm-Restore

initial

terminal

characteristics

*

* Functional

Description:

*

* This

procedure

*/ /*

ttynorm */ void

ttynorm

()

/* * Arguments: *

*

None.

is

invoked

to restore

the

initial

terminal

characteristics.

767

*/

768

Ss*

+/

/*

PGP

Source

Code

and

Internals

*

* Implicit

Inputs:

*

* *

QOldCharBuf _kbhitChan_

Initial Channel

terminal assigned

characteristics. to the terminal.

*

* Implicit

Outputs:

*

*

None.

Al ‘l int

if

sts;

(_kbhitChan_

!= 0)

1 CharBuf.Mode

=

OldCharBuf.Mode;

CharBuf.ExtChar

=

OldCharBuf.ExtChar;

/*

CharBuf.Mode &= ~TT$M_NOECHO; CharBuf.ExtChar &= ~TT2$M_PASTHRU;

*/ if ((sts

= sys$qiow

(

0, _kbhitChan_, I0$_SETMODE, &iosb,

0,

0,

&OldCharBuf ,

sts

=

iosb.sts;

ifuGi(sts

at

&101))

fprintf (stderr, "\nFailed (void) lib$signal (sts);

5

to reset

terminal

characteristics!");

} return;

a; /* * **-kbhit-Find

out

if a key has

been

pressed

*

* Description: *

* Make the terminal noecho and sense * the typeahead count. Note that the

the characters coming in by looking at character remains in the typeahead buffer

/*

File:

‘system.c’

* untill * mode.

either

¥*/

read,

or that

/*

the

user

types

a Control-X

* Arguments: None. Returns:

TRUE FALSE

if there if there

is a character in the typeahead buffer. is no character in the typeahead buffer.

Intescse struct

ef unsigned

short

TypAhdCnt ;

char

FirstChar;

char

Reserved[5];

} TypCharBuf ;

/* **x

Get

typeahead

*/

if ((sts = sys$qiow

count

(

0,

_kbhitChan_, IO$_SENSEMODE

| IO$M_TYPEAHDCNT,

&iosb,

0, O,

&TypCharBuf ,

8, 0, 0, 0, 0))

& 01) sts =

iosb.sts;

if (sts & 01)

return (TypCharBuf.TypAhdCnt (void) lib$signal (sts);

exitPGP

(1);

> 0);

when

not

in

769

’passall’

*/

/*

WerO!

static {0,

ef,

/*

int NoTerm[2]

0};

/*

Source

Code

and

Internals

=

TT Terminator

**-getch-Get

PGP

Mask

a character

(Nothing)

and return

*/

it

Description: Get

a character

from

will be explicitly character

is

the

keyboard

echoed unless

in the

typeahead,

and

return

ttycbreak()

that

will

it.

be read

* Arguments: None. Returns: ag Hap san Gar Go

A

Character

Read.

* =

unsigned

int

volatile

char

if (((ste

sts; CharBuf;

= kbhit_Getchn

if ((sts = sys$qiow 0, _kbhitChan_, IO$_READVBLK , &iosb,

0, 0, &CharBuf ,

1, 0, &NoTerm,

0 )) & 01) sts

i

iosb.sts;

if (sts & 01)

()) & 01)

(

Unlike

has been

|| sts == 0)

first.

Unix,

called

the

first.

character

If the

*/

/*

File:

‘system.c’

*/

/*

return ((int) CharBuf); fprintf (stderr, "\nFailed (void) lib$signal (sts);

to

get

character");

} **-putch-Put

*

Character

To

’Console’

Device

*

* This procedure is a companion to getch, outputing a character to the * terminal with a minimum of fuss (no VAXCRTLK, no RMS!). This routine * simply gets a channel (if there isn’t one already and uses QIO to * output. *

putch */ int

putch

(int

chr)

/*

Arguments: chr

*

Character

to

output.

Returns:

Status Side

return

Getchn

and

qio.

Effects

& eh +eeeeeeue May assign a

{

from

channel

to the

terminal.

*/ unsigned

int

sts;

if (((sts = kbhit_Getchn if ((sts

= sys$qiow

0, _kbhitChan_, IO$_WRITEVBLK, &iosb,

)) & 01) iosb.sts;

()) & 01) (

|| sts == 0)

771

*/

/*

¥/

FTTD

Te

PGP Source

Code

and Internals

Ny if

(stse&201) return (sts); fprintf (stderr, "\nFailed (void) lib$signal (sts);

to put

character");

2 /*

* *k-ttycbreak-Set

Unix-like

Cbreak

mode

*

* Functional

Description:

*

* This code must * disables echo,

be invoked to produce the Unix-like allows control character input.

cbreak

*/ /*

ttycbreak */ void

ttycbreak

()

/*

* Arguments: None. Returns:

None.

Side

Effects

May assign

a channel

to the

terminal.

HEHE HF HK HE eee Ss

if

struct

unsigned

short

TypAhdCnt ;

char

FirstChar;

char

Reserved[5];

sy TypCharBuf; char buf[80]; SIH. BESS

ao

—skbhitmGetchnm

/* * Flush

#7,

any

typeahead

if ((sts

©)

before

= sys$qiow

(

mcm Ol)

we

mllmstsm——m0))

change

characteristics

operation

which

*/

/*

File:

‘system.c’

0, _kbhitChan_, IO$_SENSEMODE

+*/

/*

; | IO$M_TYPEAHDCNT,

&iosb,

0,

0,

&TypCharBuf,

8, >

0> 0) 0 )) sts

=

& 01)

iosb.sts;

if

(sts)

{ if (TypCharBuf.TypAhdCnt > 0) af if ((sts = sys$qiow ( 0, _kbhitChan_, IO$_READVBLK &iosb,

| IO$M_NOECHO

| IO$M_TIMED,

0, 0, &buf ,

(TypCharBuf.TypAhdCnt >= 80 ? 80 TypCharBuf .TypAhdCnt) , 1,

:

&NoTerm,

0, sts

0)) & 01) iosb.sts;

=

if (sts) TypCharBuf .TypAhdCnt

-=

iosb.byteCount ;

A;

i

if (!(sts & 01))

TypCharBuf.TypAhdCnt = 0; /* * Modify characteristics

*/ CharBuf

=

OldCharBuf;

CharBuf.Mode

=

CharBuf.ExtChar

if ((sts 0

_kbhitChan_, IO$_SETMODE, &iosb,

Oo,

(OldCharBuf.Mode =

| TT$M_NOECHO)

OldCharBuf.ExtChar

= sys$qiow

(

& ~TT$M_NOTYPEAHD;

| TT2$M_PASTHRU;

773

+/

8774

ie

/*

*y

PGP Source

Code

and Internals

0, &CharBuf,

125

sts

O))= e011) = iosb.sts;

if (!(sts & 01)) fh

fprintf

(stderr,

"\nttybreak()- Failed to (void) lib$signal (sts); exitPGP (1);

set

terminal

characteristics!");

ay

#ifdef

_USEDCL_

/* * *k-vms_getcmd-Get

VMS

Style

Foreign

Command

*

* Functional

Description:

*

* Get command from VAX/VMS foreign command line interface and parse * according to DCL rules. If the command line is ok, it can then be * parsed according to the rules in the DCL command language table. *

£7,

/*

vms_GetCmd af,

int

vms_GetCmd

(char *cmdtbl)

/* * Arguments: *

*

cmdtbl

Pointer

to

command

table

to

parse.

table

defined

in DROPDCL.CLD

*

* Returns: *

EF

He AIUD

*

* Implicit

Inputs:

*

*

*/

Command

language

*/

/*

File:

‘system.c’

+*/

ti bas Gs char cmdbuf [MAX_CMDSIZ]

unsigned struct

tO;

short

/*

775

;

cmdsiz;

dsc$descriptor

cmdbuf_d

Or Obs Ox;

struct

dsc$descriptor

infile_d =

{05.02.05 0}% char filenm[MAX_FILENM] ; unsigned short filenmsiz; unsigned short verb_size; /*

**

DCL

Parse

**

fake

Expects

A Command

Verb

Prefixing

The

Argumnents

’>

’ characters

it!

*/ verb_size

=

cmdprmt_d.dsc$w_length

cmdbuf_d.dsc$w_length

=

cmdbuf_d.dsc$a_pointer

MAX_CMDSIZ

= strncpy

-

2; /*

-

verb_size

Loose

(cmdbuf,

-

*/

1;

cmdprmt_d.dsc$a_pointer,

verb_size)

at UaGHeloy faslraGy Gp ale

cmdbuf[verb_sizet+] if

((sts

=’

’;

= lib$get_foreign

( /*

Recover

command

line from DCL */

&cmdbuf_d,

O, &cmdsiz, 0)) & 01)

cmdbuf_d.dsc$a_pointer = cmdbuf; cmdbuf_d.dsc$w_length = cmdsiz + verb_size; VAXC$ESTABLISH (lib$sig_to_ret); /* Force unhandled

to return */ sts = cli$dcl_parse

( /*

Parse

Command

Line

exceptions

*/

&cmdbuf_d, cmdtbl,

lib$get_input, lib$get_input, &cmdprmt_d);

} return

(sts);

I /* * **k-vyms_TstOpt-Test

for

command

qualifier

present

ok

* Functional

Description:

*

* This procedure is invoked to test whether an option * really just a jacket routine for the system routine * converting the argument and result into ’C’ speak. * * aS

is present. CLI$PRESENT

It

is

*/

/*

TT6

*/

/*

PGP Source

Code

and Internals

/*

vms_TstOpt |

vms_TstOpt

(char opt)

/*

Arguments:

*

opt

Character

label

of qualifier

to test

for.

Returns:

+1 QO -1

Option Option Option

Implicit He H¥ OK HH HHH Uses

present. absent. negated.

Inputs:

DCL

command

line

context

established

by vms_GetOpt.

*/ int sts; char buf;

struct

dsc$descriptor

i150.

0)

option_d =

Sputs.

buf = _toupper VAXC$ESTABLISH

(opt); (lib$sig_to_ret);

/*

Force

unhandled

exceptions

to return *+/ switch case

(sts = clif$present CLI$_PRESENT:

return

case

(£option_d))

(1);

CLI$_ABSENT:

return (0); case CLI$_NEGATED: return (-1); default:

return

(0);

}

Tee

**-vyms_GetVal-Get

Functional

This KH HHH eH * SS

Value.

Description:

procedure

qualifier

Qualifier

that

is

invoked

exists

to return

(See TstOpt).

the

value

associated

with

a

a¢/

/*

File:

‘system.c’

*/

f*

/*

vms_GetVal 77

vms_GetVal

(char opt,

char *resval,

/* * Arguments:

unsigned short maxsiz)

* *

opt

Character

* *

resval maxsiz

Pointer Maximum

label

of

qualifier

to resulting value size of string.

to test

for.

string.

*

* Returns: *

*

vel DSi. «

*

* Implicit

Inputs:

*

* Uses

DCL

command

line

context

established

by vms_GetOpt.

*/ sf int sts; char buf;

struct {iS -0

dsc$descriptor F505 but};

option_d

struct dsc$descriptor value_d {maxsiz - 1, 0, 0, resval}; unsigned short valsiz;

=

=

VAXC$ESTABLISH (lib$sig_to_ret); to return */ buf = _toupper (opt); if ((sts = cli$get_value (

/*

Force unhandled

exceptions

&option_d, &value_d,

&valsiz)) & 01) resval[valsiz] = return (sts);

’\0’;

} /*

* **-vms_GetArg-Get Functional

This e+ * &

+7

Value.

Description:

procedure

argument.

Argument

is invoked

to return

the value

associated

with an

BTTT

7

/*

778

*/

/*

PGP

Source

Code

and

/*

vms_GetArg */ vms_GetArg

(unsigned

short

arg,

char

*resval,

unsigned

short

maxsiz)

/*

* Arguments: *

*

arg

Argument

* *

resval maxsiz

Pointer Maximum

Number

(1-9)

to resulting value size of string.

string.

*

* Returns: *

>

Pl Bowne

*

* Implicit

Inputs:

*

* Uses

{

DCL

command

line

context

established

by vms_GetOpt.

*/ int

sts;

Gineue (psd (| S Wve struct dsc$descriptor option_d = (2, O5 ©, Vorbeizs struct dsc$descriptor value_d = {maxsiz - 1, 0, 0, resval}; unsigned short valsiz; VAXC$ESTABLISH

to return

(lib$sig_to_ret);

/*

Force

*/

but biJy="arci+

7.07;

if ((sts = cli$present (&option_d)) { if ((sts = cli$get_value (

& 01)

&option_d, &value_d,

&valsiz)) & 01) resvallvalsizi| =

?\02>

else

return (0); return (sts);

}

/* * **-do_help-Invoke *

VMS

Help

Processor

unhandled

exceptions

Internals

*/

/*

File:

‘system.c’

* Functional

*/

/*

779

Description:

*

* This procedure is invoked to display * using the standard VMS help library.

a suitable

help message

to the

caller

*

+7 /*

do_help +*/ do_help

(char *helptext,

char *helplib)

/* * Arguments: *

5

* *

helptext helplib

Text Help

of help request. library.

*

* Returns: *

* As for kbhit_Getchn

and lbr$output_help.

*

* Side

Effects:

*

* A channel

1

+7,

int

may be opened to the

terminal.

A library

is opened.

sts;

int helpflags; struct dsc$descriptor {strlen (helptext), 0, struct dsc$descriptor {strlen (helplib), 0,

helptext_d = 0, helptext};

helplib_d

=

0, helplib};

VAXC$ESTABLISH (lib$sig_to_ret); exceptions to return */

/*

Force

unhandled

if (((sts = kbhit_Getchn ()) & 01) || sts == 0) ! helpflags

= HLP$M_PROMPT

sts = lbr$output_help lib$put_output, &OldCharBuf

| HLP$M_SYSTEM

| HLP$M_GROUP

(

.BufferSize,

&helptext_d, &helplib_d,

&khelpflags,

lib$get_input) ; return (sts); } #Hendif /* _USEDCL_

*/

unsigned long vms_clock_bits[2];

/* VMS Hardware

Clock */

| HLP$M_PROCESS;

*/

/*

780

const

¥*/

/*

long vms_ticks_per_update

= 100000L;

PGP

/* Clock

Source

update

Code

int.

and

*/

* FDL Stuff For Getting & Setting File Characteristics * This code was derived (loosely!) from the module LZVIO.C in the * domain LZW compress routine as found on the DECUS VAX SIG tapes

* given,

Internals

public (no author

so no credits!)

*

/* * **#-fdl_generate-Generate

An FDL

*

* Description: *

* This procedure takes the name of an existing file * an fdl. The FDL is retuned by pointer and length. * released after use with a call to free();

as input and creates The FDL space should

*/ /*

fdl_generate */ int fdl_generate

(char

*in_file,

char

**fdl,

short

*len)

/* * Arguments: *

*

in_file

char*

Filename

fdl

char*

Pointer

len

short

Length

bit

means

of file to examine

(Zero terminated).

*

*

to FDL that

was

*

*

of FDL

*

* Status

Returns:

*

* VMS

{

style.

lower

set

success.

*/ struct

dsc$descriptor

fdl_descr

{0, DSC$K_DTYPE_T, DSC$K_CLASS_D,

0}; struct FAB fab, *fab_addr; struct RAB rab, *rab_addr; struct NAM nam; struct XABFHC xab; Initmsitse

int

badblk;

=

created.

created.

be

*/

/*

File:

‘system.c’

+*/

/*

781

/*

i2 is ta FDL Descriptor

if ('(sts

.

= str$geti_dx

return

(&FDLSIZE,

&fdl_descr))

& 01)

(0);

/*

* Build

*/ fab

RMS

Data

Structures

= cc$rms_fab;

fab_addr

nam rab

=

&fab;

= cc$rms_nam; = cc$rms_rab;

rab_addr

=

&rab;

xab = cc$rms_xabfhc; fab.fab$l_nam = &nam; fab.fab$l_xab = &xab; fab.fab$l_fna = in_file; fab.fab$b_fns = strlen (in_file); rab-rab$lifab = &fab; fab. fab$b_fac FAB$M_GET | FAB$M_BIO; /* * Attempt

open block mode

only */

to Open File

*/ if (!((sts { if

/* This

= sys$open

(&fab))

& 01))

(verbose)

“f fprintf (stderr, "\n(SYSTEM) Failed to $0PEN %s\n", (void) lib$signal (fab.fab$l_sts, fab.fab$1l_stv);

in_file);

} return

(sts);

as if

(fab.fab$l_dev

& DEV$M_REC)

i fprintf sts

=

(stderr,

"\n(SYSTEM)

Attempt

to read

from

output

only

device\n");

0;

} else

rab.rab$l_rop = RAB$M_BIO; if ('((sts = sys$connect (&rab))

& 01))

if if

(verbose)

A fprintf (stderr, "\n(SYSTEM) Failed to $CONNECT %s\n", (void) lib$signal (fab.fab$l_sts, fab.fab$l_stv) ;

} } else

{

if ('((sts

= fdl$generate

(

in_file);

*/

/*

782

*/

/*

PGP

Source

Code

and

Internals

&flags, &fab_addr, &rab_addr,

NULL, NULL, &fdl_descr, &badblk, len)) & 01))

if (verbose) fprintf (stderr, "\n(SYSTEM) inefite); free

Failed to generate

FDL\n",

(fdl);

} else

x

if (!(*fdl = malloc

return

memcpy (void)

(*fdl,

fdl_descr.dsc$a_pointer,

str$freei_dx

sys$close Tetum

*len);

(&fdl_descr);

(&fab) ;

(stsyr:

**-fdl_close-Closes

*

(*len)))

(0);

files

created

by fdl_generate

*

* Description: *

*

This procedure is invoked * allocated by fdlfparse.

to

close

the

file

and release

the

data

structures

*/ /*

fdl_close */ void

fdl_close

(void

*rab)

/*

* Arguments: *

*

rab

VOID

*

* Returns: *

*

*/

None.

uf struct

FAB

*fab;

*

Pointer

to

RAB

(voided

to

avoid

problems

for

caller).

*/

/*

File:

‘system.c’?

fab = ((struct tte

¥*/

/*

RAB *) rab)->rab$l_fab;

(Chab)

f

{ /* Close file if not if (fab->fab$w_ifi) sys$close

783

already

closed */

(fab);

} fdl¢$release

(NULL,

&rab);

/*

**-fdl_create-Create

A File

Using the

recorded

FDL

(hope we get it right!)

Description:

This

procedure

there is no subsystem.

accepts

way

we

can

an FDL and uses easily

patch

it create

into

the

a file.

back

of the

Unfortunately VAX

C I/0

* & *eex*e** SS

/*

fdl_create */ VOID

*

fdl_create

(char

*fdl,

short

len,

char

string

*outfile,

char

*preserved_name)

/* *

Arguments:

*

*

fdl

char*

FDL

len

short

Returned

outfile

char*

Output

descriptor.

*

*

string

length.

*

*

filename.

*

*

preserved_name

char*

Name

from

FDL.

*

* Returns: *

*

{

O in case

of

error,

or

otherwise

*/ VOID *sts; int sts2; struct FAB

*fab;

struct

*rab;

RAB

struct NAM nam; int badblk; char

*resnam;

struct

dsc$descriptor

fdl_descr

=

the

RAB pointer.

*/

/*

784

*/

/*

PGP

Source

Code

len, DSC$K_DTYPE_T, DSC$K_CLASS_S, fdl

Fi sts

= NULL;

/*

* Initialize

RMS

NAM

Block

*/ nam = cc$rms_nam; nam.nam$b_rss = NAM$C_MAXRSSLCL; nam.nam$b_ess = NAM$C_MAXRSSLCL; if ('(resnam = nam.nam$l_esa = malloc af

fprintf return

/* * Parse

(stderr,

"\n(FDL_CREATE)

(NAM$C_MAXRSSLCL

+ 1)))

Out of memory! \n") ;

(NULL);

FDL

7

if ('((sts2

= fdl$parse

(&fdl_descr,

&fab, &rab,

&flags)) {

& 01))

fprintf

(stderr,

(void)

lib$signal

"\nCreating

(fdl$parse)\n");

(sts2);

else

af /* * Extract

& Return

Name

of FDL

Supplied

Filename

aif memcpy (preserved_name, fab->fab$l_fna, preserved_name[fab->fab$b_fns] = ’\0’; /*

* Set

Name

Of Temporary

File

*/ fab->fab$l_fna

= outfile;

fab->fab$b_fns

= strlen

/* * Connect

NAM

(outfile);

Block

*/ fab->fab$l_nam fab->fab$1_fop

= &nam; |= FAB$M_NAM

| FAB$M_CIF;

fab->fab$b_fac

|= FAB$M_BIO

| FAB$M_PUT;

/*

* Create

File

*/ if ('(sys$create

(fab)

& 01))

fab->fab$b_fns) ;

and

Internals

*/

/*

File:

‘system.c’

+*/

/*

785

{ fprintf (stderr, "\nCreating (RMS)\n"); (void) lib$signal (fab->fab$l_sts, fab->fab$1_stv); fdl_close

+

(rab);

else

{

if (verbose)

i;

resnam[nam.nam$b_esl + 1] = ’\0’; fprintf (stderr, "\nCreated %s successfully\n",

resnam) ;

rab->rab$l_rop = RAB$M_BIO; if [ (!(sys$connect (rab) & 01))

fprintf

(stderr,

(void)

lib$signal

fdl_close

"\nConnecting

(RMS)\n");

(rab->rab$l_sts,

rab->rab$l_stv) ;

(rab);

else sts

=

rab;

M, so

fab->fab$l_nam = 0; /* I allocated I must deallocate it! */

NAM block,

free (resnam) ; return (sts);

} /* * **-fdl_copyfile2bin-Copies

the

input

file

to a

’binary’

output

file

*

* Description: *

* * * *

This procedure is invoked to copy from an opened file f to a file opened directly through RMS. This allows us to make a block copy into one of the many esoteric RMS file types thus preserving characteristics without blowing up the C RTL. This code is based directly on copyfile from FILEIO.C.

oe

* Calling

Sequence:

*/ /*

fdl_copyfile2bin +/ int fdl_copyfile2bin *

* Arguments: *

(FILE

* f, VOID

* rab,

word32

longcount)

a7

/*

T86

*

*/

/*

ai

FILE*

Pointer

to

input

rab

RAB*

Pointer

to

output

longcount

word32

Size

PGP Source

Code and Internals

file

*

*

file

RAB

*

*

of file

*

* Returns: *

£

*

0

If we

* *

-1 +1

We had an error We had an error

were

successful.

on the input file (VAXCRTL). on the output file (direct RMS).

7, int

status = 0; count; ((struct RAB *) rab)->rab$l_rbf

&textbuf ;

((struct

0;

word32

RAB

*) rab)->rab$1_bkt

do

{ /*

Read

and write

count

if (longcount = longcount;

count

else = DISKBUFSIZE;

longcount

< (word32)

count = fread (textbuf, cise ((@oinsigs = (0)

bytes

*/

DISKBUFSIZE)

1, count,

f);

{

/* * *

No byte order conversion required, source VMS so have the same byte ordering.

*/ ((struct RAB *) rab)->rab$w_rsz if ('!(sys$write (

and target

= (unsigned short)

rab,

NULL, NULL)

& 01))

{ lib$signal (((struct RAB *) rab)->rab$l_sts, ((struct RAB *) rab)->rab$l_stv); status break;

} longcount

=

-=

1;

count;

} while (count == DISKBUFSIZE) ; burn (textbuf); return (status);

} /*

* **-vms_fileparse-Parse

A VMS

File

Specification

system

count;

are

both

aif

File:

Ps*

‘system.c’

Functional

*/

/*

Description:

This procedure is invoked to parse and related specifications to fill little like DCL’s F$PARSE function (that is we don’t check the device spec is really for when we want to directory) to supply the name of an

a VMS file specification using default in any missing components. This works a with the syntax check only specified or the directory). The related file use the name of an input file (w/o the output file.

Note that we correctly handle the situation where the output the input filespec by testing for the case and then handling OF He HE EH eH “eee the primary input specification to a temporary buffer before

buffer overlays it by copying parsing.

* ~~

/*

vms_fileparse */ int vms_fileparse /* * Arguments:

(char

*outbuf,

char

*filespec,

char

*defspec,

*

*

outbuf

Returned

* * *

filespec defspec relspec

Primary Default Related

file

file file file

specification.

specification specification specification

*

* Returns: *

*

As

for

SYS$PARSE.

*

* Implicit

Inputs:

*

*

None.

*

* Implicit

Outputs:

*

*

None.

*

* Side

Effects:

*

*

{

5 oAlieisye

*/ struct struct

FAB fab = cc$rms_fab; NAM nam = cc$rms_nam;

struct

NAM rlnam

intests)

int char

=

787

= cc$rms_nam;

1;

len; tmpbuf

[NAM$C_MAXRSSLCL]

;

(optional). (optional). (optional).

char

*relspec)

+/

788

/*

char

*/

/*

PGP

Source

Code

and

Internals

expfnam2[NAM$C_MAXRSSLCL];

slat (outbuf

!= NULL)

CKetwlowae [Ol] =

Pe)? 5

fab.fab$l_fop nam.nam$b_nop

!= FAB$M_NAM; /* Enable RMS NAM block processing |= NAM$M_PWD | NAM$M_SYNCHK;

/*

**

Handle

/

if (relspec ste ((len

Related

Spec

(If reqd).

!= NULL)

= strlen

(relspec))

> 0)

fab.fab$l_nam = fab.fab$b_fns = fab.fab$l_fna = rlnam.nam$b_ess

&rlnam; len; relspec; = NAM$C_MAXRSSLCL;

rinam.nam$l_esa

=

expfnam2;

rlnam.nam$b_nop |= NAM$M_PWD if ((sts = sys$parse (

| NAM$M_SYNCHK;

&fab,

0, 0)) & 01) rlnam.nam$l_rsa

= rlnam.nam$l_esa;

rinam.nam$b_rsl

=

rlnam.nam$b_es1;

nam.nam$1_rlf

= &rlnam;

fab.fab$l_fop

|= FAB$M_OFP;

i TE

ACsts)

fab.fab$l_nam nam.nam$l_esa nam.nam$b_ess

=

& nam ;

= outbuf; = N AM$C_MAXRSSLCL;

/*

**

Process

7, if (defspec if

((len

Specification:

!= NULL) = strlen

fab.fab$l_dna fab.fab$b_dns

**

Default

Process

(defspec))

> 0)

defspec; len;

Main

File

Specification:

*/

*/

/*

File:

‘system.c’

fab.fab$l_fna fab.fab$b_fns

*/

/*

789

= NULL; = 0;

if (filespec != NULL) { if ((len = strlen fab.fab$b_fns

(filespec))

> 0)

= len;

if (filespec == outbuf) fab.fab$l_fna = memcpy

(tmpbuf,

filespec,

len);

else

fab.fab$l_fna = filespec; } if ((sts

= sys$parse

(

&fab,

0, 0)) && 01) :

outbuf [nam.nam$b_esl] } return

=

’\0’;

(sts);

}

#endif

/* VMS */

aa

ee

a

ee

a

ee

oe

ee

ea

a

a

ae

ee

/*

aa

ae

SS

a

* AMIGA

*/

#ifdef

AMIGA

#include #include #include #include #ifdef

stuff

*/



LATTICE

#include #include #endif extern extern

/* Amiga-specific



/* LATTICE */ FILE *pgpout; int

aecho;

/* amiga version of getch() Cor

Bosman

+/

sendpacket struct struct

, jul-22-92

(struct

MsgPort

StandardPacket msgPort *rp;

*rec,

*pkt;

LONG

action,

LONG

arg1)

*/

/*

790

LONG

*/

resi

/*

=

PGP Source

*) CreatePort

(NULL,

OL))

if (pkt = (struct StandardPacket *) \ AllocMem (sizeof (struct StandardPacket), MEMF_PUBLIC pkt->sp_Msg.mn_Node.1n_Name pkt->sp_Pkt.dp_Link pkt->sp_Pkt.dp_Port pkt->sp_Pkt.dp_Type pkt->sp_Pkt.dp_Argi

= = = =

| MEMF_CLEAR))

= (BYTE *) & pkt->sp_Pkt;

&pkt->sp_Msg; rp; action; arg1;

PutMsg (rec, &pkt->sp_Msg) ; WaitPort (rp); GetMsg (rp); resi = pkt->sp_Pkt.dp_Res1; FreeMem ((UBYTE *) pkt, sizeof

DeletePort

(struct

StandardPacket)) ;

(rp);

ip (resi);

} / * ttycbreak for amiga. * Cor

Bosman

, jul-30-92

e/,

,*

ttycbreak *

/

Vv oid

ttycbreak { YI

sha,

() Ghrg

char buf[1i28]; struct MsgPort

in = Input out

();

ch = ((struct

I:

*ch;

();

= Output

sendpacket

FileHandle

(ch,

a

Bosman

*) BADDR

ACTION_SCREEN_MODE,

/ * ttynorm for amiga * Cor

and Internals

OL;

if (rp = (struct MsgPort

return

Code

, jul-30-92

(in))->fh_Type; -1L);

*/

/*

File:

‘system.c’

¥*/

/*

/*

ttynorm */ void

ee

()

BPTR

in,

out;

char buf[128]; struct MsgPort in = Input

*ch;

();

out = Output (); ch = ((struct FileHandle ; sendpacket

(ch,

*) BADDR

ACTION_SCREEN_MODE,

/*

getch */ char

getch (void) a éhar -buf[128]; BPIRe

In

Out;

in = Input

();

out = Output (); Reade(ian.) but. 1); if (aecho) Write (out, buf, return (buf[0]);

1);

}

/* kbhit() * Cor

function for amiga.

Bosman

, jul-30-92

*/ /*

kbhit */ int

kbhit () { if (WaitForChar return 1; return 0;

i;

(Input

(), 1))

(in))->fh_Type; OL);

(oil

*/

fe

INTO2

#ifdef

/*

=e/

PGP Source

Code

LATTICE

/*

*

Lattice-C

~“C-Handler

*/ /*

Che int CXBRK

()

af BPTR

in,

struct

out;

MsgPort

ing=) Input out

*ch;

();

= Output

();

/* it might happen we catch * so always set the screen

df

ch =

((struct

sendpacket

fprintf exitPGP

FileHandle

(ch,

a “C while in cbreak to the normal mode.

*) BADDR

mode.

(in) )->fh_Type;

ACTION_SCREEN_MODE,

OL);

(pgpout, "\n*+#* Program Aborted. \n") ; (6); /* INTERRUPT */

#Hendif

* clock.c

--

time

in microseconds

since

first

call

*

* RP:

this

function

is missing

from

SAS/C

*/ #include

/*

clock */ long

clock:

()

{

static unsigned long oldms unsigned long c1[2], ms; timer

(cl);

ms

= cl[0]

if

(oldms

* 1000000 ==

-1)

{ oldms = ms; return 0;

+ cl[i]

% 1000000;

library.

of

clock()

and

Internals

*/

/*

File:

‘system.c’

*/

/x

EF else

return

#endif

((long)

/* AMIGA

* other

stuff

(ms - oldms));

*/

for

non-MSDOS

systems

*/ #ifdef ATARI #include #endif #if

!'defined(MSDOS)

&&

#include

#include

''charset.h"

char

!defined (ATARI)

*

strlwr

(char *s)

4 /* #*

Turns

string

s into

lower

case.

*/. sireke (5 char *p =

s;

while (c = *p) *pt+ = to_lower return (s); } #tendif

/*

!MSDOS

&&

(c); ! ATARI

*/

/*

ey.

MV

Sstuestr

#Hifdef #undef

strstr strstr

/* Not

implemented

char

on

some

systems

*

mystrstr

(char *si,

shake Ge char *strchr

if (!s2 return

();

|| !*s2) s1;

char *s2)

-

return

first

instance

of

s2

in

si

*/

(ge

*/

/*

794

*/

/*

PGP

Source

Code

for: (=) { gf return

eCi¢cte=erstrchr

(si,

*s2)))

si;

for (i = 1; s2fi)

&& (sili)

== s20iJ);

++i)

gf 9('s2[i)) return

s1;

+t+3S1;

} #endif

/* strstr

#ifdef #undef

fopen fopen

#ifdef

ATARI

#define

*/

F_BUF_SIZE

8192 /* seems

to be a good value

...

*/

/*

myfopen */ FILE

*

myfopen (const char *filename, const char *mode) /* Open streams with larger buffer to increase disk /* Adjust F_BUF_SIZE to change buffer size.

I/0 speed.

*/ */

{ ISA,

ees

if ((f = fopen if

(setvbuf

fclose

(f);

f = fopen : return

#else

(filename, (f, NULL,

/* then

(filename, (f);

close

/* ATARI

it again

mode);

/* return

mode)) _IOFBF,

!= NULL) F_BUF_SIZE))

either

handle

*/

myfopen FILE

"b" from

2nd arg */

*

myfopen char

(char *filename, buf[1i0];

*/

*/

/* and try again in normal

/*

*/ /* Remove

/* no memory?

char *type)

or NULL

*/

mode

*/

and

Internals

+/

/*

File:

‘system.c’

¥*/

buf [0] = *typet++; if (*type == ’b’) ++type;

strcpy

(buf + 1, type);

return

fopen

#endif #Hendif

(filename,

/* not ATARI /* fopen */

buf);

*/

#ifndef MSDOS #ifdef OS2 static

eant

chr)

=

—1;

/*

kbhit */ int

kbhit (void) { af) (chr ==

—1)

chr e=)-read_kbd return

(chr

(0, 0, 0);

!= -1);

Ai /*

getch */ int

getch

(void)

t int. c;

if (chr >= 0) {

@ 2 ibe

iibgy Cale

} else

c = _read_kbd return

c;

t; #endif #Hendif

/* OS2 */ /* MSDOS */

(0,

1, 0);

/*

795

*/

/*

796

*/

/*

J/imrnsler

“usnalseh?

/* (New File)

/* usuals.h */

PGP

Source

-*&/

*/

- The usual typedefs, /* Assures

etc.

#ifndef

USUALS

#define

USUALS

typedef typedef typedef typedef typedef

unsigned char boolean; /* values are TRUE or FALSE unsigned char byte; /* values are 0-255 */ byte *byteptr; /* pointer to byte */ char *string; /* pointer to ASCII character string unsigned short wordi6; /* values are 0-65535 */

#ifdef

no redefinitions

of usual

types...

__alpha

typedef

unsigned

int word32;

#else typedef

/* values

unsigned

long word32;

are 0-4294967295

/* values

are

*/

0-4294967295

#Hendif

#ifndef #define #define

#Hendif #ifndef #define

TRUE FALSE 0 TRUE (!FALSE)

/* if TRUE not already min /* if min macro min(a,b) (((a)(b))

/* if min macro

/* void for use #ifndef #define

not

in pointers

defined */

not already defined ? (a) : (b) )

*/

? (a) : (b) ) already

defined

*/

*/

NO_VOID_STAR VOID void

#else

#define #tendif

VOID

char

/* Zero-fill the byte buffer. */ #define £i1110(buffer,count) memset(

buffer,

0, count

)

/* This file

macro is for burning sensitive data. Many of the I/O routines use it for zapping buffers */

#define

burn(x)

#endif

Code

fill0((VOID

/* if USUALS

not

*)&(x) ,sizeof(x))

already

defined

*/

*/

*/ */ */

and

Internals

+7

/*

File:

‘zbits.c’

/ +i Faille:

*/

/*

‘zbate:.c?

T97

ak/

/* (New File) */ /*

Copyright

(C) 1990,1991

Mark Adler,

Richard B. Wales,

and Jean-loup

Gailly.

Permission is granted to any individual or institution to use, copy, or redistribute this software so long as all of the original files are included unmodified, that it is not sold for profit, and that this copyright notice is retained. SS ~~*

bits.c This

by Jean-loup

is a new

Gailly.

version

of

im_bits.c

originally

written

by Richard

B.

Wales

PURPOSE

Output

variable-length

bit

strings.

DISCUSSION

The PKZIP "deflate" file format interprets compressed as a sequence of bits. Multi-bit strings in the file byte boundaries without restriction.

The

first

bit

of

each

byte

is the

The routines in this file allow be output right-to-left (useful left-to-right

output

the bits must

have been reversed

(useful

low-order

file data may cross

bit.

a variable-length bit value for literal values). For

for

code

strings

from

the

tree

to routines),

first with bi_reverse().

INTERFACE

void bi_init

(FILE *zipfile)

Initialize

the bit

void send_bits Write

out

string routines.

(int value, a bit

string,

int length) taking

the

source

bits

right

to

left.

int bi_reverse Reverse

right

(int value,

the

and

bits

of

emitting

string,

them right

void bi_windup (void) Write out any remaining HEHE KKH KEH KEK KKH HHH HH HHH HHH HK KKH HH KH

int length)

a bit

bits

taking

the

source

to left. in an

incomplete

byte.

bits

left

to

*/

/*

798

*

*/

/*

void

* t

copy_block(char

far *buf,

PGP

unsigned

Source

len,

Copy a stored block to the zip file, its one’s complement if requested.

Code

and

Internals

int header)

storing

first

the

length

and

*

*7, #include /*

=

"zip.h"

Sf

* Local

7

local

555555555555

data

FILE

used

by the

*zfile;

555555

"bit

/* output

5555

string"

zip file

local unsigned short bi_buf; /* Output buffer. bits are inserted * bits).

5555555555

55555

555

5555555555

55

SS

ES SSS

SS

routines.

*/ ; at the bottom

starting

(least

significant

cai

#define Buf_size (8 * 2*sizeof(char) ) /* Number of bits used within bi_buf. (bi_buf might be implemented on * more

than

16 bits

on

some

systems.)

*/ local int bi_valid; /* number of valid bits in bi_buf /* All bits above the last valid bit are always zero.

*/

yf #ifdef DEBUG ulg bits_sent; #endif

/* Output #define

/* bit

length

a 16 bit value

PUTSHORT(w)

(eCvoid)ezputce (void) zputc

/* Output

to the bit

SSS

SS

SS

SS

SS

+/

stream,

value

to the bit

SS

ES SS

the

SS

bit

SS

SS

SS

stream,

& Oxff),

SS

string

SS

SS

SS

SS

SS

SS

routines.

Diane */

(zipfile)

FILE *zipfile;

ab zfile

= zipfile;

(esl lied > 8), zfile);

an 8 bit

* Initialize

compressed

\

#define PUTBYTE(w) \ { (void) zputc ((char)((w) ty /*

of the

right

to left

*/

\

SS

SS

SS

SSS

SSS

SS

ee

eee

eee

eee

eee

eer

x/

/*

File:

‘zbits.c?

*/

/*

799

bi_valid = 0; #ifdef DEBUG bits_sent = OL; #endif

} /*

SSS

SS

SSS

SSS

SS

SS

SSS

SS

SS

SSS

SSS

SS

SSS

SS

SS

SSS

SS

SS

* Send a value on a given number of bits. * IN assertion: length 0 && length b) e -= 16; NEEDBITS (e)

while

((e =

(t = t->v.t

DUMPBITS

dat (@ 22

1G)

slide[wt+] if

\Gwe ==)

+

(b & mask_bits[e]))->e)

(t->b)

72 Wang

sige

a Wegecreul

= t->v.n; WSIZE)

{ flush w=

(w);

0;

iF } else

/* it’s £

an EOB or a length */

/* exit rae

(ey Se

if

end

Sl[5))

of block

*/

23//

> 16);

and

block.

bits

*/

Internals

tables

*/

*/

/*

File:

‘zinflate.c’

+/

/*

break;

/* get length of block to copy */ NEEDBITS

(e)

n = t->v.n DUMPBITS

+ (b & mask_bits[e]);

(e);

/* decode distance NEEDBITS (bd)

of block

to

copy

if ((e = (t = td + (b & md))->e)

*/

> 16)

4 af aGem==199)) return 1; DUMPBITS (t->b) e -= 16; NEEDBITS (e)

5 while

((e =

(t = t->v.t

+

(b & mask_bits[e]))->e)

> 16);

DUMPBITS (t->b) NEEDBITS (e)

d =w

- t->v.n

DUMPBITS

-

(b & mask_bits[e]);

(e)

/* do the copy */ do

£

ne—= (e =.(e #ifndef NOMEMCPY

if

= WSIZE



((d &= WSIZE

(w - d >= e) /* (this test

-

assumes

1) > wi2.d-:

unsigned

% memcpy (slide w t= e; d +=

}

+ w,

slide

+ d,

e;

else

/* do it slow to avoid memcpy()

#eendif /* !NOMEMCPY */ do

slide[w++] while

flush

Cwe==sWSLZE)

(w);

0;

WhaslewGn)s

}

IP

= slide[d++] ;

(--e); if

w=

e);

overlap

*/

w)).>.n.?

comparison)

n-:.e);

*/

835

*/

836

/*

*/

/*

PGP

Source

/* restore the globals from the locals */ wp = w; /* restore global window pointer */ bb = b; /* restore global bit buffer */ bk

= k;

/* done return

*/ 0;

/*

inflate_stored */ int

inflate_stored /*

af

()

"decompress"

an inflated

unsigned n; /* number unsigned

w;

type 0 (stored)

of bytes

/* current

window

unsigned

k;

copies

/* number

/* make

local

b = bb;

/* initialize

bit

/* initialize

window

*/

*/ of bits

of globals

in bit

*/

buffer

*/

k = bk;

w=

wp;

/* go to byte boundary

position

*/

*/

Ne= Ka 8 DUMPBITS (n);

/* get the length and its complement

*/

NEEDBITS (16) ny ES |e) 5 (Ob Gisentail DUMPBITS (16) NEEDBITS (16) ite(me=" Cob) &0xffit) ) return

DUMPBITS /* read

while

“t

1; /* error

in compressed

data

*/

(16) and

output

(n--)

the

*/

in block */ position

register ULONG b; /* bit buffer register

block.

compressed

data

*/

buffer

*/

Code

and

Internals

*/

/*

File:

‘zinflate.c’

NEEDBITS

slide[wt+] if

flush w=

*/

Vk

(8)

= b; (w ==

WSIZE)

(w);

0;

DUMPBITS

(8)

/* restore the globals from the locals */ wp = w; /* restore global window pointer */ bb = b; /* restore global bit buffer */ bk = k; return 0;



/*

inflate_fixed

=A/

int

inflate_fixed () /* decompress an inflated type 1 (fixed Huffman codes) block. We should either replace this with a custom decoder, or at least precompute the

Huffman tables.

*/

{ int

i; /* temporary

variable

*/

struct

huft

*tl;

/* literal/length

struct

huft

*td;

/* distance

code

int bl;

/* lookup bits

for tl */

int

/* lookup

for

bd;

unsigned 1[288];

"="0-

*/

*/

td */

/* length list for huft_build */

/* set up literal for(i

bits

code table table

table

i < 144;

*/

i++)

Liale= "8; for

(; i < 256;

itt)

1fi] = 9; for

280;

i++)

1 Pae= shy for (; i < 288;

(:—-i-
-="huftsebuidd?(1,

5;

430,10

bepdists/

cpdext,

> 1)

{ huft

free

return

(tl);

i;

/* decompress

until

an end-of-block

ifmCintlatescodess(tileatd.abl. return

/* free

*/

1;

the decoding tables,

huft_free huft_free return

code

ba)

return

*/

(t1); (td);

0;

/*

inflate_dynamic +/ int

inflate_dynamic () /* decompress an inflated


30) 1; /* bad lengths */ in bit-length-code

for’ (i = 0; {

i < nb;

NEEDBITS

lengths

*/

i++)

(3)

UAL | hevowatelere Mt| i) = je Ca 768 DUMPBITS

(3)

} siope

(CR Gi b;

| =

WG

DUMPBITS

11[it+]


n)

1;

(j--)

ii fits

=0;

L=..0;

} else

/* j ==

18:

11 to 138 zero

NEEDBITS

length codes

*/

(7)

fea 1iete(b DUMPBITS

820x772);

(7)

if? (4 return

ja >on) 1;

while (j--) Liisi) F=e"0; 1 =

0;

} }

/* free decoding huft_free (tl);

/* restore bb bk

table

for trees

*/

the global bit buffer

*/

= b; = k;

/* build the decoding tables bl

=

for literal/length

if?CCi

"= "huftsbuild

(Il

}inlye267,

ecpliens,

a if

(i ==

1)

huft_free (tl); return i; /* incomplete

A:

and distance

codes

lbits;

code

set

*/

Fcplextyestl,’

&bl))

=

0)

*/

*/

(*

eFilecvaSzinflate)clon) */

/*

bd = dbits; aS

= huft_build

(11 + nl,

nd,

0, cpdist,

cpdext,

&td,

if (i == 1) huft_free (td); huft_free (tl);

+

return

i; /* incomplete

/* decompress if

until

(inflate_codes return

code

an end-of-block (tl,

td,

bl,

*/

code

*/

bd))

1;

/* free the decoding tables, huft_free huft_free return

set

return

*/

(tl); (td);

0;

/*

Bs ene

|eherels

int

inflate_block

(e)

int *e; /* last block flag /* decompress an inflated block

{

unsigned

t; /* block

register

ULONG

b;

type */

/* bit

buffer

register unsigned

k; /* number

/ * make b = bb; k

local

buffer

/* read

in last

NEEDBITS * e=b DUMPBITS

/* read

block

bit

(1) & 1; (1)

in block

NEEDBITS

(2)

ae SS [s) ts GIG

DUMPBITS

bit

(2)

*/ */

type */

+*/

*/

*/

of bits

in bit buffer

*/

&bd))

!= 0)

841

7,

jx

MSA2

%/

:

/*

PGP

/* restore the global bit buffer */ ibbw=s bi: bk

=

k;

/* inflate that block type */ if (t == 2) return inflate_dynamic (); if (t == 0) return

if (t == return

inflate_stored

();

1) inflate_fixed

();

/* bad block type */ return

2;

/*

inflate_entry */ int

inflate_entry /* decompress u

() an inflated

entry */

int e; /* last block flag */

int r; /* result code */ unsigned h; /* maximum struct /* initialize ’ wp bk bb

window,

bit

huft’s

buffer

malloc’ed

*/

. ’

. ete(e)s) i) (2),

/* decompress h = do

until

the

last

block

*/

0;

{ hufts

if return

=

0;

((r =

qf Ghuttss h = hufts;

i; while

inflate_block

r;

('e);

>. h)

(&e))

!= 0)

*/

Source

Code

and Internals

*/

/*

~File:+,‘zinflate.c?.«

/* flush out flush (wp); /* return #ifdef

slide

success

*/

/*

*/

*/

DEBUG

fpmintt «(etderr, ¢'.s"'7 #endif /* DEBUG */ return

h);

0;

} /*

inflate +/ int

inflate

()

/* ignore

the

return

code

for

now

...

*/

{ int

status;

#ifdef

DYN_ALLOC

window

= (char *) calloc

/* Note *

that

array

+7.

is

if (window err

(4,

inflate shared

((unsigned)

only needs

with

deflate,

== NULL) DIC)

#endif

status

= inflate_entry

#ifdef

DYN_ALLOC

free

(window);

window #endif return

}

=

NULL;

status;

();

WSIZE,

WSIZE which

bytes, needs

2 * sizeof but

(char));

the

window

2+*WISZE

bytes.

843

*/

/*

844

*/

/ ee

;

eee

/* (New File)

/*

PGP

Source

Code

and

Internals

hes,

*/

/*

Copyright (C) 1990,1991 Mark Adler, Richard B. Wales, and Jean-loup Gailly. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as all of the original files are included unmodified, that it is not sold for profit, and that this copyright notice is retained.

+/

/* *

Zip.h

by Mark

Adler.

*/

/* Set up portability #include #define #define

*/

"ztailor.h" MIN_MATCH MAX_MATCH

/* The minimum

3 258

and maximum match

lengths

*/

#ifndef WSIZE #define WSIZE 8192 /* for PGP only use 8192 */ #endif /* Maximum window size = 32K. If you are really short of memory, compile * with a smaller WSIZE but this reduces the compression ratio for files * of size > WSIZE.

+y,

#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) /* Minimum amount of lookahead, except at the end of the * See deflate.c for comments about the MIN_MATCHt+1.

input

#define MAX_DIST (WSIZE-MIN_LOOKAHEAD ) /* In order to simplify the code, particularly on 16 bit * distances are limited to MAX_DIST instead of WSIZE.

machines,

file.

*/

#7; #include

/* Define #ifndef

#define

#Hendif

fseek()

commands

SEEK_SET

SEEK_SET

0

/* !SEEK_SET

*/

#ifndef SEEK_CUR #define SEEK_CUR 1 #Hendif /* !SEEK_CUR

*/

#ifndef #define

SEEK_END SEEK_END

2

*/

match

=,

/*

sePale: tak zips

#endif

/*

h?hod*/

!SEEK_END

/* For setting

/*

+/

stdout

to binary’*/

#ifdef MSDOS #include #include

#endif

/* MSDOS

*/

/* Types centralized #define local static typedef typedef

unsigned unsigned

here for easy modification */ /* More meaningful outside functions

typedef unsigned long ulg; /* Error #include

return codes "ziperr.h"

/* Internal #define #define #define

and

attributes

/* unsigned 32-bit value */ PERR

macro

*/

*/

UNKNOWN -1 BINARY O ASCII 1

/* Public

globals

#define

BEST

#define

STORE

#define

*/

char uch; /* unsigned 8-bit value */ short ush; /* unsigned 16-bit value */

-1

*/

/* Use

best

0 /* Store

DEFLATE

8 /* Deflation

extern

int method;

extern

int

level;

/*

DEBUG

extern

char

verbose;

#ifdef MSDOS #undef stderr #define stderr

(deflation

or

store)

*/

compression

method

*/

*/ method

/* Restriction Compression

/* Diagnostic functions #ifdef

method

method

on

+*/

level

*/

*/

/* PGP

-l

flag

*/

stdout

#endif

#define diag(where) fprintf(stderr, "zip diagnostic: %s\n", #define Assert(cond,msg) {if(!(cond)) error(msg) ;} #define Trace(x) fprintf x #define Tracev(x) {if (verbose) fprintf x ;} #define Tracevv(x) {if (verbose>1) fprintf x ;} #define Tracec(c,x) {if (verbose && (c)) fprintf x ;} #define #else

Tracecv(c,x)

{if

#define diag(where) #define Assert (cond,msg) #define Trace(x) #define Tracev(x) #define Tracevv(x) #define

Tracec(c,x)

(verbose>1i

&&

(c))

fprintf

x

;}

where)

845

*/

/*

846

#define #endif

*/

function

J/* Anazip.c,

prototypes

read_buf

#define #define

PGP

Source

Code

*/

Zipcloak.c,aorgzipsplit.c

err OF ((int c, error OF ((char

OF

¥/

char *h)); *h));

/* in zipup.c */ int zipup OF ((FILE * inFile, int

/*

Tracecv(c,x)

/* Public void void

,

((char

zfwrite fwrite zputc putc

far

FILE

* buf,

/* 7??? far

/* in deflate.c */ void lm_init OF ((int pack_level, ulg deflate OF ((void));

* outFile)); unsigned

size));

*/

ush

* flags));

/* in trees.c */ void ct_init OF ((ush * attr, int *Method)); inGuctetalivysor ((inttdist, int ic)); ulg flush_block OF ((char *buf, ulg stored_len,

int

eof));

/* in bits.c */ void bi_init OF ((FILE * zipfile)); void send_bits OF ((int value, int length));

unsigned bi_reverse OF ((unsigned value, int length)); void bi_windup OF ((void)); void copy_block OF ((char far * buf, unsigned len, int header)); /* end of zip.h */

and

Internals

*/

Ge

= BilepaYzipac’s

/* (New File) get

*/

code

exact

for

the

errors,

"usuals.h" "fileio.h" "language.h" "pgp.h"' "exitpgp.h"

#include

"ziperr.h"

Issue

error

code

ZIPDEBUG

/* for ZE_MEM

exit:

a message

zip/unzip

define

#include #include #include #include #include #include #include

/* Clean

/*

“zaipec—*/

Pe bile:

/* Support

hy %/

the

just handles

(and errors[]

c is a ZE_-class for

-

error,

error

messages.

error,

clean

if ZIPDEBUG

*msg

up files

defined)

is an error and memory,

exit

err

*/ void

(int c, char *msg)

#ifdef if

ZIPDEBUG (PERR

perror forintr

#endif

(c))

("zip error"); (stderr,

/* ZIPDEBUG

‘zip

erro:

(ies) \n";.errors[e

=

1], msg);

*/

/* Complain and return if (c == ZE_MEM)

{

4s

and

out

of memory

error

code

*/

fprintf exitPGP

(stderr, (7);

LANG

("\nOut

fprintf /* Yuck exitPGP

(stderr, */ (23);

LANG

("\nCompression/decompression

of memory\n"));

}$ else

é }

/* Internal

error,

should

never

happen

*/

*/

message. and

/*

err

To

*/

error\n"));

*/

847

ay

/*

848

*/

/* error

/ void

error err

}

(char *msg) (-1,

msg);

/*

PGP

Source

Code

and

Internals

*/

/*

File:

‘ziperr.h’

/* File:

¥*/

/*

‘ziperr.h’

/* (New File)

849

*/

*/

/*

Copyright (C) 1990,1991 Mark Adler, Richard B. Wales, and Jean-loup Gailly. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as all of the original files are included unmodified, that it is not sold for profit, and that this copyright notice is retained.

*

*/

ziperr.h

/* Error of

return

PKZIP.

by PKZIP,

#define #define #define

by Mark

Adler.

values.

The

The values so the codes

ZE_MISS ZE_OK ZE_EOF

values

4..10 5..10

are are

0..4

and

12..18

follow

-1 /* used by procname(), zipbare() 0 /* success */ 2 /* unexpected end of zip file */

#define

ZE_FORM

3 /* zip file

#define #define #define #define

ZE_MEM ZE_LOGIC ZE_BIG ZE_NOTE

4 5 6 7

#define

ZE_ABORT

9 /* user

#define

ZE_TEMP

10 /* error using a temp file */

#define #define #define #define #define #define #define

ZE_READ ZE_NONE ZE_NAME

11 12 13 14 15 16 18

/* Macro #define

ZE_WRITE ZE_CREAT

ZE_PARMS ZE_OPEN to

determine

PERR(e)

#ifdef GLOBALS /* Error messages char *errors[] =

/* /* /* /* /* /* /*

whether

(e==ZE_READ|

for

the

error

memory" */

*/

*/

or termination

*/

read or seek error */ nothing to do */ missing or empty zip file */ error writing to a file */ couldn’t open to write */ bad command line */ could not open a specified file to call perror() or not */

| e==ZE_WRITE]|

err()

function

1

2 */ "Unexpected end of zip file", 3 */ "Zip file structure invalid", 4 */ "Out of memory",

Ue

§& */ "Internal logic error",

/* /*

6 */ "Entry too big to split", 7 */ “Invalid comment format",

/*

8

sae

structure

interrupt

/* /* /*

*/

conventions

out of memory */ internal logic error */ entry too large to split */ invalid comment format */

/*

/*

* /

/* /* /* /*

the

all assigned to “insufficient used here for other purposes.

| e==ZE_CREAT|

in the

to read

| e==ZE_TEMP

zip programs

*/

*/

| | e==ZE_OPEN)

*/

/*

/*

850

*/

.

/*

PGP

9 */ "Interrupted",

/* 10 /* 11

*/ “Temporary file failure", */ "Input file read failure",

/* /* /* /* /* 7 /*

*/ */ */ */ */ / */

12 13 14 15 16 erie 18

"Nothing to do!", "Missing or empty zip file", "Output file write failure", "Could not create output file", "Invalid command arguments", >

"File

not

found

extern

'GLOBALS */ char *errors[];

#endif

/* ?GLOBALS

#else

or no

read

permission",

/*

*/

/* Error messages

for err()

*/

Source

Code

and

Internals

= 2 (for end-of-line

t unsigned

len

len;

= zread

if (len ==

(ifile,

buf,

(unsigned)

return len; return len;

EOF

size);

|| len == 0)

file,

and update

translation)

*/

the

crc

and

+¥*/

/*

File:

‘zrevisio.h’

/* File:

*/

/*

‘zrevisio.h’

855

*/

/* (New File) */ /*

Copyright

(C)

1990-1992

Mark Adler,

Richard

B. Wales,

and Jean-loup

Gailly.

Permission is granted to any individual or institution to use, copy, or redistribute this software so long as all of the original files are included unmodified, that it is not sold for profit, and that this copyright notice is retained.

*/

/* *

xrevision.h

by Mark

Adler.-

7 #define #define

REVISION 15 REVDATE '17th

/* Copyright * those

notice

(zip,

February

for binary

zipcloak,

1992" executables--this

zipsplit,

and

zipnote),

notice not

only applies

to this

to

file

* (revision.h).

*/ #ifndef

NOCPYRT

char *copyright[]

=

{

"Copyright (C) "Permission is "redistribute pmot. sold for

3;

char

1990,1991 Mark Adler, Richard B. Wales, and Jean-loup Gailly.", granted to any individual or institution to use, copy, or", this executable so long as it is not modified and that it is", profit."

*disclaimer[]

=

{ “LIKE ANYTHING ELSE THAT’S FREE, ZIP AND ITS ASSOCIATED UTILITIES ARE", “PROVIDED AS IS AND COME WITH NO WARRANTY OF ANY KIND, EITHER EXPRESSED OR", “TMPLIED. IN NO EVENT WILL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DAMAGES", “RESULTING FROM THE USE OF THIS SOFTWARE." 1G #endif

/*

!NOCPYRT

*/

7,

/*

856

/

*/

/*

PGP

Source

Code

and

cme ment aloneieee s/,

/* (New File) */ /* tailor.h

-- Not copyrighted

/* Use prototypes

and ANSI

1991 Mark Adler */

libraries

if

libraries

*/

__STDC__

*/

#ifdef __STIDC__ #ifndef PROTO #define PROTO

#Hendif #define

/* !PROTO */ MODERN

#Hendif /* __STDC__ /* Use prototypes

*/ and ANSI

#if defined(sgi)

|| defined(mips)

#ifndef PROTO #define PROTO #Hendif /* !PROTO #define MODERN

*/

#Hendif /* sgi */ /* Define

#ifdef

MSDOS

__POWERC

for

Turbo

/* For

#define __TURBOC__ #endif /* __POWERC

/* Use prototypes

C as

Power

well

C too

as

Microsoft

C */

*/

+*/

and ANSI

libraries

if Microsoft

or Borland

C */

#ifdef MSDOS #ifndef PROTO #define PROTO

#Hendif

/*

!PROTO

#define

MODERN

#Hendif

/* MSDOS

*/ */

/* Turn off prototypes #ifdef NOPROTO #ifdef PROTO #undef PROTO

#endif

/* PROTO

#endif

/* NOPROT

/* Used #ifdef

if requested

*/

*/ */

to remove PROTO

#define OF(a) a Helse /* !PROTO */

arguments

in function

prototypes

for non-ANSI

C */

Internals

*/

/*

File:

#define

#endif

‘ztailor.h’

OF(a)

*/

/*

()

/* ?PROTO

*/

/* Allow far and huge allocation for small model (Microsoft /* unless NOFAR defined (needed for ANSI mode compilations) /* But

if we’re

using DJGPP,

/* zmatch routines,

and want

to use

we can’t use DYN_ALLOC.

#ifdef MSDOS #ifndef __GNUC__ #ifndef DYN_ALLOC #define DYN_ALLOC #endif #Hendif #ifdef __TURBOC__ #include #define fcalloc calloc /* Assumes #define fcfree free #else /* !__TURBOC__ */ #ifndef __GNUC__ #include #define farmalloc _fmalloc #define

farfree

#define

fcalloc(nitems,itemsize)

#define

fcfree

that

optimized

386

#ifdef

NOFAR

huge

#define far #define near #endif #else /* !MSDOS #ifdef __QNX__

#undef

huge

#undef #undef #undef #Hundef #undef

far near farmalloc farfree fcalloc

*/

#endif /* __QNX__ */ huge

#define far #define near #define farmalloc malloc #define farfree free #define fcalloc calloc #define fcfree free #endif /* ?MSDOS */ #ifdef __GNUC__ #Hifdef MSDOS /* MSDOS GNU

C ==

DJGPP

*/

C) */

assembler

+*/

But gcc has virtual memory...

arrays

are

< 64K

for

MSDOS

halloc((long) (nitems) , (itemsize) )

hfree

/* __GNUC__ */ /* ?__TURBOC__ */

#define

all

the

C or Turbo */

_ffree

#endif #Hendif #define

857

*/

*/

a

/*

858

¥*/

;

#define

huge

#define #define #define #define #define #define

far near farmalloc farfree fcalloc fcfree

PGP

malloc free calloc free

#endif

/* MSDOS

#Hendif

/* __GNUC__

*/ */

/* Define MSVMS if either #ifdef MSDOS #define MSVMS #else /* !MSDOS +*/ #ifdef VMS #define MSVMS #endif /* VMS */

#endif

/*

/* ?MSDOS

MSDOS

or

VMS

defined

*/

*/

#include #include typedef unsigned int

extent;

/* Get types and stat */ #ifdef VMS #include #include

Helse /* !VMS */ #include #include #Hendif /* 7VMS */

/* Cheap fix for unlink on VMS */ #ifdef #define

#endif

VMS unlink

delete

/* VMS */

/* For Pyramid */ #ifdef #define

#Hendif

pyr strrchr

rindex

/* pyr */

/* File operations--use #ifdef MODERN #define FOPR "rb" #define FOPM "r+b" #define FOPW "wtb"

"b"

for binary

if allowed

*/

Source

Code

and

Internals

*/

/*

File:

#else

/*

‘ztailor.h’

!MODERN

#define

FOPR

"r"'

#define

FOPM

"r+"

#define

FOPW

"wt"

#endif

*/

/*

+*/

/* ?MODERN

*/

/* Define this symbol if your target allows access to unaligned data. * This is not mandatory, just a speed optimization. The compressed * output is strictly identical.

*/ #if defined(MSDOS) defined(mc68020) #define #endif

|| defined(M_XENIX)

|| defined(vax)

|| defined(i386)

UNALIGNED_OK

/* Under MSDOS we may run * of files. Compile with * with MIN_MEM to use as

out of memory when processing a large number MEDIUM_MEM to reduce the memory requirements little memory as possible.

*/ #ifdef SMALL_MEM #define BSZ 2048 /* Buffer #else #ifdef MEDIUM_MEM #define BSZ 8192 #else

#define #endif

BSZ

16384

#endif /* end

|| \

of tailor.h

*/

size for files

*/

or

859

*/

/*

860

*/

/*

Jin wle-.2ztrees.c° /* (New File)

PGP

Source

Code

and Internals

*/

*/

/*

Copyright

(C)

1990-1992

Mark Adler,

Richard

B. Wales,

Jean-loup

Gailly,

Kai Uwe Rommel and Igor Mandrichenko. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as all of the original files are included unmodified, that it is not sold for profit, and that this copyright notice is retained.

y/ SS*

trees.c

by Jean-loup

Gailly

This is a new version of im_ctree.c for the defunct implosion method.

originally

written

by Richard

B.

Wales

PURPOSE

Encode binary

various sets code trees.

of

source

values

using

variable-length

DISCUSSION The PKZIP ''deflation" process uses several Huffman trees. The more common source values are represented by shorter bit sequences.

Each code tree is stored in the ZIP file in a compressed form which is itself a Huffman encoding of the lengths of all the code strings (in ascending order by source values). The actual code strings are reconstructed from the lengths in the UNZIP process, as described in the "application note"

(APPNOTE.TXT)

distributed

as part

of PKWARE’s

PKZIP

program.

REFERENCES Lynch, Thomas J. Data Compression: Lifetime Learning Storer,

Data

James

A.

Compression:

Computer

Techniques and Applications, pp. 53-55. Publications, 1985. ISBN 0-534-03418-7.

Science

Methods Press,

Sedgewick, R. Algorithms, p290. Addison-Wesley, 1983. HH HOR HE MH eee Hee ee ee HHHH HH HHH HK

and

1988.

ISBN

Theory, ISBN

pp.

49-50.

0-7167-8156-5.

0-201-06672-6.

*/

/*

File:

o‘ztrees.c’ > +*/

/*

861

INTERFACE

* *

(ush *attr;

ct_init

void

*

int

*method)

*

Allocate

* *

the location of the internal method (DEFLATE/STORE)

the

match

buffer,

initialize

the

various

file attribute

tables

(ascii/binary)

and

save

and

*

void

* *

ct_tally (int Save the match

dist, int lc); info and tally

the

frequency

counts.

*

long

*

flush_block

(char

ulg

*buf,

int

stored_len,

eof)

Determine the best encoding for the current block: dynamic trees, static trees or store, and output the encoded block to the zip file. Returns the total compressed length for the file so far. ‘

* * ‘*

«/ #include #include /*

"zip.h"

—————

a

a

SS

SS

SS

SSS

SS

SS

SSS

SS

SSS

* Constants

*/ #define

/* All

MAX_BITS

codes

#define

15

must

not

MAX_BL_BITS

exceed

LENGTH_CODES

/* number #define

LITERALS

/* number #define

/* end

of length

*/

exceed MAX_BL_BITS bits

*/

29

codes,

not

counting the special END_BLOCK

END_BLOCK

bytes 0..255

D_CODES

/* number

*/

code

*/

*/

256

literal

code

*/

#define L_CODES (LITERALS+1+LENGTH_CODES) /* number of Literal or Length codes, including the END_BLOCK #define

code

256

of literal

of block

bits

7

/* Bit length codes must not #define

MAX_BITS

30

of distance

codes

#define BL_CODES 19 /* number of codes used

*/

to transfer

the bit

lengths

*/

local int near extra_lbits[LENGTH_CODES] /* extra bits for each length code */ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; local

int near

extra_dbits[D_CODES]

SS

See

Se =

*/

/*

/*

862

*/

extra

;

bits

for

#410, 0;50,1

each

distance

code

/*

PGP

Source

Code

and

Internals

*/

1.2.2.3 ,3,474,5,5,6,6,%,17,8,0;020;10;20s11911, 12g te onde

local

int near extra_blbits[BL_CODES]

/* extra

bits

for

each bit

length

code

*/

=71070,0,0,0,050,0,0,0,0,050,0,0,0,2,3, 7.5

#define #define #define

STORED_BLOCK STATIC_TREES DYN_TREES

/* The three kinds

0 1 2

of block

type */

#ifndef LIT_BUFSIZE #ifdef SMALL_MEM #define LIT_BUFSIZE 0x2000 #else #ifdef MEDIUM_MEM #define LIT_BUFSIZE 0x4000 #else #define LIT_BUFSIZE 0x8000 #endif #endif #endif #define DIST_BUFSIZE LIT_BUFSIZE /* Sizes of match buffers for literals/lengths and distances. There are * 4 reasons for limiting LIT_BUFSIZE to 64K: * - frequencies can be kept in 16 bit counters - if compression is not successful for the first block, all input data is still in the window so we can still emit a stored block even when input comes from standard input. (This can also be done for all blocks if LIT_BUFSIZE is not greater than 32K.) - if compression is not successful for a file smaller than 64K, we can

even |

emit a stored

creating

new

file

Huffman

instead

trees

less

of a stored block frequently

may

not

(saving 5 bytes). provide

fast

adaptation to changes in the input data statistics. (Take for example a binary file with poorly compressible code followed by a highly compressible string table.) Smaller buffer sizes give fast adaptation but have of course the overhead of transmitting trees ka? kat Kak ham Sue ta? had Sap a? At ie Gat

=

* The

more frequently. I can’t count above current

code

is

4

general

and

allows

DIST_BUFSIZE

* memory at the expense of compression). Some * if we rely on DIST_BUFSIZE == LIT_BUFSIZE.

< LIT_BUFSIZE

optimizations

would

+/

#define

REP_3_6

/* repeat #define

REPZ_3_10

/* repeat #define

16

previous a zero

bit length

3-6 times

(2 bits

of repeat

count)

af

length 3-10 times

REPZ_11_138

18

(3 bits

of repeat

count)

*/

*/

(to

save

be possible

*/

/*

File:

‘ztrees.c’

/* repeat /*

SSS

SSS

* Local

a zero SS

SSS

SS

+*/

length SSS

SS

/*

11-138

SS

SSS

SS

SS

times SSS

SS

(7 bits SSS

SS

SSS

SS

of repeat SS

SS

SSS

count)

2eS SSeS

SSS

*/ S555

22222======-=

;

data

*/ /* Data

structure

typedef

struct

describing

a single value

ct_data

and its code

string.

*/

{ union

{

ush freq; ush code; 3

/* frequency count /* bit string */

*/

EG

union

ol ush

dad;

/* father

ush len;

node

in Huffman

/* length of bit

tree

*/

string */

dl; ct_data;

#define

Freq fc.freq

#define #define #define

Code Dad Len

#define

HEAP_SIZE

fc.code dl.dad dl.len (2*L_CODES+1)

/* maximum heap size */ local local

ct_data near ct_data near

dyn_ltree[HEAP_SIZE]; dyn_dtree[2 * D_CODES

/* literal and length tree + 1]; /* distance tree */

*/

local ct_data near static_ltree[L_CODES + 2]; /* The static literal tree. Since the bit lengths are imposed, there is no * need for the L_CODES extra codes used during heap construction. However * The codes 286 and 287 are needed to build a canonical tree (see ct_init

* below).

*/ local

ct_data

/* The

static

near

static_dtree[D_CODES] ;

distance

tree.

(Actually

a trivial

tree

since

all

codes

* & bits~)

*/ local

ct_data

/* Huffman typedef


1) fprintf(stderr,"\ncd %3d ",(c)); send_bits(tree[c].Code, tree[c].Len); }

\

#endif

#define d_code(dist) \ ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)]) /* Mapping from a distance to a distance code. dist is the distance - 1 and * must not have side effects. dist_code[256] and dist_code[257] are never * used.

*/ Hdetane MAX Gay /* the arguments /*

b)aGaee—mb acaeacneb)) must not have side

SSS

5555555555555

buffer,

*/

5555555555555

* Allocate

the

* location

of the internal file attribute

*

match

effects

initialize

the

various

tables

(ascii/binary)

(DEFLATE/STORE) .

*/

/*

Comintt */ void ct_init

(attr,

Method)

ush *attr; /* pointer to internal file attribute */ int *Method; /* pointer to compression method */ int int

n; /* iterates over tree bits; /* bit counter */

int length; int int

code; dist;

/* length value

*/

/* code value */ /* distance index

*/

file_type = attr; file_method = Method; compressed_len = input_len #ifdef

d_buf 1_buf

elements

*/

= OL;

DYN_ALLOC

= =

(ush far "(uch far

*) fcalloc (DIST_BUFSIZE, *) “feallloc*(LITABUFSIZE*/

/* Avoid using the value

if (1_buf == NULL

sizeof “2 02)e

64K on 16 bit machines

|| d_buf == NULL)

*/

(ush));

55552555

and

save

and method

the

2=>=>

*/

/*

File:

‘ztrees.c’

error

("ct_init:

*/

/*

out of memory");

#endif

if (static_dtree[0].Len != 0) return; /* ct_init already called */

/* Initialize

the mapping length

length = 0; for (code = 0;

(0..255)

< LENGTH_CODES

code

-

-> length code

(0..28)

1; codet+)

4 base_length[code]

for

length;

=

(n = 0; n < (1 = 7; /* from now on, all distances are for (; code < D_CODES; code++)

divided

{ base_dist[code] for

(n =

= dist

0; n < (1 = base) = extra[n - base]; f = tree[n] .Freq;

xbits

opt_len += (ulg) f *(bits + xbits); if (stree) static_len += (ulg) f *(stree[n].Len + xbits); Te

Covert!

owe==) 0)

return;

Trace

((stderr,

/* This happens /* Find do

the

"\nbit

length

for example

first

bit

length

overflow\n")) ;

on obj2 and pic of the Calgary which

could

increase:

corpus

*/

*/

£ bits

= max_length

while

-

1;

(bl_count[bits]

== 0)

babe

bl_count[bits]--; /* move one leaf down the tree */ bl_count[bits + 1] += 2; /* move one overflow item as

its

brother

bl_count [max_length]--; /* The

brother

* but this

of the

does not

*/ overflow

while

-=

(overflow

2;

> 0);

overflow

affect

item

also

moves

bl_count [max_length]

one

step up,

*/

871

*/

/*

872

*/

/*

/* Now recompute

* h is still * lengths

* from

all bit

lengths,

scanning

equal to HEAP_SIZE.

instead

’ar’

of fixing

Source

in increasing

Code

wrong

ones.

This

and

Internals

frequency.

(It is simpler to reconstruct

only the

written by Haruhiko

PGP

idea

all

is taken

Okumura.)

*/ for

(bits

= max_length;

bits

!= 0; bits--)

n = bl_count [bits]; mnsihe Ga Y=

m = heap[--h]; if

(m > max_code) continue;

if (tree[m].Len Trace

!= (unsigned)

((stderr,

opt_len

+=

"code

((long)

tree[m].Len

bits)

%d bits

bits

%d->%d\n",

- (long)

m,

tree[m].Len,

tree[m].Len)

* (long)

bits));

tree[m] .Freq;

= bits;

}

Tinos

}

t

} /*

=

SSS

5555555555525

* Generate

the

codes

for

5255555555

5555555552555

a given tree

and bit

5555555555555

counts

5555555555555

(which need not

be

* optimal). * IN assertion: the array bl_count contains the bit length statistics * the given tree and the field len is set for all tree elements. * OUT assertion: the field code is set for all tree elements of non ce zero code length.

for

+/ /*

gen_codes +/ local

void

gen_codes

(tree,

ct_data int

near

max_code;

max_code) *tree;

/* the

/* largest

ush next_code[MAX_BITS

tree

code

+ 1];

to

with

/* next

ush code = 0; /* running code value

decorate

*/

non

frequency

code

zero

value

for

each

*/

bit

length

*/

*/

int bits; /* bit index */ int n; /* code index */ /* The distribution counts * without bit reversal.

are

first

used

#7,

for

(bits

=

1; bits)

E>=>=>=

*/

/*

File:

‘ztrees.c’

*/

/*

873

sl next_code[bits]

=

code

/* Check that the bit * must be all ones.

=

(code

counts

+ bl_count[bits

in bl_count

are

-

1])

consistent.

= = 1 && blcodes >= 4, "not enough codes"); L_CODES && dcodes > 3; static_lenb

and get the

Yu ",

*/

/*

File:

‘ztrees.c’

+*/

#ifdef FORCE_METHOD if (level == 1 && eof

{ /* force

&&

/*

compressed_len

stored file

==

OL)

*/.

#else

if (stored_len

= 0x2000

13 /* used in unShrink() +*/ (1 ¢ aneo eco ee a REBZE DELS 8 repaean sup eseks ans suldaroe wisi eae: RE BZ23 210 reer ety irs ou eee me ka ete

239 718 (Alf) 707 891 243 586 862 862 862

Eescale(r,currentp,newp)

570

aa...

eneaber

PRESTU) Se opened eoaeMt Geka citebeLausdels fentonlon etsous yeee(easyo,sheasye 888 REW DA iernaeaaeieubaraketde 2acaalouuada cae. aac etek 855

TEVerse at bTiG) cs Meyers, 6 syels, minis p hee tae

546

RE VALS LON erresenep-conatevsteusayoters( 0)alae Sereaie silane teisls areas FO TU pegepepienst-a5y-cdtpaite tcc neti «ice "vovartenahs otsiresovar'ev/econe.enauaans HARA: GOR DHM=s Yel Exertekenettte tenetoletaetetereteioistctahet cheat RSASDECRZERRORG sa 00 «cere dere cielsiatete srateleyevs ater selela RSACENCREERROR wuts crereae l ore «1-12,