![]() |
|
|
Курсовая работа: Разработка Java-апплета и подписывание архивного JAR-файла электронной цифровой подписьюКурсовая работа: Разработка Java-апплета и подписывание архивного JAR-файла электронной цифровой подписьюГосударственное образовательное учреждение высшего профессионального образования ПЕТЕРБУРГСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ ПУТЕЙ СООБЩЕНИЯ Кафедра «Информационные и вычислительные системы» ПОЯСНИТЕЛЬНАЯ ЗАПИСКА к курсовому проекту по дисциплине «Методы программирования» на тему: «Разработка Java-апплета и подписывание архивного JAR-файла электронной цифровой подписью» Выполнил: студент группы КИБ-708 Таранин В.В. Руководитель: к.т.н., доц. Кожомбердиева Г.И. Санкт-Петербург 2009 Задание по курсовому проекту по дисциплине «Методы программирования» на тему: «Разработка Java-апплета и подписывание архивного JAR-файла электронной цифровой подписью» · В качестве исходных данных к курсовому проекту используется апплет, являющийся результатом выполнения лабораторной работы №4 «Разработка апплета с эффектом анимации на основе многопоточности Java». Вариант задания №20 · Необходимо расширить функциональность апплета с эффектом анимации, реализовав обращение к локальной файловой системе. · Создать архивный JAR-файл, содержащий апплет. · Подписать JAR-файл электронной цифровой подписью (ЭЦП) и задать политику безопасности для подписанного апплета, включив в файл политики соответствующую запись, разрешающую доступ к локальной файловой системе и выполнение операций чтения-записи. При выполнении курсового проекта использовать утилиты jar, keytool и jarsigner, а также комплект JDK 1.4.x с модулем plug-in для браузера MS IE 5,(6),(7). Аннотация В данном курсовом проекте был разработан Java-апплет, использующий механизм многопоточности Java: использование двух потоков команд, реализующих движение геометрических фигур в области рисования апплета. Также апплет имеет возможность обращаться к локальной файловой системе, при предоставлении соответствующих прав доступа. Возможность обращения к локальной файловой системе реализована с использованием специализированных классов Java API. Архивный JAR-файл, содержащий апплет, подписывается электронной цифровой подписью. Для апплета задается политика безопасности, путём создания пользовательского файла политики безопасности, который позволяет апплету получить доступ к локальной файловой системе и обеспечивающий возможность работы апплета за пределами модели безопасности Sandbox – «Песочница». Подписанный электронной цифровой подписью апплет выполняется в среде MS IE с модулем plug-in из JDK 1.4.x. После запуска апплета пользователю предоставляется возможность оказать доверие подписанному апплету и разрешить выполнение операций ввода-вывода в файл. Содержание Введение 1. Апплет с эффектом анимации на основе многопоточности Java и обращением к локальной файловой системе 2. Создание подписанного апплета 2.1 Создание архивного JAR-файла 2.2 Создание пары ключей и сертификата в хранилище ключей 2.3 Подписывание JAR-файла цифровой подписью 2.4 Задание политики безопасности для подписанного апплета 3. Выполнение подписанного апплета Список использованных источников Введение Платформа Java 2 располагает мощной встроенной системой безопасности, включающая API-интерфейсы и механизмы, которые используются для обеспечения безопасности апплетов и приложений Java. Среди особенностей языка программирования Java, которые обеспечивают надежность и безопасность можно выделить: архитектурную независимость, интерпретируемость, переносимость, отсутствие указателей, строгую типизацию, эффективный механизм обработки исключений. Важными неотъемлимыми компонентами системы безопасности Java 2 являются Java Cryptography Architecture (JCA) – архитектура шифрования Java, а также Java Cryptography Extension (JCE) – криптографическое расширение Java. Целью данного курсового проекта является – подписание архивного JAR-файла, содержащего апплет, электронной цифровой подписью, а также задание политики безопасности для подписанного апплета; ознакомление студентов с криптографическими методоми защиты информации и возможностями, которые предоставляет Java разработчиками программного обеспечения. Для этого необходимо: создать архивный JAR-файл, пары ключей и сертификата в хранилище ключей, далее подписать JAR-файл цифровой подписью и задать политику безопасности для подписанного апплета. Результатом данной курсовой работы является подписанный электронной цифровой подписью апплет, имеющий возможность обращаться к локальной файловой системе. 1. Апплет с эффектом анимации на основе многопоточности Java и обращением к локальной файловой системе апплет архивный электронный цифровой подпись import java.applet.Applet; import java.awt.*; import java.awt.event.*; import java.io.*; import java.util.Calendar; // Класс апплета, реализующий интерфейсы блоков прослушивания событий public class Lab4 extends Applet implements ActionListener,ItemListener,Runnable { Panel p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,cards,pfield,pb,pread; Label lb1,lb2,lb3; CheckboxGroup cbg; Checkbox cb1,cb2,cb3,cb4; List list; Canvas cv; Button b1,b2,b3,b4,start,stop,read; CardLayout cardLO; Scrollbar sb1,sb2,sb3,sb4; Color col; int posX,strWidth; FontMetrics fm; int rectX=0,rectY=0,posFlag=0,movFlag=0,ovalX=0,ovalY=0; int animFlag=0; int rColor,gColor,bColor; // Флаг остановки анимации boolean stopFlag; // Поток выполняющий анимацию Thread t = null; //Текстовая область для вывода содержимого файла журнала TextArea fileText; // Имя файла-журнала для записи информации о работе апплета String fileName = ""; // Разделитель строк (признак конца строки) String ls; // Буферизированный символьный поток записи в файл BufferedWriter out; public void init() { setLayout(new GridLayout(2,2)); setForeground(Color.black); col = Color.black; // ЛЕВАЯ ВЕРХНЯЯ ПАНЕЛЬ p1 = new Panel(new BorderLayout()); p1.setBackground(Color.lightGray); p2= new Panel(); lb1 = new Label("Активная панель: ",lb1.CENTER); p2.add(lb1); p1.add(p2,BorderLayout.NORTH); // Панель радиокнопок внутри ЛЕВОЙ ВЕРХНЕЙ панели p3 = new Panel(new GridLayout(2,2)); cbg = new CheckboxGroup(); cb1= new Checkbox("Все панели",cbg,true); cb2= new Checkbox("1-я панель",cbg,false); cb3= new Checkbox("2-я панель",cbg,false); cb4= new Checkbox("3-я панель",cbg,false); cb1.addItemListener(this); cb2.addItemListener(this); cb3.addItemListener(this); cb4.addItemListener(this); p3.add(cb1); p3.add(cb2); p3.add(cb3); p3.add(cb4); p1.add(p3,BorderLayout.CENTER); add(p1); // ВЕРХНЯЯ ПРАВАЯ ПАНЕЛЬ p4 = new Panel(new GridLayout(1,1)); list = new List(9,false); list.add("Чёрный"); list.add("Синий"); list.add("Красный"); list.add("Зелёный"); list.add("Жёлтый"); list.add("Оранжевый"); list.add("Розовый"); list.add("Фиолетовый"); list.add("Тёмно-серый"); list.addItemListener(this); p4.add(list); add(p4); // ЛЕВАЯ НИЖНЯЯ ПАНЕЛЬ // Панель с кнопками p5 = new Panel(new GridLayout(2,2)); b1 = new Button("Квадрат"); b2 = new Button("Круг"); b3 = new Button("Треугольник"); b4 = new Button("Строка"); b1.addActionListener(this); b2.addActionListener(this); b3.addActionListener(this); b4.addActionListener(this); p5.add(b1); p7.add(b2); p5.add(b3); p5.add(b4); pb = new Panel(new GridLayout(1,2,5,0)); lb2 = new Label("Управление потоками",lb1.CENTER); start = new Button("Запуск"); start.addActionListener(this); stop = new Button("Остановка");stop.addActionListener(this); pb.add(start); pb.add(stop); // !!! ПАНЕЛЬ ДЛЯ ЧТЕНИЯ ФАЙЛА-ЖУРНАЛА !!! pfield = new Panel(new BorderLayout()); pread = new Panel(new GridLayout(3,1)); read = new Button("Чтение файла-журнала"); read.addActionListener(this); // Текстовая область для вывода информации из файла журнала fileText = new TextArea(); // Название файла-журнала задаётся параметром в HTML-файле // или если такого нет – создаётся по умолчанию fileName = getParameter("FileName"); if (fileName == null) fileName = "log.txt"; ls = System.getProperty("line.separator"); // разделитель строк fileText.setBackground(Color.white); pread.add(lb2); pread.add(pb); pread.add(read); pfield.add(p5,BorderLayout.NORTH); pfield.add(pread,BorderLayout.CENTER); pfield.add(fileText,BorderLayout.SOUTH); add(pfield); // ПРАВАЯ НИЖНЯЯ ПАНЕЛЬ // ПАНЕЛЬ С КАРТАМИ (ГЛАВНАЯ) cardLO = new CardLayout(); cards = new Panel(); cards.setLayout(cardLO); cards.setBackground(Color.white); posX = 65; // ПЕРВАЯ ПАНЕЛЬ В КАРТАХ p6 = new Panel(new BorderLayout()) { public void paint(Graphics g) { if(animFlag==0) { g.setColor(col); g.drawRect(rectX,rectY,50,50); } } }; // ВТОРАЯ ПАНЕЛЬ В КАРТАХ p7 = new Panel(new BorderLayout()) { public void paint(Graphics g) { if(animFlag==1) { g.setColor(col); g.fillOval(ovalX,ovalY,50,50); } } }; // ТРЕТЬЯ ПАНЕЛЬ В КАРТАХ p8 = new Panel(new BorderLayout()) { public void paint(Graphics g) { g.setColor(col); int x[] = {posX,posX+40,posX+80}; int y[] = {80,20,80}; g.drawPolygon(x,y,3); } }; sb3= new Scrollbar(Scrollbar.HORIZONTAL,0,1,0,100); sb3.addAdjustmentListener(new AdjustmentListener() { public void adjustmentValueChanged(AdjustmentEvent ae) { posX = (ae.getValue())*(cards.getSize().width -80) /sb3.getMaximum(); p8.repaint(); } }); p8.add(sb3,BorderLayout.SOUTH); // ЧЕТВЁРТАЯ ПАНЕЛЬ В КАРТАХ P9 = new Panel(new BorderLayout()) { public void paint(Graphics g) { fm = g.getFontMetrics(); strWidth = fm.stringWidth("J A V A"); g.setFont(new Font("Dialog",Font.ITALIC,20)); g.setColor(col); g.drawString("J A V A",posX,65); } }; sb4= new Scrollbar(Scrollbar.HORIZONTAL,0,1,0,5); sb4.addAdjustmentListener(new AdjustmentListener() { public void adjustmentValueChanged(AdjustmentEvent ae) { posX = (ae.getValue())*(cards.getSize().width – strWidth)/sb4.getMaximum(); p9.repaint(); } }); p9.add(sb4,BorderLayout.SOUTH); // ДОБАВЛЕНИЕ КАРТ В ПАНЕЛЬ С КАРТАМИ (cards) cards.add(p6,"sqaure"); cards.add(p7,"oval"); cards.add(p8,"rect"); cards.add(p9,"text"); add(cards); // СОЗДАНИЕ БУФЕРИЗИРОВАННОГО СИМВОЛЬНОГО ПОТОКА ЗАПИСИ В ФАЙЛ try { // В качестве параметра в данном конструкторе класса Buffered используется // ссылка на объект основного потока (приёмника данных) out = new BufferedWriter(new FileWriter(fileName)); } catch(IOException ex) { fileText.setText("Ошибка при создании потока записи: " + ls); fileText.append(ex.toString() + ls); } catch(SecurityException ex) { fileText.setText("Нет разрешения доступа к файлу: " + ls); fileText.append(ex.toString() + ls); read.setEnabled(false); } if (out != null) { // Если создание Buffered-потока прошло успешно то в качестве данных, которые // будут заполнять буфер будет являться сообщение от текущей дате и времени Calendar c = Calendar.getInstance(); String dateMessage ="Дата и время: " + c.get(Calendar.DAY_OF_MONTH) + "/" + (c.get(Calendar.MONTH)+1) + " – " + c.get(Calendar.YEAR) + " " + c.get(Calendar.HOUR_OF_DAY) + ":" + c.get(Calendar.MINUTE); // После записи в String-переменную dateMessage информации о дате – // вызывается метод writeLogMessage writeLogMessage(dateMessage); writeLogMessage("Инициализация апплета завершена"); } /*--------------INIT--------------*/ } // Вывод сообщения в буферизированный поток для записи в файл private void writeLogMessage(String message) { // Запись в файл осуществляется вызовом метода write объек-та out типа BufferedWriter try { out.write(message); out.newLine(); } catch(IOException ex) { fileText.setText("Ошибка записи в файл:" + ls); fileText.append(ex.toString() + ls); } } // Запуск потоков public void run() { // Пока флаг остановки анимации равен false – происходит анимация while (!stopFlag) { try { if(animFlag==0) { if(posFlag==0) // Начальное движение вправо по верхней грани { p6.repaint(); // Перерисовка // Временное (на 40 мс) остановка потока для создания эффекта анимации // Далее идут аналогичные изменения координат/ Thread.currentThread().sleep(40); rectX+=5; if(rectX>p6.getSize().width-50) { rectX-=7; posFlag =1; if(posFlag==1) { rColor = (int)(255*Math.random()); gColor = (int)(255*Math.random()); bColor = (int)(255*Math.random()); col = new Color(rColor,gColor,bColor); p6.repaint(); } } } if(posFlag==1) // Движение вниз по правой грани { p6.repaint(); Thread.currentThread().sleep(40); // приостановить поток rectY+=5; if(rectY>p6.getSize().height – 50) { rectY=p6.getSize().height-53; posFlag=2; if(posFlag==2) { rColor = (int)(255*Math.random()); gColor = (int)(255*Math.random()); bColor = (int)(255*Math.random()); col = new Color(rColor,gColor,bColor); p6.repaint(); } } } if(posFlag==2) // Движение влево по нижней грани { if(rectX>0) { p6.repaint(); Thread.currentThread().sleep(40); rectX-=5; } else { rectX=0; posFlag=3; if(posFlag==3) { rColor = (int)(255*Math.random()); gColor = (int)(255*Math.random()); bColor = (int)(255*Math.random()); col = new Color(rColor,gColor,bColor); p6.repaint(); } } } if(posFlag==3) // Движение вверх по левой грани { if(rectY>0) { p6.repaint(); Thread.currentThread().sleep(40); rectY-=5; if(rectY<0) { rectX=0; rectY=0; p6.repaint(); { if(rectX==0 && rectY==0) { posFlag=0; if(posFlag==0) { rColor = (int)(255*Math.random()); gColor = (int)(255*Math.random()); bColor = (int)(255*Math.random()); col = new Color(rColor,gColor,bColor); p6.repaint(); } } } } } } } if(animFlag==1) { if(movFlag==0) // Движение по диагонали сверху в нижний угол { p7.repaint(); Thread.currentThread().sleep(50); ovalX+=5; ovalY+=5; if(ovalX>p7.getSize().width-50) { ovalX = p7.getSize().width -50; ovalY = p7.getSize().height-52; movFlag =1; if(movFlag==1) { rColor = (int)(255*Math.random()); gColor = (int)(255*Math.random()); bColor = (int)(255*Math.random()); col = new Color(rColor,gColor,bColor); p7.repaint(); } } } if(movFlag==1) // Движение по нижней грани { p7.repaint(); Thread.currentThread().sleep(50); ovalX-=5; if(ovalX<0) { ovalX=0; movFlag=2; if(movFlag==2) { rColor = (int)(255*Math.random()); gColor = (int)(255*Math.random()); bColor = (int)(255*Math.random()); col = new Color(rColor,gColor,bColor); p7.repaint(); } } } if(movFlag==2) // Движение по диагонали снизу вверх { p7.repaint(); Thread.currentThread().sleep(50); ovalX+=5; ovalY-=5; if(ovalX>p7.getSize().width-50) { ovalX = p10.getSize().width – 52; ovalY = 0; movFlag=3; if(movFlag==3) { rColor = (int)(255*Math.random()); gColor = (int)(255*Math.random()); bColor = (int)(255*Math.random()); col = new Color(rColor,gColor,bColor); p7.repaint(); } } } if(movFlag==3) // Движение по верхней грани в обратном направлении { p7.repaint(); Thread.currentThread().sleep(50); ovalX-=5; if(ovalX<0) { ovalX = 0; movFlag=0; if(movFlag==0) { rColor = (int)(255*Math.random()); gColor = (int)(255*Math.random()); bColor = (int)(255*Math.random()); col = new Color(rColor,gColor,bColor); p7.repaint(); } } } } } catch (InterruptedException e) { return; // Завершить поток } } } //Реализация блоков прослушивания от кнопок public void actionPerformed(ActionEvente) { String ac = e.getActionCommand(); if(ac.equals("Квадрат")) { animFlag=0; cardLO.show(cards,"sqaure"); writeLogMessage("Рисуется Квадрат"); } if(ac.equals("Круг")) { animFlag=1; cardLO.show(cards,"oval"); writeLogMessage("Рисуется Круг"); } if(ac.equals("Треугольник")) { cardLO.show(cards,"rect"); } if(ac.equals("Строка")) { cardLO.show(cards,"text"); } else if("Запуск".equals(ac)) { t = new Thread(this); stopFlag = false; t.start(); start.setEnabled(false); writeLogMessage("Поток запущен"); } else if("Остановка".equals(ac)) { stopFlag=true; t = null; start.setEnabled(true); writeLogMessage("Поток остановлен"); } if("Чтение файла-журнала".equals(ac)) { try { // Сброс данных из буфера потока (запись в файл) out.flush(); // Далее происходит чтение из файла и заполнение текстовой области // данными, содержащимися в текстовом файле Lab4Log.txt // Создание буферизированного символьного потока чтения из файла*/ BufferedReader in = new BufferedReader(new FileReader(fileName)); String s = "", line; while ((line = in.readLine()) != null) s += line + "\n"; fileText.setText(s); in.close(); } catch(IOException ex) { fileText.setText("Ошибка чтения файла: " + ls); fileText.append(ex.toString()); } } } // Реализация блока прослушивания от списка List и переключателей(CheckBox) public void itemStateChanged(ItemEvent ie) { if(ie.getSource() == list) { String s = list.getSelectedItem(); if(s.equals("Чёрный")) { col = Color.black; } if(s.equals("Синий")) { col = Color.blue; } if(s.equals("Красный")) { col = Color.red; } if(s.equals("Зелёный")) { col = Color.green; } if(s.equals("Жёлтый")) { col = Color.yellow; } if(s.equals("Оранжевый")) { col = Color.orange; } if(s.equals("Розовый")) { col = Color.pink; } if(s.equals("Фиолетовый")) { col = Color.magenta; } if(s.equals("Тёмно-серый")) { col = Color.darkGray; } p6.repaint(); p7.repaint(); p8.repaint(); p9.repaint(); } } // Обработка события от CheckBox (Определение доступности панелей и их компонентов) if(ie.getSource() == cb1) { p1.setEnabled(true);p4.setEnabled(true); p7.setEnabled(true); cards.setEnabled(true); } if(ie.getSource() == cb2) { p1.setEnabled(true);p4.setEnabled(true); p7.setEnabled(false); cards.setEnabled(false); } if(ie.getSource() == cb3) { p1.setEnabled(true);p4.setEnabled(false); p7.setEnabled(true); cards.setEnabled(false); } if(ie.getSource() == cb4) { p1.setEnabled(true);p4.setEnabled(false); p7.setEnabled(false); cards.setEnabled(true); } } } 2. Создание подписанного апплета 2.1 Создание архивного JAR-файла Для подписания апплета электронной цифровой подписью его упаковывают в архивный JAR-файл. В данной курсовой работе для этой цели используется утилита jar, либо можно использовать интегрированную среду разработки приложений. Для создания архива применилась команда следующего вида: jar cfv Lab4.jar Lab4*.class, где: jar – название утилиты, которая упаковывает файлы и создаёт архив cfv – это набор из трёх параметров: · с – указывает на то,что создаётся новый архив · f – первый элемент в списке файлов – имя архива, который должен быть создан · v – вывод на консоль сообщений о всех действиях утилиты jar Lab4.jar – название нового архива Lab4*.class – параметр указывает, что все файлы классов расположенные в текущем каталоге, размещаются в архиве Lab4.jar При этом утилита jar создаёт каталог META-INF с файлом описания архива MANIFEST.MF Также в HTML файле, используемом для запуска апплета были внесены изменения, а именно добавлен атрибут ARCHIVE элемента Applet. Значение атрибута ARCHIVE = Lab4.JAR.
2.2 Создание пары ключей и сертификата в хранилище ключей Далее с помощью утилиты keytool создаётся пара ключей («открытый/закрытый») и сертификат по стандарту X.509 для псевдонима «Taraninkey» в хранилище ключей Taraninstore в текущем каталоге. Для создания самоподписанного сертификата применилась команда: keytool -genkey -alias «Taraninkey» -keystore Taraninstore, где: -genkey – параметр указывающий, что утилита keytool должна сгенерировать ключи -alias «Taraninkey» – псевдоним, под которым в хранилище ключей размещается сертификат -keystore Taraninstore – название хранилища ключей Также по требованиям утилиты, был введён пароль защиты хранилища ключей, информация о владельце сертификата и пароль защиты закрытого ключа. В данном курсовом проекте пароль закрытого ключа «Taraninkey» – 123369, а пароль хранилища ключей «Taraninstore» – 123. При создании ключей и подписании сертификата были использованы алгоритмы: · Алгоритм ключа RSA · Алгоритм подписи MD-5
2.3 Подписывание JAR-файла цифровой подписью Архивный JAR-файл подписывается с помощью утилиты jarsigner. используя следующую команду: jarsigner -keystore Taraninstore Lab4.jar «Taraninkey» Утилита требует ввести пароль хранилища ключей и пароль закрытого ключа после чего модифицирует файл описания архива MANIFEST.MF в каталоге META-INF архива. В него добавляются записи для каждого файла класса, входящего в архив. Запись файла класса включает имя и дайджест файла. Также в каталог META-INF архива добавляется файл подписи TARNINK.SF. Содержимое файла подписи TARNINK.SF. Файл подписи идентифицирует каждый из файлов в архиве, алгоритм дайджеста содержит для каждого файла значение дайджеста, вычисленного из записи файла в файле описания MANIFEST.MF. На заключительном этапе подписания в каталог META-INF файла архива добавляется двоичный файл подписи TARANINK.RSA. Расширение файла подписи указывает, что утилита keytool использует алгоритм цифровой подписи RSA. Этот файл содержит подпись файла подписи TARNINK.SF и сертификат, заверяющий подлинность открытого ключа, соответствующего закрытому ключу, использованному при создании подписи.
2.4 Задание политики безопасности для подписанного апплета В данной курсовом проекте для получения доступа к локальной файловой системе, для подписанного электронной цифровой подписью апплета, был создан пользовательский файл политики безопасности Lab4.policy. Содержимое данного файла – набор разрешающих записей, в которых указываются права доступа, предоставляемые источнику кода апплета. Данная запись права доступа предоставляет право чтения/записи всех файлов файловой системы. 3. Выполнение подписанного апплета При запуске апплета в среде браузера MS IE 5(6) с модулем Java plgu-in из JDK 1.4.x система безопасности задаёт вопрос о доверии поставщику, чьим сертификатом заеверен апплет. При выборе пользователем ответа Grant this session апплет получает полные права доступа ко всем ресурсам. Для обращения к локальной файловой системе пользователь может осущесвить чтение файла-журнала, хранящегося на локальном диске, нажав кнопку «View Certificate». При выборе пользователем Deny апплет получает разрешене работать только с теми ресурсами, права доступа к которым прописаны в файлах политики безопасности. При выборе Grant always апплет получает полные права доступа ко всем ресурсам, при следующем запуске апплета не будет задаваться запрос о доверии поставщику, права доступа будут автоматически ко всем ресурсам. При запуске подписанного апплета под браузером appletviewer апплет автоматически получает права доступа к ресурсам, указанные в пользовательском файле политики безопасности, размещённом в текущем каталоге. Список использованных источников 1. Корниенко А.А., Кожомбердиева Г.И., Ерофеев П.В. Электронная цифровая подпись и безопасность Java-апплетов. Метод. указания. – СПб.: ПГУПС, 2005. – 28 с. 2. Корниенко А.А., Кожомбердиева Г.И., Киселев И.С. Методы криптографической защиты информации и их реализация на платформе Java: Метод. указания. – СПб.: ПГУПС, 2006. – 35 с 3. Ноутон П., Шилдт Г. Java 2: Пер. с англ. – СПб.: БХВ-Петербург, 2006 4. Java 2 SDK, Standard Edition Documentation, version 1.2.2. 5. Яворски Дж., Перроун П. Система безопасности Java, 2001. |
![]() |
||
НОВОСТИ | ![]() |
![]() |
||
ВХОД | ![]() |
|
Рефераты бесплатно, реферат бесплатно, курсовые работы, реферат, доклады, рефераты, рефераты скачать, рефераты на тему, сочинения, курсовые, дипломы, научные работы и многое другое. |
||
При использовании материалов - ссылка на сайт обязательна. |